| ... | @@ -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 | } |
| 82 | | 82 | |
| | 83 | static LLVMValueRef get_soft_float_fn(CodeGen *g, const char *name, int param_count, LLVMTypeRef param_type, LLVMTypeRef return_type); |
| 83 | static void render_const_val(CodeGen *g, ZigValue *const_val, const char *name); | 84 | static void render_const_val(CodeGen *g, ZigValue *const_val, const char *name); |
| 84 | static void render_const_val_global(CodeGen *g, ZigValue *const_val, const char *name); | 85 | static void render_const_val_global(CodeGen *g, ZigValue *const_val, const char *name); |
| 85 | static LLVMValueRef gen_const_val(CodeGen *g, ZigValue *const_val, const char *name); | 86 | static 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 | } |
| 1738 | | 1739 | |
| 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, ""); |
| 1746 | | 1742 | |
| 1747 | // On non-Arm platforms we need to bitcast __trunc<>fhf2 result back to f16 | 1743 | // 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) { |
| 1768 | | 1764 | |
| 1769 | if ((scalar_actual_type == g->builtin_types.entry_f80 | 1765 | 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, |
| 4042 | | 4044 | |
| 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; |
| 4397 | | 4400 | |
| 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 | } |
| 4402 | | 4406 | |
| ... | @@ -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; |
| 7375 | | 7379 | |
| 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 | else | 7391 | else |
| 7386 | zig_unreachable(); | 7392 | zig_unreachable(); |
| 7387 | | 7393 | |
| 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 | } | | |
| 7395 | | 7396 | |
| 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 | } |
| 9742 | | 9744 | |
| 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); |