From 15586b3076e729649dcc79b8ac2b35f8a33274d1 Mon Sep 17 00:00:00 2001 From: Dmitry Atamanov Date: Tue, 16 Aug 2022 19:33:00 +0500 Subject: [PATCH] Add foreach_r tests --- test/test_suite/statements/foreach_custom.c3t | 18 +- .../test_suite/statements/foreach_r_break.c3t | 72 ++++ .../statements/foreach_r_common.c3t | 353 ++++++++++++++++++ .../statements/foreach_r_custom.c3t | 94 +++++ .../statements/foreach_r_custom_errors.c3 | 15 + .../statements/foreach_r_custom_macro.c3t | 93 +++++ .../test_suite/statements/foreach_r_errors.c3 | 54 +++ .../statements/foreach_r_parse_error.c3 | 5 + test/test_suite/statements/foreach_r_test.c3t | 94 ----- .../statements/foreach_r_with_error.c3 | 12 + .../test_suite2/statements/foreach_custom.c3t | 18 +- .../statements/foreach_r_break.c3t | 72 ++++ .../statements/foreach_r_common.c3t | 350 +++++++++++++++++ .../statements/foreach_r_custom.c3t | 92 +++++ .../statements/foreach_r_custom_errors.c3 | 15 + .../statements/foreach_r_custom_macro.c3t | 91 +++++ .../statements/foreach_r_errors.c3 | 54 +++ .../statements/foreach_r_parse_error.c3 | 5 + .../test_suite2/statements/foreach_r_test.c3t | 87 ----- .../statements/foreach_r_with_error.c3 | 12 + 20 files changed, 1417 insertions(+), 189 deletions(-) create mode 100644 test/test_suite/statements/foreach_r_break.c3t create mode 100644 test/test_suite/statements/foreach_r_common.c3t create mode 100644 test/test_suite/statements/foreach_r_custom.c3t create mode 100644 test/test_suite/statements/foreach_r_custom_errors.c3 create mode 100644 test/test_suite/statements/foreach_r_custom_macro.c3t create mode 100644 test/test_suite/statements/foreach_r_errors.c3 create mode 100644 test/test_suite/statements/foreach_r_parse_error.c3 delete mode 100644 test/test_suite/statements/foreach_r_test.c3t create mode 100644 test/test_suite/statements/foreach_r_with_error.c3 create mode 100644 test/test_suite2/statements/foreach_r_break.c3t create mode 100644 test/test_suite2/statements/foreach_r_common.c3t create mode 100644 test/test_suite2/statements/foreach_r_custom.c3t create mode 100644 test/test_suite2/statements/foreach_r_custom_errors.c3 create mode 100644 test/test_suite2/statements/foreach_r_custom_macro.c3t create mode 100644 test/test_suite2/statements/foreach_r_errors.c3 create mode 100644 test/test_suite2/statements/foreach_r_parse_error.c3 delete mode 100644 test/test_suite2/statements/foreach_r_test.c3t create mode 100644 test/test_suite2/statements/foreach_r_with_error.c3 diff --git a/test/test_suite/statements/foreach_custom.c3t b/test/test_suite/statements/foreach_custom.c3t index 752920d2f..01e85f25f 100644 --- a/test/test_suite/statements/foreach_custom.c3t +++ b/test/test_suite/statements/foreach_custom.c3t @@ -1,6 +1,6 @@ // #target: macos-x64 -module foo; +module test; struct Foo { int[] x; @@ -31,10 +31,10 @@ fn void main() extern fn int printf(char *fmt, ...); -/* #expect: foo.ll +/* #expect: test.ll ; Function Attrs: nounwind -define void @foo_main() #0 { +define void @test_main() #0 { entry: %i = alloca [3 x i32], align 4 %x = alloca %Foo, align 8 @@ -81,4 +81,14 @@ loop.body2: ; preds = %loop.body loop.exit: ; preds = %loop.body2, %loop.cond ret void -} \ No newline at end of file +} + +; Function Attrs: nounwind +declare i32 @printf(i8*, ...) #0 + +; Function Attrs: nounwind +define i32 @main(i32 %0, i8** %1) #0 { +entry: + call void @test_main() + ret i32 0 +} diff --git a/test/test_suite/statements/foreach_r_break.c3t b/test/test_suite/statements/foreach_r_break.c3t new file mode 100644 index 000000000..7254b5908 --- /dev/null +++ b/test/test_suite/statements/foreach_r_break.c3t @@ -0,0 +1,72 @@ +// #target: macos-x64 +module test; + +fn void test() +{ + int[3] x; + int g = 0; + foreach_r (z : x) + { + if (z > 0) break; + if (z == 1) continue; + g += z; + } +} + +/* #expect: test.ll + +; Function Attrs: nounwind +define void @test_test() #0 { +entry: + %x = alloca [3 x i32], align 4 + %g = alloca i32, align 4 + %.anon = alloca i64, align 8 + %z = alloca i32, align 4 + %0 = getelementptr inbounds [3 x i32], [3 x i32]* %x, i64 0, i64 0 + store i32 0, i32* %0, align 4 + %1 = getelementptr inbounds [3 x i32], [3 x i32]* %x, i64 0, i64 1 + store i32 0, i32* %1, align 4 + %2 = getelementptr inbounds [3 x i32], [3 x i32]* %x, i64 0, i64 2 + store i32 0, i32* %2, align 4 + store i32 0, i32* %g, align 4 + store i64 3, i64* %.anon, align 8 + br label %loop.cond + +loop.cond: ; preds = %if.exit3, %if.then2, %entry + %3 = load i64, i64* %.anon, align 8 + %gt = icmp ugt i64 %3, 0 + br i1 %gt, label %loop.body, label %loop.exit + +loop.body: ; preds = %loop.cond + %4 = load i64, i64* %.anon, align 8 + %sub = sub i64 %4, 1 + store i64 %sub, i64* %.anon, align 8 + %5 = load i64, i64* %.anon, align 8 + %6 = getelementptr inbounds [3 x i32], [3 x i32]* %x, i64 0, i64 %5 + %7 = load i32, i32* %6, align 4 + store i32 %7, i32* %z, align 4 + %8 = load i32, i32* %z, align 4 + %gt1 = icmp sgt i32 %8, 0 + br i1 %gt1, label %if.then, label %if.exit + +if.then: ; preds = %loop.body + br label %loop.exit + +if.exit: ; preds = %loop.body + %9 = load i32, i32* %z, align 4 + %eq = icmp eq i32 %9, 1 + br i1 %eq, label %if.then2, label %if.exit3 + +if.then2: ; preds = %if.exit + br label %loop.cond + +if.exit3: ; preds = %if.exit + %10 = load i32, i32* %g, align 4 + %11 = load i32, i32* %z, align 4 + %add = add i32 %10, %11 + store i32 %add, i32* %g, align 4 + br label %loop.cond + +loop.exit: ; preds = %if.then, %loop.cond + ret void +} diff --git a/test/test_suite/statements/foreach_r_common.c3t b/test/test_suite/statements/foreach_r_common.c3t new file mode 100644 index 000000000..f9d63a373 --- /dev/null +++ b/test/test_suite/statements/foreach_r_common.c3t @@ -0,0 +1,353 @@ +// #target: macos-x64 +module test; + +extern fn void printf(char*, ...); + +fn void main() +{ + float[3] foo = { 2, 4.5, 8 }; + float[<3>] foo2 = { 2, 4.5, 8 }; + foreach_r (a : foo) + { + printf("Value: %f\n", a); + } + foreach_r (float* &a : foo) + { + *a *= 2; + printf("Value: %f\n", *a); + } + foreach_r (void* &a : foo) + { + printf("Value: %f\n", *((float*)(a))); + } + foreach_r (i, a : foo) + { + printf("Value[%d]: %f\n", i, a); + } + foreach_r (char i, double a : foo) + { + printf("Value2[%d]: %f\n", i, a); + } + foreach_r (double a : foo) + { + printf("Value3: %f\n", a); + } + + foreach_r (a : foo2) + { + printf("Value: %f\n", a); + } + foreach_r (i, a : foo2) + { + printf("Value[%d]: %f\n", i, a); + } + foreach_r (char i, double a : foo2) + { + printf("Value2[%d]: %f\n", i, a); + } + foreach_r (double a : foo2) + { + printf("Value3: %f\n", a); + } +} + +/* #expect: test.ll + +@.__const = private unnamed_addr constant [3 x float] [float 2.000000e+00, float 4.500000e+00, float 8.000000e+00], align 4 +@.str = private unnamed_addr constant [11 x i8] c"Value: %f\0A\00", align 1 +@.str.1 = private unnamed_addr constant [11 x i8] c"Value: %f\0A\00", align 1 +@.str.2 = private unnamed_addr constant [11 x i8] c"Value: %f\0A\00", align 1 +@.str.3 = private unnamed_addr constant [15 x i8] c"Value[%d]: %f\0A\00", align 1 +@.str.4 = private unnamed_addr constant [16 x i8] c"Value2[%d]: %f\0A\00", align 1 +@.str.5 = private unnamed_addr constant [12 x i8] c"Value3: %f\0A\00", align 1 +@.str.6 = private unnamed_addr constant [11 x i8] c"Value: %f\0A\00", align 1 +@.str.7 = private unnamed_addr constant [15 x i8] c"Value[%d]: %f\0A\00", align 1 +@.str.8 = private unnamed_addr constant [16 x i8] c"Value2[%d]: %f\0A\00", align 1 +@.str.9 = private unnamed_addr constant [12 x i8] c"Value3: %f\0A\00", align 1 + +; Function Attrs: nounwind +declare void @printf(i8*, ...) #0 + +; Function Attrs: nounwind +define void @test_main() #0 { +entry: + %foo = alloca [3 x float], align 4 + %foo2 = alloca <3 x float>, align 16 + %.anon = alloca i64, align 8 + %a = alloca float, align 4 + %.anon1 = alloca i64, align 8 + %a6 = alloca float*, align 8 + %.anon9 = alloca i64, align 8 + %a14 = alloca i8*, align 8 + %.anon18 = alloca i64, align 8 + %i = alloca i64, align 8 + %a23 = alloca float, align 4 + %.anon26 = alloca i64, align 8 + %i31 = alloca i8, align 1 + %a32 = alloca double, align 8 + %.anon35 = alloca i64, align 8 + %a40 = alloca double, align 8 + %.anon43 = alloca i64, align 8 + %a48 = alloca float, align 4 + %.anon51 = alloca i64, align 8 + %i56 = alloca i64, align 8 + %a57 = alloca float, align 4 + %.anon60 = alloca i64, align 8 + %i65 = alloca i8, align 1 + %a67 = alloca double, align 8 + %.anon71 = alloca i64, align 8 + %a76 = alloca double, align 8 + %0 = bitcast [3 x float]* %foo to i8* + call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 4 %0, i8* align 4 bitcast ([3 x float]* @.__const to i8*), i32 12, i1 false) + store <3 x float> , <3 x float>* %foo2, align 16 + store i64 3, i64* %.anon, align 8 + br label %loop.cond + +loop.cond: ; preds = %loop.body, %entry + %1 = load i64, i64* %.anon, align 8 + %gt = icmp ugt i64 %1, 0 + br i1 %gt, label %loop.body, label %loop.exit + +loop.body: ; preds = %loop.cond + %2 = load i64, i64* %.anon, align 8 + %sub = sub i64 %2, 1 + store i64 %sub, i64* %.anon, align 8 + %3 = load i64, i64* %.anon, align 8 + %4 = getelementptr inbounds [3 x float], [3 x float]* %foo, i64 0, i64 %3 + %5 = load float, float* %4, align 4 + store float %5, float* %a, align 4 + %6 = load float, float* %a, align 4 + %fpfpext = fpext float %6 to double + call void (i8*, ...) @printf(i8* getelementptr inbounds ([11 x i8], [11 x i8]* @.str, i32 0, i32 0), double %fpfpext) + br label %loop.cond + +loop.exit: ; preds = %loop.cond + store i64 3, i64* %.anon1, align 8 + br label %loop.cond2 + +loop.cond2: ; preds = %loop.body4, %loop.exit + %7 = load i64, i64* %.anon1, align 8 + %gt3 = icmp ugt i64 %7, 0 + br i1 %gt3, label %loop.body4, label %loop.exit8 + +loop.body4: ; preds = %loop.cond2 + %8 = load i64, i64* %.anon1, align 8 + %sub5 = sub i64 %8, 1 + store i64 %sub5, i64* %.anon1, align 8 + %9 = load i64, i64* %.anon1, align 8 + %10 = getelementptr inbounds [3 x float], [3 x float]* %foo, i64 0, i64 %9 + store float* %10, float** %a6, align 8 + %11 = load float*, float** %a6, align 8 + %12 = load float, float* %11, align 8 + %fmul = fmul float %12, 2.000000e+00 + store float %fmul, float* %11, align 8 + %13 = load float*, float** %a6, align 8 + %14 = load float, float* %13, align 8 + %fpfpext7 = fpext float %14 to double + call void (i8*, ...) @printf(i8* getelementptr inbounds ([11 x i8], [11 x i8]* @.str.1, i32 0, i32 0), double %fpfpext7) + br label %loop.cond2 + +loop.exit8: ; preds = %loop.cond2 + store i64 3, i64* %.anon9, align 8 + br label %loop.cond10 + +loop.cond10: ; preds = %loop.body12, %loop.exit8 + %15 = load i64, i64* %.anon9, align 8 + %gt11 = icmp ugt i64 %15, 0 + br i1 %gt11, label %loop.body12, label %loop.exit17 + +loop.body12: ; preds = %loop.cond10 + %16 = load i64, i64* %.anon9, align 8 + %sub13 = sub i64 %16, 1 + store i64 %sub13, i64* %.anon9, align 8 + %17 = load i64, i64* %.anon9, align 8 + %18 = getelementptr inbounds [3 x float], [3 x float]* %foo, i64 0, i64 %17 + %ptrptr = bitcast float* %18 to i8* + store i8* %ptrptr, i8** %a14, align 8 + %19 = load i8*, i8** %a14, align 8 + %ptrptr15 = bitcast i8* %19 to float* + %20 = load float, float* %ptrptr15, align 8 + %fpfpext16 = fpext float %20 to double + call void (i8*, ...) @printf(i8* getelementptr inbounds ([11 x i8], [11 x i8]* @.str.2, i32 0, i32 0), double %fpfpext16) + br label %loop.cond10 + +loop.exit17: ; preds = %loop.cond10 + store i64 3, i64* %.anon18, align 8 + br label %loop.cond19 + +loop.cond19: ; preds = %loop.body21, %loop.exit17 + %21 = load i64, i64* %.anon18, align 8 + %gt20 = icmp ugt i64 %21, 0 + br i1 %gt20, label %loop.body21, label %loop.exit25 + +loop.body21: ; preds = %loop.cond19 + %22 = load i64, i64* %.anon18, align 8 + %sub22 = sub i64 %22, 1 + store i64 %sub22, i64* %.anon18, align 8 + %23 = load i64, i64* %.anon18, align 8 + store i64 %23, i64* %i, align 8 + %24 = load i64, i64* %.anon18, align 8 + %25 = getelementptr inbounds [3 x float], [3 x float]* %foo, i64 0, i64 %24 + %26 = load float, float* %25, align 4 + store float %26, float* %a23, align 4 + %27 = load i64, i64* %i, align 8 + %28 = load float, float* %a23, align 4 + %fpfpext24 = fpext float %28 to double + call void (i8*, ...) @printf(i8* getelementptr inbounds ([15 x i8], [15 x i8]* @.str.3, i32 0, i32 0), i64 %27, double %fpfpext24) + br label %loop.cond19 + +loop.exit25: ; preds = %loop.cond19 + store i64 3, i64* %.anon26, align 8 + br label %loop.cond27 + +loop.cond27: ; preds = %loop.body29, %loop.exit25 + %29 = load i64, i64* %.anon26, align 8 + %gt28 = icmp ugt i64 %29, 0 + br i1 %gt28, label %loop.body29, label %loop.exit34 + +loop.body29: ; preds = %loop.cond27 + %30 = load i64, i64* %.anon26, align 8 + %sub30 = sub i64 %30, 1 + store i64 %sub30, i64* %.anon26, align 8 + %31 = load i64, i64* %.anon26, align 8 + %ztrunc = trunc i64 %31 to i8 + store i8 %ztrunc, i8* %i31, align 1 + %32 = load i64, i64* %.anon26, align 8 + %33 = getelementptr inbounds [3 x float], [3 x float]* %foo, i64 0, i64 %32 + %34 = load float, float* %33, align 4 + %fpfpext33 = fpext float %34 to double + store double %fpfpext33, double* %a32, align 8 + %35 = load i8, i8* %i31, align 1 + %uisiext = zext i8 %35 to i32 + %36 = load double, double* %a32, align 8 + call void (i8*, ...) @printf(i8* getelementptr inbounds ([16 x i8], [16 x i8]* @.str.4, i32 0, i32 0), i32 %uisiext, double %36) + br label %loop.cond27 + +loop.exit34: ; preds = %loop.cond27 + store i64 3, i64* %.anon35, align 8 + br label %loop.cond36 + +loop.cond36: ; preds = %loop.body38, %loop.exit34 + %37 = load i64, i64* %.anon35, align 8 + %gt37 = icmp ugt i64 %37, 0 + br i1 %gt37, label %loop.body38, label %loop.exit42 + +loop.body38: ; preds = %loop.cond36 + %38 = load i64, i64* %.anon35, align 8 + %sub39 = sub i64 %38, 1 + store i64 %sub39, i64* %.anon35, align 8 + %39 = load i64, i64* %.anon35, align 8 + %40 = getelementptr inbounds [3 x float], [3 x float]* %foo, i64 0, i64 %39 + %41 = load float, float* %40, align 4 + %fpfpext41 = fpext float %41 to double + store double %fpfpext41, double* %a40, align 8 + %42 = load double, double* %a40, align 8 + call void (i8*, ...) @printf(i8* getelementptr inbounds ([12 x i8], [12 x i8]* @.str.5, i32 0, i32 0), double %42) + br label %loop.cond36 + +loop.exit42: ; preds = %loop.cond36 + store i64 3, i64* %.anon43, align 8 + br label %loop.cond44 + +loop.cond44: ; preds = %loop.body46, %loop.exit42 + %43 = load i64, i64* %.anon43, align 8 + %gt45 = icmp ugt i64 %43, 0 + br i1 %gt45, label %loop.body46, label %loop.exit50 + +loop.body46: ; preds = %loop.cond44 + %44 = load i64, i64* %.anon43, align 8 + %sub47 = sub i64 %44, 1 + store i64 %sub47, i64* %.anon43, align 8 + %45 = load <3 x float>, <3 x float>* %foo2, align 16 + %46 = load i64, i64* %.anon43, align 8 + %47 = extractelement <3 x float> %45, i64 %46 + store float %47, float* %a48, align 4 + %48 = load float, float* %a48, align 4 + %fpfpext49 = fpext float %48 to double + call void (i8*, ...) @printf(i8* getelementptr inbounds ([11 x i8], [11 x i8]* @.str.6, i32 0, i32 0), double %fpfpext49) + br label %loop.cond44 + +loop.exit50: ; preds = %loop.cond44 + store i64 3, i64* %.anon51, align 8 + br label %loop.cond52 + +loop.cond52: ; preds = %loop.body54, %loop.exit50 + %49 = load i64, i64* %.anon51, align 8 + %gt53 = icmp ugt i64 %49, 0 + br i1 %gt53, label %loop.body54, label %loop.exit59 + +loop.body54: ; preds = %loop.cond52 + %50 = load i64, i64* %.anon51, align 8 + %sub55 = sub i64 %50, 1 + store i64 %sub55, i64* %.anon51, align 8 + %51 = load i64, i64* %.anon51, align 8 + store i64 %51, i64* %i56, align 8 + %52 = load <3 x float>, <3 x float>* %foo2, align 16 + %53 = load i64, i64* %.anon51, align 8 + %54 = extractelement <3 x float> %52, i64 %53 + store float %54, float* %a57, align 4 + %55 = load i64, i64* %i56, align 8 + %56 = load float, float* %a57, align 4 + %fpfpext58 = fpext float %56 to double + call void (i8*, ...) @printf(i8* getelementptr inbounds ([15 x i8], [15 x i8]* @.str.7, i32 0, i32 0), i64 %55, double %fpfpext58) + br label %loop.cond52 + +loop.exit59: ; preds = %loop.cond52 + store i64 3, i64* %.anon60, align 8 + br label %loop.cond61 + +loop.cond61: ; preds = %loop.body63, %loop.exit59 + %57 = load i64, i64* %.anon60, align 8 + %gt62 = icmp ugt i64 %57, 0 + br i1 %gt62, label %loop.body63, label %loop.exit70 + +loop.body63: ; preds = %loop.cond61 + %58 = load i64, i64* %.anon60, align 8 + %sub64 = sub i64 %58, 1 + store i64 %sub64, i64* %.anon60, align 8 + %59 = load i64, i64* %.anon60, align 8 + %ztrunc66 = trunc i64 %59 to i8 + store i8 %ztrunc66, i8* %i65, align 1 + %60 = load <3 x float>, <3 x float>* %foo2, align 16 + %61 = load i64, i64* %.anon60, align 8 + %62 = extractelement <3 x float> %60, i64 %61 + %fpfpext68 = fpext float %62 to double + store double %fpfpext68, double* %a67, align 8 + %63 = load i8, i8* %i65, align 1 + %uisiext69 = zext i8 %63 to i32 + %64 = load double, double* %a67, align 8 + call void (i8*, ...) @printf(i8* getelementptr inbounds ([16 x i8], [16 x i8]* @.str.8, i32 0, i32 0), i32 %uisiext69, double %64) + br label %loop.cond61 + +loop.exit70: ; preds = %loop.cond61 + store i64 3, i64* %.anon71, align 8 + br label %loop.cond72 + +loop.cond72: ; preds = %loop.body74, %loop.exit70 + %65 = load i64, i64* %.anon71, align 8 + %gt73 = icmp ugt i64 %65, 0 + br i1 %gt73, label %loop.body74, label %loop.exit78 + +loop.body74: ; preds = %loop.cond72 + %66 = load i64, i64* %.anon71, align 8 + %sub75 = sub i64 %66, 1 + store i64 %sub75, i64* %.anon71, align 8 + %67 = load <3 x float>, <3 x float>* %foo2, align 16 + %68 = load i64, i64* %.anon71, align 8 + %69 = extractelement <3 x float> %67, i64 %68 + %fpfpext77 = fpext float %69 to double + store double %fpfpext77, double* %a76, align 8 + %70 = load double, double* %a76, align 8 + call void (i8*, ...) @printf(i8* getelementptr inbounds ([12 x i8], [12 x i8]* @.str.9, i32 0, i32 0), double %70) + br label %loop.cond72 + +loop.exit78: ; preds = %loop.cond72 + ret void +} + +; Function Attrs: nounwind +define i32 @main(i32 %0, i8** %1) #0 { +entry: + call void @test_main() + ret i32 0 +} diff --git a/test/test_suite/statements/foreach_r_custom.c3t b/test/test_suite/statements/foreach_r_custom.c3t new file mode 100644 index 000000000..1ebc5acd4 --- /dev/null +++ b/test/test_suite/statements/foreach_r_custom.c3t @@ -0,0 +1,94 @@ +// #target: macos-x64 + +module test; +struct Foo +{ + int[] x; +} + +macro int Foo.@operator_element_at(Foo &foo, usize index) @operator(elementat) +{ + return foo.x[index]; +} + +macro usize Foo.@operator_len(Foo &foo) @operator(len) +{ + return foo.x.len; +} + +fn void main() +{ + int[*] i = { 1, 3, 10 }; + Foo x = { &i }; + foreach_r FOO: (int f : x) { + printf("%d\n", f); + while (1) + { + break FOO; + } + } +} + +extern fn int printf(char *fmt, ...); + +/* #expect: test.ll + +; Function Attrs: nounwind +define void @test_main() #0 { +entry: + %i = alloca [3 x i32], align 4 + %x = alloca %Foo, align 8 + %.anon = alloca i64, align 8 + %f = alloca i32, align 4 + %index = alloca i64, align 8 + %0 = bitcast [3 x i32]* %i to i8* + call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 4 %0, i8* align 4 bitcast ([3 x i32]* @.__const to i8*), i32 12, i1 false) + %1 = getelementptr inbounds %Foo, %Foo* %x, i32 0, i32 0 + %2 = bitcast [3 x i32]* %i to i32* + %3 = insertvalue %"int[]" undef, i32* %2, 0 + %4 = insertvalue %"int[]" %3, i64 3, 1 + store %"int[]" %4, %"int[]"* %1, align 8 + %5 = getelementptr inbounds %Foo, %Foo* %x, i32 0, i32 0 + %6 = getelementptr inbounds %"int[]", %"int[]"* %5, i32 0, i32 1 + %7 = load i64, i64* %6, align 8 + store i64 %7, i64* %.anon, align 8 + br label %loop.cond + +loop.cond: ; preds = %entry + %8 = load i64, i64* %.anon, align 8 + %gt = icmp ugt i64 %8, 0 + br i1 %gt, label %loop.body, label %loop.exit + +loop.body: ; preds = %loop.cond + %9 = load i64, i64* %.anon, align 8 + %sub = sub i64 %9, 1 + store i64 %sub, i64* %.anon, align 8 + %10 = load i64, i64* %.anon, align 8 + store i64 %10, i64* %index, align 8 + %11 = getelementptr inbounds %Foo, %Foo* %x, i32 0, i32 0 + %12 = getelementptr inbounds %"int[]", %"int[]"* %11, i32 0, i32 0 + %13 = load i32*, i32** %12, align 8 + %14 = load i64, i64* %index, align 8 + %ptroffset = getelementptr inbounds i32, i32* %13, i64 %14 + %15 = load i32, i32* %ptroffset, align 4 + store i32 %15, i32* %f, align 4 + %16 = load i32, i32* %f, align 4 + %17 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i32 0, i32 0), i32 %16) + br label %loop.body1 + +loop.body1: ; preds = %loop.body + br label %loop.exit + +loop.exit: ; preds = %loop.body1, %loop.cond + ret void +} + +; Function Attrs: nounwind +declare i32 @printf(i8*, ...) #0 + +; Function Attrs: nounwind +define i32 @main(i32 %0, i8** %1) #0 { +entry: + call void @test_main() + ret i32 0 +} diff --git a/test/test_suite/statements/foreach_r_custom_errors.c3 b/test/test_suite/statements/foreach_r_custom_errors.c3 new file mode 100644 index 000000000..81d59d474 --- /dev/null +++ b/test/test_suite/statements/foreach_r_custom_errors.c3 @@ -0,0 +1,15 @@ +fn void test1() +{ + int x; + foreach_r (a : x) { }; // #error: It's not possible to enumerate an expression of type 'int' +} + +define Test1 = distinct int; + +fn void test2() +{ + Test1 x; + foreach_r (a : x) { }; // #error: It's not possible to enumerate an expression of type 'Test1' +} + + diff --git a/test/test_suite/statements/foreach_r_custom_macro.c3t b/test/test_suite/statements/foreach_r_custom_macro.c3t new file mode 100644 index 000000000..1dcfdb242 --- /dev/null +++ b/test/test_suite/statements/foreach_r_custom_macro.c3t @@ -0,0 +1,93 @@ +// #target: macos-x64 +module test; +struct Foo +{ + int[] x; +} + +macro int Foo.@operator_element_at(Foo &foo, usize index) @operator(elementat) +{ + return foo.x[index]; +} + +macro usize Foo.@operator_len(Foo &foo) @operator(len) +{ + return foo.x.len; +} + +fn void main() +{ + int[*] i = { 1, 3, 10 }; + Foo x = { &i }; + foreach_r FOO: (int f : x) { + printf("%d\n", f); + while (1) + { + break FOO; + } + } +} + +extern fn int printf(char *fmt, ...); + +/* #expect: test.ll + +; Function Attrs: nounwind +define void @test_main() #0 { +entry: + %i = alloca [3 x i32], align 4 + %x = alloca %Foo, align 8 + %.anon = alloca i64, align 8 + %f = alloca i32, align 4 + %index = alloca i64, align 8 + %0 = bitcast [3 x i32]* %i to i8* + call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 4 %0, i8* align 4 bitcast ([3 x i32]* @.__const to i8*), i32 12, i1 false) + %1 = getelementptr inbounds %Foo, %Foo* %x, i32 0, i32 0 + %2 = bitcast [3 x i32]* %i to i32* + %3 = insertvalue %"int[]" undef, i32* %2, 0 + %4 = insertvalue %"int[]" %3, i64 3, 1 + store %"int[]" %4, %"int[]"* %1, align 8 + %5 = getelementptr inbounds %Foo, %Foo* %x, i32 0, i32 0 + %6 = getelementptr inbounds %"int[]", %"int[]"* %5, i32 0, i32 1 + %7 = load i64, i64* %6, align 8 + store i64 %7, i64* %.anon, align 8 + br label %loop.cond + +loop.cond: ; preds = %entry + %8 = load i64, i64* %.anon, align 8 + %gt = icmp ugt i64 %8, 0 + br i1 %gt, label %loop.body, label %loop.exit + +loop.body: ; preds = %loop.cond + %9 = load i64, i64* %.anon, align 8 + %sub = sub i64 %9, 1 + store i64 %sub, i64* %.anon, align 8 + %10 = load i64, i64* %.anon, align 8 + store i64 %10, i64* %index, align 8 + %11 = getelementptr inbounds %Foo, %Foo* %x, i32 0, i32 0 + %12 = getelementptr inbounds %"int[]", %"int[]"* %11, i32 0, i32 0 + %13 = load i32*, i32** %12, align 8 + %14 = load i64, i64* %index, align 8 + %ptroffset = getelementptr inbounds i32, i32* %13, i64 %14 + %15 = load i32, i32* %ptroffset, align 4 + store i32 %15, i32* %f, align 4 + %16 = load i32, i32* %f, align 4 + %17 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i32 0, i32 0), i32 %16) + br label %loop.body1 + +loop.body1: ; preds = %loop.body + br label %loop.exit + +loop.exit: ; preds = %loop.body1, %loop.cond + ret void +} + +; Function Attrs: nounwind +declare i32 @printf(i8*, ...) #0 + +; Function Attrs: nounwind +define i32 @main(i32 %0, i8** %1) #0 { +entry: + call void @test_main() + ret i32 0 +} diff --git a/test/test_suite/statements/foreach_r_errors.c3 b/test/test_suite/statements/foreach_r_errors.c3 new file mode 100644 index 000000000..47047b375 --- /dev/null +++ b/test/test_suite/statements/foreach_r_errors.c3 @@ -0,0 +1,54 @@ +module test; + +extern fn void foo(); +int[3] z; + +fn void test1() +{ + int x; + foreach_r (a : x) // #error: It's not possible to enumerate an expression of type 'int'. + { + foo(); + } +} + +fn void test2() +{ + foreach_r (a : z) foo(); + foreach_r (i, a : z) foo(); + foreach_r (double i, a : z); // #error: Index must be an integer type, 'double' is not valid. +} + +fn void test3() +{ + foreach_r (&a : z) foo(); + foreach_r (&i, &a : z) foo(); // #error: The index cannot be held by reference, did you accidentally add a '&'? +} + +fn void test4() +{ + foreach_r (&a : z) foo(); + foreach_r (&i, a : z) foo(); // #error: The index cannot be held by reference, did you accidentally add a '&'? +} + +fn void test5() +{ + foreach_r (int! y : z) foo(); // #error: The variable may not be a failable. +} + +fn void test6() +{ + foreach_r (int! i, y : z) foo(); // #error: The index may not be a failable. +} + +fn void test7() +{ + foreach_r (int a : { 1, 2, 3 }) foo(); + foreach_r (a : { 1, 2, 3 }) foo(); // #error: Add the type of your variable here if you want to iterate over +} + +fn void test8() +{ + foreach_r (int a : { z }) foo(); // #error: 'int[3]' into 'int' +} + diff --git a/test/test_suite/statements/foreach_r_parse_error.c3 b/test/test_suite/statements/foreach_r_parse_error.c3 new file mode 100644 index 000000000..a7a00b965 --- /dev/null +++ b/test/test_suite/statements/foreach_r_parse_error.c3 @@ -0,0 +1,5 @@ +fn void test9() +{ + foreach_r (int a : { [2] = 1 }) foo(); + foreach_r (int a : { [2] = 2, 1 }) foo(); // #error: Normal initialization cannot be mixed with designated initialization. +} \ No newline at end of file diff --git a/test/test_suite/statements/foreach_r_test.c3t b/test/test_suite/statements/foreach_r_test.c3t deleted file mode 100644 index 75d2db673..000000000 --- a/test/test_suite/statements/foreach_r_test.c3t +++ /dev/null @@ -1,94 +0,0 @@ -// #target: macos-x64 -module test; -import std::io; - -fn void main() -{ - int[*] x = { 1, 5, 10 }; - int[] y = &x; - foreach_r (int i, val : y) - { - io::printfln("%d: %d", i, val); - } -} - -/* #expect: test.ll - -entry: - %x = alloca [3 x i32], align 4 - %y = alloca %"int[]", align 8 - %.anon = alloca i64, align 8 - %i = alloca i32, align 4 - %val = alloca i32, align 4 - %retparam = alloca i64, align 8 - %taddr = alloca %"char[]", align 8 - %vararg = alloca %"variant[]", align 8 - %varargslots = alloca [2 x %variant], align 16 - %0 = bitcast [3 x i32]* %x to i8* - call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 4 %0, i8* align 4 bitcast ([3 x i32]* @.__const to i8*), i32 12, i1 false) - %1 = bitcast [3 x i32]* %x to i32* - %2 = insertvalue %"int[]" undef, i32* %1, 0 - %3 = insertvalue %"int[]" %2, i64 3, 1 - store %"int[]" %3, %"int[]"* %y, align 8 - %4 = getelementptr inbounds %"int[]", %"int[]"* %y, i32 0, i32 1 - %5 = load i64, i64* %4, align 8 - store i64 %5, i64* %.anon, align 8 - br label %loop.cond - -loop.cond: ; preds = %voiderr, %entry - %6 = load i64, i64* %.anon, align 8 - %gt = icmp ugt i64 %6, 0 - br i1 %gt, label %loop.body, label %loop.exit - -loop.body: ; preds = %loop.cond - %7 = load i64, i64* %.anon, align 8 - %sub = sub i64 %7, 1 - store i64 %sub, i64* %.anon, align 8 - %8 = load i64, i64* %.anon, align 8 - %uisitrunc = trunc i64 %8 to i32 - store i32 %uisitrunc, i32* %i, align 4 - %9 = getelementptr inbounds %"int[]", %"int[]"* %y, i32 0, i32 0 - %10 = load i32*, i32** %9, align 8 - %11 = load i64, i64* %.anon, align 8 - %ptroffset = getelementptr inbounds i32, i32* %10, i64 %11 - %12 = load i32, i32* %ptroffset, align 4 - store i32 %12, i32* %val, align 4 - store %"char[]" { i8* getelementptr inbounds ([7 x i8], [7 x i8]* @.str, i32 0, i32 0), i64 6 }, %"char[]"* %taddr, align 8 - %13 = bitcast %"char[]"* %taddr to { i8*, i64 }* - %14 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %13, i32 0, i32 0 - %lo = load i8*, i8** %14, align 8 - %15 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %13, i32 0, i32 1 - %hi = load i64, i64* %15, align 8 - %16 = bitcast i32* %i to i8* - %17 = insertvalue %variant undef, i8* %16, 0 - %18 = insertvalue %variant %17, i64 ptrtoint (%.introspect* @"ct$int" to i64), 1 - %19 = getelementptr inbounds [2 x %variant], [2 x %variant]* %varargslots, i64 0, i64 0 - store %variant %18, %variant* %19, align 16 - %20 = bitcast i32* %val to i8* - %21 = insertvalue %variant undef, i8* %20, 0 - %22 = insertvalue %variant %21, i64 ptrtoint (%.introspect* @"ct$int" to i64), 1 - %23 = getelementptr inbounds [2 x %variant], [2 x %variant]* %varargslots, i64 0, i64 1 - store %variant %22, %variant* %23, align 16 - %24 = getelementptr inbounds %"variant[]", %"variant[]"* %vararg, i32 0, i32 1 - store i64 2, i64* %24, align 8 - %25 = getelementptr inbounds %"variant[]", %"variant[]"* %vararg, i32 0, i32 0 - %26 = bitcast [2 x %variant]* %varargslots to %variant* - store %variant* %26, %variant** %25, align 8 - %27 = bitcast %"variant[]"* %vararg to { i8*, i64 }* - %28 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %27, i32 0, i32 0 - %lo1 = load i8*, i8** %28, align 8 - %29 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %27, i32 0, i32 1 - %hi2 = load i64, i64* %29, align 8 - %30 = call i64 @std_io_printfln(i64* %retparam, i8* %lo, i64 %hi, i8* %lo1, i64 %hi2) - %not_err = icmp eq i64 %30, 0 - br i1 %not_err, label %after_check, label %voiderr - -after_check: ; preds = %loop.body - br label %voiderr - -voiderr: ; preds = %after_check, %loop.body - br label %loop.cond - -loop.exit: ; preds = %loop.cond - ret void -} diff --git a/test/test_suite/statements/foreach_r_with_error.c3 b/test/test_suite/statements/foreach_r_with_error.c3 new file mode 100644 index 000000000..d58d4b5a5 --- /dev/null +++ b/test/test_suite/statements/foreach_r_with_error.c3 @@ -0,0 +1,12 @@ +module test; + +fn void test() +{ + int[3]! x; + int g; + foreach_r (z : x) // #error: The expression may not be failable. + { + g += z; + x[0] = 1; + } +} diff --git a/test/test_suite2/statements/foreach_custom.c3t b/test/test_suite2/statements/foreach_custom.c3t index aa3997c4a..50f55b4f8 100644 --- a/test/test_suite2/statements/foreach_custom.c3t +++ b/test/test_suite2/statements/foreach_custom.c3t @@ -1,6 +1,6 @@ // #target: macos-x64 -module foo; +module test; struct Foo { int[] x; @@ -31,10 +31,10 @@ fn void main() extern fn int printf(char *fmt, ...); -/* #expect: foo.ll +/* #expect: test.ll ; Function Attrs: nounwind -define void @foo_main() #0 { +define void @test_main() #0 { entry: %i = alloca [3 x i32], align 4 %x = alloca %Foo, align 8 @@ -79,4 +79,14 @@ loop.body2: ; preds = %loop.body loop.exit: ; preds = %loop.body2, %loop.cond ret void -} \ No newline at end of file +} + +; Function Attrs: nounwind +declare i32 @printf(ptr, ...) #0 + +; Function Attrs: nounwind +define i32 @main(i32 %0, ptr %1) #0 { +entry: + call void @test_main() + ret i32 0 +} diff --git a/test/test_suite2/statements/foreach_r_break.c3t b/test/test_suite2/statements/foreach_r_break.c3t new file mode 100644 index 000000000..a626decf6 --- /dev/null +++ b/test/test_suite2/statements/foreach_r_break.c3t @@ -0,0 +1,72 @@ +// #target: macos-x64 +module test; + +fn void test() +{ + int[3] x; + int g = 0; + foreach_r (z : x) + { + if (z > 0) break; + if (z == 1) continue; + g += z; + } +} + +/* #expect: test.ll + +; Function Attrs: nounwind +define void @test_test() #0 { +entry: + %x = alloca [3 x i32], align 4 + %g = alloca i32, align 4 + %.anon = alloca i64, align 8 + %z = alloca i32, align 4 + %0 = getelementptr inbounds [3 x i32], ptr %x, i64 0, i64 0 + store i32 0, ptr %0, align 4 + %1 = getelementptr inbounds [3 x i32], ptr %x, i64 0, i64 1 + store i32 0, ptr %1, align 4 + %2 = getelementptr inbounds [3 x i32], ptr %x, i64 0, i64 2 + store i32 0, ptr %2, align 4 + store i32 0, ptr %g, align 4 + store i64 3, ptr %.anon, align 8 + br label %loop.cond + +loop.cond: ; preds = %if.exit3, %if.then2, %entry + %3 = load i64, ptr %.anon, align 8 + %gt = icmp ugt i64 %3, 0 + br i1 %gt, label %loop.body, label %loop.exit + +loop.body: ; preds = %loop.cond + %4 = load i64, ptr %.anon, align 8 + %sub = sub i64 %4, 1 + store i64 %sub, ptr %.anon, align 8 + %5 = load i64, ptr %.anon, align 8 + %6 = getelementptr inbounds [3 x i32], ptr %x, i64 0, i64 %5 + %7 = load i32, ptr %6, align 4 + store i32 %7, ptr %z, align 4 + %8 = load i32, ptr %z, align 4 + %gt1 = icmp sgt i32 %8, 0 + br i1 %gt1, label %if.then, label %if.exit + +if.then: ; preds = %loop.body + br label %loop.exit + +if.exit: ; preds = %loop.body + %9 = load i32, ptr %z, align 4 + %eq = icmp eq i32 %9, 1 + br i1 %eq, label %if.then2, label %if.exit3 + +if.then2: ; preds = %if.exit + br label %loop.cond + +if.exit3: ; preds = %if.exit + %10 = load i32, ptr %g, align 4 + %11 = load i32, ptr %z, align 4 + %add = add i32 %10, %11 + store i32 %add, ptr %g, align 4 + br label %loop.cond + +loop.exit: ; preds = %if.then, %loop.cond + ret void +} diff --git a/test/test_suite2/statements/foreach_r_common.c3t b/test/test_suite2/statements/foreach_r_common.c3t new file mode 100644 index 000000000..1ee5e08e3 --- /dev/null +++ b/test/test_suite2/statements/foreach_r_common.c3t @@ -0,0 +1,350 @@ +// #target: macos-x64 +module test; + +extern fn void printf(char*, ...); + +fn void main() +{ + float[3] foo = { 2, 4.5, 8 }; + float[<3>] foo2 = { 2, 4.5, 8 }; + foreach_r (a : foo) + { + printf("Value: %f\n", a); + } + foreach_r (float* &a : foo) + { + *a *= 2; + printf("Value: %f\n", *a); + } + foreach_r (void* &a : foo) + { + printf("Value: %f\n", *((float*)(a))); + } + foreach_r (i, a : foo) + { + printf("Value[%d]: %f\n", i, a); + } + foreach_r (char i, double a : foo) + { + printf("Value2[%d]: %f\n", i, a); + } + foreach_r (double a : foo) + { + printf("Value3: %f\n", a); + } + + foreach_r (a : foo2) + { + printf("Value: %f\n", a); + } + foreach_r (i, a : foo2) + { + printf("Value[%d]: %f\n", i, a); + } + foreach_r (char i, double a : foo2) + { + printf("Value2[%d]: %f\n", i, a); + } + foreach_r (double a : foo2) + { + printf("Value3: %f\n", a); + } +} + +/* #expect: test.ll + +@.__const = private unnamed_addr constant [3 x float] [float 2.000000e+00, float 4.500000e+00, float 8.000000e+00], align 4 +@.str = private unnamed_addr constant [11 x i8] c"Value: %f\0A\00", align 1 +@.str.1 = private unnamed_addr constant [11 x i8] c"Value: %f\0A\00", align 1 +@.str.2 = private unnamed_addr constant [11 x i8] c"Value: %f\0A\00", align 1 +@.str.3 = private unnamed_addr constant [15 x i8] c"Value[%d]: %f\0A\00", align 1 +@.str.4 = private unnamed_addr constant [16 x i8] c"Value2[%d]: %f\0A\00", align 1 +@.str.5 = private unnamed_addr constant [12 x i8] c"Value3: %f\0A\00", align 1 +@.str.6 = private unnamed_addr constant [11 x i8] c"Value: %f\0A\00", align 1 +@.str.7 = private unnamed_addr constant [15 x i8] c"Value[%d]: %f\0A\00", align 1 +@.str.8 = private unnamed_addr constant [16 x i8] c"Value2[%d]: %f\0A\00", align 1 +@.str.9 = private unnamed_addr constant [12 x i8] c"Value3: %f\0A\00", align 1 + +; Function Attrs: nounwind +declare void @printf(ptr, ...) #0 + +; Function Attrs: nounwind +define void @test_main() #0 { +entry: + %foo = alloca [3 x float], align 4 + %foo2 = alloca <3 x float>, align 16 + %.anon = alloca i64, align 8 + %a = alloca float, align 4 + %.anon1 = alloca i64, align 8 + %a6 = alloca ptr, align 8 + %.anon9 = alloca i64, align 8 + %a14 = alloca ptr, align 8 + %.anon17 = alloca i64, align 8 + %i = alloca i64, align 8 + %a22 = alloca float, align 4 + %.anon25 = alloca i64, align 8 + %i30 = alloca i8, align 1 + %a31 = alloca double, align 8 + %.anon34 = alloca i64, align 8 + %a39 = alloca double, align 8 + %.anon42 = alloca i64, align 8 + %a47 = alloca float, align 4 + %.anon50 = alloca i64, align 8 + %i55 = alloca i64, align 8 + %a56 = alloca float, align 4 + %.anon59 = alloca i64, align 8 + %i64 = alloca i8, align 1 + %a66 = alloca double, align 8 + %.anon70 = alloca i64, align 8 + %a75 = alloca double, align 8 + call void @llvm.memcpy.p0.p0.i32(ptr align 4 %foo, ptr align 4 @.__const, i32 12, i1 false) + store <3 x float> , ptr %foo2, align 16 + store i64 3, ptr %.anon, align 8 + br label %loop.cond + +loop.cond: ; preds = %loop.body, %entry + %0 = load i64, ptr %.anon, align 8 + %gt = icmp ugt i64 %0, 0 + br i1 %gt, label %loop.body, label %loop.exit + +loop.body: ; preds = %loop.cond + %1 = load i64, ptr %.anon, align 8 + %sub = sub i64 %1, 1 + store i64 %sub, ptr %.anon, align 8 + %2 = load i64, ptr %.anon, align 8 + %3 = getelementptr inbounds [3 x float], ptr %foo, i64 0, i64 %2 + %4 = load float, ptr %3, align 4 + store float %4, ptr %a, align 4 + %5 = load float, ptr %a, align 4 + %fpfpext = fpext float %5 to double + call void (ptr, ...) @printf(ptr @.str, double %fpfpext) + br label %loop.cond + +loop.exit: ; preds = %loop.cond + store i64 3, ptr %.anon1, align 8 + br label %loop.cond2 + +loop.cond2: ; preds = %loop.body4, %loop.exit + %6 = load i64, ptr %.anon1, align 8 + %gt3 = icmp ugt i64 %6, 0 + br i1 %gt3, label %loop.body4, label %loop.exit8 + +loop.body4: ; preds = %loop.cond2 + %7 = load i64, ptr %.anon1, align 8 + %sub5 = sub i64 %7, 1 + store i64 %sub5, ptr %.anon1, align 8 + %8 = load i64, ptr %.anon1, align 8 + %9 = getelementptr inbounds [3 x float], ptr %foo, i64 0, i64 %8 + store ptr %9, ptr %a6, align 8 + %10 = load ptr, ptr %a6, align 8 + %11 = load float, ptr %10, align 8 + %fmul = fmul float %11, 2.000000e+00 + store float %fmul, ptr %10, align 8 + %12 = load ptr, ptr %a6, align 8 + %13 = load float, ptr %12, align 8 + %fpfpext7 = fpext float %13 to double + call void (ptr, ...) @printf(ptr @.str.1, double %fpfpext7) + br label %loop.cond2 + +loop.exit8: ; preds = %loop.cond2 + store i64 3, ptr %.anon9, align 8 + br label %loop.cond10 + +loop.cond10: ; preds = %loop.body12, %loop.exit8 + %14 = load i64, ptr %.anon9, align 8 + %gt11 = icmp ugt i64 %14, 0 + br i1 %gt11, label %loop.body12, label %loop.exit16 + +loop.body12: ; preds = %loop.cond10 + %15 = load i64, ptr %.anon9, align 8 + %sub13 = sub i64 %15, 1 + store i64 %sub13, ptr %.anon9, align 8 + %16 = load i64, ptr %.anon9, align 8 + %17 = getelementptr inbounds [3 x float], ptr %foo, i64 0, i64 %16 + store ptr %17, ptr %a14, align 8 + %18 = load ptr, ptr %a14, align 8 + %19 = load float, ptr %18, align 8 + %fpfpext15 = fpext float %19 to double + call void (ptr, ...) @printf(ptr @.str.2, double %fpfpext15) + br label %loop.cond10 + +loop.exit16: ; preds = %loop.cond10 + store i64 3, ptr %.anon17, align 8 + br label %loop.cond18 + +loop.cond18: ; preds = %loop.body20, %loop.exit16 + %20 = load i64, ptr %.anon17, align 8 + %gt19 = icmp ugt i64 %20, 0 + br i1 %gt19, label %loop.body20, label %loop.exit24 + +loop.body20: ; preds = %loop.cond18 + %21 = load i64, ptr %.anon17, align 8 + %sub21 = sub i64 %21, 1 + store i64 %sub21, ptr %.anon17, align 8 + %22 = load i64, ptr %.anon17, align 8 + store i64 %22, ptr %i, align 8 + %23 = load i64, ptr %.anon17, align 8 + %24 = getelementptr inbounds [3 x float], ptr %foo, i64 0, i64 %23 + %25 = load float, ptr %24, align 4 + store float %25, ptr %a22, align 4 + %26 = load i64, ptr %i, align 8 + %27 = load float, ptr %a22, align 4 + %fpfpext23 = fpext float %27 to double + call void (ptr, ...) @printf(ptr @.str.3, i64 %26, double %fpfpext23) + br label %loop.cond18 + +loop.exit24: ; preds = %loop.cond18 + store i64 3, ptr %.anon25, align 8 + br label %loop.cond26 + +loop.cond26: ; preds = %loop.body28, %loop.exit24 + %28 = load i64, ptr %.anon25, align 8 + %gt27 = icmp ugt i64 %28, 0 + br i1 %gt27, label %loop.body28, label %loop.exit33 + +loop.body28: ; preds = %loop.cond26 + %29 = load i64, ptr %.anon25, align 8 + %sub29 = sub i64 %29, 1 + store i64 %sub29, ptr %.anon25, align 8 + %30 = load i64, ptr %.anon25, align 8 + %ztrunc = trunc i64 %30 to i8 + store i8 %ztrunc, ptr %i30, align 1 + %31 = load i64, ptr %.anon25, align 8 + %32 = getelementptr inbounds [3 x float], ptr %foo, i64 0, i64 %31 + %33 = load float, ptr %32, align 4 + %fpfpext32 = fpext float %33 to double + store double %fpfpext32, ptr %a31, align 8 + %34 = load i8, ptr %i30, align 1 + %uisiext = zext i8 %34 to i32 + %35 = load double, ptr %a31, align 8 + call void (ptr, ...) @printf(ptr @.str.4, i32 %uisiext, double %35) + br label %loop.cond26 + +loop.exit33: ; preds = %loop.cond26 + store i64 3, ptr %.anon34, align 8 + br label %loop.cond35 + +loop.cond35: ; preds = %loop.body37, %loop.exit33 + %36 = load i64, ptr %.anon34, align 8 + %gt36 = icmp ugt i64 %36, 0 + br i1 %gt36, label %loop.body37, label %loop.exit41 + +loop.body37: ; preds = %loop.cond35 + %37 = load i64, ptr %.anon34, align 8 + %sub38 = sub i64 %37, 1 + store i64 %sub38, ptr %.anon34, align 8 + %38 = load i64, ptr %.anon34, align 8 + %39 = getelementptr inbounds [3 x float], ptr %foo, i64 0, i64 %38 + %40 = load float, ptr %39, align 4 + %fpfpext40 = fpext float %40 to double + store double %fpfpext40, ptr %a39, align 8 + %41 = load double, ptr %a39, align 8 + call void (ptr, ...) @printf(ptr @.str.5, double %41) + br label %loop.cond35 + +loop.exit41: ; preds = %loop.cond35 + store i64 3, ptr %.anon42, align 8 + br label %loop.cond43 + +loop.cond43: ; preds = %loop.body45, %loop.exit41 + %42 = load i64, ptr %.anon42, align 8 + %gt44 = icmp ugt i64 %42, 0 + br i1 %gt44, label %loop.body45, label %loop.exit49 + +loop.body45: ; preds = %loop.cond43 + %43 = load i64, ptr %.anon42, align 8 + %sub46 = sub i64 %43, 1 + store i64 %sub46, ptr %.anon42, align 8 + %44 = load <3 x float>, ptr %foo2, align 16 + %45 = load i64, ptr %.anon42, align 8 + %46 = extractelement <3 x float> %44, i64 %45 + store float %46, ptr %a47, align 4 + %47 = load float, ptr %a47, align 4 + %fpfpext48 = fpext float %47 to double + call void (ptr, ...) @printf(ptr @.str.6, double %fpfpext48) + br label %loop.cond43 + +loop.exit49: ; preds = %loop.cond43 + store i64 3, ptr %.anon50, align 8 + br label %loop.cond51 + +loop.cond51: ; preds = %loop.body53, %loop.exit49 + %48 = load i64, ptr %.anon50, align 8 + %gt52 = icmp ugt i64 %48, 0 + br i1 %gt52, label %loop.body53, label %loop.exit58 + +loop.body53: ; preds = %loop.cond51 + %49 = load i64, ptr %.anon50, align 8 + %sub54 = sub i64 %49, 1 + store i64 %sub54, ptr %.anon50, align 8 + %50 = load i64, ptr %.anon50, align 8 + store i64 %50, ptr %i55, align 8 + %51 = load <3 x float>, ptr %foo2, align 16 + %52 = load i64, ptr %.anon50, align 8 + %53 = extractelement <3 x float> %51, i64 %52 + store float %53, ptr %a56, align 4 + %54 = load i64, ptr %i55, align 8 + %55 = load float, ptr %a56, align 4 + %fpfpext57 = fpext float %55 to double + call void (ptr, ...) @printf(ptr @.str.7, i64 %54, double %fpfpext57) + br label %loop.cond51 + +loop.exit58: ; preds = %loop.cond51 + store i64 3, ptr %.anon59, align 8 + br label %loop.cond60 + +loop.cond60: ; preds = %loop.body62, %loop.exit58 + %56 = load i64, ptr %.anon59, align 8 + %gt61 = icmp ugt i64 %56, 0 + br i1 %gt61, label %loop.body62, label %loop.exit69 + +loop.body62: ; preds = %loop.cond60 + %57 = load i64, ptr %.anon59, align 8 + %sub63 = sub i64 %57, 1 + store i64 %sub63, ptr %.anon59, align 8 + %58 = load i64, ptr %.anon59, align 8 + %ztrunc65 = trunc i64 %58 to i8 + store i8 %ztrunc65, ptr %i64, align 1 + %59 = load <3 x float>, ptr %foo2, align 16 + %60 = load i64, ptr %.anon59, align 8 + %61 = extractelement <3 x float> %59, i64 %60 + %fpfpext67 = fpext float %61 to double + store double %fpfpext67, ptr %a66, align 8 + %62 = load i8, ptr %i64, align 1 + %uisiext68 = zext i8 %62 to i32 + %63 = load double, ptr %a66, align 8 + call void (ptr, ...) @printf(ptr @.str.8, i32 %uisiext68, double %63) + br label %loop.cond60 + +loop.exit69: ; preds = %loop.cond60 + store i64 3, ptr %.anon70, align 8 + br label %loop.cond71 + +loop.cond71: ; preds = %loop.body73, %loop.exit69 + %64 = load i64, ptr %.anon70, align 8 + %gt72 = icmp ugt i64 %64, 0 + br i1 %gt72, label %loop.body73, label %loop.exit77 + +loop.body73: ; preds = %loop.cond71 + %65 = load i64, ptr %.anon70, align 8 + %sub74 = sub i64 %65, 1 + store i64 %sub74, ptr %.anon70, align 8 + %66 = load <3 x float>, ptr %foo2, align 16 + %67 = load i64, ptr %.anon70, align 8 + %68 = extractelement <3 x float> %66, i64 %67 + %fpfpext76 = fpext float %68 to double + store double %fpfpext76, ptr %a75, align 8 + %69 = load double, ptr %a75, align 8 + call void (ptr, ...) @printf(ptr @.str.9, double %69) + br label %loop.cond71 + +loop.exit77: ; preds = %loop.cond71 + ret void +} + +; Function Attrs: nounwind +define i32 @main(i32 %0, ptr %1) #0 { +entry: + call void @test_main() + ret i32 0 +} diff --git a/test/test_suite2/statements/foreach_r_custom.c3t b/test/test_suite2/statements/foreach_r_custom.c3t new file mode 100644 index 000000000..9c4673641 --- /dev/null +++ b/test/test_suite2/statements/foreach_r_custom.c3t @@ -0,0 +1,92 @@ +// #target: macos-x64 + +module test; +struct Foo +{ + int[] x; +} + +macro int Foo.@operator_element_at(Foo &foo, usize index) @operator(elementat) +{ + return foo.x[index]; +} + +macro usize Foo.@operator_len(Foo &foo) @operator(len) +{ + return foo.x.len; +} + +fn void main() +{ + int[*] i = { 1, 3, 10 }; + Foo x = { &i }; + foreach_r FOO: (int f : x) { + printf("%d\n", f); + while (1) + { + break FOO; + } + } +} + +extern fn int printf(char *fmt, ...); + +/* #expect: test.ll + +; Function Attrs: nounwind +define void @test_main() #0 { +entry: + %i = alloca [3 x i32], align 4 + %x = alloca %Foo, align 8 + %.anon = alloca i64, align 8 + %f = alloca i32, align 4 + %index = alloca i64, align 8 + call void @llvm.memcpy.p0.p0.i32(ptr align 4 %i, ptr align 4 @.__const, i32 12, i1 false) + %0 = getelementptr inbounds %Foo, ptr %x, i32 0, i32 0 + %1 = insertvalue %"int[]" undef, ptr %i, 0 + %2 = insertvalue %"int[]" %1, i64 3, 1 + store %"int[]" %2, ptr %0, align 8 + %3 = getelementptr inbounds %Foo, ptr %x, i32 0, i32 0 + %4 = getelementptr inbounds %"int[]", ptr %3, i32 0, i32 1 + %5 = load i64, ptr %4, align 8 + store i64 %5, ptr %.anon, align 8 + br label %loop.cond + +loop.cond: ; preds = %entry + %6 = load i64, ptr %.anon, align 8 + %gt = icmp ugt i64 %6, 0 + br i1 %gt, label %loop.body, label %loop.exit + +loop.body: ; preds = %loop.cond + %7 = load i64, ptr %.anon, align 8 + %sub = sub i64 %7, 1 + store i64 %sub, ptr %.anon, align 8 + %8 = load i64, ptr %.anon, align 8 + store i64 %8, ptr %index, align 8 + %9 = getelementptr inbounds %Foo, ptr %x, i32 0, i32 0 + %10 = getelementptr inbounds %"int[]", ptr %9, i32 0, i32 0 + %11 = load ptr, ptr %10, align 8 + %12 = load i64, ptr %index, align 8 + %ptroffset = getelementptr inbounds i32, ptr %11, i64 %12 + %13 = load i32, ptr %ptroffset, align 4 + store i32 %13, ptr %f, align 4 + %14 = load i32, ptr %f, align 4 + %15 = call i32 (ptr, ...) @printf(ptr @.str, i32 %14) + br label %loop.body1 + +loop.body1: ; preds = %loop.body + br label %loop.exit + +loop.exit: ; preds = %loop.body1, %loop.cond + ret void +} + +; Function Attrs: nounwind +declare i32 @printf(ptr, ...) #0 + +; Function Attrs: nounwind +define i32 @main(i32 %0, ptr %1) #0 { +entry: + call void @test_main() + ret i32 0 +} diff --git a/test/test_suite2/statements/foreach_r_custom_errors.c3 b/test/test_suite2/statements/foreach_r_custom_errors.c3 new file mode 100644 index 000000000..81d59d474 --- /dev/null +++ b/test/test_suite2/statements/foreach_r_custom_errors.c3 @@ -0,0 +1,15 @@ +fn void test1() +{ + int x; + foreach_r (a : x) { }; // #error: It's not possible to enumerate an expression of type 'int' +} + +define Test1 = distinct int; + +fn void test2() +{ + Test1 x; + foreach_r (a : x) { }; // #error: It's not possible to enumerate an expression of type 'Test1' +} + + diff --git a/test/test_suite2/statements/foreach_r_custom_macro.c3t b/test/test_suite2/statements/foreach_r_custom_macro.c3t new file mode 100644 index 000000000..79a50ef29 --- /dev/null +++ b/test/test_suite2/statements/foreach_r_custom_macro.c3t @@ -0,0 +1,91 @@ +// #target: macos-x64 +module test; +struct Foo +{ + int[] x; +} + +macro int Foo.@operator_element_at(Foo &foo, usize index) @operator(elementat) +{ + return foo.x[index]; +} + +macro usize Foo.@operator_len(Foo &foo) @operator(len) +{ + return foo.x.len; +} + +fn void main() +{ + int[*] i = { 1, 3, 10 }; + Foo x = { &i }; + foreach_r FOO: (int f : x) { + printf("%d\n", f); + while (1) + { + break FOO; + } + } +} + +extern fn int printf(char *fmt, ...); + +/* #expect: test.ll + +; Function Attrs: nounwind +define void @test_main() #0 { +entry: + %i = alloca [3 x i32], align 4 + %x = alloca %Foo, align 8 + %.anon = alloca i64, align 8 + %f = alloca i32, align 4 + %index = alloca i64, align 8 + call void @llvm.memcpy.p0.p0.i32(ptr align 4 %i, ptr align 4 @.__const, i32 12, i1 false) + %0 = getelementptr inbounds %Foo, ptr %x, i32 0, i32 0 + %1 = insertvalue %"int[]" undef, ptr %i, 0 + %2 = insertvalue %"int[]" %1, i64 3, 1 + store %"int[]" %2, ptr %0, align 8 + %3 = getelementptr inbounds %Foo, ptr %x, i32 0, i32 0 + %4 = getelementptr inbounds %"int[]", ptr %3, i32 0, i32 1 + %5 = load i64, ptr %4, align 8 + store i64 %5, ptr %.anon, align 8 + br label %loop.cond + +loop.cond: ; preds = %entry + %6 = load i64, ptr %.anon, align 8 + %gt = icmp ugt i64 %6, 0 + br i1 %gt, label %loop.body, label %loop.exit + +loop.body: ; preds = %loop.cond + %7 = load i64, ptr %.anon, align 8 + %sub = sub i64 %7, 1 + store i64 %sub, ptr %.anon, align 8 + %8 = load i64, ptr %.anon, align 8 + store i64 %8, ptr %index, align 8 + %9 = getelementptr inbounds %Foo, ptr %x, i32 0, i32 0 + %10 = getelementptr inbounds %"int[]", ptr %9, i32 0, i32 0 + %11 = load ptr, ptr %10, align 8 + %12 = load i64, ptr %index, align 8 + %ptroffset = getelementptr inbounds i32, ptr %11, i64 %12 + %13 = load i32, ptr %ptroffset, align 4 + store i32 %13, ptr %f, align 4 + %14 = load i32, ptr %f, align 4 + %15 = call i32 (ptr, ...) @printf(ptr @.str, i32 %14) + br label %loop.body1 + +loop.body1: ; preds = %loop.body + br label %loop.exit + +loop.exit: ; preds = %loop.body1, %loop.cond + ret void +} + +; Function Attrs: nounwind +declare i32 @printf(ptr, ...) #0 + +; Function Attrs: nounwind +define i32 @main(i32 %0, ptr %1) #0 { +entry: + call void @test_main() + ret i32 0 +} diff --git a/test/test_suite2/statements/foreach_r_errors.c3 b/test/test_suite2/statements/foreach_r_errors.c3 new file mode 100644 index 000000000..47047b375 --- /dev/null +++ b/test/test_suite2/statements/foreach_r_errors.c3 @@ -0,0 +1,54 @@ +module test; + +extern fn void foo(); +int[3] z; + +fn void test1() +{ + int x; + foreach_r (a : x) // #error: It's not possible to enumerate an expression of type 'int'. + { + foo(); + } +} + +fn void test2() +{ + foreach_r (a : z) foo(); + foreach_r (i, a : z) foo(); + foreach_r (double i, a : z); // #error: Index must be an integer type, 'double' is not valid. +} + +fn void test3() +{ + foreach_r (&a : z) foo(); + foreach_r (&i, &a : z) foo(); // #error: The index cannot be held by reference, did you accidentally add a '&'? +} + +fn void test4() +{ + foreach_r (&a : z) foo(); + foreach_r (&i, a : z) foo(); // #error: The index cannot be held by reference, did you accidentally add a '&'? +} + +fn void test5() +{ + foreach_r (int! y : z) foo(); // #error: The variable may not be a failable. +} + +fn void test6() +{ + foreach_r (int! i, y : z) foo(); // #error: The index may not be a failable. +} + +fn void test7() +{ + foreach_r (int a : { 1, 2, 3 }) foo(); + foreach_r (a : { 1, 2, 3 }) foo(); // #error: Add the type of your variable here if you want to iterate over +} + +fn void test8() +{ + foreach_r (int a : { z }) foo(); // #error: 'int[3]' into 'int' +} + diff --git a/test/test_suite2/statements/foreach_r_parse_error.c3 b/test/test_suite2/statements/foreach_r_parse_error.c3 new file mode 100644 index 000000000..a7a00b965 --- /dev/null +++ b/test/test_suite2/statements/foreach_r_parse_error.c3 @@ -0,0 +1,5 @@ +fn void test9() +{ + foreach_r (int a : { [2] = 1 }) foo(); + foreach_r (int a : { [2] = 2, 1 }) foo(); // #error: Normal initialization cannot be mixed with designated initialization. +} \ No newline at end of file diff --git a/test/test_suite2/statements/foreach_r_test.c3t b/test/test_suite2/statements/foreach_r_test.c3t deleted file mode 100644 index d89809112..000000000 --- a/test/test_suite2/statements/foreach_r_test.c3t +++ /dev/null @@ -1,87 +0,0 @@ -// #target: macos-x64 -module test; -import std::io; - -fn void main() -{ - int[*] x = { 1, 5, 10 }; - int[] y = &x; - foreach_r (int i, val : y) - { - io::printfln("%d: %d", i, val); - } -} - -/* #expect: test.ll - -entry: - %x = alloca [3 x i32], align 4 - %y = alloca %"int[]", align 8 - %.anon = alloca i64, align 8 - %i = alloca i32, align 4 - %val = alloca i32, align 4 - %retparam = alloca i64, align 8 - %taddr = alloca %"char[]", align 8 - %vararg = alloca %"variant[]", align 8 - %varargslots = alloca [2 x %variant], align 16 - call void @llvm.memcpy.p0.p0.i32(ptr align 4 %x, ptr align 4 @.__const, i32 12, i1 false) - %0 = insertvalue %"int[]" undef, ptr %x, 0 - %1 = insertvalue %"int[]" %0, i64 3, 1 - store %"int[]" %1, ptr %y, align 8 - %2 = getelementptr inbounds %"int[]", ptr %y, i32 0, i32 1 - %3 = load i64, ptr %2, align 8 - store i64 %3, ptr %.anon, align 8 - br label %loop.cond - -loop.cond: ; preds = %voiderr, %entry - %4 = load i64, ptr %.anon, align 8 - %gt = icmp ugt i64 %4, 0 - br i1 %gt, label %loop.body, label %loop.exit - -loop.body: ; preds = %loop.cond - %5 = load i64, ptr %.anon, align 8 - %sub = sub i64 %5, 1 - store i64 %sub, ptr %.anon, align 8 - %6 = load i64, ptr %.anon, align 8 - %uisitrunc = trunc i64 %6 to i32 - store i32 %uisitrunc, ptr %i, align 4 - %7 = getelementptr inbounds %"int[]", ptr %y, i32 0, i32 0 - %8 = load ptr, ptr %7, align 8 - %9 = load i64, ptr %.anon, align 8 - %ptroffset = getelementptr inbounds i32, ptr %8, i64 %9 - %10 = load i32, ptr %ptroffset, align 4 - store i32 %10, ptr %val, align 4 - store %"char[]" { ptr @.str, i64 6 }, ptr %taddr, align 8 - %11 = getelementptr inbounds { ptr, i64 }, ptr %taddr, i32 0, i32 0 - %lo = load ptr, ptr %11, align 8 - %12 = getelementptr inbounds { ptr, i64 }, ptr %taddr, i32 0, i32 1 - %hi = load i64, ptr %12, align 8 - %13 = insertvalue %variant undef, ptr %i, 0 - %14 = insertvalue %variant %13, i64 ptrtoint (ptr @"ct$int" to i64), 1 - %15 = getelementptr inbounds [2 x %variant], ptr %varargslots, i64 0, i64 0 - store %variant %14, ptr %15, align 16 - %16 = insertvalue %variant undef, ptr %val, 0 - %17 = insertvalue %variant %16, i64 ptrtoint (ptr @"ct$int" to i64), 1 - %18 = getelementptr inbounds [2 x %variant], ptr %varargslots, i64 0, i64 1 - store %variant %17, ptr %18, align 16 - %19 = getelementptr inbounds %"variant[]", ptr %vararg, i32 0, i32 1 - store i64 2, ptr %19, align 8 - %20 = getelementptr inbounds %"variant[]", ptr %vararg, i32 0, i32 0 - store ptr %varargslots, ptr %20, align 8 - %21 = getelementptr inbounds { ptr, i64 }, ptr %vararg, i32 0, i32 0 - %lo1 = load ptr, ptr %21, align 8 - %22 = getelementptr inbounds { ptr, i64 }, ptr %vararg, i32 0, i32 1 - %hi2 = load i64, ptr %22, align 8 - %23 = call i64 @std_io_printfln(ptr %retparam, ptr %lo, i64 %hi, ptr %lo1, i64 %hi2) - %not_err = icmp eq i64 %23, 0 - br i1 %not_err, label %after_check, label %voiderr - -after_check: ; preds = %loop.body - br label %voiderr - -voiderr: ; preds = %after_check, %loop.body - br label %loop.cond - -loop.exit: ; preds = %loop.cond - ret void -} diff --git a/test/test_suite2/statements/foreach_r_with_error.c3 b/test/test_suite2/statements/foreach_r_with_error.c3 new file mode 100644 index 000000000..d58d4b5a5 --- /dev/null +++ b/test/test_suite2/statements/foreach_r_with_error.c3 @@ -0,0 +1,12 @@ +module test; + +fn void test() +{ + int[3]! x; + int g; + foreach_r (z : x) // #error: The expression may not be failable. + { + g += z; + x[0] = 1; + } +}