[llvm-dev] TableGen - Help to implement a form of gather/scatter operations for Mips MSA

Alex Susu via llvm-dev llvm-dev at lists.llvm.org
Sun Dec 11 18:18:53 PST 2016


   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



On 12/11/2016 5:31 AM, Alex Susu wrote:
>   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
>
> On 12/9/2016 4:18 PM, Will Lovett wrote:
>> 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
>>
>>
>> On 9 December 2016 at 01:52:48, Alex Susu via llvm-dev (llvm-dev at lists.llvm.org
>> <mailto:llvm-dev at lists.llvm.org>) wrote:
>>
>>> 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
>>> _______________________________________________
>>> LLVM Developers mailing list
>>> llvm-dev at lists.llvm.org
>>> http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev


More information about the llvm-dev mailing list