diff --git a/src/compiler/compiler_internal.h b/src/compiler/compiler_internal.h index 26cd9995a..55f36f9ef 100644 --- a/src/compiler/compiler_internal.h +++ b/src/compiler/compiler_internal.h @@ -350,7 +350,7 @@ typedef struct typedef struct FunctionSignature_ { - CallConvention convention : 4; + CallABI call_abi : 4; bool variadic : 1; bool has_default : 1; bool failable : 1; @@ -377,7 +377,6 @@ typedef struct bool attr_inline : 1; bool attr_noinline : 1; bool attr_extname : 1; - bool attr_stdcall : 1; }; TypeInfo *type_parent; diff --git a/src/compiler/enums.h b/src/compiler/enums.h index f4edf8455..738537747 100644 --- a/src/compiler/enums.h +++ b/src/compiler/enums.h @@ -595,7 +595,6 @@ typedef enum { ATTRIBUTE_INLINE, ATTRIBUTE_NOINLINE, - ATTRIBUTE_STDCALL, ATTRIBUTE_OPAQUE, ATTRIBUTE_NORETURN, ATTRIBUTE_SECTION, @@ -603,38 +602,30 @@ typedef enum ATTRIBUTE_WEAK, ATTRIBUTE_ALIGN, ATTRIBUTE_PACKED, - NUMBER_OF_ATTRIBUTES = ATTRIBUTE_PACKED + 1, + ATTRIBUTE_UNUSED, + ATTRIBUTE_USED, + ATTRIBUTE_NAKED, + ATTRIBUTE_CDECL, + ATTRIBUTE_STDCALL, + ATTRIBUTE_VECCALL, + ATTRIBUTE_REGCALL, + ATTRIBUTE_FASTCALL, + ATTRIBUTE_DEPRECATED, + NUMBER_OF_ATTRIBUTES = ATTRIBUTE_DEPRECATED + 1, ATTRIBUTE_NONE, } AttributeType; -typedef enum -{ - CALL_CONVENTION_NORMAL = 0, - CALL_CONVENTION_VECTOR, - CALL_CONVENTION_SYSCALL, - CALL_CONVENTION_REGCALL, - CALL_CONVENTION_STD, - CALL_CONVENTION_FAST, -} CallConvention; typedef enum { + CALL_C, CALL_X86_STD, CALL_X86_FAST, CALL_X86_THIS, CALL_X86_VECTOR, - CALL_X86_PASCAL, - CALL_WIN64, - CALL_X64_SYSV, CALL_X86_REG, CALL_AAPCS, CALL_AAPCS_VFP, - CALL_INTEL_OCL_BICC, - CALL_SPIR_FUNCTION, - CALL_OPENCL_KERNEL, - CALL_PRESERVE_MOST, - CALL_PRESERVE_ALL, - CALL_AARCH64_VECTOR, } CallABI; typedef enum diff --git a/src/compiler/llvm_codegen_c_abi_win64.c b/src/compiler/llvm_codegen_c_abi_win64.c index 44c874141..69cb4f766 100644 --- a/src/compiler/llvm_codegen_c_abi_win64.c +++ b/src/compiler/llvm_codegen_c_abi_win64.c @@ -145,13 +145,13 @@ void c_abi_func_create_win64(FunctionSignature *signature) Regs regs = { 0, 0 }; bool is_reg_call = false; bool is_vector_call = false; - switch (signature->convention) + switch (signature->call_abi) { - case CALL_CONVENTION_VECTOR: + case CALL_X86_VECTOR: regs.float_regs = 4; is_vector_call = true; break; - case CALL_CONVENTION_REGCALL: + case CALL_X86_REG: regs.float_regs = 16; is_reg_call = true; break; @@ -174,13 +174,13 @@ void c_abi_func_create_win64(FunctionSignature *signature) } // Set up parameter registers. - switch (signature->convention) + switch (signature->call_abi) { - case CALL_CONVENTION_VECTOR: + case CALL_X86_VECTOR: regs.float_regs = 6; is_vector_call = true; break; - case CALL_CONVENTION_REGCALL: + case CALL_X86_REG: regs.float_regs = 16; is_reg_call = true; break; diff --git a/src/compiler/llvm_codegen_c_abi_x64.c b/src/compiler/llvm_codegen_c_abi_x64.c index 63f76f1e2..669066bea 100644 --- a/src/compiler/llvm_codegen_c_abi_x64.c +++ b/src/compiler/llvm_codegen_c_abi_x64.c @@ -913,7 +913,7 @@ void c_abi_func_create_x64(FunctionSignature *signature) return c_abi_func_create_win64(signature); } // TODO 32 bit pointers - bool is_regcall = signature->convention == CALL_CONVENTION_REGCALL; + bool is_regcall = signature->call_abi == CALL_X86_REG; Registers available_registers = { .int_registers = is_regcall ? 11 : 16, diff --git a/src/compiler/llvm_codegen_c_abi_x86.c b/src/compiler/llvm_codegen_c_abi_x86.c index caa457ae3..8779b5d4a 100644 --- a/src/compiler/llvm_codegen_c_abi_x86.c +++ b/src/compiler/llvm_codegen_c_abi_x86.c @@ -156,7 +156,7 @@ static bool x86_should_return_type_in_reg(Type *type) * @param type type of the return. * @return */ -ABIArgInfo *x86_classify_return(CallConvention call, Regs *regs, Type *type) +ABIArgInfo *x86_classify_return(CallABI call, Regs *regs, Type *type) { // 1. Lower any type like enum etc. type = type_lowering(type); @@ -168,7 +168,7 @@ ABIArgInfo *x86_classify_return(CallConvention call, Regs *regs, Type *type) // should be passed directly in a register. Type *base = NULL; unsigned elements = 0; - if (call == CALL_CONVENTION_VECTOR || call == CALL_CONVENTION_REGCALL) + if (call == CALL_X86_VECTOR || call == CALL_X86_REG) { // This aggregate can lower safely if (type_is_homogenous_aggregate(type, &base, &elements)) return abi_arg_new_direct(); @@ -246,7 +246,7 @@ ABIArgInfo *x86_classify_return(CallConvention call, Regs *regs, Type *type) } -static inline bool x86_should_aggregate_use_direct(CallConvention call, Regs *regs, Type *type, bool *needs_padding) +static inline bool x86_should_aggregate_use_direct(CallABI call, Regs *regs, Type *type, bool *needs_padding) { // On Windows, aggregates other than HFAs are never passed in registers, and // they do not consume register slots. Homogenous floating-point aggregates @@ -261,9 +261,9 @@ static inline bool x86_should_aggregate_use_direct(CallConvention call, Regs *re switch (call) { - case CALL_CONVENTION_FAST: - case CALL_CONVENTION_VECTOR: - case CALL_CONVENTION_REGCALL: + case CALL_X86_FAST: + case CALL_X86_VECTOR: + case CALL_X86_REG: if (type_size(type) <= 4 && regs->int_regs) { *needs_padding = true; @@ -367,7 +367,7 @@ static bool x86_try_use_free_regs(Regs *regs, Type *type) * Check if a primitive should be in reg, if so, remove number of free registers. * @return true if it should have an inreg attribute, false otherwise. */ -static bool x86_try_put_primitive_in_reg(CallConvention call, Regs *regs, Type *type) +static bool x86_try_put_primitive_in_reg(CallABI call, Regs *regs, Type *type) { // 1. Try to use regs for this type, // regardless whether we succeed or not, this will update @@ -385,9 +385,9 @@ static bool x86_try_put_primitive_in_reg(CallConvention call, Regs *regs, Type * // to get an inreg attribute. Investigate! switch (call) { - case CALL_CONVENTION_FAST: - case CALL_CONVENTION_VECTOR: - case CALL_CONVENTION_REGCALL: + case CALL_X86_FAST: + case CALL_X86_VECTOR: + case CALL_X86_REG: if (type_size(type) > 4) return false; return type_is_integer_kind(type) || type_is_pointer(type); default: @@ -473,7 +473,7 @@ static inline ABIArgInfo *x86_classify_vector(Regs *regs, Type *type) * error type, struct, union, subarray, * string, array, error union, complex. */ -static inline ABIArgInfo *x86_classify_aggregate(CallConvention call, Regs *regs, Type *type) +static inline ABIArgInfo *x86_classify_aggregate(CallABI call, Regs *regs, Type *type) { // Only called for aggregates. assert(type_is_abi_aggregate(type)); @@ -527,9 +527,9 @@ static inline ABIArgInfo *x86_classify_aggregate(CallConvention call, Regs *regs // This is padded expansion ABIArgInfo *info = abi_arg_new_expand_padded(type_int); - bool is_reg_call = call == CALL_CONVENTION_REGCALL; - bool is_vec_call = call == CALL_CONVENTION_VECTOR; - bool is_fast_call = call == CALL_CONVENTION_FAST; + bool is_reg_call = call == CALL_X86_REG; + bool is_vec_call = call == CALL_X86_VECTOR; + bool is_fast_call = call == CALL_X86_FAST; info->expand.padding_by_reg = is_fast_call || is_reg_call || is_vec_call; return info; @@ -543,7 +543,7 @@ static inline ABIArgInfo *x86_classify_aggregate(CallConvention call, Regs *regs * @param type * @return */ -static ABIArgInfo *x86_classify_primitives(CallConvention call, Regs *regs, Type *type) +static ABIArgInfo *x86_classify_primitives(CallABI call, Regs *regs, Type *type) { // f128 i128 u128 on stack. if (type_size(type) > 8) return x86_create_indirect_result(regs, type, BY_VAL_SKIP); @@ -566,15 +566,15 @@ static ABIArgInfo *x86_classify_primitives(CallConvention call, Regs *regs, Type /** * Classify an argument to an x86 function. */ -static ABIArgInfo *x86_classify_argument(CallConvention call, Regs *regs, Type *type) +static ABIArgInfo *x86_classify_argument(CallABI call, Regs *regs, Type *type) { // FIXME: Set alignment on indirect arguments. // We lower all types here first to avoid enums and typedefs. type = type_lowering(type); - bool is_reg_call = call == CALL_CONVENTION_REGCALL; - bool is_vec_call = call == CALL_CONVENTION_VECTOR; + bool is_reg_call = call == CALL_X86_REG; + bool is_vec_call = call == CALL_X86_VECTOR; Type *base = NULL; unsigned elements = 0; @@ -629,25 +629,24 @@ void c_abi_func_create_x86(FunctionSignature *signature) // Vector: 2 / 6 // Fast: 2 / 3 Regs regs = { 0, 0 }; - switch (signature->convention) + switch (signature->call_abi) { - case CALL_CONVENTION_NORMAL: - case CALL_CONVENTION_SYSCALL: + case CALL_C: if (platform_target.x86.is_win32_float_struct_abi) { regs.float_regs = 3; } regs.int_regs = platform_target.default_number_regs_x86; break; - case CALL_CONVENTION_REGCALL: + case CALL_X86_REG: regs.int_regs = 5; regs.float_regs = 8; break; - case CALL_CONVENTION_VECTOR: + case CALL_X86_VECTOR: regs.int_regs = 2; regs.float_regs = 6; break; - case CALL_CONVENTION_FAST: + case CALL_X86_FAST: regs.int_regs = 2; regs.float_regs = 3; break; @@ -665,15 +664,15 @@ void c_abi_func_create_x86(FunctionSignature *signature) // return type. if (signature->failable) { - signature->failable_abi_info = x86_classify_return(signature->convention, ®s, type_error); + signature->failable_abi_info = x86_classify_return(signature->call_abi, ®s, type_error); if (signature->rtype->type->type_kind != TYPE_VOID) { - signature->ret_abi_info = x86_classify_argument(signature->convention, ®s, type_get_ptr(type_lowering(signature->rtype->type))); + signature->ret_abi_info = x86_classify_argument(signature->call_abi, ®s, type_get_ptr(type_lowering(signature->rtype->type))); } } else { - signature->ret_abi_info = x86_classify_return(signature->convention, ®s, signature->rtype->type); + signature->ret_abi_info = x86_classify_return(signature->call_abi, ®s, signature->rtype->type); } /* @@ -687,7 +686,7 @@ void c_abi_func_create_x86(FunctionSignature *signature) runVectorCallFirstPass(FI, State); */ - if (signature->convention == CALL_CONVENTION_VECTOR) + if (signature->call_abi == CALL_X86_VECTOR) { FATAL_ERROR("X86 vector call not supported"); } @@ -696,7 +695,7 @@ void c_abi_func_create_x86(FunctionSignature *signature) Decl **params = signature->params; VECEACH(params, i) { - params[i]->var.abi_info = x86_classify_argument(signature->convention, ®s, params[i]->type); + params[i]->var.abi_info = x86_classify_argument(signature->call_abi, ®s, params[i]->type); } } } diff --git a/src/compiler/llvm_codegen_function.c b/src/compiler/llvm_codegen_function.c index d9fa3ac63..578686dbc 100644 --- a/src/compiler/llvm_codegen_function.c +++ b/src/compiler/llvm_codegen_function.c @@ -577,11 +577,14 @@ void llvm_emit_function_decl(GenContext *c, Decl *decl) } llvm_attribute_add(c, function, attribute_nounwind, -1); - if (decl->func_decl.attr_stdcall && (platform_target.os == OS_TYPE_WIN32)) + if (decl->func_decl.function_signature.call_abi == CALL_X86_STD) { - LLVMSetFunctionCallConv(function, LLVMX86StdcallCallConv); - LLVMSetDLLStorageClass(function, LLVMDLLImportStorageClass); + if (platform_target.os == OS_TYPE_WIN32) + { + LLVMSetDLLStorageClass(function, LLVMDLLImportStorageClass); + } } + LLVMSetFunctionCallConv(function, llvm_call_convention_from_call(decl->func_decl.function_signature.call_abi, platform_target.arch, platform_target.os)); switch (decl->visibility) { diff --git a/src/compiler/llvm_codegen_internal.h b/src/compiler/llvm_codegen_internal.h index e0a4330df..4bbbe8856 100644 --- a/src/compiler/llvm_codegen_internal.h +++ b/src/compiler/llvm_codegen_internal.h @@ -338,10 +338,7 @@ static inline bool call_supports_variadic(CallABI abi) case CALL_X86_REG: case CALL_X86_THIS: case CALL_X86_FAST: - case CALL_X86_PASCAL: case CALL_X86_VECTOR: - case CALL_SPIR_FUNCTION: - case CALL_OPENCL_KERNEL: return false; default: return true; @@ -349,42 +346,26 @@ static inline bool call_supports_variadic(CallABI abi) } } -static inline LLVMCallConv llvm_call_convention_from_call(CallABI abi) +static inline LLVMCallConv llvm_call_convention_from_call(CallABI abi, ArchType arch, OsType os) { switch (abi) { + case CALL_C: + return LLVMCCallConv; case CALL_X86_STD: return LLVMX86StdcallCallConv; case CALL_X86_FAST: return LLVMX86FastcallCallConv; - case CALL_X86_PASCAL: - return LLVMCCallConv; case CALL_X86_REG: return LLVMX86RegCallCallConv; case CALL_X86_THIS: return LLVMX86ThisCallCallConv; case CALL_X86_VECTOR: return LLVMX86VectorCallCallConv; - case CALL_WIN64: - return LLVMWin64CallConv; - case CALL_X64_SYSV: - return LLVMX8664SysVCallConv; case CALL_AAPCS: return LLVMARMAAPCSCallConv; case CALL_AAPCS_VFP: return LLVMARMAAPCSVFPCallConv; - case CALL_INTEL_OCL_BICC: - return LLVMIntelOCLBICallConv; - case CALL_AARCH64_VECTOR: - TODO - case CALL_SPIR_FUNCTION: - return LLVMSPIRFUNCCallConv; - case CALL_OPENCL_KERNEL: - TODO // Target dependent. - case CALL_PRESERVE_ALL: - return LLVMPreserveAllCallConv; - case CALL_PRESERVE_MOST: - return LLVMPreserveMostCallConv; default: return LLVMCCallConv; } diff --git a/src/compiler/sema_decls.c b/src/compiler/sema_decls.c index 506e6fbc6..7f86b6ca9 100644 --- a/src/compiler/sema_decls.c +++ b/src/compiler/sema_decls.c @@ -694,6 +694,7 @@ static AttributeType sema_analyse_attribute(Context *context, Attr *attr, Attrib static AttributeDomain attribute_domain[NUMBER_OF_ATTRIBUTES] = { [ATTRIBUTE_WEAK] = ATTR_FUNC | ATTR_CONST | ATTR_VAR, [ATTRIBUTE_EXTNAME] = ~0, + [ATTRIBUTE_DEPRECATED] = ~0, [ATTRIBUTE_SECTION] = ATTR_FUNC | ATTR_CONST | ATTR_VAR, [ATTRIBUTE_PACKED] = ATTR_STRUCT | ATTR_UNION | ATTR_ERROR, [ATTRIBUTE_NORETURN] = ATTR_FUNC, @@ -701,7 +702,14 @@ static AttributeType sema_analyse_attribute(Context *context, Attr *attr, Attrib [ATTRIBUTE_INLINE] = ATTR_FUNC, [ATTRIBUTE_NOINLINE] = ATTR_FUNC, [ATTRIBUTE_OPAQUE] = ATTR_STRUCT | ATTR_UNION, - [ATTRIBUTE_STDCALL] = ATTR_FUNC + [ATTRIBUTE_USED] = ~0, + [ATTRIBUTE_UNUSED] = ~0, + [ATTRIBUTE_NAKED] = ATTR_FUNC, + [ATTRIBUTE_CDECL] = ATTR_FUNC, + [ATTRIBUTE_STDCALL] = ATTR_FUNC, + [ATTRIBUTE_VECCALL] = ATTR_FUNC, + [ATTRIBUTE_REGCALL] = ATTR_FUNC, + [ATTRIBUTE_FASTCALL] = ATTR_FUNC, }; if ((attribute_domain[type] & domain) != domain) @@ -711,7 +719,11 @@ static AttributeType sema_analyse_attribute(Context *context, Attr *attr, Attrib } switch (type) { + case ATTRIBUTE_CDECL: + case ATTRIBUTE_FASTCALL: case ATTRIBUTE_STDCALL: + case ATTRIBUTE_VECCALL: + case ATTRIBUTE_REGCALL: return type; case ATTRIBUTE_ALIGN: if (!attr->expr) @@ -804,6 +816,13 @@ static inline bool sema_analyse_doc_header(Ast *docs, Decl **params, Decl **extr } return true; } +static inline bool sema_update_call_convention(Decl *decl, CallABI abi) +{ + bool had = decl->func_decl.function_signature.call_abi > 0; + decl->func_decl.function_signature.call_abi = abi; + return had; +} + static inline bool sema_analyse_func(Context *context, Decl *decl) { DEBUG_LOG("----Analysing function %s", decl->name); @@ -837,6 +856,7 @@ static inline bool sema_analyse_func(Context *context, Decl *decl) bool had = false; #define SET_ATTR(_X) had = decl->func_decl._X; decl->func_decl._X = true; break + switch (attribute) { case ATTRIBUTE_EXTNAME: @@ -852,7 +872,50 @@ static inline bool sema_analyse_func(Context *context, Decl *decl) decl->alignment = attr->alignment; break; case ATTRIBUTE_NOINLINE: SET_ATTR(attr_noinline); - case ATTRIBUTE_STDCALL: SET_ATTR(attr_stdcall); + case ATTRIBUTE_STDCALL: + if (platform_target.arch == ARCH_TYPE_X86 || platform_target.arch == ARCH_TYPE_X86_64) + { + had = sema_update_call_convention(decl, CALL_X86_STD); + } + else if (platform_target.arch == ARCH_TYPE_ARM || platform_target.arch == ARCH_TYPE_ARMB) + { + had = sema_update_call_convention(decl, CALL_AAPCS); + } + break; + case ATTRIBUTE_CDECL: + had = sema_update_call_convention(decl, CALL_C); + break; + case ATTRIBUTE_VECCALL: + switch (platform_target.arch) + { + case ARCH_TYPE_X86_64: + case ARCH_TYPE_X86: + had = sema_update_call_convention(decl, CALL_X86_VECTOR); + break; + case ARCH_TYPE_ARM: + case ARCH_TYPE_ARMB: + case ARCH_TYPE_AARCH64: + case ARCH_TYPE_AARCH64_32: + case ARCH_TYPE_AARCH64_BE: + had = sema_update_call_convention(decl, CALL_AAPCS_VFP); + break; + default: + break; + } + break; + case ATTRIBUTE_FASTCALL: + if (platform_target.arch == ARCH_TYPE_X86) + { + had = sema_update_call_convention(decl, CALL_X86_FAST); + } + break; + case ATTRIBUTE_REGCALL: + had = decl->func_decl.function_signature.call_abi > 0; + if (platform_target.arch == ARCH_TYPE_X86) + { + had = sema_update_call_convention(decl, CALL_X86_REG); + } + break; case ATTRIBUTE_INLINE: SET_ATTR(attr_inline); case ATTRIBUTE_NORETURN: SET_ATTR(attr_noreturn); case ATTRIBUTE_WEAK: SET_ATTR(attr_weak); diff --git a/src/compiler/symtab.c b/src/compiler/symtab.c index 199f04c04..3af919f8b 100644 --- a/src/compiler/symtab.c +++ b/src/compiler/symtab.c @@ -135,14 +135,22 @@ void symtab_init(uint32_t capacity) attribute_list[ATTRIBUTE_INLINE] = kw_inline; attribute_list[ATTRIBUTE_NOINLINE] = KW_DEF("noinline"); - attribute_list[ATTRIBUTE_STDCALL] = KW_DEF("stdcall"); + attribute_list[ATTRIBUTE_OPAQUE] = KW_DEF("opaque"); attribute_list[ATTRIBUTE_NORETURN] = KW_DEF("noreturn"); - attribute_list[ATTRIBUTE_ALIGN] = kw_align; - attribute_list[ATTRIBUTE_PACKED] = KW_DEF("packed"); attribute_list[ATTRIBUTE_SECTION] = KW_DEF("section"); attribute_list[ATTRIBUTE_EXTNAME] = KW_DEF("extname"); attribute_list[ATTRIBUTE_WEAK] = KW_DEF("weak"); - attribute_list[ATTRIBUTE_OPAQUE] = KW_DEF("opaque"); + attribute_list[ATTRIBUTE_ALIGN] = kw_align; + attribute_list[ATTRIBUTE_PACKED] = KW_DEF("packed"); + attribute_list[ATTRIBUTE_UNUSED] = KW_DEF("unused"); + attribute_list[ATTRIBUTE_USED] = KW_DEF("used"); + attribute_list[ATTRIBUTE_NAKED] = KW_DEF("naked"); + attribute_list[ATTRIBUTE_CDECL] = KW_DEF("cdecl"); + attribute_list[ATTRIBUTE_STDCALL] = KW_DEF("stdcall"); + attribute_list[ATTRIBUTE_VECCALL] = KW_DEF("veccall"); + attribute_list[ATTRIBUTE_REGCALL] = KW_DEF("regcall"); + attribute_list[ATTRIBUTE_FASTCALL] = KW_DEF("fastcall"); + attribute_list[ATTRIBUTE_DEPRECATED] = KW_DEF("deprecated"); } static inline SymEntry *entry_find(const char *key, uint32_t key_len, uint32_t hash)