diff --git a/src/alloy/backend/x64/lowering/lowering_sequences.cc b/src/alloy/backend/x64/lowering/lowering_sequences.cc index f29854bdc..fe86ae7ed 100644 --- a/src/alloy/backend/x64/lowering/lowering_sequences.cc +++ b/src/alloy/backend/x64/lowering/lowering_sequences.cc @@ -1600,7 +1600,6 @@ void alloy::backend::x64::lowering::RegisterSequences(LoweringTable* table) { [](X64Emitter& e, Instr& i, const Reg& dest_src, const Operand& src) { // RAX = value, RDX = clobbered // TODO(benvanik): make the register allocator put dest_src in RAX? - e.db(0xCC); auto Nax = LIKE_REG(e.rax, dest_src); e.mov(Nax, dest_src); if (i.flags & ARITHMETIC_UNSIGNED) { @@ -1615,7 +1614,6 @@ void alloy::backend::x64::lowering::RegisterSequences(LoweringTable* table) { // TODO(benvanik): make the register allocator put dest_src in RAX? auto Nax = LIKE_REG(e.rax, dest_src); auto Ndx = LIKE_REG(e.rdx, dest_src); - e.db(0xCC); e.mov(Nax, dest_src); e.mov(Ndx, src); if (i.flags & ARITHMETIC_UNSIGNED) { @@ -1635,7 +1633,6 @@ void alloy::backend::x64::lowering::RegisterSequences(LoweringTable* table) { [](X64Emitter& e, Instr& i, const Reg& dest_src, const Operand& src) { // RAX = value, RDX = clobbered // TODO(benvanik): make the register allocator put dest_src in RAX? - e.db(0xCC); auto Nax = LIKE_REG(e.rax, dest_src); auto Ndx = LIKE_REG(e.rdx, dest_src); e.mov(Nax, dest_src); @@ -1651,7 +1648,6 @@ void alloy::backend::x64::lowering::RegisterSequences(LoweringTable* table) { // TODO(benvanik): make the register allocator put dest_src in RAX? auto Nax = LIKE_REG(e.rax, dest_src); auto Ndx = LIKE_REG(e.rdx, dest_src); - e.db(0xCC); e.mov(Nax, dest_src); e.mov(Ndx, src); if (i.flags & ARITHMETIC_UNSIGNED) { @@ -1671,7 +1667,6 @@ void alloy::backend::x64::lowering::RegisterSequences(LoweringTable* table) { [](X64Emitter& e, Instr& i, const Reg& dest_src, const Operand& src) { // RAX = value, RDX = clobbered // TODO(benvanik): make the register allocator put dest_src in RAX? - e.db(0xCC); auto Nax = LIKE_REG(e.rax, dest_src); e.mov(Nax, dest_src); if (i.flags & ARITHMETIC_UNSIGNED) { @@ -1686,7 +1681,6 @@ void alloy::backend::x64::lowering::RegisterSequences(LoweringTable* table) { // TODO(benvanik): make the register allocator put dest_src in RAX? auto Nax = LIKE_REG(e.rax, dest_src); auto Ndx = LIKE_REG(e.rdx, dest_src); - e.db(0xCC); e.mov(Nax, dest_src); e.mov(Ndx, src); if (i.flags & ARITHMETIC_UNSIGNED) { diff --git a/src/alloy/backend/x64/x64_emitter.cc b/src/alloy/backend/x64/x64_emitter.cc index 9b68e16be..7e0ee8a6a 100644 --- a/src/alloy/backend/x64/x64_emitter.cc +++ b/src/alloy/backend/x64/x64_emitter.cc @@ -143,6 +143,8 @@ int X64Emitter::Emit(HIRBuilder* builder) { auto lowering_table = backend_->lowering_table(); + reg_state_.active_regs = reg_state_.live_regs = reserved_regs; + // Body. auto block = builder->first_block(); while (block) { @@ -156,7 +158,7 @@ int X64Emitter::Emit(HIRBuilder* builder) { // Reset reg allocation state. // If we start keeping regs across blocks this needs to change. // We mark a few active so that the allocator doesn't use them. - reg_state_.active_regs = reg_state_.live_regs = reserved_regs; + ResetRegisters(reserved_regs); // Add instructions. // The table will process sequences of instructions to (try to) @@ -192,11 +194,27 @@ int X64Emitter::Emit(HIRBuilder* builder) { return 0; } -void X64Emitter::EvictStaleRegs() { +void X64Emitter::ResetRegisters(uint32_t reserved_regs) { + // Just need to reset the register for each live value. + uint32_t live_regs = reg_state_.live_regs; + for (size_t n = 0; n < 32; n++, live_regs >>= 1) { + if (live_regs & 0x1) { + auto v = reg_state_.reg_values[n]; + if (v) { + v->reg = -1; + } + } + reg_state_.reg_values[n] = 0; + } + reg_state_.active_regs = reg_state_.live_regs = reserved_regs; +} + +void X64Emitter::EvictStaleRegisters() { // NOTE: if we are getting called it's because we *need* a register. // We must get rid of something. - uint32_t current_ordinal = current_instr_->ordinal; + uint32_t current_ordinal = current_instr_ ? + current_instr_->ordinal : 0xFFFFFFFF; // Remove any register with no more uses. uint32_t new_live_regs = 0; @@ -216,7 +234,12 @@ void X64Emitter::EvictStaleRegs() { auto v = reg_state_.reg_values[n]; if (v->last_use->ordinal < current_ordinal) { reg_state_.reg_values[n] = NULL; + v->reg = -1; + continue; } + + // Register still in use. + new_live_regs |= bit; } // Hrm. We have spilled. @@ -225,6 +248,9 @@ void X64Emitter::EvictStaleRegs() { } reg_state_.live_regs = new_live_regs; + + // Assert that live is a superset of active. + XEASSERTZERO((reg_state_.live_regs ^ reg_state_.active_regs) & reg_state_.active_regs); } void X64Emitter::FindFreeRegs( @@ -234,6 +260,9 @@ void X64Emitter::FindFreeRegs( // Already in a register. Mark active and return. v0_idx = v0->reg; reg_state_.active_regs |= 1 << v0_idx; + + // Assert that live is a superset of active. + XEASSERTZERO((reg_state_.live_regs ^ reg_state_.active_regs) & reg_state_.active_regs); return; } @@ -250,7 +279,7 @@ void X64Emitter::FindFreeRegs( uint32_t free_regs = avail_regs & ~reg_state_.live_regs; if (!free_regs) { // Need to evict something. - EvictStaleRegs(); + EvictStaleRegisters(); free_regs = avail_regs & ~reg_state_.live_regs; XEASSERT(free_regs); } diff --git a/src/alloy/backend/x64/x64_emitter.h b/src/alloy/backend/x64/x64_emitter.h index 3125d0c07..702eafa71 100644 --- a/src/alloy/backend/x64/x64_emitter.h +++ b/src/alloy/backend/x64/x64_emitter.h @@ -112,7 +112,8 @@ public: GetRegBit(r0) | GetRegBit(r1) | GetRegBit(r2) | GetRegBit(r3)); } - void EvictStaleRegs(); + void ResetRegisters(uint32_t reserved_regs); + void EvictStaleRegisters(); void FindFreeRegs(hir::Value* v0, uint32_t& v0_idx, uint32_t v0_flags); void FindFreeRegs(hir::Value* v0, uint32_t& v0_idx, uint32_t v0_flags,