| ... | ... | @@ -2711,7 +2711,7 @@ pub const DeclGen = struct { |
| 2711 | 2711 | return dg.context.intType(bit_count); |
| 2712 | 2712 | }, |
| 2713 | 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 | 2715 | 32 => return dg.context.floatType(), |
| 2716 | 2716 | 64 => return dg.context.doubleType(), |
| 2717 | 2717 | 80 => return if (backendSupportsF80(target)) dg.context.x86FP80Type() else dg.context.intType(80), |
| ... | ... | @@ -3226,7 +3226,15 @@ pub const DeclGen = struct { |
| 3226 | 3226 | .Float => { |
| 3227 | 3227 | const llvm_ty = try dg.lowerType(tv.ty); |
| 3228 | 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 | 3238 | 80 => { |
| 3231 | 3239 | const float = tv.val.toFloat(f80); |
| 3232 | 3240 | const repr = std.math.break_f80(float); |
| ... | ... | @@ -7584,11 +7592,25 @@ pub const FuncGen = struct { |
| 7584 | 7592 | const target = self.dg.module.getTarget(); |
| 7585 | 7593 | const dest_bits = dest_ty.floatBits(target); |
| 7586 | 7594 | const src_bits = operand_ty.floatBits(target); |
| 7587 | | if (!backendSupportsF80(target) and (src_bits == 80 or dest_bits == 80)) { |
| 7588 | | return softF80TruncOrExt(self, operand, src_bits, dest_bits); |
| 7595 | |
| 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 | 7616 | fn airFpext(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| ... | ... | @@ -7602,11 +7624,25 @@ pub const FuncGen = struct { |
| 7602 | 7624 | const target = self.dg.module.getTarget(); |
| 7603 | 7625 | const dest_bits = dest_ty.floatBits(target); |
| 7604 | 7626 | const src_bits = operand_ty.floatBits(target); |
| 7605 | | if (!backendSupportsF80(target) and (src_bits == 80 or dest_bits == 80)) { |
| 7606 | | return softF80TruncOrExt(self, operand, src_bits, dest_bits); |
| 7627 | |
| 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 | 7648 | fn airPtrToInt(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| ... | ... | @@ -9064,87 +9100,6 @@ pub const FuncGen = struct { |
| 9064 | 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 | 9103 | fn getErrorNameTable(self: *FuncGen) !*llvm.Value { |
| 9149 | 9104 | if (self.dg.object.error_name_table) |table| { |
| 9150 | 9105 | return table; |
| ... | ... | @@ -10424,6 +10379,11 @@ fn backendSupportsF80(target: std.Target) bool { |
| 10424 | 10379 | /// if it produces miscompilations. |
| 10425 | 10380 | fn backendSupportsF16(target: std.Target) bool { |
| 10426 | 10381 | return switch (target.cpu.arch) { |
| 10382 | .powerpc, |
| 10383 | .powerpcle, |
| 10384 | .powerpc64, |
| 10385 | .powerpc64le, |
| 10386 | => false, |
| 10427 | 10387 | else => true, |
| 10428 | 10388 | }; |
| 10429 | 10389 | } |