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;
3737const c_abi_int_param_regs = abi.c_abi_int_param_regs;
3838const c_abi_int_return_regs = abi.c_abi_int_return_regs;
3939
40const Condition = bits.Condition;
4041const RegisterManager = abi.RegisterManager;
4142const RegisterLock = RegisterManager.RegisterLock;
4243const Register = bits.Register;
......@@ -65,7 +66,7 @@ arg_index: u32,
6566src_loc: Module.SrcLoc,
6667stack_align: u32,
6768
68compare_flags_inst: ?Air.Inst.Index = null,
69eflags_inst: ?Air.Inst.Index = null,
6970
7071/// MIR Instructions
7172mir_instructions: std.MultiArrayList(Mir.Inst) = .{},
......@@ -149,12 +150,8 @@ pub const MCValue = union(enum) {
149150 stack_offset: i32,
150151 /// The value is a pointer to one of the stack variables (payload is stack offset).
151152 ptr_stack_offset: i32,
152 /// The value is in the compare flags assuming an unsigned operation,
153 /// with this operator applied on top of it.
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,
153 /// The value resides in the EFLAGS register.
154 eflags: Condition,
158155
159156 fn isMemory(mcv: MCValue) bool {
160157 return switch (mcv) {
......@@ -183,8 +180,7 @@ pub const MCValue = union(enum) {
183180
184181 .immediate,
185182 .memory,
186 .compare_flags_unsigned,
187 .compare_flags_signed,
183 .eflags,
188184 .ptr_stack_offset,
189185 .undef,
190186 .register_overflow_unsigned,
......@@ -780,10 +776,10 @@ fn processDeath(self: *Self, inst: Air.Inst.Index) void {
780776 },
781777 .register_overflow_signed, .register_overflow_unsigned => |reg| {
782778 self.register_manager.freeReg(reg.to64());
783 self.compare_flags_inst = null;
779 self.eflags_inst = null;
784780 },
785 .compare_flags_signed, .compare_flags_unsigned => {
786 self.compare_flags_inst = null;
781 .eflags => {
782 self.eflags_inst = null;
787783 },
788784 else => {}, // TODO process stack allocation death
789785 }
......@@ -929,16 +925,14 @@ pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void
929925 try self.genSetStack(self.air.typeOfIndex(inst), stack_mcv.stack_offset, reg_mcv, .{});
930926}
931927
932pub fn spillCompareFlagsIfOccupied(self: *Self) !void {
933 if (self.compare_flags_inst) |inst_to_save| {
928pub fn spillEflagsIfOccupied(self: *Self) !void {
929 if (self.eflags_inst) |inst_to_save| {
934930 const mcv = self.getResolvedInstValue(inst_to_save);
935931 const new_mcv = switch (mcv) {
936932 .register_overflow_signed,
937933 .register_overflow_unsigned,
938934 => try self.allocRegOrMem(inst_to_save, false),
939 .compare_flags_signed,
940 .compare_flags_unsigned,
941 => try self.allocRegOrMem(inst_to_save, true),
935 .eflags => try self.allocRegOrMem(inst_to_save, true),
942936 else => unreachable,
943937 };
944938
......@@ -948,7 +942,7 @@ pub fn spillCompareFlagsIfOccupied(self: *Self) !void {
948942 const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];
949943 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
953947 // TODO consolidate with register manager and spillInstruction
954948 // this call should really belong in the register manager!
......@@ -1123,31 +1117,8 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void {
11231117 switch (operand) {
11241118 .dead => unreachable,
11251119 .unreach => unreachable,
1126 .compare_flags_unsigned => |op| {
1127 const r = MCValue{
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;
1120 .eflags => |cc| {
1121 break :result MCValue{ .eflags = cc.negate() };
11511122 },
11521123 else => {},
11531124 }
......@@ -1213,13 +1184,17 @@ fn airMin(self: *Self, inst: Air.Inst.Index) !void {
12131184 try self.genBinOpMir(.cmp, ty, .{ .register = lhs_reg }, rhs_mcv);
12141185
12151186 const dst_mcv = try self.copyToRegisterWithInstTracking(inst, ty, rhs_mcv);
1187 const cc: Condition = switch (signedness) {
1188 .unsigned => .b,
1189 .signed => .l,
1190 };
12161191 _ = try self.addInst(.{
1217 .tag = if (signedness == .signed) .cond_mov_lt else .cond_mov_below,
1192 .tag = .cond_mov,
12181193 .ops = Mir.Inst.Ops.encode(.{
12191194 .reg1 = dst_mcv.register,
12201195 .reg2 = lhs_reg,
12211196 }),
1222 .data = undefined,
1197 .data = .{ .cc = cc },
12231198 });
12241199
12251200 break :result dst_mcv;
......@@ -1341,7 +1316,7 @@ fn airAddSubShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
13411316 return self.fail("TODO implement add/sub/shl with overflow for Ints larger than 64bits", .{});
13421317 }
13431318
1344 try self.spillCompareFlagsIfOccupied();
1319 try self.spillEflagsIfOccupied();
13451320
13461321 if (tag == .shl_with_overflow) {
13471322 try self.spillRegisters(1, .{.rcx});
......@@ -1362,7 +1337,7 @@ fn airAddSubShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
13621337 const int_info = ty.intInfo(self.target.*);
13631338
13641339 if (math.isPowerOfTwo(int_info.bits) and int_info.bits >= 8) {
1365 self.compare_flags_inst = inst;
1340 self.eflags_inst = inst;
13661341
13671342 const result: MCValue = switch (int_info.signedness) {
13681343 .signed => .{ .register_overflow_signed = partial.register },
......@@ -1371,7 +1346,7 @@ fn airAddSubShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
13711346 break :result result;
13721347 }
13731348
1374 self.compare_flags_inst = null;
1349 self.eflags_inst = null;
13751350
13761351 const tuple_ty = self.air.typeOfIndex(inst);
13771352 const tuple_size = @intCast(u32, tuple_ty.abiSize(self.target.*));
......@@ -1413,17 +1388,16 @@ fn genSetStackTruncatedOverflowCompare(
14131388 };
14141389
14151390 const overflow_reg = temp_regs[0];
1416 const flags: u2 = switch (int_info.signedness) {
1417 .signed => 0b00,
1418 .unsigned => 0b10,
1391 const cc: Condition = switch (int_info.signedness) {
1392 .signed => .o,
1393 .unsigned => .c,
14191394 };
14201395 _ = try self.addInst(.{
1421 .tag = .cond_set_byte_overflow,
1396 .tag = .cond_set_byte,
14221397 .ops = Mir.Inst.Ops.encode(.{
14231398 .reg1 = overflow_reg.to8(),
1424 .flags = flags,
14251399 }),
1426 .data = undefined,
1400 .data = .{ .cc = cc },
14271401 });
14281402
14291403 const scratch_reg = temp_regs[1];
......@@ -1438,9 +1412,9 @@ fn genSetStackTruncatedOverflowCompare(
14381412
14391413 const eq_reg = temp_regs[2];
14401414 _ = try self.addInst(.{
1441 .tag = .cond_set_byte_eq_ne,
1415 .tag = .cond_set_byte,
14421416 .ops = Mir.Inst.Ops.encode(.{ .reg1 = eq_reg.to8() }),
1443 .data = undefined,
1417 .data = .{ .cc = .ne },
14441418 });
14451419
14461420 try self.genBinOpMir(
......@@ -1477,8 +1451,8 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
14771451 const int_info = ty.intInfo(self.target.*);
14781452
14791453 if (math.isPowerOfTwo(int_info.bits) and int_info.bits >= 8) {
1480 try self.spillCompareFlagsIfOccupied();
1481 self.compare_flags_inst = inst;
1454 try self.spillEflagsIfOccupied();
1455 self.eflags_inst = inst;
14821456
14831457 try self.spillRegisters(2, .{ .rax, .rdx });
14841458
......@@ -1492,8 +1466,8 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
14921466 };
14931467 }
14941468
1495 try self.spillCompareFlagsIfOccupied();
1496 self.compare_flags_inst = null;
1469 try self.spillEflagsIfOccupied();
1470 self.eflags_inst = null;
14971471
14981472 const dst_reg: Register = dst_reg: {
14991473 switch (int_info.signedness) {
......@@ -1686,12 +1660,12 @@ fn genInlineIntDivFloor(self: *Self, ty: Type, lhs: MCValue, rhs: MCValue) !MCVa
16861660 .data = undefined,
16871661 });
16881662 _ = try self.addInst(.{
1689 .tag = .cond_mov_eq,
1663 .tag = .cond_mov,
16901664 .ops = Mir.Inst.Ops.encode(.{
16911665 .reg1 = divisor.to64(),
16921666 .reg2 = .rdx,
16931667 }),
1694 .data = undefined,
1668 .data = .{ .cc = .e },
16951669 });
16961670 try self.genBinOpMir(.add, Type.isize, .{ .register = divisor }, .{ .register = .rax });
16971671 return MCValue{ .register = divisor };
......@@ -2511,8 +2485,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo
25112485 .undef => unreachable,
25122486 .unreach => unreachable,
25132487 .dead => unreachable,
2514 .compare_flags_unsigned => unreachable,
2515 .compare_flags_signed => unreachable,
2488 .eflags => unreachable,
25162489 .register_overflow_unsigned => unreachable,
25172490 .register_overflow_signed => unreachable,
25182491 .immediate => |imm| {
......@@ -2532,8 +2505,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo
25322505 switch (dst_mcv) {
25332506 .dead => unreachable,
25342507 .undef => unreachable,
2535 .compare_flags_unsigned => unreachable,
2536 .compare_flags_signed => unreachable,
2508 .eflags => unreachable,
25372509 .register => |dst_reg| {
25382510 // mov dst_reg, [reg]
25392511 _ = try self.addInst(.{
......@@ -2637,8 +2609,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
26372609 .undef => unreachable,
26382610 .unreach => unreachable,
26392611 .dead => unreachable,
2640 .compare_flags_unsigned => unreachable,
2641 .compare_flags_signed => unreachable,
2612 .eflags => unreachable,
26422613 .register_overflow_unsigned => unreachable,
26432614 .register_overflow_signed => unreachable,
26442615 .immediate => |imm| {
......@@ -2660,8 +2631,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
26602631 .undef => unreachable,
26612632 .dead => unreachable,
26622633 .unreach => unreachable,
2663 .compare_flags_unsigned => unreachable,
2664 .compare_flags_signed => unreachable,
2634 .eflags => unreachable,
26652635 .immediate => |imm| {
26662636 switch (abi_size) {
26672637 1, 2, 4 => {
......@@ -3041,18 +3011,17 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
30413011 defer self.register_manager.unlockReg(reg_lock);
30423012
30433013 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,
3014 const cc: Condition = switch (mcv) {
3015 .register_overflow_unsigned => .c,
3016 .register_overflow_signed => .o,
30473017 else => unreachable,
30483018 };
30493019 _ = try self.addInst(.{
3050 .tag = .cond_set_byte_overflow,
3020 .tag = .cond_set_byte,
30513021 .ops = Mir.Inst.Ops.encode(.{
30523022 .reg1 = dst_reg.to8(),
3053 .flags = flags,
30543023 }),
3055 .data = undefined,
3024 .data = .{ .cc = cc },
30563025 });
30573026 break :result MCValue{ .register = dst_reg.to8() };
30583027 },
......@@ -3479,8 +3448,7 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValu
34793448 .none => unreachable,
34803449 .undef => unreachable,
34813450 .dead, .unreach, .immediate => unreachable,
3482 .compare_flags_unsigned => unreachable,
3483 .compare_flags_signed => unreachable,
3451 .eflags => unreachable,
34843452 .register_overflow_unsigned => unreachable,
34853453 .register_overflow_signed => unreachable,
34863454 .register => |dst_reg| {
......@@ -3559,8 +3527,7 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValu
35593527 .memory,
35603528 .got_load,
35613529 .direct_load,
3562 .compare_flags_signed,
3563 .compare_flags_unsigned,
3530 .eflags,
35643531 => {
35653532 assert(abi_size <= 8);
35663533 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
36493616 .got_load, .direct_load => {
36503617 return self.fail("TODO implement x86 ADD/SUB/CMP source symbol at index in linker", .{});
36513618 },
3652 .compare_flags_unsigned => {
3653 return self.fail("TODO implement x86 ADD/SUB/CMP source compare flag (unsigned)", .{});
3654 },
3655 .compare_flags_signed => {
3656 return self.fail("TODO implement x86 ADD/SUB/CMP source compare flag (signed)", .{});
3619 .eflags => {
3620 return self.fail("TODO implement x86 ADD/SUB/CMP source eflags", .{});
36573621 },
36583622 }
36593623 },
......@@ -3674,8 +3638,7 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M
36743638 .none => unreachable,
36753639 .undef => unreachable,
36763640 .dead, .unreach, .immediate => unreachable,
3677 .compare_flags_unsigned => unreachable,
3678 .compare_flags_signed => unreachable,
3641 .eflags => unreachable,
36793642 .ptr_stack_offset => unreachable,
36803643 .register_overflow_unsigned => unreachable,
36813644 .register_overflow_signed => unreachable,
......@@ -3734,11 +3697,8 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M
37343697 .got_load, .direct_load => {
37353698 return self.fail("TODO implement x86 multiply source symbol at index in linker", .{});
37363699 },
3737 .compare_flags_unsigned => {
3738 return self.fail("TODO implement x86 multiply source compare flag (unsigned)", .{});
3739 },
3740 .compare_flags_signed => {
3741 return self.fail("TODO implement x86 multiply source compare flag (signed)", .{});
3700 .eflags => {
3701 return self.fail("TODO implement x86 multiply source eflags", .{});
37423702 },
37433703 }
37443704 },
......@@ -3782,11 +3742,8 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M
37823742 .got_load, .direct_load => {
37833743 return self.fail("TODO implement x86 multiply source symbol at index in linker", .{});
37843744 },
3785 .compare_flags_unsigned => {
3786 return self.fail("TODO implement x86 multiply source compare flag (unsigned)", .{});
3787 },
3788 .compare_flags_signed => {
3789 return self.fail("TODO implement x86 multiply source compare flag (signed)", .{});
3745 .eflags => {
3746 return self.fail("TODO implement x86 multiply source eflags", .{});
37903747 },
37913748 }
37923749 },
......@@ -3905,7 +3862,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.
39053862 var info = try self.resolveCallingConventionValues(fn_ty);
39063863 defer info.deinit(self);
39073864
3908 try self.spillCompareFlagsIfOccupied();
3865 try self.spillEflagsIfOccupied();
39093866
39103867 for (caller_preserved_regs) |reg| {
39113868 try self.register_manager.getReg(reg, null);
......@@ -3957,8 +3914,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.
39573914 .memory => unreachable,
39583915 .got_load => unreachable,
39593916 .direct_load => unreachable,
3960 .compare_flags_signed => unreachable,
3961 .compare_flags_unsigned => unreachable,
3917 .eflags => unreachable,
39623918 .register_overflow_signed => unreachable,
39633919 .register_overflow_unsigned => unreachable,
39643920 }
......@@ -4220,8 +4176,8 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
42204176 break :blk ty.intInfo(self.target.*).signedness;
42214177 };
42224178
4223 try self.spillCompareFlagsIfOccupied();
4224 self.compare_flags_inst = inst;
4179 try self.spillEflagsIfOccupied();
4180 self.eflags_inst = inst;
42254181
42264182 const result: MCValue = result: {
42274183 // There are 2 operands, destination and source.
......@@ -4265,9 +4221,10 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
42654221 defer if (src_lock) |lock| self.register_manager.unlockReg(lock);
42664222
42674223 try self.genBinOpMir(.cmp, ty, dst_mcv, src_mcv);
4224
42684225 break :result switch (signedness) {
4269 .signed => MCValue{ .compare_flags_signed = op },
4270 .unsigned => MCValue{ .compare_flags_unsigned = op },
4226 .signed => MCValue{ .eflags = Condition.fromCompareOperatorSigned(op) },
4227 .unsigned => MCValue{ .eflags = Condition.fromCompareOperatorUnsigned(op) },
42714228 };
42724229 };
42734230
......@@ -4440,47 +4397,39 @@ fn addDbgInfoTypeReloc(self: *Self, ty: Type) !void {
44404397fn genCondBrMir(self: *Self, ty: Type, mcv: MCValue) !u32 {
44414398 const abi_size = ty.abiSize(self.target.*);
44424399 switch (mcv) {
4443 .compare_flags_unsigned,
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;
4400 .eflags => |cc| {
44614401 return self.addInst(.{
4462 .tag = tag,
4463 .ops = Mir.Inst.Ops.encode(.{ .flags = flags }),
4464 .data = .{ .inst = undefined },
4402 .tag = .cond_jmp,
4403 .ops = Mir.Inst.Ops.encode(.{}),
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 },
44654411 });
44664412 },
44674413 .register => |reg| {
4468 try self.spillCompareFlagsIfOccupied();
4414 try self.spillEflagsIfOccupied();
44694415 _ = try self.addInst(.{
44704416 .tag = .@"test",
44714417 .ops = Mir.Inst.Ops.encode(.{ .reg1 = reg }),
44724418 .data = .{ .imm = 1 },
44734419 });
44744420 return self.addInst(.{
4475 .tag = .cond_jmp_eq_ne,
4476 .ops = Mir.Inst.Ops.encode(.{ .flags = 0b01 }),
4477 .data = .{ .inst = undefined },
4421 .tag = .cond_jmp,
4422 .ops = Mir.Inst.Ops.encode(.{}),
4423 .data = .{ .inst_cc = .{
4424 .inst = undefined,
4425 .cc = .e,
4426 } },
44784427 });
44794428 },
44804429 .immediate,
44814430 .stack_offset,
44824431 => {
4483 try self.spillCompareFlagsIfOccupied();
4432 try self.spillEflagsIfOccupied();
44844433 if (abi_size <= 8) {
44854434 const reg = try self.copyToTmpRegister(ty, mcv);
44864435 return self.genCondBrMir(ty, .{ .register = reg });
......@@ -4516,7 +4465,7 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {
45164465 // Capture the state of register and stack allocation state so that we can revert to it.
45174466 const parent_next_stack_offset = self.next_stack_offset;
45184467 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;
45204469 var parent_stack = try self.stack.clone(self.gpa);
45214470 defer parent_stack.deinit(self.gpa);
45224471 const parent_registers = self.register_manager.registers;
......@@ -4538,7 +4487,7 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {
45384487 defer saved_then_branch.deinit(self.gpa);
45394488
45404489 self.register_manager.registers = parent_registers;
4541 self.compare_flags_inst = parent_compare_flags_inst;
4490 self.eflags_inst = parent_eflags_inst;
45424491
45434492 self.stack.deinit(self.gpa);
45444493 self.stack = parent_stack;
......@@ -4640,8 +4589,8 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {
46404589}
46414590
46424591fn isNull(self: *Self, inst: Air.Inst.Index, ty: Type, operand: MCValue) !MCValue {
4643 try self.spillCompareFlagsIfOccupied();
4644 self.compare_flags_inst = inst;
4592 try self.spillEflagsIfOccupied();
4593 self.eflags_inst = inst;
46454594
46464595 const cmp_ty: Type = if (!ty.isPtrLikeOptional()) blk: {
46474596 var buf: Type.Payload.ElemType = undefined;
......@@ -4651,13 +4600,13 @@ fn isNull(self: *Self, inst: Air.Inst.Index, ty: Type, operand: MCValue) !MCValu
46514600
46524601 try self.genBinOpMir(.cmp, cmp_ty, operand, MCValue{ .immediate = 0 });
46534602
4654 return MCValue{ .compare_flags_unsigned = .eq };
4603 return MCValue{ .eflags = .e };
46554604}
46564605
46574606fn isNonNull(self: *Self, inst: Air.Inst.Index, ty: Type, operand: MCValue) !MCValue {
46584607 const is_null_res = try self.isNull(inst, ty, operand);
4659 assert(is_null_res.compare_flags_unsigned == .eq);
4660 return MCValue{ .compare_flags_unsigned = .neq };
4608 assert(is_null_res.eflags == .e);
4609 return MCValue{ .eflags = is_null_res.eflags.negate() };
46614610}
46624611
46634612fn 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
46674616 return MCValue{ .immediate = 0 }; // always false
46684617 }
46694618
4670 try self.spillCompareFlagsIfOccupied();
4671 self.compare_flags_inst = inst;
4619 try self.spillEflagsIfOccupied();
4620 self.eflags_inst = inst;
46724621
46734622 const err_off = errUnionErrorOffset(ty.errorUnionPayload(), self.target.*);
46744623 switch (operand) {
......@@ -4691,15 +4640,15 @@ fn isErr(self: *Self, inst: Air.Inst.Index, ty: Type, operand: MCValue) !MCValue
46914640 else => return self.fail("TODO implement isErr for {}", .{operand}),
46924641 }
46934642
4694 return MCValue{ .compare_flags_unsigned = .gt };
4643 return MCValue{ .eflags = .a };
46954644}
46964645
46974646fn isNonErr(self: *Self, inst: Air.Inst.Index, ty: Type, operand: MCValue) !MCValue {
46984647 const is_err_res = try self.isErr(inst, ty, operand);
46994648 switch (is_err_res) {
4700 .compare_flags_unsigned => |op| {
4701 assert(op == .gt);
4702 return MCValue{ .compare_flags_unsigned = .lte };
4649 .eflags => |cc| {
4650 assert(cc == .a);
4651 return MCValue{ .eflags = cc.negate() };
47034652 },
47044653 .immediate => |imm| {
47054654 assert(imm == 0);
......@@ -4914,10 +4863,9 @@ fn genCondSwitchMir(self: *Self, ty: Type, condition: MCValue, case: MCValue) !u
49144863 .none => unreachable,
49154864 .undef => unreachable,
49164865 .dead, .unreach => unreachable,
4917 .compare_flags_signed => unreachable,
4918 .compare_flags_unsigned => unreachable,
4866 .eflags => unreachable,
49194867 .register => |cond_reg| {
4920 try self.spillCompareFlagsIfOccupied();
4868 try self.spillEflagsIfOccupied();
49214869
49224870 const cond_reg_lock = self.register_manager.lockReg(cond_reg);
49234871 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
49654913 .data = undefined,
49664914 });
49674915 return self.addInst(.{
4968 .tag = .cond_jmp_eq_ne,
4916 .tag = .cond_jmp,
49694917 .ops = Mir.Inst.Ops.encode(.{}),
4970 .data = .{ .inst = undefined },
4918 .data = .{ .inst_cc = .{
4919 .inst = undefined,
4920 .cc = .ne,
4921 } },
49714922 });
49724923 },
49734924 .stack_offset => {
4974 try self.spillCompareFlagsIfOccupied();
4925 try self.spillEflagsIfOccupied();
49754926
49764927 if (abi_size <= 8) {
49774928 const reg = try self.copyToTmpRegister(ty, condition);
......@@ -5030,7 +4981,7 @@ fn airSwitch(self: *Self, inst: Air.Inst.Index) !void {
50304981 // Capture the state of register and stack allocation state so that we can revert to it.
50314982 const parent_next_stack_offset = self.next_stack_offset;
50324983 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;
50344985 var parent_stack = try self.stack.clone(self.gpa);
50354986 defer parent_stack.deinit(self.gpa);
50364987 const parent_registers = self.register_manager.registers;
......@@ -5052,7 +5003,7 @@ fn airSwitch(self: *Self, inst: Air.Inst.Index) !void {
50525003 defer saved_case_branch.deinit(self.gpa);
50535004
50545005 self.register_manager.registers = parent_registers;
5055 self.compare_flags_inst = parent_compare_flags_inst;
5006 self.eflags_inst = parent_eflags_inst;
50565007 self.stack.deinit(self.gpa);
50575008 self.stack = parent_stack;
50585009 parent_stack = .{};
......@@ -5092,7 +5043,15 @@ fn airSwitch(self: *Self, inst: Air.Inst.Index) !void {
50925043
50935044fn performReloc(self: *Self, reloc: Mir.Inst.Index) !void {
50945045 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 }
50965055}
50975056
50985057fn 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 {
51115070 block_data.mcv = switch (operand_mcv) {
51125071 .none, .dead, .unreach => unreachable,
51135072 .register, .stack_offset, .memory => operand_mcv,
5114 .compare_flags_signed, .compare_flags_unsigned, .immediate => blk: {
5073 .eflags, .immediate => blk: {
51155074 const new_mcv = try self.allocRegOrMem(block, true);
51165075 try self.setRegOrMem(self.air.typeOfIndex(block), new_mcv, operand_mcv);
51175076 break :blk new_mcv;
......@@ -5335,9 +5294,7 @@ fn genSetStackArg(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerE
53355294 .register_overflow_unsigned,
53365295 .register_overflow_signed,
53375296 => return self.fail("TODO genSetStackArg for register with overflow bit", .{}),
5338 .compare_flags_unsigned,
5339 .compare_flags_signed,
5340 => {
5297 .eflags => {
53415298 const reg = try self.copyToTmpRegister(ty, mcv);
53425299 return self.genSetStackArg(ty, stack_offset, .{ .register = reg });
53435300 },
......@@ -5484,18 +5441,17 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: Inl
54845441 const overflow_bit_ty = ty.structFieldType(1);
54855442 const overflow_bit_offset = ty.structFieldOffset(1, self.target.*);
54865443 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,
5444 const cc: Condition = switch (mcv) {
5445 .register_overflow_unsigned => .c,
5446 .register_overflow_signed => .o,
54905447 else => unreachable,
54915448 };
54925449 _ = try self.addInst(.{
5493 .tag = .cond_set_byte_overflow,
5450 .tag = .cond_set_byte,
54945451 .ops = Mir.Inst.Ops.encode(.{
54955452 .reg1 = tmp_reg.to8(),
5496 .flags = flags,
54975453 }),
5498 .data = undefined,
5454 .data = .{ .cc = cc },
54995455 });
55005456
55015457 return self.genSetStack(
......@@ -5505,9 +5461,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: Inl
55055461 .{},
55065462 );
55075463 },
5508 .compare_flags_unsigned,
5509 .compare_flags_signed,
5510 => {
5464 .eflags => {
55115465 const reg = try self.copyToTmpRegister(ty, mcv);
55125466 return self.genSetStack(ty, stack_offset, .{ .register = reg }, opts);
55135467 },
......@@ -5832,9 +5786,12 @@ fn genInlineMemcpy(
58325786
58335787 // je end
58345788 const loop_reloc = try self.addInst(.{
5835 .tag = .cond_jmp_eq_ne,
5836 .ops = Mir.Inst.Ops.encode(.{ .flags = 0b01 }),
5837 .data = .{ .inst = undefined },
5789 .tag = .cond_jmp,
5790 .ops = Mir.Inst.Ops.encode(.{}),
5791 .data = .{ .inst_cc = .{
5792 .inst = undefined,
5793 .cc = .e,
5794 } },
58385795 });
58395796
58405797 // mov tmp, [addr + rcx]
......@@ -5950,9 +5907,12 @@ fn genInlineMemset(
59505907
59515908 // je end
59525909 const loop_reloc = try self.addInst(.{
5953 .tag = .cond_jmp_eq_ne,
5954 .ops = Mir.Inst.Ops.encode(.{ .flags = 0b01 }),
5955 .data = .{ .inst = undefined },
5910 .tag = .cond_jmp,
5911 .ops = Mir.Inst.Ops.encode(.{}),
5912 .data = .{ .inst_cc = .{
5913 .inst = undefined,
5914 .cc = .e,
5915 } },
59565916 });
59575917
59585918 switch (value) {
......@@ -6025,31 +5985,13 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
60255985 else => unreachable,
60265986 }
60275987 },
6028 .compare_flags_unsigned,
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 };
5988 .eflags => |cc| {
60465989 _ = try self.addInst(.{
6047 .tag = tag,
5990 .tag = .cond_set_byte,
60485991 .ops = Mir.Inst.Ops.encode(.{
60495992 .reg1 = reg.to8(),
6050 .flags = flags,
60515993 }),
6052 .data = undefined,
5994 .data = .{ .cc = cc },
60535995 });
60545996 },
60555997 .immediate => |x| {
src/arch/x86_64/Emit.zig+221-75
......@@ -158,20 +158,9 @@ pub fn lowerMir(emit: *Emit) InnerError!void {
158158 .jmp => try emit.mirJmpCall(.jmp_near, inst),
159159 .call => try emit.mirJmpCall(.call_near, inst),
160160
161 .cond_jmp_greater_less,
162 .cond_jmp_above_below,
163 .cond_jmp_eq_ne,
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),
161 .cond_jmp => try emit.mirCondJmp(inst),
162 .cond_set_byte => try emit.mirCondSetByte(inst),
163 .cond_mov => try emit.mirCondMov(inst),
175164
176165 .ret => try emit.mirRet(inst),
177166
......@@ -356,70 +345,130 @@ fn mirJmpCall(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {
356345 }
357346}
358347
359fn mirCondJmp(emit: *Emit, mir_tag: Mir.Inst.Tag, inst: Mir.Inst.Index) InnerError!void {
360 const ops = emit.mir.instructions.items(.ops)[inst].decode();
361 const target = emit.mir.instructions.items(.data)[inst].inst;
362 const tag = switch (mir_tag) {
363 .cond_jmp_greater_less => switch (ops.flags) {
364 0b00 => Tag.jge,
365 0b01 => Tag.jg,
366 0b10 => Tag.jl,
367 0b11 => Tag.jle,
368 },
369 .cond_jmp_above_below => switch (ops.flags) {
370 0b00 => Tag.jae,
371 0b01 => Tag.ja,
372 0b10 => Tag.jb,
373 0b11 => Tag.jbe,
374 },
375 .cond_jmp_eq_ne => switch (@truncate(u1, ops.flags)) {
376 0b0 => Tag.jne,
377 0b1 => Tag.je,
378 },
379 else => unreachable,
348fn mirCondJmp(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
349 const mir_tag = emit.mir.instructions.items(.tag)[inst];
350 assert(mir_tag == .cond_jmp);
351 const inst_cc = emit.mir.instructions.items(.data)[inst].inst_cc;
352 const tag: Tag = switch (inst_cc.cc) {
353 .a => .ja,
354 .ae => .jae,
355 .b => .jb,
356 .be => .jbe,
357 .c => .jc,
358 .e => .je,
359 .g => .jg,
360 .ge => .jge,
361 .l => .jl,
362 .le => .jle,
363 .na => .jna,
364 .nae => .jnae,
365 .nb => .jnb,
366 .nbe => .jnbe,
367 .nc => .jnc,
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,
380383 };
381384 const source = emit.code.items.len;
382385 try lowerToDEnc(tag, 0, emit.code);
383386 try emit.relocs.append(emit.bin_file.allocator, .{
384387 .source = source,
385 .target = target,
388 .target = inst_cc.inst,
386389 .offset = emit.code.items.len - 4,
387390 .length = 6,
388391 });
389392}
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);
392397 const ops = emit.mir.instructions.items(.ops)[inst].decode();
393 const tag = switch (mir_tag) {
394 .cond_set_byte_greater_less => switch (ops.flags) {
395 0b00 => Tag.setge,
396 0b01 => Tag.setg,
397 0b10 => Tag.setl,
398 0b11 => Tag.setle,
399 },
400 .cond_set_byte_above_below => switch (ops.flags) {
401 0b00 => Tag.setae,
402 0b01 => Tag.seta,
403 0b10 => Tag.setb,
404 0b11 => Tag.setbe,
405 },
406 .cond_set_byte_eq_ne => switch (@truncate(u1, ops.flags)) {
407 0b0 => Tag.setne,
408 0b1 => Tag.sete,
409 },
410 .cond_set_byte_overflow => switch (ops.flags) {
411 0b00 => Tag.seto,
412 0b01 => Tag.setno,
413 0b10 => Tag.setc,
414 0b11 => Tag.setnc,
415 },
416 else => unreachable,
398 const cc = emit.mir.instructions.items(.data)[inst].cc;
399 const tag: Tag = switch (cc) {
400 .a => .seta,
401 .ae => .setae,
402 .b => .setb,
403 .be => .setbe,
404 .c => .setc,
405 .e => .sete,
406 .g => .setg,
407 .ge => .setge,
408 .l => .setl,
409 .le => .setle,
410 .na => .setna,
411 .nae => .setnae,
412 .nb => .setnb,
413 .nbe => .setnbe,
414 .nc => .setnc,
415 .ne => .setne,
416 .ng => .setng,
417 .nge => .setnge,
418 .nl => .setnl,
419 .nle => .setnle,
420 .no => .setno,
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,
417430 };
418431 return lowerToMEnc(tag, RegisterOrMemory.reg(ops.reg1.to8()), emit.code);
419432}
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);
422437 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
423472 if (ops.flags == 0b00) {
424473 return lowerToRmEnc(tag, ops.reg1, RegisterOrMemory.reg(ops.reg2), emit.code);
425474 }
......@@ -1277,7 +1326,7 @@ const Tag = enum {
12771326 setp,
12781327 setpe,
12791328 setnp,
1280 setop,
1329 setpo,
12811330 setl,
12821331 setnge,
12831332 setnl,
......@@ -1286,6 +1335,36 @@ const Tag = enum {
12861335 setng,
12871336 setnle,
12881337 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,
12891368 shl,
12901369 sal,
12911370 shr,
......@@ -1294,12 +1373,6 @@ const Tag = enum {
12941373 cwd,
12951374 cdq,
12961375 cqo,
1297 cmove,
1298 cmovz,
1299 cmovl,
1300 cmovng,
1301 cmovb,
1302 cmovnae,
13031376 movsd,
13041377 movss,
13051378 addsd,
......@@ -1372,7 +1445,7 @@ const Tag = enum {
13721445 .setp,
13731446 .setpe,
13741447 .setnp,
1375 .setop,
1448 .setpo,
13761449 .setl,
13771450 .setnge,
13781451 .setnl,
......@@ -1492,77 +1565,110 @@ inline fn getOpCode(tag: Tag, enc: Encoding, is_one_byte: bool) OpCode {
14921565 .d => return switch (tag) {
14931566 .jmp_near => OpCode.init(&.{0xe9}),
14941567 .call_near => OpCode.init(&.{0xe8}),
1568
14951569 .jo => if (is_one_byte) OpCode.init(&.{0x70}) else OpCode.init(&.{0x0f,0x80}),
1570
14961571 .jno => if (is_one_byte) OpCode.init(&.{0x71}) else OpCode.init(&.{0x0f,0x81}),
1572
14971573 .jb,
14981574 .jc,
14991575 .jnae => if (is_one_byte) OpCode.init(&.{0x72}) else OpCode.init(&.{0x0f,0x82}),
1576
15001577 .jnb,
15011578 .jnc,
15021579 .jae => if (is_one_byte) OpCode.init(&.{0x73}) else OpCode.init(&.{0x0f,0x83}),
1580
15031581 .je,
15041582 .jz => if (is_one_byte) OpCode.init(&.{0x74}) else OpCode.init(&.{0x0f,0x84}),
1583
15051584 .jne,
15061585 .jnz => if (is_one_byte) OpCode.init(&.{0x75}) else OpCode.init(&.{0x0f,0x85}),
1586
15071587 .jna,
15081588 .jbe => if (is_one_byte) OpCode.init(&.{0x76}) else OpCode.init(&.{0x0f,0x86}),
1589
15091590 .jnbe,
15101591 .ja => if (is_one_byte) OpCode.init(&.{0x77}) else OpCode.init(&.{0x0f,0x87}),
1592
15111593 .js => if (is_one_byte) OpCode.init(&.{0x78}) else OpCode.init(&.{0x0f,0x88}),
1594
15121595 .jns => if (is_one_byte) OpCode.init(&.{0x79}) else OpCode.init(&.{0x0f,0x89}),
1596
15131597 .jpe,
15141598 .jp => if (is_one_byte) OpCode.init(&.{0x7a}) else OpCode.init(&.{0x0f,0x8a}),
1599
15151600 .jpo,
15161601 .jnp => if (is_one_byte) OpCode.init(&.{0x7b}) else OpCode.init(&.{0x0f,0x8b}),
1602
15171603 .jnge,
15181604 .jl => if (is_one_byte) OpCode.init(&.{0x7c}) else OpCode.init(&.{0x0f,0x8c}),
1605
15191606 .jge,
15201607 .jnl => if (is_one_byte) OpCode.init(&.{0x7d}) else OpCode.init(&.{0x0f,0x8d}),
1608
15211609 .jle,
15221610 .jng => if (is_one_byte) OpCode.init(&.{0x7e}) else OpCode.init(&.{0x0f,0x8e}),
1611
15231612 .jg,
15241613 .jnle => if (is_one_byte) OpCode.init(&.{0x7f}) else OpCode.init(&.{0x0f,0x8f}),
1614
15251615 else => unreachable,
15261616 },
15271617 .m => return switch (tag) {
15281618 .jmp_near,
15291619 .call_near,
15301620 .push => OpCode.init(&.{0xff}),
1621
15311622 .pop => OpCode.init(&.{0x8f}),
15321623 .seto => OpCode.init(&.{0x0f,0x90}),
15331624 .setno => OpCode.init(&.{0x0f,0x91}),
1625
15341626 .setb,
15351627 .setc,
15361628 .setnae => OpCode.init(&.{0x0f,0x92}),
1629
15371630 .setnb,
15381631 .setnc,
15391632 .setae => OpCode.init(&.{0x0f,0x93}),
1633
15401634 .sete,
15411635 .setz => OpCode.init(&.{0x0f,0x94}),
1636
15421637 .setne,
15431638 .setnz => OpCode.init(&.{0x0f,0x95}),
1639
15441640 .setbe,
15451641 .setna => OpCode.init(&.{0x0f,0x96}),
1642
15461643 .seta,
15471644 .setnbe => OpCode.init(&.{0x0f,0x97}),
1645
15481646 .sets => OpCode.init(&.{0x0f,0x98}),
15491647 .setns => OpCode.init(&.{0x0f,0x99}),
1648
15501649 .setp,
15511650 .setpe => OpCode.init(&.{0x0f,0x9a}),
1651
15521652 .setnp,
1553 .setop => OpCode.init(&.{0x0f,0x9b}),
1653 .setpo => OpCode.init(&.{0x0f,0x9b}),
1654
15541655 .setl,
15551656 .setnge => OpCode.init(&.{0x0f,0x9c}),
1657
15561658 .setnl,
15571659 .setge => OpCode.init(&.{0x0f,0x9d}),
1660
15581661 .setle,
15591662 .setng => OpCode.init(&.{0x0f,0x9e}),
1663
15601664 .setnle,
15611665 .setg => OpCode.init(&.{0x0f,0x9f}),
1666
15621667 .idiv,
15631668 .div,
15641669 .imul,
15651670 .mul => if (is_one_byte) OpCode.init(&.{0xf6}) else OpCode.init(&.{0xf7}),
1671
15661672 .fisttp16 => OpCode.init(&.{0xdf}),
15671673 .fisttp32 => OpCode.init(&.{0xdb}),
15681674 .fisttp64 => OpCode.init(&.{0xdd}),
......@@ -1640,12 +1746,52 @@ inline fn getOpCode(tag: Tag, enc: Encoding, is_one_byte: bool) OpCode {
16401746 .movzx => if (is_one_byte) OpCode.init(&.{0x0f,0xb6}) else OpCode.init(&.{0x0f,0xb7}),
16411747 .lea => if (is_one_byte) OpCode.init(&.{0x8c}) else OpCode.init(&.{0x8d}),
16421748 .imul => OpCode.init(&.{0x0f,0xaf}),
1643 .cmove,
1644 .cmovz => OpCode.init(&.{0x0f,0x44}),
1749
1750 .cmova,
1751 .cmovnbe, => OpCode.init(&.{0x0f,0x47}),
1752
1753 .cmovae,
1754 .cmovnb, => OpCode.init(&.{0x0f,0x43}),
1755
16451756 .cmovb,
1757 .cmovc,
16461758 .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
16471772 .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
16491795 .movsd => OpCode.init(&.{0xf2,0x0f,0x10}),
16501796 .movss => OpCode.init(&.{0xf3,0x0f,0x10}),
16511797 .addsd => OpCode.init(&.{0xf2,0x0f,0x58}),
......@@ -1735,7 +1881,7 @@ inline fn getModRmExt(tag: Tag) u3 {
17351881 .setp,
17361882 .setpe,
17371883 .setnp,
1738 .setop,
1884 .setpo,
17391885 .setl,
17401886 .setnge,
17411887 .setnl,
src/arch/x86_64/Mir.zig+21-28
......@@ -275,42 +275,25 @@ pub const Inst = struct {
275275 call,
276276
277277 /// ops flags:
278 /// 0b00 gte
279 /// 0b01 gt
280 /// 0b10 lt
281 /// 0b11 lte
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,
278 /// unused
279 /// Notes:
280 /// * uses `inst_cc` in Data.
281 cond_jmp,
292282
293283 /// ops flags:
294 /// 0bX0 ne
295 /// 0bX1 eq
296 cond_jmp_eq_ne,
297 cond_set_byte_eq_ne,
284 /// 0b00 reg1
285 /// Notes:
286 /// * uses condition code (CC) stored as part of data
287 cond_set_byte,
298288
299289 /// ops flags:
300290 /// 0b00 reg1, reg2,
301291 /// 0b01 reg1, word ptr [reg2 + imm]
302292 /// 0b10 reg1, dword ptr [reg2 + imm]
303293 /// 0b11 reg1, qword ptr [reg2 + imm]
304 cond_mov_eq,
305 cond_mov_lt,
306 cond_mov_below,
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,
294 /// Notes:
295 /// * uses condition code (CC) stored as part of data
296 cond_mov,
314297
315298 /// ops flags: form:
316299 /// 0b00 reg1
......@@ -451,6 +434,16 @@ pub const Inst = struct {
451434 inst: Index,
452435 /// A 32-bit immediate value.
453436 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 },
454447 /// An extern function.
455448 extern_fn: struct {
456449 /// Index of the containing atom.
src/arch/x86_64/bits.zig+129
......@@ -6,6 +6,135 @@ const ArrayList = std.ArrayList;
66const Allocator = std.mem.Allocator;
77const 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
9138// zig fmt: off
10139
11140/// Definitions of all of the general purpose x64 registers. The order is semantically meaningful.