authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2023-05-13 18:06:16-04:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2023-05-15 03:07:51-04:00
logb6d61028508c5b1e1961a124bc17d4d9bda9686f
tree9b50fbfca9bf08638a44635d7da534284afb684d
parente08eab664861461b0adbe7984881f72b5a36a979

x86_64: reimplement `@floatToInt`


7 files changed, 420 insertions(+), 253 deletions(-)

src/arch/x86_64/CodeGen.zig+92-89
......@@ -2501,12 +2501,12 @@ fn airFptrunc(self: *Self, inst: Air.Inst.Index) !void {
25012501 }
25022502 } else if (src_bits == 64 and dst_bits == 32) {
25032503 if (self.hasFeature(.avx)) if (src_mcv.isMemory()) try self.asmRegisterRegisterMemory(
2504 .{ .v_, .cvtsd2ss },
2504 .{ .v_ss, .cvtsd2 },
25052505 dst_reg,
25062506 dst_reg,
25072507 src_mcv.mem(.qword),
25082508 ) else try self.asmRegisterRegisterRegister(
2509 .{ .v_, .cvtsd2ss },
2509 .{ .v_ss, .cvtsd2 },
25102510 dst_reg,
25112511 dst_reg,
25122512 (if (src_mcv.isRegister())
......@@ -2514,11 +2514,11 @@ fn airFptrunc(self: *Self, inst: Air.Inst.Index) !void {
25142514 else
25152515 try self.copyToTmpRegister(src_ty, src_mcv)).to128(),
25162516 ) else if (src_mcv.isMemory()) try self.asmRegisterMemory(
2517 .{ ._, .cvtsd2ss },
2517 .{ ._ss, .cvtsd2 },
25182518 dst_reg,
25192519 src_mcv.mem(.qword),
25202520 ) else try self.asmRegisterRegister(
2521 .{ ._, .cvtsd2ss },
2521 .{ ._ss, .cvtsd2 },
25222522 dst_reg,
25232523 (if (src_mcv.isRegister())
25242524 src_mcv.getReg().?
......@@ -2552,22 +2552,22 @@ fn airFpext(self: *Self, inst: Air.Inst.Index) !void {
25522552 src_mcv.getReg().?
25532553 else
25542554 try self.copyToTmpRegister(src_ty, src_mcv);
2555 try self.asmRegisterRegister(.{ .v_, .cvtph2ps }, dst_reg, mat_src_reg.to128());
2555 try self.asmRegisterRegister(.{ .v_ps, .cvtph2 }, dst_reg, mat_src_reg.to128());
25562556 switch (dst_bits) {
25572557 32 => {},
2558 64 => try self.asmRegisterRegisterRegister(.{ .v_, .cvtss2sd }, dst_reg, dst_reg, dst_reg),
2558 64 => try self.asmRegisterRegisterRegister(.{ .v_sd, .cvtss2 }, dst_reg, dst_reg, dst_reg),
25592559 else => return self.fail("TODO implement airFpext from {} to {}", .{
25602560 src_ty.fmt(self.bin_file.options.module.?), dst_ty.fmt(self.bin_file.options.module.?),
25612561 }),
25622562 }
25632563 } else if (src_bits == 32 and dst_bits == 64) {
25642564 if (self.hasFeature(.avx)) if (src_mcv.isMemory()) try self.asmRegisterRegisterMemory(
2565 .{ .v_, .cvtss2sd },
2565 .{ .v_sd, .cvtss2 },
25662566 dst_reg,
25672567 dst_reg,
25682568 src_mcv.mem(.dword),
25692569 ) else try self.asmRegisterRegisterRegister(
2570 .{ .v_, .cvtss2sd },
2570 .{ .v_sd, .cvtss2 },
25712571 dst_reg,
25722572 dst_reg,
25732573 (if (src_mcv.isRegister())
......@@ -2575,11 +2575,11 @@ fn airFpext(self: *Self, inst: Air.Inst.Index) !void {
25752575 else
25762576 try self.copyToTmpRegister(src_ty, src_mcv)).to128(),
25772577 ) else if (src_mcv.isMemory()) try self.asmRegisterMemory(
2578 .{ ._, .cvtss2sd },
2578 .{ ._sd, .cvtss2 },
25792579 dst_reg,
25802580 src_mcv.mem(.dword),
25812581 ) else try self.asmRegisterRegister(
2582 .{ ._, .cvtss2sd },
2582 .{ ._sd, .cvtss2 },
25832583 dst_reg,
25842584 (if (src_mcv.isRegister())
25852585 src_mcv.getReg().?
......@@ -4789,7 +4789,6 @@ fn genRound(self: *Self, ty: Type, dst_reg: Register, src_mcv: MCValue, mode: u4
47894789 })) |tag| tag else return self.fail("TODO implement genRound for {}", .{
47904790 ty.fmt(self.bin_file.options.module.?),
47914791 });
4792
47934792 const abi_size = @intCast(u32, ty.abiSize(self.target.*));
47944793 const dst_alias = registerAlias(dst_reg, abi_size);
47954794 switch (mir_tag[0]) {
......@@ -4848,7 +4847,7 @@ fn airSqrt(self: *Self, inst: Air.Inst.Index) !void {
48484847 src_mcv.getReg().?
48494848 else
48504849 try self.copyToTmpRegister(ty, src_mcv);
4851 try self.asmRegisterRegister(.{ .v_, .cvtph2ps }, dst_reg, mat_src_reg.to128());
4850 try self.asmRegisterRegister(.{ .v_ps, .cvtph2 }, dst_reg, mat_src_reg.to128());
48524851 try self.asmRegisterRegisterRegister(.{ .v_ss, .sqrt }, dst_reg, dst_reg, dst_reg);
48534852 try self.asmRegisterRegisterImmediate(
48544853 .{ .v_, .cvtps2ph },
......@@ -4868,7 +4867,7 @@ fn airSqrt(self: *Self, inst: Air.Inst.Index) !void {
48684867 16 => if (self.hasFeature(.f16c)) switch (ty.vectorLen()) {
48694868 1 => {
48704869 try self.asmRegisterRegister(
4871 .{ .v_, .cvtph2ps },
4870 .{ .v_ps, .cvtph2 },
48724871 dst_reg,
48734872 (if (src_mcv.isRegister())
48744873 src_mcv.getReg().?
......@@ -4892,13 +4891,13 @@ fn airSqrt(self: *Self, inst: Air.Inst.Index) !void {
48924891 2...8 => {
48934892 const wide_reg = registerAlias(dst_reg, abi_size * 2);
48944893 if (src_mcv.isMemory()) try self.asmRegisterMemory(
4895 .{ .v_, .cvtph2ps },
4894 .{ .v_ps, .cvtph2 },
48964895 wide_reg,
48974896 src_mcv.mem(Memory.PtrSize.fromSize(
48984897 @intCast(u32, @divExact(wide_reg.bitSize(), 16)),
48994898 )),
49004899 ) else try self.asmRegisterRegister(
4901 .{ .v_, .cvtph2ps },
4900 .{ .v_ps, .cvtph2 },
49024901 wide_reg,
49034902 (if (src_mcv.isRegister())
49044903 src_mcv.getReg().?
......@@ -6347,7 +6346,7 @@ fn genBinOp(
63476346 else
63486347 try self.copyToTmpRegister(rhs_ty, src_mcv)).to128(),
63496348 );
6350 try self.asmRegisterRegister(.{ .v_, .cvtph2ps }, dst_reg, dst_reg);
6349 try self.asmRegisterRegister(.{ .v_ps, .cvtph2 }, dst_reg, dst_reg);
63516350 try self.asmRegisterRegister(.{ .v_, .movshdup }, tmp_reg, dst_reg);
63526351 try self.asmRegisterRegisterRegister(
63536352 switch (air_tag) {
......@@ -6424,7 +6423,7 @@ fn genBinOp(
64246423 else
64256424 try self.copyToTmpRegister(rhs_ty, src_mcv)).to128(),
64266425 );
6427 try self.asmRegisterRegister(.{ .v_, .cvtph2ps }, dst_reg, dst_reg);
6426 try self.asmRegisterRegister(.{ .v_ps, .cvtph2 }, dst_reg, dst_reg);
64286427 try self.asmRegisterRegister(.{ .v_, .movshdup }, tmp_reg, dst_reg);
64296428 try self.asmRegisterRegisterRegister(
64306429 switch (air_tag) {
......@@ -6467,7 +6466,7 @@ fn genBinOp(
64676466 else
64686467 try self.copyToTmpRegister(rhs_ty, src_mcv)).to128(),
64696468 );
6470 try self.asmRegisterRegister(.{ .v_, .cvtph2ps }, dst_reg, dst_reg);
6469 try self.asmRegisterRegister(.{ .v_ps, .cvtph2 }, dst_reg, dst_reg);
64716470 try self.asmRegisterRegisterRegister(
64726471 .{ .v_ps, .movhl },
64736472 tmp_reg,
......@@ -6501,13 +6500,13 @@ fn genBinOp(
65016500 const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
65026501 defer self.register_manager.unlockReg(tmp_lock);
65036502
6504 try self.asmRegisterRegister(.{ .v_, .cvtph2ps }, dst_reg, dst_reg);
6503 try self.asmRegisterRegister(.{ .v_ps, .cvtph2 }, dst_reg, dst_reg);
65056504 if (src_mcv.isMemory()) try self.asmRegisterMemory(
6506 .{ .v_, .cvtph2ps },
6505 .{ .v_ps, .cvtph2 },
65076506 tmp_reg,
65086507 src_mcv.mem(.qword),
65096508 ) else try self.asmRegisterRegister(
6510 .{ .v_, .cvtph2ps },
6509 .{ .v_ps, .cvtph2 },
65116510 tmp_reg,
65126511 (if (src_mcv.isRegister())
65136512 src_mcv.getReg().?
......@@ -6541,13 +6540,13 @@ fn genBinOp(
65416540 const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
65426541 defer self.register_manager.unlockReg(tmp_lock);
65436542
6544 try self.asmRegisterRegister(.{ .v_, .cvtph2ps }, dst_reg.to256(), dst_reg);
6543 try self.asmRegisterRegister(.{ .v_ps, .cvtph2 }, dst_reg.to256(), dst_reg);
65456544 if (src_mcv.isMemory()) try self.asmRegisterMemory(
6546 .{ .v_, .cvtph2ps },
6545 .{ .v_ps, .cvtph2 },
65476546 tmp_reg,
65486547 src_mcv.mem(.xword),
65496548 ) else try self.asmRegisterRegister(
6550 .{ .v_, .cvtph2ps },
6549 .{ .v_ps, .cvtph2 },
65516550 tmp_reg,
65526551 (if (src_mcv.isRegister())
65536552 src_mcv.getReg().?
......@@ -7199,13 +7198,13 @@ fn genArgDbgInfo(self: Self, ty: Type, name: [:0]const u8, mcv: MCValue) !void {
71997198 switch (self.debug_output) {
72007199 .dwarf => |dw| {
72017200 const loc: link.File.Dwarf.DeclState.DbgInfoLoc = switch (mcv) {
7202 .register => |reg| .{ .register = reg.dwarfLocOp() },
7201 .register => |reg| .{ .register = reg.dwarfNum() },
72037202 // TODO use a frame index
72047203 .load_frame => return,
72057204 //.stack_offset => |off| .{
72067205 // .stack = .{
72077206 // // TODO handle -fomit-frame-pointer
7208 // .fp_register = Register.rbp.dwarfLocOpDeref(),
7207 // .fp_register = Register.rbp.dwarfNum(),
72097208 // .offset = -off,
72107209 // },
72117210 //},
......@@ -7237,11 +7236,11 @@ fn genVarDbgInfo(
72377236 switch (self.debug_output) {
72387237 .dwarf => |dw| {
72397238 const loc: link.File.Dwarf.DeclState.DbgInfoLoc = switch (mcv) {
7240 .register => |reg| .{ .register = reg.dwarfLocOp() },
7239 .register => |reg| .{ .register = reg.dwarfNum() },
72417240 // TODO use a frame index
72427241 .load_frame, .lea_frame => return,
72437242 //=> |off| .{ .stack = .{
7244 // .fp_register = Register.rbp.dwarfLocOpDeref(),
7243 // .fp_register = Register.rbp.dwarfNum(),
72457244 // .offset = -off,
72467245 //} },
72477246 .memory => |address| .{ .memory = address },
......@@ -7595,7 +7594,7 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
75957594 else
75967595 try self.copyToTmpRegister(ty, src_mcv)).to128(),
75977596 );
7598 try self.asmRegisterRegister(.{ .v_, .cvtph2ps }, tmp1_reg, tmp1_reg);
7597 try self.asmRegisterRegister(.{ .v_ps, .cvtph2 }, tmp1_reg, tmp1_reg);
75997598 try self.asmRegisterRegister(.{ .v_, .movshdup }, tmp2_reg, tmp1_reg);
76007599 try self.genBinOpMir(.{ ._ss, .ucomi }, ty, tmp1_mcv, tmp2_mcv);
76017600 } else return self.fail("TODO implement airCmp for {}", .{
......@@ -8862,14 +8861,14 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr
88628861 }
88638862 },
88648863 .register => |src_reg| if (dst_reg.id() != src_reg.id()) try self.asmRegisterRegister(
8865 if ((dst_reg.class() == .floating_point) == (src_reg.class() == .floating_point))
8864 if ((dst_reg.class() == .sse) == (src_reg.class() == .sse))
88668865 switch (ty.zigTypeTag()) {
88678866 else => .{ ._, .mov },
88688867 .Float, .Vector => .{ ._ps, .mova },
88698868 }
88708869 else switch (abi_size) {
88718870 2 => return try self.asmRegisterRegisterImmediate(
8872 if (dst_reg.class() == .floating_point) .{ .p_w, .insr } else .{ .p_w, .extr },
8871 if (dst_reg.class() == .sse) .{ .p_w, .insr } else .{ .p_w, .extr },
88738872 registerAlias(dst_reg, 4),
88748873 registerAlias(src_reg, 4),
88758874 Immediate.u(0),
......@@ -9222,7 +9221,7 @@ fn genInlineMemcpyRegisterRegister(
92229221 try self.asmMemoryRegister(
92239222 switch (src_reg.class()) {
92249223 .general_purpose, .segment => .{ ._, .mov },
9225 .floating_point => .{ ._ss, .mov },
9224 .sse => .{ ._ss, .mov },
92269225 },
92279226 Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ .base = dst_reg, .disp = -offset }),
92289227 registerAlias(src_reg, abi_size),
......@@ -9388,10 +9387,10 @@ fn airIntToFloat(self: *Self, inst: Air.Inst.Index) !void {
93889387 });
93899388
93909389 const src_mcv = try self.resolveInst(ty_op.operand);
9391 const src_reg = switch (src_mcv) {
9392 .register => |reg| reg,
9393 else => try self.copyToTmpRegister(src_ty, src_mcv),
9394 };
9390 const src_reg = if (src_mcv.isRegister())
9391 src_mcv.getReg().?
9392 else
9393 try self.copyToTmpRegister(src_ty, src_mcv);
93959394 const src_lock = self.register_manager.lockRegAssumeUnused(src_reg);
93969395 defer self.register_manager.unlockReg(src_lock);
93979396
......@@ -9402,23 +9401,23 @@ fn airIntToFloat(self: *Self, inst: Air.Inst.Index) !void {
94029401 const dst_lock = self.register_manager.lockRegAssumeUnused(dst_reg);
94039402 defer self.register_manager.unlockReg(dst_lock);
94049403
9405 try self.asmRegisterRegister(switch (dst_ty.floatBits(self.target.*)) {
9406 32 => if (Target.x86.featureSetHas(self.target.cpu.features, .sse))
9407 .{ ._, .cvtsi2ss }
9408 else
9409 return self.fail("TODO implement airIntToFloat from {} to {} without sse", .{
9410 src_ty.fmt(self.bin_file.options.module.?), dst_ty.fmt(self.bin_file.options.module.?),
9411 }),
9412 64 => if (Target.x86.featureSetHas(self.target.cpu.features, .sse2))
9413 .{ ._, .cvtsi2sd }
9414 else
9415 return self.fail("TODO implement airIntToFloat from {} to {} without sse2", .{
9416 src_ty.fmt(self.bin_file.options.module.?), dst_ty.fmt(self.bin_file.options.module.?),
9417 }),
9418 else => return self.fail("TODO implement airIntToFloat from {} to {}", .{
9419 src_ty.fmt(self.bin_file.options.module.?), dst_ty.fmt(self.bin_file.options.module.?),
9420 }),
9421 }, dst_reg.to128(), registerAlias(src_reg, src_size));
9404 const mir_tag = if (@as(?Mir.Inst.FixedTag, switch (dst_ty.zigTypeTag()) {
9405 .Float => switch (dst_ty.floatBits(self.target.*)) {
9406 32 => if (self.hasFeature(.avx)) .{ .v_ss, .cvtsi2 } else .{ ._ss, .cvtsi2 },
9407 64 => if (self.hasFeature(.avx)) .{ .v_sd, .cvtsi2 } else .{ ._sd, .cvtsi2 },
9408 16, 80, 128 => null,
9409 else => unreachable,
9410 },
9411 else => null,
9412 })) |tag| tag else return self.fail("TODO implement airIntToFloat from {} to {}", .{
9413 src_ty.fmt(self.bin_file.options.module.?), dst_ty.fmt(self.bin_file.options.module.?),
9414 });
9415 const dst_alias = dst_reg.to128();
9416 const src_alias = registerAlias(src_reg, src_size);
9417 switch (mir_tag[0]) {
9418 .v_ss, .v_sd => try self.asmRegisterRegisterRegister(mir_tag, dst_alias, dst_alias, src_alias),
9419 else => try self.asmRegisterRegister(mir_tag, dst_alias, src_alias),
9420 }
94229421
94239422 return self.finishAir(inst, dst_mcv, .{ ty_op.operand, .none, .none });
94249423}
......@@ -9428,46 +9427,50 @@ fn airFloatToInt(self: *Self, inst: Air.Inst.Index) !void {
94289427
94299428 const src_ty = self.air.typeOf(ty_op.operand);
94309429 const dst_ty = self.air.typeOfIndex(inst);
9431 const operand = try self.resolveInst(ty_op.operand);
9432 const src_abi_size = @intCast(u32, src_ty.abiSize(self.target.*));
9433 const dst_abi_size = @intCast(u32, dst_ty.abiSize(self.target.*));
9430 const dst_bits = @intCast(u32, dst_ty.bitSize(self.target.*));
9431 const dst_signedness =
9432 if (dst_ty.isAbiInt()) dst_ty.intInfo(self.target.*).signedness else .unsigned;
94349433
9435 switch (src_abi_size) {
9436 4, 8 => {},
9437 else => |size| return self.fail("TODO load ST(0) with abiSize={}", .{size}),
9438 }
9439 if (dst_abi_size > 8) {
9440 return self.fail("TODO convert float with abiSize={}", .{dst_abi_size});
9441 }
9434 const dst_size = std.math.divCeil(u32, @max(switch (dst_signedness) {
9435 .signed => dst_bits,
9436 .unsigned => dst_bits + 1,
9437 }, 32), 8) catch unreachable;
9438 if (dst_size > 8) return self.fail("TODO implement airFloatToInt from {} to {}", .{
9439 src_ty.fmt(self.bin_file.options.module.?), dst_ty.fmt(self.bin_file.options.module.?),
9440 });
94429441
9443 // move float src to ST(0)
9444 const frame_addr: FrameAddr = switch (operand) {
9445 .load_frame => |frame_addr| frame_addr,
9446 else => frame_addr: {
9447 const frame_index = try self.allocFrameIndex(FrameAlloc.initType(src_ty, self.target.*));
9448 try self.genSetMem(.{ .frame = frame_index }, 0, src_ty, operand);
9449 break :frame_addr .{ .index = frame_index };
9450 },
9451 };
9452 try self.asmMemory(
9453 .{ .f_, .ld },
9454 Memory.sib(Memory.PtrSize.fromSize(src_abi_size), .{
9455 .base = .{ .frame = frame_addr.index },
9456 .disp = frame_addr.off,
9457 }),
9458 );
9442 const src_mcv = try self.resolveInst(ty_op.operand);
9443 const src_reg = if (src_mcv.isRegister())
9444 src_mcv.getReg().?
9445 else
9446 try self.copyToTmpRegister(src_ty, src_mcv);
9447 const src_lock = self.register_manager.lockRegAssumeUnused(src_reg);
9448 defer self.register_manager.unlockReg(src_lock);
94599449
9460 // convert
9461 const stack_dst = try self.allocRegOrMem(inst, false);
9462 try self.asmMemory(
9463 .{ .f_p, .istt },
9464 Memory.sib(Memory.PtrSize.fromSize(dst_abi_size), .{
9465 .base = .{ .frame = stack_dst.load_frame.index },
9466 .disp = stack_dst.load_frame.off,
9450 const dst_reg = try self.register_manager.allocReg(inst, regClassForType(dst_ty));
9451 const dst_mcv = MCValue{ .register = dst_reg };
9452 const dst_lock = self.register_manager.lockRegAssumeUnused(dst_reg);
9453 defer self.register_manager.unlockReg(dst_lock);
9454
9455 try self.asmRegisterRegister(
9456 if (@as(?Mir.Inst.FixedTag, switch (src_ty.zigTypeTag()) {
9457 .Float => switch (src_ty.floatBits(self.target.*)) {
9458 32 => if (self.hasFeature(.avx)) .{ .v_, .cvttss2si } else .{ ._, .cvttss2si },
9459 64 => if (self.hasFeature(.avx)) .{ .v_, .cvttsd2si } else .{ ._, .cvttsd2si },
9460 16, 80, 128 => null,
9461 else => unreachable,
9462 },
9463 else => null,
9464 })) |tag| tag else return self.fail("TODO implement airFloatToInt from {} to {}", .{
9465 src_ty.fmt(self.bin_file.options.module.?), dst_ty.fmt(self.bin_file.options.module.?),
94679466 }),
9467 registerAlias(dst_reg, dst_size),
9468 src_reg.to128(),
94689469 );
94699470
9470 return self.finishAir(inst, stack_dst, .{ ty_op.operand, .none, .none });
9471 if (dst_bits < dst_size * 8) try self.truncateRegister(dst_ty, dst_reg);
9472
9473 return self.finishAir(inst, dst_mcv, .{ ty_op.operand, .none, .none });
94719474}
94729475
94739476fn airCmpxchg(self: *Self, inst: Air.Inst.Index) !void {
......@@ -10997,13 +11000,13 @@ fn registerAlias(reg: Register, size_bytes: u32) Register {
1099711000 reg.to64()
1099811001 else
1099911002 unreachable,
11000 .floating_point => if (size_bytes <= 16)
11003 .segment, .x87, .mmx => unreachable,
11004 .sse => if (size_bytes <= 16)
1100111005 reg.to128()
1100211006 else if (size_bytes <= 32)
1100311007 reg.to256()
1100411008 else
1100511009 unreachable,
11006 .segment => unreachable,
1100711010 };
1100811011}
1100911012
src/arch/x86_64/Encoding.zig+88-71
......@@ -233,7 +233,6 @@ pub const Mnemonic = enum {
233233 cmpxchg, cmpxchg8b, cmpxchg16b,
234234 cqo, cwd, cwde,
235235 div,
236 fisttp, fld,
237236 idiv, imul, int3,
238237 ja, jae, jb, jbe, jc, jrcxz, je, jg, jge, jl, jle, jna, jnae, jnb, jnbe,
239238 jnc, jne, jng, jnge, jnl, jnle, jno, jnp, jns, jnz, jo, jp, jpe, jpo, js, jz,
......@@ -259,6 +258,8 @@ pub const Mnemonic = enum {
259258 @"test", tzcnt,
260259 ud2,
261260 xadd, xchg, xor,
261 // X87
262 fisttp, fld,
262263 // MMX
263264 movd,
264265 // SSE
......@@ -266,7 +267,7 @@ pub const Mnemonic = enum {
266267 andps,
267268 andnps,
268269 cmpss,
269 cvtsi2ss,
270 cvtpi2ps, cvtps2pi, cvtsi2ss, cvtss2si, cvttps2pi, cvttss2si,
270271 divps, divss,
271272 maxps, maxss,
272273 minps, minss,
......@@ -285,7 +286,9 @@ pub const Mnemonic = enum {
285286 andpd,
286287 andnpd,
287288 //cmpsd,
288 cvtsd2ss, cvtsi2sd, cvtss2sd,
289 cvtdq2pd, cvtdq2ps, cvtpd2dq, cvtpd2pi, cvtpd2ps, cvtpi2pd,
290 cvtps2dq, cvtps2pd, cvtsd2si, cvtsd2ss, cvtsi2sd, cvtss2sd,
291 cvttpd2dq, cvttpd2pi, cvttps2dq, cvttsd2si,
289292 divpd, divsd,
290293 maxpd, maxsd,
291294 minpd, minsd,
......@@ -314,7 +317,10 @@ pub const Mnemonic = enum {
314317 // AVX
315318 vaddpd, vaddps, vaddsd, vaddss,
316319 vbroadcastf128, vbroadcastsd, vbroadcastss,
317 vcvtsd2ss, vcvtsi2sd, vcvtsi2ss, vcvtss2sd,
320 vcvtdq2pd, vcvtdq2ps, vcvtpd2dq, vcvtpd2ps,
321 vcvtps2dq, vcvtps2pd, vcvtsd2si, vcvtsd2ss,
322 vcvtsi2sd, vcvtsi2ss, vcvtss2sd, vcvtss2si,
323 vcvttpd2dq, vcvttps2dq, vcvttsd2si, vcvttss2si,
318324 vdivpd, vdivps, vdivsd, vdivss,
319325 vextractf128, vextractps,
320326 vinsertf128, vinsertps,
......@@ -377,80 +383,84 @@ pub const Op = enum {
377383 m,
378384 moffs,
379385 sreg,
386 st, mm, mm_m64,
380387 xmm, xmm_m32, xmm_m64, xmm_m128,
381388 ymm, ymm_m256,
382389 // zig fmt: on
383390
384391 pub fn fromOperand(operand: Instruction.Operand) Op {
385 switch (operand) {
386 .none => return .none,
387
388 .reg => |reg| {
389 switch (reg.class()) {
390 .segment => return .sreg,
391 .floating_point => return switch (reg.bitSize()) {
392 128 => .xmm,
393 256 => .ymm,
392 return switch (operand) {
393 .none => .none,
394
395 .reg => |reg| switch (reg.class()) {
396 .general_purpose => if (reg.to64() == .rax)
397 switch (reg) {
398 .al => .al,
399 .ax => .ax,
400 .eax => .eax,
401 .rax => .rax,
394402 else => unreachable,
395 },
396 .general_purpose => {
397 if (reg.to64() == .rax) return switch (reg) {
398 .al => .al,
399 .ax => .ax,
400 .eax => .eax,
401 .rax => .rax,
402 else => unreachable,
403 };
404 if (reg == .cl) return .cl;
405 return switch (reg.bitSize()) {
406 8 => .r8,
407 16 => .r16,
408 32 => .r32,
409 64 => .r64,
410 else => unreachable,
411 };
412 },
413 }
403 }
404 else if (reg == .cl)
405 .cl
406 else switch (reg.bitSize()) {
407 8 => .r8,
408 16 => .r16,
409 32 => .r32,
410 64 => .r64,
411 else => unreachable,
412 },
413 .segment => .sreg,
414 .x87 => .st,
415 .mmx => .mm,
416 .sse => switch (reg.bitSize()) {
417 128 => .xmm,
418 256 => .ymm,
419 else => unreachable,
420 },
414421 },
415422
416423 .mem => |mem| switch (mem) {
417 .moffs => return .moffs,
418 .sib, .rip => {
419 const bit_size = mem.bitSize();
420 return switch (bit_size) {
421 8 => .m8,
422 16 => .m16,
423 32 => .m32,
424 64 => .m64,
425 80 => .m80,
426 128 => .m128,
427 256 => .m256,
428 else => unreachable,
429 };
424 .moffs => .moffs,
425 .sib, .rip => switch (mem.bitSize()) {
426 8 => .m8,
427 16 => .m16,
428 32 => .m32,
429 64 => .m64,
430 80 => .m80,
431 128 => .m128,
432 256 => .m256,
433 else => unreachable,
430434 },
431435 },
432436
433 .imm => |imm| {
434 switch (imm) {
435 .signed => |x| {
436 if (x == 1) return .unity;
437 if (math.cast(i8, x)) |_| return .imm8s;
438 if (math.cast(i16, x)) |_| return .imm16s;
439 return .imm32s;
440 },
441 .unsigned => |x| {
442 if (x == 1) return .unity;
443 if (math.cast(i8, x)) |_| return .imm8s;
444 if (math.cast(u8, x)) |_| return .imm8;
445 if (math.cast(i16, x)) |_| return .imm16s;
446 if (math.cast(u16, x)) |_| return .imm16;
447 if (math.cast(i32, x)) |_| return .imm32s;
448 if (math.cast(u32, x)) |_| return .imm32;
449 return .imm64;
450 },
451 }
437 .imm => |imm| switch (imm) {
438 .signed => |x| if (x == 1)
439 .unity
440 else if (math.cast(i8, x)) |_|
441 .imm8s
442 else if (math.cast(i16, x)) |_|
443 .imm16s
444 else
445 .imm32s,
446 .unsigned => |x| if (x == 1)
447 .unity
448 else if (math.cast(i8, x)) |_|
449 .imm8s
450 else if (math.cast(u8, x)) |_|
451 .imm8
452 else if (math.cast(i16, x)) |_|
453 .imm16s
454 else if (math.cast(u16, x)) |_|
455 .imm16
456 else if (math.cast(i32, x)) |_|
457 .imm32s
458 else if (math.cast(u32, x)) |_|
459 .imm32
460 else
461 .imm64,
452462 },
453 }
463 };
454464 }
455465
456466 pub fn immBitSize(op: Op) u64 {
......@@ -460,6 +470,7 @@ pub const Op = enum {
460470 .ax, .r16, .rm16 => unreachable,
461471 .eax, .r32, .rm32, .r32_m16 => unreachable,
462472 .rax, .r64, .rm64, .r64_m16 => unreachable,
473 .st, .mm, .mm_m64 => unreachable,
463474 .xmm, .xmm_m32, .xmm_m64, .xmm_m128 => unreachable,
464475 .ymm, .ymm_m256 => unreachable,
465476 .m8, .m16, .m32, .m64, .m80, .m128, .m256 => unreachable,
......@@ -480,7 +491,8 @@ pub const Op = enum {
480491 .al, .cl, .r8, .rm8 => 8,
481492 .ax, .r16, .rm16 => 16,
482493 .eax, .r32, .rm32, .r32_m8, .r32_m16 => 32,
483 .rax, .r64, .rm64, .r64_m16 => 64,
494 .rax, .r64, .rm64, .r64_m16, .mm, .mm_m64 => 64,
495 .st => 80,
484496 .xmm, .xmm_m32, .xmm_m64, .xmm_m128 => 128,
485497 .ymm, .ymm_m256 => 256,
486498 };
......@@ -491,11 +503,11 @@ pub const Op = enum {
491503 .none, .o16, .o32, .o64, .moffs, .m, .sreg => unreachable,
492504 .unity, .imm8, .imm8s, .imm16, .imm16s, .imm32, .imm32s, .imm64 => unreachable,
493505 .rel8, .rel16, .rel32 => unreachable,
494 .al, .cl, .r8, .ax, .r16, .eax, .r32, .rax, .r64, .xmm, .ymm => unreachable,
506 .al, .cl, .r8, .ax, .r16, .eax, .r32, .rax, .r64, .st, .mm, .xmm, .ymm => unreachable,
495507 .m8, .rm8, .r32_m8 => 8,
496508 .m16, .rm16, .r32_m16, .r64_m16 => 16,
497509 .m32, .rm32, .xmm_m32 => 32,
498 .m64, .rm64, .xmm_m64 => 64,
510 .m64, .rm64, .mm_m64, .xmm_m64 => 64,
499511 .m80 => 80,
500512 .m128, .xmm_m128 => 128,
501513 .m256, .ymm_m256 => 256,
......@@ -522,6 +534,7 @@ pub const Op = enum {
522534 .r8, .r16, .r32, .r64,
523535 .rm8, .rm16, .rm32, .rm64,
524536 .r32_m8, .r32_m16, .r64_m16,
537 .st, .mm, .mm_m64,
525538 .xmm, .xmm_m32, .xmm_m64, .xmm_m128,
526539 .ymm, .ymm_m256,
527540 => true,
......@@ -550,6 +563,7 @@ pub const Op = enum {
550563 .r32_m8, .r32_m16, .r64_m16,
551564 .m8, .m16, .m32, .m64, .m80, .m128, .m256,
552565 .m,
566 .mm_m64,
553567 .xmm_m32, .xmm_m64, .xmm_m128,
554568 .ymm_m256,
555569 => true,
......@@ -573,8 +587,10 @@ pub const Op = enum {
573587 .rm8, .rm16, .rm32, .rm64 => .general_purpose,
574588 .r32_m8, .r32_m16, .r64_m16 => .general_purpose,
575589 .sreg => .segment,
576 .xmm, .xmm_m32, .xmm_m64, .xmm_m128 => .floating_point,
577 .ymm, .ymm_m256 => .floating_point,
590 .st => .x87,
591 .mm, .mm_m64 => .mmx,
592 .xmm, .xmm_m32, .xmm_m64, .xmm_m128 => .sse,
593 .ymm, .ymm_m256 => .sse,
578594 };
579595 }
580596
......@@ -695,6 +711,7 @@ pub const Feature = enum {
695711 f16c,
696712 fma,
697713 lzcnt,
714 movbe,
698715 popcnt,
699716 sse,
700717 sse2,
......@@ -717,7 +734,7 @@ fn estimateInstructionLength(prefix: Prefix, encoding: Encoding, ops: []const Op
717734}
718735
719736const mnemonic_to_encodings_map = init: {
720 @setEvalBranchQuota(20_000);
737 @setEvalBranchQuota(25_000);
721738 const encodings = @import("encodings.zig");
722739 var entries = encodings.table;
723740 std.sort.sort(encodings.Entry, &entries, {}, struct {
src/arch/x86_64/Mir.zig+40-6
......@@ -439,8 +439,21 @@ pub const Inst = struct {
439439 /// Bitwise logical and not of packed single-precision floating-point values
440440 /// Bitwise logical and not of packed double-precision floating-point values
441441 andn,
442 /// Convert packed doubleword integers to packed single-precision floating-point values
443 /// Convert packed doubleword integers to packed double-precision floating-point values
444 cvtpi2,
445 /// Convert packed single-precision floating-point values to packed doubleword integers
446 cvtps2pi,
442447 /// Convert doubleword integer to scalar single-precision floating-point value
443 cvtsi2ss,
448 /// Convert doubleword integer to scalar double-precision floating-point value
449 cvtsi2,
450 /// Convert scalar single-precision floating-point value to doubleword integer
451 cvtss2si,
452 /// Convert with truncation packed single-precision floating-point values to packed doubleword integers
453 cvttps2pi,
454 /// Convert with truncation scalar single-precision floating-point value to doubleword integer
455 cvttss2si,
456
444457 /// Maximum of packed single-precision floating-point values
445458 /// Maximum of scalar single-precision floating-point values
446459 /// Maximum of packed double-precision floating-point values
......@@ -486,12 +499,33 @@ pub const Inst = struct {
486499 /// Unpack and interleave low packed double-precision floating-point values
487500 unpckl,
488501
502 /// Convert packed doubleword integers to packed single-precision floating-point values
503 /// Convert packed doubleword integers to packed double-precision floating-point values
504 cvtdq2,
505 /// Convert packed double-precision floating-point values to packed doubleword integers
506 cvtpd2dq,
507 /// Convert packed double-precision floating-point values to packed doubleword integers
508 cvtpd2pi,
509 /// Convert packed double-precision floating-point values to packed single-precision floating-point values
510 cvtpd2,
511 /// Convert packed single-precision floating-point values to packed doubleword integers
512 cvtps2dq,
513 /// Convert packed single-precision floating-point values to packed double-precision floating-point values
514 cvtps2,
515 /// Convert scalar double-precision floating-point value to doubleword integer
516 cvtsd2si,
489517 /// Convert scalar double-precision floating-point value to scalar single-precision floating-point value
490 cvtsd2ss,
491 /// Convert doubleword integer to scalar double-precision floating-point value
492 cvtsi2sd,
518 cvtsd2,
493519 /// Convert scalar single-precision floating-point value to scalar double-precision floating-point value
494 cvtss2sd,
520 cvtss2,
521 /// Convert with truncation packed double-precision floating-point values to packed doubleword integers
522 cvttpd2dq,
523 /// Convert with truncation packed double-precision floating-point values to packed doubleword integers
524 cvttpd2pi,
525 /// Convert with truncation packed single-precision floating-point values to packed doubleword integers
526 cvttps2dq,
527 /// Convert with truncation scalar double-precision floating-point value to doubleword integer
528 cvttsd2si,
495529 /// Packed interleave shuffle of quadruplets of single-precision floating-point values
496530 /// Packed interleave shuffle of pairs of double-precision floating-point values
497531 shuf,
......@@ -542,7 +576,7 @@ pub const Inst = struct {
542576 broadcast,
543577
544578 /// Convert 16-bit floating-point values to single-precision floating-point values
545 cvtph2ps,
579 cvtph2,
546580 /// Convert single-precision floating-point values to 16-bit floating-point values
547581 cvtps2ph,
548582
src/arch/x86_64/bits.zig+38-45
......@@ -175,15 +175,21 @@ pub const Register = enum(u7) {
175175 xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7,
176176 xmm8, xmm9, xmm10, xmm11, xmm12, xmm13, xmm14, xmm15,
177177
178 mm0, mm1, mm2, mm3, mm4, mm5, mm6, mm7,
179
180 st0, st1, st2, st3, st4, st5, st6, st7,
181
178182 es, cs, ss, ds, fs, gs,
179183
180184 none,
181185 // zig fmt: on
182186
183 pub const Class = enum(u2) {
187 pub const Class = enum {
184188 general_purpose,
185 floating_point,
186189 segment,
190 x87,
191 mmx,
192 sse,
187193 };
188194
189195 pub fn class(reg: Register) Class {
......@@ -195,8 +201,10 @@ pub const Register = enum(u7) {
195201 @enumToInt(Register.al) ... @enumToInt(Register.r15b) => .general_purpose,
196202 @enumToInt(Register.ah) ... @enumToInt(Register.bh) => .general_purpose,
197203
198 @enumToInt(Register.ymm0) ... @enumToInt(Register.ymm15) => .floating_point,
199 @enumToInt(Register.xmm0) ... @enumToInt(Register.xmm15) => .floating_point,
204 @enumToInt(Register.ymm0) ... @enumToInt(Register.ymm15) => .sse,
205 @enumToInt(Register.xmm0) ... @enumToInt(Register.xmm15) => .sse,
206 @enumToInt(Register.mm0) ... @enumToInt(Register.mm7) => .mmx,
207 @enumToInt(Register.st0) ... @enumToInt(Register.st7) => .x87,
200208
201209 @enumToInt(Register.es) ... @enumToInt(Register.gs) => .segment,
202210
......@@ -216,8 +224,10 @@ pub const Register = enum(u7) {
216224
217225 @enumToInt(Register.ymm0) ... @enumToInt(Register.ymm15) => @enumToInt(Register.ymm0) - 16,
218226 @enumToInt(Register.xmm0) ... @enumToInt(Register.xmm15) => @enumToInt(Register.xmm0) - 16,
227 @enumToInt(Register.mm0) ... @enumToInt(Register.mm7) => @enumToInt(Register.mm0) - 32,
228 @enumToInt(Register.st0) ... @enumToInt(Register.st7) => @enumToInt(Register.st0) - 40,
219229
220 @enumToInt(Register.es) ... @enumToInt(Register.gs) => @enumToInt(Register.es) - 32,
230 @enumToInt(Register.es) ... @enumToInt(Register.gs) => @enumToInt(Register.es) - 48,
221231
222232 else => unreachable,
223233 // zig fmt: on
......@@ -236,6 +246,8 @@ pub const Register = enum(u7) {
236246
237247 @enumToInt(Register.ymm0) ... @enumToInt(Register.ymm15) => 256,
238248 @enumToInt(Register.xmm0) ... @enumToInt(Register.xmm15) => 128,
249 @enumToInt(Register.mm0) ... @enumToInt(Register.mm7) => 64,
250 @enumToInt(Register.st0) ... @enumToInt(Register.st7) => 80,
239251
240252 @enumToInt(Register.es) ... @enumToInt(Register.gs) => 16,
241253
......@@ -271,6 +283,8 @@ pub const Register = enum(u7) {
271283
272284 @enumToInt(Register.ymm0) ... @enumToInt(Register.ymm15) => @enumToInt(Register.ymm0),
273285 @enumToInt(Register.xmm0) ... @enumToInt(Register.xmm15) => @enumToInt(Register.xmm0),
286 @enumToInt(Register.mm0) ... @enumToInt(Register.mm7) => @enumToInt(Register.mm0),
287 @enumToInt(Register.st0) ... @enumToInt(Register.st7) => @enumToInt(Register.st0),
274288
275289 @enumToInt(Register.es) ... @enumToInt(Register.gs) => @enumToInt(Register.es),
276290
......@@ -326,8 +340,8 @@ pub const Register = enum(u7) {
326340 return @intToEnum(Register, @enumToInt(reg) - reg.gpBase() + @enumToInt(Register.al));
327341 }
328342
329 fn fpBase(reg: Register) u7 {
330 assert(reg.class() == .floating_point);
343 fn sseBase(reg: Register) u7 {
344 assert(reg.class() == .sse);
331345 return switch (@enumToInt(reg)) {
332346 @enumToInt(Register.ymm0)...@enumToInt(Register.ymm15) => @enumToInt(Register.ymm0),
333347 @enumToInt(Register.xmm0)...@enumToInt(Register.xmm15) => @enumToInt(Register.xmm0),
......@@ -336,49 +350,24 @@ pub const Register = enum(u7) {
336350 }
337351
338352 pub fn to256(reg: Register) Register {
339 return @intToEnum(Register, @enumToInt(reg) - reg.fpBase() + @enumToInt(Register.ymm0));
353 return @intToEnum(Register, @enumToInt(reg) - reg.sseBase() + @enumToInt(Register.ymm0));
340354 }
341355
342356 pub fn to128(reg: Register) Register {
343 return @intToEnum(Register, @enumToInt(reg) - reg.fpBase() + @enumToInt(Register.xmm0));
344 }
345
346 pub fn dwarfLocOp(reg: Register) u8 {
347 return switch (reg.class()) {
348 .general_purpose => switch (reg.to64()) {
349 .rax => DW.OP.reg0,
350 .rdx => DW.OP.reg1,
351 .rcx => DW.OP.reg2,
352 .rbx => DW.OP.reg3,
353 .rsi => DW.OP.reg4,
354 .rdi => DW.OP.reg5,
355 .rbp => DW.OP.reg6,
356 .rsp => DW.OP.reg7,
357 else => @intCast(u8, @enumToInt(reg) - reg.gpBase()) + DW.OP.reg0,
358 },
359 .floating_point => @intCast(u8, @enumToInt(reg) - reg.fpBase()) + DW.OP.reg17,
360 else => unreachable,
361 };
357 return @intToEnum(Register, @enumToInt(reg) - reg.sseBase() + @enumToInt(Register.xmm0));
362358 }
363359
364 /// DWARF encodings that push a value onto the DWARF stack that is either
365 /// the contents of a register or the result of adding the contents a given
366 /// register to a given signed offset.
367 pub fn dwarfLocOpDeref(reg: Register) u8 {
360 /// DWARF register encoding
361 pub fn dwarfNum(reg: Register) u6 {
368362 return switch (reg.class()) {
369 .general_purpose => switch (reg.to64()) {
370 .rax => DW.OP.breg0,
371 .rdx => DW.OP.breg1,
372 .rcx => DW.OP.breg2,
373 .rbx => DW.OP.breg3,
374 .rsi => DW.OP.breg4,
375 .rdi => DW.OP.breg5,
376 .rbp => DW.OP.breg6,
377 .rsp => DW.OP.breg7,
378 else => @intCast(u8, @enumToInt(reg) - reg.gpBase()) + DW.OP.breg0,
379 },
380 .floating_point => @intCast(u8, @enumToInt(reg) - reg.fpBase()) + DW.OP.breg17,
381 else => unreachable,
363 .general_purpose => if (reg.isExtended())
364 reg.enc()
365 else
366 @truncate(u3, @as(u24, 0o54673120) >> @as(u5, reg.enc()) * 3),
367 .sse => 17 + @as(u6, reg.enc()),
368 .x87 => 33 + @as(u6, reg.enc()),
369 .mmx => 41 + @as(u6, reg.enc()),
370 .segment => 50 + @as(u6, reg.enc()),
382371 };
383372 }
384373};
......@@ -392,6 +381,8 @@ test "Register id - different classes" {
392381 try expect(Register.ymm0.id() == 0b10000);
393382 try expect(Register.ymm0.id() != Register.rax.id());
394383 try expect(Register.xmm0.id() == Register.ymm0.id());
384 try expect(Register.xmm0.id() != Register.mm0.id());
385 try expect(Register.mm0.id() != Register.st0.id());
395386
396387 try expect(Register.es.id() == 0b100000);
397388}
......@@ -407,7 +398,9 @@ test "Register enc - different classes" {
407398
408399test "Register classes" {
409400 try expect(Register.r11.class() == .general_purpose);
410 try expect(Register.ymm11.class() == .floating_point);
401 try expect(Register.ymm11.class() == .sse);
402 try expect(Register.mm3.class() == .mmx);
403 try expect(Register.st3.class() == .x87);
411404 try expect(Register.fs.class() == .segment);
412405}
413406
src/arch/x86_64/encodings.zig+94-17
......@@ -272,14 +272,6 @@ pub const table = [_]Entry{
272272 .{ .div, .m, &.{ .rm32 }, &.{ 0xf7 }, 6, .none, .none },
273273 .{ .div, .m, &.{ .rm64 }, &.{ 0xf7 }, 6, .long, .none },
274274
275 .{ .fisttp, .m, &.{ .m16 }, &.{ 0xdf }, 1, .none, .x87 },
276 .{ .fisttp, .m, &.{ .m32 }, &.{ 0xdb }, 1, .none, .x87 },
277 .{ .fisttp, .m, &.{ .m64 }, &.{ 0xdd }, 1, .none, .x87 },
278
279 .{ .fld, .m, &.{ .m32 }, &.{ 0xd9 }, 0, .none, .x87 },
280 .{ .fld, .m, &.{ .m64 }, &.{ 0xdd }, 0, .none, .x87 },
281 .{ .fld, .m, &.{ .m80 }, &.{ 0xdb }, 5, .none, .x87 },
282
283275 .{ .idiv, .m, &.{ .rm8 }, &.{ 0xf6 }, 7, .none, .none },
284276 .{ .idiv, .m, &.{ .rm8 }, &.{ 0xf6 }, 7, .rex, .none },
285277 .{ .idiv, .m, &.{ .rm16 }, &.{ 0xf7 }, 7, .short, .none },
......@@ -395,12 +387,12 @@ pub const table = [_]Entry{
395387 .{ .mov, .mi, &.{ .rm32, .imm32 }, &.{ 0xc7 }, 0, .none, .none },
396388 .{ .mov, .mi, &.{ .rm64, .imm32s }, &.{ 0xc7 }, 0, .long, .none },
397389
398 .{ .movbe, .rm, &.{ .r16, .m16 }, &.{ 0x0f, 0x38, 0xf0 }, 0, .short, .none },
399 .{ .movbe, .rm, &.{ .r32, .m32 }, &.{ 0x0f, 0x38, 0xf0 }, 0, .none, .none },
400 .{ .movbe, .rm, &.{ .r64, .m64 }, &.{ 0x0f, 0x38, 0xf0 }, 0, .long, .none },
401 .{ .movbe, .mr, &.{ .m16, .r16 }, &.{ 0x0f, 0x38, 0xf1 }, 0, .short, .none },
402 .{ .movbe, .mr, &.{ .m32, .r32 }, &.{ 0x0f, 0x38, 0xf1 }, 0, .none, .none },
403 .{ .movbe, .mr, &.{ .m64, .r64 }, &.{ 0x0f, 0x38, 0xf1 }, 0, .long, .none },
390 .{ .movbe, .rm, &.{ .r16, .m16 }, &.{ 0x0f, 0x38, 0xf0 }, 0, .short, .movbe },
391 .{ .movbe, .rm, &.{ .r32, .m32 }, &.{ 0x0f, 0x38, 0xf0 }, 0, .none, .movbe },
392 .{ .movbe, .rm, &.{ .r64, .m64 }, &.{ 0x0f, 0x38, 0xf0 }, 0, .long, .movbe },
393 .{ .movbe, .mr, &.{ .m16, .r16 }, &.{ 0x0f, 0x38, 0xf1 }, 0, .short, .movbe },
394 .{ .movbe, .mr, &.{ .m32, .r32 }, &.{ 0x0f, 0x38, 0xf1 }, 0, .none, .movbe },
395 .{ .movbe, .mr, &.{ .m64, .r64 }, &.{ 0x0f, 0x38, 0xf1 }, 0, .long, .movbe },
404396
405397 .{ .movs, .np, &.{ .m8, .m8 }, &.{ 0xa4 }, 0, .none, .none },
406398 .{ .movs, .np, &.{ .m16, .m16 }, &.{ 0xa5 }, 0, .short, .none },
......@@ -836,6 +828,15 @@ pub const table = [_]Entry{
836828 .{ .xor, .rm, &.{ .r32, .rm32 }, &.{ 0x33 }, 0, .none, .none },
837829 .{ .xor, .rm, &.{ .r64, .rm64 }, &.{ 0x33 }, 0, .long, .none },
838830
831 // X87
832 .{ .fisttp, .m, &.{ .m16 }, &.{ 0xdf }, 1, .none, .x87 },
833 .{ .fisttp, .m, &.{ .m32 }, &.{ 0xdb }, 1, .none, .x87 },
834 .{ .fisttp, .m, &.{ .m64 }, &.{ 0xdd }, 1, .none, .x87 },
835
836 .{ .fld, .m, &.{ .m32 }, &.{ 0xd9 }, 0, .none, .x87 },
837 .{ .fld, .m, &.{ .m64 }, &.{ 0xdd }, 0, .none, .x87 },
838 .{ .fld, .m, &.{ .m80 }, &.{ 0xdb }, 5, .none, .x87 },
839
839840 // SSE
840841 .{ .addps, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0x0f, 0x58 }, 0, .none, .sse },
841842
......@@ -847,9 +848,21 @@ pub const table = [_]Entry{
847848
848849 .{ .cmpss, .rmi, &.{ .xmm, .xmm_m32, .imm8 }, &.{ 0xf3, 0x0f, 0xc2 }, 0, .none, .sse },
849850
851 .{ .cvtpi2ps, .rm, &.{ .xmm, .mm_m64 }, &.{ 0x0f, 0x2a }, 0, .none, .sse },
852
853 .{ .cvtps2pi, .rm, &.{ .mm, .xmm_m64 }, &.{ 0x0f, 0x2d }, 0, .none, .sse },
854
850855 .{ .cvtsi2ss, .rm, &.{ .xmm, .rm32 }, &.{ 0xf3, 0x0f, 0x2a }, 0, .none, .sse },
851856 .{ .cvtsi2ss, .rm, &.{ .xmm, .rm64 }, &.{ 0xf3, 0x0f, 0x2a }, 0, .long, .sse },
852857
858 .{ .cvtss2si, .rm, &.{ .r32, .xmm_m32 }, &.{ 0xf3, 0x0f, 0x2d }, 0, .none, .sse },
859 .{ .cvtss2si, .rm, &.{ .r64, .xmm_m32 }, &.{ 0xf3, 0x0f, 0x2d }, 0, .long, .sse },
860
861 .{ .cvttps2pi, .rm, &.{ .mm, .xmm_m64 }, &.{ 0x0f, 0x2c }, 0, .none, .sse },
862
863 .{ .cvttss2si, .rm, &.{ .r32, .xmm_m32 }, &.{ 0xf3, 0x0f, 0x2c }, 0, .none, .sse },
864 .{ .cvttss2si, .rm, &.{ .r64, .xmm_m32 }, &.{ 0xf3, 0x0f, 0x2c }, 0, .long, .sse },
865
853866 .{ .divps, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0x0f, 0x5e }, 0, .none, .sse },
854867
855868 .{ .divss, .rm, &.{ .xmm, .xmm_m32 }, &.{ 0xf3, 0x0f, 0x5e }, 0, .none, .sse },
......@@ -906,6 +919,25 @@ pub const table = [_]Entry{
906919
907920 .{ .cmpsd, .rmi, &.{ .xmm, .xmm_m64, .imm8 }, &.{ 0xf2, 0x0f, 0xc2 }, 0, .none, .sse2 },
908921
922 .{ .cvtdq2pd, .rm, &.{ .xmm, .xmm_m64 }, &.{ 0xf3, 0x0f, 0xe6 }, 0, .none, .sse2 },
923
924 .{ .cvtdq2ps, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0x0f, 0x5b }, 0, .none, .sse2 },
925
926 .{ .cvtpd2dq, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0xf2, 0x0f, 0xe6 }, 0, .none, .sse2 },
927
928 .{ .cvtpd2pi, .rm, &.{ .mm, .xmm_m128 }, &.{ 0x66, 0x0f, 0x2d }, 0, .none, .sse2 },
929
930 .{ .cvtpd2ps, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0x5a }, 0, .none, .sse2 },
931
932 .{ .cvtpi2pd, .rm, &.{ .xmm, .mm_m64 }, &.{ 0x66, 0x0f, 0x2a }, 0, .none, .sse2 },
933
934 .{ .cvtps2dq, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0x5b }, 0, .none, .sse2 },
935
936 .{ .cvtps2pd, .rm, &.{ .xmm, .xmm_m64 }, &.{ 0x0f, 0x5a }, 0, .none, .sse2 },
937
938 .{ .cvtsd2si, .rm, &.{ .r32, .xmm_m64 }, &.{ 0xf2, 0x0f, 0x2d }, 0, .none, .sse2 },
939 .{ .cvtsd2si, .rm, &.{ .r64, .xmm_m64 }, &.{ 0xf2, 0x0f, 0x2d }, 0, .long, .sse2 },
940
909941 .{ .cvtsd2ss, .rm, &.{ .xmm, .xmm_m64 }, &.{ 0xf2, 0x0f, 0x5a }, 0, .none, .sse2 },
910942
911943 .{ .cvtsi2sd, .rm, &.{ .xmm, .rm32 }, &.{ 0xf2, 0x0f, 0x2a }, 0, .none, .sse2 },
......@@ -913,6 +945,15 @@ pub const table = [_]Entry{
913945
914946 .{ .cvtss2sd, .rm, &.{ .xmm, .xmm_m32 }, &.{ 0xf3, 0x0f, 0x5a }, 0, .none, .sse2 },
915947
948 .{ .cvttpd2dq, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0xe6 }, 0, .none, .sse2 },
949
950 .{ .cvttpd2pi, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0x2c }, 0, .none, .sse2 },
951
952 .{ .cvttps2dq, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0xf3, 0x0f, 0x5b }, 0, .none, .sse2 },
953
954 .{ .cvttsd2si, .rm, &.{ .r32, .xmm_m64 }, &.{ 0xf2, 0x0f, 0x2c }, 0, .none, .sse2 },
955 .{ .cvttsd2si, .rm, &.{ .r64, .xmm_m64 }, &.{ 0xf2, 0x0f, 0x2c }, 0, .long, .sse2 },
956
916957 .{ .divpd, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0x5e }, 0, .none, .sse2 },
917958
918959 .{ .divsd, .rm, &.{ .xmm, .xmm_m64 }, &.{ 0xf2, 0x0f, 0x5e }, 0, .none, .sse2 },
......@@ -1034,15 +1075,51 @@ pub const table = [_]Entry{
10341075 .{ .vbroadcastsd, .rm, &.{ .ymm, .m64 }, &.{ 0x66, 0x0f, 0x38, 0x19 }, 0, .vex_256_w0, .avx },
10351076 .{ .vbroadcastf128, .rm, &.{ .ymm, .m128 }, &.{ 0x66, 0x0f, 0x38, 0x1a }, 0, .vex_256_w0, .avx },
10361077
1078 .{ .vcvtdq2pd, .rm, &.{ .xmm, .xmm_m64 }, &.{ 0xf3, 0x0f, 0xe6 }, 0, .vex_128_wig, .avx },
1079 .{ .vcvtdq2pd, .rm, &.{ .ymm, .xmm_m128 }, &.{ 0xf3, 0x0f, 0xe6 }, 0, .vex_256_wig, .avx },
1080
1081 .{ .vcvtdq2ps, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0x0f, 0x5b }, 0, .vex_128_wig, .avx },
1082 .{ .vcvtdq2ps, .rm, &.{ .ymm, .ymm_m256 }, &.{ 0x0f, 0x5b }, 0, .vex_256_wig, .avx },
1083
1084 .{ .vcvtpd2dq, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0xf2, 0x0f, 0xe6 }, 0, .vex_128_wig, .avx },
1085 .{ .vcvtpd2dq, .rm, &.{ .xmm, .ymm_m256 }, &.{ 0xf2, 0x0f, 0xe6 }, 0, .vex_256_wig, .avx },
1086
1087 .{ .vcvtpd2ps, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0x5a }, 0, .vex_128_wig, .avx },
1088 .{ .vcvtpd2ps, .rm, &.{ .xmm, .ymm_m256 }, &.{ 0x66, 0x0f, 0x5a }, 0, .vex_256_wig, .avx },
1089
1090 .{ .vcvtps2dq, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0x5b }, 0, .vex_128_wig, .avx },
1091 .{ .vcvtps2dq, .rm, &.{ .ymm, .ymm_m256 }, &.{ 0x66, 0x0f, 0x5b }, 0, .vex_256_wig, .avx },
1092
1093 .{ .vcvtps2pd, .rm, &.{ .xmm, .xmm_m64 }, &.{ 0x0f, 0x5a }, 0, .vex_128_wig, .avx },
1094 .{ .vcvtps2pd, .rm, &.{ .ymm, .xmm_m128 }, &.{ 0x0f, 0x5a }, 0, .vex_256_wig, .avx },
1095
1096 .{ .vcvtsd2si, .rm, &.{ .r32, .xmm_m64 }, &.{ 0xf2, 0x0f, 0x2d }, 0, .vex_lig_w0, .sse2 },
1097 .{ .vcvtsd2si, .rm, &.{ .r64, .xmm_m64 }, &.{ 0xf2, 0x0f, 0x2d }, 0, .vex_lig_w1, .sse2 },
1098
10371099 .{ .vcvtsd2ss, .rvm, &.{ .xmm, .xmm, .xmm_m64 }, &.{ 0xf2, 0x0f, 0x5a }, 0, .vex_lig_wig, .avx },
10381100
10391101 .{ .vcvtsi2sd, .rvm, &.{ .xmm, .xmm, .rm32 }, &.{ 0xf2, 0x0f, 0x2a }, 0, .vex_lig_w0, .avx },
10401102 .{ .vcvtsi2sd, .rvm, &.{ .xmm, .xmm, .rm64 }, &.{ 0xf2, 0x0f, 0x2a }, 0, .vex_lig_w1, .avx },
10411103
1042 .{ .vcvtsi2ss, .rvm, &.{ .xmm, .xmm, .rm32 }, &.{ 0xf2, 0x0f, 0x2a }, 0, .vex_lig_w0, .avx },
1043 .{ .vcvtsi2ss, .rvm, &.{ .xmm, .xmm, .rm64 }, &.{ 0xf2, 0x0f, 0x2a }, 0, .vex_lig_w1, .avx },
1104 .{ .vcvtsi2ss, .rvm, &.{ .xmm, .xmm, .rm32 }, &.{ 0xf3, 0x0f, 0x2a }, 0, .vex_lig_w0, .avx },
1105 .{ .vcvtsi2ss, .rvm, &.{ .xmm, .xmm, .rm64 }, &.{ 0xf3, 0x0f, 0x2a }, 0, .vex_lig_w1, .avx },
1106
1107 .{ .vcvtss2sd, .rvm, &.{ .xmm, .xmm, .xmm_m32 }, &.{ 0xf3, 0x0f, 0x5a }, 0, .vex_lig_wig, .avx },
1108
1109 .{ .vcvtss2si, .rm, &.{ .r32, .xmm_m32 }, &.{ 0xf3, 0x0f, 0x2d }, 0, .vex_lig_w0, .avx },
1110 .{ .vcvtss2si, .rm, &.{ .r64, .xmm_m32 }, &.{ 0xf3, 0x0f, 0x2d }, 0, .vex_lig_w1, .avx },
1111
1112 .{ .vcvttpd2dq, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0xe6 }, 0, .vex_128_wig, .avx },
1113 .{ .vcvttpd2dq, .rm, &.{ .xmm, .ymm_m256 }, &.{ 0x66, 0x0f, 0xe6 }, 0, .vex_256_wig, .avx },
1114
1115 .{ .vcvttps2dq, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0xf3, 0x0f, 0x5b }, 0, .vex_128_wig, .avx },
1116 .{ .vcvttps2dq, .rm, &.{ .ymm, .ymm_m256 }, &.{ 0xf3, 0x0f, 0x5b }, 0, .vex_256_wig, .avx },
1117
1118 .{ .vcvttsd2si, .rm, &.{ .r32, .xmm_m64 }, &.{ 0xf2, 0x0f, 0x2c }, 0, .vex_lig_w0, .sse2 },
1119 .{ .vcvttsd2si, .rm, &.{ .r64, .xmm_m64 }, &.{ 0xf2, 0x0f, 0x2c }, 0, .vex_lig_w1, .sse2 },
10441120
1045 .{ .vcvtss2sd, .rvm, &.{ .xmm, .xmm, .xmm_m32 }, &.{ 0xf2, 0x0f, 0x5a }, 0, .vex_lig_wig, .avx },
1121 .{ .vcvttss2si, .rm, &.{ .r32, .xmm_m32 }, &.{ 0xf3, 0x0f, 0x2c }, 0, .vex_lig_w0, .avx },
1122 .{ .vcvttss2si, .rm, &.{ .r64, .xmm_m32 }, &.{ 0xf3, 0x0f, 0x2c }, 0, .vex_lig_w1, .avx },
10461123
10471124 .{ .vdivpd, .rvm, &.{ .xmm, .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0x5e }, 0, .vex_128_wig, .avx },
10481125 .{ .vdivpd, .rvm, &.{ .ymm, .ymm, .ymm_m256 }, &.{ 0x66, 0x0f, 0x5e }, 0, .vex_256_wig, .avx },
src/link/Dwarf.zig+68-24
......@@ -608,23 +608,44 @@ pub const DeclState = struct {
608608
609609 switch (loc) {
610610 .register => |reg| {
611 try dbg_info.ensureUnusedCapacity(3);
611 try dbg_info.ensureUnusedCapacity(4);
612612 dbg_info.appendAssumeCapacity(@enumToInt(AbbrevKind.parameter));
613 dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc
614 1, // ULEB128 dwarf expression length
615 reg,
616 });
613 // DW.AT.location, DW.FORM.exprloc
614 var expr_len = std.io.countingWriter(std.io.null_writer);
615 if (reg < 32) {
616 expr_len.writer().writeByte(DW.OP.reg0 + reg) catch unreachable;
617 } else {
618 expr_len.writer().writeByte(DW.OP.regx) catch unreachable;
619 leb128.writeULEB128(expr_len.writer(), reg) catch unreachable;
620 }
621 leb128.writeULEB128(dbg_info.writer(), expr_len.bytes_written) catch unreachable;
622 if (reg < 32) {
623 dbg_info.appendAssumeCapacity(DW.OP.reg0 + reg);
624 } else {
625 dbg_info.appendAssumeCapacity(DW.OP.regx);
626 leb128.writeULEB128(dbg_info.writer(), reg) catch unreachable;
627 }
617628 },
618629 .stack => |info| {
619 try dbg_info.ensureUnusedCapacity(8);
630 try dbg_info.ensureUnusedCapacity(9);
620631 dbg_info.appendAssumeCapacity(@enumToInt(AbbrevKind.parameter));
621 const fixup = dbg_info.items.len;
622 dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc
623 1, // we will backpatch it after we encode the displacement in LEB128
624 info.fp_register, // frame pointer
625 });
632 // DW.AT.location, DW.FORM.exprloc
633 var expr_len = std.io.countingWriter(std.io.null_writer);
634 if (info.fp_register < 32) {
635 expr_len.writer().writeByte(DW.OP.breg0 + info.fp_register) catch unreachable;
636 } else {
637 expr_len.writer().writeByte(DW.OP.bregx) catch unreachable;
638 leb128.writeULEB128(expr_len.writer(), info.fp_register) catch unreachable;
639 }
640 leb128.writeILEB128(expr_len.writer(), info.offset) catch unreachable;
641 leb128.writeULEB128(dbg_info.writer(), expr_len.bytes_written) catch unreachable;
642 if (info.fp_register < 32) {
643 dbg_info.appendAssumeCapacity(DW.OP.breg0 + info.fp_register);
644 } else {
645 dbg_info.appendAssumeCapacity(DW.OP.bregx);
646 leb128.writeULEB128(dbg_info.writer(), info.fp_register) catch unreachable;
647 }
626648 leb128.writeILEB128(dbg_info.writer(), info.offset) catch unreachable;
627 dbg_info.items[fixup] += @intCast(u8, dbg_info.items.len - fixup - 2);
628649 },
629650 .wasm_local => |value| {
630651 const leb_size = link.File.Wasm.getULEB128Size(value);
......@@ -670,22 +691,45 @@ pub const DeclState = struct {
670691
671692 switch (loc) {
672693 .register => |reg| {
673 try dbg_info.ensureUnusedCapacity(2);
674 dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc
675 1, // ULEB128 dwarf expression length
676 reg,
677 });
694 try dbg_info.ensureUnusedCapacity(4);
695 dbg_info.appendAssumeCapacity(@enumToInt(AbbrevKind.parameter));
696 // DW.AT.location, DW.FORM.exprloc
697 var expr_len = std.io.countingWriter(std.io.null_writer);
698 if (reg < 32) {
699 expr_len.writer().writeByte(DW.OP.reg0 + reg) catch unreachable;
700 } else {
701 expr_len.writer().writeByte(DW.OP.regx) catch unreachable;
702 leb128.writeULEB128(expr_len.writer(), reg) catch unreachable;
703 }
704 leb128.writeULEB128(dbg_info.writer(), expr_len.bytes_written) catch unreachable;
705 if (reg < 32) {
706 dbg_info.appendAssumeCapacity(DW.OP.reg0 + reg);
707 } else {
708 dbg_info.appendAssumeCapacity(DW.OP.regx);
709 leb128.writeULEB128(dbg_info.writer(), reg) catch unreachable;
710 }
678711 },
679712
680713 .stack => |info| {
681 try dbg_info.ensureUnusedCapacity(7);
682 const fixup = dbg_info.items.len;
683 dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc
684 1, // we will backpatch it after we encode the displacement in LEB128
685 info.fp_register,
686 });
714 try dbg_info.ensureUnusedCapacity(9);
715 dbg_info.appendAssumeCapacity(@enumToInt(AbbrevKind.parameter));
716 // DW.AT.location, DW.FORM.exprloc
717 var expr_len = std.io.countingWriter(std.io.null_writer);
718 if (info.fp_register < 32) {
719 expr_len.writer().writeByte(DW.OP.breg0 + info.fp_register) catch unreachable;
720 } else {
721 expr_len.writer().writeByte(DW.OP.bregx) catch unreachable;
722 leb128.writeULEB128(expr_len.writer(), info.fp_register) catch unreachable;
723 }
724 leb128.writeILEB128(expr_len.writer(), info.offset) catch unreachable;
725 leb128.writeULEB128(dbg_info.writer(), expr_len.bytes_written) catch unreachable;
726 if (info.fp_register < 32) {
727 dbg_info.appendAssumeCapacity(DW.OP.breg0 + info.fp_register);
728 } else {
729 dbg_info.appendAssumeCapacity(DW.OP.bregx);
730 leb128.writeULEB128(dbg_info.writer(), info.fp_register) catch unreachable;
731 }
687732 leb128.writeILEB128(dbg_info.writer(), info.offset) catch unreachable;
688 dbg_info.items[fixup] += @intCast(u8, dbg_info.items.len - fixup - 2);
689733 },
690734
691735 .wasm_local => |value| {
test/behavior/cast.zig-1
......@@ -153,7 +153,6 @@ test "@intToFloat(f80)" {
153153test "@floatToInt" {
154154 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
155155 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
156 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
157156 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
158157 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
159158 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;