mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
Correctly call x64 varargs.
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#include <llvm-c/Target.h>
|
||||
#include <llvm-c/TargetMachine.h>
|
||||
#include <llvm-c/Core.h>
|
||||
#include <target_info/target_info.h>
|
||||
#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;
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
@@ -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"
|
||||
@@ -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
|
||||
|
||||
84
test/test_suite/abi/darwin64_avx.c3t
Normal file
84
test/test_suite/abi/darwin64_avx.c3t
Normal file
@@ -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)
|
||||
55
test/test_suite/abi/darwin64_sse.c3t
Normal file
55
test/test_suite/abi/darwin64_sse.c3t
Normal file
@@ -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)
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user