| author | |
| committer | |
| log | 225910f9341fbc725ff5e0d2c653e29bc2f21cb8 |
| tree | eac47d40ae555398c46e4ccdff9cace12eeabd3b |
| parent | 63ee6e662582ee75ac804eb1a4dbdf4457b8f2d0 |
| parent | a0a71709bc2104c708f045fbb42c6247aff136ac |
| signature |
Add f8025 files changed, 953 insertions(+), 44 deletions(-)
CMakeLists.txt+31| ... | ... | @@ -142,15 +142,19 @@ include_directories(${CLANG_INCLUDE_DIRS}) |
| 142 | 142 | # No patches have been applied to SoftFloat-3e |
| 143 | 143 | set(EMBEDDED_SOFTFLOAT_SOURCES |
| 144 | 144 | "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/8086/f128M_isSignalingNaN.c" |
| 145 | "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/8086/extF80M_isSignalingNaN.c" | |
| 145 | 146 | "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/8086/s_commonNaNToF128M.c" |
| 147 | "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/8086/s_commonNaNToExtF80M.c" | |
| 146 | 148 | "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/8086/s_commonNaNToF16UI.c" |
| 147 | 149 | "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/8086/s_commonNaNToF32UI.c" |
| 148 | 150 | "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/8086/s_commonNaNToF64UI.c" |
| 149 | 151 | "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/8086/s_f128MToCommonNaN.c" |
| 152 | "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/8086/s_extF80MToCommonNaN.c" | |
| 150 | 153 | "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/8086/s_f16UIToCommonNaN.c" |
| 151 | 154 | "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/8086/s_f32UIToCommonNaN.c" |
| 152 | 155 | "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/8086/s_f64UIToCommonNaN.c" |
| 153 | 156 | "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/8086/s_propagateNaNF128M.c" |
| 157 | "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/8086/s_propagateNaNExtF80M.c" | |
| 154 | 158 | "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/8086/s_propagateNaNF16UI.c" |
| 155 | 159 | "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/8086/softfloat_raiseFlags.c" |
| 156 | 160 | "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f128M_add.c" |
| ... | ... | @@ -170,6 +174,7 @@ set(EMBEDDED_SOFTFLOAT_SOURCES |
| 170 | 174 | "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f128M_to_f16.c" |
| 171 | 175 | "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f128M_to_f32.c" |
| 172 | 176 | "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f128M_to_f64.c" |
| 177 | "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f128M_to_extF80M.c" | |
| 173 | 178 | "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f128M_to_i32.c" |
| 174 | 179 | "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f128M_to_i32_r_minMag.c" |
| 175 | 180 | "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f128M_to_i64.c" |
| ... | ... | @@ -178,6 +183,20 @@ set(EMBEDDED_SOFTFLOAT_SOURCES |
| 178 | 183 | "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f128M_to_ui32_r_minMag.c" |
| 179 | 184 | "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f128M_to_ui64.c" |
| 180 | 185 | "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f128M_to_ui64_r_minMag.c" |
| 186 | "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/extF80M_add.c" | |
| 187 | "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/extF80M_div.c" | |
| 188 | "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/extF80M_eq.c" | |
| 189 | "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/extF80M_le.c" | |
| 190 | "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/extF80M_lt.c" | |
| 191 | "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/extF80M_mul.c" | |
| 192 | "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/extF80M_rem.c" | |
| 193 | "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/extF80M_roundToInt.c" | |
| 194 | "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/extF80M_sqrt.c" | |
| 195 | "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/extF80M_sub.c" | |
| 196 | "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/extF80M_to_f16.c" | |
| 197 | "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/extF80M_to_f32.c" | |
| 198 | "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/extF80M_to_f64.c" | |
| 199 | "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/extF80M_to_f128M.c" | |
| 181 | 200 | "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f16_add.c" |
| 182 | 201 | "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f16_div.c" |
| 183 | 202 | "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f16_eq.c" |
| ... | ... | @@ -188,9 +207,12 @@ set(EMBEDDED_SOFTFLOAT_SOURCES |
| 188 | 207 | "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f16_roundToInt.c" |
| 189 | 208 | "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f16_sqrt.c" |
| 190 | 209 | "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f16_sub.c" |
| 210 | "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f16_to_extF80M.c" | |
| 191 | 211 | "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f16_to_f128M.c" |
| 192 | 212 | "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f16_to_f64.c" |
| 213 | "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f32_to_extF80M.c" | |
| 193 | 214 | "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f32_to_f128M.c" |
| 215 | "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f64_to_extF80M.c" | |
| 194 | 216 | "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f64_to_f128M.c" |
| 195 | 217 | "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f64_to_f16.c" |
| 196 | 218 | "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/i32_to_f128M.c" |
| ... | ... | @@ -198,6 +220,7 @@ set(EMBEDDED_SOFTFLOAT_SOURCES |
| 198 | 220 | "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_addCarryM.c" |
| 199 | 221 | "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_addComplCarryM.c" |
| 200 | 222 | "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_addF128M.c" |
| 223 | "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_addExtF80M.c" | |
| 201 | 224 | "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_addM.c" |
| 202 | 225 | "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_addMagsF16.c" |
| 203 | 226 | "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_addMagsF32.c" |
| ... | ... | @@ -208,12 +231,14 @@ set(EMBEDDED_SOFTFLOAT_SOURCES |
| 208 | 231 | "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_approxRecip_1Ks.c" |
| 209 | 232 | "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_compare128M.c" |
| 210 | 233 | "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_compare96M.c" |
| 234 | "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_compareNonnormExtF80M.c" | |
| 211 | 235 | "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_countLeadingZeros16.c" |
| 212 | 236 | "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_countLeadingZeros32.c" |
| 213 | 237 | "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_countLeadingZeros64.c" |
| 214 | 238 | "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_countLeadingZeros8.c" |
| 215 | 239 | "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_eq128.c" |
| 216 | 240 | "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_invalidF128M.c" |
| 241 | "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_invalidExtF80M.c" | |
| 217 | 242 | "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_isNaNF128M.c" |
| 218 | 243 | "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_le128.c" |
| 219 | 244 | "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_lt128.c" |
| ... | ... | @@ -224,7 +249,9 @@ set(EMBEDDED_SOFTFLOAT_SOURCES |
| 224 | 249 | "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_mulAddF32.c" |
| 225 | 250 | "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_mulAddF64.c" |
| 226 | 251 | "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_negXM.c" |
| 252 | "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_normExtF80SigM.c" | |
| 227 | 253 | "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_normRoundPackMToF128M.c" |
| 254 | "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_normRoundPackMToExtF80M.c" | |
| 228 | 255 | "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_normRoundPackToF16.c" |
| 229 | 256 | "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_normRoundPackToF32.c" |
| 230 | 257 | "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_normRoundPackToF64.c" |
| ... | ... | @@ -235,6 +262,7 @@ set(EMBEDDED_SOFTFLOAT_SOURCES |
| 235 | 262 | "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_remStepMBy32.c" |
| 236 | 263 | "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_roundMToI64.c" |
| 237 | 264 | "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_roundMToUI64.c" |
| 265 | "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_roundPackMToExtF80M.c" | |
| 238 | 266 | "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_roundPackMToF128M.c" |
| 239 | 267 | "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_roundPackToF16.c" |
| 240 | 268 | "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_roundPackToF32.c" |
| ... | ... | @@ -263,11 +291,14 @@ set(EMBEDDED_SOFTFLOAT_SOURCES |
| 263 | 291 | "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_subMagsF32.c" |
| 264 | 292 | "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_subMagsF64.c" |
| 265 | 293 | "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_tryPropagateNaNF128M.c" |
| 294 | "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_tryPropagateNaNExtF80M.c" | |
| 266 | 295 | "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f16_mulAdd.c" |
| 267 | 296 | "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f128M_mulAdd.c" |
| 268 | 297 | "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/softfloat_state.c" |
| 269 | 298 | "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/ui32_to_f128M.c" |
| 270 | 299 | "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/ui64_to_f128M.c" |
| 300 | "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/ui32_to_extF80M.c" | |
| 301 | "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/ui64_to_extF80M.c" | |
| 271 | 302 | ) |
| 272 | 303 | add_library(embedded_softfloat STATIC ${EMBEDDED_SOFTFLOAT_SOURCES}) |
| 273 | 304 | if(MSVC) |
doc/langref.html.in+6| ... | ... | @@ -737,6 +737,11 @@ pub fn main() void { |
| 737 | 737 | <td><code class="c">double</code></td> |
| 738 | 738 | <td>64-bit floating point (52-bit mantissa) IEEE-754-2008 binary64</td> |
| 739 | 739 | </tr> |
| 740 | <tr> | |
| 741 | <th scope="row">{#syntax#}f80{#endsyntax#}</th> | |
| 742 | <td><code class="c">double</code></td> | |
| 743 | <td>64-bit floating point (64-bit mantissa) IEEE-754-2008 80-bit extended precision</td> | |
| 744 | </tr> | |
| 740 | 745 | <tr> |
| 741 | 746 | <th scope="row">{#syntax#}f128{#endsyntax#}</th> |
| 742 | 747 | <td><code class="c">_Float128</code></td> |
| ... | ... | @@ -1500,6 +1505,7 @@ fn divide(a: i32, b: i32) i32 { |
| 1500 | 1505 | <li>{#syntax#}f16{#endsyntax#} - IEEE-754-2008 binary16</li> |
| 1501 | 1506 | <li>{#syntax#}f32{#endsyntax#} - IEEE-754-2008 binary32</li> |
| 1502 | 1507 | <li>{#syntax#}f64{#endsyntax#} - IEEE-754-2008 binary64</li> |
| 1508 | <li>{#syntax#}f80{#endsyntax#} - IEEE-754-2008 80-bit extended precision</li> | |
| 1503 | 1509 | <li>{#syntax#}f128{#endsyntax#} - IEEE-754-2008 binary128</li> |
| 1504 | 1510 | <li>{#syntax#}c_longdouble{#endsyntax#} - matches <code class="c">long double</code> for the target C ABI</li> |
| 1505 | 1511 | </ul> |
lib/std/math.zig+18| ... | ... | @@ -43,7 +43,21 @@ pub const f128_max = @bitCast(f128, @as(u128, 0x7FFEFFFFFFFFFFFFFFFFFFFFFFFFFFFF |
| 43 | 43 | pub const f128_epsilon = @bitCast(f128, @as(u128, 0x3F8F0000000000000000000000000000)); |
| 44 | 44 | pub const f128_toint = 1.0 / f128_epsilon; |
| 45 | 45 | |
| 46 | const F80Repr = if (@import("builtin").cpu.arch.endian() == .Little) extern struct { | |
| 47 | fraction: u64, | |
| 48 | exp: u16, | |
| 49 | } else extern struct { | |
| 50 | exp: u16, | |
| 51 | fraction: u64, | |
| 52 | }; | |
| 53 | ||
| 46 | 54 | // float.h details |
| 55 | pub const f80_true_min = @ptrCast(*const f80, &F80Repr{ .fraction = 1, .exp = 0 }).*; | |
| 56 | pub const f80_min = @ptrCast(*const f80, &F80Repr{ .fraction = 0x8000000000000000, .exp = 1 }).*; | |
| 57 | pub const f80_max = @ptrCast(*const f80, &F80Repr{ .fraction = 0xFFFFFFFFFFFFFFFF, .exp = 0x7FFE }).*; | |
| 58 | pub const f80_epsilon = @ptrCast(*const f80, &F80Repr{ .fraction = 0x8000000000000000, .exp = 0x3FC0 }).*; | |
| 59 | pub const f80_toint = 1.0 / f80_epsilon; | |
| 60 | ||
| 47 | 61 | pub const f64_true_min = 4.94065645841246544177e-324; |
| 48 | 62 | pub const f64_min = 2.2250738585072014e-308; |
| 49 | 63 | pub const f64_max = 1.79769313486231570815e+308; |
| ... | ... | @@ -91,6 +105,10 @@ pub const qnan_f64 = @bitCast(f64, qnan_u64); |
| 91 | 105 | pub const inf_u64 = @as(u64, 0x7FF << 52); |
| 92 | 106 | pub const inf_f64 = @bitCast(f64, inf_u64); |
| 93 | 107 | |
| 108 | pub const inf_f80 = @ptrCast(*const f80, &F80Repr{ .fraction = 0x8000000000000000, .exp = 0x7fff }).*; | |
| 109 | pub const nan_f80 = @ptrCast(*const f80, &F80Repr{ .fraction = 0xA000000000000000, .exp = 0x7fff }).*; | |
| 110 | pub const qnan_f80 = @ptrCast(*const f80, &F80Repr{ .fraction = 0xC000000000000000, .exp = 0x7fff }).*; | |
| 111 | ||
| 94 | 112 | pub const nan_u128 = @as(u128, 0x7fff0000000000000000000000000001); |
| 95 | 113 | pub const nan_f128 = @bitCast(f128, nan_u128); |
| 96 | 114 |
lib/std/math/epsilon.zig+1| ... | ... | @@ -8,6 +8,7 @@ pub fn epsilon(comptime T: type) T { |
| 8 | 8 | f16 => math.f16_epsilon, |
| 9 | 9 | f32 => math.f32_epsilon, |
| 10 | 10 | f64 => math.f64_epsilon, |
| 11 | f80 => math.f80_epsilon, | |
| 11 | 12 | f128 => math.f128_epsilon, |
| 12 | 13 | else => @compileError("epsilon not implemented for " ++ @typeName(T)), |
| 13 | 14 | }; |
lib/std/math/inf.zig+1| ... | ... | @@ -7,6 +7,7 @@ pub fn inf(comptime T: type) T { |
| 7 | 7 | f16 => math.inf_f16, |
| 8 | 8 | f32 => math.inf_f32, |
| 9 | 9 | f64 => math.inf_f64, |
| 10 | f80 => math.inf_f80, | |
| 10 | 11 | f128 => math.inf_f128, |
| 11 | 12 | else => @compileError("inf not implemented for " ++ @typeName(T)), |
| 12 | 13 | }; |
lib/std/math/nan.zig+3| ... | ... | @@ -6,6 +6,7 @@ pub fn nan(comptime T: type) T { |
| 6 | 6 | f16 => math.nan_f16, |
| 7 | 7 | f32 => math.nan_f32, |
| 8 | 8 | f64 => math.nan_f64, |
| 9 | f80 => math.nan_f80, | |
| 9 | 10 | f128 => math.nan_f128, |
| 10 | 11 | else => @compileError("nan not implemented for " ++ @typeName(T)), |
| 11 | 12 | }; |
| ... | ... | @@ -19,6 +20,8 @@ pub fn snan(comptime T: type) T { |
| 19 | 20 | f16 => @bitCast(f16, math.nan_u16), |
| 20 | 21 | f32 => @bitCast(f32, math.nan_u32), |
| 21 | 22 | f64 => @bitCast(f64, math.nan_u64), |
| 23 | f80 => @bitCast(f80, math.nan_u80), | |
| 24 | f128 => @bitCast(f128, math.nan_u128), | |
| 22 | 25 | else => @compileError("snan not implemented for " ++ @typeName(T)), |
| 23 | 26 | }; |
| 24 | 27 | } |
src/AstGen.zig+2| ... | ... | @@ -7723,6 +7723,7 @@ const primitives = std.ComptimeStringMap(Zir.Inst.Ref, .{ |
| 7723 | 7723 | .{ "f16", .f16_type }, |
| 7724 | 7724 | .{ "f32", .f32_type }, |
| 7725 | 7725 | .{ "f64", .f64_type }, |
| 7726 | .{ "f80", .f80_type }, | |
| 7726 | 7727 | .{ "false", .bool_false }, |
| 7727 | 7728 | .{ "i16", .i16_type }, |
| 7728 | 7729 | .{ "i32", .i32_type }, |
| ... | ... | @@ -8732,6 +8733,7 @@ fn rvalue( |
| 8732 | 8733 | as_ty | @enumToInt(Zir.Inst.Ref.f16_type), |
| 8733 | 8734 | as_ty | @enumToInt(Zir.Inst.Ref.f32_type), |
| 8734 | 8735 | as_ty | @enumToInt(Zir.Inst.Ref.f64_type), |
| 8736 | as_ty | @enumToInt(Zir.Inst.Ref.f80_type), | |
| 8735 | 8737 | as_ty | @enumToInt(Zir.Inst.Ref.f128_type), |
| 8736 | 8738 | as_ty | @enumToInt(Zir.Inst.Ref.anyopaque_type), |
| 8737 | 8739 | as_ty | @enumToInt(Zir.Inst.Ref.bool_type), |
src/Sema.zig+3| ... | ... | @@ -16950,6 +16950,7 @@ pub fn typeHasOnePossibleValue( |
| 16950 | 16950 | .f16, |
| 16951 | 16951 | .f32, |
| 16952 | 16952 | .f64, |
| 16953 | .f80, | |
| 16953 | 16954 | .f128, |
| 16954 | 16955 | .c_longdouble, |
| 16955 | 16956 | .comptime_int, |
| ... | ... | @@ -17227,6 +17228,7 @@ pub fn addType(sema: *Sema, ty: Type) !Air.Inst.Ref { |
| 17227 | 17228 | .f16 => return .f16_type, |
| 17228 | 17229 | .f32 => return .f32_type, |
| 17229 | 17230 | .f64 => return .f64_type, |
| 17231 | .f80 => return .f80_type, | |
| 17230 | 17232 | .f128 => return .f128_type, |
| 17231 | 17233 | .anyopaque => return .anyopaque_type, |
| 17232 | 17234 | .bool => return .bool_type, |
| ... | ... | @@ -17572,6 +17574,7 @@ fn typeRequiresComptime(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) C |
| 17572 | 17574 | .f16, |
| 17573 | 17575 | .f32, |
| 17574 | 17576 | .f64, |
| 17577 | .f80, | |
| 17575 | 17578 | .f128, |
| 17576 | 17579 | .anyopaque, |
| 17577 | 17580 | .bool, |
src/Zir.zig+5| ... | ... | @@ -1639,6 +1639,7 @@ pub const Inst = struct { |
| 1639 | 1639 | f16_type, |
| 1640 | 1640 | f32_type, |
| 1641 | 1641 | f64_type, |
| 1642 | f80_type, | |
| 1642 | 1643 | f128_type, |
| 1643 | 1644 | anyopaque_type, |
| 1644 | 1645 | bool_type, |
| ... | ... | @@ -1809,6 +1810,10 @@ pub const Inst = struct { |
| 1809 | 1810 | .ty = Type.initTag(.type), |
| 1810 | 1811 | .val = Value.initTag(.f64_type), |
| 1811 | 1812 | }, |
| 1813 | .f80_type = .{ | |
| 1814 | .ty = Type.initTag(.type), | |
| 1815 | .val = Value.initTag(.f80_type), | |
| 1816 | }, | |
| 1812 | 1817 | .f128_type = .{ |
| 1813 | 1818 | .ty = Type.initTag(.type), |
| 1814 | 1819 | .val = Value.initTag(.f128_type), |
src/stage1/all_types.hpp+2| ... | ... | @@ -516,6 +516,7 @@ struct ZigValue { |
| 516 | 516 | float16_t x_f16; |
| 517 | 517 | float x_f32; |
| 518 | 518 | double x_f64; |
| 519 | extFloat80_t x_f80; | |
| 519 | 520 | float128_t x_f128; |
| 520 | 521 | bool x_bool; |
| 521 | 522 | ConstBoundFnValue x_bound_fn; |
| ... | ... | @@ -2089,6 +2090,7 @@ struct CodeGen { |
| 2089 | 2090 | ZigType *entry_f16; |
| 2090 | 2091 | ZigType *entry_f32; |
| 2091 | 2092 | ZigType *entry_f64; |
| 2093 | ZigType *entry_f80; | |
| 2092 | 2094 | ZigType *entry_f128; |
| 2093 | 2095 | ZigType *entry_void; |
| 2094 | 2096 | ZigType *entry_unreachable; |
src/stage1/analyze.cpp+13| ... | ... | @@ -5647,6 +5647,9 @@ static uint32_t hash_combine_const_val(uint32_t hash_val, ZigValue *const_val) { |
| 5647 | 5647 | case 16: return hash_combine(hash_val, &const_val->data.x_f16); |
| 5648 | 5648 | case 32: return hash_combine(hash_val, &const_val->data.x_f32); |
| 5649 | 5649 | case 64: return hash_combine(hash_val, &const_val->data.x_f64); |
| 5650 | case 80: | |
| 5651 | hash_val = hash_combine(hash_val, &const_val->data.x_f80.signExp); | |
| 5652 | return hash_combine(hash_val, &const_val->data.x_f80.signif); | |
| 5650 | 5653 | case 128: return hash_combine(hash_val, &const_val->data.x_f128); |
| 5651 | 5654 | default: zig_unreachable(); |
| 5652 | 5655 | } |
| ... | ... | @@ -6325,6 +6328,7 @@ void init_const_float(ZigValue *const_val, ZigType *type, double value) { |
| 6325 | 6328 | case 64: |
| 6326 | 6329 | const_val->data.x_f64 = value; |
| 6327 | 6330 | break; |
| 6331 | case 80: | |
| 6328 | 6332 | case 128: |
| 6329 | 6333 | // if we need this, we should add a function that accepts a float128_t param |
| 6330 | 6334 | zig_unreachable(); |
| ... | ... | @@ -7218,6 +7222,8 @@ bool const_values_equal(CodeGen *g, ZigValue *a, ZigValue *b) { |
| 7218 | 7222 | return a->data.x_f32 == b->data.x_f32; |
| 7219 | 7223 | case 64: |
| 7220 | 7224 | return a->data.x_f64 == b->data.x_f64; |
| 7225 | case 80: | |
| 7226 | return extF80M_eq(&a->data.x_f80, &b->data.x_f80); | |
| 7221 | 7227 | case 128: |
| 7222 | 7228 | return f128M_eq(&a->data.x_f128, &b->data.x_f128); |
| 7223 | 7229 | default: |
| ... | ... | @@ -7470,6 +7476,13 @@ void render_const_value(CodeGen *g, Buf *buf, ZigValue *const_val) { |
| 7470 | 7476 | case 64: |
| 7471 | 7477 | buf_appendf(buf, "%f", const_val->data.x_f64); |
| 7472 | 7478 | return; |
| 7479 | case 80: { | |
| 7480 | float64_t f64_value = extF80M_to_f64(&const_val->data.x_f80); | |
| 7481 | double double_value; | |
| 7482 | memcpy(&double_value, &f64_value, sizeof(double)); | |
| 7483 | buf_appendf(buf, "%f", double_value); | |
| 7484 | return; | |
| 7485 | } | |
| 7473 | 7486 | case 128: |
| 7474 | 7487 | { |
| 7475 | 7488 | const size_t extra_len = 100; |
src/stage1/codegen.cpp+444-12| ... | ... | @@ -1598,6 +1598,81 @@ static LLVMValueRef gen_assert_zero(CodeGen *g, LLVMValueRef expr_val, ZigType * |
| 1598 | 1598 | return nullptr; |
| 1599 | 1599 | } |
| 1600 | 1600 | |
| 1601 | ||
| 1602 | static LLVMValueRef gen_soft_f80_widen_or_shorten(CodeGen *g, ZigType *actual_type, | |
| 1603 | ZigType *wanted_type, LLVMValueRef expr_val) | |
| 1604 | { | |
| 1605 | ZigType *scalar_actual_type = (actual_type->id == ZigTypeIdVector) ? | |
| 1606 | actual_type->data.vector.elem_type : actual_type; | |
| 1607 | ZigType *scalar_wanted_type = (wanted_type->id == ZigTypeIdVector) ? | |
| 1608 | wanted_type->data.vector.elem_type : wanted_type; | |
| 1609 | uint64_t actual_bits = scalar_actual_type->data.floating.bit_count; | |
| 1610 | uint64_t wanted_bits = scalar_wanted_type->data.floating.bit_count; | |
| 1611 | ||
| 1612 | ||
| 1613 | LLVMTypeRef param_type; | |
| 1614 | LLVMTypeRef return_type; | |
| 1615 | const char *func_name; | |
| 1616 | ||
| 1617 | if (actual_bits == wanted_bits) { | |
| 1618 | return expr_val; | |
| 1619 | } else if (actual_bits == 80) { | |
| 1620 | param_type = g->builtin_types.entry_f80->llvm_type; | |
| 1621 | switch (wanted_bits) { | |
| 1622 | case 16: | |
| 1623 | return_type = g->builtin_types.entry_f16->llvm_type; | |
| 1624 | func_name = "__truncxfhf2"; | |
| 1625 | break; | |
| 1626 | case 32: | |
| 1627 | return_type = g->builtin_types.entry_f32->llvm_type; | |
| 1628 | func_name = "__truncxfff2"; | |
| 1629 | break; | |
| 1630 | case 64: | |
| 1631 | return_type = g->builtin_types.entry_f64->llvm_type; | |
| 1632 | func_name = "__truncxfdf2"; | |
| 1633 | break; | |
| 1634 | case 128: | |
| 1635 | return_type = g->builtin_types.entry_f128->llvm_type; | |
| 1636 | func_name = "__extendxftf2"; | |
| 1637 | break; | |
| 1638 | default: | |
| 1639 | zig_unreachable(); | |
| 1640 | } | |
| 1641 | } else if (wanted_bits == 80) { | |
| 1642 | return_type = g->builtin_types.entry_f80->llvm_type; | |
| 1643 | switch (actual_bits) { | |
| 1644 | case 16: | |
| 1645 | param_type = g->builtin_types.entry_f16->llvm_type; | |
| 1646 | func_name = "__extendhfxf2"; | |
| 1647 | break; | |
| 1648 | case 32: | |
| 1649 | param_type = g->builtin_types.entry_f32->llvm_type; | |
| 1650 | func_name = "__extendffxf2"; | |
| 1651 | break; | |
| 1652 | case 64: | |
| 1653 | param_type = g->builtin_types.entry_f64->llvm_type; | |
| 1654 | func_name = "__extenddfxf2"; | |
| 1655 | break; | |
| 1656 | case 128: | |
| 1657 | param_type = g->builtin_types.entry_f128->llvm_type; | |
| 1658 | func_name = "__trunctfxf2"; | |
| 1659 | break; | |
| 1660 | default: | |
| 1661 | zig_unreachable(); | |
| 1662 | } | |
| 1663 | } else { | |
| 1664 | zig_unreachable(); | |
| 1665 | } | |
| 1666 | ||
| 1667 | LLVMValueRef func_ref = LLVMGetNamedFunction(g->module, func_name); | |
| 1668 | if (func_ref == nullptr) { | |
| 1669 | LLVMTypeRef fn_type = LLVMFunctionType(return_type, &param_type, 1, false); | |
| 1670 | func_ref = LLVMAddFunction(g->module, func_name, fn_type); | |
| 1671 | } | |
| 1672 | ||
| 1673 | return LLVMBuildCall(g->builder, func_ref, &expr_val, 1, ""); | |
| 1674 | } | |
| 1675 | ||
| 1601 | 1676 | static LLVMValueRef gen_widen_or_shorten(CodeGen *g, bool want_runtime_safety, ZigType *actual_type, |
| 1602 | 1677 | ZigType *wanted_type, LLVMValueRef expr_val) |
| 1603 | 1678 | { |
| ... | ... | @@ -1612,6 +1687,13 @@ static LLVMValueRef gen_widen_or_shorten(CodeGen *g, bool want_runtime_safety, Z |
| 1612 | 1687 | uint64_t actual_bits; |
| 1613 | 1688 | uint64_t wanted_bits; |
| 1614 | 1689 | if (scalar_actual_type->id == ZigTypeIdFloat) { |
| 1690 | ||
| 1691 | if ((scalar_actual_type == g->builtin_types.entry_f80 | |
| 1692 | || scalar_wanted_type == g->builtin_types.entry_f80) | |
| 1693 | && !target_has_f80(g->zig_target)) | |
| 1694 | { | |
| 1695 | return gen_soft_f80_widen_or_shorten(g, actual_type, wanted_type, expr_val); | |
| 1696 | } | |
| 1615 | 1697 | actual_bits = scalar_actual_type->data.floating.bit_count; |
| 1616 | 1698 | wanted_bits = scalar_wanted_type->data.floating.bit_count; |
| 1617 | 1699 | } else if (scalar_actual_type->id == ZigTypeIdInt) { |
| ... | ... | @@ -3142,6 +3224,187 @@ static void gen_shift_rhs_check(CodeGen *g, ZigType *lhs_type, ZigType *rhs_type |
| 3142 | 3224 | } |
| 3143 | 3225 | } |
| 3144 | 3226 | |
| 3227 | static LLVMValueRef get_soft_f80_bin_op_func(CodeGen *g, const char *name, int param_count, LLVMTypeRef return_type) { | |
| 3228 | LLVMValueRef existing_llvm_fn = LLVMGetNamedFunction(g->module, name); | |
| 3229 | if (existing_llvm_fn != nullptr) return existing_llvm_fn; | |
| 3230 | ||
| 3231 | LLVMTypeRef float_type_ref = g->builtin_types.entry_f80->llvm_type; | |
| 3232 | LLVMTypeRef param_types[2] = { float_type_ref, float_type_ref }; | |
| 3233 | LLVMTypeRef fn_type = LLVMFunctionType(return_type, param_types, param_count, false); | |
| 3234 | return LLVMAddFunction(g->module, name, fn_type); | |
| 3235 | } | |
| 3236 | ||
| 3237 | static LLVMValueRef ir_render_soft_f80_bin_op(CodeGen *g, Stage1Air *executable, | |
| 3238 | Stage1AirInstBinOp *bin_op_instruction) | |
| 3239 | { | |
| 3240 | IrBinOp op_id = bin_op_instruction->op_id; | |
| 3241 | Stage1AirInst *op1 = bin_op_instruction->op1; | |
| 3242 | Stage1AirInst *op2 = bin_op_instruction->op2; | |
| 3243 | uint32_t vector_len = op1->value->type->id == ZigTypeIdVector ? op1->value->type->data.vector.len : 0; | |
| 3244 | ||
| 3245 | LLVMValueRef op1_value = ir_llvm_value(g, op1); | |
| 3246 | LLVMValueRef op2_value = ir_llvm_value(g, op2); | |
| 3247 | ||
| 3248 | bool div_exact_safety_check = false; | |
| 3249 | LLVMTypeRef return_type = g->builtin_types.entry_f80->llvm_type; | |
| 3250 | int param_count = 2; | |
| 3251 | const char *func_name; | |
| 3252 | switch (op_id) { | |
| 3253 | case IrBinOpInvalid: | |
| 3254 | case IrBinOpArrayCat: | |
| 3255 | case IrBinOpArrayMult: | |
| 3256 | case IrBinOpRemUnspecified: | |
| 3257 | case IrBinOpBitShiftLeftLossy: | |
| 3258 | case IrBinOpBitShiftLeftExact: | |
| 3259 | case IrBinOpBitShiftRightLossy: | |
| 3260 | case IrBinOpBitShiftRightExact: | |
| 3261 | case IrBinOpBoolOr: | |
| 3262 | case IrBinOpBoolAnd: | |
| 3263 | case IrBinOpMultWrap: | |
| 3264 | case IrBinOpAddWrap: | |
| 3265 | case IrBinOpSubWrap: | |
| 3266 | case IrBinOpBinOr: | |
| 3267 | case IrBinOpBinXor: | |
| 3268 | case IrBinOpBinAnd: | |
| 3269 | case IrBinOpAddSat: | |
| 3270 | case IrBinOpSubSat: | |
| 3271 | case IrBinOpMultSat: | |
| 3272 | case IrBinOpShlSat: | |
| 3273 | zig_unreachable(); | |
| 3274 | case IrBinOpCmpEq: | |
| 3275 | return_type = g->builtin_types.entry_i32->llvm_type; | |
| 3276 | func_name = "__eqxf2"; | |
| 3277 | break; | |
| 3278 | case IrBinOpCmpNotEq: | |
| 3279 | return_type = g->builtin_types.entry_i32->llvm_type; | |
| 3280 | func_name = "__nexf2"; | |
| 3281 | break; | |
| 3282 | case IrBinOpCmpLessOrEq: | |
| 3283 | case IrBinOpCmpLessThan: | |
| 3284 | return_type = g->builtin_types.entry_i32->llvm_type; | |
| 3285 | func_name = "__lexf2"; | |
| 3286 | break; | |
| 3287 | case IrBinOpCmpGreaterOrEq: | |
| 3288 | case IrBinOpCmpGreaterThan: | |
| 3289 | return_type = g->builtin_types.entry_i32->llvm_type; | |
| 3290 | func_name = "__gexf2"; | |
| 3291 | break; | |
| 3292 | case IrBinOpMaximum: | |
| 3293 | func_name = "__fmaxx"; | |
| 3294 | break; | |
| 3295 | case IrBinOpMinimum: | |
| 3296 | func_name = "__fminx"; | |
| 3297 | break; | |
| 3298 | case IrBinOpMult: | |
| 3299 | func_name = "__mulxf3"; | |
| 3300 | break; | |
| 3301 | case IrBinOpAdd: | |
| 3302 | func_name = "__addxf3"; | |
| 3303 | break; | |
| 3304 | case IrBinOpSub: | |
| 3305 | func_name = "__subxf3"; | |
| 3306 | break; | |
| 3307 | case IrBinOpDivUnspecified: | |
| 3308 | func_name = "__divxf3"; | |
| 3309 | break; | |
| 3310 | case IrBinOpDivExact: | |
| 3311 | func_name = "__divxf3"; | |
| 3312 | div_exact_safety_check = bin_op_instruction->safety_check_on && | |
| 3313 | ir_want_runtime_safety(g, &bin_op_instruction->base); | |
| 3314 | break; | |
| 3315 | case IrBinOpDivTrunc: | |
| 3316 | param_count = 1; | |
| 3317 | func_name = "__truncx"; | |
| 3318 | break; | |
| 3319 | case IrBinOpDivFloor: | |
| 3320 | param_count = 1; | |
| 3321 | func_name = "__floorx"; | |
| 3322 | break; | |
| 3323 | case IrBinOpRemRem: | |
| 3324 | param_count = 1; | |
| 3325 | func_name = "__remx"; | |
| 3326 | break; | |
| 3327 | case IrBinOpRemMod: | |
| 3328 | param_count = 1; | |
| 3329 | func_name = "__modx"; | |
| 3330 | break; | |
| 3331 | default: | |
| 3332 | zig_unreachable(); | |
| 3333 | } | |
| 3334 | ||
| 3335 | LLVMValueRef func_ref = get_soft_f80_bin_op_func(g, func_name, param_count, return_type); | |
| 3336 | ||
| 3337 | LLVMValueRef result; | |
| 3338 | if (vector_len == 0) { | |
| 3339 | LLVMValueRef params[2] = {op1_value, op2_value}; | |
| 3340 | result = LLVMBuildCall(g->builder, func_ref, params, param_count, ""); | |
| 3341 | } else { | |
| 3342 | result = build_alloca(g, op1->value->type, "", 0); | |
| 3343 | } | |
| 3344 | ||
| 3345 | LLVMTypeRef usize_ref = g->builtin_types.entry_usize->llvm_type; | |
| 3346 | for (uint32_t i = 0; i < vector_len; i++) { | |
| 3347 | LLVMValueRef index_value = LLVMConstInt(usize_ref, i, false); | |
| 3348 | LLVMValueRef params[2] = { | |
| 3349 | LLVMBuildExtractElement(g->builder, op1_value, index_value, ""), | |
| 3350 | LLVMBuildExtractElement(g->builder, op2_value, index_value, ""), | |
| 3351 | }; | |
| 3352 | LLVMValueRef call_result = LLVMBuildCall(g->builder, func_ref, params, param_count, ""); | |
| 3353 | LLVMBuildInsertElement(g->builder, LLVMBuildLoad(g->builder, result, ""), | |
| 3354 | call_result, index_value, ""); | |
| 3355 | } | |
| 3356 | ||
| 3357 | if (div_exact_safety_check) { | |
| 3358 | // Safety check: a / b == floor(a / b) | |
| 3359 | LLVMValueRef floor_func = get_soft_f80_bin_op_func(g, "__floorx", 1, return_type); | |
| 3360 | LLVMValueRef eq_func = get_soft_f80_bin_op_func(g, "__eqxf2", 2, g->builtin_types.entry_i32->llvm_type); | |
| 3361 | ||
| 3362 | LLVMValueRef ok_bit; | |
| 3363 | if (vector_len == 0) { | |
| 3364 | LLVMValueRef floored = LLVMBuildCall(g->builder, floor_func, &result, 1, ""); | |
| 3365 | ||
| 3366 | LLVMValueRef params[2] = {result, floored}; | |
| 3367 | ok_bit = LLVMBuildCall(g->builder, eq_func, params, 2, ""); | |
| 3368 | } else { | |
| 3369 | ZigType *bool_vec_ty = get_vector_type(g, vector_len, g->builtin_types.entry_bool); | |
| 3370 | ok_bit = build_alloca(g, bool_vec_ty, "", 0); | |
| 3371 | } | |
| 3372 | ||
| 3373 | for (uint32_t i = 0; i < vector_len; i++) { | |
| 3374 | LLVMValueRef index_value = LLVMConstInt(usize_ref, i, false); | |
| 3375 | LLVMValueRef div_res = LLVMBuildExtractElement(g->builder, | |
| 3376 | LLVMBuildLoad(g->builder, result, ""), index_value, ""); | |
| 3377 | ||
| 3378 | LLVMValueRef params[2] = { | |
| 3379 | div_res, | |
| 3380 | LLVMBuildCall(g->builder, floor_func, &div_res, 1, ""), | |
| 3381 | }; | |
| 3382 | LLVMValueRef cmp_res = LLVMBuildCall(g->builder, eq_func, params, 2, ""); | |
| 3383 | cmp_res = LLVMBuildTrunc(g->builder, cmp_res, g->builtin_types.entry_bool->llvm_type, ""); | |
| 3384 | LLVMBuildInsertElement(g->builder, LLVMBuildLoad(g->builder, ok_bit, ""), | |
| 3385 | cmp_res, index_value, ""); | |
| 3386 | } | |
| 3387 | ||
| 3388 | if (vector_len != 0) { | |
| 3389 | ok_bit = ZigLLVMBuildAndReduce(g->builder, LLVMBuildLoad(g->builder, ok_bit, "")); | |
| 3390 | } | |
| 3391 | LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "DivExactOk"); | |
| 3392 | LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "DivExactFail"); | |
| 3393 | ||
| 3394 | LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block); | |
| 3395 | ||
| 3396 | LLVMPositionBuilderAtEnd(g->builder, fail_block); | |
| 3397 | gen_safety_crash(g, PanicMsgIdExactDivisionRemainder); | |
| 3398 | ||
| 3399 | LLVMPositionBuilderAtEnd(g->builder, ok_block); | |
| 3400 | } | |
| 3401 | ||
| 3402 | if (vector_len != 0) { | |
| 3403 | result = LLVMBuildLoad(g->builder, result, ""); | |
| 3404 | } | |
| 3405 | return result; | |
| 3406 | } | |
| 3407 | ||
| 3145 | 3408 | static LLVMValueRef ir_render_bin_op(CodeGen *g, Stage1Air *executable, |
| 3146 | 3409 | Stage1AirInstBinOp *bin_op_instruction) |
| 3147 | 3410 | { |
| ... | ... | @@ -3151,6 +3414,10 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, Stage1Air *executable, |
| 3151 | 3414 | |
| 3152 | 3415 | ZigType *operand_type = op1->value->type; |
| 3153 | 3416 | ZigType *scalar_type = (operand_type->id == ZigTypeIdVector) ? operand_type->data.vector.elem_type : operand_type; |
| 3417 | if (scalar_type == g->builtin_types.entry_f80 && !target_has_f80(g->zig_target)) { | |
| 3418 | return ir_render_soft_f80_bin_op(g, executable, bin_op_instruction); | |
| 3419 | } | |
| 3420 | ||
| 3154 | 3421 | |
| 3155 | 3422 | bool want_runtime_safety = bin_op_instruction->safety_check_on && |
| 3156 | 3423 | ir_want_runtime_safety(g, &bin_op_instruction->base); |
| ... | ... | @@ -3158,7 +3425,6 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, Stage1Air *executable, |
| 3158 | 3425 | LLVMValueRef op1_value = ir_llvm_value(g, op1); |
| 3159 | 3426 | LLVMValueRef op2_value = ir_llvm_value(g, op2); |
| 3160 | 3427 | |
| 3161 | ||
| 3162 | 3428 | switch (op_id) { |
| 3163 | 3429 | case IrBinOpInvalid: |
| 3164 | 3430 | case IrBinOpArrayCat: |
| ... | ... | @@ -5927,7 +6193,7 @@ static LLVMValueRef ir_render_prefetch(CodeGen *g, Stage1Air *executable, Stage1 |
| 5927 | 6193 | static_assert(PrefetchCacheInstruction == 0, ""); |
| 5928 | 6194 | static_assert(PrefetchCacheData == 1, ""); |
| 5929 | 6195 | assert(instruction->cache == PrefetchCacheData || instruction->cache == PrefetchCacheInstruction); |
| 5930 | ||
| 6196 | ||
| 5931 | 6197 | // LLVM fails during codegen of instruction cache prefetchs for these architectures. |
| 5932 | 6198 | // This is an LLVM bug as the prefetch intrinsic should be a noop if not supported by the target. |
| 5933 | 6199 | // To work around this, simply don't emit llvm.prefetch in this case. |
| ... | ... | @@ -6622,13 +6888,148 @@ static LLVMValueRef ir_render_atomic_store(CodeGen *g, Stage1Air *executable, |
| 6622 | 6888 | return nullptr; |
| 6623 | 6889 | } |
| 6624 | 6890 | |
| 6891 | static LLVMValueRef ir_render_soft_f80_float_op(CodeGen *g, Stage1Air *executable, Stage1AirInstFloatOp *instruction) { | |
| 6892 | ZigType *op_type = instruction->operand->value->type; | |
| 6893 | uint32_t vector_len = op_type->id == ZigTypeIdVector ? op_type->data.vector.len : 0; | |
| 6894 | ||
| 6895 | const char *func_name; | |
| 6896 | switch (instruction->fn_id) { | |
| 6897 | case BuiltinFnIdSqrt: | |
| 6898 | func_name = "__sqrt"; | |
| 6899 | break; | |
| 6900 | case BuiltinFnIdSin: | |
| 6901 | func_name = "__sinx"; | |
| 6902 | break; | |
| 6903 | case BuiltinFnIdCos: | |
| 6904 | func_name = "__cosx"; | |
| 6905 | break; | |
| 6906 | case BuiltinFnIdExp: | |
| 6907 | func_name = "__expx"; | |
| 6908 | break; | |
| 6909 | case BuiltinFnIdExp2: | |
| 6910 | func_name = "__exp2x"; | |
| 6911 | break; | |
| 6912 | case BuiltinFnIdLog: | |
| 6913 | func_name = "__logx"; | |
| 6914 | break; | |
| 6915 | case BuiltinFnIdLog2: | |
| 6916 | func_name = "__log2x"; | |
| 6917 | break; | |
| 6918 | case BuiltinFnIdLog10: | |
| 6919 | func_name = "__log10x"; | |
| 6920 | break; | |
| 6921 | case BuiltinFnIdFabs: | |
| 6922 | func_name = "__fabsx"; | |
| 6923 | break; | |
| 6924 | case BuiltinFnIdFloor: | |
| 6925 | func_name = "__floorx"; | |
| 6926 | break; | |
| 6927 | case BuiltinFnIdCeil: | |
| 6928 | func_name = "__ceilx"; | |
| 6929 | break; | |
| 6930 | case BuiltinFnIdTrunc: | |
| 6931 | func_name = "__truncx"; | |
| 6932 | break; | |
| 6933 | case BuiltinFnIdNearbyInt: | |
| 6934 | func_name = "__nearbyintx"; | |
| 6935 | break; | |
| 6936 | case BuiltinFnIdRound: | |
| 6937 | func_name = "__roundx"; | |
| 6938 | break; | |
| 6939 | default: | |
| 6940 | zig_unreachable(); | |
| 6941 | } | |
| 6942 | ||
| 6943 | ||
| 6944 | LLVMValueRef func_ref = LLVMGetNamedFunction(g->module, func_name); | |
| 6945 | if (func_ref == nullptr) { | |
| 6946 | LLVMTypeRef f80_ref = g->builtin_types.entry_f80->llvm_type; | |
| 6947 | LLVMTypeRef fn_type = LLVMFunctionType(f80_ref, &f80_ref, 1, false); | |
| 6948 | func_ref = LLVMAddFunction(g->module, func_name, fn_type); | |
| 6949 | } | |
| 6950 | ||
| 6951 | LLVMValueRef operand = ir_llvm_value(g, instruction->operand); | |
| 6952 | LLVMValueRef result; | |
| 6953 | if (vector_len == 0) { | |
| 6954 | result = LLVMBuildCall(g->builder, func_ref, &operand, 1, ""); | |
| 6955 | } else { | |
| 6956 | result = build_alloca(g, instruction->operand->value->type, "", 0); | |
| 6957 | } | |
| 6958 | ||
| 6959 | LLVMTypeRef usize_ref = g->builtin_types.entry_usize->llvm_type; | |
| 6960 | for (uint32_t i = 0; i < vector_len; i++) { | |
| 6961 | LLVMValueRef index_value = LLVMConstInt(usize_ref, i, false); | |
| 6962 | LLVMValueRef param = LLVMBuildExtractElement(g->builder, operand, index_value, ""); | |
| 6963 | LLVMValueRef call_result = LLVMBuildCall(g->builder, func_ref, &param, 1, ""); | |
| 6964 | LLVMBuildInsertElement(g->builder, LLVMBuildLoad(g->builder, result, ""), | |
| 6965 | call_result, index_value, ""); | |
| 6966 | } | |
| 6967 | if (vector_len != 0) { | |
| 6968 | result = LLVMBuildLoad(g->builder, result, ""); | |
| 6969 | } | |
| 6970 | return result; | |
| 6971 | } | |
| 6972 | ||
| 6625 | 6973 | static LLVMValueRef ir_render_float_op(CodeGen *g, Stage1Air *executable, Stage1AirInstFloatOp *instruction) { |
| 6974 | ZigType *op_type = instruction->operand->value->type; | |
| 6975 | op_type = op_type->id == ZigTypeIdVector ? op_type->data.vector.elem_type : op_type; | |
| 6976 | if (op_type == g->builtin_types.entry_f80 && !target_has_f80(g->zig_target)) { | |
| 6977 | return ir_render_soft_f80_float_op(g, executable, instruction); | |
| 6978 | } | |
| 6626 | 6979 | LLVMValueRef operand = ir_llvm_value(g, instruction->operand); |
| 6627 | 6980 | LLVMValueRef fn_val = get_float_fn(g, instruction->base.value->type, ZigLLVMFnIdFloatOp, instruction->fn_id); |
| 6628 | 6981 | return LLVMBuildCall(g->builder, fn_val, &operand, 1, ""); |
| 6629 | 6982 | } |
| 6630 | 6983 | |
| 6984 | static LLVMValueRef ir_render_soft_f80_mul_add(CodeGen *g, Stage1Air *executable, Stage1AirInstMulAdd *instruction) { | |
| 6985 | ZigType *op_type = instruction->op1->value->type; | |
| 6986 | uint32_t vector_len = op_type->id == ZigTypeIdVector ? op_type->data.vector.len : 0; | |
| 6987 | ||
| 6988 | const char *func_name = "__fmax"; | |
| 6989 | LLVMValueRef func_ref = LLVMGetNamedFunction(g->module, func_name); | |
| 6990 | if (func_ref == nullptr) { | |
| 6991 | LLVMTypeRef f80_ref = g->builtin_types.entry_f80->llvm_type; | |
| 6992 | LLVMTypeRef params[3] = { f80_ref, f80_ref, f80_ref }; | |
| 6993 | LLVMTypeRef fn_type = LLVMFunctionType(f80_ref, params, 3, false); | |
| 6994 | func_ref = LLVMAddFunction(g->module, func_name, fn_type); | |
| 6995 | } | |
| 6996 | ||
| 6997 | LLVMValueRef op1 = ir_llvm_value(g, instruction->op1); | |
| 6998 | LLVMValueRef op2 = ir_llvm_value(g, instruction->op2); | |
| 6999 | LLVMValueRef op3 = ir_llvm_value(g, instruction->op3); | |
| 7000 | LLVMValueRef result; | |
| 7001 | if (vector_len == 0) { | |
| 7002 | LLVMValueRef params[3] = { op1, op2, op3 }; | |
| 7003 | result = LLVMBuildCall(g->builder, func_ref, params, 3, ""); | |
| 7004 | } else { | |
| 7005 | result = build_alloca(g, instruction->op1->value->type, "", 0); | |
| 7006 | } | |
| 7007 | ||
| 7008 | LLVMTypeRef usize_ref = g->builtin_types.entry_usize->llvm_type; | |
| 7009 | for (uint32_t i = 0; i < vector_len; i++) { | |
| 7010 | LLVMValueRef index_value = LLVMConstInt(usize_ref, i, false); | |
| 7011 | ||
| 7012 | LLVMValueRef params[3] = { | |
| 7013 | LLVMBuildExtractElement(g->builder, op1, index_value, ""), | |
| 7014 | LLVMBuildExtractElement(g->builder, op2, index_value, ""), | |
| 7015 | LLVMBuildExtractElement(g->builder, op3, index_value, ""), | |
| 7016 | }; | |
| 7017 | LLVMValueRef call_result = LLVMBuildCall(g->builder, func_ref, params, 3, ""); | |
| 7018 | LLVMBuildInsertElement(g->builder, LLVMBuildLoad(g->builder, result, ""), | |
| 7019 | call_result, index_value, ""); | |
| 7020 | } | |
| 7021 | if (vector_len != 0) { | |
| 7022 | result = LLVMBuildLoad(g->builder, result, ""); | |
| 7023 | } | |
| 7024 | return result; | |
| 7025 | } | |
| 7026 | ||
| 6631 | 7027 | static LLVMValueRef ir_render_mul_add(CodeGen *g, Stage1Air *executable, Stage1AirInstMulAdd *instruction) { |
| 7028 | ZigType *op_type = instruction->op1->value->type; | |
| 7029 | op_type = op_type->id == ZigTypeIdVector ? op_type->data.vector.elem_type : op_type; | |
| 7030 | if (op_type == g->builtin_types.entry_f80 && !target_has_f80(g->zig_target)) { | |
| 7031 | return ir_render_soft_f80_mul_add(g, executable, instruction); | |
| 7032 | } | |
| 6632 | 7033 | LLVMValueRef op1 = ir_llvm_value(g, instruction->op1); |
| 6633 | 7034 | LLVMValueRef op2 = ir_llvm_value(g, instruction->op2); |
| 6634 | 7035 | LLVMValueRef op3 = ir_llvm_value(g, instruction->op3); |
| ... | ... | @@ -7692,20 +8093,33 @@ static LLVMValueRef gen_const_val(CodeGen *g, ZigValue *const_val, const char *n |
| 7692 | 8093 | return LLVMConstReal(get_llvm_type(g, type_entry), const_val->data.x_f32); |
| 7693 | 8094 | case 64: |
| 7694 | 8095 | return LLVMConstReal(get_llvm_type(g, type_entry), const_val->data.x_f64); |
| 8096 | case 80: { | |
| 8097 | uint64_t buf[2]; | |
| 8098 | memcpy(&buf, &const_val->data.x_f80, 16); | |
| 8099 | #if ZIG_BYTE_ORDER == ZIG_BIG_ENDIAN | |
| 8100 | uint64_t tmp = buf[0]; | |
| 8101 | buf[0] = buf[1]; | |
| 8102 | buf[1] = tmp; | |
| 8103 | #endif | |
| 8104 | LLVMValueRef as_i128 = LLVMConstIntOfArbitraryPrecision(LLVMInt128Type(), 2, buf); | |
| 8105 | LLVMValueRef as_int = LLVMConstTrunc(as_i128, LLVMIntType(80)); | |
| 8106 | return LLVMConstBitCast(as_int, get_llvm_type(g, type_entry)); | |
| 8107 | } | |
| 7695 | 8108 | case 128: |
| 7696 | 8109 | { |
| 7697 | 8110 | uint64_t buf[2]; |
| 7698 | 8111 | |
| 7699 | // LLVM seems to require that the lower half of the f128 be placed first in the buffer. | |
| 7700 | #if defined(ZIG_BYTE_ORDER) && ZIG_BYTE_ORDER == ZIG_LITTLE_ENDIAN | |
| 7701 | buf[0] = const_val->data.x_f128.v[0]; | |
| 7702 | buf[1] = const_val->data.x_f128.v[1]; | |
| 7703 | #elif defined(ZIG_BYTE_ORDER) && ZIG_BYTE_ORDER == ZIG_BIG_ENDIAN | |
| 7704 | buf[0] = const_val->data.x_f128.v[1]; | |
| 7705 | buf[1] = const_val->data.x_f128.v[0]; | |
| 7706 | #else | |
| 7707 | #error Unsupported endian | |
| 7708 | #endif | |
| 8112 | // LLVM seems to require that the lower half of the f128 be | |
| 8113 | // placed first in the buffer. | |
| 8114 | #if ZIG_BYTE_ORDER == ZIG_LITTLE_ENDIAN | |
| 8115 | buf[0] = const_val->data.x_f128.v[0]; | |
| 8116 | buf[1] = const_val->data.x_f128.v[1]; | |
| 8117 | #elif ZIG_BYTE_ORDER == ZIG_BIG_ENDIAN | |
| 8118 | buf[0] = const_val->data.x_f128.v[1]; | |
| 8119 | buf[1] = const_val->data.x_f128.v[0]; | |
| 8120 | #else | |
| 8121 | #error Unsupported endian | |
| 8122 | #endif | |
| 7709 | 8123 | |
| 7710 | 8124 | LLVMValueRef as_int = LLVMConstIntOfArbitraryPrecision(LLVMInt128Type(), 2, buf); |
| 7711 | 8125 | return LLVMConstBitCast(as_int, get_llvm_type(g, type_entry)); |
| ... | ... | @@ -8911,6 +9325,24 @@ static void define_builtin_types(CodeGen *g) { |
| 8911 | 9325 | add_fp_entry(g, "f64", 64, LLVMDoubleType(), &g->builtin_types.entry_f64); |
| 8912 | 9326 | add_fp_entry(g, "f128", 128, LLVMFP128Type(), &g->builtin_types.entry_f128); |
| 8913 | 9327 | |
| 9328 | if (target_has_f80(g->zig_target)) { | |
| 9329 | add_fp_entry(g, "f80", 80, LLVMX86FP80Type(), &g->builtin_types.entry_f80); | |
| 9330 | } else { | |
| 9331 | ZigType *entry = new_type_table_entry(ZigTypeIdFloat); | |
| 9332 | entry->llvm_type = get_int_type(g, false, 128)->llvm_type; | |
| 9333 | entry->size_in_bits = 8 * LLVMStoreSizeOfType(g->target_data_ref, entry->llvm_type); | |
| 9334 | entry->abi_size = LLVMABISizeOfType(g->target_data_ref, entry->llvm_type); | |
| 9335 | entry->abi_align = 16; | |
| 9336 | buf_init_from_str(&entry->name, "f80"); | |
| 9337 | entry->data.floating.bit_count = 80; | |
| 9338 | ||
| 9339 | entry->llvm_di_type = ZigLLVMCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name), | |
| 9340 | entry->size_in_bits, ZigLLVMEncoding_DW_ATE_unsigned()); | |
| 9341 | ||
| 9342 | g->builtin_types.entry_f80 = entry; | |
| 9343 | g->primitive_type_table.put(&entry->name, entry); | |
| 9344 | } | |
| 9345 | ||
| 8914 | 9346 | switch (g->zig_target->arch) { |
| 8915 | 9347 | case ZigLLVM_x86: |
| 8916 | 9348 | case ZigLLVM_x86_64: |
src/stage1/ir.cpp+239-23| ... | ... | @@ -2688,6 +2688,12 @@ static bool float_has_fraction(ZigValue *const_val) { |
| 2688 | 2688 | return floorf(const_val->data.x_f32) != const_val->data.x_f32; |
| 2689 | 2689 | case 64: |
| 2690 | 2690 | return floor(const_val->data.x_f64) != const_val->data.x_f64; |
| 2691 | case 80: | |
| 2692 | { | |
| 2693 | extFloat80_t floored; | |
| 2694 | extF80M_roundToInt(&const_val->data.x_f80, softfloat_round_minMag, false, &floored); | |
| 2695 | return !extF80M_eq(&floored, &const_val->data.x_f80); | |
| 2696 | } | |
| 2691 | 2697 | case 128: |
| 2692 | 2698 | { |
| 2693 | 2699 | float128_t floored; |
| ... | ... | @@ -2716,6 +2722,15 @@ static void float_append_buf(Buf *buf, ZigValue *const_val) { |
| 2716 | 2722 | case 64: |
| 2717 | 2723 | buf_appendf(buf, "%f", const_val->data.x_f64); |
| 2718 | 2724 | break; |
| 2725 | case 80: | |
| 2726 | { | |
| 2727 | float64_t f64_value = extF80M_to_f64(&const_val->data.x_f80); | |
| 2728 | double double_value; | |
| 2729 | memcpy(&double_value, &f64_value, sizeof(double)); | |
| 2730 | ||
| 2731 | buf_appendf(buf, "%f", const_val->data.x_f64); | |
| 2732 | break; | |
| 2733 | } | |
| 2719 | 2734 | case 128: |
| 2720 | 2735 | { |
| 2721 | 2736 | // TODO actual implementation |
| ... | ... | @@ -2772,6 +2787,15 @@ static void float_init_bigint(BigInt *bigint, ZigValue *const_val) { |
| 2772 | 2787 | bigint->is_negative = true; |
| 2773 | 2788 | } |
| 2774 | 2789 | break; |
| 2790 | case 80: | |
| 2791 | { | |
| 2792 | float128_t f128_value; | |
| 2793 | extF80M_to_f128M(&const_val->data.x_f80, &f128_value); | |
| 2794 | BigFloat tmp_float; | |
| 2795 | bigfloat_init_128(&tmp_float, f128_value); | |
| 2796 | bigint_init_bigfloat(bigint, &tmp_float); | |
| 2797 | } | |
| 2798 | break; | |
| 2775 | 2799 | case 128: |
| 2776 | 2800 | { |
| 2777 | 2801 | BigFloat tmp_float; |
| ... | ... | @@ -2801,8 +2825,11 @@ static void float_init_bigfloat(ZigValue *dest_val, BigFloat *bigfloat) { |
| 2801 | 2825 | case 64: |
| 2802 | 2826 | dest_val->data.x_f64 = bigfloat_to_f64(bigfloat); |
| 2803 | 2827 | break; |
| 2804 | case 80: | |
| 2805 | zig_panic("TODO: float_init_bigfloat c_longdouble"); | |
| 2828 | case 80: { | |
| 2829 | float128_t f128_value = bigfloat_to_f128(bigfloat); | |
| 2830 | f128M_to_extF80M(&f128_value, &dest_val->data.x_f80); | |
| 2831 | break; | |
| 2832 | } | |
| 2806 | 2833 | case 128: |
| 2807 | 2834 | dest_val->data.x_f128 = bigfloat_to_f128(bigfloat); |
| 2808 | 2835 | break; |
| ... | ... | @@ -2828,6 +2855,9 @@ static void float_init_f16(ZigValue *dest_val, float16_t x) { |
| 2828 | 2855 | case 64: |
| 2829 | 2856 | dest_val->data.x_f64 = zig_f16_to_double(x); |
| 2830 | 2857 | break; |
| 2858 | case 80: | |
| 2859 | f16_to_extF80M(x, &dest_val->data.x_f80); | |
| 2860 | break; | |
| 2831 | 2861 | case 128: |
| 2832 | 2862 | f16_to_f128M(x, &dest_val->data.x_f128); |
| 2833 | 2863 | break; |
| ... | ... | @@ -2853,6 +2883,12 @@ static void float_init_f32(ZigValue *dest_val, float x) { |
| 2853 | 2883 | case 64: |
| 2854 | 2884 | dest_val->data.x_f64 = x; |
| 2855 | 2885 | break; |
| 2886 | case 80: { | |
| 2887 | float32_t x_f32; | |
| 2888 | memcpy(&x_f32, &x, sizeof(float)); | |
| 2889 | f32_to_extF80M(x_f32, &dest_val->data.x_f80); | |
| 2890 | break; | |
| 2891 | } | |
| 2856 | 2892 | case 128: |
| 2857 | 2893 | { |
| 2858 | 2894 | float32_t x_f32; |
| ... | ... | @@ -2882,6 +2918,12 @@ static void float_init_f64(ZigValue *dest_val, double x) { |
| 2882 | 2918 | case 64: |
| 2883 | 2919 | dest_val->data.x_f64 = x; |
| 2884 | 2920 | break; |
| 2921 | case 80: { | |
| 2922 | float64_t x_f64; | |
| 2923 | memcpy(&x_f64, &x, sizeof(double)); | |
| 2924 | f64_to_extF80M(x_f64, &dest_val->data.x_f80); | |
| 2925 | break; | |
| 2926 | } | |
| 2885 | 2927 | case 128: |
| 2886 | 2928 | { |
| 2887 | 2929 | float64_t x_f64; |
| ... | ... | @@ -2917,6 +2959,9 @@ static void float_init_f128(ZigValue *dest_val, float128_t x) { |
| 2917 | 2959 | memcpy(&dest_val->data.x_f64, &f64_val, sizeof(double)); |
| 2918 | 2960 | break; |
| 2919 | 2961 | } |
| 2962 | case 80: | |
| 2963 | f128M_to_extF80M(&x, &dest_val->data.x_f80); | |
| 2964 | break; | |
| 2920 | 2965 | case 128: |
| 2921 | 2966 | { |
| 2922 | 2967 | memcpy(&dest_val->data.x_f128, &x, sizeof(float128_t)); |
| ... | ... | @@ -2944,6 +2989,12 @@ static void float_init_float(ZigValue *dest_val, ZigValue *src_val) { |
| 2944 | 2989 | case 64: |
| 2945 | 2990 | float_init_f64(dest_val, src_val->data.x_f64); |
| 2946 | 2991 | break; |
| 2992 | case 80: { | |
| 2993 | float128_t f128_value; | |
| 2994 | extF80M_to_f128M(&src_val->data.x_f80, &f128_value); | |
| 2995 | float_init_f128(dest_val, f128_value); | |
| 2996 | break; | |
| 2997 | } | |
| 2947 | 2998 | case 128: |
| 2948 | 2999 | float_init_f128(dest_val, src_val->data.x_f128); |
| 2949 | 3000 | break; |
| ... | ... | @@ -2966,6 +3017,8 @@ static bool float_is_nan(ZigValue *op) { |
| 2966 | 3017 | return op->data.x_f32 != op->data.x_f32; |
| 2967 | 3018 | case 64: |
| 2968 | 3019 | return op->data.x_f64 != op->data.x_f64; |
| 3020 | case 80: | |
| 3021 | return zig_extF80_isNaN(&op->data.x_f80); | |
| 2969 | 3022 | case 128: |
| 2970 | 3023 | return zig_f128_isNaN(&op->data.x_f128); |
| 2971 | 3024 | default: |
| ... | ... | @@ -3006,6 +3059,14 @@ static Cmp float_cmp(ZigValue *op1, ZigValue *op2) { |
| 3006 | 3059 | } else { |
| 3007 | 3060 | return CmpEQ; |
| 3008 | 3061 | } |
| 3062 | case 80: | |
| 3063 | if (extF80M_lt(&op1->data.x_f80, &op2->data.x_f80)) { | |
| 3064 | return CmpLT; | |
| 3065 | } else if (extF80M_eq(&op1->data.x_f80, &op2->data.x_f80)) { | |
| 3066 | return CmpEQ; | |
| 3067 | } else { | |
| 3068 | return CmpGT; | |
| 3069 | } | |
| 3009 | 3070 | case 128: |
| 3010 | 3071 | if (f128M_lt(&op1->data.x_f128, &op2->data.x_f128)) { |
| 3011 | 3072 | return CmpLT; |
| ... | ... | @@ -3061,7 +3122,18 @@ static Cmp float_cmp_zero(ZigValue *op) { |
| 3061 | 3122 | } else { |
| 3062 | 3123 | return CmpEQ; |
| 3063 | 3124 | } |
| 3064 | case 128: | |
| 3125 | case 80: { | |
| 3126 | extFloat80_t zero_float; | |
| 3127 | ui32_to_extF80M(0, &zero_float); | |
| 3128 | if (extF80M_lt(&op->data.x_f80, &zero_float)) { | |
| 3129 | return CmpLT; | |
| 3130 | } else if (extF80M_eq(&op->data.x_f80, &zero_float)) { | |
| 3131 | return CmpEQ; | |
| 3132 | } else { | |
| 3133 | return CmpGT; | |
| 3134 | } | |
| 3135 | } | |
| 3136 | case 128: { | |
| 3065 | 3137 | float128_t zero_float; |
| 3066 | 3138 | ui32_to_f128M(0, &zero_float); |
| 3067 | 3139 | if (f128M_lt(&op->data.x_f128, &zero_float)) { |
| ... | ... | @@ -3071,6 +3143,7 @@ static Cmp float_cmp_zero(ZigValue *op) { |
| 3071 | 3143 | } else { |
| 3072 | 3144 | return CmpGT; |
| 3073 | 3145 | } |
| 3146 | } | |
| 3074 | 3147 | default: |
| 3075 | 3148 | zig_unreachable(); |
| 3076 | 3149 | } |
| ... | ... | @@ -3095,6 +3168,9 @@ static void float_add(ZigValue *out_val, ZigValue *op1, ZigValue *op2) { |
| 3095 | 3168 | case 64: |
| 3096 | 3169 | out_val->data.x_f64 = op1->data.x_f64 + op2->data.x_f64; |
| 3097 | 3170 | return; |
| 3171 | case 80: | |
| 3172 | extF80M_add(&op1->data.x_f80, &op2->data.x_f80, &out_val->data.x_f80); | |
| 3173 | return; | |
| 3098 | 3174 | case 128: |
| 3099 | 3175 | f128M_add(&op1->data.x_f128, &op2->data.x_f128, &out_val->data.x_f128); |
| 3100 | 3176 | return; |
| ... | ... | @@ -3122,6 +3198,9 @@ static void float_sub(ZigValue *out_val, ZigValue *op1, ZigValue *op2) { |
| 3122 | 3198 | case 64: |
| 3123 | 3199 | out_val->data.x_f64 = op1->data.x_f64 - op2->data.x_f64; |
| 3124 | 3200 | return; |
| 3201 | case 80: | |
| 3202 | extF80M_sub(&op1->data.x_f80, &op2->data.x_f80, &out_val->data.x_f80); | |
| 3203 | return; | |
| 3125 | 3204 | case 128: |
| 3126 | 3205 | f128M_sub(&op1->data.x_f128, &op2->data.x_f128, &out_val->data.x_f128); |
| 3127 | 3206 | return; |
| ... | ... | @@ -3149,6 +3228,9 @@ static void float_mul(ZigValue *out_val, ZigValue *op1, ZigValue *op2) { |
| 3149 | 3228 | case 64: |
| 3150 | 3229 | out_val->data.x_f64 = op1->data.x_f64 * op2->data.x_f64; |
| 3151 | 3230 | return; |
| 3231 | case 80: | |
| 3232 | extF80M_mul(&op1->data.x_f80, &op2->data.x_f80, &out_val->data.x_f80); | |
| 3233 | return; | |
| 3152 | 3234 | case 128: |
| 3153 | 3235 | f128M_mul(&op1->data.x_f128, &op2->data.x_f128, &out_val->data.x_f128); |
| 3154 | 3236 | return; |
| ... | ... | @@ -3176,6 +3258,9 @@ static void float_div(ZigValue *out_val, ZigValue *op1, ZigValue *op2) { |
| 3176 | 3258 | case 64: |
| 3177 | 3259 | out_val->data.x_f64 = op1->data.x_f64 / op2->data.x_f64; |
| 3178 | 3260 | return; |
| 3261 | case 80: | |
| 3262 | extF80M_div(&op1->data.x_f80, &op2->data.x_f80, &out_val->data.x_f80); | |
| 3263 | return; | |
| 3179 | 3264 | case 128: |
| 3180 | 3265 | f128M_div(&op1->data.x_f128, &op2->data.x_f128, &out_val->data.x_f128); |
| 3181 | 3266 | return; |
| ... | ... | @@ -3204,6 +3289,10 @@ static void float_div_trunc(ZigValue *out_val, ZigValue *op1, ZigValue *op2) { |
| 3204 | 3289 | case 64: |
| 3205 | 3290 | out_val->data.x_f64 = trunc(op1->data.x_f64 / op2->data.x_f64); |
| 3206 | 3291 | return; |
| 3292 | case 80: | |
| 3293 | extF80M_div(&op1->data.x_f80, &op2->data.x_f80, &out_val->data.x_f80); | |
| 3294 | extF80M_roundToInt(&out_val->data.x_f80, softfloat_round_minMag, false, &out_val->data.x_f80); | |
| 3295 | return; | |
| 3207 | 3296 | case 128: |
| 3208 | 3297 | f128M_div(&op1->data.x_f128, &op2->data.x_f128, &out_val->data.x_f128); |
| 3209 | 3298 | f128M_roundToInt(&out_val->data.x_f128, softfloat_round_minMag, false, &out_val->data.x_f128); |
| ... | ... | @@ -3233,6 +3322,10 @@ static void float_div_floor(ZigValue *out_val, ZigValue *op1, ZigValue *op2) { |
| 3233 | 3322 | case 64: |
| 3234 | 3323 | out_val->data.x_f64 = floor(op1->data.x_f64 / op2->data.x_f64); |
| 3235 | 3324 | return; |
| 3325 | case 80: | |
| 3326 | extF80M_div(&op1->data.x_f80, &op2->data.x_f80, &out_val->data.x_f80); | |
| 3327 | extF80M_roundToInt(&out_val->data.x_f80, softfloat_round_min, false, &out_val->data.x_f80); | |
| 3328 | return; | |
| 3236 | 3329 | case 128: |
| 3237 | 3330 | f128M_div(&op1->data.x_f128, &op2->data.x_f128, &out_val->data.x_f128); |
| 3238 | 3331 | f128M_roundToInt(&out_val->data.x_f128, softfloat_round_min, false, &out_val->data.x_f128); |
| ... | ... | @@ -3261,6 +3354,9 @@ static void float_rem(ZigValue *out_val, ZigValue *op1, ZigValue *op2) { |
| 3261 | 3354 | case 64: |
| 3262 | 3355 | out_val->data.x_f64 = fmod(op1->data.x_f64, op2->data.x_f64); |
| 3263 | 3356 | return; |
| 3357 | case 80: | |
| 3358 | extF80M_rem(&op1->data.x_f80, &op2->data.x_f80, &out_val->data.x_f80); | |
| 3359 | return; | |
| 3264 | 3360 | case 128: |
| 3265 | 3361 | f128M_rem(&op1->data.x_f128, &op2->data.x_f128, &out_val->data.x_f128); |
| 3266 | 3362 | return; |
| ... | ... | @@ -3290,6 +3386,14 @@ static void zig_f128M_mod(const float128_t* a, const float128_t* b, float128_t* |
| 3290 | 3386 | f128M_sub(a, c, c); |
| 3291 | 3387 | } |
| 3292 | 3388 | |
| 3389 | // c = a - b * trunc(a / b) | |
| 3390 | static void zig_extF80M_mod(const extFloat80_t* a, const extFloat80_t* b, extFloat80_t* c) { | |
| 3391 | extF80M_div(a, b, c); | |
| 3392 | extF80M_roundToInt(c, softfloat_round_min, true, c); | |
| 3393 | extF80M_mul(b, c, c); | |
| 3394 | extF80M_sub(a, c, c); | |
| 3395 | } | |
| 3396 | ||
| 3293 | 3397 | static void float_mod(ZigValue *out_val, ZigValue *op1, ZigValue *op2) { |
| 3294 | 3398 | assert(op1->type == op2->type); |
| 3295 | 3399 | out_val->type = op1->type; |
| ... | ... | @@ -3306,6 +3410,9 @@ static void float_mod(ZigValue *out_val, ZigValue *op1, ZigValue *op2) { |
| 3306 | 3410 | case 64: |
| 3307 | 3411 | out_val->data.x_f64 = fmod(fmod(op1->data.x_f64, op2->data.x_f64) + op2->data.x_f64, op2->data.x_f64); |
| 3308 | 3412 | return; |
| 3413 | case 80: | |
| 3414 | zig_extF80M_mod(&op1->data.x_f80, &op2->data.x_f80, &out_val->data.x_f80); | |
| 3415 | return; | |
| 3309 | 3416 | case 128: |
| 3310 | 3417 | zig_f128M_mod(&op1->data.x_f128, &op2->data.x_f128, &out_val->data.x_f128); |
| 3311 | 3418 | return; |
| ... | ... | @@ -3351,6 +3458,15 @@ static void float_max(ZigValue *out_val, ZigValue *op1, ZigValue *op2) { |
| 3351 | 3458 | out_val->data.x_f64 = op1->data.x_f64 > op2->data.x_f64 ? op1->data.x_f64 : op2->data.x_f64; |
| 3352 | 3459 | } |
| 3353 | 3460 | return; |
| 3461 | case 80: | |
| 3462 | if (zig_extF80_isNaN(&op1->data.x_f80)) { | |
| 3463 | out_val->data.x_f80 = op2->data.x_f80; | |
| 3464 | } else if (zig_extF80_isNaN(&op2->data.x_f80)) { | |
| 3465 | out_val->data.x_f80 = op1->data.x_f80; | |
| 3466 | } else { | |
| 3467 | out_val->data.x_f80 = extF80M_lt(&op1->data.x_f80, &op2->data.x_f80) ? op2->data.x_f80 : op1->data.x_f80; | |
| 3468 | } | |
| 3469 | return; | |
| 3354 | 3470 | case 128: |
| 3355 | 3471 | if (zig_f128_isNaN(&op1->data.x_f128)) { |
| 3356 | 3472 | out_val->data.x_f128 = op2->data.x_f128; |
| ... | ... | @@ -3402,6 +3518,15 @@ static void float_min(ZigValue *out_val, ZigValue *op1, ZigValue *op2) { |
| 3402 | 3518 | out_val->data.x_f64 = op1->data.x_f32 < op2->data.x_f64 ? op1->data.x_f64 : op2->data.x_f64; |
| 3403 | 3519 | } |
| 3404 | 3520 | return; |
| 3521 | case 80: | |
| 3522 | if (zig_extF80_isNaN(&op1->data.x_f80)) { | |
| 3523 | out_val->data.x_f80 = op2->data.x_f80; | |
| 3524 | } else if (zig_extF80_isNaN(&op2->data.x_f80)) { | |
| 3525 | out_val->data.x_f80 = op1->data.x_f80; | |
| 3526 | } else { | |
| 3527 | out_val->data.x_f80 = extF80M_lt(&op1->data.x_f80, &op2->data.x_f80) ? op1->data.x_f80 : op2->data.x_f80; | |
| 3528 | } | |
| 3529 | return; | |
| 3405 | 3530 | case 128: |
| 3406 | 3531 | if (zig_f128_isNaN(&op1->data.x_f128)) { |
| 3407 | 3532 | out_val->data.x_f128 = op2->data.x_f128; |
| ... | ... | @@ -3434,6 +3559,9 @@ static void float_negate(ZigValue *out_val, ZigValue *op) { |
| 3434 | 3559 | case 64: |
| 3435 | 3560 | out_val->data.x_f64 = -op->data.x_f64; |
| 3436 | 3561 | return; |
| 3562 | case 80: | |
| 3563 | extF80M_neg(&op->data.x_f80, &out_val->data.x_f80); | |
| 3564 | return; | |
| 3437 | 3565 | case 128: |
| 3438 | 3566 | f128M_neg(&op->data.x_f128, &out_val->data.x_f128); |
| 3439 | 3567 | return; |
| ... | ... | @@ -3462,6 +3590,9 @@ void float_write_ieee597(ZigValue *op, uint8_t *buf, bool target_is_big_endian) |
| 3462 | 3590 | case 64: |
| 3463 | 3591 | memcpy(buf, &op->data.x_f64, 8); |
| 3464 | 3592 | break; |
| 3593 | case 80: | |
| 3594 | memcpy(buf, &op->data.x_f80, 16); | |
| 3595 | break; | |
| 3465 | 3596 | case 128: |
| 3466 | 3597 | memcpy(buf, &op->data.x_f128, 16); |
| 3467 | 3598 | break; |
| ... | ... | @@ -3511,6 +3642,9 @@ void float_read_ieee597(ZigValue *val, uint8_t *buf, bool target_is_big_endian) |
| 3511 | 3642 | case 64: |
| 3512 | 3643 | memcpy(&val->data.x_f64, ptr, 8); |
| 3513 | 3644 | return; |
| 3645 | case 80: | |
| 3646 | memcpy(&val->data.x_f80, ptr, 16); | |
| 3647 | return; | |
| 3514 | 3648 | case 128: |
| 3515 | 3649 | memcpy(&val->data.x_f128, ptr, 16); |
| 3516 | 3650 | return; |
| ... | ... | @@ -3538,8 +3672,12 @@ static void value_to_bigfloat(BigFloat *out, ZigValue *val) { |
| 3538 | 3672 | case 64: |
| 3539 | 3673 | bigfloat_init_64(out, val->data.x_f64); |
| 3540 | 3674 | return; |
| 3541 | case 80: | |
| 3542 | zig_panic("TODO: value_to_bigfloat c_longdouble"); | |
| 3675 | case 80: { | |
| 3676 | float128_t f128_value; | |
| 3677 | extF80M_to_f128M(&val->data.x_f80, &f128_value); | |
| 3678 | bigfloat_init_128(out, f128_value); | |
| 3679 | return; | |
| 3680 | } | |
| 3543 | 3681 | case 128: |
| 3544 | 3682 | bigfloat_init_128(out, val->data.x_f128); |
| 3545 | 3683 | return; |
| ... | ... | @@ -3628,8 +3766,14 @@ static bool ir_num_lit_fits_in_other_type(IrAnalyze *ira, Stage1AirInst *instruc |
| 3628 | 3766 | bigfloat_init_64(&orig_bf, tmp); |
| 3629 | 3767 | break; |
| 3630 | 3768 | } |
| 3631 | case 80: | |
| 3632 | zig_panic("TODO: ir_num_lit_fits_in_other_type c_longdouble"); | |
| 3769 | case 80: { | |
| 3770 | float128_t tmp = bigfloat_to_f128(&tmp_bf); | |
| 3771 | extFloat80_t tmp80; | |
| 3772 | f128M_to_extF80M(&tmp, &tmp80); | |
| 3773 | extF80M_to_f128M(&tmp80, &tmp); | |
| 3774 | bigfloat_init_128(&orig_bf, tmp); | |
| 3775 | break; | |
| 3776 | } | |
| 3633 | 3777 | case 128: { |
| 3634 | 3778 | float128_t tmp = bigfloat_to_f128(&tmp_bf); |
| 3635 | 3779 | bigfloat_init_128(&orig_bf, tmp); |
| ... | ... | @@ -3673,8 +3817,15 @@ static bool ir_num_lit_fits_in_other_type(IrAnalyze *ira, Stage1AirInst *instruc |
| 3673 | 3817 | } |
| 3674 | 3818 | break; |
| 3675 | 3819 | } |
| 3676 | case 80: | |
| 3677 | zig_panic("TODO: ir_num_lit_fits_in_other_type c_longdouble"); | |
| 3820 | case 80: { | |
| 3821 | float16_t tmp = extF80M_to_f16(&const_val->data.x_f80); | |
| 3822 | extFloat80_t orig; | |
| 3823 | f16_to_extF80M(tmp, &orig); | |
| 3824 | if (extF80M_eq(&orig, &const_val->data.x_f80)) { | |
| 3825 | return true; | |
| 3826 | } | |
| 3827 | break; | |
| 3828 | } | |
| 3678 | 3829 | case 128: { |
| 3679 | 3830 | float16_t tmp = f128M_to_f16(&const_val->data.x_f128); |
| 3680 | 3831 | float128_t orig; |
| ... | ... | @@ -3698,8 +3849,15 @@ static bool ir_num_lit_fits_in_other_type(IrAnalyze *ira, Stage1AirInst *instruc |
| 3698 | 3849 | } |
| 3699 | 3850 | break; |
| 3700 | 3851 | } |
| 3701 | case 80: | |
| 3702 | zig_panic("TODO: ir_num_lit_fits_in_other_type c_longdouble"); | |
| 3852 | case 80: { | |
| 3853 | float32_t tmp = extF80M_to_f32(&const_val->data.x_f80); | |
| 3854 | extFloat80_t orig; | |
| 3855 | f32_to_extF80M(tmp, &orig); | |
| 3856 | if (extF80M_eq(&orig, &const_val->data.x_f80)) { | |
| 3857 | return true; | |
| 3858 | } | |
| 3859 | break; | |
| 3860 | } | |
| 3703 | 3861 | case 128: { |
| 3704 | 3862 | float32_t tmp = f128M_to_f32(&const_val->data.x_f128); |
| 3705 | 3863 | float128_t orig; |
| ... | ... | @@ -3715,8 +3873,15 @@ static bool ir_num_lit_fits_in_other_type(IrAnalyze *ira, Stage1AirInst *instruc |
| 3715 | 3873 | break; |
| 3716 | 3874 | case 64: |
| 3717 | 3875 | switch (const_val->type->data.floating.bit_count) { |
| 3718 | case 80: | |
| 3719 | zig_panic("TODO: ir_num_lit_fits_in_other_type c_longdouble"); | |
| 3876 | case 80: { | |
| 3877 | float64_t tmp = extF80M_to_f64(&const_val->data.x_f80); | |
| 3878 | extFloat80_t orig; | |
| 3879 | f64_to_extF80M(tmp, &orig); | |
| 3880 | if (extF80M_eq(&orig, &const_val->data.x_f80)) { | |
| 3881 | return true; | |
| 3882 | } | |
| 3883 | break; | |
| 3884 | } | |
| 3720 | 3885 | case 128: { |
| 3721 | 3886 | float64_t tmp = f128M_to_f64(&const_val->data.x_f128); |
| 3722 | 3887 | float128_t orig; |
| ... | ... | @@ -3730,9 +3895,17 @@ static bool ir_num_lit_fits_in_other_type(IrAnalyze *ira, Stage1AirInst *instruc |
| 3730 | 3895 | zig_unreachable(); |
| 3731 | 3896 | } |
| 3732 | 3897 | break; |
| 3733 | case 80: | |
| 3898 | case 80: { | |
| 3734 | 3899 | assert(const_val->type->data.floating.bit_count == 128); |
| 3735 | zig_panic("TODO: ir_num_lit_fits_in_other_type c_longdouble"); | |
| 3900 | extFloat80_t tmp; | |
| 3901 | f128M_to_extF80M(&const_val->data.x_f128, &tmp); | |
| 3902 | float128_t orig; | |
| 3903 | extF80M_to_f128M(&tmp, &orig); | |
| 3904 | if (f128M_eq(&orig, &const_val->data.x_f128)) { | |
| 3905 | return true; | |
| 3906 | } | |
| 3907 | break; | |
| 3908 | } | |
| 3736 | 3909 | case 128: |
| 3737 | 3910 | return true; |
| 3738 | 3911 | default: |
| ... | ... | @@ -5143,8 +5316,11 @@ static bool eval_const_expr_implicit_cast(IrAnalyze *ira, Scope *scope, AstNode |
| 5143 | 5316 | case 64: |
| 5144 | 5317 | const_val->data.x_f64 = bigfloat_to_f64(&other_val->data.x_bigfloat); |
| 5145 | 5318 | break; |
| 5146 | case 80: | |
| 5147 | zig_panic("TODO: eval_const_expr_implicit_cast c_longdouble"); | |
| 5319 | case 80: { | |
| 5320 | float128_t tmp = bigfloat_to_f128(&other_val->data.x_bigfloat); | |
| 5321 | f128M_to_extF80M(&tmp, &const_val->data.x_f80); | |
| 5322 | break; | |
| 5323 | } | |
| 5148 | 5324 | case 128: |
| 5149 | 5325 | const_val->data.x_f128 = bigfloat_to_f128(&other_val->data.x_bigfloat); |
| 5150 | 5326 | break; |
| ... | ... | @@ -5172,8 +5348,11 @@ static bool eval_const_expr_implicit_cast(IrAnalyze *ira, Scope *scope, AstNode |
| 5172 | 5348 | case 64: |
| 5173 | 5349 | const_val->data.x_f64 = bigfloat_to_f64(&bigfloat); |
| 5174 | 5350 | break; |
| 5175 | case 80: | |
| 5176 | zig_panic("TODO: eval_const_expr_implicit_cast c_longdouble"); | |
| 5351 | case 80: { | |
| 5352 | float128_t tmp = bigfloat_to_f128(&other_val->data.x_bigfloat); | |
| 5353 | f128M_to_extF80M(&tmp, &const_val->data.x_f80); | |
| 5354 | break; | |
| 5355 | } | |
| 5177 | 5356 | case 128: |
| 5178 | 5357 | const_val->data.x_f128 = bigfloat_to_f128(&bigfloat); |
| 5179 | 5358 | break; |
| ... | ... | @@ -18960,6 +19139,7 @@ static ZigType *type_info_to_type(IrAnalyze *ira, Scope *scope, AstNode *source_ |
| 18960 | 19139 | case 16: return ira->codegen->builtin_types.entry_f16; |
| 18961 | 19140 | case 32: return ira->codegen->builtin_types.entry_f32; |
| 18962 | 19141 | case 64: return ira->codegen->builtin_types.entry_f64; |
| 19142 | case 80: return ira->codegen->builtin_types.entry_f80; | |
| 18963 | 19143 | case 128: return ira->codegen->builtin_types.entry_f128; |
| 18964 | 19144 | } |
| 18965 | 19145 | ir_add_error_node(ira, source_node, buf_sprintf("%d-bit float unsupported", bits)); |
| ... | ... | @@ -21943,6 +22123,8 @@ static void ir_eval_mul_add(IrAnalyze *ira, ZigType *float_type, |
| 21943 | 22123 | case 64: |
| 21944 | 22124 | out_val->data.x_f64 = fma(op1->data.x_f64, op2->data.x_f64, op3->data.x_f64); |
| 21945 | 22125 | break; |
| 22126 | case 80: | |
| 22127 | zig_panic("compiler bug: TODO: implement 'mulAdd' for type 'f80'. See https://github.com/ziglang/zig/issues/4026"); | |
| 21946 | 22128 | case 128: |
| 21947 | 22129 | f128M_mulAdd(&op1->data.x_f128, &op2->data.x_f128, &op3->data.x_f128, &out_val->data.x_f128); |
| 21948 | 22130 | break; |
| ... | ... | @@ -24156,10 +24338,44 @@ static ErrorMsg *ir_eval_float_op(IrAnalyze *ira, Scope *scope, AstNode *source_ |
| 24156 | 24338 | } |
| 24157 | 24339 | break; |
| 24158 | 24340 | } |
| 24159 | case 80: | |
| 24160 | return ir_add_error_node(ira, source_node, | |
| 24161 | buf_sprintf("compiler bug: TODO: implement '%s' for type '%s'. See https://github.com/ziglang/zig/issues/4026", | |
| 24162 | float_op_to_name(fop), buf_ptr(&float_type->name))); | |
| 24341 | case 80: { | |
| 24342 | extFloat80_t *out = &out_val->data.x_f80; | |
| 24343 | extFloat80_t *in = &op->data.x_f80; | |
| 24344 | switch (fop) { | |
| 24345 | case BuiltinFnIdSqrt: | |
| 24346 | extF80M_sqrt(in, out); | |
| 24347 | break; | |
| 24348 | case BuiltinFnIdFabs: | |
| 24349 | extF80M_abs(in, out); | |
| 24350 | break; | |
| 24351 | case BuiltinFnIdFloor: | |
| 24352 | extF80M_roundToInt(in, softfloat_round_min, false, out); | |
| 24353 | break; | |
| 24354 | case BuiltinFnIdCeil: | |
| 24355 | extF80M_roundToInt(in, softfloat_round_max, false, out); | |
| 24356 | break; | |
| 24357 | case BuiltinFnIdTrunc: | |
| 24358 | extF80M_trunc(in, out); | |
| 24359 | break; | |
| 24360 | case BuiltinFnIdRound: | |
| 24361 | extF80M_roundToInt(in, softfloat_round_near_maxMag, false, out); | |
| 24362 | break; | |
| 24363 | case BuiltinFnIdNearbyInt: | |
| 24364 | case BuiltinFnIdSin: | |
| 24365 | case BuiltinFnIdCos: | |
| 24366 | case BuiltinFnIdExp: | |
| 24367 | case BuiltinFnIdExp2: | |
| 24368 | case BuiltinFnIdLog: | |
| 24369 | case BuiltinFnIdLog10: | |
| 24370 | case BuiltinFnIdLog2: | |
| 24371 | return ir_add_error_node(ira, source_node, | |
| 24372 | buf_sprintf("compiler bug: TODO: implement '%s' for type '%s'. See https://github.com/ziglang/zig/issues/4026", | |
| 24373 | float_op_to_name(fop), buf_ptr(&float_type->name))); | |
| 24374 | default: | |
| 24375 | zig_unreachable(); | |
| 24376 | } | |
| 24377 | break; | |
| 24378 | } | |
| 24163 | 24379 | case 128: { |
| 24164 | 24380 | float128_t *out, *in; |
| 24165 | 24381 | if (float_type->id == ZigTypeIdComptimeFloat) { |
src/stage1/softfloat.hpp+4| ... | ... | @@ -56,4 +56,8 @@ static inline bool zig_f128_isNaN(float128_t *aPtr) { |
| 56 | 56 | || ((absA64 == UINT64_C(0x7FFF000000000000)) && lo); |
| 57 | 57 | } |
| 58 | 58 | |
| 59 | static inline bool zig_extF80_isNaN(extFloat80_t *aPtr) { | |
| 60 | return (aPtr->signExp & 0x7FFF) == 0x7FFF && aPtr->signif & UINT64_C(0x7FFFFFFFFFFFFFFF); | |
| 61 | } | |
| 62 | ||
| 59 | 63 | #endif |
src/stage1/softfloat_ext.cpp+30-8| ... | ... | @@ -28,13 +28,6 @@ void f128M_trunc(const float128_t *aPtr, float128_t *zPtr) { |
| 28 | 28 | } |
| 29 | 29 | } |
| 30 | 30 | |
| 31 | float16_t f16_neg(const float16_t a) { | |
| 32 | union { uint16_t ui; float16_t f; } uA; | |
| 33 | // Toggle the sign bit. | |
| 34 | uA.ui = a.v ^ (UINT16_C(1) << 15); | |
| 35 | return uA.f; | |
| 36 | } | |
| 37 | ||
| 38 | 31 | void f128M_neg(const float128_t *aPtr, float128_t *zPtr) { |
| 39 | 32 | // Toggle the sign bit. |
| 40 | 33 | #if ZIG_BYTE_ORDER == ZIG_LITTLE_ENDIAN |
| ... | ... | @@ -46,4 +39,33 @@ void f128M_neg(const float128_t *aPtr, float128_t *zPtr) { |
| 46 | 39 | #else |
| 47 | 40 | #error Unsupported endian |
| 48 | 41 | #endif |
| 49 | } | |
| \ No newline at end of file | ||
| 42 | } | |
| 43 | ||
| 44 | void extF80M_abs(const extFloat80_t *aPtr, extFloat80_t *zPtr) { | |
| 45 | // Clear the sign bit. | |
| 46 | zPtr->signExp = aPtr->signExp & UINT16_C(0x7FFF); | |
| 47 | zPtr->signif = aPtr->signif; | |
| 48 | } | |
| 49 | ||
| 50 | void extF80M_trunc(const extFloat80_t *aPtr, extFloat80_t *zPtr) { | |
| 51 | extFloat80_t zero_float; | |
| 52 | ui32_to_extF80M(0, &zero_float); | |
| 53 | if (extF80M_lt(aPtr, &zero_float)) { | |
| 54 | extF80M_roundToInt(aPtr, softfloat_round_max, false, zPtr); | |
| 55 | } else { | |
| 56 | extF80M_roundToInt(aPtr, softfloat_round_min, false, zPtr); | |
| 57 | } | |
| 58 | } | |
| 59 | ||
| 60 | void extF80M_neg(const extFloat80_t *aPtr, extFloat80_t *zPtr) { | |
| 61 | // Toggle the sign bit. | |
| 62 | zPtr->signExp = aPtr->signExp ^ UINT16_C(0x8000); | |
| 63 | zPtr->signif = aPtr->signif; | |
| 64 | } | |
| 65 | ||
| 66 | float16_t f16_neg(const float16_t a) { | |
| 67 | union { uint16_t ui; float16_t f; } uA; | |
| 68 | // Toggle the sign bit. | |
| 69 | uA.ui = a.v ^ (UINT16_C(1) << 15); | |
| 70 | return uA.f; | |
| 71 | } |
src/stage1/softfloat_ext.hpp+4| ... | ... | @@ -7,6 +7,10 @@ void f128M_abs(const float128_t *aPtr, float128_t *zPtr); |
| 7 | 7 | void f128M_trunc(const float128_t *aPtr, float128_t *zPtr); |
| 8 | 8 | void f128M_neg(const float128_t *aPtr, float128_t *zPtr); |
| 9 | 9 | |
| 10 | void extF80M_abs(const extFloat80_t *aPtr, extFloat80_t *zPtr); | |
| 11 | void extF80M_trunc(const extFloat80_t *aPtr, extFloat80_t *zPtr); | |
| 12 | void extF80M_neg(const extFloat80_t *aPtr, extFloat80_t *zPtr); | |
| 13 | ||
| 10 | 14 | float16_t f16_neg(const float16_t a); |
| 11 | 15 | |
| 12 | 16 | #endif |
| \ No newline at end of file |
src/stage1/target.cpp+11| ... | ... | @@ -1019,6 +1019,17 @@ bool target_long_double_is_f128(const ZigTarget *target) { |
| 1019 | 1019 | } |
| 1020 | 1020 | } |
| 1021 | 1021 | |
| 1022 | bool target_has_f80(const ZigTarget *target) { | |
| 1023 | switch (target->arch) { | |
| 1024 | case ZigLLVM_x86: | |
| 1025 | case ZigLLVM_x86_64: | |
| 1026 | return true; | |
| 1027 | ||
| 1028 | default: | |
| 1029 | return false; | |
| 1030 | } | |
| 1031 | } | |
| 1032 | ||
| 1022 | 1033 | bool target_is_riscv(const ZigTarget *target) { |
| 1023 | 1034 | return target->arch == ZigLLVM_riscv32 || target->arch == ZigLLVM_riscv64; |
| 1024 | 1035 | } |
src/stage1/target.hpp+1| ... | ... | @@ -81,6 +81,7 @@ bool target_is_sparc(const ZigTarget *target); |
| 81 | 81 | bool target_is_android(const ZigTarget *target); |
| 82 | 82 | bool target_has_debug_info(const ZigTarget *target); |
| 83 | 83 | bool target_long_double_is_f128(const ZigTarget *target); |
| 84 | bool target_has_f80(const ZigTarget *target); | |
| 84 | 85 | |
| 85 | 86 | uint32_t target_arch_pointer_bit_width(ZigLLVM_ArchType arch); |
| 86 | 87 | uint32_t target_arch_largest_atomic_bits(ZigLLVM_ArchType arch); |
src/type.zig+17| ... | ... | @@ -58,6 +58,7 @@ pub const Type = extern union { |
| 58 | 58 | .f16, |
| 59 | 59 | .f32, |
| 60 | 60 | .f64, |
| 61 | .f80, | |
| 61 | 62 | .f128, |
| 62 | 63 | .c_longdouble, |
| 63 | 64 | => return .Float, |
| ... | ... | @@ -833,6 +834,7 @@ pub const Type = extern union { |
| 833 | 834 | .f16, |
| 834 | 835 | .f32, |
| 835 | 836 | .f64, |
| 837 | .f80, | |
| 836 | 838 | .f128, |
| 837 | 839 | .bool, |
| 838 | 840 | .void, |
| ... | ... | @@ -1053,6 +1055,7 @@ pub const Type = extern union { |
| 1053 | 1055 | .f16, |
| 1054 | 1056 | .f32, |
| 1055 | 1057 | .f64, |
| 1058 | .f80, | |
| 1056 | 1059 | .f128, |
| 1057 | 1060 | .bool, |
| 1058 | 1061 | .void, |
| ... | ... | @@ -1371,6 +1374,7 @@ pub const Type = extern union { |
| 1371 | 1374 | .f16, |
| 1372 | 1375 | .f32, |
| 1373 | 1376 | .f64, |
| 1377 | .f80, | |
| 1374 | 1378 | .f128, |
| 1375 | 1379 | .bool, |
| 1376 | 1380 | .void, |
| ... | ... | @@ -1473,6 +1477,7 @@ pub const Type = extern union { |
| 1473 | 1477 | .f16 => return Value.initTag(.f16_type), |
| 1474 | 1478 | .f32 => return Value.initTag(.f32_type), |
| 1475 | 1479 | .f64 => return Value.initTag(.f64_type), |
| 1480 | .f80 => return Value.initTag(.f80_type), | |
| 1476 | 1481 | .f128 => return Value.initTag(.f128_type), |
| 1477 | 1482 | .bool => return Value.initTag(.bool_type), |
| 1478 | 1483 | .void => return Value.initTag(.void_type), |
| ... | ... | @@ -1543,6 +1548,7 @@ pub const Type = extern union { |
| 1543 | 1548 | .f16, |
| 1544 | 1549 | .f32, |
| 1545 | 1550 | .f64, |
| 1551 | .f80, | |
| 1546 | 1552 | .f128, |
| 1547 | 1553 | .bool, |
| 1548 | 1554 | .anyerror, |
| ... | ... | @@ -1858,6 +1864,7 @@ pub const Type = extern union { |
| 1858 | 1864 | .f16 => return 2, |
| 1859 | 1865 | .f32 => return 4, |
| 1860 | 1866 | .f64 => return 8, |
| 1867 | .f80 => return 16, | |
| 1861 | 1868 | .f128 => return 16, |
| 1862 | 1869 | .c_longdouble => return 16, |
| 1863 | 1870 | |
| ... | ... | @@ -2138,6 +2145,7 @@ pub const Type = extern union { |
| 2138 | 2145 | .f16 => return 2, |
| 2139 | 2146 | .f32 => return 4, |
| 2140 | 2147 | .f64 => return 8, |
| 2148 | .f80 => return 16, | |
| 2141 | 2149 | .f128 => return 16, |
| 2142 | 2150 | .c_longdouble => return 16, |
| 2143 | 2151 | |
| ... | ... | @@ -2277,6 +2285,7 @@ pub const Type = extern union { |
| 2277 | 2285 | .i16, .u16, .f16 => 16, |
| 2278 | 2286 | .i32, .u32, .f32 => 32, |
| 2279 | 2287 | .i64, .u64, .f64 => 64, |
| 2288 | .f80 => 80, | |
| 2280 | 2289 | .u128, .i128, .f128 => 128, |
| 2281 | 2290 | |
| 2282 | 2291 | .isize, |
| ... | ... | @@ -3170,6 +3179,7 @@ pub const Type = extern union { |
| 3170 | 3179 | .f16, |
| 3171 | 3180 | .f32, |
| 3172 | 3181 | .f64, |
| 3182 | .f80, | |
| 3173 | 3183 | .f128, |
| 3174 | 3184 | .c_longdouble, |
| 3175 | 3185 | => true, |
| ... | ... | @@ -3184,6 +3194,7 @@ pub const Type = extern union { |
| 3184 | 3194 | .f16, |
| 3185 | 3195 | .f32, |
| 3186 | 3196 | .f64, |
| 3197 | .f80, | |
| 3187 | 3198 | .f128, |
| 3188 | 3199 | .c_longdouble, |
| 3189 | 3200 | .comptime_float, |
| ... | ... | @@ -3200,6 +3211,7 @@ pub const Type = extern union { |
| 3200 | 3211 | .f16 => 16, |
| 3201 | 3212 | .f32 => 32, |
| 3202 | 3213 | .f64 => 64, |
| 3214 | .f80 => 80, | |
| 3203 | 3215 | .f128, .comptime_float => 128, |
| 3204 | 3216 | .c_longdouble => CType.longdouble.sizeInBits(target), |
| 3205 | 3217 | |
| ... | ... | @@ -3340,6 +3352,7 @@ pub const Type = extern union { |
| 3340 | 3352 | .f16, |
| 3341 | 3353 | .f32, |
| 3342 | 3354 | .f64, |
| 3355 | .f80, | |
| 3343 | 3356 | .f128, |
| 3344 | 3357 | .c_longdouble, |
| 3345 | 3358 | .comptime_int, |
| ... | ... | @@ -3381,6 +3394,7 @@ pub const Type = extern union { |
| 3381 | 3394 | .f16, |
| 3382 | 3395 | .f32, |
| 3383 | 3396 | .f64, |
| 3397 | .f80, | |
| 3384 | 3398 | .f128, |
| 3385 | 3399 | .c_longdouble, |
| 3386 | 3400 | .comptime_int, |
| ... | ... | @@ -3579,6 +3593,7 @@ pub const Type = extern union { |
| 3579 | 3593 | .f16, |
| 3580 | 3594 | .f32, |
| 3581 | 3595 | .f64, |
| 3596 | .f80, | |
| 3582 | 3597 | .f128, |
| 3583 | 3598 | .anyopaque, |
| 3584 | 3599 | .bool, |
| ... | ... | @@ -4334,6 +4349,7 @@ pub const Type = extern union { |
| 4334 | 4349 | f16, |
| 4335 | 4350 | f32, |
| 4336 | 4351 | f64, |
| 4352 | f80, | |
| 4337 | 4353 | f128, |
| 4338 | 4354 | anyopaque, |
| 4339 | 4355 | bool, |
| ... | ... | @@ -4453,6 +4469,7 @@ pub const Type = extern union { |
| 4453 | 4469 | .f16, |
| 4454 | 4470 | .f32, |
| 4455 | 4471 | .f64, |
| 4472 | .f80, | |
| 4456 | 4473 | .f128, |
| 4457 | 4474 | .anyopaque, |
| 4458 | 4475 | .bool, |
src/value.zig+5| ... | ... | @@ -47,6 +47,7 @@ pub const Value = extern union { |
| 47 | 47 | f16_type, |
| 48 | 48 | f32_type, |
| 49 | 49 | f64_type, |
| 50 | f80_type, | |
| 50 | 51 | f128_type, |
| 51 | 52 | anyopaque_type, |
| 52 | 53 | bool_type, |
| ... | ... | @@ -205,6 +206,7 @@ pub const Value = extern union { |
| 205 | 206 | .f16_type, |
| 206 | 207 | .f32_type, |
| 207 | 208 | .f64_type, |
| 209 | .f80_type, | |
| 208 | 210 | .f128_type, |
| 209 | 211 | .anyopaque_type, |
| 210 | 212 | .bool_type, |
| ... | ... | @@ -398,6 +400,7 @@ pub const Value = extern union { |
| 398 | 400 | .f16_type, |
| 399 | 401 | .f32_type, |
| 400 | 402 | .f64_type, |
| 403 | .f80_type, | |
| 401 | 404 | .f128_type, |
| 402 | 405 | .anyopaque_type, |
| 403 | 406 | .bool_type, |
| ... | ... | @@ -630,6 +633,7 @@ pub const Value = extern union { |
| 630 | 633 | .f16_type => return out_stream.writeAll("f16"), |
| 631 | 634 | .f32_type => return out_stream.writeAll("f32"), |
| 632 | 635 | .f64_type => return out_stream.writeAll("f64"), |
| 636 | .f80_type => return out_stream.writeAll("f80"), | |
| 633 | 637 | .f128_type => return out_stream.writeAll("f128"), |
| 634 | 638 | .anyopaque_type => return out_stream.writeAll("anyopaque"), |
| 635 | 639 | .bool_type => return out_stream.writeAll("bool"), |
| ... | ... | @@ -824,6 +828,7 @@ pub const Value = extern union { |
| 824 | 828 | .f16_type => Type.initTag(.f16), |
| 825 | 829 | .f32_type => Type.initTag(.f32), |
| 826 | 830 | .f64_type => Type.initTag(.f64), |
| 831 | .f80_type => Type.initTag(.f80), | |
| 827 | 832 | .f128_type => Type.initTag(.f128), |
| 828 | 833 | .anyopaque_type => Type.initTag(.anyopaque), |
| 829 | 834 | .bool_type => Type.initTag(.bool), |
test/behavior/floatop_stage1.zig+81| ... | ... | @@ -4,6 +4,7 @@ const math = std.math; |
| 4 | 4 | const pi = std.math.pi; |
| 5 | 5 | const e = std.math.e; |
| 6 | 6 | const Vector = std.meta.Vector; |
| 7 | const has_f80_rt = @import("builtin").cpu.arch == .x86_64; | |
| 7 | 8 | |
| 8 | 9 | const epsilon = 0.000001; |
| 9 | 10 | |
| ... | ... | @@ -27,6 +28,10 @@ fn testSqrt() !void { |
| 27 | 28 | var a: f64 = 25; |
| 28 | 29 | try expect(@sqrt(a) == 5); |
| 29 | 30 | } |
| 31 | if (has_f80_rt) { | |
| 32 | var a: f80 = 25; | |
| 33 | try expect(@sqrt(a) == 5); | |
| 34 | } | |
| 30 | 35 | { |
| 31 | 36 | const a: comptime_float = 25.0; |
| 32 | 37 | try expect(@sqrt(a) == 5.0); |
| ... | ... | @@ -86,6 +91,10 @@ fn testSin() !void { |
| 86 | 91 | var a: f64 = 0; |
| 87 | 92 | try expect(@sin(a) == 0); |
| 88 | 93 | } |
| 94 | // { | |
| 95 | // var a: f80 = 0; | |
| 96 | // try expect(@sin(a) == 0); | |
| 97 | // } | |
| 89 | 98 | { |
| 90 | 99 | var v: Vector(4, f32) = [_]f32{ 1.1, 2.2, 3.3, 4.4 }; |
| 91 | 100 | var result = @sin(v); |
| ... | ... | @@ -116,6 +125,10 @@ fn testCos() !void { |
| 116 | 125 | var a: f64 = 0; |
| 117 | 126 | try expect(@cos(a) == 1); |
| 118 | 127 | } |
| 128 | // { | |
| 129 | // var a: f80 = 0; | |
| 130 | // try expect(@cos(a) == 1); | |
| 131 | // } | |
| 119 | 132 | { |
| 120 | 133 | var v: Vector(4, f32) = [_]f32{ 1.1, 2.2, 3.3, 4.4 }; |
| 121 | 134 | var result = @cos(v); |
| ... | ... | @@ -146,6 +159,10 @@ fn testExp() !void { |
| 146 | 159 | var a: f64 = 0; |
| 147 | 160 | try expect(@exp(a) == 1); |
| 148 | 161 | } |
| 162 | // { | |
| 163 | // var a: f80 = 0; | |
| 164 | // try expect(@exp(a) == 1); | |
| 165 | // } | |
| 149 | 166 | { |
| 150 | 167 | var v: Vector(4, f32) = [_]f32{ 1.1, 2.2, 0.3, 0.4 }; |
| 151 | 168 | var result = @exp(v); |
| ... | ... | @@ -176,6 +193,10 @@ fn testExp2() !void { |
| 176 | 193 | var a: f64 = 2; |
| 177 | 194 | try expect(@exp2(a) == 4); |
| 178 | 195 | } |
| 196 | // { | |
| 197 | // var a: f80 = 2; | |
| 198 | // try expect(@exp2(a) == 4); | |
| 199 | // } | |
| 179 | 200 | { |
| 180 | 201 | var v: Vector(4, f32) = [_]f32{ 1.1, 2.2, 0.3, 0.4 }; |
| 181 | 202 | var result = @exp2(v); |
| ... | ... | @@ -208,6 +229,10 @@ fn testLog() !void { |
| 208 | 229 | var a: f64 = e; |
| 209 | 230 | try expect(@log(a) == 1 or @log(a) == @bitCast(f64, @as(u64, 0x3ff0000000000000))); |
| 210 | 231 | } |
| 232 | // { | |
| 233 | // var a: f80 = e; | |
| 234 | // try expect(@log(a) == 1); | |
| 235 | // } | |
| 211 | 236 | { |
| 212 | 237 | var v: Vector(4, f32) = [_]f32{ 1.1, 2.2, 0.3, 0.4 }; |
| 213 | 238 | var result = @log(v); |
| ... | ... | @@ -238,6 +263,10 @@ fn testLog2() !void { |
| 238 | 263 | var a: f64 = 4; |
| 239 | 264 | try expect(@log2(a) == 2); |
| 240 | 265 | } |
| 266 | // { | |
| 267 | // var a: f80 = 4; | |
| 268 | // try expect(@log2(a) == 2); | |
| 269 | // } | |
| 241 | 270 | { |
| 242 | 271 | var v: Vector(4, f32) = [_]f32{ 1.1, 2.2, 0.3, 0.4 }; |
| 243 | 272 | var result = @log2(v); |
| ... | ... | @@ -268,6 +297,10 @@ fn testLog10() !void { |
| 268 | 297 | var a: f64 = 1000; |
| 269 | 298 | try expect(@log10(a) == 3); |
| 270 | 299 | } |
| 300 | // { | |
| 301 | // var a: f80 = 1000; | |
| 302 | // try expect(@log10(a) == 3); | |
| 303 | // } | |
| 271 | 304 | { |
| 272 | 305 | var v: Vector(4, f32) = [_]f32{ 1.1, 2.2, 0.3, 0.4 }; |
| 273 | 306 | var result = @log10(v); |
| ... | ... | @@ -304,6 +337,12 @@ fn testFabs() !void { |
| 304 | 337 | try expect(@fabs(a) == 2.5); |
| 305 | 338 | try expect(@fabs(b) == 2.5); |
| 306 | 339 | } |
| 340 | // { | |
| 341 | // var a: f80 = -2.5; | |
| 342 | // var b: f80 = 2.5; | |
| 343 | // try expect(@fabs(a) == 2.5); | |
| 344 | // try expect(@fabs(b) == 2.5); | |
| 345 | // } | |
| 307 | 346 | { |
| 308 | 347 | var v: Vector(4, f32) = [_]f32{ 1.1, -2.2, 0.3, -0.4 }; |
| 309 | 348 | var result = @fabs(v); |
| ... | ... | @@ -334,6 +373,10 @@ fn testFloor() !void { |
| 334 | 373 | var a: f64 = 3.5; |
| 335 | 374 | try expect(@floor(a) == 3); |
| 336 | 375 | } |
| 376 | // { | |
| 377 | // var a: f80 = 3.5; | |
| 378 | // try expect(@floor(a) == 3); | |
| 379 | // } | |
| 337 | 380 | { |
| 338 | 381 | var v: Vector(4, f32) = [_]f32{ 1.1, -2.2, 0.3, -0.4 }; |
| 339 | 382 | var result = @floor(v); |
| ... | ... | @@ -364,6 +407,10 @@ fn testCeil() !void { |
| 364 | 407 | var a: f64 = 3.5; |
| 365 | 408 | try expect(@ceil(a) == 4); |
| 366 | 409 | } |
| 410 | // { | |
| 411 | // var a: f80 = 3.5; | |
| 412 | // try expect(@ceil(a) == 4); | |
| 413 | // } | |
| 367 | 414 | { |
| 368 | 415 | var v: Vector(4, f32) = [_]f32{ 1.1, -2.2, 0.3, -0.4 }; |
| 369 | 416 | var result = @ceil(v); |
| ... | ... | @@ -394,6 +441,10 @@ fn testTrunc() !void { |
| 394 | 441 | var a: f64 = -3.5; |
| 395 | 442 | try expect(@trunc(a) == -3); |
| 396 | 443 | } |
| 444 | // { | |
| 445 | // var a: f80 = -3.5; | |
| 446 | // try expect(@trunc(a) == -3); | |
| 447 | // } | |
| 397 | 448 | { |
| 398 | 449 | var v: Vector(4, f32) = [_]f32{ 1.1, -2.2, 0.3, -0.4 }; |
| 399 | 450 | var result = @trunc(v); |
| ... | ... | @@ -403,3 +454,33 @@ fn testTrunc() !void { |
| 403 | 454 | try expect(math.approxEqAbs(f32, @trunc(@as(f32, -0.4)), result[3], epsilon)); |
| 404 | 455 | } |
| 405 | 456 | } |
| 457 | ||
| 458 | test "floating point comparisons" { | |
| 459 | if (has_f80_rt) try testFloatComparisons(); | |
| 460 | comptime try testFloatComparisons(); | |
| 461 | } | |
| 462 | ||
| 463 | fn testFloatComparisons() !void { | |
| 464 | inline for ([_]type{ f16, f32, f64, f80, f128 }) |ty| { | |
| 465 | // No decimal part | |
| 466 | { | |
| 467 | const x: ty = 1.0; | |
| 468 | try expect(x == 1); | |
| 469 | try expect(x != 0); | |
| 470 | try expect(x > 0); | |
| 471 | try expect(x < 2); | |
| 472 | try expect(x >= 1); | |
| 473 | try expect(x <= 1); | |
| 474 | } | |
| 475 | // Non-zero decimal part | |
| 476 | { | |
| 477 | const x: ty = 1.5; | |
| 478 | try expect(x != 1); | |
| 479 | try expect(x != 2); | |
| 480 | try expect(x > 1); | |
| 481 | try expect(x < 2); | |
| 482 | try expect(x >= 1); | |
| 483 | try expect(x <= 2); | |
| 484 | } | |
| 485 | } | |
| 486 | } |
test/behavior/math_stage1.zig+19| ... | ... | @@ -5,6 +5,7 @@ const expectEqualSlices = std.testing.expectEqualSlices; |
| 5 | 5 | const maxInt = std.math.maxInt; |
| 6 | 6 | const minInt = std.math.minInt; |
| 7 | 7 | const mem = std.mem; |
| 8 | const has_f80_rt = @import("builtin").cpu.arch == .x86_64; | |
| 8 | 9 | |
| 9 | 10 | test "allow signed integer division/remainder when values are comptime known and positive or exact" { |
| 10 | 11 | try expect(5 / 3 == 1); |
| ... | ... | @@ -194,6 +195,8 @@ fn testSqrt(comptime T: type, x: T) !void { |
| 194 | 195 | test "@fabs" { |
| 195 | 196 | try testFabs(f128, 12.0); |
| 196 | 197 | comptime try testFabs(f128, 12.0); |
| 198 | if (has_f80_rt) try testFabs(f80, 12.0); | |
| 199 | // comptime try testFabs(f80, 12.0); | |
| 197 | 200 | try testFabs(f64, 12.0); |
| 198 | 201 | comptime try testFabs(f64, 12.0); |
| 199 | 202 | try testFabs(f32, 12.0); |
| ... | ... | @@ -217,6 +220,8 @@ test "@floor" { |
| 217 | 220 | // FIXME: Generates a floorl function call |
| 218 | 221 | // testFloor(f128, 12.0); |
| 219 | 222 | comptime try testFloor(f128, 12.0); |
| 223 | // try testFloor(f80, 12.0); | |
| 224 | comptime try testFloor(f80, 12.0); | |
| 220 | 225 | try testFloor(f64, 12.0); |
| 221 | 226 | comptime try testFloor(f64, 12.0); |
| 222 | 227 | try testFloor(f32, 12.0); |
| ... | ... | @@ -240,6 +245,8 @@ test "@ceil" { |
| 240 | 245 | // FIXME: Generates a ceill function call |
| 241 | 246 | //testCeil(f128, 12.0); |
| 242 | 247 | comptime try testCeil(f128, 12.0); |
| 248 | // try testCeil(f80, 12.0); | |
| 249 | comptime try testCeil(f80, 12.0); | |
| 243 | 250 | try testCeil(f64, 12.0); |
| 244 | 251 | comptime try testCeil(f64, 12.0); |
| 245 | 252 | try testCeil(f32, 12.0); |
| ... | ... | @@ -263,6 +270,14 @@ test "@trunc" { |
| 263 | 270 | // FIXME: Generates a truncl function call |
| 264 | 271 | //testTrunc(f128, 12.0); |
| 265 | 272 | comptime try testTrunc(f128, 12.0); |
| 273 | // try testTrunc(f80, 12.0); | |
| 274 | // comptime try testTrunc(f80, 12.0); | |
| 275 | comptime { | |
| 276 | const x: f80 = 12.0; | |
| 277 | const y = x + 0.8; | |
| 278 | const z = @trunc(y); | |
| 279 | try expectEqual(x, z); | |
| 280 | } | |
| 266 | 281 | try testTrunc(f64, 12.0); |
| 267 | 282 | comptime try testTrunc(f64, 12.0); |
| 268 | 283 | try testTrunc(f32, 12.0); |
| ... | ... | @@ -294,6 +309,8 @@ test "@round" { |
| 294 | 309 | // FIXME: Generates a roundl function call |
| 295 | 310 | //testRound(f128, 12.0); |
| 296 | 311 | comptime try testRound(f128, 12.0); |
| 312 | // try testRound(f80, 12.0); | |
| 313 | comptime try testRound(f80, 12.0); | |
| 297 | 314 | try testRound(f64, 12.0); |
| 298 | 315 | comptime try testRound(f64, 12.0); |
| 299 | 316 | try testRound(f32, 12.0); |
| ... | ... | @@ -333,10 +350,12 @@ test "NaN comparison" { |
| 333 | 350 | try testNanEqNan(f32); |
| 334 | 351 | try testNanEqNan(f64); |
| 335 | 352 | try testNanEqNan(f128); |
| 353 | if (has_f80_rt) try testNanEqNan(f80); | |
| 336 | 354 | comptime try testNanEqNan(f16); |
| 337 | 355 | comptime try testNanEqNan(f32); |
| 338 | 356 | comptime try testNanEqNan(f64); |
| 339 | 357 | comptime try testNanEqNan(f128); |
| 358 | // comptime try testNanEqNan(f80); | |
| 340 | 359 | } |
| 341 | 360 | |
| 342 | 361 | fn testNanEqNan(comptime F: type) !void { |
test/behavior/muladd.zig+6| ... | ... | @@ -25,6 +25,12 @@ fn testMulAdd() !void { |
| 25 | 25 | var c: f64 = 6.25; |
| 26 | 26 | try expect(@mulAdd(f64, a, b, c) == 20); |
| 27 | 27 | } |
| 28 | // { | |
| 29 | // var a: f16 = 5.5; | |
| 30 | // var b: f80 = 2.5; | |
| 31 | // var c: f80 = 6.25; | |
| 32 | // try expect(@mulAdd(f80, a, b, c) == 20); | |
| 33 | // } | |
| 28 | 34 | if (builtin.os.tag == .macos and builtin.cpu.arch == .aarch64) { |
| 29 | 35 | // https://github.com/ziglang/zig/issues/9900 |
| 30 | 36 | return error.SkipZigTest; |
test/behavior/type_stage1.zig+2-1| ... | ... | @@ -13,8 +13,9 @@ test "Type.Float" { |
| 13 | 13 | try testing.expect(f16 == @Type(TypeInfo{ .Float = TypeInfo.Float{ .bits = 16 } })); |
| 14 | 14 | try testing.expect(f32 == @Type(TypeInfo{ .Float = TypeInfo.Float{ .bits = 32 } })); |
| 15 | 15 | try testing.expect(f64 == @Type(TypeInfo{ .Float = TypeInfo.Float{ .bits = 64 } })); |
| 16 | try testing.expect(f80 == @Type(TypeInfo{ .Float = TypeInfo.Float{ .bits = 80 } })); | |
| 16 | 17 | try testing.expect(f128 == @Type(TypeInfo{ .Float = TypeInfo.Float{ .bits = 128 } })); |
| 17 | try testTypes(&[_]type{ f16, f32, f64, f128 }); | |
| 18 | try testTypes(&[_]type{ f16, f32, f64, f80, f128 }); | |
| 18 | 19 | } |
| 19 | 20 | |
| 20 | 21 | test "Type.Array" { |
test/behavior/widening.zig+5| ... | ... | @@ -2,6 +2,7 @@ const std = @import("std"); |
| 2 | 2 | const expect = std.testing.expect; |
| 3 | 3 | const mem = std.mem; |
| 4 | 4 | const builtin = @import("builtin"); |
| 5 | const has_f80_rt = @import("builtin").cpu.arch == .x86_64; | |
| 5 | 6 | |
| 6 | 7 | test "integer widening" { |
| 7 | 8 | var a: u8 = 250; |
| ... | ... | @@ -27,6 +28,10 @@ test "float widening" { |
| 27 | 28 | try expect(a == b); |
| 28 | 29 | try expect(b == c); |
| 29 | 30 | try expect(c == d); |
| 31 | if (has_f80_rt) { | |
| 32 | var e: f80 = c; | |
| 33 | try expect(c == e); | |
| 34 | } | |
| 30 | 35 | } |
| 31 | 36 | |
| 32 | 37 | test "float widening f16 to f128" { |