| ... | ... | @@ -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 | 84 | static void render_const_val(CodeGen *g, ZigValue *const_val, const char *name); |
| 84 | 85 | static void render_const_val_global(CodeGen *g, ZigValue *const_val, const char *name); |
| 85 | 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 | 1737 | } |
| 1737 | 1738 | } |
| 1738 | 1739 | |
| 1739 | | LLVMValueRef func_ref = LLVMGetNamedFunction(g->module, fn_name); |
| 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 | | |
| 1740 | LLVMValueRef func_ref = get_soft_float_fn(g, fn_name, 1, param_type, return_type); |
| 1745 | 1741 | result = LLVMBuildCall2(g->builder, LLVMGlobalGetValueType(func_ref), func_ref, &expr_val, 1, ""); |
| 1746 | 1742 | |
| 1747 | 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 | 1762 | uint64_t wanted_bits; |
| 1767 | 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 | 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 | 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 | 3099 | ZigType *elem_type = operand_type->id == ZigTypeIdVector ? operand_type->data.vector.elem_type : operand_type; |
| 3101 | 3100 | if ((elem_type == g->builtin_types.entry_f80 && !target_has_f80(g->zig_target)) || |
| 3102 | 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 | 3103 | op == BuiltinFnIdTan) |
| 3104 | 3104 | { |
| 3105 | 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 | 3690 | ZigType *operand_type = op1->value->type; |
| 3691 | 3691 | ZigType *scalar_type = (operand_type->id == ZigTypeIdVector) ? operand_type->data.vector.elem_type : operand_type; |
| 3692 | 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 | 3695 | // LLVM incorrectly lowers the soft float calls for f128 as if they operated on `long double`. |
| 3695 | 3696 | // On some targets this will be incorrect, so we manually lower the call ourselves. |
| 3696 | 3697 | LLVMValueRef op1_value = ir_llvm_value(g, op1); |
| ... | ... | @@ -4024,7 +4025,8 @@ static LLVMValueRef ir_render_cast(CodeGen *g, Stage1Air *executable, |
| 4024 | 4025 | assert(actual_type->id == ZigTypeIdInt); |
| 4025 | 4026 | { |
| 4026 | 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 | 4030 | return gen_soft_int_to_float_op(g, expr_val, actual_type, wanted_type); |
| 4029 | 4031 | } else { |
| 4030 | 4032 | if (actual_type->data.integral.is_signed) { |
| ... | ... | @@ -4042,7 +4044,8 @@ static LLVMValueRef ir_render_cast(CodeGen *g, Stage1Air *executable, |
| 4042 | 4044 | |
| 4043 | 4045 | LLVMValueRef result; |
| 4044 | 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 | 4049 | result = gen_soft_float_to_int_op(g, expr_val, actual_type, wanted_type); |
| 4047 | 4050 | } else { |
| 4048 | 4051 | if (wanted_type->data.integral.is_signed) { |
| ... | ... | @@ -4396,7 +4399,8 @@ static LLVMValueRef gen_negation(CodeGen *g, Stage1AirInst *inst, Stage1AirInst |
| 4396 | 4399 | operand_type->data.vector.elem_type : operand_type; |
| 4397 | 4400 | |
| 4398 | 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 | 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 | 7378 | uint32_t vector_len = operand_type->id == ZigTypeIdVector ? operand_type->data.vector.len : 0; |
| 7375 | 7379 | |
| 7376 | 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 | 7384 | fn_name = "fmaf"; |
| 7379 | 7385 | else if (float_type == g->builtin_types.entry_f64) |
| 7380 | 7386 | fn_name = "fma"; |
| ... | ... | @@ -7385,13 +7391,8 @@ static LLVMValueRef ir_render_soft_mul_add(CodeGen *g, Stage1Air *executable, St |
| 7385 | 7391 | else |
| 7386 | 7392 | zig_unreachable(); |
| 7387 | 7393 | |
| 7388 | | LLVMValueRef func_ref = LLVMGetNamedFunction(g->module, fn_name); |
| 7389 | | if (func_ref == nullptr) { |
| 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 | | } |
| 7394 | LLVMTypeRef float_type_ref = float_type->llvm_type; |
| 7395 | LLVMValueRef func_ref = get_soft_float_fn(g, fn_name, 3, float_type_ref, float_type_ref); |
| 7395 | 7396 | |
| 7396 | 7397 | LLVMValueRef op1 = ir_llvm_value(g, instruction->op1); |
| 7397 | 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 | 7422 | ZigType *operand_type = instruction->op1->value->type; |
| 7422 | 7423 | operand_type = operand_type->id == ZigTypeIdVector ? operand_type->data.vector.elem_type : operand_type; |
| 7423 | 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 | 7427 | return ir_render_soft_mul_add(g, executable, instruction, operand_type); |
| 7426 | 7428 | } |
| 7427 | 7429 | LLVMValueRef op1 = ir_llvm_value(g, instruction->op1); |
| ... | ... | @@ -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 | 9751 | add_fp_entry(g, "f32", 32, LLVMFloatType(), &g->builtin_types.entry_f32); |
| 9745 | 9752 | add_fp_entry(g, "f64", 64, LLVMDoubleType(), &g->builtin_types.entry_f64); |
| 9746 | 9753 | add_fp_entry(g, "f128", 128, LLVMFP128Type(), &g->builtin_types.entry_f128); |