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));
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 ?