authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-01-29 03:45:15-05:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2022-01-29 03:45:15-05:00
log225910f9341fbc725ff5e0d2c653e29bc2f21cb8
treeeac47d40ae555398c46e4ccdff9cace12eeabd3b
parent63ee6e662582ee75ac804eb1a4dbdf4457b8f2d0
parenta0a71709bc2104c708f045fbb42c6247aff136ac
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #10639 from Vexu/f80

Add f80

25 files changed, 953 insertions(+), 44 deletions(-)

CMakeLists.txt+31
......@@ -142,15 +142,19 @@ include_directories(${CLANG_INCLUDE_DIRS})
142142# No patches have been applied to SoftFloat-3e
143143set(EMBEDDED_SOFTFLOAT_SOURCES
144144 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/8086/f128M_isSignalingNaN.c"
145 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/8086/extF80M_isSignalingNaN.c"
145146 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/8086/s_commonNaNToF128M.c"
147 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/8086/s_commonNaNToExtF80M.c"
146148 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/8086/s_commonNaNToF16UI.c"
147149 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/8086/s_commonNaNToF32UI.c"
148150 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/8086/s_commonNaNToF64UI.c"
149151 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/8086/s_f128MToCommonNaN.c"
152 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/8086/s_extF80MToCommonNaN.c"
150153 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/8086/s_f16UIToCommonNaN.c"
151154 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/8086/s_f32UIToCommonNaN.c"
152155 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/8086/s_f64UIToCommonNaN.c"
153156 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/8086/s_propagateNaNF128M.c"
157 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/8086/s_propagateNaNExtF80M.c"
154158 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/8086/s_propagateNaNF16UI.c"
155159 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/8086/softfloat_raiseFlags.c"
156160 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f128M_add.c"
......@@ -170,6 +174,7 @@ set(EMBEDDED_SOFTFLOAT_SOURCES
170174 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f128M_to_f16.c"
171175 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f128M_to_f32.c"
172176 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f128M_to_f64.c"
177 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f128M_to_extF80M.c"
173178 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f128M_to_i32.c"
174179 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f128M_to_i32_r_minMag.c"
175180 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f128M_to_i64.c"
......@@ -178,6 +183,20 @@ set(EMBEDDED_SOFTFLOAT_SOURCES
178183 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f128M_to_ui32_r_minMag.c"
179184 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f128M_to_ui64.c"
180185 "${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"
181200 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f16_add.c"
182201 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f16_div.c"
183202 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f16_eq.c"
......@@ -188,9 +207,12 @@ set(EMBEDDED_SOFTFLOAT_SOURCES
188207 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f16_roundToInt.c"
189208 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f16_sqrt.c"
190209 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f16_sub.c"
210 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f16_to_extF80M.c"
191211 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f16_to_f128M.c"
192212 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f16_to_f64.c"
213 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f32_to_extF80M.c"
193214 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f32_to_f128M.c"
215 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f64_to_extF80M.c"
194216 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f64_to_f128M.c"
195217 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f64_to_f16.c"
196218 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/i32_to_f128M.c"
......@@ -198,6 +220,7 @@ set(EMBEDDED_SOFTFLOAT_SOURCES
198220 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_addCarryM.c"
199221 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_addComplCarryM.c"
200222 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_addF128M.c"
223 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_addExtF80M.c"
201224 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_addM.c"
202225 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_addMagsF16.c"
203226 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_addMagsF32.c"
......@@ -208,12 +231,14 @@ set(EMBEDDED_SOFTFLOAT_SOURCES
208231 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_approxRecip_1Ks.c"
209232 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_compare128M.c"
210233 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_compare96M.c"
234 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_compareNonnormExtF80M.c"
211235 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_countLeadingZeros16.c"
212236 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_countLeadingZeros32.c"
213237 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_countLeadingZeros64.c"
214238 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_countLeadingZeros8.c"
215239 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_eq128.c"
216240 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_invalidF128M.c"
241 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_invalidExtF80M.c"
217242 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_isNaNF128M.c"
218243 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_le128.c"
219244 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_lt128.c"
......@@ -224,7 +249,9 @@ set(EMBEDDED_SOFTFLOAT_SOURCES
224249 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_mulAddF32.c"
225250 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_mulAddF64.c"
226251 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_negXM.c"
252 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_normExtF80SigM.c"
227253 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_normRoundPackMToF128M.c"
254 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_normRoundPackMToExtF80M.c"
228255 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_normRoundPackToF16.c"
229256 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_normRoundPackToF32.c"
230257 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_normRoundPackToF64.c"
......@@ -235,6 +262,7 @@ set(EMBEDDED_SOFTFLOAT_SOURCES
235262 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_remStepMBy32.c"
236263 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_roundMToI64.c"
237264 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_roundMToUI64.c"
265 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_roundPackMToExtF80M.c"
238266 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_roundPackMToF128M.c"
239267 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_roundPackToF16.c"
240268 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_roundPackToF32.c"
......@@ -263,11 +291,14 @@ set(EMBEDDED_SOFTFLOAT_SOURCES
263291 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_subMagsF32.c"
264292 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_subMagsF64.c"
265293 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_tryPropagateNaNF128M.c"
294 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_tryPropagateNaNExtF80M.c"
266295 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f16_mulAdd.c"
267296 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f128M_mulAdd.c"
268297 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/softfloat_state.c"
269298 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/ui32_to_f128M.c"
270299 "${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"
271302)
272303add_library(embedded_softfloat STATIC ${EMBEDDED_SOFTFLOAT_SOURCES})
273304if(MSVC)
doc/langref.html.in+6
......@@ -737,6 +737,11 @@ pub fn main() void {
737737 <td><code class="c">double</code></td>
738738 <td>64-bit floating point (52-bit mantissa) IEEE-754-2008 binary64</td>
739739 </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>
740745 <tr>
741746 <th scope="row">{#syntax#}f128{#endsyntax#}</th>
742747 <td><code class="c">_Float128</code></td>
......@@ -1500,6 +1505,7 @@ fn divide(a: i32, b: i32) i32 {
15001505 <li>{#syntax#}f16{#endsyntax#} - IEEE-754-2008 binary16</li>
15011506 <li>{#syntax#}f32{#endsyntax#} - IEEE-754-2008 binary32</li>
15021507 <li>{#syntax#}f64{#endsyntax#} - IEEE-754-2008 binary64</li>
1508 <li>{#syntax#}f80{#endsyntax#} - IEEE-754-2008 80-bit extended precision</li>
15031509 <li>{#syntax#}f128{#endsyntax#} - IEEE-754-2008 binary128</li>
15041510 <li>{#syntax#}c_longdouble{#endsyntax#} - matches <code class="c">long double</code> for the target C ABI</li>
15051511 </ul>
lib/std/math.zig+18
......@@ -43,7 +43,21 @@ pub const f128_max = @bitCast(f128, @as(u128, 0x7FFEFFFFFFFFFFFFFFFFFFFFFFFFFFFF
4343pub const f128_epsilon = @bitCast(f128, @as(u128, 0x3F8F0000000000000000000000000000));
4444pub const f128_toint = 1.0 / f128_epsilon;
4545
46const 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
4654// float.h details
55pub const f80_true_min = @ptrCast(*const f80, &F80Repr{ .fraction = 1, .exp = 0 }).*;
56pub const f80_min = @ptrCast(*const f80, &F80Repr{ .fraction = 0x8000000000000000, .exp = 1 }).*;
57pub const f80_max = @ptrCast(*const f80, &F80Repr{ .fraction = 0xFFFFFFFFFFFFFFFF, .exp = 0x7FFE }).*;
58pub const f80_epsilon = @ptrCast(*const f80, &F80Repr{ .fraction = 0x8000000000000000, .exp = 0x3FC0 }).*;
59pub const f80_toint = 1.0 / f80_epsilon;
60
4761pub const f64_true_min = 4.94065645841246544177e-324;
4862pub const f64_min = 2.2250738585072014e-308;
4963pub const f64_max = 1.79769313486231570815e+308;
......@@ -91,6 +105,10 @@ pub const qnan_f64 = @bitCast(f64, qnan_u64);
91105pub const inf_u64 = @as(u64, 0x7FF << 52);
92106pub const inf_f64 = @bitCast(f64, inf_u64);
93107
108pub const inf_f80 = @ptrCast(*const f80, &F80Repr{ .fraction = 0x8000000000000000, .exp = 0x7fff }).*;
109pub const nan_f80 = @ptrCast(*const f80, &F80Repr{ .fraction = 0xA000000000000000, .exp = 0x7fff }).*;
110pub const qnan_f80 = @ptrCast(*const f80, &F80Repr{ .fraction = 0xC000000000000000, .exp = 0x7fff }).*;
111
94112pub const nan_u128 = @as(u128, 0x7fff0000000000000000000000000001);
95113pub const nan_f128 = @bitCast(f128, nan_u128);
96114
lib/std/math/epsilon.zig+1
......@@ -8,6 +8,7 @@ pub fn epsilon(comptime T: type) T {
88 f16 => math.f16_epsilon,
99 f32 => math.f32_epsilon,
1010 f64 => math.f64_epsilon,
11 f80 => math.f80_epsilon,
1112 f128 => math.f128_epsilon,
1213 else => @compileError("epsilon not implemented for " ++ @typeName(T)),
1314 };
lib/std/math/inf.zig+1
......@@ -7,6 +7,7 @@ pub fn inf(comptime T: type) T {
77 f16 => math.inf_f16,
88 f32 => math.inf_f32,
99 f64 => math.inf_f64,
10 f80 => math.inf_f80,
1011 f128 => math.inf_f128,
1112 else => @compileError("inf not implemented for " ++ @typeName(T)),
1213 };
lib/std/math/nan.zig+3
......@@ -6,6 +6,7 @@ pub fn nan(comptime T: type) T {
66 f16 => math.nan_f16,
77 f32 => math.nan_f32,
88 f64 => math.nan_f64,
9 f80 => math.nan_f80,
910 f128 => math.nan_f128,
1011 else => @compileError("nan not implemented for " ++ @typeName(T)),
1112 };
......@@ -19,6 +20,8 @@ pub fn snan(comptime T: type) T {
1920 f16 => @bitCast(f16, math.nan_u16),
2021 f32 => @bitCast(f32, math.nan_u32),
2122 f64 => @bitCast(f64, math.nan_u64),
23 f80 => @bitCast(f80, math.nan_u80),
24 f128 => @bitCast(f128, math.nan_u128),
2225 else => @compileError("snan not implemented for " ++ @typeName(T)),
2326 };
2427}
src/AstGen.zig+2
......@@ -7723,6 +7723,7 @@ const primitives = std.ComptimeStringMap(Zir.Inst.Ref, .{
77237723 .{ "f16", .f16_type },
77247724 .{ "f32", .f32_type },
77257725 .{ "f64", .f64_type },
7726 .{ "f80", .f80_type },
77267727 .{ "false", .bool_false },
77277728 .{ "i16", .i16_type },
77287729 .{ "i32", .i32_type },
......@@ -8732,6 +8733,7 @@ fn rvalue(
87328733 as_ty | @enumToInt(Zir.Inst.Ref.f16_type),
87338734 as_ty | @enumToInt(Zir.Inst.Ref.f32_type),
87348735 as_ty | @enumToInt(Zir.Inst.Ref.f64_type),
8736 as_ty | @enumToInt(Zir.Inst.Ref.f80_type),
87358737 as_ty | @enumToInt(Zir.Inst.Ref.f128_type),
87368738 as_ty | @enumToInt(Zir.Inst.Ref.anyopaque_type),
87378739 as_ty | @enumToInt(Zir.Inst.Ref.bool_type),
src/Sema.zig+3
......@@ -16950,6 +16950,7 @@ pub fn typeHasOnePossibleValue(
1695016950 .f16,
1695116951 .f32,
1695216952 .f64,
16953 .f80,
1695316954 .f128,
1695416955 .c_longdouble,
1695516956 .comptime_int,
......@@ -17227,6 +17228,7 @@ pub fn addType(sema: *Sema, ty: Type) !Air.Inst.Ref {
1722717228 .f16 => return .f16_type,
1722817229 .f32 => return .f32_type,
1722917230 .f64 => return .f64_type,
17231 .f80 => return .f80_type,
1723017232 .f128 => return .f128_type,
1723117233 .anyopaque => return .anyopaque_type,
1723217234 .bool => return .bool_type,
......@@ -17572,6 +17574,7 @@ fn typeRequiresComptime(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) C
1757217574 .f16,
1757317575 .f32,
1757417576 .f64,
17577 .f80,
1757517578 .f128,
1757617579 .anyopaque,
1757717580 .bool,
src/Zir.zig+5
......@@ -1639,6 +1639,7 @@ pub const Inst = struct {
16391639 f16_type,
16401640 f32_type,
16411641 f64_type,
1642 f80_type,
16421643 f128_type,
16431644 anyopaque_type,
16441645 bool_type,
......@@ -1809,6 +1810,10 @@ pub const Inst = struct {
18091810 .ty = Type.initTag(.type),
18101811 .val = Value.initTag(.f64_type),
18111812 },
1813 .f80_type = .{
1814 .ty = Type.initTag(.type),
1815 .val = Value.initTag(.f80_type),
1816 },
18121817 .f128_type = .{
18131818 .ty = Type.initTag(.type),
18141819 .val = Value.initTag(.f128_type),
src/stage1/all_types.hpp+2
......@@ -516,6 +516,7 @@ struct ZigValue {
516516 float16_t x_f16;
517517 float x_f32;
518518 double x_f64;
519 extFloat80_t x_f80;
519520 float128_t x_f128;
520521 bool x_bool;
521522 ConstBoundFnValue x_bound_fn;
......@@ -2089,6 +2090,7 @@ struct CodeGen {
20892090 ZigType *entry_f16;
20902091 ZigType *entry_f32;
20912092 ZigType *entry_f64;
2093 ZigType *entry_f80;
20922094 ZigType *entry_f128;
20932095 ZigType *entry_void;
20942096 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) {
56475647 case 16: return hash_combine(hash_val, &const_val->data.x_f16);
56485648 case 32: return hash_combine(hash_val, &const_val->data.x_f32);
56495649 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);
56505653 case 128: return hash_combine(hash_val, &const_val->data.x_f128);
56515654 default: zig_unreachable();
56525655 }
......@@ -6325,6 +6328,7 @@ void init_const_float(ZigValue *const_val, ZigType *type, double value) {
63256328 case 64:
63266329 const_val->data.x_f64 = value;
63276330 break;
6331 case 80:
63286332 case 128:
63296333 // if we need this, we should add a function that accepts a float128_t param
63306334 zig_unreachable();
......@@ -7218,6 +7222,8 @@ bool const_values_equal(CodeGen *g, ZigValue *a, ZigValue *b) {
72187222 return a->data.x_f32 == b->data.x_f32;
72197223 case 64:
72207224 return a->data.x_f64 == b->data.x_f64;
7225 case 80:
7226 return extF80M_eq(&a->data.x_f80, &b->data.x_f80);
72217227 case 128:
72227228 return f128M_eq(&a->data.x_f128, &b->data.x_f128);
72237229 default:
......@@ -7470,6 +7476,13 @@ void render_const_value(CodeGen *g, Buf *buf, ZigValue *const_val) {
74707476 case 64:
74717477 buf_appendf(buf, "%f", const_val->data.x_f64);
74727478 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 }
74737486 case 128:
74747487 {
74757488 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 *
15981598 return nullptr;
15991599}
16001600
1601
1602static 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
16011676static LLVMValueRef gen_widen_or_shorten(CodeGen *g, bool want_runtime_safety, ZigType *actual_type,
16021677 ZigType *wanted_type, LLVMValueRef expr_val)
16031678{
......@@ -1612,6 +1687,13 @@ static LLVMValueRef gen_widen_or_shorten(CodeGen *g, bool want_runtime_safety, Z
16121687 uint64_t actual_bits;
16131688 uint64_t wanted_bits;
16141689 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 }
16151697 actual_bits = scalar_actual_type->data.floating.bit_count;
16161698 wanted_bits = scalar_wanted_type->data.floating.bit_count;
16171699 } 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
31423224 }
31433225}
31443226
3227static 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
3237static 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
31453408static LLVMValueRef ir_render_bin_op(CodeGen *g, Stage1Air *executable,
31463409 Stage1AirInstBinOp *bin_op_instruction)
31473410{
......@@ -3151,6 +3414,10 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, Stage1Air *executable,
31513414
31523415 ZigType *operand_type = op1->value->type;
31533416 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
31543421
31553422 bool want_runtime_safety = bin_op_instruction->safety_check_on &&
31563423 ir_want_runtime_safety(g, &bin_op_instruction->base);
......@@ -3158,7 +3425,6 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, Stage1Air *executable,
31583425 LLVMValueRef op1_value = ir_llvm_value(g, op1);
31593426 LLVMValueRef op2_value = ir_llvm_value(g, op2);
31603427
3161
31623428 switch (op_id) {
31633429 case IrBinOpInvalid:
31643430 case IrBinOpArrayCat:
......@@ -5927,7 +6193,7 @@ static LLVMValueRef ir_render_prefetch(CodeGen *g, Stage1Air *executable, Stage1
59276193 static_assert(PrefetchCacheInstruction == 0, "");
59286194 static_assert(PrefetchCacheData == 1, "");
59296195 assert(instruction->cache == PrefetchCacheData || instruction->cache == PrefetchCacheInstruction);
5930
6196
59316197 // LLVM fails during codegen of instruction cache prefetchs for these architectures.
59326198 // This is an LLVM bug as the prefetch intrinsic should be a noop if not supported by the target.
59336199 // 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,
66226888 return nullptr;
66236889}
66246890
6891static 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
66256973static 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 }
66266979 LLVMValueRef operand = ir_llvm_value(g, instruction->operand);
66276980 LLVMValueRef fn_val = get_float_fn(g, instruction->base.value->type, ZigLLVMFnIdFloatOp, instruction->fn_id);
66286981 return LLVMBuildCall(g->builder, fn_val, &operand, 1, "");
66296982}
66306983
6984static 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
66317027static 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 }
66327033 LLVMValueRef op1 = ir_llvm_value(g, instruction->op1);
66337034 LLVMValueRef op2 = ir_llvm_value(g, instruction->op2);
66347035 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
76928093 return LLVMConstReal(get_llvm_type(g, type_entry), const_val->data.x_f32);
76938094 case 64:
76948095 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 }
76958108 case 128:
76968109 {
76978110 uint64_t buf[2];
76988111
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
77098123
77108124 LLVMValueRef as_int = LLVMConstIntOfArbitraryPrecision(LLVMInt128Type(), 2, buf);
77118125 return LLVMConstBitCast(as_int, get_llvm_type(g, type_entry));
......@@ -8911,6 +9325,24 @@ static void define_builtin_types(CodeGen *g) {
89119325 add_fp_entry(g, "f64", 64, LLVMDoubleType(), &g->builtin_types.entry_f64);
89129326 add_fp_entry(g, "f128", 128, LLVMFP128Type(), &g->builtin_types.entry_f128);
89139327
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
89149346 switch (g->zig_target->arch) {
89159347 case ZigLLVM_x86:
89169348 case ZigLLVM_x86_64:
src/stage1/ir.cpp+239-23
......@@ -2688,6 +2688,12 @@ static bool float_has_fraction(ZigValue *const_val) {
26882688 return floorf(const_val->data.x_f32) != const_val->data.x_f32;
26892689 case 64:
26902690 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 }
26912697 case 128:
26922698 {
26932699 float128_t floored;
......@@ -2716,6 +2722,15 @@ static void float_append_buf(Buf *buf, ZigValue *const_val) {
27162722 case 64:
27172723 buf_appendf(buf, "%f", const_val->data.x_f64);
27182724 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 }
27192734 case 128:
27202735 {
27212736 // TODO actual implementation
......@@ -2772,6 +2787,15 @@ static void float_init_bigint(BigInt *bigint, ZigValue *const_val) {
27722787 bigint->is_negative = true;
27732788 }
27742789 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;
27752799 case 128:
27762800 {
27772801 BigFloat tmp_float;
......@@ -2801,8 +2825,11 @@ static void float_init_bigfloat(ZigValue *dest_val, BigFloat *bigfloat) {
28012825 case 64:
28022826 dest_val->data.x_f64 = bigfloat_to_f64(bigfloat);
28032827 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 }
28062833 case 128:
28072834 dest_val->data.x_f128 = bigfloat_to_f128(bigfloat);
28082835 break;
......@@ -2828,6 +2855,9 @@ static void float_init_f16(ZigValue *dest_val, float16_t x) {
28282855 case 64:
28292856 dest_val->data.x_f64 = zig_f16_to_double(x);
28302857 break;
2858 case 80:
2859 f16_to_extF80M(x, &dest_val->data.x_f80);
2860 break;
28312861 case 128:
28322862 f16_to_f128M(x, &dest_val->data.x_f128);
28332863 break;
......@@ -2853,6 +2883,12 @@ static void float_init_f32(ZigValue *dest_val, float x) {
28532883 case 64:
28542884 dest_val->data.x_f64 = x;
28552885 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 }
28562892 case 128:
28572893 {
28582894 float32_t x_f32;
......@@ -2882,6 +2918,12 @@ static void float_init_f64(ZigValue *dest_val, double x) {
28822918 case 64:
28832919 dest_val->data.x_f64 = x;
28842920 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 }
28852927 case 128:
28862928 {
28872929 float64_t x_f64;
......@@ -2917,6 +2959,9 @@ static void float_init_f128(ZigValue *dest_val, float128_t x) {
29172959 memcpy(&dest_val->data.x_f64, &f64_val, sizeof(double));
29182960 break;
29192961 }
2962 case 80:
2963 f128M_to_extF80M(&x, &dest_val->data.x_f80);
2964 break;
29202965 case 128:
29212966 {
29222967 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) {
29442989 case 64:
29452990 float_init_f64(dest_val, src_val->data.x_f64);
29462991 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 }
29472998 case 128:
29482999 float_init_f128(dest_val, src_val->data.x_f128);
29493000 break;
......@@ -2966,6 +3017,8 @@ static bool float_is_nan(ZigValue *op) {
29663017 return op->data.x_f32 != op->data.x_f32;
29673018 case 64:
29683019 return op->data.x_f64 != op->data.x_f64;
3020 case 80:
3021 return zig_extF80_isNaN(&op->data.x_f80);
29693022 case 128:
29703023 return zig_f128_isNaN(&op->data.x_f128);
29713024 default:
......@@ -3006,6 +3059,14 @@ static Cmp float_cmp(ZigValue *op1, ZigValue *op2) {
30063059 } else {
30073060 return CmpEQ;
30083061 }
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 }
30093070 case 128:
30103071 if (f128M_lt(&op1->data.x_f128, &op2->data.x_f128)) {
30113072 return CmpLT;
......@@ -3061,7 +3122,18 @@ static Cmp float_cmp_zero(ZigValue *op) {
30613122 } else {
30623123 return CmpEQ;
30633124 }
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: {
30653137 float128_t zero_float;
30663138 ui32_to_f128M(0, &zero_float);
30673139 if (f128M_lt(&op->data.x_f128, &zero_float)) {
......@@ -3071,6 +3143,7 @@ static Cmp float_cmp_zero(ZigValue *op) {
30713143 } else {
30723144 return CmpGT;
30733145 }
3146 }
30743147 default:
30753148 zig_unreachable();
30763149 }
......@@ -3095,6 +3168,9 @@ static void float_add(ZigValue *out_val, ZigValue *op1, ZigValue *op2) {
30953168 case 64:
30963169 out_val->data.x_f64 = op1->data.x_f64 + op2->data.x_f64;
30973170 return;
3171 case 80:
3172 extF80M_add(&op1->data.x_f80, &op2->data.x_f80, &out_val->data.x_f80);
3173 return;
30983174 case 128:
30993175 f128M_add(&op1->data.x_f128, &op2->data.x_f128, &out_val->data.x_f128);
31003176 return;
......@@ -3122,6 +3198,9 @@ static void float_sub(ZigValue *out_val, ZigValue *op1, ZigValue *op2) {
31223198 case 64:
31233199 out_val->data.x_f64 = op1->data.x_f64 - op2->data.x_f64;
31243200 return;
3201 case 80:
3202 extF80M_sub(&op1->data.x_f80, &op2->data.x_f80, &out_val->data.x_f80);
3203 return;
31253204 case 128:
31263205 f128M_sub(&op1->data.x_f128, &op2->data.x_f128, &out_val->data.x_f128);
31273206 return;
......@@ -3149,6 +3228,9 @@ static void float_mul(ZigValue *out_val, ZigValue *op1, ZigValue *op2) {
31493228 case 64:
31503229 out_val->data.x_f64 = op1->data.x_f64 * op2->data.x_f64;
31513230 return;
3231 case 80:
3232 extF80M_mul(&op1->data.x_f80, &op2->data.x_f80, &out_val->data.x_f80);
3233 return;
31523234 case 128:
31533235 f128M_mul(&op1->data.x_f128, &op2->data.x_f128, &out_val->data.x_f128);
31543236 return;
......@@ -3176,6 +3258,9 @@ static void float_div(ZigValue *out_val, ZigValue *op1, ZigValue *op2) {
31763258 case 64:
31773259 out_val->data.x_f64 = op1->data.x_f64 / op2->data.x_f64;
31783260 return;
3261 case 80:
3262 extF80M_div(&op1->data.x_f80, &op2->data.x_f80, &out_val->data.x_f80);
3263 return;
31793264 case 128:
31803265 f128M_div(&op1->data.x_f128, &op2->data.x_f128, &out_val->data.x_f128);
31813266 return;
......@@ -3204,6 +3289,10 @@ static void float_div_trunc(ZigValue *out_val, ZigValue *op1, ZigValue *op2) {
32043289 case 64:
32053290 out_val->data.x_f64 = trunc(op1->data.x_f64 / op2->data.x_f64);
32063291 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;
32073296 case 128:
32083297 f128M_div(&op1->data.x_f128, &op2->data.x_f128, &out_val->data.x_f128);
32093298 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) {
32333322 case 64:
32343323 out_val->data.x_f64 = floor(op1->data.x_f64 / op2->data.x_f64);
32353324 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;
32363329 case 128:
32373330 f128M_div(&op1->data.x_f128, &op2->data.x_f128, &out_val->data.x_f128);
32383331 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) {
32613354 case 64:
32623355 out_val->data.x_f64 = fmod(op1->data.x_f64, op2->data.x_f64);
32633356 return;
3357 case 80:
3358 extF80M_rem(&op1->data.x_f80, &op2->data.x_f80, &out_val->data.x_f80);
3359 return;
32643360 case 128:
32653361 f128M_rem(&op1->data.x_f128, &op2->data.x_f128, &out_val->data.x_f128);
32663362 return;
......@@ -3290,6 +3386,14 @@ static void zig_f128M_mod(const float128_t* a, const float128_t* b, float128_t*
32903386 f128M_sub(a, c, c);
32913387}
32923388
3389// c = a - b * trunc(a / b)
3390static 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
32933397static void float_mod(ZigValue *out_val, ZigValue *op1, ZigValue *op2) {
32943398 assert(op1->type == op2->type);
32953399 out_val->type = op1->type;
......@@ -3306,6 +3410,9 @@ static void float_mod(ZigValue *out_val, ZigValue *op1, ZigValue *op2) {
33063410 case 64:
33073411 out_val->data.x_f64 = fmod(fmod(op1->data.x_f64, op2->data.x_f64) + op2->data.x_f64, op2->data.x_f64);
33083412 return;
3413 case 80:
3414 zig_extF80M_mod(&op1->data.x_f80, &op2->data.x_f80, &out_val->data.x_f80);
3415 return;
33093416 case 128:
33103417 zig_f128M_mod(&op1->data.x_f128, &op2->data.x_f128, &out_val->data.x_f128);
33113418 return;
......@@ -3351,6 +3458,15 @@ static void float_max(ZigValue *out_val, ZigValue *op1, ZigValue *op2) {
33513458 out_val->data.x_f64 = op1->data.x_f64 > op2->data.x_f64 ? op1->data.x_f64 : op2->data.x_f64;
33523459 }
33533460 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;
33543470 case 128:
33553471 if (zig_f128_isNaN(&op1->data.x_f128)) {
33563472 out_val->data.x_f128 = op2->data.x_f128;
......@@ -3402,6 +3518,15 @@ static void float_min(ZigValue *out_val, ZigValue *op1, ZigValue *op2) {
34023518 out_val->data.x_f64 = op1->data.x_f32 < op2->data.x_f64 ? op1->data.x_f64 : op2->data.x_f64;
34033519 }
34043520 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;
34053530 case 128:
34063531 if (zig_f128_isNaN(&op1->data.x_f128)) {
34073532 out_val->data.x_f128 = op2->data.x_f128;
......@@ -3434,6 +3559,9 @@ static void float_negate(ZigValue *out_val, ZigValue *op) {
34343559 case 64:
34353560 out_val->data.x_f64 = -op->data.x_f64;
34363561 return;
3562 case 80:
3563 extF80M_neg(&op->data.x_f80, &out_val->data.x_f80);
3564 return;
34373565 case 128:
34383566 f128M_neg(&op->data.x_f128, &out_val->data.x_f128);
34393567 return;
......@@ -3462,6 +3590,9 @@ void float_write_ieee597(ZigValue *op, uint8_t *buf, bool target_is_big_endian)
34623590 case 64:
34633591 memcpy(buf, &op->data.x_f64, 8);
34643592 break;
3593 case 80:
3594 memcpy(buf, &op->data.x_f80, 16);
3595 break;
34653596 case 128:
34663597 memcpy(buf, &op->data.x_f128, 16);
34673598 break;
......@@ -3511,6 +3642,9 @@ void float_read_ieee597(ZigValue *val, uint8_t *buf, bool target_is_big_endian)
35113642 case 64:
35123643 memcpy(&val->data.x_f64, ptr, 8);
35133644 return;
3645 case 80:
3646 memcpy(&val->data.x_f80, ptr, 16);
3647 return;
35143648 case 128:
35153649 memcpy(&val->data.x_f128, ptr, 16);
35163650 return;
......@@ -3538,8 +3672,12 @@ static void value_to_bigfloat(BigFloat *out, ZigValue *val) {
35383672 case 64:
35393673 bigfloat_init_64(out, val->data.x_f64);
35403674 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 }
35433681 case 128:
35443682 bigfloat_init_128(out, val->data.x_f128);
35453683 return;
......@@ -3628,8 +3766,14 @@ static bool ir_num_lit_fits_in_other_type(IrAnalyze *ira, Stage1AirInst *instruc
36283766 bigfloat_init_64(&orig_bf, tmp);
36293767 break;
36303768 }
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 }
36333777 case 128: {
36343778 float128_t tmp = bigfloat_to_f128(&tmp_bf);
36353779 bigfloat_init_128(&orig_bf, tmp);
......@@ -3673,8 +3817,15 @@ static bool ir_num_lit_fits_in_other_type(IrAnalyze *ira, Stage1AirInst *instruc
36733817 }
36743818 break;
36753819 }
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 }
36783829 case 128: {
36793830 float16_t tmp = f128M_to_f16(&const_val->data.x_f128);
36803831 float128_t orig;
......@@ -3698,8 +3849,15 @@ static bool ir_num_lit_fits_in_other_type(IrAnalyze *ira, Stage1AirInst *instruc
36983849 }
36993850 break;
37003851 }
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 }
37033861 case 128: {
37043862 float32_t tmp = f128M_to_f32(&const_val->data.x_f128);
37053863 float128_t orig;
......@@ -3715,8 +3873,15 @@ static bool ir_num_lit_fits_in_other_type(IrAnalyze *ira, Stage1AirInst *instruc
37153873 break;
37163874 case 64:
37173875 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 }
37203885 case 128: {
37213886 float64_t tmp = f128M_to_f64(&const_val->data.x_f128);
37223887 float128_t orig;
......@@ -3730,9 +3895,17 @@ static bool ir_num_lit_fits_in_other_type(IrAnalyze *ira, Stage1AirInst *instruc
37303895 zig_unreachable();
37313896 }
37323897 break;
3733 case 80:
3898 case 80: {
37343899 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 }
37363909 case 128:
37373910 return true;
37383911 default:
......@@ -5143,8 +5316,11 @@ static bool eval_const_expr_implicit_cast(IrAnalyze *ira, Scope *scope, AstNode
51435316 case 64:
51445317 const_val->data.x_f64 = bigfloat_to_f64(&other_val->data.x_bigfloat);
51455318 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 }
51485324 case 128:
51495325 const_val->data.x_f128 = bigfloat_to_f128(&other_val->data.x_bigfloat);
51505326 break;
......@@ -5172,8 +5348,11 @@ static bool eval_const_expr_implicit_cast(IrAnalyze *ira, Scope *scope, AstNode
51725348 case 64:
51735349 const_val->data.x_f64 = bigfloat_to_f64(&bigfloat);
51745350 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 }
51775356 case 128:
51785357 const_val->data.x_f128 = bigfloat_to_f128(&bigfloat);
51795358 break;
......@@ -18960,6 +19139,7 @@ static ZigType *type_info_to_type(IrAnalyze *ira, Scope *scope, AstNode *source_
1896019139 case 16: return ira->codegen->builtin_types.entry_f16;
1896119140 case 32: return ira->codegen->builtin_types.entry_f32;
1896219141 case 64: return ira->codegen->builtin_types.entry_f64;
19142 case 80: return ira->codegen->builtin_types.entry_f80;
1896319143 case 128: return ira->codegen->builtin_types.entry_f128;
1896419144 }
1896519145 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,
2194322123 case 64:
2194422124 out_val->data.x_f64 = fma(op1->data.x_f64, op2->data.x_f64, op3->data.x_f64);
2194522125 break;
22126 case 80:
22127 zig_panic("compiler bug: TODO: implement 'mulAdd' for type 'f80'. See https://github.com/ziglang/zig/issues/4026");
2194622128 case 128:
2194722129 f128M_mulAdd(&op1->data.x_f128, &op2->data.x_f128, &op3->data.x_f128, &out_val->data.x_f128);
2194822130 break;
......@@ -24156,10 +24338,44 @@ static ErrorMsg *ir_eval_float_op(IrAnalyze *ira, Scope *scope, AstNode *source_
2415624338 }
2415724339 break;
2415824340 }
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 }
2416324379 case 128: {
2416424380 float128_t *out, *in;
2416524381 if (float_type->id == ZigTypeIdComptimeFloat) {
src/stage1/softfloat.hpp+4
......@@ -56,4 +56,8 @@ static inline bool zig_f128_isNaN(float128_t *aPtr) {
5656 || ((absA64 == UINT64_C(0x7FFF000000000000)) && lo);
5757}
5858
59static inline bool zig_extF80_isNaN(extFloat80_t *aPtr) {
60 return (aPtr->signExp & 0x7FFF) == 0x7FFF && aPtr->signif & UINT64_C(0x7FFFFFFFFFFFFFFF);
61}
62
5963#endif
src/stage1/softfloat_ext.cpp+30-8
......@@ -28,13 +28,6 @@ void f128M_trunc(const float128_t *aPtr, float128_t *zPtr) {
2828 }
2929}
3030
31float16_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
3831void f128M_neg(const float128_t *aPtr, float128_t *zPtr) {
3932 // Toggle the sign bit.
4033#if ZIG_BYTE_ORDER == ZIG_LITTLE_ENDIAN
......@@ -46,4 +39,33 @@ void f128M_neg(const float128_t *aPtr, float128_t *zPtr) {
4639#else
4740#error Unsupported endian
4841#endif
49}
\ No newline at end of file
42}
43
44void 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
50void 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
60void 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
66float16_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);
77void f128M_trunc(const float128_t *aPtr, float128_t *zPtr);
88void f128M_neg(const float128_t *aPtr, float128_t *zPtr);
99
10void extF80M_abs(const extFloat80_t *aPtr, extFloat80_t *zPtr);
11void extF80M_trunc(const extFloat80_t *aPtr, extFloat80_t *zPtr);
12void extF80M_neg(const extFloat80_t *aPtr, extFloat80_t *zPtr);
13
1014float16_t f16_neg(const float16_t a);
1115
1216#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) {
10191019 }
10201020}
10211021
1022bool 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
10221033bool target_is_riscv(const ZigTarget *target) {
10231034 return target->arch == ZigLLVM_riscv32 || target->arch == ZigLLVM_riscv64;
10241035}
src/stage1/target.hpp+1
......@@ -81,6 +81,7 @@ bool target_is_sparc(const ZigTarget *target);
8181bool target_is_android(const ZigTarget *target);
8282bool target_has_debug_info(const ZigTarget *target);
8383bool target_long_double_is_f128(const ZigTarget *target);
84bool target_has_f80(const ZigTarget *target);
8485
8586uint32_t target_arch_pointer_bit_width(ZigLLVM_ArchType arch);
8687uint32_t target_arch_largest_atomic_bits(ZigLLVM_ArchType arch);
src/type.zig+17
......@@ -58,6 +58,7 @@ pub const Type = extern union {
5858 .f16,
5959 .f32,
6060 .f64,
61 .f80,
6162 .f128,
6263 .c_longdouble,
6364 => return .Float,
......@@ -833,6 +834,7 @@ pub const Type = extern union {
833834 .f16,
834835 .f32,
835836 .f64,
837 .f80,
836838 .f128,
837839 .bool,
838840 .void,
......@@ -1053,6 +1055,7 @@ pub const Type = extern union {
10531055 .f16,
10541056 .f32,
10551057 .f64,
1058 .f80,
10561059 .f128,
10571060 .bool,
10581061 .void,
......@@ -1371,6 +1374,7 @@ pub const Type = extern union {
13711374 .f16,
13721375 .f32,
13731376 .f64,
1377 .f80,
13741378 .f128,
13751379 .bool,
13761380 .void,
......@@ -1473,6 +1477,7 @@ pub const Type = extern union {
14731477 .f16 => return Value.initTag(.f16_type),
14741478 .f32 => return Value.initTag(.f32_type),
14751479 .f64 => return Value.initTag(.f64_type),
1480 .f80 => return Value.initTag(.f80_type),
14761481 .f128 => return Value.initTag(.f128_type),
14771482 .bool => return Value.initTag(.bool_type),
14781483 .void => return Value.initTag(.void_type),
......@@ -1543,6 +1548,7 @@ pub const Type = extern union {
15431548 .f16,
15441549 .f32,
15451550 .f64,
1551 .f80,
15461552 .f128,
15471553 .bool,
15481554 .anyerror,
......@@ -1858,6 +1864,7 @@ pub const Type = extern union {
18581864 .f16 => return 2,
18591865 .f32 => return 4,
18601866 .f64 => return 8,
1867 .f80 => return 16,
18611868 .f128 => return 16,
18621869 .c_longdouble => return 16,
18631870
......@@ -2138,6 +2145,7 @@ pub const Type = extern union {
21382145 .f16 => return 2,
21392146 .f32 => return 4,
21402147 .f64 => return 8,
2148 .f80 => return 16,
21412149 .f128 => return 16,
21422150 .c_longdouble => return 16,
21432151
......@@ -2277,6 +2285,7 @@ pub const Type = extern union {
22772285 .i16, .u16, .f16 => 16,
22782286 .i32, .u32, .f32 => 32,
22792287 .i64, .u64, .f64 => 64,
2288 .f80 => 80,
22802289 .u128, .i128, .f128 => 128,
22812290
22822291 .isize,
......@@ -3170,6 +3179,7 @@ pub const Type = extern union {
31703179 .f16,
31713180 .f32,
31723181 .f64,
3182 .f80,
31733183 .f128,
31743184 .c_longdouble,
31753185 => true,
......@@ -3184,6 +3194,7 @@ pub const Type = extern union {
31843194 .f16,
31853195 .f32,
31863196 .f64,
3197 .f80,
31873198 .f128,
31883199 .c_longdouble,
31893200 .comptime_float,
......@@ -3200,6 +3211,7 @@ pub const Type = extern union {
32003211 .f16 => 16,
32013212 .f32 => 32,
32023213 .f64 => 64,
3214 .f80 => 80,
32033215 .f128, .comptime_float => 128,
32043216 .c_longdouble => CType.longdouble.sizeInBits(target),
32053217
......@@ -3340,6 +3352,7 @@ pub const Type = extern union {
33403352 .f16,
33413353 .f32,
33423354 .f64,
3355 .f80,
33433356 .f128,
33443357 .c_longdouble,
33453358 .comptime_int,
......@@ -3381,6 +3394,7 @@ pub const Type = extern union {
33813394 .f16,
33823395 .f32,
33833396 .f64,
3397 .f80,
33843398 .f128,
33853399 .c_longdouble,
33863400 .comptime_int,
......@@ -3579,6 +3593,7 @@ pub const Type = extern union {
35793593 .f16,
35803594 .f32,
35813595 .f64,
3596 .f80,
35823597 .f128,
35833598 .anyopaque,
35843599 .bool,
......@@ -4334,6 +4349,7 @@ pub const Type = extern union {
43344349 f16,
43354350 f32,
43364351 f64,
4352 f80,
43374353 f128,
43384354 anyopaque,
43394355 bool,
......@@ -4453,6 +4469,7 @@ pub const Type = extern union {
44534469 .f16,
44544470 .f32,
44554471 .f64,
4472 .f80,
44564473 .f128,
44574474 .anyopaque,
44584475 .bool,
src/value.zig+5
......@@ -47,6 +47,7 @@ pub const Value = extern union {
4747 f16_type,
4848 f32_type,
4949 f64_type,
50 f80_type,
5051 f128_type,
5152 anyopaque_type,
5253 bool_type,
......@@ -205,6 +206,7 @@ pub const Value = extern union {
205206 .f16_type,
206207 .f32_type,
207208 .f64_type,
209 .f80_type,
208210 .f128_type,
209211 .anyopaque_type,
210212 .bool_type,
......@@ -398,6 +400,7 @@ pub const Value = extern union {
398400 .f16_type,
399401 .f32_type,
400402 .f64_type,
403 .f80_type,
401404 .f128_type,
402405 .anyopaque_type,
403406 .bool_type,
......@@ -630,6 +633,7 @@ pub const Value = extern union {
630633 .f16_type => return out_stream.writeAll("f16"),
631634 .f32_type => return out_stream.writeAll("f32"),
632635 .f64_type => return out_stream.writeAll("f64"),
636 .f80_type => return out_stream.writeAll("f80"),
633637 .f128_type => return out_stream.writeAll("f128"),
634638 .anyopaque_type => return out_stream.writeAll("anyopaque"),
635639 .bool_type => return out_stream.writeAll("bool"),
......@@ -824,6 +828,7 @@ pub const Value = extern union {
824828 .f16_type => Type.initTag(.f16),
825829 .f32_type => Type.initTag(.f32),
826830 .f64_type => Type.initTag(.f64),
831 .f80_type => Type.initTag(.f80),
827832 .f128_type => Type.initTag(.f128),
828833 .anyopaque_type => Type.initTag(.anyopaque),
829834 .bool_type => Type.initTag(.bool),
test/behavior/floatop_stage1.zig+81
......@@ -4,6 +4,7 @@ const math = std.math;
44const pi = std.math.pi;
55const e = std.math.e;
66const Vector = std.meta.Vector;
7const has_f80_rt = @import("builtin").cpu.arch == .x86_64;
78
89const epsilon = 0.000001;
910
......@@ -27,6 +28,10 @@ fn testSqrt() !void {
2728 var a: f64 = 25;
2829 try expect(@sqrt(a) == 5);
2930 }
31 if (has_f80_rt) {
32 var a: f80 = 25;
33 try expect(@sqrt(a) == 5);
34 }
3035 {
3136 const a: comptime_float = 25.0;
3237 try expect(@sqrt(a) == 5.0);
......@@ -86,6 +91,10 @@ fn testSin() !void {
8691 var a: f64 = 0;
8792 try expect(@sin(a) == 0);
8893 }
94 // {
95 // var a: f80 = 0;
96 // try expect(@sin(a) == 0);
97 // }
8998 {
9099 var v: Vector(4, f32) = [_]f32{ 1.1, 2.2, 3.3, 4.4 };
91100 var result = @sin(v);
......@@ -116,6 +125,10 @@ fn testCos() !void {
116125 var a: f64 = 0;
117126 try expect(@cos(a) == 1);
118127 }
128 // {
129 // var a: f80 = 0;
130 // try expect(@cos(a) == 1);
131 // }
119132 {
120133 var v: Vector(4, f32) = [_]f32{ 1.1, 2.2, 3.3, 4.4 };
121134 var result = @cos(v);
......@@ -146,6 +159,10 @@ fn testExp() !void {
146159 var a: f64 = 0;
147160 try expect(@exp(a) == 1);
148161 }
162 // {
163 // var a: f80 = 0;
164 // try expect(@exp(a) == 1);
165 // }
149166 {
150167 var v: Vector(4, f32) = [_]f32{ 1.1, 2.2, 0.3, 0.4 };
151168 var result = @exp(v);
......@@ -176,6 +193,10 @@ fn testExp2() !void {
176193 var a: f64 = 2;
177194 try expect(@exp2(a) == 4);
178195 }
196 // {
197 // var a: f80 = 2;
198 // try expect(@exp2(a) == 4);
199 // }
179200 {
180201 var v: Vector(4, f32) = [_]f32{ 1.1, 2.2, 0.3, 0.4 };
181202 var result = @exp2(v);
......@@ -208,6 +229,10 @@ fn testLog() !void {
208229 var a: f64 = e;
209230 try expect(@log(a) == 1 or @log(a) == @bitCast(f64, @as(u64, 0x3ff0000000000000)));
210231 }
232 // {
233 // var a: f80 = e;
234 // try expect(@log(a) == 1);
235 // }
211236 {
212237 var v: Vector(4, f32) = [_]f32{ 1.1, 2.2, 0.3, 0.4 };
213238 var result = @log(v);
......@@ -238,6 +263,10 @@ fn testLog2() !void {
238263 var a: f64 = 4;
239264 try expect(@log2(a) == 2);
240265 }
266 // {
267 // var a: f80 = 4;
268 // try expect(@log2(a) == 2);
269 // }
241270 {
242271 var v: Vector(4, f32) = [_]f32{ 1.1, 2.2, 0.3, 0.4 };
243272 var result = @log2(v);
......@@ -268,6 +297,10 @@ fn testLog10() !void {
268297 var a: f64 = 1000;
269298 try expect(@log10(a) == 3);
270299 }
300 // {
301 // var a: f80 = 1000;
302 // try expect(@log10(a) == 3);
303 // }
271304 {
272305 var v: Vector(4, f32) = [_]f32{ 1.1, 2.2, 0.3, 0.4 };
273306 var result = @log10(v);
......@@ -304,6 +337,12 @@ fn testFabs() !void {
304337 try expect(@fabs(a) == 2.5);
305338 try expect(@fabs(b) == 2.5);
306339 }
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 // }
307346 {
308347 var v: Vector(4, f32) = [_]f32{ 1.1, -2.2, 0.3, -0.4 };
309348 var result = @fabs(v);
......@@ -334,6 +373,10 @@ fn testFloor() !void {
334373 var a: f64 = 3.5;
335374 try expect(@floor(a) == 3);
336375 }
376 // {
377 // var a: f80 = 3.5;
378 // try expect(@floor(a) == 3);
379 // }
337380 {
338381 var v: Vector(4, f32) = [_]f32{ 1.1, -2.2, 0.3, -0.4 };
339382 var result = @floor(v);
......@@ -364,6 +407,10 @@ fn testCeil() !void {
364407 var a: f64 = 3.5;
365408 try expect(@ceil(a) == 4);
366409 }
410 // {
411 // var a: f80 = 3.5;
412 // try expect(@ceil(a) == 4);
413 // }
367414 {
368415 var v: Vector(4, f32) = [_]f32{ 1.1, -2.2, 0.3, -0.4 };
369416 var result = @ceil(v);
......@@ -394,6 +441,10 @@ fn testTrunc() !void {
394441 var a: f64 = -3.5;
395442 try expect(@trunc(a) == -3);
396443 }
444 // {
445 // var a: f80 = -3.5;
446 // try expect(@trunc(a) == -3);
447 // }
397448 {
398449 var v: Vector(4, f32) = [_]f32{ 1.1, -2.2, 0.3, -0.4 };
399450 var result = @trunc(v);
......@@ -403,3 +454,33 @@ fn testTrunc() !void {
403454 try expect(math.approxEqAbs(f32, @trunc(@as(f32, -0.4)), result[3], epsilon));
404455 }
405456}
457
458test "floating point comparisons" {
459 if (has_f80_rt) try testFloatComparisons();
460 comptime try testFloatComparisons();
461}
462
463fn 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;
55const maxInt = std.math.maxInt;
66const minInt = std.math.minInt;
77const mem = std.mem;
8const has_f80_rt = @import("builtin").cpu.arch == .x86_64;
89
910test "allow signed integer division/remainder when values are comptime known and positive or exact" {
1011 try expect(5 / 3 == 1);
......@@ -194,6 +195,8 @@ fn testSqrt(comptime T: type, x: T) !void {
194195test "@fabs" {
195196 try testFabs(f128, 12.0);
196197 comptime try testFabs(f128, 12.0);
198 if (has_f80_rt) try testFabs(f80, 12.0);
199 // comptime try testFabs(f80, 12.0);
197200 try testFabs(f64, 12.0);
198201 comptime try testFabs(f64, 12.0);
199202 try testFabs(f32, 12.0);
......@@ -217,6 +220,8 @@ test "@floor" {
217220 // FIXME: Generates a floorl function call
218221 // testFloor(f128, 12.0);
219222 comptime try testFloor(f128, 12.0);
223 // try testFloor(f80, 12.0);
224 comptime try testFloor(f80, 12.0);
220225 try testFloor(f64, 12.0);
221226 comptime try testFloor(f64, 12.0);
222227 try testFloor(f32, 12.0);
......@@ -240,6 +245,8 @@ test "@ceil" {
240245 // FIXME: Generates a ceill function call
241246 //testCeil(f128, 12.0);
242247 comptime try testCeil(f128, 12.0);
248 // try testCeil(f80, 12.0);
249 comptime try testCeil(f80, 12.0);
243250 try testCeil(f64, 12.0);
244251 comptime try testCeil(f64, 12.0);
245252 try testCeil(f32, 12.0);
......@@ -263,6 +270,14 @@ test "@trunc" {
263270 // FIXME: Generates a truncl function call
264271 //testTrunc(f128, 12.0);
265272 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 }
266281 try testTrunc(f64, 12.0);
267282 comptime try testTrunc(f64, 12.0);
268283 try testTrunc(f32, 12.0);
......@@ -294,6 +309,8 @@ test "@round" {
294309 // FIXME: Generates a roundl function call
295310 //testRound(f128, 12.0);
296311 comptime try testRound(f128, 12.0);
312 // try testRound(f80, 12.0);
313 comptime try testRound(f80, 12.0);
297314 try testRound(f64, 12.0);
298315 comptime try testRound(f64, 12.0);
299316 try testRound(f32, 12.0);
......@@ -333,10 +350,12 @@ test "NaN comparison" {
333350 try testNanEqNan(f32);
334351 try testNanEqNan(f64);
335352 try testNanEqNan(f128);
353 if (has_f80_rt) try testNanEqNan(f80);
336354 comptime try testNanEqNan(f16);
337355 comptime try testNanEqNan(f32);
338356 comptime try testNanEqNan(f64);
339357 comptime try testNanEqNan(f128);
358 // comptime try testNanEqNan(f80);
340359}
341360
342361fn testNanEqNan(comptime F: type) !void {
test/behavior/muladd.zig+6
......@@ -25,6 +25,12 @@ fn testMulAdd() !void {
2525 var c: f64 = 6.25;
2626 try expect(@mulAdd(f64, a, b, c) == 20);
2727 }
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 // }
2834 if (builtin.os.tag == .macos and builtin.cpu.arch == .aarch64) {
2935 // https://github.com/ziglang/zig/issues/9900
3036 return error.SkipZigTest;
test/behavior/type_stage1.zig+2-1
......@@ -13,8 +13,9 @@ test "Type.Float" {
1313 try testing.expect(f16 == @Type(TypeInfo{ .Float = TypeInfo.Float{ .bits = 16 } }));
1414 try testing.expect(f32 == @Type(TypeInfo{ .Float = TypeInfo.Float{ .bits = 32 } }));
1515 try testing.expect(f64 == @Type(TypeInfo{ .Float = TypeInfo.Float{ .bits = 64 } }));
16 try testing.expect(f80 == @Type(TypeInfo{ .Float = TypeInfo.Float{ .bits = 80 } }));
1617 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 });
1819}
1920
2021test "Type.Array" {
test/behavior/widening.zig+5
......@@ -2,6 +2,7 @@ const std = @import("std");
22const expect = std.testing.expect;
33const mem = std.mem;
44const builtin = @import("builtin");
5const has_f80_rt = @import("builtin").cpu.arch == .x86_64;
56
67test "integer widening" {
78 var a: u8 = 250;
......@@ -27,6 +28,10 @@ test "float widening" {
2728 try expect(a == b);
2829 try expect(b == c);
2930 try expect(c == d);
31 if (has_f80_rt) {
32 var e: f80 = c;
33 try expect(c == e);
34 }
3035}
3136
3237test "float widening f16 to f128" {