| ... | @@ -37,6 +37,7 @@ const caller_preserved_regs = abi.caller_preserved_regs; | ... | @@ -37,6 +37,7 @@ const caller_preserved_regs = abi.caller_preserved_regs; |
| 37 | const c_abi_int_param_regs = abi.c_abi_int_param_regs; | 37 | const c_abi_int_param_regs = abi.c_abi_int_param_regs; |
| 38 | const c_abi_int_return_regs = abi.c_abi_int_return_regs; | 38 | const c_abi_int_return_regs = abi.c_abi_int_return_regs; |
| 39 | | 39 | |
| | 40 | const Condition = bits.Condition; |
| 40 | const RegisterManager = abi.RegisterManager; | 41 | const RegisterManager = abi.RegisterManager; |
| 41 | const RegisterLock = RegisterManager.RegisterLock; | 42 | const RegisterLock = RegisterManager.RegisterLock; |
| 42 | const Register = bits.Register; | 43 | const Register = bits.Register; |
| ... | @@ -65,7 +66,7 @@ arg_index: u32, | ... | @@ -65,7 +66,7 @@ arg_index: u32, |
| 65 | src_loc: Module.SrcLoc, | 66 | src_loc: Module.SrcLoc, |
| 66 | stack_align: u32, | 67 | stack_align: u32, |
| 67 | | 68 | |
| 68 | compare_flags_inst: ?Air.Inst.Index = null, | 69 | eflags_inst: ?Air.Inst.Index = null, |
| 69 | | 70 | |
| 70 | /// MIR Instructions | 71 | /// MIR Instructions |
| 71 | mir_instructions: std.MultiArrayList(Mir.Inst) = .{}, | 72 | mir_instructions: std.MultiArrayList(Mir.Inst) = .{}, |
| ... | @@ -149,12 +150,8 @@ pub const MCValue = union(enum) { | ... | @@ -149,12 +150,8 @@ pub const MCValue = union(enum) { |
| 149 | stack_offset: i32, | 150 | stack_offset: i32, |
| 150 | /// The value is a pointer to one of the stack variables (payload is stack offset). | 151 | /// The value is a pointer to one of the stack variables (payload is stack offset). |
| 151 | ptr_stack_offset: i32, | 152 | ptr_stack_offset: i32, |
| 152 | /// The value is in the compare flags assuming an unsigned operation, | 153 | /// The value resides in the EFLAGS register. |
| 153 | /// with this operator applied on top of it. | 154 | eflags: Condition, |
| 154 | compare_flags_unsigned: math.CompareOperator, | | |
| 155 | /// The value is in the compare flags assuming a signed operation, | | |
| 156 | /// with this operator applied on top of it. | | |
| 157 | compare_flags_signed: math.CompareOperator, | | |
| 158 | | 155 | |
| 159 | fn isMemory(mcv: MCValue) bool { | 156 | fn isMemory(mcv: MCValue) bool { |
| 160 | return switch (mcv) { | 157 | return switch (mcv) { |
| ... | @@ -183,8 +180,7 @@ pub const MCValue = union(enum) { | ... | @@ -183,8 +180,7 @@ pub const MCValue = union(enum) { |
| 183 | | 180 | |
| 184 | .immediate, | 181 | .immediate, |
| 185 | .memory, | 182 | .memory, |
| 186 | .compare_flags_unsigned, | 183 | .eflags, |
| 187 | .compare_flags_signed, | | |
| 188 | .ptr_stack_offset, | 184 | .ptr_stack_offset, |
| 189 | .undef, | 185 | .undef, |
| 190 | .register_overflow_unsigned, | 186 | .register_overflow_unsigned, |
| ... | @@ -780,10 +776,10 @@ fn processDeath(self: *Self, inst: Air.Inst.Index) void { | ... | @@ -780,10 +776,10 @@ fn processDeath(self: *Self, inst: Air.Inst.Index) void { |
| 780 | }, | 776 | }, |
| 781 | .register_overflow_signed, .register_overflow_unsigned => |reg| { | 777 | .register_overflow_signed, .register_overflow_unsigned => |reg| { |
| 782 | self.register_manager.freeReg(reg.to64()); | 778 | self.register_manager.freeReg(reg.to64()); |
| 783 | self.compare_flags_inst = null; | 779 | self.eflags_inst = null; |
| 784 | }, | 780 | }, |
| 785 | .compare_flags_signed, .compare_flags_unsigned => { | 781 | .eflags => { |
| 786 | self.compare_flags_inst = null; | 782 | self.eflags_inst = null; |
| 787 | }, | 783 | }, |
| 788 | else => {}, // TODO process stack allocation death | 784 | else => {}, // TODO process stack allocation death |
| 789 | } | 785 | } |
| ... | @@ -929,16 +925,14 @@ pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void | ... | @@ -929,16 +925,14 @@ pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void |
| 929 | try self.genSetStack(self.air.typeOfIndex(inst), stack_mcv.stack_offset, reg_mcv, .{}); | 925 | try self.genSetStack(self.air.typeOfIndex(inst), stack_mcv.stack_offset, reg_mcv, .{}); |
| 930 | } | 926 | } |
| 931 | | 927 | |
| 932 | pub fn spillCompareFlagsIfOccupied(self: *Self) !void { | 928 | pub fn spillEflagsIfOccupied(self: *Self) !void { |
| 933 | if (self.compare_flags_inst) |inst_to_save| { | 929 | if (self.eflags_inst) |inst_to_save| { |
| 934 | const mcv = self.getResolvedInstValue(inst_to_save); | 930 | const mcv = self.getResolvedInstValue(inst_to_save); |
| 935 | const new_mcv = switch (mcv) { | 931 | const new_mcv = switch (mcv) { |
| 936 | .register_overflow_signed, | 932 | .register_overflow_signed, |
| 937 | .register_overflow_unsigned, | 933 | .register_overflow_unsigned, |
| 938 | => try self.allocRegOrMem(inst_to_save, false), | 934 | => try self.allocRegOrMem(inst_to_save, false), |
| 939 | .compare_flags_signed, | 935 | .eflags => try self.allocRegOrMem(inst_to_save, true), |
| 940 | .compare_flags_unsigned, | | |
| 941 | => try self.allocRegOrMem(inst_to_save, true), | | |
| 942 | else => unreachable, | 936 | else => unreachable, |
| 943 | }; | 937 | }; |
| 944 | | 938 | |
| ... | @@ -948,7 +942,7 @@ pub fn spillCompareFlagsIfOccupied(self: *Self) !void { | ... | @@ -948,7 +942,7 @@ pub fn spillCompareFlagsIfOccupied(self: *Self) !void { |
| 948 | const branch = &self.branch_stack.items[self.branch_stack.items.len - 1]; | 942 | const branch = &self.branch_stack.items[self.branch_stack.items.len - 1]; |
| 949 | try branch.inst_table.put(self.gpa, inst_to_save, new_mcv); | 943 | try branch.inst_table.put(self.gpa, inst_to_save, new_mcv); |
| 950 | | 944 | |
| 951 | self.compare_flags_inst = null; | 945 | self.eflags_inst = null; |
| 952 | | 946 | |
| 953 | // TODO consolidate with register manager and spillInstruction | 947 | // TODO consolidate with register manager and spillInstruction |
| 954 | // this call should really belong in the register manager! | 948 | // this call should really belong in the register manager! |
| ... | @@ -1123,31 +1117,8 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1123,31 +1117,8 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void { |
| 1123 | switch (operand) { | 1117 | switch (operand) { |
| 1124 | .dead => unreachable, | 1118 | .dead => unreachable, |
| 1125 | .unreach => unreachable, | 1119 | .unreach => unreachable, |
| 1126 | .compare_flags_unsigned => |op| { | 1120 | .eflags => |cc| { |
| 1127 | const r = MCValue{ | 1121 | break :result MCValue{ .eflags = cc.negate() }; |
| 1128 | .compare_flags_unsigned = switch (op) { | | |
| 1129 | .gte => .lt, | | |
| 1130 | .gt => .lte, | | |
| 1131 | .neq => .eq, | | |
| 1132 | .lt => .gte, | | |
| 1133 | .lte => .gt, | | |
| 1134 | .eq => .neq, | | |
| 1135 | }, | | |
| 1136 | }; | | |
| 1137 | break :result r; | | |
| 1138 | }, | | |
| 1139 | .compare_flags_signed => |op| { | | |
| 1140 | const r = MCValue{ | | |
| 1141 | .compare_flags_signed = switch (op) { | | |
| 1142 | .gte => .lt, | | |
| 1143 | .gt => .lte, | | |
| 1144 | .neq => .eq, | | |
| 1145 | .lt => .gte, | | |
| 1146 | .lte => .gt, | | |
| 1147 | .eq => .neq, | | |
| 1148 | }, | | |
| 1149 | }; | | |
| 1150 | break :result r; | | |
| 1151 | }, | 1122 | }, |
| 1152 | else => {}, | 1123 | else => {}, |
| 1153 | } | 1124 | } |
| ... | @@ -1213,13 +1184,17 @@ fn airMin(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1213,13 +1184,17 @@ fn airMin(self: *Self, inst: Air.Inst.Index) !void { |
| 1213 | try self.genBinOpMir(.cmp, ty, .{ .register = lhs_reg }, rhs_mcv); | 1184 | try self.genBinOpMir(.cmp, ty, .{ .register = lhs_reg }, rhs_mcv); |
| 1214 | | 1185 | |
| 1215 | const dst_mcv = try self.copyToRegisterWithInstTracking(inst, ty, rhs_mcv); | 1186 | const dst_mcv = try self.copyToRegisterWithInstTracking(inst, ty, rhs_mcv); |
| | 1187 | const cc: Condition = switch (signedness) { |
| | 1188 | .unsigned => .b, |
| | 1189 | .signed => .l, |
| | 1190 | }; |
| 1216 | _ = try self.addInst(.{ | 1191 | _ = try self.addInst(.{ |
| 1217 | .tag = if (signedness == .signed) .cond_mov_lt else .cond_mov_below, | 1192 | .tag = .cond_mov, |
| 1218 | .ops = Mir.Inst.Ops.encode(.{ | 1193 | .ops = Mir.Inst.Ops.encode(.{ |
| 1219 | .reg1 = dst_mcv.register, | 1194 | .reg1 = dst_mcv.register, |
| 1220 | .reg2 = lhs_reg, | 1195 | .reg2 = lhs_reg, |
| 1221 | }), | 1196 | }), |
| 1222 | .data = undefined, | 1197 | .data = .{ .cc = cc }, |
| 1223 | }); | 1198 | }); |
| 1224 | | 1199 | |
| 1225 | break :result dst_mcv; | 1200 | break :result dst_mcv; |
| ... | @@ -1341,7 +1316,7 @@ fn airAddSubShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1341,7 +1316,7 @@ fn airAddSubShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1341 | return self.fail("TODO implement add/sub/shl with overflow for Ints larger than 64bits", .{}); | 1316 | return self.fail("TODO implement add/sub/shl with overflow for Ints larger than 64bits", .{}); |
| 1342 | } | 1317 | } |
| 1343 | | 1318 | |
| 1344 | try self.spillCompareFlagsIfOccupied(); | 1319 | try self.spillEflagsIfOccupied(); |
| 1345 | | 1320 | |
| 1346 | if (tag == .shl_with_overflow) { | 1321 | if (tag == .shl_with_overflow) { |
| 1347 | try self.spillRegisters(1, .{.rcx}); | 1322 | try self.spillRegisters(1, .{.rcx}); |
| ... | @@ -1362,7 +1337,7 @@ fn airAddSubShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1362,7 +1337,7 @@ fn airAddSubShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1362 | const int_info = ty.intInfo(self.target.*); | 1337 | const int_info = ty.intInfo(self.target.*); |
| 1363 | | 1338 | |
| 1364 | if (math.isPowerOfTwo(int_info.bits) and int_info.bits >= 8) { | 1339 | if (math.isPowerOfTwo(int_info.bits) and int_info.bits >= 8) { |
| 1365 | self.compare_flags_inst = inst; | 1340 | self.eflags_inst = inst; |
| 1366 | | 1341 | |
| 1367 | const result: MCValue = switch (int_info.signedness) { | 1342 | const result: MCValue = switch (int_info.signedness) { |
| 1368 | .signed => .{ .register_overflow_signed = partial.register }, | 1343 | .signed => .{ .register_overflow_signed = partial.register }, |
| ... | @@ -1371,7 +1346,7 @@ fn airAddSubShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1371,7 +1346,7 @@ fn airAddSubShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1371 | break :result result; | 1346 | break :result result; |
| 1372 | } | 1347 | } |
| 1373 | | 1348 | |
| 1374 | self.compare_flags_inst = null; | 1349 | self.eflags_inst = null; |
| 1375 | | 1350 | |
| 1376 | const tuple_ty = self.air.typeOfIndex(inst); | 1351 | const tuple_ty = self.air.typeOfIndex(inst); |
| 1377 | const tuple_size = @intCast(u32, tuple_ty.abiSize(self.target.*)); | 1352 | const tuple_size = @intCast(u32, tuple_ty.abiSize(self.target.*)); |
| ... | @@ -1413,17 +1388,16 @@ fn genSetStackTruncatedOverflowCompare( | ... | @@ -1413,17 +1388,16 @@ fn genSetStackTruncatedOverflowCompare( |
| 1413 | }; | 1388 | }; |
| 1414 | | 1389 | |
| 1415 | const overflow_reg = temp_regs[0]; | 1390 | const overflow_reg = temp_regs[0]; |
| 1416 | const flags: u2 = switch (int_info.signedness) { | 1391 | const cc: Condition = switch (int_info.signedness) { |
| 1417 | .signed => 0b00, | 1392 | .signed => .o, |
| 1418 | .unsigned => 0b10, | 1393 | .unsigned => .c, |
| 1419 | }; | 1394 | }; |
| 1420 | _ = try self.addInst(.{ | 1395 | _ = try self.addInst(.{ |
| 1421 | .tag = .cond_set_byte_overflow, | 1396 | .tag = .cond_set_byte, |
| 1422 | .ops = Mir.Inst.Ops.encode(.{ | 1397 | .ops = Mir.Inst.Ops.encode(.{ |
| 1423 | .reg1 = overflow_reg.to8(), | 1398 | .reg1 = overflow_reg.to8(), |
| 1424 | .flags = flags, | | |
| 1425 | }), | 1399 | }), |
| 1426 | .data = undefined, | 1400 | .data = .{ .cc = cc }, |
| 1427 | }); | 1401 | }); |
| 1428 | | 1402 | |
| 1429 | const scratch_reg = temp_regs[1]; | 1403 | const scratch_reg = temp_regs[1]; |
| ... | @@ -1438,9 +1412,9 @@ fn genSetStackTruncatedOverflowCompare( | ... | @@ -1438,9 +1412,9 @@ fn genSetStackTruncatedOverflowCompare( |
| 1438 | | 1412 | |
| 1439 | const eq_reg = temp_regs[2]; | 1413 | const eq_reg = temp_regs[2]; |
| 1440 | _ = try self.addInst(.{ | 1414 | _ = try self.addInst(.{ |
| 1441 | .tag = .cond_set_byte_eq_ne, | 1415 | .tag = .cond_set_byte, |
| 1442 | .ops = Mir.Inst.Ops.encode(.{ .reg1 = eq_reg.to8() }), | 1416 | .ops = Mir.Inst.Ops.encode(.{ .reg1 = eq_reg.to8() }), |
| 1443 | .data = undefined, | 1417 | .data = .{ .cc = .ne }, |
| 1444 | }); | 1418 | }); |
| 1445 | | 1419 | |
| 1446 | try self.genBinOpMir( | 1420 | try self.genBinOpMir( |
| ... | @@ -1477,8 +1451,8 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1477,8 +1451,8 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1477 | const int_info = ty.intInfo(self.target.*); | 1451 | const int_info = ty.intInfo(self.target.*); |
| 1478 | | 1452 | |
| 1479 | if (math.isPowerOfTwo(int_info.bits) and int_info.bits >= 8) { | 1453 | if (math.isPowerOfTwo(int_info.bits) and int_info.bits >= 8) { |
| 1480 | try self.spillCompareFlagsIfOccupied(); | 1454 | try self.spillEflagsIfOccupied(); |
| 1481 | self.compare_flags_inst = inst; | 1455 | self.eflags_inst = inst; |
| 1482 | | 1456 | |
| 1483 | try self.spillRegisters(2, .{ .rax, .rdx }); | 1457 | try self.spillRegisters(2, .{ .rax, .rdx }); |
| 1484 | | 1458 | |
| ... | @@ -1492,8 +1466,8 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1492,8 +1466,8 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1492 | }; | 1466 | }; |
| 1493 | } | 1467 | } |
| 1494 | | 1468 | |
| 1495 | try self.spillCompareFlagsIfOccupied(); | 1469 | try self.spillEflagsIfOccupied(); |
| 1496 | self.compare_flags_inst = null; | 1470 | self.eflags_inst = null; |
| 1497 | | 1471 | |
| 1498 | const dst_reg: Register = dst_reg: { | 1472 | const dst_reg: Register = dst_reg: { |
| 1499 | switch (int_info.signedness) { | 1473 | switch (int_info.signedness) { |
| ... | @@ -1686,12 +1660,12 @@ fn genInlineIntDivFloor(self: *Self, ty: Type, lhs: MCValue, rhs: MCValue) !MCVa | ... | @@ -1686,12 +1660,12 @@ fn genInlineIntDivFloor(self: *Self, ty: Type, lhs: MCValue, rhs: MCValue) !MCVa |
| 1686 | .data = undefined, | 1660 | .data = undefined, |
| 1687 | }); | 1661 | }); |
| 1688 | _ = try self.addInst(.{ | 1662 | _ = try self.addInst(.{ |
| 1689 | .tag = .cond_mov_eq, | 1663 | .tag = .cond_mov, |
| 1690 | .ops = Mir.Inst.Ops.encode(.{ | 1664 | .ops = Mir.Inst.Ops.encode(.{ |
| 1691 | .reg1 = divisor.to64(), | 1665 | .reg1 = divisor.to64(), |
| 1692 | .reg2 = .rdx, | 1666 | .reg2 = .rdx, |
| 1693 | }), | 1667 | }), |
| 1694 | .data = undefined, | 1668 | .data = .{ .cc = .e }, |
| 1695 | }); | 1669 | }); |
| 1696 | try self.genBinOpMir(.add, Type.isize, .{ .register = divisor }, .{ .register = .rax }); | 1670 | try self.genBinOpMir(.add, Type.isize, .{ .register = divisor }, .{ .register = .rax }); |
| 1697 | return MCValue{ .register = divisor }; | 1671 | return MCValue{ .register = divisor }; |
| ... | @@ -2511,8 +2485,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo | ... | @@ -2511,8 +2485,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo |
| 2511 | .undef => unreachable, | 2485 | .undef => unreachable, |
| 2512 | .unreach => unreachable, | 2486 | .unreach => unreachable, |
| 2513 | .dead => unreachable, | 2487 | .dead => unreachable, |
| 2514 | .compare_flags_unsigned => unreachable, | 2488 | .eflags => unreachable, |
| 2515 | .compare_flags_signed => unreachable, | | |
| 2516 | .register_overflow_unsigned => unreachable, | 2489 | .register_overflow_unsigned => unreachable, |
| 2517 | .register_overflow_signed => unreachable, | 2490 | .register_overflow_signed => unreachable, |
| 2518 | .immediate => |imm| { | 2491 | .immediate => |imm| { |
| ... | @@ -2532,8 +2505,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo | ... | @@ -2532,8 +2505,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo |
| 2532 | switch (dst_mcv) { | 2505 | switch (dst_mcv) { |
| 2533 | .dead => unreachable, | 2506 | .dead => unreachable, |
| 2534 | .undef => unreachable, | 2507 | .undef => unreachable, |
| 2535 | .compare_flags_unsigned => unreachable, | 2508 | .eflags => unreachable, |
| 2536 | .compare_flags_signed => unreachable, | | |
| 2537 | .register => |dst_reg| { | 2509 | .register => |dst_reg| { |
| 2538 | // mov dst_reg, [reg] | 2510 | // mov dst_reg, [reg] |
| 2539 | _ = try self.addInst(.{ | 2511 | _ = try self.addInst(.{ |
| ... | @@ -2637,8 +2609,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type | ... | @@ -2637,8 +2609,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type |
| 2637 | .undef => unreachable, | 2609 | .undef => unreachable, |
| 2638 | .unreach => unreachable, | 2610 | .unreach => unreachable, |
| 2639 | .dead => unreachable, | 2611 | .dead => unreachable, |
| 2640 | .compare_flags_unsigned => unreachable, | 2612 | .eflags => unreachable, |
| 2641 | .compare_flags_signed => unreachable, | | |
| 2642 | .register_overflow_unsigned => unreachable, | 2613 | .register_overflow_unsigned => unreachable, |
| 2643 | .register_overflow_signed => unreachable, | 2614 | .register_overflow_signed => unreachable, |
| 2644 | .immediate => |imm| { | 2615 | .immediate => |imm| { |
| ... | @@ -2660,8 +2631,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type | ... | @@ -2660,8 +2631,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type |
| 2660 | .undef => unreachable, | 2631 | .undef => unreachable, |
| 2661 | .dead => unreachable, | 2632 | .dead => unreachable, |
| 2662 | .unreach => unreachable, | 2633 | .unreach => unreachable, |
| 2663 | .compare_flags_unsigned => unreachable, | 2634 | .eflags => unreachable, |
| 2664 | .compare_flags_signed => unreachable, | | |
| 2665 | .immediate => |imm| { | 2635 | .immediate => |imm| { |
| 2666 | switch (abi_size) { | 2636 | switch (abi_size) { |
| 2667 | 1, 2, 4 => { | 2637 | 1, 2, 4 => { |
| ... | @@ -3041,18 +3011,17 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -3041,18 +3011,17 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { |
| 3041 | defer self.register_manager.unlockReg(reg_lock); | 3011 | defer self.register_manager.unlockReg(reg_lock); |
| 3042 | | 3012 | |
| 3043 | const dst_reg = try self.register_manager.allocReg(inst, gp); | 3013 | const dst_reg = try self.register_manager.allocReg(inst, gp); |
| 3044 | const flags: u2 = switch (mcv) { | 3014 | const cc: Condition = switch (mcv) { |
| 3045 | .register_overflow_unsigned => 0b10, | 3015 | .register_overflow_unsigned => .c, |
| 3046 | .register_overflow_signed => 0b00, | 3016 | .register_overflow_signed => .o, |
| 3047 | else => unreachable, | 3017 | else => unreachable, |
| 3048 | }; | 3018 | }; |
| 3049 | _ = try self.addInst(.{ | 3019 | _ = try self.addInst(.{ |
| 3050 | .tag = .cond_set_byte_overflow, | 3020 | .tag = .cond_set_byte, |
| 3051 | .ops = Mir.Inst.Ops.encode(.{ | 3021 | .ops = Mir.Inst.Ops.encode(.{ |
| 3052 | .reg1 = dst_reg.to8(), | 3022 | .reg1 = dst_reg.to8(), |
| 3053 | .flags = flags, | | |
| 3054 | }), | 3023 | }), |
| 3055 | .data = undefined, | 3024 | .data = .{ .cc = cc }, |
| 3056 | }); | 3025 | }); |
| 3057 | break :result MCValue{ .register = dst_reg.to8() }; | 3026 | break :result MCValue{ .register = dst_reg.to8() }; |
| 3058 | }, | 3027 | }, |
| ... | @@ -3479,8 +3448,7 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValu | ... | @@ -3479,8 +3448,7 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValu |
| 3479 | .none => unreachable, | 3448 | .none => unreachable, |
| 3480 | .undef => unreachable, | 3449 | .undef => unreachable, |
| 3481 | .dead, .unreach, .immediate => unreachable, | 3450 | .dead, .unreach, .immediate => unreachable, |
| 3482 | .compare_flags_unsigned => unreachable, | 3451 | .eflags => unreachable, |
| 3483 | .compare_flags_signed => unreachable, | | |
| 3484 | .register_overflow_unsigned => unreachable, | 3452 | .register_overflow_unsigned => unreachable, |
| 3485 | .register_overflow_signed => unreachable, | 3453 | .register_overflow_signed => unreachable, |
| 3486 | .register => |dst_reg| { | 3454 | .register => |dst_reg| { |
| ... | @@ -3559,8 +3527,7 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValu | ... | @@ -3559,8 +3527,7 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValu |
| 3559 | .memory, | 3527 | .memory, |
| 3560 | .got_load, | 3528 | .got_load, |
| 3561 | .direct_load, | 3529 | .direct_load, |
| 3562 | .compare_flags_signed, | 3530 | .eflags, |
| 3563 | .compare_flags_unsigned, | | |
| 3564 | => { | 3531 | => { |
| 3565 | assert(abi_size <= 8); | 3532 | assert(abi_size <= 8); |
| 3566 | const dst_reg_lock = self.register_manager.lockReg(dst_reg); | 3533 | const dst_reg_lock = self.register_manager.lockReg(dst_reg); |
| ... | @@ -3649,11 +3616,8 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValu | ... | @@ -3649,11 +3616,8 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValu |
| 3649 | .got_load, .direct_load => { | 3616 | .got_load, .direct_load => { |
| 3650 | return self.fail("TODO implement x86 ADD/SUB/CMP source symbol at index in linker", .{}); | 3617 | return self.fail("TODO implement x86 ADD/SUB/CMP source symbol at index in linker", .{}); |
| 3651 | }, | 3618 | }, |
| 3652 | .compare_flags_unsigned => { | 3619 | .eflags => { |
| 3653 | return self.fail("TODO implement x86 ADD/SUB/CMP source compare flag (unsigned)", .{}); | 3620 | return self.fail("TODO implement x86 ADD/SUB/CMP source eflags", .{}); |
| 3654 | }, | | |
| 3655 | .compare_flags_signed => { | | |
| 3656 | return self.fail("TODO implement x86 ADD/SUB/CMP source compare flag (signed)", .{}); | | |
| 3657 | }, | 3621 | }, |
| 3658 | } | 3622 | } |
| 3659 | }, | 3623 | }, |
| ... | @@ -3674,8 +3638,7 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M | ... | @@ -3674,8 +3638,7 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M |
| 3674 | .none => unreachable, | 3638 | .none => unreachable, |
| 3675 | .undef => unreachable, | 3639 | .undef => unreachable, |
| 3676 | .dead, .unreach, .immediate => unreachable, | 3640 | .dead, .unreach, .immediate => unreachable, |
| 3677 | .compare_flags_unsigned => unreachable, | 3641 | .eflags => unreachable, |
| 3678 | .compare_flags_signed => unreachable, | | |
| 3679 | .ptr_stack_offset => unreachable, | 3642 | .ptr_stack_offset => unreachable, |
| 3680 | .register_overflow_unsigned => unreachable, | 3643 | .register_overflow_unsigned => unreachable, |
| 3681 | .register_overflow_signed => unreachable, | 3644 | .register_overflow_signed => unreachable, |
| ... | @@ -3734,11 +3697,8 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M | ... | @@ -3734,11 +3697,8 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M |
| 3734 | .got_load, .direct_load => { | 3697 | .got_load, .direct_load => { |
| 3735 | return self.fail("TODO implement x86 multiply source symbol at index in linker", .{}); | 3698 | return self.fail("TODO implement x86 multiply source symbol at index in linker", .{}); |
| 3736 | }, | 3699 | }, |
| 3737 | .compare_flags_unsigned => { | 3700 | .eflags => { |
| 3738 | return self.fail("TODO implement x86 multiply source compare flag (unsigned)", .{}); | 3701 | return self.fail("TODO implement x86 multiply source eflags", .{}); |
| 3739 | }, | | |
| 3740 | .compare_flags_signed => { | | |
| 3741 | return self.fail("TODO implement x86 multiply source compare flag (signed)", .{}); | | |
| 3742 | }, | 3702 | }, |
| 3743 | } | 3703 | } |
| 3744 | }, | 3704 | }, |
| ... | @@ -3782,11 +3742,8 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M | ... | @@ -3782,11 +3742,8 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M |
| 3782 | .got_load, .direct_load => { | 3742 | .got_load, .direct_load => { |
| 3783 | return self.fail("TODO implement x86 multiply source symbol at index in linker", .{}); | 3743 | return self.fail("TODO implement x86 multiply source symbol at index in linker", .{}); |
| 3784 | }, | 3744 | }, |
| 3785 | .compare_flags_unsigned => { | 3745 | .eflags => { |
| 3786 | return self.fail("TODO implement x86 multiply source compare flag (unsigned)", .{}); | 3746 | return self.fail("TODO implement x86 multiply source eflags", .{}); |
| 3787 | }, | | |
| 3788 | .compare_flags_signed => { | | |
| 3789 | return self.fail("TODO implement x86 multiply source compare flag (signed)", .{}); | | |
| 3790 | }, | 3747 | }, |
| 3791 | } | 3748 | } |
| 3792 | }, | 3749 | }, |
| ... | @@ -3905,7 +3862,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions. | ... | @@ -3905,7 +3862,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions. |
| 3905 | var info = try self.resolveCallingConventionValues(fn_ty); | 3862 | var info = try self.resolveCallingConventionValues(fn_ty); |
| 3906 | defer info.deinit(self); | 3863 | defer info.deinit(self); |
| 3907 | | 3864 | |
| 3908 | try self.spillCompareFlagsIfOccupied(); | 3865 | try self.spillEflagsIfOccupied(); |
| 3909 | | 3866 | |
| 3910 | for (caller_preserved_regs) |reg| { | 3867 | for (caller_preserved_regs) |reg| { |
| 3911 | try self.register_manager.getReg(reg, null); | 3868 | try self.register_manager.getReg(reg, null); |
| ... | @@ -3957,8 +3914,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions. | ... | @@ -3957,8 +3914,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions. |
| 3957 | .memory => unreachable, | 3914 | .memory => unreachable, |
| 3958 | .got_load => unreachable, | 3915 | .got_load => unreachable, |
| 3959 | .direct_load => unreachable, | 3916 | .direct_load => unreachable, |
| 3960 | .compare_flags_signed => unreachable, | 3917 | .eflags => unreachable, |
| 3961 | .compare_flags_unsigned => unreachable, | | |
| 3962 | .register_overflow_signed => unreachable, | 3918 | .register_overflow_signed => unreachable, |
| 3963 | .register_overflow_unsigned => unreachable, | 3919 | .register_overflow_unsigned => unreachable, |
| 3964 | } | 3920 | } |
| ... | @@ -4220,8 +4176,8 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { | ... | @@ -4220,8 +4176,8 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { |
| 4220 | break :blk ty.intInfo(self.target.*).signedness; | 4176 | break :blk ty.intInfo(self.target.*).signedness; |
| 4221 | }; | 4177 | }; |
| 4222 | | 4178 | |
| 4223 | try self.spillCompareFlagsIfOccupied(); | 4179 | try self.spillEflagsIfOccupied(); |
| 4224 | self.compare_flags_inst = inst; | 4180 | self.eflags_inst = inst; |
| 4225 | | 4181 | |
| 4226 | const result: MCValue = result: { | 4182 | const result: MCValue = result: { |
| 4227 | // There are 2 operands, destination and source. | 4183 | // There are 2 operands, destination and source. |
| ... | @@ -4265,9 +4221,10 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { | ... | @@ -4265,9 +4221,10 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { |
| 4265 | defer if (src_lock) |lock| self.register_manager.unlockReg(lock); | 4221 | defer if (src_lock) |lock| self.register_manager.unlockReg(lock); |
| 4266 | | 4222 | |
| 4267 | try self.genBinOpMir(.cmp, ty, dst_mcv, src_mcv); | 4223 | try self.genBinOpMir(.cmp, ty, dst_mcv, src_mcv); |
| | 4224 | |
| 4268 | break :result switch (signedness) { | 4225 | break :result switch (signedness) { |
| 4269 | .signed => MCValue{ .compare_flags_signed = op }, | 4226 | .signed => MCValue{ .eflags = Condition.fromCompareOperatorSigned(op) }, |
| 4270 | .unsigned => MCValue{ .compare_flags_unsigned = op }, | 4227 | .unsigned => MCValue{ .eflags = Condition.fromCompareOperatorUnsigned(op) }, |
| 4271 | }; | 4228 | }; |
| 4272 | }; | 4229 | }; |
| 4273 | | 4230 | |
| ... | @@ -4440,47 +4397,39 @@ fn addDbgInfoTypeReloc(self: *Self, ty: Type) !void { | ... | @@ -4440,47 +4397,39 @@ fn addDbgInfoTypeReloc(self: *Self, ty: Type) !void { |
| 4440 | fn genCondBrMir(self: *Self, ty: Type, mcv: MCValue) !u32 { | 4397 | fn genCondBrMir(self: *Self, ty: Type, mcv: MCValue) !u32 { |
| 4441 | const abi_size = ty.abiSize(self.target.*); | 4398 | const abi_size = ty.abiSize(self.target.*); |
| 4442 | switch (mcv) { | 4399 | switch (mcv) { |
| 4443 | .compare_flags_unsigned, | 4400 | .eflags => |cc| { |
| 4444 | .compare_flags_signed, | | |
| 4445 | => |cmp_op| { | | |
| 4446 | // Here we map the opposites since the jump is to the false branch. | | |
| 4447 | const flags: u2 = switch (cmp_op) { | | |
| 4448 | .gte => 0b10, | | |
| 4449 | .gt => 0b11, | | |
| 4450 | .neq => 0b01, | | |
| 4451 | .lt => 0b00, | | |
| 4452 | .lte => 0b01, | | |
| 4453 | .eq => 0b00, | | |
| 4454 | }; | | |
| 4455 | const tag: Mir.Inst.Tag = if (cmp_op == .neq or cmp_op == .eq) | | |
| 4456 | .cond_jmp_eq_ne | | |
| 4457 | else if (mcv == .compare_flags_unsigned) | | |
| 4458 | Mir.Inst.Tag.cond_jmp_above_below | | |
| 4459 | else | | |
| 4460 | Mir.Inst.Tag.cond_jmp_greater_less; | | |
| 4461 | return self.addInst(.{ | 4401 | return self.addInst(.{ |
| 4462 | .tag = tag, | 4402 | .tag = .cond_jmp, |
| 4463 | .ops = Mir.Inst.Ops.encode(.{ .flags = flags }), | 4403 | .ops = Mir.Inst.Ops.encode(.{}), |
| 4464 | .data = .{ .inst = undefined }, | 4404 | .data = .{ |
| | 4405 | .inst_cc = .{ |
| | 4406 | .inst = undefined, |
| | 4407 | // Here we map the opposites since the jump is to the false branch. |
| | 4408 | .cc = cc.negate(), |
| | 4409 | }, |
| | 4410 | }, |
| 4465 | }); | 4411 | }); |
| 4466 | }, | 4412 | }, |
| 4467 | .register => |reg| { | 4413 | .register => |reg| { |
| 4468 | try self.spillCompareFlagsIfOccupied(); | 4414 | try self.spillEflagsIfOccupied(); |
| 4469 | _ = try self.addInst(.{ | 4415 | _ = try self.addInst(.{ |
| 4470 | .tag = .@"test", | 4416 | .tag = .@"test", |
| 4471 | .ops = Mir.Inst.Ops.encode(.{ .reg1 = reg }), | 4417 | .ops = Mir.Inst.Ops.encode(.{ .reg1 = reg }), |
| 4472 | .data = .{ .imm = 1 }, | 4418 | .data = .{ .imm = 1 }, |
| 4473 | }); | 4419 | }); |
| 4474 | return self.addInst(.{ | 4420 | return self.addInst(.{ |
| 4475 | .tag = .cond_jmp_eq_ne, | 4421 | .tag = .cond_jmp, |
| 4476 | .ops = Mir.Inst.Ops.encode(.{ .flags = 0b01 }), | 4422 | .ops = Mir.Inst.Ops.encode(.{}), |
| 4477 | .data = .{ .inst = undefined }, | 4423 | .data = .{ .inst_cc = .{ |
| | 4424 | .inst = undefined, |
| | 4425 | .cc = .e, |
| | 4426 | } }, |
| 4478 | }); | 4427 | }); |
| 4479 | }, | 4428 | }, |
| 4480 | .immediate, | 4429 | .immediate, |
| 4481 | .stack_offset, | 4430 | .stack_offset, |
| 4482 | => { | 4431 | => { |
| 4483 | try self.spillCompareFlagsIfOccupied(); | 4432 | try self.spillEflagsIfOccupied(); |
| 4484 | if (abi_size <= 8) { | 4433 | if (abi_size <= 8) { |
| 4485 | const reg = try self.copyToTmpRegister(ty, mcv); | 4434 | const reg = try self.copyToTmpRegister(ty, mcv); |
| 4486 | return self.genCondBrMir(ty, .{ .register = reg }); | 4435 | return self.genCondBrMir(ty, .{ .register = reg }); |
| ... | @@ -4516,7 +4465,7 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -4516,7 +4465,7 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void { |
| 4516 | // Capture the state of register and stack allocation state so that we can revert to it. | 4465 | // Capture the state of register and stack allocation state so that we can revert to it. |
| 4517 | const parent_next_stack_offset = self.next_stack_offset; | 4466 | const parent_next_stack_offset = self.next_stack_offset; |
| 4518 | const parent_free_registers = self.register_manager.free_registers; | 4467 | const parent_free_registers = self.register_manager.free_registers; |
| 4519 | const parent_compare_flags_inst = self.compare_flags_inst; | 4468 | const parent_eflags_inst = self.eflags_inst; |
| 4520 | var parent_stack = try self.stack.clone(self.gpa); | 4469 | var parent_stack = try self.stack.clone(self.gpa); |
| 4521 | defer parent_stack.deinit(self.gpa); | 4470 | defer parent_stack.deinit(self.gpa); |
| 4522 | const parent_registers = self.register_manager.registers; | 4471 | const parent_registers = self.register_manager.registers; |
| ... | @@ -4538,7 +4487,7 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -4538,7 +4487,7 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void { |
| 4538 | defer saved_then_branch.deinit(self.gpa); | 4487 | defer saved_then_branch.deinit(self.gpa); |
| 4539 | | 4488 | |
| 4540 | self.register_manager.registers = parent_registers; | 4489 | self.register_manager.registers = parent_registers; |
| 4541 | self.compare_flags_inst = parent_compare_flags_inst; | 4490 | self.eflags_inst = parent_eflags_inst; |
| 4542 | | 4491 | |
| 4543 | self.stack.deinit(self.gpa); | 4492 | self.stack.deinit(self.gpa); |
| 4544 | self.stack = parent_stack; | 4493 | self.stack = parent_stack; |
| ... | @@ -4640,8 +4589,8 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -4640,8 +4589,8 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void { |
| 4640 | } | 4589 | } |
| 4641 | | 4590 | |
| 4642 | fn isNull(self: *Self, inst: Air.Inst.Index, ty: Type, operand: MCValue) !MCValue { | 4591 | fn isNull(self: *Self, inst: Air.Inst.Index, ty: Type, operand: MCValue) !MCValue { |
| 4643 | try self.spillCompareFlagsIfOccupied(); | 4592 | try self.spillEflagsIfOccupied(); |
| 4644 | self.compare_flags_inst = inst; | 4593 | self.eflags_inst = inst; |
| 4645 | | 4594 | |
| 4646 | const cmp_ty: Type = if (!ty.isPtrLikeOptional()) blk: { | 4595 | const cmp_ty: Type = if (!ty.isPtrLikeOptional()) blk: { |
| 4647 | var buf: Type.Payload.ElemType = undefined; | 4596 | var buf: Type.Payload.ElemType = undefined; |
| ... | @@ -4651,13 +4600,13 @@ fn isNull(self: *Self, inst: Air.Inst.Index, ty: Type, operand: MCValue) !MCValu | ... | @@ -4651,13 +4600,13 @@ fn isNull(self: *Self, inst: Air.Inst.Index, ty: Type, operand: MCValue) !MCValu |
| 4651 | | 4600 | |
| 4652 | try self.genBinOpMir(.cmp, cmp_ty, operand, MCValue{ .immediate = 0 }); | 4601 | try self.genBinOpMir(.cmp, cmp_ty, operand, MCValue{ .immediate = 0 }); |
| 4653 | | 4602 | |
| 4654 | return MCValue{ .compare_flags_unsigned = .eq }; | 4603 | return MCValue{ .eflags = .e }; |
| 4655 | } | 4604 | } |
| 4656 | | 4605 | |
| 4657 | fn isNonNull(self: *Self, inst: Air.Inst.Index, ty: Type, operand: MCValue) !MCValue { | 4606 | fn isNonNull(self: *Self, inst: Air.Inst.Index, ty: Type, operand: MCValue) !MCValue { |
| 4658 | const is_null_res = try self.isNull(inst, ty, operand); | 4607 | const is_null_res = try self.isNull(inst, ty, operand); |
| 4659 | assert(is_null_res.compare_flags_unsigned == .eq); | 4608 | assert(is_null_res.eflags == .e); |
| 4660 | return MCValue{ .compare_flags_unsigned = .neq }; | 4609 | return MCValue{ .eflags = is_null_res.eflags.negate() }; |
| 4661 | } | 4610 | } |
| 4662 | | 4611 | |
| 4663 | fn isErr(self: *Self, inst: Air.Inst.Index, ty: Type, operand: MCValue) !MCValue { | 4612 | fn isErr(self: *Self, inst: Air.Inst.Index, ty: Type, operand: MCValue) !MCValue { |
| ... | @@ -4667,8 +4616,8 @@ fn isErr(self: *Self, inst: Air.Inst.Index, ty: Type, operand: MCValue) !MCValue | ... | @@ -4667,8 +4616,8 @@ fn isErr(self: *Self, inst: Air.Inst.Index, ty: Type, operand: MCValue) !MCValue |
| 4667 | return MCValue{ .immediate = 0 }; // always false | 4616 | return MCValue{ .immediate = 0 }; // always false |
| 4668 | } | 4617 | } |
| 4669 | | 4618 | |
| 4670 | try self.spillCompareFlagsIfOccupied(); | 4619 | try self.spillEflagsIfOccupied(); |
| 4671 | self.compare_flags_inst = inst; | 4620 | self.eflags_inst = inst; |
| 4672 | | 4621 | |
| 4673 | const err_off = errUnionErrorOffset(ty.errorUnionPayload(), self.target.*); | 4622 | const err_off = errUnionErrorOffset(ty.errorUnionPayload(), self.target.*); |
| 4674 | switch (operand) { | 4623 | switch (operand) { |
| ... | @@ -4691,15 +4640,15 @@ fn isErr(self: *Self, inst: Air.Inst.Index, ty: Type, operand: MCValue) !MCValue | ... | @@ -4691,15 +4640,15 @@ fn isErr(self: *Self, inst: Air.Inst.Index, ty: Type, operand: MCValue) !MCValue |
| 4691 | else => return self.fail("TODO implement isErr for {}", .{operand}), | 4640 | else => return self.fail("TODO implement isErr for {}", .{operand}), |
| 4692 | } | 4641 | } |
| 4693 | | 4642 | |
| 4694 | return MCValue{ .compare_flags_unsigned = .gt }; | 4643 | return MCValue{ .eflags = .a }; |
| 4695 | } | 4644 | } |
| 4696 | | 4645 | |
| 4697 | fn isNonErr(self: *Self, inst: Air.Inst.Index, ty: Type, operand: MCValue) !MCValue { | 4646 | fn isNonErr(self: *Self, inst: Air.Inst.Index, ty: Type, operand: MCValue) !MCValue { |
| 4698 | const is_err_res = try self.isErr(inst, ty, operand); | 4647 | const is_err_res = try self.isErr(inst, ty, operand); |
| 4699 | switch (is_err_res) { | 4648 | switch (is_err_res) { |
| 4700 | .compare_flags_unsigned => |op| { | 4649 | .eflags => |cc| { |
| 4701 | assert(op == .gt); | 4650 | assert(cc == .a); |
| 4702 | return MCValue{ .compare_flags_unsigned = .lte }; | 4651 | return MCValue{ .eflags = cc.negate() }; |
| 4703 | }, | 4652 | }, |
| 4704 | .immediate => |imm| { | 4653 | .immediate => |imm| { |
| 4705 | assert(imm == 0); | 4654 | assert(imm == 0); |
| ... | @@ -4914,10 +4863,9 @@ fn genCondSwitchMir(self: *Self, ty: Type, condition: MCValue, case: MCValue) !u | ... | @@ -4914,10 +4863,9 @@ fn genCondSwitchMir(self: *Self, ty: Type, condition: MCValue, case: MCValue) !u |
| 4914 | .none => unreachable, | 4863 | .none => unreachable, |
| 4915 | .undef => unreachable, | 4864 | .undef => unreachable, |
| 4916 | .dead, .unreach => unreachable, | 4865 | .dead, .unreach => unreachable, |
| 4917 | .compare_flags_signed => unreachable, | 4866 | .eflags => unreachable, |
| 4918 | .compare_flags_unsigned => unreachable, | | |
| 4919 | .register => |cond_reg| { | 4867 | .register => |cond_reg| { |
| 4920 | try self.spillCompareFlagsIfOccupied(); | 4868 | try self.spillEflagsIfOccupied(); |
| 4921 | | 4869 | |
| 4922 | const cond_reg_lock = self.register_manager.lockReg(cond_reg); | 4870 | const cond_reg_lock = self.register_manager.lockReg(cond_reg); |
| 4923 | defer if (cond_reg_lock) |lock| self.register_manager.unlockReg(lock); | 4871 | defer if (cond_reg_lock) |lock| self.register_manager.unlockReg(lock); |
| ... | @@ -4965,13 +4913,16 @@ fn genCondSwitchMir(self: *Self, ty: Type, condition: MCValue, case: MCValue) !u | ... | @@ -4965,13 +4913,16 @@ fn genCondSwitchMir(self: *Self, ty: Type, condition: MCValue, case: MCValue) !u |
| 4965 | .data = undefined, | 4913 | .data = undefined, |
| 4966 | }); | 4914 | }); |
| 4967 | return self.addInst(.{ | 4915 | return self.addInst(.{ |
| 4968 | .tag = .cond_jmp_eq_ne, | 4916 | .tag = .cond_jmp, |
| 4969 | .ops = Mir.Inst.Ops.encode(.{}), | 4917 | .ops = Mir.Inst.Ops.encode(.{}), |
| 4970 | .data = .{ .inst = undefined }, | 4918 | .data = .{ .inst_cc = .{ |
| | 4919 | .inst = undefined, |
| | 4920 | .cc = .ne, |
| | 4921 | } }, |
| 4971 | }); | 4922 | }); |
| 4972 | }, | 4923 | }, |
| 4973 | .stack_offset => { | 4924 | .stack_offset => { |
| 4974 | try self.spillCompareFlagsIfOccupied(); | 4925 | try self.spillEflagsIfOccupied(); |
| 4975 | | 4926 | |
| 4976 | if (abi_size <= 8) { | 4927 | if (abi_size <= 8) { |
| 4977 | const reg = try self.copyToTmpRegister(ty, condition); | 4928 | const reg = try self.copyToTmpRegister(ty, condition); |
| ... | @@ -5030,7 +4981,7 @@ fn airSwitch(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -5030,7 +4981,7 @@ fn airSwitch(self: *Self, inst: Air.Inst.Index) !void { |
| 5030 | // Capture the state of register and stack allocation state so that we can revert to it. | 4981 | // Capture the state of register and stack allocation state so that we can revert to it. |
| 5031 | const parent_next_stack_offset = self.next_stack_offset; | 4982 | const parent_next_stack_offset = self.next_stack_offset; |
| 5032 | const parent_free_registers = self.register_manager.free_registers; | 4983 | const parent_free_registers = self.register_manager.free_registers; |
| 5033 | const parent_compare_flags_inst = self.compare_flags_inst; | 4984 | const parent_eflags_inst = self.eflags_inst; |
| 5034 | var parent_stack = try self.stack.clone(self.gpa); | 4985 | var parent_stack = try self.stack.clone(self.gpa); |
| 5035 | defer parent_stack.deinit(self.gpa); | 4986 | defer parent_stack.deinit(self.gpa); |
| 5036 | const parent_registers = self.register_manager.registers; | 4987 | const parent_registers = self.register_manager.registers; |
| ... | @@ -5052,7 +5003,7 @@ fn airSwitch(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -5052,7 +5003,7 @@ fn airSwitch(self: *Self, inst: Air.Inst.Index) !void { |
| 5052 | defer saved_case_branch.deinit(self.gpa); | 5003 | defer saved_case_branch.deinit(self.gpa); |
| 5053 | | 5004 | |
| 5054 | self.register_manager.registers = parent_registers; | 5005 | self.register_manager.registers = parent_registers; |
| 5055 | self.compare_flags_inst = parent_compare_flags_inst; | 5006 | self.eflags_inst = parent_eflags_inst; |
| 5056 | self.stack.deinit(self.gpa); | 5007 | self.stack.deinit(self.gpa); |
| 5057 | self.stack = parent_stack; | 5008 | self.stack = parent_stack; |
| 5058 | parent_stack = .{}; | 5009 | parent_stack = .{}; |
| ... | @@ -5092,7 +5043,15 @@ fn airSwitch(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -5092,7 +5043,15 @@ fn airSwitch(self: *Self, inst: Air.Inst.Index) !void { |
| 5092 | | 5043 | |
| 5093 | fn performReloc(self: *Self, reloc: Mir.Inst.Index) !void { | 5044 | fn performReloc(self: *Self, reloc: Mir.Inst.Index) !void { |
| 5094 | const next_inst = @intCast(u32, self.mir_instructions.len); | 5045 | const next_inst = @intCast(u32, self.mir_instructions.len); |
| 5095 | self.mir_instructions.items(.data)[reloc].inst = next_inst; | 5046 | switch (self.mir_instructions.items(.tag)[reloc]) { |
| | 5047 | .cond_jmp => { |
| | 5048 | self.mir_instructions.items(.data)[reloc].inst_cc.inst = next_inst; |
| | 5049 | }, |
| | 5050 | .jmp => { |
| | 5051 | self.mir_instructions.items(.data)[reloc].inst = next_inst; |
| | 5052 | }, |
| | 5053 | else => unreachable, |
| | 5054 | } |
| 5096 | } | 5055 | } |
| 5097 | | 5056 | |
| 5098 | fn airBr(self: *Self, inst: Air.Inst.Index) !void { | 5057 | fn airBr(self: *Self, inst: Air.Inst.Index) !void { |
| ... | @@ -5111,7 +5070,7 @@ fn br(self: *Self, block: Air.Inst.Index, operand: Air.Inst.Ref) !void { | ... | @@ -5111,7 +5070,7 @@ fn br(self: *Self, block: Air.Inst.Index, operand: Air.Inst.Ref) !void { |
| 5111 | block_data.mcv = switch (operand_mcv) { | 5070 | block_data.mcv = switch (operand_mcv) { |
| 5112 | .none, .dead, .unreach => unreachable, | 5071 | .none, .dead, .unreach => unreachable, |
| 5113 | .register, .stack_offset, .memory => operand_mcv, | 5072 | .register, .stack_offset, .memory => operand_mcv, |
| 5114 | .compare_flags_signed, .compare_flags_unsigned, .immediate => blk: { | 5073 | .eflags, .immediate => blk: { |
| 5115 | const new_mcv = try self.allocRegOrMem(block, true); | 5074 | const new_mcv = try self.allocRegOrMem(block, true); |
| 5116 | try self.setRegOrMem(self.air.typeOfIndex(block), new_mcv, operand_mcv); | 5075 | try self.setRegOrMem(self.air.typeOfIndex(block), new_mcv, operand_mcv); |
| 5117 | break :blk new_mcv; | 5076 | break :blk new_mcv; |
| ... | @@ -5335,9 +5294,7 @@ fn genSetStackArg(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerE | ... | @@ -5335,9 +5294,7 @@ fn genSetStackArg(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerE |
| 5335 | .register_overflow_unsigned, | 5294 | .register_overflow_unsigned, |
| 5336 | .register_overflow_signed, | 5295 | .register_overflow_signed, |
| 5337 | => return self.fail("TODO genSetStackArg for register with overflow bit", .{}), | 5296 | => return self.fail("TODO genSetStackArg for register with overflow bit", .{}), |
| 5338 | .compare_flags_unsigned, | 5297 | .eflags => { |
| 5339 | .compare_flags_signed, | | |
| 5340 | => { | | |
| 5341 | const reg = try self.copyToTmpRegister(ty, mcv); | 5298 | const reg = try self.copyToTmpRegister(ty, mcv); |
| 5342 | return self.genSetStackArg(ty, stack_offset, .{ .register = reg }); | 5299 | return self.genSetStackArg(ty, stack_offset, .{ .register = reg }); |
| 5343 | }, | 5300 | }, |
| ... | @@ -5484,18 +5441,17 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: Inl | ... | @@ -5484,18 +5441,17 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: Inl |
| 5484 | const overflow_bit_ty = ty.structFieldType(1); | 5441 | const overflow_bit_ty = ty.structFieldType(1); |
| 5485 | const overflow_bit_offset = ty.structFieldOffset(1, self.target.*); | 5442 | const overflow_bit_offset = ty.structFieldOffset(1, self.target.*); |
| 5486 | const tmp_reg = try self.register_manager.allocReg(null, gp); | 5443 | const tmp_reg = try self.register_manager.allocReg(null, gp); |
| 5487 | const flags: u2 = switch (mcv) { | 5444 | const cc: Condition = switch (mcv) { |
| 5488 | .register_overflow_unsigned => 0b10, | 5445 | .register_overflow_unsigned => .c, |
| 5489 | .register_overflow_signed => 0b00, | 5446 | .register_overflow_signed => .o, |
| 5490 | else => unreachable, | 5447 | else => unreachable, |
| 5491 | }; | 5448 | }; |
| 5492 | _ = try self.addInst(.{ | 5449 | _ = try self.addInst(.{ |
| 5493 | .tag = .cond_set_byte_overflow, | 5450 | .tag = .cond_set_byte, |
| 5494 | .ops = Mir.Inst.Ops.encode(.{ | 5451 | .ops = Mir.Inst.Ops.encode(.{ |
| 5495 | .reg1 = tmp_reg.to8(), | 5452 | .reg1 = tmp_reg.to8(), |
| 5496 | .flags = flags, | | |
| 5497 | }), | 5453 | }), |
| 5498 | .data = undefined, | 5454 | .data = .{ .cc = cc }, |
| 5499 | }); | 5455 | }); |
| 5500 | | 5456 | |
| 5501 | return self.genSetStack( | 5457 | return self.genSetStack( |
| ... | @@ -5505,9 +5461,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: Inl | ... | @@ -5505,9 +5461,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: Inl |
| 5505 | .{}, | 5461 | .{}, |
| 5506 | ); | 5462 | ); |
| 5507 | }, | 5463 | }, |
| 5508 | .compare_flags_unsigned, | 5464 | .eflags => { |
| 5509 | .compare_flags_signed, | | |
| 5510 | => { | | |
| 5511 | const reg = try self.copyToTmpRegister(ty, mcv); | 5465 | const reg = try self.copyToTmpRegister(ty, mcv); |
| 5512 | return self.genSetStack(ty, stack_offset, .{ .register = reg }, opts); | 5466 | return self.genSetStack(ty, stack_offset, .{ .register = reg }, opts); |
| 5513 | }, | 5467 | }, |
| ... | @@ -5832,9 +5786,12 @@ fn genInlineMemcpy( | ... | @@ -5832,9 +5786,12 @@ fn genInlineMemcpy( |
| 5832 | | 5786 | |
| 5833 | // je end | 5787 | // je end |
| 5834 | const loop_reloc = try self.addInst(.{ | 5788 | const loop_reloc = try self.addInst(.{ |
| 5835 | .tag = .cond_jmp_eq_ne, | 5789 | .tag = .cond_jmp, |
| 5836 | .ops = Mir.Inst.Ops.encode(.{ .flags = 0b01 }), | 5790 | .ops = Mir.Inst.Ops.encode(.{}), |
| 5837 | .data = .{ .inst = undefined }, | 5791 | .data = .{ .inst_cc = .{ |
| | 5792 | .inst = undefined, |
| | 5793 | .cc = .e, |
| | 5794 | } }, |
| 5838 | }); | 5795 | }); |
| 5839 | | 5796 | |
| 5840 | // mov tmp, [addr + rcx] | 5797 | // mov tmp, [addr + rcx] |
| ... | @@ -5950,9 +5907,12 @@ fn genInlineMemset( | ... | @@ -5950,9 +5907,12 @@ fn genInlineMemset( |
| 5950 | | 5907 | |
| 5951 | // je end | 5908 | // je end |
| 5952 | const loop_reloc = try self.addInst(.{ | 5909 | const loop_reloc = try self.addInst(.{ |
| 5953 | .tag = .cond_jmp_eq_ne, | 5910 | .tag = .cond_jmp, |
| 5954 | .ops = Mir.Inst.Ops.encode(.{ .flags = 0b01 }), | 5911 | .ops = Mir.Inst.Ops.encode(.{}), |
| 5955 | .data = .{ .inst = undefined }, | 5912 | .data = .{ .inst_cc = .{ |
| | 5913 | .inst = undefined, |
| | 5914 | .cc = .e, |
| | 5915 | } }, |
| 5956 | }); | 5916 | }); |
| 5957 | | 5917 | |
| 5958 | switch (value) { | 5918 | switch (value) { |
| ... | @@ -6025,31 +5985,13 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void | ... | @@ -6025,31 +5985,13 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void |
| 6025 | else => unreachable, | 5985 | else => unreachable, |
| 6026 | } | 5986 | } |
| 6027 | }, | 5987 | }, |
| 6028 | .compare_flags_unsigned, | 5988 | .eflags => |cc| { |
| 6029 | .compare_flags_signed, | | |
| 6030 | => |op| { | | |
| 6031 | const tag: Mir.Inst.Tag = switch (op) { | | |
| 6032 | .gte, .gt, .lt, .lte => if (mcv == .compare_flags_unsigned) | | |
| 6033 | Mir.Inst.Tag.cond_set_byte_above_below | | |
| 6034 | else | | |
| 6035 | Mir.Inst.Tag.cond_set_byte_greater_less, | | |
| 6036 | .eq, .neq => .cond_set_byte_eq_ne, | | |
| 6037 | }; | | |
| 6038 | const flags: u2 = switch (op) { | | |
| 6039 | .gte => 0b00, | | |
| 6040 | .gt => 0b01, | | |
| 6041 | .lt => 0b10, | | |
| 6042 | .lte => 0b11, | | |
| 6043 | .eq => 0b01, | | |
| 6044 | .neq => 0b00, | | |
| 6045 | }; | | |
| 6046 | _ = try self.addInst(.{ | 5989 | _ = try self.addInst(.{ |
| 6047 | .tag = tag, | 5990 | .tag = .cond_set_byte, |
| 6048 | .ops = Mir.Inst.Ops.encode(.{ | 5991 | .ops = Mir.Inst.Ops.encode(.{ |
| 6049 | .reg1 = reg.to8(), | 5992 | .reg1 = reg.to8(), |
| 6050 | .flags = flags, | | |
| 6051 | }), | 5993 | }), |
| 6052 | .data = undefined, | 5994 | .data = .{ .cc = cc }, |
| 6053 | }); | 5995 | }); |
| 6054 | }, | 5996 | }, |
| 6055 | .immediate => |x| { | 5997 | .immediate => |x| { |