From 31e9ec3d525e3cdd95d8713a98e33a91789ab360 Mon Sep 17 00:00:00 2001 From: Christoffer Lerno Date: Tue, 24 Nov 2020 20:30:01 +0100 Subject: [PATCH] Optimize load of return & some parameter types. Fix issue with non-exapanding coerce. Add support for specific arch_os in tests. --- src/compiler/llvm_codegen.c | 14 ++-- src/compiler/llvm_codegen_expr.c | 112 ++++++++++++++++++--------- src/compiler/llvm_codegen_function.c | 26 +++---- src/compiler/llvm_codegen_internal.h | 7 +- src/compiler/llvm_codegen_stmt.c | 25 +++--- src/compiler/sema_types.c | 3 +- test/src/tester.py | 9 ++- test/test_suite/abi/literal_load.c3t | 29 +++++++ 8 files changed, 151 insertions(+), 74 deletions(-) create mode 100644 test/test_suite/abi/literal_load.c3t diff --git a/src/compiler/llvm_codegen.c b/src/compiler/llvm_codegen.c index 7471d302d..d755bbc60 100644 --- a/src/compiler/llvm_codegen.c +++ b/src/compiler/llvm_codegen.c @@ -75,7 +75,7 @@ static void gencontext_emit_global_variable_definition(GenContext *context, Decl { BEValue value; llvm_emit_expr(context, &value, decl->var.init_expr); - LLVMSetInitializer(decl->backend_ref, bevalue_store_value(context, &value)); + LLVMSetInitializer(decl->backend_ref, llvm_value_rvalue_store(context, &value)); } else { @@ -338,7 +338,7 @@ void llvm_value_set_address(BEValue *value, LLVMValueRef llvm_value, Type *type) llvm_value_set_address_align(value, llvm_value, type, type_abi_alignment(type)); } -static inline void be_value_fold_failable(GenContext *c, BEValue *value) +void llvm_value_fold_failable(GenContext *c, BEValue *value) { if (value->kind == BE_ADDRESS_FAILABLE) { @@ -364,9 +364,9 @@ static inline void be_value_fold_failable(GenContext *c, BEValue *value) } } -LLVMValueRef bevalue_store_value(GenContext *c, BEValue *value) +LLVMValueRef llvm_value_rvalue_store(GenContext *c, BEValue *value) { - be_value_fold_failable(c, value); + llvm_value_fold_failable(c, value); switch (value->kind) { case BE_VALUE: @@ -393,7 +393,7 @@ LLVMBasicBlockRef llvm_basic_block_new(GenContext *c, const char *name) void llvm_value_addr(GenContext *c, BEValue *value) { - be_value_fold_failable(c, value); + llvm_value_fold_failable(c, value); if (value->kind == BE_ADDRESS) return; LLVMValueRef temp = llvm_emit_alloca_aligned(c, value->type, "tempaddr"); llvm_store_self_aligned(c, temp, value->value, value->type); @@ -403,7 +403,7 @@ void llvm_value_addr(GenContext *c, BEValue *value) void llvm_value_rvalue(GenContext *c, BEValue *value) { if (value->kind != BE_ADDRESS && value->kind != BE_ADDRESS_FAILABLE) return; - be_value_fold_failable(c, value); + llvm_value_fold_failable(c, value); value->value = llvm_emit_load_aligned(c, llvm_get_type(c, value->type), value->value, @@ -573,7 +573,7 @@ unsigned llvm_abi_alignment(LLVMTypeRef type) void llvm_store_bevalue_aligned(GenContext *c, LLVMValueRef destination, BEValue *value, unsigned alignment) { // If we have an address but not an aggregate, do a load. - be_value_fold_failable(c, value); + llvm_value_fold_failable(c, value); if (value->kind == BE_ADDRESS && !type_is_abi_aggregate(value->type)) { value->value = llvm_emit_load_aligned(c, llvm_get_type(c, value->type), value->value, value->alignment, ""); diff --git a/src/compiler/llvm_codegen_expr.c b/src/compiler/llvm_codegen_expr.c index 3d8e8fe83..ce916cb02 100644 --- a/src/compiler/llvm_codegen_expr.c +++ b/src/compiler/llvm_codegen_expr.c @@ -51,15 +51,30 @@ static inline LLVMValueRef gencontext_emit_add_int(GenContext *context, Type *ty : LLVMBuildNSWAdd(context->builder, left, right, "add"); } -LLVMValueRef gencontext_emit_convert_value_to_coerced(GenContext *context, LLVMTypeRef coerced, LLVMValueRef value, Type *original_type) +LLVMValueRef llvm_emit_coerce(GenContext *context, LLVMTypeRef coerced, BEValue *value, Type *original_type) { - // Must be the same size. - assert(type_size(original_type) <= llvm_abi_size(coerced)); - assert(llvm_get_type(context, original_type) != coerced); - unsigned max_align = MAX(type_abi_alignment(original_type), llvm_abi_alignment(coerced)); - LLVMValueRef temp = llvm_emit_alloca_aligned(context, original_type, "tempcoerce1"); - llvm_store_aligned(context, temp, value, max_align); - LLVMValueRef cast = LLVMBuildBitCast(context->builder, temp, LLVMPointerType(coerced, 0), ""); + LLVMValueRef cast; + unsigned target_alignment = llvm_abi_alignment(coerced); + unsigned max_align = MAX(((unsigned)value->alignment), llvm_abi_alignment(coerced)); + + // If we are loading something with greater alignment than what we have, we cannot directly memcpy. + if (llvm_value_is_addr(value) && value->alignment < target_alignment) + { + // So load it instead. + llvm_value_rvalue(context, value); + } + + // In this case we have something nicely aligned, so we just do a cast. + if (llvm_value_is_addr(value)) + { + cast = LLVMBuildBitCast(context->builder, value->value, LLVMPointerType(coerced, 0), ""); + } + else + { + cast = llvm_emit_alloca(context, coerced, max_align, "coerce"); + LLVMValueRef target = LLVMBuildBitCast(context->builder, cast, llvm_get_ptr_type(context, value->type), ""); + llvm_store_bevalue_aligned(context, target, value, max_align); + } return llvm_emit_load_aligned(context, coerced, cast, max_align, "coerced"); } @@ -522,7 +537,7 @@ static void gencontext_construct_const_union_struct(GenContext *context, BEValue { LLVMValueRef values[2]; gencontext_construct_const_value(context, be_value, value); - values[0] = bevalue_store_value(context, be_value); + values[0] = llvm_value_rvalue_store(context, be_value); unsigned size_diff = type_size(canonical) - type_size(value->type); if (size_diff > 0) { @@ -547,7 +562,7 @@ static void gencontext_recursive_set_const_value(GenContext *context, BEValue *b } gencontext_construct_const_value(context, be_value, value); llvm_value_set(be_value, - LLVMConstInsertValue(parent, bevalue_store_value(context, be_value), &path->index, 1), + LLVMConstInsertValue(parent, llvm_value_rvalue_store(context, be_value), &path->index, 1), parent_type); return; } @@ -558,7 +573,7 @@ static void gencontext_recursive_set_const_value(GenContext *context, BEValue *b LLVMConstExtractValue(parent, &path->index, 1), parent_type, value); llvm_value_set(be_value, - LLVMConstInsertValue(parent, bevalue_store_value(context, be_value), &path->index, 1), + LLVMConstInsertValue(parent, llvm_value_rvalue_store(context, be_value), &path->index, 1), parent_type); return; } @@ -571,7 +586,7 @@ static void gencontext_recursive_set_const_value(GenContext *context, BEValue *b { gencontext_construct_const_value(context, be_value, value); llvm_value_set(be_value, - LLVMConstInsertValue(parent, bevalue_store_value(context, be_value), &index, 1), + LLVMConstInsertValue(parent, llvm_value_rvalue_store(context, be_value), &index, 1), parent_type); return ; } @@ -580,7 +595,7 @@ static void gencontext_recursive_set_const_value(GenContext *context, BEValue *b LLVMConstExtractValue(parent, &index, 1), parent_type, value); llvm_value_set(be_value, - LLVMConstInsertValue(parent, bevalue_store_value(context, be_value), &index, 1), + LLVMConstInsertValue(parent, llvm_value_rvalue_store(context, be_value), &index, 1), parent_type); return; } @@ -631,7 +646,7 @@ static void gencontext_emit_initializer_list_expr_const(GenContext *context, BEV } llvm_emit_expr(context, be_value, element); - value = LLVMConstInsertValue(value, bevalue_store_value(context, be_value), &i, 1); + value = LLVMConstInsertValue(value, llvm_value_rvalue_store(context, be_value), &i, 1); } llvm_value_set(be_value, value, expr->type); return; @@ -649,7 +664,7 @@ static void gencontext_emit_initializer_list_expr_const(GenContext *context, BEV value, parent_type, element->designated_init_expr.value); - value = bevalue_store_value(context, be_value); + value = llvm_value_rvalue_store(context, be_value); } llvm_value_set(be_value, value, expr->type); } @@ -668,7 +683,7 @@ static inline LLVMValueRef llvm_emit_initializer_list_expr_addr(GenContext *c, E BEValue be_value; gencontext_emit_initializer_list_expr_const(c, &be_value, expr); LLVMValueRef ref = LLVMAddGlobal(c->module, type, ""); - LLVMSetInitializer(ref, bevalue_store_value(c, &be_value)); + LLVMSetInitializer(ref, llvm_value_rvalue_store(c, &be_value)); LLVMSetGlobalConstant(ref, true); if (optional_ref) { @@ -710,7 +725,7 @@ static inline LLVMValueRef llvm_emit_initializer_list_expr_addr(GenContext *c, E BEValue init_value; llvm_emit_expr(c, &init_value, elements[0]); LLVMValueRef u = LLVMBuildBitCast(c->builder, ref, llvm_get_ptr_type(c, elements[0]->type->canonical), ""); - LLVMBuildStore(c->builder, bevalue_store_value(c, &init_value), u); + LLVMBuildStore(c->builder, llvm_value_rvalue_store(c, &init_value), u); return ref; } VECEACH(elements, i) @@ -719,7 +734,7 @@ static inline LLVMValueRef llvm_emit_initializer_list_expr_addr(GenContext *c, E BEValue init_value; llvm_emit_expr(c, &init_value, element); LLVMValueRef subref = LLVMBuildStructGEP2(c->builder, type, ref, i + (int)is_error, ""); - llvm_store_self_aligned(c, subref, bevalue_store_value(c, &init_value), element->type); + llvm_store_self_aligned(c, subref, llvm_value_rvalue_store(c, &init_value), element->type); } return ref; } @@ -756,7 +771,7 @@ static inline LLVMValueRef llvm_emit_initializer_list_expr_addr(GenContext *c, E llvm_emit_expr(c, &index, path->index_expr); LLVMValueRef indices[2] = { zero, - bevalue_store_value(c, &index), + llvm_value_rvalue_store(c, &index), }; sub_ref = LLVMBuildInBoundsGEP2(c->builder, llvm_get_type(c, parent_type), @@ -770,7 +785,7 @@ static inline LLVMValueRef llvm_emit_initializer_list_expr_addr(GenContext *c, E parent_type = path->type; path = path->sub_path; } - LLVMBuildStore(c->builder, bevalue_store_value(c, &sub_value), sub_ref); + LLVMBuildStore(c->builder, llvm_value_rvalue_store(c, &sub_value), sub_ref); } return ref; } @@ -1826,7 +1841,9 @@ static inline void gencontext_emit_guard_expr(GenContext *c, BEValue *be_value, if (llvm_emit_check_block_branch(c)) { llvm_emit_defer(c, expr->guard_expr.defer, 0); - llvm_emit_return_abi(c, NULL, gencontext_emit_load(c, type_error, error_var)); + BEValue value; + llvm_value_set_address(&value, error_var, type_error); + llvm_emit_return_abi(c, NULL, &value); c->current_block = NULL; c->current_block_is_target = NULL; } @@ -2103,7 +2120,7 @@ void gencontext_emit_call_expr(GenContext *context, BEValue *be_value, Expr *exp signature = expr->call_expr.function->type->canonical->pointer->func.signature; BEValue func_value; llvm_emit_expr(context, &func_value, expr->call_expr.function); - func = bevalue_store_value(context, &func_value); + func = llvm_value_rvalue_store(context, &func_value); func_type = llvm_get_type(context, expr->call_expr.function->type->canonical->pointer); } else if (expr->call_expr.is_struct_function) @@ -2154,8 +2171,6 @@ void gencontext_emit_call_expr(GenContext *context, BEValue *be_value, Expr *exp { Expr *arg_expr = expr->call_expr.arguments[i]; llvm_emit_expr(context, be_value, arg_expr); - LLVMValueRef value = bevalue_store_value(context, be_value); - printf("TODO: param passing is not using bevalue\n"); Decl *param = signature->params[i]; ABIArgInfo *info = param->var.abi_info; switch (info->kind) @@ -2171,31 +2186,50 @@ void gencontext_emit_call_expr(GenContext *context, BEValue *be_value, Expr *exp llvm_get_type(context, param->type), alignment, "indirectarg"); - llvm_store_aligned(context, indirect, value, alignment); + llvm_store_bevalue_aligned(context, indirect, be_value, alignment); vec_add(values, indirect); break; } case ABI_ARG_DIRECT_COERCE: { - LLVMTypeRef type = llvm_get_coerce_type(context, info); - if (!type || llvm_get_type(context, param->type)) + LLVMTypeRef coerce_type = llvm_get_coerce_type(context, info); + if (!coerce_type || coerce_type == llvm_get_type(context, param->type)) { - vec_add(values, value); + vec_add(values, llvm_value_rvalue_store(context, be_value)); break; } + if (!abi_info_should_flatten(info)) { - vec_add(values, gencontext_emit_convert_value_to_coerced(context, type, value, param->type)); + vec_add(values, llvm_emit_coerce(context, coerce_type, be_value, param->type)); break; } - unsigned max_align = MAX(type_abi_alignment(param->type), llvm_abi_alignment(type)); - LLVMValueRef temp = llvm_emit_alloca(context, type, max_align, "tempcoerce"); - LLVMValueRef cast = LLVMBuildBitCast(context->builder, temp, LLVMPointerType(type, 0), ""); - llvm_store_aligned(context, cast, value, max_align); + LLVMValueRef cast; + unsigned target_alignment = llvm_abi_alignment(coerce_type); + unsigned max_align = MAX(((unsigned)be_value->alignment), llvm_abi_alignment(coerce_type)); + + // If we are loading something with greater alignment than what we have, we cannot directly memcpy. + if (llvm_value_is_addr(be_value) && be_value->alignment < target_alignment) + { + // So load it instead. + llvm_value_rvalue(context, be_value); + } + + // In this case we have something nicely aligned, so we just do a cast. + if (llvm_value_is_addr(be_value)) + { + cast = LLVMBuildBitCast(context->builder, be_value->value, LLVMPointerType(coerce_type, 0), ""); + } + else + { + cast = llvm_emit_alloca(context, coerce_type, max_align, "coerce"); + LLVMValueRef target = LLVMBuildBitCast(context->builder, cast, llvm_get_ptr_type(context, param->type), ""); + llvm_store_bevalue_aligned(context, target, be_value, max_align); + } LLVMTypeRef element = llvm_abi_type(context, info->direct_coerce.type); for (unsigned idx = 0; idx < info->direct_coerce.elements; idx++) { - LLVMValueRef element_ptr = LLVMBuildStructGEP2(context->builder, type, temp, idx, ""); + LLVMValueRef element_ptr = LLVMBuildStructGEP2(context->builder, coerce_type, cast, idx, ""); vec_add(values, llvm_emit_load_aligned(context, element, element_ptr, llvm_abi_alignment(element), "")); } @@ -2203,6 +2237,8 @@ void gencontext_emit_call_expr(GenContext *context, BEValue *be_value, Expr *exp } case ABI_ARG_DIRECT_PAIR: { + printf("TODO: Optimize load\n"); + LLVMValueRef value = llvm_value_rvalue_store(context, be_value); // Here we do the following transform: // struct -> { lo, hi } -> lo, hi LLVMTypeRef lo = llvm_abi_type(context, info->direct_pair.lo); @@ -2225,6 +2261,8 @@ void gencontext_emit_call_expr(GenContext *context, BEValue *be_value, Expr *exp } case ABI_ARG_EXPAND: { + printf("TODO: Optimize load\n"); + LLVMValueRef value = llvm_value_rvalue_store(context, be_value); LLVMValueRef expand = llvm_emit_alloca_aligned(context, param->type, "expand"); llvm_store_aligned(context, expand, value, type_abi_alignment(param->type)); llvm_expand_type_to_args(context, param->type, expand, &values); @@ -2242,7 +2280,7 @@ void gencontext_emit_call_expr(GenContext *context, BEValue *be_value, Expr *exp Expr *arg_expr = expr->call_expr.arguments[i]; llvm_emit_expr(context, be_value, arg_expr); printf("TODO: varargs should be expanded correctly\n"); - vec_add(values, bevalue_store_value(context, be_value)); + vec_add(values, llvm_value_rvalue_store(context, be_value)); } LLVMValueRef call = LLVMBuildCall2(context->builder, func_type, func, values, vec_size(values), ""); @@ -2414,7 +2452,7 @@ static inline void gencontext_emit_macro_block(GenContext *context, BEValue *be_ BEValue value; llvm_emit_expr(context, &value, expr->macro_block.args[i]); printf("TODO: unoptimized use of BEValue\n"); - llvm_emit_store(context, decl, bevalue_store_value(context, &value)); + llvm_emit_store(context, decl, llvm_value_rvalue_store(context, &value)); } VECEACH(stmts, i) @@ -2497,7 +2535,7 @@ static inline void gencontext_emit_failable(GenContext *context, BEValue *be_val assert(context->error_var); llvm_emit_expr(context, be_value, fail); printf("TODO // fix failable \n"); - LLVMBuildStore(context->builder, bevalue_store_value(context, be_value), + LLVMBuildStore(context->builder, llvm_value_rvalue_store(context, be_value), llvm_emit_bitcast(context, context->error_var, type_get_ptr(fail->type))); } llvm_emit_br(context, context->catch_block); diff --git a/src/compiler/llvm_codegen_function.c b/src/compiler/llvm_codegen_function.c index 5f086824e..f58c2d9e7 100644 --- a/src/compiler/llvm_codegen_function.c +++ b/src/compiler/llvm_codegen_function.c @@ -228,7 +228,7 @@ static inline void llvm_emit_return_value(GenContext *context, LLVMValueRef valu context->current_block_is_target = false; } -void llvm_emit_return_abi(GenContext *c, LLVMValueRef return_value, LLVMValueRef failable) +void llvm_emit_return_abi(GenContext *c, BEValue *return_value, BEValue *failable) { FunctionSignature *signature = &c->cur_func_decl->func.function_signature; ABIArgInfo *info = signature->ret_abi_info; @@ -243,7 +243,7 @@ void llvm_emit_return_abi(GenContext *c, LLVMValueRef return_value, LLVMValueRef { if (return_value) { - LLVMBuildStore(c->builder, return_value, c->return_out); + llvm_store_bevalue_aligned(c, c->return_out, return_value, 0); } return_out = c->failable_out; return_type = type_error; @@ -254,8 +254,7 @@ void llvm_emit_return_abi(GenContext *c, LLVMValueRef return_value, LLVMValueRef switch (info->kind) { case ABI_ARG_INDIRECT: - LLVMBuildStore(c->builder, return_value, return_out); - if (info->indirect.realignment) TODO + llvm_store_bevalue_aligned(c, return_out, return_value, info->indirect.realignment); llvm_emit_return_value(c, NULL); return; case ABI_ARG_IGNORE: @@ -272,15 +271,11 @@ void llvm_emit_return_abi(GenContext *c, LLVMValueRef return_value, LLVMValueRef if (!coerce_type || coerce_type == llvm_get_type(c, return_type)) { // The normal return - llvm_emit_return_value(c, return_value); + llvm_emit_return_value(c, llvm_value_rvalue_store(c, return_value)); return; } assert(!abi_info_should_flatten(info)); - llvm_emit_return_value(c, - gencontext_emit_convert_value_to_coerced(c, - coerce_type, - return_value, - return_type)); + llvm_emit_return_value(c, llvm_emit_coerce(c, coerce_type, return_value, return_type)); return; } } @@ -293,9 +288,14 @@ void llvm_emit_return_implicit(GenContext *c) LLVMBuildUnreachable(c->builder); return; } - LLVMValueRef failable = c->cur_func_decl->func.function_signature.failable ? - LLVMConstNull(llvm_get_type(c, type_error)) : NULL; - llvm_emit_return_abi(c, NULL, failable); + if (!c->cur_func_decl->func.function_signature.failable) + { + llvm_emit_return_abi(c, NULL, NULL); + return; + } + BEValue value; + llvm_value_set(&value, LLVMConstNull(llvm_get_type(c, type_error)), type_error); + llvm_emit_return_abi(c, NULL, &value); } void llvm_emit_function_body(GenContext *context, Decl *decl) diff --git a/src/compiler/llvm_codegen_internal.h b/src/compiler/llvm_codegen_internal.h index 9e2d9465a..d3ed6640c 100644 --- a/src/compiler/llvm_codegen_internal.h +++ b/src/compiler/llvm_codegen_internal.h @@ -209,8 +209,9 @@ void llvm_value_set_bool(BEValue *value, LLVMValueRef llvm_value); void llvm_value_set(BEValue *value, LLVMValueRef llvm_value, Type *type); void llvm_value_set_address_align(BEValue *value, LLVMValueRef llvm_value, Type *type, unsigned alignment); void llvm_value_set_address(BEValue *value, LLVMValueRef llvm_value, Type *type); +void llvm_value_fold_failable(GenContext *c, BEValue *value); -LLVMValueRef bevalue_store_value(GenContext *c, BEValue *value); +LLVMValueRef llvm_value_rvalue_store(GenContext *c, BEValue *value); LLVMTypeRef llvm_abi_type(GenContext *c, AbiType *type); unsigned llvm_abi_size(LLVMTypeRef type); @@ -252,7 +253,7 @@ void llvm_emit_memcpy_to_decl(GenContext *c, Decl *decl, LLVMValueRef source, un void llvm_emit_stmt(GenContext *c, Ast *ast); static inline LLVMValueRef llvm_emit_store(GenContext *context, Decl *decl, LLVMValueRef value); void llvm_emit_panic_on_true(GenContext *c, LLVMValueRef value, const char *panic_name); -void llvm_emit_return_abi(GenContext *c, LLVMValueRef return_value, LLVMValueRef failable); +void llvm_emit_return_abi(GenContext *c, BEValue *return_value, BEValue *failable); void llvm_emit_return_implicit(GenContext *c); LLVMValueRef llvm_get_next_param(GenContext *context, unsigned *index); @@ -283,7 +284,7 @@ void llvm_store_aligned(GenContext *context, LLVMValueRef pointer, LLVMValueRef void llvm_store_aligned_decl(GenContext *context, Decl *decl, LLVMValueRef value); LLVMTypeRef gencontext_get_twostruct(GenContext *context, LLVMTypeRef lo, LLVMTypeRef hi); -LLVMValueRef gencontext_emit_convert_value_to_coerced(GenContext *context, LLVMTypeRef coerced, LLVMValueRef value, Type *original_type); +LLVMValueRef llvm_emit_coerce(GenContext *context, LLVMTypeRef coerced, BEValue *value, Type *original_type); static inline LLVMValueRef gencontext_emit_load(GenContext *c, Type *type, LLVMValueRef value) { diff --git a/src/compiler/llvm_codegen_stmt.c b/src/compiler/llvm_codegen_stmt.c index 4e33f9c77..9c62cb8d6 100644 --- a/src/compiler/llvm_codegen_stmt.c +++ b/src/compiler/llvm_codegen_stmt.c @@ -155,12 +155,12 @@ static inline void gencontext_emit_return(GenContext *c, Ast *ast) c->catch_block = error_return_block; } - LLVMValueRef ret_value = NULL; - if (ast->return_stmt.expr) + bool has_return_value = ast->return_stmt.expr != NULL; + BEValue return_value = {}; + if (has_return_value) { - BEValue value = {}; - llvm_emit_expr(c, &value, ast->return_stmt.expr); - ret_value = bevalue_store_value(c, &value); + llvm_emit_expr(c, &return_value, ast->return_stmt.expr); + llvm_value_fold_failable(c, &return_value); } POP_ERROR(); @@ -172,25 +172,27 @@ static inline void gencontext_emit_return(GenContext *c, Ast *ast) { if (c->return_out) { - LLVMBuildStore(c->builder, ret_value, c->return_out); + llvm_store_bevalue_aligned(c, c->return_out, &return_value, 0); } gencontext_emit_jmp(c, c->expr_block_exit); return; } - if (!ret_value) + if (!has_return_value) { llvm_emit_return_implicit(c); } else { - llvm_emit_return_abi(c, ret_value, NULL); + llvm_emit_return_abi(c, &return_value, NULL); } c->current_block = NULL; if (error_return_block && LLVMGetFirstUse(LLVMBasicBlockAsValue(error_return_block))) { llvm_emit_block(c, error_return_block); - llvm_emit_return_abi(c, NULL, gencontext_emit_load(c, type_error, error_out)); + BEValue value; + llvm_value_set_address(&value, error_out, type_error); + llvm_emit_return_abi(c, NULL, &value); c->current_block = NULL; } LLVMBasicBlockRef post_ret_block = llvm_basic_block_new(c, "ret"); @@ -622,7 +624,7 @@ static void gencontext_emit_switch_body(GenContext *context, BEValue *switch_val Type *switch_type = switch_ast->switch_stmt.cond->type; LLVMValueRef switch_var = llvm_emit_alloca_aligned(context, switch_type, "switch"); switch_ast->switch_stmt.codegen.retry_var = switch_var; - LLVMBuildStore(context->builder, bevalue_store_value(context, switch_value), switch_var); + LLVMBuildStore(context->builder, llvm_value_rvalue_store(context, switch_value), switch_var); llvm_emit_br(context, switch_block); llvm_emit_block(context, switch_block); @@ -758,7 +760,8 @@ void gencontext_emit_next_stmt(GenContext *context, Ast *ast) } BEValue be_value; llvm_emit_expr(context, &be_value, ast->next_stmt.switch_expr); - LLVMBuildStore(context->builder, bevalue_store_value(context, &be_value), jump_target->switch_stmt.codegen.retry_var); + LLVMBuildStore(context->builder, + llvm_value_rvalue_store(context, &be_value), jump_target->switch_stmt.codegen.retry_var); llvm_emit_defer(context, ast->next_stmt.defers.start, ast->next_stmt.defers.end); gencontext_emit_jmp(context, jump_target->switch_stmt.codegen.retry_block); } diff --git a/src/compiler/sema_types.c b/src/compiler/sema_types.c index 5b225db90..f34986273 100644 --- a/src/compiler/sema_types.c +++ b/src/compiler/sema_types.c @@ -18,7 +18,6 @@ static inline bool sema_resolve_ptr_type(Context *context, TypeInfo *type_info) return true; } - static inline bool sema_resolve_array_type(Context *context, TypeInfo *type) { if (!sema_resolve_type_info(context, type->array.base)) @@ -53,7 +52,7 @@ static inline bool sema_resolve_array_type(Context *context, TypeInfo *type) } if (!bigint_fits_in_bits(&type->array.len->const_expr.i, 64, true)) { - SEMA_ERROR(type->array.len, "An array may not exceed the max of an 64 bit signed int."); + SEMA_ERROR(type->array.len, "An array length may not exceed the max of an 64 bit signed int."); return type_info_poison(type); } diff --git a/test/src/tester.py b/test/src/tester.py index 0a868b2e5..d417f4c85 100644 --- a/test/src/tester.py +++ b/test/src/tester.py @@ -51,6 +51,7 @@ class Issues: self.error_message = "unknown" self.skip = False self.cur = 0 + self.arch = None self.current_file = None self.files = [] self.errors = {} @@ -100,7 +101,10 @@ class Issues: def compile(self, args): os.chdir(TEST_DIR) - code = subprocess.run(self.conf.compiler + ' -O0 ' + args, universal_newlines=True, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + target = "" + if (self.arch): + target = " --target " + self.arch + code = subprocess.run(self.conf.compiler + target + ' -O0 ' + args, universal_newlines=True, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) os.chdir(self.conf.cwd) if code.returncode != 0 and code.returncode != 1: self.set_failed() @@ -129,6 +133,9 @@ class Issues: def parse_header_directive(self, line): line = line[4:].strip() + if (line.startswith("target:")): + self.arch = line[7:].strip() + return if (line.startswith("file:")): if self.current_file: self.current_file.close() diff --git a/test/test_suite/abi/literal_load.c3t b/test/test_suite/abi/literal_load.c3t new file mode 100644 index 000000000..6376e3334 --- /dev/null +++ b/test/test_suite/abi/literal_load.c3t @@ -0,0 +1,29 @@ +// #target: x64_darwin + +struct Test +{ + int x; +} + +extern func void blorg(Test t); + +func Test creator() +{ + blorg(Test {} ); + return Test {}; +} + +// #expect: literal_load.ll + + %literal = alloca %literal_load.Test, align 4 + %literal1 = alloca %literal_load.Test, align 4 + %0 = bitcast %literal_load.Test* %literal to i8* + call void @llvm.memset.p0i8.i64(i8* align 4 %0, i8 0, i64 4, i1 false) + %1 = bitcast %literal_load.Test* %literal to i32* + %coerced = load i32, i32* %1, align 4 + call void @blorg(i32 %coerced) + %2 = bitcast %literal_load.Test* %literal1 to i8* + call void @llvm.memset.p0i8.i64(i8* align 4 %2, i8 0, i64 4, i1 false) + %3 = bitcast %literal_load.Test* %literal1 to i32* + %coerced2 = load i32, i32* %3, align 4 + ret i32 %coerced2 \ No newline at end of file