Predicated instruction in SSA

In SSA, the variable can only have one definition, so if we want to use a predicated instruction in SSA form, we have to convert its outs to inout operands, and use Constraints to make sure these two operands will be alloc to the same register. For example an predicated mov instruction in ARM may be:

let isCommutable = 1, isSelect = 1 in
def MOVCCr : ARMPseudoInst<(outs GPR:$Rd),
                           (ins GPR:$false, GPR:$Rm, cmovpred:$p),
                           4, IIC_iCMOVr,
                           [(set GPR:$Rd, (ARMcmov GPR:$false, GPR:$Rm,
                                                   cmovpred:$p))]>,
             RegConstraint<"$false = $Rd">, Sched<[WriteALU]>;

and this instruction can not use as a normal mov instruction, because of the inout operand. So there is another definition for normal mov:

def MOVr : AsI1<0b1101, (outs GPR:$Rd), (ins GPR:$Rm), DPFrm, IIC_iMOVr,
                "mov", "\t$Rd, $Rm", []>, UnaryDP, Sched<[WriteALU]>

It is ok when we have few predicated instructions, but if most of the instructions in a target can be predicated, we need to generate an extra definition for each instruction which convert all def operands to inout operands if we want to predicated this instruction in SSA form.

How can we enhance the framework for predicated execution?
It’s no good to maintain too many definitions of instruction, so if ignore the instruction selection, can we convert a normal instruction into predicated form by adding an additional register constraint to a MachineInstr? I don’t know if we can add such constraints outside of the tblgen.

It shouldn’t really be difficult to maintain 2 copies of the same instruction. You can create a common multiclass for them, and then have the predicated version !con an additional operand on the operand list and add the tied constraint. You could also define an InstrMapping table to convert back and forth between the opcodes.

So you’d have something like:

class MyInst<a, b> ...

multiclass MaybePredicated<output_list, input_list> {
   def "" : MyInst<output_list, input_list>;
   def _predicated : MyInst<output_list, !con(input_list, MySrcOp:$pred_op)> {
     let Constraints = "$dst=$pred_op";
  }
}

def SOME_INST : MaybePredicated<(outs MyOp:$dst), (ins MyOp:$src0, MyOp:$src1)>;
// Now you have SOME_INST and SOME_INST_pred without repeating the definition

wow, good idea. The only drawback is that we have to check two opcodes if we want to identify a specific instruction, but this case is not common.
I will check if it is feasible to be implemented, thx.

BTW, the resolution I though before is that using a pseudo instruction like:

def Select: Pseudo<(outs GPR:$dst), (ins GPR:$src0, GPR $src1, Pred:$pred_op)> {
  let Constraints = "$dst=$src0";
}

to represent a predicated instruction, for example:

%dst = Instr %src, %op0, %op1, %pred // a predicated instruction which has constraint "$dst=$src"

can be represented by:

%tmp = Instr %op0, %op1
%dst = Select %src, %tmp, %pred

which can be combined after eliminate PHI node:

%src = Instr %op0, %op1, %pred, implicit %src

but I worry about that there may be some optimization passes break the relations between them.

New progress, there is a function which can add register constraint
MachineInstr::tieOperands

I strongly recommend using static instruction definitions rather than trying to dynamically modify operand lists like that. You get free verification and construction is more reliable