Register Coalescer does not preserve TargetFlag


R600 hardware (Radeon gfx card) does neither have a NEG nor an ABS instruction ; however any sources operand can be negated/abs'd by setting a bit for every source operand in the final bytecode (but not DST).
A good way of modeling this behavior in LLVM is by using TargetFlag on operand.

Currently the R600 LLVM backend in Mesa lower NEG and ABS DAG instruction to a MOV + TargetFlag using customEmitter pass. This emulates the existence of a NEG/ABS instruction, but is not optimal as it costs an extra (often uneeded) MOV instruction.
I'm trying to rework this : I'd like that a "DST = FNEG SRC" custom Emitter lowering pass replaces every occurence of DST by SRC and set the corresponding TargetFlag in the process. Something like this :

MachineOperand *MO = &(MI->getOperand(0));

while(MO) {
MachineOperand *next_MO = MO->getNextOperandForReg();
MO = next_MO;

As far as I can tell, this works as every register are still virtual when lowering custom Emitter instructions. However the RegisterCoalescer pass does not preserve TargetFlag in the JoinCopy() member function.
For instance, here is some output of the regalloc pass (TF=2 corresponds to a Neg TargetFlag) :

352B %vreg20:sel_x<def,undef> = COPY %vreg16<kill>[TF=2], %vreg20<imp-def>; R600_Reg128:%vreg20 R600_Reg32:%vreg16
Considering merging %vreg16 with %vreg20:sel_x
Cross-class to R600_Reg128.
RHS = %vreg16 = [304r,352r:0) 0@304r
LHS = %vreg20 = [352r,400r:0) 0@352r
updated: 304B %vreg20:sel_x<def,undef> = MUL %vreg3:sel_x<kill>, %vreg15; R600_Reg128:%vreg20,%vreg3 R600_Reg32:%vreg15
Joined. Result = %vreg20 = [304r,400r:0) 0@304r

I'd like to prevent this specific join from occuring, because DST register cannot be negated. Is there a way to control the JoinCopy function from RegisterCoalescer ? Or is there any way to do that otherwise ?

Vincent Lejeune.

Hi Vincent,

TargetFlags are not a good way of modeling semantic information about machine instructions. They are not preserved by any passes in the backend.

Use immediate operands instead.


No, these instructions must be pure register copies. They can't have additional target-specific semantics.

You would need to insert target-specific NEG and ABS instructions instead.


We make no guarantees about the order of operands in the use-def chains, and there are no analyses that can reorder them.

I would suggest that you read the code in other targets to see how things are usually done.


Do you know any backend that implement instructions as a flag modifier in instruction ?

Vincent Lejeune

----- Mail original -----

The AMDIL backend does this for custom swizzles for certain instructions(Vector insert/extract).


No, I am not aware that any of the targets in the tree do something like that. TargetFlags is used by ARM to modify global symbol operands and such.

But I meant you should be looking at the coding style used in the other targets. The getNextOperandForReg() function isn't used anywhere, see the MachineRegisterInfo iterators instead.


Should we remove it?


If it isn't being used by any back ends and it shouldn't be used by any backends, then I would say yes.

'Anywhere' was a slight exaggeration. It is used by the defusechain_iterator template in MachineRegisterInfo.

If science ever discovers a way of declaring an inner template as a friend without including the .h file, we can make it private.

There's nothing wrong with using the method if you know what you're doing. We should probably put some warning signs in its header comment.