LLVM学习笔记(16)

3.4.2.4. PatFrag的处理

3.4.2.4.1. 模式树的构建

PatFrag是一个可重用的构件,TableGen会在PatFrag出现的地方展开其定义,有点像C/C++中的宏。为此,CodeGenDAGPatterns将每个可能嵌入PatFrag的定义——Instruction,Pattern,Pat以及PatFrag,构建为一棵TreePattern树,并在适当的时候将其中包含的PatFrag展开(这是个递归的过程,会一直进行到PatFrag不存在为止)。

v7.0里,PatFragPatFrags的派生定义(或者说是PatFrags单匹配片段的特例),PatFrags支持多个匹配片段,只要其中一个匹配,就可视为匹配成功,因此在v7.0里是对PatFrags展开处理。

函数CodeGenDAGPatterns::ParsePatternFragments()处理、展开所有的PatFrag定义。

它会生成这样的结构:对一个PatFrag定义(v7.0PatFrags下同)生成一个TreePattern实例;从定义里的Fragment(v7.0Fragments)生成一个保存在TreePattern的Trees容器里的TreePatternNode实例(v7.0Fragments里每成员一个TreePatternNode实例);定义里Operands中的操作数名则保存在Args容器里。如果Fragment的dag值仍然是一个PatFrag派生定义,那么其TreePatternNode实例的Operator记录这个PatFrag的Record对象,Children容器则保存由该dag操作数生成的TreePatternNode实例。以此类推,直到该定义中涉及的所有PatFrag定义都被处理。这分为两大步进行。

首先在2428行循环为所有的PatFrag定义生成模式树,并进行一些有效性检查。

2424  void CodeGenDAGPatterns::ParsePatternFragments(bool OutFrags) {

2425    std::vector<Record*> Fragments = Records.getAllDerivedDefinitions("PatFrag");    <- v7.0删除

  std::vector<Record*> Fragments = Records.getAllDerivedDefinitions("PatFrags");  <- v7.0增加

2426 

2427    // First step, parse all of the fragments.

2428    for (unsigned i = 0, e = Fragments.size(); i != e; ++i) {

2429    if (OutFrags != Fragments[i]->isSubClassOf("OutPatFrag"))

2430        continue;

2431 

2432      DagInit *Tree = Fragments[i]->getValueAsDag("Fragment");    <- v7.0删除

    ListInit *LI = Frag->getValueAsListInit("Fragments");                <- v7.0增加

2433      TreePattern *P =

2434          (PatternFragments[Fragments[i]] = llvm::make_unique<TreePattern>(

2435               Fragments[i], Tree LI, !Fragments[i]->isSubClassOf("OutPatFrag"),

2436               *this)).get();

2437 

2438      // Validate the argument list, converting it to set, to discard duplicates.

2439      std::vector<std::string> &Args = P->getArgList();

 

    // Copy the args so we can take StringRefs to them.

auto ArgsCopy = Args;                                                                     <- v7.0增加

SmallDenseSet<StringRef, 4> OperandsSet;

OperandsSet.insert(ArgsCopy.begin(), ArgsCopy.end());

 

2440      std::set<std::string> OperandsSet(Args.begin(), Args.end());   <- v7.0删除

2441 

2442      if (OperandsSet.count(""))

2443        P->error("Cannot have unnamed 'node' values in pattern fragment!");

2444 

2445      // Parse the operands list.

2446      DagInit *OpsList = Fragments[i]->getValueAsDag("Operands");

2447      DefInit *OpsOp = dyn_cast<DefInit>(OpsList->getOperator());

2448      // Special cases: ops == outs == ins. Different names are used to

2449      // improve readability.

2450      if (!OpsOp ||

2451          (OpsOp->getDef()->getName() != "ops" &&

2452           OpsOp->getDef()->getName() != "outs" &&

2453           OpsOp->getDef()->getName() != "ins"))

2454        P->error("Operands list should start with '(ops ... '!");

2455 

2456      // Copy over the arguments.

2457      Args.clear();

2458      for (unsigned j = 0, e = OpsList->getNumArgs(); j != e; ++j) {

2459        if (!isa<DefInit>(OpsList->getArg(j)) ||

2460            cast<DefInit>(OpsList->getArg(j))->getDef()->getName() != "node")

2461          P->error("Operands list should all be 'node' values.");

2462        if (OpsList->getArgName(j).empty())

2463          P->error("Operands list should have names for each operand!");

2464        if (!OperandsSet.count(OpsList->getArgName(j)))

2465          P->error("'" + OpsList->getArgName(j) +

2466                   "' does not occur in pattern or was multiply specified!");

2467        OperandsSet.erase(OpsList->getArgName(j));

2468        Args.push_back(OpsList->getArgName(j));

2469      }

2470 

2471      if (!OperandsSet.empty())

2472        P->error("Operands list does not contain an entry for operand '" +

2473                 *OperandsSet.begin() + "'!");

2474 

2475      // If there is a code init for this fragment, keep track of the fact that

2476      // this fragment uses it.

2477      TreePredicateFn PredFn(P);

2478      if (!PredFn.isAlwaysTrue())

2479        P->getOnlyTree()->addPredicateFn(PredFn);

2480 

2481      // If there is a node transformation corresponding to this, keep track of

2482      // it.

2483      Record *Transform = Fragments[i]->getValueAsDef("OperandTransform");

2484      if (!getSDNodeTransform(Transform).second.empty())    // not noop xform?

      for (auto T : P->getTrees())           <- v7.0增加

2485          P->getOnlyTree()->setTransformFn(Transform);

2486    }

2487 

2488    // Now that we've parsed all of the tree fragments, do a closure on them so

2489    // that there are not references to PatFrags left inside of them.

2490    for (unsigned i = 0, e = Fragments.size(); i != e; ++i) {

2491     if (OutFrags != Fragments[i]->isSubClassOf("OutPatFrag"))

2492        continue;

2493 

2494      TreePattern &ThePat = *PatternFragments[Fragments[i]];

2495      ThePat.InlinePatternFragments();

2496 

2497      // Infer as many types as possible.  Don't worry about it if we don't infer

2498      // all of them, some may depend on the inputs of the pattern. Also, don't           <- v7.0增加

    // validate type sets; validation may cause spurious failures e.g. if a

    // fragment needs floating-point types but the current target does not have

    // any (this is only an error if that fragment is ever used!).

    {

      TypeInfer::SuppressValidation SV(ThePat.getInfer());

2499        ThePat.InferAllTypes();

2500        ThePat.resetError();

   }

2501 

2502      // If debugging, print out the pattern fragment result.

2503      DEBUG(ThePat.dump());

2504    }

2505  }

在CodeGenDAGPatterns构造函数里两次调用了ParsePatternFragments(),第一次参数OutFrags是false(缺省值),表示不考虑OutPatFrag类型的定义。2434行的llvm::make_unique调用new操作符构建一个TreePattern实例,并返回一个std::unique_ptr<TreePattern>实例。因此,2434行的成员PatternFragments是类型为std::map<Record *, std::unique_ptr<TreePattern>, LessRecordByID>的容器。TreePattern的构造函数定义在CodeGenDAGPatterns.cpp里:

2006  TreePattern::TreePattern(Record *TheRec, DagInit *Pat, bool isInput,

2007                           CodeGenDAGPatterns &cdp) : TheRecord(TheRec), CDP(cdp),

2008                           isInputPattern(isInput), HasError(false) {

2009    Trees.push_back(ParseTreePattern(Pat, ""));

2010  }

V7.0中调用这个版本,因为PatFrags里现在是Fragments(类型为list<dag>):

2534  TreePattern::TreePattern(Record *TheRec, ListInit *RawPat, bool isInput,

2535                           CodeGenDAGPatterns &cdp) : TheRecord(TheRec), CDP(cdp),

2536                           isInputPattern(isInput), HasError(false),

2537                           Infer(*this) {

2538    for (Init *I : RawPat->getValues())

2539      Trees.push_back(ParseTreePattern(I, ""));

2540  }

其中2537行的Infer是类型为TypeInfer的成员,用于辅助类型推导。

注意只要这个PatFrag不是OutPatFrag的派生定义,参数isInputPattern就是false。2009行的Trees是TreePattern中类型为std::vector<TreePatternNode*>的容器,显然TreePatternNode用作树的节点。PatFrag的具体解析由ParseTreePattern()完成,参数TheInit是PatFrag定义中的Fragment(匹配片段):

2040  TreePatternNode *TreePattern::ParseTreePattern(Init *TheInit, StringRef OpName){

2041    if (DefInit *DI = dyn_cast<DefInit>(TheInit)) {

2042      Record *R = DI->getDef();

2043 

2044      // Direct reference to a leaf DagNode or PatFrag?  Turn it into a

2045      // TreePatternNode of its own.  For example:

2046      ///   (foo GPR, imm) -> (foo GPR, (imm))

2047      if (R->isSubClassOf("SDNode") || R->isSubClassOf("PatFrag"))

2048        return ParseTreePattern(

2049          DagInit::get(DI, "",

2050                       std::vector<std::pair<Init*, std::string> >()),

2051          OpName);

2052 

2053      // Input argument?

2054      TreePatternNode *Res = new TreePatternNode(DI, 1);       <- v7.0删除

    TreePatternNodePtr Res = std::make_shared<TreePatternNode>(DI, 1);       <- v7.0增加

2055      if (R->getName() == "node" && !OpName.empty()) {

2056        if (OpName.empty())

2057          error("'node' argument requires a name to match with operand list");

2058        Args.push_back(OpName);

2059      }

2060 

2061      Res->setName(OpName);

2062      return Res;

2063    }

2064 

2065    // ?:$name or just $name.

2066    if (isa<UnsetInit>(TheInit)) {

2067      if (OpName.empty())

2068        error("'?' argument requires a name to match with operand list");

2069      TreePatternNode *Res = new TreePatternNode(TheInit, 1);       <- v7.0删除

    TreePatternNodePtr Res = std::make_shared<TreePatternNode>(TheInit, 1);      <- v7.0增加

2070      Args.push_back(OpName);

2071      Res->setName(OpName);

2072      return Res;

2073    }

2074 

2075    if (IntInit *II = dyn_cast<IntInit>(TheInit)) {

2076      if (!OpName.empty())

2077        error("Constant int argument should not have a name!");

2078      return new TreePatternNode(II, 1);       <- v7.0删除

    return std::make_shared<TreePatternNode>(TheInit, 1);      <- v7.0增加

2079    }

2080 

2081    if (BitsInit *BI = dyn_cast<BitsInit>(TheInit)) {

2082      // Turn this into an IntInit.

2083      Init *II = BI->convertInitializerTo(IntRecTy::get());

2084      if (!II || !isa<IntInit>(II))

2085        error("Bits value must be constants!");

2086      return ParseTreePattern(II, OpName);

2087    }

2088 

2089    DagInit *Dag = dyn_cast<DagInit>(TheInit);

2090    if (!Dag) {

2091      TheInit->dump();

2092      error("Pattern has unexpected init kind!");

2093    }

2094    DefInit *OpDef = dyn_cast<DefInit>(Dag->getOperator());

2095    if (!OpDef) error("Pattern has unexpected operator type!");

2096    Record *Operator = OpDef->getDef();

2097 

2098    if (Operator->isSubClassOf("ValueType")) {

2099      // If the operator is a ValueType, then this must be "type cast" of a leaf

2100      // node.

2101      if (Dag->getNumArgs() != 1)

2102        error("Type cast only takes one operand!");

2103 

2104      TreePatternNode *New = ParseTreePattern(Dag->getArg(0), Dag->getArgName(0));

2105 

2106      // Apply the type cast.

2107      assert(New->getNumTypes() == 1 && "FIXME: Unhandled");

2108      New->UpdateNodeType(0, getValueType(Operator), *this);       <- v7.0删除

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

    New->UpdateNodeType(0, getValueTypeByHwMode(Operator, CGH), *this);

2109 

2110      if (!OpName.empty())

2111        error("ValueType cast should not have a name!");

2112      return New;

2113    }

2114 

2115    // Verify that this is something that makes sense for an operator.

2116    if (!Operator->isSubClassOf("PatFrag") &&            <- v7.0删除

  if (!Operator->isSubClassOf("PatFrags") &&          <- v7.0增加

2117        !Operator->isSubClassOf("SDNode") &&

2118        !Operator->isSubClassOf("Instruction") &&

2119        !Operator->isSubClassOf("SDNodeXForm") &&

2120        !Operator->isSubClassOf("Intrinsic") &&

2121        !Operator->isSubClassOf("ComplexPattern") &&

2122        Operator->getName() != "set" &&

2123        Operator->getName() != "implicit")

2124      error("Unrecognized node '" + Operator->getName() + "'!");

2125 

2126    //  Check to see if this is something that is illegal in an input pattern.

2127    if (isInputPattern) {

2128      if (Operator->isSubClassOf("Instruction") ||

2129          Operator->isSubClassOf("SDNodeXForm"))

2130        error("Cannot use '" + Operator->getName() + "' in an input pattern!");

2131    } else {

2132      if (Operator->isSubClassOf("Intrinsic"))

2133        error("Cannot use '" + Operator->getName() + "' in an output pattern!");

2134 

2135      if (Operator->isSubClassOf("SDNode") &&

2136          Operator->getName() != "imm" &&

2137          Operator->getName() != "fpimm" &&

2138          Operator->getName() != "tglobaltlsaddr" &&

2139          Operator->getName() != "tconstpool" &&

2140          Operator->getName() != "tjumptable" &&

2141          Operator->getName() != "tframeindex" &&

2142          Operator->getName() != "texternalsym" &&

2143          Operator->getName() != "tblockaddress" &&

2144          Operator->getName() != "tglobaladdr" &&

2145          Operator->getName() != "bb" &&

2146          Operator->getName() != "vt" &&

2147          Operator->getName() != "mcsym")

2148        error("Cannot use '" + Operator->getName() + "' in an output pattern!");

2149    }

PatFrag的匹配片段(Fragment)通常是一个dag值,Fragment的操作数也可以包含PatFrag(当然要满足一定的条件),因此ParseTreePattern()先递归处理Fragment的操作数。(v7.0补充: PatFrags派生定义对应TreePattern实例,其中的每个Fragments片段对应TreePatternNode实例,保存在对应TreePattern实例的Trees容器中。Fragments片段通常是dag,合法dag的操作数也将生成TreePatternNode实例,保存在父TreePatternNodeChildren容器里。具体细节参见下面的描述

如果要匹配的部分是一个SDNode或PatFrag(v7.0PatFrags),在2049行构建一个自己为操作符,没有操作数的匿名dag值(DagInit实例),然后新调用ParseTreePattern()。这个处理非常重要。DagInit生成的树节点不是叶子节点,即使它没有子节点。后面进行的内联与展开是不对叶子节点进行的。其他的DefInit(对应一个def定义)可以直接生成TreePatternNode叶子节点。但如果这是一个node(一个空def,参见TargetSelectionDAG.TD的310行),它必须具名(node:$name)。

类似的,UnsetInit(表示未初始化的值)、IntInit(TD整数常量)、BitsInit(TD比特值)都必须是具名的,而且BitsInit还必须是常量。不能匿名是因为TableGen需要通过名字将它们匹配到模式片段的操作数。它们都对应一个叶子TreePatternNode节点(v7.0使用std::make_shared< TreePatternNode>()来创建TreePatternNode实例,这是对原来TreePatternNode对象内存泄露的一个修正)。下面的构造函数用于创建TreePatternNode叶子节点:

349       TreePatternNode(Init *val, unsigned NumResults)    // leaf ctor

350         : Operator(nullptr), Val(val), TransformFn(nullptr) {

351         Types.resize(NumResults);

352       }

这里,NumResults为1,因为叶子节点只产生一个结果。

而如果要匹配的部分是一个dag。这个dag可以是一个PatFrag,还可能是上面2049行从SDNode与PatFrag生成的。

从这里的代码可以看出,Fragment所包含dag的操作符无外乎这些定义:ValueType,PatFrag,SDNode,Instruction,SDNodeXForm,Intrinsic,ComplexPattern,或者特殊节点set以及implicit。其中Instruction,SDNodeXForm不允许用于输入模式。至于OutPatFrag,SDNode还被进一步限定为imm,fpimm,tglobaltlsaddr,tconstpool,tjumptable,tframeindex,texternalsym,tblockaddress,tglobaladdr,bb,vt,mcsym之一。

在这中间,ValueType类型的操作符代表一个类型转换,必须有且只有一个操作数。那么对它的操作数调用ParseTreePattern()进行解析,在2108行把对应树节点的类型更新为这个ValueType代表类型。执行更新操作的TreePatternNode::UpdateNodeType()定义如下(CodeGenDAGPatterns.h):

486       bool UpdateNodeType(unsigned ResNo, MVT::SimpleValueType InTy,

487                           TreePattern &TP) {

488         return Types[ResNo].MergeInTypeInfo(EEVT::TypeSet(InTy, TP), TP);

489       }

V7.0则是调用了下面的函数。其中第二个参数是通过llvm::getValueTypeByHwMode()方法生成的,在这个上下文里,这个方法的实参Operator一定是ValueTypes的派生定义,生成的ValueTypeByHwMode实例会将Operator的类型关联到缺省硬件模式。

915   inline bool TreePatternNode::UpdateNodeType(unsigned ResNo,

916                                               ValueTypeByHwMode InTy,

917                                               TreePattern &TP) {

918     TypeSetByHwMode VTS(InTy);

919     TP.getInfer().expandOverloads(VTS);

920     return TP.getInfer().MergeInTypeInfo(Types[ResNo], VTS);

921   }

919行的getInfer()方法返回TreePattern的成员Infer,它是一个struct TypeInfer的实例。这个结构显然是用于类型推导的,其成员函数expandOverloads()将所谓的重载类型替换为对应的类型集合,并通过参数VTS返回。

732  void TypeInfer::expandOverloads(TypeSetByHwMode &VTS) {

733    ValidateOnExit _1(VTS, *this);

734    TypeSetByHwMode Legal = getLegalTypes();

735    bool HaveLegalDef = Legal.hasDefault();

736 

737    for (auto &I : VTS) {

738      unsigned M = I.first;

739      if (!Legal.hasMode(M) && !HaveLegalDef) {

740        TP.error("Invalid mode " + Twine(M));

741       return;

742     }

743     expandOverloads(I.second, Legal.get(M));

744   }

745 }

734行的成员函数getLegalTypes()获取所有合法类型,并关联到缺省硬件模式下:

796 TypeSetByHwMode TypeInfer::getLegalTypes() {

797   if (!LegalTypesCached) {

798     // Stuff all types from all modes into the default mode.

799     const TypeSetByHwMode &LTS = TP.getDAGPatterns().getLegalTypes();

800     for (const auto &I : LTS)

801        LegalCache.insert(I.second);

802      LegalTypesCached = true;

803    }

804    TypeSetByHwMode VTS;

805    VTS.getOrCreate(DefaultMode) = LegalCache;

806    return VTS;

807  }

799CodeGenDAGPatternsgetLegalTypes()方法返回其成员LegalVTSTypeSetByHwMode实例)。LegalCacheTypeInfer类型为TypeSetByHwMode::SetType(即MachineValueTypeSet)的成员800行的循环遍历LegalVTS底下类型为std::map<unsigned, MachineValueTypeSet>的容器,获取所有合法的类型(合法类型来自TD文件的定义,如ValueTypeByHwMode及其派生定义)。在801行调用MachineValueTypeSet这个版本的insert()方法:

97         MachineValueTypeSet &insert(const MachineValueTypeSet &S) {

98           for (unsigned i = 0; i != NumWords; ++i)

99             Words[i] |= S.Words[i];

101         return *this;

102       }

MachineValueTypeSet使用数组的比特位来记录类型。在805行将这些类型与缺省模式绑定。

TypeInfer::expandOverloads()743行调用的expandOverloads()是这个版本:

747 void TypeInfer::expandOverloads(TypeSetByHwMode::SetType &Out,

748                                 const TypeSetByHwMode::SetType &Legal) {

749   std::set<MVT> Ovs;

750   for (MVT T : Out) {

751     if (!T.isOverloaded())

752       continue;

753

754     Ovs.insert(T);

755     // MachineValueTypeSet allows iteration and erasing.

756     Out.erase(T);

757   }

758

759   for (MVT Ov : Ovs) {

760     switch (Ov.SimpleTy) {

761       case MVT::iPTRAny:

762         Out.insert(MVT::iPTR);

763         return;

764       case MVT::iAny:

765         for (MVT T : MVT::integer_valuetypes())

766           if (Legal.count(T))

767             Out.insert(T);

768         for (MVT T : MVT::integer_vector_valuetypes())

769           if (Legal.count(T))

770             Out.insert(T);

771          return;

772        case MVT::fAny:

773          for (MVT T : MVT::fp_valuetypes())

774            if (Legal.count(T))

775              Out.insert(T);

776          for (MVT T : MVT::fp_vector_valuetypes())

777            if (Legal.count(T))

778              Out.insert(T);

779          return;

780        case MVT::vAny:

781          for (MVT T : MVT::vector_valuetypes())

782            if (Legal.count(T))

783              Out.insert(T);

784          return;

785        case MVT::Any:

786          for (MVT T : MVT::all_valuetypes())

787            if (Legal.count(T))

788              Out.insert(T);

789          return;

790        default:

791          break;

792      }

793    }

794  }

750行循环查找所谓的重载类型:

388     bool isOverloaded() const {

389        return (SimpleTy==MVT::Any  ||

390                SimpleTy==MVT::iAny || SimpleTy==MVT::fAny ||

391                SimpleTy==MVT::vAny || SimpleTy==MVT::iPTRAny);

392      }

759行的大循环就是将Legal中存在的对应合法类型替换掉重载类型。765768773781786行循环的含义参考下面对SimpleValueType的说明。

UpdateNodeType()920行,MergeInTypeInfo()方法现在是TypeInfer的成员。参数Out是该TreePatternNode的结果类型,In就是指定硬件模式下可用的类型,MergeInTypeInfo()就是获取两者间的交集。

326  bool TypeInfer::MergeInTypeInfo(TypeSetByHwMode &Out,

327                                  const TypeSetByHwMode &In) {

328    ValidateOnExit _1(Out, *this);

329    In.validate();

330    if (In.empty() || Out == In || TP.hasError())

331      return false;

332    if (Out.empty()) {

333      Out = In;

334      return true;

335    }

336  

337    bool Changed = Out.constrain(In);

338    if (Changed && Out.empty())

339      TP.error("Type contradiction");

340  

341    return Changed;

342  }

329TypeSetByHwModevalidate()方法在不打开调试时是空函数。如果Out不是空,那么要取OutIn的交集,即337行的Constrain()方法:

112  bool TypeSetByHwMode::constrain(const TypeSetByHwMode &VTS) {

113    bool Changed = false;

114    if (hasDefault()) {

115      for (const auto &I : VTS) {

116        unsigned M = I.first;

117        if (M == DefaultMode || hasMode(M))

118          continue;

119        Map.insert({M, Map.at(DefaultMode)});

120        Changed = true;

121      }

122    }

123  

124    for (auto &I : *this) {

125      unsigned M = I.first;

126      SetType &S = I.second;

127      if (VTS.hasMode(M) || VTS.hasDefault()) {

128        Changed |= intersect(I.second, VTS.get(M));

129      } else if (!S.empty()) {

130        S.clear();

131        Changed = true;

132      }

133    }

134    return Changed;

135  }

如果Out里有缺省硬件模式,115行循环将VTS中所没有的Out硬件模式都关联到缺省模式对应的合法类型。124行循环对OUT的合法类型与VTS对应模式或缺省模式的合法类型求交集。求交集的方法是下面的TypeSetByHwMode::intersect()

253  bool TypeSetByHwMode::intersect(SetType &Out, const SetType &In) {

254    bool OutP = Out.count(MVT::iPTR), InP = In.count(MVT::iPTR);

255    auto Int = [&In](MVT T) -> bool { return !In.count(T); };

256  

257    if (OutP == InP)

258      return berase_if(Out, Int);

259  

260    // Compute the intersection of scalars separately to account for only

261    // one set containing iPTR.

262    // The itersection of iPTR with a set of integer scalar types that does not

263    // include iPTR will result in the most specific scalar type:

264    // - iPTR is more specific than any set with two elements or more

265    // - iPTR is less specific than any single integer scalar type.

266    // For example

267    // { iPTR } * { i32 }     -> { i32 }

268    // { iPTR } * { i32 i64 } -> { iPTR }

269    // and

270    // { iPTR i32 } * { i32 }          -> { i32 }

271    // { iPTR i32 } * { i32 i64 }      -> { i32 i64 }

272    // { iPTR i32 } * { i32 i64 i128 } -> { iPTR i32 }

273  

274    // Compute the difference between the two sets in such a way that the

275    // iPTR is in the set that is being subtracted. This is to see if there

276    // are any extra scalars in the set without iPTR that are not in the

277    // set containing iPTR. Then the iPTR could be considered a "wildcard"

278    // matching these scalars. If there is only one such scalar, it would

279    // replace the iPTR, if there are more, the iPTR would be retained.

280    SetType Diff;

281    if (InP) {

282      Diff = Out;

283      berase_if(Diff, [&In](MVT T) { return In.count(T); });

284      // Pre-remove these elements and rely only on InP/OutP to determine

285      // whether a change has been made.

286      berase_if(Out, [&Diff](MVT T) { return Diff.count(T); });

287    } else {

288      Diff = In;

289      berase_if(Diff, [&Out](MVT T) { return Out.count(T); });

290      Out.erase(MVT::iPTR);

291    }

292  

293    // The actual intersection.

294    bool Changed = berase_if(Out, Int);

295    unsigned NumD = Diff.size();

296    if (NumD == 0)

297      return Changed;

298  

299    if (NumD == 1) {

300      Out.insert(*Diff.begin());

301      // This is a change only if Out was the one with iPTR (which is now

302      // being replaced).

303      Changed |= OutP;

304    } else {

305      // Multiple elements from Out are now replaced with iPTR.

306      Out.insert(MVT::iPTR);

307      Changed |= !OutP;

308    }

309    return Changed;

310  }

TypeSetByHwModeSetTypeMachineValueTypeSet,因此254行的count()方法就是在MachineValueTypeSet里查找MVT::iPTR是否存在。如果在OUTVTS中都有MVT::iPTR255行的兰布达表达式将用作方法berase_if()的第二个参数Predicate。因此这时berase_if()的作用就是,如果OUT指定模式中的合法类型没有出现在VTS的对应模式里,从OUT中把这些类型删除。

47  template <typename Predicate>

48  static bool berase_if(MachineValueTypeSet &S, Predicate P) {

49    bool Erased = false;

50    // It is ok to iterate over MachineValueTypeSet and remove elements from it

51    // at the same time.

52    for (MVT T : S) {

53      if (!P(T))

54        continue;

55      Erased = true;

56      S.erase(T);

57    }

58    return Erased;

59  }

如果只有一方有MVT::iPTR260行的注释谈到了如何处理。如果除了iPTR之外,两个集合间只相差一个标量,那么该标量作为iPTR的替代;如果两个集合间相差多个标量,那么iPTR作为这些标量的通配。具体参考266~279行的注释。

与下面3.6.0的实现比较,通过引入硬件模式的概念,v7.0这部分的实现干净利落不少,LLVM的重构确实是不遗余力的。

MVT::SimpleValueType是一个枚举类型,它与ValueType中Value域的值一一对应。EEVT::TypeSet表示类型的集合,它在内部维护一个SmallVector<MVT::SimpleValueType, 4>类型的容器TypeVec。488行的Types是一个SmallVector<EEVT::TypeSet, 1>容器,由其MergeInTypeInfo()方法执行类型推导。

165     bool EEVT::TypeSet::MergeInTypeInfo(const EEVT::TypeSet &InVT, TreePattern &TP){

166       if (InVT.isCompletelyUnknown() || *this == InVT || TP.hasError())

167         return false;

168    

169       if (isCompletelyUnknown()) {

170         *this = InVT;

171         return true;

172       }

173    

174       assert(TypeVec.size() >= 1 && InVT.TypeVec.size() >= 1 && "No unknowns");

175    

176       // Handle the abstract cases, seeing if we can resolve them better.

177       switch (TypeVec[0]) {

178       default: break;

179       case MVT::iPTR:

180       case MVT::iPTRAny:

181         if (InVT.hasIntegerTypes()) {

182           EEVT::TypeSet InCopy(InVT);

183           InCopy.EnforceInteger(TP);

184           InCopy.EnforceScalar(TP);

185    

186           if (InCopy.isConcrete()) {

187             // If the RHS has one integer type, upgrade iPTR to i32.

188             TypeVec[0] = InVT.TypeVec[0];

189             return true;

190           }

191    

192           // If the input has multiple scalar integers, this doesn't add any info.

193           if (!InCopy.isCompletelyUnknown())

194             return false;

195         }

196         break;

197       }

198    

199       // If the input constraint is iAny/iPTR and this is an integer type list,

200      // remove non-integer types from the list.

201       if ((InVT.TypeVec[0] == MVT::iPTR || InVT.TypeVec[0] == MVT::iPTRAny) &&

202           hasIntegerTypes()) {

203         bool MadeChange = EnforceInteger(TP);

204    

205         // If we're merging in iPTR/iPTRAny and the node currently has a list of

206         // multiple different integer types, replace them with a single iPTR.

207         if ((InVT.TypeVec[0] == MVT::iPTR || InVT.TypeVec[0] == MVT::iPTRAny) &&

208             TypeVec.size() != 1) {

209           TypeVec.resize(1);

210           TypeVec[0] = InVT.TypeVec[0];

211           MadeChange = true;

212         }

213    

214         return MadeChange;

215       }

216    

217       // If this is a type list and the RHS is a typelist as well, eliminate entries

218       // from this list that aren't in the other one.

219       bool MadeChange = false;

220       TypeSet InputSet(*this);

221    

222       for (unsigned i = 0; i != TypeVec.size(); ++i) {

223         bool InInVT = false;

224         for (unsigned j = 0, e = InVT.TypeVec.size(); j != e; ++j)

225           if (TypeVec[i] == InVT.TypeVec[j]) {

226             InInVT = true;

227             break;

228           }

229    

230         if (InInVT) continue;

231         TypeVec.erase(TypeVec.begin()+i--);

232         MadeChange = true;

233       }

234    

235       // If we removed all of our types, we have a type contradiction.

236       if (!TypeVec.empty())

237         return MadeChange;

238    

239       // FIXME: Really want an SMLoc here!

240       TP.error("Type inference contradiction found, merging '" +

241                InVT.getName() + "' into '" + InputSet.getName() + "'");

242       return false;

243     }

基本上MergeInTypeInfo()只干这几件事:

如果原有的是指针类型,而新发现的类型包含了整数类型,183与184行的EnforceInteger()与EnforceScalar()会分别滤除新发现类型中包含的浮点类型与向量类型,如果此时还有整形,就以这个类型来替换原有的指针类型。

如果原有的是整形,而新发现的类型是指针类型,203行的EnforceInteger()过滤掉浮点类型后,如果剩余的整形有多个,就替换为指针类型,否则维持原样。

如果不是上述情形,将原有类型集中不在新发现类型集里的类型删除,删除后的类型集不能是空,否则就代表类型冲突。

这段逻辑就是TableGen进行类型推导的依据。这样类型集将会越来越小,最终能确定一个具体的类型。枚举类型MVT::SimpleValueType的定义有助于理解这段代码:

31           enum SimpleValueType {

32             // INVALID_SIMPLE_VALUE_TYPE - Simple value types less than zero are

33             // considered extended value types.

34             INVALID_SIMPLE_VALUE_TYPE = -1,

35      

36             // If you change this numbering, you must change the values in

37             // ValueTypes.td as well!

38             Other          =   0,   // This is a non-standard value

39             i1             =   1,   // This is a 1 bit integer value

40             i8             =   2,   // This is an 8 bit integer value

41             i16            =   3,   // This is a 16 bit integer value

42             i32            =   4,   // This is a 32 bit integer value

43             i64            =   5,   // This is a 64 bit integer value

44             i128           =   6,   // This is a 128 bit integer value

45      

46             FIRST_INTEGER_VALUETYPE = i1,  // ------+-------这个区间满足isInteger

47             LAST_INTEGER_VALUETYPE  = i128, // ----+

48      

49             f16            =   7,   // This is a 16 bit floating point value

50             f32            =   8,   // This is a 32 bit floating point value

51             f64            =   9,   // This is a 64 bit floating point value

52             f80            =  10,   // This is a 80 bit floating point value

53             f128           =  11,   // This is a 128 bit floating point value

54             ppcf128        =  12,   // This is a PPC 128-bit floating point value

55      

56             FIRST_FP_VALUETYPE = f16,  // 这个区间还同时满足isFloatingPoint

57             LAST_FP_VALUETYPE  = ppcf128,  // >= ppcf128 + iPTR + iPTRAny满足 isConcrete

58      

59             v2i1           =  13,   //  2 x i1

60             v4i1           =  14,   //  4 x i1

61             v8i1           =  15,   //  8 x i1

62             v16i1          =  16,   // 16 x i1

63             v32i1          =  17,   // 32 x i1

64             v64i1          =  18,   // 64 x i1

65      

66             v1i8           =  19,   //  1 x i8

67             v2i8           =  20,   //  2 x i8

68             v4i8           =  21,   //  4 x i8

69             v8i8           =  22,   //  8 x i8

70             v16i8          =  23,   // 16 x i8

71             v32i8          =  24,   // 32 x i8

72             v64i8          =  25,   // 64 x i8

73             v1i16          =  26,   //  1 x i16

74             v2i16          =  27,   //  2 x i16

75             v4i16          =  28,   //  4 x i16

76             v8i16          =  29,   //  8 x i16

77             v16i16         =  30,   // 16 x i16

78             v32i16         =  31,   // 32 x i16

79             v1i32          =  32,   //  1 x i32

80             v2i32          =  33,   //  2 x i32

81             v4i32          =  34,   //  4 x i32

82             v8i32          =  35,   //  8 x i32

83             v16i32         =  36,   // 16 x i32

84             v1i64          =  37,   //  1 x i64

85             v2i64          =  38,   //  2 x i64

86             v4i64          =  39,   //  4 x i64

87             v8i64          =  40,   //  8 x i64

88             v16i64         =  41,   // 16 x i64

89             v1i128         =  42,   //  1 x i128

90            

91             FIRST_INTEGER_VECTOR_VALUETYPE = v2i1, // --------+---- 这个区间满足isInteger

92             LAST_INTEGER_VECTOR_VALUETYPE = v1i128, // ------+

93      

94             v2f16          =  43,   //  2 x f16

95             v4f16          =  44,   //  4 x f16

96             v8f16          =  45,   //  8 x f16

97             v1f32          =  46,   //  1 x f32

98             v2f32          =  47,   //  2 x f32

99             v4f32          =  48,   //  4 x f32

100           v8f32          =  49,   //  8 x f32

101           v16f32         =  50,   // 16 x f32

102           v1f64          =  51,   //  1 x f64

103           v2f64          =  52,   //  2 x f64

104           v4f64          =  53,   //  4 x f64

105           v8f64          =  54,   //  8 x f64

106    

107           FIRST_FP_VECTOR_VALUETYPE = v2f16, // --------+----这个区间满足isFloatingPoint

108           LAST_FP_VECTOR_VALUETYPE = v8f64, // ---------+

109    

110           FIRST_VECTOR_VALUETYPE = v2i1, // ---- -+---- 这个区间满足isVector

111           LAST_VECTOR_VALUETYPE  = v8f64, // ----+

112    

113           x86mmx         =  55,   // This is an X86 MMX value

114    

115           Glue           =  56,   // This glues nodes together during pre-RA sched

116    

117           isVoid         =  57,   // This has no value

118    

119           Untyped        =  58,   // This value takes a register, but has

120                                   // unspecified type.  The register class

121                                   // will be determined by the opcode.

122    

123           FIRST_VALUETYPE = 0,    // This is always the beginning of the list. ----+

124           LAST_VALUETYPE =  59,  // This always remains at the end of the list.  +--这个区间满足isValid

125    

126           // This is the current maximum for LAST_VALUETYPE.

127           // MVT::MAX_ALLOWED_VALUETYPE is used for asserts and to size bit vectors

128           // This value must be a multiple of 32.

129           MAX_ALLOWED_VALUETYPE = 64,

130    

131           // Metadata - This is MDNode or MDString.

132           Metadata       = 250,

133    

134           // iPTRAny - An int value the size of the pointer of the current

135           // target to any address space. This must only be used internal to

136           // tblgen. Other than for overloading, we treat iPTRAny the same as iPTR.

137           iPTRAny        = 251,

138    

139           // vAny - A vector with any length and element size. This is used

140           // for intrinsics that have overloadings based on vector types.

141           // This is only for tblgen's consumption!

142           vAny           = 252,

143    

144           // fAny - Any floating-point or vector floating-point value. This is used

145           // for intrinsics that have overloadings based on floating-point types.

146           // This is only for tblgen's consumption!

147           fAny           = 253,

148    

149           // iAny - An integer or vector integer value of any bit width. This is

150           // used for intrinsics that have overloadings based on integer bit widths.

151           // This is only for tblgen's consumption!

152           iAny           = 254,

153    

154           // iPTR - An int value the size of the pointer of the current

155           // target.  This should only be used internal to tblgen!

156           iPTR           = 255,

157    

158           // Any - Any type. This is used for intrinsics that have overloadings.

159           // This is only for tblgen's consumption!

160           Any            = 256

161         };

2116~2149行进行有效性检查。对于输入模式的派生定义(除了OutPatFrag派生定义,Pattern定义的ResultInstrs也视为输出模式),isInputPattern就是true。输入模式片段不允许使用Instruction和SDNodeXForm作为操作符(因为这两者分别代表结果和对结果的修改)。对于输出模式,限制就更多了,tglobaltlsaddr~tglobaladdr(2138~2144行)表示需要目标机器处理的特定于目标机器的地址,而bb与vt分别代表基本块与ValueType,它们都不能用作模式的操作符。

通过了检查后,在2155行对dag的每个操作数递归调用ParseTreePattern(),生成的树节点(子树)保存在临时的Children容器内。这个容器里的内容会在后面调用TreePatternNode非叶子节点构造函数时,保存在父TreePatternNode节点的Children容器内。

TreePattern::ParseTreePattern(续)

2151    std::vector<TreePatternNode*> Children;

2152 

2153    // Parse all the operands.

2154    for (unsigned i = 0, e = Dag->getNumArgs(); i != e; ++i)

2155      Children.push_back(ParseTreePattern(Dag->getArg(i), Dag->getArgName(i)));

  // Get the actual number of results before Operator is converted to an intrinsic <- v7.0增加

  // node (which is hard-coded to have either zero or one result).

  unsigned NumResults = GetNumNodeResults(Operator, CDP);

 

2157    // If the operator is an intrinsic, then this is just syntactic sugar for for

2158    // (intrinsic_* <number>, ..children..).  Pick the right intrinsic node, and

2159    // convert the intrinsic name to a number.

2160    if (Operator->isSubClassOf("Intrinsic")) {

2161      const CodeGenIntrinsic &Int = getDAGPatterns().getIntrinsic(Operator);

2162      unsigned IID = getDAGPatterns().getIntrinsicID(Operator)+1;

2163 

2164      // If this intrinsic returns void, it must have side-effects and thus a

2165      // chain.

2166      if (Int.IS.RetVTs.empty())

2167        Operator = getDAGPatterns().get_intrinsic_void_sdnode();

2168      else if (Int.ModRef != CodeGenIntrinsic::NoMem)

2169        // Has side-effects, requires chain.

2170        Operator = getDAGPatterns().get_intrinsic_w_chain_sdnode();

2171      else // Otherwise, no chain.

2172        Operator = getDAGPatterns().get_intrinsic_wo_chain_sdnode();

2173 

2174      TreePatternNode *IIDNode = new TreePatternNode(IntInit::get(IID), 1);   <- v7.0删除

2175      Children.insert(Children.begin(), IIDNode);

    Children.insert(Children.begin(),                        <- v7.0增加

                    std::make_shared<TreePatternNode>(IntInit::get(IID), 1));

2176    }

2177 

2178    if (Operator->isSubClassOf("ComplexPattern")) {

2179      for (unsigned i = 0; i < Children.size(); ++i) {

2180        TreePatternNode *Child = Children[i];

2181 

2182        if (Child->getName().empty())

2183          error("All arguments to a ComplexPattern must be named");

2184 

2185        // Check that the ComplexPattern uses are consistent: "(MY_PAT $a, $b)"

2186        // and "(MY_PAT $b, $a)" should not be allowed in the same pattern;

2187        // neither should "(MY_PAT_1 $a, $b)" and "(MY_PAT_2 $a, $b)".

2188        auto OperandId = std::make_pair(Operator, i);

2189        auto PrevOp = ComplexPatternOperands.find(Child->getName());

2190        if (PrevOp != ComplexPatternOperands.end()) {

2191          if (PrevOp->getValue() != OperandId)

2192            error("All ComplexPattern operands must appear consistently: "

2193                  "in the same order in just one ComplexPattern instance.");

2194        } else

2195          ComplexPatternOperands[Child->getName()] = OperandId;

2196      }

2197    }

2198 

2199    unsigned NumResults = GetNumNodeResults(Operator, CDP);       <- v7.0删除

2200    TreePatternNode *Result = new TreePatternNode(Operator, Children, NumResults);

  TreePatternNodePtr Result =                      <- v7.0增加

      std::make_shared<TreePatternNode>(Operator, std::move(Children),

                                        NumResults);

2201    Result->setName(OpName);

2202 

2203    if (!Dag->getName().empty()) {

2204      assert(Result->getName().empty());

2205      Result->setName(Dag->getName());

2206    }

2207    return Result;

2208  }

另外,有两种操作符还需要额外的处理。

第一个是固有函数。前面在CodeGenDAGPatterns构造函数的一开始就通过LoadIntrinsics()方法将TD文件里定义的固有函数翻译为了CodeGenIntrinsic对象,因此在2161与2162行分别获取指定固有函数的CodeGenIntrinsic对象与ID。接着根据这个固有函数的特点,使用intrinsic_void_sdnode,intrinsic_w_chain_sdnode或intrinsic_wo_chain_sdnode来封装它。注意,容器Children里已经保存了固有函数参数的模式树节点(2155行的深度优先递归),在2175行将ID插入为第一个操作数,构造成这三个类型所需的形式。

再一个就是ComplexPattern操作符。2189行的ComplexPatternOperands是TreePattern的容器,只由这个模式里的ComplexPattern对象共享。它的类型是StringMap<std::pair<Record*, unsigned>>,StringMap是LLVM将map对string的优化容器。在一个模式中对ComplexPattern的使用(它(们)作为dag值的操作符)有这些限制:1)援引同一个ComplexPattern时,操作数必须具名且一致,2)援引不同的ComplexPattern时,操作数必须具名且不相同。

最后为这个dag值的操作符创建它所表示的模式树的根节点。首先需要确定它所代表操作返回的结果数(v7.0GetNumNodeResults()提前了,原因在2156行后的注释提及)。

1168  static unsigned GetNumNodeResults(Record *Operator, CodeGenDAGPatterns &CDP) {

1169    if (Operator->getName() == "set" ||

1170        Operator->getName() == "implicit")

1171      return 0;  // All return nothing.

1172 

1173    if (Operator->isSubClassOf("Intrinsic"))

1174      return CDP.getIntrinsic(Operator).IS.RetVTs.size();

1175 

1176    if (Operator->isSubClassOf("SDNode"))

1177      return CDP.getSDNodeInfo(Operator).getNumResults();

1178 

1179    if (Operator->isSubClassOf("PatFrag")) {           <- v7.0删除

1180      // If we've already parsed this pattern fragment, get it.  Otherwise, handle

1181      // the forward reference case where one pattern fragment references another

1182      // before it is processed.

1183      if (TreePattern *PFRec = CDP.getPatternFragmentIfRead(Operator))

1184        return PFRec->getOnlyTree()->getNumTypes();

1185 

1186      // Get the result tree.

1187      DagInit *Tree = Operator->getValueAsDag("Fragment");

1188      Record *Op = nullptr;

1189      if (Tree)

1190        if (DefInit *DI = dyn_cast<DefInit>(Tree->getOperator()))

1191          Op = DI->getDef();

1192      assert(Op && "Invalid Fragment");

1193      return GetNumNodeResults(Op, CDP);

1194    }

  if (Operator->isSubClassOf("PatFrags")) {   <- v7.0增加

    // If we've already parsed this pattern fragment, get it.  Otherwise, handle

    // the forward reference case where one pattern fragment references another

    // before it is processed.

    if (TreePattern *PFRec = CDP.getPatternFragmentIfRead(Operator)) {

      // The number of results of a fragment with alternative records is the

      // maximum number of results across all alternatives.

      unsigned NumResults = 0;

      for (auto T : PFRec->getTrees())

        NumResults = std::max(NumResults, T->getNumTypes());

      return NumResults;

    }

 

    ListInit *LI = Operator->getValueAsListInit("Fragments");

    assert(LI && "Invalid Fragment");

    unsigned NumResults = 0;

    for (Init *I : LI->getValues()) {

      Record *Op = nullptr;

      if (DagInit *Dag = dyn_cast<DagInit>(I))

        if (DefInit *DI = dyn_cast<DefInit>(Dag->getOperator()))

          Op = DI->getDef();

      assert(Op && "Invalid Fragment");

      NumResults = std::max(NumResults, GetNumNodeResults(Op, CDP));

    }

    return NumResults;

  }

1196    if (Operator->isSubClassOf("Instruction")) {

1197      CodeGenInstruction &InstInfo = CDP.getTargetInfo().getInstruction(Operator);

1198 

1199      unsigned NumDefsToAdd = InstInfo.Operands.NumDefs;

1200 

1201      // Subtract any defaulted outputs.

1202      for (unsigned i = 0; i != InstInfo.Operands.NumDefs; ++i) {

1203        Record *OperandNode = InstInfo.Operands[i].Rec;

1204 

1205        if (OperandNode->isSubClassOf("OperandWithDefaultOps") &&

1206           !CDP.getDefaultOperand(OperandNode).DefaultOps.empty())

1207          --NumDefsToAdd;

1208      }

1209 

1210      // Add on one implicit def if it has a resolvable type.

1211      if (InstInfo.HasOneImplicitDefWithKnownVT(CDP.getTargetInfo()) !=MVT::Other)

1212        ++NumDefsToAdd;

1213      return NumDefsToAdd;

1214    }

1215 

1216    if (Operator->isSubClassOf("SDNodeXForm"))

1217      return 1;  // FIXME: Generalize SDNodeXForm

1218 

1219    if (Operator->isSubClassOf("ValueType"))

1220      return 1;  // A type-cast of one result.

1221 

1222    if (Operator->isSubClassOf("ComplexPattern"))

1223      return 1;

1224 

1225    Operator->dump();

1226   PrintFatalError("Unhandled node in GetNumNodeResults");

1227  }

因为v7.0增加了PatFrags作为PatFrag的基类,因此GetNumNodeResults做了相应的调整,但基本原则是相同的。

2200行的TreePatternNode构造函数创建了一个非叶子模式树节点:

344       TreePatternNode(Record *Op, const std::vector<TreePatternNode*> &Ch,

345                       unsigned NumResults)

346         : Operator(Op), Val(nullptr), TransformFn(nullptr), Children(Ch) {

347         Types.resize(NumResults);

348       }

这个生成的节点返回后保存在TreePattern的容器Trees里。

在ParsePatternFragments()的2995行,TreePattern::getArgList()返回PatFrag(v7.0PatFrags,下同)的输入参数。这些参数是在TreePattern::ParseTreePattern()的2058行(node:$name)及2070行(UnsetInit)加入的。在2446行获取PatFrag定义的Operands域,这是一个dag值。在2447行获取其操作符,操作符只能是ops、ins与outs。2458行循环遍历这个dag值的操作数(模式的参数操作数),确认对这个PatFrag而言,在其Operands与Fragment域中出现的参数是相同的。

接着,为这个PatFrag产生谓词对象TreePredicateFn,它可根据这个PatFrag定义的PredicateCode与ImmediateCode域给出判断代码。这两个域是不能同时为空的。如果两者之一为空,这个谓词就视为总是真的。最后处理PatFrag定义中对输出进行修改的OperandTransform域(SDNodeXForm派生定义)。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值