Merge remote-tracking branch 'origin' into libc-wasi-test

This commit is contained in:
Takeshi Yoneda
2021-08-09 14:39:26 +09:00
437 changed files with 10206 additions and 65011 deletions

View File

@@ -2144,75 +2144,103 @@ static bool iter_function_params_c_abi(CodeGen *g, ZigType *fn_type, FnWalk *fn_
}
}
return true;
} else if (abi_class == X64CABIClass_SSE) {
// For now only handle structs with only floats/doubles in it.
if (ty->id != ZigTypeIdStruct) {
if (source_node != nullptr) {
give_up_with_c_abi_error(g, source_node);
}
// otherwise allow codegen code to report a compile error
return false;
}
for (uint32_t i = 0; i < ty->data.structure.src_field_count; i += 1) {
if (ty->data.structure.fields[i]->type_entry->id != ZigTypeIdFloat) {
if (source_node != nullptr) {
give_up_with_c_abi_error(g, source_node);
}
// otherwise allow codegen code to report a compile error
return false;
}
}
// The SystemV ABI says that we have to setup 1 FP register per f64.
} else if (abi_class == X64CABIClass_AGG) {
// The SystemV ABI says that we have to setup 1 register per eightbyte.
// So two f32 can be passed in one f64, but 3 f32 have to be passed in 2 FP registers.
// To achieve this with LLVM API, we pass multiple f64 parameters to the LLVM function if
// the type is bigger than 8 bytes.
// Similarly, two i32 can be passed in one i64, but 3 i32 have to be passed in 2 registers.
// LLVM does not allow us to control registers in this way, nor to request specific
// ABI conventions. So we have to trick it into allocating the right registers, based
// on how clang does it.
// First, we get the LLVM type corresponding to the C abi for the struct, then
// we pass each field as an argument.
// Example:
// extern struct {
// x: f32,
// y: f32,
// z: f32,
// z: i32,
// };
// const ptr = (*f64)*Struct;
// Register 1: ptr.*
// Register 2: (ptr + 1).*
// LLVM abi type: { double, i32 }
// const ptr = (*abi_type)*Struct;
// FP Register 1: abi_type[0]
// Register 1: abi_type[1]
// One floating point register per f64 or 2 f32's
size_t number_of_fp_regs = (ty_size + 7) / 8;
// However, if the struct fits in one register, then we'll pass it as such
size_t number_of_regs = (size_t)ceilf((float)ty_size / (float)8);
LLVMTypeRef abi_type = get_llvm_c_abi_type(g, ty);
assert(ty_size <= 16);
switch (fn_walk->id) {
case FnWalkIdAttrs: {
fn_walk->data.attrs.gen_i += number_of_fp_regs;
fn_walk->data.attrs.gen_i += number_of_regs;
break;
}
case FnWalkIdCall: {
LLVMValueRef f64_ptr_to_struct = LLVMBuildBitCast(g->builder, val, LLVMPointerType(LLVMDoubleType(), 0), "");
for (uint32_t i = 0; i < number_of_fp_regs; i += 1) {
LLVMValueRef index = LLVMConstInt(g->builtin_types.entry_usize->llvm_type, i, false);
LLVMValueRef indices[] = { index };
LLVMValueRef adjusted_ptr_to_struct = LLVMBuildInBoundsGEP(g->builder, f64_ptr_to_struct, indices, 1, "");
LLVMValueRef abi_ptr_to_struct = LLVMBuildBitCast(g->builder, val, LLVMPointerType(abi_type, 0), "");
if (number_of_regs == 1) {
LLVMValueRef loaded = LLVMBuildLoad(g->builder, abi_ptr_to_struct, "");
fn_walk->data.call.gen_param_values->append(loaded);
break;
}
for (uint32_t i = 0; i < number_of_regs; i += 1) {
LLVMValueRef zero = LLVMConstInt(LLVMInt32Type(), 0, false);
LLVMValueRef index = LLVMConstInt(LLVMInt32Type(), i, false);
LLVMValueRef indices[] = { zero, index };
LLVMValueRef adjusted_ptr_to_struct = LLVMBuildInBoundsGEP(g->builder, abi_ptr_to_struct, indices, 2, "");
LLVMValueRef loaded = LLVMBuildLoad(g->builder, adjusted_ptr_to_struct, "");
fn_walk->data.call.gen_param_values->append(loaded);
}
break;
}
case FnWalkIdTypes: {
for (uint32_t i = 0; i < number_of_fp_regs; i += 1) {
fn_walk->data.types.gen_param_types->append(get_llvm_type(g, g->builtin_types.entry_f64));
if (number_of_regs == 1) {
fn_walk->data.types.gen_param_types->append(abi_type);
fn_walk->data.types.param_di_types->append(get_llvm_di_type(g, g->builtin_types.entry_f64));
break;
}
for (uint32_t i = 0; i < number_of_regs; i += 1) {
fn_walk->data.types.gen_param_types->append(LLVMStructGetTypeAtIndex(abi_type, i));
fn_walk->data.types.param_di_types->append(get_llvm_di_type(g, g->builtin_types.entry_f64));
}
break;
}
case FnWalkIdVars:
case FnWalkIdVars: {
var->value_ref = build_alloca(g, ty, var->name, var->align_bytes);
di_arg_index = fn_walk->data.vars.gen_i;
fn_walk->data.vars.gen_i += 1;
dest_ty = ty;
goto var_ok;
}
case FnWalkIdInits: {
// TODO: Handle exporting functions
if (source_node != nullptr) {
give_up_with_c_abi_error(g, source_node);
// since we're representing the struct differently as an arg, and potentially
// splitting it, we have to do some work to put it back together.
// the one reg case is straightforward, but if we used two registers we have
// to iterate through the struct abi repr fields and load them one by one.
if (number_of_regs == 1) {
LLVMValueRef arg = LLVMGetParam(llvm_fn, fn_walk->data.inits.gen_i);
LLVMTypeRef ptr_to_int_type_ref = LLVMPointerType(abi_type, 0);
LLVMValueRef bitcasted = LLVMBuildBitCast(g->builder, var->value_ref, ptr_to_int_type_ref, "");
gen_store_untyped(g, arg, bitcasted, var->align_bytes, false);
} else {
LLVMValueRef abi_ptr_to_struct = LLVMBuildBitCast(g->builder, var->value_ref, LLVMPointerType(abi_type, 0), "");
for (uint32_t i = 0; i < number_of_regs; i += 1) {
LLVMValueRef arg = LLVMGetParam(llvm_fn, fn_walk->data.inits.gen_i + i);
LLVMValueRef zero = LLVMConstInt(LLVMInt32Type(), 0, false);
LLVMValueRef index = LLVMConstInt(LLVMInt32Type(), i, false);
LLVMValueRef indices[] = { zero, index };
LLVMValueRef adjusted_ptr_to_struct = LLVMBuildInBoundsGEP(g->builder, abi_ptr_to_struct, indices, 2, "");
LLVMBuildStore(g->builder, arg, adjusted_ptr_to_struct);
}
fn_walk->data.inits.gen_i += 1;
}
// otherwise allow codegen code to report a compile error
return false;
if (var->decl_node) {
gen_var_debug_decl(g, var);
}
fn_walk->data.inits.gen_i += 1;
break;
}
}
return true;
@@ -2656,13 +2684,36 @@ static void gen_async_return(CodeGen *g, Stage1AirInstReturn *instruction) {
LLVMBuildRetVoid(g->builder);
}
static LLVMValueRef gen_convert_to_c_abi(CodeGen *g, LLVMValueRef location, LLVMValueRef value) {
ZigType *return_type = g->cur_fn->type_entry->data.fn.gen_return_type;
size_t size = type_size(g, return_type);
LLVMTypeRef abi_return_type = get_llvm_c_abi_type(g, return_type);
LLVMTypeRef abi_return_type_pointer = LLVMPointerType(abi_return_type, 0);
if (size < 8) {
LLVMValueRef bitcast = LLVMBuildBitCast(g->builder, value, abi_return_type_pointer, "");
return LLVMBuildLoad(g->builder, bitcast, "");
} else {
LLVMTypeRef i8ptr = LLVMPointerType(LLVMInt8Type(), 0);
LLVMValueRef bc_location = LLVMBuildBitCast(g->builder, location, i8ptr, "");
LLVMValueRef bc_value = LLVMBuildBitCast(g->builder, value, i8ptr, "");
LLVMValueRef len = LLVMConstInt(LLVMInt64Type(), size, false);
ZigLLVMBuildMemCpy(g->builder, bc_location, 8, bc_value, return_type->abi_align, len, false);
return LLVMBuildLoad(g->builder, location, "");
}
}
static LLVMValueRef ir_render_return(CodeGen *g, Stage1Air *executable, Stage1AirInstReturn *instruction) {
if (fn_is_async(g->cur_fn)) {
gen_async_return(g, instruction);
return nullptr;
}
if (want_first_arg_sret(g, &g->cur_fn->type_entry->data.fn.fn_type_id)) {
FnTypeId *fn_type_id = &g->cur_fn->type_entry->data.fn.fn_type_id;
if (want_first_arg_sret(g, fn_type_id)) {
if (instruction->operand == nullptr) {
LLVMBuildRetVoid(g->builder);
return nullptr;
@@ -2673,6 +2724,16 @@ static LLVMValueRef ir_render_return(CodeGen *g, Stage1Air *executable, Stage1Ai
ZigType *return_type = instruction->operand->value->type;
gen_assign_raw(g, g->cur_ret_ptr, get_pointer_to_type(g, return_type, false), value);
LLVMBuildRetVoid(g->builder);
} else if (fn_returns_c_abi_small_struct(fn_type_id)) {
LLVMValueRef location = g->cur_fn->abi_return_value;
if (instruction->operand == nullptr) {
LLVMValueRef converted = gen_convert_to_c_abi(g, location, g->cur_ret_ptr);
LLVMBuildRet(g->builder, converted);
} else {
LLVMValueRef value = ir_llvm_value(g, instruction->operand);
LLVMValueRef converted = gen_convert_to_c_abi(g, location, value);
LLVMBuildRet(g->builder, converted);
}
} else if (g->cur_fn->type_entry->data.fn.fn_type_id.cc != CallingConventionAsync &&
handle_is_ptr(g, g->cur_fn->type_entry->data.fn.fn_type_id.return_type))
{
@@ -3250,6 +3311,30 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, Stage1Air *executable,
case IrBinOpRemMod:
return gen_rem(g, want_runtime_safety, ir_want_fast_math(g, &bin_op_instruction->base),
op1_value, op2_value, operand_type, RemKindMod);
case IrBinOpMaximum:
if (scalar_type->id == ZigTypeIdFloat) {
return ZigLLVMBuildMaxNum(g->builder, op1_value, op2_value, "");
} else if (scalar_type->id == ZigTypeIdInt) {
if (scalar_type->data.integral.is_signed) {
return ZigLLVMBuildSMax(g->builder, op1_value, op2_value, "");
} else {
return ZigLLVMBuildUMax(g->builder, op1_value, op2_value, "");
}
} else {
zig_unreachable();
}
case IrBinOpMinimum:
if (scalar_type->id == ZigTypeIdFloat) {
return ZigLLVMBuildMinNum(g->builder, op1_value, op2_value, "");
} else if (scalar_type->id == ZigTypeIdInt) {
if (scalar_type->data.integral.is_signed) {
return ZigLLVMBuildSMin(g->builder, op1_value, op2_value, "");
} else {
return ZigLLVMBuildUMin(g->builder, op1_value, op2_value, "");
}
} else {
zig_unreachable();
}
}
zig_unreachable();
}
@@ -4656,6 +4741,12 @@ static LLVMValueRef ir_render_call(CodeGen *g, Stage1Air *executable, Stage1AirI
} else if (first_arg_ret) {
ZigLLVMSetCallSret(result, get_llvm_type(g, src_return_type));
return result_loc;
} else if (fn_returns_c_abi_small_struct(fn_type_id)) {
LLVMTypeRef abi_type = get_llvm_c_abi_type(g, src_return_type);
LLVMTypeRef abi_type_ptr = LLVMPointerType(abi_type, 0);
LLVMValueRef bitcast = LLVMBuildBitCast(g->builder, result_loc, abi_type_ptr, "");
LLVMBuildStore(g->builder, result, bitcast);
return result_loc;
} else if (handle_is_ptr(g, src_return_type)) {
LLVMValueRef store_instr = LLVMBuildStore(g->builder, result, result_loc);
LLVMSetAlignment(store_instr, get_ptr_align(g, instruction->result_loc->value->type));
@@ -5164,6 +5255,13 @@ static LLVMValueRef ir_render_shuffle_vector(CodeGen *g, Stage1Air *executable,
llvm_mask_value, "");
}
static LLVMValueRef ir_render_select(CodeGen *g, Stage1Air *executable, Stage1AirInstSelect *instruction) {
LLVMValueRef pred = ir_llvm_value(g, instruction->pred);
LLVMValueRef a = ir_llvm_value(g, instruction->a);
LLVMValueRef b = ir_llvm_value(g, instruction->b);
return LLVMBuildSelect(g->builder, pred, a, b, "");
}
static LLVMValueRef ir_render_splat(CodeGen *g, Stage1Air *executable, Stage1AirInstSplat *instruction) {
ZigType *result_type = instruction->base.value->type;
ir_assert(result_type->id == ZigTypeIdVector, &instruction->base);
@@ -7017,6 +7115,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, Stage1Air *executable, Sta
return ir_render_spill_end(g, executable, (Stage1AirInstSpillEnd *)instruction);
case Stage1AirInstIdShuffleVector:
return ir_render_shuffle_vector(g, executable, (Stage1AirInstShuffleVector *) instruction);
case Stage1AirInstIdSelect:
return ir_render_select(g, executable, (Stage1AirInstSelect *) instruction);
case Stage1AirInstIdSplat:
return ir_render_splat(g, executable, (Stage1AirInstSplat *) instruction);
case Stage1AirInstIdVectorExtractElem:
@@ -8260,6 +8360,11 @@ static void do_code_gen(CodeGen *g) {
g->cur_err_ret_trace_val_stack = nullptr;
}
if (fn_returns_c_abi_small_struct(fn_type_id)) {
LLVMTypeRef abi_type = get_llvm_c_abi_type(g, fn_type_id->return_type);
fn_table_entry->abi_return_value = LLVMBuildAlloca(g->builder, abi_type, "");
}
if (!is_async) {
// allocate async frames for nosuspend calls & awaits to async functions
ZigType *largest_call_frame_type = nullptr;
@@ -8763,6 +8868,9 @@ static void define_builtin_types(CodeGen *g) {
case ZigLLVM_sparcv9:
add_fp_entry(g, "c_longdouble", 128, LLVMFP128Type(), &g->builtin_types.entry_c_longdouble);
break;
case ZigLLVM_systemz:
add_fp_entry(g, "c_longdouble", 128, LLVMDoubleType(), &g->builtin_types.entry_c_longdouble);
break;
case ZigLLVM_avr:
// It's either a float or a double, depending on a toolchain switch
add_fp_entry(g, "c_longdouble", 64, LLVMDoubleType(), &g->builtin_types.entry_c_longdouble);
@@ -8922,6 +9030,7 @@ static void define_builtin_fns(CodeGen *g) {
create_builtin_fn(g, BuiltinFnIdCompileLog, "compileLog", SIZE_MAX);
create_builtin_fn(g, BuiltinFnIdVectorType, "Vector", 2);
create_builtin_fn(g, BuiltinFnIdShuffle, "shuffle", 4);
create_builtin_fn(g, BuiltinFnIdSelect, "select", 4);
create_builtin_fn(g, BuiltinFnIdSplat, "splat", 2);
create_builtin_fn(g, BuiltinFnIdSetCold, "setCold", 1);
create_builtin_fn(g, BuiltinFnIdSetRuntimeSafety, "setRuntimeSafety", 1);
@@ -8982,6 +9091,8 @@ static void define_builtin_fns(CodeGen *g) {
create_builtin_fn(g, BuiltinFnIdWasmMemoryGrow, "wasmMemoryGrow", 2);
create_builtin_fn(g, BuiltinFnIdSrc, "src", 0);
create_builtin_fn(g, BuiltinFnIdReduce, "reduce", 2);
create_builtin_fn(g, BuiltinFnIdMaximum, "maximum", 2);
create_builtin_fn(g, BuiltinFnIdMinimum, "minimum", 2);
}
static const char *bool_to_str(bool b) {