Merge pull request #10738 from Vexu/f80
Add compiler-rt functions for f80
This commit is contained in:
@@ -3240,6 +3240,49 @@ static LLVMValueRef get_soft_f80_bin_op_func(CodeGen *g, const char *name, int p
|
||||
return LLVMAddFunction(g->module, name, fn_type);
|
||||
}
|
||||
|
||||
enum SoftF80Icmp {
|
||||
NONE,
|
||||
EQ_ZERO,
|
||||
NE_ZERO,
|
||||
LE_ZERO,
|
||||
EQ_NEG,
|
||||
GE_ZERO,
|
||||
EQ_ONE,
|
||||
};
|
||||
|
||||
static LLVMValueRef add_f80_icmp(CodeGen *g, LLVMValueRef val, SoftF80Icmp kind) {
|
||||
switch (kind) {
|
||||
case NONE:
|
||||
return val;
|
||||
case EQ_ZERO: {
|
||||
LLVMValueRef zero = LLVMConstInt(g->builtin_types.entry_i32->llvm_type, 0, true);
|
||||
return LLVMBuildICmp(g->builder, LLVMIntEQ, val, zero, "");
|
||||
}
|
||||
case NE_ZERO: {
|
||||
LLVMValueRef zero = LLVMConstInt(g->builtin_types.entry_i32->llvm_type, 0, true);
|
||||
return LLVMBuildICmp(g->builder, LLVMIntNE, val, zero, "");
|
||||
}
|
||||
case LE_ZERO: {
|
||||
LLVMValueRef zero = LLVMConstInt(g->builtin_types.entry_i32->llvm_type, 0, true);
|
||||
return LLVMBuildICmp(g->builder, LLVMIntSLE, val, zero, "");
|
||||
}
|
||||
case EQ_NEG: {
|
||||
LLVMValueRef zero = LLVMConstInt(g->builtin_types.entry_i32->llvm_type, -1, true);
|
||||
return LLVMBuildICmp(g->builder, LLVMIntEQ, val, zero, "");
|
||||
}
|
||||
case GE_ZERO: {
|
||||
LLVMValueRef zero = LLVMConstInt(g->builtin_types.entry_i32->llvm_type, 0, true);
|
||||
return LLVMBuildICmp(g->builder, LLVMIntSGE, val, zero, "");
|
||||
}
|
||||
case EQ_ONE: {
|
||||
LLVMValueRef zero = LLVMConstInt(g->builtin_types.entry_i32->llvm_type, 1, true);
|
||||
return LLVMBuildICmp(g->builder, LLVMIntEQ, val, zero, "");
|
||||
}
|
||||
default:
|
||||
zig_unreachable();
|
||||
}
|
||||
}
|
||||
|
||||
static LLVMValueRef ir_render_soft_f80_bin_op(CodeGen *g, Stage1Air *executable,
|
||||
Stage1AirInstBinOp *bin_op_instruction)
|
||||
{
|
||||
@@ -3255,6 +3298,7 @@ static LLVMValueRef ir_render_soft_f80_bin_op(CodeGen *g, Stage1Air *executable,
|
||||
LLVMTypeRef return_type = g->builtin_types.entry_f80->llvm_type;
|
||||
int param_count = 2;
|
||||
const char *func_name;
|
||||
SoftF80Icmp res_icmp = NONE;
|
||||
switch (op_id) {
|
||||
case IrBinOpInvalid:
|
||||
case IrBinOpArrayCat:
|
||||
@@ -3280,20 +3324,32 @@ static LLVMValueRef ir_render_soft_f80_bin_op(CodeGen *g, Stage1Air *executable,
|
||||
case IrBinOpCmpEq:
|
||||
return_type = g->builtin_types.entry_i32->llvm_type;
|
||||
func_name = "__eqxf2";
|
||||
res_icmp = EQ_ZERO;
|
||||
break;
|
||||
case IrBinOpCmpNotEq:
|
||||
return_type = g->builtin_types.entry_i32->llvm_type;
|
||||
func_name = "__nexf2";
|
||||
res_icmp = NE_ZERO;
|
||||
break;
|
||||
case IrBinOpCmpLessOrEq:
|
||||
return_type = g->builtin_types.entry_i32->llvm_type;
|
||||
func_name = "__lexf2";
|
||||
res_icmp = LE_ZERO;
|
||||
break;
|
||||
case IrBinOpCmpLessThan:
|
||||
return_type = g->builtin_types.entry_i32->llvm_type;
|
||||
func_name = "__lexf2";
|
||||
res_icmp = EQ_NEG;
|
||||
break;
|
||||
case IrBinOpCmpGreaterOrEq:
|
||||
return_type = g->builtin_types.entry_i32->llvm_type;
|
||||
func_name = "__gexf2";
|
||||
res_icmp = GE_ZERO;
|
||||
break;
|
||||
case IrBinOpCmpGreaterThan:
|
||||
return_type = g->builtin_types.entry_i32->llvm_type;
|
||||
func_name = "__gexf2";
|
||||
res_icmp = EQ_ONE;
|
||||
break;
|
||||
case IrBinOpMaximum:
|
||||
func_name = "__fmaxx";
|
||||
@@ -3344,8 +3400,11 @@ static LLVMValueRef ir_render_soft_f80_bin_op(CodeGen *g, Stage1Air *executable,
|
||||
if (vector_len == 0) {
|
||||
LLVMValueRef params[2] = {op1_value, op2_value};
|
||||
result = LLVMBuildCall(g->builder, func_ref, params, param_count, "");
|
||||
result = add_f80_icmp(g, result, res_icmp);
|
||||
} else {
|
||||
result = build_alloca(g, op1->value->type, "", 0);
|
||||
ZigType *alloca_ty = op1->value->type;
|
||||
if (res_icmp != NONE) alloca_ty = get_vector_type(g, vector_len, g->builtin_types.entry_bool);
|
||||
result = build_alloca(g, alloca_ty, "", 0);
|
||||
}
|
||||
|
||||
LLVMTypeRef usize_ref = g->builtin_types.entry_usize->llvm_type;
|
||||
@@ -3356,6 +3415,7 @@ static LLVMValueRef ir_render_soft_f80_bin_op(CodeGen *g, Stage1Air *executable,
|
||||
LLVMBuildExtractElement(g->builder, op2_value, index_value, ""),
|
||||
};
|
||||
LLVMValueRef call_result = LLVMBuildCall(g->builder, func_ref, params, param_count, "");
|
||||
call_result = add_f80_icmp(g, call_result, res_icmp);
|
||||
LLVMBuildInsertElement(g->builder, LLVMBuildLoad(g->builder, result, ""),
|
||||
call_result, index_value, "");
|
||||
}
|
||||
@@ -4052,12 +4112,47 @@ static LLVMValueRef ir_render_binary_not(CodeGen *g, Stage1Air *executable,
|
||||
return LLVMBuildNot(g->builder, operand, "");
|
||||
}
|
||||
|
||||
static LLVMValueRef ir_gen_soft_f80_neg(CodeGen *g, ZigType *op_type, LLVMValueRef operand) {
|
||||
uint32_t vector_len = op_type->id == ZigTypeIdVector ? op_type->data.vector.len : 0;
|
||||
|
||||
uint64_t buf[2] = {0, 0};
|
||||
if (g->is_big_endian != native_is_big_endian) {
|
||||
buf[1] = 0x8000000000000000;
|
||||
} else {
|
||||
buf[1] = 0x8000;
|
||||
}
|
||||
LLVMValueRef sign_mask = LLVMConstIntOfArbitraryPrecision(LLVMInt128Type(), 2, buf);
|
||||
|
||||
LLVMValueRef result;
|
||||
if (vector_len == 0) {
|
||||
result = LLVMBuildXor(g->builder, operand, sign_mask, "");
|
||||
} else {
|
||||
result = build_alloca(g, op_type, "", 0);
|
||||
}
|
||||
|
||||
LLVMTypeRef usize_ref = g->builtin_types.entry_usize->llvm_type;
|
||||
for (uint32_t i = 0; i < vector_len; i++) {
|
||||
LLVMValueRef index_value = LLVMConstInt(usize_ref, i, false);
|
||||
LLVMValueRef xor_operand = LLVMBuildExtractElement(g->builder, operand, index_value, "");
|
||||
LLVMValueRef xor_result = LLVMBuildXor(g->builder, xor_operand, sign_mask, "");
|
||||
LLVMBuildInsertElement(g->builder, LLVMBuildLoad(g->builder, result, ""),
|
||||
xor_result, index_value, "");
|
||||
}
|
||||
if (vector_len != 0) {
|
||||
result = LLVMBuildLoad(g->builder, result, "");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static LLVMValueRef ir_gen_negation(CodeGen *g, Stage1AirInst *inst, Stage1AirInst *operand, bool wrapping) {
|
||||
LLVMValueRef llvm_operand = ir_llvm_value(g, operand);
|
||||
ZigType *operand_type = operand->value->type;
|
||||
ZigType *scalar_type = (operand_type->id == ZigTypeIdVector) ?
|
||||
operand_type->data.vector.elem_type : operand_type;
|
||||
|
||||
if (scalar_type == g->builtin_types.entry_f80 && !target_has_f80(g->zig_target))
|
||||
return ir_gen_soft_f80_neg(g, operand_type, llvm_operand);
|
||||
|
||||
if (scalar_type->id == ZigTypeIdFloat) {
|
||||
ZigLLVMSetFastMath(g->builder, ir_want_fast_math(g, inst));
|
||||
return LLVMBuildFNeg(g->builder, llvm_operand, "");
|
||||
@@ -8108,6 +8203,7 @@ static LLVMValueRef gen_const_val(CodeGen *g, ZigValue *const_val, const char *n
|
||||
buf[1] = tmp;
|
||||
#endif
|
||||
LLVMValueRef as_i128 = LLVMConstIntOfArbitraryPrecision(LLVMInt128Type(), 2, buf);
|
||||
if (!target_has_f80(g->zig_target)) return as_i128;
|
||||
LLVMValueRef as_int = LLVMConstTrunc(as_i128, LLVMIntType(80));
|
||||
return LLVMConstBitCast(as_int, get_llvm_type(g, type_entry));
|
||||
}
|
||||
@@ -9331,13 +9427,15 @@ static void define_builtin_types(CodeGen *g) {
|
||||
add_fp_entry(g, "f64", 64, LLVMDoubleType(), &g->builtin_types.entry_f64);
|
||||
add_fp_entry(g, "f128", 128, LLVMFP128Type(), &g->builtin_types.entry_f128);
|
||||
|
||||
if (target_has_f80(g->zig_target)) {
|
||||
add_fp_entry(g, "f80", 80, LLVMX86FP80Type(), &g->builtin_types.entry_f80);
|
||||
} else {
|
||||
{
|
||||
ZigType *entry = new_type_table_entry(ZigTypeIdFloat);
|
||||
entry->llvm_type = get_int_type(g, false, 128)->llvm_type;
|
||||
entry->size_in_bits = 8 * LLVMStoreSizeOfType(g->target_data_ref, entry->llvm_type);
|
||||
entry->abi_size = LLVMABISizeOfType(g->target_data_ref, entry->llvm_type);
|
||||
if (target_has_f80(g->zig_target)) {
|
||||
entry->llvm_type = LLVMX86FP80Type();
|
||||
} else {
|
||||
entry->llvm_type = get_int_type(g, false, 128)->llvm_type;
|
||||
}
|
||||
entry->size_in_bits = 8 * 16;
|
||||
entry->abi_size = 16;
|
||||
entry->abi_align = 16;
|
||||
buf_init_from_str(&entry->name, "f80");
|
||||
entry->data.floating.bit_count = 80;
|
||||
|
||||
Reference in New Issue
Block a user