authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-10-15 10:05:00-04:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2022-10-15 10:05:00-04:00
logb4e3424594aecbd5a038d7c3a9e1e01c66a239ee
treee5dfde6fa751626cd9e0ba6bf36bbd0bb9789fa1
parent8bb2e96ac3b61a8aa393f250144fb9e1195ca60a
parenta168893e0097093665154c7897b7f909cec855a1
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #13100 from topolarity/powerpc64le

stage2: Fix softfloat support for PPC64(LE)

35 files changed, 601 insertions(+), 201 deletions(-)

deps/SoftFloat-3e-prebuilt/platform.h+8-8
......@@ -3,6 +3,10 @@
33
44#if defined(__BIG_ENDIAN__)
55#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
610#elif defined(__ARMEB__)
711#define BIGENDIAN 1
812#elif defined(__THUMBEB__)
......@@ -15,18 +19,12 @@
1519#define BIGENDIAN 1
1620#elif defined(__MIPSEB__)
1721#define BIGENDIAN 1
18#elif defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
19#define BIGENDIAN 1
2022#elif defined(__sparc)
2123#define BIGENDIAN 1
2224#elif defined(__sparc__)
2325#define BIGENDIAN 1
2426#elif defined(_POWER)
2527#define BIGENDIAN 1
26#elif defined(__powerpc__)
27#define BIGENDIAN 1
28#elif defined(__ppc__)
29#define BIGENDIAN 1
3028#elif defined(__hpux)
3129#define BIGENDIAN 1
3230#elif defined(__hppa)
......@@ -39,6 +37,10 @@
3937
4038#if defined(__LITTLE_ENDIAN__)
4139#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
4244#elif defined(__ARMEL__)
4345#define LITTLEENDIAN 1
4446#elif defined(__THUMBEL__)
......@@ -51,8 +53,6 @@
5153#define LITTLEENDIAN 1
5254#elif defined(__MIPSEL__)
5355#define LITTLEENDIAN 1
54#elif defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
55#define LITTLEENDIAN 1
5656#elif defined(__i386__)
5757#define LITTLEENDIAN 1
5858#elif defined(__alpha__)
lib/compiler_rt.zig+17-7
......@@ -4,17 +4,20 @@ comptime {
44 _ = @import("compiler_rt/atomics.zig");
55
66 _ = @import("compiler_rt/addf3.zig");
7 _ = @import("compiler_rt/addhf3.zig");
78 _ = @import("compiler_rt/addsf3.zig");
89 _ = @import("compiler_rt/adddf3.zig");
910 _ = @import("compiler_rt/addtf3.zig");
1011 _ = @import("compiler_rt/addxf3.zig");
1112
13 _ = @import("compiler_rt/subhf3.zig");
1214 _ = @import("compiler_rt/subsf3.zig");
1315 _ = @import("compiler_rt/subdf3.zig");
1416 _ = @import("compiler_rt/subtf3.zig");
1517 _ = @import("compiler_rt/subxf3.zig");
1618
1719 _ = @import("compiler_rt/mulf3.zig");
20 _ = @import("compiler_rt/mulhf3.zig");
1821 _ = @import("compiler_rt/mulsf3.zig");
1922 _ = @import("compiler_rt/muldf3.zig");
2023 _ = @import("compiler_rt/multf3.zig");
......@@ -34,51 +37,58 @@ comptime {
3437 _ = @import("compiler_rt/divxc3.zig");
3538 _ = @import("compiler_rt/divtc3.zig");
3639
40 _ = @import("compiler_rt/neghf2.zig");
3741 _ = @import("compiler_rt/negsf2.zig");
3842 _ = @import("compiler_rt/negdf2.zig");
3943 _ = @import("compiler_rt/negtf2.zig");
4044 _ = @import("compiler_rt/negxf2.zig");
4145
4246 _ = @import("compiler_rt/comparef.zig");
47 _ = @import("compiler_rt/cmphf2.zig");
4348 _ = @import("compiler_rt/cmpsf2.zig");
4449 _ = @import("compiler_rt/cmpdf2.zig");
4550 _ = @import("compiler_rt/cmptf2.zig");
4651 _ = @import("compiler_rt/cmpxf2.zig");
52 _ = @import("compiler_rt/gehf2.zig");
4753 _ = @import("compiler_rt/gesf2.zig");
4854 _ = @import("compiler_rt/gedf2.zig");
49 _ = @import("compiler_rt/getf2.zig");
5055 _ = @import("compiler_rt/gexf2.zig");
56 _ = @import("compiler_rt/getf2.zig");
57 _ = @import("compiler_rt/unordhf2.zig");
5158 _ = @import("compiler_rt/unordsf2.zig");
5259 _ = @import("compiler_rt/unorddf2.zig");
60 _ = @import("compiler_rt/unordxf2.zig");
5361 _ = @import("compiler_rt/unordtf2.zig");
5462
5563 _ = @import("compiler_rt/extendf.zig");
56 _ = @import("compiler_rt/extenddftf2.zig");
57 _ = @import("compiler_rt/extenddfxf2.zig");
5864 _ = @import("compiler_rt/extendhfsf2.zig");
65 _ = @import("compiler_rt/extendhfdf2.zig");
5966 _ = @import("compiler_rt/extendhftf2.zig");
6067 _ = @import("compiler_rt/extendhfxf2.zig");
6168 _ = @import("compiler_rt/extendsfdf2.zig");
6269 _ = @import("compiler_rt/extendsftf2.zig");
6370 _ = @import("compiler_rt/extendsfxf2.zig");
71 _ = @import("compiler_rt/extenddftf2.zig");
72 _ = @import("compiler_rt/extenddfxf2.zig");
6473 _ = @import("compiler_rt/extendxftf2.zig");
6574
6675 _ = @import("compiler_rt/truncf.zig");
6776 _ = @import("compiler_rt/truncsfhf2.zig");
6877 _ = @import("compiler_rt/truncdfhf2.zig");
6978 _ = @import("compiler_rt/truncdfsf2.zig");
79 _ = @import("compiler_rt/truncxfhf2.zig");
80 _ = @import("compiler_rt/truncxfsf2.zig");
81 _ = @import("compiler_rt/truncxfdf2.zig");
7082 _ = @import("compiler_rt/trunctfhf2.zig");
7183 _ = @import("compiler_rt/trunctfsf2.zig");
7284 _ = @import("compiler_rt/trunctfdf2.zig");
7385 _ = @import("compiler_rt/trunctfxf2.zig");
74 _ = @import("compiler_rt/truncxfhf2.zig");
75 _ = @import("compiler_rt/truncxfsf2.zig");
76 _ = @import("compiler_rt/truncxfdf2.zig");
7786
78 _ = @import("compiler_rt/divtf3.zig");
87 _ = @import("compiler_rt/divhf3.zig");
7988 _ = @import("compiler_rt/divsf3.zig");
8089 _ = @import("compiler_rt/divdf3.zig");
8190 _ = @import("compiler_rt/divxf3.zig");
91 _ = @import("compiler_rt/divtf3.zig");
8292 _ = @import("compiler_rt/sin.zig");
8393 _ = @import("compiler_rt/cos.zig");
8494 _ = @import("compiler_rt/sincos.zig");
lib/compiler_rt/addhf3.zig created+12
......@@ -0,0 +1,12 @@
1const common = @import("./common.zig");
2const addf3 = @import("./addf3.zig").addf3;
3
4pub const panic = common.panic;
5
6comptime {
7 @export(__addhf3, .{ .name = "__addhf3", .linkage = common.linkage });
8}
9
10fn __addhf3(a: f16, b: f16) callconv(.C) f16 {
11 return addf3(f16, a, b);
12}
lib/compiler_rt/cmphf2.zig created+50
......@@ -0,0 +1,50 @@
1///! The quoted behavior definitions are from
2///! https://gcc.gnu.org/onlinedocs/gcc-12.1.0/gccint/Soft-float-library-routines.html#Soft-float-library-routines
3const common = @import("./common.zig");
4const comparef = @import("./comparef.zig");
5
6pub const panic = common.panic;
7
8comptime {
9 @export(__eqhf2, .{ .name = "__eqhf2", .linkage = common.linkage });
10 @export(__nehf2, .{ .name = "__nehf2", .linkage = common.linkage });
11 @export(__lehf2, .{ .name = "__lehf2", .linkage = common.linkage });
12 @export(__cmphf2, .{ .name = "__cmphf2", .linkage = common.linkage });
13 @export(__lthf2, .{ .name = "__lthf2", .linkage = common.linkage });
14}
15
16/// "These functions calculate a <=> b. That is, if a is less than b, they return -1;
17/// if a is greater than b, they return 1; and if a and b are equal they return 0.
18/// If either argument is NaN they return 1..."
19///
20/// Note that this matches the definition of `__lehf2`, `__eqhf2`, `__nehf2`, `__cmphf2`,
21/// and `__lthf2`.
22fn __cmphf2(a: f16, b: f16) callconv(.C) i32 {
23 return @enumToInt(comparef.cmpf2(f16, comparef.LE, a, b));
24}
25
26/// "These functions return a value less than or equal to zero if neither argument is NaN,
27/// and a is less than or equal to b."
28pub fn __lehf2(a: f16, b: f16) callconv(.C) i32 {
29 return __cmphf2(a, b);
30}
31
32/// "These functions return zero if neither argument is NaN, and a and b are equal."
33/// Note that due to some kind of historical accident, __eqhf2 and __nehf2 are defined
34/// to have the same return value.
35pub fn __eqhf2(a: f16, b: f16) callconv(.C) i32 {
36 return __cmphf2(a, b);
37}
38
39/// "These functions return a nonzero value if either argument is NaN, or if a and b are unequal."
40/// Note that due to some kind of historical accident, __eqhf2 and __nehf2 are defined
41/// to have the same return value.
42pub fn __nehf2(a: f16, b: f16) callconv(.C) i32 {
43 return __cmphf2(a, b);
44}
45
46/// "These functions return a value less than zero if neither argument is NaN, and a
47/// is strictly less than b."
48pub fn __lthf2(a: f16, b: f16) callconv(.C) i32 {
49 return __cmphf2(a, b);
50}
lib/compiler_rt/divhf3.zig created+11
......@@ -0,0 +1,11 @@
1const common = @import("common.zig");
2const divsf3 = @import("./divsf3.zig");
3
4comptime {
5 @export(__divhf3, .{ .name = "__divhf3", .linkage = common.linkage });
6}
7
8pub fn __divhf3(a: f16, b: f16) callconv(.C) f16 {
9 // TODO: more efficient implementation
10 return @floatCast(f16, divsf3.__divsf3(a, b));
11}
lib/compiler_rt/extendhfdf2.zig created+12
......@@ -0,0 +1,12 @@
1const common = @import("./common.zig");
2const extendf = @import("./extendf.zig").extendf;
3
4pub const panic = common.panic;
5
6comptime {
7 @export(__extendhfdf2, .{ .name = "__extendhfdf2", .linkage = common.linkage });
8}
9
10pub fn __extendhfdf2(a: common.F16T) callconv(.C) f64 {
11 return extendf(f64, f16, @bitCast(u16, a));
12}
lib/compiler_rt/extendhfsf2.zig+2-7
......@@ -5,22 +5,17 @@ pub const panic = common.panic;
55
66comptime {
77 if (common.gnu_f16_abi) {
8 @export(__gnu_h2f_ieee, .{ .name = "__gnu_h2f_ieee", .linkage = common.linkage });
8 @export(__extendhfsf2, .{ .name = "__gnu_h2f_ieee", .linkage = common.linkage });
99 } else if (common.want_aeabi) {
1010 @export(__aeabi_h2f, .{ .name = "__aeabi_h2f", .linkage = common.linkage });
11 } else {
12 @export(__extendhfsf2, .{ .name = "__extendhfsf2", .linkage = common.linkage });
1311 }
12 @export(__extendhfsf2, .{ .name = "__extendhfsf2", .linkage = common.linkage });
1413}
1514
1615pub fn __extendhfsf2(a: common.F16T) callconv(.C) f32 {
1716 return extendf(f32, f16, @bitCast(u16, a));
1817}
1918
20fn __gnu_h2f_ieee(a: common.F16T) callconv(.C) f32 {
21 return extendf(f32, f16, @bitCast(u16, a));
22}
23
2419fn __aeabi_h2f(a: u16) callconv(.AAPCS) f32 {
2520 return extendf(f32, f16, @bitCast(u16, a));
2621}
lib/compiler_rt/gehf2.zig created+31
......@@ -0,0 +1,31 @@
1///! The quoted behavior definitions are from
2///! https://gcc.gnu.org/onlinedocs/gcc-12.1.0/gccint/Soft-float-library-routines.html#Soft-float-library-routines
3const common = @import("./common.zig");
4const comparef = @import("./comparef.zig");
5
6pub const panic = common.panic;
7
8comptime {
9 @export(__gehf2, .{ .name = "__gehf2", .linkage = common.linkage });
10 @export(__gthf2, .{ .name = "__gthf2", .linkage = common.linkage });
11}
12
13/// "These functions return a value greater than or equal to zero if neither
14/// argument is NaN, and a is greater than or equal to b."
15pub fn __gehf2(a: f16, b: f16) callconv(.C) i32 {
16 return @enumToInt(comparef.cmpf2(f16, comparef.GE, a, b));
17}
18
19/// "These functions return a value greater than zero if neither argument is NaN,
20/// and a is strictly greater than b."
21pub fn __gthf2(a: f16, b: f16) callconv(.C) i32 {
22 return __gehf2(a, b);
23}
24
25fn __aeabi_fcmpge(a: f16, b: f16) callconv(.AAPCS) i32 {
26 return @boolToInt(comparef.cmpf2(f16, comparef.GE, a, b) != .Less);
27}
28
29fn __aeabi_fcmpgt(a: f16, b: f16) callconv(.AAPCS) i32 {
30 return @boolToInt(comparef.cmpf2(f16, comparef.LE, a, b) == .Greater);
31}
lib/compiler_rt/mulf3.zig+3-2
......@@ -32,8 +32,9 @@ pub inline fn mulf3(comptime T: type, a: T, b: T) T {
3232 const infRep = @bitCast(Z, math.inf(T));
3333 const minNormalRep = @bitCast(Z, math.floatMin(T));
3434
35 const aExponent = @truncate(u32, (@bitCast(Z, a) >> significandBits) & maxExponent);
36 const bExponent = @truncate(u32, (@bitCast(Z, b) >> significandBits) & maxExponent);
35 const ZExp = if (typeWidth >= 32) u32 else Z;
36 const aExponent = @truncate(ZExp, (@bitCast(Z, a) >> significandBits) & maxExponent);
37 const bExponent = @truncate(ZExp, (@bitCast(Z, b) >> significandBits) & maxExponent);
3738 const productSign: Z = (@bitCast(Z, a) ^ @bitCast(Z, b)) & signBit;
3839
3940 var aSignificand: ZSignificand = @intCast(ZSignificand, @bitCast(Z, a) & significandMask);
lib/compiler_rt/mulhf3.zig created+12
......@@ -0,0 +1,12 @@
1const common = @import("./common.zig");
2const mulf3 = @import("./mulf3.zig").mulf3;
3
4pub const panic = common.panic;
5
6comptime {
7 @export(__mulhf3, .{ .name = "__mulhf3", .linkage = common.linkage });
8}
9
10pub fn __mulhf3(a: f16, b: f16) callconv(.C) f16 {
11 return mulf3(f16, a, b);
12}
lib/compiler_rt/neghf2.zig created+11
......@@ -0,0 +1,11 @@
1const common = @import("./common.zig");
2
3pub const panic = common.panic;
4
5comptime {
6 @export(__neghf2, .{ .name = "__neghf2", .linkage = common.linkage });
7}
8
9fn __neghf2(a: f16) callconv(.C) f16 {
10 return common.fneg(a);
11}
lib/compiler_rt/subhf3.zig created+12
......@@ -0,0 +1,12 @@
1const common = @import("./common.zig");
2
3pub const panic = common.panic;
4
5comptime {
6 @export(__subhf3, .{ .name = "__subhf3", .linkage = common.linkage });
7}
8
9fn __subhf3(a: f16, b: f16) callconv(.C) f16 {
10 const neg_b = @bitCast(f16, @bitCast(u16, b) ^ (@as(u16, 1) << 15));
11 return a + neg_b;
12}
lib/compiler_rt/tan.zig+4-2
......@@ -24,8 +24,10 @@ comptime {
2424 @export(tanf, .{ .name = "tanf", .linkage = common.linkage });
2525 @export(tan, .{ .name = "tan", .linkage = common.linkage });
2626 @export(__tanx, .{ .name = "__tanx", .linkage = common.linkage });
27 const tanq_sym_name = if (common.want_ppc_abi) "tanf128" else "tanq";
28 @export(tanq, .{ .name = tanq_sym_name, .linkage = common.linkage });
27 if (common.want_ppc_abi) {
28 @export(tanq, .{ .name = "tanf128", .linkage = common.linkage });
29 }
30 @export(tanq, .{ .name = "tanq", .linkage = common.linkage });
2931 @export(tanl, .{ .name = "tanl", .linkage = common.linkage });
3032}
3133
lib/compiler_rt/truncsfhf2.zig+2-7
......@@ -5,22 +5,17 @@ pub const panic = common.panic;
55
66comptime {
77 if (common.gnu_f16_abi) {
8 @export(__gnu_f2h_ieee, .{ .name = "__gnu_f2h_ieee", .linkage = common.linkage });
8 @export(__truncsfhf2, .{ .name = "__gnu_f2h_ieee", .linkage = common.linkage });
99 } else if (common.want_aeabi) {
1010 @export(__aeabi_f2h, .{ .name = "__aeabi_f2h", .linkage = common.linkage });
11 } else {
12 @export(__truncsfhf2, .{ .name = "__truncsfhf2", .linkage = common.linkage });
1311 }
12 @export(__truncsfhf2, .{ .name = "__truncsfhf2", .linkage = common.linkage });
1413}
1514
1615pub fn __truncsfhf2(a: f32) callconv(.C) common.F16T {
1716 return @bitCast(common.F16T, truncf(f16, f32, a));
1817}
1918
20fn __gnu_f2h_ieee(a: f32) callconv(.C) common.F16T {
21 return @bitCast(common.F16T, truncf(f16, f32, a));
22}
23
2419fn __aeabi_f2h(a: f32) callconv(.AAPCS) u16 {
2520 return @bitCast(common.F16T, truncf(f16, f32, a));
2621}
lib/compiler_rt/unordhf2.zig created+12
......@@ -0,0 +1,12 @@
1const common = @import("./common.zig");
2const comparef = @import("./comparef.zig");
3
4pub const panic = common.panic;
5
6comptime {
7 @export(__unordhf2, .{ .name = "__unordhf2", .linkage = common.linkage });
8}
9
10pub fn __unordhf2(a: f16, b: f16) callconv(.C) i32 {
11 return comparef.unordcmp(f16, a, b);
12}
lib/compiler_rt/unordxf2.zig created+12
......@@ -0,0 +1,12 @@
1const common = @import("./common.zig");
2const comparef = @import("./comparef.zig");
3
4pub const panic = common.panic;
5
6comptime {
7 @export(__unordxf2, .{ .name = "__unordxf2", .linkage = common.linkage });
8}
9
10pub fn __unordxf2(a: f80, b: f80) callconv(.C) i32 {
11 return comparef.unordcmp(f80, a, b);
12}
lib/std/atomic/Atomic.zig+4
......@@ -374,6 +374,10 @@ const atomic_rmw_orderings = [_]Ordering{
374374};
375375
376376test "Atomic.swap" {
377 // TODO: Re-enable when LLVM is released with a bugfix for isel of
378 // atomic load (currently fixed on trunk, broken on 15.0.2)
379 if (builtin.cpu.arch == .powerpc64le) return error.SkipZigTest;
380
377381 inline for (atomic_rmw_orderings) |ordering| {
378382 var x = Atomic(usize).init(5);
379383 try testing.expectEqual(x.swap(10, ordering), 5);
lib/std/target.zig+2
......@@ -1789,6 +1789,8 @@ pub const Target = struct {
17891789 .powerpcle,
17901790 .powerpc64,
17911791 .powerpc64le,
1792 .wasm32,
1793 .wasm64,
17921794 => true,
17931795
17941796 else => false,
src/codegen/llvm.zig+177-97
......@@ -2738,7 +2738,7 @@ pub const DeclGen = struct {
27382738 return dg.context.intType(bit_count);
27392739 },
27402740 .Float => switch (t.floatBits(target)) {
2741 16 => return dg.context.halfType(),
2741 16 => return if (backendSupportsF16(target)) dg.context.halfType() else dg.context.intType(16),
27422742 32 => return dg.context.floatType(),
27432743 64 => return dg.context.doubleType(),
27442744 80 => return if (backendSupportsF80(target)) dg.context.x86FP80Type() else dg.context.intType(80),
......@@ -3253,7 +3253,15 @@ pub const DeclGen = struct {
32533253 .Float => {
32543254 const llvm_ty = try dg.lowerType(tv.ty);
32553255 switch (tv.ty.floatBits(target)) {
3256 16, 32, 64 => return llvm_ty.constReal(tv.val.toFloat(f64)),
3256 16 => if (intrinsicsAllowed(tv.ty, target)) {
3257 return llvm_ty.constReal(tv.val.toFloat(f16));
3258 } else {
3259 const repr = @bitCast(u16, tv.val.toFloat(f16));
3260 const llvm_i16 = dg.context.intType(16);
3261 const int = llvm_i16.constInt(repr, .False);
3262 return int.constBitCast(llvm_ty);
3263 },
3264 32, 64 => return llvm_ty.constReal(tv.val.toFloat(f64)),
32573265 80 => {
32583266 const float = tv.val.toFloat(f80);
32593267 const repr = std.math.break_f80(float);
......@@ -7611,11 +7619,25 @@ pub const FuncGen = struct {
76117619 const target = self.dg.module.getTarget();
76127620 const dest_bits = dest_ty.floatBits(target);
76137621 const src_bits = operand_ty.floatBits(target);
7614 if (!backendSupportsF80(target) and (src_bits == 80 or dest_bits == 80)) {
7615 return softF80TruncOrExt(self, operand, src_bits, dest_bits);
7622
7623 if (intrinsicsAllowed(dest_ty, target) and intrinsicsAllowed(operand_ty, target)) {
7624 const dest_llvm_ty = try self.dg.lowerType(dest_ty);
7625 return self.builder.buildFPTrunc(operand, dest_llvm_ty, "");
7626 } else {
7627 const operand_llvm_ty = try self.dg.lowerType(operand_ty);
7628 const dest_llvm_ty = try self.dg.lowerType(dest_ty);
7629
7630 var fn_name_buf: [64]u8 = undefined;
7631 const fn_name = std.fmt.bufPrintZ(&fn_name_buf, "__trunc{s}f{s}f2", .{
7632 compilerRtFloatAbbrev(src_bits), compilerRtFloatAbbrev(dest_bits),
7633 }) catch unreachable;
7634
7635 const params = [1]*llvm.Value{operand};
7636 const param_types = [1]*llvm.Type{operand_llvm_ty};
7637 const llvm_fn = self.getLibcFunction(fn_name, &param_types, dest_llvm_ty);
7638
7639 return self.builder.buildCall(llvm_fn.globalGetValueType(), llvm_fn, &params, params.len, .C, .Auto, "");
76167640 }
7617 const dest_llvm_ty = try self.dg.lowerType(dest_ty);
7618 return self.builder.buildFPTrunc(operand, dest_llvm_ty, "");
76197641 }
76207642
76217643 fn airFpext(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
......@@ -7629,11 +7651,25 @@ pub const FuncGen = struct {
76297651 const target = self.dg.module.getTarget();
76307652 const dest_bits = dest_ty.floatBits(target);
76317653 const src_bits = operand_ty.floatBits(target);
7632 if (!backendSupportsF80(target) and (src_bits == 80 or dest_bits == 80)) {
7633 return softF80TruncOrExt(self, operand, src_bits, dest_bits);
7654
7655 if (intrinsicsAllowed(dest_ty, target) and intrinsicsAllowed(operand_ty, target)) {
7656 const dest_llvm_ty = try self.dg.lowerType(dest_ty);
7657 return self.builder.buildFPExt(operand, dest_llvm_ty, "");
7658 } else {
7659 const operand_llvm_ty = try self.dg.lowerType(operand_ty);
7660 const dest_llvm_ty = try self.dg.lowerType(dest_ty);
7661
7662 var fn_name_buf: [64]u8 = undefined;
7663 const fn_name = std.fmt.bufPrintZ(&fn_name_buf, "__extend{s}f{s}f2", .{
7664 compilerRtFloatAbbrev(src_bits), compilerRtFloatAbbrev(dest_bits),
7665 }) catch unreachable;
7666
7667 const params = [1]*llvm.Value{operand};
7668 const param_types = [1]*llvm.Type{operand_llvm_ty};
7669 const llvm_fn = self.getLibcFunction(fn_name, &param_types, dest_llvm_ty);
7670
7671 return self.builder.buildCall(llvm_fn.globalGetValueType(), llvm_fn, &params, params.len, .C, .Auto, "");
76347672 }
7635 const dest_llvm_ty = try self.dg.lowerType(self.air.typeOfIndex(inst));
7636 return self.builder.buildFPExt(operand, dest_llvm_ty, "");
76377673 }
76387674
76397675 fn airPtrToInt(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
......@@ -8717,12 +8753,78 @@ pub const FuncGen = struct {
87178753 return self.builder.buildShuffleVector(a, b, llvm_mask_value, "");
87188754 }
87198755
8756 /// Reduce a vector by repeatedly applying `llvm_fn` to produce an accumulated result.
8757 ///
8758 /// Equivalent to:
8759 /// reduce: {
8760 /// var i: usize = 0;
8761 /// var accum: T = init;
8762 /// while (i < vec.len) : (i += 1) {
8763 /// accum = llvm_fn(accum, vec[i]);
8764 /// }
8765 /// break :reduce accum;
8766 /// }
8767 ///
8768 fn buildReducedCall(
8769 self: *FuncGen,
8770 llvm_fn: *llvm.Value,
8771 operand_vector: *llvm.Value,
8772 vector_len: usize,
8773 accum_init: *llvm.Value,
8774 ) !*llvm.Value {
8775 const llvm_usize_ty = try self.dg.lowerType(Type.usize);
8776 const llvm_vector_len = llvm_usize_ty.constInt(vector_len, .False);
8777 const llvm_result_ty = accum_init.typeOf();
8778
8779 // Allocate and initialize our mutable variables
8780 const i_ptr = self.buildAlloca(llvm_usize_ty);
8781 _ = self.builder.buildStore(llvm_usize_ty.constInt(0, .False), i_ptr);
8782 const accum_ptr = self.buildAlloca(llvm_result_ty);
8783 _ = self.builder.buildStore(accum_init, accum_ptr);
8784
8785 // Setup the loop
8786 const loop = self.context.appendBasicBlock(self.llvm_func, "ReduceLoop");
8787 const loop_exit = self.context.appendBasicBlock(self.llvm_func, "AfterReduce");
8788 _ = self.builder.buildBr(loop);
8789 {
8790 self.builder.positionBuilderAtEnd(loop);
8791
8792 // while (i < vec.len)
8793 const i = self.builder.buildLoad(llvm_usize_ty, i_ptr, "");
8794 const cond = self.builder.buildICmp(.ULT, i, llvm_vector_len, "");
8795 const loop_then = self.context.appendBasicBlock(self.llvm_func, "ReduceLoopThen");
8796
8797 _ = self.builder.buildCondBr(cond, loop_then, loop_exit);
8798
8799 {
8800 self.builder.positionBuilderAtEnd(loop_then);
8801
8802 // accum = f(accum, vec[i]);
8803 const accum = self.builder.buildLoad(llvm_result_ty, accum_ptr, "");
8804 const element = self.builder.buildExtractElement(operand_vector, i, "");
8805 const params = [2]*llvm.Value{ accum, element };
8806 const new_accum = self.builder.buildCall(llvm_fn.globalGetValueType(), llvm_fn, &params, params.len, .C, .Auto, "");
8807 _ = self.builder.buildStore(new_accum, accum_ptr);
8808
8809 // i += 1
8810 const new_i = self.builder.buildAdd(i, llvm_usize_ty.constInt(1, .False), "");
8811 _ = self.builder.buildStore(new_i, i_ptr);
8812 _ = self.builder.buildBr(loop);
8813 }
8814 }
8815
8816 self.builder.positionBuilderAtEnd(loop_exit);
8817 return self.builder.buildLoad(llvm_result_ty, accum_ptr, "");
8818 }
8819
87208820 fn airReduce(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*llvm.Value {
87218821 if (self.liveness.isUnused(inst)) return null;
87228822 self.builder.setFastMath(want_fast_math);
8823 const target = self.dg.module.getTarget();
87238824
87248825 const reduce = self.air.instructions.items(.data)[inst].reduce;
8725 const operand = try self.resolveInst(reduce.operand);
8826 var operand = try self.resolveInst(reduce.operand);
8827 const operand_ty = self.air.typeOf(reduce.operand);
87268828 const scalar_ty = self.air.typeOfIndex(inst);
87278829
87288830 // TODO handle the fast math setting
......@@ -8733,17 +8835,21 @@ pub const FuncGen = struct {
87338835 .Xor => return self.builder.buildXorReduce(operand),
87348836 .Min => switch (scalar_ty.zigTypeTag()) {
87358837 .Int => return self.builder.buildIntMinReduce(operand, scalar_ty.isSignedInt()),
8736 .Float => return self.builder.buildFPMinReduce(operand),
8838 .Float => if (intrinsicsAllowed(scalar_ty, target)) {
8839 return self.builder.buildFPMinReduce(operand);
8840 },
87378841 else => unreachable,
87388842 },
87398843 .Max => switch (scalar_ty.zigTypeTag()) {
87408844 .Int => return self.builder.buildIntMaxReduce(operand, scalar_ty.isSignedInt()),
8741 .Float => return self.builder.buildFPMaxReduce(operand),
8845 .Float => if (intrinsicsAllowed(scalar_ty, target)) {
8846 return self.builder.buildFPMaxReduce(operand);
8847 },
87428848 else => unreachable,
87438849 },
87448850 .Add => switch (scalar_ty.zigTypeTag()) {
87458851 .Int => return self.builder.buildAddReduce(operand),
8746 .Float => {
8852 .Float => if (intrinsicsAllowed(scalar_ty, target)) {
87478853 const scalar_llvm_ty = try self.dg.lowerType(scalar_ty);
87488854 const neutral_value = scalar_llvm_ty.constReal(-0.0);
87498855 return self.builder.buildFPAddReduce(neutral_value, operand);
......@@ -8752,7 +8858,7 @@ pub const FuncGen = struct {
87528858 },
87538859 .Mul => switch (scalar_ty.zigTypeTag()) {
87548860 .Int => return self.builder.buildMulReduce(operand),
8755 .Float => {
8861 .Float => if (intrinsicsAllowed(scalar_ty, target)) {
87568862 const scalar_llvm_ty = try self.dg.lowerType(scalar_ty);
87578863 const neutral_value = scalar_llvm_ty.constReal(1.0);
87588864 return self.builder.buildFPMulReduce(neutral_value, operand);
......@@ -8760,6 +8866,44 @@ pub const FuncGen = struct {
87608866 else => unreachable,
87618867 },
87628868 }
8869
8870 // Reduction could not be performed with intrinsics.
8871 // Use a manual loop over a softfloat call instead.
8872 var fn_name_buf: [64]u8 = undefined;
8873 const float_bits = scalar_ty.floatBits(target);
8874 const fn_name = switch (reduce.operation) {
8875 .Min => std.fmt.bufPrintZ(&fn_name_buf, "{s}fmin{s}", .{
8876 libcFloatPrefix(float_bits), libcFloatSuffix(float_bits),
8877 }) catch unreachable,
8878 .Max => std.fmt.bufPrintZ(&fn_name_buf, "{s}fmax{s}", .{
8879 libcFloatPrefix(float_bits), libcFloatSuffix(float_bits),
8880 }) catch unreachable,
8881 .Add => std.fmt.bufPrintZ(&fn_name_buf, "__add{s}f3", .{
8882 compilerRtFloatAbbrev(float_bits),
8883 }) catch unreachable,
8884 .Mul => std.fmt.bufPrintZ(&fn_name_buf, "__mul{s}f3", .{
8885 compilerRtFloatAbbrev(float_bits),
8886 }) catch unreachable,
8887 else => unreachable,
8888 };
8889 var init_value_payload = Value.Payload.Float_32{
8890 .data = switch (reduce.operation) {
8891 .Min => std.math.nan(f32),
8892 .Max => std.math.nan(f32),
8893 .Add => -0.0,
8894 .Mul => 1.0,
8895 else => unreachable,
8896 },
8897 };
8898
8899 const param_llvm_ty = try self.dg.lowerType(scalar_ty);
8900 const param_types = [2]*llvm.Type{ param_llvm_ty, param_llvm_ty };
8901 const libc_fn = self.getLibcFunction(fn_name, &param_types, param_llvm_ty);
8902 const init_value = try self.dg.lowerValue(.{
8903 .ty = scalar_ty,
8904 .val = Value.initPayload(&init_value_payload.base),
8905 });
8906 return self.buildReducedCall(libc_fn, operand, operand_ty.vectorLen(), init_value);
87638907 }
87648908
87658909 fn airAggregateInit(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
......@@ -9051,7 +9195,13 @@ pub const FuncGen = struct {
90519195 const target = self.dg.module.getTarget();
90529196 switch (prefetch.cache) {
90539197 .instruction => switch (target.cpu.arch) {
9054 .x86_64, .i386 => return null,
9198 .x86_64,
9199 .i386,
9200 .powerpc,
9201 .powerpcle,
9202 .powerpc64,
9203 .powerpc64le,
9204 => return null,
90559205 .arm, .armeb, .thumb, .thumbeb => {
90569206 switch (prefetch.rw) {
90579207 .write => return null,
......@@ -9091,87 +9241,6 @@ pub const FuncGen = struct {
90919241 return null;
90929242 }
90939243
9094 fn softF80TruncOrExt(
9095 self: *FuncGen,
9096 operand: *llvm.Value,
9097 src_bits: u16,
9098 dest_bits: u16,
9099 ) !?*llvm.Value {
9100 const target = self.dg.module.getTarget();
9101
9102 var param_llvm_ty: *llvm.Type = self.context.intType(80);
9103 var ret_llvm_ty: *llvm.Type = param_llvm_ty;
9104 var fn_name: [*:0]const u8 = undefined;
9105 var arg = operand;
9106 var final_cast: ?*llvm.Type = null;
9107
9108 assert(src_bits == 80 or dest_bits == 80);
9109
9110 if (src_bits == 80) switch (dest_bits) {
9111 16 => {
9112 // See corresponding condition at definition of
9113 // __truncxfhf2 in compiler-rt.
9114 if (target.cpu.arch.isAARCH64()) {
9115 ret_llvm_ty = self.context.halfType();
9116 } else {
9117 ret_llvm_ty = self.context.intType(16);
9118 final_cast = self.context.halfType();
9119 }
9120 fn_name = "__truncxfhf2";
9121 },
9122 32 => {
9123 ret_llvm_ty = self.context.floatType();
9124 fn_name = "__truncxfsf2";
9125 },
9126 64 => {
9127 ret_llvm_ty = self.context.doubleType();
9128 fn_name = "__truncxfdf2";
9129 },
9130 80 => return operand,
9131 128 => {
9132 ret_llvm_ty = self.context.fp128Type();
9133 fn_name = "__extendxftf2";
9134 },
9135 else => unreachable,
9136 } else switch (src_bits) {
9137 16 => {
9138 // See corresponding condition at definition of
9139 // __extendhfxf2 in compiler-rt.
9140 param_llvm_ty = if (target.cpu.arch.isAARCH64())
9141 self.context.halfType()
9142 else
9143 self.context.intType(16);
9144 arg = self.builder.buildBitCast(arg, param_llvm_ty, "");
9145 fn_name = "__extendhfxf2";
9146 },
9147 32 => {
9148 param_llvm_ty = self.context.floatType();
9149 fn_name = "__extendsfxf2";
9150 },
9151 64 => {
9152 param_llvm_ty = self.context.doubleType();
9153 fn_name = "__extenddfxf2";
9154 },
9155 80 => return operand,
9156 128 => {
9157 param_llvm_ty = self.context.fp128Type();
9158 fn_name = "__trunctfxf2";
9159 },
9160 else => unreachable,
9161 }
9162
9163 const llvm_fn = self.dg.object.llvm_module.getNamedFunction(fn_name) orelse f: {
9164 const param_types = [_]*llvm.Type{param_llvm_ty};
9165 const fn_type = llvm.functionType(ret_llvm_ty, &param_types, param_types.len, .False);
9166 break :f self.dg.object.llvm_module.addFunction(fn_name, fn_type);
9167 };
9168
9169 var args: [1]*llvm.Value = .{arg};
9170 const result = self.builder.buildCall(llvm_fn.globalGetValueType(), llvm_fn, &args, args.len, .C, .Auto, "");
9171 const final_cast_llvm_ty = final_cast orelse return result;
9172 return self.builder.buildBitCast(result, final_cast_llvm_ty, "");
9173 }
9174
91759244 fn getErrorNameTable(self: *FuncGen) !*llvm.Value {
91769245 if (self.dg.object.error_name_table) |table| {
91779246 return table;
......@@ -10451,6 +10520,17 @@ fn backendSupportsF80(target: std.Target) bool {
1045110520/// if it produces miscompilations.
1045210521fn backendSupportsF16(target: std.Target) bool {
1045310522 return switch (target.cpu.arch) {
10523 .powerpc,
10524 .powerpcle,
10525 .powerpc64,
10526 .powerpc64le,
10527 .wasm32,
10528 .wasm64,
10529 .mips,
10530 .mipsel,
10531 .mips64,
10532 .mips64el,
10533 => false,
1045410534 else => true,
1045510535 };
1045610536}
src/stage1/analyze.cpp+4-2
......@@ -6358,9 +6358,11 @@ void init_const_float(ZigValue *const_val, ZigType *type, double value) {
63586358 const_val->data.x_f64 = value;
63596359 break;
63606360 case 80:
6361 zig_double_to_extF80M(value, &const_val->data.x_f80);
6362 break;
63616363 case 128:
6362 // if we need this, we should add a function that accepts a float128_t param
6363 zig_unreachable();
6364 zig_double_to_f128M(value, &const_val->data.x_f128);
6365 break;
63646366 default:
63656367 zig_unreachable();
63666368 }
src/stage1/codegen.cpp+139-39
......@@ -80,6 +80,7 @@ void codegen_set_strip(CodeGen *g, bool strip) {
8080 }
8181}
8282
83static LLVMValueRef get_soft_float_fn(CodeGen *g, const char *name, int param_count, LLVMTypeRef param_type, LLVMTypeRef return_type);
8384static void render_const_val(CodeGen *g, ZigValue *const_val, const char *name);
8485static void render_const_val_global(CodeGen *g, ZigValue *const_val, const char *name);
8586static 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_
17361737 }
17371738 }
17381739
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);
17451741 result = LLVMBuildCall2(g->builder, LLVMGlobalGetValueType(func_ref), func_ref, &expr_val, 1, "");
17461742
17471743 // 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
17661762 uint64_t wanted_bits;
17671763 if (scalar_actual_type->id == ZigTypeIdFloat) {
17681764
1769 if ((scalar_actual_type == g->builtin_types.entry_f80
1765 if (((scalar_actual_type == g->builtin_types.entry_f80
17701766 || 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)))
17721771 {
17731772 return gen_soft_float_widen_or_shorten(g, actual_type, wanted_type, expr_val);
17741773 }
......@@ -3100,6 +3099,7 @@ static LLVMValueRef gen_float_un_op(CodeGen *g, LLVMValueRef operand, ZigType *o
31003099 ZigType *elem_type = operand_type->id == ZigTypeIdVector ? operand_type->data.vector.elem_type : operand_type;
31013100 if ((elem_type == g->builtin_types.entry_f80 && !target_has_f80(g->zig_target)) ||
31023101 (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)) ||
31033103 op == BuiltinFnIdTan)
31043104 {
31053105 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,
36903690 ZigType *operand_type = op1->value->type;
36913691 ZigType *scalar_type = (operand_type->id == ZigTypeIdVector) ? operand_type->data.vector.elem_type : operand_type;
36923692 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))) {
36943695 // LLVM incorrectly lowers the soft float calls for f128 as if they operated on `long double`.
36953696 // On some targets this will be incorrect, so we manually lower the call ourselves.
36963697 LLVMValueRef op1_value = ir_llvm_value(g, op1);
......@@ -4024,7 +4025,8 @@ static LLVMValueRef ir_render_cast(CodeGen *g, Stage1Air *executable,
40244025 assert(actual_type->id == ZigTypeIdInt);
40254026 {
40264027 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))) {
40284030 return gen_soft_int_to_float_op(g, expr_val, actual_type, wanted_type);
40294031 } else {
40304032 if (actual_type->data.integral.is_signed) {
......@@ -4042,7 +4044,8 @@ static LLVMValueRef ir_render_cast(CodeGen *g, Stage1Air *executable,
40424044
40434045 LLVMValueRef result;
40444046 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))) {
40464049 result = gen_soft_float_to_int_op(g, expr_val, actual_type, wanted_type);
40474050 } else {
40484051 if (wanted_type->data.integral.is_signed) {
......@@ -4396,7 +4399,8 @@ static LLVMValueRef gen_negation(CodeGen *g, Stage1AirInst *inst, Stage1AirInst
43964399 operand_type->data.vector.elem_type : operand_type;
43974400
43984401 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))) {
44004404 return gen_soft_float_neg(g, operand_type, llvm_operand);
44014405 }
44024406
......@@ -6477,6 +6481,55 @@ static LLVMValueRef ir_render_cmpxchg(CodeGen *g, Stage1Air *executable, Stage1A
64776481 return result_loc;
64786482}
64796483
6484static LLVMValueRef ir_render_reduced_call(CodeGen *g, LLVMValueRef llvm_fn, LLVMValueRef operand_vector, size_t vector_len, LLVMValueRef accum_init, ZigType *accum_ty) {
6485 LLVMTypeRef llvm_usize_ty = g->builtin_types.entry_usize->llvm_type;
6486 LLVMValueRef llvm_vector_len = LLVMConstInt(llvm_usize_ty, vector_len, false);
6487 LLVMTypeRef llvm_result_ty = LLVMTypeOf(accum_init);
6488
6489 // Allocate and initialize our mutable variables
6490 LLVMValueRef i_ptr = build_alloca(g, g->builtin_types.entry_usize, "i", 0);
6491 LLVMBuildStore(g->builder, LLVMConstInt(llvm_usize_ty, 0, false), i_ptr);
6492 LLVMValueRef accum_ptr = build_alloca(g, accum_ty, "accum", 0);
6493 LLVMBuildStore(g->builder, accum_init, accum_ptr);
6494
6495 // Setup the loop
6496 LLVMBasicBlockRef loop = LLVMAppendBasicBlock(g->cur_fn_val, "ReduceLoop");
6497 LLVMBasicBlockRef loop_exit = LLVMAppendBasicBlock(g->cur_fn_val, "AfterReduce");
6498 LLVMBuildBr(g->builder, loop);
6499 {
6500 LLVMPositionBuilderAtEnd(g->builder, loop);
6501
6502 // while (i < vec.len)
6503 LLVMValueRef i = LLVMBuildLoad2(g->builder, llvm_usize_ty, i_ptr, "");
6504 LLVMValueRef cond = LLVMBuildICmp(g->builder, LLVMIntULT, i, llvm_vector_len, "");
6505 LLVMBasicBlockRef loop_then = LLVMAppendBasicBlock(g->cur_fn_val, "ReduceLoopThen");
6506
6507 LLVMBuildCondBr(g->builder, cond, loop_then, loop_exit);
6508
6509 {
6510 LLVMPositionBuilderAtEnd(g->builder, loop_then);
6511
6512 // accum = f(accum, vec[i]);
6513 LLVMValueRef accum = LLVMBuildLoad2(g->builder, llvm_result_ty, accum_ptr, "");
6514 LLVMValueRef element = LLVMBuildExtractElement(g->builder, operand_vector, i, "");
6515 LLVMValueRef params[] {
6516 accum,
6517 element
6518 };
6519 LLVMValueRef new_accum = LLVMBuildCall2(g->builder, LLVMGlobalGetValueType(llvm_fn), llvm_fn, params, 2, "");
6520 LLVMBuildStore(g->builder, new_accum, accum_ptr);
6521
6522 // i += 1
6523 LLVMValueRef new_i = LLVMBuildAdd(g->builder, i, LLVMConstInt(llvm_usize_ty, 1, false), "");
6524 LLVMBuildStore(g->builder, new_i, i_ptr);
6525 LLVMBuildBr(g->builder, loop);
6526 }
6527 }
6528
6529 LLVMPositionBuilderAtEnd(g->builder, loop_exit);
6530 return LLVMBuildLoad2(g->builder, llvm_result_ty, accum_ptr, "");
6531}
6532
64806533static LLVMValueRef ir_render_reduce(CodeGen *g, Stage1Air *executable, Stage1AirInstReduce *instruction) {
64816534 LLVMValueRef value = ir_llvm_value(g, instruction->value);
64826535
......@@ -6484,61 +6537,100 @@ static LLVMValueRef ir_render_reduce(CodeGen *g, Stage1Air *executable, Stage1Ai
64846537 assert(value_type->id == ZigTypeIdVector);
64856538 ZigType *scalar_type = value_type->data.vector.elem_type;
64866539
6540 bool float_intrinsics_allowed = true;
6541 const char *compiler_rt_type_abbrev = nullptr;
6542 const char *math_float_prefix = nullptr;
6543 const char *math_float_suffix = nullptr;
6544 if ((scalar_type == g->builtin_types.entry_f80 && !target_has_f80(g->zig_target)) ||
6545 (scalar_type == g->builtin_types.entry_f128 && !target_long_double_is_f128(g->zig_target)) ||
6546 (scalar_type == g->builtin_types.entry_f16 && !target_is_arm(g->zig_target))) {
6547 float_intrinsics_allowed = false;
6548 compiler_rt_type_abbrev = get_compiler_rt_type_abbrev(scalar_type);
6549 math_float_prefix = libc_float_prefix(g, scalar_type);
6550 math_float_suffix = libc_float_suffix(g, scalar_type);
6551 }
6552
64876553 ZigLLVMSetFastMath(g->builder, ir_want_fast_math(g, &instruction->base));
64886554
6489 LLVMValueRef result_val;
6555 char fn_name[64];
6556 ZigValue *init_value = nullptr;
64906557 switch (instruction->op) {
64916558 case ReduceOp_and:
64926559 assert(scalar_type->id == ZigTypeIdInt || scalar_type->id == ZigTypeIdBool);
6493 result_val = ZigLLVMBuildAndReduce(g->builder, value);
6560 return ZigLLVMBuildAndReduce(g->builder, value);
64946561 break;
64956562 case ReduceOp_or:
64966563 assert(scalar_type->id == ZigTypeIdInt || scalar_type->id == ZigTypeIdBool);
6497 result_val = ZigLLVMBuildOrReduce(g->builder, value);
6564 return ZigLLVMBuildOrReduce(g->builder, value);
64986565 break;
64996566 case ReduceOp_xor:
65006567 assert(scalar_type->id == ZigTypeIdInt || scalar_type->id == ZigTypeIdBool);
6501 result_val = ZigLLVMBuildXorReduce(g->builder, value);
6568 return ZigLLVMBuildXorReduce(g->builder, value);
65026569 break;
65036570 case ReduceOp_min: {
65046571 if (scalar_type->id == ZigTypeIdInt) {
65056572 const bool is_signed = scalar_type->data.integral.is_signed;
6506 result_val = ZigLLVMBuildIntMinReduce(g->builder, value, is_signed);
6573 return ZigLLVMBuildIntMinReduce(g->builder, value, is_signed);
65076574 } else if (scalar_type->id == ZigTypeIdFloat) {
6508 result_val = ZigLLVMBuildFPMinReduce(g->builder, value);
6575 if (float_intrinsics_allowed) {
6576 return ZigLLVMBuildFPMinReduce(g->builder, value);
6577 } else {
6578 snprintf(fn_name, sizeof(fn_name), "%sfmin%s", math_float_prefix, math_float_suffix);
6579 init_value = create_const_float(g, scalar_type, NAN);
6580 }
65096581 } else zig_unreachable();
65106582 } break;
65116583 case ReduceOp_max: {
65126584 if (scalar_type->id == ZigTypeIdInt) {
65136585 const bool is_signed = scalar_type->data.integral.is_signed;
6514 result_val = ZigLLVMBuildIntMaxReduce(g->builder, value, is_signed);
6586 return ZigLLVMBuildIntMaxReduce(g->builder, value, is_signed);
65156587 } else if (scalar_type->id == ZigTypeIdFloat) {
6516 result_val = ZigLLVMBuildFPMaxReduce(g->builder, value);
6588 if (float_intrinsics_allowed) {
6589 return ZigLLVMBuildFPMaxReduce(g->builder, value);
6590 } else {
6591 snprintf(fn_name, sizeof(fn_name), "%sfmax%s", math_float_prefix, math_float_suffix);
6592 init_value = create_const_float(g, scalar_type, NAN);
6593 }
65176594 } else zig_unreachable();
65186595 } break;
65196596 case ReduceOp_add: {
65206597 if (scalar_type->id == ZigTypeIdInt) {
6521 result_val = ZigLLVMBuildAddReduce(g->builder, value);
6598 return ZigLLVMBuildAddReduce(g->builder, value);
65226599 } else if (scalar_type->id == ZigTypeIdFloat) {
6523 LLVMValueRef neutral_value = LLVMConstReal(
6524 get_llvm_type(g, scalar_type), -0.0);
6525 result_val = ZigLLVMBuildFPAddReduce(g->builder, neutral_value, value);
6600 if (float_intrinsics_allowed) {
6601 LLVMValueRef neutral_value = LLVMConstReal(
6602 get_llvm_type(g, scalar_type), -0.0);
6603 return ZigLLVMBuildFPAddReduce(g->builder, neutral_value, value);
6604 } else {
6605 snprintf(fn_name, sizeof(fn_name), "__add%sf3", compiler_rt_type_abbrev);
6606 init_value = create_const_float(g, scalar_type, 0.0);
6607 }
65266608 } else zig_unreachable();
65276609 } break;
65286610 case ReduceOp_mul: {
65296611 if (scalar_type->id == ZigTypeIdInt) {
6530 result_val = ZigLLVMBuildMulReduce(g->builder, value);
6612 return ZigLLVMBuildMulReduce(g->builder, value);
65316613 } else if (scalar_type->id == ZigTypeIdFloat) {
6532 LLVMValueRef neutral_value = LLVMConstReal(
6533 get_llvm_type(g, scalar_type), 1.0);
6534 result_val = ZigLLVMBuildFPMulReduce(g->builder, neutral_value, value);
6614 if (float_intrinsics_allowed) {
6615 LLVMValueRef neutral_value = LLVMConstReal(
6616 get_llvm_type(g, scalar_type), 1.0);
6617 return ZigLLVMBuildFPMulReduce(g->builder, neutral_value, value);
6618 } else {
6619 snprintf(fn_name, sizeof(fn_name), "__mul%sf3", compiler_rt_type_abbrev);
6620 init_value = create_const_float(g, scalar_type, 1.0);
6621 }
65356622 } else zig_unreachable();
65366623 } break;
65376624 default:
65386625 zig_unreachable();
65396626 }
65406627
6541 return result_val;
6628
6629 LLVMValueRef llvm_init_value = gen_const_val(g, init_value, "");
6630 uint32_t vector_len = value_type->data.vector.len;
6631 LLVMTypeRef llvm_scalar_type = get_llvm_type(g, scalar_type);
6632 const LLVMValueRef llvm_fn = get_soft_float_fn(g, fn_name, 2, llvm_scalar_type, llvm_scalar_type);
6633 return ir_render_reduced_call(g, llvm_fn, value, vector_len, llvm_init_value, scalar_type);
65426634}
65436635
65446636static LLVMValueRef ir_render_fence(CodeGen *g, Stage1Air *executable, Stage1AirInstFence *instruction) {
......@@ -6650,6 +6742,10 @@ static LLVMValueRef ir_render_prefetch(CodeGen *g, Stage1Air *executable, Stage1
66506742 switch (g->zig_target->arch) {
66516743 case ZigLLVM_x86:
66526744 case ZigLLVM_x86_64:
6745 case ZigLLVM_ppc:
6746 case ZigLLVM_ppcle:
6747 case ZigLLVM_ppc64:
6748 case ZigLLVM_ppc64le:
66536749 return nullptr;
66546750 default:
66556751 break;
......@@ -7374,7 +7470,9 @@ static LLVMValueRef ir_render_soft_mul_add(CodeGen *g, Stage1Air *executable, St
73747470 uint32_t vector_len = operand_type->id == ZigTypeIdVector ? operand_type->data.vector.len : 0;
73757471
73767472 const char *fn_name;
7377 if (float_type == g->builtin_types.entry_f32)
7473 if (float_type == g->builtin_types.entry_f16)
7474 fn_name = "__fmah";
7475 else if (float_type == g->builtin_types.entry_f32)
73787476 fn_name = "fmaf";
73797477 else if (float_type == g->builtin_types.entry_f64)
73807478 fn_name = "fma";
......@@ -7385,13 +7483,8 @@ static LLVMValueRef ir_render_soft_mul_add(CodeGen *g, Stage1Air *executable, St
73857483 else
73867484 zig_unreachable();
73877485
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 }
7486 LLVMTypeRef float_type_ref = float_type->llvm_type;
7487 LLVMValueRef func_ref = get_soft_float_fn(g, fn_name, 3, float_type_ref, float_type_ref);
73957488
73967489 LLVMValueRef op1 = ir_llvm_value(g, instruction->op1);
73977490 LLVMValueRef op2 = ir_llvm_value(g, instruction->op2);
......@@ -7421,7 +7514,8 @@ static LLVMValueRef ir_render_mul_add(CodeGen *g, Stage1Air *executable, Stage1A
74217514 ZigType *operand_type = instruction->op1->value->type;
74227515 operand_type = operand_type->id == ZigTypeIdVector ? operand_type->data.vector.elem_type : operand_type;
74237516 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))) {
7517 (operand_type == g->builtin_types.entry_f128 && !target_long_double_is_f128(g->zig_target)) ||
7518 (operand_type == g->builtin_types.entry_f16 && !target_is_arm(g->zig_target))) {
74257519 return ir_render_soft_mul_add(g, executable, instruction, operand_type);
74267520 }
74277521 LLVMValueRef op1 = ir_llvm_value(g, instruction->op1);
......@@ -9740,7 +9834,12 @@ static void define_builtin_types(CodeGen *g) {
97409834 }
97419835 }
97429836
9743 add_fp_entry(g, "f16", 16, LLVMHalfType(), &g->builtin_types.entry_f16);
9837 if (target_is_arm(g->zig_target)) {
9838 add_fp_entry(g, "f16", 16, LLVMHalfType(), &g->builtin_types.entry_f16);
9839 } else {
9840 ZigType *u16_ty = get_int_type(g, false, 16);
9841 add_fp_entry(g, "f16", 16, get_llvm_type(g, u16_ty), &g->builtin_types.entry_f16);
9842 }
97449843 add_fp_entry(g, "f32", 32, LLVMFloatType(), &g->builtin_types.entry_f32);
97459844 add_fp_entry(g, "f64", 64, LLVMDoubleType(), &g->builtin_types.entry_f64);
97469845 add_fp_entry(g, "f128", 128, LLVMFP128Type(), &g->builtin_types.entry_f128);
......@@ -9837,6 +9936,7 @@ static void define_builtin_types(CodeGen *g) {
98379936 add_fp_entry(g, "c_longdouble", 128, LLVMFP128Type(), &g->builtin_types.entry_c_longdouble);
98389937 break;
98399938 case ZigLLVM_ppc:
9939 case ZigLLVM_ppcle:
98409940 case ZigLLVM_ppc64:
98419941 case ZigLLVM_ppc64le:
98429942 add_fp_entry(g, "c_longdouble", 128, LLVMFP128Type(), &g->builtin_types.entry_c_longdouble);
src/stage1/softfloat.hpp+14
......@@ -21,6 +21,20 @@ static inline float16_t zig_double_to_f16(double x) {
2121 return f64_to_f16(y);
2222}
2323
24static inline void zig_double_to_extF80M(double x, extFloat80_t *result) {
25 float64_t y;
26 static_assert(sizeof(x) == sizeof(y), "");
27 memcpy(&y, &x, sizeof(x));
28 f64_to_extF80M(y, result);
29}
30
31static inline void zig_double_to_f128M(double x, float128_t *result) {
32 float64_t y;
33 static_assert(sizeof(x) == sizeof(y), "");
34 memcpy(&y, &x, sizeof(x));
35 f64_to_f128M(y, result);
36}
37
2438
2539// Return value is safe to coerce to float even when |x| is NaN or Infinity.
2640static inline double zig_f16_to_double(float16_t x) {
src/stage1/target.cpp+3-3
......@@ -950,7 +950,6 @@ bool target_is_arm(const ZigTarget *target) {
950950 case ZigLLVM_msp430:
951951 case ZigLLVM_nvptx:
952952 case ZigLLVM_nvptx64:
953 case ZigLLVM_ppc64le:
954953 case ZigLLVM_r600:
955954 case ZigLLVM_renderscript32:
956955 case ZigLLVM_renderscript64:
......@@ -971,6 +970,7 @@ bool target_is_arm(const ZigTarget *target) {
971970 case ZigLLVM_ppc:
972971 case ZigLLVM_ppcle:
973972 case ZigLLVM_ppc64:
973 case ZigLLVM_ppc64le:
974974 case ZigLLVM_ve:
975975 case ZigLLVM_spirv32:
976976 case ZigLLVM_spirv64:
......@@ -1125,8 +1125,8 @@ bool target_is_mips(const ZigTarget *target) {
11251125}
11261126
11271127bool target_is_ppc(const ZigTarget *target) {
1128 return target->arch == ZigLLVM_ppc || target->arch == ZigLLVM_ppc64 ||
1129 target->arch == ZigLLVM_ppc64le;
1128 return target->arch == ZigLLVM_ppc || target->arch == ZigLLVM_ppcle ||
1129 target->arch == ZigLLVM_ppc64 || target->arch == ZigLLVM_ppc64le;
11301130}
11311131
11321132// Returns the minimum alignment for every function pointer on the given
test/behavior.zig+2-1
......@@ -89,7 +89,6 @@ test {
8989 _ = @import("behavior/bugs/12551.zig");
9090 _ = @import("behavior/bugs/12644.zig");
9191 _ = @import("behavior/bugs/12680.zig");
92 _ = @import("behavior/bugs/12776.zig");
9392 _ = @import("behavior/bugs/12786.zig");
9493 _ = @import("behavior/bugs/12794.zig");
9594 _ = @import("behavior/bugs/12801-1.zig");
......@@ -187,6 +186,8 @@ test {
187186 _ = @import("behavior/packed_struct_explicit_backing_int.zig");
188187 _ = @import("behavior/empty_union.zig");
189188 _ = @import("behavior/inline_switch.zig");
189 _ = @import("behavior/bugs/12723.zig");
190 _ = @import("behavior/bugs/12776.zig");
190191 }
191192
192193 if (builtin.os.tag != .wasi) {
test/behavior/align.zig+2
......@@ -566,6 +566,8 @@ test "@alignCast null" {
566566}
567567
568568test "alignment of slice element" {
569 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
570
569571 const a: []align(1024) const u8 = undefined;
570572 try expect(@TypeOf(&a[0]) == *align(1024) const u8);
571573}
test/behavior/bugs/11816.zig+1
......@@ -3,6 +3,7 @@ const builtin = @import("builtin");
33
44test {
55 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
6 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
67
78 var x: u32 = 3;
89 const val: usize = while (true) switch (x) {
test/behavior/bugs/12723.zig created+11
......@@ -0,0 +1,11 @@
1const expect = @import("std").testing.expect;
2
3// This test causes a compile error on stage1 regardless of whether
4// the body of the test is comptime-gated or not. To workaround this,
5// we gate the inclusion of the test file.
6test "Non-exhaustive enum backed by comptime_int" {
7 const E = enum(comptime_int) { a, b, c, _ };
8 comptime var e: E = .a;
9 e = @intToEnum(E, 378089457309184723749);
10 try expect(@enumToInt(e) == 378089457309184723749);
11}
test/behavior/bugs/12801-1.zig+1
......@@ -8,6 +8,7 @@ fn capacity_() u64 {
88
99test {
1010 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
11 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
1112
1213 try std.testing.expect((@This(){}).capacity() == 64);
1314}
test/behavior/bugs/12801-2.zig+1
......@@ -14,6 +14,7 @@ const Auto = struct {
1414 }
1515};
1616test {
17 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
1718 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1819 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1920 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
test/behavior/enum.zig-7
......@@ -1169,10 +1169,3 @@ test "Non-exhaustive enum with nonstandard int size behaves correctly" {
11691169 const E = enum(u15) { _ };
11701170 try expect(@sizeOf(E) == @sizeOf(u15));
11711171}
1172
1173test "Non-exhaustive enum backed by comptime_int" {
1174 const E = enum(comptime_int) { a, b, c, _ };
1175 comptime var e: E = .a;
1176 e = @intToEnum(E, 378089457309184723749);
1177 try expect(@enumToInt(e) == 378089457309184723749);
1178}
test/behavior/eval.zig+2
......@@ -1339,6 +1339,8 @@ test "lazy value is resolved as slice operand" {
13391339}
13401340
13411341test "break from inline loop depends on runtime condition" {
1342 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
1343
13421344 const S = struct {
13431345 fn foo(a: u8) bool {
13441346 return a == 4;
test/behavior/muladd.zig-11
......@@ -71,17 +71,6 @@ test "@mulAdd f128" {
7171 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
7272 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
7373
74 if (builtin.os.tag == .macos and builtin.cpu.arch == .aarch64) {
75 // https://github.com/ziglang/zig/issues/9900
76 return error.SkipZigTest;
77 }
78
79 if (builtin.zig_backend == .stage1 and
80 builtin.cpu.arch == .i386 and builtin.os.tag == .linux)
81 {
82 return error.SkipZigTest;
83 }
84
8574 comptime try testMulAdd128();
8675 try testMulAdd128();
8776}
test/behavior/packed-struct.zig+1
......@@ -585,6 +585,7 @@ test "runtime init of unnamed packed struct type" {
585585}
586586
587587test "packed struct passed to callconv(.C) function" {
588 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
588589 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
589590 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
590591 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
test/behavior/vector.zig+2-8
......@@ -506,18 +506,12 @@ test "vector division operators" {
506506 }
507507
508508 fn doTheTest() !void {
509 // https://github.com/ziglang/zig/issues/4952
510 if (builtin.target.os.tag != .windows) {
511 try doTheTestDiv(f16, [4]f16{ 4.0, -4.0, 4.0, -4.0 }, [4]f16{ 1.0, 2.0, -1.0, -2.0 });
512 }
509 try doTheTestDiv(f16, [4]f16{ 4.0, -4.0, 4.0, -4.0 }, [4]f16{ 1.0, 2.0, -1.0, -2.0 });
513510
514511 try doTheTestDiv(f32, [4]f32{ 4.0, -4.0, 4.0, -4.0 }, [4]f32{ 1.0, 2.0, -1.0, -2.0 });
515512 try doTheTestDiv(f64, [4]f64{ 4.0, -4.0, 4.0, -4.0 }, [4]f64{ 1.0, 2.0, -1.0, -2.0 });
516513
517 // https://github.com/ziglang/zig/issues/4952
518 if (builtin.target.os.tag != .windows) {
519 try doTheTestMod(f16, [4]f16{ 4.0, -4.0, 4.0, -4.0 }, [4]f16{ 1.0, 2.0, 0.5, 3.0 });
520 }
514 try doTheTestMod(f16, [4]f16{ 4.0, -4.0, 4.0, -4.0 }, [4]f16{ 1.0, 2.0, 0.5, 3.0 });
521515 try doTheTestMod(f32, [4]f32{ 4.0, -4.0, 4.0, -4.0 }, [4]f32{ 1.0, 2.0, 0.5, 3.0 });
522516 try doTheTestMod(f64, [4]f64{ 4.0, -4.0, 4.0, -4.0 }, [4]f64{ 1.0, 2.0, 0.5, 3.0 });
523517
test/tests.zig+24
......@@ -315,6 +315,30 @@ const test_targets = blk: {
315315 // .link_libc = true,
316316 //},
317317
318 .{
319 .target = .{
320 .cpu_arch = .powerpc64le,
321 .os_tag = .linux,
322 .abi = .none,
323 },
324 },
325 .{
326 .target = .{
327 .cpu_arch = .powerpc64le,
328 .os_tag = .linux,
329 .abi = .musl,
330 },
331 .link_libc = true,
332 },
333 .{
334 .target = .{
335 .cpu_arch = .powerpc64le,
336 .os_tag = .linux,
337 .abi = .gnu,
338 },
339 .link_libc = true,
340 },
341
318342 .{
319343 .target = .{
320344 .cpu_arch = .riscv64,