| ... | @@ -2711,7 +2711,7 @@ pub const DeclGen = struct { | ... | @@ -2711,7 +2711,7 @@ pub const DeclGen = struct { |
| 2711 | return dg.context.intType(bit_count); | 2711 | return dg.context.intType(bit_count); |
| 2712 | }, | 2712 | }, |
| 2713 | .Float => switch (t.floatBits(target)) { | 2713 | .Float => switch (t.floatBits(target)) { |
| 2714 | 16 => return dg.context.halfType(), | 2714 | 16 => return if (backendSupportsF16(target)) dg.context.halfType() else dg.context.intType(16), |
| 2715 | 32 => return dg.context.floatType(), | 2715 | 32 => return dg.context.floatType(), |
| 2716 | 64 => return dg.context.doubleType(), | 2716 | 64 => return dg.context.doubleType(), |
| 2717 | 80 => return if (backendSupportsF80(target)) dg.context.x86FP80Type() else dg.context.intType(80), | 2717 | 80 => return if (backendSupportsF80(target)) dg.context.x86FP80Type() else dg.context.intType(80), |
| ... | @@ -3226,7 +3226,15 @@ pub const DeclGen = struct { | ... | @@ -3226,7 +3226,15 @@ pub const DeclGen = struct { |
| 3226 | .Float => { | 3226 | .Float => { |
| 3227 | const llvm_ty = try dg.lowerType(tv.ty); | 3227 | const llvm_ty = try dg.lowerType(tv.ty); |
| 3228 | switch (tv.ty.floatBits(target)) { | 3228 | switch (tv.ty.floatBits(target)) { |
| 3229 | 16, 32, 64 => return llvm_ty.constReal(tv.val.toFloat(f64)), | 3229 | 16 => if (intrinsicsAllowed(tv.ty, target)) { |
| | 3230 | return llvm_ty.constReal(tv.val.toFloat(f16)); |
| | 3231 | } else { |
| | 3232 | const repr = @bitCast(u16, tv.val.toFloat(f16)); |
| | 3233 | const llvm_i16 = dg.context.intType(16); |
| | 3234 | const int = llvm_i16.constInt(repr, .False); |
| | 3235 | return int.constBitCast(llvm_ty); |
| | 3236 | }, |
| | 3237 | 32, 64 => return llvm_ty.constReal(tv.val.toFloat(f64)), |
| 3230 | 80 => { | 3238 | 80 => { |
| 3231 | const float = tv.val.toFloat(f80); | 3239 | const float = tv.val.toFloat(f80); |
| 3232 | const repr = std.math.break_f80(float); | 3240 | const repr = std.math.break_f80(float); |
| ... | @@ -7584,11 +7592,25 @@ pub const FuncGen = struct { | ... | @@ -7584,11 +7592,25 @@ pub const FuncGen = struct { |
| 7584 | const target = self.dg.module.getTarget(); | 7592 | const target = self.dg.module.getTarget(); |
| 7585 | const dest_bits = dest_ty.floatBits(target); | 7593 | const dest_bits = dest_ty.floatBits(target); |
| 7586 | const src_bits = operand_ty.floatBits(target); | 7594 | const src_bits = operand_ty.floatBits(target); |
| 7587 | if (!backendSupportsF80(target) and (src_bits == 80 or dest_bits == 80)) { | 7595 | |
| 7588 | return softF80TruncOrExt(self, operand, src_bits, dest_bits); | 7596 | if (intrinsicsAllowed(dest_ty, target) and intrinsicsAllowed(operand_ty, target)) { |
| | 7597 | const dest_llvm_ty = try self.dg.lowerType(dest_ty); |
| | 7598 | return self.builder.buildFPTrunc(operand, dest_llvm_ty, ""); |
| | 7599 | } else { |
| | 7600 | const operand_llvm_ty = try self.dg.lowerType(operand_ty); |
| | 7601 | const dest_llvm_ty = try self.dg.lowerType(dest_ty); |
| | 7602 | |
| | 7603 | var fn_name_buf: [64]u8 = undefined; |
| | 7604 | const fn_name = std.fmt.bufPrintZ(&fn_name_buf, "__trunc{s}f{s}f2", .{ |
| | 7605 | compilerRtFloatAbbrev(src_bits), compilerRtFloatAbbrev(dest_bits), |
| | 7606 | }) catch unreachable; |
| | 7607 | |
| | 7608 | const params = [1]*llvm.Value{operand}; |
| | 7609 | const param_types = [1]*llvm.Type{operand_llvm_ty}; |
| | 7610 | const llvm_fn = self.getLibcFunction(fn_name, &param_types, dest_llvm_ty); |
| | 7611 | |
| | 7612 | return self.builder.buildCall(llvm_fn.globalGetValueType(), llvm_fn, &params, params.len, .C, .Auto, ""); |
| 7589 | } | 7613 | } |
| 7590 | const dest_llvm_ty = try self.dg.lowerType(dest_ty); | | |
| 7591 | return self.builder.buildFPTrunc(operand, dest_llvm_ty, ""); | | |
| 7592 | } | 7614 | } |
| 7593 | | 7615 | |
| 7594 | fn airFpext(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { | 7616 | fn airFpext(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| ... | @@ -7602,11 +7624,25 @@ pub const FuncGen = struct { | ... | @@ -7602,11 +7624,25 @@ pub const FuncGen = struct { |
| 7602 | const target = self.dg.module.getTarget(); | 7624 | const target = self.dg.module.getTarget(); |
| 7603 | const dest_bits = dest_ty.floatBits(target); | 7625 | const dest_bits = dest_ty.floatBits(target); |
| 7604 | const src_bits = operand_ty.floatBits(target); | 7626 | const src_bits = operand_ty.floatBits(target); |
| 7605 | if (!backendSupportsF80(target) and (src_bits == 80 or dest_bits == 80)) { | 7627 | |
| 7606 | return softF80TruncOrExt(self, operand, src_bits, dest_bits); | 7628 | if (intrinsicsAllowed(dest_ty, target) and intrinsicsAllowed(operand_ty, target)) { |
| | 7629 | const dest_llvm_ty = try self.dg.lowerType(dest_ty); |
| | 7630 | return self.builder.buildFPExt(operand, dest_llvm_ty, ""); |
| | 7631 | } else { |
| | 7632 | const operand_llvm_ty = try self.dg.lowerType(operand_ty); |
| | 7633 | const dest_llvm_ty = try self.dg.lowerType(dest_ty); |
| | 7634 | |
| | 7635 | var fn_name_buf: [64]u8 = undefined; |
| | 7636 | const fn_name = std.fmt.bufPrintZ(&fn_name_buf, "__extend{s}f{s}f2", .{ |
| | 7637 | compilerRtFloatAbbrev(src_bits), compilerRtFloatAbbrev(dest_bits), |
| | 7638 | }) catch unreachable; |
| | 7639 | |
| | 7640 | const params = [1]*llvm.Value{operand}; |
| | 7641 | const param_types = [1]*llvm.Type{operand_llvm_ty}; |
| | 7642 | const llvm_fn = self.getLibcFunction(fn_name, &param_types, dest_llvm_ty); |
| | 7643 | |
| | 7644 | return self.builder.buildCall(llvm_fn.globalGetValueType(), llvm_fn, &params, params.len, .C, .Auto, ""); |
| 7607 | } | 7645 | } |
| 7608 | const dest_llvm_ty = try self.dg.lowerType(self.air.typeOfIndex(inst)); | | |
| 7609 | return self.builder.buildFPExt(operand, dest_llvm_ty, ""); | | |
| 7610 | } | 7646 | } |
| 7611 | | 7647 | |
| 7612 | fn airPtrToInt(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { | 7648 | fn airPtrToInt(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| ... | @@ -9064,87 +9100,6 @@ pub const FuncGen = struct { | ... | @@ -9064,87 +9100,6 @@ pub const FuncGen = struct { |
| 9064 | return null; | 9100 | return null; |
| 9065 | } | 9101 | } |
| 9066 | | 9102 | |
| 9067 | fn softF80TruncOrExt( | | |
| 9068 | self: *FuncGen, | | |
| 9069 | operand: *llvm.Value, | | |
| 9070 | src_bits: u16, | | |
| 9071 | dest_bits: u16, | | |
| 9072 | ) !?*llvm.Value { | | |
| 9073 | const target = self.dg.module.getTarget(); | | |
| 9074 | | | |
| 9075 | var param_llvm_ty: *llvm.Type = self.context.intType(80); | | |
| 9076 | var ret_llvm_ty: *llvm.Type = param_llvm_ty; | | |
| 9077 | var fn_name: [*:0]const u8 = undefined; | | |
| 9078 | var arg = operand; | | |
| 9079 | var final_cast: ?*llvm.Type = null; | | |
| 9080 | | | |
| 9081 | assert(src_bits == 80 or dest_bits == 80); | | |
| 9082 | | | |
| 9083 | if (src_bits == 80) switch (dest_bits) { | | |
| 9084 | 16 => { | | |
| 9085 | // See corresponding condition at definition of | | |
| 9086 | // __truncxfhf2 in compiler-rt. | | |
| 9087 | if (target.cpu.arch.isAARCH64()) { | | |
| 9088 | ret_llvm_ty = self.context.halfType(); | | |
| 9089 | } else { | | |
| 9090 | ret_llvm_ty = self.context.intType(16); | | |
| 9091 | final_cast = self.context.halfType(); | | |
| 9092 | } | | |
| 9093 | fn_name = "__truncxfhf2"; | | |
| 9094 | }, | | |
| 9095 | 32 => { | | |
| 9096 | ret_llvm_ty = self.context.floatType(); | | |
| 9097 | fn_name = "__truncxfsf2"; | | |
| 9098 | }, | | |
| 9099 | 64 => { | | |
| 9100 | ret_llvm_ty = self.context.doubleType(); | | |
| 9101 | fn_name = "__truncxfdf2"; | | |
| 9102 | }, | | |
| 9103 | 80 => return operand, | | |
| 9104 | 128 => { | | |
| 9105 | ret_llvm_ty = self.context.fp128Type(); | | |
| 9106 | fn_name = "__extendxftf2"; | | |
| 9107 | }, | | |
| 9108 | else => unreachable, | | |
| 9109 | } else switch (src_bits) { | | |
| 9110 | 16 => { | | |
| 9111 | // See corresponding condition at definition of | | |
| 9112 | // __extendhfxf2 in compiler-rt. | | |
| 9113 | param_llvm_ty = if (target.cpu.arch.isAARCH64()) | | |
| 9114 | self.context.halfType() | | |
| 9115 | else | | |
| 9116 | self.context.intType(16); | | |
| 9117 | arg = self.builder.buildBitCast(arg, param_llvm_ty, ""); | | |
| 9118 | fn_name = "__extendhfxf2"; | | |
| 9119 | }, | | |
| 9120 | 32 => { | | |
| 9121 | param_llvm_ty = self.context.floatType(); | | |
| 9122 | fn_name = "__extendsfxf2"; | | |
| 9123 | }, | | |
| 9124 | 64 => { | | |
| 9125 | param_llvm_ty = self.context.doubleType(); | | |
| 9126 | fn_name = "__extenddfxf2"; | | |
| 9127 | }, | | |
| 9128 | 80 => return operand, | | |
| 9129 | 128 => { | | |
| 9130 | param_llvm_ty = self.context.fp128Type(); | | |
| 9131 | fn_name = "__trunctfxf2"; | | |
| 9132 | }, | | |
| 9133 | else => unreachable, | | |
| 9134 | } | | |
| 9135 | | | |
| 9136 | const llvm_fn = self.dg.object.llvm_module.getNamedFunction(fn_name) orelse f: { | | |
| 9137 | const param_types = [_]*llvm.Type{param_llvm_ty}; | | |
| 9138 | const fn_type = llvm.functionType(ret_llvm_ty, &param_types, param_types.len, .False); | | |
| 9139 | break :f self.dg.object.llvm_module.addFunction(fn_name, fn_type); | | |
| 9140 | }; | | |
| 9141 | | | |
| 9142 | var args: [1]*llvm.Value = .{arg}; | | |
| 9143 | const result = self.builder.buildCall(llvm_fn.globalGetValueType(), llvm_fn, &args, args.len, .C, .Auto, ""); | | |
| 9144 | const final_cast_llvm_ty = final_cast orelse return result; | | |
| 9145 | return self.builder.buildBitCast(result, final_cast_llvm_ty, ""); | | |
| 9146 | } | | |
| 9147 | | | |
| 9148 | fn getErrorNameTable(self: *FuncGen) !*llvm.Value { | 9103 | fn getErrorNameTable(self: *FuncGen) !*llvm.Value { |
| 9149 | if (self.dg.object.error_name_table) |table| { | 9104 | if (self.dg.object.error_name_table) |table| { |
| 9150 | return table; | 9105 | return table; |
| ... | @@ -10424,6 +10379,11 @@ fn backendSupportsF80(target: std.Target) bool { | ... | @@ -10424,6 +10379,11 @@ fn backendSupportsF80(target: std.Target) bool { |
| 10424 | /// if it produces miscompilations. | 10379 | /// if it produces miscompilations. |
| 10425 | fn backendSupportsF16(target: std.Target) bool { | 10380 | fn backendSupportsF16(target: std.Target) bool { |
| 10426 | return switch (target.cpu.arch) { | 10381 | return switch (target.cpu.arch) { |
| | 10382 | .powerpc, |
| | 10383 | .powerpcle, |
| | 10384 | .powerpc64, |
| | 10385 | .powerpc64le, |
| | 10386 | => false, |
| 10427 | else => true, | 10387 | else => true, |
| 10428 | }; | 10388 | }; |
| 10429 | } | 10389 | } |