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