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 {...@@ -2008,6 +2008,11 @@ fn computeFrameLayout(self: *Self) !FrameLayout {
2008 };2008 };
2009}2009}
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
2011fn allocFrameIndex(self: *Self, alloc: FrameAlloc) !FrameIndex {2016fn allocFrameIndex(self: *Self, alloc: FrameAlloc) !FrameIndex {
2012 const frame_allocs_slice = self.frame_allocs.slice();2017 const frame_allocs_slice = self.frame_allocs.slice();
2013 const frame_size = frame_allocs_slice.items(.abi_size);2018 const frame_size = frame_allocs_slice.items(.abi_size);
...@@ -2051,24 +2056,36 @@ fn allocTempRegOrMem(self: *Self, elem_ty: Type, reg_ok: bool) !MCValue {...@@ -2051,24 +2056,36 @@ fn allocTempRegOrMem(self: *Self, elem_ty: Type, reg_ok: bool) !MCValue {
2051 return self.allocRegOrMemAdvanced(elem_ty, null, reg_ok);2056 return self.allocRegOrMemAdvanced(elem_ty, null, reg_ok);
2052}2057}
20532058
2054fn allocRegOrMemAdvanced(self: *Self, elem_ty: Type, inst: ?Air.Inst.Index, reg_ok: bool) !MCValue {2059fn allocRegOrMemAdvanced(self: *Self, ty: Type, inst: ?Air.Inst.Index, reg_ok: bool) !MCValue {
2055 const abi_size = math.cast(u32, elem_ty.abiSize(self.target.*)) orelse {2060 const abi_size = math.cast(u32, ty.abiSize(self.target.*)) orelse {
2056 const mod = self.bin_file.options.module.?;2061 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)});
2058 };2063 };
20592064
2060 if (reg_ok) {2065 if (reg_ok) need_mem: {
2061 // Make sure the type can fit in a register before we try to allocate one.2066 if (abi_size <= @as(u32, switch (ty.zigTypeTag()) {
2062 const ptr_bits = self.target.cpu.arch.ptrBitWidth();2067 .Float => switch (ty.floatBits(self.target.*)) {
2063 const ptr_bytes: u64 = @divExact(ptr_bits, 8);2068 16, 32, 64, 128 => 16,
2064 if (abi_size <= ptr_bytes) {2069 80 => break :need_mem,
2065 if (self.register_manager.tryAllocReg(inst, regClassForType(elem_ty))) |reg| {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| {
2066 return MCValue{ .register = registerAlias(reg, abi_size) };2083 return MCValue{ .register = registerAlias(reg, abi_size) };
2067 }2084 }
2068 }2085 }
2069 }2086 }
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.*));
2072 return .{ .load_frame = .{ .index = frame_index } };2089 return .{ .load_frame = .{ .index = frame_index } };
2073}2090}
20742091
...@@ -4442,12 +4459,19 @@ fn airRound(self: *Self, inst: Air.Inst.Index, mode: Immediate) !void {...@@ -4442,12 +4459,19 @@ fn airRound(self: *Self, inst: Air.Inst.Index, mode: Immediate) !void {
4442 }),4459 }),
4443 };4460 };
4444 assert(dst_mcv.isRegister());4461 assert(dst_mcv.isRegister());
4462 const abi_size = @intCast(u32, ty.abiSize(self.target.*));
4463 const dst_reg = registerAlias(dst_mcv.getReg().?, abi_size);
4445 if (src_mcv.isRegister())4464 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 )
4447 else4471 else
4448 try self.asmRegisterMemoryImmediate(4472 try self.asmRegisterMemoryImmediate(
4449 mir_tag,4473 mir_tag,
4450 dst_mcv.getReg().?,4474 dst_reg,
4451 src_mcv.mem(Memory.PtrSize.fromSize(@intCast(u32, ty.abiSize(self.target.*)))),4475 src_mcv.mem(Memory.PtrSize.fromSize(@intCast(u32, ty.abiSize(self.target.*)))),
4452 mode,4476 mode,
4453 );4477 );
...@@ -7847,19 +7871,43 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {...@@ -7847,19 +7871,43 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
7847 return self.finishAirResult(inst, result);7871 return self.finishAirResult(inst, result);
7848}7872}
78497873
7850fn movMirTag(self: *Self, ty: Type) !Mir.Inst.Tag {7874fn movMirTag(self: *Self, ty: Type, aligned: bool) !Mir.Inst.Tag {
7851 return switch (ty.zigTypeTag()) {7875 switch (ty.zigTypeTag()) {
7852 else => .mov,7876 else => return .mov,
7853 .Float => switch (ty.floatBits(self.target.*)) {7877 .Float => switch (ty.floatBits(self.target.*)) {
7854 16 => unreachable, // needs special handling7878 16 => unreachable, // needs special handling
7855 32 => .movss,7879 32 => return if (self.hasFeature(.avx)) .vmovss else .movss,
7856 64 => .movsd,7880 64 => return if (self.hasFeature(.avx)) .vmovsd else .movsd,
7857 128 => .movaps,7881 128 => return if (self.hasFeature(.avx))
7858 else => return self.fail("TODO movMirTag from {}", .{7882 if (aligned) .vmovaps else .vmovups
7859 ty.fmt(self.bin_file.options.module.?),7883 else if (aligned) .movaps else .movups,
7860 }),7884 else => {},
7861 },7885 },
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.?)});
7863}7911}
78647912
7865fn genCopy(self: *Self, ty: Type, dst_mcv: MCValue, src_mcv: MCValue) InnerError!void {7913fn 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...@@ -8016,7 +8064,11 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr
8016 0 => return self.genSetReg(dst_reg, ty, .{ .register = reg_off.reg }),8064 0 => return self.genSetReg(dst_reg, ty, .{ .register = reg_off.reg }),
8017 else => .lea,8065 else => .lea,
8018 },8066 },
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 ),
8020 .lea_frame => .lea,8072 .lea_frame => .lea,
8021 else => unreachable,8073 else => unreachable,
8022 },8074 },
...@@ -8040,7 +8092,11 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr...@@ -8040,7 +8092,11 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr
8040 )8092 )
8041 else8093 else
8042 self.asmRegisterMemory(8094 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 )),
8044 registerAlias(dst_reg, abi_size),8100 registerAlias(dst_reg, abi_size),
8045 src_mem,8101 src_mem,
8046 );8102 );
...@@ -8080,7 +8136,7 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr...@@ -8080,7 +8136,7 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr
8080 )8136 )
8081 else8137 else
8082 try self.asmRegisterMemory(8138 try self.asmRegisterMemory(
8083 try self.movMirTag(ty),8139 try self.movMirTag(ty, false),
8084 registerAlias(dst_reg, abi_size),8140 registerAlias(dst_reg, abi_size),
8085 src_mem,8141 src_mem,
8086 );8142 );
...@@ -8194,7 +8250,24 @@ fn genSetMem(self: *Self, base: Memory.Base, disp: i32, ty: Type, src_mcv: MCVal...@@ -8194,7 +8250,24 @@ fn genSetMem(self: *Self, base: Memory.Base, disp: i32, ty: Type, src_mcv: MCVal
8194 )8250 )
8195 else8251 else
8196 try self.asmMemoryRegister(8252 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 }),
8198 dst_mem,8271 dst_mem,
8199 registerAlias(src_reg, abi_size),8272 registerAlias(src_reg, abi_size),
8200 );8273 );
...@@ -8415,7 +8488,7 @@ fn airBitCast(self: *Self, inst: Air.Inst.Index) !void {...@@ -8415,7 +8488,7 @@ fn airBitCast(self: *Self, inst: Air.Inst.Index) !void {
8415 defer if (operand_lock) |lock| self.register_manager.unlockReg(lock);8488 defer if (operand_lock) |lock| self.register_manager.unlockReg(lock);
84168489
8417 const dest = try self.allocRegOrMem(inst, true);8490 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);
8419 break :result dest;8492 break :result dest;
8420 };8493 };
8421 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });8494 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(...@@ -206,7 +206,7 @@ pub fn format(
206 try writer.print("+{s} ", .{tag});206 try writer.print("+{s} ", .{tag});
207 },207 },
208 .m, .mi, .m1, .mc, .vmi => try writer.print("/{d} ", .{encoding.modRmExt()}),208 .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 "),
210 }210 }
211211
212 switch (encoding.data.op_en) {212 switch (encoding.data.op_en) {
...@@ -230,7 +230,7 @@ pub fn format(...@@ -230,7 +230,7 @@ pub fn format(
230 };230 };
231 try writer.print("{s} ", .{tag});231 try writer.print("{s} ", .{tag});
232 },232 },
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 => {},
234 }234 }
235235
236 try writer.print("{s} ", .{@tagName(encoding.mnemonic)});236 try writer.print("{s} ", .{@tagName(encoding.mnemonic)});
...@@ -332,7 +332,12 @@ pub const Mnemonic = enum {...@@ -332,7 +332,12 @@ pub const Mnemonic = enum {
332 // SSE4.1332 // SSE4.1
333 roundsd, roundss,333 roundsd, roundss,
334 // AVX334 // AVX
335 vmovddup, vmovshdup, vmovsldup,335 vmovapd, vmovaps,
336 vmovddup,
337 vmovsd,
338 vmovshdup, vmovsldup,
339 vmovss,
340 vmovupd, vmovups,
336 vpextrw, vpinsrw,341 vpextrw, vpinsrw,
337 vpshufhw, vpshuflw,342 vpshufhw, vpshuflw,
338 vpsrld, vpsrlq, vpsrlw,343 vpsrld, vpsrlq, vpsrlw,
...@@ -357,7 +362,7 @@ pub const OpEn = enum {...@@ -357,7 +362,7 @@ pub const OpEn = enum {
357 fd, td,362 fd, td,
358 m1, mc, mi, mr, rm,363 m1, mc, mi, mr, rm,
359 rmi, mri, mrc,364 rmi, mri, mrc,
360 vmi, rvm, rvmi,365 vmi, rvm, rvmi, mvr,
361 // zig fmt: on366 // zig fmt: on
362};367};
363368
...@@ -549,9 +554,10 @@ pub const Op = enum {...@@ -549,9 +554,10 @@ pub const Op = enum {
549 return switch (op) {554 return switch (op) {
550 .rm8, .rm16, .rm32, .rm64,555 .rm8, .rm16, .rm32, .rm64,
551 .r32_m16, .r64_m16,556 .r32_m16, .r64_m16,
552 .m8, .m16, .m32, .m64, .m80, .m128,557 .m8, .m16, .m32, .m64, .m80, .m128, .m256,
553 .m,558 .m,
554 .xmm_m32, .xmm_m64, .xmm_m128, .ymm_m256,559 .xmm_m32, .xmm_m64, .xmm_m128,
560 .ymm_m256,
555 => true,561 => true,
556 else => false,562 else => false,
557 };563 };
src/arch/x86_64/Lower.zig+6
...@@ -184,9 +184,15 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct {...@@ -184,9 +184,15 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct {
184 .roundsd,184 .roundsd,
185 .roundss,185 .roundss,
186186
187 .vmovapd,
188 .vmovaps,
187 .vmovddup,189 .vmovddup,
190 .vmovsd,
188 .vmovshdup,191 .vmovshdup,
189 .vmovsldup,192 .vmovsldup,
193 .vmovss,
194 .vmovupd,
195 .vmovups,
190 .vpextrw,196 .vpextrw,
191 .vpinsrw,197 .vpinsrw,
192 .vpshufhw,198 .vpshufhw,
src/arch/x86_64/Mir.zig+12
...@@ -282,12 +282,24 @@ pub const Inst = struct {...@@ -282,12 +282,24 @@ pub const Inst = struct {
282 /// Round scalar single-precision floating-point values282 /// Round scalar single-precision floating-point values
283 roundss,283 roundss,
284284
285 /// Move aligned packed double-precision floating-point values
286 vmovapd,
287 /// Move aligned packed single-precision floating-point values
288 vmovaps,
285 /// Replicate double floating-point values289 /// Replicate double floating-point values
286 vmovddup,290 vmovddup,
291 /// Move or merge scalar double-precision floating-point value
292 vmovsd,
287 /// Replicate single floating-point values293 /// Replicate single floating-point values
288 vmovshdup,294 vmovshdup,
289 /// Replicate single floating-point values295 /// Replicate single floating-point values
290 vmovsldup,296 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,
291 /// Extract word303 /// Extract word
292 vpextrw,304 vpextrw,
293 /// Insert word305 /// Insert word
src/arch/x86_64/encoder.zig+8-5
...@@ -228,7 +228,7 @@ pub const Instruction = struct {...@@ -228,7 +228,7 @@ pub const Instruction = struct {
228 .td => try encoder.imm64(inst.ops[0].mem.moffs.offset),228 .td => try encoder.imm64(inst.ops[0].mem.moffs.offset),
229 else => {229 else => {
230 const mem_op = switch (data.op_en) {230 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],
232 .rm, .rmi, .vmi => inst.ops[1],232 .rm, .rmi, .vmi => inst.ops[1],
233 .rvm, .rvmi => inst.ops[2],233 .rvm, .rvmi => inst.ops[2],
234 else => unreachable,234 else => unreachable,
...@@ -239,6 +239,7 @@ pub const Instruction = struct {...@@ -239,6 +239,7 @@ pub const Instruction = struct {
239 .m, .mi, .m1, .mc, .vmi => enc.modRmExt(),239 .m, .mi, .m1, .mc, .vmi => enc.modRmExt(),
240 .mr, .mri, .mrc => inst.ops[1].reg.lowEnc(),240 .mr, .mri, .mrc => inst.ops[1].reg.lowEnc(),
241 .rm, .rmi, .rvm, .rvmi => inst.ops[0].reg.lowEnc(),241 .rm, .rmi, .rvm, .rvmi => inst.ops[0].reg.lowEnc(),
242 .mvr => inst.ops[2].reg.lowEnc(),
242 else => unreachable,243 else => unreachable,
243 };244 };
244 try encoder.modRm_direct(rm, reg.lowEnc());245 try encoder.modRm_direct(rm, reg.lowEnc());
...@@ -248,6 +249,7 @@ pub const Instruction = struct {...@@ -248,6 +249,7 @@ pub const Instruction = struct {
248 .m, .mi, .m1, .mc, .vmi => .none,249 .m, .mi, .m1, .mc, .vmi => .none,
249 .mr, .mri, .mrc => inst.ops[1],250 .mr, .mri, .mrc => inst.ops[1],
250 .rm, .rmi, .rvm, .rvmi => inst.ops[0],251 .rm, .rmi, .rvm, .rvmi => inst.ops[0],
252 .mvr => inst.ops[2],
251 else => unreachable,253 else => unreachable,
252 };254 };
253 try encodeMemory(enc, mem, op, encoder);255 try encodeMemory(enc, mem, op, encoder);
...@@ -315,7 +317,7 @@ pub const Instruction = struct {...@@ -315,7 +317,7 @@ pub const Instruction = struct {
315 }317 }
316 else318 else
317 null,319 null,
318 .vmi, .rvm, .rvmi => unreachable,320 .vmi, .rvm, .rvmi, .mvr => unreachable,
319 };321 };
320 if (segment_override) |seg| {322 if (segment_override) |seg| {
321 legacy.setSegmentOverride(seg);323 legacy.setSegmentOverride(seg);
...@@ -350,7 +352,7 @@ pub const Instruction = struct {...@@ -350,7 +352,7 @@ pub const Instruction = struct {
350 rex.b = b_x_op.isBaseExtended();352 rex.b = b_x_op.isBaseExtended();
351 rex.x = b_x_op.isIndexExtended();353 rex.x = b_x_op.isIndexExtended();
352 },354 },
353 .vmi, .rvm, .rvmi => unreachable,355 .vmi, .rvm, .rvmi, .mvr => unreachable,
354 }356 }
355357
356 try encoder.rex(rex);358 try encoder.rex(rex);
...@@ -372,10 +374,11 @@ pub const Instruction = struct {...@@ -372,10 +374,11 @@ pub const Instruction = struct {
372 switch (op_en) {374 switch (op_en) {
373 .np, .i, .zi, .fd, .td, .d => {},375 .np, .i, .zi, .fd, .td, .d => {},
374 .o, .oi => vex.b = inst.ops[0].reg.isExtended(),376 .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 => {
376 const r_op = switch (op_en) {378 const r_op = switch (op_en) {
377 .rm, .rmi, .rvm, .rvmi => inst.ops[0],379 .rm, .rmi, .rvm, .rvmi => inst.ops[0],
378 .mr, .mri, .mrc => inst.ops[1],380 .mr, .mri, .mrc => inst.ops[1],
381 .mvr => inst.ops[2],
379 .m, .mi, .m1, .mc, .vmi => .none,382 .m, .mi, .m1, .mc, .vmi => .none,
380 else => unreachable,383 else => unreachable,
381 };384 };
...@@ -383,7 +386,7 @@ pub const Instruction = struct {...@@ -383,7 +386,7 @@ pub const Instruction = struct {
383386
384 const b_x_op = switch (op_en) {387 const b_x_op = switch (op_en) {
385 .rm, .rmi, .vmi => inst.ops[1],388 .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],
387 .rvm, .rvmi => inst.ops[2],390 .rvm, .rvmi => inst.ops[2],
388 else => unreachable,391 else => unreachable,
389 };392 };
src/arch/x86_64/encodings.zig+30
...@@ -974,12 +974,42 @@ pub const table = [_]Entry{...@@ -974,12 +974,42 @@ pub const table = [_]Entry{
974 .{ .roundsd, .rmi, &.{ .xmm, .xmm_m64, .imm8 }, &.{ 0x66, 0x0f, 0x3a, 0x0b }, 0, .none, .sse4_1 },974 .{ .roundsd, .rmi, &.{ .xmm, .xmm_m64, .imm8 }, &.{ 0x66, 0x0f, 0x3a, 0x0b }, 0, .none, .sse4_1 },
975975
976 // AVX976 // 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
977 .{ .vmovddup, .rm, &.{ .xmm, .xmm_m64 }, &.{ 0xf2, 0x0f, 0x12 }, 0, .vex_128, .avx },987 .{ .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
979 .{ .vmovshdup, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0xf3, 0x0f, 0x16 }, 0, .vex_128, .avx },994 .{ .vmovshdup, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0xf3, 0x0f, 0x16 }, 0, .vex_128, .avx },
980995
981 .{ .vmovsldup, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0xf3, 0x0f, 0x12 }, 0, .vex_128, .avx },996 .{ .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
983 .{ .vpextrw, .mri, &.{ .r32, .xmm, .imm8 }, &.{ 0x66, 0x0f, 0x15 }, 0, .vex_128, .avx },1013 .{ .vpextrw, .mri, &.{ .r32, .xmm, .imm8 }, &.{ 0x66, 0x0f, 0x15 }, 0, .vex_128, .avx },
984 .{ .vpextrw, .mri, &.{ .r64, .xmm, .imm8 }, &.{ 0x66, 0x0f, 0x15 }, 0, .vex_128_long, .avx },1014 .{ .vpextrw, .mri, &.{ .r64, .xmm, .imm8 }, &.{ 0x66, 0x0f, 0x15 }, 0, .vex_128_long, .avx },
985 .{ .vpextrw, .mri, &.{ .r32_m16, .xmm, .imm8 }, &.{ 0x66, 0x0f, 0x3a, 0x15 }, 0, .vex_128, .avx },1015 .{ .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 {...@@ -399,7 +399,8 @@ fn testBinaryNot128(comptime Type: type, x: Type) !void {
399399
400test "division" {400test "division" {
401 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO401 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
402 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO402 if (builtin.zig_backend == .stage2_x86_64 and
403 !comptime std.Target.x86.featureSetHas(builtin.cpu.features, .sse4_1)) return error.SkipZigTest; // TODO
403 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO404 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
404 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO405 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
405 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO406 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
test/behavior/muladd.zig+6-4
...@@ -2,9 +2,11 @@ const std = @import("std");...@@ -2,9 +2,11 @@ const std = @import("std");
2const builtin = @import("builtin");2const builtin = @import("builtin");
3const expect = std.testing.expect;3const 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
5test "@mulAdd" {8test "@mulAdd" {
6 if (builtin.zig_backend == .stage2_x86_64 and9 if (stage2_x86_64_without_hardware_fma_support) return error.SkipZigTest; // TODO
7 !comptime std.Target.x86.featureSetHas(builtin.cpu.features, .fma)) return error.SkipZigTest; // TODO
8 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO10 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
9 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO11 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
10 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO12 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
...@@ -118,7 +120,7 @@ fn vector32() !void {...@@ -118,7 +120,7 @@ fn vector32() !void {
118120
119test "vector f32" {121test "vector f32" {
120 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO122 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
121 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO123 if (stage2_x86_64_without_hardware_fma_support) return error.SkipZigTest; // TODO
122 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO124 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
123 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO125 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
124 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO126 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
...@@ -141,7 +143,7 @@ fn vector64() !void {...@@ -141,7 +143,7 @@ fn vector64() !void {
141143
142test "vector f64" {144test "vector f64" {
143 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO145 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
144 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO146 if (stage2_x86_64_without_hardware_fma_support) return error.SkipZigTest; // TODO
145 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO147 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
146 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO148 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
147 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO149 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO