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)
|
option(C3_USE_MIMALLOC "Use built-in mimalloc" OFF)
|
||||||
set(C3_MIMALLOC_TAG "v1.7.3" CACHE STRING "Used version of mimalloc")
|
set(C3_MIMALLOC_TAG "v1.7.3" CACHE STRING "Used version of mimalloc")
|
||||||
|
|
||||||
|
set(C3_USE_MIMALLOC OFF)
|
||||||
if(C3_USE_MIMALLOC)
|
if(C3_USE_MIMALLOC)
|
||||||
option(MI_BUILD_TESTS OFF)
|
option(MI_BUILD_TESTS OFF)
|
||||||
option(MI_BUILD_SHARED OFF)
|
option(MI_BUILD_SHARED OFF)
|
||||||
@@ -180,7 +181,6 @@ add_executable(c3c
|
|||||||
src/compiler/tokens.c
|
src/compiler/tokens.c
|
||||||
src/compiler/types.c
|
src/compiler/types.c
|
||||||
src/main.c
|
src/main.c
|
||||||
src/target_info/target_info.c
|
|
||||||
src/utils/errors.c
|
src/utils/errors.c
|
||||||
src/utils/file_utils.c
|
src/utils/file_utils.c
|
||||||
src/utils/find_msvc.c
|
src/utils/find_msvc.c
|
||||||
|
|||||||
@@ -389,6 +389,22 @@ static void parse_option(BuildOptions *options)
|
|||||||
FAIL_WITH_ERR("Invalid optimization level.");
|
FAIL_WITH_ERR("Invalid optimization level.");
|
||||||
}
|
}
|
||||||
return;
|
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':
|
case 'E':
|
||||||
if (options->compile_option != COMPILE_NORMAL)
|
if (options->compile_option != COMPILE_NORMAL)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -204,6 +204,9 @@ typedef struct BuildOptions_
|
|||||||
bool emit_bitcode;
|
bool emit_bitcode;
|
||||||
bool test_mode;
|
bool test_mode;
|
||||||
bool no_stdlib;
|
bool no_stdlib;
|
||||||
|
bool no_avx;
|
||||||
|
bool avx;
|
||||||
|
bool avx512;
|
||||||
} BuildOptions;
|
} BuildOptions;
|
||||||
|
|
||||||
|
|
||||||
@@ -262,6 +265,8 @@ typedef struct
|
|||||||
bool no_sse : 1;
|
bool no_sse : 1;
|
||||||
bool no_mmx : 1;
|
bool no_mmx : 1;
|
||||||
bool no_avx : 1;
|
bool no_avx : 1;
|
||||||
|
bool avx : 1;
|
||||||
|
bool avx512 : 1;
|
||||||
} feature;
|
} feature;
|
||||||
} BuildTarget;
|
} BuildTarget;
|
||||||
|
|
||||||
|
|||||||
@@ -117,6 +117,9 @@ static void update_build_target_from_options(BuildTarget *target, BuildOptions *
|
|||||||
}
|
}
|
||||||
target->no_stdlib = options->no_stdlib;
|
target->no_stdlib = options->no_stdlib;
|
||||||
target->emit_llvm = options->emit_llvm;
|
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)
|
switch (options->compile_option)
|
||||||
{
|
{
|
||||||
case COMPILE_NORMAL:
|
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
|
// 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.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.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_avx = get_valid_bool(table, "no-avx", type, false);
|
||||||
target->feature.no_sse = get_valid_bool(table, "no-sse", 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);
|
target->feature.no_mmx = get_valid_bool(table, "no-mmx", type, false);
|
||||||
|
|||||||
@@ -1561,11 +1561,13 @@ typedef struct FunctionPrototype_
|
|||||||
bool ret_by_ref : 1;
|
bool ret_by_ref : 1;
|
||||||
Type *rtype;
|
Type *rtype;
|
||||||
Type **params;
|
Type **params;
|
||||||
|
Type **varargs;
|
||||||
Type *ret_by_ref_type;
|
Type *ret_by_ref_type;
|
||||||
Type *abi_ret_type;
|
Type *abi_ret_type;
|
||||||
ABIArgInfo *ret_abi_info;
|
ABIArgInfo *ret_abi_info;
|
||||||
ABIArgInfo *ret_by_ref_abi_info;
|
ABIArgInfo *ret_by_ref_abi_info;
|
||||||
ABIArgInfo **abi_args;
|
ABIArgInfo **abi_args;
|
||||||
|
ABIArgInfo **abi_varargs;
|
||||||
void *tb_prototype;
|
void *tb_prototype;
|
||||||
} FunctionPrototype;
|
} FunctionPrototype;
|
||||||
|
|
||||||
@@ -2050,6 +2052,7 @@ void *llvm_target_machine_create(void);
|
|||||||
void target_setup(BuildTarget *build_target);
|
void target_setup(BuildTarget *build_target);
|
||||||
int target_alloca_addr_space();
|
int target_alloca_addr_space();
|
||||||
|
|
||||||
|
void c_abi_func_create(FunctionPrototype *proto);
|
||||||
|
|
||||||
bool token_is_type(TokenType type);
|
bool token_is_type(TokenType type);
|
||||||
bool token_is_any_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;
|
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;
|
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;
|
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;
|
res = element;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
res = LLVMBuildOr(c->builder, element, res, "");
|
res = LLVMBuildOr(c->builder, element, res, "");
|
||||||
}
|
}
|
||||||
if (big_endian)
|
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);
|
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)
|
void llvm_emit_call_expr(GenContext *c, BEValue *result_value, Expr *expr)
|
||||||
{
|
{
|
||||||
if (expr->call_expr.is_builtin)
|
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;
|
ABIArgInfo **abi_args = prototype->abi_args;
|
||||||
unsigned param_count = vec_size(params);
|
unsigned param_count = vec_size(params);
|
||||||
unsigned non_variadic_params = param_count;
|
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--;
|
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;
|
ABIArgInfo *ret_info = prototype->ret_abi_info;
|
||||||
Type *call_return_type = prototype->abi_ret_type;
|
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.
|
// 8. Add all other arguments.
|
||||||
unsigned arguments = vec_size(expr->call_expr.arguments);
|
|
||||||
assert(arguments >= non_variadic_params);
|
assert(arguments >= non_variadic_params);
|
||||||
for (unsigned i = 0; i < non_variadic_params; i++)
|
for (unsigned i = 0; i < non_variadic_params; i++)
|
||||||
{
|
{
|
||||||
// 8a. Evaluate the expression.
|
// 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);
|
llvm_emit_expr(c, &temp_value, arg_expr);
|
||||||
|
|
||||||
// 8b. Emit the parameter according to ABI rules.
|
// 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
|
else
|
||||||
{
|
{
|
||||||
// 9. Emit varargs.
|
if (prototype->abi_varargs)
|
||||||
for (unsigned i = param_count; i < arguments; i++)
|
|
||||||
{
|
{
|
||||||
Expr *arg_expr = expr->call_expr.arguments[i];
|
// 9. Emit varargs.
|
||||||
llvm_emit_expr(c, &temp_value, arg_expr);
|
unsigned index = 0;
|
||||||
REMINDER("Varargs should be expanded correctly");
|
ABIArgInfo **abi_varargs = prototype->abi_varargs;
|
||||||
vec_add(values, llvm_load_value_store(c, &temp_value));
|
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];
|
llvm_add_call_attributes(c, call_value, 1 + non_variadic_params, vec_size(prototype->varargs), prototype->varargs, prototype->abi_varargs);
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 11. Process the return value.
|
// 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_fold_failable(GenContext *c, BEValue *value);
|
||||||
void llvm_value_struct_gep(GenContext *c, BEValue *element, BEValue *struct_pointer, unsigned index);
|
void llvm_value_struct_gep(GenContext *c, BEValue *element, BEValue *struct_pointer, unsigned index);
|
||||||
|
|
||||||
|
|
||||||
LLVMTypeRef llvm_abi_type(GenContext *c, AbiType type);
|
LLVMTypeRef llvm_abi_type(GenContext *c, AbiType type);
|
||||||
TypeSize llvm_abi_size(GenContext *c, LLVMTypeRef type);
|
TypeSize llvm_abi_size(GenContext *c, LLVMTypeRef type);
|
||||||
BitSize llvm_bitsize(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_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_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);
|
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 ---
|
// -- instr ---
|
||||||
void llvm_emit_cond_br(GenContext *context, BEValue *value, LLVMBasicBlockRef then_block, LLVMBasicBlockRef else_block);
|
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);
|
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;
|
LLVMTypeRef *params = NULL;
|
||||||
FunctionPrototype *prototype = type->func.prototype;
|
|
||||||
|
|
||||||
LLVMTypeRef return_type = NULL;
|
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);
|
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);
|
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:
|
case TYPE_BITSTRUCT:
|
||||||
return any_type->backend_type = llvm_type_from_decl(c, any_type->decl);
|
return any_type->backend_type = llvm_type_from_decl(c, any_type->decl);
|
||||||
case TYPE_FUNC:
|
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:
|
case TYPE_VOID:
|
||||||
return any_type->backend_type = LLVMVoidTypeInContext(c->context);
|
return any_type->backend_type = LLVMVoidTypeInContext(c->context);
|
||||||
case TYPE_F64:
|
case TYPE_F64:
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
#include <llvm-c/Target.h>
|
#include <llvm-c/Target.h>
|
||||||
#include <llvm-c/TargetMachine.h>
|
#include <llvm-c/TargetMachine.h>
|
||||||
#include <llvm-c/Core.h>
|
#include <llvm-c/Core.h>
|
||||||
#include <target_info/target_info.h>
|
|
||||||
#include "compiler_internal.h"
|
#include "compiler_internal.h"
|
||||||
|
|
||||||
static unsigned arch_pointer_bit_width(OsType os, ArchType arch);
|
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.abi = ABI_X64;
|
||||||
platform_target.x64.avx_level = AVX;
|
platform_target.x64.avx_level = AVX;
|
||||||
platform_target.x64.is_win64 = platform_target.os == OS_TYPE_WIN32;
|
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_avx) platform_target.x64.avx_level = AVX_NONE;
|
||||||
if (target->feature.no_mmx) platform_target.x64.no_mmx = true;
|
if (target->feature.no_mmx) platform_target.x64.no_mmx = true;
|
||||||
if (target->feature.no_sse) platform_target.x64.no_sse = 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;
|
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)
|
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.files = []
|
||||||
self.errors = {}
|
self.errors = {}
|
||||||
self.warnings = {}
|
self.warnings = {}
|
||||||
|
self.opts = []
|
||||||
|
|
||||||
def exit_error(self, message):
|
def exit_error(self, message):
|
||||||
print('Error in file ' + self.sourcefile.filepath + ': ' + message)
|
print('Error in file ' + self.sourcefile.filepath + ': ' + message)
|
||||||
@@ -109,7 +110,10 @@ class Issues:
|
|||||||
target = " --target " + self.arch
|
target = " --target " + self.arch
|
||||||
if (self.debuginfo):
|
if (self.debuginfo):
|
||||||
debug = "-g "
|
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)
|
os.chdir(self.conf.cwd)
|
||||||
if code.returncode != 0 and code.returncode != 1:
|
if code.returncode != 0 and code.returncode != 1:
|
||||||
self.set_failed()
|
self.set_failed()
|
||||||
@@ -141,6 +145,9 @@ class Issues:
|
|||||||
if (line.startswith("debuginfo:")):
|
if (line.startswith("debuginfo:")):
|
||||||
self.debuginfo = line[10:].strip() == "yes"
|
self.debuginfo = line[10:].strip() == "yes"
|
||||||
return
|
return
|
||||||
|
if (line.startswith("opt:")):
|
||||||
|
self.opts.append(line[4:].strip())
|
||||||
|
return
|
||||||
if (line.startswith("target:")):
|
if (line.startswith("target:")):
|
||||||
self.arch = line[7:].strip()
|
self.arch = line[7:].strip()
|
||||||
return
|
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;
|
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
|
/* #expect: test.ll
|
||||||
|
|
||||||
define i32 @test.f12_0()
|
define i32 @test.f12_0()
|
||||||
@@ -91,3 +171,15 @@ entry:
|
|||||||
%fadd = fadd <4 x float> %0, %0
|
%fadd = fadd <4 x float> %0, %0
|
||||||
ret <4 x float> %fadd
|
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