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 @@...@@ -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__)
lib/compiler_rt.zig+17-7
...@@ -4,17 +4,20 @@ comptime {...@@ -4,17 +4,20 @@ comptime {
4 _ = @import("compiler_rt/atomics.zig");4 _ = @import("compiler_rt/atomics.zig");
55
6 _ = @import("compiler_rt/addf3.zig");6 _ = @import("compiler_rt/addf3.zig");
7 _ = @import("compiler_rt/addhf3.zig");
7 _ = @import("compiler_rt/addsf3.zig");8 _ = @import("compiler_rt/addsf3.zig");
8 _ = @import("compiler_rt/adddf3.zig");9 _ = @import("compiler_rt/adddf3.zig");
9 _ = @import("compiler_rt/addtf3.zig");10 _ = @import("compiler_rt/addtf3.zig");
10 _ = @import("compiler_rt/addxf3.zig");11 _ = @import("compiler_rt/addxf3.zig");
1112
13 _ = @import("compiler_rt/subhf3.zig");
12 _ = @import("compiler_rt/subsf3.zig");14 _ = @import("compiler_rt/subsf3.zig");
13 _ = @import("compiler_rt/subdf3.zig");15 _ = @import("compiler_rt/subdf3.zig");
14 _ = @import("compiler_rt/subtf3.zig");16 _ = @import("compiler_rt/subtf3.zig");
15 _ = @import("compiler_rt/subxf3.zig");17 _ = @import("compiler_rt/subxf3.zig");
1618
17 _ = @import("compiler_rt/mulf3.zig");19 _ = @import("compiler_rt/mulf3.zig");
20 _ = @import("compiler_rt/mulhf3.zig");
18 _ = @import("compiler_rt/mulsf3.zig");21 _ = @import("compiler_rt/mulsf3.zig");
19 _ = @import("compiler_rt/muldf3.zig");22 _ = @import("compiler_rt/muldf3.zig");
20 _ = @import("compiler_rt/multf3.zig");23 _ = @import("compiler_rt/multf3.zig");
...@@ -34,51 +37,58 @@ comptime {...@@ -34,51 +37,58 @@ comptime {
34 _ = @import("compiler_rt/divxc3.zig");37 _ = @import("compiler_rt/divxc3.zig");
35 _ = @import("compiler_rt/divtc3.zig");38 _ = @import("compiler_rt/divtc3.zig");
3639
40 _ = @import("compiler_rt/neghf2.zig");
37 _ = @import("compiler_rt/negsf2.zig");41 _ = @import("compiler_rt/negsf2.zig");
38 _ = @import("compiler_rt/negdf2.zig");42 _ = @import("compiler_rt/negdf2.zig");
39 _ = @import("compiler_rt/negtf2.zig");43 _ = @import("compiler_rt/negtf2.zig");
40 _ = @import("compiler_rt/negxf2.zig");44 _ = @import("compiler_rt/negxf2.zig");
4145
42 _ = @import("compiler_rt/comparef.zig");46 _ = @import("compiler_rt/comparef.zig");
47 _ = @import("compiler_rt/cmphf2.zig");
43 _ = @import("compiler_rt/cmpsf2.zig");48 _ = @import("compiler_rt/cmpsf2.zig");
44 _ = @import("compiler_rt/cmpdf2.zig");49 _ = @import("compiler_rt/cmpdf2.zig");
45 _ = @import("compiler_rt/cmptf2.zig");50 _ = @import("compiler_rt/cmptf2.zig");
46 _ = @import("compiler_rt/cmpxf2.zig");51 _ = @import("compiler_rt/cmpxf2.zig");
52 _ = @import("compiler_rt/gehf2.zig");
47 _ = @import("compiler_rt/gesf2.zig");53 _ = @import("compiler_rt/gesf2.zig");
48 _ = @import("compiler_rt/gedf2.zig");54 _ = @import("compiler_rt/gedf2.zig");
49 _ = @import("compiler_rt/getf2.zig");
50 _ = @import("compiler_rt/gexf2.zig");55 _ = @import("compiler_rt/gexf2.zig");
56 _ = @import("compiler_rt/getf2.zig");
57 _ = @import("compiler_rt/unordhf2.zig");
51 _ = @import("compiler_rt/unordsf2.zig");58 _ = @import("compiler_rt/unordsf2.zig");
52 _ = @import("compiler_rt/unorddf2.zig");59 _ = @import("compiler_rt/unorddf2.zig");
60 _ = @import("compiler_rt/unordxf2.zig");
53 _ = @import("compiler_rt/unordtf2.zig");61 _ = @import("compiler_rt/unordtf2.zig");
5462
55 _ = @import("compiler_rt/extendf.zig");63 _ = @import("compiler_rt/extendf.zig");
56 _ = @import("compiler_rt/extenddftf2.zig");
57 _ = @import("compiler_rt/extenddfxf2.zig");
58 _ = @import("compiler_rt/extendhfsf2.zig");64 _ = @import("compiler_rt/extendhfsf2.zig");
65 _ = @import("compiler_rt/extendhfdf2.zig");
59 _ = @import("compiler_rt/extendhftf2.zig");66 _ = @import("compiler_rt/extendhftf2.zig");
60 _ = @import("compiler_rt/extendhfxf2.zig");67 _ = @import("compiler_rt/extendhfxf2.zig");
61 _ = @import("compiler_rt/extendsfdf2.zig");68 _ = @import("compiler_rt/extendsfdf2.zig");
62 _ = @import("compiler_rt/extendsftf2.zig");69 _ = @import("compiler_rt/extendsftf2.zig");
63 _ = @import("compiler_rt/extendsfxf2.zig");70 _ = @import("compiler_rt/extendsfxf2.zig");
71 _ = @import("compiler_rt/extenddftf2.zig");
72 _ = @import("compiler_rt/extenddfxf2.zig");
64 _ = @import("compiler_rt/extendxftf2.zig");73 _ = @import("compiler_rt/extendxftf2.zig");
6574
66 _ = @import("compiler_rt/truncf.zig");75 _ = @import("compiler_rt/truncf.zig");
67 _ = @import("compiler_rt/truncsfhf2.zig");76 _ = @import("compiler_rt/truncsfhf2.zig");
68 _ = @import("compiler_rt/truncdfhf2.zig");77 _ = @import("compiler_rt/truncdfhf2.zig");
69 _ = @import("compiler_rt/truncdfsf2.zig");78 _ = @import("compiler_rt/truncdfsf2.zig");
79 _ = @import("compiler_rt/truncxfhf2.zig");
80 _ = @import("compiler_rt/truncxfsf2.zig");
81 _ = @import("compiler_rt/truncxfdf2.zig");
70 _ = @import("compiler_rt/trunctfhf2.zig");82 _ = @import("compiler_rt/trunctfhf2.zig");
71 _ = @import("compiler_rt/trunctfsf2.zig");83 _ = @import("compiler_rt/trunctfsf2.zig");
72 _ = @import("compiler_rt/trunctfdf2.zig");84 _ = @import("compiler_rt/trunctfdf2.zig");
73 _ = @import("compiler_rt/trunctfxf2.zig");85 _ = @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");
79 _ = @import("compiler_rt/divsf3.zig");88 _ = @import("compiler_rt/divsf3.zig");
80 _ = @import("compiler_rt/divdf3.zig");89 _ = @import("compiler_rt/divdf3.zig");
81 _ = @import("compiler_rt/divxf3.zig");90 _ = @import("compiler_rt/divxf3.zig");
91 _ = @import("compiler_rt/divtf3.zig");
82 _ = @import("compiler_rt/sin.zig");92 _ = @import("compiler_rt/sin.zig");
83 _ = @import("compiler_rt/cos.zig");93 _ = @import("compiler_rt/cos.zig");
84 _ = @import("compiler_rt/sincos.zig");94 _ = @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;...@@ -5,22 +5,17 @@ pub const panic = common.panic;
55
6comptime {6comptime {
7 if (common.gnu_f16_abi) {7 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 });
9 } else if (common.want_aeabi) {9 } else if (common.want_aeabi) {
10 @export(__aeabi_h2f, .{ .name = "__aeabi_h2f", .linkage = common.linkage });10 @export(__aeabi_h2f, .{ .name = "__aeabi_h2f", .linkage = common.linkage });
11 } else {
12 @export(__extendhfsf2, .{ .name = "__extendhfsf2", .linkage = common.linkage });
13 }11 }
12 @export(__extendhfsf2, .{ .name = "__extendhfsf2", .linkage = common.linkage });
14}13}
1514
16pub fn __extendhfsf2(a: common.F16T) callconv(.C) f32 {15pub fn __extendhfsf2(a: common.F16T) callconv(.C) f32 {
17 return extendf(f32, f16, @bitCast(u16, a));16 return extendf(f32, f16, @bitCast(u16, a));
18}17}
1918
20fn __gnu_h2f_ieee(a: common.F16T) callconv(.C) f32 {
21 return extendf(f32, f16, @bitCast(u16, a));
22}
23
24fn __aeabi_h2f(a: u16) callconv(.AAPCS) f32 {19fn __aeabi_h2f(a: u16) callconv(.AAPCS) f32 {
25 return extendf(f32, f16, @bitCast(u16, a));20 return extendf(f32, f16, @bitCast(u16, a));
26}21}
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 {...@@ -32,8 +32,9 @@ pub inline fn mulf3(comptime T: type, a: T, b: T) T {
32 const infRep = @bitCast(Z, math.inf(T));32 const infRep = @bitCast(Z, math.inf(T));
33 const minNormalRep = @bitCast(Z, math.floatMin(T));33 const minNormalRep = @bitCast(Z, math.floatMin(T));
3434
35 const aExponent = @truncate(u32, (@bitCast(Z, a) >> significandBits) & maxExponent);35 const ZExp = if (typeWidth >= 32) u32 else Z;
36 const bExponent = @truncate(u32, (@bitCast(Z, b) >> significandBits) & maxExponent);36 const aExponent = @truncate(ZExp, (@bitCast(Z, a) >> significandBits) & maxExponent);
37 const bExponent = @truncate(ZExp, (@bitCast(Z, b) >> significandBits) & maxExponent);
37 const productSign: Z = (@bitCast(Z, a) ^ @bitCast(Z, b)) & signBit;38 const productSign: Z = (@bitCast(Z, a) ^ @bitCast(Z, b)) & signBit;
3839
39 var aSignificand: ZSignificand = @intCast(ZSignificand, @bitCast(Z, a) & significandMask);40 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 {...@@ -24,8 +24,10 @@ comptime {
24 @export(tanf, .{ .name = "tanf", .linkage = common.linkage });24 @export(tanf, .{ .name = "tanf", .linkage = common.linkage });
25 @export(tan, .{ .name = "tan", .linkage = common.linkage });25 @export(tan, .{ .name = "tan", .linkage = common.linkage });
26 @export(__tanx, .{ .name = "__tanx", .linkage = common.linkage });26 @export(__tanx, .{ .name = "__tanx", .linkage = common.linkage });
27 const tanq_sym_name = if (common.want_ppc_abi) "tanf128" else "tanq";27 if (common.want_ppc_abi) {
28 @export(tanq, .{ .name = tanq_sym_name, .linkage = common.linkage });28 @export(tanq, .{ .name = "tanf128", .linkage = common.linkage });
29 }
30 @export(tanq, .{ .name = "tanq", .linkage = common.linkage });
29 @export(tanl, .{ .name = "tanl", .linkage = common.linkage });31 @export(tanl, .{ .name = "tanl", .linkage = common.linkage });
30}32}
3133
lib/compiler_rt/truncsfhf2.zig+2-7
...@@ -5,22 +5,17 @@ pub const panic = common.panic;...@@ -5,22 +5,17 @@ pub const panic = common.panic;
55
6comptime {6comptime {
7 if (common.gnu_f16_abi) {7 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 });
9 } else if (common.want_aeabi) {9 } else if (common.want_aeabi) {
10 @export(__aeabi_f2h, .{ .name = "__aeabi_f2h", .linkage = common.linkage });10 @export(__aeabi_f2h, .{ .name = "__aeabi_f2h", .linkage = common.linkage });
11 } else {
12 @export(__truncsfhf2, .{ .name = "__truncsfhf2", .linkage = common.linkage });
13 }11 }
12 @export(__truncsfhf2, .{ .name = "__truncsfhf2", .linkage = common.linkage });
14}13}
1514
16pub fn __truncsfhf2(a: f32) callconv(.C) common.F16T {15pub fn __truncsfhf2(a: f32) callconv(.C) common.F16T {
17 return @bitCast(common.F16T, truncf(f16, f32, a));16 return @bitCast(common.F16T, truncf(f16, f32, a));
18}17}
1918
20fn __gnu_f2h_ieee(a: f32) callconv(.C) common.F16T {
21 return @bitCast(common.F16T, truncf(f16, f32, a));
22}
23
24fn __aeabi_f2h(a: f32) callconv(.AAPCS) u16 {19fn __aeabi_f2h(a: f32) callconv(.AAPCS) u16 {
25 return @bitCast(common.F16T, truncf(f16, f32, a));20 return @bitCast(common.F16T, truncf(f16, f32, a));
26}21}
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{...@@ -374,6 +374,10 @@ const atomic_rmw_orderings = [_]Ordering{
374};374};
375375
376test "Atomic.swap" {376test "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
377 inline for (atomic_rmw_orderings) |ordering| {381 inline for (atomic_rmw_orderings) |ordering| {
378 var x = Atomic(usize).init(5);382 var x = Atomic(usize).init(5);
379 try testing.expectEqual(x.swap(10, ordering), 5);383 try testing.expectEqual(x.swap(10, ordering), 5);
lib/std/target.zig+2
...@@ -1789,6 +1789,8 @@ pub const Target = struct {...@@ -1789,6 +1789,8 @@ pub const Target = struct {
1789 .powerpcle,1789 .powerpcle,
1790 .powerpc64,1790 .powerpc64,
1791 .powerpc64le,1791 .powerpc64le,
1792 .wasm32,
1793 .wasm64,
1792 => true,1794 => true,
17931795
1794 else => false,1796 else => false,
src/codegen/llvm.zig+177-97
...@@ -2738,7 +2738,7 @@ pub const DeclGen = struct {...@@ -2738,7 +2738,7 @@ pub const DeclGen = struct {
2738 return dg.context.intType(bit_count);2738 return dg.context.intType(bit_count);
2739 },2739 },
2740 .Float => switch (t.floatBits(target)) {2740 .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),
2742 32 => return dg.context.floatType(),2742 32 => return dg.context.floatType(),
2743 64 => return dg.context.doubleType(),2743 64 => return dg.context.doubleType(),
2744 80 => return if (backendSupportsF80(target)) dg.context.x86FP80Type() else dg.context.intType(80),2744 80 => return if (backendSupportsF80(target)) dg.context.x86FP80Type() else dg.context.intType(80),
...@@ -3253,7 +3253,15 @@ pub const DeclGen = struct {...@@ -3253,7 +3253,15 @@ pub const DeclGen = struct {
3253 .Float => {3253 .Float => {
3254 const llvm_ty = try dg.lowerType(tv.ty);3254 const llvm_ty = try dg.lowerType(tv.ty);
3255 switch (tv.ty.floatBits(target)) {3255 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)),
3257 80 => {3265 80 => {
3258 const float = tv.val.toFloat(f80);3266 const float = tv.val.toFloat(f80);
3259 const repr = std.math.break_f80(float);3267 const repr = std.math.break_f80(float);
...@@ -7611,11 +7619,25 @@ pub const FuncGen = struct {...@@ -7611,11 +7619,25 @@ pub const FuncGen = struct {
7611 const target = self.dg.module.getTarget();7619 const target = self.dg.module.getTarget();
7612 const dest_bits = dest_ty.floatBits(target);7620 const dest_bits = dest_ty.floatBits(target);
7613 const src_bits = operand_ty.floatBits(target);7621 const src_bits = operand_ty.floatBits(target);
7614 if (!backendSupportsF80(target) and (src_bits == 80 or dest_bits == 80)) {7622
7615 return softF80TruncOrExt(self, operand, src_bits, dest_bits);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, "");
7616 }7640 }
7617 const dest_llvm_ty = try self.dg.lowerType(dest_ty);
7618 return self.builder.buildFPTrunc(operand, dest_llvm_ty, "");
7619 }7641 }
76207642
7621 fn airFpext(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {7643 fn airFpext(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
...@@ -7629,11 +7651,25 @@ pub const FuncGen = struct {...@@ -7629,11 +7651,25 @@ pub const FuncGen = struct {
7629 const target = self.dg.module.getTarget();7651 const target = self.dg.module.getTarget();
7630 const dest_bits = dest_ty.floatBits(target);7652 const dest_bits = dest_ty.floatBits(target);
7631 const src_bits = operand_ty.floatBits(target);7653 const src_bits = operand_ty.floatBits(target);
7632 if (!backendSupportsF80(target) and (src_bits == 80 or dest_bits == 80)) {7654
7633 return softF80TruncOrExt(self, operand, src_bits, dest_bits);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, "");
7634 }7672 }
7635 const dest_llvm_ty = try self.dg.lowerType(self.air.typeOfIndex(inst));
7636 return self.builder.buildFPExt(operand, dest_llvm_ty, "");
7637 }7673 }
76387674
7639 fn airPtrToInt(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {7675 fn airPtrToInt(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
...@@ -8717,12 +8753,78 @@ pub const FuncGen = struct {...@@ -8717,12 +8753,78 @@ pub const FuncGen = struct {
8717 return self.builder.buildShuffleVector(a, b, llvm_mask_value, "");8753 return self.builder.buildShuffleVector(a, b, llvm_mask_value, "");
8718 }8754 }
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
8720 fn airReduce(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*llvm.Value {8820 fn airReduce(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*llvm.Value {
8721 if (self.liveness.isUnused(inst)) return null;8821 if (self.liveness.isUnused(inst)) return null;
8722 self.builder.setFastMath(want_fast_math);8822 self.builder.setFastMath(want_fast_math);
8823 const target = self.dg.module.getTarget();
87238824
8724 const reduce = self.air.instructions.items(.data)[inst].reduce;8825 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);
8726 const scalar_ty = self.air.typeOfIndex(inst);8828 const scalar_ty = self.air.typeOfIndex(inst);
87278829
8728 // TODO handle the fast math setting8830 // TODO handle the fast math setting
...@@ -8733,17 +8835,21 @@ pub const FuncGen = struct {...@@ -8733,17 +8835,21 @@ pub const FuncGen = struct {
8733 .Xor => return self.builder.buildXorReduce(operand),8835 .Xor => return self.builder.buildXorReduce(operand),
8734 .Min => switch (scalar_ty.zigTypeTag()) {8836 .Min => switch (scalar_ty.zigTypeTag()) {
8735 .Int => return self.builder.buildIntMinReduce(operand, scalar_ty.isSignedInt()),8837 .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 },
8737 else => unreachable,8841 else => unreachable,
8738 },8842 },
8739 .Max => switch (scalar_ty.zigTypeTag()) {8843 .Max => switch (scalar_ty.zigTypeTag()) {
8740 .Int => return self.builder.buildIntMaxReduce(operand, scalar_ty.isSignedInt()),8844 .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 },
8742 else => unreachable,8848 else => unreachable,
8743 },8849 },
8744 .Add => switch (scalar_ty.zigTypeTag()) {8850 .Add => switch (scalar_ty.zigTypeTag()) {
8745 .Int => return self.builder.buildAddReduce(operand),8851 .Int => return self.builder.buildAddReduce(operand),
8746 .Float => {8852 .Float => if (intrinsicsAllowed(scalar_ty, target)) {
8747 const scalar_llvm_ty = try self.dg.lowerType(scalar_ty);8853 const scalar_llvm_ty = try self.dg.lowerType(scalar_ty);
8748 const neutral_value = scalar_llvm_ty.constReal(-0.0);8854 const neutral_value = scalar_llvm_ty.constReal(-0.0);
8749 return self.builder.buildFPAddReduce(neutral_value, operand);8855 return self.builder.buildFPAddReduce(neutral_value, operand);
...@@ -8752,7 +8858,7 @@ pub const FuncGen = struct {...@@ -8752,7 +8858,7 @@ pub const FuncGen = struct {
8752 },8858 },
8753 .Mul => switch (scalar_ty.zigTypeTag()) {8859 .Mul => switch (scalar_ty.zigTypeTag()) {
8754 .Int => return self.builder.buildMulReduce(operand),8860 .Int => return self.builder.buildMulReduce(operand),
8755 .Float => {8861 .Float => if (intrinsicsAllowed(scalar_ty, target)) {
8756 const scalar_llvm_ty = try self.dg.lowerType(scalar_ty);8862 const scalar_llvm_ty = try self.dg.lowerType(scalar_ty);
8757 const neutral_value = scalar_llvm_ty.constReal(1.0);8863 const neutral_value = scalar_llvm_ty.constReal(1.0);
8758 return self.builder.buildFPMulReduce(neutral_value, operand);8864 return self.builder.buildFPMulReduce(neutral_value, operand);
...@@ -8760,6 +8866,44 @@ pub const FuncGen = struct {...@@ -8760,6 +8866,44 @@ pub const FuncGen = struct {
8760 else => unreachable,8866 else => unreachable,
8761 },8867 },
8762 }8868 }
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);
8763 }8907 }
87648908
8765 fn airAggregateInit(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {8909 fn airAggregateInit(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
...@@ -9051,7 +9195,13 @@ pub const FuncGen = struct {...@@ -9051,7 +9195,13 @@ pub const FuncGen = struct {
9051 const target = self.dg.module.getTarget();9195 const target = self.dg.module.getTarget();
9052 switch (prefetch.cache) {9196 switch (prefetch.cache) {
9053 .instruction => switch (target.cpu.arch) {9197 .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,
9055 .arm, .armeb, .thumb, .thumbeb => {9205 .arm, .armeb, .thumb, .thumbeb => {
9056 switch (prefetch.rw) {9206 switch (prefetch.rw) {
9057 .write => return null,9207 .write => return null,
...@@ -9091,87 +9241,6 @@ pub const FuncGen = struct {...@@ -9091,87 +9241,6 @@ pub const FuncGen = struct {
9091 return null;9241 return null;
9092 }9242 }
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
9175 fn getErrorNameTable(self: *FuncGen) !*llvm.Value {9244 fn getErrorNameTable(self: *FuncGen) !*llvm.Value {
9176 if (self.dg.object.error_name_table) |table| {9245 if (self.dg.object.error_name_table) |table| {
9177 return table;9246 return table;
...@@ -10451,6 +10520,17 @@ fn backendSupportsF80(target: std.Target) bool {...@@ -10451,6 +10520,17 @@ fn backendSupportsF80(target: std.Target) bool {
10451/// if it produces miscompilations.10520/// if it produces miscompilations.
10452fn backendSupportsF16(target: std.Target) bool {10521fn backendSupportsF16(target: std.Target) bool {
10453 return switch (target.cpu.arch) {10522 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,
10454 else => true,10534 else => true,
10455 };10535 };
10456}10536}
src/stage1/analyze.cpp+4-2
...@@ -6358,9 +6358,11 @@ void init_const_float(ZigValue *const_val, ZigType *type, double value) {...@@ -6358,9 +6358,11 @@ void init_const_float(ZigValue *const_val, ZigType *type, double value) {
6358 const_val->data.x_f64 = value;6358 const_val->data.x_f64 = value;
6359 break;6359 break;
6360 case 80:6360 case 80:
6361 zig_double_to_extF80M(value, &const_val->data.x_f80);
6362 break;
6361 case 128:6363 case 128:
6362 // if we need this, we should add a function that accepts a float128_t param6364 zig_double_to_f128M(value, &const_val->data.x_f128);
6363 zig_unreachable();6365 break;
6364 default:6366 default:
6365 zig_unreachable();6367 zig_unreachable();
6366 }6368 }
src/stage1/codegen.cpp+139-39
...@@ -80,6 +80,7 @@ void codegen_set_strip(CodeGen *g, bool strip) {...@@ -80,6 +80,7 @@ void codegen_set_strip(CodeGen *g, bool strip) {
80 }80 }
81}81}
8282
83static LLVMValueRef get_soft_float_fn(CodeGen *g, const char *name, int param_count, LLVMTypeRef param_type, LLVMTypeRef return_type);
83static void render_const_val(CodeGen *g, ZigValue *const_val, const char *name);84static void render_const_val(CodeGen *g, ZigValue *const_val, const char *name);
84static void render_const_val_global(CodeGen *g, ZigValue *const_val, const char *name);85static void render_const_val_global(CodeGen *g, ZigValue *const_val, const char *name);
85static LLVMValueRef gen_const_val(CodeGen *g, ZigValue *const_val, const char *name);86static 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,12 +1737,7 @@ static LLVMValueRef gen_soft_float_widen_or_shorten(CodeGen *g, ZigType *actual_
1736 }1737 }
1737 }1738 }
17381739
1739 LLVMValueRef func_ref = LLVMGetNamedFunction(g->module, fn_name);1740 LLVMValueRef func_ref = get_soft_float_fn(g, fn_name, 1, param_type, return_type);
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
1745 result = LLVMBuildCall2(g->builder, LLVMGlobalGetValueType(func_ref), func_ref, &expr_val, 1, "");1741 result = LLVMBuildCall2(g->builder, LLVMGlobalGetValueType(func_ref), func_ref, &expr_val, 1, "");
17461742
1747 // On non-Arm platforms we need to bitcast __trunc<>fhf2 result back to f161743 // 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,9 +1762,12 @@ static LLVMValueRef gen_widen_or_shorten(CodeGen *g, bool want_runtime_safety, Z
1766 uint64_t wanted_bits;1762 uint64_t wanted_bits;
1767 if (scalar_actual_type->id == ZigTypeIdFloat) {1763 if (scalar_actual_type->id == ZigTypeIdFloat) {
17681764
1769 if ((scalar_actual_type == g->builtin_types.entry_f801765 if (((scalar_actual_type == g->builtin_types.entry_f80
1770 || scalar_wanted_type == g->builtin_types.entry_f80)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 return gen_soft_float_widen_or_shorten(g, actual_type, wanted_type, expr_val);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,6 +3099,7 @@ static LLVMValueRef gen_float_un_op(CodeGen *g, LLVMValueRef operand, ZigType *o
3100 ZigType *elem_type = operand_type->id == ZigTypeIdVector ? operand_type->data.vector.elem_type : operand_type;3099 ZigType *elem_type = operand_type->id == ZigTypeIdVector ? operand_type->data.vector.elem_type : operand_type;
3101 if ((elem_type == g->builtin_types.entry_f80 && !target_has_f80(g->zig_target)) ||3100 if ((elem_type == g->builtin_types.entry_f80 && !target_has_f80(g->zig_target)) ||
3102 (elem_type == g->builtin_types.entry_f128 && !target_long_double_is_f128(g->zig_target)) ||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 op == BuiltinFnIdTan)3103 op == BuiltinFnIdTan)
3104 {3104 {
3105 return gen_soft_float_un_op(g, operand, operand_type, op);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,7 +3690,8 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, Stage1Air *executable,
3690 ZigType *operand_type = op1->value->type;3690 ZigType *operand_type = op1->value->type;
3691 ZigType *scalar_type = (operand_type->id == ZigTypeIdVector) ? operand_type->data.vector.elem_type : operand_type;3691 ZigType *scalar_type = (operand_type->id == ZigTypeIdVector) ? operand_type->data.vector.elem_type : operand_type;
3692 if ((scalar_type == g->builtin_types.entry_f80 && !target_has_f80(g->zig_target)) ||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 // LLVM incorrectly lowers the soft float calls for f128 as if they operated on `long double`.3695 // LLVM incorrectly lowers the soft float calls for f128 as if they operated on `long double`.
3695 // On some targets this will be incorrect, so we manually lower the call ourselves.3696 // On some targets this will be incorrect, so we manually lower the call ourselves.
3696 LLVMValueRef op1_value = ir_llvm_value(g, op1);3697 LLVMValueRef op1_value = ir_llvm_value(g, op1);
...@@ -4024,7 +4025,8 @@ static LLVMValueRef ir_render_cast(CodeGen *g, Stage1Air *executable,...@@ -4024,7 +4025,8 @@ static LLVMValueRef ir_render_cast(CodeGen *g, Stage1Air *executable,
4024 assert(actual_type->id == ZigTypeIdInt);4025 assert(actual_type->id == ZigTypeIdInt);
4025 {4026 {
4026 if ((wanted_type == g->builtin_types.entry_f80 && !target_has_f80(g->zig_target)) ||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 return gen_soft_int_to_float_op(g, expr_val, actual_type, wanted_type);4030 return gen_soft_int_to_float_op(g, expr_val, actual_type, wanted_type);
4029 } else {4031 } else {
4030 if (actual_type->data.integral.is_signed) {4032 if (actual_type->data.integral.is_signed) {
...@@ -4042,7 +4044,8 @@ static LLVMValueRef ir_render_cast(CodeGen *g, Stage1Air *executable,...@@ -4042,7 +4044,8 @@ static LLVMValueRef ir_render_cast(CodeGen *g, Stage1Air *executable,
40424044
4043 LLVMValueRef result;4045 LLVMValueRef result;
4044 if ((actual_type == g->builtin_types.entry_f80 && !target_has_f80(g->zig_target)) ||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 result = gen_soft_float_to_int_op(g, expr_val, actual_type, wanted_type);4049 result = gen_soft_float_to_int_op(g, expr_val, actual_type, wanted_type);
4047 } else {4050 } else {
4048 if (wanted_type->data.integral.is_signed) {4051 if (wanted_type->data.integral.is_signed) {
...@@ -4396,7 +4399,8 @@ static LLVMValueRef gen_negation(CodeGen *g, Stage1AirInst *inst, Stage1AirInst...@@ -4396,7 +4399,8 @@ static LLVMValueRef gen_negation(CodeGen *g, Stage1AirInst *inst, Stage1AirInst
4396 operand_type->data.vector.elem_type : operand_type;4399 operand_type->data.vector.elem_type : operand_type;
43974400
4398 if ((scalar_type == g->builtin_types.entry_f80 && !target_has_f80(g->zig_target)) ||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 return gen_soft_float_neg(g, operand_type, llvm_operand);4404 return gen_soft_float_neg(g, operand_type, llvm_operand);
4401 }4405 }
44024406
...@@ -6477,6 +6481,55 @@ static LLVMValueRef ir_render_cmpxchg(CodeGen *g, Stage1Air *executable, Stage1A...@@ -6477,6 +6481,55 @@ static LLVMValueRef ir_render_cmpxchg(CodeGen *g, Stage1Air *executable, Stage1A
6477 return result_loc;6481 return result_loc;
6478}6482}
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
6480static LLVMValueRef ir_render_reduce(CodeGen *g, Stage1Air *executable, Stage1AirInstReduce *instruction) {6533static LLVMValueRef ir_render_reduce(CodeGen *g, Stage1Air *executable, Stage1AirInstReduce *instruction) {
6481 LLVMValueRef value = ir_llvm_value(g, instruction->value);6534 LLVMValueRef value = ir_llvm_value(g, instruction->value);
64826535
...@@ -6484,61 +6537,100 @@ static LLVMValueRef ir_render_reduce(CodeGen *g, Stage1Air *executable, Stage1Ai...@@ -6484,61 +6537,100 @@ static LLVMValueRef ir_render_reduce(CodeGen *g, Stage1Air *executable, Stage1Ai
6484 assert(value_type->id == ZigTypeIdVector);6537 assert(value_type->id == ZigTypeIdVector);
6485 ZigType *scalar_type = value_type->data.vector.elem_type;6538 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
6487 ZigLLVMSetFastMath(g->builder, ir_want_fast_math(g, &instruction->base));6553 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;
6490 switch (instruction->op) {6557 switch (instruction->op) {
6491 case ReduceOp_and:6558 case ReduceOp_and:
6492 assert(scalar_type->id == ZigTypeIdInt || scalar_type->id == ZigTypeIdBool);6559 assert(scalar_type->id == ZigTypeIdInt || scalar_type->id == ZigTypeIdBool);
6493 result_val = ZigLLVMBuildAndReduce(g->builder, value);6560 return ZigLLVMBuildAndReduce(g->builder, value);
6494 break;6561 break;
6495 case ReduceOp_or:6562 case ReduceOp_or:
6496 assert(scalar_type->id == ZigTypeIdInt || scalar_type->id == ZigTypeIdBool);6563 assert(scalar_type->id == ZigTypeIdInt || scalar_type->id == ZigTypeIdBool);
6497 result_val = ZigLLVMBuildOrReduce(g->builder, value);6564 return ZigLLVMBuildOrReduce(g->builder, value);
6498 break;6565 break;
6499 case ReduceOp_xor:6566 case ReduceOp_xor:
6500 assert(scalar_type->id == ZigTypeIdInt || scalar_type->id == ZigTypeIdBool);6567 assert(scalar_type->id == ZigTypeIdInt || scalar_type->id == ZigTypeIdBool);
6501 result_val = ZigLLVMBuildXorReduce(g->builder, value);6568 return ZigLLVMBuildXorReduce(g->builder, value);
6502 break;6569 break;
6503 case ReduceOp_min: {6570 case ReduceOp_min: {
6504 if (scalar_type->id == ZigTypeIdInt) {6571 if (scalar_type->id == ZigTypeIdInt) {
6505 const bool is_signed = scalar_type->data.integral.is_signed;6572 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);
6507 } else if (scalar_type->id == ZigTypeIdFloat) {6574 } 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 }
6509 } else zig_unreachable();6581 } else zig_unreachable();
6510 } break;6582 } break;
6511 case ReduceOp_max: {6583 case ReduceOp_max: {
6512 if (scalar_type->id == ZigTypeIdInt) {6584 if (scalar_type->id == ZigTypeIdInt) {
6513 const bool is_signed = scalar_type->data.integral.is_signed;6585 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);
6515 } else if (scalar_type->id == ZigTypeIdFloat) {6587 } 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 }
6517 } else zig_unreachable();6594 } else zig_unreachable();
6518 } break;6595 } break;
6519 case ReduceOp_add: {6596 case ReduceOp_add: {
6520 if (scalar_type->id == ZigTypeIdInt) {6597 if (scalar_type->id == ZigTypeIdInt) {
6521 result_val = ZigLLVMBuildAddReduce(g->builder, value);6598 return ZigLLVMBuildAddReduce(g->builder, value);
6522 } else if (scalar_type->id == ZigTypeIdFloat) {6599 } else if (scalar_type->id == ZigTypeIdFloat) {
6523 LLVMValueRef neutral_value = LLVMConstReal(6600 if (float_intrinsics_allowed) {
6524 get_llvm_type(g, scalar_type), -0.0);6601 LLVMValueRef neutral_value = LLVMConstReal(
6525 result_val = ZigLLVMBuildFPAddReduce(g->builder, neutral_value, value);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 }
6526 } else zig_unreachable();6608 } else zig_unreachable();
6527 } break;6609 } break;
6528 case ReduceOp_mul: {6610 case ReduceOp_mul: {
6529 if (scalar_type->id == ZigTypeIdInt) {6611 if (scalar_type->id == ZigTypeIdInt) {
6530 result_val = ZigLLVMBuildMulReduce(g->builder, value);6612 return ZigLLVMBuildMulReduce(g->builder, value);
6531 } else if (scalar_type->id == ZigTypeIdFloat) {6613 } else if (scalar_type->id == ZigTypeIdFloat) {
6532 LLVMValueRef neutral_value = LLVMConstReal(6614 if (float_intrinsics_allowed) {
6533 get_llvm_type(g, scalar_type), 1.0);6615 LLVMValueRef neutral_value = LLVMConstReal(
6534 result_val = ZigLLVMBuildFPMulReduce(g->builder, neutral_value, value);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 }
6535 } else zig_unreachable();6622 } else zig_unreachable();
6536 } break;6623 } break;
6537 default:6624 default:
6538 zig_unreachable();6625 zig_unreachable();
6539 }6626 }
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);
6542}6634}
65436635
6544static LLVMValueRef ir_render_fence(CodeGen *g, Stage1Air *executable, Stage1AirInstFence *instruction) {6636static LLVMValueRef ir_render_fence(CodeGen *g, Stage1Air *executable, Stage1AirInstFence *instruction) {
...@@ -6650,6 +6742,10 @@ static LLVMValueRef ir_render_prefetch(CodeGen *g, Stage1Air *executable, Stage1...@@ -6650,6 +6742,10 @@ static LLVMValueRef ir_render_prefetch(CodeGen *g, Stage1Air *executable, Stage1
6650 switch (g->zig_target->arch) {6742 switch (g->zig_target->arch) {
6651 case ZigLLVM_x86:6743 case ZigLLVM_x86:
6652 case ZigLLVM_x86_64:6744 case ZigLLVM_x86_64:
6745 case ZigLLVM_ppc:
6746 case ZigLLVM_ppcle:
6747 case ZigLLVM_ppc64:
6748 case ZigLLVM_ppc64le:
6653 return nullptr;6749 return nullptr;
6654 default:6750 default:
6655 break;6751 break;
...@@ -7374,7 +7470,9 @@ static LLVMValueRef ir_render_soft_mul_add(CodeGen *g, Stage1Air *executable, St...@@ -7374,7 +7470,9 @@ static LLVMValueRef ir_render_soft_mul_add(CodeGen *g, Stage1Air *executable, St
7374 uint32_t vector_len = operand_type->id == ZigTypeIdVector ? operand_type->data.vector.len : 0;7470 uint32_t vector_len = operand_type->id == ZigTypeIdVector ? operand_type->data.vector.len : 0;
73757471
7376 const char *fn_name;7472 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)
7378 fn_name = "fmaf";7476 fn_name = "fmaf";
7379 else if (float_type == g->builtin_types.entry_f64)7477 else if (float_type == g->builtin_types.entry_f64)
7380 fn_name = "fma";7478 fn_name = "fma";
...@@ -7385,13 +7483,8 @@ static LLVMValueRef ir_render_soft_mul_add(CodeGen *g, Stage1Air *executable, St...@@ -7385,13 +7483,8 @@ static LLVMValueRef ir_render_soft_mul_add(CodeGen *g, Stage1Air *executable, St
7385 else7483 else
7386 zig_unreachable();7484 zig_unreachable();
73877485
7388 LLVMValueRef func_ref = LLVMGetNamedFunction(g->module, fn_name);7486 LLVMTypeRef float_type_ref = float_type->llvm_type;
7389 if (func_ref == nullptr) {7487 LLVMValueRef func_ref = get_soft_float_fn(g, fn_name, 3, float_type_ref, float_type_ref);
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 }
73957488
7396 LLVMValueRef op1 = ir_llvm_value(g, instruction->op1);7489 LLVMValueRef op1 = ir_llvm_value(g, instruction->op1);
7397 LLVMValueRef op2 = ir_llvm_value(g, instruction->op2);7490 LLVMValueRef op2 = ir_llvm_value(g, instruction->op2);
...@@ -7421,7 +7514,8 @@ static LLVMValueRef ir_render_mul_add(CodeGen *g, Stage1Air *executable, Stage1A...@@ -7421,7 +7514,8 @@ static LLVMValueRef ir_render_mul_add(CodeGen *g, Stage1Air *executable, Stage1A
7421 ZigType *operand_type = instruction->op1->value->type;7514 ZigType *operand_type = instruction->op1->value->type;
7422 operand_type = operand_type->id == ZigTypeIdVector ? operand_type->data.vector.elem_type : operand_type;7515 operand_type = operand_type->id == ZigTypeIdVector ? operand_type->data.vector.elem_type : operand_type;
7423 if ((operand_type == g->builtin_types.entry_f80 && !target_has_f80(g->zig_target)) ||7516 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))) {
7425 return ir_render_soft_mul_add(g, executable, instruction, operand_type);7519 return ir_render_soft_mul_add(g, executable, instruction, operand_type);
7426 }7520 }
7427 LLVMValueRef op1 = ir_llvm_value(g, instruction->op1);7521 LLVMValueRef op1 = ir_llvm_value(g, instruction->op1);
...@@ -9740,7 +9834,12 @@ static void define_builtin_types(CodeGen *g) {...@@ -9740,7 +9834,12 @@ static void define_builtin_types(CodeGen *g) {
9740 }9834 }
9741 }9835 }
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 }
9744 add_fp_entry(g, "f32", 32, LLVMFloatType(), &g->builtin_types.entry_f32);9843 add_fp_entry(g, "f32", 32, LLVMFloatType(), &g->builtin_types.entry_f32);
9745 add_fp_entry(g, "f64", 64, LLVMDoubleType(), &g->builtin_types.entry_f64);9844 add_fp_entry(g, "f64", 64, LLVMDoubleType(), &g->builtin_types.entry_f64);
9746 add_fp_entry(g, "f128", 128, LLVMFP128Type(), &g->builtin_types.entry_f128);9845 add_fp_entry(g, "f128", 128, LLVMFP128Type(), &g->builtin_types.entry_f128);
...@@ -9837,6 +9936,7 @@ static void define_builtin_types(CodeGen *g) {...@@ -9837,6 +9936,7 @@ static void define_builtin_types(CodeGen *g) {
9837 add_fp_entry(g, "c_longdouble", 128, LLVMFP128Type(), &g->builtin_types.entry_c_longdouble);9936 add_fp_entry(g, "c_longdouble", 128, LLVMFP128Type(), &g->builtin_types.entry_c_longdouble);
9838 break;9937 break;
9839 case ZigLLVM_ppc:9938 case ZigLLVM_ppc:
9939 case ZigLLVM_ppcle:
9840 case ZigLLVM_ppc64:9940 case ZigLLVM_ppc64:
9841 case ZigLLVM_ppc64le:9941 case ZigLLVM_ppc64le:
9842 add_fp_entry(g, "c_longdouble", 128, LLVMFP128Type(), &g->builtin_types.entry_c_longdouble);9942 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) {...@@ -21,6 +21,20 @@ static inline float16_t zig_double_to_f16(double x) {
21 return f64_to_f16(y);21 return f64_to_f16(y);
22}22}
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
25// Return value is safe to coerce to float even when |x| is NaN or Infinity.39// Return value is safe to coerce to float even when |x| is NaN or Infinity.
26static inline double zig_f16_to_double(float16_t x) {40static 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) {...@@ -950,7 +950,6 @@ bool target_is_arm(const ZigTarget *target) {
950 case ZigLLVM_msp430:950 case ZigLLVM_msp430:
951 case ZigLLVM_nvptx:951 case ZigLLVM_nvptx:
952 case ZigLLVM_nvptx64:952 case ZigLLVM_nvptx64:
953 case ZigLLVM_ppc64le:
954 case ZigLLVM_r600:953 case ZigLLVM_r600:
955 case ZigLLVM_renderscript32:954 case ZigLLVM_renderscript32:
956 case ZigLLVM_renderscript64:955 case ZigLLVM_renderscript64:
...@@ -971,6 +970,7 @@ bool target_is_arm(const ZigTarget *target) {...@@ -971,6 +970,7 @@ bool target_is_arm(const ZigTarget *target) {
971 case ZigLLVM_ppc:970 case ZigLLVM_ppc:
972 case ZigLLVM_ppcle:971 case ZigLLVM_ppcle:
973 case ZigLLVM_ppc64:972 case ZigLLVM_ppc64:
973 case ZigLLVM_ppc64le:
974 case ZigLLVM_ve:974 case ZigLLVM_ve:
975 case ZigLLVM_spirv32:975 case ZigLLVM_spirv32:
976 case ZigLLVM_spirv64:976 case ZigLLVM_spirv64:
...@@ -1125,8 +1125,8 @@ bool target_is_mips(const ZigTarget *target) {...@@ -1125,8 +1125,8 @@ bool target_is_mips(const ZigTarget *target) {
1125}1125}
11261126
1127bool target_is_ppc(const ZigTarget *target) {1127bool target_is_ppc(const ZigTarget *target) {
1128 return target->arch == ZigLLVM_ppc || target->arch == ZigLLVM_ppc64 ||1128 return target->arch == ZigLLVM_ppc || target->arch == ZigLLVM_ppcle ||
1129 target->arch == ZigLLVM_ppc64le;1129 target->arch == ZigLLVM_ppc64 || target->arch == ZigLLVM_ppc64le;
1130}1130}
11311131
1132// Returns the minimum alignment for every function pointer on the given1132// Returns the minimum alignment for every function pointer on the given
test/behavior.zig+2-1
...@@ -89,7 +89,6 @@ test {...@@ -89,7 +89,6 @@ test {
89 _ = @import("behavior/bugs/12551.zig");89 _ = @import("behavior/bugs/12551.zig");
90 _ = @import("behavior/bugs/12644.zig");90 _ = @import("behavior/bugs/12644.zig");
91 _ = @import("behavior/bugs/12680.zig");91 _ = @import("behavior/bugs/12680.zig");
92 _ = @import("behavior/bugs/12776.zig");
93 _ = @import("behavior/bugs/12786.zig");92 _ = @import("behavior/bugs/12786.zig");
94 _ = @import("behavior/bugs/12794.zig");93 _ = @import("behavior/bugs/12794.zig");
95 _ = @import("behavior/bugs/12801-1.zig");94 _ = @import("behavior/bugs/12801-1.zig");
...@@ -187,6 +186,8 @@ test {...@@ -187,6 +186,8 @@ test {
187 _ = @import("behavior/packed_struct_explicit_backing_int.zig");186 _ = @import("behavior/packed_struct_explicit_backing_int.zig");
188 _ = @import("behavior/empty_union.zig");187 _ = @import("behavior/empty_union.zig");
189 _ = @import("behavior/inline_switch.zig");188 _ = @import("behavior/inline_switch.zig");
189 _ = @import("behavior/bugs/12723.zig");
190 _ = @import("behavior/bugs/12776.zig");
190 }191 }
191192
192 if (builtin.os.tag != .wasi) {193 if (builtin.os.tag != .wasi) {
test/behavior/align.zig+2
...@@ -566,6 +566,8 @@ test "@alignCast null" {...@@ -566,6 +566,8 @@ test "@alignCast null" {
566}566}
567567
568test "alignment of slice element" {568test "alignment of slice element" {
569 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
570
569 const a: []align(1024) const u8 = undefined;571 const a: []align(1024) const u8 = undefined;
570 try expect(@TypeOf(&a[0]) == *align(1024) const u8);572 try expect(@TypeOf(&a[0]) == *align(1024) const u8);
571}573}
test/behavior/bugs/11816.zig+1
...@@ -3,6 +3,7 @@ const builtin = @import("builtin");...@@ -3,6 +3,7 @@ const builtin = @import("builtin");
33
4test {4test {
5 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO5 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
6 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
67
7 var x: u32 = 3;8 var x: u32 = 3;
8 const val: usize = while (true) switch (x) {9 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 {...@@ -8,6 +8,7 @@ fn capacity_() u64 {
88
9test {9test {
10 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO10 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
11 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
1112
12 try std.testing.expect((@This(){}).capacity() == 64);13 try std.testing.expect((@This(){}).capacity() == 64);
13}14}
test/behavior/bugs/12801-2.zig+1
...@@ -14,6 +14,7 @@ const Auto = struct {...@@ -14,6 +14,7 @@ const Auto = struct {
14 }14 }
15};15};
16test {16test {
17 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
17 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO18 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
18 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO19 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
19 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO20 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" {...@@ -1169,10 +1169,3 @@ test "Non-exhaustive enum with nonstandard int size behaves correctly" {
1169 const E = enum(u15) { _ };1169 const E = enum(u15) { _ };
1170 try expect(@sizeOf(E) == @sizeOf(u15));1170 try expect(@sizeOf(E) == @sizeOf(u15));
1171}1171}
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" {...@@ -1339,6 +1339,8 @@ test "lazy value is resolved as slice operand" {
1339}1339}
13401340
1341test "break from inline loop depends on runtime condition" {1341test "break from inline loop depends on runtime condition" {
1342 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
1343
1342 const S = struct {1344 const S = struct {
1343 fn foo(a: u8) bool {1345 fn foo(a: u8) bool {
1344 return a == 4;1346 return a == 4;
test/behavior/muladd.zig-11
...@@ -71,17 +71,6 @@ test "@mulAdd f128" {...@@ -71,17 +71,6 @@ test "@mulAdd f128" {
71 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO71 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
72 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO72 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
85 comptime try testMulAdd128();74 comptime try testMulAdd128();
86 try testMulAdd128();75 try testMulAdd128();
87}76}
test/behavior/packed-struct.zig+1
...@@ -585,6 +585,7 @@ test "runtime init of unnamed packed struct type" {...@@ -585,6 +585,7 @@ test "runtime init of unnamed packed struct type" {
585}585}
586586
587test "packed struct passed to callconv(.C) function" {587test "packed struct passed to callconv(.C) function" {
588 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
588 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;589 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
589 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;590 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
590 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;591 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
test/behavior/vector.zig+2-8
...@@ -506,18 +506,12 @@ test "vector division operators" {...@@ -506,18 +506,12 @@ test "vector division operators" {
506 }506 }
507507
508 fn doTheTest() !void {508 fn doTheTest() !void {
509 // https://github.com/ziglang/zig/issues/4952509 try doTheTestDiv(f16, [4]f16{ 4.0, -4.0, 4.0, -4.0 }, [4]f16{ 1.0, 2.0, -1.0, -2.0 });
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 }
513510
514 try doTheTestDiv(f32, [4]f32{ 4.0, -4.0, 4.0, -4.0 }, [4]f32{ 1.0, 2.0, -1.0, -2.0 });511 try doTheTestDiv(f32, [4]f32{ 4.0, -4.0, 4.0, -4.0 }, [4]f32{ 1.0, 2.0, -1.0, -2.0 });
515 try doTheTestDiv(f64, [4]f64{ 4.0, -4.0, 4.0, -4.0 }, [4]f64{ 1.0, 2.0, -1.0, -2.0 });512 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/4952514 try doTheTestMod(f16, [4]f16{ 4.0, -4.0, 4.0, -4.0 }, [4]f16{ 1.0, 2.0, 0.5, 3.0 });
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 }
521 try doTheTestMod(f32, [4]f32{ 4.0, -4.0, 4.0, -4.0 }, [4]f32{ 1.0, 2.0, 0.5, 3.0 });515 try doTheTestMod(f32, [4]f32{ 4.0, -4.0, 4.0, -4.0 }, [4]f32{ 1.0, 2.0, 0.5, 3.0 });
522 try doTheTestMod(f64, [4]f64{ 4.0, -4.0, 4.0, -4.0 }, [4]f64{ 1.0, 2.0, 0.5, 3.0 });516 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: {...@@ -315,6 +315,30 @@ const test_targets = blk: {
315 // .link_libc = true,315 // .link_libc = true,
316 //},316 //},
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
318 .{342 .{
319 .target = .{343 .target = .{
320 .cpu_arch = .riscv64,344 .cpu_arch = .riscv64,