TableGen - Help to implement a form of gather/scatter operations for Mips MSA

Hello.
     I read on page 4 of http://www.cs.fsu.edu/~whalley/cda5155/chap4.pdf that gather and scatter operations exist for Mips, named LVI and SVI, respectively.

     Did anyone think of implementing in the LLVM Mips back end (part of the MSA vector instructions) gather and scatter operations?
     If so, can you share with me the TableGen spec? (I tried to start from LD_DESC_BASE, but it doesn't seem to be trivial. Also, LLVM seems to have implemented scatter/gather instructions only for the x86 processor - there, they defined new SDNodes called GatherNode and ScatterNode.)

   Thank you,
     Alex

Hi Alex,

I don’t know too much about recent MIPS, but have recently been doing something similar for the new ARM SVE architecture, so hopefully this will get you closer to what you need:

If you’re looking where I think you are (lib/Target/X86/X86InstrAVX512.td), ‘GatherNode’ is a template argument, not a definition.
It allows a PatFrag be passed into the avx512_gather multiclass definition.

Working backwards from here, the actual PatFrags passed into this are things like ‘mgatherv4i32’. These are patterns that match a MaskedGatherSDNode for a particular data type.

MaskedGatherSDNode is the generic SD node that represents a predicated gather, which in turn was generated from Intrinsic::masked_gather in the IR (in SelectionDAGBuilder::visitMaskedGather)

If your MIPS instruction has a predicate, you will need to create MIPS tablegen that matches MaskedGatherSDNode. If not, I guess you’ll need to create a new intrinsic that represents an unpredicted gather, and add appropriate uses of it during IR creation (such as in LoopVectorize, where masked gathers are created today)

Hope that helps,

Will Lovett

Hello.
     Will, thanks a lot for pointing me to the MaskedGatherSDNode and mgatherv4i32. I have to say that the definition of the "multiclass avx512_gather" from lib/Target/X86/X86InstrAVX512.td is difficult to follow and I prefer not to use it.

     I currently have some serious problems with TableGen - it gives an assertion failure: "llvm/utils/TableGen/CodeGenDAGPatterns.cpp:2153: llvm::TreePatternNode* llvm::TreePattern::ParseTreePattern(llvm::Init*, llvm::StringRef): Assertion `New->getNumTypes() == 1 && "FIXME: Unhandled"' failed."

     Can somebody help me with the code below responsible for this error?

     // From llvm/lib/Target/X86/X86InstrFragmentsSIMD.td
     def mgatherv128i16 : PatFrag<(ops node:$src1, node:$src2, node:$src3),
       (masked_gather node:$src1, node:$src2, node:$src3) , [{
       if (MaskedGatherSDNode *mgNode = dyn_cast<MaskedGatherSDNode>(N))
         return (mgNode->getIndex().getValueType() == MVT::v128i16 ||
                 mgNode->getBasePtr().getValueType() == MVT::v128i16);
       return false;
     }]>;

     foreach RegId = 0-31 in
         def Mask#RegId : MipsReg<0, "Mask"#RegId>, DwarfRegNum<[!add(RegId, 10)]>;
     def VK128: RegisterClass<"Connex", [v128i1], 32, (sequence "Mask%u", 0, 31)>;
     def VK128Opnd : RegisterOperand<VK128> {
       let ParserMatchClass = MSA128AsmOperand;
     }

     class LD_INDIRECT_DESC_BASE2<string instr_asm,
                     ValueType TyNode,
                     RegisterOperand ROWD,
                     RegisterOperand ROWSI = ROWD,
                     RegisterOperand ROWSP = ROWD, // passthru register
                     InstrItinClass itin = NoItinerary> {
       dag OutOperandList = (outs ROWD:$wd);
       dag InOperandList = (ins ROWSP:$wsp, VK128Opnd:$wsm, ROWSI:$wsptr, ROWSI:$wsi);
       string AsmString = "$wd = LS[R($wsi )];";
       list<dag> Pattern = [(set ROWD:$wd, (TyNode (masked_gather ROWSP:$wsp, VK128Opnd :$wsm, ROWSI:$wsptr, ROWSI:$wsi)))];
       InstrItinClass Itinerary = itin;
       string DecoderMethod = "DecodeMSA128Mem";
     }
     class LD_INDIRECT_D_DESC2 : LD_INDIRECT_DESC_BASE2<"read", v128i16, MSA128DOpnd>;
     class LD_INDIRECT_D_ENC2 : MSA_2R_FMT<0b101001110>;
     def LD_INDIRECT_D2: LD_INDIRECT_D_ENC2, LD_INDIRECT_D_DESC2;

     /*
     // From http://llvm.org/docs/doxygen/html/SelectionDAGNodes_8h_source.html:
         02115 // In the both nodes address is Op1, mask is Op2:
         02116 // MaskedGatherSDNode (Chain, src0, mask, base, index), src0 is a passthru value
         02117 // MaskedScatterSDNode (Chain, value, mask, base, index)
         02118 // Mask is a vector of i1 elements
         02119 const SDValue &getBasePtr() const { return getOperand(3); }
         02120 const SDValue &getIndex() const { return getOperand(4); }
         02121 const SDValue &getMask() const { return getOperand(2); }
         02122 const SDValue &getValue() const { return getOperand(1); } // Alex: this is pass-thru

     */

   Thank you very much,
     Alex

Hello.
    I wanted to inform that I fixed the bug from the previous email.
    The main reason for the bug was that I thought that the SDNode masked_gather is returning only 1 value, but it returns 2 (hence, I guess, the earlier reported, difficult to follow, error: "Assertion `New->getNumTypes() == 1").

     masked_gather returns 2 values because:
         // SDTypeProfile - This profile describes the type requirements of a Selection
         // DAG node.
         class SDTypeProfile<int numresults, int numoperands,
                             list<SDTypeConstraint> constraints> {
           int NumResults = numresults;
           int NumOperands = numoperands;
           list<SDTypeConstraint> Constraints = constraints;
         }

         // So: 2 results, 3 operands.
         // Params are: passthru, mask, index; results are: vector of i1, ptr!!
         // Params are 0, 1, 2 and results are 3, 4.
         // Opnds 0 and 1 have vector type, with same number of elements.
         // Opnds 0 and 2 have identical types.
         // Opnds 1 and 3 have identical types.
         // --> Opnd 3 (result 0?) is i1 vector
         // Opnd 4 (result 1?) has pointer type.
         // Opnd 1 is vector type with element type of i1.
         def SDTMaskedGather: SDTypeProfile<2, 3, [ // masked gather
           SDTCisVec<0>, SDTCisVec<1>, SDTCisSameAs<0, 2>, SDTCisSameAs<1, 3>,
           SDTCisPtrTy<4>, SDTCVecEltisVT<1, i1>, SDTCisSameNumEltsAs<0, 1>
         ]>;

         def masked_gather : SDNode<"ISD::MGATHER", SDTMaskedGather,
                                [SDNPHasChain, SDNPMayLoad, SDNPMemOperand]>;

     Also, we need to make the operand $wsi a memory operand (otherwise we get the difficult error: <<In LD_INDIRECT_D2: Type inference contradiction found, 'v128i16' needs to be scalar>>), like in the following complete specification:
         // Inspired heavily from lib/Target/X86/X86InstrInfo.td
         class X86MemOperand<string printMethod> : Operand<iPTR> {
           let PrintMethod = printMethod;
           let MIOperandInfo = (ops i8imm, i32imm);
           let OperandType = "OPERAND_MEMORY";
         }
         // Gather mem operands
         class X86VMemOperand<RegisterClass RC, string printMethod>
             : X86MemOperand<printMethod> {
           let MIOperandInfo = (ops i8imm, RC, i32imm);
         }
         def vx256xmem : X86VMemOperand<MSA128D, "printi256mem">;

         def vectoraddr : ComplexPattern<iPTR, 5, "selectVectorAddr", ,[SDNPWantParent]>;

         class LD_INDIRECT_DESC_BASE2<string instr_asm,
                                     RegisterOperand ROWD,
                                     RegisterOperand ROWSP = ROWD,
                                     InstrItinClass itin = NoItinerary> {
           dag OutOperandList = (outs ROWD:$wd, VK128Opnd:$wdm);
           dag InOperandList = (ins ROWSP:$wsp, VK128Opnd:$wsm, vx256xmem:$wsi);
           string AsmString = !strconcat("$wd = LS[$wsi]; // iread (or Mips MSA's LD) strinstr_asm = ",
                                         instr_asm);
           list<dag> Pattern = [(set ROWD:$wd, VK128Opnd:$wdm,
                     (masked_gather
                         ROWSP:$wsp, VK128Opnd:$wsm, vectoraddr:$wsi))];

           InstrItinClass Itinerary = itin;
           string DecoderMethod = "DecodeMSA128Mem";
         }
         class LD_INDIRECT_D_DESC2 : LD_INDIRECT_DESC_BASE2<"read", MSA128DOpnd>;
         class LD_INDIRECT_D_ENC2 : MSA_3R_FMT<0b101001110>;
         def LD_INDIRECT_D2: LD_INDIRECT_D_ENC2, LD_INDIRECT_D_DESC2;

     Unfortunately, now I have another problem: llc fails when trying to select my masked_gather node. More exactly, it first tries to split it and then gives an error:
     Split node operand: t13: v128i16,ch = masked_gather<LD256[<unknown>]> t0, t23, t40, TargetConstant:i64<0>, t24
     Widen node result 0: t46: v64i16 = extract_subvector t23, Constant:i64<64>
     Widen node result 0: t48: v64i16,ch = masked_gather<LD128[<unknown>](align=256)> t0, t46, t44, TargetConstant:i64<0>, t26
     Split node result: t121: v128i64 = BUILD_VECTOR Constant:i64<0>, Constant:i64<0>, Constant:i64<0>, Constant:i64<0>, Constant:i64<0>, Constant:i64<0>, Constant:i64<0>, Constant:i64<0>, Constant:i64<0>, Constant:i64<0>, Constant:i64<0>, Constant:i64<0>, Constant:i...
     Split node result: t123: v64i64 = BUILD_VECTOR undef:i64, undef:i64, undef:i64, undef:i64, undef:i64, undef:i64, undef:i64, undef:i64, undef:i64, undef:i64, undef:i64, undef:i64, undef:i64, undef:i64, undef:i64, undef:i64, undef:i64, undef:i64, undef:i64, undef:...
     Split node result: t124: v32i64 = BUILD_VECTOR undef:i64, undef:i64, undef:i64, undef:i64, undef:i64, undef:i64, undef:i64, undef:i64, undef:i64, undef:i64, undef:i64, undef:i64, undef:i64, undef:i64, undef:i64, undef:i64, undef:i64, undef:i64, undef:i64, undef:...
     Split node result: t125: v16i64 = BUILD_VECTOR undef:i64, undef:i64, undef:i64, undef:i64, undef:i64, undef:i64, undef:i64, undef:i64, undef:i64, undef:i64, undef:i64, undef:i64, undef:i64, undef:i64, undef:i64, undef:i64...
     Split node result: t126: v8i64 = BUILD_VECTOR undef:i64, undef:i64, undef:i64, undef:i64, undef:i64, undef:i64, undef:i64, undef:i64...
     Split node result: t127: v4i64 = BUILD_VECTOR undef:i64, undef:i64, undef:i64, undef:i64...
     Split node result: t128: v2i64 = BUILD_VECTOR undef:i64, undef:i64

     Split node operand: t122: v128i16,ch = masked_gather<LD128[<unknown>](align=256)> t0, t130, t193, TargetConstant:i64<0>, t121

     llc: /home/asusu/LLVM/llvm38Nov2016/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp:6804: llvm::MemSDNode::MemSDNode(unsigned int, unsigned int, const llvm::DebugLoc&, llvm::SDVTList, llvm::EVT, llvm::MachineMemOperand*): Assertion `memvt.getStoreSize() <= MMO->getSize() && "Size mismatch!"' failed.

     Does anybody know why this happens? I'd like to mention that I also gave in [Target]ISelLowering.cpp a call to setOperationAction(ISD::MGATHER, aType, Legal), which should have fixed this problem, but it doesn't.

   Best regards,
     Alex

Hi Alex,

Hello.
   I read on page 4 of https://urldefense.proofpoint.com/v2/url?u=http-3A__www.cs.fsu.edu_-7Ewhalley_cda5155_chap4.pdf&d=CwIGaQ&c=Hw-EJUFt2_D9PK5csBJ29kRV40HqSDXWTLPyZ6W8u84&r=OWKUiguzzd2_T_K4Ka0qDEQ1sz6uNXO3VsbQDbiA6R8&m=qBOLs4N_Wqx6PzrOly6PAZyiapHyxBMIhn3E9OkjYjc&s=oukhOwlS56XWO6LLHzfUbAUVUvWNyAQ4nEcCxOOqeCs&e= that gather and scatter operations exist for Mips, named LVI and SVI, respectively.

The title of slide 4 is 'Extending the MIPS to Support Vector Operations' and slide 6 mentions VMIPS so I think you may be looking at a VMIPS specific extension of the MIPS ISA. VMIPS appears to be an implementation of the R3000 that's intended as a teaching tool. Does your MIPS CPU have this extension?

   Did anyone think of implementing in the LLVM Mips back end (part of the MSA vector instructions) gather and scatter operations?

Simon Dardis would be able to confirm but there aren't any as far as I know. The closest I can think of is in MSA where you can get a similar effect with a sequence of ld.df's and vshf.df's (or pck*.df's, ilv*.df's, etc. for some of the common cases).

Hi Alex,

The operations you refer to are part of an extension to MIPS called VMIPS for teaching purposes.

The MIPS MSA ASE does not define vector scatter/gather instructions. As Daniel points out in his reply, it's
possible to simulate vector scatter/gather operations through combinations of shuffles, interleaves or just plain
GPR loads/stores combined with cross register bank copies.

I haven't looked at implementing any sort of vector scatter/gather style optimizations for MIPS yet.

Thanks,
Simon

Hello.
     Daniel, Simon, I need to specify gather and scatter operations for our research SIMD processor that uses TableGen specs inspired heavily from the Mips (MSA) back end.
     Although Mips currently does not have gather and scatter operations it is an interesting feature to have in mind, given also the fact that Mips has a very clean TableGen specification.
     As far as I can see, currently only x86 (and some non-official ARM versions) have gather and scatter operations.

     Now, it seems that I managed to do the TableGen for gather rather well, but now I face problems at instruction selection - I don't understand why it starts splitting some constant vectors as I described in the previous email (and also why the back end fills a constant vector's 2nd half with undefs, when it shouldn't).

   Thank you,
     Alex

Hello.
     I fixed the bug reported in the previous post on this thread (<<llvm::MemSDNode::MemSDNode(unsigned int, unsigned int, const llvm::DebugLoc&, llvm::SDVTList, llvm::EVT, llvm::MachineMemOperand*): Assertion `memvt.getStoreSize() <=
  MMO->getSize() && "Size mismatch!"' failed.>>)

     The problem with this strange error reported comes from the fact I actually did NOT have defined type v128i64 in files:
     [repo]/llvm/include/llvm/IR/Intrinsics.td
     [repo]/llvm/include/llvm/CodeGen/MachineValueType.h
     [repo]/llvm/lib/IR/ValueTypes.cpp
     [repo]/llvm/include/llvm/CodeGen/ValueTypes.td
     The reason I need this type, v128i64, is that pointers have size 64 bits - my ConnexTargetMachine::computeDataLayout() returns normally string "e-m:e-p:64:32-i32:32:32-i64:64-n32:32-S128", since my back end basically extends with vector instructions the LLVM BPF back end.
     So, at instruction selection it lowers the <128 x i16> value to <128 x i64>, since pointers have 64 bits, which we can see from the debug info of llc:
       t25: v128i16 = BUILD_VECTOR Constant:i64<31>, Constant:i64<31>, Constant:i64<31>, Constant:i64<31>, Constant:i64<31>, Constant:i64<31>, Constant:i64<31>, Constant:i64<31>, Constant:i64<31>, Constant:i64<31>, Constant:i64<31>, ...
            Combining: t10: v128i64 = zero_extend t25
             ... into: t26: v128i64 = BUILD_VECTOR Constant:i64<31>, Constant:i64<31>, Constant:i64<31>, Constant:i64<31>
Once I have defined type v128i64 in the above mentioned 4 files (2 .td, 1 .h, 1 .cpp), I no longer get this strange error.

     However, now I start getting Segfault at selection for masked_gather, the reason being that I don't have vector registers of 64-bits:
       ISEL: Starting pattern match on root node: t14: v128i16,ch = masked_gather<LD256[<unknown>]> t0, t22, t29, TargetConstant:i64<0>, t33
       Initial Opcode index to 1692
       #0 0x00007f08faa9e700 llvm::sys::PrintStackTrace(llvm::raw_ostream&) /llvm/lib/Support/Unix/Signals.inc:402:0
       #1 0x00007f08faa9ea9a PrintStackTraceSignalHandler(void*) /llvm/lib/Support/Unix/Signals.inc:470:0
       #2 0x00007f08faa9cb55 llvm::sys::RunSignalHandlers() /llvm/lib/Support/Signals.cpp:44:0
       #3 0x00007f08faa9df4b SignalHandler(int) /llvm/lib/Support/Unix/Signals.inc:256:0
       #4 0x00007f08f994e4a0 (/lib/x86_64-linux-gnu/libc.so.6+0x354a0)
       #5 0x00007f08fae80078 llvm::SDUse::addToList(llvm::SDUse**) /llvm/include/llvm/CodeGen/SelectionDAGNodes.h:299:0
       #6 0x00007f08fae80b2b llvm::SDNode::addUse(llvm::SDUse&) /llvm/include/llvm/CodeGen/SelectionDAGNodes.h:801:0
       #7 0x00007f08fae80f6c llvm::SDUse::setInitial(llvm::SDValue const&) /llvm/include/llvm/CodeGen/SelectionDAGNodes.h:920:0
       #8 0x00007f08fb024851 llvm::SelectionDAG::createOperands(llvm::SDNode*, llvm::ArrayRef<llvm::SDValue>) /llvm/include/llvm/CodeGen/SelectionDAG.h:300:0
       #9 0x00007f08fb0186b8 llvm::SelectionDAG::MorphNodeTo(llvm::SDNode*, unsigned int, llvm::SDVTList, llvm::ArrayRef<llvm::SDValue>) /llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp:6092:0
       #10 0x00007f08fb04a3e9 llvm::SelectionDAGISel::MorphNode(llvm::SDNode*, unsigned int, llvm::SDVTList, llvm::ArrayRef<llvm::SDValue>, unsigned int) /llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp:2474:0
       #11 0x00007f08fb05106b llvm::SelectionDAGISel::SelectCodeCommon(llvm::SDNode*, unsigned char const*, unsigned int) /llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp:3441:0
       #12 0x00007f0901714eb0 (anonymous namespace)::ConnexDAGToDAGISel::SelectCode(llvm::SDNode*) /llvm/lib/Target/Connex/ConnexGenDAGISel.inc:1075:0
       ...

     I really need the pointer values of masked_gather to be stored in a 16-bit element vector register, which is standard in my back end, since I don't want to create 64-bits vector registers just for scatter/gather pointer value vectors, since my processor does not have physical 64-bist registers. To achieve this I made ConnexTargetMachine::computeDataLayout() return string "e-m:e-p:16:16-i32:32:32-i64:64-n32:32-S128". I also gave at the end of ConnexTargetLowering::ConnexTargetLowering() the following:
     ValueTypeActions.setTypeAction(MVT::i16, TypeLegal);
   to avoid errors like:
     Promote integer operand: t16: ch = store<ST256[inttoptr (i16 250 to <128 x i16>*)]> t13:1, t13, Constant:i16<250>, undef:i16

     But even now it gives errors like:
      ISEL: Starting pattern match on root node: t16: ch = store<ST256[inttoptr (i16 250 to <128 x i16>*)]> t13:1, t13, Constant:i16<250>, undef:i16
       Initial Opcode index to 157
       Skipped scope entry (due to false predicate) at index 162, continuing at 236
       Match failed at index 246
       Continuing at 263
     LLVM ERROR: Cannot select: t16: ch = store<ST256[inttoptr (i16 250 to <128 x i16>*)]> t13:1, t13, Constant:i16<250>, undef:i16
   because all my scalar memory operands are i64 or i64imm in the .td specification files.
     So I guess I need to change all scalar memory operands to i16 or i16imm in the .td specification files.

     Please let me know if you see a possibility to fix this problem I guess I should do something like:
    - // Inspired from ARMISelLowering.cpp:
     for (unsigned im = (unsigned)ISD::PRE_INC;
          im != (unsigned)ISD::LAST_INDEXED_MODE; ++im) {
       setIndexedLoadAction(im, MVT::i64, Legal);
       setIndexedLoadAction(im, MVT::i16, Promote);
       setIndexedStoreAction(im, MVT::i64, Legal);
       setIndexedStoreAction(im, MVT::i16, Promote);
      }
    - do custom instruction selection for masked_gather and masked_scatter .

   Best regards,
     Alex

Hello.
     I managed to fix the bug reported earlier here.
     An important reason it failed is that vectoraddr took 5 arguments instead of just 1 (meaning the C++ helper method selectVectorAddr() took 5 reference parameters which are used as return values), and I was not setting these arguments to proper values before returning from the function. (Note also, that, although, in this email I don't talk about masked_scatter, we need to give in the constructor of TargetLowering to avoid errors: setOperationAction(ISD::MSCATTER, aType, Legal); ).

     Now, the correct TableGen spec for gather is:
     /* Because of the SDNPMemOperand attribute of masked_gather it seems
           we need to make the index operator a memory operand.
         It also seems we need to make it a scalar operand by using iPTR and use a C++
            method that returns a vector type. */
     // Gather mem operands
     def ScatterGatherMemOperand : Operand<iPTR> {
       let PrintMethod = "printScatterGatherMemOperand";
       let MIOperandInfo = (ops MSA128D);
     }

     /* 1 means selectVectorAddr() takes 1 extra argument, in this case reference
          int Index which we set with N->getIndex(). Otherwise, the 3rd parameter of
          masked_gather would receive the base pointer IIRC. */
     def vectoraddr : ComplexPattern<iPTR, 1, "selectVectorAddr", , [SDNPWantParent]>;

     // Inspired from [REPO]/llvm/lib/Target/X86/X86InstrAVX512.td
     class LD_INDIRECT_DESC_BASE<
                                 RegisterOperand ROWD,
                                 RegisterOperand ROWSP = ROWD,
                                 InstrItinClass itin = NoItinerary> {
       dag OutOperandList = (outs ROWD:$wd, BoolMaskOpnd:$wdm);
       dag InOperandList = (ins ROWSP:$wsp, // passthru register
                             BoolMaskOpnd:$wsm, // mask register
                             ScatterGatherMemOperand:$wsi // index register
                           );
       string AsmString = "$wd = LS[$wsi]; // READ (gather)";
       list<dag> Pattern = [(set ROWD:$wd, BoolMaskOpnd:$wdm,
                 (masked_gather
                       ROWSP:$wsp, BoolMaskOpnd:$wsm, vectoraddr:$wsi)
                 )];
       InstrItinClass Itinerary = itin;
       string DecoderMethod = "DecodeMSA128Mem";
     }
     class LD_INDIRECT_D_DESC : LD_INDIRECT_DESC_BASE<MSA128DOpnd>;
     class LD_INDIRECT_D_ENC : MSA_3R_FMT<0b101001110>;
     def LD_INDIRECT_D: LD_INDIRECT_D_ENC, LD_INDIRECT_D_DESC;

     Note that at selection time, the ConnexDAGToDAGISel::selectVectorAddr() method is called. This method is responsible for taking both vector address (by calling getIndex()) and base-pointer (by calling getBasePtr()) parameters of the machine-independent SDNode and assembling them in one iPTR parameter, as required by the machine instruction ISD::MGATHER. Note that the parameters differ quite a bit between the machine-independent masked_gather and the machine instruction ISD::MGATHER, whose parameters are specified by the SDTMaskedGather TableGen record.

     Note that we need to pass a vector of pointers obtained with the LLVM IR instruction getelementptr to the gather instr - see http://llvm.org/docs/LangRef.html#llvm-masked-gather-intrinsics for list of arguments, etc.
     An example of LLVM IR program that llc is able to compile is:
         %myOnes = add <128 x i16> zeroinitializer, <i16 1,...>
         %B = inttoptr i16 51 to i16*
         %VectorGep = getelementptr i16, i16* %B, <128 x i16> %myOnes
         %gatherResMyOnes = call <128 x i16> @llvm.masked.gather.v128i16(<128 x i16*> %VectorGep, i32 4, <128 x i1> <i1 true,...>
         ...

   Wish you Merry Xmas!
     Alex

Hello.
     I come back to this older thread about specifying (automatic or manual) instruction selection for gather/scatter operations.
     I have in my ISA a gather (and scatter) instruction that doesn't have mask and passthru. I would like to avoid using them, but LLVM's machine instruction masked_gather takes all these parameters - see https://llvm.org/svn/llvm-project/llvm/trunk/include/llvm/Target/TargetSelectionDAG.td, around "def masked_gather" (and also the email from this thread from date 12/15/2016 and the LLVM IR instruction equivalent http://llvm.org/docs/LangRef.html#llvm-masked-gather-intrinsics). This forces the instruction-selection to generate unnecessary instructions (and lated allocate unnecessary registers) for the passthru operand (the mask seems to be discarded by my back end by default).

     I am therefore planning to discard the previous solution with TableGen description (see below) and perform manual/custom Instruction selection to avoid selecting the passthru (maybe also the mask) operand.
     Can you recommend a (better) way to do this in TableGen? I tried to avoid the selection of the passthru operand in my TableGen description below, but I always got an error.

   Thank you very much,
     Alex