| author | |
| committer | |
| log | 083c0f1cebc763e4e43529b50f6df9839c32c1c7 |
| tree | 6ea2d31ae701bcd0703026fde44f2efaa2981c33 |
| parent | dc35b8641badf3169a3124e84b672c3bf4bfd5f8 |
closes #60643 files changed, 60 insertions(+), 4 deletions(-)
src-self-hosted/codegen.zig+13-4| ... | ... | @@ -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 | 871 | fn genLoad(self: *Self, inst: *ir.Inst.UnOp) !MCValue { |
| 862 | 872 | const elem_ty = inst.base.ty; |
| 863 | 873 | if (!elem_ty.hasCodeGenBits()) |
| ... | ... | @@ -867,9 +877,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 867 | 877 | if (inst.base.isUnused() and !is_volatile) |
| 868 | 878 | return MCValue.dead; |
| 869 | 879 | const dst_mcv: MCValue = blk: { |
| 870 | if (inst.base.operandDies(0) and ptr.isMutable()) { | |
| 880 | if (reuseOperand(&inst.base, 0, ptr)) { | |
| 871 | 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 | 882 | break :blk ptr; |
| 874 | 883 | } else { |
| 875 | 884 | break :blk try self.allocRegOrMem(&inst.base); |
| ... | ... | @@ -966,7 +975,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 966 | 975 | var dst_mcv: MCValue = undefined; |
| 967 | 976 | var src_mcv: MCValue = undefined; |
| 968 | 977 | var src_inst: *ir.Inst = undefined; |
| 969 | if (inst.operandDies(0) and lhs.isMutable()) { | |
| 978 | if (reuseOperand(inst, 0, lhs)) { | |
| 970 | 979 | // LHS dies; use it as the destination. |
| 971 | 980 | // Both operands cannot be memory. |
| 972 | 981 | src_inst = op_rhs; |
| ... | ... | @@ -977,7 +986,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 977 | 986 | dst_mcv = lhs; |
| 978 | 987 | src_mcv = rhs; |
| 979 | 988 | } |
| 980 | } else if (inst.operandDies(1) and rhs.isMutable()) { | |
| 989 | } else if (reuseOperand(inst, 1, rhs)) { | |
| 981 | 990 | // RHS dies; use it as the destination. |
| 982 | 991 | // Both operands cannot be memory. |
| 983 | 992 | src_inst = op_lhs; |
src-self-hosted/ir.zig+5| ... | ... | @@ -42,6 +42,11 @@ pub const Inst = struct { |
| 42 | 42 | return @truncate(u1, self.deaths >> index) != 0; |
| 43 | 43 | } |
| 44 | 44 | |
| 45 | pub fn clearOperandDeath(self: *Inst, index: DeathsBitIndex) void { | |
| 46 | assert(index < deaths_bits); | |
| 47 | self.deaths &= ~(@as(DeathsInt, 1) << index); | |
| 48 | } | |
| 49 | ||
| 45 | 50 | pub fn specialOperandDeaths(self: Inst) bool { |
| 46 | 51 | return (self.deaths & (1 << deaths_bits)) != 0; |
| 47 | 52 | } |
test/stage2/compare_output.zig+42| ... | ... | @@ -544,6 +544,48 @@ pub fn addCases(ctx: *TestContext) !void { |
| 544 | 544 | "", |
| 545 | 545 | ); |
| 546 | 546 | |
| 547 | // This catches a possible bug in the logic for re-using dying operands. | |
| 548 | case.addCompareOutput( | |
| 549 | \\export fn _start() noreturn { | |
| 550 | \\ assert(add(3, 4) == 116); | |
| 551 | \\ | |
| 552 | \\ exit(); | |
| 553 | \\} | |
| 554 | \\ | |
| 555 | \\fn add(a: u32, b: u32) u32 { | |
| 556 | \\ const x: u32 = blk: { | |
| 557 | \\ const c = a + b; // 7 | |
| 558 | \\ const d = a + c; // 10 | |
| 559 | \\ const e = d + b; // 14 | |
| 560 | \\ const f = d + e; // 24 | |
| 561 | \\ const g = e + f; // 38 | |
| 562 | \\ const h = f + g; // 62 | |
| 563 | \\ const i = g + h; // 100 | |
| 564 | \\ const j = i + d; // 110 | |
| 565 | \\ break :blk j; | |
| 566 | \\ }; | |
| 567 | \\ const y = x + a; // 113 | |
| 568 | \\ const z = y + a; // 116 | |
| 569 | \\ return z; | |
| 570 | \\} | |
| 571 | \\ | |
| 572 | \\pub fn assert(ok: bool) void { | |
| 573 | \\ if (!ok) unreachable; // assertion failure | |
| 574 | \\} | |
| 575 | \\ | |
| 576 | \\fn exit() noreturn { | |
| 577 | \\ asm volatile ("syscall" | |
| 578 | \\ : | |
| 579 | \\ : [number] "{rax}" (231), | |
| 580 | \\ [arg1] "{rdi}" (0) | |
| 581 | \\ : "rcx", "r11", "memory" | |
| 582 | \\ ); | |
| 583 | \\ unreachable; | |
| 584 | \\} | |
| 585 | , | |
| 586 | "", | |
| 587 | ); | |
| 588 | ||
| 547 | 589 | case.addCompareOutput( |
| 548 | 590 | \\export fn _start() noreturn { |
| 549 | 591 | \\ const ignore = |