| ... | @@ -91,7 +91,7 @@ register_manager: RegisterManager = .{}, | ... | @@ -91,7 +91,7 @@ register_manager: RegisterManager = .{}, |
| 91 | /// Maps offset to what is stored there. | 91 | /// Maps offset to what is stored there. |
| 92 | stack: std.AutoHashMapUnmanaged(u32, StackAllocation) = .{}, | 92 | stack: std.AutoHashMapUnmanaged(u32, StackAllocation) = .{}, |
| 93 | /// Tracks the current instruction allocated to the compare flags | 93 | /// Tracks the current instruction allocated to the compare flags |
| 94 | condition_flags_inst: ?Air.Inst.Index = null, | 94 | compare_flags_inst: ?Air.Inst.Index = null, |
| 95 | | 95 | |
| 96 | /// Offset from the stack base, representing the end of the stack frame. | 96 | /// Offset from the stack base, representing the end of the stack frame. |
| 97 | max_end_stack: u32 = 0, | 97 | max_end_stack: u32 = 0, |
| ... | @@ -154,7 +154,7 @@ const MCValue = union(enum) { | ... | @@ -154,7 +154,7 @@ const MCValue = union(enum) { |
| 154 | /// The value resides in the N, Z, C, V flags. The value is 1 (if | 154 | /// The value resides in the N, Z, C, V flags. The value is 1 (if |
| 155 | /// the type is u1) or true (if the type in bool) iff the | 155 | /// the type is u1) or true (if the type in bool) iff the |
| 156 | /// specified condition is true. | 156 | /// specified condition is true. |
| 157 | condition_flags: Condition, | 157 | compare_flags: Condition, |
| 158 | /// The value is a function argument passed via the stack. | 158 | /// The value is a function argument passed via the stack. |
| 159 | stack_argument_offset: u32, | 159 | stack_argument_offset: u32, |
| 160 | }; | 160 | }; |
| ... | @@ -201,6 +201,29 @@ const BigTomb = struct { | ... | @@ -201,6 +201,29 @@ const BigTomb = struct { |
| 201 | log.debug("%{d} => {}", .{ bt.inst, result }); | 201 | log.debug("%{d} => {}", .{ bt.inst, result }); |
| 202 | const branch = &bt.function.branch_stack.items[bt.function.branch_stack.items.len - 1]; | 202 | const branch = &bt.function.branch_stack.items[bt.function.branch_stack.items.len - 1]; |
| 203 | branch.inst_table.putAssumeCapacityNoClobber(bt.inst, result); | 203 | branch.inst_table.putAssumeCapacityNoClobber(bt.inst, result); |
| | 204 | |
| | 205 | switch (result) { |
| | 206 | .register => |reg| { |
| | 207 | // In some cases (such as bitcast), an operand |
| | 208 | // may be the same MCValue as the result. If |
| | 209 | // that operand died and was a register, it |
| | 210 | // was freed by processDeath. We have to |
| | 211 | // "re-allocate" the register. |
| | 212 | if (bt.function.register_manager.isRegFree(reg)) { |
| | 213 | bt.function.register_manager.getRegAssumeFree(reg, bt.inst); |
| | 214 | } |
| | 215 | }, |
| | 216 | .register_with_overflow => |rwo| { |
| | 217 | if (bt.function.register_manager.isRegFree(rwo.reg)) { |
| | 218 | bt.function.register_manager.getRegAssumeFree(rwo.reg, bt.inst); |
| | 219 | } |
| | 220 | bt.function.compare_flags_inst = bt.inst; |
| | 221 | }, |
| | 222 | .compare_flags => |_| { |
| | 223 | bt.function.compare_flags_inst = bt.inst; |
| | 224 | }, |
| | 225 | else => {}, |
| | 226 | } |
| 204 | } | 227 | } |
| 205 | bt.function.finishAirBookkeeping(); | 228 | bt.function.finishAirBookkeeping(); |
| 206 | } | 229 | } |
| ... | @@ -764,10 +787,10 @@ fn processDeath(self: *Self, inst: Air.Inst.Index) void { | ... | @@ -764,10 +787,10 @@ fn processDeath(self: *Self, inst: Air.Inst.Index) void { |
| 764 | }, | 787 | }, |
| 765 | .register_with_overflow => |rwo| { | 788 | .register_with_overflow => |rwo| { |
| 766 | self.register_manager.freeReg(rwo.reg); | 789 | self.register_manager.freeReg(rwo.reg); |
| 767 | self.condition_flags_inst = null; | 790 | self.compare_flags_inst = null; |
| 768 | }, | 791 | }, |
| 769 | .condition_flags => { | 792 | .compare_flags => { |
| 770 | self.condition_flags_inst = null; | 793 | self.compare_flags_inst = null; |
| 771 | }, | 794 | }, |
| 772 | else => {}, // TODO process stack allocation death | 795 | else => {}, // TODO process stack allocation death |
| 773 | } | 796 | } |
| ... | @@ -808,6 +831,15 @@ fn finishAir(self: *Self, inst: Air.Inst.Index, result: MCValue, operands: [Live | ... | @@ -808,6 +831,15 @@ fn finishAir(self: *Self, inst: Air.Inst.Index, result: MCValue, operands: [Live |
| 808 | self.register_manager.getRegAssumeFree(reg, inst); | 831 | self.register_manager.getRegAssumeFree(reg, inst); |
| 809 | } | 832 | } |
| 810 | }, | 833 | }, |
| | 834 | .register_with_overflow => |rwo| { |
| | 835 | if (self.register_manager.isRegFree(rwo.reg)) { |
| | 836 | self.register_manager.getRegAssumeFree(rwo.reg, inst); |
| | 837 | } |
| | 838 | self.compare_flags_inst = inst; |
| | 839 | }, |
| | 840 | .compare_flags => |_| { |
| | 841 | self.compare_flags_inst = inst; |
| | 842 | }, |
| 811 | else => {}, | 843 | else => {}, |
| 812 | } | 844 | } |
| 813 | } | 845 | } |
| ... | @@ -931,11 +963,11 @@ pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void | ... | @@ -931,11 +963,11 @@ pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void |
| 931 | /// Save the current instruction stored in the compare flags if | 963 | /// Save the current instruction stored in the compare flags if |
| 932 | /// occupied | 964 | /// occupied |
| 933 | fn spillCompareFlagsIfOccupied(self: *Self) !void { | 965 | fn spillCompareFlagsIfOccupied(self: *Self) !void { |
| 934 | if (self.condition_flags_inst) |inst_to_save| { | 966 | if (self.compare_flags_inst) |inst_to_save| { |
| 935 | const ty = self.air.typeOfIndex(inst_to_save); | 967 | const ty = self.air.typeOfIndex(inst_to_save); |
| 936 | const mcv = self.getResolvedInstValue(inst_to_save); | 968 | const mcv = self.getResolvedInstValue(inst_to_save); |
| 937 | const new_mcv = switch (mcv) { | 969 | const new_mcv = switch (mcv) { |
| 938 | .condition_flags => try self.allocRegOrMem(ty, true, inst_to_save), | 970 | .compare_flags => try self.allocRegOrMem(ty, true, inst_to_save), |
| 939 | .register_with_overflow => try self.allocRegOrMem(ty, false, inst_to_save), | 971 | .register_with_overflow => try self.allocRegOrMem(ty, false, inst_to_save), |
| 940 | else => unreachable, // mcv doesn't occupy the compare flags | 972 | else => unreachable, // mcv doesn't occupy the compare flags |
| 941 | }; | 973 | }; |
| ... | @@ -946,7 +978,7 @@ fn spillCompareFlagsIfOccupied(self: *Self) !void { | ... | @@ -946,7 +978,7 @@ fn spillCompareFlagsIfOccupied(self: *Self) !void { |
| 946 | const branch = &self.branch_stack.items[self.branch_stack.items.len - 1]; | 978 | const branch = &self.branch_stack.items[self.branch_stack.items.len - 1]; |
| 947 | try branch.inst_table.put(self.gpa, inst_to_save, new_mcv); | 979 | try branch.inst_table.put(self.gpa, inst_to_save, new_mcv); |
| 948 | | 980 | |
| 949 | self.condition_flags_inst = null; | 981 | self.compare_flags_inst = null; |
| 950 | | 982 | |
| 951 | // TODO consolidate with register manager and spillInstruction | 983 | // TODO consolidate with register manager and spillInstruction |
| 952 | // this call should really belong in the register manager! | 984 | // this call should really belong in the register manager! |
| ... | @@ -1155,7 +1187,7 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1155,7 +1187,7 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void { |
| 1155 | switch (operand) { | 1187 | switch (operand) { |
| 1156 | .dead => unreachable, | 1188 | .dead => unreachable, |
| 1157 | .unreach => unreachable, | 1189 | .unreach => unreachable, |
| 1158 | .condition_flags => |cond| break :result MCValue{ .condition_flags = cond.negate() }, | 1190 | .compare_flags => |cond| break :result MCValue{ .compare_flags = cond.negate() }, |
| 1159 | else => { | 1191 | else => { |
| 1160 | switch (operand_ty.zigTypeTag()) { | 1192 | switch (operand_ty.zigTypeTag()) { |
| 1161 | .Bool => { | 1193 | .Bool => { |
| ... | @@ -1564,9 +1596,9 @@ fn allocRegs( | ... | @@ -1564,9 +1596,9 @@ fn allocRegs( |
| 1564 | // If the previous MCValue occupied some space we track, we | 1596 | // If the previous MCValue occupied some space we track, we |
| 1565 | // need to make sure it is marked as free now. | 1597 | // need to make sure it is marked as free now. |
| 1566 | switch (mcv) { | 1598 | switch (mcv) { |
| 1567 | .condition_flags => { | 1599 | .compare_flags => { |
| 1568 | assert(self.condition_flags_inst.? == inst); | 1600 | assert(self.compare_flags_inst.? == inst); |
| 1569 | self.condition_flags_inst = null; | 1601 | self.compare_flags_inst = null; |
| 1570 | }, | 1602 | }, |
| 1571 | .register => |prev_reg| { | 1603 | .register => |prev_reg| { |
| 1572 | assert(!self.register_manager.isRegFree(prev_reg)); | 1604 | assert(!self.register_manager.isRegFree(prev_reg)); |
| ... | @@ -2363,7 +2395,7 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2363,7 +2395,7 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 2363 | const stack_offset = try self.allocMem(tuple_size, tuple_align, inst); | 2395 | const stack_offset = try self.allocMem(tuple_size, tuple_align, inst); |
| 2364 | | 2396 | |
| 2365 | try self.spillCompareFlagsIfOccupied(); | 2397 | try self.spillCompareFlagsIfOccupied(); |
| 2366 | self.condition_flags_inst = null; | 2398 | self.compare_flags_inst = null; |
| 2367 | | 2399 | |
| 2368 | const base_tag: Air.Inst.Tag = switch (tag) { | 2400 | const base_tag: Air.Inst.Tag = switch (tag) { |
| 2369 | .add_with_overflow => .add, | 2401 | .add_with_overflow => .add, |
| ... | @@ -2395,7 +2427,7 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2395,7 +2427,7 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 2395 | }); | 2427 | }); |
| 2396 | | 2428 | |
| 2397 | try self.genSetStack(lhs_ty, stack_offset, .{ .register = truncated_reg }); | 2429 | try self.genSetStack(lhs_ty, stack_offset, .{ .register = truncated_reg }); |
| 2398 | try self.genSetStack(Type.initTag(.u1), stack_offset - overflow_bit_offset, .{ .condition_flags = .ne }); | 2430 | try self.genSetStack(Type.initTag(.u1), stack_offset - overflow_bit_offset, .{ .compare_flags = .ne }); |
| 2399 | | 2431 | |
| 2400 | break :result MCValue{ .stack_offset = stack_offset }; | 2432 | break :result MCValue{ .stack_offset = stack_offset }; |
| 2401 | }, | 2433 | }, |
| ... | @@ -2430,7 +2462,7 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2430,7 +2462,7 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 2430 | }; | 2462 | }; |
| 2431 | | 2463 | |
| 2432 | try self.spillCompareFlagsIfOccupied(); | 2464 | try self.spillCompareFlagsIfOccupied(); |
| 2433 | self.condition_flags_inst = inst; | 2465 | self.compare_flags_inst = inst; |
| 2434 | | 2466 | |
| 2435 | const dest = blk: { | 2467 | const dest = blk: { |
| 2436 | if (rhs_immediate_ok) { | 2468 | if (rhs_immediate_ok) { |
| ... | @@ -2539,7 +2571,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2539,7 +2571,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 2539 | } | 2571 | } |
| 2540 | | 2572 | |
| 2541 | try self.genSetStack(lhs_ty, stack_offset, .{ .register = truncated_reg }); | 2573 | try self.genSetStack(lhs_ty, stack_offset, .{ .register = truncated_reg }); |
| 2542 | try self.genSetStack(Type.initTag(.u1), stack_offset - overflow_bit_offset, .{ .condition_flags = .ne }); | 2574 | try self.genSetStack(Type.initTag(.u1), stack_offset - overflow_bit_offset, .{ .compare_flags = .ne }); |
| 2543 | | 2575 | |
| 2544 | break :result MCValue{ .stack_offset = stack_offset }; | 2576 | break :result MCValue{ .stack_offset = stack_offset }; |
| 2545 | } else if (int_info.bits <= 64) { | 2577 | } else if (int_info.bits <= 64) { |
| ... | @@ -2679,7 +2711,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2679,7 +2711,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 2679 | try self.truncRegister(dest_reg, truncated_reg, int_info.signedness, int_info.bits); | 2711 | try self.truncRegister(dest_reg, truncated_reg, int_info.signedness, int_info.bits); |
| 2680 | | 2712 | |
| 2681 | try self.genSetStack(lhs_ty, stack_offset, .{ .register = truncated_reg }); | 2713 | try self.genSetStack(lhs_ty, stack_offset, .{ .register = truncated_reg }); |
| 2682 | try self.genSetStack(Type.initTag(.u1), stack_offset - overflow_bit_offset, .{ .condition_flags = .ne }); | 2714 | try self.genSetStack(Type.initTag(.u1), stack_offset - overflow_bit_offset, .{ .compare_flags = .ne }); |
| 2683 | | 2715 | |
| 2684 | break :result MCValue{ .stack_offset = stack_offset }; | 2716 | break :result MCValue{ .stack_offset = stack_offset }; |
| 2685 | } else return self.fail("TODO implement mul_with_overflow for integers > u64/i64", .{}); | 2717 | } else return self.fail("TODO implement mul_with_overflow for integers > u64/i64", .{}); |
| ... | @@ -2811,7 +2843,7 @@ fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2811,7 +2843,7 @@ fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 2811 | }); | 2843 | }); |
| 2812 | | 2844 | |
| 2813 | try self.genSetStack(lhs_ty, stack_offset, .{ .register = dest_reg }); | 2845 | try self.genSetStack(lhs_ty, stack_offset, .{ .register = dest_reg }); |
| 2814 | try self.genSetStack(Type.initTag(.u1), stack_offset - overflow_bit_offset, .{ .condition_flags = .ne }); | 2846 | try self.genSetStack(Type.initTag(.u1), stack_offset - overflow_bit_offset, .{ .compare_flags = .ne }); |
| 2815 | | 2847 | |
| 2816 | break :result MCValue{ .stack_offset = stack_offset }; | 2848 | break :result MCValue{ .stack_offset = stack_offset }; |
| 2817 | } else { | 2849 | } else { |
| ... | @@ -3262,7 +3294,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo | ... | @@ -3262,7 +3294,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo |
| 3262 | .undef => unreachable, | 3294 | .undef => unreachable, |
| 3263 | .unreach => unreachable, | 3295 | .unreach => unreachable, |
| 3264 | .dead => unreachable, | 3296 | .dead => unreachable, |
| 3265 | .condition_flags, | 3297 | .compare_flags, |
| 3266 | .register_with_overflow, | 3298 | .register_with_overflow, |
| 3267 | => unreachable, // cannot hold an address | 3299 | => unreachable, // cannot hold an address |
| 3268 | .immediate => |imm| try self.setRegOrMem(elem_ty, dst_mcv, .{ .memory = imm }), | 3300 | .immediate => |imm| try self.setRegOrMem(elem_ty, dst_mcv, .{ .memory = imm }), |
| ... | @@ -3274,7 +3306,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo | ... | @@ -3274,7 +3306,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo |
| 3274 | switch (dst_mcv) { | 3306 | switch (dst_mcv) { |
| 3275 | .dead => unreachable, | 3307 | .dead => unreachable, |
| 3276 | .undef => unreachable, | 3308 | .undef => unreachable, |
| 3277 | .condition_flags => unreachable, | 3309 | .compare_flags => unreachable, |
| 3278 | .register => |dst_reg| { | 3310 | .register => |dst_reg| { |
| 3279 | try self.genLdrRegister(dst_reg, addr_reg, elem_ty); | 3311 | try self.genLdrRegister(dst_reg, addr_reg, elem_ty); |
| 3280 | }, | 3312 | }, |
| ... | @@ -3483,7 +3515,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type | ... | @@ -3483,7 +3515,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type |
| 3483 | .undef => unreachable, | 3515 | .undef => unreachable, |
| 3484 | .unreach => unreachable, | 3516 | .unreach => unreachable, |
| 3485 | .dead => unreachable, | 3517 | .dead => unreachable, |
| 3486 | .condition_flags, | 3518 | .compare_flags, |
| 3487 | .register_with_overflow, | 3519 | .register_with_overflow, |
| 3488 | => unreachable, // cannot hold an address | 3520 | => unreachable, // cannot hold an address |
| 3489 | .immediate => |imm| { | 3521 | .immediate => |imm| { |
| ... | @@ -3638,7 +3670,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -3638,7 +3670,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { |
| 3638 | 0 => MCValue{ .register = rwo.reg }, | 3670 | 0 => MCValue{ .register = rwo.reg }, |
| 3639 | | 3671 | |
| 3640 | // get overflow bit: return C or V flag | 3672 | // get overflow bit: return C or V flag |
| 3641 | 1 => MCValue{ .condition_flags = rwo.flag }, | 3673 | 1 => MCValue{ .compare_flags = rwo.flag }, |
| 3642 | | 3674 | |
| 3643 | else => unreachable, | 3675 | else => unreachable, |
| 3644 | }; | 3676 | }; |
| ... | @@ -4092,8 +4124,8 @@ fn cmp( | ... | @@ -4092,8 +4124,8 @@ fn cmp( |
| 4092 | } | 4124 | } |
| 4093 | | 4125 | |
| 4094 | return switch (int_info.signedness) { | 4126 | return switch (int_info.signedness) { |
| 4095 | .signed => MCValue{ .condition_flags = Condition.fromCompareOperatorSigned(op) }, | 4127 | .signed => MCValue{ .compare_flags = Condition.fromCompareOperatorSigned(op) }, |
| 4096 | .unsigned => MCValue{ .condition_flags = Condition.fromCompareOperatorUnsigned(op) }, | 4128 | .unsigned => MCValue{ .compare_flags = Condition.fromCompareOperatorUnsigned(op) }, |
| 4097 | }; | 4129 | }; |
| 4098 | } else { | 4130 | } else { |
| 4099 | return self.fail("TODO AArch64 cmp for ints > 64 bits", .{}); | 4131 | return self.fail("TODO AArch64 cmp for ints > 64 bits", .{}); |
| ... | @@ -4151,7 +4183,7 @@ fn airDbgVar(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -4151,7 +4183,7 @@ fn airDbgVar(self: *Self, inst: Air.Inst.Index) !void { |
| 4151 | | 4183 | |
| 4152 | fn condBr(self: *Self, condition: MCValue) !Mir.Inst.Index { | 4184 | fn condBr(self: *Self, condition: MCValue) !Mir.Inst.Index { |
| 4153 | switch (condition) { | 4185 | switch (condition) { |
| 4154 | .condition_flags => |cond| return try self.addInst(.{ | 4186 | .compare_flags => |cond| return try self.addInst(.{ |
| 4155 | .tag = .b_cond, | 4187 | .tag = .b_cond, |
| 4156 | .data = .{ | 4188 | .data = .{ |
| 4157 | .inst_cond = .{ | 4189 | .inst_cond = .{ |
| ... | @@ -4207,7 +4239,7 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -4207,7 +4239,7 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void { |
| 4207 | var parent_stack = try self.stack.clone(self.gpa); | 4239 | var parent_stack = try self.stack.clone(self.gpa); |
| 4208 | defer parent_stack.deinit(self.gpa); | 4240 | defer parent_stack.deinit(self.gpa); |
| 4209 | const parent_registers = self.register_manager.registers; | 4241 | const parent_registers = self.register_manager.registers; |
| 4210 | const parent_condition_flags_inst = self.condition_flags_inst; | 4242 | const parent_compare_flags_inst = self.compare_flags_inst; |
| 4211 | | 4243 | |
| 4212 | try self.branch_stack.append(.{}); | 4244 | try self.branch_stack.append(.{}); |
| 4213 | errdefer { | 4245 | errdefer { |
| ... | @@ -4226,7 +4258,7 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -4226,7 +4258,7 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void { |
| 4226 | defer saved_then_branch.deinit(self.gpa); | 4258 | defer saved_then_branch.deinit(self.gpa); |
| 4227 | | 4259 | |
| 4228 | self.register_manager.registers = parent_registers; | 4260 | self.register_manager.registers = parent_registers; |
| 4229 | self.condition_flags_inst = parent_condition_flags_inst; | 4261 | self.compare_flags_inst = parent_compare_flags_inst; |
| 4230 | | 4262 | |
| 4231 | self.stack.deinit(self.gpa); | 4263 | self.stack.deinit(self.gpa); |
| 4232 | self.stack = parent_stack; | 4264 | self.stack = parent_stack; |
| ... | @@ -4354,9 +4386,9 @@ fn isErr(self: *Self, ty: Type, operand: MCValue) !MCValue { | ... | @@ -4354,9 +4386,9 @@ fn isErr(self: *Self, ty: Type, operand: MCValue) !MCValue { |
| 4354 | fn isNonErr(self: *Self, ty: Type, operand: MCValue) !MCValue { | 4386 | fn isNonErr(self: *Self, ty: Type, operand: MCValue) !MCValue { |
| 4355 | const is_err_result = try self.isErr(ty, operand); | 4387 | const is_err_result = try self.isErr(ty, operand); |
| 4356 | switch (is_err_result) { | 4388 | switch (is_err_result) { |
| 4357 | .condition_flags => |cond| { | 4389 | .compare_flags => |cond| { |
| 4358 | assert(cond == .hi); | 4390 | assert(cond == .hi); |
| 4359 | return MCValue{ .condition_flags = cond.negate() }; | 4391 | return MCValue{ .compare_flags = cond.negate() }; |
| 4360 | }, | 4392 | }, |
| 4361 | .immediate => |imm| { | 4393 | .immediate => |imm| { |
| 4362 | assert(imm == 0); | 4394 | assert(imm == 0); |
| ... | @@ -4519,10 +4551,132 @@ fn airBlock(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -4519,10 +4551,132 @@ fn airBlock(self: *Self, inst: Air.Inst.Index) !void { |
| 4519 | | 4551 | |
| 4520 | fn airSwitch(self: *Self, inst: Air.Inst.Index) !void { | 4552 | fn airSwitch(self: *Self, inst: Air.Inst.Index) !void { |
| 4521 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; | 4553 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; |
| 4522 | const condition = pl_op.operand; | 4554 | const condition_ty = self.air.typeOf(pl_op.operand); |
| 4523 | _ = condition; | 4555 | const switch_br = self.air.extraData(Air.SwitchBr, pl_op.payload); |
| | 4556 | const liveness = try self.liveness.getSwitchBr( |
| | 4557 | self.gpa, |
| | 4558 | inst, |
| | 4559 | switch_br.data.cases_len + 1, |
| | 4560 | ); |
| | 4561 | defer self.gpa.free(liveness.deaths); |
| | 4562 | |
| | 4563 | var extra_index: usize = switch_br.end; |
| | 4564 | var case_i: u32 = 0; |
| | 4565 | while (case_i < switch_br.data.cases_len) : (case_i += 1) { |
| | 4566 | const case = self.air.extraData(Air.SwitchBr.Case, extra_index); |
| | 4567 | const items = @ptrCast([]const Air.Inst.Ref, self.air.extra[case.end..][0..case.data.items_len]); |
| | 4568 | assert(items.len > 0); |
| | 4569 | const case_body = self.air.extra[case.end + items.len ..][0..case.data.body_len]; |
| | 4570 | extra_index = case.end + items.len + case_body.len; |
| | 4571 | |
| | 4572 | // For every item, we compare it to condition and branch into |
| | 4573 | // the prong if they are equal. After we compared to all |
| | 4574 | // items, we branch into the next prong (or if no other prongs |
| | 4575 | // exist out of the switch statement). |
| | 4576 | // |
| | 4577 | // cmp condition, item1 |
| | 4578 | // beq prong |
| | 4579 | // cmp condition, item2 |
| | 4580 | // beq prong |
| | 4581 | // cmp condition, item3 |
| | 4582 | // beq prong |
| | 4583 | // b out |
| | 4584 | // prong: ... |
| | 4585 | // ... |
| | 4586 | // out: ... |
| | 4587 | const branch_into_prong_relocs = try self.gpa.alloc(u32, items.len); |
| | 4588 | defer self.gpa.free(branch_into_prong_relocs); |
| | 4589 | |
| | 4590 | for (items) |item, idx| { |
| | 4591 | const cmp_result = try self.cmp(.{ .inst = pl_op.operand }, .{ .inst = item }, condition_ty, .neq); |
| | 4592 | branch_into_prong_relocs[idx] = try self.condBr(cmp_result); |
| | 4593 | } |
| | 4594 | |
| | 4595 | const branch_away_from_prong_reloc = try self.addInst(.{ |
| | 4596 | .tag = .b, |
| | 4597 | .data = .{ .inst = undefined }, // populated later through performReloc |
| | 4598 | }); |
| | 4599 | |
| | 4600 | for (branch_into_prong_relocs) |reloc| { |
| | 4601 | try self.performReloc(reloc); |
| | 4602 | } |
| | 4603 | |
| | 4604 | // Capture the state of register and stack allocation state so that we can revert to it. |
| | 4605 | const parent_next_stack_offset = self.next_stack_offset; |
| | 4606 | const parent_free_registers = self.register_manager.free_registers; |
| | 4607 | const parent_compare_flags_inst = self.compare_flags_inst; |
| | 4608 | var parent_stack = try self.stack.clone(self.gpa); |
| | 4609 | defer parent_stack.deinit(self.gpa); |
| | 4610 | const parent_registers = self.register_manager.registers; |
| | 4611 | |
| | 4612 | try self.branch_stack.append(.{}); |
| | 4613 | errdefer { |
| | 4614 | _ = self.branch_stack.pop(); |
| | 4615 | } |
| | 4616 | |
| | 4617 | try self.ensureProcessDeathCapacity(liveness.deaths[case_i].len); |
| | 4618 | for (liveness.deaths[case_i]) |operand| { |
| | 4619 | self.processDeath(operand); |
| | 4620 | } |
| | 4621 | try self.genBody(case_body); |
| | 4622 | |
| | 4623 | // Revert to the previous register and stack allocation state. |
| | 4624 | var saved_case_branch = self.branch_stack.pop(); |
| | 4625 | defer saved_case_branch.deinit(self.gpa); |
| | 4626 | |
| | 4627 | self.register_manager.registers = parent_registers; |
| | 4628 | self.compare_flags_inst = parent_compare_flags_inst; |
| | 4629 | self.stack.deinit(self.gpa); |
| | 4630 | self.stack = parent_stack; |
| | 4631 | parent_stack = .{}; |
| | 4632 | |
| | 4633 | self.next_stack_offset = parent_next_stack_offset; |
| | 4634 | self.register_manager.free_registers = parent_free_registers; |
| | 4635 | |
| | 4636 | try self.performReloc(branch_away_from_prong_reloc); |
| | 4637 | } |
| | 4638 | |
| | 4639 | if (switch_br.data.else_body_len > 0) { |
| | 4640 | const else_body = self.air.extra[extra_index..][0..switch_br.data.else_body_len]; |
| | 4641 | |
| | 4642 | // Capture the state of register and stack allocation state so that we can revert to it. |
| | 4643 | const parent_next_stack_offset = self.next_stack_offset; |
| | 4644 | const parent_free_registers = self.register_manager.free_registers; |
| | 4645 | const parent_compare_flags_inst = self.compare_flags_inst; |
| | 4646 | var parent_stack = try self.stack.clone(self.gpa); |
| | 4647 | defer parent_stack.deinit(self.gpa); |
| | 4648 | const parent_registers = self.register_manager.registers; |
| | 4649 | |
| | 4650 | try self.branch_stack.append(.{}); |
| | 4651 | errdefer { |
| | 4652 | _ = self.branch_stack.pop(); |
| | 4653 | } |
| | 4654 | |
| | 4655 | const else_deaths = liveness.deaths.len - 1; |
| | 4656 | try self.ensureProcessDeathCapacity(liveness.deaths[else_deaths].len); |
| | 4657 | for (liveness.deaths[else_deaths]) |operand| { |
| | 4658 | self.processDeath(operand); |
| | 4659 | } |
| | 4660 | try self.genBody(else_body); |
| | 4661 | |
| | 4662 | // Revert to the previous register and stack allocation state. |
| | 4663 | var saved_case_branch = self.branch_stack.pop(); |
| | 4664 | defer saved_case_branch.deinit(self.gpa); |
| | 4665 | |
| | 4666 | self.register_manager.registers = parent_registers; |
| | 4667 | self.compare_flags_inst = parent_compare_flags_inst; |
| | 4668 | self.stack.deinit(self.gpa); |
| | 4669 | self.stack = parent_stack; |
| | 4670 | parent_stack = .{}; |
| | 4671 | |
| | 4672 | self.next_stack_offset = parent_next_stack_offset; |
| | 4673 | self.register_manager.free_registers = parent_free_registers; |
| | 4674 | |
| | 4675 | // TODO consolidate returned MCValues between prongs and else branch like we do |
| | 4676 | // in airCondBr. |
| | 4677 | } |
| 4524 | | 4678 | |
| 4525 | return self.fail("TODO airSwitch for {}", .{self.target.cpu.arch}); | 4679 | return self.finishAir(inst, .unreach, .{ pl_op.operand, .none, .none }); |
| 4526 | } | 4680 | } |
| 4527 | | 4681 | |
| 4528 | fn performReloc(self: *Self, inst: Mir.Inst.Index) !void { | 4682 | fn performReloc(self: *Self, inst: Mir.Inst.Index) !void { |
| ... | @@ -4551,7 +4705,7 @@ fn br(self: *Self, block: Air.Inst.Index, operand: Air.Inst.Ref) !void { | ... | @@ -4551,7 +4705,7 @@ fn br(self: *Self, block: Air.Inst.Index, operand: Air.Inst.Ref) !void { |
| 4551 | block_data.mcv = switch (operand_mcv) { | 4705 | block_data.mcv = switch (operand_mcv) { |
| 4552 | .none, .dead, .unreach => unreachable, | 4706 | .none, .dead, .unreach => unreachable, |
| 4553 | .register, .stack_offset, .memory => operand_mcv, | 4707 | .register, .stack_offset, .memory => operand_mcv, |
| 4554 | .immediate, .stack_argument_offset, .condition_flags => blk: { | 4708 | .immediate, .stack_argument_offset, .compare_flags => blk: { |
| 4555 | const new_mcv = try self.allocRegOrMem(self.air.typeOfIndex(block), true, block); | 4709 | const new_mcv = try self.allocRegOrMem(self.air.typeOfIndex(block), true, block); |
| 4556 | try self.setRegOrMem(self.air.typeOfIndex(block), new_mcv, operand_mcv); | 4710 | try self.setRegOrMem(self.air.typeOfIndex(block), new_mcv, operand_mcv); |
| 4557 | break :blk new_mcv; | 4711 | break :blk new_mcv; |
| ... | @@ -4734,7 +4888,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro | ... | @@ -4734,7 +4888,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro |
| 4734 | else => return self.fail("TODO implement memset", .{}), | 4888 | else => return self.fail("TODO implement memset", .{}), |
| 4735 | } | 4889 | } |
| 4736 | }, | 4890 | }, |
| 4737 | .condition_flags, | 4891 | .compare_flags, |
| 4738 | .immediate, | 4892 | .immediate, |
| 4739 | .ptr_stack_offset, | 4893 | .ptr_stack_offset, |
| 4740 | => { | 4894 | => { |
| ... | @@ -4894,7 +5048,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void | ... | @@ -4894,7 +5048,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void |
| 4894 | } }, | 5048 | } }, |
| 4895 | }); | 5049 | }); |
| 4896 | }, | 5050 | }, |
| 4897 | .condition_flags => |condition| { | 5051 | .compare_flags => |condition| { |
| 4898 | _ = try self.addInst(.{ | 5052 | _ = try self.addInst(.{ |
| 4899 | .tag = .cset, | 5053 | .tag = .cset, |
| 4900 | .data = .{ .r_cond = .{ | 5054 | .data = .{ .r_cond = .{ |
| ... | @@ -5171,7 +5325,7 @@ fn genSetStackArgument(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) I | ... | @@ -5171,7 +5325,7 @@ fn genSetStackArgument(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) I |
| 5171 | try self.genInlineMemcpy(src_reg, dst_reg, len_reg, count_reg, tmp_reg); | 5325 | try self.genInlineMemcpy(src_reg, dst_reg, len_reg, count_reg, tmp_reg); |
| 5172 | } | 5326 | } |
| 5173 | }, | 5327 | }, |
| 5174 | .condition_flags, | 5328 | .compare_flags, |
| 5175 | .immediate, | 5329 | .immediate, |
| 5176 | .ptr_stack_offset, | 5330 | .ptr_stack_offset, |
| 5177 | => { | 5331 | => { |