authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-05-18 14:15:27+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-05-19 19:39:34+02:00
log36b939e8db902b01870d709faeb6d2725f4f73ae
tree3e8951aa6f3baa2c56239274d24c1cbe946c186c
parent020f99d893be794376eea329af06838474744e80

x64: handle basic f32 using AVX registers


4 files changed, 352 insertions(+), 341 deletions(-)

src/arch/x86_64/CodeGen.zig+96-74
...@@ -3469,22 +3469,28 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValu...@@ -3469,22 +3469,28 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValu
3469 return self.genBinOpMir(mir_tag, dst_ty, dst_mcv, .{ .register = reg });3469 return self.genBinOpMir(mir_tag, dst_ty, dst_mcv, .{ .register = reg });
3470 },3470 },
3471 .register => |src_reg| switch (dst_ty.zigTypeTag()) {3471 .register => |src_reg| switch (dst_ty.zigTypeTag()) {
3472 .Float => switch (dst_ty.tag()) {3472 .Float => {
3473 .f64 => {3473 const actual_tag: Mir.Inst.Tag = switch (dst_ty.tag()) {
3474 _ = try self.addInst(.{3474 .f32 => switch (mir_tag) {
3475 .tag = switch (mir_tag) {3475 .add => Mir.Inst.Tag.add_f32,
3476 .add => .add_f64,3476 .cmp => Mir.Inst.Tag.cmp_f32,
3477 .cmp => .cmp_f64,3477 else => return self.fail("TODO genBinOpMir for f32 register-register with MIR tag {}", .{mir_tag}),
3478 else => return self.fail("TODO genBinOpMir for f64 register-register with MIR tag {}", .{mir_tag}),3478 },
3479 },3479 .f64 => switch (mir_tag) {
3480 .ops = Mir.Inst.Ops.encode(.{3480 .add => Mir.Inst.Tag.add_f64,
3481 .reg1 = dst_reg.to128(),3481 .cmp => Mir.Inst.Tag.cmp_f64,
3482 .reg2 = src_reg.to128(),3482 else => return self.fail("TODO genBinOpMir for f64 register-register with MIR tag {}", .{mir_tag}),
3483 }),3483 },
3484 .data = undefined,3484 else => return self.fail("TODO genBinOpMir for float register-register and type {}", .{dst_ty.fmtDebug()}),
3485 });3485 };
3486 },3486 _ = try self.addInst(.{
3487 else => return self.fail("TODO genBinOpMir for float register-register and type {}", .{dst_ty.fmtDebug()}),3487 .tag = actual_tag,
3488 .ops = Mir.Inst.Ops.encode(.{
3489 .reg1 = dst_reg.to128(),
3490 .reg2 = src_reg.to128(),
3491 }),
3492 .data = undefined,
3493 });
3488 },3494 },
3489 else => {3495 else => {
3490 _ = try self.addInst(.{3496 _ = try self.addInst(.{
...@@ -5475,20 +5481,25 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: Inl...@@ -5475,20 +5481,25 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: Inl
5475 const base_reg = opts.dest_stack_base orelse .rbp;5481 const base_reg = opts.dest_stack_base orelse .rbp;
54765482
5477 switch (ty.zigTypeTag()) {5483 switch (ty.zigTypeTag()) {
5478 .Float => switch (ty.tag()) {5484 .Float => {
5479 .f32 => return self.fail("TODO genSetStack for register for f32", .{}),5485 const tag: Mir.Inst.Tag = switch (ty.tag()) {
5480 .f64 => {5486 .f32 => .mov_f32,
5481 _ = try self.addInst(.{5487 .f64 => .mov_f64,
5482 .tag = .mov_f64,5488 else => return self.fail("TODO genSetStack for register for type {}", .{ty.fmtDebug()}),
5483 .ops = Mir.Inst.Ops.encode(.{5489 };
5484 .reg1 = base_reg,5490 _ = try self.addInst(.{
5485 .reg2 = reg.to128(),5491 .tag = tag,
5486 .flags = 0b01,5492 .ops = Mir.Inst.Ops.encode(.{
5487 }),5493 .reg1 = switch (ty.tag()) {
5488 .data = .{ .imm = @bitCast(u32, -stack_offset) },5494 .f32 => base_reg.to32(),
5489 });5495 .f64 => base_reg.to64(),
5490 },5496 else => unreachable,
5491 else => return self.fail("TODO genSetStack for register for type {}", .{ty.fmtDebug()}),5497 },
5498 .reg2 = reg.to128(),
5499 .flags = 0b01,
5500 }),
5501 .data = .{ .imm = @bitCast(u32, -stack_offset) },
5502 });
5492 },5503 },
5493 else => {5504 else => {
5494 if (!math.isPowerOfTwo(abi_size)) {5505 if (!math.isPowerOfTwo(abi_size)) {
...@@ -5991,21 +6002,22 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void...@@ -5991,21 +6002,22 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
5991 }6002 }
5992 },6003 },
5993 },6004 },
5994 .Float => switch (ty.tag()) {6005 .Float => {
5995 .f32 => return self.fail("TODO genSetReg from register for f32", .{}),6006 const tag: Mir.Inst.Tag = switch (ty.tag()) {
5996 .f64 => {6007 .f32 => .mov_f32,
5997 _ = try self.addInst(.{6008 .f64 => .mov_f64,
5998 .tag = .mov_f64,6009 else => return self.fail("TODO genSetReg from register for {}", .{ty.fmtDebug()}),
5999 .ops = Mir.Inst.Ops.encode(.{6010 };
6000 .reg1 = reg.to128(),6011 _ = try self.addInst(.{
6001 .reg2 = src_reg.to128(),6012 .tag = tag,
6002 .flags = 0b10,6013 .ops = Mir.Inst.Ops.encode(.{
6003 }),6014 .reg1 = reg.to128(),
6004 .data = undefined,6015 .reg2 = src_reg.to128(),
6005 });6016 .flags = 0b10,
6006 return;6017 }),
6007 },6018 .data = undefined,
6008 else => return self.fail("TODO genSetReg from register for {}", .{ty.fmtDebug()}),6019 });
6020 return;
6009 },6021 },
6010 else => {},6022 else => {},
6011 }6023 }
...@@ -6035,22 +6047,27 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void...@@ -6035,22 +6047,27 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
6035 },6047 },
6036 .memory => |x| switch (ty.zigTypeTag()) {6048 .memory => |x| switch (ty.zigTypeTag()) {
6037 .Float => {6049 .Float => {
6038 switch (ty.tag()) {6050 const base_reg = try self.register_manager.allocReg(null, .{ .selector_mask = gp });
6039 .f32 => return self.fail("TODO genSetReg from memory for f32", .{}),6051 try self.loadMemPtrIntoRegister(base_reg, Type.usize, mcv);
6040 .f64 => {6052
6041 const base_reg = try self.register_manager.allocReg(null, .{ .selector_mask = gp });6053 const tag: Mir.Inst.Tag = switch (ty.tag()) {
6042 try self.loadMemPtrIntoRegister(base_reg, Type.usize, mcv);6054 .f32 => .mov_f32,
6043 _ = try self.addInst(.{6055 .f64 => .mov_f64,
6044 .tag = .mov_f64,
6045 .ops = Mir.Inst.Ops.encode(.{
6046 .reg1 = reg.to128(),
6047 .reg2 = base_reg.to64(),
6048 }),
6049 .data = .{ .imm = 0 },
6050 });
6051 },
6052 else => return self.fail("TODO genSetReg from memory for {}", .{ty.fmtDebug()}),6056 else => return self.fail("TODO genSetReg from memory for {}", .{ty.fmtDebug()}),
6053 }6057 };
6058
6059 _ = try self.addInst(.{
6060 .tag = tag,
6061 .ops = Mir.Inst.Ops.encode(.{
6062 .reg1 = reg.to128(),
6063 .reg2 = switch (ty.tag()) {
6064 .f32 => base_reg.to32(),
6065 .f64 => base_reg.to64(),
6066 else => unreachable,
6067 },
6068 }),
6069 .data = .{ .imm = 0 },
6070 });
6054 },6071 },
6055 else => {6072 else => {
6056 if (x <= math.maxInt(i32)) {6073 if (x <= math.maxInt(i32)) {
...@@ -6142,20 +6159,25 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void...@@ -6142,20 +6159,25 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
6142 }6159 }
6143 },6160 },
6144 },6161 },
6145 .Float => switch (ty.tag()) {6162 .Float => {
6146 .f32 => return self.fail("TODO genSetReg from stack offset for f32", .{}),6163 const tag: Mir.Inst.Tag = switch (ty.tag()) {
6147 .f64 => {6164 .f32 => .mov_f32,
6148 _ = try self.addInst(.{6165 .f64 => .mov_f64,
6149 .tag = .mov_f64,6166 else => return self.fail("TODO genSetReg from stack offset for {}", .{ty.fmtDebug()}),
6150 .ops = Mir.Inst.Ops.encode(.{6167 };
6151 .reg1 = reg.to128(),6168 _ = try self.addInst(.{
6152 .reg2 = .rbp,6169 .tag = tag,
6153 }),6170 .ops = Mir.Inst.Ops.encode(.{
6154 .data = .{ .imm = @bitCast(u32, -off) },6171 .reg1 = reg.to128(),
6155 });6172 .reg2 = switch (ty.tag()) {
6156 return;6173 .f32 => .ebp,
6157 },6174 .f64 => .rbp,
6158 else => return self.fail("TODO genSetReg from stack offset for {}", .{ty.fmtDebug()}),6175 else => unreachable,
6176 },
6177 }),
6178 .data = .{ .imm = @bitCast(u32, -off) },
6179 });
6180 return;
6159 },6181 },
6160 else => {},6182 else => {},
6161 }6183 }
src/arch/x86_64/Emit.zig+97-111
...@@ -183,11 +183,14 @@ pub fn lowerMir(emit: *Emit) InnerError!void {...@@ -183,11 +183,14 @@ pub fn lowerMir(emit: *Emit) InnerError!void {
183 .nop => try emit.mirNop(),183 .nop => try emit.mirNop(),
184184
185 // AVX instructions185 // AVX instructions
186 .mov_f64 => try emit.mirMovF64(inst),186 .mov_f64 => try emit.mirMovFloatAvx(.vmovsd, inst),
187 .mov_f32 => try emit.mirMovFloatAvx(.vmovss, inst),
187188
188 .add_f64 => try emit.mirAddF64(inst),189 .add_f64 => try emit.mirAddFloatAvx(.vaddsd, inst),
190 .add_f32 => try emit.mirAddFloatAvx(.vaddss, inst),
189191
190 .cmp_f64 => try emit.mirCmpF64(inst),192 .cmp_f64 => try emit.mirCmpFloatAvx(.vucomisd, inst),
193 .cmp_f32 => try emit.mirCmpFloatAvx(.vucomiss, inst),
191194
192 // Pseudo-instructions195 // Pseudo-instructions
193 .call_extern => try emit.mirCallExtern(inst),196 .call_extern => try emit.mirCallExtern(inst),
...@@ -962,71 +965,48 @@ fn mirLeaPie(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {...@@ -962,71 +965,48 @@ fn mirLeaPie(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
962965
963// AVX instructions966// AVX instructions
964967
965fn mirMovF64(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {968fn mirMovFloatAvx(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {
966 const tag = emit.mir.instructions.items(.tag)[inst];
967 assert(tag == .mov_f64);
968 const ops = emit.mir.instructions.items(.ops)[inst].decode();969 const ops = emit.mir.instructions.items(.ops)[inst].decode();
969970
970 switch (ops.flags) {971 switch (ops.flags) {
971 0b00 => {972 0b00 => {
972 const imm = emit.mir.instructions.items(.data)[inst].imm;973 const imm = emit.mir.instructions.items(.data)[inst].imm;
973 return lowerToVmEnc(.vmovsd, ops.reg1, RegisterOrMemory.mem(.qword_ptr, .{974 return lowerToVmEnc(tag, ops.reg1, RegisterOrMemory.mem(Memory.PtrSize.new(ops.reg2.size()), .{
974 .disp = imm,975 .disp = imm,
975 .base = ops.reg2,976 .base = ops.reg2,
976 }), emit.code);977 }), emit.code);
977 },978 },
978 0b01 => {979 0b01 => {
979 const imm = emit.mir.instructions.items(.data)[inst].imm;980 const imm = emit.mir.instructions.items(.data)[inst].imm;
980 return lowerToMvEnc(.vmovsd, RegisterOrMemory.mem(.qword_ptr, .{981 return lowerToMvEnc(tag, RegisterOrMemory.mem(Memory.PtrSize.new(ops.reg1.size()), .{
981 .disp = imm,982 .disp = imm,
982 .base = ops.reg1,983 .base = ops.reg1,
983 }), ops.reg2, emit.code);984 }), ops.reg2, emit.code);
984 },985 },
985 0b10 => {986 0b10 => {
986 return lowerToRvmEnc(987 return lowerToRvmEnc(tag, ops.reg1, ops.reg1, RegisterOrMemory.reg(ops.reg2), emit.code);
987 .vmovsd,
988 ops.reg1,
989 ops.reg1,
990 RegisterOrMemory.reg(ops.reg2),
991 emit.code,
992 );
993 },988 },
994 else => return emit.fail("TODO unused variant 0b{b} for mov_f64", .{ops.flags}),989 else => return emit.fail("TODO unused variant 0b{b} for mov_f64", .{ops.flags}),
995 }990 }
996}991}
997992
998fn mirAddF64(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {993fn mirAddFloatAvx(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {
999 const tag = emit.mir.instructions.items(.tag)[inst];
1000 assert(tag == .add_f64);
1001 const ops = emit.mir.instructions.items(.ops)[inst].decode();994 const ops = emit.mir.instructions.items(.ops)[inst].decode();
1002995
1003 switch (ops.flags) {996 switch (ops.flags) {
1004 0b00 => {997 0b00 => {
1005 return lowerToRvmEnc(998 return lowerToRvmEnc(tag, ops.reg1, ops.reg1, RegisterOrMemory.reg(ops.reg2), emit.code);
1006 .vaddsd,
1007 ops.reg1,
1008 ops.reg1,
1009 RegisterOrMemory.reg(ops.reg2),
1010 emit.code,
1011 );
1012 },999 },
1013 else => return emit.fail("TODO unused variant 0b{b} for mov_f64", .{ops.flags}),1000 else => return emit.fail("TODO unused variant 0b{b} for mov_f64", .{ops.flags}),
1014 }1001 }
1015}1002}
10161003
1017fn mirCmpF64(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {1004fn mirCmpFloatAvx(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {
1018 const tag = emit.mir.instructions.items(.tag)[inst];
1019 assert(tag == .cmp_f64);
1020 const ops = emit.mir.instructions.items(.ops)[inst].decode();1005 const ops = emit.mir.instructions.items(.ops)[inst].decode();
10211006
1022 switch (ops.flags) {1007 switch (ops.flags) {
1023 0b00 => {1008 0b00 => {
1024 return lowerToVmEnc(1009 return lowerToVmEnc(tag, ops.reg1, RegisterOrMemory.reg(ops.reg2), emit.code);
1025 .vucomisd,
1026 ops.reg1,
1027 RegisterOrMemory.reg(ops.reg2),
1028 emit.code,
1029 );
1030 },1010 },
1031 else => return emit.fail("TODO unused variant 0b{b} for mov_f64", .{ops.flags}),1011 else => return emit.fail("TODO unused variant 0b{b} for mov_f64", .{ops.flags}),
1032 }1012 }
...@@ -1268,16 +1248,24 @@ const Tag = enum {...@@ -1268,16 +1248,24 @@ const Tag = enum {
1268 cmovb,1248 cmovb,
1269 cmovnae,1249 cmovnae,
1270 vmovsd,1250 vmovsd,
1251 vmovss,
1271 vaddsd,1252 vaddsd,
1253 vaddss,
1272 vcmpsd,1254 vcmpsd,
1255 vcmpss,
1273 vucomisd,1256 vucomisd,
1257 vucomiss,
12741258
1275 fn isAvx(tag: Tag) bool {1259 fn isAvx(tag: Tag) bool {
1276 return switch (tag) {1260 return switch (tag) {
1277 .vmovsd,1261 .vmovsd,
1262 .vmovss,
1278 .vaddsd,1263 .vaddsd,
1264 .vaddss,
1279 .vcmpsd,1265 .vcmpsd,
1266 .vcmpss,
1280 .vucomisd,1267 .vucomisd,
1268 .vucomiss,
1281 => true,1269 => true,
12821270
1283 else => false,1271 else => false,
...@@ -1406,7 +1394,7 @@ const OpCode = union(enum) {...@@ -1406,7 +1394,7 @@ const OpCode = union(enum) {
1406 }1394 }
1407};1395};
14081396
1409inline fn getOpCode(tag: Tag, enc: Encoding, is_one_byte: bool) ?OpCode {1397inline fn getOpCode(tag: Tag, enc: Encoding, is_one_byte: bool) OpCode {
1410 switch (enc) {1398 switch (enc) {
1411 .zo => return switch (tag) {1399 .zo => return switch (tag) {
1412 .ret_near => OpCode.oneByte(0xc3),1400 .ret_near => OpCode.oneByte(0xc3),
...@@ -1416,7 +1404,7 @@ inline fn getOpCode(tag: Tag, enc: Encoding, is_one_byte: bool) ?OpCode {...@@ -1416,7 +1404,7 @@ inline fn getOpCode(tag: Tag, enc: Encoding, is_one_byte: bool) ?OpCode {
1416 .syscall => OpCode.twoByte(0x0f, 0x05),1404 .syscall => OpCode.twoByte(0x0f, 0x05),
1417 .cbw => OpCode.oneByte(0x98),1405 .cbw => OpCode.oneByte(0x98),
1418 .cwd, .cdq, .cqo => OpCode.oneByte(0x99),1406 .cwd, .cdq, .cqo => OpCode.oneByte(0x99),
1419 else => null,1407 else => unreachable,
1420 },1408 },
1421 .d => return switch (tag) {1409 .d => return switch (tag) {
1422 .jmp_near => OpCode.oneByte(0xe9),1410 .jmp_near => OpCode.oneByte(0xe9),
...@@ -1437,7 +1425,7 @@ inline fn getOpCode(tag: Tag, enc: Encoding, is_one_byte: bool) ?OpCode {...@@ -1437,7 +1425,7 @@ inline fn getOpCode(tag: Tag, enc: Encoding, is_one_byte: bool) ?OpCode {
1437 .jge, .jnl => if (is_one_byte) OpCode.oneByte(0x7d) else OpCode.twoByte(0x0f, 0x8d),1425 .jge, .jnl => if (is_one_byte) OpCode.oneByte(0x7d) else OpCode.twoByte(0x0f, 0x8d),
1438 .jle, .jng => if (is_one_byte) OpCode.oneByte(0x7e) else OpCode.twoByte(0x0f, 0x8e),1426 .jle, .jng => if (is_one_byte) OpCode.oneByte(0x7e) else OpCode.twoByte(0x0f, 0x8e),
1439 .jg, .jnle => if (is_one_byte) OpCode.oneByte(0x7f) else OpCode.twoByte(0x0f, 0x8f),1427 .jg, .jnle => if (is_one_byte) OpCode.oneByte(0x7f) else OpCode.twoByte(0x0f, 0x8f),
1440 else => null,1428 else => unreachable,
1441 },1429 },
1442 .m => return switch (tag) {1430 .m => return switch (tag) {
1443 .jmp_near, .call_near, .push => OpCode.oneByte(0xff),1431 .jmp_near, .call_near, .push => OpCode.oneByte(0xff),
...@@ -1464,38 +1452,38 @@ inline fn getOpCode(tag: Tag, enc: Encoding, is_one_byte: bool) ?OpCode {...@@ -1464,38 +1452,38 @@ inline fn getOpCode(tag: Tag, enc: Encoding, is_one_byte: bool) ?OpCode {
1464 .fisttp64 => OpCode.oneByte(0xdd),1452 .fisttp64 => OpCode.oneByte(0xdd),
1465 .fld32 => OpCode.oneByte(0xd9),1453 .fld32 => OpCode.oneByte(0xd9),
1466 .fld64 => OpCode.oneByte(0xdd),1454 .fld64 => OpCode.oneByte(0xdd),
1467 else => null,1455 else => unreachable,
1468 },1456 },
1469 .o => return switch (tag) {1457 .o => return switch (tag) {
1470 .push => OpCode.oneByte(0x50),1458 .push => OpCode.oneByte(0x50),
1471 .pop => OpCode.oneByte(0x58),1459 .pop => OpCode.oneByte(0x58),
1472 else => null,1460 else => unreachable,
1473 },1461 },
1474 .i => return switch (tag) {1462 .i => return switch (tag) {
1475 .push => OpCode.oneByte(if (is_one_byte) 0x6a else 0x68),1463 .push => OpCode.oneByte(if (is_one_byte) 0x6a else 0x68),
1476 .@"test" => OpCode.oneByte(if (is_one_byte) 0xa8 else 0xa9),1464 .@"test" => OpCode.oneByte(if (is_one_byte) 0xa8 else 0xa9),
1477 .ret_near => OpCode.oneByte(0xc2),1465 .ret_near => OpCode.oneByte(0xc2),
1478 .ret_far => OpCode.oneByte(0xca),1466 .ret_far => OpCode.oneByte(0xca),
1479 else => null,1467 else => unreachable,
1480 },1468 },
1481 .m1 => return switch (tag) {1469 .m1 => return switch (tag) {
1482 .shl, .sal, .shr, .sar => OpCode.oneByte(if (is_one_byte) 0xd0 else 0xd1),1470 .shl, .sal, .shr, .sar => OpCode.oneByte(if (is_one_byte) 0xd0 else 0xd1),
1483 else => null,1471 else => unreachable,
1484 },1472 },
1485 .mc => return switch (tag) {1473 .mc => return switch (tag) {
1486 .shl, .sal, .shr, .sar => OpCode.oneByte(if (is_one_byte) 0xd2 else 0xd3),1474 .shl, .sal, .shr, .sar => OpCode.oneByte(if (is_one_byte) 0xd2 else 0xd3),
1487 else => null,1475 else => unreachable,
1488 },1476 },
1489 .mi => return switch (tag) {1477 .mi => return switch (tag) {
1490 .adc, .add, .sub, .xor, .@"and", .@"or", .sbb, .cmp => OpCode.oneByte(if (is_one_byte) 0x80 else 0x81),1478 .adc, .add, .sub, .xor, .@"and", .@"or", .sbb, .cmp => OpCode.oneByte(if (is_one_byte) 0x80 else 0x81),
1491 .mov => OpCode.oneByte(if (is_one_byte) 0xc6 else 0xc7),1479 .mov => OpCode.oneByte(if (is_one_byte) 0xc6 else 0xc7),
1492 .@"test" => OpCode.oneByte(if (is_one_byte) 0xf6 else 0xf7),1480 .@"test" => OpCode.oneByte(if (is_one_byte) 0xf6 else 0xf7),
1493 else => null,1481 else => unreachable,
1494 },1482 },
1495 .mi8 => return switch (tag) {1483 .mi8 => return switch (tag) {
1496 .adc, .add, .sub, .xor, .@"and", .@"or", .sbb, .cmp => OpCode.oneByte(0x83),1484 .adc, .add, .sub, .xor, .@"and", .@"or", .sbb, .cmp => OpCode.oneByte(0x83),
1497 .shl, .sal, .shr, .sar => OpCode.oneByte(if (is_one_byte) 0xc0 else 0xc1),1485 .shl, .sal, .shr, .sar => OpCode.oneByte(if (is_one_byte) 0xc0 else 0xc1),
1498 else => null,1486 else => unreachable,
1499 },1487 },
1500 .mr => return switch (tag) {1488 .mr => return switch (tag) {
1501 .adc => OpCode.oneByte(if (is_one_byte) 0x10 else 0x11),1489 .adc => OpCode.oneByte(if (is_one_byte) 0x10 else 0x11),
...@@ -1508,8 +1496,7 @@ inline fn getOpCode(tag: Tag, enc: Encoding, is_one_byte: bool) ?OpCode {...@@ -1508,8 +1496,7 @@ inline fn getOpCode(tag: Tag, enc: Encoding, is_one_byte: bool) ?OpCode {
1508 .cmp => OpCode.oneByte(if (is_one_byte) 0x38 else 0x39),1496 .cmp => OpCode.oneByte(if (is_one_byte) 0x38 else 0x39),
1509 .mov => OpCode.oneByte(if (is_one_byte) 0x88 else 0x89),1497 .mov => OpCode.oneByte(if (is_one_byte) 0x88 else 0x89),
1510 .@"test" => OpCode.oneByte(if (is_one_byte) 0x84 else 0x85),1498 .@"test" => OpCode.oneByte(if (is_one_byte) 0x84 else 0x85),
1511 .vmovsd => OpCode.oneByte(0x11),1499 else => unreachable,
1512 else => null,
1513 },1500 },
1514 .rm => return switch (tag) {1501 .rm => return switch (tag) {
1515 .adc => OpCode.oneByte(if (is_one_byte) 0x12 else 0x13),1502 .adc => OpCode.oneByte(if (is_one_byte) 0x12 else 0x13),
...@@ -1529,48 +1516,46 @@ inline fn getOpCode(tag: Tag, enc: Encoding, is_one_byte: bool) ?OpCode {...@@ -1529,48 +1516,46 @@ inline fn getOpCode(tag: Tag, enc: Encoding, is_one_byte: bool) ?OpCode {
1529 .cmove, .cmovz => OpCode.twoByte(0x0f, 0x44),1516 .cmove, .cmovz => OpCode.twoByte(0x0f, 0x44),
1530 .cmovb, .cmovnae => OpCode.twoByte(0x0f, 0x42),1517 .cmovb, .cmovnae => OpCode.twoByte(0x0f, 0x42),
1531 .cmovl, .cmovng => OpCode.twoByte(0x0f, 0x4c),1518 .cmovl, .cmovng => OpCode.twoByte(0x0f, 0x4c),
1532 .vmovsd => OpCode.oneByte(0x10),1519 else => unreachable,
1533 .vucomisd => OpCode.oneByte(0x2e),
1534 else => null,
1535 },1520 },
1536 .oi => return switch (tag) {1521 .oi => return switch (tag) {
1537 .mov => OpCode.oneByte(if (is_one_byte) 0xb0 else 0xb8),1522 .mov => OpCode.oneByte(if (is_one_byte) 0xb0 else 0xb8),
1538 else => null,1523 else => unreachable,
1539 },1524 },
1540 .fd => return switch (tag) {1525 .fd => return switch (tag) {
1541 .mov => OpCode.oneByte(if (is_one_byte) 0xa0 else 0xa1),1526 .mov => OpCode.oneByte(if (is_one_byte) 0xa0 else 0xa1),
1542 else => null,1527 else => unreachable,
1543 },1528 },
1544 .td => return switch (tag) {1529 .td => return switch (tag) {
1545 .mov => OpCode.oneByte(if (is_one_byte) 0xa2 else 0xa3),1530 .mov => OpCode.oneByte(if (is_one_byte) 0xa2 else 0xa3),
1546 else => null,1531 else => unreachable,
1547 },1532 },
1548 .rmi => return switch (tag) {1533 .rmi => return switch (tag) {
1549 .imul => OpCode.oneByte(if (is_one_byte) 0x6b else 0x69),1534 .imul => OpCode.oneByte(if (is_one_byte) 0x6b else 0x69),
1550 else => null,1535 else => unreachable,
1551 },1536 },
1552 .mv => return switch (tag) {1537 .mv => return switch (tag) {
1553 .vmovsd => OpCode.oneByte(0x11),1538 .vmovsd, .vmovss => OpCode.oneByte(0x11),
1554 else => null,1539 else => unreachable,
1555 },1540 },
1556 .vm => return switch (tag) {1541 .vm => return switch (tag) {
1557 .vmovsd => OpCode.oneByte(0x10),1542 .vmovsd, .vmovss => OpCode.oneByte(0x10),
1558 .vucomisd => OpCode.oneByte(0x2e),1543 .vucomisd, .vucomiss => OpCode.oneByte(0x2e),
1559 else => null,1544 else => unreachable,
1560 },1545 },
1561 .rvm => return switch (tag) {1546 .rvm => return switch (tag) {
1562 .vaddsd => OpCode.oneByte(0x58),1547 .vaddsd, .vaddss => OpCode.oneByte(0x58),
1563 .vmovsd => OpCode.oneByte(0x10),1548 .vmovsd, .vmovss => OpCode.oneByte(0x10),
1564 else => null,1549 else => unreachable,
1565 },1550 },
1566 .rvmi => return switch (tag) {1551 .rvmi => return switch (tag) {
1567 .vcmpsd => OpCode.oneByte(0xc2),1552 .vcmpsd, .vcmpss => OpCode.oneByte(0xc2),
1568 else => null,1553 else => unreachable,
1569 },1554 },
1570 }1555 }
1571}1556}
15721557
1573inline fn getModRmExt(tag: Tag) ?u3 {1558inline fn getModRmExt(tag: Tag) u3 {
1574 return switch (tag) {1559 return switch (tag) {
1575 .adc => 0x2,1560 .adc => 0x2,
1576 .add => 0x0,1561 .add => 0x0,
...@@ -1631,11 +1616,11 @@ inline fn getModRmExt(tag: Tag) ?u3 {...@@ -1631,11 +1616,11 @@ inline fn getModRmExt(tag: Tag) ?u3 {
1631 .fisttp64 => 0x1,1616 .fisttp64 => 0x1,
1632 .fld32 => 0x0,1617 .fld32 => 0x0,
1633 .fld64 => 0x0,1618 .fld64 => 0x0,
1634 else => null,1619 else => unreachable,
1635 };1620 };
1636}1621}
16371622
1638const VexPrefix = struct {1623const VexEncoding = struct {
1639 prefix: Encoder.Vex,1624 prefix: Encoder.Vex,
1640 reg: ?enum {1625 reg: ?enum {
1641 ndd,1626 ndd,
...@@ -1644,7 +1629,7 @@ const VexPrefix = struct {...@@ -1644,7 +1629,7 @@ const VexPrefix = struct {
1644 },1629 },
1645};1630};
16461631
1647inline fn getVexPrefix(tag: Tag, enc: Encoding) ?VexPrefix {1632inline fn getVexEncoding(tag: Tag, enc: Encoding) VexEncoding {
1648 const desc: struct {1633 const desc: struct {
1649 reg: enum {1634 reg: enum {
1650 none,1635 none,
...@@ -1671,21 +1656,27 @@ inline fn getVexPrefix(tag: Tag, enc: Encoding) ?VexPrefix {...@@ -1671,21 +1656,27 @@ inline fn getVexPrefix(tag: Tag, enc: Encoding) ?VexPrefix {
1671 switch (enc) {1656 switch (enc) {
1672 .mv => switch (tag) {1657 .mv => switch (tag) {
1673 .vmovsd => break :blk .{ .lig = true, .simd_prefix = .p_f2, .wig = true },1658 .vmovsd => break :blk .{ .lig = true, .simd_prefix = .p_f2, .wig = true },
1674 else => return null,1659 .vmovss => break :blk .{ .lig = true, .simd_prefix = .p_f3, .wig = true },
1660 else => unreachable,
1675 },1661 },
1676 .vm => switch (tag) {1662 .vm => switch (tag) {
1677 .vmovsd => break :blk .{ .lig = true, .simd_prefix = .p_f2, .wig = true },1663 .vmovsd => break :blk .{ .lig = true, .simd_prefix = .p_f2, .wig = true },
1664 .vmovss => break :blk .{ .lig = true, .simd_prefix = .p_f3, .wig = true },
1678 .vucomisd => break :blk .{ .lig = true, .simd_prefix = .p_66, .wig = true },1665 .vucomisd => break :blk .{ .lig = true, .simd_prefix = .p_66, .wig = true },
1679 else => return null,1666 .vucomiss => break :blk .{ .lig = true, .wig = true },
1667 else => unreachable,
1680 },1668 },
1681 .rvm => switch (tag) {1669 .rvm => switch (tag) {
1682 .vaddsd => break :blk .{ .reg = .nds, .lig = true, .simd_prefix = .p_f2, .wig = true },1670 .vaddsd => break :blk .{ .reg = .nds, .lig = true, .simd_prefix = .p_f2, .wig = true },
1671 .vaddss => break :blk .{ .reg = .nds, .lig = true, .simd_prefix = .p_f3, .wig = true },
1683 .vmovsd => break :blk .{ .reg = .nds, .lig = true, .simd_prefix = .p_f2, .wig = true },1672 .vmovsd => break :blk .{ .reg = .nds, .lig = true, .simd_prefix = .p_f2, .wig = true },
1684 else => return null,1673 .vmovss => break :blk .{ .reg = .nds, .lig = true, .simd_prefix = .p_f3, .wig = true },
1674 else => unreachable,
1685 },1675 },
1686 .rvmi => switch (tag) {1676 .rvmi => switch (tag) {
1687 .vcmpsd => break :blk .{ .reg = .nds, .lig = true, .simd_prefix = .p_f2, .wig = true },1677 .vcmpsd => break :blk .{ .reg = .nds, .lig = true, .simd_prefix = .p_f2, .wig = true },
1688 else => return null,1678 .vcmpss => break :blk .{ .reg = .nds, .lig = true, .simd_prefix = .p_f3, .wig = true },
1679 else => unreachable,
1689 },1680 },
1690 else => unreachable,1681 else => unreachable,
1691 }1682 }
...@@ -1711,7 +1702,7 @@ inline fn getVexPrefix(tag: Tag, enc: Encoding) ?VexPrefix {...@@ -1711,7 +1702,7 @@ inline fn getVexPrefix(tag: Tag, enc: Encoding) ?VexPrefix {
1711 .p_f3 => vex.simd_prefix_f3(),1702 .p_f3 => vex.simd_prefix_f3(),
1712 }1703 }
17131704
1714 return VexPrefix{ .prefix = vex, .reg = switch (desc.reg) {1705 return VexEncoding{ .prefix = vex, .reg = switch (desc.reg) {
1715 .none => null,1706 .none => null,
1716 .nds => .nds,1707 .nds => .nds,
1717 .dds => .dds,1708 .dds => .dds,
...@@ -1862,7 +1853,7 @@ const RegisterOrMemory = union(enum) {...@@ -1862,7 +1853,7 @@ const RegisterOrMemory = union(enum) {
18621853
1863fn lowerToZoEnc(tag: Tag, code: *std.ArrayList(u8)) InnerError!void {1854fn lowerToZoEnc(tag: Tag, code: *std.ArrayList(u8)) InnerError!void {
1864 assert(!tag.isAvx());1855 assert(!tag.isAvx());
1865 const opc = getOpCode(tag, .zo, false).?;1856 const opc = getOpCode(tag, .zo, false);
1866 const encoder = try Encoder.init(code, 2);1857 const encoder = try Encoder.init(code, 2);
1867 switch (tag) {1858 switch (tag) {
1868 .cqo => {1859 .cqo => {
...@@ -1879,12 +1870,12 @@ fn lowerToIEnc(tag: Tag, imm: u32, code: *std.ArrayList(u8)) InnerError!void {...@@ -1879,12 +1870,12 @@ fn lowerToIEnc(tag: Tag, imm: u32, code: *std.ArrayList(u8)) InnerError!void {
1879 assert(!tag.isAvx());1870 assert(!tag.isAvx());
1880 if (tag == .ret_far or tag == .ret_near) {1871 if (tag == .ret_far or tag == .ret_near) {
1881 const encoder = try Encoder.init(code, 3);1872 const encoder = try Encoder.init(code, 3);
1882 const opc = getOpCode(tag, .i, false).?;1873 const opc = getOpCode(tag, .i, false);
1883 opc.encode(encoder);1874 opc.encode(encoder);
1884 encoder.imm16(@bitCast(i16, @truncate(u16, imm)));1875 encoder.imm16(@bitCast(i16, @truncate(u16, imm)));
1885 return;1876 return;
1886 }1877 }
1887 const opc = getOpCode(tag, .i, immOpSize(imm) == 8).?;1878 const opc = getOpCode(tag, .i, immOpSize(imm) == 8);
1888 const encoder = try Encoder.init(code, 5);1879 const encoder = try Encoder.init(code, 5);
1889 if (immOpSize(imm) == 16) {1880 if (immOpSize(imm) == 16) {
1890 encoder.prefix16BitMode();1881 encoder.prefix16BitMode();
...@@ -1895,7 +1886,7 @@ fn lowerToIEnc(tag: Tag, imm: u32, code: *std.ArrayList(u8)) InnerError!void {...@@ -1895,7 +1886,7 @@ fn lowerToIEnc(tag: Tag, imm: u32, code: *std.ArrayList(u8)) InnerError!void {
18951886
1896fn lowerToOEnc(tag: Tag, reg: Register, code: *std.ArrayList(u8)) InnerError!void {1887fn lowerToOEnc(tag: Tag, reg: Register, code: *std.ArrayList(u8)) InnerError!void {
1897 assert(!tag.isAvx());1888 assert(!tag.isAvx());
1898 const opc = getOpCode(tag, .o, false).?;1889 const opc = getOpCode(tag, .o, false);
1899 const encoder = try Encoder.init(code, 3);1890 const encoder = try Encoder.init(code, 3);
1900 if (reg.size() == 16) {1891 if (reg.size() == 16) {
1901 encoder.prefix16BitMode();1892 encoder.prefix16BitMode();
...@@ -1909,7 +1900,7 @@ fn lowerToOEnc(tag: Tag, reg: Register, code: *std.ArrayList(u8)) InnerError!voi...@@ -1909,7 +1900,7 @@ fn lowerToOEnc(tag: Tag, reg: Register, code: *std.ArrayList(u8)) InnerError!voi
19091900
1910fn lowerToDEnc(tag: Tag, imm: u32, code: *std.ArrayList(u8)) InnerError!void {1901fn lowerToDEnc(tag: Tag, imm: u32, code: *std.ArrayList(u8)) InnerError!void {
1911 assert(!tag.isAvx());1902 assert(!tag.isAvx());
1912 const opc = getOpCode(tag, .d, false).?;1903 const opc = getOpCode(tag, .d, false);
1913 const encoder = try Encoder.init(code, 6);1904 const encoder = try Encoder.init(code, 6);
1914 opc.encode(encoder);1905 opc.encode(encoder);
1915 encoder.imm32(@bitCast(i32, imm));1906 encoder.imm32(@bitCast(i32, imm));
...@@ -1917,8 +1908,8 @@ fn lowerToDEnc(tag: Tag, imm: u32, code: *std.ArrayList(u8)) InnerError!void {...@@ -1917,8 +1908,8 @@ fn lowerToDEnc(tag: Tag, imm: u32, code: *std.ArrayList(u8)) InnerError!void {
19171908
1918fn lowerToMxEnc(tag: Tag, reg_or_mem: RegisterOrMemory, enc: Encoding, code: *std.ArrayList(u8)) InnerError!void {1909fn lowerToMxEnc(tag: Tag, reg_or_mem: RegisterOrMemory, enc: Encoding, code: *std.ArrayList(u8)) InnerError!void {
1919 assert(!tag.isAvx());1910 assert(!tag.isAvx());
1920 const opc = getOpCode(tag, enc, reg_or_mem.size() == 8).?;1911 const opc = getOpCode(tag, enc, reg_or_mem.size() == 8);
1921 const modrm_ext = getModRmExt(tag).?;1912 const modrm_ext = getModRmExt(tag);
1922 switch (reg_or_mem) {1913 switch (reg_or_mem) {
1923 .register => |reg| {1914 .register => |reg| {
1924 const encoder = try Encoder.init(code, 4);1915 const encoder = try Encoder.init(code, 4);
...@@ -1973,10 +1964,7 @@ fn lowerToFdEnc(tag: Tag, reg: Register, moffs: u64, code: *std.ArrayList(u8)) I...@@ -1973,10 +1964,7 @@ fn lowerToFdEnc(tag: Tag, reg: Register, moffs: u64, code: *std.ArrayList(u8)) I
19731964
1974fn lowerToTdFdEnc(tag: Tag, reg: Register, moffs: u64, code: *std.ArrayList(u8), td: bool) InnerError!void {1965fn lowerToTdFdEnc(tag: Tag, reg: Register, moffs: u64, code: *std.ArrayList(u8), td: bool) InnerError!void {
1975 assert(!tag.isAvx());1966 assert(!tag.isAvx());
1976 const opc = if (td)1967 const opc = if (td) getOpCode(tag, .td, reg.size() == 8) else getOpCode(tag, .fd, reg.size() == 8);
1977 getOpCode(tag, .td, reg.size() == 8).?
1978 else
1979 getOpCode(tag, .fd, reg.size() == 8).?;
1980 const encoder = try Encoder.init(code, 10);1968 const encoder = try Encoder.init(code, 10);
1981 if (reg.size() == 16) {1969 if (reg.size() == 16) {
1982 encoder.prefix16BitMode();1970 encoder.prefix16BitMode();
...@@ -1996,7 +1984,7 @@ fn lowerToTdFdEnc(tag: Tag, reg: Register, moffs: u64, code: *std.ArrayList(u8),...@@ -1996,7 +1984,7 @@ fn lowerToTdFdEnc(tag: Tag, reg: Register, moffs: u64, code: *std.ArrayList(u8),
19961984
1997fn lowerToOiEnc(tag: Tag, reg: Register, imm: u64, code: *std.ArrayList(u8)) InnerError!void {1985fn lowerToOiEnc(tag: Tag, reg: Register, imm: u64, code: *std.ArrayList(u8)) InnerError!void {
1998 assert(!tag.isAvx());1986 assert(!tag.isAvx());
1999 const opc = getOpCode(tag, .oi, reg.size() == 8).?;1987 const opc = getOpCode(tag, .oi, reg.size() == 8);
2000 const encoder = try Encoder.init(code, 10);1988 const encoder = try Encoder.init(code, 10);
2001 if (reg.size() == 16) {1989 if (reg.size() == 16) {
2002 encoder.prefix16BitMode();1990 encoder.prefix16BitMode();
...@@ -2023,8 +2011,8 @@ fn lowerToMiXEnc(...@@ -2023,8 +2011,8 @@ fn lowerToMiXEnc(
2023 code: *std.ArrayList(u8),2011 code: *std.ArrayList(u8),
2024) InnerError!void {2012) InnerError!void {
2025 assert(!tag.isAvx());2013 assert(!tag.isAvx());
2026 const modrm_ext = getModRmExt(tag).?;2014 const modrm_ext = getModRmExt(tag);
2027 const opc = getOpCode(tag, enc, reg_or_mem.size() == 8).?;2015 const opc = getOpCode(tag, enc, reg_or_mem.size() == 8);
2028 switch (reg_or_mem) {2016 switch (reg_or_mem) {
2029 .register => |dst_reg| {2017 .register => |dst_reg| {
2030 const encoder = try Encoder.init(code, 7);2018 const encoder = try Encoder.init(code, 7);
...@@ -2079,7 +2067,7 @@ fn lowerToRmEnc(...@@ -2079,7 +2067,7 @@ fn lowerToRmEnc(
2079 code: *std.ArrayList(u8),2067 code: *std.ArrayList(u8),
2080) InnerError!void {2068) InnerError!void {
2081 assert(!tag.isAvx());2069 assert(!tag.isAvx());
2082 const opc = getOpCode(tag, .rm, reg.size() == 8 or reg_or_mem.size() == 8).?;2070 const opc = getOpCode(tag, .rm, reg.size() == 8 or reg_or_mem.size() == 8);
2083 switch (reg_or_mem) {2071 switch (reg_or_mem) {
2084 .register => |src_reg| {2072 .register => |src_reg| {
2085 const encoder = try Encoder.init(code, 5);2073 const encoder = try Encoder.init(code, 5);
...@@ -2126,7 +2114,7 @@ fn lowerToMrEnc(...@@ -2126,7 +2114,7 @@ fn lowerToMrEnc(
2126 code: *std.ArrayList(u8),2114 code: *std.ArrayList(u8),
2127) InnerError!void {2115) InnerError!void {
2128 assert(!tag.isAvx());2116 assert(!tag.isAvx());
2129 const opc = getOpCode(tag, .mr, reg.size() == 8 or reg_or_mem.size() == 8).?;2117 const opc = getOpCode(tag, .mr, reg.size() == 8 or reg_or_mem.size() == 8);
2130 switch (reg_or_mem) {2118 switch (reg_or_mem) {
2131 .register => |dst_reg| {2119 .register => |dst_reg| {
2132 const encoder = try Encoder.init(code, 4);2120 const encoder = try Encoder.init(code, 4);
...@@ -2172,7 +2160,7 @@ fn lowerToRmiEnc(...@@ -2172,7 +2160,7 @@ fn lowerToRmiEnc(
2172 code: *std.ArrayList(u8),2160 code: *std.ArrayList(u8),
2173) InnerError!void {2161) InnerError!void {
2174 assert(!tag.isAvx());2162 assert(!tag.isAvx());
2175 const opc = getOpCode(tag, .rmi, false).?;2163 const opc = getOpCode(tag, .rmi, false);
2176 const encoder = try Encoder.init(code, 13);2164 const encoder = try Encoder.init(code, 13);
2177 if (reg.size() == 16) {2165 if (reg.size() == 16) {
2178 encoder.prefix16BitMode();2166 encoder.prefix16BitMode();
...@@ -2216,9 +2204,9 @@ fn lowerToVmEnc(...@@ -2216,9 +2204,9 @@ fn lowerToVmEnc(
2216 reg_or_mem: RegisterOrMemory,2204 reg_or_mem: RegisterOrMemory,
2217 code: *std.ArrayList(u8),2205 code: *std.ArrayList(u8),
2218) InnerError!void {2206) InnerError!void {
2219 const opc = getOpCode(tag, .vm, false).?;2207 const opc = getOpCode(tag, .vm, false);
2220 var vex_prefix = getVexPrefix(tag, .vm).?;2208 var enc = getVexEncoding(tag, .vm);
2221 const vex = &vex_prefix.prefix;2209 const vex = &enc.prefix;
2222 switch (reg_or_mem) {2210 switch (reg_or_mem) {
2223 .register => |src_reg| {2211 .register => |src_reg| {
2224 const encoder = try Encoder.init(code, 5);2212 const encoder = try Encoder.init(code, 5);
...@@ -2226,12 +2214,11 @@ fn lowerToVmEnc(...@@ -2226,12 +2214,11 @@ fn lowerToVmEnc(
2226 .r = reg.isExtended(),2214 .r = reg.isExtended(),
2227 .b = src_reg.isExtended(),2215 .b = src_reg.isExtended(),
2228 });2216 });
2229 encoder.vex(vex_prefix.prefix);2217 encoder.vex(enc.prefix);
2230 opc.encode(encoder);2218 opc.encode(encoder);
2231 encoder.modRm_direct(reg.lowEnc(), src_reg.lowEnc());2219 encoder.modRm_direct(reg.lowEnc(), src_reg.lowEnc());
2232 },2220 },
2233 .memory => |src_mem| {2221 .memory => |src_mem| {
2234 assert(src_mem.ptr_size == .qword_ptr);
2235 const encoder = try Encoder.init(code, 10);2222 const encoder = try Encoder.init(code, 10);
2236 if (src_mem.base) |base| {2223 if (src_mem.base) |base| {
2237 vex.rex(.{2224 vex.rex(.{
...@@ -2243,7 +2230,7 @@ fn lowerToVmEnc(...@@ -2243,7 +2230,7 @@ fn lowerToVmEnc(
2243 .r = reg.isExtended(),2230 .r = reg.isExtended(),
2244 });2231 });
2245 }2232 }
2246 encoder.vex(vex_prefix.prefix);2233 encoder.vex(enc.prefix);
2247 opc.encode(encoder);2234 opc.encode(encoder);
2248 src_mem.encode(encoder, reg.lowEnc());2235 src_mem.encode(encoder, reg.lowEnc());
2249 },2236 },
...@@ -2257,9 +2244,9 @@ fn lowerToMvEnc(...@@ -2257,9 +2244,9 @@ fn lowerToMvEnc(
2257 reg: Register,2244 reg: Register,
2258 code: *std.ArrayList(u8),2245 code: *std.ArrayList(u8),
2259) InnerError!void {2246) InnerError!void {
2260 const opc = getOpCode(tag, .mv, false).?;2247 const opc = getOpCode(tag, .mv, false);
2261 var vex_prefix = getVexPrefix(tag, .mv).?;2248 var enc = getVexEncoding(tag, .mv);
2262 const vex = &vex_prefix.prefix;2249 const vex = &enc.prefix;
2263 switch (reg_or_mem) {2250 switch (reg_or_mem) {
2264 .register => |dst_reg| {2251 .register => |dst_reg| {
2265 const encoder = try Encoder.init(code, 4);2252 const encoder = try Encoder.init(code, 4);
...@@ -2267,12 +2254,11 @@ fn lowerToMvEnc(...@@ -2267,12 +2254,11 @@ fn lowerToMvEnc(
2267 .r = reg.isExtended(),2254 .r = reg.isExtended(),
2268 .b = dst_reg.isExtended(),2255 .b = dst_reg.isExtended(),
2269 });2256 });
2270 encoder.vex(vex_prefix.prefix);2257 encoder.vex(enc.prefix);
2271 opc.encode(encoder);2258 opc.encode(encoder);
2272 encoder.modRm_direct(reg.lowEnc(), dst_reg.lowEnc());2259 encoder.modRm_direct(reg.lowEnc(), dst_reg.lowEnc());
2273 },2260 },
2274 .memory => |dst_mem| {2261 .memory => |dst_mem| {
2275 assert(dst_mem.ptr_size == .qword_ptr);
2276 const encoder = try Encoder.init(code, 10);2262 const encoder = try Encoder.init(code, 10);
2277 if (dst_mem.base) |base| {2263 if (dst_mem.base) |base| {
2278 vex.rex(.{2264 vex.rex(.{
...@@ -2284,7 +2270,7 @@ fn lowerToMvEnc(...@@ -2284,7 +2270,7 @@ fn lowerToMvEnc(
2284 .r = reg.isExtended(),2270 .r = reg.isExtended(),
2285 });2271 });
2286 }2272 }
2287 encoder.vex(vex_prefix.prefix);2273 encoder.vex(enc.prefix);
2288 opc.encode(encoder);2274 opc.encode(encoder);
2289 dst_mem.encode(encoder, reg.lowEnc());2275 dst_mem.encode(encoder, reg.lowEnc());
2290 },2276 },
...@@ -2298,12 +2284,12 @@ fn lowerToRvmEnc(...@@ -2298,12 +2284,12 @@ fn lowerToRvmEnc(
2298 reg_or_mem: RegisterOrMemory,2284 reg_or_mem: RegisterOrMemory,
2299 code: *std.ArrayList(u8),2285 code: *std.ArrayList(u8),
2300) InnerError!void {2286) InnerError!void {
2301 const opc = getOpCode(tag, .rvm, false).?;2287 const opc = getOpCode(tag, .rvm, false);
2302 var vex_prefix = getVexPrefix(tag, .rvm).?;2288 var enc = getVexEncoding(tag, .rvm);
2303 const vex = &vex_prefix.prefix;2289 const vex = &enc.prefix;
2304 switch (reg_or_mem) {2290 switch (reg_or_mem) {
2305 .register => |reg3| {2291 .register => |reg3| {
2306 if (vex_prefix.reg) |vvvv| {2292 if (enc.reg) |vvvv| {
2307 switch (vvvv) {2293 switch (vvvv) {
2308 .nds => vex.reg(reg2.enc()),2294 .nds => vex.reg(reg2.enc()),
2309 else => unreachable, // TODO2295 else => unreachable, // TODO
...@@ -2314,7 +2300,7 @@ fn lowerToRvmEnc(...@@ -2314,7 +2300,7 @@ fn lowerToRvmEnc(
2314 .r = reg1.isExtended(),2300 .r = reg1.isExtended(),
2315 .b = reg3.isExtended(),2301 .b = reg3.isExtended(),
2316 });2302 });
2317 encoder.vex(vex_prefix.prefix);2303 encoder.vex(enc.prefix);
2318 opc.encode(encoder);2304 opc.encode(encoder);
2319 encoder.modRm_direct(reg1.lowEnc(), reg3.lowEnc());2305 encoder.modRm_direct(reg1.lowEnc(), reg3.lowEnc());
2320 },2306 },
...@@ -2333,13 +2319,13 @@ fn lowerToRvmiEnc(...@@ -2333,13 +2319,13 @@ fn lowerToRvmiEnc(
2333 imm: u32,2319 imm: u32,
2334 code: *std.ArrayList(u8),2320 code: *std.ArrayList(u8),
2335) InnerError!void {2321) InnerError!void {
2336 const opc = getOpCode(tag, .rvmi, false).?;2322 const opc = getOpCode(tag, .rvmi, false);
2337 var vex_prefix = getVexPrefix(tag, .rvmi).?;2323 var enc = getVexEncoding(tag, .rvmi);
2338 const vex = &vex_prefix.prefix;2324 const vex = &enc.prefix;
2339 const encoder: Encoder = blk: {2325 const encoder: Encoder = blk: {
2340 switch (reg_or_mem) {2326 switch (reg_or_mem) {
2341 .register => |reg3| {2327 .register => |reg3| {
2342 if (vex_prefix.reg) |vvvv| {2328 if (enc.reg) |vvvv| {
2343 switch (vvvv) {2329 switch (vvvv) {
2344 .nds => vex.reg(reg2.enc()),2330 .nds => vex.reg(reg2.enc()),
2345 else => unreachable, // TODO2331 else => unreachable, // TODO
...@@ -2350,7 +2336,7 @@ fn lowerToRvmiEnc(...@@ -2350,7 +2336,7 @@ fn lowerToRvmiEnc(
2350 .r = reg1.isExtended(),2336 .r = reg1.isExtended(),
2351 .b = reg3.isExtended(),2337 .b = reg3.isExtended(),
2352 });2338 });
2353 encoder.vex(vex_prefix.prefix);2339 encoder.vex(enc.prefix);
2354 opc.encode(encoder);2340 opc.encode(encoder);
2355 encoder.modRm_direct(reg1.lowEnc(), reg3.lowEnc());2341 encoder.modRm_direct(reg1.lowEnc(), reg3.lowEnc());
2356 break :blk encoder;2342 break :blk encoder;
src/arch/x86_64/Mir.zig+3
...@@ -351,14 +351,17 @@ pub const Inst = struct {...@@ -351,14 +351,17 @@ pub const Inst = struct {
351 /// 0b01 qword ptr [reg1 + imm32], reg2351 /// 0b01 qword ptr [reg1 + imm32], reg2
352 /// 0b10 reg1, reg2352 /// 0b10 reg1, reg2
353 mov_f64,353 mov_f64,
354 mov_f32,
354355
355 /// ops flags: form:356 /// ops flags: form:
356 /// 0b00 reg1, reg1, reg2357 /// 0b00 reg1, reg1, reg2
357 add_f64,358 add_f64,
359 add_f32,
358360
359 /// ops flags: form:361 /// ops flags: form:
360 ///362 ///
361 cmp_f64,363 cmp_f64,
364 cmp_f32,
362365
363 /// Pseudo-instructions366 /// Pseudo-instructions
364 /// call extern function367 /// call extern function
test/behavior.zig+156-156
...@@ -1,163 +1,163 @@...@@ -1,163 +1,163 @@
1const builtin = @import("builtin");1const builtin = @import("builtin");
22
3test {3test {
4 _ = @import("behavior/align.zig");4 // _ = @import("behavior/align.zig");
5 _ = @import("behavior/alignof.zig");5 // _ = @import("behavior/alignof.zig");
6 _ = @import("behavior/array.zig");6 // _ = @import("behavior/array.zig");
7 _ = @import("behavior/async_fn.zig");7 // _ = @import("behavior/async_fn.zig");
8 _ = @import("behavior/atomics.zig");8 // _ = @import("behavior/atomics.zig");
9 _ = @import("behavior/await_struct.zig");9 // _ = @import("behavior/await_struct.zig");
10 _ = @import("behavior/basic.zig");10 _ = @import("behavior/basic.zig");
11 _ = @import("behavior/bit_shifting.zig");11 // _ = @import("behavior/bit_shifting.zig");
12 _ = @import("behavior/bitcast.zig");12 // _ = @import("behavior/bitcast.zig");
13 _ = @import("behavior/bitreverse.zig");13 // _ = @import("behavior/bitreverse.zig");
14 _ = @import("behavior/bool.zig");14 // _ = @import("behavior/bool.zig");
15 _ = @import("behavior/bugs/394.zig");15 // _ = @import("behavior/bugs/394.zig");
16 _ = @import("behavior/bugs/421.zig");16 // _ = @import("behavior/bugs/421.zig");
17 _ = @import("behavior/bugs/529.zig");17 // _ = @import("behavior/bugs/529.zig");
18 _ = @import("behavior/bugs/624.zig");18 // _ = @import("behavior/bugs/624.zig");
19 _ = @import("behavior/bugs/655.zig");19 // _ = @import("behavior/bugs/655.zig");
20 _ = @import("behavior/bugs/656.zig");20 // _ = @import("behavior/bugs/656.zig");
21 _ = @import("behavior/bugs/679.zig");21 // _ = @import("behavior/bugs/679.zig");
22 _ = @import("behavior/bugs/704.zig");22 // _ = @import("behavior/bugs/704.zig");
23 _ = @import("behavior/bugs/718.zig");23 // _ = @import("behavior/bugs/718.zig");
24 _ = @import("behavior/bugs/726.zig");24 // _ = @import("behavior/bugs/726.zig");
25 _ = @import("behavior/bugs/828.zig");25 // _ = @import("behavior/bugs/828.zig");
26 _ = @import("behavior/bugs/920.zig");26 // _ = @import("behavior/bugs/920.zig");
27 _ = @import("behavior/bugs/1025.zig");27 // _ = @import("behavior/bugs/1025.zig");
28 _ = @import("behavior/bugs/1076.zig");28 // _ = @import("behavior/bugs/1076.zig");
29 _ = @import("behavior/bugs/1111.zig");29 // _ = @import("behavior/bugs/1111.zig");
30 _ = @import("behavior/bugs/1120.zig");30 // _ = @import("behavior/bugs/1120.zig");
31 _ = @import("behavior/bugs/1277.zig");31 // _ = @import("behavior/bugs/1277.zig");
32 _ = @import("behavior/bugs/1310.zig");32 // _ = @import("behavior/bugs/1310.zig");
33 _ = @import("behavior/bugs/1381.zig");33 // _ = @import("behavior/bugs/1381.zig");
34 _ = @import("behavior/bugs/1421.zig");34 // _ = @import("behavior/bugs/1421.zig");
35 _ = @import("behavior/bugs/1442.zig");35 // _ = @import("behavior/bugs/1442.zig");
36 _ = @import("behavior/bugs/1486.zig");36 // _ = @import("behavior/bugs/1486.zig");
37 _ = @import("behavior/bugs/1500.zig");37 // _ = @import("behavior/bugs/1500.zig");
38 _ = @import("behavior/bugs/1607.zig");38 // _ = @import("behavior/bugs/1607.zig");
39 _ = @import("behavior/bugs/1735.zig");39 // _ = @import("behavior/bugs/1735.zig");
40 _ = @import("behavior/bugs/1741.zig");40 // _ = @import("behavior/bugs/1741.zig");
41 _ = @import("behavior/bugs/1851.zig");41 // _ = @import("behavior/bugs/1851.zig");
42 _ = @import("behavior/bugs/1914.zig");42 // _ = @import("behavior/bugs/1914.zig");
43 _ = @import("behavior/bugs/2006.zig");43 // _ = @import("behavior/bugs/2006.zig");
44 _ = @import("behavior/bugs/2114.zig");44 // _ = @import("behavior/bugs/2114.zig");
45 _ = @import("behavior/bugs/2346.zig");45 // _ = @import("behavior/bugs/2346.zig");
46 _ = @import("behavior/bugs/2578.zig");46 // _ = @import("behavior/bugs/2578.zig");
47 _ = @import("behavior/bugs/2692.zig");47 // _ = @import("behavior/bugs/2692.zig");
48 _ = @import("behavior/bugs/2889.zig");48 // _ = @import("behavior/bugs/2889.zig");
49 _ = @import("behavior/bugs/3007.zig");49 // _ = @import("behavior/bugs/3007.zig");
50 _ = @import("behavior/bugs/3046.zig");50 // _ = @import("behavior/bugs/3046.zig");
51 _ = @import("behavior/bugs/3112.zig");51 // _ = @import("behavior/bugs/3112.zig");
52 _ = @import("behavior/bugs/3367.zig");52 // _ = @import("behavior/bugs/3367.zig");
53 _ = @import("behavior/bugs/3384.zig");53 // _ = @import("behavior/bugs/3384.zig");
54 _ = @import("behavior/bugs/3586.zig");54 // _ = @import("behavior/bugs/3586.zig");
55 _ = @import("behavior/bugs/3742.zig");55 // _ = @import("behavior/bugs/3742.zig");
56 _ = @import("behavior/bugs/3779.zig");56 // _ = @import("behavior/bugs/3779.zig");
57 _ = @import("behavior/bugs/4328.zig");57 // _ = @import("behavior/bugs/4328.zig");
58 _ = @import("behavior/bugs/4560.zig");58 // _ = @import("behavior/bugs/4560.zig");
59 _ = @import("behavior/bugs/4769_a.zig");59 // _ = @import("behavior/bugs/4769_a.zig");
60 _ = @import("behavior/bugs/4769_b.zig");60 // _ = @import("behavior/bugs/4769_b.zig");
61 _ = @import("behavior/bugs/4954.zig");61 // _ = @import("behavior/bugs/4954.zig");
62 _ = @import("behavior/bugs/5398.zig");62 // _ = @import("behavior/bugs/5398.zig");
63 _ = @import("behavior/bugs/5413.zig");63 // _ = @import("behavior/bugs/5413.zig");
64 _ = @import("behavior/bugs/5474.zig");64 // _ = @import("behavior/bugs/5474.zig");
65 _ = @import("behavior/bugs/5487.zig");65 // _ = @import("behavior/bugs/5487.zig");
66 _ = @import("behavior/bugs/6456.zig");66 // _ = @import("behavior/bugs/6456.zig");
67 _ = @import("behavior/bugs/6781.zig");67 // _ = @import("behavior/bugs/6781.zig");
68 _ = @import("behavior/bugs/6850.zig");68 // _ = @import("behavior/bugs/6850.zig");
69 _ = @import("behavior/bugs/7003.zig");69 // _ = @import("behavior/bugs/7003.zig");
70 _ = @import("behavior/bugs/7027.zig");70 // _ = @import("behavior/bugs/7027.zig");
71 _ = @import("behavior/bugs/7047.zig");71 // _ = @import("behavior/bugs/7047.zig");
72 _ = @import("behavior/bugs/7187.zig");72 // _ = @import("behavior/bugs/7187.zig");
73 _ = @import("behavior/bugs/7250.zig");73 // _ = @import("behavior/bugs/7250.zig");
74 _ = @import("behavior/bugs/9584.zig");74 // _ = @import("behavior/bugs/9584.zig");
75 _ = @import("behavior/bugs/10138.zig");75 // _ = @import("behavior/bugs/10138.zig");
76 _ = @import("behavior/bugs/10147.zig");76 // _ = @import("behavior/bugs/10147.zig");
77 _ = @import("behavior/bugs/10970.zig");77 // _ = @import("behavior/bugs/10970.zig");
78 _ = @import("behavior/bugs/11046.zig");78 // _ = @import("behavior/bugs/11046.zig");
79 _ = @import("behavior/bugs/11100.zig");79 // _ = @import("behavior/bugs/11100.zig");
80 _ = @import("behavior/bugs/11139.zig");80 // _ = @import("behavior/bugs/11139.zig");
81 _ = @import("behavior/bugs/11159.zig");81 // _ = @import("behavior/bugs/11159.zig");
82 _ = @import("behavior/bugs/11162.zig");82 // _ = @import("behavior/bugs/11162.zig");
83 _ = @import("behavior/bugs/11165.zig");83 // _ = @import("behavior/bugs/11165.zig");
84 _ = @import("behavior/bugs/11181.zig");84 // _ = @import("behavior/bugs/11181.zig");
85 _ = @import("behavior/bugs/11182.zig");85 // _ = @import("behavior/bugs/11182.zig");
86 _ = @import("behavior/bugs/11213.zig");86 // _ = @import("behavior/bugs/11213.zig");
87 _ = @import("behavior/byteswap.zig");87 // _ = @import("behavior/byteswap.zig");
88 _ = @import("behavior/byval_arg_var.zig");88 // _ = @import("behavior/byval_arg_var.zig");
89 _ = @import("behavior/call.zig");89 // _ = @import("behavior/call.zig");
90 _ = @import("behavior/cast.zig");90 // _ = @import("behavior/cast.zig");
91 _ = @import("behavior/cast_int.zig");91 // _ = @import("behavior/cast_int.zig");
92 _ = @import("behavior/comptime_memory.zig");92 // _ = @import("behavior/comptime_memory.zig");
93 _ = @import("behavior/const_slice_child.zig");93 // _ = @import("behavior/const_slice_child.zig");
94 _ = @import("behavior/defer.zig");94 // _ = @import("behavior/defer.zig");
95 _ = @import("behavior/enum.zig");95 // _ = @import("behavior/enum.zig");
96 _ = @import("behavior/error.zig");96 // _ = @import("behavior/error.zig");
97 _ = @import("behavior/eval.zig");97 // _ = @import("behavior/eval.zig");
98 _ = @import("behavior/field_parent_ptr.zig");98 // _ = @import("behavior/field_parent_ptr.zig");
99 _ = @import("behavior/floatop.zig");99 // _ = @import("behavior/floatop.zig");
100 _ = @import("behavior/fn.zig");100 // _ = @import("behavior/fn.zig");
101 _ = @import("behavior/fn_delegation.zig");101 // _ = @import("behavior/fn_delegation.zig");
102 _ = @import("behavior/fn_in_struct_in_comptime.zig");102 // _ = @import("behavior/fn_in_struct_in_comptime.zig");
103 _ = @import("behavior/for.zig");103 // _ = @import("behavior/for.zig");
104 _ = @import("behavior/generics.zig");104 // _ = @import("behavior/generics.zig");
105 _ = @import("behavior/hasdecl.zig");105 // _ = @import("behavior/hasdecl.zig");
106 _ = @import("behavior/hasfield.zig");106 // _ = @import("behavior/hasfield.zig");
107 _ = @import("behavior/if.zig");107 // _ = @import("behavior/if.zig");
108 _ = @import("behavior/import.zig");108 // _ = @import("behavior/import.zig");
109 _ = @import("behavior/incomplete_struct_param_tld.zig");109 // _ = @import("behavior/incomplete_struct_param_tld.zig");
110 _ = @import("behavior/int128.zig");110 // _ = @import("behavior/int128.zig");
111 _ = @import("behavior/int_div.zig");111 // _ = @import("behavior/int_div.zig");
112 _ = @import("behavior/inttoptr.zig");112 // _ = @import("behavior/inttoptr.zig");
113 _ = @import("behavior/ir_block_deps.zig");113 // _ = @import("behavior/ir_block_deps.zig");
114 _ = @import("behavior/math.zig");114 // _ = @import("behavior/math.zig");
115 _ = @import("behavior/maximum_minimum.zig");115 // _ = @import("behavior/maximum_minimum.zig");
116 _ = @import("behavior/member_func.zig");116 // _ = @import("behavior/member_func.zig");
117 _ = @import("behavior/merge_error_sets.zig");117 // _ = @import("behavior/merge_error_sets.zig");
118 _ = @import("behavior/muladd.zig");118 // _ = @import("behavior/muladd.zig");
119 _ = @import("behavior/namespace_depends_on_compile_var.zig");119 // _ = @import("behavior/namespace_depends_on_compile_var.zig");
120 _ = @import("behavior/null.zig");120 // _ = @import("behavior/null.zig");
121 _ = @import("behavior/optional.zig");121 // _ = @import("behavior/optional.zig");
122 _ = @import("behavior/pointers.zig");122 // _ = @import("behavior/pointers.zig");
123 _ = @import("behavior/popcount.zig");123 // _ = @import("behavior/popcount.zig");
124 _ = @import("behavior/prefetch.zig");124 // _ = @import("behavior/prefetch.zig");
125 _ = @import("behavior/ptrcast.zig");125 // _ = @import("behavior/ptrcast.zig");
126 _ = @import("behavior/pub_enum.zig");126 // _ = @import("behavior/pub_enum.zig");
127 _ = @import("behavior/ref_var_in_if_after_if_2nd_switch_prong.zig");127 // _ = @import("behavior/ref_var_in_if_after_if_2nd_switch_prong.zig");
128 _ = @import("behavior/reflection.zig");128 // _ = @import("behavior/reflection.zig");
129 _ = @import("behavior/saturating_arithmetic.zig");129 // _ = @import("behavior/saturating_arithmetic.zig");
130 _ = @import("behavior/select.zig");130 // _ = @import("behavior/select.zig");
131 _ = @import("behavior/shuffle.zig");131 // _ = @import("behavior/shuffle.zig");
132 _ = @import("behavior/sizeof_and_typeof.zig");132 // _ = @import("behavior/sizeof_and_typeof.zig");
133 _ = @import("behavior/slice.zig");133 // _ = @import("behavior/slice.zig");
134 _ = @import("behavior/slice_sentinel_comptime.zig");134 // _ = @import("behavior/slice_sentinel_comptime.zig");
135 _ = @import("behavior/src.zig");135 // _ = @import("behavior/src.zig");
136 _ = @import("behavior/struct.zig");136 // _ = @import("behavior/struct.zig");
137 _ = @import("behavior/packed-struct.zig");137 // _ = @import("behavior/packed-struct.zig");
138 _ = @import("behavior/struct_contains_null_ptr_itself.zig");138 // _ = @import("behavior/struct_contains_null_ptr_itself.zig");
139 _ = @import("behavior/struct_contains_slice_of_itself.zig");139 // _ = @import("behavior/struct_contains_slice_of_itself.zig");
140 _ = @import("behavior/switch.zig");140 // _ = @import("behavior/switch.zig");
141 _ = @import("behavior/switch_prong_err_enum.zig");141 // _ = @import("behavior/switch_prong_err_enum.zig");
142 _ = @import("behavior/switch_prong_implicit_cast.zig");142 // _ = @import("behavior/switch_prong_implicit_cast.zig");
143 _ = @import("behavior/this.zig");143 // _ = @import("behavior/this.zig");
144 _ = @import("behavior/translate_c_macros.zig");144 // _ = @import("behavior/translate_c_macros.zig");
145 _ = @import("behavior/truncate.zig");145 // _ = @import("behavior/truncate.zig");
146 _ = @import("behavior/try.zig");146 // _ = @import("behavior/try.zig");
147 _ = @import("behavior/tuple.zig");147 // _ = @import("behavior/tuple.zig");
148 _ = @import("behavior/type.zig");148 // _ = @import("behavior/type.zig");
149 _ = @import("behavior/type_info.zig");149 // _ = @import("behavior/type_info.zig");
150 _ = @import("behavior/typename.zig");150 // _ = @import("behavior/typename.zig");
151 _ = @import("behavior/undefined.zig");151 // _ = @import("behavior/undefined.zig");
152 _ = @import("behavior/underscore.zig");152 // _ = @import("behavior/underscore.zig");
153 _ = @import("behavior/union.zig");153 // _ = @import("behavior/union.zig");
154 _ = @import("behavior/union_with_members.zig");154 // _ = @import("behavior/union_with_members.zig");
155 _ = @import("behavior/usingnamespace.zig");155 // _ = @import("behavior/usingnamespace.zig");
156 _ = @import("behavior/var_args.zig");156 // _ = @import("behavior/var_args.zig");
157 _ = @import("behavior/vector.zig");157 // _ = @import("behavior/vector.zig");
158 _ = @import("behavior/void.zig");158 // _ = @import("behavior/void.zig");
159 _ = @import("behavior/while.zig");159 // _ = @import("behavior/while.zig");
160 _ = @import("behavior/widening.zig");160 // _ = @import("behavior/widening.zig");
161161
162 if (builtin.stage2_arch == .wasm32) {162 if (builtin.stage2_arch == .wasm32) {
163 _ = @import("behavior/wasm.zig");163 _ = @import("behavior/wasm.zig");