From ec612eea67cbca1ad6d40adf696d2631a074b58a Mon Sep 17 00:00:00 2001 From: Christoffer Lerno Date: Thu, 29 Jul 2021 16:42:20 +0200 Subject: [PATCH] Added some explicit casts. Added sret at call site. --- src/build/build_options.c | 2 +- src/compiler/compiler_internal.h | 4 +-- src/compiler/lexer.c | 3 +- src/compiler/llvm_codegen.c | 6 ++++ src/compiler/llvm_codegen_expr.c | 6 ++-- src/compiler/llvm_codegen_internal.h | 1 + src/compiler/sema_casts.c | 1 - src/compiler/sema_decls.c | 4 +-- src/compiler/sema_expr.c | 2 +- test/test_suite/abi/pass_large_aarch.c3t | 37 ++++++++++++++++++++++ test/test_suite/abi/test_sret.c3t | 39 ++++++++++++++++++++++++ 11 files changed, 94 insertions(+), 11 deletions(-) create mode 100644 test/test_suite/abi/pass_large_aarch.c3t create mode 100644 test/test_suite/abi/test_sret.c3t diff --git a/src/build/build_options.c b/src/build/build_options.c index a860efa82..13ffe584d 100644 --- a/src/build/build_options.c +++ b/src/build/build_options.c @@ -572,7 +572,7 @@ ArchOsTarget arch_os_target_from_string(const char *target) { if (strcasecmp(arch_os_target[i], target) == 0) { - return i; + return (ArchOsTarget)i; } } return ARCH_OS_TARGET_DEFAULT; diff --git a/src/compiler/compiler_internal.h b/src/compiler/compiler_internal.h index eb783d0cf..7ac2664cf 100644 --- a/src/compiler/compiler_internal.h +++ b/src/compiler/compiler_internal.h @@ -1752,8 +1752,8 @@ static inline TokenData *tokendata_from_token(Token token) { return tokdataptr(t #define TOKREAL(T) TOKDATA(T)->value -static inline TokenType tokenid_type(TokenId token) { return toktypeptr(token.index)[0]; } -static inline TokenType token_type(Token token) { return toktypeptr(token.id.index)[0]; } +static inline TokenType tokenid_type(TokenId token) { return (TokenType)toktypeptr(token.index)[0]; } +static inline TokenType token_type(Token token) { return (TokenType)toktypeptr(token.id.index)[0]; } #define TOKTYPE(T) _Generic((T), TokenId: tokenid_type, Token: token_type)(T) #define TOKLEN(T) TOKLOC(T)->length diff --git a/src/compiler/lexer.c b/src/compiler/lexer.c index 0d2f3f8c3..b26d7889e 100644 --- a/src/compiler/lexer.c +++ b/src/compiler/lexer.c @@ -271,7 +271,7 @@ static void skip_whitespace(Lexer *lexer, LexMode lex_type) // we split identifiers into 2 types + find keywords. static inline bool scan_ident(Lexer *lexer, TokenType normal, TokenType const_token, TokenType type_token, char prefix) { - TokenType type = 0; + TokenType type = (TokenType)0; uint32_t hash = FNV1_SEED; if (prefix) { @@ -414,7 +414,6 @@ static inline bool scan_hex(Lexer *lexer) char c = peek(lexer); if (c == 'p' || c == 'P') { - is_float = true; is_float = true; if (!scan_exponent(lexer)) return false; } diff --git a/src/compiler/llvm_codegen.c b/src/compiler/llvm_codegen.c index 01341e79c..2572b19a6 100644 --- a/src/compiler/llvm_codegen.c +++ b/src/compiler/llvm_codegen.c @@ -1039,6 +1039,12 @@ void llvm_attribute_add(GenContext *context, LLVMValueRef value_to_add_attribute llvm_attribute_add_int(context, value_to_add_attribute_to, attribute_id, 0, index); } +void llvm_attribute_add_call(GenContext *context, LLVMValueRef call, unsigned attribute_id, int index, int64_t value) +{ + LLVMAttributeRef llvm_attr = LLVMCreateEnumAttribute(context->context, attribute_id, value); + LLVMAddCallSiteAttribute(call, index, llvm_attr); +} + void llvm_attribute_add_range(GenContext *context, LLVMValueRef value_to_add_attribute_to, unsigned attribute_id, int index_start, int index_end) { for (int i = index_start; i <= index_end; i++) diff --git a/src/compiler/llvm_codegen_expr.c b/src/compiler/llvm_codegen_expr.c index 3a6d23e09..a0df13f8c 100644 --- a/src/compiler/llvm_codegen_expr.c +++ b/src/compiler/llvm_codegen_expr.c @@ -2712,6 +2712,7 @@ static void llvm_emit_unpacked_variadic_arg(GenContext *c, Expr *expr, BEValue * UNREACHABLE } } + void llvm_emit_call_expr(GenContext *c, BEValue *be_value, Expr *expr) { Expr *function = expr->call_expr.function; @@ -2791,7 +2792,7 @@ void llvm_emit_call_expr(GenContext *c, BEValue *be_value, Expr *expr) { case ABI_ARG_INDIRECT: // 6a. We can use the stored error var if there is no redirect. - if (signature->failable && c->error_var && ret_info->attributes.realign) + if (signature->failable && c->error_var && !ret_info->attributes.realign) { error_var = c->error_var; vec_add(values, error_var); @@ -2931,7 +2932,8 @@ void llvm_emit_call_expr(GenContext *c, BEValue *be_value, Expr *expr) *be_value = (BEValue) { .type = type_void, .kind = BE_VALUE }; return; case ABI_ARG_INDIRECT: - + llvm_attribute_add_call(c, call_value, attribute_sret, 1, 0); + llvm_attribute_add_call(c, call_value, attribute_align, 1, ret_info->indirect.alignment); // 13. Indirect, that is passing the result through an out parameter. // 13a. In the case of an already present error_var, we don't need to do a load here. diff --git a/src/compiler/llvm_codegen_internal.h b/src/compiler/llvm_codegen_internal.h index 3de6d6329..8645b3f9c 100644 --- a/src/compiler/llvm_codegen_internal.h +++ b/src/compiler/llvm_codegen_internal.h @@ -203,6 +203,7 @@ unsigned llvm_abi_size(GenContext *c, LLVMTypeRef type); AlignSize llvm_abi_alignment(GenContext *c, LLVMTypeRef type); void llvm_attribute_add_range(GenContext *c, LLVMValueRef value_to_add_attribute_to, unsigned attribute_id, int index_start, int index_end); void llvm_attribute_add(GenContext *c, LLVMValueRef value_to_add_attribute_to, unsigned attribute_id, int index); +void llvm_attribute_add_call(GenContext *context, LLVMValueRef call, unsigned attribute_id, int index, int64_t value); void llvm_attribute_add_string(GenContext *c, LLVMValueRef value_to_add_attribute_to, const char *attribute, const char *value, int index); void llvm_attribute_add_int(GenContext *c, LLVMValueRef value_to_add_attribute_to, unsigned attribute_id, uint64_t val, int index); LLVMBasicBlockRef llvm_basic_block_new(GenContext *c, const char *name); diff --git a/src/compiler/sema_casts.c b/src/compiler/sema_casts.c index 9a4093167..37ad2685a 100644 --- a/src/compiler/sema_casts.c +++ b/src/compiler/sema_casts.c @@ -337,7 +337,6 @@ Type *type_by_expr_range(ExprConst *expr) return type_double; } assert(expr->kind == TYPE_IXX); - BigInt *b = &expr->i; // 1. Does it fit in a C int? If so, that's the type. Type *type = type_cint(); if (!expr_const_will_overflow(expr, type->type_kind)) return type; diff --git a/src/compiler/sema_decls.c b/src/compiler/sema_decls.c index deede8d4a..3af43a0e5 100644 --- a/src/compiler/sema_decls.c +++ b/src/compiler/sema_decls.c @@ -1260,7 +1260,7 @@ static bool sema_analyse_parameterized_define(Context *c, Decl *decl) if (define_type->resolve_status == RESOLVE_DONE && type_is_user_defined(define_type->type)) { SEMA_ERROR(define_type, "Expected a user defined type for parameterization."); - return poisoned_decl; + return decl_poison(decl); } decl_path = define_type->unresolved.path; name = define_type->unresolved.name_loc; @@ -1291,7 +1291,7 @@ static bool sema_analyse_parameterized_define(Context *c, Decl *decl) VECEACH(decl->define_decl.generic_params, i) { TypeInfo *type_info = decl->define_decl.generic_params[i]; - if (!sema_resolve_type_info(c, type_info)) return poisoned_decl; + if (!sema_resolve_type_info(c, type_info)) return decl_poison(decl); if (i != 0) scratch_buffer_append_char('.'); const char *type_name = type_info->type->canonical->name; scratch_buffer_append(type_name); diff --git a/src/compiler/sema_expr.c b/src/compiler/sema_expr.c index 2cbf58cbf..6d35e1b77 100644 --- a/src/compiler/sema_expr.c +++ b/src/compiler/sema_expr.c @@ -547,7 +547,7 @@ static inline bool sema_expr_analyse_identifier(Context *context, Type *to, Expr } if (decl->resolve_status != RESOLVE_DONE) { - if (!sema_analyse_decl(context, decl)) return poisoned_decl; + if (!sema_analyse_decl(context, decl)) return decl_poison(decl); } if (decl->decl_kind == DECL_VAR && decl->var.failable) { diff --git a/test/test_suite/abi/pass_large_aarch.c3t b/test/test_suite/abi/pass_large_aarch.c3t new file mode 100644 index 000000000..551915811 --- /dev/null +++ b/test/test_suite/abi/pass_large_aarch.c3t @@ -0,0 +1,37 @@ +// #target: aarch64_linux + +module pass_large; + + +struct Large +{ + void*[8] pointers; +} + +extern func void pass_large(Large large); + +func void example() +{ + Large l = {}; + pass_large(l); + pass_large(l); +} + +// #expect: pass_large.ll + +define void @pass_large.example() +entry: + %l = alloca %Large, align 8 + %indirectarg = alloca %Large, align 8 + %indirectarg1 = alloca %Large, align 8 + %0 = bitcast %Large* %l to i8* + call void @llvm.memset.p0i8.i64(i8* align 8 %0, i8 0, i64 64, i1 false) + %1 = bitcast %Large* %indirectarg to i8* + %2 = bitcast %Large* %l to i8* + call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 8 %1, i8* align 8 %2, i32 64, i1 false) + call void @pass_large(%Large* %indirectarg) + %3 = bitcast %Large* %indirectarg1 to i8* + %4 = bitcast %Large* %l to i8* + call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 8 %3, i8* align 8 %4, i32 64, i1 false) + call void @pass_large(%Large* %indirectarg1) + ret void diff --git a/test/test_suite/abi/test_sret.c3t b/test/test_suite/abi/test_sret.c3t new file mode 100644 index 000000000..c7c2e99f4 --- /dev/null +++ b/test/test_suite/abi/test_sret.c3t @@ -0,0 +1,39 @@ +// #target: x64_darwin + +struct Abc { + long a; + long b; + long c; + long d; + long e; +} + +extern func Abc foo1(); +extern func Abc foo2(); + +func void bar() { + Abc dummy1 = foo1(); + Abc dummy2 = foo2(); +} + +// Cleanup for this result, since it's creating an unnecessary sret. + +// #expect: test_sret.ll + +declare void @foo1(%Abc* sret align 8) + +declare void @foo2(%Abc* sret align 8) + + %dummy1 = alloca %Abc, align 8 + %sretparam = alloca %Abc, align 8 + %dummy2 = alloca %Abc, align 8 + %sretparam1 = alloca %Abc, align 8 + call void @foo1(%Abc* sret align 8 %sretparam) + %0 = bitcast %Abc* %dummy1 to i8* + %1 = bitcast %Abc* %sretparam to i8* + call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 8 %0, i8* align 8 %1, i32 40, i1 false) + call void @foo2(%Abc* sret align 8 %sretparam1) + %2 = bitcast %Abc* %dummy2 to i8* + %3 = bitcast %Abc* %sretparam1 to i8* + call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 8 %2, i8* align 8 %3, i32 40, i1 false) + ret void