authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-05-25 20:33:43+02:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2022-05-25 20:33:43+02:00
log39ebfedd2bea7ebb8630f8593ae59538969bfea7
treeeb11df8c0125d4afd99fd4ecf43ac3f1ce13e9d6
parente0be22b6c06530d56308853723f982c492e768fd
parent7000395a7d002a6d242d717de60614516f4e29af
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #11715 from ziglang/stage2-x64-cond-codes


4 files changed, 552 insertions(+), 369 deletions(-)

src/arch/x86_64/CodeGen.zig+181-266
...@@ -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) = .{},
...@@ -127,12 +128,8 @@ pub const MCValue = union(enum) {...@@ -127,12 +128,8 @@ pub const MCValue = union(enum) {
127 immediate: u64,128 immediate: u64,
128 /// The value is in a GP register.129 /// The value is in a GP register.
129 register: Register,130 register: Register,
130 /// The value is a tuple { wrapped, overflow } where wrapped value is stored in the GP register,131 /// The value is a tuple { wrapped, overflow } where wrapped value is stored in the GP register.
131 /// and the operation is an unsigned operation.132 register_overflow: struct { reg: Register, eflags: Condition },
132 register_overflow_unsigned: Register,
133 /// The value is a tuple { wrapped, overflow } where wrapped value is stored in the GP register,
134 /// and the operation is a signed operation.
135 register_overflow_signed: Register,
136 /// The value is in memory at a hard-coded address.133 /// The value is in memory at a hard-coded address.
137 /// If the type is a pointer, it means the pointer address is at this memory location.134 /// If the type is a pointer, it means the pointer address is at this memory location.
138 memory: u64,135 memory: u64,
...@@ -149,12 +146,8 @@ pub const MCValue = union(enum) {...@@ -149,12 +146,8 @@ pub const MCValue = union(enum) {
149 stack_offset: i32,146 stack_offset: i32,
150 /// The value is a pointer to one of the stack variables (payload is stack offset).147 /// The value is a pointer to one of the stack variables (payload is stack offset).
151 ptr_stack_offset: i32,148 ptr_stack_offset: i32,
152 /// The value is in the compare flags assuming an unsigned operation,149 /// The value resides in the EFLAGS register.
153 /// with this operator applied on top of it.150 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,
158151
159 fn isMemory(mcv: MCValue) bool {152 fn isMemory(mcv: MCValue) bool {
160 return switch (mcv) {153 return switch (mcv) {
...@@ -183,12 +176,10 @@ pub const MCValue = union(enum) {...@@ -183,12 +176,10 @@ pub const MCValue = union(enum) {
183176
184 .immediate,177 .immediate,
185 .memory,178 .memory,
186 .compare_flags_unsigned,179 .eflags,
187 .compare_flags_signed,
188 .ptr_stack_offset,180 .ptr_stack_offset,
189 .undef,181 .undef,
190 .register_overflow_unsigned,182 .register_overflow,
191 .register_overflow_signed,
192 => false,183 => false,
193184
194 .register,185 .register,
...@@ -778,12 +769,12 @@ fn processDeath(self: *Self, inst: Air.Inst.Index) void {...@@ -778,12 +769,12 @@ fn processDeath(self: *Self, inst: Air.Inst.Index) void {
778 .register => |reg| {769 .register => |reg| {
779 self.register_manager.freeReg(reg.to64());770 self.register_manager.freeReg(reg.to64());
780 },771 },
781 .register_overflow_signed, .register_overflow_unsigned => |reg| {772 .register_overflow => |ro| {
782 self.register_manager.freeReg(reg.to64());773 self.register_manager.freeReg(ro.reg.to64());
783 self.compare_flags_inst = null;774 self.eflags_inst = null;
784 },775 },
785 .compare_flags_signed, .compare_flags_unsigned => {776 .eflags => {
786 self.compare_flags_inst = null;777 self.eflags_inst = null;
787 },778 },
788 else => {}, // TODO process stack allocation death779 else => {}, // TODO process stack allocation death
789 }780 }
...@@ -813,20 +804,22 @@ fn finishAir(self: *Self, inst: Air.Inst.Index, result: MCValue, operands: [Live...@@ -813,20 +804,22 @@ fn finishAir(self: *Self, inst: Air.Inst.Index, result: MCValue, operands: [Live
813 const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];804 const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];
814 branch.inst_table.putAssumeCapacityNoClobber(inst, result);805 branch.inst_table.putAssumeCapacityNoClobber(inst, result);
815806
807 // In some cases (such as bitcast), an operand
808 // may be the same MCValue as the result. If
809 // that operand died and was a register, it
810 // was freed by processDeath. We have to
811 // "re-allocate" the register.
816 switch (result) {812 switch (result) {
817 .register,813 .register => |reg| {
818 .register_overflow_signed,
819 .register_overflow_unsigned,
820 => |reg| {
821 // In some cases (such as bitcast), an operand
822 // may be the same MCValue as the result. If
823 // that operand died and was a register, it
824 // was freed by processDeath. We have to
825 // "re-allocate" the register.
826 if (self.register_manager.isRegFree(reg)) {814 if (self.register_manager.isRegFree(reg)) {
827 self.register_manager.getRegAssumeFree(reg, inst);815 self.register_manager.getRegAssumeFree(reg, inst);
828 }816 }
829 },817 },
818 .register_overflow => |ro| {
819 if (self.register_manager.isRegFree(ro.reg)) {
820 self.register_manager.getRegAssumeFree(ro.reg, inst);
821 }
822 },
830 else => {},823 else => {},
831 }824 }
832 }825 }
...@@ -916,12 +909,12 @@ pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void...@@ -916,12 +909,12 @@ pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void
916 log.debug("spilling {d} to stack mcv {any}", .{ inst, stack_mcv });909 log.debug("spilling {d} to stack mcv {any}", .{ inst, stack_mcv });
917 const reg_mcv = self.getResolvedInstValue(inst);910 const reg_mcv = self.getResolvedInstValue(inst);
918 switch (reg_mcv) {911 switch (reg_mcv) {
919 .register,912 .register => |other| {
920 .register_overflow_unsigned,
921 .register_overflow_signed,
922 => |other| {
923 assert(reg.to64() == other.to64());913 assert(reg.to64() == other.to64());
924 },914 },
915 .register_overflow => |ro| {
916 assert(reg.to64() == ro.reg.to64());
917 },
925 else => {},918 else => {},
926 }919 }
927 const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];920 const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];
...@@ -929,16 +922,12 @@ pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void...@@ -929,16 +922,12 @@ 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, .{});922 try self.genSetStack(self.air.typeOfIndex(inst), stack_mcv.stack_offset, reg_mcv, .{});
930}923}
931924
932pub fn spillCompareFlagsIfOccupied(self: *Self) !void {925pub fn spillEflagsIfOccupied(self: *Self) !void {
933 if (self.compare_flags_inst) |inst_to_save| {926 if (self.eflags_inst) |inst_to_save| {
934 const mcv = self.getResolvedInstValue(inst_to_save);927 const mcv = self.getResolvedInstValue(inst_to_save);
935 const new_mcv = switch (mcv) {928 const new_mcv = switch (mcv) {
936 .register_overflow_signed,929 .register_overflow => try self.allocRegOrMem(inst_to_save, false),
937 .register_overflow_unsigned,930 .eflags => try self.allocRegOrMem(inst_to_save, true),
938 => try self.allocRegOrMem(inst_to_save, false),
939 .compare_flags_signed,
940 .compare_flags_unsigned,
941 => try self.allocRegOrMem(inst_to_save, true),
942 else => unreachable,931 else => unreachable,
943 };932 };
944933
...@@ -948,14 +937,12 @@ pub fn spillCompareFlagsIfOccupied(self: *Self) !void {...@@ -948,14 +937,12 @@ pub fn spillCompareFlagsIfOccupied(self: *Self) !void {
948 const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];937 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);938 try branch.inst_table.put(self.gpa, inst_to_save, new_mcv);
950939
951 self.compare_flags_inst = null;940 self.eflags_inst = null;
952941
953 // TODO consolidate with register manager and spillInstruction942 // TODO consolidate with register manager and spillInstruction
954 // this call should really belong in the register manager!943 // this call should really belong in the register manager!
955 switch (mcv) {944 switch (mcv) {
956 .register_overflow_signed,945 .register_overflow => |ro| self.register_manager.freeReg(ro.reg),
957 .register_overflow_unsigned,
958 => |reg| self.register_manager.freeReg(reg),
959 else => {},946 else => {},
960 }947 }
961 }948 }
...@@ -1123,31 +1110,8 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void {...@@ -1123,31 +1110,8 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void {
1123 switch (operand) {1110 switch (operand) {
1124 .dead => unreachable,1111 .dead => unreachable,
1125 .unreach => unreachable,1112 .unreach => unreachable,
1126 .compare_flags_unsigned => |op| {1113 .eflags => |cc| {
1127 const r = MCValue{1114 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 },1115 },
1152 else => {},1116 else => {},
1153 }1117 }
...@@ -1213,13 +1177,17 @@ fn airMin(self: *Self, inst: Air.Inst.Index) !void {...@@ -1213,13 +1177,17 @@ fn airMin(self: *Self, inst: Air.Inst.Index) !void {
1213 try self.genBinOpMir(.cmp, ty, .{ .register = lhs_reg }, rhs_mcv);1177 try self.genBinOpMir(.cmp, ty, .{ .register = lhs_reg }, rhs_mcv);
12141178
1215 const dst_mcv = try self.copyToRegisterWithInstTracking(inst, ty, rhs_mcv);1179 const dst_mcv = try self.copyToRegisterWithInstTracking(inst, ty, rhs_mcv);
1180 const cc: Condition = switch (signedness) {
1181 .unsigned => .b,
1182 .signed => .l,
1183 };
1216 _ = try self.addInst(.{1184 _ = try self.addInst(.{
1217 .tag = if (signedness == .signed) .cond_mov_lt else .cond_mov_below,1185 .tag = .cond_mov,
1218 .ops = Mir.Inst.Ops.encode(.{1186 .ops = Mir.Inst.Ops.encode(.{
1219 .reg1 = dst_mcv.register,1187 .reg1 = dst_mcv.register,
1220 .reg2 = lhs_reg,1188 .reg2 = lhs_reg,
1221 }),1189 }),
1222 .data = undefined,1190 .data = .{ .cc = cc },
1223 });1191 });
12241192
1225 break :result dst_mcv;1193 break :result dst_mcv;
...@@ -1341,7 +1309,7 @@ fn airAddSubShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void {...@@ -1341,7 +1309,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", .{});1309 return self.fail("TODO implement add/sub/shl with overflow for Ints larger than 64bits", .{});
1342 }1310 }
13431311
1344 try self.spillCompareFlagsIfOccupied();1312 try self.spillEflagsIfOccupied();
13451313
1346 if (tag == .shl_with_overflow) {1314 if (tag == .shl_with_overflow) {
1347 try self.spillRegisters(1, .{.rcx});1315 try self.spillRegisters(1, .{.rcx});
...@@ -1362,16 +1330,19 @@ fn airAddSubShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void {...@@ -1362,16 +1330,19 @@ fn airAddSubShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
1362 const int_info = ty.intInfo(self.target.*);1330 const int_info = ty.intInfo(self.target.*);
13631331
1364 if (math.isPowerOfTwo(int_info.bits) and int_info.bits >= 8) {1332 if (math.isPowerOfTwo(int_info.bits) and int_info.bits >= 8) {
1365 self.compare_flags_inst = inst;1333 self.eflags_inst = inst;
13661334
1367 const result: MCValue = switch (int_info.signedness) {1335 const cc: Condition = switch (int_info.signedness) {
1368 .signed => .{ .register_overflow_signed = partial.register },1336 .unsigned => .c,
1369 .unsigned => .{ .register_overflow_unsigned = partial.register },1337 .signed => .o,
1370 };1338 };
1371 break :result result;1339 break :result MCValue{ .register_overflow = .{
1340 .reg = partial.register,
1341 .eflags = cc,
1342 } };
1372 }1343 }
13731344
1374 self.compare_flags_inst = null;1345 self.eflags_inst = null;
13751346
1376 const tuple_ty = self.air.typeOfIndex(inst);1347 const tuple_ty = self.air.typeOfIndex(inst);
1377 const tuple_size = @intCast(u32, tuple_ty.abiSize(self.target.*));1348 const tuple_size = @intCast(u32, tuple_ty.abiSize(self.target.*));
...@@ -1413,17 +1384,16 @@ fn genSetStackTruncatedOverflowCompare(...@@ -1413,17 +1384,16 @@ fn genSetStackTruncatedOverflowCompare(
1413 };1384 };
14141385
1415 const overflow_reg = temp_regs[0];1386 const overflow_reg = temp_regs[0];
1416 const flags: u2 = switch (int_info.signedness) {1387 const cc: Condition = switch (int_info.signedness) {
1417 .signed => 0b00,1388 .signed => .o,
1418 .unsigned => 0b10,1389 .unsigned => .c,
1419 };1390 };
1420 _ = try self.addInst(.{1391 _ = try self.addInst(.{
1421 .tag = .cond_set_byte_overflow,1392 .tag = .cond_set_byte,
1422 .ops = Mir.Inst.Ops.encode(.{1393 .ops = Mir.Inst.Ops.encode(.{
1423 .reg1 = overflow_reg.to8(),1394 .reg1 = overflow_reg.to8(),
1424 .flags = flags,
1425 }),1395 }),
1426 .data = undefined,1396 .data = .{ .cc = cc },
1427 });1397 });
14281398
1429 const scratch_reg = temp_regs[1];1399 const scratch_reg = temp_regs[1];
...@@ -1438,9 +1408,9 @@ fn genSetStackTruncatedOverflowCompare(...@@ -1438,9 +1408,9 @@ fn genSetStackTruncatedOverflowCompare(
14381408
1439 const eq_reg = temp_regs[2];1409 const eq_reg = temp_regs[2];
1440 _ = try self.addInst(.{1410 _ = try self.addInst(.{
1441 .tag = .cond_set_byte_eq_ne,1411 .tag = .cond_set_byte,
1442 .ops = Mir.Inst.Ops.encode(.{ .reg1 = eq_reg.to8() }),1412 .ops = Mir.Inst.Ops.encode(.{ .reg1 = eq_reg.to8() }),
1443 .data = undefined,1413 .data = .{ .cc = .ne },
1444 });1414 });
14451415
1446 try self.genBinOpMir(1416 try self.genBinOpMir(
...@@ -1477,8 +1447,8 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {...@@ -1477,8 +1447,8 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
1477 const int_info = ty.intInfo(self.target.*);1447 const int_info = ty.intInfo(self.target.*);
14781448
1479 if (math.isPowerOfTwo(int_info.bits) and int_info.bits >= 8) {1449 if (math.isPowerOfTwo(int_info.bits) and int_info.bits >= 8) {
1480 try self.spillCompareFlagsIfOccupied();1450 try self.spillEflagsIfOccupied();
1481 self.compare_flags_inst = inst;1451 self.eflags_inst = inst;
14821452
1483 try self.spillRegisters(2, .{ .rax, .rdx });1453 try self.spillRegisters(2, .{ .rax, .rdx });
14841454
...@@ -1486,14 +1456,18 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {...@@ -1486,14 +1456,18 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
1486 const rhs = try self.resolveInst(bin_op.rhs);1456 const rhs = try self.resolveInst(bin_op.rhs);
14871457
1488 const partial = try self.genMulDivBinOp(.mul, null, ty, lhs, rhs);1458 const partial = try self.genMulDivBinOp(.mul, null, ty, lhs, rhs);
1489 break :result switch (int_info.signedness) {1459 const cc: Condition = switch (int_info.signedness) {
1490 .signed => MCValue{ .register_overflow_signed = partial.register },1460 .unsigned => .c,
1491 .unsigned => MCValue{ .register_overflow_unsigned = partial.register },1461 .signed => .o,
1492 };1462 };
1463 break :result MCValue{ .register_overflow = .{
1464 .reg = partial.register,
1465 .eflags = cc,
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,10 +2485,8 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo...@@ -2511,10 +2485,8 @@ 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,2489 .register_overflow => unreachable,
2516 .register_overflow_unsigned => unreachable,
2517 .register_overflow_signed => unreachable,
2518 .immediate => |imm| {2490 .immediate => |imm| {
2519 try self.setRegOrMem(elem_ty, dst_mcv, .{ .memory = imm });2491 try self.setRegOrMem(elem_ty, dst_mcv, .{ .memory = imm });
2520 },2492 },
...@@ -2532,8 +2504,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo...@@ -2532,8 +2504,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo
2532 switch (dst_mcv) {2504 switch (dst_mcv) {
2533 .dead => unreachable,2505 .dead => unreachable,
2534 .undef => unreachable,2506 .undef => unreachable,
2535 .compare_flags_unsigned => unreachable,2507 .eflags => unreachable,
2536 .compare_flags_signed => unreachable,
2537 .register => |dst_reg| {2508 .register => |dst_reg| {
2538 // mov dst_reg, [reg]2509 // mov dst_reg, [reg]
2539 _ = try self.addInst(.{2510 _ = try self.addInst(.{
...@@ -2637,10 +2608,8 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type...@@ -2637,10 +2608,8 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
2637 .undef => unreachable,2608 .undef => unreachable,
2638 .unreach => unreachable,2609 .unreach => unreachable,
2639 .dead => unreachable,2610 .dead => unreachable,
2640 .compare_flags_unsigned => unreachable,2611 .eflags => unreachable,
2641 .compare_flags_signed => unreachable,2612 .register_overflow => unreachable,
2642 .register_overflow_unsigned => unreachable,
2643 .register_overflow_signed => unreachable,
2644 .immediate => |imm| {2613 .immediate => |imm| {
2645 try self.setRegOrMem(value_ty, .{ .memory = imm }, value);2614 try self.setRegOrMem(value_ty, .{ .memory = imm }, value);
2646 },2615 },
...@@ -2660,8 +2629,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type...@@ -2660,8 +2629,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
2660 .undef => unreachable,2629 .undef => unreachable,
2661 .dead => unreachable,2630 .dead => unreachable,
2662 .unreach => unreachable,2631 .unreach => unreachable,
2663 .compare_flags_unsigned => unreachable,2632 .eflags => unreachable,
2664 .compare_flags_signed => unreachable,
2665 .immediate => |imm| {2633 .immediate => |imm| {
2666 switch (abi_size) {2634 switch (abi_size) {
2667 1, 2, 4 => {2635 1, 2, 4 => {
...@@ -3027,32 +2995,24 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {...@@ -3027,32 +2995,24 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
30272995
3028 break :result dst_mcv;2996 break :result dst_mcv;
3029 },2997 },
3030 .register_overflow_unsigned,2998 .register_overflow => |ro| {
3031 .register_overflow_signed,
3032 => |reg| {
3033 switch (index) {2999 switch (index) {
3034 0 => {3000 0 => {
3035 // Get wrapped value for overflow operation.3001 // Get wrapped value for overflow operation.
3036 break :result MCValue{ .register = reg };3002 break :result MCValue{ .register = ro.reg };
3037 },3003 },
3038 1 => {3004 1 => {
3039 // Get overflow bit.3005 // Get overflow bit.
3040 const reg_lock = self.register_manager.lockRegAssumeUnused(reg);3006 const reg_lock = self.register_manager.lockRegAssumeUnused(ro.reg);
3041 defer self.register_manager.unlockReg(reg_lock);3007 defer self.register_manager.unlockReg(reg_lock);
30423008
3043 const dst_reg = try self.register_manager.allocReg(inst, gp);3009 const dst_reg = try self.register_manager.allocReg(inst, gp);
3044 const flags: u2 = switch (mcv) {
3045 .register_overflow_unsigned => 0b10,
3046 .register_overflow_signed => 0b00,
3047 else => unreachable,
3048 };
3049 _ = try self.addInst(.{3010 _ = try self.addInst(.{
3050 .tag = .cond_set_byte_overflow,3011 .tag = .cond_set_byte,
3051 .ops = Mir.Inst.Ops.encode(.{3012 .ops = Mir.Inst.Ops.encode(.{
3052 .reg1 = dst_reg.to8(),3013 .reg1 = dst_reg.to8(),
3053 .flags = flags,
3054 }),3014 }),
3055 .data = undefined,3015 .data = .{ .cc = ro.eflags },
3056 });3016 });
3057 break :result MCValue{ .register = dst_reg.to8() };3017 break :result MCValue{ .register = dst_reg.to8() };
3058 },3018 },
...@@ -3479,17 +3439,14 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValu...@@ -3479,17 +3439,14 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValu
3479 .none => unreachable,3439 .none => unreachable,
3480 .undef => unreachable,3440 .undef => unreachable,
3481 .dead, .unreach, .immediate => unreachable,3441 .dead, .unreach, .immediate => unreachable,
3482 .compare_flags_unsigned => unreachable,3442 .eflags => unreachable,
3483 .compare_flags_signed => unreachable,3443 .register_overflow => unreachable,
3484 .register_overflow_unsigned => unreachable,
3485 .register_overflow_signed => unreachable,
3486 .register => |dst_reg| {3444 .register => |dst_reg| {
3487 switch (src_mcv) {3445 switch (src_mcv) {
3488 .none => unreachable,3446 .none => unreachable,
3489 .undef => unreachable,3447 .undef => unreachable,
3490 .dead, .unreach => unreachable,3448 .dead, .unreach => unreachable,
3491 .register_overflow_unsigned => unreachable,3449 .register_overflow => unreachable,
3492 .register_overflow_signed => unreachable,
3493 .ptr_stack_offset => {3450 .ptr_stack_offset => {
3494 const dst_reg_lock = self.register_manager.lockReg(dst_reg);3451 const dst_reg_lock = self.register_manager.lockReg(dst_reg);
3495 defer if (dst_reg_lock) |lock| self.register_manager.unlockReg(lock);3452 defer if (dst_reg_lock) |lock| self.register_manager.unlockReg(lock);
...@@ -3559,8 +3516,7 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValu...@@ -3559,8 +3516,7 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValu
3559 .memory,3516 .memory,
3560 .got_load,3517 .got_load,
3561 .direct_load,3518 .direct_load,
3562 .compare_flags_signed,3519 .eflags,
3563 .compare_flags_unsigned,
3564 => {3520 => {
3565 assert(abi_size <= 8);3521 assert(abi_size <= 8);
3566 const dst_reg_lock = self.register_manager.lockReg(dst_reg);3522 const dst_reg_lock = self.register_manager.lockReg(dst_reg);
...@@ -3597,8 +3553,7 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValu...@@ -3597,8 +3553,7 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValu
3597 .none => unreachable,3553 .none => unreachable,
3598 .undef => unreachable,3554 .undef => unreachable,
3599 .dead, .unreach => unreachable,3555 .dead, .unreach => unreachable,
3600 .register_overflow_unsigned => unreachable,3556 .register_overflow => unreachable,
3601 .register_overflow_signed => unreachable,
3602 .register => |src_reg| {3557 .register => |src_reg| {
3603 _ = try self.addInst(.{3558 _ = try self.addInst(.{
3604 .tag = mir_tag,3559 .tag = mir_tag,
...@@ -3649,11 +3604,8 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValu...@@ -3649,11 +3604,8 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValu
3649 .got_load, .direct_load => {3604 .got_load, .direct_load => {
3650 return self.fail("TODO implement x86 ADD/SUB/CMP source symbol at index in linker", .{});3605 return self.fail("TODO implement x86 ADD/SUB/CMP source symbol at index in linker", .{});
3651 },3606 },
3652 .compare_flags_unsigned => {3607 .eflags => {
3653 return self.fail("TODO implement x86 ADD/SUB/CMP source compare flag (unsigned)", .{});3608 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 },3609 },
3658 }3610 }
3659 },3611 },
...@@ -3674,19 +3626,16 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M...@@ -3674,19 +3626,16 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M
3674 .none => unreachable,3626 .none => unreachable,
3675 .undef => unreachable,3627 .undef => unreachable,
3676 .dead, .unreach, .immediate => unreachable,3628 .dead, .unreach, .immediate => unreachable,
3677 .compare_flags_unsigned => unreachable,3629 .eflags => unreachable,
3678 .compare_flags_signed => unreachable,
3679 .ptr_stack_offset => unreachable,3630 .ptr_stack_offset => unreachable,
3680 .register_overflow_unsigned => unreachable,3631 .register_overflow => unreachable,
3681 .register_overflow_signed => unreachable,
3682 .register => |dst_reg| {3632 .register => |dst_reg| {
3683 switch (src_mcv) {3633 switch (src_mcv) {
3684 .none => unreachable,3634 .none => unreachable,
3685 .undef => try self.genSetReg(dst_ty, dst_reg, .undef),3635 .undef => try self.genSetReg(dst_ty, dst_reg, .undef),
3686 .dead, .unreach => unreachable,3636 .dead, .unreach => unreachable,
3687 .ptr_stack_offset => unreachable,3637 .ptr_stack_offset => unreachable,
3688 .register_overflow_unsigned => unreachable,3638 .register_overflow => unreachable,
3689 .register_overflow_signed => unreachable,
3690 .register => |src_reg| {3639 .register => |src_reg| {
3691 // register, register3640 // register, register
3692 _ = try self.addInst(.{3641 _ = try self.addInst(.{
...@@ -3734,11 +3683,8 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M...@@ -3734,11 +3683,8 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M
3734 .got_load, .direct_load => {3683 .got_load, .direct_load => {
3735 return self.fail("TODO implement x86 multiply source symbol at index in linker", .{});3684 return self.fail("TODO implement x86 multiply source symbol at index in linker", .{});
3736 },3685 },
3737 .compare_flags_unsigned => {3686 .eflags => {
3738 return self.fail("TODO implement x86 multiply source compare flag (unsigned)", .{});3687 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 },3688 },
3743 }3689 }
3744 },3690 },
...@@ -3748,8 +3694,7 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M...@@ -3748,8 +3694,7 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M
3748 .undef => return self.genSetStack(dst_ty, off, .undef, .{}),3694 .undef => return self.genSetStack(dst_ty, off, .undef, .{}),
3749 .dead, .unreach => unreachable,3695 .dead, .unreach => unreachable,
3750 .ptr_stack_offset => unreachable,3696 .ptr_stack_offset => unreachable,
3751 .register_overflow_unsigned => unreachable,3697 .register_overflow => unreachable,
3752 .register_overflow_signed => unreachable,
3753 .register => |src_reg| {3698 .register => |src_reg| {
3754 // copy dst to a register3699 // copy dst to a register
3755 const dst_reg = try self.copyToTmpRegister(dst_ty, dst_mcv);3700 const dst_reg = try self.copyToTmpRegister(dst_ty, dst_mcv);
...@@ -3782,11 +3727,8 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M...@@ -3782,11 +3727,8 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M
3782 .got_load, .direct_load => {3727 .got_load, .direct_load => {
3783 return self.fail("TODO implement x86 multiply source symbol at index in linker", .{});3728 return self.fail("TODO implement x86 multiply source symbol at index in linker", .{});
3784 },3729 },
3785 .compare_flags_unsigned => {3730 .eflags => {
3786 return self.fail("TODO implement x86 multiply source compare flag (unsigned)", .{});3731 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 },3732 },
3791 }3733 }
3792 },3734 },
...@@ -3905,7 +3847,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions....@@ -3905,7 +3847,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.
3905 var info = try self.resolveCallingConventionValues(fn_ty);3847 var info = try self.resolveCallingConventionValues(fn_ty);
3906 defer info.deinit(self);3848 defer info.deinit(self);
39073849
3908 try self.spillCompareFlagsIfOccupied();3850 try self.spillEflagsIfOccupied();
39093851
3910 for (caller_preserved_regs) |reg| {3852 for (caller_preserved_regs) |reg| {
3911 try self.register_manager.getReg(reg, null);3853 try self.register_manager.getReg(reg, null);
...@@ -3957,10 +3899,8 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions....@@ -3957,10 +3899,8 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.
3957 .memory => unreachable,3899 .memory => unreachable,
3958 .got_load => unreachable,3900 .got_load => unreachable,
3959 .direct_load => unreachable,3901 .direct_load => unreachable,
3960 .compare_flags_signed => unreachable,3902 .eflags => unreachable,
3961 .compare_flags_unsigned => unreachable,3903 .register_overflow => unreachable,
3962 .register_overflow_signed => unreachable,
3963 .register_overflow_unsigned => unreachable,
3964 }3904 }
3965 }3905 }
39663906
...@@ -4220,8 +4160,8 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {...@@ -4220,8 +4160,8 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
4220 break :blk ty.intInfo(self.target.*).signedness;4160 break :blk ty.intInfo(self.target.*).signedness;
4221 };4161 };
42224162
4223 try self.spillCompareFlagsIfOccupied();4163 try self.spillEflagsIfOccupied();
4224 self.compare_flags_inst = inst;4164 self.eflags_inst = inst;
42254165
4226 const result: MCValue = result: {4166 const result: MCValue = result: {
4227 // There are 2 operands, destination and source.4167 // There are 2 operands, destination and source.
...@@ -4265,9 +4205,10 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {...@@ -4265,9 +4205,10 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
4265 defer if (src_lock) |lock| self.register_manager.unlockReg(lock);4205 defer if (src_lock) |lock| self.register_manager.unlockReg(lock);
42664206
4267 try self.genBinOpMir(.cmp, ty, dst_mcv, src_mcv);4207 try self.genBinOpMir(.cmp, ty, dst_mcv, src_mcv);
4208
4268 break :result switch (signedness) {4209 break :result switch (signedness) {
4269 .signed => MCValue{ .compare_flags_signed = op },4210 .signed => MCValue{ .eflags = Condition.fromCompareOperatorSigned(op) },
4270 .unsigned => MCValue{ .compare_flags_unsigned = op },4211 .unsigned => MCValue{ .eflags = Condition.fromCompareOperatorUnsigned(op) },
4271 };4212 };
4272 };4213 };
42734214
...@@ -4440,47 +4381,39 @@ fn addDbgInfoTypeReloc(self: *Self, ty: Type) !void {...@@ -4440,47 +4381,39 @@ fn addDbgInfoTypeReloc(self: *Self, ty: Type) !void {
4440fn genCondBrMir(self: *Self, ty: Type, mcv: MCValue) !u32 {4381fn genCondBrMir(self: *Self, ty: Type, mcv: MCValue) !u32 {
4441 const abi_size = ty.abiSize(self.target.*);4382 const abi_size = ty.abiSize(self.target.*);
4442 switch (mcv) {4383 switch (mcv) {
4443 .compare_flags_unsigned,4384 .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(.{4385 return self.addInst(.{
4462 .tag = tag,4386 .tag = .cond_jmp,
4463 .ops = Mir.Inst.Ops.encode(.{ .flags = flags }),4387 .ops = Mir.Inst.Ops.encode(.{}),
4464 .data = .{ .inst = undefined },4388 .data = .{
4389 .inst_cc = .{
4390 .inst = undefined,
4391 // Here we map the opposites since the jump is to the false branch.
4392 .cc = cc.negate(),
4393 },
4394 },
4465 });4395 });
4466 },4396 },
4467 .register => |reg| {4397 .register => |reg| {
4468 try self.spillCompareFlagsIfOccupied();4398 try self.spillEflagsIfOccupied();
4469 _ = try self.addInst(.{4399 _ = try self.addInst(.{
4470 .tag = .@"test",4400 .tag = .@"test",
4471 .ops = Mir.Inst.Ops.encode(.{ .reg1 = reg }),4401 .ops = Mir.Inst.Ops.encode(.{ .reg1 = reg }),
4472 .data = .{ .imm = 1 },4402 .data = .{ .imm = 1 },
4473 });4403 });
4474 return self.addInst(.{4404 return self.addInst(.{
4475 .tag = .cond_jmp_eq_ne,4405 .tag = .cond_jmp,
4476 .ops = Mir.Inst.Ops.encode(.{ .flags = 0b01 }),4406 .ops = Mir.Inst.Ops.encode(.{}),
4477 .data = .{ .inst = undefined },4407 .data = .{ .inst_cc = .{
4408 .inst = undefined,
4409 .cc = .e,
4410 } },
4478 });4411 });
4479 },4412 },
4480 .immediate,4413 .immediate,
4481 .stack_offset,4414 .stack_offset,
4482 => {4415 => {
4483 try self.spillCompareFlagsIfOccupied();4416 try self.spillEflagsIfOccupied();
4484 if (abi_size <= 8) {4417 if (abi_size <= 8) {
4485 const reg = try self.copyToTmpRegister(ty, mcv);4418 const reg = try self.copyToTmpRegister(ty, mcv);
4486 return self.genCondBrMir(ty, .{ .register = reg });4419 return self.genCondBrMir(ty, .{ .register = reg });
...@@ -4516,7 +4449,7 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {...@@ -4516,7 +4449,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.4449 // 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;4450 const parent_next_stack_offset = self.next_stack_offset;
4518 const parent_free_registers = self.register_manager.free_registers;4451 const parent_free_registers = self.register_manager.free_registers;
4519 const parent_compare_flags_inst = self.compare_flags_inst;4452 const parent_eflags_inst = self.eflags_inst;
4520 var parent_stack = try self.stack.clone(self.gpa);4453 var parent_stack = try self.stack.clone(self.gpa);
4521 defer parent_stack.deinit(self.gpa);4454 defer parent_stack.deinit(self.gpa);
4522 const parent_registers = self.register_manager.registers;4455 const parent_registers = self.register_manager.registers;
...@@ -4538,7 +4471,7 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {...@@ -4538,7 +4471,7 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {
4538 defer saved_then_branch.deinit(self.gpa);4471 defer saved_then_branch.deinit(self.gpa);
45394472
4540 self.register_manager.registers = parent_registers;4473 self.register_manager.registers = parent_registers;
4541 self.compare_flags_inst = parent_compare_flags_inst;4474 self.eflags_inst = parent_eflags_inst;
45424475
4543 self.stack.deinit(self.gpa);4476 self.stack.deinit(self.gpa);
4544 self.stack = parent_stack;4477 self.stack = parent_stack;
...@@ -4640,8 +4573,8 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {...@@ -4640,8 +4573,8 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {
4640}4573}
46414574
4642fn isNull(self: *Self, inst: Air.Inst.Index, ty: Type, operand: MCValue) !MCValue {4575fn isNull(self: *Self, inst: Air.Inst.Index, ty: Type, operand: MCValue) !MCValue {
4643 try self.spillCompareFlagsIfOccupied();4576 try self.spillEflagsIfOccupied();
4644 self.compare_flags_inst = inst;4577 self.eflags_inst = inst;
46454578
4646 const cmp_ty: Type = if (!ty.isPtrLikeOptional()) blk: {4579 const cmp_ty: Type = if (!ty.isPtrLikeOptional()) blk: {
4647 var buf: Type.Payload.ElemType = undefined;4580 var buf: Type.Payload.ElemType = undefined;
...@@ -4651,13 +4584,13 @@ fn isNull(self: *Self, inst: Air.Inst.Index, ty: Type, operand: MCValue) !MCValu...@@ -4651,13 +4584,13 @@ fn isNull(self: *Self, inst: Air.Inst.Index, ty: Type, operand: MCValue) !MCValu
46514584
4652 try self.genBinOpMir(.cmp, cmp_ty, operand, MCValue{ .immediate = 0 });4585 try self.genBinOpMir(.cmp, cmp_ty, operand, MCValue{ .immediate = 0 });
46534586
4654 return MCValue{ .compare_flags_unsigned = .eq };4587 return MCValue{ .eflags = .e };
4655}4588}
46564589
4657fn isNonNull(self: *Self, inst: Air.Inst.Index, ty: Type, operand: MCValue) !MCValue {4590fn isNonNull(self: *Self, inst: Air.Inst.Index, ty: Type, operand: MCValue) !MCValue {
4658 const is_null_res = try self.isNull(inst, ty, operand);4591 const is_null_res = try self.isNull(inst, ty, operand);
4659 assert(is_null_res.compare_flags_unsigned == .eq);4592 assert(is_null_res.eflags == .e);
4660 return MCValue{ .compare_flags_unsigned = .neq };4593 return MCValue{ .eflags = is_null_res.eflags.negate() };
4661}4594}
46624595
4663fn isErr(self: *Self, inst: Air.Inst.Index, ty: Type, operand: MCValue) !MCValue {4596fn isErr(self: *Self, inst: Air.Inst.Index, ty: Type, operand: MCValue) !MCValue {
...@@ -4667,8 +4600,8 @@ fn isErr(self: *Self, inst: Air.Inst.Index, ty: Type, operand: MCValue) !MCValue...@@ -4667,8 +4600,8 @@ fn isErr(self: *Self, inst: Air.Inst.Index, ty: Type, operand: MCValue) !MCValue
4667 return MCValue{ .immediate = 0 }; // always false4600 return MCValue{ .immediate = 0 }; // always false
4668 }4601 }
46694602
4670 try self.spillCompareFlagsIfOccupied();4603 try self.spillEflagsIfOccupied();
4671 self.compare_flags_inst = inst;4604 self.eflags_inst = inst;
46724605
4673 const err_off = errUnionErrorOffset(ty.errorUnionPayload(), self.target.*);4606 const err_off = errUnionErrorOffset(ty.errorUnionPayload(), self.target.*);
4674 switch (operand) {4607 switch (operand) {
...@@ -4691,15 +4624,15 @@ fn isErr(self: *Self, inst: Air.Inst.Index, ty: Type, operand: MCValue) !MCValue...@@ -4691,15 +4624,15 @@ fn isErr(self: *Self, inst: Air.Inst.Index, ty: Type, operand: MCValue) !MCValue
4691 else => return self.fail("TODO implement isErr for {}", .{operand}),4624 else => return self.fail("TODO implement isErr for {}", .{operand}),
4692 }4625 }
46934626
4694 return MCValue{ .compare_flags_unsigned = .gt };4627 return MCValue{ .eflags = .a };
4695}4628}
46964629
4697fn isNonErr(self: *Self, inst: Air.Inst.Index, ty: Type, operand: MCValue) !MCValue {4630fn isNonErr(self: *Self, inst: Air.Inst.Index, ty: Type, operand: MCValue) !MCValue {
4698 const is_err_res = try self.isErr(inst, ty, operand);4631 const is_err_res = try self.isErr(inst, ty, operand);
4699 switch (is_err_res) {4632 switch (is_err_res) {
4700 .compare_flags_unsigned => |op| {4633 .eflags => |cc| {
4701 assert(op == .gt);4634 assert(cc == .a);
4702 return MCValue{ .compare_flags_unsigned = .lte };4635 return MCValue{ .eflags = cc.negate() };
4703 },4636 },
4704 .immediate => |imm| {4637 .immediate => |imm| {
4705 assert(imm == 0);4638 assert(imm == 0);
...@@ -4914,10 +4847,9 @@ fn genCondSwitchMir(self: *Self, ty: Type, condition: MCValue, case: MCValue) !u...@@ -4914,10 +4847,9 @@ fn genCondSwitchMir(self: *Self, ty: Type, condition: MCValue, case: MCValue) !u
4914 .none => unreachable,4847 .none => unreachable,
4915 .undef => unreachable,4848 .undef => unreachable,
4916 .dead, .unreach => unreachable,4849 .dead, .unreach => unreachable,
4917 .compare_flags_signed => unreachable,4850 .eflags => unreachable,
4918 .compare_flags_unsigned => unreachable,
4919 .register => |cond_reg| {4851 .register => |cond_reg| {
4920 try self.spillCompareFlagsIfOccupied();4852 try self.spillEflagsIfOccupied();
49214853
4922 const cond_reg_lock = self.register_manager.lockReg(cond_reg);4854 const cond_reg_lock = self.register_manager.lockReg(cond_reg);
4923 defer if (cond_reg_lock) |lock| self.register_manager.unlockReg(lock);4855 defer if (cond_reg_lock) |lock| self.register_manager.unlockReg(lock);
...@@ -4965,13 +4897,16 @@ fn genCondSwitchMir(self: *Self, ty: Type, condition: MCValue, case: MCValue) !u...@@ -4965,13 +4897,16 @@ fn genCondSwitchMir(self: *Self, ty: Type, condition: MCValue, case: MCValue) !u
4965 .data = undefined,4897 .data = undefined,
4966 });4898 });
4967 return self.addInst(.{4899 return self.addInst(.{
4968 .tag = .cond_jmp_eq_ne,4900 .tag = .cond_jmp,
4969 .ops = Mir.Inst.Ops.encode(.{}),4901 .ops = Mir.Inst.Ops.encode(.{}),
4970 .data = .{ .inst = undefined },4902 .data = .{ .inst_cc = .{
4903 .inst = undefined,
4904 .cc = .ne,
4905 } },
4971 });4906 });
4972 },4907 },
4973 .stack_offset => {4908 .stack_offset => {
4974 try self.spillCompareFlagsIfOccupied();4909 try self.spillEflagsIfOccupied();
49754910
4976 if (abi_size <= 8) {4911 if (abi_size <= 8) {
4977 const reg = try self.copyToTmpRegister(ty, condition);4912 const reg = try self.copyToTmpRegister(ty, condition);
...@@ -5030,7 +4965,7 @@ fn airSwitch(self: *Self, inst: Air.Inst.Index) !void {...@@ -5030,7 +4965,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.4965 // 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;4966 const parent_next_stack_offset = self.next_stack_offset;
5032 const parent_free_registers = self.register_manager.free_registers;4967 const parent_free_registers = self.register_manager.free_registers;
5033 const parent_compare_flags_inst = self.compare_flags_inst;4968 const parent_eflags_inst = self.eflags_inst;
5034 var parent_stack = try self.stack.clone(self.gpa);4969 var parent_stack = try self.stack.clone(self.gpa);
5035 defer parent_stack.deinit(self.gpa);4970 defer parent_stack.deinit(self.gpa);
5036 const parent_registers = self.register_manager.registers;4971 const parent_registers = self.register_manager.registers;
...@@ -5052,7 +4987,7 @@ fn airSwitch(self: *Self, inst: Air.Inst.Index) !void {...@@ -5052,7 +4987,7 @@ fn airSwitch(self: *Self, inst: Air.Inst.Index) !void {
5052 defer saved_case_branch.deinit(self.gpa);4987 defer saved_case_branch.deinit(self.gpa);
50534988
5054 self.register_manager.registers = parent_registers;4989 self.register_manager.registers = parent_registers;
5055 self.compare_flags_inst = parent_compare_flags_inst;4990 self.eflags_inst = parent_eflags_inst;
5056 self.stack.deinit(self.gpa);4991 self.stack.deinit(self.gpa);
5057 self.stack = parent_stack;4992 self.stack = parent_stack;
5058 parent_stack = .{};4993 parent_stack = .{};
...@@ -5092,7 +5027,15 @@ fn airSwitch(self: *Self, inst: Air.Inst.Index) !void {...@@ -5092,7 +5027,15 @@ fn airSwitch(self: *Self, inst: Air.Inst.Index) !void {
50925027
5093fn performReloc(self: *Self, reloc: Mir.Inst.Index) !void {5028fn performReloc(self: *Self, reloc: Mir.Inst.Index) !void {
5094 const next_inst = @intCast(u32, self.mir_instructions.len);5029 const next_inst = @intCast(u32, self.mir_instructions.len);
5095 self.mir_instructions.items(.data)[reloc].inst = next_inst;5030 switch (self.mir_instructions.items(.tag)[reloc]) {
5031 .cond_jmp => {
5032 self.mir_instructions.items(.data)[reloc].inst_cc.inst = next_inst;
5033 },
5034 .jmp => {
5035 self.mir_instructions.items(.data)[reloc].inst = next_inst;
5036 },
5037 else => unreachable,
5038 }
5096}5039}
50975040
5098fn airBr(self: *Self, inst: Air.Inst.Index) !void {5041fn airBr(self: *Self, inst: Air.Inst.Index) !void {
...@@ -5111,7 +5054,7 @@ fn br(self: *Self, block: Air.Inst.Index, operand: Air.Inst.Ref) !void {...@@ -5111,7 +5054,7 @@ fn br(self: *Self, block: Air.Inst.Index, operand: Air.Inst.Ref) !void {
5111 block_data.mcv = switch (operand_mcv) {5054 block_data.mcv = switch (operand_mcv) {
5112 .none, .dead, .unreach => unreachable,5055 .none, .dead, .unreach => unreachable,
5113 .register, .stack_offset, .memory => operand_mcv,5056 .register, .stack_offset, .memory => operand_mcv,
5114 .compare_flags_signed, .compare_flags_unsigned, .immediate => blk: {5057 .eflags, .immediate => blk: {
5115 const new_mcv = try self.allocRegOrMem(block, true);5058 const new_mcv = try self.allocRegOrMem(block, true);
5116 try self.setRegOrMem(self.air.typeOfIndex(block), new_mcv, operand_mcv);5059 try self.setRegOrMem(self.air.typeOfIndex(block), new_mcv, operand_mcv);
5117 break :blk new_mcv;5060 break :blk new_mcv;
...@@ -5332,12 +5275,8 @@ fn genSetStackArg(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerE...@@ -5332,12 +5275,8 @@ fn genSetStackArg(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerE
5332 .{ .dest_stack_base = .rsp },5275 .{ .dest_stack_base = .rsp },
5333 );5276 );
5334 },5277 },
5335 .register_overflow_unsigned,5278 .register_overflow => return self.fail("TODO genSetStackArg for register with overflow bit", .{}),
5336 .register_overflow_signed,5279 .eflags => {
5337 => return self.fail("TODO genSetStackArg for register with overflow bit", .{}),
5338 .compare_flags_unsigned,
5339 .compare_flags_signed,
5340 => {
5341 const reg = try self.copyToTmpRegister(ty, mcv);5280 const reg = try self.copyToTmpRegister(ty, mcv);
5342 return self.genSetStackArg(ty, stack_offset, .{ .register = reg });5281 return self.genSetStackArg(ty, stack_offset, .{ .register = reg });
5343 },5282 },
...@@ -5472,30 +5411,22 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: Inl...@@ -5472,30 +5411,22 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: Inl
5472 ),5411 ),
5473 }5412 }
5474 },5413 },
5475 .register_overflow_unsigned,5414 .register_overflow => |ro| {
5476 .register_overflow_signed,5415 const reg_lock = self.register_manager.lockReg(ro.reg);
5477 => |reg| {
5478 const reg_lock = self.register_manager.lockReg(reg);
5479 defer if (reg_lock) |lock| self.register_manager.unlockReg(lock);5416 defer if (reg_lock) |lock| self.register_manager.unlockReg(lock);
54805417
5481 const wrapped_ty = ty.structFieldType(0);5418 const wrapped_ty = ty.structFieldType(0);
5482 try self.genSetStack(wrapped_ty, stack_offset, .{ .register = reg }, .{});5419 try self.genSetStack(wrapped_ty, stack_offset, .{ .register = ro.reg }, .{});
54835420
5484 const overflow_bit_ty = ty.structFieldType(1);5421 const overflow_bit_ty = ty.structFieldType(1);
5485 const overflow_bit_offset = ty.structFieldOffset(1, self.target.*);5422 const overflow_bit_offset = ty.structFieldOffset(1, self.target.*);
5486 const tmp_reg = try self.register_manager.allocReg(null, gp);5423 const tmp_reg = try self.register_manager.allocReg(null, gp);
5487 const flags: u2 = switch (mcv) {
5488 .register_overflow_unsigned => 0b10,
5489 .register_overflow_signed => 0b00,
5490 else => unreachable,
5491 };
5492 _ = try self.addInst(.{5424 _ = try self.addInst(.{
5493 .tag = .cond_set_byte_overflow,5425 .tag = .cond_set_byte,
5494 .ops = Mir.Inst.Ops.encode(.{5426 .ops = Mir.Inst.Ops.encode(.{
5495 .reg1 = tmp_reg.to8(),5427 .reg1 = tmp_reg.to8(),
5496 .flags = flags,
5497 }),5428 }),
5498 .data = undefined,5429 .data = .{ .cc = ro.eflags },
5499 });5430 });
55005431
5501 return self.genSetStack(5432 return self.genSetStack(
...@@ -5505,9 +5436,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: Inl...@@ -5505,9 +5436,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: Inl
5505 .{},5436 .{},
5506 );5437 );
5507 },5438 },
5508 .compare_flags_unsigned,5439 .eflags => {
5509 .compare_flags_signed,
5510 => {
5511 const reg = try self.copyToTmpRegister(ty, mcv);5440 const reg = try self.copyToTmpRegister(ty, mcv);
5512 return self.genSetStack(ty, stack_offset, .{ .register = reg }, opts);5441 return self.genSetStack(ty, stack_offset, .{ .register = reg }, opts);
5513 },5442 },
...@@ -5832,9 +5761,12 @@ fn genInlineMemcpy(...@@ -5832,9 +5761,12 @@ fn genInlineMemcpy(
58325761
5833 // je end5762 // je end
5834 const loop_reloc = try self.addInst(.{5763 const loop_reloc = try self.addInst(.{
5835 .tag = .cond_jmp_eq_ne,5764 .tag = .cond_jmp,
5836 .ops = Mir.Inst.Ops.encode(.{ .flags = 0b01 }),5765 .ops = Mir.Inst.Ops.encode(.{}),
5837 .data = .{ .inst = undefined },5766 .data = .{ .inst_cc = .{
5767 .inst = undefined,
5768 .cc = .e,
5769 } },
5838 });5770 });
58395771
5840 // mov tmp, [addr + rcx]5772 // mov tmp, [addr + rcx]
...@@ -5950,9 +5882,12 @@ fn genInlineMemset(...@@ -5950,9 +5882,12 @@ fn genInlineMemset(
59505882
5951 // je end5883 // je end
5952 const loop_reloc = try self.addInst(.{5884 const loop_reloc = try self.addInst(.{
5953 .tag = .cond_jmp_eq_ne,5885 .tag = .cond_jmp,
5954 .ops = Mir.Inst.Ops.encode(.{ .flags = 0b01 }),5886 .ops = Mir.Inst.Ops.encode(.{}),
5955 .data = .{ .inst = undefined },5887 .data = .{ .inst_cc = .{
5888 .inst = undefined,
5889 .cc = .e,
5890 } },
5956 });5891 });
59575892
5958 switch (value) {5893 switch (value) {
...@@ -5996,9 +5931,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void...@@ -5996,9 +5931,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
5996 const abi_size = @intCast(u32, ty.abiSize(self.target.*));5931 const abi_size = @intCast(u32, ty.abiSize(self.target.*));
5997 switch (mcv) {5932 switch (mcv) {
5998 .dead => unreachable,5933 .dead => unreachable,
5999 .register_overflow_unsigned,5934 .register_overflow => unreachable,
6000 .register_overflow_signed,
6001 => unreachable,
6002 .ptr_stack_offset => |off| {5935 .ptr_stack_offset => |off| {
6003 if (off < std.math.minInt(i32) or off > std.math.maxInt(i32)) {5936 if (off < std.math.minInt(i32) or off > std.math.maxInt(i32)) {
6004 return self.fail("stack offset too large", .{});5937 return self.fail("stack offset too large", .{});
...@@ -6025,31 +5958,13 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void...@@ -6025,31 +5958,13 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
6025 else => unreachable,5958 else => unreachable,
6026 }5959 }
6027 },5960 },
6028 .compare_flags_unsigned,5961 .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(.{5962 _ = try self.addInst(.{
6047 .tag = tag,5963 .tag = .cond_set_byte,
6048 .ops = Mir.Inst.Ops.encode(.{5964 .ops = Mir.Inst.Ops.encode(.{
6049 .reg1 = reg.to8(),5965 .reg1 = reg.to8(),
6050 .flags = flags,
6051 }),5966 }),
6052 .data = undefined,5967 .data = .{ .cc = cc },
6053 });5968 });
6054 },5969 },
6055 .immediate => |x| {5970 .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.