authorgravatar for topolarity@tapscott.meCody Tapscott <topolarity@tapscott.me> 2022-10-07 09:25:19-07:00
committergravatar for topolarity@tapscott.meCody Tapscott <topolarity@tapscott.me> 2022-10-13 12:53:20-07:00
logaedafb20cf32caea453b648cd19b7c82e993d02d
treee98e7ad72450682aac110421108c0ddaeb745115
parent83e2d3fb3701d77c8177f7b2b164cbd7c790a3ed

stage2: Fix softfloat support for PPC64(LE)

Stage 2's softfloat support still had a couple of gaps, which were preventing us from lowering `f16` on this target. With any luck, this is enough to get PPC64 working as a Tier 2 target again.

2 files changed, 59 insertions(+), 99 deletions(-)

deps/SoftFloat-3e-prebuilt/platform.h+8-8
...@@ -3,6 +3,10 @@...@@ -3,6 +3,10 @@
33
4#if defined(__BIG_ENDIAN__)4#if defined(__BIG_ENDIAN__)
5#define BIGENDIAN 15#define BIGENDIAN 1
6#elif defined(_BIG_ENDIAN) && (_BIG_ENDIAN == 1)
7#define BIGENDIAN 1
8#elif defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
9#define BIGENDIAN 1
6#elif defined(__ARMEB__)10#elif defined(__ARMEB__)
7#define BIGENDIAN 111#define BIGENDIAN 1
8#elif defined(__THUMBEB__)12#elif defined(__THUMBEB__)
...@@ -15,18 +19,12 @@...@@ -15,18 +19,12 @@
15#define BIGENDIAN 119#define BIGENDIAN 1
16#elif defined(__MIPSEB__)20#elif defined(__MIPSEB__)
17#define BIGENDIAN 121#define BIGENDIAN 1
18#elif defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
19#define BIGENDIAN 1
20#elif defined(__sparc)22#elif defined(__sparc)
21#define BIGENDIAN 123#define BIGENDIAN 1
22#elif defined(__sparc__)24#elif defined(__sparc__)
23#define BIGENDIAN 125#define BIGENDIAN 1
24#elif defined(_POWER)26#elif defined(_POWER)
25#define BIGENDIAN 127#define BIGENDIAN 1
26#elif defined(__powerpc__)
27#define BIGENDIAN 1
28#elif defined(__ppc__)
29#define BIGENDIAN 1
30#elif defined(__hpux)28#elif defined(__hpux)
31#define BIGENDIAN 129#define BIGENDIAN 1
32#elif defined(__hppa)30#elif defined(__hppa)
...@@ -39,6 +37,10 @@...@@ -39,6 +37,10 @@
3937
40#if defined(__LITTLE_ENDIAN__)38#if defined(__LITTLE_ENDIAN__)
41#define LITTLEENDIAN 139#define LITTLEENDIAN 1
40#elif defined(_LITTLE_ENDIAN) && (_LITTLE_ENDIAN == 1)
41#define LITTLEENDIAN 1
42#elif defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
43#define LITTLEENDIAN 1
42#elif defined(__ARMEL__)44#elif defined(__ARMEL__)
43#define LITTLEENDIAN 145#define LITTLEENDIAN 1
44#elif defined(__THUMBEL__)46#elif defined(__THUMBEL__)
...@@ -51,8 +53,6 @@...@@ -51,8 +53,6 @@
51#define LITTLEENDIAN 153#define LITTLEENDIAN 1
52#elif defined(__MIPSEL__)54#elif defined(__MIPSEL__)
53#define LITTLEENDIAN 155#define LITTLEENDIAN 1
54#elif defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
55#define LITTLEENDIAN 1
56#elif defined(__i386__)56#elif defined(__i386__)
57#define LITTLEENDIAN 157#define LITTLEENDIAN 1
58#elif defined(__alpha__)58#elif defined(__alpha__)
src/codegen/llvm.zig+51-91
...@@ -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 }
75937615
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 }
76117647
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 }
90669102
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.
10425fn backendSupportsF16(target: std.Target) bool {10380fn 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}