Default behavior of DeadMachineInstructionElim deletes all instructions

I’ve recently sync’d to a newer version of LLVM(Apple branch 2326 from Apple branch 2323.8) that changed the interface to addCommonCodeGenPasses which caused the default implementation to be executed instead of my overriding implementation. This default implementation has DeadMachineInstructionElim pass enabled, which is causing havoc with my backend. Before entering this pass, everything in my machine function is fine, after this pass, all instructions that are not function calls are deleted. I’ve tracked this issue down to the line:

BitVector NonAllocatableRegs = TRI->getAllocatableSet(MF); (In my case all registers defined in RegisterInfo.td)

This function loops through all registers classes and sets all registers in the bitset that are allocatable. It then inverts the registers that are set to get the NonAllocatable registers and assigns that to the LivePhysRegs for each basic block in a function. The function then loops through all instructions in a basic block and checks to see if it is a dead instruction. The check is whether it is a physical register or not with the check:

TargetRegisterInfo::isPhysicalRegister(reg) ? LivePhysRegs[Reg] : !MRI->use_nodbg_empty(Reg)

If the register is virtual, then MRI->use_nodbg_empty() returns false, if the register is physical LivePhysRegs[Reg] returns false, since the bitvector was inverted. So my instruction is considered dead and deleted.

So, what I am trying to figure out is why this behavior is occurring? I don’t see this happening on the x86 backend because getAllocatableSet does not return all registers as set.

Since I’m working on virtual registers, how do I get MRI->use_nodbg_empty() to return true? Is there something I should be setting in my backend that affects this?

Thanks,

Micah

Huh? The code is

if (TargetRegisterInfo::isPhysicalRegister(Reg) ?
LivePhysRegs[Reg] : !MRI->use_nodbg_empty(Reg)) {
// This def has a non-debug use. Don’t delete the instruction!
return false;

Returning false from MRI->use_nodbg_empty means the instruction has a use, and it is not deleted. That’s what’s supposed to happen.

Dale,

Yeah that is correct, so that isn’t the problem, not sure why I was thinking it is. The !MRI->use_no_dbg_empty(Reg) seems to be correct and the problem is LivePhysRegs[Reg] always returning false. I’ve looked into this more and there is a part where I’m working with physical registers.

If there is a function call, there is a copy from virtual register space to the functions that are expected to be passed into the register.

So it looks something like this:

… do some work …

Mov %r0, %r1025

Mov %r1, %r1026

Mov %r2, %r1027

Call someFunc %r0, %r1, %r2 ß this func stores to memory

Ret

The moves to the physical registers are being deleted as NonAllocatableRegs is set to all one’s and then inverted, and since these are deleted, every instruction that they depended on is also deleted.

I have a workaround(disable the pass), but I’d much rather figure out what I am doing incorrectly that is causing this behavior or if determining if the default assumptions by this pass are correct.

Micah

Ping. Anyone have any idea on how to fix this?

Thanks,

Micah

Does your getAllocatableSet() return a BitVector that is at least getNumRegs() bits long? Otherwise this doesn't work:

  BitVector NonAllocatableRegs = TRI->getAllocatableSet(MF);
  NonAllocatableRegs.flip();

Jakob,
Here is my implementation of getAllocatableSet:
BitVector
AMDILRegisterInfo::getAllocatableSet(const MachineFunction& MF,
    const TargetRegisterClass *RC = NULL) const
{
  BitVector Allocatable(getNumRegs());
  Allocatable.clear();
  return Allocatable;
}

Micah

Well, there's your problem.

BitVector::clear() resets the size to 0, and callers of getAllocatableSet expect a bit per physical register.

Please add an assert(NonAllocatableRegs.size() >= TRI->getNumRegs()) to DeadMachineInstructionElim.

/jakob