Define an instruction with many operands

If I have an instruction which has many register and immediate
operands, what's the difference between these two implementations to
define the instruction in TableGen *.td file?

(1) Similar to what has been done to complex X86 addressing mode. A
single 32-bit immediate (i32) encodes how to add many MachineOperands
to the MachineInstr object (With the help of functions in
X86InstrBuilder.h).

// similar to X86MemOperand in X86InstrInfo.td !!
class ManyOperands : Operand<i32> {
  let NumMIOperands = 100; // a very large number
  let PrintMethod = "printManyOperands";
}
def MO : ManyOperands;
def FOOBAR: Instruction<(ops MO:$operands), "foobar {$operands}">;

(2) 'Collapse' all operands in .td file. Contrary to method (1), each
operand is explicitly specified.

def FOOBAR: Instruction<(ops R32:$src0, R16:$src1, ... ), "foobar
$src0, $src1, ...">;

The operand list could be very long.

If I have an instruction which has many register and immediate
operands, what's the difference between these two implementations to
define the instruction in TableGen *.td file?

There isn't a big difference. The MachineInstr objects used to dynamically represent these instructions will have to have the number of operands specified in either case. It is largely a representational issue in the .td file. That said, you should only use this grouping if they are logically related to each other. Future improvements to the code generator will cause these things to be basically "glued together tree patterns". In the X86 example, we might have something like this (very psuedo code just to give the idea:

   def RRIaddr : Operand<(add R32, (add R32, imm32))>;
   def R4RIaddr : Operand<(add R32, (shl R32, 2))>;
   def AddrModes : RRIaddr or R4RIaddr;

This would allow us to write something like this:

def AND8rm : I<0x22, MRMSrcMem,
                  (ops R8 :$dst, R8 :$src1, i8mem :$src2),
                  "and{b} {$src2, $dst|$dst, $src2}",
                  (set R8:$dst, (and R8:$src1, AddrMode:$src2)) >;

The last line is the new one for AND8rm, which would basically say that the pattern it matches are the specified one with any of the "AddrMode" patterns glued into it.

If your instructions fit into this sort of flavor, it makes sense to use operands like the X86 backend does. If not, probably not.

-Chris

(1) Similar to what has been done to complex X86 addressing mode. A
single 32-bit immediate (i32) encodes how to add many MachineOperands
to the MachineInstr object (With the help of functions in
X86InstrBuilder.h).

// similar to X86MemOperand in X86InstrInfo.td !!
class ManyOperands : Operand<i32> {
let NumMIOperands = 100; // a very large number
let PrintMethod = "printManyOperands";
}
def MO : ManyOperands;
def FOOBAR: Instruction<(ops MO:$operands), "foobar {$operands}">;

(2) 'Collapse' all operands in .td file. Contrary to method (1), each
operand is explicitly specified.

def FOOBAR: Instruction<(ops R32:$src0, R16:$src1, ... ), "foobar
$src0, $src1, ...">;

The operand list could be very long.

-Chris