| ... | @@ -858,6 +858,16 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -858,6 +858,16 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 858 | } | 858 | } |
| 859 | } | 859 | } |
| 860 | | 860 | |
| | 861 | fn reuseOperand(inst: *ir.Inst, op_index: ir.Inst.DeathsBitIndex, mcv: MCValue) bool { |
| | 862 | if (!inst.operandDies(op_index) or !mcv.isMutable()) |
| | 863 | return false; |
| | 864 | |
| | 865 | // OK we're going to do it, but we need to clear the operand death bit so that |
| | 866 | // it stays allocated. |
| | 867 | inst.clearOperandDeath(op_index); |
| | 868 | return true; |
| | 869 | } |
| | 870 | |
| 861 | fn genLoad(self: *Self, inst: *ir.Inst.UnOp) !MCValue { | 871 | fn genLoad(self: *Self, inst: *ir.Inst.UnOp) !MCValue { |
| 862 | const elem_ty = inst.base.ty; | 872 | const elem_ty = inst.base.ty; |
| 863 | if (!elem_ty.hasCodeGenBits()) | 873 | if (!elem_ty.hasCodeGenBits()) |
| ... | @@ -867,9 +877,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -867,9 +877,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 867 | if (inst.base.isUnused() and !is_volatile) | 877 | if (inst.base.isUnused() and !is_volatile) |
| 868 | return MCValue.dead; | 878 | return MCValue.dead; |
| 869 | const dst_mcv: MCValue = blk: { | 879 | const dst_mcv: MCValue = blk: { |
| 870 | if (inst.base.operandDies(0) and ptr.isMutable()) { | 880 | if (reuseOperand(&inst.base, 0, ptr)) { |
| 871 | // The MCValue that holds the pointer can be re-used as the value. | 881 | // The MCValue that holds the pointer can be re-used as the value. |
| 872 | // TODO track this in the register/stack allocation metadata. | | |
| 873 | break :blk ptr; | 882 | break :blk ptr; |
| 874 | } else { | 883 | } else { |
| 875 | break :blk try self.allocRegOrMem(&inst.base); | 884 | break :blk try self.allocRegOrMem(&inst.base); |
| ... | @@ -966,7 +975,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -966,7 +975,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 966 | var dst_mcv: MCValue = undefined; | 975 | var dst_mcv: MCValue = undefined; |
| 967 | var src_mcv: MCValue = undefined; | 976 | var src_mcv: MCValue = undefined; |
| 968 | var src_inst: *ir.Inst = undefined; | 977 | var src_inst: *ir.Inst = undefined; |
| 969 | if (inst.operandDies(0) and lhs.isMutable()) { | 978 | if (reuseOperand(inst, 0, lhs)) { |
| 970 | // LHS dies; use it as the destination. | 979 | // LHS dies; use it as the destination. |
| 971 | // Both operands cannot be memory. | 980 | // Both operands cannot be memory. |
| 972 | src_inst = op_rhs; | 981 | src_inst = op_rhs; |
| ... | @@ -977,7 +986,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -977,7 +986,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 977 | dst_mcv = lhs; | 986 | dst_mcv = lhs; |
| 978 | src_mcv = rhs; | 987 | src_mcv = rhs; |
| 979 | } | 988 | } |
| 980 | } else if (inst.operandDies(1) and rhs.isMutable()) { | 989 | } else if (reuseOperand(inst, 1, rhs)) { |
| 981 | // RHS dies; use it as the destination. | 990 | // RHS dies; use it as the destination. |
| 982 | // Both operands cannot be memory. | 991 | // Both operands cannot be memory. |
| 983 | src_inst = op_lhs; | 992 | src_inst = op_lhs; |