Initial foreach implementation based on index

This commit is contained in:
Christoffer Lerno
2021-11-27 00:23:48 +01:00
committed by Christoffer Lerno
parent 17a03bc104
commit 164a1ef59d
18 changed files with 1090 additions and 785 deletions

View File

@@ -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

View File

@@ -11,7 +11,7 @@
#define MAX_FILES 2048
#define MAX_THREADS 0xFFFF
#define TB_BACKEND 1
#define TB_BACKEND 0
typedef enum
{

View File

@@ -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);

View File

@@ -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;

View File

@@ -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;

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);
}

View File

@@ -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);

View File

@@ -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
}

View File

@@ -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
}
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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

View File

@@ -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.
}

View File

@@ -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
}
}

View File

@@ -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;