authorgravatar for topolarity@tapscott.meCody Tapscott <topolarity@tapscott.me> 2022-10-08 11:27:29-07:00
committergravatar for topolarity@tapscott.meCody Tapscott <topolarity@tapscott.me> 2022-10-13 12:53:20-07:00
logb992ea1b079c5967348655f8719cdadaf2df8261
tree0a3132cf40f312fd51cd61359315e83ba616172b
parent37c6fcafa27c9dc4b323ca2fc79f5a928c1b4d14

stage1: Rely on softfloat for `f16` on non-arm targets


1 files changed, 29 insertions(+), 22 deletions(-)

src/stage1/codegen.cpp+29-22
...@@ -80,6 +80,7 @@ void codegen_set_strip(CodeGen *g, bool strip) {...@@ -80,6 +80,7 @@ void codegen_set_strip(CodeGen *g, bool strip) {
80 }80 }
81}81}
8282
83static LLVMValueRef get_soft_float_fn(CodeGen *g, const char *name, int param_count, LLVMTypeRef param_type, LLVMTypeRef return_type);
83static void render_const_val(CodeGen *g, ZigValue *const_val, const char *name);84static void render_const_val(CodeGen *g, ZigValue *const_val, const char *name);
84static void render_const_val_global(CodeGen *g, ZigValue *const_val, const char *name);85static void render_const_val_global(CodeGen *g, ZigValue *const_val, const char *name);
85static LLVMValueRef gen_const_val(CodeGen *g, ZigValue *const_val, const char *name);86static LLVMValueRef gen_const_val(CodeGen *g, ZigValue *const_val, const char *name);
...@@ -1736,12 +1737,7 @@ static LLVMValueRef gen_soft_float_widen_or_shorten(CodeGen *g, ZigType *actual_...@@ -1736,12 +1737,7 @@ static LLVMValueRef gen_soft_float_widen_or_shorten(CodeGen *g, ZigType *actual_
1736 }1737 }
1737 }1738 }
17381739
1739 LLVMValueRef func_ref = LLVMGetNamedFunction(g->module, fn_name);1740 LLVMValueRef func_ref = get_soft_float_fn(g, fn_name, 1, param_type, return_type);
1740 if (func_ref == nullptr) {
1741 LLVMTypeRef fn_type = LLVMFunctionType(return_type, &param_type, 1, false);
1742 func_ref = LLVMAddFunction(g->module, fn_name, fn_type);
1743 }
1744
1745 result = LLVMBuildCall2(g->builder, LLVMGlobalGetValueType(func_ref), func_ref, &expr_val, 1, "");1741 result = LLVMBuildCall2(g->builder, LLVMGlobalGetValueType(func_ref), func_ref, &expr_val, 1, "");
17461742
1747 // On non-Arm platforms we need to bitcast __trunc<>fhf2 result back to f161743 // On non-Arm platforms we need to bitcast __trunc<>fhf2 result back to f16
...@@ -1766,9 +1762,12 @@ static LLVMValueRef gen_widen_or_shorten(CodeGen *g, bool want_runtime_safety, Z...@@ -1766,9 +1762,12 @@ static LLVMValueRef gen_widen_or_shorten(CodeGen *g, bool want_runtime_safety, Z
1766 uint64_t wanted_bits;1762 uint64_t wanted_bits;
1767 if (scalar_actual_type->id == ZigTypeIdFloat) {1763 if (scalar_actual_type->id == ZigTypeIdFloat) {
17681764
1769 if ((scalar_actual_type == g->builtin_types.entry_f801765 if (((scalar_actual_type == g->builtin_types.entry_f80
1770 || scalar_wanted_type == g->builtin_types.entry_f80)1766 || scalar_wanted_type == g->builtin_types.entry_f80)
1771 && !target_has_f80(g->zig_target))1767 && !target_has_f80(g->zig_target)) ||
1768 ((scalar_actual_type == g->builtin_types.entry_f16
1769 || scalar_wanted_type == g->builtin_types.entry_f16)
1770 && !target_is_arm(g->zig_target)))
1772 {1771 {
1773 return gen_soft_float_widen_or_shorten(g, actual_type, wanted_type, expr_val);1772 return gen_soft_float_widen_or_shorten(g, actual_type, wanted_type, expr_val);
1774 }1773 }
...@@ -3100,6 +3099,7 @@ static LLVMValueRef gen_float_un_op(CodeGen *g, LLVMValueRef operand, ZigType *o...@@ -3100,6 +3099,7 @@ static LLVMValueRef gen_float_un_op(CodeGen *g, LLVMValueRef operand, ZigType *o
3100 ZigType *elem_type = operand_type->id == ZigTypeIdVector ? operand_type->data.vector.elem_type : operand_type;3099 ZigType *elem_type = operand_type->id == ZigTypeIdVector ? operand_type->data.vector.elem_type : operand_type;
3101 if ((elem_type == g->builtin_types.entry_f80 && !target_has_f80(g->zig_target)) ||3100 if ((elem_type == g->builtin_types.entry_f80 && !target_has_f80(g->zig_target)) ||
3102 (elem_type == g->builtin_types.entry_f128 && !target_long_double_is_f128(g->zig_target)) ||3101 (elem_type == g->builtin_types.entry_f128 && !target_long_double_is_f128(g->zig_target)) ||
3102 (elem_type == g->builtin_types.entry_f16 && !target_is_arm(g->zig_target)) ||
3103 op == BuiltinFnIdTan)3103 op == BuiltinFnIdTan)
3104 {3104 {
3105 return gen_soft_float_un_op(g, operand, operand_type, op);3105 return gen_soft_float_un_op(g, operand, operand_type, op);
...@@ -3690,7 +3690,8 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, Stage1Air *executable,...@@ -3690,7 +3690,8 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, Stage1Air *executable,
3690 ZigType *operand_type = op1->value->type;3690 ZigType *operand_type = op1->value->type;
3691 ZigType *scalar_type = (operand_type->id == ZigTypeIdVector) ? operand_type->data.vector.elem_type : operand_type;3691 ZigType *scalar_type = (operand_type->id == ZigTypeIdVector) ? operand_type->data.vector.elem_type : operand_type;
3692 if ((scalar_type == g->builtin_types.entry_f80 && !target_has_f80(g->zig_target)) ||3692 if ((scalar_type == g->builtin_types.entry_f80 && !target_has_f80(g->zig_target)) ||
3693 (scalar_type == g->builtin_types.entry_f128 && !target_long_double_is_f128(g->zig_target))) {3693 (scalar_type == g->builtin_types.entry_f128 && !target_long_double_is_f128(g->zig_target)) ||
3694 (scalar_type == g->builtin_types.entry_f16 && !target_is_arm(g->zig_target))) {
3694 // LLVM incorrectly lowers the soft float calls for f128 as if they operated on `long double`.3695 // LLVM incorrectly lowers the soft float calls for f128 as if they operated on `long double`.
3695 // On some targets this will be incorrect, so we manually lower the call ourselves.3696 // On some targets this will be incorrect, so we manually lower the call ourselves.
3696 LLVMValueRef op1_value = ir_llvm_value(g, op1);3697 LLVMValueRef op1_value = ir_llvm_value(g, op1);
...@@ -4024,7 +4025,8 @@ static LLVMValueRef ir_render_cast(CodeGen *g, Stage1Air *executable,...@@ -4024,7 +4025,8 @@ static LLVMValueRef ir_render_cast(CodeGen *g, Stage1Air *executable,
4024 assert(actual_type->id == ZigTypeIdInt);4025 assert(actual_type->id == ZigTypeIdInt);
4025 {4026 {
4026 if ((wanted_type == g->builtin_types.entry_f80 && !target_has_f80(g->zig_target)) ||4027 if ((wanted_type == g->builtin_types.entry_f80 && !target_has_f80(g->zig_target)) ||
4027 (wanted_type == g->builtin_types.entry_f128 && !target_long_double_is_f128(g->zig_target))) {4028 (wanted_type == g->builtin_types.entry_f128 && !target_long_double_is_f128(g->zig_target)) ||
4029 (wanted_type == g->builtin_types.entry_f16 && !target_is_arm(g->zig_target))) {
4028 return gen_soft_int_to_float_op(g, expr_val, actual_type, wanted_type);4030 return gen_soft_int_to_float_op(g, expr_val, actual_type, wanted_type);
4029 } else {4031 } else {
4030 if (actual_type->data.integral.is_signed) {4032 if (actual_type->data.integral.is_signed) {
...@@ -4042,7 +4044,8 @@ static LLVMValueRef ir_render_cast(CodeGen *g, Stage1Air *executable,...@@ -4042,7 +4044,8 @@ static LLVMValueRef ir_render_cast(CodeGen *g, Stage1Air *executable,
40424044
4043 LLVMValueRef result;4045 LLVMValueRef result;
4044 if ((actual_type == g->builtin_types.entry_f80 && !target_has_f80(g->zig_target)) ||4046 if ((actual_type == g->builtin_types.entry_f80 && !target_has_f80(g->zig_target)) ||
4045 (actual_type == g->builtin_types.entry_f128 && !target_long_double_is_f128(g->zig_target))) {4047 (actual_type == g->builtin_types.entry_f128 && !target_long_double_is_f128(g->zig_target)) ||
4048 (actual_type == g->builtin_types.entry_f16 && !target_is_arm(g->zig_target))) {
4046 result = gen_soft_float_to_int_op(g, expr_val, actual_type, wanted_type);4049 result = gen_soft_float_to_int_op(g, expr_val, actual_type, wanted_type);
4047 } else {4050 } else {
4048 if (wanted_type->data.integral.is_signed) {4051 if (wanted_type->data.integral.is_signed) {
...@@ -4396,7 +4399,8 @@ static LLVMValueRef gen_negation(CodeGen *g, Stage1AirInst *inst, Stage1AirInst...@@ -4396,7 +4399,8 @@ static LLVMValueRef gen_negation(CodeGen *g, Stage1AirInst *inst, Stage1AirInst
4396 operand_type->data.vector.elem_type : operand_type;4399 operand_type->data.vector.elem_type : operand_type;
43974400
4398 if ((scalar_type == g->builtin_types.entry_f80 && !target_has_f80(g->zig_target)) ||4401 if ((scalar_type == g->builtin_types.entry_f80 && !target_has_f80(g->zig_target)) ||
4399 (scalar_type == g->builtin_types.entry_f128 && !target_long_double_is_f128(g->zig_target))) {4402 (scalar_type == g->builtin_types.entry_f128 && !target_long_double_is_f128(g->zig_target)) ||
4403 (scalar_type == g->builtin_types.entry_f16 && !target_is_arm(g->zig_target))) {
4400 return gen_soft_float_neg(g, operand_type, llvm_operand);4404 return gen_soft_float_neg(g, operand_type, llvm_operand);
4401 }4405 }
44024406
...@@ -7374,7 +7378,9 @@ static LLVMValueRef ir_render_soft_mul_add(CodeGen *g, Stage1Air *executable, St...@@ -7374,7 +7378,9 @@ static LLVMValueRef ir_render_soft_mul_add(CodeGen *g, Stage1Air *executable, St
7374 uint32_t vector_len = operand_type->id == ZigTypeIdVector ? operand_type->data.vector.len : 0;7378 uint32_t vector_len = operand_type->id == ZigTypeIdVector ? operand_type->data.vector.len : 0;
73757379
7376 const char *fn_name;7380 const char *fn_name;
7377 if (float_type == g->builtin_types.entry_f32)7381 if (float_type == g->builtin_types.entry_f16)
7382 fn_name = "__fmah";
7383 else if (float_type == g->builtin_types.entry_f32)
7378 fn_name = "fmaf";7384 fn_name = "fmaf";
7379 else if (float_type == g->builtin_types.entry_f64)7385 else if (float_type == g->builtin_types.entry_f64)
7380 fn_name = "fma";7386 fn_name = "fma";
...@@ -7385,13 +7391,8 @@ static LLVMValueRef ir_render_soft_mul_add(CodeGen *g, Stage1Air *executable, St...@@ -7385,13 +7391,8 @@ static LLVMValueRef ir_render_soft_mul_add(CodeGen *g, Stage1Air *executable, St
7385 else7391 else
7386 zig_unreachable();7392 zig_unreachable();
73877393
7388 LLVMValueRef func_ref = LLVMGetNamedFunction(g->module, fn_name);7394 LLVMTypeRef float_type_ref = float_type->llvm_type;
7389 if (func_ref == nullptr) {7395 LLVMValueRef func_ref = get_soft_float_fn(g, fn_name, 3, float_type_ref, float_type_ref);
7390 LLVMTypeRef float_type_ref = float_type->llvm_type;
7391 LLVMTypeRef params[3] = { float_type_ref, float_type_ref, float_type_ref };
7392 LLVMTypeRef fn_type = LLVMFunctionType(float_type_ref, params, 3, false);
7393 func_ref = LLVMAddFunction(g->module, fn_name, fn_type);
7394 }
73957396
7396 LLVMValueRef op1 = ir_llvm_value(g, instruction->op1);7397 LLVMValueRef op1 = ir_llvm_value(g, instruction->op1);
7397 LLVMValueRef op2 = ir_llvm_value(g, instruction->op2);7398 LLVMValueRef op2 = ir_llvm_value(g, instruction->op2);
...@@ -7421,7 +7422,8 @@ static LLVMValueRef ir_render_mul_add(CodeGen *g, Stage1Air *executable, Stage1A...@@ -7421,7 +7422,8 @@ static LLVMValueRef ir_render_mul_add(CodeGen *g, Stage1Air *executable, Stage1A
7421 ZigType *operand_type = instruction->op1->value->type;7422 ZigType *operand_type = instruction->op1->value->type;
7422 operand_type = operand_type->id == ZigTypeIdVector ? operand_type->data.vector.elem_type : operand_type;7423 operand_type = operand_type->id == ZigTypeIdVector ? operand_type->data.vector.elem_type : operand_type;
7423 if ((operand_type == g->builtin_types.entry_f80 && !target_has_f80(g->zig_target)) ||7424 if ((operand_type == g->builtin_types.entry_f80 && !target_has_f80(g->zig_target)) ||
7424 (operand_type == g->builtin_types.entry_f128 && !target_long_double_is_f128(g->zig_target))) {7425 (operand_type == g->builtin_types.entry_f128 && !target_long_double_is_f128(g->zig_target)) ||
7426 (operand_type == g->builtin_types.entry_f16 && !target_is_arm(g->zig_target))) {
7425 return ir_render_soft_mul_add(g, executable, instruction, operand_type);7427 return ir_render_soft_mul_add(g, executable, instruction, operand_type);
7426 }7428 }
7427 LLVMValueRef op1 = ir_llvm_value(g, instruction->op1);7429 LLVMValueRef op1 = ir_llvm_value(g, instruction->op1);
...@@ -9740,7 +9742,12 @@ static void define_builtin_types(CodeGen *g) {...@@ -9740,7 +9742,12 @@ static void define_builtin_types(CodeGen *g) {
9740 }9742 }
9741 }9743 }
97429744
9743 add_fp_entry(g, "f16", 16, LLVMHalfType(), &g->builtin_types.entry_f16);9745 if (target_is_arm(g->zig_target)) {
9746 add_fp_entry(g, "f16", 16, LLVMHalfType(), &g->builtin_types.entry_f16);
9747 } else {
9748 ZigType *u16_ty = get_int_type(g, false, 16);
9749 add_fp_entry(g, "f16", 16, get_llvm_type(g, u16_ty), &g->builtin_types.entry_f16);
9750 }
9744 add_fp_entry(g, "f32", 32, LLVMFloatType(), &g->builtin_types.entry_f32);9751 add_fp_entry(g, "f32", 32, LLVMFloatType(), &g->builtin_types.entry_f32);
9745 add_fp_entry(g, "f64", 64, LLVMDoubleType(), &g->builtin_types.entry_f64);9752 add_fp_entry(g, "f64", 64, LLVMDoubleType(), &g->builtin_types.entry_f64);
9746 add_fp_entry(g, "f128", 128, LLVMFP128Type(), &g->builtin_types.entry_f128);9753 add_fp_entry(g, "f128", 128, LLVMFP128Type(), &g->builtin_types.entry_f128);