Mapping virtual registers to physical registers

Hi,

In the context of MachineCode custom inserter, I’m trying to enforce the mapping of virtual register to a physical one.

According to the documentation https://llvm.org/docs/CodeGenerator.html#mapping-virtual-registers-to-physical-registers

There are two ways: the direct one and the indirect ones. The indirect ones refer VirtRegMap class that I’ve never found. So I tried the direct one…

Mapping virtual registers to physical registers

^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

There are two ways to map virtual registers to physical registers (or to memory

slots). The first way, that we will call direct mapping, is based on the use

of methods of the classes TargetRegisterInfo, and MachineOperand. The

second way, that we will call indirect mapping, relies on the VirtRegMap

class in order to insert loads and stores sending and getting values to and from

memory.

The direct mapping provides more flexibility to the developer of the register

allocator; however, it is more error prone, and demands more implementation

work. Basically, the programmer will have to specify where load and store

instructions should be inserted in the target function being compiled in order

to get and store values in memory. To assign a physical register to a virtual

register present in a given operand, use MachineOperand::setReg(p_reg). To

insert a store instruction, use TargetInstrInfo::storeRegToStackSlot(...),

and to insert a load instruction, use TargetInstrInfo::loadRegFromStackSlot.

I tried the direct mapping as following:

MachineOperand destination = MI->getOperand(0);

MachineOperand offset = MI->getOperand(1);

unsigned destinationReg = destination.getReg();

int64_t FrameIndex = offset.getIndex();

destination.setReg(CLP::FA_ROFF0+FrameIndex);

destination.setIsDef(true);

TII->loadRegFromStackSlot(*MBB,

MI, destinationReg, FrameIndex,

&CLP::FPUaOffsetClassRegClass, TRI);

The code after customInserter seems valid but the compilation later hang-up in an infinite loop in procedure computeVirtRegs(); of pass LiveIntervals::runOnMachineFunction.

In other targets, I’ve seen an example with a setIsDef(true) for such physically mapped register. Is there something missing in my code (register other setting,…) ?

Hi again,

After further investigation, I’ve found that the private PhysRegUseDefLists array (“head of use/def list for physical register”) from MachineRegisterInfo class seems to be empty.

But I didn’t found any methods for updating such data structure. How/where this “use/def list” should be managed ?

Is the documentation https://llvm.org/docs/CodeGenerator.html#mapping-virtual-registers-to-physical-registers still valid ?

Are there other options to enforce the mapping of virtual registers to physical ones ?

TIA, Dominique Torette.

For direct mapping, I guess you can grep addReg in lib/Target to see how things done.

HTH,
chenwj

Hi Dominique,

From your description it is not really clear what you are trying to do here. It may be the case that the goal you are trying to accomplish can be better reached using a different approach.
In general, optimizations don't try to assign physical registers, that's done by the register allocation passes. There are some cases when target-specific passes use physical registers before register allocation, but these registers are usually reserved (such as frame pointer, status register, etc.)

You can use non-reserved registers before register allocation, it's just that it's not something typical. If your backend tracks register liveness, you will need to make sure that the physical registers that you use are properly marked as live-in in appropriate basic blocks. Also, you can only use physical registers in COPY instructions, either as the source, or as the destination. You should not use non-reserved physical registers directly in instructions. For example, you'd have something like this:
   %virt_reg0 = COPY $phys_reg
   %virt_reg1 = some_instr %virt_reg0, ...
   $phys_reg = COPY %virt_reg1

The functions "load/store from stack slot" are used for spills/restores. They do exactly what their names suggest and they are not required to be used (unless, of course, you want to generate a load/store).

In the code snippet below you create a local copy of MachineOperand, and then modify it. I'm assuming it's a typo because the changed made by calling setReg will be discarded one you go out of scope. Having said that, setReg can be used to change the register in the given operand. Make sure to change the subregister to 0, since physical registers are not allowed to have explicit subregisters in machine operands. Calling setIsDef on an existing operand is not a good practice. If you want to make significant changes to an instruction, it's usually better to build a new one and remove the old one.

Hope this helps,
-Krzysztof

Hi Krzysztof, Thanks for your response.

I was trying to map function input parameters to machine specific registers.
My solution I found is based to the RegInfo.setSimpleHint() API.

Here is the body of the parameters loop of TargetLowering::LowerFormalArguments
  
        VReg = RegInfo.createVirtualRegister(RC);
        RegInfo.setSimpleHint(VReg,CLP::FA_ROFF1+i);
        RegInfo.addLiveIn(CLP::FA_ROFF1+i, VReg);
        Load = DAG.getCopyFromReg(Chain, Loc, VReg, ValVT.getSimpleVT().SimpleTy);

Thanks again for your support, Dominique T.

Hi Dominique,

Using setSimpleHint shouldn't be necessary for correctness. Does anything fail without it? For correctness, the "RegInfo.addLiveIn" and the copies from physical regs into the vregs matching the addLiveIn arguments should be enough.

Typically, though, you wouldn't specify physical registers directly in LowerFormalArguments. Instead, the CallingConv mechanism is used that automatically assigns physical registers to incoming parameters according to the calling convention definition that you'd provide in a .td file. It's not absolutely required, just the usual way of doing this.

-Krzysztof