From bb9c8fb93e02e93664fec9da58896bc55fc758a3 Mon Sep 17 00:00:00 2001 From: Christoffer Lerno Date: Sun, 28 Aug 2022 23:20:15 +0200 Subject: [PATCH] Fix of macro/fn use of operator overloading for foreach. --- src/compiler/sema_expr.c | 34 ++- src/compiler/sema_internal.h | 1 + src/compiler/sema_stmts.c | 25 +-- src/version.h | 2 +- .../foreach_more_implementations.c3t | 201 ++++++++++++++++++ .../foreach_more_implementations.c3t | 187 ++++++++++++++++ 6 files changed, 421 insertions(+), 29 deletions(-) create mode 100644 test/test_suite/statements/foreach_more_implementations.c3t create mode 100644 test/test_suite2/statements/foreach_more_implementations.c3t diff --git a/src/compiler/sema_expr.c b/src/compiler/sema_expr.c index f5e063dba..89127a3c4 100644 --- a/src/compiler/sema_expr.c +++ b/src/compiler/sema_expr.c @@ -3213,12 +3213,9 @@ static inline bool sema_expr_analyse_subscript(SemaContext *context, Expr *expr, } if (decl) { - expr->expr_kind = EXPR_CALL; Expr **args = NULL; vec_add(args, index); - expr->call_expr = (ExprCall){ .func_ref = declid(decl), .is_func_ref = true, .arguments = args }; - expr->call_expr.is_type_method = true; - return sema_expr_analyse_macro_call(context, expr, current_expr, decl, failable); + return sema_insert_method_call(context, expr, decl, current_expr, args); } } if (!inner_type) @@ -8469,4 +8466,31 @@ bool splitpathref(const char *string, ArraySize len, Path **path_ref, const char *type_ref = TOKEN_INVALID_TOKEN; } return true; -} \ No newline at end of file +} + +bool sema_insert_method_call(SemaContext *context, Expr *method_call, Decl *method_decl, Expr *parent, Expr **arguments) +{ + *method_call = (Expr) { .expr_kind = EXPR_CALL, + .resolve_status = RESOLVE_RUNNING, + .call_expr.func_ref = declid(method_decl), + .call_expr.arguments = arguments, + .call_expr.is_func_ref = true, + .call_expr.is_type_method = true }; + Type *type = parent->type->canonical; + Type *first = method_decl->func_decl.signature.params[0]->type; + if (type != first) + { + if (first->type_kind == TYPE_POINTER && first->pointer == type) + { + expr_insert_addr(parent); + } + else if (type->type_kind == TYPE_POINTER && type->pointer == first) + { + expr_insert_deref(parent); + } + } + assert(first == parent->type->canonical); + if (!sema_expr_analyse_general_call(context, method_call, method_decl, parent, false)) return expr_poison(method_call); + method_call->resolve_status = RESOLVE_DONE; + return true; +} diff --git a/src/compiler/sema_internal.h b/src/compiler/sema_internal.h index fb4831dba..87700d3f6 100644 --- a/src/compiler/sema_internal.h +++ b/src/compiler/sema_internal.h @@ -73,6 +73,7 @@ void sema_analysis_pass_ct_assert(Module *module); void sema_analysis_pass_functions(Module *module); void sema_analyze_stage(Module *module, AnalysisStage stage); Decl *sema_find_operator(SemaContext *context, Expr *expr, OperatorOverload operator_overload); +bool sema_insert_method_call(SemaContext *context, Expr *method_call, Decl *method_decl, Expr *parent, Expr **arguments); bool sema_analyse_expr_lvalue(SemaContext *context, Expr *expr); bool sema_analyse_expr_lvalue_fold_const(SemaContext *context, Expr *expr); bool sema_analyse_ct_expr(SemaContext *context, Expr *expr); diff --git a/src/compiler/sema_stmts.c b/src/compiler/sema_stmts.c index 59ea9dff3..83e08b6a4 100644 --- a/src/compiler/sema_stmts.c +++ b/src/compiler/sema_stmts.c @@ -901,28 +901,6 @@ static inline bool sema_analyse_for_stmt(SemaContext *context, Ast *statement) return success; } - - -static Expr *sema_insert_method_macro_call(SemaContext *context, SourceSpan span, Decl *method_decl, Expr *parent, Expr **arguments) -{ - Expr *len_call = expr_new(EXPR_CALL, span); - len_call->resolve_status = RESOLVE_RUNNING; - len_call->call_expr.func_ref = declid(method_decl); - len_call->call_expr.arguments = arguments; - len_call->call_expr.body = 0; - len_call->call_expr.is_func_ref = true; - len_call->call_expr.splat_vararg = false; - len_call->call_expr.is_type_method = true; - bool is_macro = method_decl->decl_kind == DECL_MACRO; - if (!is_macro) - { - if (parent->type->type_kind != TYPE_POINTER) expr_insert_addr(parent); - } - if (!sema_expr_analyse_general_call(context, len_call, method_decl, parent, false)) return poisoned_expr; - len_call->resolve_status = RESOLVE_DONE; - return len_call; -} - static inline bool sema_analyse_foreach_stmt(SemaContext *context, Ast *statement) { // Pull out the relevant data. @@ -1128,7 +1106,8 @@ static inline bool sema_analyse_foreach_stmt(SemaContext *context, Ast *statemen ArraySize array_len = 0; if (len) { - ASSIGN_EXPR_OR_RET(len_call, sema_insert_method_macro_call(context, enumerator->span, len, enum_val, NULL), false); + len_call = expr_new(EXPR_CALL, enumerator->span); + if (!sema_insert_method_call(context, len_call, len, enum_val, NULL)) return false; } else { diff --git a/src/version.h b/src/version.h index 4fc0259e7..d68677ecb 100644 --- a/src/version.h +++ b/src/version.h @@ -1 +1 @@ -#define COMPILER_VERSION "0.3.32" \ No newline at end of file +#define COMPILER_VERSION "0.3.33" \ No newline at end of file diff --git a/test/test_suite/statements/foreach_more_implementations.c3t b/test/test_suite/statements/foreach_more_implementations.c3t new file mode 100644 index 000000000..1ae516aff --- /dev/null +++ b/test/test_suite/statements/foreach_more_implementations.c3t @@ -0,0 +1,201 @@ +// #target: macos-x64 +module test; + +import std::io; +struct Vector +{ + usize size; + int* elements; +} + +macro int Vector.get(Vector* vector, usize element) @operator(elementat) +{ + return vector.elements[element]; +} + +macro int* Vector.get_ref(Vector* vector, usize element) @operator(elementref) +{ + return &vector.elements[element]; +} + +macro usize Vector.size(Vector vector) @operator(len) { + return vector.size; +} + +fn void main() +{ + int[2] x = { 1, 2 }; + Vector v = { 2, &x }; + + foreach (int* &ref : v) + { + std::io::printf("%d\n", *ref); + *ref += 2; + } + foreach (int i : v) + { + std::io::printf("%d\n", i); + } +} + +/* #expect: test.ll + +define void @test_main() #0 { +entry: + %x = alloca [2 x i32], align 4 + %v = alloca %Vector, align 8 + %.anon = alloca i64, align 8 + %vector = alloca %Vector, align 8 + %.anon1 = alloca i64, align 8 + %ref = alloca i32*, align 8 + %vector2 = alloca %Vector*, align 8 + %element = alloca i64, align 8 + %retparam = alloca i64, align 8 + %taddr = alloca %"char[]", align 8 + %vararg = alloca %"variant[]", align 8 + %varargslots = alloca [1 x %variant], align 16 + %.anon6 = alloca i64, align 8 + %vector7 = alloca %Vector, align 8 + %.anon8 = alloca i64, align 8 + %i = alloca i32, align 4 + %vector12 = alloca %Vector*, align 8 + %element13 = alloca i64, align 8 + %retparam15 = alloca i64, align 8 + %taddr16 = alloca %"char[]", align 8 + %vararg19 = alloca %"variant[]", align 8 + %varargslots20 = alloca [1 x %variant], align 16 + %0 = bitcast [2 x i32]* %x to i8* + call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 4 %0, i8* align 4 bitcast ([2 x i32]* @.__const to i8*), i32 8, i1 false) + %1 = getelementptr inbounds %Vector, %Vector* %v, i32 0, i32 0 + store i64 2, i64* %1, align 8 + %2 = getelementptr inbounds %Vector, %Vector* %v, i32 0, i32 1 + %ptrptr = bitcast [2 x i32]* %x to i32* + store i32* %ptrptr, i32** %2, align 8 + %3 = bitcast %Vector* %vector to i8* + %4 = bitcast %Vector* %v to i8* + call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 8 %3, i8* align 8 %4, i32 16, i1 false) + %5 = getelementptr inbounds %Vector, %Vector* %vector, i32 0, i32 0 + %6 = load i64, i64* %5, align 8 + store i64 %6, i64* %.anon, align 8 + store i64 0, i64* %.anon1, align 8 + br label %loop.cond + +loop.cond: ; preds = %voiderr, %entry + %7 = load i64, i64* %.anon1, align 8 + %8 = load i64, i64* %.anon, align 8 + %lt = icmp ult i64 %7, %8 + br i1 %lt, label %loop.body, label %loop.exit + +loop.body: ; preds = %loop.cond + store %Vector* %v, %Vector** %vector2, align 8 + %9 = load i64, i64* %.anon1, align 8 + store i64 %9, i64* %element, align 8 + %10 = load %Vector*, %Vector** %vector2, align 8 + %11 = getelementptr inbounds %Vector, %Vector* %10, i32 0, i32 1 + %12 = load i32*, i32** %11, align 8 + %13 = load i64, i64* %element, align 8 + %ptroffset = getelementptr inbounds i32, i32* %12, i64 %13 + store i32* %ptroffset, i32** %ref, align 8 + store %"char[]" { i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i32 0, i32 0), i64 3 }, %"char[]"* %taddr, align 8 + %14 = bitcast %"char[]"* %taddr to { i8*, i64 }* + %15 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %14, i32 0, i32 0 + %lo = load i8*, i8** %15, align 8 + %16 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %14, i32 0, i32 1 + %hi = load i64, i64* %16, align 8 + %17 = load i32*, i32** %ref, align 8 + %18 = bitcast i32* %17 to i8* + %19 = insertvalue %variant undef, i8* %18, 0 + %20 = insertvalue %variant %19, i64 ptrtoint (%.introspect* @"ct$int" to i64), 1 + %21 = getelementptr inbounds [1 x %variant], [1 x %variant]* %varargslots, i64 0, i64 0 + store %variant %20, %variant* %21, align 16 + %22 = getelementptr inbounds %"variant[]", %"variant[]"* %vararg, i32 0, i32 1 + store i64 1, i64* %22, align 8 + %23 = getelementptr inbounds %"variant[]", %"variant[]"* %vararg, i32 0, i32 0 + %24 = bitcast [1 x %variant]* %varargslots to %variant* + store %variant* %24, %variant** %23, align 8 + %25 = bitcast %"variant[]"* %vararg to { i8*, i64 }* + %26 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %25, i32 0, i32 0 + %lo3 = load i8*, i8** %26, align 8 + %27 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %25, i32 0, i32 1 + %hi4 = load i64, i64* %27, align 8 + %28 = call i64 @std_io_printf(i64* %retparam, i8* %lo, i64 %hi, i8* %lo3, i64 %hi4) + %not_err = icmp eq i64 %28, 0 + br i1 %not_err, label %after_check, label %voiderr + +after_check: ; preds = %loop.body + br label %voiderr + +voiderr: ; preds = %after_check, %loop.body + %29 = load i32*, i32** %ref, align 8 + %30 = load i32, i32* %29, align 8 + %add = add i32 %30, 2 + store i32 %add, i32* %29, align 8 + %31 = load i64, i64* %.anon1, align 8 + %add5 = add i64 %31, 1 + store i64 %add5, i64* %.anon1, align 8 + br label %loop.cond + +loop.exit: ; preds = %loop.cond + %32 = bitcast %Vector* %vector7 to i8* + %33 = bitcast %Vector* %v to i8* + call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 8 %32, i8* align 8 %33, i32 16, i1 false) + %34 = getelementptr inbounds %Vector, %Vector* %vector7, i32 0, i32 0 + %35 = load i64, i64* %34, align 8 + store i64 %35, i64* %.anon6, align 8 + store i64 0, i64* %.anon8, align 8 + br label %loop.cond9 + +loop.cond9: ; preds = %voiderr25, %loop.exit + %36 = load i64, i64* %.anon8, align 8 + %37 = load i64, i64* %.anon6, align 8 + %lt10 = icmp ult i64 %36, %37 + br i1 %lt10, label %loop.body11, label %loop.exit27 + +loop.body11: ; preds = %loop.cond9 + store %Vector* %v, %Vector** %vector12, align 8 + %38 = load i64, i64* %.anon8, align 8 + store i64 %38, i64* %element13, align 8 + %39 = load %Vector*, %Vector** %vector12, align 8 + %40 = getelementptr inbounds %Vector, %Vector* %39, i32 0, i32 1 + %41 = load i32*, i32** %40, align 8 + %42 = load i64, i64* %element13, align 8 + %ptroffset14 = getelementptr inbounds i32, i32* %41, i64 %42 + %43 = load i32, i32* %ptroffset14, align 4 + store i32 %43, i32* %i, align 4 + store %"char[]" { i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str.1, i32 0, i32 0), i64 3 }, %"char[]"* %taddr16, align 8 + %44 = bitcast %"char[]"* %taddr16 to { i8*, i64 }* + %45 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %44, i32 0, i32 0 + %lo17 = load i8*, i8** %45, align 8 + %46 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %44, i32 0, i32 1 + %hi18 = load i64, i64* %46, align 8 + %47 = bitcast i32* %i to i8* + %48 = insertvalue %variant undef, i8* %47, 0 + %49 = insertvalue %variant %48, i64 ptrtoint (%.introspect* @"ct$int" to i64), 1 + %50 = getelementptr inbounds [1 x %variant], [1 x %variant]* %varargslots20, i64 0, i64 0 + store %variant %49, %variant* %50, align 16 + %51 = getelementptr inbounds %"variant[]", %"variant[]"* %vararg19, i32 0, i32 1 + store i64 1, i64* %51, align 8 + %52 = getelementptr inbounds %"variant[]", %"variant[]"* %vararg19, i32 0, i32 0 + %53 = bitcast [1 x %variant]* %varargslots20 to %variant* + store %variant* %53, %variant** %52, align 8 + %54 = bitcast %"variant[]"* %vararg19 to { i8*, i64 }* + %55 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %54, i32 0, i32 0 + %lo21 = load i8*, i8** %55, align 8 + %56 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %54, i32 0, i32 1 + %hi22 = load i64, i64* %56, align 8 + %57 = call i64 @std_io_printf(i64* %retparam15, i8* %lo17, i64 %hi18, i8* %lo21, i64 %hi22) + %not_err23 = icmp eq i64 %57, 0 + br i1 %not_err23, label %after_check24, label %voiderr25 + +after_check24: ; preds = %loop.body11 + br label %voiderr25 + +voiderr25: ; preds = %after_check24, %loop.body11 + %58 = load i64, i64* %.anon8, align 8 + %add26 = add i64 %58, 1 + store i64 %add26, i64* %.anon8, align 8 + br label %loop.cond9 + +loop.exit27: ; preds = %loop.cond9 + ret void +} \ No newline at end of file diff --git a/test/test_suite2/statements/foreach_more_implementations.c3t b/test/test_suite2/statements/foreach_more_implementations.c3t new file mode 100644 index 000000000..676ff983d --- /dev/null +++ b/test/test_suite2/statements/foreach_more_implementations.c3t @@ -0,0 +1,187 @@ +// #target: macos-x64 +module test; + +import std::io; +struct Vector +{ + usize size; + int* elements; +} + +macro int Vector.get(Vector* vector, usize element) @operator(elementat) +{ + return vector.elements[element]; +} + +macro int* Vector.get_ref(Vector* vector, usize element) @operator(elementref) +{ + return &vector.elements[element]; +} + +macro usize Vector.size(Vector vector) @operator(len) { + return vector.size; +} + +fn void main() +{ + int[2] x = { 1, 2 }; + Vector v = { 2, &x }; + + foreach (int* &ref : v) + { + std::io::printf("%d\n", *ref); + *ref += 2; + } + foreach (int i : v) + { + std::io::printf("%d\n", i); + } +} + +/* #expect: test.ll + +define void @test_main() #0 { +entry: + %x = alloca [2 x i32], align 4 + %v = alloca %Vector, align 8 + %.anon = alloca i64, align 8 + %vector = alloca %Vector, align 8 + %.anon1 = alloca i64, align 8 + %ref = alloca ptr, align 8 + %vector2 = alloca ptr, align 8 + %element = alloca i64, align 8 + %retparam = alloca i64, align 8 + %taddr = alloca %"char[]", align 8 + %vararg = alloca %"variant[]", align 8 + %varargslots = alloca [1 x %variant], align 16 + %.anon6 = alloca i64, align 8 + %vector7 = alloca %Vector, align 8 + %.anon8 = alloca i64, align 8 + %i = alloca i32, align 4 + %vector12 = alloca ptr, align 8 + %element13 = alloca i64, align 8 + %retparam15 = alloca i64, align 8 + %taddr16 = alloca %"char[]", align 8 + %vararg19 = alloca %"variant[]", align 8 + %varargslots20 = alloca [1 x %variant], align 16 + call void @llvm.memcpy.p0.p0.i32(ptr align 4 %x, ptr align 4 @.__const, i32 8, i1 false) + %0 = getelementptr inbounds %Vector, ptr %v, i32 0, i32 0 + store i64 2, ptr %0, align 8 + %1 = getelementptr inbounds %Vector, ptr %v, i32 0, i32 1 + store ptr %x, ptr %1, align 8 + call void @llvm.memcpy.p0.p0.i32(ptr align 8 %vector, ptr align 8 %v, i32 16, i1 false) + %2 = getelementptr inbounds %Vector, ptr %vector, i32 0, i32 0 + %3 = load i64, ptr %2, align 8 + store i64 %3, ptr %.anon, align 8 + store i64 0, ptr %.anon1, align 8 + br label %loop.cond + +loop.cond: ; preds = %voiderr, %entry + %4 = load i64, ptr %.anon1, align 8 + %5 = load i64, ptr %.anon, align 8 + %lt = icmp ult i64 %4, %5 + br i1 %lt, label %loop.body, label %loop.exit + +loop.body: ; preds = %loop.cond + store ptr %v, ptr %vector2, align 8 + %6 = load i64, ptr %.anon1, align 8 + store i64 %6, ptr %element, align 8 + %7 = load ptr, ptr %vector2, align 8 + %8 = getelementptr inbounds %Vector, ptr %7, i32 0, i32 1 + %9 = load ptr, ptr %8, align 8 + %10 = load i64, ptr %element, align 8 + %ptroffset = getelementptr inbounds i32, ptr %9, i64 %10 + store ptr %ptroffset, ptr %ref, align 8 + store %"char[]" { ptr @.str, i64 3 }, 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 = load ptr, ptr %ref, align 8 + %14 = insertvalue %variant undef, ptr %13, 0 + %15 = insertvalue %variant %14, i64 ptrtoint (ptr @"ct$int" to i64), 1 + %16 = getelementptr inbounds [1 x %variant], ptr %varargslots, i64 0, i64 0 + store %variant %15, ptr %16, align 16 + %17 = getelementptr inbounds %"variant[]", ptr %vararg, i32 0, i32 1 + store i64 1, ptr %17, align 8 + %18 = getelementptr inbounds %"variant[]", ptr %vararg, i32 0, i32 0 + store ptr %varargslots, ptr %18, align 8 + %19 = getelementptr inbounds { ptr, i64 }, ptr %vararg, i32 0, i32 0 + %lo3 = load ptr, ptr %19, align 8 + %20 = getelementptr inbounds { ptr, i64 }, ptr %vararg, i32 0, i32 1 + %hi4 = load i64, ptr %20, align 8 + %21 = call i64 @std_io_printf(ptr %retparam, ptr %lo, i64 %hi, ptr %lo3, i64 %hi4) + %not_err = icmp eq i64 %21, 0 + br i1 %not_err, label %after_check, label %voiderr + +after_check: ; preds = %loop.body + br label %voiderr + +voiderr: ; preds = %after_check, %loop.body + %22 = load ptr, ptr %ref, align 8 + %23 = load i32, ptr %22, align 8 + %add = add i32 %23, 2 + store i32 %add, ptr %22, align 8 + %24 = load i64, ptr %.anon1, align 8 + %add5 = add i64 %24, 1 + store i64 %add5, ptr %.anon1, align 8 + br label %loop.cond + +loop.exit: ; preds = %loop.cond + call void @llvm.memcpy.p0.p0.i32(ptr align 8 %vector7, ptr align 8 %v, i32 16, i1 false) + %25 = getelementptr inbounds %Vector, ptr %vector7, i32 0, i32 0 + %26 = load i64, ptr %25, align 8 + store i64 %26, ptr %.anon6, align 8 + store i64 0, ptr %.anon8, align 8 + br label %loop.cond9 + +loop.cond9: ; preds = %voiderr25, %loop.exit + %27 = load i64, ptr %.anon8, align 8 + %28 = load i64, ptr %.anon6, align 8 + %lt10 = icmp ult i64 %27, %28 + br i1 %lt10, label %loop.body11, label %loop.exit27 + +loop.body11: ; preds = %loop.cond9 + store ptr %v, ptr %vector12, align 8 + %29 = load i64, ptr %.anon8, align 8 + store i64 %29, ptr %element13, align 8 + %30 = load ptr, ptr %vector12, align 8 + %31 = getelementptr inbounds %Vector, ptr %30, i32 0, i32 1 + %32 = load ptr, ptr %31, align 8 + %33 = load i64, ptr %element13, align 8 + %ptroffset14 = getelementptr inbounds i32, ptr %32, i64 %33 + %34 = load i32, ptr %ptroffset14, align 4 + store i32 %34, ptr %i, align 4 + store %"char[]" { ptr @.str.1, i64 3 }, ptr %taddr16, align 8 + %35 = getelementptr inbounds { ptr, i64 }, ptr %taddr16, i32 0, i32 0 + %lo17 = load ptr, ptr %35, align 8 + %36 = getelementptr inbounds { ptr, i64 }, ptr %taddr16, i32 0, i32 1 + %hi18 = load i64, ptr %36, align 8 + %37 = insertvalue %variant undef, ptr %i, 0 + %38 = insertvalue %variant %37, i64 ptrtoint (ptr @"ct$int" to i64), 1 + %39 = getelementptr inbounds [1 x %variant], ptr %varargslots20, i64 0, i64 0 + store %variant %38, ptr %39, align 16 + %40 = getelementptr inbounds %"variant[]", ptr %vararg19, i32 0, i32 1 + store i64 1, ptr %40, align 8 + %41 = getelementptr inbounds %"variant[]", ptr %vararg19, i32 0, i32 0 + store ptr %varargslots20, ptr %41, align 8 + %42 = getelementptr inbounds { ptr, i64 }, ptr %vararg19, i32 0, i32 0 + %lo21 = load ptr, ptr %42, align 8 + %43 = getelementptr inbounds { ptr, i64 }, ptr %vararg19, i32 0, i32 1 + %hi22 = load i64, ptr %43, align 8 + %44 = call i64 @std_io_printf(ptr %retparam15, ptr %lo17, i64 %hi18, ptr %lo21, i64 %hi22) + %not_err23 = icmp eq i64 %44, 0 + br i1 %not_err23, label %after_check24, label %voiderr25 + +after_check24: ; preds = %loop.body11 + br label %voiderr25 + +voiderr25: ; preds = %after_check24, %loop.body11 + %45 = load i64, ptr %.anon8, align 8 + %add26 = add i64 %45, 1 + store i64 %add26, ptr %.anon8, align 8 + br label %loop.cond9 + +loop.exit27: ; preds = %loop.cond9 + ret void +} \ No newline at end of file