authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2023-05-06 22:27:39-04:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2023-05-08 07:36:20-04:00
logcba195c1170fff77c5210f023e019d72f13b9614
tree7f6af0b2b395f62bbd1ab5e79535c1dee98d0df6
parent3a5e3c52e0f09112989a2a40345305bfe9508431

x86_64: implement some float and float vector movement

This allows actually storing value of these supported types in registers, and not restricting them to stack slots.

8 files changed, 176 insertions(+), 43 deletions(-)

src/arch/x86_64/CodeGen.zig+100-27
......@@ -2008,6 +2008,11 @@ fn computeFrameLayout(self: *Self) !FrameLayout {
20082008 };
20092009}
20102010
2011fn getFrameAddrAlignment(self: *Self, frame_addr: FrameAddr) u32 {
2012 const alloc_align = @as(u32, 1) << self.frame_allocs.get(@enumToInt(frame_addr.index)).abi_align;
2013 return @min(alloc_align, @bitCast(u32, frame_addr.off) & (alloc_align - 1));
2014}
2015
20112016fn allocFrameIndex(self: *Self, alloc: FrameAlloc) !FrameIndex {
20122017 const frame_allocs_slice = self.frame_allocs.slice();
20132018 const frame_size = frame_allocs_slice.items(.abi_size);
......@@ -2051,24 +2056,36 @@ fn allocTempRegOrMem(self: *Self, elem_ty: Type, reg_ok: bool) !MCValue {
20512056 return self.allocRegOrMemAdvanced(elem_ty, null, reg_ok);
20522057}
20532058
2054fn allocRegOrMemAdvanced(self: *Self, elem_ty: Type, inst: ?Air.Inst.Index, reg_ok: bool) !MCValue {
2055 const abi_size = math.cast(u32, elem_ty.abiSize(self.target.*)) orelse {
2059fn allocRegOrMemAdvanced(self: *Self, ty: Type, inst: ?Air.Inst.Index, reg_ok: bool) !MCValue {
2060 const abi_size = math.cast(u32, ty.abiSize(self.target.*)) orelse {
20562061 const mod = self.bin_file.options.module.?;
2057 return self.fail("type '{}' too big to fit into stack frame", .{elem_ty.fmt(mod)});
2062 return self.fail("type '{}' too big to fit into stack frame", .{ty.fmt(mod)});
20582063 };
20592064
2060 if (reg_ok) {
2061 // Make sure the type can fit in a register before we try to allocate one.
2062 const ptr_bits = self.target.cpu.arch.ptrBitWidth();
2063 const ptr_bytes: u64 = @divExact(ptr_bits, 8);
2064 if (abi_size <= ptr_bytes) {
2065 if (self.register_manager.tryAllocReg(inst, regClassForType(elem_ty))) |reg| {
2065 if (reg_ok) need_mem: {
2066 if (abi_size <= @as(u32, switch (ty.zigTypeTag()) {
2067 .Float => switch (ty.floatBits(self.target.*)) {
2068 16, 32, 64, 128 => 16,
2069 80 => break :need_mem,
2070 else => unreachable,
2071 },
2072 .Vector => switch (ty.childType().zigTypeTag()) {
2073 .Float => switch (ty.childType().floatBits(self.target.*)) {
2074 16, 32, 64 => if (self.hasFeature(.avx)) 32 else 16,
2075 80, 128 => break :need_mem,
2076 else => unreachable,
2077 },
2078 else => break :need_mem,
2079 },
2080 else => 8,
2081 })) {
2082 if (self.register_manager.tryAllocReg(inst, regClassForType(ty))) |reg| {
20662083 return MCValue{ .register = registerAlias(reg, abi_size) };
20672084 }
20682085 }
20692086 }
20702087
2071 const frame_index = try self.allocFrameIndex(FrameAlloc.initType(elem_ty, self.target.*));
2088 const frame_index = try self.allocFrameIndex(FrameAlloc.initType(ty, self.target.*));
20722089 return .{ .load_frame = .{ .index = frame_index } };
20732090}
20742091
......@@ -4442,12 +4459,19 @@ fn airRound(self: *Self, inst: Air.Inst.Index, mode: Immediate) !void {
44424459 }),
44434460 };
44444461 assert(dst_mcv.isRegister());
4462 const abi_size = @intCast(u32, ty.abiSize(self.target.*));
4463 const dst_reg = registerAlias(dst_mcv.getReg().?, abi_size);
44454464 if (src_mcv.isRegister())
4446 try self.asmRegisterRegisterImmediate(mir_tag, dst_mcv.getReg().?, src_mcv.getReg().?, mode)
4465 try self.asmRegisterRegisterImmediate(
4466 mir_tag,
4467 dst_reg,
4468 registerAlias(src_mcv.getReg().?, abi_size),
4469 mode,
4470 )
44474471 else
44484472 try self.asmRegisterMemoryImmediate(
44494473 mir_tag,
4450 dst_mcv.getReg().?,
4474 dst_reg,
44514475 src_mcv.mem(Memory.PtrSize.fromSize(@intCast(u32, ty.abiSize(self.target.*)))),
44524476 mode,
44534477 );
......@@ -7847,19 +7871,43 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
78477871 return self.finishAirResult(inst, result);
78487872}
78497873
7850fn movMirTag(self: *Self, ty: Type) !Mir.Inst.Tag {
7851 return switch (ty.zigTypeTag()) {
7852 else => .mov,
7874fn movMirTag(self: *Self, ty: Type, aligned: bool) !Mir.Inst.Tag {
7875 switch (ty.zigTypeTag()) {
7876 else => return .mov,
78537877 .Float => switch (ty.floatBits(self.target.*)) {
78547878 16 => unreachable, // needs special handling
7855 32 => .movss,
7856 64 => .movsd,
7857 128 => .movaps,
7858 else => return self.fail("TODO movMirTag from {}", .{
7859 ty.fmt(self.bin_file.options.module.?),
7860 }),
7879 32 => return if (self.hasFeature(.avx)) .vmovss else .movss,
7880 64 => return if (self.hasFeature(.avx)) .vmovsd else .movsd,
7881 128 => return if (self.hasFeature(.avx))
7882 if (aligned) .vmovaps else .vmovups
7883 else if (aligned) .movaps else .movups,
7884 else => {},
78617885 },
7862 };
7886 .Vector => switch (ty.childType().zigTypeTag()) {
7887 .Float => switch (ty.childType().floatBits(self.target.*)) {
7888 16 => unreachable, // needs special handling
7889 32 => switch (ty.vectorLen()) {
7890 1 => return if (self.hasFeature(.avx)) .vmovss else .movss,
7891 2...4 => return if (self.hasFeature(.avx))
7892 if (aligned) .vmovaps else .vmovups
7893 else if (aligned) .movaps else .movups,
7894 5...8 => if (self.hasFeature(.avx)) return if (aligned) .vmovaps else .vmovups,
7895 else => {},
7896 },
7897 64 => switch (ty.vectorLen()) {
7898 1 => return if (self.hasFeature(.avx)) .vmovsd else .movsd,
7899 2 => return if (self.hasFeature(.avx))
7900 if (aligned) .vmovaps else .vmovups
7901 else if (aligned) .movaps else .movups,
7902 3...4 => if (self.hasFeature(.avx)) return if (aligned) .vmovaps else .vmovups,
7903 else => {},
7904 },
7905 else => {},
7906 },
7907 else => {},
7908 },
7909 }
7910 return self.fail("TODO movMirTag for {}", .{ty.fmt(self.bin_file.options.module.?)});
78637911}
78647912
78657913fn genCopy(self: *Self, ty: Type, dst_mcv: MCValue, src_mcv: MCValue) InnerError!void {
......@@ -8016,7 +8064,11 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr
80168064 0 => return self.genSetReg(dst_reg, ty, .{ .register = reg_off.reg }),
80178065 else => .lea,
80188066 },
8019 .indirect, .load_frame => try self.movMirTag(ty),
8067 .indirect => try self.movMirTag(ty, false),
8068 .load_frame => |frame_addr| try self.movMirTag(
8069 ty,
8070 self.getFrameAddrAlignment(frame_addr) >= ty.abiAlignment(self.target.*),
8071 ),
80208072 .lea_frame => .lea,
80218073 else => unreachable,
80228074 },
......@@ -8040,7 +8092,11 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr
80408092 )
80418093 else
80428094 self.asmRegisterMemory(
8043 try self.movMirTag(ty),
8095 try self.movMirTag(ty, mem.isAlignedGeneric(
8096 u32,
8097 @bitCast(u32, small_addr),
8098 ty.abiAlignment(self.target.*),
8099 )),
80448100 registerAlias(dst_reg, abi_size),
80458101 src_mem,
80468102 );
......@@ -8080,7 +8136,7 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr
80808136 )
80818137 else
80828138 try self.asmRegisterMemory(
8083 try self.movMirTag(ty),
8139 try self.movMirTag(ty, false),
80848140 registerAlias(dst_reg, abi_size),
80858141 src_mem,
80868142 );
......@@ -8194,7 +8250,24 @@ fn genSetMem(self: *Self, base: Memory.Base, disp: i32, ty: Type, src_mcv: MCVal
81948250 )
81958251 else
81968252 try self.asmMemoryRegister(
8197 try self.movMirTag(ty),
8253 try self.movMirTag(ty, switch (base) {
8254 .none => mem.isAlignedGeneric(
8255 u32,
8256 @bitCast(u32, disp),
8257 ty.abiAlignment(self.target.*),
8258 ),
8259 .reg => |reg| switch (reg) {
8260 .es, .cs, .ss, .ds => mem.isAlignedGeneric(
8261 u32,
8262 @bitCast(u32, disp),
8263 ty.abiAlignment(self.target.*),
8264 ),
8265 else => false,
8266 },
8267 .frame => |frame_index| self.getFrameAddrAlignment(
8268 .{ .index = frame_index, .off = disp },
8269 ) >= ty.abiAlignment(self.target.*),
8270 }),
81988271 dst_mem,
81998272 registerAlias(src_reg, abi_size),
82008273 );
......@@ -8415,7 +8488,7 @@ fn airBitCast(self: *Self, inst: Air.Inst.Index) !void {
84158488 defer if (operand_lock) |lock| self.register_manager.unlockReg(lock);
84168489
84178490 const dest = try self.allocRegOrMem(inst, true);
8418 try self.genCopy(self.air.typeOfIndex(inst), dest, operand);
8491 try self.genCopy(if (!dest.isMemory() or operand.isMemory()) dst_ty else src_ty, dest, operand);
84198492 break :result dest;
84208493 };
84218494 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
src/arch/x86_64/Encoding.zig+12-6
......@@ -206,7 +206,7 @@ pub fn format(
206206 try writer.print("+{s} ", .{tag});
207207 },
208208 .m, .mi, .m1, .mc, .vmi => try writer.print("/{d} ", .{encoding.modRmExt()}),
209 .mr, .rm, .rmi, .mri, .mrc, .rvm, .rvmi => try writer.writeAll("/r "),
209 .mr, .rm, .rmi, .mri, .mrc, .rvm, .rvmi, .mvr => try writer.writeAll("/r "),
210210 }
211211
212212 switch (encoding.data.op_en) {
......@@ -230,7 +230,7 @@ pub fn format(
230230 };
231231 try writer.print("{s} ", .{tag});
232232 },
233 .np, .fd, .td, .o, .m, .m1, .mc, .mr, .rm, .mrc, .rvm => {},
233 .np, .fd, .td, .o, .m, .m1, .mc, .mr, .rm, .mrc, .rvm, .mvr => {},
234234 }
235235
236236 try writer.print("{s} ", .{@tagName(encoding.mnemonic)});
......@@ -332,7 +332,12 @@ pub const Mnemonic = enum {
332332 // SSE4.1
333333 roundsd, roundss,
334334 // AVX
335 vmovddup, vmovshdup, vmovsldup,
335 vmovapd, vmovaps,
336 vmovddup,
337 vmovsd,
338 vmovshdup, vmovsldup,
339 vmovss,
340 vmovupd, vmovups,
336341 vpextrw, vpinsrw,
337342 vpshufhw, vpshuflw,
338343 vpsrld, vpsrlq, vpsrlw,
......@@ -357,7 +362,7 @@ pub const OpEn = enum {
357362 fd, td,
358363 m1, mc, mi, mr, rm,
359364 rmi, mri, mrc,
360 vmi, rvm, rvmi,
365 vmi, rvm, rvmi, mvr,
361366 // zig fmt: on
362367};
363368
......@@ -549,9 +554,10 @@ pub const Op = enum {
549554 return switch (op) {
550555 .rm8, .rm16, .rm32, .rm64,
551556 .r32_m16, .r64_m16,
552 .m8, .m16, .m32, .m64, .m80, .m128,
557 .m8, .m16, .m32, .m64, .m80, .m128, .m256,
553558 .m,
554 .xmm_m32, .xmm_m64, .xmm_m128, .ymm_m256,
559 .xmm_m32, .xmm_m64, .xmm_m128,
560 .ymm_m256,
555561 => true,
556562 else => false,
557563 };
src/arch/x86_64/Lower.zig+6
......@@ -184,9 +184,15 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct {
184184 .roundsd,
185185 .roundss,
186186
187 .vmovapd,
188 .vmovaps,
187189 .vmovddup,
190 .vmovsd,
188191 .vmovshdup,
189192 .vmovsldup,
193 .vmovss,
194 .vmovupd,
195 .vmovups,
190196 .vpextrw,
191197 .vpinsrw,
192198 .vpshufhw,
src/arch/x86_64/Mir.zig+12
......@@ -282,12 +282,24 @@ pub const Inst = struct {
282282 /// Round scalar single-precision floating-point values
283283 roundss,
284284
285 /// Move aligned packed double-precision floating-point values
286 vmovapd,
287 /// Move aligned packed single-precision floating-point values
288 vmovaps,
285289 /// Replicate double floating-point values
286290 vmovddup,
291 /// Move or merge scalar double-precision floating-point value
292 vmovsd,
287293 /// Replicate single floating-point values
288294 vmovshdup,
289295 /// Replicate single floating-point values
290296 vmovsldup,
297 /// Move or merge scalar single-precision floating-point value
298 vmovss,
299 /// Move unaligned packed double-precision floating-point values
300 vmovupd,
301 /// Move unaligned packed single-precision floating-point values
302 vmovups,
291303 /// Extract word
292304 vpextrw,
293305 /// Insert word
src/arch/x86_64/encoder.zig+8-5
......@@ -228,7 +228,7 @@ pub const Instruction = struct {
228228 .td => try encoder.imm64(inst.ops[0].mem.moffs.offset),
229229 else => {
230230 const mem_op = switch (data.op_en) {
231 .m, .mi, .m1, .mc, .mr, .mri, .mrc => inst.ops[0],
231 .m, .mi, .m1, .mc, .mr, .mri, .mrc, .mvr => inst.ops[0],
232232 .rm, .rmi, .vmi => inst.ops[1],
233233 .rvm, .rvmi => inst.ops[2],
234234 else => unreachable,
......@@ -239,6 +239,7 @@ pub const Instruction = struct {
239239 .m, .mi, .m1, .mc, .vmi => enc.modRmExt(),
240240 .mr, .mri, .mrc => inst.ops[1].reg.lowEnc(),
241241 .rm, .rmi, .rvm, .rvmi => inst.ops[0].reg.lowEnc(),
242 .mvr => inst.ops[2].reg.lowEnc(),
242243 else => unreachable,
243244 };
244245 try encoder.modRm_direct(rm, reg.lowEnc());
......@@ -248,6 +249,7 @@ pub const Instruction = struct {
248249 .m, .mi, .m1, .mc, .vmi => .none,
249250 .mr, .mri, .mrc => inst.ops[1],
250251 .rm, .rmi, .rvm, .rvmi => inst.ops[0],
252 .mvr => inst.ops[2],
251253 else => unreachable,
252254 };
253255 try encodeMemory(enc, mem, op, encoder);
......@@ -315,7 +317,7 @@ pub const Instruction = struct {
315317 }
316318 else
317319 null,
318 .vmi, .rvm, .rvmi => unreachable,
320 .vmi, .rvm, .rvmi, .mvr => unreachable,
319321 };
320322 if (segment_override) |seg| {
321323 legacy.setSegmentOverride(seg);
......@@ -350,7 +352,7 @@ pub const Instruction = struct {
350352 rex.b = b_x_op.isBaseExtended();
351353 rex.x = b_x_op.isIndexExtended();
352354 },
353 .vmi, .rvm, .rvmi => unreachable,
355 .vmi, .rvm, .rvmi, .mvr => unreachable,
354356 }
355357
356358 try encoder.rex(rex);
......@@ -372,10 +374,11 @@ pub const Instruction = struct {
372374 switch (op_en) {
373375 .np, .i, .zi, .fd, .td, .d => {},
374376 .o, .oi => vex.b = inst.ops[0].reg.isExtended(),
375 .m, .mi, .m1, .mc, .mr, .rm, .rmi, .mri, .mrc, .vmi, .rvm, .rvmi => {
377 .m, .mi, .m1, .mc, .mr, .rm, .rmi, .mri, .mrc, .vmi, .rvm, .rvmi, .mvr => {
376378 const r_op = switch (op_en) {
377379 .rm, .rmi, .rvm, .rvmi => inst.ops[0],
378380 .mr, .mri, .mrc => inst.ops[1],
381 .mvr => inst.ops[2],
379382 .m, .mi, .m1, .mc, .vmi => .none,
380383 else => unreachable,
381384 };
......@@ -383,7 +386,7 @@ pub const Instruction = struct {
383386
384387 const b_x_op = switch (op_en) {
385388 .rm, .rmi, .vmi => inst.ops[1],
386 .m, .mi, .m1, .mc, .mr, .mri, .mrc => inst.ops[0],
389 .m, .mi, .m1, .mc, .mr, .mri, .mrc, .mvr => inst.ops[0],
387390 .rvm, .rvmi => inst.ops[2],
388391 else => unreachable,
389392 };
src/arch/x86_64/encodings.zig+30
......@@ -974,12 +974,42 @@ pub const table = [_]Entry{
974974 .{ .roundsd, .rmi, &.{ .xmm, .xmm_m64, .imm8 }, &.{ 0x66, 0x0f, 0x3a, 0x0b }, 0, .none, .sse4_1 },
975975
976976 // AVX
977 .{ .vmovapd, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0x28 }, 0, .vex_128, .avx },
978 .{ .vmovapd, .mr, &.{ .xmm_m128, .xmm }, &.{ 0x66, 0x0f, 0x29 }, 0, .vex_128, .avx },
979 .{ .vmovapd, .rm, &.{ .ymm, .ymm_m256 }, &.{ 0x66, 0x0f, 0x28 }, 0, .vex_256, .avx },
980 .{ .vmovapd, .mr, &.{ .ymm_m256, .ymm }, &.{ 0x66, 0x0f, 0x29 }, 0, .vex_256, .avx },
981
982 .{ .vmovaps, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0x0f, 0x28 }, 0, .vex_128, .avx },
983 .{ .vmovaps, .mr, &.{ .xmm_m128, .xmm }, &.{ 0x0f, 0x29 }, 0, .vex_128, .avx },
984 .{ .vmovaps, .rm, &.{ .ymm, .ymm_m256 }, &.{ 0x0f, 0x28 }, 0, .vex_256, .avx },
985 .{ .vmovaps, .mr, &.{ .ymm_m256, .ymm }, &.{ 0x0f, 0x29 }, 0, .vex_256, .avx },
986
977987 .{ .vmovddup, .rm, &.{ .xmm, .xmm_m64 }, &.{ 0xf2, 0x0f, 0x12 }, 0, .vex_128, .avx },
978988
989 .{ .vmovsd, .rvm, &.{ .xmm, .xmm, .xmm }, &.{ 0xf2, 0x0f, 0x10 }, 0, .vex_128, .avx },
990 .{ .vmovsd, .rm, &.{ .xmm, .m64 }, &.{ 0xf2, 0x0f, 0x10 }, 0, .vex_128, .avx },
991 .{ .vmovsd, .mvr, &.{ .xmm, .xmm, .xmm }, &.{ 0xf2, 0x0f, 0x11 }, 0, .vex_128, .avx },
992 .{ .vmovsd, .mr, &.{ .m64, .xmm }, &.{ 0xf2, 0x0f, 0x11 }, 0, .vex_128, .avx },
993
979994 .{ .vmovshdup, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0xf3, 0x0f, 0x16 }, 0, .vex_128, .avx },
980995
981996 .{ .vmovsldup, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0xf3, 0x0f, 0x12 }, 0, .vex_128, .avx },
982997
998 .{ .vmovss, .rvm, &.{ .xmm, .xmm, .xmm }, &.{ 0xf3, 0x0f, 0x10 }, 0, .vex_128, .avx },
999 .{ .vmovss, .rm, &.{ .xmm, .m32 }, &.{ 0xf3, 0x0f, 0x10 }, 0, .vex_128, .avx },
1000 .{ .vmovss, .mvr, &.{ .xmm, .xmm, .xmm }, &.{ 0xf3, 0x0f, 0x11 }, 0, .vex_128, .avx },
1001 .{ .vmovss, .mr, &.{ .m32, .xmm }, &.{ 0xf3, 0x0f, 0x11 }, 0, .vex_128, .avx },
1002
1003 .{ .vmovupd, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0x10 }, 0, .vex_128, .avx },
1004 .{ .vmovupd, .mr, &.{ .xmm_m128, .xmm }, &.{ 0x66, 0x0f, 0x11 }, 0, .vex_128, .avx },
1005 .{ .vmovupd, .rm, &.{ .ymm, .ymm_m256 }, &.{ 0x66, 0x0f, 0x10 }, 0, .vex_256, .avx },
1006 .{ .vmovupd, .mr, &.{ .ymm_m256, .ymm }, &.{ 0x66, 0x0f, 0x11 }, 0, .vex_256, .avx },
1007
1008 .{ .vmovups, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0x0f, 0x10 }, 0, .vex_128, .avx },
1009 .{ .vmovups, .mr, &.{ .xmm_m128, .xmm }, &.{ 0x0f, 0x11 }, 0, .vex_128, .avx },
1010 .{ .vmovups, .rm, &.{ .ymm, .ymm_m256 }, &.{ 0x0f, 0x10 }, 0, .vex_256, .avx },
1011 .{ .vmovups, .mr, &.{ .ymm_m256, .ymm }, &.{ 0x0f, 0x11 }, 0, .vex_256, .avx },
1012
9831013 .{ .vpextrw, .mri, &.{ .r32, .xmm, .imm8 }, &.{ 0x66, 0x0f, 0x15 }, 0, .vex_128, .avx },
9841014 .{ .vpextrw, .mri, &.{ .r64, .xmm, .imm8 }, &.{ 0x66, 0x0f, 0x15 }, 0, .vex_128_long, .avx },
9851015 .{ .vpextrw, .mri, &.{ .r32_m16, .xmm, .imm8 }, &.{ 0x66, 0x0f, 0x3a, 0x15 }, 0, .vex_128, .avx },
test/behavior/math.zig+2-1
......@@ -399,7 +399,8 @@ fn testBinaryNot128(comptime Type: type, x: Type) !void {
399399
400400test "division" {
401401 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
402 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
402 if (builtin.zig_backend == .stage2_x86_64 and
403 !comptime std.Target.x86.featureSetHas(builtin.cpu.features, .sse4_1)) return error.SkipZigTest; // TODO
403404 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
404405 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
405406 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
test/behavior/muladd.zig+6-4
......@@ -2,9 +2,11 @@ const std = @import("std");
22const builtin = @import("builtin");
33const expect = std.testing.expect;
44
5const stage2_x86_64_without_hardware_fma_support = builtin.zig_backend == .stage2_x86_64 and
6 !std.Target.x86.featureSetHas(builtin.cpu.features, .fma);
7
58test "@mulAdd" {
6 if (builtin.zig_backend == .stage2_x86_64 and
7 !comptime std.Target.x86.featureSetHas(builtin.cpu.features, .fma)) return error.SkipZigTest; // TODO
9 if (stage2_x86_64_without_hardware_fma_support) return error.SkipZigTest; // TODO
810 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
911 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1012 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
......@@ -118,7 +120,7 @@ fn vector32() !void {
118120
119121test "vector f32" {
120122 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
121 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
123 if (stage2_x86_64_without_hardware_fma_support) return error.SkipZigTest; // TODO
122124 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
123125 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
124126 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
......@@ -141,7 +143,7 @@ fn vector64() !void {
141143
142144test "vector f64" {
143145 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
144 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
146 if (stage2_x86_64_without_hardware_fma_support) return error.SkipZigTest; // TODO
145147 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
146148 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
147149 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO