| 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 | 3 | |
| 4 | 4 | #if defined(__BIG_ENDIAN__) |
| 5 | 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 | 10 | #elif defined(__ARMEB__) |
| 7 | 11 | #define BIGENDIAN 1 |
| 8 | 12 | #elif defined(__THUMBEB__) |
| ... | ... | @@ -15,18 +19,12 @@ |
| 15 | 19 | #define BIGENDIAN 1 |
| 16 | 20 | #elif defined(__MIPSEB__) |
| 17 | 21 | #define BIGENDIAN 1 |
| 18 | #elif defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ | |
| 19 | #define BIGENDIAN 1 | |
| 20 | 22 | #elif defined(__sparc) |
| 21 | 23 | #define BIGENDIAN 1 |
| 22 | 24 | #elif defined(__sparc__) |
| 23 | 25 | #define BIGENDIAN 1 |
| 24 | 26 | #elif defined(_POWER) |
| 25 | 27 | #define BIGENDIAN 1 |
| 26 | #elif defined(__powerpc__) | |
| 27 | #define BIGENDIAN 1 | |
| 28 | #elif defined(__ppc__) | |
| 29 | #define BIGENDIAN 1 | |
| 30 | 28 | #elif defined(__hpux) |
| 31 | 29 | #define BIGENDIAN 1 |
| 32 | 30 | #elif defined(__hppa) |
| ... | ... | @@ -39,6 +37,10 @@ |
| 39 | 37 | |
| 40 | 38 | #if defined(__LITTLE_ENDIAN__) |
| 41 | 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 | 44 | #elif defined(__ARMEL__) |
| 43 | 45 | #define LITTLEENDIAN 1 |
| 44 | 46 | #elif defined(__THUMBEL__) |
| ... | ... | @@ -51,8 +53,6 @@ |
| 51 | 53 | #define LITTLEENDIAN 1 |
| 52 | 54 | #elif defined(__MIPSEL__) |
| 53 | 55 | #define LITTLEENDIAN 1 |
| 54 | #elif defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ | |
| 55 | #define LITTLEENDIAN 1 | |
| 56 | 56 | #elif defined(__i386__) |
| 57 | 57 | #define LITTLEENDIAN 1 |
| 58 | 58 | #elif defined(__alpha__) |
lib/compiler_rt.zig+17-7| ... | ... | @@ -4,17 +4,20 @@ comptime { |
| 4 | 4 | _ = @import("compiler_rt/atomics.zig"); |
| 5 | 5 | |
| 6 | 6 | _ = @import("compiler_rt/addf3.zig"); |
| 7 | _ = @import("compiler_rt/addhf3.zig"); | |
| 7 | 8 | _ = @import("compiler_rt/addsf3.zig"); |
| 8 | 9 | _ = @import("compiler_rt/adddf3.zig"); |
| 9 | 10 | _ = @import("compiler_rt/addtf3.zig"); |
| 10 | 11 | _ = @import("compiler_rt/addxf3.zig"); |
| 11 | 12 | |
| 13 | _ = @import("compiler_rt/subhf3.zig"); | |
| 12 | 14 | _ = @import("compiler_rt/subsf3.zig"); |
| 13 | 15 | _ = @import("compiler_rt/subdf3.zig"); |
| 14 | 16 | _ = @import("compiler_rt/subtf3.zig"); |
| 15 | 17 | _ = @import("compiler_rt/subxf3.zig"); |
| 16 | 18 | |
| 17 | 19 | _ = @import("compiler_rt/mulf3.zig"); |
| 20 | _ = @import("compiler_rt/mulhf3.zig"); | |
| 18 | 21 | _ = @import("compiler_rt/mulsf3.zig"); |
| 19 | 22 | _ = @import("compiler_rt/muldf3.zig"); |
| 20 | 23 | _ = @import("compiler_rt/multf3.zig"); |
| ... | ... | @@ -34,51 +37,58 @@ comptime { |
| 34 | 37 | _ = @import("compiler_rt/divxc3.zig"); |
| 35 | 38 | _ = @import("compiler_rt/divtc3.zig"); |
| 36 | 39 | |
| 40 | _ = @import("compiler_rt/neghf2.zig"); | |
| 37 | 41 | _ = @import("compiler_rt/negsf2.zig"); |
| 38 | 42 | _ = @import("compiler_rt/negdf2.zig"); |
| 39 | 43 | _ = @import("compiler_rt/negtf2.zig"); |
| 40 | 44 | _ = @import("compiler_rt/negxf2.zig"); |
| 41 | 45 | |
| 42 | 46 | _ = @import("compiler_rt/comparef.zig"); |
| 47 | _ = @import("compiler_rt/cmphf2.zig"); | |
| 43 | 48 | _ = @import("compiler_rt/cmpsf2.zig"); |
| 44 | 49 | _ = @import("compiler_rt/cmpdf2.zig"); |
| 45 | 50 | _ = @import("compiler_rt/cmptf2.zig"); |
| 46 | 51 | _ = @import("compiler_rt/cmpxf2.zig"); |
| 52 | _ = @import("compiler_rt/gehf2.zig"); | |
| 47 | 53 | _ = @import("compiler_rt/gesf2.zig"); |
| 48 | 54 | _ = @import("compiler_rt/gedf2.zig"); |
| 49 | _ = @import("compiler_rt/getf2.zig"); | |
| 50 | 55 | _ = @import("compiler_rt/gexf2.zig"); |
| 56 | _ = @import("compiler_rt/getf2.zig"); | |
| 57 | _ = @import("compiler_rt/unordhf2.zig"); | |
| 51 | 58 | _ = @import("compiler_rt/unordsf2.zig"); |
| 52 | 59 | _ = @import("compiler_rt/unorddf2.zig"); |
| 60 | _ = @import("compiler_rt/unordxf2.zig"); | |
| 53 | 61 | _ = @import("compiler_rt/unordtf2.zig"); |
| 54 | 62 | |
| 55 | 63 | _ = @import("compiler_rt/extendf.zig"); |
| 56 | _ = @import("compiler_rt/extenddftf2.zig"); | |
| 57 | _ = @import("compiler_rt/extenddfxf2.zig"); | |
| 58 | 64 | _ = @import("compiler_rt/extendhfsf2.zig"); |
| 65 | _ = @import("compiler_rt/extendhfdf2.zig"); | |
| 59 | 66 | _ = @import("compiler_rt/extendhftf2.zig"); |
| 60 | 67 | _ = @import("compiler_rt/extendhfxf2.zig"); |
| 61 | 68 | _ = @import("compiler_rt/extendsfdf2.zig"); |
| 62 | 69 | _ = @import("compiler_rt/extendsftf2.zig"); |
| 63 | 70 | _ = @import("compiler_rt/extendsfxf2.zig"); |
| 71 | _ = @import("compiler_rt/extenddftf2.zig"); | |
| 72 | _ = @import("compiler_rt/extenddfxf2.zig"); | |
| 64 | 73 | _ = @import("compiler_rt/extendxftf2.zig"); |
| 65 | 74 | |
| 66 | 75 | _ = @import("compiler_rt/truncf.zig"); |
| 67 | 76 | _ = @import("compiler_rt/truncsfhf2.zig"); |
| 68 | 77 | _ = @import("compiler_rt/truncdfhf2.zig"); |
| 69 | 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 | 82 | _ = @import("compiler_rt/trunctfhf2.zig"); |
| 71 | 83 | _ = @import("compiler_rt/trunctfsf2.zig"); |
| 72 | 84 | _ = @import("compiler_rt/trunctfdf2.zig"); |
| 73 | 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 | 88 | _ = @import("compiler_rt/divsf3.zig"); |
| 80 | 89 | _ = @import("compiler_rt/divdf3.zig"); |
| 81 | 90 | _ = @import("compiler_rt/divxf3.zig"); |
| 91 | _ = @import("compiler_rt/divtf3.zig"); | |
| 82 | 92 | _ = @import("compiler_rt/sin.zig"); |
| 83 | 93 | _ = @import("compiler_rt/cos.zig"); |
| 84 | 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 | 5 | |
| 6 | 6 | comptime { |
| 7 | 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 | 9 | } else if (common.want_aeabi) { |
| 10 | 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 | 15 | pub fn __extendhfsf2(a: common.F16T) callconv(.C) f32 { |
| 17 | 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 | 19 | fn __aeabi_h2f(a: u16) callconv(.AAPCS) f32 { |
| 25 | 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 | 32 | const infRep = @bitCast(Z, math.inf(T)); |
| 33 | 33 | const minNormalRep = @bitCast(Z, math.floatMin(T)); |
| 34 | 34 | |
| 35 | const aExponent = @truncate(u32, (@bitCast(Z, a) >> significandBits) & maxExponent); | |
| 36 | const bExponent = @truncate(u32, (@bitCast(Z, b) >> significandBits) & maxExponent); | |
| 35 | const ZExp = if (typeWidth >= 32) u32 else Z; | |
| 36 | const aExponent = @truncate(ZExp, (@bitCast(Z, a) >> significandBits) & maxExponent); | |
| 37 | const bExponent = @truncate(ZExp, (@bitCast(Z, b) >> significandBits) & maxExponent); | |
| 37 | 38 | const productSign: Z = (@bitCast(Z, a) ^ @bitCast(Z, b)) & signBit; |
| 38 | 39 | |
| 39 | 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 | 24 | @export(tanf, .{ .name = "tanf", .linkage = common.linkage }); |
| 25 | 25 | @export(tan, .{ .name = "tan", .linkage = common.linkage }); |
| 26 | 26 | @export(__tanx, .{ .name = "__tanx", .linkage = common.linkage }); |
| 27 | const tanq_sym_name = if (common.want_ppc_abi) "tanf128" else "tanq"; | |
| 28 | @export(tanq, .{ .name = tanq_sym_name, .linkage = common.linkage }); | |
| 27 | if (common.want_ppc_abi) { | |
| 28 | @export(tanq, .{ .name = "tanf128", .linkage = common.linkage }); | |
| 29 | } | |
| 30 | @export(tanq, .{ .name = "tanq", .linkage = common.linkage }); | |
| 29 | 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 | 5 | |
| 6 | 6 | comptime { |
| 7 | 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 | 9 | } else if (common.want_aeabi) { |
| 10 | 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 | 15 | pub fn __truncsfhf2(a: f32) callconv(.C) common.F16T { |
| 17 | 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 | 19 | fn __aeabi_f2h(a: f32) callconv(.AAPCS) u16 { |
| 25 | 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 | 374 | }; |
| 375 | 375 | |
| 376 | 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 | 381 | inline for (atomic_rmw_orderings) |ordering| { |
| 378 | 382 | var x = Atomic(usize).init(5); |
| 379 | 383 | try testing.expectEqual(x.swap(10, ordering), 5); |
lib/std/target.zig+2| ... | ... | @@ -1789,6 +1789,8 @@ pub const Target = struct { |
| 1789 | 1789 | .powerpcle, |
| 1790 | 1790 | .powerpc64, |
| 1791 | 1791 | .powerpc64le, |
| 1792 | .wasm32, | |
| 1793 | .wasm64, | |
| 1792 | 1794 | => true, |
| 1793 | 1795 | |
| 1794 | 1796 | else => false, |
src/codegen/llvm.zig+177-97| ... | ... | @@ -2738,7 +2738,7 @@ pub const DeclGen = struct { |
| 2738 | 2738 | return dg.context.intType(bit_count); |
| 2739 | 2739 | }, |
| 2740 | 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 | 2742 | 32 => return dg.context.floatType(), |
| 2743 | 2743 | 64 => return dg.context.doubleType(), |
| 2744 | 2744 | 80 => return if (backendSupportsF80(target)) dg.context.x86FP80Type() else dg.context.intType(80), |
| ... | ... | @@ -3253,7 +3253,15 @@ pub const DeclGen = struct { |
| 3253 | 3253 | .Float => { |
| 3254 | 3254 | const llvm_ty = try dg.lowerType(tv.ty); |
| 3255 | 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 | 3265 | 80 => { |
| 3258 | 3266 | const float = tv.val.toFloat(f80); |
| 3259 | 3267 | const repr = std.math.break_f80(float); |
| ... | ... | @@ -7611,11 +7619,25 @@ pub const FuncGen = struct { |
| 7611 | 7619 | const target = self.dg.module.getTarget(); |
| 7612 | 7620 | const dest_bits = dest_ty.floatBits(target); |
| 7613 | 7621 | const src_bits = operand_ty.floatBits(target); |
| 7614 | if (!backendSupportsF80(target) and (src_bits == 80 or dest_bits == 80)) { | |
| 7615 | return softF80TruncOrExt(self, operand, src_bits, dest_bits); | |
| 7622 | ||
| 7623 | if (intrinsicsAllowed(dest_ty, target) and intrinsicsAllowed(operand_ty, target)) { | |
| 7624 | const dest_llvm_ty = try self.dg.lowerType(dest_ty); | |
| 7625 | return self.builder.buildFPTrunc(operand, dest_llvm_ty, ""); | |
| 7626 | } else { | |
| 7627 | const operand_llvm_ty = try self.dg.lowerType(operand_ty); | |
| 7628 | const dest_llvm_ty = try self.dg.lowerType(dest_ty); | |
| 7629 | ||
| 7630 | var fn_name_buf: [64]u8 = undefined; | |
| 7631 | const fn_name = std.fmt.bufPrintZ(&fn_name_buf, "__trunc{s}f{s}f2", .{ | |
| 7632 | compilerRtFloatAbbrev(src_bits), compilerRtFloatAbbrev(dest_bits), | |
| 7633 | }) catch unreachable; | |
| 7634 | ||
| 7635 | const params = [1]*llvm.Value{operand}; | |
| 7636 | const param_types = [1]*llvm.Type{operand_llvm_ty}; | |
| 7637 | const llvm_fn = self.getLibcFunction(fn_name, &param_types, dest_llvm_ty); | |
| 7638 | ||
| 7639 | return self.builder.buildCall(llvm_fn.globalGetValueType(), llvm_fn, &params, params.len, .C, .Auto, ""); | |
| 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 | 7643 | fn airFpext(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| ... | ... | @@ -7629,11 +7651,25 @@ pub const FuncGen = struct { |
| 7629 | 7651 | const target = self.dg.module.getTarget(); |
| 7630 | 7652 | const dest_bits = dest_ty.floatBits(target); |
| 7631 | 7653 | const src_bits = operand_ty.floatBits(target); |
| 7632 | if (!backendSupportsF80(target) and (src_bits == 80 or dest_bits == 80)) { | |
| 7633 | return softF80TruncOrExt(self, operand, src_bits, dest_bits); | |
| 7654 | ||
| 7655 | if (intrinsicsAllowed(dest_ty, target) and intrinsicsAllowed(operand_ty, target)) { | |
| 7656 | const dest_llvm_ty = try self.dg.lowerType(dest_ty); | |
| 7657 | return self.builder.buildFPExt(operand, dest_llvm_ty, ""); | |
| 7658 | } else { | |
| 7659 | const operand_llvm_ty = try self.dg.lowerType(operand_ty); | |
| 7660 | const dest_llvm_ty = try self.dg.lowerType(dest_ty); | |
| 7661 | ||
| 7662 | var fn_name_buf: [64]u8 = undefined; | |
| 7663 | const fn_name = std.fmt.bufPrintZ(&fn_name_buf, "__extend{s}f{s}f2", .{ | |
| 7664 | compilerRtFloatAbbrev(src_bits), compilerRtFloatAbbrev(dest_bits), | |
| 7665 | }) catch unreachable; | |
| 7666 | ||
| 7667 | const params = [1]*llvm.Value{operand}; | |
| 7668 | const param_types = [1]*llvm.Type{operand_llvm_ty}; | |
| 7669 | const llvm_fn = self.getLibcFunction(fn_name, &param_types, dest_llvm_ty); | |
| 7670 | ||
| 7671 | return self.builder.buildCall(llvm_fn.globalGetValueType(), llvm_fn, &params, params.len, .C, .Auto, ""); | |
| 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 | 7675 | fn airPtrToInt(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| ... | ... | @@ -8717,12 +8753,78 @@ pub const FuncGen = struct { |
| 8717 | 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 | 8820 | fn airReduce(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*llvm.Value { |
| 8721 | 8821 | if (self.liveness.isUnused(inst)) return null; |
| 8722 | 8822 | self.builder.setFastMath(want_fast_math); |
| 8823 | const target = self.dg.module.getTarget(); | |
| 8723 | 8824 | |
| 8724 | 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 | 8828 | const scalar_ty = self.air.typeOfIndex(inst); |
| 8727 | 8829 | |
| 8728 | 8830 | // TODO handle the fast math setting |
| ... | ... | @@ -8733,17 +8835,21 @@ pub const FuncGen = struct { |
| 8733 | 8835 | .Xor => return self.builder.buildXorReduce(operand), |
| 8734 | 8836 | .Min => switch (scalar_ty.zigTypeTag()) { |
| 8735 | 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 | 8841 | else => unreachable, |
| 8738 | 8842 | }, |
| 8739 | 8843 | .Max => switch (scalar_ty.zigTypeTag()) { |
| 8740 | 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 | 8848 | else => unreachable, |
| 8743 | 8849 | }, |
| 8744 | 8850 | .Add => switch (scalar_ty.zigTypeTag()) { |
| 8745 | 8851 | .Int => return self.builder.buildAddReduce(operand), |
| 8746 | .Float => { | |
| 8852 | .Float => if (intrinsicsAllowed(scalar_ty, target)) { | |
| 8747 | 8853 | const scalar_llvm_ty = try self.dg.lowerType(scalar_ty); |
| 8748 | 8854 | const neutral_value = scalar_llvm_ty.constReal(-0.0); |
| 8749 | 8855 | return self.builder.buildFPAddReduce(neutral_value, operand); |
| ... | ... | @@ -8752,7 +8858,7 @@ pub const FuncGen = struct { |
| 8752 | 8858 | }, |
| 8753 | 8859 | .Mul => switch (scalar_ty.zigTypeTag()) { |
| 8754 | 8860 | .Int => return self.builder.buildMulReduce(operand), |
| 8755 | .Float => { | |
| 8861 | .Float => if (intrinsicsAllowed(scalar_ty, target)) { | |
| 8756 | 8862 | const scalar_llvm_ty = try self.dg.lowerType(scalar_ty); |
| 8757 | 8863 | const neutral_value = scalar_llvm_ty.constReal(1.0); |
| 8758 | 8864 | return self.builder.buildFPMulReduce(neutral_value, operand); |
| ... | ... | @@ -8760,6 +8866,44 @@ pub const FuncGen = struct { |
| 8760 | 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 | 8909 | fn airAggregateInit(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| ... | ... | @@ -9051,7 +9195,13 @@ pub const FuncGen = struct { |
| 9051 | 9195 | const target = self.dg.module.getTarget(); |
| 9052 | 9196 | switch (prefetch.cache) { |
| 9053 | 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 | 9205 | .arm, .armeb, .thumb, .thumbeb => { |
| 9056 | 9206 | switch (prefetch.rw) { |
| 9057 | 9207 | .write => return null, |
| ... | ... | @@ -9091,87 +9241,6 @@ pub const FuncGen = struct { |
| 9091 | 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 | 9244 | fn getErrorNameTable(self: *FuncGen) !*llvm.Value { |
| 9176 | 9245 | if (self.dg.object.error_name_table) |table| { |
| 9177 | 9246 | return table; |
| ... | ... | @@ -10451,6 +10520,17 @@ fn backendSupportsF80(target: std.Target) bool { |
| 10451 | 10520 | /// if it produces miscompilations. |
| 10452 | 10521 | fn backendSupportsF16(target: std.Target) bool { |
| 10453 | 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 | 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 | 6358 | const_val->data.x_f64 = value; |
| 6359 | 6359 | break; |
| 6360 | 6360 | case 80: |
| 6361 | zig_double_to_extF80M(value, &const_val->data.x_f80); | |
| 6362 | break; | |
| 6361 | 6363 | case 128: |
| 6362 | // if we need this, we should add a function that accepts a float128_t param | |
| 6363 | zig_unreachable(); | |
| 6364 | zig_double_to_f128M(value, &const_val->data.x_f128); | |
| 6365 | break; | |
| 6364 | 6366 | default: |
| 6365 | 6367 | zig_unreachable(); |
| 6366 | 6368 | } |
src/stage1/codegen.cpp+139-39| ... | ... | @@ -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 | 84 | static void render_const_val(CodeGen *g, ZigValue *const_val, const char *name); |
| 84 | 85 | static void render_const_val_global(CodeGen *g, ZigValue *const_val, const char *name); |
| 85 | 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 | 1737 | } |
| 1737 | 1738 | } |
| 1738 | 1739 | |
| 1739 | LLVMValueRef func_ref = LLVMGetNamedFunction(g->module, fn_name); | |
| 1740 | if (func_ref == nullptr) { | |
| 1741 | LLVMTypeRef fn_type = LLVMFunctionType(return_type, &param_type, 1, false); | |
| 1742 | func_ref = LLVMAddFunction(g->module, fn_name, fn_type); | |
| 1743 | } | |
| 1744 | ||
| 1740 | LLVMValueRef func_ref = get_soft_float_fn(g, fn_name, 1, param_type, return_type); | |
| 1745 | 1741 | result = LLVMBuildCall2(g->builder, LLVMGlobalGetValueType(func_ref), func_ref, &expr_val, 1, ""); |
| 1746 | 1742 | |
| 1747 | 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 | 1762 | uint64_t wanted_bits; |
| 1767 | 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 | 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 | 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 | 3099 | ZigType *elem_type = operand_type->id == ZigTypeIdVector ? operand_type->data.vector.elem_type : operand_type; |
| 3101 | 3100 | if ((elem_type == g->builtin_types.entry_f80 && !target_has_f80(g->zig_target)) || |
| 3102 | 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 | 3103 | op == BuiltinFnIdTan) |
| 3104 | 3104 | { |
| 3105 | 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 | 3690 | ZigType *operand_type = op1->value->type; |
| 3691 | 3691 | ZigType *scalar_type = (operand_type->id == ZigTypeIdVector) ? operand_type->data.vector.elem_type : operand_type; |
| 3692 | 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 | 3695 | // LLVM incorrectly lowers the soft float calls for f128 as if they operated on `long double`. |
| 3695 | 3696 | // On some targets this will be incorrect, so we manually lower the call ourselves. |
| 3696 | 3697 | LLVMValueRef op1_value = ir_llvm_value(g, op1); |
| ... | ... | @@ -4024,7 +4025,8 @@ static LLVMValueRef ir_render_cast(CodeGen *g, Stage1Air *executable, |
| 4024 | 4025 | assert(actual_type->id == ZigTypeIdInt); |
| 4025 | 4026 | { |
| 4026 | 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 | 4030 | return gen_soft_int_to_float_op(g, expr_val, actual_type, wanted_type); |
| 4029 | 4031 | } else { |
| 4030 | 4032 | if (actual_type->data.integral.is_signed) { |
| ... | ... | @@ -4042,7 +4044,8 @@ static LLVMValueRef ir_render_cast(CodeGen *g, Stage1Air *executable, |
| 4042 | 4044 | |
| 4043 | 4045 | LLVMValueRef result; |
| 4044 | 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 | 4049 | result = gen_soft_float_to_int_op(g, expr_val, actual_type, wanted_type); |
| 4047 | 4050 | } else { |
| 4048 | 4051 | if (wanted_type->data.integral.is_signed) { |
| ... | ... | @@ -4396,7 +4399,8 @@ static LLVMValueRef gen_negation(CodeGen *g, Stage1AirInst *inst, Stage1AirInst |
| 4396 | 4399 | operand_type->data.vector.elem_type : operand_type; |
| 4397 | 4400 | |
| 4398 | 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 | 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 | 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 | 6533 | static LLVMValueRef ir_render_reduce(CodeGen *g, Stage1Air *executable, Stage1AirInstReduce *instruction) { |
| 6481 | 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 | 6537 | assert(value_type->id == ZigTypeIdVector); |
| 6485 | 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 | 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 | 6557 | switch (instruction->op) { |
| 6491 | 6558 | case ReduceOp_and: |
| 6492 | 6559 | assert(scalar_type->id == ZigTypeIdInt || scalar_type->id == ZigTypeIdBool); |
| 6493 | result_val = ZigLLVMBuildAndReduce(g->builder, value); | |
| 6560 | return ZigLLVMBuildAndReduce(g->builder, value); | |
| 6494 | 6561 | break; |
| 6495 | 6562 | case ReduceOp_or: |
| 6496 | 6563 | assert(scalar_type->id == ZigTypeIdInt || scalar_type->id == ZigTypeIdBool); |
| 6497 | result_val = ZigLLVMBuildOrReduce(g->builder, value); | |
| 6564 | return ZigLLVMBuildOrReduce(g->builder, value); | |
| 6498 | 6565 | break; |
| 6499 | 6566 | case ReduceOp_xor: |
| 6500 | 6567 | assert(scalar_type->id == ZigTypeIdInt || scalar_type->id == ZigTypeIdBool); |
| 6501 | result_val = ZigLLVMBuildXorReduce(g->builder, value); | |
| 6568 | return ZigLLVMBuildXorReduce(g->builder, value); | |
| 6502 | 6569 | break; |
| 6503 | 6570 | case ReduceOp_min: { |
| 6504 | 6571 | if (scalar_type->id == ZigTypeIdInt) { |
| 6505 | 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 | 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 | 6581 | } else zig_unreachable(); |
| 6510 | 6582 | } break; |
| 6511 | 6583 | case ReduceOp_max: { |
| 6512 | 6584 | if (scalar_type->id == ZigTypeIdInt) { |
| 6513 | 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 | 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 | 6594 | } else zig_unreachable(); |
| 6518 | 6595 | } break; |
| 6519 | 6596 | case ReduceOp_add: { |
| 6520 | 6597 | if (scalar_type->id == ZigTypeIdInt) { |
| 6521 | result_val = ZigLLVMBuildAddReduce(g->builder, value); | |
| 6598 | return ZigLLVMBuildAddReduce(g->builder, value); | |
| 6522 | 6599 | } else if (scalar_type->id == ZigTypeIdFloat) { |
| 6523 | LLVMValueRef neutral_value = LLVMConstReal( | |
| 6524 | get_llvm_type(g, scalar_type), -0.0); | |
| 6525 | result_val = ZigLLVMBuildFPAddReduce(g->builder, neutral_value, value); | |
| 6600 | if (float_intrinsics_allowed) { | |
| 6601 | LLVMValueRef neutral_value = LLVMConstReal( | |
| 6602 | get_llvm_type(g, scalar_type), -0.0); | |
| 6603 | return ZigLLVMBuildFPAddReduce(g->builder, neutral_value, value); | |
| 6604 | } else { | |
| 6605 | snprintf(fn_name, sizeof(fn_name), "__add%sf3", compiler_rt_type_abbrev); | |
| 6606 | init_value = create_const_float(g, scalar_type, 0.0); | |
| 6607 | } | |
| 6526 | 6608 | } else zig_unreachable(); |
| 6527 | 6609 | } break; |
| 6528 | 6610 | case ReduceOp_mul: { |
| 6529 | 6611 | if (scalar_type->id == ZigTypeIdInt) { |
| 6530 | result_val = ZigLLVMBuildMulReduce(g->builder, value); | |
| 6612 | return ZigLLVMBuildMulReduce(g->builder, value); | |
| 6531 | 6613 | } else if (scalar_type->id == ZigTypeIdFloat) { |
| 6532 | LLVMValueRef neutral_value = LLVMConstReal( | |
| 6533 | get_llvm_type(g, scalar_type), 1.0); | |
| 6534 | result_val = ZigLLVMBuildFPMulReduce(g->builder, neutral_value, value); | |
| 6614 | if (float_intrinsics_allowed) { | |
| 6615 | LLVMValueRef neutral_value = LLVMConstReal( | |
| 6616 | get_llvm_type(g, scalar_type), 1.0); | |
| 6617 | return ZigLLVMBuildFPMulReduce(g->builder, neutral_value, value); | |
| 6618 | } else { | |
| 6619 | snprintf(fn_name, sizeof(fn_name), "__mul%sf3", compiler_rt_type_abbrev); | |
| 6620 | init_value = create_const_float(g, scalar_type, 1.0); | |
| 6621 | } | |
| 6535 | 6622 | } else zig_unreachable(); |
| 6536 | 6623 | } break; |
| 6537 | 6624 | default: |
| 6538 | 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 | 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 | 6742 | switch (g->zig_target->arch) { |
| 6651 | 6743 | case ZigLLVM_x86: |
| 6652 | 6744 | case ZigLLVM_x86_64: |
| 6745 | case ZigLLVM_ppc: | |
| 6746 | case ZigLLVM_ppcle: | |
| 6747 | case ZigLLVM_ppc64: | |
| 6748 | case ZigLLVM_ppc64le: | |
| 6653 | 6749 | return nullptr; |
| 6654 | 6750 | default: |
| 6655 | 6751 | break; |
| ... | ... | @@ -7374,7 +7470,9 @@ static LLVMValueRef ir_render_soft_mul_add(CodeGen *g, Stage1Air *executable, St |
| 7374 | 7470 | uint32_t vector_len = operand_type->id == ZigTypeIdVector ? operand_type->data.vector.len : 0; |
| 7375 | 7471 | |
| 7376 | 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 | 7476 | fn_name = "fmaf"; |
| 7379 | 7477 | else if (float_type == g->builtin_types.entry_f64) |
| 7380 | 7478 | fn_name = "fma"; |
| ... | ... | @@ -7385,13 +7483,8 @@ static LLVMValueRef ir_render_soft_mul_add(CodeGen *g, Stage1Air *executable, St |
| 7385 | 7483 | else |
| 7386 | 7484 | zig_unreachable(); |
| 7387 | 7485 | |
| 7388 | LLVMValueRef func_ref = LLVMGetNamedFunction(g->module, fn_name); | |
| 7389 | if (func_ref == nullptr) { | |
| 7390 | LLVMTypeRef float_type_ref = float_type->llvm_type; | |
| 7391 | LLVMTypeRef params[3] = { float_type_ref, float_type_ref, float_type_ref }; | |
| 7392 | LLVMTypeRef fn_type = LLVMFunctionType(float_type_ref, params, 3, false); | |
| 7393 | func_ref = LLVMAddFunction(g->module, fn_name, fn_type); | |
| 7394 | } | |
| 7486 | LLVMTypeRef float_type_ref = float_type->llvm_type; | |
| 7487 | LLVMValueRef func_ref = get_soft_float_fn(g, fn_name, 3, float_type_ref, float_type_ref); | |
| 7395 | 7488 | |
| 7396 | 7489 | LLVMValueRef op1 = ir_llvm_value(g, instruction->op1); |
| 7397 | 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 | 7514 | ZigType *operand_type = instruction->op1->value->type; |
| 7422 | 7515 | operand_type = operand_type->id == ZigTypeIdVector ? operand_type->data.vector.elem_type : operand_type; |
| 7423 | 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 | 7519 | return ir_render_soft_mul_add(g, executable, instruction, operand_type); |
| 7426 | 7520 | } |
| 7427 | 7521 | LLVMValueRef op1 = ir_llvm_value(g, instruction->op1); |
| ... | ... | @@ -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 | 9843 | add_fp_entry(g, "f32", 32, LLVMFloatType(), &g->builtin_types.entry_f32); |
| 9745 | 9844 | add_fp_entry(g, "f64", 64, LLVMDoubleType(), &g->builtin_types.entry_f64); |
| 9746 | 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 | 9936 | add_fp_entry(g, "c_longdouble", 128, LLVMFP128Type(), &g->builtin_types.entry_c_longdouble); |
| 9838 | 9937 | break; |
| 9839 | 9938 | case ZigLLVM_ppc: |
| 9939 | case ZigLLVM_ppcle: | |
| 9840 | 9940 | case ZigLLVM_ppc64: |
| 9841 | 9941 | case ZigLLVM_ppc64le: |
| 9842 | 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 | 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 | 39 | // Return value is safe to coerce to float even when |x| is NaN or Infinity. |
| 26 | 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 | 950 | case ZigLLVM_msp430: |
| 951 | 951 | case ZigLLVM_nvptx: |
| 952 | 952 | case ZigLLVM_nvptx64: |
| 953 | case ZigLLVM_ppc64le: | |
| 954 | 953 | case ZigLLVM_r600: |
| 955 | 954 | case ZigLLVM_renderscript32: |
| 956 | 955 | case ZigLLVM_renderscript64: |
| ... | ... | @@ -971,6 +970,7 @@ bool target_is_arm(const ZigTarget *target) { |
| 971 | 970 | case ZigLLVM_ppc: |
| 972 | 971 | case ZigLLVM_ppcle: |
| 973 | 972 | case ZigLLVM_ppc64: |
| 973 | case ZigLLVM_ppc64le: | |
| 974 | 974 | case ZigLLVM_ve: |
| 975 | 975 | case ZigLLVM_spirv32: |
| 976 | 976 | case ZigLLVM_spirv64: |
| ... | ... | @@ -1125,8 +1125,8 @@ bool target_is_mips(const ZigTarget *target) { |
| 1125 | 1125 | } |
| 1126 | 1126 | |
| 1127 | 1127 | bool target_is_ppc(const ZigTarget *target) { |
| 1128 | return target->arch == ZigLLVM_ppc || target->arch == ZigLLVM_ppc64 || | |
| 1129 | target->arch == ZigLLVM_ppc64le; | |
| 1128 | return target->arch == ZigLLVM_ppc || target->arch == ZigLLVM_ppcle || | |
| 1129 | target->arch == ZigLLVM_ppc64 || target->arch == ZigLLVM_ppc64le; | |
| 1130 | 1130 | } |
| 1131 | 1131 | |
| 1132 | 1132 | // Returns the minimum alignment for every function pointer on the given |
test/behavior.zig+2-1| ... | ... | @@ -89,7 +89,6 @@ test { |
| 89 | 89 | _ = @import("behavior/bugs/12551.zig"); |
| 90 | 90 | _ = @import("behavior/bugs/12644.zig"); |
| 91 | 91 | _ = @import("behavior/bugs/12680.zig"); |
| 92 | _ = @import("behavior/bugs/12776.zig"); | |
| 93 | 92 | _ = @import("behavior/bugs/12786.zig"); |
| 94 | 93 | _ = @import("behavior/bugs/12794.zig"); |
| 95 | 94 | _ = @import("behavior/bugs/12801-1.zig"); |
| ... | ... | @@ -187,6 +186,8 @@ test { |
| 187 | 186 | _ = @import("behavior/packed_struct_explicit_backing_int.zig"); |
| 188 | 187 | _ = @import("behavior/empty_union.zig"); |
| 189 | 188 | _ = @import("behavior/inline_switch.zig"); |
| 189 | _ = @import("behavior/bugs/12723.zig"); | |
| 190 | _ = @import("behavior/bugs/12776.zig"); | |
| 190 | 191 | } |
| 191 | 192 | |
| 192 | 193 | if (builtin.os.tag != .wasi) { |
test/behavior/align.zig+2| ... | ... | @@ -566,6 +566,8 @@ test "@alignCast null" { |
| 566 | 566 | } |
| 567 | 567 | |
| 568 | 568 | test "alignment of slice element" { |
| 569 | if (builtin.zig_backend == .stage1) return error.SkipZigTest; | |
| 570 | ||
| 569 | 571 | const a: []align(1024) const u8 = undefined; |
| 570 | 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 | 3 | |
| 4 | 4 | test { |
| 5 | 5 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 6 | if (builtin.zig_backend == .stage1) return error.SkipZigTest; | |
| 6 | 7 | |
| 7 | 8 | var x: u32 = 3; |
| 8 | 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 | 8 | |
| 9 | 9 | test { |
| 10 | 10 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 11 | if (builtin.zig_backend == .stage1) return error.SkipZigTest; | |
| 11 | 12 | |
| 12 | 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 | 14 | } |
| 15 | 15 | }; |
| 16 | 16 | test { |
| 17 | if (builtin.zig_backend == .stage1) return error.SkipZigTest; | |
| 17 | 18 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 18 | 19 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 19 | 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 | 1169 | const E = enum(u15) { _ }; |
| 1170 | 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 | 1339 | } |
| 1340 | 1340 | |
| 1341 | 1341 | test "break from inline loop depends on runtime condition" { |
| 1342 | if (builtin.zig_backend == .stage1) return error.SkipZigTest; | |
| 1343 | ||
| 1342 | 1344 | const S = struct { |
| 1343 | 1345 | fn foo(a: u8) bool { |
| 1344 | 1346 | return a == 4; |
test/behavior/muladd.zig-11| ... | ... | @@ -71,17 +71,6 @@ test "@mulAdd f128" { |
| 71 | 71 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 72 | 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 | 74 | comptime try testMulAdd128(); |
| 86 | 75 | try testMulAdd128(); |
| 87 | 76 | } |
test/behavior/packed-struct.zig+1| ... | ... | @@ -585,6 +585,7 @@ test "runtime init of unnamed packed struct type" { |
| 585 | 585 | } |
| 586 | 586 | |
| 587 | 587 | test "packed struct passed to callconv(.C) function" { |
| 588 | if (builtin.zig_backend == .stage1) return error.SkipZigTest; | |
| 588 | 589 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 589 | 590 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 590 | 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 | 506 | } |
| 507 | 507 | |
| 508 | 508 | fn doTheTest() !void { |
| 509 | // https://github.com/ziglang/zig/issues/4952 | |
| 510 | if (builtin.target.os.tag != .windows) { | |
| 511 | try doTheTestDiv(f16, [4]f16{ 4.0, -4.0, 4.0, -4.0 }, [4]f16{ 1.0, 2.0, -1.0, -2.0 }); | |
| 512 | } | |
| 509 | try doTheTestDiv(f16, [4]f16{ 4.0, -4.0, 4.0, -4.0 }, [4]f16{ 1.0, 2.0, -1.0, -2.0 }); | |
| 513 | 510 | |
| 514 | 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 | 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 | |
| 518 | if (builtin.target.os.tag != .windows) { | |
| 519 | try doTheTestMod(f16, [4]f16{ 4.0, -4.0, 4.0, -4.0 }, [4]f16{ 1.0, 2.0, 0.5, 3.0 }); | |
| 520 | } | |
| 514 | try doTheTestMod(f16, [4]f16{ 4.0, -4.0, 4.0, -4.0 }, [4]f16{ 1.0, 2.0, 0.5, 3.0 }); | |
| 521 | 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 | 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 | 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 | 343 | .target = .{ |
| 320 | 344 | .cpu_arch = .riscv64, |