diff --git a/CMakeLists.txt b/CMakeLists.txt index c4ae5d92e..e08a44d6a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,6 +9,7 @@ set(C3_LLVM_VERSION "auto" CACHE STRING "Use LLVM version [default: auto]") option(C3_USE_MIMALLOC "Use built-in mimalloc" OFF) set(C3_MIMALLOC_TAG "v1.7.3" CACHE STRING "Used version of mimalloc") +set(C3_USE_MIMALLOC OFF) if(C3_USE_MIMALLOC) option(MI_BUILD_TESTS OFF) option(MI_BUILD_SHARED OFF) @@ -180,7 +181,6 @@ add_executable(c3c src/compiler/tokens.c src/compiler/types.c src/main.c - src/target_info/target_info.c src/utils/errors.c src/utils/file_utils.c src/utils/find_msvc.c diff --git a/src/build/build_options.c b/src/build/build_options.c index d8224a4c4..cac087060 100644 --- a/src/build/build_options.c +++ b/src/build/build_options.c @@ -389,6 +389,22 @@ static void parse_option(BuildOptions *options) FAIL_WITH_ERR("Invalid optimization level."); } return; + case 'm': + if (match_shortopt("mno-avx")) + { + options->no_avx = true; + } else if (match_shortopt("mavx")) + { + options->avx = true; + } else if (match_shortopt("mavx512")) + { + options->avx512 = true; + } + else + { + FAIL_WITH_ERR("Invalid -m option."); + } + return; case 'E': if (options->compile_option != COMPILE_NORMAL) { diff --git a/src/build/build_options.h b/src/build/build_options.h index e34a4527f..7ea40d205 100644 --- a/src/build/build_options.h +++ b/src/build/build_options.h @@ -204,6 +204,9 @@ typedef struct BuildOptions_ bool emit_bitcode; bool test_mode; bool no_stdlib; + bool no_avx; + bool avx; + bool avx512; } BuildOptions; @@ -262,6 +265,8 @@ typedef struct bool no_sse : 1; bool no_mmx : 1; bool no_avx : 1; + bool avx : 1; + bool avx512 : 1; } feature; } BuildTarget; diff --git a/src/build/builder.c b/src/build/builder.c index 690c4e413..9ee8465af 100644 --- a/src/build/builder.c +++ b/src/build/builder.c @@ -117,6 +117,9 @@ static void update_build_target_from_options(BuildTarget *target, BuildOptions * } target->no_stdlib = options->no_stdlib; target->emit_llvm = options->emit_llvm; + if (options->no_avx) target->feature.no_avx = true; + if (options->avx) target->feature.avx = true; + if (options->avx512) target->feature.avx512 = true; switch (options->compile_option) { case COMPILE_NORMAL: diff --git a/src/build/project.c b/src/build/project.c index 9bfd22073..380a0cac3 100644 --- a/src/build/project.c +++ b/src/build/project.c @@ -201,6 +201,8 @@ void project_add_target(Project *project, TomlValue *wrapped_table, const char * // Use the fact that they correspond to 0, 1, -1 target->feature.struct_return = get_valid_bool(table, "stack-struct-return", type, STRUCT_RETURN_DEFAULT); target->feature.soft_float = get_valid_bool(table, "soft-float", type, SOFT_FLOAT_DEFAULT); + target->feature.avx = get_valid_bool(table, "avx", type, false); + target->feature.avx512 = get_valid_bool(table, "avx512", type, false); target->feature.no_avx = get_valid_bool(table, "no-avx", type, false); target->feature.no_sse = get_valid_bool(table, "no-sse", type, false); target->feature.no_mmx = get_valid_bool(table, "no-mmx", type, false); diff --git a/src/compiler/compiler_internal.h b/src/compiler/compiler_internal.h index 4c176bc74..57f4639b6 100644 --- a/src/compiler/compiler_internal.h +++ b/src/compiler/compiler_internal.h @@ -1561,11 +1561,13 @@ typedef struct FunctionPrototype_ bool ret_by_ref : 1; Type *rtype; Type **params; + Type **varargs; Type *ret_by_ref_type; Type *abi_ret_type; ABIArgInfo *ret_abi_info; ABIArgInfo *ret_by_ref_abi_info; ABIArgInfo **abi_args; + ABIArgInfo **abi_varargs; void *tb_prototype; } FunctionPrototype; @@ -2050,6 +2052,7 @@ void *llvm_target_machine_create(void); void target_setup(BuildTarget *build_target); int target_alloca_addr_space(); +void c_abi_func_create(FunctionPrototype *proto); bool token_is_type(TokenType type); bool token_is_any_type(TokenType type); diff --git a/src/compiler/llvm_codegen_c_abi_x64.c b/src/compiler/llvm_codegen_c_abi_x64.c index 5ad0ec2e2..c4b00e0af 100644 --- a/src/compiler/llvm_codegen_c_abi_x64.c +++ b/src/compiler/llvm_codegen_c_abi_x64.c @@ -359,7 +359,7 @@ void x64_classify_vector(Type *type, ByteSize offset_base, X64Class *current, X6 } return; } - if (size == 16 || named_arg || size <= x64_native_vector_size_for_avx()) + if (size == 16 || (named_arg == NAMED && size <= x64_native_vector_size_for_avx())) { if (platform_target.x64.pass_int128_vector_in_mem) return; @@ -921,4 +921,15 @@ void c_abi_func_create_x64(FunctionPrototype *prototype) } prototype->abi_args = args; } + unsigned vararg_count = vec_size(prototype->varargs); + if (vararg_count) + { + ABIArgInfo **args = MALLOC(sizeof(ABIArgInfo) * vararg_count); + for (unsigned i = 0; i < vararg_count; i++) + { + args[i] = x64_classify_parameter(prototype->varargs[i], &available_registers, is_regcall, UNNAMED); + } + prototype->abi_varargs = args; + } + } diff --git a/src/compiler/llvm_codegen_expr.c b/src/compiler/llvm_codegen_expr.c index b2bea509f..4df3cb261 100644 --- a/src/compiler/llvm_codegen_expr.c +++ b/src/compiler/llvm_codegen_expr.c @@ -789,6 +789,7 @@ static inline void llvm_extract_bitvalue_from_array(GenContext *c, BEValue *be_v res = element; continue; } + res = LLVMBuildOr(c->builder, element, res, ""); } if (big_endian) @@ -4331,6 +4332,31 @@ void llvm_emit_builtin_call(GenContext *c, BEValue *result_value, Expr *expr) llvm_emit_intrinsic_expr(c, llvm_get_intrinsic(func), result_value, expr); } +void llvm_add_call_attributes(GenContext *c, LLVMValueRef call_value, int start_index, int count, Type **types, ABIArgInfo **infos) +{ + for (unsigned i = 0; i < count; i++) + { + Type *param = types[i]; + ABIArgInfo *info = infos[i]; + switch (info->kind) + { + case ABI_ARG_INDIRECT: + if (info->attributes.by_val) + { + llvm_attribute_add_call_type(c, + call_value, + attribute_id.byval, + (int)i + start_index, + llvm_get_type(c, info->indirect.type)); + } + llvm_attribute_add_call(c, call_value, attribute_id.align, (int)i + start_index, info->indirect.alignment); + break; + default: + break; + } + } + +} void llvm_emit_call_expr(GenContext *c, BEValue *result_value, Expr *expr) { if (expr->call_expr.is_builtin) @@ -4385,7 +4411,28 @@ void llvm_emit_call_expr(GenContext *c, BEValue *result_value, Expr *expr) ABIArgInfo **abi_args = prototype->abi_args; unsigned param_count = vec_size(params); unsigned non_variadic_params = param_count; + Expr **args = expr->call_expr.arguments; + unsigned arguments = vec_size(args); + if (prototype->variadic == VARIADIC_TYPED) non_variadic_params--; + FunctionPrototype copy; + if (prototype->variadic == VARIADIC_RAW) + { + if (arguments > non_variadic_params) + { + copy = *prototype; + copy.varargs = NULL; + for (unsigned i = non_variadic_params; i < arguments; i++) + { + vec_add(copy.varargs, args[i]->type); + } + copy.ret_abi_info = NULL; + copy.ret_by_ref_abi_info = NULL; + copy.abi_args = NULL; + c_abi_func_create(©); + prototype = © + } + } ABIArgInfo *ret_info = prototype->ret_abi_info; Type *call_return_type = prototype->abi_ret_type; @@ -4442,12 +4489,11 @@ void llvm_emit_call_expr(GenContext *c, BEValue *result_value, Expr *expr) // 8. Add all other arguments. - unsigned arguments = vec_size(expr->call_expr.arguments); assert(arguments >= non_variadic_params); for (unsigned i = 0; i < non_variadic_params; i++) { // 8a. Evaluate the expression. - Expr *arg_expr = expr->call_expr.arguments[i]; + Expr *arg_expr = args[i]; llvm_emit_expr(c, &temp_value, arg_expr); // 8b. Emit the parameter according to ABI rules. @@ -4508,13 +4554,30 @@ void llvm_emit_call_expr(GenContext *c, BEValue *result_value, Expr *expr) } else { - // 9. Emit varargs. - for (unsigned i = param_count; i < arguments; i++) + if (prototype->abi_varargs) { - Expr *arg_expr = expr->call_expr.arguments[i]; - llvm_emit_expr(c, &temp_value, arg_expr); - REMINDER("Varargs should be expanded correctly"); - vec_add(values, llvm_load_value_store(c, &temp_value)); + // 9. Emit varargs. + unsigned index = 0; + ABIArgInfo **abi_varargs = prototype->abi_varargs; + for (unsigned i = param_count; i < arguments; i++) + { + Expr *arg_expr = args[i]; + llvm_emit_expr(c, &temp_value, arg_expr); + ABIArgInfo *info = abi_varargs[index]; + llvm_emit_parameter(c, &values, info, &temp_value, prototype->varargs[index]); + index++; + } + } + else + { + // 9. Emit varargs. + for (unsigned i = param_count; i < arguments; i++) + { + Expr *arg_expr = args[i]; + llvm_emit_expr(c, &temp_value, arg_expr); + REMINDER("Varargs should be expanded correctly"); + vec_add(values, llvm_load_value_store(c, &temp_value)); + } } } @@ -4538,22 +4601,10 @@ void llvm_emit_call_expr(GenContext *c, BEValue *result_value, Expr *expr) } } - for (unsigned i = 0; i < non_variadic_params; i++) + llvm_add_call_attributes(c, call_value, 1, non_variadic_params, params, abi_args); + if (prototype->abi_varargs) { - Type *param = params[i]; - ABIArgInfo *info = abi_args[i]; - switch (info->kind) - { - case ABI_ARG_INDIRECT: - if (info->attributes.by_val) - { - llvm_attribute_add_call_type(c, call_value, attribute_id.byval, (int)i + 1, llvm_get_type(c, info->indirect.type)); - } - llvm_attribute_add_call(c, call_value, attribute_id.align, (int)i + 1, info->indirect.alignment); - break; - default: - break; - } + llvm_add_call_attributes(c, call_value, 1 + non_variadic_params, vec_size(prototype->varargs), prototype->varargs, prototype->abi_varargs); } // 11. Process the return value. diff --git a/src/compiler/llvm_codegen_internal.h b/src/compiler/llvm_codegen_internal.h index 839aca4b0..f521442a6 100644 --- a/src/compiler/llvm_codegen_internal.h +++ b/src/compiler/llvm_codegen_internal.h @@ -217,7 +217,6 @@ void llvm_value_set_decl(BEValue *value, Decl *decl); void llvm_value_fold_failable(GenContext *c, BEValue *value); void llvm_value_struct_gep(GenContext *c, BEValue *element, BEValue *struct_pointer, unsigned index); - LLVMTypeRef llvm_abi_type(GenContext *c, AbiType type); TypeSize llvm_abi_size(GenContext *c, LLVMTypeRef type); BitSize llvm_bitsize(GenContext *c, LLVMTypeRef type); @@ -269,6 +268,8 @@ void llvm_emit_int_comparison(GenContext *c, BEValue *result, BEValue *lhs, BEVa void llvm_emit_int_comp(GenContext *c, BEValue *result, Type *lhs_type, Type *rhs_type, LLVMValueRef lhs_value, LLVMValueRef rhs_value, BinaryOp binary_op); void llvm_emit_comparison(GenContext *c, BEValue *be_value, BEValue *lhs, BEValue *rhs, BinaryOp binary_op); void llvm_emit_len_for_expr(GenContext *c, BEValue *be_value, BEValue *expr_to_len); +// -- type --- +LLVMTypeRef llvm_func_type(GenContext *context, FunctionPrototype *prototype); // -- instr --- void llvm_emit_cond_br(GenContext *context, BEValue *value, LLVMBasicBlockRef then_block, LLVMBasicBlockRef else_block); diff --git a/src/compiler/llvm_codegen_type.c b/src/compiler/llvm_codegen_type.c index 883601f5c..749c67115 100644 --- a/src/compiler/llvm_codegen_type.c +++ b/src/compiler/llvm_codegen_type.c @@ -217,10 +217,9 @@ static inline void add_func_type_param(GenContext *context, Type *param_type, AB arg_info->param_index_end = (MemberIndex)vec_size(*params); } -LLVMTypeRef llvm_func_type(GenContext *context, Type *type) +LLVMTypeRef llvm_func_type(GenContext *context, FunctionPrototype *prototype) { LLVMTypeRef *params = NULL; - FunctionPrototype *prototype = type->func.prototype; LLVMTypeRef return_type = NULL; @@ -282,6 +281,11 @@ LLVMTypeRef llvm_func_type(GenContext *context, Type *type) add_func_type_param(context, prototype->params[i], prototype->abi_args[i], ¶ms); } + VECEACH(prototype->varargs, i) + { + add_func_type_param(context, prototype->varargs[i], prototype->abi_varargs[i], ¶ms); + } + return LLVMFunctionType(return_type, params, vec_size(params), prototype->variadic == VARIADIC_RAW); } @@ -324,7 +328,7 @@ LLVMTypeRef llvm_get_type(GenContext *c, Type *any_type) case TYPE_BITSTRUCT: return any_type->backend_type = llvm_type_from_decl(c, any_type->decl); case TYPE_FUNC: - return any_type->backend_type = llvm_func_type(c, any_type); + return any_type->backend_type = llvm_func_type(c, any_type->func.prototype); case TYPE_VOID: return any_type->backend_type = LLVMVoidTypeInContext(c->context); case TYPE_F64: diff --git a/src/compiler/target.c b/src/compiler/target.c index c1a2103fc..fae4d92fd 100644 --- a/src/compiler/target.c +++ b/src/compiler/target.c @@ -1,7 +1,6 @@ #include #include #include -#include #include "compiler_internal.h" static unsigned arch_pointer_bit_width(OsType os, ArchType arch); @@ -426,6 +425,8 @@ static inline void target_setup_x64_abi(BuildTarget *target) platform_target.abi = ABI_X64; platform_target.x64.avx_level = AVX; platform_target.x64.is_win64 = platform_target.os == OS_TYPE_WIN32; + if (target->feature.avx512) platform_target.x64.avx_level = AVX_512; + if (target->feature.avx) platform_target.x64.avx_level = AVX; if (target->feature.no_avx) platform_target.x64.avx_level = AVX_NONE; if (target->feature.no_mmx) platform_target.x64.no_mmx = true; if (target->feature.no_sse) platform_target.x64.no_sse = true; diff --git a/src/compiler/types.c b/src/compiler/types.c index 0b09f8fc3..5fe42b9e2 100644 --- a/src/compiler/types.c +++ b/src/compiler/types.c @@ -1035,7 +1035,6 @@ static int compare_function(FunctionSignature *sig, FunctionPrototype *proto) return 0; } -void c_abi_func_create(FunctionPrototype *proto); static inline Type *func_create_new_func_proto(FunctionSignature *sig, CallABI abi, uint32_t hash, FuncTypeEntry *entry) { diff --git a/src/target_info/target_info.c b/src/target_info/target_info.c deleted file mode 100644 index a58c2d7fe..000000000 --- a/src/target_info/target_info.c +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright (c) 2020 Christoffer Lerno. All rights reserved. -// Use of this source code is governed by a LGPLv3.0 -// a copy of which can be found in the LICENSE file. - -#include "target_info_internal.h" - -typedef enum -{ - AVXABI_LEVEL_NONE, - AVXABI_AVX, - AVXABI_512 -} X86AVXABILevel; - -static unsigned x86avxabi_vector_size(X86AVXABILevel level) -{ - switch (level) - { - case AVXABI_512: - return 512; - case AVXABI_AVX: - return 256; - case AVXABI_LEVEL_NONE: - return 128; - } - UNREACHABLE -} - -TargetInfo target_info_new() -{ - // From the glibc documentation, on GNU systems, malloc guarantees 16-byte - // alignment on 64-bit systems and 8-byte alignment on 32-bit systems. See - // https://www.gnu.org/software/libc/manual/html_node/Malloc-Examples.html. - // This alignment guarantee also applies to Windows and Android. - /* - if (T.isGNUEnvironment() || T.isWindowsMSVCEnvironment() || T.isAndroid()) - NewAlign = Triple.isArch64Bit() ? 128 : Triple.isArch32Bit() ? 64 : 0; - else - NewAlign = 0; // Infer from basic type alignment. - */ - TargetInfo target_info = { - .little_endian = true, - .asm_supported = false, - .float_128 = false, - .float_16 = false, - .align_pointer = 8, - .align_char = 8, - .align_c_int = 32, - .align_c_long = 32, - .align_c_long_long = 64, - .align_c_long_double = 64, - .align_f128 = 128, - .align_large_array = 0, - .align_global_min = 0, - .align_new = 0, - .align_max_vector = 0, - .align_simd_default = 0, - .width_pointer = 32, - .width_c_int = 32, - .width_c_long = 32, - .width_c_long_long = 64, - .width_c_long_double = 64, - .width_large_array_min = 0, - .width_c_wchar = 32, - .width_c_wint = 32, - .reg_param_max = 0, - .sse_reg_param_max = 0, - .builtin_ms_valist = false, - .aarch64sve_types = false, - .platform_name = "unknown" - }; - return target_info; -} - diff --git a/src/target_info/target_info.h b/src/target_info/target_info.h deleted file mode 100644 index 4bad859a1..000000000 --- a/src/target_info/target_info.h +++ /dev/null @@ -1,87 +0,0 @@ -#pragma once - -// Copyright (c) 2020 Christoffer Lerno. All rights reserved. -// Use of this source code is governed by a LGPLv3.0 -// a copy of which can be found in the LICENSE file. - -#include "utils/common.h" - - - - -typedef enum -{ - SUB_ARCH_NONE, - SUB_ARCH_ARM_V8_5A, - SUB_ARCH_ARM_V8_4A, - SUB_ARCH_ARM_V8_3A, - SUB_ARCH_ARM_V8_2A, - SUB_ARCH_ARM_V8_1A, - SUB_ARCH_ARM_V8, - SUB_ARCH_ARM_V8R, - SUB_ARCH_ARM_V8M_BASELINE, - SUB_ARCH_ARM_V8M_MAINLINE, - SUB_ARCH_ARM_V8_1M_MAINLINE, - SUB_ARCH_ARM_V7, - SUB_ARCH_ARM_V7EM, - SUB_ARCH_ARM_V7M, - SUB_ARCH_ARM_V7S, - SUB_ARCH_ARM_V7K, - SUB_ARCH_ARM_V7VE, - SUB_ARCH_ARM_V6, - SUB_ARCH_ARM_V6M, - SUB_ARCH_ARM_V6K, - SUB_ARCH_ARM_V6T2, - SUB_ARCH_ARM_V5, - SUB_ARCH_ARM_V5TE, - SUB_ARCH_ARM_V4, - SUB_ARCH_KALIMBA_V3, - SUB_ARCH_KALIMBA_V4, - SUB_ARCH_KALIMBA_V5, - SUB_ARCH_MIPS_V6, -} SubArchType; - - - - - -typedef struct -{ - bool little_endian; - bool tls_supported; - bool asm_supported; - bool float_128; - bool float_16; - unsigned align_pointer; - unsigned align_char; - unsigned align_short; - unsigned align_int; - unsigned align_long; - unsigned align_half; - unsigned align_float; - unsigned align_double; - unsigned align_f128; - unsigned align_c_long_double; - unsigned align_c_int; - unsigned align_c_long; - unsigned align_c_long_long; - unsigned align_simd_default; - unsigned align_max_vector; - unsigned align_global_min; - unsigned align_new; - unsigned align_large_array; - unsigned width_size; - unsigned width_pointer; - unsigned width_c_int; - unsigned width_c_long; - unsigned width_c_long_long; - unsigned width_c_long_double; - unsigned width_c_wchar; - unsigned width_c_wint; - unsigned width_large_array_min; - unsigned reg_param_max; - unsigned sse_reg_param_max; - unsigned builtin_ms_valist; - unsigned aarch64sve_types; - char *platform_name; -} TargetInfo; diff --git a/src/target_info/target_info_internal.h b/src/target_info/target_info_internal.h deleted file mode 100644 index 17457796e..000000000 --- a/src/target_info/target_info_internal.h +++ /dev/null @@ -1,7 +0,0 @@ -#pragma once - -// Copyright (c) 2020 Christoffer Lerno. All rights reserved. -// Use of this source code is governed by a LGPLv3.0 -// a copy of which can be found in the LICENSE file. - -#include "target_info.h" diff --git a/test/src/tester.py b/test/src/tester.py index 50ccbf34c..195efc290 100644 --- a/test/src/tester.py +++ b/test/src/tester.py @@ -58,6 +58,7 @@ class Issues: self.files = [] self.errors = {} self.warnings = {} + self.opts = [] def exit_error(self, message): print('Error in file ' + self.sourcefile.filepath + ': ' + message) @@ -109,7 +110,10 @@ class Issues: target = " --target " + self.arch if (self.debuginfo): debug = "-g " - code = subprocess.run(self.conf.compiler + target + ' -O0 ' + debug + args, universal_newlines=True, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + opts = "" + for opt in self.opts: + opts += ' -' + opt + code = subprocess.run(self.conf.compiler + target + ' -O0 ' + opts + ' ' + debug + 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() @@ -141,6 +145,9 @@ class Issues: if (line.startswith("debuginfo:")): self.debuginfo = line[10:].strip() == "yes" return + if (line.startswith("opt:")): + self.opts.append(line[4:].strip()) + return if (line.startswith("target:")): self.arch = line[7:].strip() return diff --git a/test/test_suite/abi/darwin64_avx.c3t b/test/test_suite/abi/darwin64_avx.c3t new file mode 100644 index 000000000..5fa641ee5 --- /dev/null +++ b/test/test_suite/abi/darwin64_avx.c3t @@ -0,0 +1,84 @@ +// #target: x64-darwin +// #opt: mavx +module test; + +define Mm256 = float[<8>]; +struct St256 { + Mm256 m; +} + +St256 x38; +Mm256 x37; + +extern fn void f38(St256 x); +extern fn void f37(Mm256 x); +fn void f39() { f38(x38); f37(x37); } + +// The two next tests make sure that the struct below is passed +// in the same way regardless of avx being used + +// CHECK: declare void @func40(%struct.t128* byval(%struct.t128) align 16) + +define Mm128 = float[<4>]; +struct Two128 { + Mm128 m; + Mm128 n; +} + +extern fn void func40(Two128 s); +fn void func41(Two128 s) { + func40(s); +} + +struct Atwo128 { + Mm128[2] array; +} + +struct Sa { + Atwo128 x; +} + +extern fn void func42(Sa s); +fn void func43(Sa s) { + func42(s); +} + + +define Vec46 = float[<2>]; +extern fn void f46(Vec46,Vec46,Vec46,Vec46,Vec46,Vec46,Vec46,Vec46,Vec46,Vec46); +fn void test46() { Vec46 x = {1,2}; f46(x,x,x,x,x,x,x,x,x,x); } + +struct Vec47 { uint a; } +extern fn void f47(int,int,int,int,int,int,Vec47); +fn void test47(int a, Vec47 b) { f47(a, a, a, a, a, a, b); } + +fn void test49_helper(double, ...); +fn void test49(double d, double e) { test49_helper(d, e); } + +extern fn void test52_helper(int, ...); +Mm256 x52; +fn void test52() { + test52_helper(0, x52, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0); +} + +/* #expect: test.ll + +declare void @f38(<8 x float>) +declare void @f37(<8 x float>) + +declare void @func40(%Two128* byval(%Two128) align 16) +define void @test.func41(%Two128* byval(%Two128) align 16 %0) + +declare void @func42(%Sa* byval(%Sa) align 16) +define void @test.func43(%Sa* byval(%Sa) align 16 %0) + +declare void @f46(double, double, double, double, double, double, double, double, <2 x float>* byval(<2 x float>) align 8, <2 x float>* byval(<2 x float>) align 8) +declare void @f47(i32, i32, i32, i32, i32, i32, i32) + +declare void @test.test49_helper(double, ...) +define void @test.test49(double %0, double %1) +entry: + call void (double, ...) @test.test49_helper(double %0, double %1) + ret void + +call void (i32, ...) @test52_helper(i32 0, <8 x float>* byval(<8 x float>) align 32 %indirectarg, double 1.000000e+00, double 1.000000e+00, double 1.000000e+00, double 1.000000e+00, double 1.000000e+00, double 1.000000e+00, double 1.000000e+00) diff --git a/test/test_suite/abi/darwin64_sse.c3t b/test/test_suite/abi/darwin64_sse.c3t new file mode 100644 index 000000000..a5f72c419 --- /dev/null +++ b/test/test_suite/abi/darwin64_sse.c3t @@ -0,0 +1,55 @@ +// #target: x64-darwin +// #opt: mno-avx +module test; + +define Mm256 = float[<8>]; +struct St256 { + Mm256 m; +} + +St256 x38; +Mm256 x37; + +extern fn void f38(St256 x); +extern fn void f37(Mm256 x); +fn void f39() { f38(x38); f37(x37); } + +// The two next tests make sure that the struct below is passed +// in the same way regardless of avx being used + +// CHECK: declare void @func40(%struct.t128* byval(%struct.t128) align 16) + +define Mm128 = float[<4>]; +struct Two128 { + Mm128 m; + Mm128 n; +} + +extern fn void func40(Two128 s); +fn void func41(Two128 s) { + func40(s); +} + +struct Atwo128 { + Mm128[2] array; +} + +struct Sa { + Atwo128 x; +} + +extern fn void func42(Sa s); +fn void func43(Sa s) { + func42(s); +} + +/* #expect: test.ll + +declare void @f38(%St256* byval(%St256) align 32) +declare void @f37(<8 x float>* byval(<8 x float>) align 32) + +declare void @func40(%Two128* byval(%Two128) align 16) +define void @test.func41(%Two128* byval(%Two128) align 16 %0) + +declare void @func42(%Sa* byval(%Sa) align 16) +define void @test.func43(%Sa* byval(%Sa) align 16 %0) diff --git a/test/test_suite/abi/darwinx64_2.c3t b/test/test_suite/abi/darwinx64_2.c3t index be5684fc1..239d81250 100644 --- a/test/test_suite/abi/darwinx64_2.c3t +++ b/test/test_suite/abi/darwinx64_2.c3t @@ -64,6 +64,86 @@ fn float[<4>] f25(float[<4>] x) { return x+x; } +struct Foo26 { + int *x; + float *y; +} + +fn Foo26 f26(Foo26 *p) { + return *p; +} + + +struct V4f32wrapper { + float[<4>] v; +} + +fn V4f32wrapper f27(V4f32wrapper x) { + return x; +} + +// PR22563 - We should unwrap simple structs and arrays to pass +// and return them in the appropriate vector registers if possible. + +define V8f32 = float[<8>]; +struct V8f32wrapper { + V8f32 v; +} + +fn V8f32wrapper f27a(V8f32wrapper x) { + return x; +} + +struct V8f32wrapper_wrapper { + V8f32[1] v; +} + +fn V8f32wrapper_wrapper f27b(V8f32wrapper_wrapper x) { + return x; +} + +struct F28c { + double x; + int y; +} +fn void f28(F28c c) { +} + +struct Inner +{ + double x; + int y; +} +struct F29a +{ + Inner[1] c; +} + +fn void f29a(F29a a) { +} + +struct St0 { + char[8] f0; char f2; char f3; char f4; } +fn void f30(St0 p_4) { +} + +struct F31foo { float a, b, c; } +fn float f31(F31foo x) { + return x.c; +} + +define V1i64 = ulong[<1>]; + +fn V1i64 f34(V1i64 arg) { return arg; } + + +define V1i64_2 = uint[<2>]; +fn V1i64_2 f35(V1i64_2 arg) { return arg+arg; } + +define V2i32 = float[<2>]; +fn V2i32 f36(V2i32 arg) { return arg; } + + /* #expect: test.ll define i32 @test.f12_0() @@ -91,3 +171,15 @@ entry: %fadd = fadd <4 x float> %0, %0 ret <4 x float> %fadd } + +define { i32*, float* } @test.f26(%Foo26* %0) +define <4 x float> @test.f27(<4 x float> %0) +define <8 x float> @test.f27a(<8 x float> %0) +define <8 x float> @test.f27b(<8 x float> %0) +define void @test.f28(double %0, i32 %1) +define void @test.f29a(double %0, i32 %1) +define void @test.f30(i64 %0, i24 %1) +define float @test.f31(<2 x float> %0, float %1) +define double @test.f34(double %0) +define double @test.f35(double %0) +define double @test.f36(double %0)