LLVM学习笔记(15)

3.4. DAG指令选择器的生成代码

3.4.1. 概述

选项-gen-dag-isel用于产生DAG指令选择器,处理这个选项的入口在EmitDAGISel()。TableGen首先根据对指令的描述,为指令定义中的匹配模板(亦称源模板,它指出长怎么样的IR代码片段能匹配这条指令)以及结果模板(它指出匹配成功后指令应该输出怎样的结果,这个结果包含隐含的寄存器的变化)构建DAG实例(下文的展开的TreePatternNode图)。然后根据这两个DAG的结构产生一系列Matcher对象。所有指令所生成的Matcher对象都被串接起来。之后遍历这些Matcher对象,TableGen将输出一张表。函数SelectCodeCommon()将根据这张表进行指令选择。

170     void EmitDAGISel(RecordKeeper &RK, raw_ostream &OS) {

171       DAGISelEmitter(RK).run(OS);

172     }

参数RK就是保存了所有class与def定义的Record实例的容器。171行首先构造了一个临时的DAGISelEmitter实例。

29         explicit DAGISelEmitter(RecordKeeper &R) : CGP(R) {}

​​​​​​​3.4.1. CodeGenDAGPatterns对象

CGP是一个CodeGenDAGPatterns对象,顾名思义这是生成DAG模式处理代码的对象,这个对象在构造函数里完成了输出代码前几乎所有的处理。

2347  CodeGenDAGPatterns::CodeGenDAGPatterns(RecordKeeper &R,

                                                               PatternRewriterFn PatternRewriter) :   <-- v7.0增加,缺省为null

2348    Records(R), Target(R),

                 LegalVTS(Target.getLegalValueTypes()), PatternRewriter(PatternRewriter) {    ß v7.0增加

2349 

2350    Intrinsics = LoadIntrinsics(Records, false);       <-- v7.0删除

2351    TgtIntrinsics = LoadIntrinsics(Records, true);

Intrinsics = CodeGenIntrinsicTable(Records, false);    <-- v7.0增加

TgtIntrinsics = CodeGenIntrinsicTable(Records, true);

2352    ParseNodeInfo();

2353    ParseNodeTransforms();

2354    ParseComplexPatterns();

2355    ParsePatternFragments();

2356    ParseDefaultOperands();

2357    ParseInstructions();

2358    ParsePatternFragments(/*OutFrags*/true);

2359    ParsePatterns();

2360 

2361    // Generate variants.  For example, commutative patterns can match

2362    // multiple ways.  Add them to PatternsToMatch as well.

2363    GenerateVariants();

2364 

  // Break patterns with parameterized types into a series of patterns,

  // where each one has a fixed type and is predicated on the conditions

  // of the associated HW mode.

  ExpandHwModeBasedTypes();    <-- v7.0增加

2365    // Infer instruction flags.  For example, we can detect loads,

2366    // stores, and side effects in many cases by examining an

2367    // instruction's pattern.

2368    InferInstructionFlags();

2369 

2370    // Verify that instruction flags match the patterns.

2371    VerifyInstructionFlags();

2372  }

2350与2351行的LoadIntrinsics()(v7.0CodeGenIntrinsicTable())从固有函数的Record实例生成对应的CodeGenIntrinsic对象。在这里我们不深入其中的细节。维基百科Intrinsic function条目下详细解释了固有函数,简单来说,编译器完全理解固有函数的语义,能更好地生成这些函数的优化代码。LLVM兼容GCC,提供了大量的固有函数(http://llvm.org/docs/LangRef.html#instruction-reference里给出了一个详细列表,但不完全)。

V7.0在初始化列表中调用了CodeGenTargetgetLegalValueTypes()方法来获取合法类型:

124       ArrayRef getLegalValueTypes() const {

125         if (LegalValueTypes.empty())

126           ReadLegalValueTypes();

127         return LegalValueTypes;

128       }

方法ReadLegalValueTypes()收集所有寄存器类支持的类型。其中成员容器LegalValueTypes的类型是mutable SmallVectorValueTypeByHwMode定义了“<”操作符,该操作符调用std::map的“<”操作符,该操作符进而调用MVT的“<”操作符,它按在其内部封装的SimpleValueType值大小排序。

312     void CodeGenTarget::ReadLegalValueTypes() const {

313       for (const auto &RC : getRegBank().getRegClasses())

314         LegalValueTypes.insert(LegalValueTypes.end(), RC.VTs.begin(), RC.VTs.end());

315    

316       // Remove duplicates.

317       llvm::sort(LegalValueTypes.begin(), LegalValueTypes.end());

318       LegalValueTypes.erase(std::unique(LegalValueTypes.begin(),

319                                                                       LegalValueTypes.end()),

320                                                  LegalValueTypes.end());

321     }

得到的合法类型在CodeGenDAGPatterns实例里保存在LegalVTS成员中(TypeSetByHwMode类型),并调用下面的构造函数:

67           TypeSetByHwMode::TypeSetByHwMode(ArrayRef VTList) {

68         for (const ValueTypeByHwMode &VVT : VTList)

69           insert(VVT);

70       }

TypeSetByHwModeInfoByHwMode 的派生类。MachineValueTypeSet用于表示一组MVT,因为MVT包含的SimpleValueType8位的枚举,因此MachineValueTypeSet256位的数组来记录这些MVT。上面69TypeSetByHwModeinsert()方法的定义为:

100     bool TypeSetByHwMode::insert(const ValueTypeByHwMode &VVT) {

101       bool Changed = false;

102       SmallDenseSet Modes;

103       for (const auto &P : VVT) {

104         unsigned M = P.first;

105         Modes.insert(M);

106         // Make sure there exists a set for each specific mode from VVT.

107         Changed |= getOrCreate(M).insert(P.second).second;

108       }

109    

110       // If VVT has a default mode, add the corresponding type to all

111       // modes in "this" that do not exist in VVT.

112       if (Modes.count(DefaultMode)) {

113         MVT DT = VVT.getType(DefaultMode);

114         for (auto &I : *this)

115           if (!Modes.count(I.first))

116             Changed |= I.second.insert(DT).second;

117       }

118       return Changed;

119     }

上面103行循环首先记录硬件模式,然后插入对应的类型。getOrCreate()方法是这样的:

201       SetType &getOrCreate(unsigned Mode) {

202         if (hasMode(Mode))

203           return get(Mode);

204         return Map.insert({Mode,SetType()}).first->second;

205       }

Map就是基类InfoByHwMode中的std::map,因此204行将返回新创建的MachineValueTypeSet实例。而203行的get()方法则来自InfoByHwMode

85         InfoT &get(unsigned Mode) {

86           if (!hasMode(Mode)) {

87             assert(hasMode(DefaultMode));

88             Map.insert({Mode, Map.at(DefaultMode)});

89           }

90           return Map.at(Mode);

91         }

回到TypeSetByHwMode::insert()107行,方法getOrCreate()返回后调用的insert()方法来自MachineValueTypeSet

92         std::pair insert(MVT T) {

93           bool V = count(T.SimpleTy);

94           Words[T.SimpleTy / WordWidth] |= WordType(1) << (T.SimpleTy % WordWidth);

95           return {*this, V};

96         }

Words就是MachineValueTypeSet中记录MVT256位。

​​​​​​​3.4.2.1. SDNode的处理

在TD文件里SDNode表示SelectionDAG的节点,代表操作的类型。TableGen通过下面一系列的方法,根据SDNode的Record实例,获取对应的SDNodeInfo与SDTypeConstraint对象。这两个类型的定义如下:

169     struct SDTypeConstraint {

170       SDTypeConstraint(Record *R);

171    

172       unsigned OperandNo;   // The operand # this constraint applies to.

173       enum {

174         SDTCisVT, SDTCisPtrTy, SDTCisInt, SDTCisFP, SDTCisVec, SDTCisSameAs,

175         SDTCisVTSmallerThanOp, SDTCisOpSmallerThanOp, SDTCisEltOfVec,

176         SDTCisSubVecOfVec, SDTCVecEltisVT, SDTCisSameNumEltsAs

177       } ConstraintType;

178    

179       union {   // The discriminated union.

180         struct {

181           MVT::SimpleValueType VT;

182         } SDTCisVT_Info;

183         struct {

184           unsigned OtherOperandNum;

185         } SDTCisSameAs_Info;

186         struct {

187           unsigned OtherOperandNum;

188         } SDTCisVTSmallerThanOp_Info;

189         struct {

190           unsigned BigOperandNum;

191         } SDTCisOpSmallerThanOp_Info;

192         struct {

193           unsigned OtherOperandNum;

194         } SDTCisEltOfVec_Info;

195         struct {

196           unsigned OtherOperandNum;

197         } SDTCisSubVecOfVec_Info;

198         struct {

199           MVT::SimpleValueType VT;

200         } SDTCVecEltisVT_Info;

201         struct {

202           unsigned OtherOperandNum;

203         } SDTCisSameNumEltsAs_Info;

204       } x;

  // The VT for SDTCisVT and SDTCVecEltisVT.

  // Must not be in the union because it has a non-trivial destructor.

  ValueTypeByHwMode VVT;                                                                      <--v7.0增加

205    

206       /// ApplyTypeConstraint - Given a node in a pattern, apply this type

207       /// constraint to the nodes operands.  This returns true if it makes a

208       /// change, false otherwise.  If a type contradiction is found, an error

209       /// is flagged.

210       bool ApplyTypeConstraint(TreePatternNode *N, const SDNodeInfo &NodeInfo,

211                                TreePattern &TP) const;

212     };

SDTypeConstraint对应TD文件中的SDTypeConstraint派生定义,它隐藏在SDNode的TypeProfile域中。而SDNodeInfo就是TableGen所使用的SDNode的对应类型。

217     class SDNodeInfo {

218       Record *Def;

219       std::string EnumName;

220       std::string SDClassName;

221       unsigned Properties;

222       unsigned NumResults;

223       int NumOperands;

224       std::vector TypeConstraints;

225     public:

226       SDNodeInfo(Record *R);  // Parse the specified record.

227    

228       unsigned getNumResults() const { return NumResults; }

229    

230       /// getNumOperands - This is the number of operands required or -1 if

231       /// variadic.

232       int getNumOperands() const { return NumOperands; }

233       Record *getRecord() const { return Def; }

234       const std::string &getEnumName() const { return EnumName; }

235       const std::string &getSDClassName() const { return SDClassName; }

236    

237       const std::vector &getTypeConstraints() const {

238         return TypeConstraints;

239       }

240    

241       /// getKnownType - If the type constraints on this node imply a fixed type

242       /// (e.g. all stores return void, etc), then return it as an

243       /// MVT::SimpleValueType.  Otherwise, return MVT::Other.

244       MVT::SimpleValueType getKnownType(unsigned ResNo) const;

245    

246       /// hasProperty - Return true if this node has the specified property.

247       ///

248       bool hasProperty(enum SDNP Prop) const { return Properties & (1 << Prop); }

249    

250       /// ApplyTypeConstraints - Given a node in a pattern, apply the type

251       /// constraints for this node to the operands of the node.  This returns

252       /// true if it makes a change, false otherwise.  If a type contradiction is

253       /// found, an error is flagged.

254       bool ApplyTypeConstraints(TreePatternNode *N, TreePattern &TP) const {

255         bool MadeChange = false;

256         for (unsigned i = 0, e = TypeConstraints.size(); i != e; ++i)

257           MadeChange |= TypeConstraints[i].ApplyTypeConstraint(N, *this, TP);

258         return MadeChange;

259       }

260     };

处理方法CodeGenDAGPatterns::ParseNodeInfo()则是这样定义的:

2383  void CodeGenDAGPatterns::ParseNodeInfo() {

2384    std::vector Nodes = Records.getAllDerivedDefinitions("SDNode");

  const CodeGenHwModes &CGH = getTargetInfo().getHwModes();              <-- v7.0增加

2385    while (!Nodes.empty()) {

2386      SDNodes.insert(std::make_pair(Nodes.back(), Nodes.back()));        <-- v7.0删除

    Record *R = Nodes.back();                                                                           <-- v7.0增加

    SDNodes.insert(std::make_pair(R, SDNodeInfo(R, CGH)));

2387      Nodes.pop_back();

2388    }

2389 

2390    // Get the builtin intrinsic nodes.

2391    intrinsic_void_sdnode     = getSDNodeNamed("intrinsic_void");

2392    intrinsic_w_chain_sdnode  = getSDNodeNamed("intrinsic_w_chain");

2393    intrinsic_wo_chain_sdnode = getSDNodeNamed("intrinsic_wo_chain");

2394  }

2386行的SDNodes是CodeGenDAGPatterns类型为std::map的容器。因此,2386行处会调用SDNodeInfo构造函数:

1085  SDNodeInfo::SDNodeInfo(Record *R , const CodeGenHwModes &CGH) : Def(R) {    <-- v7.0增加

1086    EnumName    = R->getValueAsString("Opcode");

1087    SDClassName = R->getValueAsString("SDClass");

1088    Record *TypeProfile = R->getValueAsDef("TypeProfile");

1089    NumResults = TypeProfile->getValueAsInt("NumResults");

1090    NumOperands = TypeProfile->getValueAsInt("NumOperands");

1091 

1092    // Parse the properties.

1093    Properties = 0;

1094    std::vector PropList = R->getValueAsListOfDefs("Properties");

1095    for (unsigned i = 0, e = PropList.size(); i != e; ++i) {

1096      if (PropList[i]->getName() == "SDNPCommutative") {

1097        Properties |= 1 << SDNPCommutative;

1098      } else if (PropList[i]->getName() == "SDNPAssociative") {

1099        Properties |= 1 << SDNPAssociative;

1100      } else if (PropList[i]->getName() == "SDNPHasChain") {

1101        Properties |= 1 << SDNPHasChain;

1102      } else if (PropList[i]->getName() == "SDNPOutGlue") {

1103        Properties |= 1 << SDNPOutGlue;

1104      } else if (PropList[i]->getName() == "SDNPInGlue") {

1105        Properties |= 1 << SDNPInGlue;

1106      } else if (PropList[i]->getName() == "SDNPOptInGlue") {

1107        Properties |= 1 << SDNPOptInGlue;

1108      } else if (PropList[i]->getName() == "SDNPMayStore") {

1109        Properties |= 1 << SDNPMayStore;

1110      } else if (PropList[i]->getName() == "SDNPMayLoad") {

1111        Properties |= 1 << SDNPMayLoad;

1112      } else if (PropList[i]->getName() == "SDNPSideEffect") {

1113        Properties |= 1 << SDNPSideEffect;

1114      } else if (PropList[i]->getName() == "SDNPMemOperand") {

1115        Properties |= 1 << SDNPMemOperand;

1116      } else if (PropList[i]->getName() == "SDNPVariadic") {

1117        Properties |= 1 << SDNPVariadic;

1118      } else {

1119        PrintFatalError("Unknown SD Node property '" +

1120                        PropList[i]->getName() + "' on node '" +

1121                        R->getName() + "'!");

1122      }

1123    }

1124 

1125 

1126    // Parse the type constraints.

1127    std::vector ConstraintList =

1128      TypeProfile->getValueAsListOfDefs("Constraints");

1129    TypeConstraints.assign(ConstraintList.begin(), ConstraintList.end());   <-- v7.0删除

  for (Record *R : ConstraintList)                        <-- v7.0增加

    TypeConstraints.emplace_back(R, CGH);

1130  }

SDNodeInfo将Properties用作位图,用比特位来表示特定的属性。而1129行为TD文件的SDNode定义里的Constraints每项调用SDTypeConstraint构造函数:

867     SDTypeConstraint::SDTypeConstraint(Record *R , const CodeGenHwModes &CGH) {    <-- v7.0增加

868       OperandNo = R->getValueAsInt("OperandNum");

869    

870       if (R->isSubClassOf("SDTCisVT")) {

871         ConstraintType = SDTCisVT;

872         x.SDTCisVT_Info.VT = getValueType(R->getValueAsDef("VT"));        <-- v7.0删除

    VVT = getValueTypeByHwMode(R->getValueAsDef("VT"), CGH);     ß v7.0增加

    for (const auto &P : VVT)

873           if (x.SDTCisVT_Info.VT == MVT::isVoid)

874             PrintFatalError(R->getLoc(), "Cannot use 'Void' as type to SDTCisVT");

875    

876       } else if (R->isSubClassOf("SDTCisPtrTy")) {

877         ConstraintType = SDTCisPtrTy;

878       } else if (R->isSubClassOf("SDTCisInt")) {

879         ConstraintType = SDTCisInt;

880       } else if (R->isSubClassOf("SDTCisFP")) {

881         ConstraintType = SDTCisFP;

882       } else if (R->isSubClassOf("SDTCisVec")) {

883         ConstraintType = SDTCisVec;

884       } else if (R->isSubClassOf("SDTCisSameAs")) {

885         ConstraintType = SDTCisSameAs;

886         x.SDTCisSameAs_Info.OtherOperandNum = R->getValueAsInt("OtherOperandNum");

887       } else if (R->isSubClassOf("SDTCisVTSmallerThanOp")) {

888         ConstraintType = SDTCisVTSmallerThanOp;

889         x.SDTCisVTSmallerThanOp_Info.OtherOperandNum =

890           R->getValueAsInt("OtherOperandNum");

891       } else if (R->isSubClassOf("SDTCisOpSmallerThanOp")) {

892         ConstraintType = SDTCisOpSmallerThanOp;

893         x.SDTCisOpSmallerThanOp_Info.BigOperandNum =

894           R->getValueAsInt("BigOperandNum");

895       } else if (R->isSubClassOf("SDTCisEltOfVec")) {

896         ConstraintType = SDTCisEltOfVec;

897         x.SDTCisEltOfVec_Info.OtherOperandNum = R->getValueAsInt("OtherOpNum");

898       } else if (R->isSubClassOf("SDTCisSubVecOfVec")) {

899         ConstraintType = SDTCisSubVecOfVec;

900         x.SDTCisSubVecOfVec_Info.OtherOperandNum =

901           R->getValueAsInt("OtherOpNum");

902       } else if (R->isSubClassOf("SDTCVecEltisVT")) {

903         ConstraintType = SDTCVecEltisVT;

904         x.SDTCVecEltisVT_Info.VT = getValueType(R->getValueAsDef("VT"));   ß v7.0删除

    VVT = getValueTypeByHwMode(R->getValueAsDef("VT"), CGH);    ß v7.0增加

for (const auto &P : VVT) {

  MVT T = P.second;

905           if (MVT(x.SDTCVecEltisVT_Info.VT).isVector())

906             PrintFatalError(R->getLoc(), "Cannot use vector type as SDTCVecEltisVT");

907           if (!MVT(x.SDTCVecEltisVT_Info.VT).isInteger() &&

908                   !MVT(x.SDTCVecEltisVT_Info.VT).isFloatingPoint())

909             PrintFatalError(R->getLoc(), "Must use integer or floating point type "

910                                        "as SDTCVecEltisVT");

}

911       } else if (R->isSubClassOf("SDTCisSameNumEltsAs")) {

912         ConstraintType = SDTCisSameNumEltsAs;

913         x.SDTCisSameNumEltsAs_Info.OtherOperandNum =

914           R->getValueAsInt("OtherOperandNum");

915       } else {

916         PrintFatalError("Unrecognized SDTypeConstraint '" + R->getName() + "'!\n");

917       }

918     }

CodeGenDAGPatterns::ParseNodeInfo()的2391~2393行,类成员intrinsic_void,intrinsic_w_chain与intrinsic_wo_chain都是LLVM内部用来表示一类固有函数调用的。在LLVM源代码目录下的文件include/llvm/CodeGen/ISDOpcodes.h里可以找到下述的描述:

RESULT = INTRINSIC_WO_CHAIN(INTRINSICID, arg1, arg2, ...),表示没有副作用的目标机器固有函数。第一个操作数是来自llvm::Intrinsic名字空间的该固有函数的ID号,后跟该固有函数的操作数。该节点返回该固有函数的结果。

RESULT, OUTCHAIN = INTRINSIC_W_CHAIN(INCHAIN, INTRINSICID, arg1, ...),表示返回一个结果的有副作用的目标机器固有函数。第一个操作数是链指针,第二个是来自llvm::Intrinsic名字空间的该固有函数的ID号,后跟该固有函数的操作数。该节点返回两个结果,该固有函数的结果与输出链。

OUTCHAIN = INTRINSIC_VOID(INCHAIN, INTRINSICID, arg1, arg2, ...),表示不返回值、有副作用的目标机器固有函数。第一个操作数是链指针,第二个是来自llvm::Intrinsic名字空间的该固有函数的ID号,后跟该固有函数的操作数。

使用上述三个类型封装固有函数调用,无疑将极大地简化对固有函数的处理,除非必要,我们都无需操心固有函数的语义。因此,这里我们无需它们生成对应的SDNodeInfo对象,而是要记住它们的Record对象,因为它们是什么,我们很清楚。

​​​​​​​3.4.2.2. SDNodeXForm的处理

SDNodeXForm也可以作为dag值中的操作符,来表示对操作数的一个修改。执行修改代码片段保存在成员XFormFunction里,而操作数由成员Opcode保存。这里要做的处理,就是整理一下,使得SDNodeXForm定义的内容可以快速获取。

2398  void CodeGenDAGPatterns::ParseNodeTransforms() {

2399    std::vector Xforms = Records.getAllDerivedDefinitions("SDNodeXForm");

2400    while (!Xforms.empty()) {

2401      Record *XFormNode = Xforms.back();

2402      Record *SDNode = XFormNode->getValueAsDef("Opcode");

2403      std::string Code = XFormNode->getValueAsString("XFormFunction");

2404      SDNodeXForms.insert(std::make_pair(XFormNode, NodeXForm(SDNode, Code)));

2405 

2406      Xforms.pop_back();

2407    }

2408  }

在代码中SDNodeXForms是std::map, LessRecordByID>类型的容器,NodeXForm则是std::pair的typedef。

​​​​​​​3.4.2.3. ComplexPattern的处理

前面看到ComplexPattern用于描述复杂操作数。CodeGenDAGPatterns::ParseComplexPatterns()方法准备TableGen所需的ComplexPattern对象:

198     class ComplexPattern {

199       MVT::SimpleValueType Ty;

200       unsigned NumOperands;

201       std::string SelectFunc;

202       std::vector RootNodes;

203       unsigned Properties; // Node properties

  unsigned Complexity;    <-- v7.0增加

204     public:

205       ComplexPattern() : NumOperands(0) {}

206       ComplexPattern(Record *R);

207    

208       MVT::SimpleValueType getValueType() const { return Ty; }

209     unsigned getNumOperands() const { return NumOperands; }

210       const std::string &getSelectFunc() const { return SelectFunc; }

211       const std::vector &getRootNodes() const {

212         return RootNodes;

213       }

214       bool hasProperty(enum SDNP Prop) const { return Properties & (1 << Prop); }

  unsigned getComplexity() const { return Complexity; }    <-- v7.0增加

215     };

TableGen的ComplexPattern几乎就是TD文件中ComplexPattern的定义的一对一翻译。生成它相当简单:

2410  void CodeGenDAGPatterns::ParseComplexPatterns() {

2411    std::vector AMs = Records.getAllDerivedDefinitions("ComplexPattern");

2412    while (!AMs.empty()) {

2413      ComplexPatterns.insert(std::make_pair(AMs.back(), AMs.back()));

2414      AMs.pop_back();

2415    }

2416  }

ComplexPatterns容器的类型是std::map,因此,2413行包含了对ComplexPattern构造函数的调用:

385     ComplexPattern::ComplexPattern(Record *R) {

386       Ty          = ::getValueType(R->getValueAsDef("Ty"));

387       NumOperands = R->getValueAsInt("NumOperands");

388       SelectFunc  = R->getValueAsString("SelectFunc");

389       RootNodes   = R->getValueAsListOfDefs("RootNodes");

390     <-- v7.0增加

  // FIXME: This is a hack to statically increase the priority of patterns which

  // maps a sub-dag to a complex pattern. e.g. favors LEA over ADD. To get best

  // possible pattern match we'll need to dynamically calculate the complexity

  // of all patterns a dag can potentially map to.

  int64_t RawComplexity = R->getValueAsInt("Complexity");

  if (RawComplexity == -1)

    Complexity = NumOperands * 3;

  else

    Complexity = RawComplexity;

​​​​​​​  // FIXME: Why is this different from parseSDPatternOperatorProperties?

391       // Parse the properties.

392       Properties = 0;

393       std::vector PropList = R->getValueAsListOfDefs("Properties");

394       for (unsigned i = 0, e = PropList.size(); i != e; ++i)

395         if (PropList[i]->getName() == "SDNPHasChain") {

396           Properties |= 1 << SDNPHasChain;

397         } else if (PropList[i]->getName() == "SDNPOptInGlue") {

398           Properties |= 1 << SDNPOptInGlue;

399         } else if (PropList[i]->getName() == "SDNPMayStore") {

400           Properties |= 1 << SDNPMayStore;

401         } else if (PropList[i]->getName() == "SDNPMayLoad") {

402           Properties |= 1 << SDNPMayLoad;

403         } else if (PropList[i]->getName() == "SDNPSideEffect") {

404           Properties |= 1 << SDNPSideEffect;

405         } else if (PropList[i]->getName() == "SDNPMemOperand") {

406           Properties |= 1 << SDNPMemOperand;

407         } else if (PropList[i]->getName() == "SDNPVariadic") {

408           Properties |= 1 << SDNPVariadic;

409         } else if (PropList[i]->getName() == "SDNPWantRoot") {

410           Properties |= 1 << SDNPWantRoot;

411         } else if (PropList[i]->getName() == "SDNPWantParent") {

412           Properties |= 1 << SDNPWantParent;

413         } else {

414           PrintFatalError("Unsupported SD Node property '" +

415                           PropList[i]->getName() + "' on ComplexPattern '" +

416                           R->getName() + "'!");

417         }

418     }

NumOperands是SelectFunc将要返回的值个数。RootNodes则是list类型的容器,因为一个ComplexPattern定义可以适用于多个不同的子dag匹配。

你可能感兴趣的:(LLVM学习笔记)