authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-02-22 13:37:26+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-02-22 21:56:34+01:00
log3be6c79ca2414044600426204ac19ea31774420f
treeb5cd25a04f0207d6be728fccb90243daf56d8202
parentb9b4e4671f4377024efb076edd9cc2da9e889a5a

x64: spill compare flags between blocks, extern calls, and cmp insts

This is just the first step towards the final solution as to get here I had omit a safety assert check in `getResolvedInst` helper.

1 files changed, 102 insertions(+), 38 deletions(-)

src/arch/x86_64/CodeGen.zig+102-38
...@@ -50,6 +50,7 @@ src_loc: Module.SrcLoc,...@@ -50,6 +50,7 @@ src_loc: Module.SrcLoc,
50stack_align: u32,50stack_align: u32,
5151
52ret_backpatch: ?Mir.Inst.Index = null,52ret_backpatch: ?Mir.Inst.Index = null,
53compare_flags_inst: ?Air.Inst.Index = null,
5354
54/// MIR Instructions55/// MIR Instructions
55mir_instructions: std.MultiArrayList(Mir.Inst) = .{},56mir_instructions: std.MultiArrayList(Mir.Inst) = .{},
...@@ -774,6 +775,9 @@ fn processDeath(self: *Self, inst: Air.Inst.Index) void {...@@ -774,6 +775,9 @@ fn processDeath(self: *Self, inst: Air.Inst.Index) void {
774 const canon_reg = reg.to64();775 const canon_reg = reg.to64();
775 self.register_manager.freeReg(canon_reg);776 self.register_manager.freeReg(canon_reg);
776 },777 },
778 .compare_flags_signed, .compare_flags_unsigned => {
779 self.compare_flags_inst = null;
780 },
777 else => {}, // TODO process stack allocation death781 else => {}, // TODO process stack allocation death
778 }782 }
779}783}
...@@ -889,6 +893,22 @@ pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void...@@ -889,6 +893,22 @@ pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void
889 try self.genSetStack(self.air.typeOfIndex(inst), stack_mcv.stack_offset, reg_mcv, .{});893 try self.genSetStack(self.air.typeOfIndex(inst), stack_mcv.stack_offset, reg_mcv, .{});
890}894}
891895
896pub fn spillCompareFlagsIfOccupied(self: *Self) !void {
897 if (self.compare_flags_inst) |inst_to_save| {
898 const mcv = self.getResolvedInstValue(inst_to_save);
899 assert(mcv == .compare_flags_signed or mcv == .compare_flags_unsigned);
900
901 const new_mcv = try self.allocRegOrMem(inst_to_save, true);
902 try self.setRegOrMem(self.air.typeOfIndex(inst_to_save), new_mcv, mcv);
903 log.debug("spilling {d} to mcv {any}", .{ inst_to_save, new_mcv });
904
905 const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];
906 try branch.inst_table.put(self.gpa, inst_to_save, new_mcv);
907
908 self.compare_flags_inst = null;
909 }
910}
911
892/// Copies a value to a register without tracking the register. The register is not considered912/// Copies a value to a register without tracking the register. The register is not considered
893/// allocated. A second call to `copyToTmpRegister` may return the same register.913/// allocated. A second call to `copyToTmpRegister` may return the same register.
894/// This can have a side effect of spilling instructions to the stack to free up a register.914/// This can have a side effect of spilling instructions to the stack to free up a register.
...@@ -2763,6 +2783,8 @@ fn genBinMathOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MC...@@ -2763,6 +2783,8 @@ fn genBinMathOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MC
2763 .memory,2783 .memory,
2764 .got_load,2784 .got_load,
2765 .direct_load,2785 .direct_load,
2786 .compare_flags_signed,
2787 .compare_flags_unsigned,
2766 => {2788 => {
2767 assert(abi_size <= 8);2789 assert(abi_size <= 8);
2768 self.register_manager.freezeRegs(&.{dst_reg});2790 self.register_manager.freezeRegs(&.{dst_reg});
...@@ -2784,12 +2806,6 @@ fn genBinMathOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MC...@@ -2784,12 +2806,6 @@ fn genBinMathOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MC
2784 .data = .{ .imm = @bitCast(u32, -off) },2806 .data = .{ .imm = @bitCast(u32, -off) },
2785 });2807 });
2786 },2808 },
2787 .compare_flags_unsigned => {
2788 return self.fail("TODO implement x86 ADD/SUB/CMP source compare flag (unsigned)", .{});
2789 },
2790 .compare_flags_signed => {
2791 return self.fail("TODO implement x86 ADD/SUB/CMP source compare flag (signed)", .{});
2792 },
2793 }2809 }
2794 },2810 },
2795 .stack_offset => |off| {2811 .stack_offset => |off| {
...@@ -3061,6 +3077,8 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void {...@@ -3061,6 +3077,8 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void {
3061 var info = try self.resolveCallingConventionValues(fn_ty);3077 var info = try self.resolveCallingConventionValues(fn_ty);
3062 defer info.deinit(self);3078 defer info.deinit(self);
30633079
3080 try self.spillCompareFlagsIfOccupied();
3081
3064 if (info.return_value == .stack_offset) {3082 if (info.return_value == .stack_offset) {
3065 const ret_ty = fn_ty.fnReturnType();3083 const ret_ty = fn_ty.fnReturnType();
3066 const ret_abi_size = @intCast(u32, ret_ty.abiSize(self.target.*));3084 const ret_abi_size = @intCast(u32, ret_ty.abiSize(self.target.*));
...@@ -3384,17 +3402,24 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {...@@ -3384,17 +3402,24 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
3384 break :blk ty.intInfo(self.target.*).signedness;3402 break :blk ty.intInfo(self.target.*).signedness;
3385 };3403 };
33863404
3387 const lhs = try self.resolveInst(bin_op.lhs);3405 try self.spillCompareFlagsIfOccupied();
3388 const rhs = try self.resolveInst(bin_op.rhs);3406 self.compare_flags_inst = inst;
3407
3389 const result: MCValue = result: {3408 const result: MCValue = result: {
3390 // There are 2 operands, destination and source.3409 // There are 2 operands, destination and source.
3391 // Either one, but not both, can be a memory operand.3410 // Either one, but not both, can be a memory operand.
3392 // Source operand can be an immediate, 8 bits or 32 bits.3411 // Source operand can be an immediate, 8 bits or 32 bits.
3393 // TODO this looks wrong. Why do simply reuse lhs without checking if it is dead or alive?3412 // TODO look into reusing the operand
3394 const dst_mcv = if (lhs.isImmediate() or (lhs.isMemory() and rhs.isMemory()))3413 const lhs = try self.resolveInst(bin_op.lhs);
3395 MCValue{ .register = try self.copyToTmpRegister(ty, lhs) }3414 lhs.freezeIfRegister(&self.register_manager);
3396 else3415 defer lhs.unfreezeIfRegister(&self.register_manager);
3397 lhs;3416
3417 const dst_reg = try self.copyToTmpRegister(ty, lhs);
3418 self.register_manager.freezeRegs(&.{dst_reg});
3419 defer self.register_manager.unfreezeRegs(&.{dst_reg});
3420
3421 const dst_mcv = MCValue{ .register = dst_reg };
3422
3398 // This instruction supports only signed 32-bit immediates at most.3423 // This instruction supports only signed 32-bit immediates at most.
3399 const src_mcv = try self.limitImmediateType(bin_op.rhs, i32);3424 const src_mcv = try self.limitImmediateType(bin_op.rhs, i32);
34003425
...@@ -3404,6 +3429,7 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {...@@ -3404,6 +3429,7 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
3404 .unsigned => MCValue{ .compare_flags_unsigned = op },3429 .unsigned => MCValue{ .compare_flags_unsigned = op },
3405 };3430 };
3406 };3431 };
3432
3407 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });3433 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
3408}3434}
34093435
...@@ -3451,6 +3477,7 @@ fn genCondBrMir(self: *Self, ty: Type, mcv: MCValue) !u32 {...@@ -3451,6 +3477,7 @@ fn genCondBrMir(self: *Self, ty: Type, mcv: MCValue) !u32 {
3451 });3477 });
3452 },3478 },
3453 .register => |reg| {3479 .register => |reg| {
3480 try self.spillCompareFlagsIfOccupied();
3454 _ = try self.addInst(.{3481 _ = try self.addInst(.{
3455 .tag = .@"test",3482 .tag = .@"test",
3456 .ops = (Mir.Ops{3483 .ops = (Mir.Ops{
...@@ -3467,19 +3494,15 @@ fn genCondBrMir(self: *Self, ty: Type, mcv: MCValue) !u32 {...@@ -3467,19 +3494,15 @@ fn genCondBrMir(self: *Self, ty: Type, mcv: MCValue) !u32 {
3467 .data = .{ .inst = undefined },3494 .data = .{ .inst = undefined },
3468 });3495 });
3469 },3496 },
3470 .immediate => {3497 .immediate,
3471 if (abi_size <= 8) {3498 .stack_offset,
3472 const reg = try self.copyToTmpRegister(ty, mcv);3499 => {
3473 return self.genCondBrMir(ty, .{ .register = reg });3500 try self.spillCompareFlagsIfOccupied();
3474 }
3475 return self.fail("TODO implement condbr when condition is immediate larger than 4 bytes", .{});
3476 },
3477 .stack_offset => {
3478 if (abi_size <= 8) {3501 if (abi_size <= 8) {
3479 const reg = try self.copyToTmpRegister(ty, mcv);3502 const reg = try self.copyToTmpRegister(ty, mcv);
3480 return self.genCondBrMir(ty, .{ .register = reg });3503 return self.genCondBrMir(ty, .{ .register = reg });
3481 }3504 }
3482 return self.fail("TODO implement condbr when condition is stack offset with abi larger than 8 bytes", .{});3505 return self.fail("TODO implement condbr when condition is {} with abi larger than 8 bytes", .{mcv});
3483 },3506 },
3484 else => return self.fail("TODO implement condbr when condition is {s}", .{@tagName(mcv)}),3507 else => return self.fail("TODO implement condbr when condition is {s}", .{@tagName(mcv)}),
3485 }3508 }
...@@ -3496,9 +3519,23 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {...@@ -3496,9 +3519,23 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {
34963519
3497 const reloc = try self.genCondBrMir(cond_ty, cond);3520 const reloc = try self.genCondBrMir(cond_ty, cond);
34983521
3522 // If the condition dies here in this condbr instruction, process
3523 // that death now instead of later as this has an effect on
3524 // whether it needs to be spilled in the branches
3525 // TODO I need investigate how to make this work without removing
3526 // an assertion from getResolvedInstValue()
3527 if (self.liveness.operandDies(inst, 0)) {
3528 const op_int = @enumToInt(pl_op.operand);
3529 if (op_int >= Air.Inst.Ref.typed_value_map.len) {
3530 const op_index = @intCast(Air.Inst.Index, op_int - Air.Inst.Ref.typed_value_map.len);
3531 self.processDeath(op_index);
3532 }
3533 }
3534
3499 // Capture the state of register and stack allocation state so that we can revert to it.3535 // Capture the state of register and stack allocation state so that we can revert to it.
3500 const parent_next_stack_offset = self.next_stack_offset;3536 const parent_next_stack_offset = self.next_stack_offset;
3501 const parent_free_registers = self.register_manager.free_registers;3537 const parent_free_registers = self.register_manager.free_registers;
3538 const parent_compare_flags_inst = self.compare_flags_inst;
3502 var parent_stack = try self.stack.clone(self.gpa);3539 var parent_stack = try self.stack.clone(self.gpa);
3503 defer parent_stack.deinit(self.gpa);3540 defer parent_stack.deinit(self.gpa);
3504 const parent_registers = self.register_manager.registers;3541 const parent_registers = self.register_manager.registers;
...@@ -3520,6 +3557,7 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {...@@ -3520,6 +3557,7 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {
3520 defer saved_then_branch.deinit(self.gpa);3557 defer saved_then_branch.deinit(self.gpa);
35213558
3522 self.register_manager.registers = parent_registers;3559 self.register_manager.registers = parent_registers;
3560 self.compare_flags_inst = parent_compare_flags_inst;
35233561
3524 self.stack.deinit(self.gpa);3562 self.stack.deinit(self.gpa);
3525 self.stack = parent_stack;3563 self.stack = parent_stack;
...@@ -3590,6 +3628,7 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {...@@ -3590,6 +3628,7 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {
3590 // We already deleted the items from this table that matched the else_branch.3628 // We already deleted the items from this table that matched the else_branch.
3591 // So these are all instructions that are only overridden in the then branch.3629 // So these are all instructions that are only overridden in the then branch.
3592 parent_branch.inst_table.putAssumeCapacity(then_key, then_value);3630 parent_branch.inst_table.putAssumeCapacity(then_key, then_value);
3631 log.debug("then_value = {}", .{then_value});
3593 if (then_value == .dead)3632 if (then_value == .dead)
3594 continue;3633 continue;
3595 const parent_mcv = blk: {3634 const parent_mcv = blk: {
...@@ -3614,23 +3653,31 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {...@@ -3614,23 +3653,31 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {
3614 return self.finishAir(inst, .unreach, .{ pl_op.operand, .none, .none });3653 return self.finishAir(inst, .unreach, .{ pl_op.operand, .none, .none });
3615}3654}
36163655
3617fn isNull(self: *Self, ty: Type, operand: MCValue) !MCValue {3656fn isNull(self: *Self, inst: Air.Inst.Index, ty: Type, operand: MCValue) !MCValue {
3657 try self.spillCompareFlagsIfOccupied();
3658 self.compare_flags_inst = inst;
3659
3618 try self.genBinMathOpMir(.cmp, ty, operand, MCValue{ .immediate = 0 });3660 try self.genBinMathOpMir(.cmp, ty, operand, MCValue{ .immediate = 0 });
3619 return MCValue{ .compare_flags_unsigned = .eq };3661 return MCValue{ .compare_flags_unsigned = .eq };
3620}3662}
36213663
3622fn isNonNull(self: *Self, ty: Type, operand: MCValue) !MCValue {3664fn isNonNull(self: *Self, inst: Air.Inst.Index, ty: Type, operand: MCValue) !MCValue {
3623 const is_null_res = try self.isNull(ty, operand);3665 const is_null_res = try self.isNull(inst, ty, operand);
3624 assert(is_null_res.compare_flags_unsigned == .eq);3666 assert(is_null_res.compare_flags_unsigned == .eq);
3625 return MCValue{ .compare_flags_unsigned = .neq };3667 return MCValue{ .compare_flags_unsigned = .neq };
3626}3668}
36273669
3628fn isErr(self: *Self, ty: Type, operand: MCValue) !MCValue {3670fn isErr(self: *Self, inst: Air.Inst.Index, ty: Type, operand: MCValue) !MCValue {
3629 const err_type = ty.errorUnionSet();3671 const err_type = ty.errorUnionSet();
3630 const payload_type = ty.errorUnionPayload();3672 const payload_type = ty.errorUnionPayload();
3631 if (!err_type.hasRuntimeBits()) {3673 if (!err_type.hasRuntimeBits()) {
3632 return MCValue{ .immediate = 0 }; // always false3674 return MCValue{ .immediate = 0 }; // always false
3633 } else if (!payload_type.hasRuntimeBits()) {3675 }
3676
3677 try self.spillCompareFlagsIfOccupied();
3678 self.compare_flags_inst = inst;
3679
3680 if (!payload_type.hasRuntimeBits()) {
3634 if (err_type.abiSize(self.target.*) <= 8) {3681 if (err_type.abiSize(self.target.*) <= 8) {
3635 try self.genBinMathOpMir(.cmp, err_type, operand, MCValue{ .immediate = 0 });3682 try self.genBinMathOpMir(.cmp, err_type, operand, MCValue{ .immediate = 0 });
3636 return MCValue{ .compare_flags_unsigned = .gt };3683 return MCValue{ .compare_flags_unsigned = .gt };
...@@ -3643,8 +3690,8 @@ fn isErr(self: *Self, ty: Type, operand: MCValue) !MCValue {...@@ -3643,8 +3690,8 @@ fn isErr(self: *Self, ty: Type, operand: MCValue) !MCValue {
3643 }3690 }
3644}3691}
36453692
3646fn isNonErr(self: *Self, ty: Type, operand: MCValue) !MCValue {3693fn isNonErr(self: *Self, inst: Air.Inst.Index, ty: Type, operand: MCValue) !MCValue {
3647 const is_err_res = try self.isErr(ty, operand);3694 const is_err_res = try self.isErr(inst, ty, operand);
3648 switch (is_err_res) {3695 switch (is_err_res) {
3649 .compare_flags_unsigned => |op| {3696 .compare_flags_unsigned => |op| {
3650 assert(op == .gt);3697 assert(op == .gt);
...@@ -3663,7 +3710,7 @@ fn airIsNull(self: *Self, inst: Air.Inst.Index) !void {...@@ -3663,7 +3710,7 @@ fn airIsNull(self: *Self, inst: Air.Inst.Index) !void {
3663 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {3710 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
3664 const operand = try self.resolveInst(un_op);3711 const operand = try self.resolveInst(un_op);
3665 const ty = self.air.typeOf(un_op);3712 const ty = self.air.typeOf(un_op);
3666 break :result try self.isNull(ty, operand);3713 break :result try self.isNull(inst, ty, operand);
3667 };3714 };
3668 return self.finishAir(inst, result, .{ un_op, .none, .none });3715 return self.finishAir(inst, result, .{ un_op, .none, .none });
3669}3716}
...@@ -3684,7 +3731,7 @@ fn airIsNullPtr(self: *Self, inst: Air.Inst.Index) !void {...@@ -3684,7 +3731,7 @@ fn airIsNullPtr(self: *Self, inst: Air.Inst.Index) !void {
3684 };3731 };
3685 const ptr_ty = self.air.typeOf(un_op);3732 const ptr_ty = self.air.typeOf(un_op);
3686 try self.load(operand, operand_ptr, ptr_ty);3733 try self.load(operand, operand_ptr, ptr_ty);
3687 break :result try self.isNull(ptr_ty.elemType(), operand);3734 break :result try self.isNull(inst, ptr_ty.elemType(), operand);
3688 };3735 };
3689 return self.finishAir(inst, result, .{ un_op, .none, .none });3736 return self.finishAir(inst, result, .{ un_op, .none, .none });
3690}3737}
...@@ -3694,7 +3741,7 @@ fn airIsNonNull(self: *Self, inst: Air.Inst.Index) !void {...@@ -3694,7 +3741,7 @@ fn airIsNonNull(self: *Self, inst: Air.Inst.Index) !void {
3694 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {3741 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
3695 const operand = try self.resolveInst(un_op);3742 const operand = try self.resolveInst(un_op);
3696 const ty = self.air.typeOf(un_op);3743 const ty = self.air.typeOf(un_op);
3697 break :result try self.isNonNull(ty, operand);3744 break :result try self.isNonNull(inst, ty, operand);
3698 };3745 };
3699 return self.finishAir(inst, result, .{ un_op, .none, .none });3746 return self.finishAir(inst, result, .{ un_op, .none, .none });
3700}3747}
...@@ -3715,7 +3762,7 @@ fn airIsNonNullPtr(self: *Self, inst: Air.Inst.Index) !void {...@@ -3715,7 +3762,7 @@ fn airIsNonNullPtr(self: *Self, inst: Air.Inst.Index) !void {
3715 };3762 };
3716 const ptr_ty = self.air.typeOf(un_op);3763 const ptr_ty = self.air.typeOf(un_op);
3717 try self.load(operand, operand_ptr, ptr_ty);3764 try self.load(operand, operand_ptr, ptr_ty);
3718 break :result try self.isNonNull(ptr_ty.elemType(), operand);3765 break :result try self.isNonNull(inst, ptr_ty.elemType(), operand);
3719 };3766 };
3720 return self.finishAir(inst, result, .{ un_op, .none, .none });3767 return self.finishAir(inst, result, .{ un_op, .none, .none });
3721}3768}
...@@ -3725,7 +3772,7 @@ fn airIsErr(self: *Self, inst: Air.Inst.Index) !void {...@@ -3725,7 +3772,7 @@ fn airIsErr(self: *Self, inst: Air.Inst.Index) !void {
3725 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {3772 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
3726 const operand = try self.resolveInst(un_op);3773 const operand = try self.resolveInst(un_op);
3727 const ty = self.air.typeOf(un_op);3774 const ty = self.air.typeOf(un_op);
3728 break :result try self.isErr(ty, operand);3775 break :result try self.isErr(inst, ty, operand);
3729 };3776 };
3730 return self.finishAir(inst, result, .{ un_op, .none, .none });3777 return self.finishAir(inst, result, .{ un_op, .none, .none });
3731}3778}
...@@ -3746,7 +3793,7 @@ fn airIsErrPtr(self: *Self, inst: Air.Inst.Index) !void {...@@ -3746,7 +3793,7 @@ fn airIsErrPtr(self: *Self, inst: Air.Inst.Index) !void {
3746 };3793 };
3747 const ptr_ty = self.air.typeOf(un_op);3794 const ptr_ty = self.air.typeOf(un_op);
3748 try self.load(operand, operand_ptr, ptr_ty);3795 try self.load(operand, operand_ptr, ptr_ty);
3749 break :result try self.isErr(ptr_ty.elemType(), operand);3796 break :result try self.isErr(inst, ptr_ty.elemType(), operand);
3750 };3797 };
3751 return self.finishAir(inst, result, .{ un_op, .none, .none });3798 return self.finishAir(inst, result, .{ un_op, .none, .none });
3752}3799}
...@@ -3756,7 +3803,7 @@ fn airIsNonErr(self: *Self, inst: Air.Inst.Index) !void {...@@ -3756,7 +3803,7 @@ fn airIsNonErr(self: *Self, inst: Air.Inst.Index) !void {
3756 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {3803 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
3757 const operand = try self.resolveInst(un_op);3804 const operand = try self.resolveInst(un_op);
3758 const ty = self.air.typeOf(un_op);3805 const ty = self.air.typeOf(un_op);
3759 break :result try self.isNonErr(ty, operand);3806 break :result try self.isNonErr(inst, ty, operand);
3760 };3807 };
3761 return self.finishAir(inst, result, .{ un_op, .none, .none });3808 return self.finishAir(inst, result, .{ un_op, .none, .none });
3762}3809}
...@@ -3777,7 +3824,7 @@ fn airIsNonErrPtr(self: *Self, inst: Air.Inst.Index) !void {...@@ -3777,7 +3824,7 @@ fn airIsNonErrPtr(self: *Self, inst: Air.Inst.Index) !void {
3777 };3824 };
3778 const ptr_ty = self.air.typeOf(un_op);3825 const ptr_ty = self.air.typeOf(un_op);
3779 try self.load(operand, operand_ptr, ptr_ty);3826 try self.load(operand, operand_ptr, ptr_ty);
3780 break :result try self.isNonErr(ptr_ty.elemType(), operand);3827 break :result try self.isNonErr(inst, ptr_ty.elemType(), operand);
3781 };3828 };
3782 return self.finishAir(inst, result, .{ un_op, .none, .none });3829 return self.finishAir(inst, result, .{ un_op, .none, .none });
3783}3830}
...@@ -3832,6 +3879,7 @@ fn genCondSwitchMir(self: *Self, ty: Type, condition: MCValue, case: MCValue) !u...@@ -3832,6 +3879,7 @@ fn genCondSwitchMir(self: *Self, ty: Type, condition: MCValue, case: MCValue) !u
3832 .compare_flags_signed => unreachable,3879 .compare_flags_signed => unreachable,
3833 .compare_flags_unsigned => unreachable,3880 .compare_flags_unsigned => unreachable,
3834 .register => |cond_reg| {3881 .register => |cond_reg| {
3882 try self.spillCompareFlagsIfOccupied();
3835 switch (case) {3883 switch (case) {
3836 .none => unreachable,3884 .none => unreachable,
3837 .undef => unreachable,3885 .undef => unreachable,
...@@ -3916,9 +3964,23 @@ fn airSwitch(self: *Self, inst: Air.Inst.Index) !void {...@@ -3916,9 +3964,23 @@ fn airSwitch(self: *Self, inst: Air.Inst.Index) !void {
3916 relocs[item_i] = try self.genCondSwitchMir(condition_ty, condition, item_mcv);3964 relocs[item_i] = try self.genCondSwitchMir(condition_ty, condition, item_mcv);
3917 }3965 }
39183966
3967 // If the condition dies here in this condbr instruction, process
3968 // that death now instead of later as this has an effect on
3969 // whether it needs to be spilled in the branches
3970 // TODO I need investigate how to make this work without removing
3971 // an assertion from getResolvedInstValue()
3972 if (self.liveness.operandDies(inst, 0)) {
3973 const op_int = @enumToInt(pl_op.operand);
3974 if (op_int >= Air.Inst.Ref.typed_value_map.len) {
3975 const op_index = @intCast(Air.Inst.Index, op_int - Air.Inst.Ref.typed_value_map.len);
3976 self.processDeath(op_index);
3977 }
3978 }
3979
3919 // Capture the state of register and stack allocation state so that we can revert to it.3980 // Capture the state of register and stack allocation state so that we can revert to it.
3920 const parent_next_stack_offset = self.next_stack_offset;3981 const parent_next_stack_offset = self.next_stack_offset;
3921 const parent_free_registers = self.register_manager.free_registers;3982 const parent_free_registers = self.register_manager.free_registers;
3983 const parent_compare_flags_inst = self.compare_flags_inst;
3922 var parent_stack = try self.stack.clone(self.gpa);3984 var parent_stack = try self.stack.clone(self.gpa);
3923 defer parent_stack.deinit(self.gpa);3985 defer parent_stack.deinit(self.gpa);
3924 const parent_registers = self.register_manager.registers;3986 const parent_registers = self.register_manager.registers;
...@@ -3940,6 +4002,7 @@ fn airSwitch(self: *Self, inst: Air.Inst.Index) !void {...@@ -3940,6 +4002,7 @@ fn airSwitch(self: *Self, inst: Air.Inst.Index) !void {
3940 defer saved_case_branch.deinit(self.gpa);4002 defer saved_case_branch.deinit(self.gpa);
39414003
3942 self.register_manager.registers = parent_registers;4004 self.register_manager.registers = parent_registers;
4005 self.compare_flags_inst = parent_compare_flags_inst;
3943 self.stack.deinit(self.gpa);4006 self.stack.deinit(self.gpa);
3944 self.stack = parent_stack;4007 self.stack = parent_stack;
3945 parent_stack = .{};4008 parent_stack = .{};
...@@ -5208,7 +5271,8 @@ fn getResolvedInstValue(self: *Self, inst: Air.Inst.Index) MCValue {...@@ -5208,7 +5271,8 @@ fn getResolvedInstValue(self: *Self, inst: Air.Inst.Index) MCValue {
5208 while (true) {5271 while (true) {
5209 i -= 1;5272 i -= 1;
5210 if (self.branch_stack.items[i].inst_table.get(inst)) |mcv| {5273 if (self.branch_stack.items[i].inst_table.get(inst)) |mcv| {
5211 assert(mcv != .dead);5274 // TODO see comment in `airCondBr` and `airSwitch`
5275 // assert(mcv != .dead);
5212 return mcv;5276 return mcv;
5213 }5277 }
5214 }5278 }