authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2023-09-30 20:07:59-04:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2023-10-01 15:09:52-04:00
log1eb023908d50e601f68f2200c3cf126ca3035167
tree25a64718cb04673e42845bcb5237bb854713590c
parentc3042cbe12dec72c07e021a76f7e5438a03dc854

x86_64: implement float round builtins


6 files changed, 216 insertions(+), 100 deletions(-)

src/arch/x86_64/CodeGen.zig+196-79
......@@ -215,6 +215,7 @@ pub const MCValue = union(enum) {
215215 /// but it has not been spilled there yet in the current control flow.
216216 /// Payload is a frame index.
217217 reserved_frame: FrameIndex,
218 air_ref: Air.Inst.Ref,
218219
219220 fn isMemory(mcv: MCValue) bool {
220221 return switch (mcv) {
......@@ -278,6 +279,7 @@ pub const MCValue = union(enum) {
278279 .lea_tlv,
279280 .lea_frame,
280281 .reserved_frame,
282 .air_ref,
281283 => unreachable, // not in memory
282284 .memory => |addr| .{ .immediate = addr },
283285 .indirect => |reg_off| switch (reg_off.off) {
......@@ -306,6 +308,7 @@ pub const MCValue = union(enum) {
306308 .load_tlv,
307309 .load_frame,
308310 .reserved_frame,
311 .air_ref,
309312 => unreachable, // not dereferenceable
310313 .immediate => |addr| .{ .memory = addr },
311314 .register => |reg| .{ .indirect = .{ .reg = reg } },
......@@ -335,6 +338,7 @@ pub const MCValue = union(enum) {
335338 .lea_tlv,
336339 .load_frame,
337340 .reserved_frame,
341 .air_ref,
338342 => unreachable, // not offsettable
339343 .immediate => |imm| .{ .immediate = @bitCast(@as(i64, @bitCast(imm)) +% off) },
340344 .register => |reg| .{ .register_offset = .{ .reg = reg, .off = off } },
......@@ -366,6 +370,7 @@ pub const MCValue = union(enum) {
366370 .lea_tlv,
367371 .lea_frame,
368372 .reserved_frame,
373 .air_ref,
369374 => unreachable,
370375 .memory => |addr| if (math.cast(i32, @as(i64, @bitCast(addr)))) |small_addr|
371376 Memory.sib(ptr_size, .{ .base = .{ .reg = .ds }, .disp = small_addr })
......@@ -405,6 +410,7 @@ pub const MCValue = union(enum) {
405410 .load_frame => |pl| try writer.print("[{} + 0x{x}]", .{ pl.index, pl.off }),
406411 .lea_frame => |pl| try writer.print("{} + 0x{x}", .{ pl.index, pl.off }),
407412 .reserved_frame => |pl| try writer.print("(dead:{})", .{pl}),
413 .air_ref => |pl| try writer.print("(air:0x{x})", .{@intFromEnum(pl)}),
408414 }
409415 }
410416};
......@@ -433,6 +439,7 @@ const InstTracking = struct {
433439 => result,
434440 .dead,
435441 .reserved_frame,
442 .air_ref,
436443 => unreachable,
437444 .eflags,
438445 .register,
......@@ -491,6 +498,7 @@ const InstTracking = struct {
491498 .register_overflow,
492499 .indirect,
493500 .reserved_frame,
501 .air_ref,
494502 => unreachable,
495503 };
496504 }
......@@ -531,6 +539,7 @@ const InstTracking = struct {
531539 .register_offset,
532540 .register_overflow,
533541 .indirect,
542 .air_ref,
534543 => unreachable,
535544 }
536545 }
......@@ -1809,9 +1818,9 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
18091818 .round,
18101819 => |tag| try self.airUnaryMath(inst, tag),
18111820
1812 .floor => try self.airRound(inst, 0b1_0_01),
1813 .ceil => try self.airRound(inst, 0b1_0_10),
1814 .trunc_float => try self.airRound(inst, 0b1_0_11),
1821 .floor => try self.airRound(inst, .{ .mode = .down, .precision = .inexact }),
1822 .ceil => try self.airRound(inst, .{ .mode = .up, .precision = .inexact }),
1823 .trunc_float => try self.airRound(inst, .{ .mode = .zero, .precision = .inexact }),
18151824 .sqrt => try self.airSqrt(inst),
18161825 .neg => try self.airFloatSign(inst),
18171826
......@@ -2439,7 +2448,7 @@ fn restoreState(self: *Self, state: State, deaths: []const Air.Inst.Index, compt
24392448}
24402449
24412450pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void {
2442 const tracking = self.inst_tracking.getPtr(inst).?;
2451 const tracking = self.inst_tracking.getPtr(inst) orelse return;
24432452 assert(tracking.getReg().?.id() == reg.id());
24442453 try tracking.spill(self, inst);
24452454 tracking.trackSpill(self, inst);
......@@ -2545,7 +2554,7 @@ fn airFptrunc(self: *Self, inst: Air.Inst.Index) !void {
25452554 floatCompilerRtAbiName(src_bits),
25462555 floatCompilerRtAbiName(dst_bits),
25472556 }) catch unreachable,
2548 } }, &.{ty_op.operand});
2557 } }, &.{src_ty}, &.{.{ .air_ref = ty_op.operand }});
25492558 }
25502559
25512560 const src_mcv = try self.resolveInst(ty_op.operand);
......@@ -2644,7 +2653,7 @@ fn airFpext(self: *Self, inst: Air.Inst.Index) !void {
26442653 floatCompilerRtAbiName(src_bits),
26452654 floatCompilerRtAbiName(dst_bits),
26462655 }) catch unreachable,
2647 } }, &.{ty_op.operand});
2656 } }, &.{src_ty}, &.{.{ .air_ref = ty_op.operand }});
26482657 }
26492658
26502659 const src_mcv = try self.resolveInst(ty_op.operand);
......@@ -5073,7 +5082,26 @@ fn airFloatSign(self: *Self, inst: Air.Inst.Index) !void {
50735082 return self.floatSign(inst, un_op, ty);
50745083}
50755084
5076fn airRound(self: *Self, inst: Air.Inst.Index, mode: u4) !void {
5085const RoundMode = packed struct(u5) {
5086 mode: enum(u4) {
5087 /// Round to nearest (even)
5088 nearest = 0b0_00,
5089 /// Round down (toward -∞)
5090 down = 0b0_01,
5091 /// Round up (toward +∞)
5092 up = 0b0_10,
5093 /// Round toward zero (truncate)
5094 zero = 0b0_11,
5095 /// Use current rounding mode of MXCSR.RC
5096 mxcsr = 0b1_00,
5097 },
5098 precision: enum(u1) {
5099 normal = 0b0,
5100 inexact = 0b1,
5101 },
5102};
5103
5104fn airRound(self: *Self, inst: Air.Inst.Index, mode: RoundMode) !void {
50775105 const un_op = self.air.instructions.items(.data)[inst].un_op;
50785106 const ty = self.typeOf(un_op);
50795107
......@@ -5089,12 +5117,9 @@ fn airRound(self: *Self, inst: Air.Inst.Index, mode: u4) !void {
50895117 return self.finishAir(inst, dst_mcv, .{ un_op, .none, .none });
50905118}
50915119
5092fn genRound(self: *Self, ty: Type, dst_reg: Register, src_mcv: MCValue, mode: u4) !void {
5120fn genRound(self: *Self, ty: Type, dst_reg: Register, src_mcv: MCValue, mode: RoundMode) !void {
50935121 const mod = self.bin_file.options.module.?;
5094 if (!self.hasFeature(.sse4_1))
5095 return self.fail("TODO implement genRound without sse4_1 feature", .{});
5096
5097 const mir_tag = @as(?Mir.Inst.FixedTag, switch (ty.zigTypeTag(mod)) {
5122 const mir_tag = @as(?Mir.Inst.FixedTag, if (self.hasFeature(.sse4_1)) switch (ty.zigTypeTag(mod)) {
50985123 .Float => switch (ty.floatBits(self.target.*)) {
50995124 32 => if (self.hasFeature(.avx)) .{ .v_ss, .round } else .{ ._ss, .round },
51005125 64 => if (self.hasFeature(.avx)) .{ .v_sd, .round } else .{ ._sd, .round },
......@@ -5121,9 +5146,28 @@ fn genRound(self: *Self, ty: Type, dst_reg: Register, src_mcv: MCValue, mode: u4
51215146 else => null,
51225147 },
51235148 else => unreachable,
5124 }) orelse return self.fail("TODO implement genRound for {}", .{
5125 ty.fmt(self.bin_file.options.module.?),
5126 });
5149 } else null) orelse {
5150 if (ty.zigTypeTag(mod) != .Float) return self.fail("TODO implement genRound for {}", .{
5151 ty.fmt(self.bin_file.options.module.?),
5152 });
5153
5154 var callee: ["__trunc?".len]u8 = undefined;
5155 const res = try self.genCall(.{ .lib = .{
5156 .return_type = ty.toIntern(),
5157 .param_types = &.{ty.toIntern()},
5158 .callee = std.fmt.bufPrint(&callee, "{s}{s}{s}", .{
5159 floatLibcAbiPrefix(ty),
5160 switch (mode.mode) {
5161 .down => "floor",
5162 .up => "ceil",
5163 .zero => "trunc",
5164 else => unreachable,
5165 },
5166 floatLibcAbiSuffix(ty),
5167 }) catch unreachable,
5168 } }, &.{ty}, &.{src_mcv});
5169 return self.genSetReg(dst_reg, ty, res);
5170 };
51275171 const abi_size: u32 = @intCast(ty.abiSize(mod));
51285172 const dst_alias = registerAlias(dst_reg, abi_size);
51295173 switch (mir_tag[0]) {
......@@ -5132,7 +5176,7 @@ fn genRound(self: *Self, ty: Type, dst_reg: Register, src_mcv: MCValue, mode: u4
51325176 dst_alias,
51335177 dst_alias,
51345178 src_mcv.mem(Memory.PtrSize.fromSize(abi_size)),
5135 Immediate.u(mode),
5179 Immediate.u(@as(u5, @bitCast(mode))),
51365180 ) else try self.asmRegisterRegisterRegisterImmediate(
51375181 mir_tag,
51385182 dst_alias,
......@@ -5141,13 +5185,13 @@ fn genRound(self: *Self, ty: Type, dst_reg: Register, src_mcv: MCValue, mode: u4
51415185 src_mcv.getReg().?
51425186 else
51435187 try self.copyToTmpRegister(ty, src_mcv), abi_size),
5144 Immediate.u(mode),
5188 Immediate.u(@as(u5, @bitCast(mode))),
51455189 ),
51465190 else => if (src_mcv.isMemory()) try self.asmRegisterMemoryImmediate(
51475191 mir_tag,
51485192 dst_alias,
51495193 src_mcv.mem(Memory.PtrSize.fromSize(abi_size)),
5150 Immediate.u(mode),
5194 Immediate.u(@as(u5, @bitCast(mode))),
51515195 ) else try self.asmRegisterRegisterImmediate(
51525196 mir_tag,
51535197 dst_alias,
......@@ -5155,7 +5199,7 @@ fn genRound(self: *Self, ty: Type, dst_reg: Register, src_mcv: MCValue, mode: u4
51555199 src_mcv.getReg().?
51565200 else
51575201 try self.copyToTmpRegister(ty, src_mcv), abi_size),
5158 Immediate.u(mode),
5202 Immediate.u(@as(u5, @bitCast(mode))),
51595203 ),
51605204 }
51615205}
......@@ -5353,34 +5397,29 @@ fn airSqrt(self: *Self, inst: Air.Inst.Index) !void {
53535397
53545398fn airUnaryMath(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void {
53555399 const un_op = self.air.instructions.items(.data)[inst].un_op;
5356 const ty = self.typeOf(un_op).toIntern();
5400 const ty = self.typeOf(un_op);
5401 var callee: ["__round?".len]u8 = undefined;
53575402 const result = try self.genCall(.{ .lib = .{
5358 .return_type = ty,
5359 .param_types = &.{ty},
5360 .callee = switch (tag) {
5361 inline .sin,
5362 .cos,
5363 .tan,
5364 .exp,
5365 .exp2,
5366 .log,
5367 .log2,
5368 .log10,
5369 .round,
5370 => |comptime_tag| switch (ty) {
5371 .f16_type => "__" ++ @tagName(comptime_tag) ++ "h",
5372 .f32_type => @tagName(comptime_tag) ++ "f",
5373 .f64_type => @tagName(comptime_tag),
5374 .f80_type => "__" ++ @tagName(comptime_tag) ++ "x",
5375 .f128_type => @tagName(comptime_tag) ++ "q",
5376 .c_longdouble_type => @tagName(comptime_tag) ++ "l",
5377 else => return self.fail("TODO implement airUnaryMath for {s} of {}", .{
5378 @tagName(tag), ty.toType().fmt(self.bin_file.options.module.?),
5379 }),
5403 .return_type = ty.toIntern(),
5404 .param_types = &.{ty.toIntern()},
5405 .callee = std.fmt.bufPrint(&callee, "{s}{s}{s}", .{
5406 floatLibcAbiPrefix(ty),
5407 switch (tag) {
5408 .sin,
5409 .cos,
5410 .tan,
5411 .exp,
5412 .exp2,
5413 .log,
5414 .log2,
5415 .log10,
5416 .round,
5417 => @tagName(tag),
5418 else => unreachable,
53805419 },
5381 else => unreachable,
5382 },
5383 } }, &.{un_op});
5420 floatLibcAbiSuffix(ty),
5421 }) catch unreachable,
5422 } }, &.{ty}, &.{.{ .air_ref = un_op }});
53845423 return self.finishAir(inst, result, .{ un_op, .none, .none });
53855424}
53865425
......@@ -5534,6 +5573,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr_ty: Type, ptr_mcv: MCValue) InnerErro
55345573
55355574 try self.genCopy(dst_ty, dst_mcv, .{ .indirect = .{ .reg = addr_reg } });
55365575 },
5576 .air_ref => |ref| try self.load(dst_mcv, ptr_ty, try self.resolveInst(ref)),
55375577 }
55385578}
55395579
......@@ -5679,6 +5719,7 @@ fn store(self: *Self, ptr_ty: Type, ptr_mcv: MCValue, src_mcv: MCValue) InnerErr
56795719
56805720 try self.genCopy(src_ty, .{ .indirect = .{ .reg = addr_reg } }, src_mcv);
56815721 },
5722 .air_ref => |ref| try self.store(ptr_ty, ptr_mcv, try self.resolveInst(ref)),
56825723 }
56835724}
56845725
......@@ -6020,6 +6061,7 @@ fn genUnOpMir(self: *Self, mir_tag: Mir.Inst.FixedTag, dst_ty: Type, dst_mcv: MC
60206061 .lea_tlv,
60216062 .lea_frame,
60226063 .reserved_frame,
6064 .air_ref,
60236065 => unreachable, // unmodifiable destination
60246066 .register => |dst_reg| try self.asmRegister(mir_tag, registerAlias(dst_reg, abi_size)),
60256067 .memory, .load_got, .load_direct, .load_tlv => {
......@@ -6679,7 +6721,11 @@ fn genBinOp(
66796721 .min,
66806722 .max,
66816723 => {
6682 const mat_src_mcv: MCValue = if (switch (src_mcv) {
6724 const resolved_src_mcv = switch (src_mcv) {
6725 else => src_mcv,
6726 .air_ref => |ref| try self.resolveInst(ref),
6727 };
6728 const mat_src_mcv: MCValue = if (switch (resolved_src_mcv) {
66836729 .immediate,
66846730 .eflags,
66856731 .register_offset,
......@@ -6693,7 +6739,10 @@ fn genBinOp(
66936739 => true,
66946740 .memory => |addr| math.cast(i32, @as(i64, @bitCast(addr))) == null,
66956741 else => false,
6696 }) .{ .register = try self.copyToTmpRegister(rhs_ty, src_mcv) } else src_mcv;
6742 })
6743 .{ .register = try self.copyToTmpRegister(rhs_ty, resolved_src_mcv) }
6744 else
6745 resolved_src_mcv;
66976746 const mat_mcv_lock = switch (mat_src_mcv) {
66986747 .register => |reg| self.register_manager.lockReg(reg),
66996748 else => null,
......@@ -6740,6 +6789,7 @@ fn genBinOp(
67406789 .lea_tlv,
67416790 .lea_frame,
67426791 .reserved_frame,
6792 .air_ref,
67436793 => unreachable,
67446794 .register => |src_reg| try self.asmCmovccRegisterRegister(
67456795 registerAlias(tmp_reg, cmov_abi_size),
......@@ -7389,11 +7439,11 @@ fn genBinOp(
73897439 lhs_ty,
73907440 dst_reg,
73917441 .{ .register = dst_reg },
7392 switch (air_tag) {
7393 .div_trunc => 0b1_0_11,
7394 .div_floor => 0b1_0_01,
7442 .{ .mode = switch (air_tag) {
7443 .div_trunc => .zero,
7444 .div_floor => .down,
73957445 else => unreachable,
7396 },
7446 }, .precision = .inexact },
73977447 ),
73987448 .bit_and, .bit_or, .xor => {},
73997449 .max, .min => if (maybe_mask_reg) |mask_reg| if (self.hasFeature(.avx)) {
......@@ -7651,6 +7701,7 @@ fn genBinOpMir(
76517701 .lea_tlv,
76527702 .lea_frame,
76537703 .reserved_frame,
7704 .air_ref,
76547705 => unreachable, // unmodifiable destination
76557706 .register, .register_offset => {
76567707 assert(dst_mcv.isRegister());
......@@ -7766,6 +7817,7 @@ fn genBinOpMir(
77667817 else => unreachable,
77677818 }
77687819 },
7820 .air_ref => |ref| try self.genBinOpMir(mir_tag, ty, dst_mcv, try self.resolveInst(ref)),
77697821 }
77707822 },
77717823 .memory, .indirect, .load_got, .load_direct, .load_tlv, .load_frame => {
......@@ -7789,13 +7841,18 @@ fn genBinOpMir(
77897841 };
77907842 defer if (dst_info) |info| self.register_manager.unlockReg(info.addr_lock);
77917843
7792 const src_info: OpInfo = switch (src_mcv) {
7844 const resolved_src_mcv = switch (src_mcv) {
7845 else => src_mcv,
7846 .air_ref => |ref| try self.resolveInst(ref),
7847 };
7848 const src_info: OpInfo = switch (resolved_src_mcv) {
77937849 .none,
77947850 .unreach,
77957851 .dead,
77967852 .undef,
77977853 .register_overflow,
77987854 .reserved_frame,
7855 .air_ref,
77997856 => unreachable,
78007857 .immediate,
78017858 .register,
......@@ -7809,7 +7866,7 @@ fn genBinOpMir(
78097866 .lea_frame,
78107867 => null,
78117868 .memory, .load_got, .load_direct, .load_tlv => src: {
7812 switch (src_mcv) {
7869 switch (resolved_src_mcv) {
78137870 .memory => |addr| if (math.cast(i32, @as(i64, @bitCast(addr))) != null and
78147871 math.cast(i32, @as(i64, @bitCast(addr)) + abi_size - limb_abi_size) != null)
78157872 break :src null,
......@@ -7821,7 +7878,7 @@ fn genBinOpMir(
78217878 const src_addr_lock = self.register_manager.lockRegAssumeUnused(src_addr_reg);
78227879 errdefer self.register_manager.unlockReg(src_addr_lock);
78237880
7824 try self.genSetReg(src_addr_reg, Type.usize, src_mcv.address());
7881 try self.genSetReg(src_addr_reg, Type.usize, resolved_src_mcv.address());
78257882 break :src .{
78267883 .addr_reg = src_addr_reg,
78277884 .addr_lock = src_addr_lock,
......@@ -7868,13 +7925,14 @@ fn genBinOpMir(
78687925 else => unreachable,
78697926 },
78707927 );
7871 switch (src_mcv) {
7928 switch (resolved_src_mcv) {
78727929 .none,
78737930 .unreach,
78747931 .dead,
78757932 .undef,
78767933 .register_overflow,
78777934 .reserved_frame,
7935 .air_ref,
78787936 => unreachable,
78797937 .register => |src_reg| switch (off) {
78807938 0 => try self.asmMemoryRegister(
......@@ -7950,7 +8008,7 @@ fn genBinOpMir(
79508008 => {
79518009 const src_limb_reg = try self.copyToTmpRegister(limb_ty, if (src_info) |info| .{
79528010 .indirect = .{ .reg = info.addr_reg, .off = off },
7953 } else switch (src_mcv) {
8011 } else switch (resolved_src_mcv) {
79548012 .eflags,
79558013 .register_offset,
79568014 .lea_direct,
......@@ -7958,7 +8016,7 @@ fn genBinOpMir(
79588016 .lea_tlv,
79598017 .lea_frame,
79608018 => switch (off) {
7961 0 => src_mcv,
8019 0 => resolved_src_mcv,
79628020 else => .{ .immediate = 0 },
79638021 },
79648022 .memory => |addr| .{ .memory = @bitCast(@as(i64, @bitCast(addr)) + off) },
......@@ -8003,19 +8061,25 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M
80038061 .lea_tlv,
80048062 .lea_frame,
80058063 .reserved_frame,
8064 .air_ref,
80068065 => unreachable, // unmodifiable destination
80078066 .register => |dst_reg| {
80088067 const dst_alias = registerAlias(dst_reg, abi_size);
80098068 const dst_lock = self.register_manager.lockReg(dst_reg);
80108069 defer if (dst_lock) |lock| self.register_manager.unlockReg(lock);
80118070
8012 switch (src_mcv) {
8071 const resolved_src_mcv = switch (src_mcv) {
8072 else => src_mcv,
8073 .air_ref => |ref| try self.resolveInst(ref),
8074 };
8075 switch (resolved_src_mcv) {
80138076 .none,
80148077 .unreach,
80158078 .dead,
80168079 .undef,
80178080 .register_overflow,
80188081 .reserved_frame,
8082 .air_ref,
80198083 => unreachable,
80208084 .register => |src_reg| try self.asmRegisterRegister(
80218085 .{ .i_, .mul },
......@@ -8031,7 +8095,7 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M
80318095 Immediate.s(small),
80328096 );
80338097 } else {
8034 const src_reg = try self.copyToTmpRegister(dst_ty, src_mcv);
8098 const src_reg = try self.copyToTmpRegister(dst_ty, resolved_src_mcv);
80358099 return self.genIntMulComplexOpMir(dst_ty, dst_mcv, MCValue{ .register = src_reg });
80368100 }
80378101 },
......@@ -8047,19 +8111,22 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M
80478111 => try self.asmRegisterRegister(
80488112 .{ .i_, .mul },
80498113 dst_alias,
8050 registerAlias(try self.copyToTmpRegister(dst_ty, src_mcv), abi_size),
8114 registerAlias(try self.copyToTmpRegister(dst_ty, resolved_src_mcv), abi_size),
80518115 ),
80528116 .memory, .indirect, .load_frame => try self.asmRegisterMemory(
80538117 .{ .i_, .mul },
80548118 dst_alias,
8055 Memory.sib(Memory.PtrSize.fromSize(abi_size), switch (src_mcv) {
8119 Memory.sib(Memory.PtrSize.fromSize(abi_size), switch (resolved_src_mcv) {
80568120 .memory => |addr| .{
80578121 .base = .{ .reg = .ds },
80588122 .disp = math.cast(i32, @as(i64, @bitCast(addr))) orelse
80598123 return self.asmRegisterRegister(
80608124 .{ .i_, .mul },
80618125 dst_alias,
8062 registerAlias(try self.copyToTmpRegister(dst_ty, src_mcv), abi_size),
8126 registerAlias(
8127 try self.copyToTmpRegister(dst_ty, resolved_src_mcv),
8128 abi_size,
8129 ),
80638130 ),
80648131 },
80658132 .indirect => |reg_off| .{
......@@ -8221,13 +8288,30 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
82218288
82228289 const pl_op = self.air.instructions.items(.data)[inst].pl_op;
82238290 const extra = self.air.extraData(Air.Call, pl_op.payload);
8224 const args: []const Air.Inst.Ref = @ptrCast(self.air.extra[extra.end..][0..extra.data.args_len]);
8291 const arg_refs: []const Air.Inst.Ref =
8292 @ptrCast(self.air.extra[extra.end..][0..extra.data.args_len]);
8293
8294 const ExpectedContents = extern struct {
8295 tys: [16][@sizeOf(Type)]u8 align(@alignOf(Type)),
8296 vals: [16][@sizeOf(MCValue)]u8 align(@alignOf(MCValue)),
8297 };
8298 var stack align(@max(@alignOf(ExpectedContents), @alignOf(std.heap.StackFallbackAllocator(0)))) =
8299 std.heap.stackFallback(@sizeOf(ExpectedContents), self.gpa);
8300 const allocator = stack.get();
8301
8302 const arg_tys = try allocator.alloc(Type, arg_refs.len);
8303 defer allocator.free(arg_tys);
8304 for (arg_tys, arg_refs) |*arg_ty, arg_ref| arg_ty.* = self.typeOf(arg_ref);
82258305
8226 const ret = try self.genCall(.{ .air = pl_op.operand }, args);
8306 const arg_vals = try allocator.alloc(MCValue, arg_refs.len);
8307 defer allocator.free(arg_vals);
8308 for (arg_vals, arg_refs) |*arg_val, arg_ref| arg_val.* = .{ .air_ref = arg_ref };
8309
8310 const ret = try self.genCall(.{ .air = pl_op.operand }, arg_tys, arg_vals);
82278311
82288312 var bt = self.liveness.iterateBigTomb(inst);
82298313 self.feed(&bt, pl_op.operand);
8230 for (args) |arg| self.feed(&bt, arg);
8314 for (arg_refs) |arg_ref| self.feed(&bt, arg_ref);
82318315
82328316 const result = if (self.liveness.isUnused(inst)) .unreach else ret;
82338317 return self.finishAirResult(inst, result);
......@@ -8241,7 +8325,7 @@ fn genCall(self: *Self, info: union(enum) {
82418325 lib: ?[]const u8 = null,
82428326 callee: []const u8,
82438327 },
8244}, args: []const Air.Inst.Ref) !MCValue {
8328}, arg_types: []const Type, args: []const MCValue) !MCValue {
82458329 const mod = self.bin_file.options.module.?;
82468330
82478331 const fn_ty = switch (info) {
......@@ -8261,8 +8345,17 @@ fn genCall(self: *Self, info: union(enum) {
82618345 };
82628346 const fn_info = mod.typeToFunc(fn_ty).?;
82638347
8348 const ExpectedContents = [16]Type;
8349 var stack align(@max(@alignOf(ExpectedContents), @alignOf(std.heap.StackFallbackAllocator(0)))) =
8350 std.heap.stackFallback(@sizeOf(ExpectedContents), self.gpa);
8351 const allocator = stack.get();
8352
8353 const var_args = try allocator.alloc(Type, args.len - fn_info.param_types.len);
8354 defer allocator.free(var_args);
8355 for (var_args, arg_types[fn_info.param_types.len..]) |*var_arg, arg_ty| var_arg.* = arg_ty;
8356
82648357 var call_info =
8265 try self.resolveCallingConventionValues(fn_info, args[fn_info.param_types.len..], .call_frame);
8358 try self.resolveCallingConventionValues(fn_info, var_args, .call_frame);
82668359 defer call_info.deinit(self);
82678360
82688361 // We need a properly aligned and sized call frame to be able to call this function.
......@@ -8290,10 +8383,10 @@ fn genCall(self: *Self, info: union(enum) {
82908383 .indirect => |reg_off| try self.spillRegisters(&.{reg_off.reg}),
82918384 else => unreachable,
82928385 }
8293 for (call_info.args, args) |dst_arg, src_arg| switch (dst_arg) {
8386 for (call_info.args, arg_types, args) |dst_arg, arg_ty, src_arg| switch (dst_arg) {
82948387 .none => {},
82958388 .register => |reg| try self.spillRegisters(&.{reg}),
8296 .load_frame => try self.genCopy(self.typeOf(src_arg), dst_arg, try self.resolveInst(src_arg)),
8389 .load_frame => try self.genCopy(arg_ty, dst_arg, src_arg),
82978390 else => unreachable,
82988391 };
82998392
......@@ -8313,10 +8406,10 @@ fn genCall(self: *Self, info: union(enum) {
83138406 };
83148407 defer if (ret_lock) |lock| self.register_manager.unlockReg(lock);
83158408
8316 for (call_info.args, args) |dst_arg, src_arg| {
8409 for (call_info.args, arg_types, args) |dst_arg, arg_ty, src_arg| {
83178410 switch (dst_arg) {
83188411 .none, .load_frame => {},
8319 .register => try self.genCopy(self.typeOf(src_arg), dst_arg, try self.resolveInst(src_arg)),
8412 .register => try self.genCopy(arg_ty, dst_arg, src_arg),
83208413 else => unreachable,
83218414 }
83228415 }
......@@ -8374,7 +8467,7 @@ fn genCall(self: *Self, info: union(enum) {
83748467 }
83758468 } else {
83768469 assert(self.typeOf(callee).zigTypeTag(mod) == .Pointer);
8377 try self.genSetReg(.rax, Type.usize, try self.resolveInst(callee));
8470 try self.genSetReg(.rax, Type.usize, .{ .air_ref = callee });
83788471 try self.asmRegister(.{ ._, .call }, .rax);
83798472 },
83808473 .lib => |lib| try self.genExternSymbolRef(.call, lib.lib, lib.callee),
......@@ -8454,7 +8547,7 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
84548547 },
84558548 floatCompilerRtAbiName(float_bits),
84568549 }) catch unreachable,
8457 } }, &.{ bin_op.lhs, bin_op.rhs });
8550 } }, &.{ ty, ty }, &.{ .{ .air_ref = bin_op.lhs }, .{ .air_ref = bin_op.rhs } });
84588551 try self.genBinOpMir(.{ ._, .@"test" }, Type.i32, ret, ret);
84598552 break :result switch (op) {
84608553 .eq => .e,
......@@ -8908,6 +9001,7 @@ fn isNull(self: *Self, inst: Air.Inst.Index, opt_ty: Type, opt_mcv: MCValue) !MC
89089001 .lea_tlv,
89099002 .lea_frame,
89109003 .reserved_frame,
9004 .air_ref,
89119005 => unreachable,
89129006
89139007 .register => |opt_reg| {
......@@ -9933,6 +10027,7 @@ fn genCopy(self: *Self, ty: Type, dst_mcv: MCValue, src_mcv: MCValue) InnerError
993310027 .lea_tlv,
993410028 .lea_frame,
993510029 .reserved_frame,
10030 .air_ref,
993610031 => unreachable, // unmodifiable destination
993710032 .register => |reg| try self.genSetReg(reg, ty, src_mcv),
993810033 .register_offset => |dst_reg_off| try self.genSetReg(dst_reg_off.reg, ty, switch (src_mcv) {
......@@ -10258,6 +10353,7 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr
1025810353 @tagName(self.bin_file.tag),
1025910354 });
1026010355 },
10356 .air_ref => |ref| try self.genSetReg(dst_reg, ty, try self.resolveInst(ref)),
1026110357 }
1026210358}
1026310359
......@@ -10370,6 +10466,7 @@ fn genSetMem(self: *Self, base: Memory.Base, disp: i32, ty: Type, src_mcv: MCVal
1037010466 },
1037110467 else => try self.genInlineMemcpy(dst_ptr_mcv, src_mcv.address(), .{ .immediate = abi_size }),
1037210468 },
10469 .air_ref => |ref| try self.genSetMem(base, disp, ty, try self.resolveInst(ref)),
1037310470 }
1037410471}
1037510472
......@@ -10663,7 +10760,7 @@ fn airFloatFromInt(self: *Self, inst: Air.Inst.Index) !void {
1066310760 intCompilerRtAbiName(src_bits),
1066410761 floatCompilerRtAbiName(dst_bits),
1066510762 }) catch unreachable,
10666 } }, &.{ty_op.operand});
10763 } }, &.{src_ty}, &.{.{ .air_ref = ty_op.operand }});
1066710764 }
1066810765
1066910766 if (src_size > 8) return self.fail("TODO implement airFloatFromInt from {} to {}", .{
......@@ -10742,7 +10839,7 @@ fn airIntFromFloat(self: *Self, inst: Air.Inst.Index) !void {
1074210839 floatCompilerRtAbiName(src_bits),
1074310840 intCompilerRtAbiName(dst_bits),
1074410841 }) catch unreachable,
10745 } }, &.{ty_op.operand});
10842 } }, &.{src_ty}, &.{.{ .air_ref = ty_op.operand }});
1074610843 }
1074710844
1074810845 if (dst_size > 8) return self.fail("TODO implement airIntFromFloat from {} to {}", .{
......@@ -12103,7 +12200,7 @@ const CallMCValues = struct {
1210312200fn resolveCallingConventionValues(
1210412201 self: *Self,
1210512202 fn_info: InternPool.Key.FuncType,
12106 var_args: []const Air.Inst.Ref,
12203 var_args: []const Type,
1210712204 stack_frame_base: FrameIndex,
1210812205) !CallMCValues {
1210912206 const mod = self.bin_file.options.module.?;
......@@ -12116,9 +12213,7 @@ fn resolveCallingConventionValues(
1211612213 dest.* = src.toType();
1211712214 }
1211812215 // TODO: promote var arg types
12119 for (param_types[fn_info.param_types.len..], var_args) |*param_ty, arg| {
12120 param_ty.* = self.typeOf(arg);
12121 }
12216 for (param_types[fn_info.param_types.len..], var_args) |*param_ty, arg_ty| param_ty.* = arg_ty;
1212212217
1212312218 var result: CallMCValues = .{
1212412219 .args = try self.gpa.alloc(MCValue, param_types.len),
......@@ -12454,3 +12549,25 @@ fn floatCompilerRtAbiType(self: *Self, ty: Type, other_ty: Type) Type {
1245412549 self.target.isDarwin()) return Type.u16;
1245512550 return ty;
1245612551}
12552
12553fn floatLibcAbiPrefix(ty: Type) []const u8 {
12554 return switch (ty.toIntern()) {
12555 .f16_type,
12556 .f80_type,
12557 => "__",
12558 .f32_type, .f64_type, .f128_type, .c_longdouble_type => "",
12559 else => unreachable,
12560 };
12561}
12562
12563fn floatLibcAbiSuffix(ty: Type) []const u8 {
12564 return switch (ty.toIntern()) {
12565 .f16_type => "h",
12566 .f32_type => "f",
12567 .f64_type => "",
12568 .f80_type => "x",
12569 .f128_type => "q",
12570 .c_longdouble_type => "l",
12571 else => unreachable,
12572 };
12573}
test/behavior/abs.zig+2-1
......@@ -86,9 +86,10 @@ test "@abs floats" {
8686 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO
8787 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
8888 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
89 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf) return error.SkipZigTest;
8990
9091 try comptime testAbsFloats(f16);
91 if (builtin.zig_backend != .stage2_x86_64) try testAbsFloats(f16);
92 try testAbsFloats(f16);
9293 try comptime testAbsFloats(f32);
9394 try testAbsFloats(f32);
9495 try comptime testAbsFloats(f64);
test/behavior/floatop.zig+8-8
......@@ -928,7 +928,7 @@ test "@floor f16" {
928928 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
929929 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
930930 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
931 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
931 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf) return error.SkipZigTest;
932932
933933 try testFloor(f16);
934934 try comptime testFloor(f16);
......@@ -938,7 +938,7 @@ test "@floor f32/f64" {
938938 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
939939 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
940940 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
941 if (builtin.zig_backend == .stage2_x86_64 and (builtin.target.ofmt != .elf or !comptime std.Target.x86.featureSetHas(builtin.cpu.features, .sse4_1))) return error.SkipZigTest;
941 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf) return error.SkipZigTest;
942942
943943 try testFloor(f32);
944944 try comptime testFloor(f32);
......@@ -1010,7 +1010,7 @@ test "@ceil f16" {
10101010 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
10111011 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
10121012 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1013 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
1013 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf) return error.SkipZigTest;
10141014
10151015 try testCeil(f16);
10161016 try comptime testCeil(f16);
......@@ -1020,7 +1020,7 @@ test "@ceil f32/f64" {
10201020 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
10211021 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
10221022 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1023 if (builtin.zig_backend == .stage2_x86_64 and (builtin.target.ofmt != .elf or !comptime std.Target.x86.featureSetHas(builtin.cpu.features, .sse4_1))) return error.SkipZigTest;
1023 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf) return error.SkipZigTest;
10241024
10251025 try testCeil(f32);
10261026 try comptime testCeil(f32);
......@@ -1092,7 +1092,7 @@ test "@trunc f16" {
10921092 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
10931093 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
10941094 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1095 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
1095 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf) return error.SkipZigTest;
10961096
10971097 if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch.isMIPS()) {
10981098 // https://github.com/ziglang/zig/issues/16846
......@@ -1107,7 +1107,7 @@ test "@trunc f32/f64" {
11071107 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
11081108 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
11091109 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1110 if (builtin.zig_backend == .stage2_x86_64 and (builtin.target.ofmt != .elf or !comptime std.Target.x86.featureSetHas(builtin.cpu.features, .sse4_1))) return error.SkipZigTest;
1110 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf) return error.SkipZigTest;
11111111
11121112 if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch.isMIPS()) {
11131113 // https://github.com/ziglang/zig/issues/16846
......@@ -1160,10 +1160,10 @@ fn testTrunc(comptime T: type) !void {
11601160}
11611161
11621162test "@trunc with vectors" {
1163 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1164 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
11651163 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1164 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
11661165 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
1166 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
11671167 if (builtin.zig_backend == .stage2_x86_64 and
11681168 !comptime std.Target.x86.featureSetHas(builtin.cpu.features, .sse4_1)) return error.SkipZigTest;
11691169
test/behavior/math.zig+1-2
......@@ -412,12 +412,11 @@ fn testBinaryNot128(comptime Type: type, x: Type) !void {
412412
413413test "division" {
414414 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
415 if (builtin.zig_backend == .stage2_x86_64 and
416 !comptime std.Target.x86.featureSetHas(builtin.cpu.features, .sse4_1)) return error.SkipZigTest; // TODO
417415 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
418416 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
419417 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
420418 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
419 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf) return error.SkipZigTest;
421420
422421 if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch.isMIPS()) {
423422 // https://github.com/ziglang/zig/issues/16846
test/behavior/maximum_minimum.zig+7-8
......@@ -10,6 +10,7 @@ test "@max" {
1010 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1111 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1212 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
13 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
1314
1415 const S = struct {
1516 fn doTheTest() !void {
......@@ -25,12 +26,11 @@ test "@max" {
2526
2627test "@max on vectors" {
2728 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
28 if (builtin.zig_backend == .stage2_x86_64 and
29 !comptime std.Target.x86.featureSetHas(builtin.cpu.features, .sse4_1)) return error.SkipZigTest; // TODO
3029 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
3130 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
3231 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
3332 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
33 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
3434
3535 const S = struct {
3636 fn doTheTest() !void {
......@@ -74,12 +74,11 @@ test "@min" {
7474
7575test "@min for vectors" {
7676 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
77 if (builtin.zig_backend == .stage2_x86_64 and
78 !comptime std.Target.x86.featureSetHas(builtin.cpu.features, .sse4_1)) return error.SkipZigTest; // TODO
7977 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
8078 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
8179 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
8280 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
81 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
8382
8483 const S = struct {
8584 fn doTheTest() !void {
......@@ -104,12 +103,12 @@ test "@min for vectors" {
104103}
105104
106105test "@min/max for floats" {
107 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
108106 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
109107 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
110108 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
111109 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
112110 if (builtin.zig_backend == .stage2_c and comptime builtin.cpu.arch.isArmOrThumb()) return error.SkipZigTest;
111 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
113112
114113 const S = struct {
115114 fn doTheTest(comptime T: type) !void {
......@@ -179,11 +178,11 @@ test "@min/@max notices bounds" {
179178
180179test "@min/@max notices vector bounds" {
181180 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
182 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
183181 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
184182 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
185183 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
186184 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
185 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
187186
188187 var x: @Vector(2, u16) = .{ 140, 40 };
189188 const y: @Vector(2, u64) = .{ 5, 100 };
......@@ -232,11 +231,11 @@ test "@min/@max notices bounds from types" {
232231
233232test "@min/@max notices bounds from vector types" {
234233 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
235 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
236234 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
237235 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
238236 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
239237 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
238 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
240239
241240 var x: @Vector(2, u16) = .{ 30, 67 };
242241 var y: @Vector(2, u32) = .{ 20, 500 };
......@@ -272,11 +271,11 @@ test "@min/@max notices bounds from types when comptime-known value is undef" {
272271
273272test "@min/@max notices bounds from vector types when element of comptime-known vector is undef" {
274273 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
275 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
276274 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
277275 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
278276 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
279277 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
278 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
280279
281280 var x: @Vector(2, u32) = .{ 1_000_000, 12345 };
282281 const y: @Vector(2, u16) = .{ 10, undefined };
test/behavior/vector.zig+2-2
......@@ -26,12 +26,12 @@ test "implicit cast vector to array - bool" {
2626
2727test "vector wrap operators" {
2828 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
29 if (builtin.zig_backend == .stage2_x86_64 and
30 !comptime std.Target.x86.featureSetHas(builtin.cpu.features, .sse4_1)) return error.SkipZigTest; // TODO
3129 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
3230 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
3331 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
3432 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
33 if (builtin.zig_backend == .stage2_x86_64 and
34 !comptime std.Target.x86.featureSetHas(builtin.cpu.features, .sse4_1)) return error.SkipZigTest; // TODO
3535
3636 const S = struct {
3737 fn doTheTest() !void {