| ... | ... | @@ -91,7 +91,7 @@ register_manager: RegisterManager = .{}, |
| 91 | 91 | /// Maps offset to what is stored there. |
| 92 | 92 | stack: std.AutoHashMapUnmanaged(u32, StackAllocation) = .{}, |
| 93 | 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 | 96 | /// Offset from the stack base, representing the end of the stack frame. |
| 97 | 97 | max_end_stack: u32 = 0, |
| ... | ... | @@ -154,7 +154,7 @@ const MCValue = union(enum) { |
| 154 | 154 | /// The value resides in the N, Z, C, V flags. The value is 1 (if |
| 155 | 155 | /// the type is u1) or true (if the type in bool) iff the |
| 156 | 156 | /// specified condition is true. |
| 157 | | condition_flags: Condition, |
| 157 | compare_flags: Condition, |
| 158 | 158 | /// The value is a function argument passed via the stack. |
| 159 | 159 | stack_argument_offset: u32, |
| 160 | 160 | }; |
| ... | ... | @@ -201,6 +201,29 @@ const BigTomb = struct { |
| 201 | 201 | log.debug("%{d} => {}", .{ bt.inst, result }); |
| 202 | 202 | const branch = &bt.function.branch_stack.items[bt.function.branch_stack.items.len - 1]; |
| 203 | 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 | 228 | bt.function.finishAirBookkeeping(); |
| 206 | 229 | } |
| ... | ... | @@ -764,10 +787,10 @@ fn processDeath(self: *Self, inst: Air.Inst.Index) void { |
| 764 | 787 | }, |
| 765 | 788 | .register_with_overflow => |rwo| { |
| 766 | 789 | self.register_manager.freeReg(rwo.reg); |
| 767 | | self.condition_flags_inst = null; |
| 790 | self.compare_flags_inst = null; |
| 768 | 791 | }, |
| 769 | | .condition_flags => { |
| 770 | | self.condition_flags_inst = null; |
| 792 | .compare_flags => { |
| 793 | self.compare_flags_inst = null; |
| 771 | 794 | }, |
| 772 | 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 | 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 | 843 | else => {}, |
| 812 | 844 | } |
| 813 | 845 | } |
| ... | ... | @@ -931,11 +963,11 @@ pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void |
| 931 | 963 | /// Save the current instruction stored in the compare flags if |
| 932 | 964 | /// occupied |
| 933 | 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 | 967 | const ty = self.air.typeOfIndex(inst_to_save); |
| 936 | 968 | const mcv = self.getResolvedInstValue(inst_to_save); |
| 937 | 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 | 971 | .register_with_overflow => try self.allocRegOrMem(ty, false, inst_to_save), |
| 940 | 972 | else => unreachable, // mcv doesn't occupy the compare flags |
| 941 | 973 | }; |
| ... | ... | @@ -946,7 +978,7 @@ fn spillCompareFlagsIfOccupied(self: *Self) !void { |
| 946 | 978 | const branch = &self.branch_stack.items[self.branch_stack.items.len - 1]; |
| 947 | 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 | 983 | // TODO consolidate with register manager and spillInstruction |
| 952 | 984 | // this call should really belong in the register manager! |
| ... | ... | @@ -1155,7 +1187,7 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void { |
| 1155 | 1187 | switch (operand) { |
| 1156 | 1188 | .dead => unreachable, |
| 1157 | 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 | 1191 | else => { |
| 1160 | 1192 | switch (operand_ty.zigTypeTag()) { |
| 1161 | 1193 | .Bool => { |
| ... | ... | @@ -1564,9 +1596,9 @@ fn allocRegs( |
| 1564 | 1596 | // If the previous MCValue occupied some space we track, we |
| 1565 | 1597 | // need to make sure it is marked as free now. |
| 1566 | 1598 | switch (mcv) { |
| 1567 | | .condition_flags => { |
| 1568 | | assert(self.condition_flags_inst.? == inst); |
| 1569 | | self.condition_flags_inst = null; |
| 1599 | .compare_flags => { |
| 1600 | assert(self.compare_flags_inst.? == inst); |
| 1601 | self.compare_flags_inst = null; |
| 1570 | 1602 | }, |
| 1571 | 1603 | .register => |prev_reg| { |
| 1572 | 1604 | assert(!self.register_manager.isRegFree(prev_reg)); |
| ... | ... | @@ -2363,7 +2395,7 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 2363 | 2395 | const stack_offset = try self.allocMem(tuple_size, tuple_align, inst); |
| 2364 | 2396 | |
| 2365 | 2397 | try self.spillCompareFlagsIfOccupied(); |
| 2366 | | self.condition_flags_inst = null; |
| 2398 | self.compare_flags_inst = null; |
| 2367 | 2399 | |
| 2368 | 2400 | const base_tag: Air.Inst.Tag = switch (tag) { |
| 2369 | 2401 | .add_with_overflow => .add, |
| ... | ... | @@ -2395,7 +2427,7 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 2395 | 2427 | }); |
| 2396 | 2428 | |
| 2397 | 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 | 2432 | break :result MCValue{ .stack_offset = stack_offset }; |
| 2401 | 2433 | }, |
| ... | ... | @@ -2430,7 +2462,7 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 2430 | 2462 | }; |
| 2431 | 2463 | |
| 2432 | 2464 | try self.spillCompareFlagsIfOccupied(); |
| 2433 | | self.condition_flags_inst = inst; |
| 2465 | self.compare_flags_inst = inst; |
| 2434 | 2466 | |
| 2435 | 2467 | const dest = blk: { |
| 2436 | 2468 | if (rhs_immediate_ok) { |
| ... | ... | @@ -2539,7 +2571,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 2539 | 2571 | } |
| 2540 | 2572 | |
| 2541 | 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 | 2576 | break :result MCValue{ .stack_offset = stack_offset }; |
| 2545 | 2577 | } else if (int_info.bits <= 64) { |
| ... | ... | @@ -2679,7 +2711,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 2679 | 2711 | try self.truncRegister(dest_reg, truncated_reg, int_info.signedness, int_info.bits); |
| 2680 | 2712 | |
| 2681 | 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 | 2716 | break :result MCValue{ .stack_offset = stack_offset }; |
| 2685 | 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 | 2843 | }); |
| 2812 | 2844 | |
| 2813 | 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 | 2848 | break :result MCValue{ .stack_offset = stack_offset }; |
| 2817 | 2849 | } else { |
| ... | ... | @@ -3262,7 +3294,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo |
| 3262 | 3294 | .undef => unreachable, |
| 3263 | 3295 | .unreach => unreachable, |
| 3264 | 3296 | .dead => unreachable, |
| 3265 | | .condition_flags, |
| 3297 | .compare_flags, |
| 3266 | 3298 | .register_with_overflow, |
| 3267 | 3299 | => unreachable, // cannot hold an address |
| 3268 | 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 | 3306 | switch (dst_mcv) { |
| 3275 | 3307 | .dead => unreachable, |
| 3276 | 3308 | .undef => unreachable, |
| 3277 | | .condition_flags => unreachable, |
| 3309 | .compare_flags => unreachable, |
| 3278 | 3310 | .register => |dst_reg| { |
| 3279 | 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 | 3515 | .undef => unreachable, |
| 3484 | 3516 | .unreach => unreachable, |
| 3485 | 3517 | .dead => unreachable, |
| 3486 | | .condition_flags, |
| 3518 | .compare_flags, |
| 3487 | 3519 | .register_with_overflow, |
| 3488 | 3520 | => unreachable, // cannot hold an address |
| 3489 | 3521 | .immediate => |imm| { |
| ... | ... | @@ -3638,7 +3670,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { |
| 3638 | 3670 | 0 => MCValue{ .register = rwo.reg }, |
| 3639 | 3671 | |
| 3640 | 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 | 3675 | else => unreachable, |
| 3644 | 3676 | }; |
| ... | ... | @@ -4092,8 +4124,8 @@ fn cmp( |
| 4092 | 4124 | } |
| 4093 | 4125 | |
| 4094 | 4126 | return switch (int_info.signedness) { |
| 4095 | | .signed => MCValue{ .condition_flags = Condition.fromCompareOperatorSigned(op) }, |
| 4096 | | .unsigned => MCValue{ .condition_flags = Condition.fromCompareOperatorUnsigned(op) }, |
| 4127 | .signed => MCValue{ .compare_flags = Condition.fromCompareOperatorSigned(op) }, |
| 4128 | .unsigned => MCValue{ .compare_flags = Condition.fromCompareOperatorUnsigned(op) }, |
| 4097 | 4129 | }; |
| 4098 | 4130 | } else { |
| 4099 | 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 | 4183 | |
| 4152 | 4184 | fn condBr(self: *Self, condition: MCValue) !Mir.Inst.Index { |
| 4153 | 4185 | switch (condition) { |
| 4154 | | .condition_flags => |cond| return try self.addInst(.{ |
| 4186 | .compare_flags => |cond| return try self.addInst(.{ |
| 4155 | 4187 | .tag = .b_cond, |
| 4156 | 4188 | .data = .{ |
| 4157 | 4189 | .inst_cond = .{ |
| ... | ... | @@ -4207,7 +4239,7 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void { |
| 4207 | 4239 | var parent_stack = try self.stack.clone(self.gpa); |
| 4208 | 4240 | defer parent_stack.deinit(self.gpa); |
| 4209 | 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 | 4244 | try self.branch_stack.append(.{}); |
| 4213 | 4245 | errdefer { |
| ... | ... | @@ -4226,7 +4258,7 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void { |
| 4226 | 4258 | defer saved_then_branch.deinit(self.gpa); |
| 4227 | 4259 | |
| 4228 | 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 | 4263 | self.stack.deinit(self.gpa); |
| 4232 | 4264 | self.stack = parent_stack; |
| ... | ... | @@ -4354,9 +4386,9 @@ fn isErr(self: *Self, ty: Type, operand: MCValue) !MCValue { |
| 4354 | 4386 | fn isNonErr(self: *Self, ty: Type, operand: MCValue) !MCValue { |
| 4355 | 4387 | const is_err_result = try self.isErr(ty, operand); |
| 4356 | 4388 | switch (is_err_result) { |
| 4357 | | .condition_flags => |cond| { |
| 4389 | .compare_flags => |cond| { |
| 4358 | 4390 | assert(cond == .hi); |
| 4359 | | return MCValue{ .condition_flags = cond.negate() }; |
| 4391 | return MCValue{ .compare_flags = cond.negate() }; |
| 4360 | 4392 | }, |
| 4361 | 4393 | .immediate => |imm| { |
| 4362 | 4394 | assert(imm == 0); |
| ... | ... | @@ -4519,10 +4551,132 @@ fn airBlock(self: *Self, inst: Air.Inst.Index) !void { |
| 4519 | 4551 | |
| 4520 | 4552 | fn airSwitch(self: *Self, inst: Air.Inst.Index) !void { |
| 4521 | 4553 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; |
| 4522 | | const condition = pl_op.operand; |
| 4523 | | _ = condition; |
| 4554 | const condition_ty = self.air.typeOf(pl_op.operand); |
| 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 | 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 | 4705 | block_data.mcv = switch (operand_mcv) { |
| 4552 | 4706 | .none, .dead, .unreach => unreachable, |
| 4553 | 4707 | .register, .stack_offset, .memory => operand_mcv, |
| 4554 | | .immediate, .stack_argument_offset, .condition_flags => blk: { |
| 4708 | .immediate, .stack_argument_offset, .compare_flags => blk: { |
| 4555 | 4709 | const new_mcv = try self.allocRegOrMem(self.air.typeOfIndex(block), true, block); |
| 4556 | 4710 | try self.setRegOrMem(self.air.typeOfIndex(block), new_mcv, operand_mcv); |
| 4557 | 4711 | break :blk new_mcv; |
| ... | ... | @@ -4734,7 +4888,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro |
| 4734 | 4888 | else => return self.fail("TODO implement memset", .{}), |
| 4735 | 4889 | } |
| 4736 | 4890 | }, |
| 4737 | | .condition_flags, |
| 4891 | .compare_flags, |
| 4738 | 4892 | .immediate, |
| 4739 | 4893 | .ptr_stack_offset, |
| 4740 | 4894 | => { |
| ... | ... | @@ -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 | 5052 | _ = try self.addInst(.{ |
| 4899 | 5053 | .tag = .cset, |
| 4900 | 5054 | .data = .{ .r_cond = .{ |
| ... | ... | @@ -5171,7 +5325,7 @@ fn genSetStackArgument(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) I |
| 5171 | 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 | 5329 | .immediate, |
| 5176 | 5330 | .ptr_stack_offset, |
| 5177 | 5331 | => { |