| author | |
| committer | |
| log | b4e3424594aecbd5a038d7c3a9e1e01c66a239ee |
| tree | e5dfde6fa751626cd9e0ba6bf36bbd0bb9789fa1 |
| parent | 8bb2e96ac3b61a8aa393f250144fb9e1195ca60a |
| parent | a168893e0097093665154c7897b7f909cec855a1 |
| signature |
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 @@ |
| 3 | 3 | ||
| 4 | #if defined(__BIG_ENDIAN__) | 4 | #if defined(__BIG_ENDIAN__) |
| 5 | #define BIGENDIAN 1 | 5 | #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 1 | 11 | #define BIGENDIAN 1 |
| 8 | #elif defined(__THUMBEB__) | 12 | #elif defined(__THUMBEB__) |
| ... | @@ -15,18 +19,12 @@ | ... | @@ -15,18 +19,12 @@ |
| 15 | #define BIGENDIAN 1 | 19 | #define BIGENDIAN 1 |
| 16 | #elif defined(__MIPSEB__) | 20 | #elif defined(__MIPSEB__) |
| 17 | #define BIGENDIAN 1 | 21 | #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 1 | 23 | #define BIGENDIAN 1 |
| 22 | #elif defined(__sparc__) | 24 | #elif defined(__sparc__) |
| 23 | #define BIGENDIAN 1 | 25 | #define BIGENDIAN 1 |
| 24 | #elif defined(_POWER) | 26 | #elif defined(_POWER) |
| 25 | #define BIGENDIAN 1 | 27 | #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 1 | 29 | #define BIGENDIAN 1 |
| 32 | #elif defined(__hppa) | 30 | #elif defined(__hppa) |
| ... | @@ -39,6 +37,10 @@ | ... | @@ -39,6 +37,10 @@ |
| 39 | 37 | ||
| 40 | #if defined(__LITTLE_ENDIAN__) | 38 | #if defined(__LITTLE_ENDIAN__) |
| 41 | #define LITTLEENDIAN 1 | 39 | #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 1 | 45 | #define LITTLEENDIAN 1 |
| 44 | #elif defined(__THUMBEL__) | 46 | #elif defined(__THUMBEL__) |
| ... | @@ -51,8 +53,6 @@ | ... | @@ -51,8 +53,6 @@ |
| 51 | #define LITTLEENDIAN 1 | 53 | #define LITTLEENDIAN 1 |
| 52 | #elif defined(__MIPSEL__) | 54 | #elif defined(__MIPSEL__) |
| 53 | #define LITTLEENDIAN 1 | 55 | #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 1 | 57 | #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"); |
| 5 | 5 | ||
| 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"); |
| 11 | 12 | ||
| 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"); |
| 16 | 18 | ||
| 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"); |
| 36 | 39 | ||
| 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"); |
| 41 | 45 | ||
| 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"); |
| 54 | 62 | ||
| 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"); |
| 65 | 74 | ||
| 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"); | ||
| 77 | 86 | ||
| 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 @@ | ||
| 1 | const common = @import("./common.zig"); | ||
| 2 | const addf3 = @import("./addf3.zig").addf3; | ||
| 3 | |||
| 4 | pub const panic = common.panic; | ||
| 5 | |||
| 6 | comptime { | ||
| 7 | @export(__addhf3, .{ .name = "__addhf3", .linkage = common.linkage }); | ||
| 8 | } | ||
| 9 | |||
| 10 | fn __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 | ||
| 3 | const common = @import("./common.zig"); | ||
| 4 | const comparef = @import("./comparef.zig"); | ||
| 5 | |||
| 6 | pub const panic = common.panic; | ||
| 7 | |||
| 8 | comptime { | ||
| 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`. | ||
| 22 | fn __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." | ||
| 28 | pub 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. | ||
| 35 | pub 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. | ||
| 42 | pub 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." | ||
| 48 | pub 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 @@ | ||
| 1 | const common = @import("common.zig"); | ||
| 2 | const divsf3 = @import("./divsf3.zig"); | ||
| 3 | |||
| 4 | comptime { | ||
| 5 | @export(__divhf3, .{ .name = "__divhf3", .linkage = common.linkage }); | ||
| 6 | } | ||
| 7 | |||
| 8 | pub 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 @@ | ||
| 1 | const common = @import("./common.zig"); | ||
| 2 | const extendf = @import("./extendf.zig").extendf; | ||
| 3 | |||
| 4 | pub const panic = common.panic; | ||
| 5 | |||
| 6 | comptime { | ||
| 7 | @export(__extendhfdf2, .{ .name = "__extendhfdf2", .linkage = common.linkage }); | ||
| 8 | } | ||
| 9 | |||
| 10 | pub 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; |
| 5 | 5 | ||
| 6 | comptime { | 6 | comptime { |
| 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 | } |
| 15 | 14 | ||
| 16 | pub fn __extendhfsf2(a: common.F16T) callconv(.C) f32 { | 15 | pub 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 | } |
| 19 | 18 | ||
| 20 | fn __gnu_h2f_ieee(a: common.F16T) callconv(.C) f32 { | ||
| 21 | return extendf(f32, f16, @bitCast(u16, a)); | ||
| 22 | } | ||
| 23 | |||
| 24 | fn __aeabi_h2f(a: u16) callconv(.AAPCS) f32 { | 19 | fn __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 | ||
| 3 | const common = @import("./common.zig"); | ||
| 4 | const comparef = @import("./comparef.zig"); | ||
| 5 | |||
| 6 | pub const panic = common.panic; | ||
| 7 | |||
| 8 | comptime { | ||
| 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." | ||
| 15 | pub 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." | ||
| 21 | pub fn __gthf2(a: f16, b: f16) callconv(.C) i32 { | ||
| 22 | return __gehf2(a, b); | ||
| 23 | } | ||
| 24 | |||
| 25 | fn __aeabi_fcmpge(a: f16, b: f16) callconv(.AAPCS) i32 { | ||
| 26 | return @boolToInt(comparef.cmpf2(f16, comparef.GE, a, b) != .Less); | ||
| 27 | } | ||
| 28 | |||
| 29 | fn __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)); |
| 34 | 34 | ||
| 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; |
| 38 | 39 | ||
| 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 @@ | ||
| 1 | const common = @import("./common.zig"); | ||
| 2 | const mulf3 = @import("./mulf3.zig").mulf3; | ||
| 3 | |||
| 4 | pub const panic = common.panic; | ||
| 5 | |||
| 6 | comptime { | ||
| 7 | @export(__mulhf3, .{ .name = "__mulhf3", .linkage = common.linkage }); | ||
| 8 | } | ||
| 9 | |||
| 10 | pub 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 @@ | ||
| 1 | const common = @import("./common.zig"); | ||
| 2 | |||
| 3 | pub const panic = common.panic; | ||
| 4 | |||
| 5 | comptime { | ||
| 6 | @export(__neghf2, .{ .name = "__neghf2", .linkage = common.linkage }); | ||
| 7 | } | ||
| 8 | |||
| 9 | fn __neghf2(a: f16) callconv(.C) f16 { | ||
| 10 | return common.fneg(a); | ||
| 11 | } | ||
lib/compiler_rt/subhf3.zig created+12| ... | @@ -0,0 +1,12 @@ | ||
| 1 | const common = @import("./common.zig"); | ||
| 2 | |||
| 3 | pub const panic = common.panic; | ||
| 4 | |||
| 5 | comptime { | ||
| 6 | @export(__subhf3, .{ .name = "__subhf3", .linkage = common.linkage }); | ||
| 7 | } | ||
| 8 | |||
| 9 | fn __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 | } |
| 31 | 33 |
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; |
| 5 | 5 | ||
| 6 | comptime { | 6 | comptime { |
| 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 | } |
| 15 | 14 | ||
| 16 | pub fn __truncsfhf2(a: f32) callconv(.C) common.F16T { | 15 | pub 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 | } |
| 19 | 18 | ||
| 20 | fn __gnu_f2h_ieee(a: f32) callconv(.C) common.F16T { | ||
| 21 | return @bitCast(common.F16T, truncf(f16, f32, a)); | ||
| 22 | } | ||
| 23 | |||
| 24 | fn __aeabi_f2h(a: f32) callconv(.AAPCS) u16 { | 19 | fn __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 @@ | ||
| 1 | const common = @import("./common.zig"); | ||
| 2 | const comparef = @import("./comparef.zig"); | ||
| 3 | |||
| 4 | pub const panic = common.panic; | ||
| 5 | |||
| 6 | comptime { | ||
| 7 | @export(__unordhf2, .{ .name = "__unordhf2", .linkage = common.linkage }); | ||
| 8 | } | ||
| 9 | |||
| 10 | pub 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 @@ | ||
| 1 | const common = @import("./common.zig"); | ||
| 2 | const comparef = @import("./comparef.zig"); | ||
| 3 | |||
| 4 | pub const panic = common.panic; | ||
| 5 | |||
| 6 | comptime { | ||
| 7 | @export(__unordxf2, .{ .name = "__unordxf2", .linkage = common.linkage }); | ||
| 8 | } | ||
| 9 | |||
| 10 | pub 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 | }; |
| 375 | 375 | ||
| 376 | test "Atomic.swap" { | 376 | test "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, |
| 1793 | 1795 | ||
| 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 | } |
| 7620 | 7642 | ||
| 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 | } |
| 7638 | 7674 | ||
| 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 | } |
| 8719 | 8755 | ||
| 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(); | ||
| 8723 | 8824 | ||
| 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); |
| 8727 | 8829 | ||
| 8728 | // TODO handle the fast math setting | 8830 | // 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 | } |
| 8764 | 8908 | ||
| 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 | } |
| 9093 | 9243 | ||
| 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. |
| 10452 | fn backendSupportsF16(target: std.Target) bool { | 10521 | fn 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 param | 6364 | 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 | } |
| 82 | 82 | ||
| 83 | static LLVMValueRef get_soft_float_fn(CodeGen *g, const char *name, int param_count, LLVMTypeRef param_type, LLVMTypeRef return_type); | ||
| 83 | static void render_const_val(CodeGen *g, ZigValue *const_val, const char *name); | 84 | static void render_const_val(CodeGen *g, ZigValue *const_val, const char *name); |
| 84 | static void render_const_val_global(CodeGen *g, ZigValue *const_val, const char *name); | 85 | static void render_const_val_global(CodeGen *g, ZigValue *const_val, const char *name); |
| 85 | static LLVMValueRef gen_const_val(CodeGen *g, ZigValue *const_val, const char *name); | 86 | static 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 | } |
| 1738 | 1739 | ||
| 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, ""); |
| 1746 | 1742 | ||
| 1747 | // On non-Arm platforms we need to bitcast __trunc<>fhf2 result back to f16 | 1743 | // 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) { |
| 1768 | 1764 | ||
| 1769 | if ((scalar_actual_type == g->builtin_types.entry_f80 | 1765 | 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, |
| 4042 | 4044 | ||
| 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; |
| 4397 | 4400 | ||
| 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 | } |
| 4402 | 4406 | ||
| ... | @@ -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 | } |
| 6479 | 6483 | ||
| 6484 | static 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 | |||
| 6480 | static LLVMValueRef ir_render_reduce(CodeGen *g, Stage1Air *executable, Stage1AirInstReduce *instruction) { | 6533 | static 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); |
| 6482 | 6535 | ||
| ... | @@ -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; |
| 6486 | 6539 | ||
| 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)); |
| 6488 | 6554 | ||
| 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 | } |
| 6540 | 6627 | ||
| 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 | } |
| 6543 | 6635 | ||
| 6544 | static LLVMValueRef ir_render_fence(CodeGen *g, Stage1Air *executable, Stage1AirInstFence *instruction) { | 6636 | static 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; |
| 7375 | 7471 | ||
| 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 | else | 7483 | else |
| 7386 | zig_unreachable(); | 7484 | zig_unreachable(); |
| 7387 | 7485 | ||
| 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 | } | ||
| 7395 | 7488 | ||
| 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 | } |
| 9742 | 9836 | ||
| 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 | } |
| 23 | 23 | ||
| 24 | static 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 | |||
| 31 | static 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 | |||
| 24 | 38 | ||
| 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. |
| 26 | static inline double zig_f16_to_double(float16_t x) { | 40 | static 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 | } |
| 1126 | 1126 | ||
| 1127 | bool target_is_ppc(const ZigTarget *target) { | 1127 | bool 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 | } |
| 1131 | 1131 | ||
| 1132 | // Returns the minimum alignment for every function pointer on the given | 1132 | // 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 | } |
| 191 | 192 | ||
| 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 | } |
| 567 | 567 | ||
| 568 | test "alignment of slice element" { | 568 | test "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"); |
| 3 | 3 | ||
| 4 | test { | 4 | test { |
| 5 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 5 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 6 | if (builtin.zig_backend == .stage1) return error.SkipZigTest; | ||
| 6 | 7 | ||
| 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 @@ | ||
| 1 | const 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. | ||
| 6 | test "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 { |
| 8 | 8 | ||
| 9 | test { | 9 | test { |
| 10 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 10 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 11 | if (builtin.zig_backend == .stage1) return error.SkipZigTest; | ||
| 11 | 12 | ||
| 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 | }; |
| 16 | test { | 16 | test { |
| 17 | if (builtin.zig_backend == .stage1) return error.SkipZigTest; | ||
| 17 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 18 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 18 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 19 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 19 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | 20 | 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 | |||
| 1173 | test "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 | } |
| 1340 | 1340 | ||
| 1341 | test "break from inline loop depends on runtime condition" { | 1341 | test "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; // TODO | 71 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 72 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 72 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 73 | 73 | ||
| 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 | } |
| 586 | 586 | ||
| 587 | test "packed struct passed to callconv(.C) function" { | 587 | test "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 | } |
| 507 | 507 | ||
| 508 | fn doTheTest() !void { | 508 | fn doTheTest() !void { |
| 509 | // https://github.com/ziglang/zig/issues/4952 | 509 | 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 | } | ||
| 513 | 510 | ||
| 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 }); |
| 516 | 513 | ||
| 517 | // https://github.com/ziglang/zig/issues/4952 | 514 | 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 }); |
| 523 | 517 |
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 | //}, |
| 317 | 317 | ||
| 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, |