| ... | @@ -96,7 +96,7 @@ register_manager: RegisterManager = .{}, | ... | @@ -96,7 +96,7 @@ register_manager: RegisterManager = .{}, |
| 96 | /// Maps offset to what is stored there. | 96 | /// Maps offset to what is stored there. |
| 97 | stack: std.AutoHashMapUnmanaged(u32, StackAllocation) = .{}, | 97 | stack: std.AutoHashMapUnmanaged(u32, StackAllocation) = .{}, |
| 98 | /// Tracks the current instruction allocated to the compare flags | 98 | /// Tracks the current instruction allocated to the compare flags |
| 99 | compare_flags_inst: ?Air.Inst.Index = null, | 99 | cpsr_flags_inst: ?Air.Inst.Index = null, |
| 100 | | 100 | |
| 101 | /// Offset from the stack base, representing the end of the stack frame. | 101 | /// Offset from the stack base, representing the end of the stack frame. |
| 102 | max_end_stack: u32 = 0, | 102 | max_end_stack: u32 = 0, |
| ... | @@ -159,12 +159,11 @@ const MCValue = union(enum) { | ... | @@ -159,12 +159,11 @@ const MCValue = union(enum) { |
| 159 | /// The value is a pointer to one of the stack variables (payload | 159 | /// The value is a pointer to one of the stack variables (payload |
| 160 | /// is stack offset). | 160 | /// is stack offset). |
| 161 | ptr_stack_offset: u32, | 161 | ptr_stack_offset: u32, |
| 162 | /// The value is in the compare flags assuming an unsigned | 162 | /// The value resides in the N, Z, C, V flags of the Current |
| 163 | /// operation, with this operator applied on top of it. | 163 | /// Program Status Register (CPSR). The value is 1 (if the type is |
| 164 | compare_flags_unsigned: math.CompareOperator, | 164 | /// u1) or true (if the type in bool) iff the specified condition |
| 165 | /// The value is in the compare flags assuming a signed operation, | 165 | /// is true. |
| 166 | /// with this operator applied on top of it. | 166 | cpsr_flags: Condition, |
| 167 | compare_flags_signed: math.CompareOperator, | | |
| 168 | /// The value is a function argument passed via the stack. | 167 | /// The value is a function argument passed via the stack. |
| 169 | stack_argument_offset: u32, | 168 | stack_argument_offset: u32, |
| 170 | | 169 | |
| ... | @@ -190,8 +189,7 @@ const MCValue = union(enum) { | ... | @@ -190,8 +189,7 @@ const MCValue = union(enum) { |
| 190 | | 189 | |
| 191 | .immediate, | 190 | .immediate, |
| 192 | .memory, | 191 | .memory, |
| 193 | .compare_flags_unsigned, | 192 | .cpsr_flags, |
| 194 | .compare_flags_signed, | | |
| 195 | .ptr_stack_offset, | 193 | .ptr_stack_offset, |
| 196 | .undef, | 194 | .undef, |
| 197 | .stack_argument_offset, | 195 | .stack_argument_offset, |
| ... | @@ -768,10 +766,10 @@ fn processDeath(self: *Self, inst: Air.Inst.Index) void { | ... | @@ -768,10 +766,10 @@ fn processDeath(self: *Self, inst: Air.Inst.Index) void { |
| 768 | .register_v_flag, | 766 | .register_v_flag, |
| 769 | => |reg| { | 767 | => |reg| { |
| 770 | self.register_manager.freeReg(reg); | 768 | self.register_manager.freeReg(reg); |
| 771 | self.compare_flags_inst = null; | 769 | self.cpsr_flags_inst = null; |
| 772 | }, | 770 | }, |
| 773 | .compare_flags_signed, .compare_flags_unsigned => { | 771 | .cpsr_flags => { |
| 774 | self.compare_flags_inst = null; | 772 | self.cpsr_flags_inst = null; |
| 775 | }, | 773 | }, |
| 776 | else => {}, // TODO process stack allocation death | 774 | else => {}, // TODO process stack allocation death |
| 777 | } | 775 | } |
| ... | @@ -903,12 +901,10 @@ pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void | ... | @@ -903,12 +901,10 @@ pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void |
| 903 | /// Save the current instruction stored in the compare flags if | 901 | /// Save the current instruction stored in the compare flags if |
| 904 | /// occupied | 902 | /// occupied |
| 905 | fn spillCompareFlagsIfOccupied(self: *Self) !void { | 903 | fn spillCompareFlagsIfOccupied(self: *Self) !void { |
| 906 | if (self.compare_flags_inst) |inst_to_save| { | 904 | if (self.cpsr_flags_inst) |inst_to_save| { |
| 907 | const mcv = self.getResolvedInstValue(inst_to_save); | 905 | const mcv = self.getResolvedInstValue(inst_to_save); |
| 908 | const new_mcv = switch (mcv) { | 906 | const new_mcv = switch (mcv) { |
| 909 | .compare_flags_signed, | 907 | .cpsr_flags => try self.allocRegOrMem(inst_to_save, true), |
| 910 | .compare_flags_unsigned, | | |
| 911 | => try self.allocRegOrMem(inst_to_save, true), | | |
| 912 | .register_c_flag, | 908 | .register_c_flag, |
| 913 | .register_v_flag, | 909 | .register_v_flag, |
| 914 | => try self.allocRegOrMem(inst_to_save, false), | 910 | => try self.allocRegOrMem(inst_to_save, false), |
| ... | @@ -921,7 +917,7 @@ fn spillCompareFlagsIfOccupied(self: *Self) !void { | ... | @@ -921,7 +917,7 @@ fn spillCompareFlagsIfOccupied(self: *Self) !void { |
| 921 | const branch = &self.branch_stack.items[self.branch_stack.items.len - 1]; | 917 | const branch = &self.branch_stack.items[self.branch_stack.items.len - 1]; |
| 922 | try branch.inst_table.put(self.gpa, inst_to_save, new_mcv); | 918 | try branch.inst_table.put(self.gpa, inst_to_save, new_mcv); |
| 923 | | 919 | |
| 924 | self.compare_flags_inst = null; | 920 | self.cpsr_flags_inst = null; |
| 925 | | 921 | |
| 926 | // TODO consolidate with register manager and spillInstruction | 922 | // TODO consolidate with register manager and spillInstruction |
| 927 | // this call should really belong in the register manager! | 923 | // this call should really belong in the register manager! |
| ... | @@ -1111,32 +1107,7 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1111,32 +1107,7 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void { |
| 1111 | switch (operand) { | 1107 | switch (operand) { |
| 1112 | .dead => unreachable, | 1108 | .dead => unreachable, |
| 1113 | .unreach => unreachable, | 1109 | .unreach => unreachable, |
| 1114 | .compare_flags_unsigned => |op| { | 1110 | .cpsr_flags => |cond| break :result MCValue{ .cpsr_flags = cond.negate() }, |
| 1115 | const r = MCValue{ | | |
| 1116 | .compare_flags_unsigned = switch (op) { | | |
| 1117 | .gte => .lt, | | |
| 1118 | .gt => .lte, | | |
| 1119 | .neq => .eq, | | |
| 1120 | .lt => .gte, | | |
| 1121 | .lte => .gt, | | |
| 1122 | .eq => .neq, | | |
| 1123 | }, | | |
| 1124 | }; | | |
| 1125 | break :result r; | | |
| 1126 | }, | | |
| 1127 | .compare_flags_signed => |op| { | | |
| 1128 | const r = MCValue{ | | |
| 1129 | .compare_flags_signed = switch (op) { | | |
| 1130 | .gte => .lt, | | |
| 1131 | .gt => .lte, | | |
| 1132 | .neq => .eq, | | |
| 1133 | .lt => .gte, | | |
| 1134 | .lte => .gt, | | |
| 1135 | .eq => .neq, | | |
| 1136 | }, | | |
| 1137 | }; | | |
| 1138 | break :result r; | | |
| 1139 | }, | | |
| 1140 | else => { | 1111 | else => { |
| 1141 | switch (operand_ty.zigTypeTag()) { | 1112 | switch (operand_ty.zigTypeTag()) { |
| 1142 | .Bool => { | 1113 | .Bool => { |
| ... | @@ -1425,7 +1396,7 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1425,7 +1396,7 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1425 | const stack_offset = try self.allocMem(inst, tuple_size, tuple_align); | 1396 | const stack_offset = try self.allocMem(inst, tuple_size, tuple_align); |
| 1426 | | 1397 | |
| 1427 | try self.spillCompareFlagsIfOccupied(); | 1398 | try self.spillCompareFlagsIfOccupied(); |
| 1428 | self.compare_flags_inst = null; | 1399 | self.cpsr_flags_inst = null; |
| 1429 | | 1400 | |
| 1430 | const base_tag: Air.Inst.Tag = switch (tag) { | 1401 | const base_tag: Air.Inst.Tag = switch (tag) { |
| 1431 | .add_with_overflow => .add, | 1402 | .add_with_overflow => .add, |
| ... | @@ -1448,7 +1419,7 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1448,7 +1419,7 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1448 | _ = try self.binOp(.cmp_eq, dest, .{ .register = truncated_reg }, Type.usize, Type.usize, null); | 1419 | _ = try self.binOp(.cmp_eq, dest, .{ .register = truncated_reg }, Type.usize, Type.usize, null); |
| 1449 | | 1420 | |
| 1450 | try self.genSetStack(lhs_ty, stack_offset, .{ .register = truncated_reg }); | 1421 | try self.genSetStack(lhs_ty, stack_offset, .{ .register = truncated_reg }); |
| 1451 | try self.genSetStack(Type.initTag(.u1), stack_offset - overflow_bit_offset, .{ .compare_flags_unsigned = .neq }); | 1422 | try self.genSetStack(Type.initTag(.u1), stack_offset - overflow_bit_offset, .{ .cpsr_flags = .ne }); |
| 1452 | | 1423 | |
| 1453 | break :result MCValue{ .stack_offset = stack_offset }; | 1424 | break :result MCValue{ .stack_offset = stack_offset }; |
| 1454 | } else if (int_info.bits == 32) { | 1425 | } else if (int_info.bits == 32) { |
| ... | @@ -1474,7 +1445,7 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1474,7 +1445,7 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1474 | }; | 1445 | }; |
| 1475 | | 1446 | |
| 1476 | try self.spillCompareFlagsIfOccupied(); | 1447 | try self.spillCompareFlagsIfOccupied(); |
| 1477 | self.compare_flags_inst = inst; | 1448 | self.cpsr_flags_inst = inst; |
| 1478 | | 1449 | |
| 1479 | const dest = blk: { | 1450 | const dest = blk: { |
| 1480 | if (rhs_immediate_ok) { | 1451 | if (rhs_immediate_ok) { |
| ... | @@ -1530,7 +1501,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1530,7 +1501,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1530 | const stack_offset = try self.allocMem(inst, tuple_size, tuple_align); | 1501 | const stack_offset = try self.allocMem(inst, tuple_size, tuple_align); |
| 1531 | | 1502 | |
| 1532 | try self.spillCompareFlagsIfOccupied(); | 1503 | try self.spillCompareFlagsIfOccupied(); |
| 1533 | self.compare_flags_inst = null; | 1504 | self.cpsr_flags_inst = null; |
| 1534 | | 1505 | |
| 1535 | const base_tag: Mir.Inst.Tag = switch (int_info.signedness) { | 1506 | const base_tag: Mir.Inst.Tag = switch (int_info.signedness) { |
| 1536 | .signed => .smulbb, | 1507 | .signed => .smulbb, |
| ... | @@ -1553,14 +1524,14 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1553,14 +1524,14 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1553 | _ = try self.binOp(.cmp_eq, dest, .{ .register = truncated_reg }, Type.usize, Type.usize, null); | 1524 | _ = try self.binOp(.cmp_eq, dest, .{ .register = truncated_reg }, Type.usize, Type.usize, null); |
| 1554 | | 1525 | |
| 1555 | try self.genSetStack(lhs_ty, stack_offset, .{ .register = truncated_reg }); | 1526 | try self.genSetStack(lhs_ty, stack_offset, .{ .register = truncated_reg }); |
| 1556 | try self.genSetStack(Type.initTag(.u1), stack_offset - overflow_bit_offset, .{ .compare_flags_unsigned = .neq }); | 1527 | try self.genSetStack(Type.initTag(.u1), stack_offset - overflow_bit_offset, .{ .cpsr_flags = .ne }); |
| 1557 | | 1528 | |
| 1558 | break :result MCValue{ .stack_offset = stack_offset }; | 1529 | break :result MCValue{ .stack_offset = stack_offset }; |
| 1559 | } else if (int_info.bits <= 32) { | 1530 | } else if (int_info.bits <= 32) { |
| 1560 | const stack_offset = try self.allocMem(inst, tuple_size, tuple_align); | 1531 | const stack_offset = try self.allocMem(inst, tuple_size, tuple_align); |
| 1561 | | 1532 | |
| 1562 | try self.spillCompareFlagsIfOccupied(); | 1533 | try self.spillCompareFlagsIfOccupied(); |
| 1563 | self.compare_flags_inst = null; | 1534 | self.cpsr_flags_inst = null; |
| 1564 | | 1535 | |
| 1565 | const base_tag: Mir.Inst.Tag = switch (int_info.signedness) { | 1536 | const base_tag: Mir.Inst.Tag = switch (int_info.signedness) { |
| 1566 | .signed => .smull, | 1537 | .signed => .smull, |
| ... | @@ -1704,7 +1675,7 @@ fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1704,7 +1675,7 @@ fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1704 | defer if (lhs_lock) |reg| self.register_manager.unlockReg(reg); | 1675 | defer if (lhs_lock) |reg| self.register_manager.unlockReg(reg); |
| 1705 | | 1676 | |
| 1706 | try self.spillCompareFlagsIfOccupied(); | 1677 | try self.spillCompareFlagsIfOccupied(); |
| 1707 | self.compare_flags_inst = null; | 1678 | self.cpsr_flags_inst = null; |
| 1708 | | 1679 | |
| 1709 | // lsl dest, lhs, rhs | 1680 | // lsl dest, lhs, rhs |
| 1710 | const dest = try self.binOp(.shl, lhs, rhs, lhs_ty, rhs_ty, null); | 1681 | const dest = try self.binOp(.shl, lhs, rhs, lhs_ty, rhs_ty, null); |
| ... | @@ -1719,7 +1690,7 @@ fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1719,7 +1690,7 @@ fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1719 | _ = try self.binOp(.cmp_eq, lhs, reconstructed, lhs_ty, lhs_ty, null); | 1690 | _ = try self.binOp(.cmp_eq, lhs, reconstructed, lhs_ty, lhs_ty, null); |
| 1720 | | 1691 | |
| 1721 | try self.genSetStack(lhs_ty, stack_offset, dest); | 1692 | try self.genSetStack(lhs_ty, stack_offset, dest); |
| 1722 | try self.genSetStack(Type.initTag(.u1), stack_offset - overflow_bit_offset, .{ .compare_flags_unsigned = .neq }); | 1693 | try self.genSetStack(Type.initTag(.u1), stack_offset - overflow_bit_offset, .{ .cpsr_flags = .ne }); |
| 1723 | | 1694 | |
| 1724 | break :result MCValue{ .stack_offset = stack_offset }; | 1695 | break :result MCValue{ .stack_offset = stack_offset }; |
| 1725 | } else { | 1696 | } else { |
| ... | @@ -2213,8 +2184,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo | ... | @@ -2213,8 +2184,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo |
| 2213 | .undef => unreachable, | 2184 | .undef => unreachable, |
| 2214 | .unreach => unreachable, | 2185 | .unreach => unreachable, |
| 2215 | .dead => unreachable, | 2186 | .dead => unreachable, |
| 2216 | .compare_flags_unsigned, | 2187 | .cpsr_flags, |
| 2217 | .compare_flags_signed, | | |
| 2218 | .register_c_flag, | 2188 | .register_c_flag, |
| 2219 | .register_v_flag, | 2189 | .register_v_flag, |
| 2220 | => unreachable, // cannot hold an address | 2190 | => unreachable, // cannot hold an address |
| ... | @@ -2227,7 +2197,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo | ... | @@ -2227,7 +2197,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo |
| 2227 | switch (dst_mcv) { | 2197 | switch (dst_mcv) { |
| 2228 | .dead => unreachable, | 2198 | .dead => unreachable, |
| 2229 | .undef => unreachable, | 2199 | .undef => unreachable, |
| 2230 | .compare_flags_signed, .compare_flags_unsigned => unreachable, | 2200 | .cpsr_flags => unreachable, |
| 2231 | .register => |dst_reg| { | 2201 | .register => |dst_reg| { |
| 2232 | try self.genLdrRegister(dst_reg, reg, elem_ty); | 2202 | try self.genLdrRegister(dst_reg, reg, elem_ty); |
| 2233 | }, | 2203 | }, |
| ... | @@ -2314,8 +2284,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type | ... | @@ -2314,8 +2284,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type |
| 2314 | .undef => unreachable, | 2284 | .undef => unreachable, |
| 2315 | .unreach => unreachable, | 2285 | .unreach => unreachable, |
| 2316 | .dead => unreachable, | 2286 | .dead => unreachable, |
| 2317 | .compare_flags_unsigned, | 2287 | .cpsr_flags, |
| 2318 | .compare_flags_signed, | | |
| 2319 | .register_c_flag, | 2288 | .register_c_flag, |
| 2320 | .register_v_flag, | 2289 | .register_v_flag, |
| 2321 | => unreachable, // cannot hold an address | 2290 | => unreachable, // cannot hold an address |
| ... | @@ -2484,37 +2453,48 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2484,37 +2453,48 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { |
| 2484 | break :result MCValue{ .register = reg }; | 2453 | break :result MCValue{ .register = reg }; |
| 2485 | }, | 2454 | }, |
| 2486 | 1 => { | 2455 | 1 => { |
| 2487 | // get overflow bit: set register to C flag | 2456 | // get overflow bit: return C or V flag |
| 2488 | // resp. V flag | 2457 | if (self.liveness.operandDies(inst, 0)) { |
| 2489 | const dest_reg = try self.register_manager.allocReg(null, gp); | 2458 | self.cpsr_flags_inst = inst; |
| 2490 | | 2459 | |
| 2491 | // mov reg, #0 | 2460 | const cond: Condition = switch (mcv) { |
| 2492 | _ = try self.addInst(.{ | | |
| 2493 | .tag = .mov, | | |
| 2494 | .data = .{ .rr_op = .{ | | |
| 2495 | .rd = dest_reg, | | |
| 2496 | .rn = .r0, | | |
| 2497 | .op = Instruction.Operand.fromU32(0).?, | | |
| 2498 | } }, | | |
| 2499 | }); | | |
| 2500 | | | |
| 2501 | // C flag: movcs reg, #1 | | |
| 2502 | // V flag: movvs reg, #1 | | |
| 2503 | _ = try self.addInst(.{ | | |
| 2504 | .tag = .mov, | | |
| 2505 | .cond = switch (mcv) { | | |
| 2506 | .register_c_flag => .cs, | 2461 | .register_c_flag => .cs, |
| 2507 | .register_v_flag => .vs, | 2462 | .register_v_flag => .vs, |
| 2508 | else => unreachable, | 2463 | else => unreachable, |
| 2509 | }, | 2464 | }; |
| 2510 | .data = .{ .rr_op = .{ | | |
| 2511 | .rd = dest_reg, | | |
| 2512 | .rn = .r0, | | |
| 2513 | .op = Instruction.Operand.fromU32(1).?, | | |
| 2514 | } }, | | |
| 2515 | }); | | |
| 2516 | | 2465 | |
| 2517 | break :result MCValue{ .register = dest_reg }; | 2466 | break :result MCValue{ .cpsr_flags = cond }; |
| | 2467 | } else { |
| | 2468 | const dest_reg = try self.register_manager.allocReg(null, gp); |
| | 2469 | |
| | 2470 | // mov reg, #0 |
| | 2471 | _ = try self.addInst(.{ |
| | 2472 | .tag = .mov, |
| | 2473 | .data = .{ .rr_op = .{ |
| | 2474 | .rd = dest_reg, |
| | 2475 | .rn = .r0, |
| | 2476 | .op = Instruction.Operand.fromU32(0).?, |
| | 2477 | } }, |
| | 2478 | }); |
| | 2479 | |
| | 2480 | // C flag: movcs reg, #1 |
| | 2481 | // V flag: movvs reg, #1 |
| | 2482 | _ = try self.addInst(.{ |
| | 2483 | .tag = .mov, |
| | 2484 | .cond = switch (mcv) { |
| | 2485 | .register_c_flag => .cs, |
| | 2486 | .register_v_flag => .vs, |
| | 2487 | else => unreachable, |
| | 2488 | }, |
| | 2489 | .data = .{ .rr_op = .{ |
| | 2490 | .rd = dest_reg, |
| | 2491 | .rn = .r0, |
| | 2492 | .op = Instruction.Operand.fromU32(1).?, |
| | 2493 | } }, |
| | 2494 | }); |
| | 2495 | |
| | 2496 | break :result MCValue{ .register = dest_reg }; |
| | 2497 | } |
| 2518 | }, | 2498 | }, |
| 2519 | else => unreachable, | 2499 | else => unreachable, |
| 2520 | } | 2500 | } |
| ... | @@ -3602,7 +3582,7 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { | ... | @@ -3602,7 +3582,7 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { |
| 3602 | const int_info = int_ty.intInfo(self.target.*); | 3582 | const int_info = int_ty.intInfo(self.target.*); |
| 3603 | if (int_info.bits <= 32) { | 3583 | if (int_info.bits <= 32) { |
| 3604 | try self.spillCompareFlagsIfOccupied(); | 3584 | try self.spillCompareFlagsIfOccupied(); |
| 3605 | self.compare_flags_inst = inst; | 3585 | self.cpsr_flags_inst = inst; |
| 3606 | | 3586 | |
| 3607 | _ = try self.binOp(.cmp_eq, lhs, rhs, int_ty, int_ty, BinOpMetadata{ | 3587 | _ = try self.binOp(.cmp_eq, lhs, rhs, int_ty, int_ty, BinOpMetadata{ |
| 3608 | .lhs = bin_op.lhs, | 3588 | .lhs = bin_op.lhs, |
| ... | @@ -3611,8 +3591,8 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { | ... | @@ -3611,8 +3591,8 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { |
| 3611 | }); | 3591 | }); |
| 3612 | | 3592 | |
| 3613 | break :result switch (int_info.signedness) { | 3593 | break :result switch (int_info.signedness) { |
| 3614 | .signed => MCValue{ .compare_flags_signed = op }, | 3594 | .signed => MCValue{ .cpsr_flags = Condition.fromCompareOperatorSigned(op) }, |
| 3615 | .unsigned => MCValue{ .compare_flags_unsigned = op }, | 3595 | .unsigned => MCValue{ .cpsr_flags = Condition.fromCompareOperatorUnsigned(op) }, |
| 3616 | }; | 3596 | }; |
| 3617 | } else { | 3597 | } else { |
| 3618 | return self.fail("TODO ARM cmp for ints > 32 bits", .{}); | 3598 | return self.fail("TODO ARM cmp for ints > 32 bits", .{}); |
| ... | @@ -3673,28 +3653,19 @@ fn airDbgVar(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -3673,28 +3653,19 @@ fn airDbgVar(self: *Self, inst: Air.Inst.Index) !void { |
| 3673 | | 3653 | |
| 3674 | fn airCondBr(self: *Self, inst: Air.Inst.Index) !void { | 3654 | fn airCondBr(self: *Self, inst: Air.Inst.Index) !void { |
| 3675 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; | 3655 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; |
| 3676 | const cond = try self.resolveInst(pl_op.operand); | 3656 | const cond_inst = try self.resolveInst(pl_op.operand); |
| 3677 | const extra = self.air.extraData(Air.CondBr, pl_op.payload); | 3657 | const extra = self.air.extraData(Air.CondBr, pl_op.payload); |
| 3678 | const then_body = self.air.extra[extra.end..][0..extra.data.then_body_len]; | 3658 | const then_body = self.air.extra[extra.end..][0..extra.data.then_body_len]; |
| 3679 | const else_body = self.air.extra[extra.end + then_body.len ..][0..extra.data.else_body_len]; | 3659 | const else_body = self.air.extra[extra.end + then_body.len ..][0..extra.data.else_body_len]; |
| 3680 | const liveness_condbr = self.liveness.getCondBr(inst); | 3660 | const liveness_condbr = self.liveness.getCondBr(inst); |
| 3681 | | 3661 | |
| 3682 | const reloc: Mir.Inst.Index = reloc: { | 3662 | const reloc: Mir.Inst.Index = reloc: { |
| 3683 | const condition: Condition = switch (cond) { | 3663 | const condition: Condition = switch (cond_inst) { |
| 3684 | .compare_flags_signed => |cmp_op| blk: { | 3664 | .cpsr_flags => |cond| cond.negate(), |
| 3685 | // Here we map to the opposite condition because the jump is to the false branch. | | |
| 3686 | const condition = Condition.fromCompareOperatorSigned(cmp_op); | | |
| 3687 | break :blk condition.negate(); | | |
| 3688 | }, | | |
| 3689 | .compare_flags_unsigned => |cmp_op| blk: { | | |
| 3690 | // Here we map to the opposite condition because the jump is to the false branch. | | |
| 3691 | const condition = Condition.fromCompareOperatorUnsigned(cmp_op); | | |
| 3692 | break :blk condition.negate(); | | |
| 3693 | }, | | |
| 3694 | else => blk: { | 3665 | else => blk: { |
| 3695 | const reg = switch (cond) { | 3666 | const reg = switch (cond_inst) { |
| 3696 | .register => |r| r, | 3667 | .register => |r| r, |
| 3697 | else => try self.copyToTmpRegister(Type.bool, cond), | 3668 | else => try self.copyToTmpRegister(Type.bool, cond_inst), |
| 3698 | }; | 3669 | }; |
| 3699 | | 3670 | |
| 3700 | try self.spillCompareFlagsIfOccupied(); | 3671 | try self.spillCompareFlagsIfOccupied(); |
| ... | @@ -3739,7 +3710,7 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -3739,7 +3710,7 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void { |
| 3739 | var parent_stack = try self.stack.clone(self.gpa); | 3710 | var parent_stack = try self.stack.clone(self.gpa); |
| 3740 | defer parent_stack.deinit(self.gpa); | 3711 | defer parent_stack.deinit(self.gpa); |
| 3741 | const parent_registers = self.register_manager.registers; | 3712 | const parent_registers = self.register_manager.registers; |
| 3742 | const parent_compare_flags_inst = self.compare_flags_inst; | 3713 | const parent_cpsr_flags_inst = self.cpsr_flags_inst; |
| 3743 | | 3714 | |
| 3744 | try self.branch_stack.append(.{}); | 3715 | try self.branch_stack.append(.{}); |
| 3745 | errdefer { | 3716 | errdefer { |
| ... | @@ -3758,7 +3729,7 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -3758,7 +3729,7 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void { |
| 3758 | defer saved_then_branch.deinit(self.gpa); | 3729 | defer saved_then_branch.deinit(self.gpa); |
| 3759 | | 3730 | |
| 3760 | self.register_manager.registers = parent_registers; | 3731 | self.register_manager.registers = parent_registers; |
| 3761 | self.compare_flags_inst = parent_compare_flags_inst; | 3732 | self.cpsr_flags_inst = parent_cpsr_flags_inst; |
| 3762 | | 3733 | |
| 3763 | self.stack.deinit(self.gpa); | 3734 | self.stack.deinit(self.gpa); |
| 3764 | self.stack = parent_stack; | 3735 | self.stack = parent_stack; |
| ... | @@ -3876,7 +3847,7 @@ fn isNull(self: *Self, ty: Type, operand: MCValue) !MCValue { | ... | @@ -3876,7 +3847,7 @@ fn isNull(self: *Self, ty: Type, operand: MCValue) !MCValue { |
| 3876 | } }, | 3847 | } }, |
| 3877 | }); | 3848 | }); |
| 3878 | | 3849 | |
| 3879 | return MCValue{ .compare_flags_unsigned = .eq }; | 3850 | return MCValue{ .cpsr_flags = .eq }; |
| 3880 | } else { | 3851 | } else { |
| 3881 | return self.fail("TODO implement non-pointer optionals", .{}); | 3852 | return self.fail("TODO implement non-pointer optionals", .{}); |
| 3882 | } | 3853 | } |
| ... | @@ -3884,9 +3855,9 @@ fn isNull(self: *Self, ty: Type, operand: MCValue) !MCValue { | ... | @@ -3884,9 +3855,9 @@ fn isNull(self: *Self, ty: Type, operand: MCValue) !MCValue { |
| 3884 | | 3855 | |
| 3885 | fn isNonNull(self: *Self, ty: Type, operand: MCValue) !MCValue { | 3856 | fn isNonNull(self: *Self, ty: Type, operand: MCValue) !MCValue { |
| 3886 | const is_null_result = try self.isNull(ty, operand); | 3857 | const is_null_result = try self.isNull(ty, operand); |
| 3887 | assert(is_null_result.compare_flags_unsigned == .eq); | 3858 | assert(is_null_result.cpsr_flags == .eq); |
| 3888 | | 3859 | |
| 3889 | return MCValue{ .compare_flags_unsigned = .neq }; | 3860 | return MCValue{ .cpsr_flags = .ne }; |
| 3890 | } | 3861 | } |
| 3891 | | 3862 | |
| 3892 | fn isErr(self: *Self, ty: Type, operand: MCValue) !MCValue { | 3863 | fn isErr(self: *Self, ty: Type, operand: MCValue) !MCValue { |
| ... | @@ -3899,15 +3870,15 @@ fn isErr(self: *Self, ty: Type, operand: MCValue) !MCValue { | ... | @@ -3899,15 +3870,15 @@ fn isErr(self: *Self, ty: Type, operand: MCValue) !MCValue { |
| 3899 | | 3870 | |
| 3900 | const error_mcv = try self.errUnionErr(operand, ty); | 3871 | const error_mcv = try self.errUnionErr(operand, ty); |
| 3901 | _ = try self.binOp(.cmp_eq, error_mcv, .{ .immediate = 0 }, error_int_type, error_int_type, null); | 3872 | _ = try self.binOp(.cmp_eq, error_mcv, .{ .immediate = 0 }, error_int_type, error_int_type, null); |
| 3902 | return MCValue{ .compare_flags_unsigned = .gt }; | 3873 | return MCValue{ .cpsr_flags = .hi }; |
| 3903 | } | 3874 | } |
| 3904 | | 3875 | |
| 3905 | fn isNonErr(self: *Self, ty: Type, operand: MCValue) !MCValue { | 3876 | fn isNonErr(self: *Self, ty: Type, operand: MCValue) !MCValue { |
| 3906 | const is_err_result = try self.isErr(ty, operand); | 3877 | const is_err_result = try self.isErr(ty, operand); |
| 3907 | switch (is_err_result) { | 3878 | switch (is_err_result) { |
| 3908 | .compare_flags_unsigned => |op| { | 3879 | .cpsr_flags => |cond| { |
| 3909 | assert(op == .gt); | 3880 | assert(cond == .hi); |
| 3910 | return MCValue{ .compare_flags_unsigned = .lte }; | 3881 | return MCValue{ .cpsr_flags = cond.negate() }; |
| 3911 | }, | 3882 | }, |
| 3912 | .immediate => |imm| { | 3883 | .immediate => |imm| { |
| 3913 | assert(imm == 0); | 3884 | assert(imm == 0); |
| ... | @@ -3921,7 +3892,7 @@ fn airIsNull(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -3921,7 +3892,7 @@ fn airIsNull(self: *Self, inst: Air.Inst.Index) !void { |
| 3921 | const un_op = self.air.instructions.items(.data)[inst].un_op; | 3892 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 3922 | | 3893 | |
| 3923 | try self.spillCompareFlagsIfOccupied(); | 3894 | try self.spillCompareFlagsIfOccupied(); |
| 3924 | self.compare_flags_inst = inst; | 3895 | self.cpsr_flags_inst = inst; |
| 3925 | | 3896 | |
| 3926 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { | 3897 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 3927 | const operand = try self.resolveInst(un_op); | 3898 | const operand = try self.resolveInst(un_op); |
| ... | @@ -4298,8 +4269,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro | ... | @@ -4298,8 +4269,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro |
| 4298 | else => return self.fail("TODO implement memset", .{}), | 4269 | else => return self.fail("TODO implement memset", .{}), |
| 4299 | } | 4270 | } |
| 4300 | }, | 4271 | }, |
| 4301 | .compare_flags_unsigned, | 4272 | .cpsr_flags, |
| 4302 | .compare_flags_signed, | | |
| 4303 | .immediate, | 4273 | .immediate, |
| 4304 | .ptr_stack_offset, | 4274 | .ptr_stack_offset, |
| 4305 | => { | 4275 | => { |
| ... | @@ -4469,15 +4439,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void | ... | @@ -4469,15 +4439,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void |
| 4469 | } }, | 4439 | } }, |
| 4470 | }); | 4440 | }); |
| 4471 | }, | 4441 | }, |
| 4472 | .compare_flags_unsigned, | 4442 | .cpsr_flags => |condition| { |
| 4473 | .compare_flags_signed, | | |
| 4474 | => |op| { | | |
| 4475 | const condition = switch (mcv) { | | |
| 4476 | .compare_flags_unsigned => Condition.fromCompareOperatorUnsigned(op), | | |
| 4477 | .compare_flags_signed => Condition.fromCompareOperatorSigned(op), | | |
| 4478 | else => unreachable, | | |
| 4479 | }; | | |
| 4480 | | | |
| 4481 | const zero = Instruction.Operand.imm(0, 0); | 4443 | const zero = Instruction.Operand.imm(0, 0); |
| 4482 | const one = Instruction.Operand.imm(1, 0); | 4444 | const one = Instruction.Operand.imm(1, 0); |
| 4483 | | 4445 | |
| ... | @@ -4826,8 +4788,7 @@ fn genSetStackArgument(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) I | ... | @@ -4826,8 +4788,7 @@ fn genSetStackArgument(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) I |
| 4826 | try self.genInlineMemcpy(src_reg, dst_reg, len_reg, count_reg, tmp_reg); | 4788 | try self.genInlineMemcpy(src_reg, dst_reg, len_reg, count_reg, tmp_reg); |
| 4827 | } | 4789 | } |
| 4828 | }, | 4790 | }, |
| 4829 | .compare_flags_unsigned, | 4791 | .cpsr_flags, |
| 4830 | .compare_flags_signed, | | |
| 4831 | .immediate, | 4792 | .immediate, |
| 4832 | .ptr_stack_offset, | 4793 | .ptr_stack_offset, |
| 4833 | => { | 4794 | => { |