From 164a1ef59d044b6369fd450412f889e599bb8f1d Mon Sep 17 00:00:00 2001 From: Christoffer Lerno Date: Sat, 27 Nov 2021 00:23:48 +0100 Subject: [PATCH] Initial foreach implementation based on index --- CMakeLists.txt | 8 +- src/build/build_options.h | 2 +- src/compiler/compiler_internal.h | 5 +- src/compiler/llvm_codegen_c_abi_x64.c | 2 +- src/compiler/llvm_codegen_stmt.c | 145 +---- src/compiler/sema_expr.c | 53 +- src/compiler/sema_internal.h | 2 + src/compiler/sema_stmts.c | 394 +++++++------ src/compiler/tb_codegen.c | 10 +- .../initializer_lists/ranges_to_dynamic.c3t | 41 +- test/test_suite/slices/slice_assign.c3t | 51 +- .../statements/custom_foreach_with_ref.c3t | 519 ++++++++++++++++++ test/test_suite/statements/foreach_break.c3t | 69 +-- test/test_suite/statements/foreach_common.c3t | 292 +++++----- test/test_suite/statements/foreach_custom.c3t | 111 +--- .../statements/foreach_custom_errors.c3 | 64 +-- .../statements/foreach_custom_macro.c3t | 105 ++-- .../statements/foreach_with_error.c3 | 2 +- 18 files changed, 1090 insertions(+), 785 deletions(-) create mode 100644 test/test_suite/statements/custom_foreach_with_ref.c3t diff --git a/CMakeLists.txt b/CMakeLists.txt index 0b74941ca..0b6702833 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,6 +9,7 @@ SET(CMAKE_FIND_PACKAGE_SORT_DIRECTION DEC) find_package(LLVM REQUIRED CONFIG) + message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}") message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}") message(STATUS "Libraries located in: ${LLVM_LIBRARY_DIRS}") @@ -56,7 +57,7 @@ file(COPY ${CMAKE_SOURCE_DIR}/resources/lib DESTINATION ${CMAKE_BINARY_DIR}) # These don't seem to be reliable on windows. if(UNIX) message(STATUS "using find_library") - find_library(TB_LIB NAMES tinybackend.a PATHS ${CMAKE_SOURCE_DIR}/resources/tblib) +# find_library(TB_LIB NAMES tinybackend.a PATHS ${CMAKE_SOURCE_DIR}/resources/tblib) find_library(LLD_COFF NAMES lldCOFF.a liblldCOFF.a PATHS ${LLVM_LIBRARY_DIRS}) find_library(LLD_COMMON NAMES lldCommon.a liblldCommon.a PATHS ${LLVM_LIBRARY_DIRS}) find_library(LLD_CORE NAMES lldCore.a liblldCore.a PATHS ${LLVM_LIBRARY_DIRS}) @@ -158,7 +159,7 @@ add_executable(c3c if(NOT CMAKE_C_COMPILER_ID STREQUAL "MSVC") message(STATUS "using gcc/clang warning switches") target_compile_options(c3c PRIVATE -Wall -Werror -Wno-unknown-pragmas -Wno-unused-result - -Wno-unused-function -Wno-unused-variable -Wno-unused-parameter) + -Wno-unused-function -Wno-unused-variable -Wno-unused-parameter) endif() target_include_directories(c3c PRIVATE @@ -176,7 +177,8 @@ message(STATUS "Found LLD ${lld_libs}") if(UNIX) message(STATUS "adding unix link params") target_link_libraries(c3c_wrappers ${llvm_libs} ${lld_libs}) - target_link_libraries(c3c m ${llvm_libs} c3c_wrappers ${TB_LIB} ${lld_libs}) + target_link_libraries(c3c m ${llvm_libs} c3c_wrappers ${lld_libs}) +# target_link_libraries(c3c m ${llvm_libs} c3c_wrappers ${TB_LIB} ${lld_libs}) else() # todo: maybe get this from llvm-config somehow? it should be in LLVM_DIR\..\..\..\bin I think. set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -LIBPATH:C:\\llvm\\llvm\\build\\Release\\lib") # needed for lldCommon.lib diff --git a/src/build/build_options.h b/src/build/build_options.h index d2214fe63..ad71d9f8b 100644 --- a/src/build/build_options.h +++ b/src/build/build_options.h @@ -11,7 +11,7 @@ #define MAX_FILES 2048 #define MAX_THREADS 0xFFFF -#define TB_BACKEND 1 +#define TB_BACKEND 0 typedef enum { diff --git a/src/compiler/compiler_internal.h b/src/compiler/compiler_internal.h index 77889066a..c690c65c8 100644 --- a/src/compiler/compiler_internal.h +++ b/src/compiler/compiler_internal.h @@ -256,13 +256,13 @@ typedef struct typedef struct { Type *base; - TypeSize len; + ArraySize len; } TypeArray; typedef struct { Type *base; - TypeSize len; + ArraySize len; } TypeVector; typedef struct @@ -1856,6 +1856,7 @@ bool expr_const_compare(const ExprConst *left, const ExprConst *right, BinaryOp bool expr_const_will_overflow(const ExprConst *expr, TypeKind kind); ArraySize expr_const_list_size(const ConstInitializer *list); +Expr *expr_generate_decl(Decl *decl, Expr *assign); void expr_insert_addr(Expr *original); void expr_insert_deref(Expr *expr); Expr *expr_variable(Decl *decl); diff --git a/src/compiler/llvm_codegen_c_abi_x64.c b/src/compiler/llvm_codegen_c_abi_x64.c index e53790a29..c042dfd45 100644 --- a/src/compiler/llvm_codegen_c_abi_x64.c +++ b/src/compiler/llvm_codegen_c_abi_x64.c @@ -309,7 +309,7 @@ void x64_classify_array(Type *type, ByteSize offset_base, X64Class *current, X64 } ByteSize offset = offset_base; - for (ByteSize i = 0; i < type->array.len; i++) + for (ArraySize i = 0; i < type->array.len; i++) { X64Class field_lo; X64Class field_hi; diff --git a/src/compiler/llvm_codegen_stmt.c b/src/compiler/llvm_codegen_stmt.c index d85a741a8..728a34d85 100644 --- a/src/compiler/llvm_codegen_stmt.c +++ b/src/compiler/llvm_codegen_stmt.c @@ -444,147 +444,6 @@ void gencontext_emit_for_stmt(GenContext *c, Ast *ast) llvm_emit_block(c, exit_block); } -static void llvm_emit_foreach_stmt(GenContext *c, Ast *ast) -{ - // First we generate an exit. - LLVMBasicBlockRef exit_block = llvm_basic_block_new(c, "foreach.exit"); - - PUSH_ERROR(); - - llvm_set_error_exit(c, exit_block); - - // First evaluate the enumerated collection - BEValue enum_value; - llvm_emit_expr(c, &enum_value, ast->foreach_stmt.enumeration); - - // Get the length - BEValue len; - llvm_emit_len_for_expr(c, &len, &enum_value); - llvm_value_rvalue(c, &len); - - // We pop the error here. - POP_ERROR(); - - llvm_emit_ptr_from_array(c, &enum_value); - - // Create the index and optionally the index var - LLVMTypeRef real_index_type = llvm_get_type(c, type_usize); - BEValue index_var = { 0 }; - LLVMTypeRef index_type = ast->foreach_stmt.index ? llvm_get_type(c, ast->foreach_stmt.index->type) : NULL; - BEValue index = { 0 }; - - bool extend_bits = false; - - // In case we have an index, set it up. - if (ast->foreach_stmt.index) - { - llvm_emit_local_var_alloca(c, ast->foreach_stmt.index); - llvm_value_set_address(&index_var, ast->foreach_stmt.index->backend_ref, ast->foreach_stmt.index->type); - // And set it to zero. - llvm_store_bevalue_raw(c, &index_var, llvm_get_zero(c, index_var.type)); - index = index_var; - extend_bits = type_size(index_var.type) > type_size(type_isize); - } - - // If types don't match (either index has a different type or it doesn't exist) - // then create the address for the internal index and set it to zero. - if (index_type != real_index_type) - { - llvm_value_set_address(&index, llvm_emit_alloca(c, real_index_type, type_abi_alignment(type_isize), "idx"), type_usize); - llvm_store_bevalue_raw(c, &index, llvm_get_zero(c, index.type)); - } - - Type *actual_type = type_get_indexed_type(ast->foreach_stmt.enumeration->type); - LLVMTypeRef actual_type_llvm = llvm_get_type(c, actual_type); - - llvm_emit_local_var_alloca(c, ast->foreach_stmt.variable); - Type *var_type = type_lowering(ast->foreach_stmt.variable->type); - LLVMTypeRef var_type_llvm = llvm_get_type(c, var_type); - BEValue var; - llvm_value_set_address(&var, ast->foreach_stmt.variable->backend_ref, var_type); - - LLVMBasicBlockRef inc_block = llvm_basic_block_new(c, "foreach.inc"); - LLVMBasicBlockRef body_block = llvm_basic_block_new(c, "foreach.body"); - LLVMBasicBlockRef cond_block = llvm_basic_block_new(c, "foreach.cond"); - - ast->foreach_stmt.continue_block = inc_block; - ast->foreach_stmt.exit_block = exit_block; - - // Emit cond - llvm_emit_br(c, cond_block); - llvm_emit_block(c, cond_block); - - BEValue index_value; - llvm_value_set(&index_value, llvm_value_rvalue_store(c, &index), type_usize); - BEValue b; - llvm_emit_int_comparison(c, &b, &index_value, &len, BINARYOP_LT); - llvm_emit_cond_br(c, &b, body_block, exit_block); - - llvm_emit_block(c, body_block); - - // In the case where we have an index that is smaller, we need to do a cast. - if (index_var.value && index.value != index_var.value) - { - LLVMValueRef stored_value; - if (extend_bits) - { - // Note that we zero extend. We never deal in negative indices. - stored_value = LLVMBuildZExt(c->builder, index_value.value, index_type, ""); - } - else - { - stored_value = LLVMBuildTrunc(c->builder, index_value.value, index_type, ""); - } - llvm_store_bevalue_raw(c, &index_var, stored_value); - } - - assert(llvm_value_is_addr(&enum_value)); - - LLVMValueRef ref_to_element; - AlignSize align; - if (enum_value.type->type_kind == TYPE_ARRAY || enum_value.type->type_kind == TYPE_VECTOR) - { - ref_to_element = llvm_emit_array_gep_raw_index(c, enum_value.value, - llvm_get_type(c, enum_value.type), index_value.value, index_value.alignment, &align); - } - else - { - ref_to_element = llvm_emit_pointer_inbounds_gep_raw(c, actual_type_llvm, enum_value.value, index_value.value); - } - BEValue result; - if (ast->foreach_stmt.value_by_ref) - { - llvm_value_set(&result, ref_to_element, type_get_ptr(actual_type)); - LLVMTypeRef pointer_llvm = llvm_get_ptr_type(c, actual_type); - if (pointer_llvm != var_type_llvm) - { - llvm_emit_cast(c, ast->foreach_stmt.cast, &result, var_type, result.type); - } - } - else - { - llvm_value_set_address(&result, ref_to_element, actual_type); - if (var_type_llvm != actual_type_llvm) - { - llvm_emit_cast(c, ast->foreach_stmt.cast, &result, var_type, actual_type); - } - } - llvm_store_bevalue(c, &var, &result); - - llvm_emit_stmt(c, ast->foreach_stmt.body); - - llvm_emit_br(c, inc_block); - - llvm_emit_block(c, inc_block); - index_value.value = LLVMBuildAdd(c->builder, llvm_value_rvalue_store(c, &index), llvm_const_int(c, type_isize, 1), ""); - llvm_store_bevalue(c, &index, &index_value); - - // Loop back. - llvm_emit_br(c, cond_block); - - // And insert exit block - llvm_emit_block(c, exit_block); -} void gencontext_emit_while_stmt(GenContext *context, Ast *ast) { @@ -1301,6 +1160,7 @@ void llvm_emit_stmt(GenContext *c, Ast *ast) case AST_VAR_STMT: case AST_IF_CATCH_SWITCH_STMT: case AST_SCOPING_STMT: + case AST_FOREACH_STMT: UNREACHABLE case AST_SCOPED_STMT: gencontext_emit_scoped_stmt(c, ast); @@ -1332,9 +1192,6 @@ void llvm_emit_stmt(GenContext *c, Ast *ast) case AST_FOR_STMT: gencontext_emit_for_stmt(c, ast); break; - case AST_FOREACH_STMT: - llvm_emit_foreach_stmt(c, ast); - break; case AST_WHILE_STMT: gencontext_emit_while_stmt(c, ast); break; diff --git a/src/compiler/sema_expr.c b/src/compiler/sema_expr.c index 0a8b8554d..1086b8a77 100644 --- a/src/compiler/sema_expr.c +++ b/src/compiler/sema_expr.c @@ -80,6 +80,17 @@ static inline bool both_any_integer_or_integer_vector(Expr *left, Expr *right) return type_is_integer(flatten_left->vector.base) && type_is_integer(flatten_right->vector.base); } +Expr *expr_generate_decl(Decl *decl, Expr *assign) +{ + assert(decl->decl_kind == DECL_VAR); + assert(decl->var.init_expr == NULL); + Expr *expr_decl = expr_new(EXPR_DECL, decl->span); + expr_decl->decl_expr = decl; + if (!assign) assign = expr_new(EXPR_UNDEF, decl->span); + decl->var.init_expr = assign; + return expr_decl; +} + void expr_insert_addr(Expr *original) { assert(original->resolve_status == RESOLVE_DONE); @@ -98,11 +109,19 @@ void expr_insert_addr(Expr *original) Expr *expr_variable(Decl *decl) { + if (decl->resolve_status == RESOLVE_DONE) + { + Expr *expr = expr_new(EXPR_IDENTIFIER, decl->span); + expr->identifier_expr.decl = decl; + expr->resolve_status = RESOLVE_DONE; + expr->type = decl->type; + return expr; + } Expr *expr = expr_new(EXPR_IDENTIFIER, decl->span); - expr->identifier_expr.decl = decl; - expr->resolve_status = RESOLVE_DONE; - expr->type = decl->type; + expr->identifier_expr.identifier = decl->name_token; + expr->resolve_status = RESOLVE_NOT_DONE; return expr; + } static inline bool expr_unary_addr_is_constant_eval(Expr *expr, ConstantEvalKind eval_kind) @@ -387,26 +406,30 @@ bool expr_is_constant_eval(Expr *expr, ConstantEvalKind eval_kind) void expr_insert_deref(Expr *original) { - assert(original->resolve_status == RESOLVE_DONE); - Type *no_fail = type_no_fail(original->type); - assert(no_fail->canonical->type_kind == TYPE_POINTER); - - // 1. Assume *(&x) => x + // Assume *(&x) => x if (original->expr_kind == EXPR_UNARY && original->unary_expr.operator == UNARYOP_ADDR) { *original = *original->unary_expr.expr; return; } - // 2. Only fold to the canonical type if it wasn't a pointer. - Type *pointee = no_fail->type_kind == TYPE_POINTER ? no_fail->pointer : no_fail->canonical->pointer; - - // 3. Allocate our new and create our new inner, and overwrite the original. + // Allocate our new and create our new inner, and overwrite the original. Expr *inner = expr_copy(original); original->expr_kind = EXPR_UNARY; - original->type = type_get_opt_fail(pointee, IS_FAILABLE(inner)); + original->type = NULL; original->unary_expr.operator = UNARYOP_DEREF; original->unary_expr.expr = inner; + + // In the case the original is already resolved, we want to resolve the deref as well. + if (original->resolve_status == RESOLVE_DONE) + { + Type *no_fail = type_no_fail(inner->type); + assert(no_fail->canonical->type_kind == TYPE_POINTER); + + // Only fold to the canonical type if it wasn't a pointer. + Type *pointee = no_fail->type_kind == TYPE_POINTER ? no_fail->pointer : no_fail->canonical->pointer; + original->type = type_get_opt_fail(pointee, IS_FAILABLE(inner)); + } } @@ -1559,7 +1582,7 @@ static bool sema_check_stmt_compile_time(Context *context, Ast *ast) } } -static bool sema_expr_analyse_macro_call(Context *context, Expr *call_expr, Expr *struct_var, Decl *decl, bool failable) +bool sema_expr_analyse_macro_call(Context *context, Expr *call_expr, Expr *struct_var, Decl *decl, bool failable) { assert(decl->decl_kind == DECL_MACRO); @@ -2499,7 +2522,7 @@ static inline bool sema_expr_analyse_group(Context *context, Expr *expr) } -static inline void expr_rewrite_to_int_const(Expr *expr_to_rewrite, Type *type, uint64_t value, bool narrowable) +void expr_rewrite_to_int_const(Expr *expr_to_rewrite, Type *type, uint64_t value, bool narrowable) { expr_to_rewrite->expr_kind = EXPR_CONST; expr_const_set_int(&expr_to_rewrite->const_expr, value, type->canonical->type_kind); diff --git a/src/compiler/sema_internal.h b/src/compiler/sema_internal.h index b6233d27c..44266151b 100644 --- a/src/compiler/sema_internal.h +++ b/src/compiler/sema_internal.h @@ -57,3 +57,5 @@ bool expr_is_ltype(Expr *expr); Decl *sema_find_operator(Context *context, Expr *expr, const char *kw); bool sema_analyse_expr_lvalue(Context *context, Expr *expr); +bool sema_expr_analyse_macro_call(Context *context, Expr *call_expr, Expr *struct_var, Decl *decl, bool failable); +void expr_rewrite_to_int_const(Expr *expr_to_rewrite, Type *type, uint64_t value, bool narrowable); \ No newline at end of file diff --git a/src/compiler/sema_stmts.c b/src/compiler/sema_stmts.c index 17f58404a..8f4581a53 100644 --- a/src/compiler/sema_stmts.c +++ b/src/compiler/sema_stmts.c @@ -997,77 +997,18 @@ static Decl *find_iterator_next(Context *context, Expr *enumerator) return method; } -static bool sema_rewrite_foreach_to_for(Context *context, Ast *statement, Expr *enumerator, Decl *next_method) +static Expr *sema_insert_method_macro_call(Context *context, SourceSpan span, Decl *macro_decl, Expr *parent, Expr **arguments) { - assert(enumerator->type); - REMINDER("Handle foreach by ref, index"); - Decl *value = statement->foreach_stmt.variable; - if (!value->type) - { - Type *type; - if (next_method->decl_kind == DECL_FUNC) - { - type = next_method->func_decl.function_signature.params[1]->type->pointer; - } - else - { - assert(next_method->decl_kind == DECL_MACRO); - type = next_method->macro_decl.parameters[1]->type->pointer; - } - value->var.type_info = type_info_new_base(type, value->span); - value->type = type; - } - - Decl *iterator = decl_new_generated_var(".iterator", enumerator->type, VARDECL_LOCAL, enumerator->span); - iterator->var.init_expr = enumerator; - - // Generate Foo *value, FooIterator ".iterator" = foo.iterator(); - Expr *init_expr = expr_new(EXPR_COND, enumerator->span); - Expr *expr = expr_new(EXPR_DECL, value->span); - expr->decl_expr = value; - vec_add(init_expr->cond_expr, expr); - expr = expr_new(EXPR_DECL, enumerator->span); - expr->decl_expr = iterator; - vec_add(init_expr->cond_expr, expr); - init_expr->resolve_status = RESOLVE_DONE; - init_expr->type = iterator->type; - - // Generate "next": it.next(&value) - Expr *call = expr_new(EXPR_CALL, enumerator->span); - call->call_expr.arguments = NULL; - call->call_expr.body = NULL; - call->call_expr.unsplat_last = false; - call->call_expr.is_type_method = true; - - Expr *value_access = expr_variable(value); - expr_insert_addr(value_access); - vec_add(call->call_expr.arguments, value_access); - - Expr *iterator_access = expr_variable(iterator); - expr_insert_addr(iterator_access); - - REMINDER("Failability"); - if (!sema_expr_analyse_general_call(context, - call, - next_method, - iterator_access, - next_method->decl_kind == DECL_MACRO, false)) return false; - call->resolve_status = RESOLVE_DONE; - - statement->for_stmt = (AstForStmt){ .init = init_expr, - .cond = call, - .flow = statement->foreach_stmt.flow, - .body = statement->foreach_stmt.body - }; - statement->ast_kind = AST_FOR_STMT; - return sema_analyse_for_stmt(context, statement); - /* - - Expr *call - - statement->for_stmt.cond - statement->for_stmt.init = init_expr; - statement*/ + Expr *len_call = expr_new(EXPR_CALL, span); + len_call->resolve_status = RESOLVE_RUNNING; + len_call->call_expr.func_ref = macro_decl; + len_call->call_expr.arguments = arguments; + len_call->call_expr.body = NULL; + len_call->call_expr.unsplat_last = false; + len_call->call_expr.is_type_method = true; + if (!sema_expr_analyse_macro_call(context, len_call, parent, macro_decl, false)) return poisoned_expr; + len_call->resolve_status = RESOLVE_DONE; + return len_call; } static inline bool sema_analyse_foreach_stmt(Context *context, Ast *statement) @@ -1077,8 +1018,11 @@ static inline bool sema_analyse_foreach_stmt(Context *context, Ast *statement) Decl *var = statement->foreach_stmt.variable; Expr *enumerator = statement->foreach_stmt.enumeration; Ast *body = statement->foreach_stmt.body; + Ast **stmts = NULL; + Expr **expressions = NULL; + + bool value_by_ref = statement->foreach_stmt.value_by_ref; bool success = true; - Type *indexed_type; // First fold the enumerator expression, removing any () around it. while (enumerator->expr_kind == EXPR_GROUP) enumerator = enumerator->inner_expr; @@ -1141,130 +1085,238 @@ static inline bool sema_analyse_foreach_stmt(Context *context, Ast *statement) // And pop the cond scope. SCOPE_END; - // Check that we can even index this expression. - indexed_type = type_get_indexed_type(enumerator->type); - if (!indexed_type || type_flatten_distinct(enumerator->type)->type_kind == TYPE_POINTER) + if (IS_FAILABLE(enumerator)) { - Type *type = type_flatten_distinct(enumerator->type); - Decl *method = find_iterator(context, enumerator); - if (!method) return false; - if (!sema_inline_default_iterator(context, enumerator, method)) return false; - Decl *next_method = find_iterator_next(context, enumerator); - if (!next_method) return false; - return sema_rewrite_foreach_to_for(context, statement, enumerator, next_method); - /* - Expr *new_expr = expr_alloc(); - *new_expr = *enumerator; - Expr *iterator = expr_new(EXPR_IDENTIFIER, new_expr->span); - iterator->identifier_expr.decl = method; - iterator->failable = false; - iterator->resolve_status = RESOLVE_DONE; - iterator->type = iterator->original_type = method->type; - *enumerator = (Expr) { - .span = new_expr->span, - .expr_kind = EXPR_CALL, - .call_expr = (ExprCall) { - .is_type_method = true, - .function = iterator, - } - }; - if (!sema_expr_analyse_general_call(context, enumerator, method)) - if (!sema_analyse_expr(context, NULL, enumerator)) return SCOPE_POP_ERROR();*/ - TODO + SEMA_ERROR(enumerator, "The expression may not be failable."); + return false; } - // Enter foreach scope, to put index + variable into the internal scope. - // the foreach may be labelled. - SCOPE_START_WITH_LABEL(statement->foreach_stmt.flow.label) + if (statement->foreach_stmt.index_by_ref) + { + SEMA_ERROR(index, "The index cannot be held by reference, did you accidentally add a '&'?"); + return false; + } - if (index) + // Insert a single deref as needed. + Type *flattened_type = enumerator->type->canonical; + if (flattened_type->type_kind == TYPE_POINTER) + { + // Something like Foo** will not be dereferenced, only Foo* + if (flattened_type->pointer->type_kind == TYPE_POINTER) { - if (statement->foreach_stmt.index_by_ref) - { - SEMA_ERROR(index, "The index cannot be held by reference, did you accidentally add a '&'?"); - return SCOPE_POP_ERROR(); - } - // Set type to isize if missing. - if (!index->var.type_info) - { - index->var.type_info = type_info_new_base(type_isize, index->span); - } - // Analyse the declaration. - if (!sema_analyse_var_decl(context, index, true)) return SCOPE_POP_ERROR(); - - if (type_is_failable(index->type)) - { - SEMA_ERROR(index->var.type_info, "The index may not be a failable."); - return SCOPE_POP_ERROR(); - } - - // Make sure that the index is an integer. - if (!type_is_integer(type_flatten(index->type))) - { - SEMA_ERROR(index->var.type_info, - "Index must be an integer type, '%s' is not valid.", - type_to_error_string(index->type)); - return SCOPE_POP_ERROR(); - } + SEMA_ERROR(enumerator, "It is not possible to enumerate an expression of type %s.", type_quoted_error_string(enumerator->type)); + return false; } + expr_insert_deref(enumerator); + } - // Find the expected type for the value. - Type *expected_var_type = indexed_type; + // At this point we should have dereferenced any pointer or bailed. + assert(!type_is_pointer(enumerator->type)); - // If by ref, then the pointer. - if (statement->foreach_stmt.value_by_ref) expected_var_type = type_get_ptr(expected_var_type); + // Check that we can even index this expression. - // If we type infer, then the expected type is the same as the indexed type. - if (!var->var.type_info) + Type *value_type = type_get_indexed_type(enumerator->type); + if (value_type && value_by_ref) value_type = type_get_ptr(value_type); + + Decl *len = NULL; + Decl *index_macro = NULL; + Type *index_type = type_usize; + + if (!value_type) + { + len = sema_find_operator(context, enumerator, kw_operator_len); + Decl *by_val = sema_find_operator(context, enumerator, kw_operator_element_at); + Decl *by_ref = sema_find_operator(context, enumerator, kw_operator_element_at_ref); + if (!len || (!by_val && !by_ref)) { - var->var.type_info = type_info_new_base(expected_var_type, var->span); + SEMA_ERROR(enumerator, "It's not possible to enumerate an expression of type %s.", type_quoted_error_string(enumerator->type)); + return false; } - - // Analyse the value declaration. - if (!sema_analyse_var_decl(context, var, true)) return SCOPE_POP_ERROR(); - - if (IS_FAILABLE(var)) + if (!by_ref && value_by_ref) { - SEMA_ERROR(var->var.type_info, "The variable may not be a failable."); - return SCOPE_POP_ERROR(); + SEMA_ERROR(enumerator, "%s does not support 'foreach' with the value by reference.", type_quoted_error_string(enumerator->type)); + return false; } - // TODO consider failables. + index_macro = value_by_ref ? by_ref : by_val; + index_type = index_macro->macro_decl.parameters[1]->type; + value_type = index_macro->macro_decl.rtype->type; + } - // We may have an implicit cast happening. - statement->foreach_stmt.cast = CAST_ERROR; - // If the type is different, attempt an implicit cast. - if (var->type != expected_var_type) + // Set up the value, assigning the type as needed. + // Element *value = void + Decl *value = statement->foreach_stmt.variable; + if (!value->var.type_info) + { + value->var.type_info = type_info_new_base(value_type, value->span); + } + if (!sema_resolve_type_info(context, value->var.type_info)) return false; + + if (type_is_failable(value->var.type_info->type)) + { + SEMA_ERROR(value->var.type_info, "The variable may not be a failable."); + return false; + } + + // Set up the optional index parameter + Decl *index_decl = statement->foreach_stmt.index; + Type *index_var_type = NULL; + if (index_decl) + { + if (!index_decl->var.type_info) index_decl->var.type_info = type_info_new_base(index_type, enumerator->span); + if (!sema_resolve_type_info(context, index_decl->var.type_info)) return false; + index_var_type = index_decl->var.type_info->type; + if (type_is_failable(index_var_type)) { - // This is hackish, replace when cast is refactored. - Expr dummy = { .resolve_status = RESOLVE_DONE, .span = { var->var.type_info->span.loc, - var->span.end_loc }, .expr_kind = EXPR_IDENTIFIER, .type = expected_var_type }; - if (!cast_implicit(&dummy, var->type)) return SCOPE_POP_ERROR(); - if (IS_FAILABLE(&dummy)) - { - SEMA_ERROR(var, "The variable may not be failable."); - return false; - } - assert(dummy.expr_kind == EXPR_CAST); - statement->foreach_stmt.cast = dummy.cast_expr.kind; + SEMA_ERROR(index_decl->var.type_info, "The index may not be a failable."); + return false; } + if (!type_is_integer(type_flatten(index_var_type))) + { + SEMA_ERROR(index->var.type_info, + "Index must be an integer type, '%s' is not valid.", + type_to_error_string(index_var_type)); + return false; + } + } - // Push the statement on the break/continue stack. - PUSH_BREAKCONT(statement); + // IndexType __idx$ = 0 + Decl *idx_decl = decl_new_generated_var("__idx$", index_type, VARDECL_LOCAL, index_decl ? index_decl->span : enumerator->span); + Expr *idx_init = expr_new(EXPR_CONST, idx_decl->span); + expr_rewrite_to_int_const(idx_init, index_type, 0, true); + vec_add(expressions, expr_generate_decl(idx_decl, idx_init)); - success = sema_analyse_statement(context, body); - statement->foreach_stmt.flow.no_exit = context->active_scope.jump_end; + // We either have "foreach (x : some_var)" or "foreach (x : some_call())" + // So we grab the former by address (implicit &) and the latter as the value. + assert(enumerator->resolve_status == RESOLVE_DONE); + bool is_addr = false; + bool is_variable = false; + if (expr_is_ltype(enumerator)) + { + if (enumerator->expr_kind == EXPR_IDENTIFIER) + { + is_variable = true; + } + else + { + is_addr = true; + expr_insert_addr(enumerator); + } + } - // Pop the stack. - POP_BREAKCONT(); + Decl *temp = NULL; + if (is_variable) + { + temp = enumerator->identifier_expr.decl; + } + else + { + // Store either "Foo* __enum$ = &some_var;" or "Foo __enum$ = some_call()" + temp = decl_new_generated_var("__enum$", enumerator->type, VARDECL_LOCAL, enumerator->span); + vec_add(expressions, expr_generate_decl(temp, enumerator)); + } - // End foreach scope - context_pop_defers_and_replace_ast(context, body); + // Create @__enum$.len() or @(*__enum$).len() + Expr *enum_val = expr_variable(temp); + if (is_addr) expr_insert_deref(enum_val); + Type *enumerator_type = type_flatten(enum_val->type); + Expr *len_call; + ArraySize array_len = 0; + if (len) + { + ASSIGN_EXPR_ELSE(len_call, sema_insert_method_macro_call(context, enumerator->span, len, enum_val, NULL), false); + } + else + { + if (enumerator_type->type_kind == TYPE_ARRAY) + { + array_len = enumerator_type->array.len; + len_call = NULL; + } + else + { + len_call = expr_new(EXPR_LEN, enumerator->span); + if (!sema_analyse_expr(context, enum_val)) return false; + len_call->len_expr.inner = enum_val; + len_call->resolve_status = RESOLVE_DONE; + len_call->type = type_isize; + } + } - SCOPE_END; + // IndexType __len$ = (IndexType)(@__enum$.len()) + Decl *len_decl = NULL; + if (len_call) + { + len_decl = decl_new_generated_var("__len$", idx_init->type, VARDECL_LOCAL, enumerator->span); + if (!cast_implicit(len_call, idx_init->type)) return false; + vec_add(expressions, expr_generate_decl(len_decl, len_call)); + } - return success; + // Add all declarations to the init + Expr *init_expr = expr_new(EXPR_COND, value->span); + init_expr->cond_expr = expressions; + + // Create __idx$ < __len$ + Expr *binary = expr_new(EXPR_BINARY, idx_decl->span); + binary->binary_expr.operator = BINARYOP_LT; + binary->binary_expr.left = expr_variable(idx_decl); + if (len_decl) + { + binary->binary_expr.right = expr_variable(len_decl); + } + else + { + Expr *rhs = expr_new(EXPR_CONST, enumerator->span); + expr_rewrite_to_int_const(rhs, type_isize, array_len, true); + binary->binary_expr.right = rhs; + } + + // Create __idx$++ + Expr *inc = expr_new(EXPR_UNARY, idx_decl->span); + inc->unary_expr.expr = expr_variable(idx_decl); + inc->unary_expr.operator = UNARYOP_INC; + + // Create IndexType index = __idx$++ + if (index_decl) + { + Ast *declare_ast = new_ast(AST_DECLARE_STMT, value->span); + declare_ast->declare_stmt = index_decl; + Expr *load_idx = expr_variable(idx_decl); + if (!cast(load_idx, index_var_type)) return false; + index_decl->var.init_expr = load_idx; + vec_add(stmts, declare_ast); + } + + // Create value = (*__$enum)[__idx$] + Ast *value_declare_ast = new_ast(AST_DECLARE_STMT, value->span); + value_declare_ast->declare_stmt = value; + + Expr *subscript = expr_new(EXPR_SUBSCRIPT, value->span); + enum_val = expr_variable(temp); + if (is_addr) expr_insert_deref(enum_val); + subscript->subscript_expr.expr = enum_val; + subscript->subscript_expr.index = expr_variable(idx_decl); + if (value_by_ref) + { + Expr *addr = expr_new(EXPR_UNARY, subscript->span); + addr->unary_expr.operator = UNARYOP_ADDR; + addr->unary_expr.expr = subscript; + subscript = addr; + } + value->var.init_expr = subscript; + vec_add(stmts, value_declare_ast); + vec_add(stmts, body); + Ast *compound_stmt = new_ast(AST_COMPOUND_STMT, body->span); + compound_stmt->compound_stmt.stmts = stmts; + statement->for_stmt = (AstForStmt){ .init = init_expr, + .cond = binary, + .incr = inc, + .flow = statement->foreach_stmt.flow, + .body = compound_stmt + }; + statement->ast_kind = AST_FOR_STMT; + return sema_analyse_for_stmt(context, statement); } diff --git a/src/compiler/tb_codegen.c b/src/compiler/tb_codegen.c index e4076a787..ba0ede732 100644 --- a/src/compiler/tb_codegen.c +++ b/src/compiler/tb_codegen.c @@ -52,10 +52,10 @@ static inline bool tinybackend_value_is_bool(BEValue *value) static TB_DataType tinybackend_get_type(Type *type) { type = type_lowering(type); - int elements = 1; + uint8_t elements = 1; if (type->type_kind == TYPE_VECTOR) { - elements = type->vector.len; + elements = (uint8_t)type->vector.len; type = type->vector.base; } switch (type->type_kind) @@ -155,7 +155,7 @@ void tinybackend_store_bevalue(GenContext *c, TB_DataType type, BEValue *destina tb_inst_memcpy(c->function, destination->value, value->value, copy_size, - value->alignment ? value->alignment : type_abi_alignment(value->type)); + value->alignment ? (int)value->alignment : (int)type_abi_alignment(value->type)); return; } default: @@ -271,7 +271,7 @@ static void tinybackend_emit_member_addr(GenContext *c, BEValue *value, Decl *pa break; case TYPE_STRUCT: { - TB_Register ref = tb_inst_member_access(c->function, value->value, found->offset); + TB_Register ref = tb_inst_member_access(c->function, value->value, (int32_t)found->offset); tinybackend_value_set_address(value, ref, member->type); value->alignment = found->alignment; @@ -557,7 +557,7 @@ static TB_Register tinybackend_emit_local_decl(GenContext *c, Decl *decl) } TB_DataType dt = tinybackend_get_type(decl->type); - ByteSize size = type_size(decl->type); + TypeSize size = type_size(decl->type); AlignSize align = decl->alignment; TB_Register reg = tb_inst_local(c->function, size, align); diff --git a/test/test_suite/initializer_lists/ranges_to_dynamic.c3t b/test/test_suite/initializer_lists/ranges_to_dynamic.c3t index ce58e6acc..f03864184 100644 --- a/test/test_suite/initializer_lists/ranges_to_dynamic.c3t +++ b/test/test_suite/initializer_lists/ranges_to_dynamic.c3t @@ -23,7 +23,7 @@ define void @test.test(i32 %0) #0 { entry: %x = alloca i32, align 4 %y = alloca [10 x i32], align 16 - %idx = alloca i64, align 8 + %"__idx$" = alloca i64, align 8 %v = alloca i32, align 4 store i32 %0, i32* %x, align 4 %1 = bitcast [10 x i32]* %y to i8* @@ -43,28 +43,29 @@ entry: store i32 %7, i32* %8, align 4 %9 = getelementptr inbounds [10 x i32], [10 x i32]* %y, i64 0, i64 8 store i32 %7, i32* %9, align 4 - store i64 0, i64* %idx, align 8 - br label %foreach.cond + store i64 0, i64* %"__idx$", align 8 + br label %for.cond -foreach.cond: ; preds = %foreach.inc, %entry - %10 = load i64, i64* %idx, align 8 - %lt = icmp ult i64 %10, 10 - br i1 %lt, label %foreach.body, label %foreach.exit +for.cond: ; preds = %for.inc, %entry + %10 = load i64, i64* %"__idx$", align 8 + %gt = icmp ugt i64 10, %10 + br i1 %gt, label %for.body, label %for.exit -foreach.body: ; preds = %foreach.cond - %11 = getelementptr inbounds [10 x i32], [10 x i32]* %y, i64 0, i64 %10 - %12 = load i32, i32* %11, align 4 - store i32 %12, i32* %v, align 4 - %13 = load i32, i32* %v, align 4 - call void (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i32 0, i32 0), i32 %13) - br label %foreach.inc +for.body: ; preds = %for.cond + %11 = load i64, i64* %"__idx$", align 8 + %12 = getelementptr inbounds [10 x i32], [10 x i32]* %y, i64 0, i64 %11 + %13 = load i32, i32* %12, align 4 + store i32 %13, i32* %v, align 4 + %14 = load i32, i32* %v, align 4 + call void (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i32 0, i32 0), i32 %14) + br label %for.inc -foreach.inc: ; preds = %foreach.body - %14 = load i64, i64* %idx, align 8 - %15 = add i64 %14, 1 - store i64 %15, i64* %idx, align 8 - br label %foreach.cond +for.inc: ; preds = %for.body + %15 = load i64, i64* %"__idx$", align 8 + %add = add i64 %15, 1 + store i64 %add, i64* %"__idx$", align 8 + br label %for.cond -foreach.exit: ; preds = %foreach.cond +for.exit: ; preds = %for.cond ret void } diff --git a/test/test_suite/slices/slice_assign.c3t b/test/test_suite/slices/slice_assign.c3t index 8b3c8668c..fffa98bed 100644 --- a/test/test_suite/slices/slice_assign.c3t +++ b/test/test_suite/slices/slice_assign.c3t @@ -19,15 +19,13 @@ fn void main() /* #expect: test.ll @.str = private constant [4 x i8] c"%d\0A\00", align 1 - ; Function Attrs: nounwind declare void @printf(i8*, ...) #0 - ; Function Attrs: nounwind define void @main() #0 { entry: %x = alloca [8 x i32], align 16 - %idx = alloca i64, align 8 + %"__idx$" = alloca i64, align 8 %i = alloca i32, align 4 %0 = bitcast [8 x i32]* %x to i8* call void @llvm.memset.p0i8.i64(i8* align 16 %0, i8 0, i64 32, i1 false) @@ -45,35 +43,36 @@ entry: store i32 52, i32* %6, align 4 %7 = getelementptr inbounds [8 x i32], [8 x i32]* %x, i64 0, i64 7 store i32 52, i32* %7, align 4 - store i64 0, i64* %idx, align 8 - br label %foreach.cond -foreach.cond: ; preds = %foreach.inc, %entry - %8 = load i64, i64* %idx, align 8 - %lt = icmp ult i64 %8, 8 - br i1 %lt, label %foreach.body, label %foreach.exit -foreach.body: ; preds = %foreach.cond - %9 = getelementptr inbounds [8 x i32], [8 x i32]* %x, i64 0, i64 %8 - %10 = load i32, i32* %9, align 4 - store i32 %10, i32* %i, align 4 - %11 = load i32, i32* %i, align 4 - call void (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i32 0, i32 0), i32 %11) - br label %foreach.inc -foreach.inc: ; preds = %foreach.body - %12 = load i64, i64* %idx, align 8 - %13 = add i64 %12, 1 - store i64 %13, i64* %idx, align 8 - br label %foreach.cond -foreach.exit: ; preds = %foreach.cond + store i64 0, i64* %"__idx$", align 8 + br label %for.cond +for.cond: ; preds = %for.inc, %entry + %8 = load i64, i64* %"__idx$", align 8 + %gt = icmp ugt i64 8, %8 + br i1 %gt, label %for.body, label %for.exit +for.body: ; preds = %for.cond + %9 = load i64, i64* %"__idx$", align 8 + %10 = getelementptr inbounds [8 x i32], [8 x i32]* %x, i64 0, i64 %9 + %11 = load i32, i32* %10, align 4 + store i32 %11, i32* %i, align 4 + %12 = load i32, i32* %i, align 4 + call void (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i32 0, i32 0), i32 %12) + br label %for.inc +for.inc: ; preds = %for.body + %13 = load i64, i64* %"__idx$", align 8 + %add = add i64 %13, 1 + store i64 %add, i64* %"__idx$", align 8 + br label %for.cond +for.exit: ; preds = %for.cond br label %cond -cond: ; preds = %assign, %foreach.exit - %14 = phi i64 [ 0, %foreach.exit ], [ %add, %assign ] +cond: ; preds = %assign, %for.exit + %14 = phi i64 [ 0, %for.exit ], [ %add1, %assign ] %le = icmp sle i64 %14, 7 br i1 %le, label %assign, label %exit assign: ; preds = %cond %15 = getelementptr inbounds [8 x i32], [8 x i32]* %x, i64 0, i64 %14 store i32 123, i32* %15, align 4 - %add = add i64 %14, 1 + %add1 = add i64 %14, 1 br label %cond exit: ; preds = %cond ret void -} \ No newline at end of file +} diff --git a/test/test_suite/statements/custom_foreach_with_ref.c3t b/test/test_suite/statements/custom_foreach_with_ref.c3t new file mode 100644 index 000000000..1c6891bd2 --- /dev/null +++ b/test/test_suite/statements/custom_foreach_with_ref.c3t @@ -0,0 +1,519 @@ +// #target: x64-darwin +module foo; + +struct Foo +{ + int[3] a; +} + +extern fn void printf(char*, ...); + +macro int* Foo.operator_element_at_ref(Foo &f, int a) +{ + return &f.a[a]; +} + +macro int Foo.operator_len(Foo &f) +{ + return 3; +} + +macro int Foo.operator_element_at(Foo &f, int a) +{ + return f.a[a]; +} + +fn int[5] getFields() +{ + printf("getFields\n"); + return int[5] { 3, 5, 2, 10, 111}; +} +fn Foo *call(Foo *f) +{ + printf("Call made\n"); + return f; +} +fn void main() +{ + Foo x = { { 1, 5, 7} }; + printf("%d %d %d\n", x[0], x[1], x[2]); + foreach (i, int y : *call(&x)) + { + printf("Hello %d: %d\n", i, y); + } + foreach (i, int* &y : x) + { + *y += 1; + printf("Hello %d: %d\n", i, *y); + } + foreach (i, int y : x) + { + printf("After one %d: %d\n", i, y); + } + + foreach (i, int y : &x) + { + printf("By pointer %d: %d\n", i, y); + } + + foreach (i, int y : x) + { + printf("Adding %d: %d\n", i, y); + i++; + } + + foreach(i, y : int[5] { 1, 2, 10, 111, 123 } ) + { + printf("Adding %d: %d\n", i, y); + i++; + } + foreach(i, y : getFields() ) + { + printf("Pull value %d: %d\n", i, y); + } + foreach(i, y : &&getFields()) + { + printf("Pull value tempptr %d: %d\n", i, y); + } + printf("%d %d\n", x[0], x[1]); + int* y = &x[1]; + *y += 1; + printf("%d %d\n", x[0], x[1]); +} + +/* #expect: foo.ll + + +%Foo = type { [3 x i32] } + +@Foo = linkonce_odr constant i8 1 +@.str = private constant [11 x i8] c"getFields\0A\00", align 1 +@.str.1 = private constant [11 x i8] c"Call made\0A\00", align 1 +@.__const = private constant %Foo { [3 x i32] [i32 1, i32 5, i32 7] }, align 4 +@.str.2 = private constant [10 x i8] c"%d %d %d\0A\00", align 1 +@.str.3 = private constant [14 x i8] c"Hello %d: %d\0A\00", align 1 +@.str.4 = private constant [14 x i8] c"Hello %d: %d\0A\00", align 1 +@.str.5 = private constant [18 x i8] c"After one %d: %d\0A\00", align 1 +@.str.6 = private constant [19 x i8] c"By pointer %d: %d\0A\00", align 1 +@.str.7 = private constant [15 x i8] c"Adding %d: %d\0A\00", align 1 +@.__const.8 = private constant [5 x i32] [i32 1, i32 2, i32 10, i32 111, i32 123], align 16 +@.str.9 = private constant [15 x i8] c"Adding %d: %d\0A\00", align 1 +@.str.10 = private constant [19 x i8] c"Pull value %d: %d\0A\00", align 1 +@.str.11 = private constant [27 x i8] c"Pull value tempptr %d: %d\0A\00", align 1 +@.str.12 = private constant [7 x i8] c"%d %d\0A\00", align 1 +@.str.13 = private constant [7 x i8] c"%d %d\0A\00", align 1 + +; Function Attrs: nounwind +declare void @printf(i8*, ...) #0 + +; Function Attrs: nounwind +define void @foo.getFields([5 x i32]* sret([5 x i32]) align 4 %0) #0 { +entry: + %literal = alloca [5 x i32], align 16 + call void (i8*, ...) @printf(i8* getelementptr inbounds ([11 x i8], [11 x i8]* @.str, i32 0, i32 0)) + %1 = getelementptr inbounds [5 x i32], [5 x i32]* %literal, i64 0, i64 0 + store i32 3, i32* %1, align 4 + %2 = getelementptr inbounds [5 x i32], [5 x i32]* %literal, i64 0, i64 1 + store i32 5, i32* %2, align 4 + %3 = getelementptr inbounds [5 x i32], [5 x i32]* %literal, i64 0, i64 2 + store i32 2, i32* %3, align 4 + %4 = getelementptr inbounds [5 x i32], [5 x i32]* %literal, i64 0, i64 3 + store i32 10, i32* %4, align 4 + %5 = getelementptr inbounds [5 x i32], [5 x i32]* %literal, i64 0, i64 4 + store i32 111, i32* %5, align 4 + %6 = bitcast [5 x i32]* %0 to i8* + %7 = bitcast [5 x i32]* %literal to i8* + call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 4 %6, i8* align 4 %7, i32 20, i1 false) + ret void +} + +; Function Attrs: nounwind +define %Foo* @foo.call(%Foo* %0) #0 { +entry: + %f = alloca %Foo*, align 8 + store %Foo* %0, %Foo** %f, align 8 + call void (i8*, ...) @printf(i8* getelementptr inbounds ([11 x i8], [11 x i8]* @.str.1, i32 0, i32 0)) + %1 = load %Foo*, %Foo** %f, align 8 + ret %Foo* %1 +} + +; Function Attrs: nounwind +define void @main() #0 { +entry: + %x = alloca %Foo, align 4 + %a = alloca i32, align 4 + %a1 = alloca i32, align 4 + %a3 = alloca i32, align 4 + %"__idx$" = alloca i32, align 4 + %"__enum$" = alloca %Foo*, align 8 + %"__len$" = alloca i32, align 4 + %i = alloca i32, align 4 + %y = alloca i32, align 4 + %a5 = alloca i32, align 4 + %"__idx$7" = alloca i32, align 4 + %"__len$8" = alloca i32, align 4 + %i12 = alloca i32, align 4 + %y13 = alloca i32*, align 8 + %a14 = alloca i32, align 4 + %"__idx$20" = alloca i32, align 4 + %"__len$21" = alloca i32, align 4 + %i25 = alloca i32, align 4 + %y26 = alloca i32, align 4 + %a27 = alloca i32, align 4 + %"__idx$32" = alloca i32, align 4 + %"__len$33" = alloca i32, align 4 + %i37 = alloca i32, align 4 + %y38 = alloca i32, align 4 + %a39 = alloca i32, align 4 + %"__idx$44" = alloca i32, align 4 + %"__len$45" = alloca i32, align 4 + %i49 = alloca i32, align 4 + %y50 = alloca i32, align 4 + %a51 = alloca i32, align 4 + %"__idx$57" = alloca i64, align 8 + %"__enum$58" = alloca [5 x i32], align 16 + %i61 = alloca i64, align 8 + %y62 = alloca i32, align 4 + %"__idx$67" = alloca i64, align 8 + %"__enum$68" = alloca [5 x i32], align 16 + %sretparam = alloca [5 x i32], align 4 + %i72 = alloca i64, align 8 + %y73 = alloca i32, align 4 + %"__idx$77" = alloca i64, align 8 + %"__enum$78" = alloca [5 x i32]*, align 8 + %sretparam79 = alloca [5 x i32], align 4 + %i83 = alloca i64, align 8 + %y84 = alloca i32, align 4 + %a88 = alloca i32, align 4 + %a90 = alloca i32, align 4 + %y92 = alloca i32*, align 8 + %a93 = alloca i32, align 4 + %a96 = alloca i32, align 4 + %a98 = alloca i32, align 4 + %0 = bitcast %Foo* %x to i8* + call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 4 %0, i8* align 4 bitcast (%Foo* @.__const to i8*), i32 12, i1 false) + store i32 0, i32* %a, align 4 + %1 = getelementptr inbounds %Foo, %Foo* %x, i32 0, i32 0 + %2 = load i32, i32* %a, align 4 + %sisiext = sext i32 %2 to i64 + %3 = getelementptr inbounds [3 x i32], [3 x i32]* %1, i64 0, i64 %sisiext + %4 = load i32, i32* %3, align 4 + store i32 1, i32* %a1, align 4 + %5 = getelementptr inbounds %Foo, %Foo* %x, i32 0, i32 0 + %6 = load i32, i32* %a1, align 4 + %sisiext2 = sext i32 %6 to i64 + %7 = getelementptr inbounds [3 x i32], [3 x i32]* %5, i64 0, i64 %sisiext2 + %8 = load i32, i32* %7, align 4 + store i32 2, i32* %a3, align 4 + %9 = getelementptr inbounds %Foo, %Foo* %x, i32 0, i32 0 + %10 = load i32, i32* %a3, align 4 + %sisiext4 = sext i32 %10 to i64 + %11 = getelementptr inbounds [3 x i32], [3 x i32]* %9, i64 0, i64 %sisiext4 + %12 = load i32, i32* %11, align 4 + call void (i8*, ...) @printf(i8* getelementptr inbounds ([10 x i8], [10 x i8]* @.str.2, i32 0, i32 0), i32 %4, i32 %8, i32 %12) + store i32 0, i32* %"__idx$", align 4 + %13 = call %Foo* @foo.call(%Foo* %x) + store %Foo* %13, %Foo** %"__enum$", align 8 + store i32 3, i32* %"__len$", align 4 + br label %for.cond + +for.cond: ; preds = %for.inc, %entry + %14 = load i32, i32* %"__idx$", align 4 + %15 = load i32, i32* %"__len$", align 4 + %lt = icmp slt i32 %14, %15 + br i1 %lt, label %for.body, label %for.exit + +for.body: ; preds = %for.cond + %16 = load i32, i32* %"__idx$", align 4 + store i32 %16, i32* %i, align 4 + %17 = load %Foo*, %Foo** %"__enum$", align 8 + %18 = load i32, i32* %"__idx$", align 4 + store i32 %18, i32* %a5, align 4 + %19 = getelementptr inbounds %Foo, %Foo* %17, i32 0, i32 0 + %20 = load i32, i32* %a5, align 4 + %sisiext6 = sext i32 %20 to i64 + %21 = getelementptr inbounds [3 x i32], [3 x i32]* %19, i64 0, i64 %sisiext6 + %22 = load i32, i32* %21, align 4 + store i32 %22, i32* %y, align 4 + %23 = load i32, i32* %i, align 4 + %24 = load i32, i32* %y, align 4 + call void (i8*, ...) @printf(i8* getelementptr inbounds ([14 x i8], [14 x i8]* @.str.3, i32 0, i32 0), i32 %23, i32 %24) + br label %for.inc + +for.inc: ; preds = %for.body + %25 = load i32, i32* %"__idx$", align 4 + %add = add i32 %25, 1 + store i32 %add, i32* %"__idx$", align 4 + br label %for.cond + +for.exit: ; preds = %for.cond + store i32 0, i32* %"__idx$7", align 4 + store i32 3, i32* %"__len$8", align 4 + br label %for.cond9 + +for.cond9: ; preds = %for.inc17, %for.exit + %26 = load i32, i32* %"__idx$7", align 4 + %27 = load i32, i32* %"__len$8", align 4 + %lt10 = icmp slt i32 %26, %27 + br i1 %lt10, label %for.body11, label %for.exit19 + +for.body11: ; preds = %for.cond9 + %28 = load i32, i32* %"__idx$7", align 4 + store i32 %28, i32* %i12, align 4 + %29 = load i32, i32* %"__idx$7", align 4 + store i32 %29, i32* %a14, align 4 + %30 = getelementptr inbounds %Foo, %Foo* %x, i32 0, i32 0 + %31 = load i32, i32* %a14, align 4 + %sisiext15 = sext i32 %31 to i64 + %32 = getelementptr inbounds [3 x i32], [3 x i32]* %30, i64 0, i64 %sisiext15 + store i32* %32, i32** %y13, align 8 + %33 = load i32*, i32** %y13, align 8 + %34 = load i32, i32* %33, align 8 + %add16 = add i32 %34, 1 + store i32 %add16, i32* %33, align 8 + %35 = load i32, i32* %i12, align 4 + %36 = load i32*, i32** %y13, align 8 + %37 = load i32, i32* %36, align 8 + call void (i8*, ...) @printf(i8* getelementptr inbounds ([14 x i8], [14 x i8]* @.str.4, i32 0, i32 0), i32 %35, i32 %37) + br label %for.inc17 + +for.inc17: ; preds = %for.body11 + %38 = load i32, i32* %"__idx$7", align 4 + %add18 = add i32 %38, 1 + store i32 %add18, i32* %"__idx$7", align 4 + br label %for.cond9 + +for.exit19: ; preds = %for.cond9 + store i32 0, i32* %"__idx$20", align 4 + store i32 3, i32* %"__len$21", align 4 + br label %for.cond22 + +for.cond22: ; preds = %for.inc29, %for.exit19 + %39 = load i32, i32* %"__idx$20", align 4 + %40 = load i32, i32* %"__len$21", align 4 + %lt23 = icmp slt i32 %39, %40 + br i1 %lt23, label %for.body24, label %for.exit31 + +for.body24: ; preds = %for.cond22 + %41 = load i32, i32* %"__idx$20", align 4 + store i32 %41, i32* %i25, align 4 + %42 = load i32, i32* %"__idx$20", align 4 + store i32 %42, i32* %a27, align 4 + %43 = getelementptr inbounds %Foo, %Foo* %x, i32 0, i32 0 + %44 = load i32, i32* %a27, align 4 + %sisiext28 = sext i32 %44 to i64 + %45 = getelementptr inbounds [3 x i32], [3 x i32]* %43, i64 0, i64 %sisiext28 + %46 = load i32, i32* %45, align 4 + store i32 %46, i32* %y26, align 4 + %47 = load i32, i32* %i25, align 4 + %48 = load i32, i32* %y26, align 4 + call void (i8*, ...) @printf(i8* getelementptr inbounds ([18 x i8], [18 x i8]* @.str.5, i32 0, i32 0), i32 %47, i32 %48) + br label %for.inc29 + +for.inc29: ; preds = %for.body24 + %49 = load i32, i32* %"__idx$20", align 4 + %add30 = add i32 %49, 1 + store i32 %add30, i32* %"__idx$20", align 4 + br label %for.cond22 + +for.exit31: ; preds = %for.cond22 + store i32 0, i32* %"__idx$32", align 4 + store i32 3, i32* %"__len$33", align 4 + br label %for.cond34 + +for.cond34: ; preds = %for.inc41, %for.exit31 + %50 = load i32, i32* %"__idx$32", align 4 + %51 = load i32, i32* %"__len$33", align 4 + %lt35 = icmp slt i32 %50, %51 + br i1 %lt35, label %for.body36, label %for.exit43 + +for.body36: ; preds = %for.cond34 + %52 = load i32, i32* %"__idx$32", align 4 + store i32 %52, i32* %i37, align 4 + %53 = load i32, i32* %"__idx$32", align 4 + store i32 %53, i32* %a39, align 4 + %54 = getelementptr inbounds %Foo, %Foo* %x, i32 0, i32 0 + %55 = load i32, i32* %a39, align 4 + %sisiext40 = sext i32 %55 to i64 + %56 = getelementptr inbounds [3 x i32], [3 x i32]* %54, i64 0, i64 %sisiext40 + %57 = load i32, i32* %56, align 4 + store i32 %57, i32* %y38, align 4 + %58 = load i32, i32* %i37, align 4 + %59 = load i32, i32* %y38, align 4 + call void (i8*, ...) @printf(i8* getelementptr inbounds ([19 x i8], [19 x i8]* @.str.6, i32 0, i32 0), i32 %58, i32 %59) + br label %for.inc41 + +for.inc41: ; preds = %for.body36 + %60 = load i32, i32* %"__idx$32", align 4 + %add42 = add i32 %60, 1 + store i32 %add42, i32* %"__idx$32", align 4 + br label %for.cond34 + +for.exit43: ; preds = %for.cond34 + store i32 0, i32* %"__idx$44", align 4 + store i32 3, i32* %"__len$45", align 4 + br label %for.cond46 + +for.cond46: ; preds = %for.inc54, %for.exit43 + %61 = load i32, i32* %"__idx$44", align 4 + %62 = load i32, i32* %"__len$45", align 4 + %lt47 = icmp slt i32 %61, %62 + br i1 %lt47, label %for.body48, label %for.exit56 + +for.body48: ; preds = %for.cond46 + %63 = load i32, i32* %"__idx$44", align 4 + store i32 %63, i32* %i49, align 4 + %64 = load i32, i32* %"__idx$44", align 4 + store i32 %64, i32* %a51, align 4 + %65 = getelementptr inbounds %Foo, %Foo* %x, i32 0, i32 0 + %66 = load i32, i32* %a51, align 4 + %sisiext52 = sext i32 %66 to i64 + %67 = getelementptr inbounds [3 x i32], [3 x i32]* %65, i64 0, i64 %sisiext52 + %68 = load i32, i32* %67, align 4 + store i32 %68, i32* %y50, align 4 + %69 = load i32, i32* %i49, align 4 + %70 = load i32, i32* %y50, align 4 + call void (i8*, ...) @printf(i8* getelementptr inbounds ([15 x i8], [15 x i8]* @.str.7, i32 0, i32 0), i32 %69, i32 %70) + %71 = load i32, i32* %i49, align 4 + %add53 = add i32 %71, 1 + store i32 %add53, i32* %i49, align 4 + br label %for.inc54 + +for.inc54: ; preds = %for.body48 + %72 = load i32, i32* %"__idx$44", align 4 + %add55 = add i32 %72, 1 + store i32 %add55, i32* %"__idx$44", align 4 + br label %for.cond46 + +for.exit56: ; preds = %for.cond46 + store i64 0, i64* %"__idx$57", align 8 + %73 = bitcast [5 x i32]* %"__enum$58" to i8* + call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 16 %73, i8* align 16 bitcast ([5 x i32]* @.__const.8 to i8*), i32 20, i1 false) + br label %for.cond59 + +for.cond59: ; preds = %for.inc64, %for.exit56 + %74 = load i64, i64* %"__idx$57", align 8 + %gt = icmp ugt i64 5, %74 + br i1 %gt, label %for.body60, label %for.exit66 + +for.body60: ; preds = %for.cond59 + %75 = load i64, i64* %"__idx$57", align 8 + store i64 %75, i64* %i61, align 8 + %76 = load i64, i64* %"__idx$57", align 8 + %77 = getelementptr inbounds [5 x i32], [5 x i32]* %"__enum$58", i64 0, i64 %76 + %78 = load i32, i32* %77, align 4 + store i32 %78, i32* %y62, align 4 + %79 = load i64, i64* %i61, align 8 + %80 = load i32, i32* %y62, align 4 + call void (i8*, ...) @printf(i8* getelementptr inbounds ([15 x i8], [15 x i8]* @.str.9, i32 0, i32 0), i64 %79, i32 %80) + %81 = load i64, i64* %i61, align 8 + %add63 = add i64 %81, 1 + store i64 %add63, i64* %i61, align 8 + br label %for.inc64 + +for.inc64: ; preds = %for.body60 + %82 = load i64, i64* %"__idx$57", align 8 + %add65 = add i64 %82, 1 + store i64 %add65, i64* %"__idx$57", align 8 + br label %for.cond59 + +for.exit66: ; preds = %for.cond59 + store i64 0, i64* %"__idx$67", align 8 + call void @foo.getFields([5 x i32]* sret([5 x i32]) align 4 %sretparam) + %83 = bitcast [5 x i32]* %"__enum$68" to i8* + %84 = bitcast [5 x i32]* %sretparam to i8* + call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 16 %83, i8* align 4 %84, i32 20, i1 false) + br label %for.cond69 + +for.cond69: ; preds = %for.inc74, %for.exit66 + %85 = load i64, i64* %"__idx$67", align 8 + %gt70 = icmp ugt i64 5, %85 + br i1 %gt70, label %for.body71, label %for.exit76 + +for.body71: ; preds = %for.cond69 + %86 = load i64, i64* %"__idx$67", align 8 + store i64 %86, i64* %i72, align 8 + %87 = load i64, i64* %"__idx$67", align 8 + %88 = getelementptr inbounds [5 x i32], [5 x i32]* %"__enum$68", i64 0, i64 %87 + %89 = load i32, i32* %88, align 4 + store i32 %89, i32* %y73, align 4 + %90 = load i64, i64* %i72, align 8 + %91 = load i32, i32* %y73, align 4 + call void (i8*, ...) @printf(i8* getelementptr inbounds ([19 x i8], [19 x i8]* @.str.10, i32 0, i32 0), i64 %90, i32 %91) + br label %for.inc74 + +for.inc74: ; preds = %for.body71 + %92 = load i64, i64* %"__idx$67", align 8 + %add75 = add i64 %92, 1 + store i64 %add75, i64* %"__idx$67", align 8 + br label %for.cond69 + +for.exit76: ; preds = %for.cond69 + store i64 0, i64* %"__idx$77", align 8 + call void @foo.getFields([5 x i32]* sret([5 x i32]) align 4 %sretparam79) + store [5 x i32]* %sretparam79, [5 x i32]** %"__enum$78", align 8 + br label %for.cond80 + +for.cond80: ; preds = %for.inc85, %for.exit76 + %93 = load i64, i64* %"__idx$77", align 8 + %gt81 = icmp ugt i64 5, %93 + br i1 %gt81, label %for.body82, label %for.exit87 + +for.body82: ; preds = %for.cond80 + %94 = load i64, i64* %"__idx$77", align 8 + store i64 %94, i64* %i83, align 8 + %95 = load [5 x i32]*, [5 x i32]** %"__enum$78", align 8 + %96 = load i64, i64* %"__idx$77", align 8 + %97 = getelementptr inbounds [5 x i32], [5 x i32]* %95, i64 0, i64 %96 + %98 = load i32, i32* %97, align 4 + store i32 %98, i32* %y84, align 4 + %99 = load i64, i64* %i83, align 8 + %100 = load i32, i32* %y84, align 4 + call void (i8*, ...) @printf(i8* getelementptr inbounds ([27 x i8], [27 x i8]* @.str.11, i32 0, i32 0), i64 %99, i32 %100) + br label %for.inc85 + +for.inc85: ; preds = %for.body82 + %101 = load i64, i64* %"__idx$77", align 8 + %add86 = add i64 %101, 1 + store i64 %add86, i64* %"__idx$77", align 8 + br label %for.cond80 + +for.exit87: ; preds = %for.cond80 + store i32 0, i32* %a88, align 4 + %102 = getelementptr inbounds %Foo, %Foo* %x, i32 0, i32 0 + %103 = load i32, i32* %a88, align 4 + %sisiext89 = sext i32 %103 to i64 + %104 = getelementptr inbounds [3 x i32], [3 x i32]* %102, i64 0, i64 %sisiext89 + %105 = load i32, i32* %104, align 4 + store i32 1, i32* %a90, align 4 + %106 = getelementptr inbounds %Foo, %Foo* %x, i32 0, i32 0 + %107 = load i32, i32* %a90, align 4 + %sisiext91 = sext i32 %107 to i64 + %108 = getelementptr inbounds [3 x i32], [3 x i32]* %106, i64 0, i64 %sisiext91 + %109 = load i32, i32* %108, align 4 + call void (i8*, ...) @printf(i8* getelementptr inbounds ([7 x i8], [7 x i8]* @.str.12, i32 0, i32 0), i32 %105, i32 %109) + store i32 1, i32* %a93, align 4 + %110 = getelementptr inbounds %Foo, %Foo* %x, i32 0, i32 0 + %111 = load i32, i32* %a93, align 4 + %sisiext94 = sext i32 %111 to i64 + %112 = getelementptr inbounds [3 x i32], [3 x i32]* %110, i64 0, i64 %sisiext94 + store i32* %112, i32** %y92, align 8 + %113 = load i32*, i32** %y92, align 8 + %114 = load i32, i32* %113, align 8 + %add95 = add i32 %114, 1 + store i32 %add95, i32* %113, align 8 + store i32 0, i32* %a96, align 4 + %115 = getelementptr inbounds %Foo, %Foo* %x, i32 0, i32 0 + %116 = load i32, i32* %a96, align 4 + %sisiext97 = sext i32 %116 to i64 + %117 = getelementptr inbounds [3 x i32], [3 x i32]* %115, i64 0, i64 %sisiext97 + %118 = load i32, i32* %117, align 4 + store i32 1, i32* %a98, align 4 + %119 = getelementptr inbounds %Foo, %Foo* %x, i32 0, i32 0 + %120 = load i32, i32* %a98, align 4 + %sisiext99 = sext i32 %120 to i64 + %121 = getelementptr inbounds [3 x i32], [3 x i32]* %119, i64 0, i64 %sisiext99 + %122 = load i32, i32* %121, align 4 + call void (i8*, ...) @printf(i8* getelementptr inbounds ([7 x i8], [7 x i8]* @.str.13, i32 0, i32 0), i32 %118, i32 %122) + ret void +} diff --git a/test/test_suite/statements/foreach_break.c3t b/test/test_suite/statements/foreach_break.c3t index d09b8398b..0703d737a 100644 --- a/test/test_suite/statements/foreach_break.c3t +++ b/test/test_suite/statements/foreach_break.c3t @@ -19,7 +19,7 @@ define void @test.test() #0 { entry: %x = alloca [3 x i32], align 4 %g = alloca i32, align 4 - %idx = alloca i64, align 8 + %"__idx$" = 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 @@ -28,46 +28,47 @@ entry: %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 0, i64* %idx, align 8 - br label %foreach.cond + store i64 0, i64* %"__idx$", align 8 + br label %for.cond -foreach.cond: ; preds = %foreach.inc, %entry - %3 = load i64, i64* %idx, align 8 - %lt = icmp ult i64 %3, 3 - br i1 %lt, label %foreach.body, label %foreach.exit +for.cond: ; preds = %for.inc, %entry + %3 = load i64, i64* %"__idx$", align 8 + %gt = icmp ugt i64 3, %3 + br i1 %gt, label %for.body, label %for.exit -foreach.body: ; preds = %foreach.cond - %4 = getelementptr inbounds [3 x i32], [3 x i32]* %x, i64 0, i64 %3 - %5 = load i32, i32* %4, align 4 - store i32 %5, i32* %z, align 4 - %6 = load i32, i32* %z, align 4 - %gt = icmp sgt i32 %6, 0 - br i1 %gt, label %if.then, label %if.exit - -if.then: ; preds = %foreach.body - br label %foreach.exit - -if.exit: ; preds = %foreach.body +for.body: ; preds = %for.cond + %4 = load i64, i64* %"__idx$", align 8 + %5 = getelementptr inbounds [3 x i32], [3 x i32]* %x, i64 0, i64 %4 + %6 = load i32, i32* %5, align 4 + store i32 %6, i32* %z, align 4 %7 = load i32, i32* %z, align 4 - %eq = icmp eq i32 %7, 1 - br i1 %eq, label %if.then1, label %if.exit2 + %gt1 = icmp sgt i32 %7, 0 + br i1 %gt1, label %if.then, label %if.exit -if.then1: ; preds = %if.exit - br label %foreach.inc +if.then: ; preds = %for.body + br label %for.exit -if.exit2: ; preds = %if.exit - %8 = load i32, i32* %g, align 4 - %9 = load i32, i32* %z, align 4 - %add = add i32 %8, %9 +if.exit: ; preds = %for.body + %8 = load i32, i32* %z, align 4 + %eq = icmp eq i32 %8, 1 + br i1 %eq, label %if.then2, label %if.exit3 + +if.then2: ; preds = %if.exit + br label %for.inc + +if.exit3: ; preds = %if.exit + %9 = load i32, i32* %g, align 4 + %10 = load i32, i32* %z, align 4 + %add = add i32 %9, %10 store i32 %add, i32* %g, align 4 - br label %foreach.inc + br label %for.inc -foreach.inc: ; preds = %if.exit2, %if.then1 - %10 = load i64, i64* %idx, align 8 - %11 = add i64 %10, 1 - store i64 %11, i64* %idx, align 8 - br label %foreach.cond +for.inc: ; preds = %if.exit3, %if.then2 + %11 = load i64, i64* %"__idx$", align 8 + %add4 = add i64 %11, 1 + store i64 %add4, i64* %"__idx$", align 8 + br label %for.cond -foreach.exit: ; preds = %if.then, %foreach.cond +for.exit: ; preds = %if.then, %for.cond ret void } \ No newline at end of file diff --git a/test/test_suite/statements/foreach_common.c3t b/test/test_suite/statements/foreach_common.c3t index a040bbfc9..33595c4c9 100644 --- a/test/test_suite/statements/foreach_common.c3t +++ b/test/test_suite/statements/foreach_common.c3t @@ -1,3 +1,4 @@ +// #target: x64-darwin module test; extern fn void printf(char*, ...); @@ -36,176 +37,185 @@ fn void main() entry: %foo = alloca [3 x float], align 4 - %idx = alloca i64, align 8 + %"__idx$" = alloca i64, align 8 %a = alloca float, align 4 - %idx1 = alloca i64, align 8 - %a2 = alloca float*, align 8 - %idx9 = alloca i64, align 8 - %a10 = alloca i8*, align 8 + %"__idx$1" = alloca i64, align 8 + %a5 = alloca float*, align 8 + %"__idx$10" = alloca i64, align 8 + %a14 = alloca i8*, align 8 + %"__idx$20" = alloca i64, align 8 %i = alloca i64, align 8 - %a18 = alloca float, align 4 - %i25 = alloca i8, align 1 - %idx26 = alloca i64, align 8 - %a27 = alloca double, align 8 - %idx34 = alloca i64, align 8 - %a35 = alloca double, align 8 + %a24 = alloca float, align 4 + %"__idx$29" = alloca i64, align 8 + %i33 = alloca i8, align 1 + %a34 = alloca double, align 8 + %"__idx$39" = alloca i64, align 8 + %a43 = 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 i64 0, i64* %idx, align 8 - br label %foreach.cond + store i64 0, i64* %"__idx$", align 8 + br label %for.cond -foreach.cond: ; preds = %foreach.inc, %entry - %1 = load i64, i64* %idx, align 8 - %lt = icmp ult i64 %1, 3 - br i1 %lt, label %foreach.body, label %foreach.exit +for.cond: ; preds = %for.inc, %entry + %1 = load i64, i64* %"__idx$", align 8 + %gt = icmp ugt i64 3, %1 + br i1 %gt, label %for.body, label %for.exit -foreach.body: ; preds = %foreach.cond - %2 = getelementptr inbounds [3 x float], [3 x float]* %foo, i64 0, i64 %1 - %3 = load float, float* %2, align 4 - store float %3, float* %a, align 4 - %4 = load float, float* %a, align 4 - %fpfpext = fpext float %4 to double +for.body: ; preds = %for.cond + %2 = load i64, i64* %"__idx$", align 8 + %3 = getelementptr inbounds [3 x float], [3 x float]* %foo, i64 0, i64 %2 + %4 = load float, float* %3, align 4 + store float %4, float* %a, align 4 + %5 = load float, float* %a, align 4 + %fpfpext = fpext float %5 to double call void (i8*, ...) @printf(i8* getelementptr inbounds ([11 x i8], [11 x i8]* @.str, i32 0, i32 0), double %fpfpext) - br label %foreach.inc + br label %for.inc -foreach.inc: ; preds = %foreach.body - %5 = load i64, i64* %idx, align 8 - %6 = add i64 %5, 1 - store i64 %6, i64* %idx, align 8 - br label %foreach.cond +for.inc: ; preds = %for.body + %6 = load i64, i64* %"__idx$", align 8 + %add = add i64 %6, 1 + store i64 %add, i64* %"__idx$", align 8 + br label %for.cond -foreach.exit: ; preds = %foreach.cond - store i64 0, i64* %idx1, align 8 - br label %foreach.cond3 +for.exit: ; preds = %for.cond + store i64 0, i64* %"__idx$1", align 8 + br label %for.cond2 -foreach.cond3: ; preds = %foreach.inc7, %foreach.exit - %7 = load i64, i64* %idx1, align 8 - %lt4 = icmp ult i64 %7, 3 - br i1 %lt4, label %foreach.body5, label %foreach.exit8 +for.cond2: ; preds = %for.inc7, %for.exit + %7 = load i64, i64* %"__idx$1", align 8 + %gt3 = icmp ugt i64 3, %7 + br i1 %gt3, label %for.body4, label %for.exit9 -foreach.body5: ; preds = %foreach.cond3 - %8 = getelementptr inbounds [3 x float], [3 x float]* %foo, i64 0, i64 %7 - store float* %8, float** %a2, align 8 - %9 = load float*, float** %a2, align 8 - %10 = load float, float* %9, align 8 - %fmul = fmul float %10, 2.000000e+00 - store float %fmul, float* %9, align 8 - %11 = load float*, float** %a2, align 8 - %12 = load float, float* %11, align 8 - %fpfpext6 = fpext float %12 to double +for.body4: ; preds = %for.cond2 + %8 = load i64, i64* %"__idx$1", align 8 + %9 = getelementptr inbounds [3 x float], [3 x float]* %foo, i64 0, i64 %8 + store float* %9, float** %a5, align 8 + %10 = load float*, float** %a5, align 8 + %11 = load float, float* %10, align 8 + %fmul = fmul float %11, 2.000000e+00 + store float %fmul, float* %10, align 8 + %12 = load float*, float** %a5, align 8 + %13 = load float, float* %12, align 8 + %fpfpext6 = fpext float %13 to double call void (i8*, ...) @printf(i8* getelementptr inbounds ([11 x i8], [11 x i8]* @.str.1, i32 0, i32 0), double %fpfpext6) - br label %foreach.inc7 + br label %for.inc7 -foreach.inc7: ; preds = %foreach.body5 - %13 = load i64, i64* %idx1, align 8 - %14 = add i64 %13, 1 - store i64 %14, i64* %idx1, align 8 - br label %foreach.cond3 +for.inc7: ; preds = %for.body4 + %14 = load i64, i64* %"__idx$1", align 8 + %add8 = add i64 %14, 1 + store i64 %add8, i64* %"__idx$1", align 8 + br label %for.cond2 -foreach.exit8: ; preds = %foreach.cond3 - store i64 0, i64* %idx9, align 8 - br label %foreach.cond11 +for.exit9: ; preds = %for.cond2 + store i64 0, i64* %"__idx$10", align 8 + br label %for.cond11 -foreach.cond11: ; preds = %foreach.inc16, %foreach.exit8 - %15 = load i64, i64* %idx9, align 8 - %lt12 = icmp ult i64 %15, 3 - br i1 %lt12, label %foreach.body13, label %foreach.exit17 +for.cond11: ; preds = %for.inc17, %for.exit9 + %15 = load i64, i64* %"__idx$10", align 8 + %gt12 = icmp ugt i64 3, %15 + br i1 %gt12, label %for.body13, label %for.exit19 -foreach.body13: ; preds = %foreach.cond11 - %16 = getelementptr inbounds [3 x float], [3 x float]* %foo, i64 0, i64 %15 - %ptrptr = bitcast float* %16 to i8* - store i8* %ptrptr, i8** %a10, align 8 - %17 = load i8*, i8** %a10, align 8 - %ptrptr14 = bitcast i8* %17 to float* - %18 = load float, float* %ptrptr14, align 8 - %fpfpext15 = fpext float %18 to double - call void (i8*, ...) @printf(i8* getelementptr inbounds ([11 x i8], [11 x i8]* @.str.2, i32 0, i32 0), double %fpfpext15) - br label %foreach.inc16 +for.body13: ; preds = %for.cond11 + %16 = load i64, i64* %"__idx$10", align 8 + %17 = getelementptr inbounds [3 x float], [3 x float]* %foo, i64 0, i64 %16 + %ptrptr = bitcast float* %17 to i8* + store i8* %ptrptr, i8** %a14, align 8 + %18 = load i8*, i8** %a14, align 8 + %ptrptr15 = bitcast i8* %18 to float* + %19 = load float, float* %ptrptr15, align 8 + %fpfpext16 = fpext float %19 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 %for.inc17 -foreach.inc16: ; preds = %foreach.body13 - %19 = load i64, i64* %idx9, align 8 - %20 = add i64 %19, 1 - store i64 %20, i64* %idx9, align 8 - br label %foreach.cond11 +for.inc17: ; preds = %for.body13 + %20 = load i64, i64* %"__idx$10", align 8 + %add18 = add i64 %20, 1 + store i64 %add18, i64* %"__idx$10", align 8 + br label %for.cond11 -foreach.exit17: ; preds = %foreach.cond11 - store i64 0, i64* %i, align 8 - br label %foreach.cond19 +for.exit19: ; preds = %for.cond11 + store i64 0, i64* %"__idx$20", align 8 + br label %for.cond21 -foreach.cond19: ; preds = %foreach.inc23, %foreach.exit17 - %21 = load i64, i64* %i, align 8 - %lt20 = icmp ult i64 %21, 3 - br i1 %lt20, label %foreach.body21, label %foreach.exit24 +for.cond21: ; preds = %for.inc26, %for.exit19 + %21 = load i64, i64* %"__idx$20", align 8 + %gt22 = icmp ugt i64 3, %21 + br i1 %gt22, label %for.body23, label %for.exit28 -foreach.body21: ; preds = %foreach.cond19 - %22 = getelementptr inbounds [3 x float], [3 x float]* %foo, i64 0, i64 %21 - %23 = load float, float* %22, align 4 - store float %23, float* %a18, align 4 - %24 = load i64, i64* %i, align 8 - %25 = load float, float* %a18, align 4 - %fpfpext22 = fpext float %25 to double - call void (i8*, ...) @printf(i8* getelementptr inbounds ([15 x i8], [15 x i8]* @.str.3, i32 0, i32 0), i64 %24, double %fpfpext22) - br label %foreach.inc23 - -foreach.inc23: ; preds = %foreach.body21 +for.body23: ; preds = %for.cond21 + %22 = load i64, i64* %"__idx$20", align 8 + store i64 %22, i64* %i, align 8 + %23 = load i64, i64* %"__idx$20", align 8 + %24 = getelementptr inbounds [3 x float], [3 x float]* %foo, i64 0, i64 %23 + %25 = load float, float* %24, align 4 + store float %25, float* %a24, align 4 %26 = load i64, i64* %i, align 8 - %27 = add i64 %26, 1 - store i64 %27, i64* %i, align 8 - br label %foreach.cond19 + %27 = load float, float* %a24, align 4 + %fpfpext25 = fpext float %27 to double + call void (i8*, ...) @printf(i8* getelementptr inbounds ([15 x i8], [15 x i8]* @.str.3, i32 0, i32 0), i64 %26, double %fpfpext25) + br label %for.inc26 -foreach.exit24: ; preds = %foreach.cond19 - store i8 0, i8* %i25, align 1 - store i64 0, i64* %idx26, align 8 - br label %foreach.cond28 +for.inc26: ; preds = %for.body23 + %28 = load i64, i64* %"__idx$20", align 8 + %add27 = add i64 %28, 1 + store i64 %add27, i64* %"__idx$20", align 8 + br label %for.cond21 -foreach.cond28: ; preds = %foreach.inc32, %foreach.exit24 - %28 = load i64, i64* %idx26, align 8 - %lt29 = icmp ult i64 %28, 3 - br i1 %lt29, label %foreach.body30, label %foreach.exit33 +for.exit28: ; preds = %for.cond21 + store i64 0, i64* %"__idx$29", align 8 + br label %for.cond30 -foreach.body30: ; preds = %foreach.cond28 - %29 = trunc i64 %28 to i8 - store i8 %29, i8* %i25, align 1 - %30 = getelementptr inbounds [3 x float], [3 x float]* %foo, i64 0, i64 %28 - %31 = load float, float* %30, align 4 - %fpfpext31 = fpext float %31 to double - store double %fpfpext31, double* %a27, align 8 - %32 = load i8, i8* %i25, align 1 - %uisiext = zext i8 %32 to i32 - %33 = load double, double* %a27, align 8 - call void (i8*, ...) @printf(i8* getelementptr inbounds ([16 x i8], [16 x i8]* @.str.4, i32 0, i32 0), i32 %uisiext, double %33) - br label %foreach.inc32 +for.cond30: ; preds = %for.inc36, %for.exit28 + %29 = load i64, i64* %"__idx$29", align 8 + %gt31 = icmp ugt i64 3, %29 + br i1 %gt31, label %for.body32, label %for.exit38 -foreach.inc32: ; preds = %foreach.body30 - %34 = load i64, i64* %idx26, align 8 - %35 = add i64 %34, 1 - store i64 %35, i64* %idx26, align 8 - br label %foreach.cond28 +for.body32: ; preds = %for.cond30 + %30 = load i64, i64* %"__idx$29", align 8 + %uiuitrunc = trunc i64 %30 to i8 + store i8 %uiuitrunc, i8* %i33, align 1 + %31 = load i64, i64* %"__idx$29", align 8 + %32 = getelementptr inbounds [3 x float], [3 x float]* %foo, i64 0, i64 %31 + %33 = load float, float* %32, align 4 + %fpfpext35 = fpext float %33 to double + store double %fpfpext35, double* %a34, align 8 + %34 = load i8, i8* %i33, align 1 + %uisiext = zext i8 %34 to i32 + %35 = load double, double* %a34, align 8 + call void (i8*, ...) @printf(i8* getelementptr inbounds ([16 x i8], [16 x i8]* @.str.4, i32 0, i32 0), i32 %uisiext, double %35) + br label %for.inc36 -foreach.exit33: ; preds = %foreach.cond28 - store i64 0, i64* %idx34, align 8 - br label %foreach.cond36 +for.inc36: ; preds = %for.body32 + %36 = load i64, i64* %"__idx$29", align 8 + %add37 = add i64 %36, 1 + store i64 %add37, i64* %"__idx$29", align 8 + br label %for.cond30 -foreach.cond36: ; preds = %foreach.inc40, %foreach.exit33 - %36 = load i64, i64* %idx34, align 8 - %lt37 = icmp ult i64 %36, 3 - br i1 %lt37, label %foreach.body38, label %foreach.exit41 +for.exit38: ; preds = %for.cond30 + store i64 0, i64* %"__idx$39", align 8 + br label %for.cond40 -foreach.body38: ; preds = %foreach.cond36 - %37 = getelementptr inbounds [3 x float], [3 x float]* %foo, i64 0, i64 %36 - %38 = load float, float* %37, align 4 - %fpfpext39 = fpext float %38 to double - store double %fpfpext39, double* %a35, align 8 - %39 = load double, double* %a35, align 8 - call void (i8*, ...) @printf(i8* getelementptr inbounds ([12 x i8], [12 x i8]* @.str.5, i32 0, i32 0), double %39) - br label %foreach.inc40 +for.cond40: ; preds = %for.inc45, %for.exit38 + %37 = load i64, i64* %"__idx$39", align 8 + %gt41 = icmp ugt i64 3, %37 + br i1 %gt41, label %for.body42, label %for.exit47 -foreach.inc40: ; preds = %foreach.body38 - %40 = load i64, i64* %idx34, align 8 - %41 = add i64 %40, 1 - store i64 %41, i64* %idx34, align 8 - br label %foreach.cond36 +for.body42: ; preds = %for.cond40 + %38 = load i64, i64* %"__idx$39", align 8 + %39 = getelementptr inbounds [3 x float], [3 x float]* %foo, i64 0, i64 %38 + %40 = load float, float* %39, align 4 + %fpfpext44 = fpext float %40 to double + store double %fpfpext44, double* %a43, align 8 + %41 = load double, double* %a43, align 8 + call void (i8*, ...) @printf(i8* getelementptr inbounds ([12 x i8], [12 x i8]* @.str.5, i32 0, i32 0), double %41) + br label %for.inc45 -foreach.exit41: ; preds = %foreach.cond36 +for.inc45: ; preds = %for.body42 + %42 = load i64, i64* %"__idx$39", align 8 + %add46 = add i64 %42, 1 + store i64 %add46, i64* %"__idx$39", align 8 + br label %for.cond40 + +for.exit47: ; preds = %for.cond40 ret void } \ No newline at end of file diff --git a/test/test_suite/statements/foreach_custom.c3t b/test/test_suite/statements/foreach_custom.c3t index 9ade5d4f9..91f695897 100644 --- a/test/test_suite/statements/foreach_custom.c3t +++ b/test/test_suite/statements/foreach_custom.c3t @@ -6,21 +6,14 @@ struct Foo int[] x; } -struct FooIterator +macro int Foo.operator_element_at(Foo &foo, usize index) { - usize index; - Foo *f; -} -fn FooIterator Foo.iterator(Foo *f) -{ - return FooIterator {0, f}; + return foo.x[index]; } -fn bool FooIterator.next(FooIterator *it, int *value) +macro usize Foo.operator_len(Foo &foo) { - if (it.index == it.f.x.len) return false; - *value = it.f.x[it.index++]; - return true; + return foo.x.len; } fn void main() @@ -40,73 +33,15 @@ extern fn int printf(char *fmt, ...); // #expect: foo.ll -define { i64, %Foo* } @foo.Foo__iterator(%Foo* %0) -entry: - %f = alloca %Foo*, align 8 - %literal = alloca %FooIterator, align 8 - %tempcoerce = alloca { i64, %Foo* }, align 8 - store %Foo* %0, %Foo** %f, align 8 - %1 = getelementptr inbounds %FooIterator, %FooIterator* %literal, i32 0, i32 0 - store i64 0, i64* %1, align 8 - %2 = getelementptr inbounds %FooIterator, %FooIterator* %literal, i32 0, i32 1 - %3 = load %Foo*, %Foo** %f, align 8 - store %Foo* %3, %Foo** %2, align 8 - %4 = bitcast { i64, %Foo* }* %tempcoerce to i8* - %5 = bitcast %FooIterator* %literal to i8* - call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 8 %4, i8* align 8 %5, i32 16, i1 false) - %6 = load { i64, %Foo* }, { i64, %Foo* }* %tempcoerce, align 8 - ret { i64, %Foo* } %6 -} - -; Function Attrs: nounwind -define zeroext i8 @foo.FooIterator__next(%FooIterator* %0, i32* %1) #0 { -entry: - %it = alloca %FooIterator*, align 8 - %value = alloca i32*, align 8 - store %FooIterator* %0, %FooIterator** %it, align 8 - store i32* %1, i32** %value, align 8 - %2 = load %FooIterator*, %FooIterator** %it, align 8 - %3 = getelementptr inbounds %FooIterator, %FooIterator* %2, i32 0, i32 0 - %4 = load i64, i64* %3, align 8 - %5 = load %FooIterator*, %FooIterator** %it, align 8 - %6 = getelementptr inbounds %FooIterator, %FooIterator* %5, i32 0, i32 1 - %7 = load %Foo*, %Foo** %6, align 8 - %8 = getelementptr inbounds %Foo, %Foo* %7, i32 0, i32 0 - %9 = getelementptr inbounds %"int[]", %"int[]"* %8, i32 0, i32 1 - %10 = load i64, i64* %9, align 8 - %eq = icmp eq i64 %4, %10 - br i1 %eq, label %if.then, label %if.exit - -if.then: ; preds = %entry - ret i8 0 - -if.exit: ; preds = %entry - %11 = load i32*, i32** %value, align 8 - %12 = load %FooIterator*, %FooIterator** %it, align 8 - %13 = getelementptr inbounds %FooIterator, %FooIterator* %12, i32 0, i32 1 - %14 = load %Foo*, %Foo** %13, align 8 - %15 = getelementptr inbounds %Foo, %Foo* %14, i32 0, i32 0 - %16 = getelementptr inbounds %"int[]", %"int[]"* %15, i32 0, i32 0 - %17 = load i32*, i32** %16, align 8 - %18 = load %FooIterator*, %FooIterator** %it, align 8 - %19 = getelementptr inbounds %FooIterator, %FooIterator* %18, i32 0, i32 0 - %20 = load i64, i64* %19, align 8 - %add = add i64 %20, 1 - store i64 %add, i64* %19, align 8 - %ptroffset = getelementptr inbounds i32, i32* %17, i64 %20 - %21 = load i32, i32* %ptroffset, align 4 - store i32 %21, i32* %11, align 8 - ret i8 1 -} - ; Function Attrs: nounwind define void @main() #0 { entry: %i = alloca [3 x i32], align 4 %x = alloca %Foo, align 8 + %"__idx$" = alloca i64, align 8 + %"__len$" = alloca i64, align 8 %f = alloca i32, align 4 - %.iterator = alloca %FooIterator, align 8 - %result = alloca %FooIterator, align 8 + %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 @@ -114,23 +49,31 @@ entry: %3 = insertvalue %"int[]" undef, i32* %2, 0 %4 = insertvalue %"int[]" %3, i64 3, 1 store %"int[]" %4, %"int[]"* %1, align 8 - store i32 0, i32* %f, align 4 - %5 = call { i64, %Foo* } @foo.Foo__iterator(%Foo* %x) - %6 = bitcast %FooIterator* %result to { i64, %Foo* }* - store { i64, %Foo* } %5, { i64, %Foo* }* %6, align 8 - %7 = bitcast %FooIterator* %.iterator to i8* - %8 = bitcast %FooIterator* %result to i8* - call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 8 %7, i8* align 8 %8, i32 16, i1 false) + store i64 0, i64* %"__idx$", 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* %"__len$", align 8 br label %for.cond for.cond: ; preds = %entry - %9 = call i8 @foo.FooIterator__next(%FooIterator* %.iterator, i32* %f) - %10 = trunc i8 %9 to i1 - br i1 %10, label %for.body, label %for.exit + %8 = load i64, i64* %"__idx$", align 8 + %9 = load i64, i64* %"__len$", align 8 + %lt = icmp ult i64 %8, %9 + br i1 %lt, label %for.body, label %for.exit for.body: ; preds = %for.cond - %11 = load i32, i32* %f, align 4 - %12 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i32 0, i32 0), i32 %11) + %10 = load i64, i64* %"__idx$", 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 %while.begin while.begin: ; preds = %for.body diff --git a/test/test_suite/statements/foreach_custom_errors.c3 b/test/test_suite/statements/foreach_custom_errors.c3 index 8c067e4b8..e98d72275 100644 --- a/test/test_suite/statements/foreach_custom_errors.c3 +++ b/test/test_suite/statements/foreach_custom_errors.c3 @@ -10,69 +10,7 @@ define Test1 = distinct int; fn void test2() { Test1 x; - foreach (a : x) { }; // #error: This type cannot be iterated over, implement a method or method macro called 'iterator' + foreach (a : x) { }; // #error: This type cannot be iterated over, implement a method or method macro called 'iteratofefer' } -struct Test3 -{} - -fn void Test3.iterator(Test3* x, int y) { } - -fn void test3() -{ - Test3 x; - foreach (a : x) { }; // #error: 'iterator()' takes parameters and can't be used for 'foreach'. -} - -struct Test4 -{} - -macro Test4.iterator(Test4* x) { } - -fn void test4() -{ - Test4 x; - foreach (a : x) { }; // #error: This type has an iterator without a declared result type, this can't be used with 'foreach' -} - -struct Test5 -{} - -fn int Test5.iterator(Test5* x) { return 1; } - -fn void test5() -{ - Test5 x; - foreach (a : x) { }; // #error: This type has an implementation of 'iterator()' that doesn't return a struct, so it can't be used with 'foreach' -} - -struct Test6 -{} - -fn TestIterator6 Test6.iterator(Test6* x) { return TestIterator6{}; } - -struct TestIterator6 -{} - -fn void test6() -{ - Test6 x; - foreach (a : x) { }; // #error: The iterator 'TestIterator6' is missing a definition for 'next()' -} - -struct Test7 -{} - -fn TestIterator7 Test7.iterator(Test7* x) { return TestIterator7{}; } - -struct TestIterator7 -{} - -fn bool TestIterator7.next(TestIterator7* x, int a, int b) { return true; } - -fn void test7() -{ - Test7 x; - foreach (a : x) { }; // #error: An iterator with a 'next()' that take takes 2 parameters can't be used for 'foreach', it should have 1. -} diff --git a/test/test_suite/statements/foreach_custom_macro.c3t b/test/test_suite/statements/foreach_custom_macro.c3t index 4a603fb2e..3c4127b58 100644 --- a/test/test_suite/statements/foreach_custom_macro.c3t +++ b/test/test_suite/statements/foreach_custom_macro.c3t @@ -1,25 +1,18 @@ -// #skip +// #target: x64-darwin module foo; struct Foo { int[] x; } -struct FooIterator +macro int Foo.operator_element_at(Foo &foo, usize index) { - usize index; - Foo *f; -} -macro FooIterator Foo.iterator(Foo &f) -{ - return FooIterator { 0, &f }; + return foo.x[index]; } -macro bool FooIterator.next(FooIterator &it, int *value) +macro usize Foo.operator_len(Foo &foo) { - if (it.index == it.f.x.len) return false; - *value = it.f.x[it.index++]; - return true; + return foo.x.len; } fn void main() @@ -43,13 +36,10 @@ define void @main() #0 { entry: %i = alloca [3 x i32], align 4 %x = alloca %Foo, align 8 + %"__idx$" = alloca i64, align 8 + %"__len$" = alloca i64, align 8 %f = alloca i32, align 4 - %.iterator = alloca %FooIterator, align 8 - %f1 = alloca %Foo*, align 8 - %literal = alloca %FooIterator, align 8 - %it = alloca %FooIterator*, align 8 - %value = alloca i32*, align 8 - %blockret = alloca i8, align 1 + %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 @@ -57,69 +47,36 @@ entry: %3 = insertvalue %"int[]" undef, i32* %2, 0 %4 = insertvalue %"int[]" %3, i64 3, 1 store %"int[]" %4, %"int[]"* %1, align 8 - store i32 0, i32* %f, align 4 - store %Foo* %x, %Foo** %f1, align 8 - %5 = getelementptr inbounds %FooIterator, %FooIterator* %literal, i32 0, i32 0 - store i64 0, i64* %5, align 8 - %6 = getelementptr inbounds %FooIterator, %FooIterator* %literal, i32 0, i32 1 - %7 = load %Foo*, %Foo** %f1, align 8 - store %Foo* %7, %Foo** %6, align 8 - %8 = bitcast %FooIterator* %.iterator to i8* - %9 = bitcast %FooIterator* %literal to i8* - call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 8 %8, i8* align 8 %9, i32 16, i1 false) + store i64 0, i64* %"__idx$", 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* %"__len$", align 8 br label %for.cond for.cond: ; preds = %entry - store %FooIterator* %.iterator, %FooIterator** %it, align 8 - store i32* %f, i32** %value, align 8 - %10 = load %FooIterator*, %FooIterator** %it, align 8 - %11 = getelementptr inbounds %FooIterator, %FooIterator* %10, i32 0, i32 0 - %12 = load i64, i64* %11, align 8 - %13 = load %FooIterator*, %FooIterator** %it, align 8 - %14 = getelementptr inbounds %FooIterator, %FooIterator* %13, i32 0, i32 1 - %15 = load %Foo*, %Foo** %14, align 8 - %16 = getelementptr inbounds %Foo, %Foo* %15, i32 0, i32 0 - %17 = getelementptr inbounds %"int[]", %"int[]"* %16, i32 0, i32 1 - %18 = load i64, i64* %17, align 8 - %eq = icmp eq i64 %12, %18 - br i1 %eq, label %if.then, label %if.exit + %8 = load i64, i64* %"__idx$", align 8 + %9 = load i64, i64* %"__len$", align 8 + %lt = icmp ult i64 %8, %9 + br i1 %lt, label %for.body, label %for.exit -if.then: ; preds = %for.cond - store i8 0, i8* %blockret, align 1 - br label %expr_block.exit - -if.exit: ; preds = %for.cond - %19 = load i32*, i32** %value, align 8 - %20 = load %FooIterator*, %FooIterator** %it, align 8 - %21 = getelementptr inbounds %FooIterator, %FooIterator* %20, i32 0, i32 1 - %22 = load %Foo*, %Foo** %21, align 8 - %23 = getelementptr inbounds %Foo, %Foo* %22, i32 0, i32 0 - %24 = getelementptr inbounds %"int[]", %"int[]"* %23, i32 0, i32 0 - %25 = load i32*, i32** %24, align 8 - %26 = load %FooIterator*, %FooIterator** %it, align 8 - %27 = getelementptr inbounds %FooIterator, %FooIterator* %26, i32 0, i32 0 - %28 = load i64, i64* %27, align 8 - %add = add i64 %28, 1 - store i64 %add, i64* %27, align 8 - %ptroffset = getelementptr inbounds i32, i32* %25, i64 %28 - %29 = load i32, i32* %ptroffset, align 4 - store i32 %29, i32* %19, align 8 - store i8 1, i8* %blockret, align 1 - br label %expr_block.exit - -expr_block.exit: ; preds = %if.exit, %if.then - %30 = load i8, i8* %blockret, align 1 - %31 = trunc i8 %30 to i1 - br i1 %31, label %for.body, label %for.exit - -for.body: ; preds = %expr_block.exit - %32 = load i32, i32* %f, align 4 - %33 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i32 0, i32 0), i32 %32) +for.body: ; preds = %for.cond + %10 = load i64, i64* %"__idx$", 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 %while.begin while.begin: ; preds = %for.body br label %for.exit -for.exit: ; preds = %while.begin, %expr_block.exit +for.exit: ; preds = %while.begin, %for.cond ret void -} \ No newline at end of file +} diff --git a/test/test_suite/statements/foreach_with_error.c3 b/test/test_suite/statements/foreach_with_error.c3 index 9554b4537..6f8f59f7f 100644 --- a/test/test_suite/statements/foreach_with_error.c3 +++ b/test/test_suite/statements/foreach_with_error.c3 @@ -4,7 +4,7 @@ fn void test() { int[3]! x; int g; - foreach (z : x) // #error: It's not possible to enumerate an expression of type 'int[3]!' + foreach (z : x) // #error: The expression may not be failable. { g += z; x[0] = 1;