authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-05-25 17:06:47+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-05-25 17:06:47+02:00
log5fb7070642b660a83a2333a23d9163032f0dfcb9
treeb5ddb901bce957be857230280dd58e3ec88d6349
parent71e2a56e3ef7aba10cc0648aab786973cf8416bc

x64: move from compare_flags_* mcv to eflags with condition codes enum


4 files changed, 505 insertions(+), 295 deletions(-)

src/arch/x86_64/CodeGen.zig+134-192
...@@ -37,6 +37,7 @@ const caller_preserved_regs = abi.caller_preserved_regs;...@@ -37,6 +37,7 @@ const caller_preserved_regs = abi.caller_preserved_regs;
37const c_abi_int_param_regs = abi.c_abi_int_param_regs;37const c_abi_int_param_regs = abi.c_abi_int_param_regs;
38const c_abi_int_return_regs = abi.c_abi_int_return_regs;38const c_abi_int_return_regs = abi.c_abi_int_return_regs;
3939
40const Condition = bits.Condition;
40const RegisterManager = abi.RegisterManager;41const RegisterManager = abi.RegisterManager;
41const RegisterLock = RegisterManager.RegisterLock;42const RegisterLock = RegisterManager.RegisterLock;
42const Register = bits.Register;43const Register = bits.Register;
...@@ -65,7 +66,7 @@ arg_index: u32,...@@ -65,7 +66,7 @@ arg_index: u32,
65src_loc: Module.SrcLoc,66src_loc: Module.SrcLoc,
66stack_align: u32,67stack_align: u32,
6768
68compare_flags_inst: ?Air.Inst.Index = null,69eflags_inst: ?Air.Inst.Index = null,
6970
70/// MIR Instructions71/// MIR Instructions
71mir_instructions: std.MultiArrayList(Mir.Inst) = .{},72mir_instructions: std.MultiArrayList(Mir.Inst) = .{},
...@@ -149,12 +150,8 @@ pub const MCValue = union(enum) {...@@ -149,12 +150,8 @@ pub const MCValue = union(enum) {
149 stack_offset: i32,150 stack_offset: i32,
150 /// The value is a pointer to one of the stack variables (payload is stack offset).151 /// The value is a pointer to one of the stack variables (payload is stack offset).
151 ptr_stack_offset: i32,152 ptr_stack_offset: i32,
152 /// The value is in the compare flags assuming an unsigned operation,153 /// The value resides in the EFLAGS register.
153 /// with this operator applied on top of it.154 eflags: Condition,
154 compare_flags_unsigned: math.CompareOperator,
155 /// The value is in the compare flags assuming a signed operation,
156 /// with this operator applied on top of it.
157 compare_flags_signed: math.CompareOperator,
158155
159 fn isMemory(mcv: MCValue) bool {156 fn isMemory(mcv: MCValue) bool {
160 return switch (mcv) {157 return switch (mcv) {
...@@ -183,8 +180,7 @@ pub const MCValue = union(enum) {...@@ -183,8 +180,7 @@ pub const MCValue = union(enum) {
183180
184 .immediate,181 .immediate,
185 .memory,182 .memory,
186 .compare_flags_unsigned,183 .eflags,
187 .compare_flags_signed,
188 .ptr_stack_offset,184 .ptr_stack_offset,
189 .undef,185 .undef,
190 .register_overflow_unsigned,186 .register_overflow_unsigned,
...@@ -780,10 +776,10 @@ fn processDeath(self: *Self, inst: Air.Inst.Index) void {...@@ -780,10 +776,10 @@ fn processDeath(self: *Self, inst: Air.Inst.Index) void {
780 },776 },
781 .register_overflow_signed, .register_overflow_unsigned => |reg| {777 .register_overflow_signed, .register_overflow_unsigned => |reg| {
782 self.register_manager.freeReg(reg.to64());778 self.register_manager.freeReg(reg.to64());
783 self.compare_flags_inst = null;779 self.eflags_inst = null;
784 },780 },
785 .compare_flags_signed, .compare_flags_unsigned => {781 .eflags => {
786 self.compare_flags_inst = null;782 self.eflags_inst = null;
787 },783 },
788 else => {}, // TODO process stack allocation death784 else => {}, // TODO process stack allocation death
789 }785 }
...@@ -929,16 +925,14 @@ pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void...@@ -929,16 +925,14 @@ pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void
929 try self.genSetStack(self.air.typeOfIndex(inst), stack_mcv.stack_offset, reg_mcv, .{});925 try self.genSetStack(self.air.typeOfIndex(inst), stack_mcv.stack_offset, reg_mcv, .{});
930}926}
931927
932pub fn spillCompareFlagsIfOccupied(self: *Self) !void {928pub fn spillEflagsIfOccupied(self: *Self) !void {
933 if (self.compare_flags_inst) |inst_to_save| {929 if (self.eflags_inst) |inst_to_save| {
934 const mcv = self.getResolvedInstValue(inst_to_save);930 const mcv = self.getResolvedInstValue(inst_to_save);
935 const new_mcv = switch (mcv) {931 const new_mcv = switch (mcv) {
936 .register_overflow_signed,932 .register_overflow_signed,
937 .register_overflow_unsigned,933 .register_overflow_unsigned,
938 => try self.allocRegOrMem(inst_to_save, false),934 => try self.allocRegOrMem(inst_to_save, false),
939 .compare_flags_signed,935 .eflags => try self.allocRegOrMem(inst_to_save, true),
940 .compare_flags_unsigned,
941 => try self.allocRegOrMem(inst_to_save, true),
942 else => unreachable,936 else => unreachable,
943 };937 };
944938
...@@ -948,7 +942,7 @@ pub fn spillCompareFlagsIfOccupied(self: *Self) !void {...@@ -948,7 +942,7 @@ pub fn spillCompareFlagsIfOccupied(self: *Self) !void {
948 const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];942 const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];
949 try branch.inst_table.put(self.gpa, inst_to_save, new_mcv);943 try branch.inst_table.put(self.gpa, inst_to_save, new_mcv);
950944
951 self.compare_flags_inst = null;945 self.eflags_inst = null;
952946
953 // TODO consolidate with register manager and spillInstruction947 // TODO consolidate with register manager and spillInstruction
954 // this call should really belong in the register manager!948 // this call should really belong in the register manager!
...@@ -1123,31 +1117,8 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void {...@@ -1123,31 +1117,8 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void {
1123 switch (operand) {1117 switch (operand) {
1124 .dead => unreachable,1118 .dead => unreachable,
1125 .unreach => unreachable,1119 .unreach => unreachable,
1126 .compare_flags_unsigned => |op| {1120 .eflags => |cc| {
1127 const r = MCValue{1121 break :result MCValue{ .eflags = cc.negate() };
1128 .compare_flags_unsigned = switch (op) {
1129 .gte => .lt,
1130 .gt => .lte,
1131 .neq => .eq,
1132 .lt => .gte,
1133 .lte => .gt,
1134 .eq => .neq,
1135 },
1136 };
1137 break :result r;
1138 },
1139 .compare_flags_signed => |op| {
1140 const r = MCValue{
1141 .compare_flags_signed = switch (op) {
1142 .gte => .lt,
1143 .gt => .lte,
1144 .neq => .eq,
1145 .lt => .gte,
1146 .lte => .gt,
1147 .eq => .neq,
1148 },
1149 };
1150 break :result r;
1151 },1122 },
1152 else => {},1123 else => {},
1153 }1124 }
...@@ -1213,13 +1184,17 @@ fn airMin(self: *Self, inst: Air.Inst.Index) !void {...@@ -1213,13 +1184,17 @@ fn airMin(self: *Self, inst: Air.Inst.Index) !void {
1213 try self.genBinOpMir(.cmp, ty, .{ .register = lhs_reg }, rhs_mcv);1184 try self.genBinOpMir(.cmp, ty, .{ .register = lhs_reg }, rhs_mcv);
12141185
1215 const dst_mcv = try self.copyToRegisterWithInstTracking(inst, ty, rhs_mcv);1186 const dst_mcv = try self.copyToRegisterWithInstTracking(inst, ty, rhs_mcv);
1187 const cc: Condition = switch (signedness) {
1188 .unsigned => .b,
1189 .signed => .l,
1190 };
1216 _ = try self.addInst(.{1191 _ = try self.addInst(.{
1217 .tag = if (signedness == .signed) .cond_mov_lt else .cond_mov_below,1192 .tag = .cond_mov,
1218 .ops = Mir.Inst.Ops.encode(.{1193 .ops = Mir.Inst.Ops.encode(.{
1219 .reg1 = dst_mcv.register,1194 .reg1 = dst_mcv.register,
1220 .reg2 = lhs_reg,1195 .reg2 = lhs_reg,
1221 }),1196 }),
1222 .data = undefined,1197 .data = .{ .cc = cc },
1223 });1198 });
12241199
1225 break :result dst_mcv;1200 break :result dst_mcv;
...@@ -1341,7 +1316,7 @@ fn airAddSubShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void {...@@ -1341,7 +1316,7 @@ fn airAddSubShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
1341 return self.fail("TODO implement add/sub/shl with overflow for Ints larger than 64bits", .{});1316 return self.fail("TODO implement add/sub/shl with overflow for Ints larger than 64bits", .{});
1342 }1317 }
13431318
1344 try self.spillCompareFlagsIfOccupied();1319 try self.spillEflagsIfOccupied();
13451320
1346 if (tag == .shl_with_overflow) {1321 if (tag == .shl_with_overflow) {
1347 try self.spillRegisters(1, .{.rcx});1322 try self.spillRegisters(1, .{.rcx});
...@@ -1362,7 +1337,7 @@ fn airAddSubShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void {...@@ -1362,7 +1337,7 @@ fn airAddSubShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
1362 const int_info = ty.intInfo(self.target.*);1337 const int_info = ty.intInfo(self.target.*);
13631338
1364 if (math.isPowerOfTwo(int_info.bits) and int_info.bits >= 8) {1339 if (math.isPowerOfTwo(int_info.bits) and int_info.bits >= 8) {
1365 self.compare_flags_inst = inst;1340 self.eflags_inst = inst;
13661341
1367 const result: MCValue = switch (int_info.signedness) {1342 const result: MCValue = switch (int_info.signedness) {
1368 .signed => .{ .register_overflow_signed = partial.register },1343 .signed => .{ .register_overflow_signed = partial.register },
...@@ -1371,7 +1346,7 @@ fn airAddSubShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void {...@@ -1371,7 +1346,7 @@ fn airAddSubShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
1371 break :result result;1346 break :result result;
1372 }1347 }
13731348
1374 self.compare_flags_inst = null;1349 self.eflags_inst = null;
13751350
1376 const tuple_ty = self.air.typeOfIndex(inst);1351 const tuple_ty = self.air.typeOfIndex(inst);
1377 const tuple_size = @intCast(u32, tuple_ty.abiSize(self.target.*));1352 const tuple_size = @intCast(u32, tuple_ty.abiSize(self.target.*));
...@@ -1413,17 +1388,16 @@ fn genSetStackTruncatedOverflowCompare(...@@ -1413,17 +1388,16 @@ fn genSetStackTruncatedOverflowCompare(
1413 };1388 };
14141389
1415 const overflow_reg = temp_regs[0];1390 const overflow_reg = temp_regs[0];
1416 const flags: u2 = switch (int_info.signedness) {1391 const cc: Condition = switch (int_info.signedness) {
1417 .signed => 0b00,1392 .signed => .o,
1418 .unsigned => 0b10,1393 .unsigned => .c,
1419 };1394 };
1420 _ = try self.addInst(.{1395 _ = try self.addInst(.{
1421 .tag = .cond_set_byte_overflow,1396 .tag = .cond_set_byte,
1422 .ops = Mir.Inst.Ops.encode(.{1397 .ops = Mir.Inst.Ops.encode(.{
1423 .reg1 = overflow_reg.to8(),1398 .reg1 = overflow_reg.to8(),
1424 .flags = flags,
1425 }),1399 }),
1426 .data = undefined,1400 .data = .{ .cc = cc },
1427 });1401 });
14281402
1429 const scratch_reg = temp_regs[1];1403 const scratch_reg = temp_regs[1];
...@@ -1438,9 +1412,9 @@ fn genSetStackTruncatedOverflowCompare(...@@ -1438,9 +1412,9 @@ fn genSetStackTruncatedOverflowCompare(
14381412
1439 const eq_reg = temp_regs[2];1413 const eq_reg = temp_regs[2];
1440 _ = try self.addInst(.{1414 _ = try self.addInst(.{
1441 .tag = .cond_set_byte_eq_ne,1415 .tag = .cond_set_byte,
1442 .ops = Mir.Inst.Ops.encode(.{ .reg1 = eq_reg.to8() }),1416 .ops = Mir.Inst.Ops.encode(.{ .reg1 = eq_reg.to8() }),
1443 .data = undefined,1417 .data = .{ .cc = .ne },
1444 });1418 });
14451419
1446 try self.genBinOpMir(1420 try self.genBinOpMir(
...@@ -1477,8 +1451,8 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {...@@ -1477,8 +1451,8 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
1477 const int_info = ty.intInfo(self.target.*);1451 const int_info = ty.intInfo(self.target.*);
14781452
1479 if (math.isPowerOfTwo(int_info.bits) and int_info.bits >= 8) {1453 if (math.isPowerOfTwo(int_info.bits) and int_info.bits >= 8) {
1480 try self.spillCompareFlagsIfOccupied();1454 try self.spillEflagsIfOccupied();
1481 self.compare_flags_inst = inst;1455 self.eflags_inst = inst;
14821456
1483 try self.spillRegisters(2, .{ .rax, .rdx });1457 try self.spillRegisters(2, .{ .rax, .rdx });
14841458
...@@ -1492,8 +1466,8 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {...@@ -1492,8 +1466,8 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
1492 };1466 };
1493 }1467 }
14941468
1495 try self.spillCompareFlagsIfOccupied();1469 try self.spillEflagsIfOccupied();
1496 self.compare_flags_inst = null;1470 self.eflags_inst = null;
14971471
1498 const dst_reg: Register = dst_reg: {1472 const dst_reg: Register = dst_reg: {
1499 switch (int_info.signedness) {1473 switch (int_info.signedness) {
...@@ -1686,12 +1660,12 @@ fn genInlineIntDivFloor(self: *Self, ty: Type, lhs: MCValue, rhs: MCValue) !MCVa...@@ -1686,12 +1660,12 @@ fn genInlineIntDivFloor(self: *Self, ty: Type, lhs: MCValue, rhs: MCValue) !MCVa
1686 .data = undefined,1660 .data = undefined,
1687 });1661 });
1688 _ = try self.addInst(.{1662 _ = try self.addInst(.{
1689 .tag = .cond_mov_eq,1663 .tag = .cond_mov,
1690 .ops = Mir.Inst.Ops.encode(.{1664 .ops = Mir.Inst.Ops.encode(.{
1691 .reg1 = divisor.to64(),1665 .reg1 = divisor.to64(),
1692 .reg2 = .rdx,1666 .reg2 = .rdx,
1693 }),1667 }),
1694 .data = undefined,1668 .data = .{ .cc = .e },
1695 });1669 });
1696 try self.genBinOpMir(.add, Type.isize, .{ .register = divisor }, .{ .register = .rax });1670 try self.genBinOpMir(.add, Type.isize, .{ .register = divisor }, .{ .register = .rax });
1697 return MCValue{ .register = divisor };1671 return MCValue{ .register = divisor };
...@@ -2511,8 +2485,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo...@@ -2511,8 +2485,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo
2511 .undef => unreachable,2485 .undef => unreachable,
2512 .unreach => unreachable,2486 .unreach => unreachable,
2513 .dead => unreachable,2487 .dead => unreachable,
2514 .compare_flags_unsigned => unreachable,2488 .eflags => unreachable,
2515 .compare_flags_signed => unreachable,
2516 .register_overflow_unsigned => unreachable,2489 .register_overflow_unsigned => unreachable,
2517 .register_overflow_signed => unreachable,2490 .register_overflow_signed => unreachable,
2518 .immediate => |imm| {2491 .immediate => |imm| {
...@@ -2532,8 +2505,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo...@@ -2532,8 +2505,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo
2532 switch (dst_mcv) {2505 switch (dst_mcv) {
2533 .dead => unreachable,2506 .dead => unreachable,
2534 .undef => unreachable,2507 .undef => unreachable,
2535 .compare_flags_unsigned => unreachable,2508 .eflags => unreachable,
2536 .compare_flags_signed => unreachable,
2537 .register => |dst_reg| {2509 .register => |dst_reg| {
2538 // mov dst_reg, [reg]2510 // mov dst_reg, [reg]
2539 _ = try self.addInst(.{2511 _ = try self.addInst(.{
...@@ -2637,8 +2609,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type...@@ -2637,8 +2609,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
2637 .undef => unreachable,2609 .undef => unreachable,
2638 .unreach => unreachable,2610 .unreach => unreachable,
2639 .dead => unreachable,2611 .dead => unreachable,
2640 .compare_flags_unsigned => unreachable,2612 .eflags => unreachable,
2641 .compare_flags_signed => unreachable,
2642 .register_overflow_unsigned => unreachable,2613 .register_overflow_unsigned => unreachable,
2643 .register_overflow_signed => unreachable,2614 .register_overflow_signed => unreachable,
2644 .immediate => |imm| {2615 .immediate => |imm| {
...@@ -2660,8 +2631,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type...@@ -2660,8 +2631,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
2660 .undef => unreachable,2631 .undef => unreachable,
2661 .dead => unreachable,2632 .dead => unreachable,
2662 .unreach => unreachable,2633 .unreach => unreachable,
2663 .compare_flags_unsigned => unreachable,2634 .eflags => unreachable,
2664 .compare_flags_signed => unreachable,
2665 .immediate => |imm| {2635 .immediate => |imm| {
2666 switch (abi_size) {2636 switch (abi_size) {
2667 1, 2, 4 => {2637 1, 2, 4 => {
...@@ -3041,18 +3011,17 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {...@@ -3041,18 +3011,17 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
3041 defer self.register_manager.unlockReg(reg_lock);3011 defer self.register_manager.unlockReg(reg_lock);
30423012
3043 const dst_reg = try self.register_manager.allocReg(inst, gp);3013 const dst_reg = try self.register_manager.allocReg(inst, gp);
3044 const flags: u2 = switch (mcv) {3014 const cc: Condition = switch (mcv) {
3045 .register_overflow_unsigned => 0b10,3015 .register_overflow_unsigned => .c,
3046 .register_overflow_signed => 0b00,3016 .register_overflow_signed => .o,
3047 else => unreachable,3017 else => unreachable,
3048 };3018 };
3049 _ = try self.addInst(.{3019 _ = try self.addInst(.{
3050 .tag = .cond_set_byte_overflow,3020 .tag = .cond_set_byte,
3051 .ops = Mir.Inst.Ops.encode(.{3021 .ops = Mir.Inst.Ops.encode(.{
3052 .reg1 = dst_reg.to8(),3022 .reg1 = dst_reg.to8(),
3053 .flags = flags,
3054 }),3023 }),
3055 .data = undefined,3024 .data = .{ .cc = cc },
3056 });3025 });
3057 break :result MCValue{ .register = dst_reg.to8() };3026 break :result MCValue{ .register = dst_reg.to8() };
3058 },3027 },
...@@ -3479,8 +3448,7 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValu...@@ -3479,8 +3448,7 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValu
3479 .none => unreachable,3448 .none => unreachable,
3480 .undef => unreachable,3449 .undef => unreachable,
3481 .dead, .unreach, .immediate => unreachable,3450 .dead, .unreach, .immediate => unreachable,
3482 .compare_flags_unsigned => unreachable,3451 .eflags => unreachable,
3483 .compare_flags_signed => unreachable,
3484 .register_overflow_unsigned => unreachable,3452 .register_overflow_unsigned => unreachable,
3485 .register_overflow_signed => unreachable,3453 .register_overflow_signed => unreachable,
3486 .register => |dst_reg| {3454 .register => |dst_reg| {
...@@ -3559,8 +3527,7 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValu...@@ -3559,8 +3527,7 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValu
3559 .memory,3527 .memory,
3560 .got_load,3528 .got_load,
3561 .direct_load,3529 .direct_load,
3562 .compare_flags_signed,3530 .eflags,
3563 .compare_flags_unsigned,
3564 => {3531 => {
3565 assert(abi_size <= 8);3532 assert(abi_size <= 8);
3566 const dst_reg_lock = self.register_manager.lockReg(dst_reg);3533 const dst_reg_lock = self.register_manager.lockReg(dst_reg);
...@@ -3649,11 +3616,8 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValu...@@ -3649,11 +3616,8 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValu
3649 .got_load, .direct_load => {3616 .got_load, .direct_load => {
3650 return self.fail("TODO implement x86 ADD/SUB/CMP source symbol at index in linker", .{});3617 return self.fail("TODO implement x86 ADD/SUB/CMP source symbol at index in linker", .{});
3651 },3618 },
3652 .compare_flags_unsigned => {3619 .eflags => {
3653 return self.fail("TODO implement x86 ADD/SUB/CMP source compare flag (unsigned)", .{});3620 return self.fail("TODO implement x86 ADD/SUB/CMP source eflags", .{});
3654 },
3655 .compare_flags_signed => {
3656 return self.fail("TODO implement x86 ADD/SUB/CMP source compare flag (signed)", .{});
3657 },3621 },
3658 }3622 }
3659 },3623 },
...@@ -3674,8 +3638,7 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M...@@ -3674,8 +3638,7 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M
3674 .none => unreachable,3638 .none => unreachable,
3675 .undef => unreachable,3639 .undef => unreachable,
3676 .dead, .unreach, .immediate => unreachable,3640 .dead, .unreach, .immediate => unreachable,
3677 .compare_flags_unsigned => unreachable,3641 .eflags => unreachable,
3678 .compare_flags_signed => unreachable,
3679 .ptr_stack_offset => unreachable,3642 .ptr_stack_offset => unreachable,
3680 .register_overflow_unsigned => unreachable,3643 .register_overflow_unsigned => unreachable,
3681 .register_overflow_signed => unreachable,3644 .register_overflow_signed => unreachable,
...@@ -3734,11 +3697,8 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M...@@ -3734,11 +3697,8 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M
3734 .got_load, .direct_load => {3697 .got_load, .direct_load => {
3735 return self.fail("TODO implement x86 multiply source symbol at index in linker", .{});3698 return self.fail("TODO implement x86 multiply source symbol at index in linker", .{});
3736 },3699 },
3737 .compare_flags_unsigned => {3700 .eflags => {
3738 return self.fail("TODO implement x86 multiply source compare flag (unsigned)", .{});3701 return self.fail("TODO implement x86 multiply source eflags", .{});
3739 },
3740 .compare_flags_signed => {
3741 return self.fail("TODO implement x86 multiply source compare flag (signed)", .{});
3742 },3702 },
3743 }3703 }
3744 },3704 },
...@@ -3782,11 +3742,8 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M...@@ -3782,11 +3742,8 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M
3782 .got_load, .direct_load => {3742 .got_load, .direct_load => {
3783 return self.fail("TODO implement x86 multiply source symbol at index in linker", .{});3743 return self.fail("TODO implement x86 multiply source symbol at index in linker", .{});
3784 },3744 },
3785 .compare_flags_unsigned => {3745 .eflags => {
3786 return self.fail("TODO implement x86 multiply source compare flag (unsigned)", .{});3746 return self.fail("TODO implement x86 multiply source eflags", .{});
3787 },
3788 .compare_flags_signed => {
3789 return self.fail("TODO implement x86 multiply source compare flag (signed)", .{});
3790 },3747 },
3791 }3748 }
3792 },3749 },
...@@ -3905,7 +3862,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions....@@ -3905,7 +3862,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.
3905 var info = try self.resolveCallingConventionValues(fn_ty);3862 var info = try self.resolveCallingConventionValues(fn_ty);
3906 defer info.deinit(self);3863 defer info.deinit(self);
39073864
3908 try self.spillCompareFlagsIfOccupied();3865 try self.spillEflagsIfOccupied();
39093866
3910 for (caller_preserved_regs) |reg| {3867 for (caller_preserved_regs) |reg| {
3911 try self.register_manager.getReg(reg, null);3868 try self.register_manager.getReg(reg, null);
...@@ -3957,8 +3914,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions....@@ -3957,8 +3914,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.
3957 .memory => unreachable,3914 .memory => unreachable,
3958 .got_load => unreachable,3915 .got_load => unreachable,
3959 .direct_load => unreachable,3916 .direct_load => unreachable,
3960 .compare_flags_signed => unreachable,3917 .eflags => unreachable,
3961 .compare_flags_unsigned => unreachable,
3962 .register_overflow_signed => unreachable,3918 .register_overflow_signed => unreachable,
3963 .register_overflow_unsigned => unreachable,3919 .register_overflow_unsigned => unreachable,
3964 }3920 }
...@@ -4220,8 +4176,8 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {...@@ -4220,8 +4176,8 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
4220 break :blk ty.intInfo(self.target.*).signedness;4176 break :blk ty.intInfo(self.target.*).signedness;
4221 };4177 };
42224178
4223 try self.spillCompareFlagsIfOccupied();4179 try self.spillEflagsIfOccupied();
4224 self.compare_flags_inst = inst;4180 self.eflags_inst = inst;
42254181
4226 const result: MCValue = result: {4182 const result: MCValue = result: {
4227 // There are 2 operands, destination and source.4183 // There are 2 operands, destination and source.
...@@ -4265,9 +4221,10 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {...@@ -4265,9 +4221,10 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
4265 defer if (src_lock) |lock| self.register_manager.unlockReg(lock);4221 defer if (src_lock) |lock| self.register_manager.unlockReg(lock);
42664222
4267 try self.genBinOpMir(.cmp, ty, dst_mcv, src_mcv);4223 try self.genBinOpMir(.cmp, ty, dst_mcv, src_mcv);
4224
4268 break :result switch (signedness) {4225 break :result switch (signedness) {
4269 .signed => MCValue{ .compare_flags_signed = op },4226 .signed => MCValue{ .eflags = Condition.fromCompareOperatorSigned(op) },
4270 .unsigned => MCValue{ .compare_flags_unsigned = op },4227 .unsigned => MCValue{ .eflags = Condition.fromCompareOperatorUnsigned(op) },
4271 };4228 };
4272 };4229 };
42734230
...@@ -4440,47 +4397,39 @@ fn addDbgInfoTypeReloc(self: *Self, ty: Type) !void {...@@ -4440,47 +4397,39 @@ fn addDbgInfoTypeReloc(self: *Self, ty: Type) !void {
4440fn genCondBrMir(self: *Self, ty: Type, mcv: MCValue) !u32 {4397fn genCondBrMir(self: *Self, ty: Type, mcv: MCValue) !u32 {
4441 const abi_size = ty.abiSize(self.target.*);4398 const abi_size = ty.abiSize(self.target.*);
4442 switch (mcv) {4399 switch (mcv) {
4443 .compare_flags_unsigned,4400 .eflags => |cc| {
4444 .compare_flags_signed,
4445 => |cmp_op| {
4446 // Here we map the opposites since the jump is to the false branch.
4447 const flags: u2 = switch (cmp_op) {
4448 .gte => 0b10,
4449 .gt => 0b11,
4450 .neq => 0b01,
4451 .lt => 0b00,
4452 .lte => 0b01,
4453 .eq => 0b00,
4454 };
4455 const tag: Mir.Inst.Tag = if (cmp_op == .neq or cmp_op == .eq)
4456 .cond_jmp_eq_ne
4457 else if (mcv == .compare_flags_unsigned)
4458 Mir.Inst.Tag.cond_jmp_above_below
4459 else
4460 Mir.Inst.Tag.cond_jmp_greater_less;
4461 return self.addInst(.{4401 return self.addInst(.{
4462 .tag = tag,4402 .tag = .cond_jmp,
4463 .ops = Mir.Inst.Ops.encode(.{ .flags = flags }),4403 .ops = Mir.Inst.Ops.encode(.{}),
4464 .data = .{ .inst = undefined },4404 .data = .{
4405 .inst_cc = .{
4406 .inst = undefined,
4407 // Here we map the opposites since the jump is to the false branch.
4408 .cc = cc.negate(),
4409 },
4410 },
4465 });4411 });
4466 },4412 },
4467 .register => |reg| {4413 .register => |reg| {
4468 try self.spillCompareFlagsIfOccupied();4414 try self.spillEflagsIfOccupied();
4469 _ = try self.addInst(.{4415 _ = try self.addInst(.{
4470 .tag = .@"test",4416 .tag = .@"test",
4471 .ops = Mir.Inst.Ops.encode(.{ .reg1 = reg }),4417 .ops = Mir.Inst.Ops.encode(.{ .reg1 = reg }),
4472 .data = .{ .imm = 1 },4418 .data = .{ .imm = 1 },
4473 });4419 });
4474 return self.addInst(.{4420 return self.addInst(.{
4475 .tag = .cond_jmp_eq_ne,4421 .tag = .cond_jmp,
4476 .ops = Mir.Inst.Ops.encode(.{ .flags = 0b01 }),4422 .ops = Mir.Inst.Ops.encode(.{}),
4477 .data = .{ .inst = undefined },4423 .data = .{ .inst_cc = .{
4424 .inst = undefined,
4425 .cc = .e,
4426 } },
4478 });4427 });
4479 },4428 },
4480 .immediate,4429 .immediate,
4481 .stack_offset,4430 .stack_offset,
4482 => {4431 => {
4483 try self.spillCompareFlagsIfOccupied();4432 try self.spillEflagsIfOccupied();
4484 if (abi_size <= 8) {4433 if (abi_size <= 8) {
4485 const reg = try self.copyToTmpRegister(ty, mcv);4434 const reg = try self.copyToTmpRegister(ty, mcv);
4486 return self.genCondBrMir(ty, .{ .register = reg });4435 return self.genCondBrMir(ty, .{ .register = reg });
...@@ -4516,7 +4465,7 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {...@@ -4516,7 +4465,7 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {
4516 // Capture the state of register and stack allocation state so that we can revert to it.4465 // Capture the state of register and stack allocation state so that we can revert to it.
4517 const parent_next_stack_offset = self.next_stack_offset;4466 const parent_next_stack_offset = self.next_stack_offset;
4518 const parent_free_registers = self.register_manager.free_registers;4467 const parent_free_registers = self.register_manager.free_registers;
4519 const parent_compare_flags_inst = self.compare_flags_inst;4468 const parent_eflags_inst = self.eflags_inst;
4520 var parent_stack = try self.stack.clone(self.gpa);4469 var parent_stack = try self.stack.clone(self.gpa);
4521 defer parent_stack.deinit(self.gpa);4470 defer parent_stack.deinit(self.gpa);
4522 const parent_registers = self.register_manager.registers;4471 const parent_registers = self.register_manager.registers;
...@@ -4538,7 +4487,7 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {...@@ -4538,7 +4487,7 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {
4538 defer saved_then_branch.deinit(self.gpa);4487 defer saved_then_branch.deinit(self.gpa);
45394488
4540 self.register_manager.registers = parent_registers;4489 self.register_manager.registers = parent_registers;
4541 self.compare_flags_inst = parent_compare_flags_inst;4490 self.eflags_inst = parent_eflags_inst;
45424491
4543 self.stack.deinit(self.gpa);4492 self.stack.deinit(self.gpa);
4544 self.stack = parent_stack;4493 self.stack = parent_stack;
...@@ -4640,8 +4589,8 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {...@@ -4640,8 +4589,8 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {
4640}4589}
46414590
4642fn isNull(self: *Self, inst: Air.Inst.Index, ty: Type, operand: MCValue) !MCValue {4591fn isNull(self: *Self, inst: Air.Inst.Index, ty: Type, operand: MCValue) !MCValue {
4643 try self.spillCompareFlagsIfOccupied();4592 try self.spillEflagsIfOccupied();
4644 self.compare_flags_inst = inst;4593 self.eflags_inst = inst;
46454594
4646 const cmp_ty: Type = if (!ty.isPtrLikeOptional()) blk: {4595 const cmp_ty: Type = if (!ty.isPtrLikeOptional()) blk: {
4647 var buf: Type.Payload.ElemType = undefined;4596 var buf: Type.Payload.ElemType = undefined;
...@@ -4651,13 +4600,13 @@ fn isNull(self: *Self, inst: Air.Inst.Index, ty: Type, operand: MCValue) !MCValu...@@ -4651,13 +4600,13 @@ fn isNull(self: *Self, inst: Air.Inst.Index, ty: Type, operand: MCValue) !MCValu
46514600
4652 try self.genBinOpMir(.cmp, cmp_ty, operand, MCValue{ .immediate = 0 });4601 try self.genBinOpMir(.cmp, cmp_ty, operand, MCValue{ .immediate = 0 });
46534602
4654 return MCValue{ .compare_flags_unsigned = .eq };4603 return MCValue{ .eflags = .e };
4655}4604}
46564605
4657fn isNonNull(self: *Self, inst: Air.Inst.Index, ty: Type, operand: MCValue) !MCValue {4606fn isNonNull(self: *Self, inst: Air.Inst.Index, ty: Type, operand: MCValue) !MCValue {
4658 const is_null_res = try self.isNull(inst, ty, operand);4607 const is_null_res = try self.isNull(inst, ty, operand);
4659 assert(is_null_res.compare_flags_unsigned == .eq);4608 assert(is_null_res.eflags == .e);
4660 return MCValue{ .compare_flags_unsigned = .neq };4609 return MCValue{ .eflags = is_null_res.eflags.negate() };
4661}4610}
46624611
4663fn isErr(self: *Self, inst: Air.Inst.Index, ty: Type, operand: MCValue) !MCValue {4612fn isErr(self: *Self, inst: Air.Inst.Index, ty: Type, operand: MCValue) !MCValue {
...@@ -4667,8 +4616,8 @@ fn isErr(self: *Self, inst: Air.Inst.Index, ty: Type, operand: MCValue) !MCValue...@@ -4667,8 +4616,8 @@ fn isErr(self: *Self, inst: Air.Inst.Index, ty: Type, operand: MCValue) !MCValue
4667 return MCValue{ .immediate = 0 }; // always false4616 return MCValue{ .immediate = 0 }; // always false
4668 }4617 }
46694618
4670 try self.spillCompareFlagsIfOccupied();4619 try self.spillEflagsIfOccupied();
4671 self.compare_flags_inst = inst;4620 self.eflags_inst = inst;
46724621
4673 const err_off = errUnionErrorOffset(ty.errorUnionPayload(), self.target.*);4622 const err_off = errUnionErrorOffset(ty.errorUnionPayload(), self.target.*);
4674 switch (operand) {4623 switch (operand) {
...@@ -4691,15 +4640,15 @@ fn isErr(self: *Self, inst: Air.Inst.Index, ty: Type, operand: MCValue) !MCValue...@@ -4691,15 +4640,15 @@ fn isErr(self: *Self, inst: Air.Inst.Index, ty: Type, operand: MCValue) !MCValue
4691 else => return self.fail("TODO implement isErr for {}", .{operand}),4640 else => return self.fail("TODO implement isErr for {}", .{operand}),
4692 }4641 }
46934642
4694 return MCValue{ .compare_flags_unsigned = .gt };4643 return MCValue{ .eflags = .a };
4695}4644}
46964645
4697fn isNonErr(self: *Self, inst: Air.Inst.Index, ty: Type, operand: MCValue) !MCValue {4646fn isNonErr(self: *Self, inst: Air.Inst.Index, ty: Type, operand: MCValue) !MCValue {
4698 const is_err_res = try self.isErr(inst, ty, operand);4647 const is_err_res = try self.isErr(inst, ty, operand);
4699 switch (is_err_res) {4648 switch (is_err_res) {
4700 .compare_flags_unsigned => |op| {4649 .eflags => |cc| {
4701 assert(op == .gt);4650 assert(cc == .a);
4702 return MCValue{ .compare_flags_unsigned = .lte };4651 return MCValue{ .eflags = cc.negate() };
4703 },4652 },
4704 .immediate => |imm| {4653 .immediate => |imm| {
4705 assert(imm == 0);4654 assert(imm == 0);
...@@ -4914,10 +4863,9 @@ fn genCondSwitchMir(self: *Self, ty: Type, condition: MCValue, case: MCValue) !u...@@ -4914,10 +4863,9 @@ fn genCondSwitchMir(self: *Self, ty: Type, condition: MCValue, case: MCValue) !u
4914 .none => unreachable,4863 .none => unreachable,
4915 .undef => unreachable,4864 .undef => unreachable,
4916 .dead, .unreach => unreachable,4865 .dead, .unreach => unreachable,
4917 .compare_flags_signed => unreachable,4866 .eflags => unreachable,
4918 .compare_flags_unsigned => unreachable,
4919 .register => |cond_reg| {4867 .register => |cond_reg| {
4920 try self.spillCompareFlagsIfOccupied();4868 try self.spillEflagsIfOccupied();
49214869
4922 const cond_reg_lock = self.register_manager.lockReg(cond_reg);4870 const cond_reg_lock = self.register_manager.lockReg(cond_reg);
4923 defer if (cond_reg_lock) |lock| self.register_manager.unlockReg(lock);4871 defer if (cond_reg_lock) |lock| self.register_manager.unlockReg(lock);
...@@ -4965,13 +4913,16 @@ fn genCondSwitchMir(self: *Self, ty: Type, condition: MCValue, case: MCValue) !u...@@ -4965,13 +4913,16 @@ fn genCondSwitchMir(self: *Self, ty: Type, condition: MCValue, case: MCValue) !u
4965 .data = undefined,4913 .data = undefined,
4966 });4914 });
4967 return self.addInst(.{4915 return self.addInst(.{
4968 .tag = .cond_jmp_eq_ne,4916 .tag = .cond_jmp,
4969 .ops = Mir.Inst.Ops.encode(.{}),4917 .ops = Mir.Inst.Ops.encode(.{}),
4970 .data = .{ .inst = undefined },4918 .data = .{ .inst_cc = .{
4919 .inst = undefined,
4920 .cc = .ne,
4921 } },
4971 });4922 });
4972 },4923 },
4973 .stack_offset => {4924 .stack_offset => {
4974 try self.spillCompareFlagsIfOccupied();4925 try self.spillEflagsIfOccupied();
49754926
4976 if (abi_size <= 8) {4927 if (abi_size <= 8) {
4977 const reg = try self.copyToTmpRegister(ty, condition);4928 const reg = try self.copyToTmpRegister(ty, condition);
...@@ -5030,7 +4981,7 @@ fn airSwitch(self: *Self, inst: Air.Inst.Index) !void {...@@ -5030,7 +4981,7 @@ fn airSwitch(self: *Self, inst: Air.Inst.Index) !void {
5030 // Capture the state of register and stack allocation state so that we can revert to it.4981 // Capture the state of register and stack allocation state so that we can revert to it.
5031 const parent_next_stack_offset = self.next_stack_offset;4982 const parent_next_stack_offset = self.next_stack_offset;
5032 const parent_free_registers = self.register_manager.free_registers;4983 const parent_free_registers = self.register_manager.free_registers;
5033 const parent_compare_flags_inst = self.compare_flags_inst;4984 const parent_eflags_inst = self.eflags_inst;
5034 var parent_stack = try self.stack.clone(self.gpa);4985 var parent_stack = try self.stack.clone(self.gpa);
5035 defer parent_stack.deinit(self.gpa);4986 defer parent_stack.deinit(self.gpa);
5036 const parent_registers = self.register_manager.registers;4987 const parent_registers = self.register_manager.registers;
...@@ -5052,7 +5003,7 @@ fn airSwitch(self: *Self, inst: Air.Inst.Index) !void {...@@ -5052,7 +5003,7 @@ fn airSwitch(self: *Self, inst: Air.Inst.Index) !void {
5052 defer saved_case_branch.deinit(self.gpa);5003 defer saved_case_branch.deinit(self.gpa);
50535004
5054 self.register_manager.registers = parent_registers;5005 self.register_manager.registers = parent_registers;
5055 self.compare_flags_inst = parent_compare_flags_inst;5006 self.eflags_inst = parent_eflags_inst;
5056 self.stack.deinit(self.gpa);5007 self.stack.deinit(self.gpa);
5057 self.stack = parent_stack;5008 self.stack = parent_stack;
5058 parent_stack = .{};5009 parent_stack = .{};
...@@ -5092,7 +5043,15 @@ fn airSwitch(self: *Self, inst: Air.Inst.Index) !void {...@@ -5092,7 +5043,15 @@ fn airSwitch(self: *Self, inst: Air.Inst.Index) !void {
50925043
5093fn performReloc(self: *Self, reloc: Mir.Inst.Index) !void {5044fn performReloc(self: *Self, reloc: Mir.Inst.Index) !void {
5094 const next_inst = @intCast(u32, self.mir_instructions.len);5045 const next_inst = @intCast(u32, self.mir_instructions.len);
5095 self.mir_instructions.items(.data)[reloc].inst = next_inst;5046 switch (self.mir_instructions.items(.tag)[reloc]) {
5047 .cond_jmp => {
5048 self.mir_instructions.items(.data)[reloc].inst_cc.inst = next_inst;
5049 },
5050 .jmp => {
5051 self.mir_instructions.items(.data)[reloc].inst = next_inst;
5052 },
5053 else => unreachable,
5054 }
5096}5055}
50975056
5098fn airBr(self: *Self, inst: Air.Inst.Index) !void {5057fn airBr(self: *Self, inst: Air.Inst.Index) !void {
...@@ -5111,7 +5070,7 @@ fn br(self: *Self, block: Air.Inst.Index, operand: Air.Inst.Ref) !void {...@@ -5111,7 +5070,7 @@ fn br(self: *Self, block: Air.Inst.Index, operand: Air.Inst.Ref) !void {
5111 block_data.mcv = switch (operand_mcv) {5070 block_data.mcv = switch (operand_mcv) {
5112 .none, .dead, .unreach => unreachable,5071 .none, .dead, .unreach => unreachable,
5113 .register, .stack_offset, .memory => operand_mcv,5072 .register, .stack_offset, .memory => operand_mcv,
5114 .compare_flags_signed, .compare_flags_unsigned, .immediate => blk: {5073 .eflags, .immediate => blk: {
5115 const new_mcv = try self.allocRegOrMem(block, true);5074 const new_mcv = try self.allocRegOrMem(block, true);
5116 try self.setRegOrMem(self.air.typeOfIndex(block), new_mcv, operand_mcv);5075 try self.setRegOrMem(self.air.typeOfIndex(block), new_mcv, operand_mcv);
5117 break :blk new_mcv;5076 break :blk new_mcv;
...@@ -5335,9 +5294,7 @@ fn genSetStackArg(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerE...@@ -5335,9 +5294,7 @@ fn genSetStackArg(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerE
5335 .register_overflow_unsigned,5294 .register_overflow_unsigned,
5336 .register_overflow_signed,5295 .register_overflow_signed,
5337 => return self.fail("TODO genSetStackArg for register with overflow bit", .{}),5296 => return self.fail("TODO genSetStackArg for register with overflow bit", .{}),
5338 .compare_flags_unsigned,5297 .eflags => {
5339 .compare_flags_signed,
5340 => {
5341 const reg = try self.copyToTmpRegister(ty, mcv);5298 const reg = try self.copyToTmpRegister(ty, mcv);
5342 return self.genSetStackArg(ty, stack_offset, .{ .register = reg });5299 return self.genSetStackArg(ty, stack_offset, .{ .register = reg });
5343 },5300 },
...@@ -5484,18 +5441,17 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: Inl...@@ -5484,18 +5441,17 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: Inl
5484 const overflow_bit_ty = ty.structFieldType(1);5441 const overflow_bit_ty = ty.structFieldType(1);
5485 const overflow_bit_offset = ty.structFieldOffset(1, self.target.*);5442 const overflow_bit_offset = ty.structFieldOffset(1, self.target.*);
5486 const tmp_reg = try self.register_manager.allocReg(null, gp);5443 const tmp_reg = try self.register_manager.allocReg(null, gp);
5487 const flags: u2 = switch (mcv) {5444 const cc: Condition = switch (mcv) {
5488 .register_overflow_unsigned => 0b10,5445 .register_overflow_unsigned => .c,
5489 .register_overflow_signed => 0b00,5446 .register_overflow_signed => .o,
5490 else => unreachable,5447 else => unreachable,
5491 };5448 };
5492 _ = try self.addInst(.{5449 _ = try self.addInst(.{
5493 .tag = .cond_set_byte_overflow,5450 .tag = .cond_set_byte,
5494 .ops = Mir.Inst.Ops.encode(.{5451 .ops = Mir.Inst.Ops.encode(.{
5495 .reg1 = tmp_reg.to8(),5452 .reg1 = tmp_reg.to8(),
5496 .flags = flags,
5497 }),5453 }),
5498 .data = undefined,5454 .data = .{ .cc = cc },
5499 });5455 });
55005456
5501 return self.genSetStack(5457 return self.genSetStack(
...@@ -5505,9 +5461,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: Inl...@@ -5505,9 +5461,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: Inl
5505 .{},5461 .{},
5506 );5462 );
5507 },5463 },
5508 .compare_flags_unsigned,5464 .eflags => {
5509 .compare_flags_signed,
5510 => {
5511 const reg = try self.copyToTmpRegister(ty, mcv);5465 const reg = try self.copyToTmpRegister(ty, mcv);
5512 return self.genSetStack(ty, stack_offset, .{ .register = reg }, opts);5466 return self.genSetStack(ty, stack_offset, .{ .register = reg }, opts);
5513 },5467 },
...@@ -5832,9 +5786,12 @@ fn genInlineMemcpy(...@@ -5832,9 +5786,12 @@ fn genInlineMemcpy(
58325786
5833 // je end5787 // je end
5834 const loop_reloc = try self.addInst(.{5788 const loop_reloc = try self.addInst(.{
5835 .tag = .cond_jmp_eq_ne,5789 .tag = .cond_jmp,
5836 .ops = Mir.Inst.Ops.encode(.{ .flags = 0b01 }),5790 .ops = Mir.Inst.Ops.encode(.{}),
5837 .data = .{ .inst = undefined },5791 .data = .{ .inst_cc = .{
5792 .inst = undefined,
5793 .cc = .e,
5794 } },
5838 });5795 });
58395796
5840 // mov tmp, [addr + rcx]5797 // mov tmp, [addr + rcx]
...@@ -5950,9 +5907,12 @@ fn genInlineMemset(...@@ -5950,9 +5907,12 @@ fn genInlineMemset(
59505907
5951 // je end5908 // je end
5952 const loop_reloc = try self.addInst(.{5909 const loop_reloc = try self.addInst(.{
5953 .tag = .cond_jmp_eq_ne,5910 .tag = .cond_jmp,
5954 .ops = Mir.Inst.Ops.encode(.{ .flags = 0b01 }),5911 .ops = Mir.Inst.Ops.encode(.{}),
5955 .data = .{ .inst = undefined },5912 .data = .{ .inst_cc = .{
5913 .inst = undefined,
5914 .cc = .e,
5915 } },
5956 });5916 });
59575917
5958 switch (value) {5918 switch (value) {
...@@ -6025,31 +5985,13 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void...@@ -6025,31 +5985,13 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
6025 else => unreachable,5985 else => unreachable,
6026 }5986 }
6027 },5987 },
6028 .compare_flags_unsigned,5988 .eflags => |cc| {
6029 .compare_flags_signed,
6030 => |op| {
6031 const tag: Mir.Inst.Tag = switch (op) {
6032 .gte, .gt, .lt, .lte => if (mcv == .compare_flags_unsigned)
6033 Mir.Inst.Tag.cond_set_byte_above_below
6034 else
6035 Mir.Inst.Tag.cond_set_byte_greater_less,
6036 .eq, .neq => .cond_set_byte_eq_ne,
6037 };
6038 const flags: u2 = switch (op) {
6039 .gte => 0b00,
6040 .gt => 0b01,
6041 .lt => 0b10,
6042 .lte => 0b11,
6043 .eq => 0b01,
6044 .neq => 0b00,
6045 };
6046 _ = try self.addInst(.{5989 _ = try self.addInst(.{
6047 .tag = tag,5990 .tag = .cond_set_byte,
6048 .ops = Mir.Inst.Ops.encode(.{5991 .ops = Mir.Inst.Ops.encode(.{
6049 .reg1 = reg.to8(),5992 .reg1 = reg.to8(),
6050 .flags = flags,
6051 }),5993 }),
6052 .data = undefined,5994 .data = .{ .cc = cc },
6053 });5995 });
6054 },5996 },
6055 .immediate => |x| {5997 .immediate => |x| {
src/arch/x86_64/Emit.zig+221-75
...@@ -158,20 +158,9 @@ pub fn lowerMir(emit: *Emit) InnerError!void {...@@ -158,20 +158,9 @@ pub fn lowerMir(emit: *Emit) InnerError!void {
158 .jmp => try emit.mirJmpCall(.jmp_near, inst),158 .jmp => try emit.mirJmpCall(.jmp_near, inst),
159 .call => try emit.mirJmpCall(.call_near, inst),159 .call => try emit.mirJmpCall(.call_near, inst),
160160
161 .cond_jmp_greater_less,161 .cond_jmp => try emit.mirCondJmp(inst),
162 .cond_jmp_above_below,162 .cond_set_byte => try emit.mirCondSetByte(inst),
163 .cond_jmp_eq_ne,163 .cond_mov => try emit.mirCondMov(inst),
164 => try emit.mirCondJmp(tag, inst),
165
166 .cond_set_byte_greater_less,
167 .cond_set_byte_above_below,
168 .cond_set_byte_eq_ne,
169 .cond_set_byte_overflow,
170 => try emit.mirCondSetByte(tag, inst),
171
172 .cond_mov_eq => try emit.mirCondMov(.cmove, inst),
173 .cond_mov_lt => try emit.mirCondMov(.cmovl, inst),
174 .cond_mov_below => try emit.mirCondMov(.cmovb, inst),
175164
176 .ret => try emit.mirRet(inst),165 .ret => try emit.mirRet(inst),
177166
...@@ -356,70 +345,130 @@ fn mirJmpCall(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {...@@ -356,70 +345,130 @@ fn mirJmpCall(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {
356 }345 }
357}346}
358347
359fn mirCondJmp(emit: *Emit, mir_tag: Mir.Inst.Tag, inst: Mir.Inst.Index) InnerError!void {348fn mirCondJmp(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
360 const ops = emit.mir.instructions.items(.ops)[inst].decode();349 const mir_tag = emit.mir.instructions.items(.tag)[inst];
361 const target = emit.mir.instructions.items(.data)[inst].inst;350 assert(mir_tag == .cond_jmp);
362 const tag = switch (mir_tag) {351 const inst_cc = emit.mir.instructions.items(.data)[inst].inst_cc;
363 .cond_jmp_greater_less => switch (ops.flags) {352 const tag: Tag = switch (inst_cc.cc) {
364 0b00 => Tag.jge,353 .a => .ja,
365 0b01 => Tag.jg,354 .ae => .jae,
366 0b10 => Tag.jl,355 .b => .jb,
367 0b11 => Tag.jle,356 .be => .jbe,
368 },357 .c => .jc,
369 .cond_jmp_above_below => switch (ops.flags) {358 .e => .je,
370 0b00 => Tag.jae,359 .g => .jg,
371 0b01 => Tag.ja,360 .ge => .jge,
372 0b10 => Tag.jb,361 .l => .jl,
373 0b11 => Tag.jbe,362 .le => .jle,
374 },363 .na => .jna,
375 .cond_jmp_eq_ne => switch (@truncate(u1, ops.flags)) {364 .nae => .jnae,
376 0b0 => Tag.jne,365 .nb => .jnb,
377 0b1 => Tag.je,366 .nbe => .jnbe,
378 },367 .nc => .jnc,
379 else => unreachable,368 .ne => .jne,
369 .ng => .jng,
370 .nge => .jnge,
371 .nl => .jnl,
372 .nle => .jnle,
373 .no => .jno,
374 .np => .jnp,
375 .ns => .jns,
376 .nz => .jnz,
377 .o => .jo,
378 .p => .jp,
379 .pe => .jpe,
380 .po => .jpo,
381 .s => .js,
382 .z => .jz,
380 };383 };
381 const source = emit.code.items.len;384 const source = emit.code.items.len;
382 try lowerToDEnc(tag, 0, emit.code);385 try lowerToDEnc(tag, 0, emit.code);
383 try emit.relocs.append(emit.bin_file.allocator, .{386 try emit.relocs.append(emit.bin_file.allocator, .{
384 .source = source,387 .source = source,
385 .target = target,388 .target = inst_cc.inst,
386 .offset = emit.code.items.len - 4,389 .offset = emit.code.items.len - 4,
387 .length = 6,390 .length = 6,
388 });391 });
389}392}
390393
391fn mirCondSetByte(emit: *Emit, mir_tag: Mir.Inst.Tag, inst: Mir.Inst.Index) InnerError!void {394fn mirCondSetByte(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
395 const mir_tag = emit.mir.instructions.items(.tag)[inst];
396 assert(mir_tag == .cond_set_byte);
392 const ops = emit.mir.instructions.items(.ops)[inst].decode();397 const ops = emit.mir.instructions.items(.ops)[inst].decode();
393 const tag = switch (mir_tag) {398 const cc = emit.mir.instructions.items(.data)[inst].cc;
394 .cond_set_byte_greater_less => switch (ops.flags) {399 const tag: Tag = switch (cc) {
395 0b00 => Tag.setge,400 .a => .seta,
396 0b01 => Tag.setg,401 .ae => .setae,
397 0b10 => Tag.setl,402 .b => .setb,
398 0b11 => Tag.setle,403 .be => .setbe,
399 },404 .c => .setc,
400 .cond_set_byte_above_below => switch (ops.flags) {405 .e => .sete,
401 0b00 => Tag.setae,406 .g => .setg,
402 0b01 => Tag.seta,407 .ge => .setge,
403 0b10 => Tag.setb,408 .l => .setl,
404 0b11 => Tag.setbe,409 .le => .setle,
405 },410 .na => .setna,
406 .cond_set_byte_eq_ne => switch (@truncate(u1, ops.flags)) {411 .nae => .setnae,
407 0b0 => Tag.setne,412 .nb => .setnb,
408 0b1 => Tag.sete,413 .nbe => .setnbe,
409 },414 .nc => .setnc,
410 .cond_set_byte_overflow => switch (ops.flags) {415 .ne => .setne,
411 0b00 => Tag.seto,416 .ng => .setng,
412 0b01 => Tag.setno,417 .nge => .setnge,
413 0b10 => Tag.setc,418 .nl => .setnl,
414 0b11 => Tag.setnc,419 .nle => .setnle,
415 },420 .no => .setno,
416 else => unreachable,421 .np => .setnp,
422 .ns => .setns,
423 .nz => .setnz,
424 .o => .seto,
425 .p => .setp,
426 .pe => .setpe,
427 .po => .setpo,
428 .s => .sets,
429 .z => .setz,
417 };430 };
418 return lowerToMEnc(tag, RegisterOrMemory.reg(ops.reg1.to8()), emit.code);431 return lowerToMEnc(tag, RegisterOrMemory.reg(ops.reg1.to8()), emit.code);
419}432}
420433
421fn mirCondMov(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {434fn mirCondMov(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
435 const mir_tag = emit.mir.instructions.items(.tag)[inst];
436 assert(mir_tag == .cond_mov);
422 const ops = emit.mir.instructions.items(.ops)[inst].decode();437 const ops = emit.mir.instructions.items(.ops)[inst].decode();
438 const cc = emit.mir.instructions.items(.data)[inst].cc;
439 const tag: Tag = switch (cc) {
440 .a => .cmova,
441 .ae => .cmovae,
442 .b => .cmovb,
443 .be => .cmovbe,
444 .c => .cmovc,
445 .e => .cmove,
446 .g => .cmovg,
447 .ge => .cmovge,
448 .l => .cmovl,
449 .le => .cmovle,
450 .na => .cmovna,
451 .nae => .cmovnae,
452 .nb => .cmovnb,
453 .nbe => .cmovnbe,
454 .nc => .cmovnc,
455 .ne => .cmovne,
456 .ng => .cmovng,
457 .nge => .cmovnge,
458 .nl => .cmovnl,
459 .nle => .cmovnle,
460 .no => .cmovno,
461 .np => .cmovnp,
462 .ns => .cmovns,
463 .nz => .cmovnz,
464 .o => .cmovo,
465 .p => .cmovp,
466 .pe => .cmovpe,
467 .po => .cmovpo,
468 .s => .cmovs,
469 .z => .cmovz,
470 };
471
423 if (ops.flags == 0b00) {472 if (ops.flags == 0b00) {
424 return lowerToRmEnc(tag, ops.reg1, RegisterOrMemory.reg(ops.reg2), emit.code);473 return lowerToRmEnc(tag, ops.reg1, RegisterOrMemory.reg(ops.reg2), emit.code);
425 }474 }
...@@ -1277,7 +1326,7 @@ const Tag = enum {...@@ -1277,7 +1326,7 @@ const Tag = enum {
1277 setp,1326 setp,
1278 setpe,1327 setpe,
1279 setnp,1328 setnp,
1280 setop,1329 setpo,
1281 setl,1330 setl,
1282 setnge,1331 setnge,
1283 setnl,1332 setnl,
...@@ -1286,6 +1335,36 @@ const Tag = enum {...@@ -1286,6 +1335,36 @@ const Tag = enum {
1286 setng,1335 setng,
1287 setnle,1336 setnle,
1288 setg,1337 setg,
1338 cmovo,
1339 cmovno,
1340 cmovb,
1341 cmovc,
1342 cmovnae,
1343 cmovnb,
1344 cmovnc,
1345 cmovae,
1346 cmove,
1347 cmovz,
1348 cmovne,
1349 cmovnz,
1350 cmovbe,
1351 cmovna,
1352 cmova,
1353 cmovnbe,
1354 cmovs,
1355 cmovns,
1356 cmovp,
1357 cmovpe,
1358 cmovnp,
1359 cmovpo,
1360 cmovl,
1361 cmovnge,
1362 cmovnl,
1363 cmovge,
1364 cmovle,
1365 cmovng,
1366 cmovnle,
1367 cmovg,
1289 shl,1368 shl,
1290 sal,1369 sal,
1291 shr,1370 shr,
...@@ -1294,12 +1373,6 @@ const Tag = enum {...@@ -1294,12 +1373,6 @@ const Tag = enum {
1294 cwd,1373 cwd,
1295 cdq,1374 cdq,
1296 cqo,1375 cqo,
1297 cmove,
1298 cmovz,
1299 cmovl,
1300 cmovng,
1301 cmovb,
1302 cmovnae,
1303 movsd,1376 movsd,
1304 movss,1377 movss,
1305 addsd,1378 addsd,
...@@ -1372,7 +1445,7 @@ const Tag = enum {...@@ -1372,7 +1445,7 @@ const Tag = enum {
1372 .setp,1445 .setp,
1373 .setpe,1446 .setpe,
1374 .setnp,1447 .setnp,
1375 .setop,1448 .setpo,
1376 .setl,1449 .setl,
1377 .setnge,1450 .setnge,
1378 .setnl,1451 .setnl,
...@@ -1492,77 +1565,110 @@ inline fn getOpCode(tag: Tag, enc: Encoding, is_one_byte: bool) OpCode {...@@ -1492,77 +1565,110 @@ inline fn getOpCode(tag: Tag, enc: Encoding, is_one_byte: bool) OpCode {
1492 .d => return switch (tag) {1565 .d => return switch (tag) {
1493 .jmp_near => OpCode.init(&.{0xe9}),1566 .jmp_near => OpCode.init(&.{0xe9}),
1494 .call_near => OpCode.init(&.{0xe8}),1567 .call_near => OpCode.init(&.{0xe8}),
1568
1495 .jo => if (is_one_byte) OpCode.init(&.{0x70}) else OpCode.init(&.{0x0f,0x80}),1569 .jo => if (is_one_byte) OpCode.init(&.{0x70}) else OpCode.init(&.{0x0f,0x80}),
1570
1496 .jno => if (is_one_byte) OpCode.init(&.{0x71}) else OpCode.init(&.{0x0f,0x81}),1571 .jno => if (is_one_byte) OpCode.init(&.{0x71}) else OpCode.init(&.{0x0f,0x81}),
1572
1497 .jb,1573 .jb,
1498 .jc,1574 .jc,
1499 .jnae => if (is_one_byte) OpCode.init(&.{0x72}) else OpCode.init(&.{0x0f,0x82}),1575 .jnae => if (is_one_byte) OpCode.init(&.{0x72}) else OpCode.init(&.{0x0f,0x82}),
1576
1500 .jnb,1577 .jnb,
1501 .jnc, 1578 .jnc,
1502 .jae => if (is_one_byte) OpCode.init(&.{0x73}) else OpCode.init(&.{0x0f,0x83}),1579 .jae => if (is_one_byte) OpCode.init(&.{0x73}) else OpCode.init(&.{0x0f,0x83}),
1580
1503 .je, 1581 .je,
1504 .jz => if (is_one_byte) OpCode.init(&.{0x74}) else OpCode.init(&.{0x0f,0x84}),1582 .jz => if (is_one_byte) OpCode.init(&.{0x74}) else OpCode.init(&.{0x0f,0x84}),
1583
1505 .jne, 1584 .jne,
1506 .jnz => if (is_one_byte) OpCode.init(&.{0x75}) else OpCode.init(&.{0x0f,0x85}),1585 .jnz => if (is_one_byte) OpCode.init(&.{0x75}) else OpCode.init(&.{0x0f,0x85}),
1586
1507 .jna, 1587 .jna,
1508 .jbe => if (is_one_byte) OpCode.init(&.{0x76}) else OpCode.init(&.{0x0f,0x86}),1588 .jbe => if (is_one_byte) OpCode.init(&.{0x76}) else OpCode.init(&.{0x0f,0x86}),
1589
1509 .jnbe, 1590 .jnbe,
1510 .ja => if (is_one_byte) OpCode.init(&.{0x77}) else OpCode.init(&.{0x0f,0x87}),1591 .ja => if (is_one_byte) OpCode.init(&.{0x77}) else OpCode.init(&.{0x0f,0x87}),
1592
1511 .js => if (is_one_byte) OpCode.init(&.{0x78}) else OpCode.init(&.{0x0f,0x88}),1593 .js => if (is_one_byte) OpCode.init(&.{0x78}) else OpCode.init(&.{0x0f,0x88}),
1594
1512 .jns => if (is_one_byte) OpCode.init(&.{0x79}) else OpCode.init(&.{0x0f,0x89}),1595 .jns => if (is_one_byte) OpCode.init(&.{0x79}) else OpCode.init(&.{0x0f,0x89}),
1596
1513 .jpe, 1597 .jpe,
1514 .jp => if (is_one_byte) OpCode.init(&.{0x7a}) else OpCode.init(&.{0x0f,0x8a}),1598 .jp => if (is_one_byte) OpCode.init(&.{0x7a}) else OpCode.init(&.{0x0f,0x8a}),
1599
1515 .jpo, 1600 .jpo,
1516 .jnp => if (is_one_byte) OpCode.init(&.{0x7b}) else OpCode.init(&.{0x0f,0x8b}),1601 .jnp => if (is_one_byte) OpCode.init(&.{0x7b}) else OpCode.init(&.{0x0f,0x8b}),
1602
1517 .jnge, 1603 .jnge,
1518 .jl => if (is_one_byte) OpCode.init(&.{0x7c}) else OpCode.init(&.{0x0f,0x8c}),1604 .jl => if (is_one_byte) OpCode.init(&.{0x7c}) else OpCode.init(&.{0x0f,0x8c}),
1605
1519 .jge, 1606 .jge,
1520 .jnl => if (is_one_byte) OpCode.init(&.{0x7d}) else OpCode.init(&.{0x0f,0x8d}),1607 .jnl => if (is_one_byte) OpCode.init(&.{0x7d}) else OpCode.init(&.{0x0f,0x8d}),
1608
1521 .jle, 1609 .jle,
1522 .jng => if (is_one_byte) OpCode.init(&.{0x7e}) else OpCode.init(&.{0x0f,0x8e}),1610 .jng => if (is_one_byte) OpCode.init(&.{0x7e}) else OpCode.init(&.{0x0f,0x8e}),
1611
1523 .jg, 1612 .jg,
1524 .jnle => if (is_one_byte) OpCode.init(&.{0x7f}) else OpCode.init(&.{0x0f,0x8f}),1613 .jnle => if (is_one_byte) OpCode.init(&.{0x7f}) else OpCode.init(&.{0x0f,0x8f}),
1614
1525 else => unreachable,1615 else => unreachable,
1526 },1616 },
1527 .m => return switch (tag) {1617 .m => return switch (tag) {
1528 .jmp_near,1618 .jmp_near,
1529 .call_near,1619 .call_near,
1530 .push => OpCode.init(&.{0xff}),1620 .push => OpCode.init(&.{0xff}),
1621
1531 .pop => OpCode.init(&.{0x8f}),1622 .pop => OpCode.init(&.{0x8f}),
1532 .seto => OpCode.init(&.{0x0f,0x90}),1623 .seto => OpCode.init(&.{0x0f,0x90}),
1533 .setno => OpCode.init(&.{0x0f,0x91}),1624 .setno => OpCode.init(&.{0x0f,0x91}),
1625
1534 .setb,1626 .setb,
1535 .setc,1627 .setc,
1536 .setnae => OpCode.init(&.{0x0f,0x92}),1628 .setnae => OpCode.init(&.{0x0f,0x92}),
1629
1537 .setnb,1630 .setnb,
1538 .setnc,1631 .setnc,
1539 .setae => OpCode.init(&.{0x0f,0x93}),1632 .setae => OpCode.init(&.{0x0f,0x93}),
1633
1540 .sete,1634 .sete,
1541 .setz => OpCode.init(&.{0x0f,0x94}),1635 .setz => OpCode.init(&.{0x0f,0x94}),
1636
1542 .setne,1637 .setne,
1543 .setnz => OpCode.init(&.{0x0f,0x95}),1638 .setnz => OpCode.init(&.{0x0f,0x95}),
1639
1544 .setbe,1640 .setbe,
1545 .setna => OpCode.init(&.{0x0f,0x96}),1641 .setna => OpCode.init(&.{0x0f,0x96}),
1642
1546 .seta,1643 .seta,
1547 .setnbe => OpCode.init(&.{0x0f,0x97}),1644 .setnbe => OpCode.init(&.{0x0f,0x97}),
1645
1548 .sets => OpCode.init(&.{0x0f,0x98}),1646 .sets => OpCode.init(&.{0x0f,0x98}),
1549 .setns => OpCode.init(&.{0x0f,0x99}),1647 .setns => OpCode.init(&.{0x0f,0x99}),
1648
1550 .setp,1649 .setp,
1551 .setpe => OpCode.init(&.{0x0f,0x9a}),1650 .setpe => OpCode.init(&.{0x0f,0x9a}),
1651
1552 .setnp, 1652 .setnp,
1553 .setop => OpCode.init(&.{0x0f,0x9b}),1653 .setpo => OpCode.init(&.{0x0f,0x9b}),
1654
1554 .setl, 1655 .setl,
1555 .setnge => OpCode.init(&.{0x0f,0x9c}),1656 .setnge => OpCode.init(&.{0x0f,0x9c}),
1657
1556 .setnl,1658 .setnl,
1557 .setge => OpCode.init(&.{0x0f,0x9d}),1659 .setge => OpCode.init(&.{0x0f,0x9d}),
1660
1558 .setle,1661 .setle,
1559 .setng => OpCode.init(&.{0x0f,0x9e}),1662 .setng => OpCode.init(&.{0x0f,0x9e}),
1663
1560 .setnle,1664 .setnle,
1561 .setg => OpCode.init(&.{0x0f,0x9f}),1665 .setg => OpCode.init(&.{0x0f,0x9f}),
1666
1562 .idiv,1667 .idiv,
1563 .div,1668 .div,
1564 .imul,1669 .imul,
1565 .mul => if (is_one_byte) OpCode.init(&.{0xf6}) else OpCode.init(&.{0xf7}),1670 .mul => if (is_one_byte) OpCode.init(&.{0xf6}) else OpCode.init(&.{0xf7}),
1671
1566 .fisttp16 => OpCode.init(&.{0xdf}),1672 .fisttp16 => OpCode.init(&.{0xdf}),
1567 .fisttp32 => OpCode.init(&.{0xdb}),1673 .fisttp32 => OpCode.init(&.{0xdb}),
1568 .fisttp64 => OpCode.init(&.{0xdd}),1674 .fisttp64 => OpCode.init(&.{0xdd}),
...@@ -1640,12 +1746,52 @@ inline fn getOpCode(tag: Tag, enc: Encoding, is_one_byte: bool) OpCode {...@@ -1640,12 +1746,52 @@ inline fn getOpCode(tag: Tag, enc: Encoding, is_one_byte: bool) OpCode {
1640 .movzx => if (is_one_byte) OpCode.init(&.{0x0f,0xb6}) else OpCode.init(&.{0x0f,0xb7}),1746 .movzx => if (is_one_byte) OpCode.init(&.{0x0f,0xb6}) else OpCode.init(&.{0x0f,0xb7}),
1641 .lea => if (is_one_byte) OpCode.init(&.{0x8c}) else OpCode.init(&.{0x8d}),1747 .lea => if (is_one_byte) OpCode.init(&.{0x8c}) else OpCode.init(&.{0x8d}),
1642 .imul => OpCode.init(&.{0x0f,0xaf}),1748 .imul => OpCode.init(&.{0x0f,0xaf}),
1643 .cmove, 1749
1644 .cmovz => OpCode.init(&.{0x0f,0x44}),1750 .cmova,
1751 .cmovnbe, => OpCode.init(&.{0x0f,0x47}),
1752
1753 .cmovae,
1754 .cmovnb, => OpCode.init(&.{0x0f,0x43}),
1755
1645 .cmovb,1756 .cmovb,
1757 .cmovc,
1646 .cmovnae => OpCode.init(&.{0x0f,0x42}),1758 .cmovnae => OpCode.init(&.{0x0f,0x42}),
1759
1760 .cmovbe,
1761 .cmovna, => OpCode.init(&.{0x0f,0x46}),
1762
1763 .cmove,
1764 .cmovz, => OpCode.init(&.{0x0f,0x44}),
1765
1766 .cmovg,
1767 .cmovnle, => OpCode.init(&.{0x0f,0x4f}),
1768
1769 .cmovge,
1770 .cmovnl, => OpCode.init(&.{0x0f,0x4d}),
1771
1647 .cmovl,1772 .cmovl,
1648 .cmovng => OpCode.init(&.{0x0f,0x4c}),1773 .cmovnge, => OpCode.init(&.{0x0f,0x4c}),
1774
1775 .cmovle,
1776 .cmovng, => OpCode.init(&.{0x0f,0x4e}),
1777
1778 .cmovne,
1779 .cmovnz, => OpCode.init(&.{0x0f,0x45}),
1780
1781 .cmovno => OpCode.init(&.{0x0f,0x41}),
1782
1783 .cmovnp,
1784 .cmovpo, => OpCode.init(&.{0x0f,0x4b}),
1785
1786 .cmovns => OpCode.init(&.{0x0f,0x49}),
1787
1788 .cmovo => OpCode.init(&.{0x0f,0x40}),
1789
1790 .cmovp,
1791 .cmovpe, => OpCode.init(&.{0x0f,0x4a}),
1792
1793 .cmovs => OpCode.init(&.{0x0f,0x48}),
1794
1649 .movsd => OpCode.init(&.{0xf2,0x0f,0x10}),1795 .movsd => OpCode.init(&.{0xf2,0x0f,0x10}),
1650 .movss => OpCode.init(&.{0xf3,0x0f,0x10}),1796 .movss => OpCode.init(&.{0xf3,0x0f,0x10}),
1651 .addsd => OpCode.init(&.{0xf2,0x0f,0x58}),1797 .addsd => OpCode.init(&.{0xf2,0x0f,0x58}),
...@@ -1735,7 +1881,7 @@ inline fn getModRmExt(tag: Tag) u3 {...@@ -1735,7 +1881,7 @@ inline fn getModRmExt(tag: Tag) u3 {
1735 .setp,1881 .setp,
1736 .setpe,1882 .setpe,
1737 .setnp,1883 .setnp,
1738 .setop,1884 .setpo,
1739 .setl,1885 .setl,
1740 .setnge,1886 .setnge,
1741 .setnl,1887 .setnl,
src/arch/x86_64/Mir.zig+21-28
...@@ -275,42 +275,25 @@ pub const Inst = struct {...@@ -275,42 +275,25 @@ pub const Inst = struct {
275 call,275 call,
276276
277 /// ops flags:277 /// ops flags:
278 /// 0b00 gte278 /// unused
279 /// 0b01 gt279 /// Notes:
280 /// 0b10 lt280 /// * uses `inst_cc` in Data.
281 /// 0b11 lte281 cond_jmp,
282 cond_jmp_greater_less,
283 cond_set_byte_greater_less,
284
285 /// ops flags:
286 /// 0b00 above or equal
287 /// 0b01 above
288 /// 0b10 below
289 /// 0b11 below or equal
290 cond_jmp_above_below,
291 cond_set_byte_above_below,
292282
293 /// ops flags:283 /// ops flags:
294 /// 0bX0 ne284 /// 0b00 reg1
295 /// 0bX1 eq285 /// Notes:
296 cond_jmp_eq_ne,286 /// * uses condition code (CC) stored as part of data
297 cond_set_byte_eq_ne,287 cond_set_byte,
298288
299 /// ops flags:289 /// ops flags:
300 /// 0b00 reg1, reg2,290 /// 0b00 reg1, reg2,
301 /// 0b01 reg1, word ptr [reg2 + imm]291 /// 0b01 reg1, word ptr [reg2 + imm]
302 /// 0b10 reg1, dword ptr [reg2 + imm]292 /// 0b10 reg1, dword ptr [reg2 + imm]
303 /// 0b11 reg1, qword ptr [reg2 + imm]293 /// 0b11 reg1, qword ptr [reg2 + imm]
304 cond_mov_eq,294 /// Notes:
305 cond_mov_lt,295 /// * uses condition code (CC) stored as part of data
306 cond_mov_below,296 cond_mov,
307
308 /// ops flags:
309 /// 0b00 reg1 if OF = 1
310 /// 0b01 reg1 if OF = 0
311 /// 0b10 reg1 if CF = 1
312 /// 0b11 reg1 if CF = 0
313 cond_set_byte_overflow,
314297
315 /// ops flags: form:298 /// ops flags: form:
316 /// 0b00 reg1299 /// 0b00 reg1
...@@ -451,6 +434,16 @@ pub const Inst = struct {...@@ -451,6 +434,16 @@ pub const Inst = struct {
451 inst: Index,434 inst: Index,
452 /// A 32-bit immediate value.435 /// A 32-bit immediate value.
453 imm: u32,436 imm: u32,
437 /// A condition code for use with EFLAGS register.
438 cc: bits.Condition,
439 /// Another instruction with condition code.
440 /// Used by `cond_jmp`.
441 inst_cc: struct {
442 /// Another instruction.
443 inst: Index,
444 /// A condition code for use with EFLAGS register.
445 cc: bits.Condition,
446 },
454 /// An extern function.447 /// An extern function.
455 extern_fn: struct {448 extern_fn: struct {
456 /// Index of the containing atom.449 /// Index of the containing atom.
src/arch/x86_64/bits.zig+129
...@@ -6,6 +6,135 @@ const ArrayList = std.ArrayList;...@@ -6,6 +6,135 @@ const ArrayList = std.ArrayList;
6const Allocator = std.mem.Allocator;6const Allocator = std.mem.Allocator;
7const DW = std.dwarf;7const DW = std.dwarf;
88
9/// EFLAGS condition codes
10pub const Condition = enum(u5) {
11 /// above
12 a,
13 /// above or equal
14 ae,
15 /// below
16 b,
17 /// below or equal
18 be,
19 /// carry
20 c,
21 /// equal
22 e,
23 /// greater
24 g,
25 /// greater or equal
26 ge,
27 /// less
28 l,
29 /// less or equal
30 le,
31 /// not above
32 na,
33 /// not above or equal
34 nae,
35 /// not below
36 nb,
37 /// not below or equal
38 nbe,
39 /// not carry
40 nc,
41 /// not equal
42 ne,
43 /// not greater
44 ng,
45 /// not greater or equal
46 nge,
47 /// not less
48 nl,
49 /// not less or equal
50 nle,
51 /// not overflow
52 no,
53 /// not parity
54 np,
55 /// not sign
56 ns,
57 /// not zero
58 nz,
59 /// overflow
60 o,
61 /// parity
62 p,
63 /// parity even
64 pe,
65 /// parity odd
66 po,
67 /// sign
68 s,
69 /// zero
70 z,
71
72 /// Converts a std.math.CompareOperator into a condition flag,
73 /// i.e. returns the condition that is true iff the result of the
74 /// comparison is true. Assumes signed comparison
75 pub fn fromCompareOperatorSigned(op: std.math.CompareOperator) Condition {
76 return switch (op) {
77 .gte => .ge,
78 .gt => .g,
79 .neq => .ne,
80 .lt => .l,
81 .lte => .le,
82 .eq => .e,
83 };
84 }
85
86 /// Converts a std.math.CompareOperator into a condition flag,
87 /// i.e. returns the condition that is true iff the result of the
88 /// comparison is true. Assumes unsigned comparison
89 pub fn fromCompareOperatorUnsigned(op: std.math.CompareOperator) Condition {
90 return switch (op) {
91 .gte => .ae,
92 .gt => .a,
93 .neq => .ne,
94 .lt => .b,
95 .lte => .be,
96 .eq => .e,
97 };
98 }
99
100 /// Returns the condition which is true iff the given condition is
101 /// false (if such a condition exists)
102 pub fn negate(cond: Condition) Condition {
103 return switch (cond) {
104 .a => .na,
105 .ae => .nae,
106 .b => .nb,
107 .be => .nbe,
108 .c => .nc,
109 .e => .ne,
110 .g => .ng,
111 .ge => .nge,
112 .l => .nl,
113 .le => .nle,
114 .na => .a,
115 .nae => .ae,
116 .nb => .b,
117 .nbe => .be,
118 .nc => .c,
119 .ne => .e,
120 .ng => .g,
121 .nge => .ge,
122 .nl => .l,
123 .nle => .le,
124 .no => .o,
125 .np => .p,
126 .ns => .s,
127 .nz => .z,
128 .o => .no,
129 .p => .np,
130 .pe => unreachable,
131 .po => unreachable,
132 .s => .ns,
133 .z => .nz,
134 };
135 }
136};
137
9// zig fmt: off138// zig fmt: off
10139
11/// Definitions of all of the general purpose x64 registers. The order is semantically meaningful.140/// Definitions of all of the general purpose x64 registers. The order is semantically meaningful.