LLVM学习笔记(21)

3.4.2.6. Pattern的处理

我们已经知道Pattern定义可以将通用的IR指令表示映射为特定于目标机器的指令(对目标机器不同的型号,可以映射到这些型号特有的、更高效的指令)。因此对指令选择,Pattern定义是有益的补充。因为Pattern定义会援引指令,因此需要在解析完所有的指令定义后才开始处理。

3386  void CodeGenDAGPatterns::ParsePatterns() {

3387    std::vector<Record*> Patterns = Records.getAllDerivedDefinitions("Pattern");

3388 

3389    for (unsigned i = 0, e = Patterns.size(); i != e; ++i) {

3390      Record *CurPattern = Patterns[i];

3391      DagInit *Tree = CurPattern->getValueAsDag("PatternToMatch");

3392 

3393      // If the pattern references the null_frag, there's nothing to do.

3394      if (hasNullFragReference(Tree))

3395        continue;

3396 

3397      TreePattern *Pattern = new TreePattern(CurPattern, Tree, true, *this);

3398 

3399      // Inline pattern fragments into it.

3400      Pattern->InlinePatternFragments();

3401 

3402      ListInit *LI = CurPattern->getValueAsListInit("ResultInstrs");

3403      if (LI->empty()) continue// no pattern.

3404 

3405      // Parse the instruction.

3406      TreePattern Result(CurPattern, LI, false, *this);

3407 

3408      // Inline pattern fragments into it.

3409      Result.InlinePatternFragments();

3410 

3411      if (Result.getNumTrees() != 1)

3412        Result.error("Cannot handle instructions producing instructions "

3413                     "with temporaries yet!");

3414 

3415      bool IterateInference;

3416      bool InferredAllPatternTypes, InferredAllResultTypes;

3417      do {

3418        // Infer as many types as possible.  If we cannot infer all of them, we

3419        // can never do anything with this pattern: report it to the user.

3420        InferredAllPatternTypes =

3421          Pattern->InferAllTypes(&Pattern->getNamedNodesMap());

3422 

3423        // Infer as many types as possible.  If we cannot infer all of them, we

3424        // can never do anything with this pattern: report it to the user.

3425        InferredAllResultTypes =

3426            Result.InferAllTypes(&Pattern->getNamedNodesMap());

3427 

3428        IterateInference = false;

3429 

3430        // Apply the type of the result to the source pattern.  This helps us

3431        // resolve cases where the input type is known to be a pointer type (which

3432        // is considered resolved), but the result knows it needs to be 32- or

3433        // 64-bits.  Infer the other way for good measure.

3434        for (unsigned i = 0, e = std::min(Result.getTree(0)->getNumTypes(),

3435                                          Pattern->getTree(0)->getNumTypes());

3436             i != e; ++i) {

3437          IterateInference = Pattern->getTree(0)->UpdateNodeType(

3438              i, Result.getTree(0)->getExtType(i), Result);

3439          IterateInference |= Result.getTree(0)->UpdateNodeType(

3440              i, Pattern->getTree(0)->getExtType(i), Result);

3441        }

3442 

3443        // If our iteration has converged and the input pattern's types are fully

3444        // resolved but the result pattern is not fully resolved, we may have a

3445        // situation where we have two instructions in the result pattern and

3446        // the instructions require a common register class, but don't care about

3447        // what actual MVT is used.  This is actually a bug in our modelling:

3448        // output patterns should have register classes, not MVTs.

3449        //

3450        // In any case, to handle this, we just go through and disambiguate some

3451        // arbitrary types to the result pattern's nodes.

3452        if (!IterateInference && InferredAllPatternTypes &&

3453            !InferredAllResultTypes)

3454          IterateInference =

3455              ForceArbitraryInstResultType(Result.getTree(0), Result);

3456      } while (IterateInference);

3457 

3458      // Verify that we inferred enough types that we can do something with the

3459      // pattern and result.  If these fire the user has to add type casts.

3460      if (!InferredAllPatternTypes)

3461        Pattern->error("Could not infer all types in pattern!");

3462      if (!InferredAllResultTypes) {

3463        Pattern->dump();

3464        Result.error("Could not infer all types in pattern result!");

3465      }

3466 

3467      // Validate that the input pattern is correct.

3468      std::map<std::string, TreePatternNode*> InstInputs;

3469      std::map<std::string, TreePatternNode*> InstResults;

3470      std::vector<Record*> InstImpResults;

3471      for (unsigned j = 0, ee = Pattern->getNumTrees(); j != ee; ++j)

3472        FindPatternInputsAndOutputs(Pattern, Pattern->getTree(j),

3473                                    InstInputs, InstResults,

3474                                    InstImpResults);

3475 

3476      // Promote the xform function to be an explicit node if set.

3477      TreePatternNode *DstPattern = Result.getOnlyTree();

3478      std::vector<TreePatternNode*> ResultNodeOperands;

3479      for (unsigned ii = 0, ee = DstPattern->getNumChildren(); ii != ee; ++ii) {

3480        TreePatternNode *OpNode = DstPattern->getChild(ii);

3481        if (Record *Xform = OpNode->getTransformFn()) {

3482          OpNode->setTransformFn(nullptr);

3483          std::vector<TreePatternNode*> Children;

3484          Children.push_back(OpNode);

3485          OpNode = new TreePatternNode(Xform, Children, OpNode->getNumTypes());

3486        }

3487        ResultNodeOperands.push_back(OpNode);

3488      }

3489      DstPattern = Result.getOnlyTree();

3490      if (!DstPattern->isLeaf())

3491        DstPattern = new TreePatternNode(DstPattern->getOperator(),

3492                                         ResultNodeOperands,

3493                                         DstPattern->getNumTypes());

3494 

3495      for (unsigned i = 0, e = Result.getOnlyTree()->getNumTypes(); i != e; ++i)

3496        DstPattern->setType(i, Result.getOnlyTree()->getExtType(i));

3497 

3498      TreePattern Temp(Result.getRecord(), DstPattern, false, *this);

3499      Temp.InferAllTypes();

3500 

3501 

3502      AddPatternToMatch(Pattern,

3503                      PatternToMatch(CurPattern,

3504                                     CurPattern->getValueAsListInit("Predicates"),

3505                                     Pattern->getTree(0),

3506                                     Temp.getOnlyTree(), InstImpResults,

3507                                     CurPattern->getValueAsInt("AddedComplexity"),

3508                                     CurPattern->getID()));

3509    }

3510  }

上面根据Pattern定义的PatternToMatch与ResultInstrs,分别建立了两棵TreePattern树,Pattern与Result,注意Pattern被视为输入模板,Result则是输出目标,因此它们的处理与内联展开是有区别的。接着在3417行循环里不停地进行类型推导迭代,直到不再发生变化。

其中,3455行的ForceArbitraryInstResultType()尝试尽可能地确定Result包含的返回类型。

3360 static bool ForceArbitraryInstResultType(TreePatternNode *N, TreePattern &TP) {

3361    if (N->isLeaf())

3362      return false;

3363 

3364    // Analyze children.

3365    for (unsigned i = 0, e = N->getNumChildren(); i != e; ++i)

3366      if (ForceArbitraryInstResultType(N->getChild(i), TP))

3367        return true;

3368 

3369    if (!N->getOperator()->isSubClassOf("Instruction"))

3370      return false;

3371 

3372    // If this type is already concrete or completely unknown we can't do

3373    // anything.

3374    for (unsigned i = 0, e = N->getNumTypes(); i != e; ++i) {

3375      if (N->getExtType(i).isCompletelyUnknown() || N->getExtType(i).isConcrete())

3376        continue;

3377 

3378      // Otherwise, force its type to the first possibility (an arbitrary choice).

3379      if (N->getExtType(i).MergeInTypeInfo(N->getExtType(i).getTypeList()[0], TP))

3380        return true;

3381    }

3382 

3383    return false;

3384  }

在3379行,如果指定的返回类型既不是确定,又不是完全未知,就将它尽可能向第一个类型靠拢。因为只有所有的类型都能推导出来时InferAllTypes()才返回true,因此在3468行以下类型都是已知的。接下来在Pattern中确定输入操作数、结果及隐含结果。而Result则用于表示指令的结果。最后生成PatternToMatch实例。这些操作都与对Instruction的处理类似。

V7.0的处理

V7.0版本的CodeGenDAGPatterns::ParsePatterns()定义如下:

4061  void CodeGenDAGPatterns::ParsePatterns() {

4062    std::vector<Record*> Patterns = Records.getAllDerivedDefinitions("Pattern");

4063 

4064    for (Record *CurPattern : Patterns) {

4065      DagInit *Tree = CurPattern->getValueAsDag("PatternToMatch");

4066 

4067      // If the pattern references the null_frag, there's nothing to do.

4068      if (hasNullFragReference(Tree))

4069        continue;

4070 

4071      TreePattern Pattern(CurPattern, Tree, true, *this);

4072 

4073      ListInit *LI = CurPattern->getValueAsListInit("ResultInstrs");

4074      if (LI->empty()) continue// no pattern.

4075 

4076      // Parse the instruction.

4077      TreePattern Result(CurPattern, LI, false, *this);

4078 

4079      if (Result.getNumTrees() != 1)

4080        Result.error("Cannot handle instructions producing instructions "

4081                     "with temporaries yet!");

4082 

4083      // Validate that the input pattern is correct.

4084      std::map<std::string, TreePatternNodePtr> InstInputs;

4085      std::map<std::string, TreePatternNodePtr> InstResults;

4086      std::vector<Record*> InstImpResults;

4087      for (unsigned j = 0, ee = Pattern.getNumTrees(); j != ee; ++j)

4088        FindPatternInputsAndOutputs(Pattern, Pattern.getTree(j), InstInputs,

4089                                    InstResults, InstImpResults);

4090 

4091      ParseOnePattern(CurPattern, Pattern, Result, InstImpResults);

4092    }

4093  }

重构后结构清晰了很多。

3​​​.4.2.7. 展开基于硬件模式的类型(v7.0

前面我们已经对指令生成了PatternToMatch对象,但是我们没有考虑指令的结果类型可能与硬件模式相关。我们需要为每个相关硬件模式构建一个PatternToMatch实例,以及对应的选择谓词。这就是下面的CodeGenDAGPatterns::ExpandHwModeBasedTypes()方法要做的事情。

4104  void CodeGenDAGPatterns::ExpandHwModeBasedTypes() {

4105    const CodeGenHwModes &CGH = getTargetInfo().getHwModes();

4106    std::map<unsigned,std::vector<Predicate>> ModeChecks;

4107    std::vector<PatternToMatch> Copy = PatternsToMatch;

4108    PatternsToMatch.clear();

4109 

4110    auto AppendPattern = [this, &ModeChecks](PatternToMatch &P, unsigned Mode) {

4111      TreePatternNodePtr NewSrc = P.SrcPattern->clone();

4112      TreePatternNodePtr NewDst = P.DstPattern->clone();

4113      if (!NewSrc->setDefaultMode(Mode) || !NewDst->setDefaultMode(Mode)) {

4114        return;

4115      }

4116 

4117      std::vector<Predicate> Preds = P.Predicates;

4118     const std::vector<Predicate> &MC = ModeChecks[Mode];

4119      Preds.insert(Preds.end(), MC.begin(), MC.end());

4120     PatternsToMatch.emplace_back(P.getSrcRecord(), Preds, std::move(NewSrc),

4121                                   std::move(NewDst), P.getDstRegs(),

4122                                   P.getAddedComplexity(), Record::getNewUID(),

4123                                   Mode);

4124    };

4125 

4126    for (PatternToMatch &P : Copy) {

4127      TreePatternNodePtr SrcP = nullptr, DstP = nullptr;

4128      if (P.SrcPattern->hasProperTypeByHwMode())

4129        SrcP = P.SrcPattern;

4130      if (P.DstPattern->hasProperTypeByHwMode())

4131        DstP = P.DstPattern;

4132      if (!SrcP && !DstP) {

4133        PatternsToMatch.push_back(P);

4134        continue;

4135      }

4136 

4137      std::set<unsigned> Modes;

4138      if (SrcP)

4139        collectModes(Modes, SrcP.get());

4140      if (DstP)

4141        collectModes(Modes, DstP.get());

4142 

4143      // The predicate for the default mode needs to be constructed for each

4144      // pattern separately.

4145      // Since not all modes must be present in each pattern, if a mode m is

4146      // absent, then there is no point in constructing a check for m. If such

4147      // a check was created, it would be equivalent to checking the default

4148      // mode, except not all modes' predicates would be a part of the checking

4149      // code. The subsequently generated check for the default mode would then

4150      // have the exact same patterns, but a different predicate code. To avoid

4151      // duplicated patterns with different predicate checks, construct the

4152      // default check as a negation of all predicates that are actually present

4153      // in the source/destination patterns.

4154      std::vector<Predicate> DefaultPred;

4155 

4156      for (unsigned M : Modes) {

4157        if (M == DefaultMode)

4158          continue;

4159        if (ModeChecks.find(M) != ModeChecks.end())

4160          continue;

4161 

4162        // Fill the map entry for this mode.

4163        const HwMode &HM = CGH.getMode(M);

4164        ModeChecks[M].emplace_back(Predicate(HM.Features, true));

4165 

4166        // Add negations of the HM's predicates to the default predicate.

4167        DefaultPred.emplace_back(Predicate(HM.Features, false));

4168      }

4169 

4170      for (unsigned M : Modes) {

4171        if (M == DefaultMode)

4172          continue;

4173        AppendPattern(P, M);

4174      }

4175 

4176      bool HasDefault = Modes.count(DefaultMode);

4177      if (HasDefault)

4178        AppendPattern(P, DefaultMode);

4179    }

4180  }

41284130行的TreePatternNode::hasProperTypeByHwMode()方法分别检查匹配模式与结果模式是否有缺省模式以外的硬件模式。如果有,进入4139行以下,通过collectModes()方法收集这些模式。在4156行循环根据非缺省模式构造Predicate实例保存在ModeChecks容器,构造条件相反的Predicate实例保存在DefaultPred容器。

接着在4170行循环,通过4110~4124行定义的AppendPattern兰布达表达式,在PatternsToMatch容器中添加各个模式对应的PatternToMatch实例。注意在4123行向PatternToMatch构造函数插入参数ForceMode

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值