LLVM学习笔记(65)

4.4.3.4. X86FrameLowering子对象

X86Subtarget成员FrameLowering的类型是X86FrameLowering,它派生自TargetFrameLowering。它记录了目标机器上栈布局的信息。比如栈的生长方向,每个函数入口已知的栈对齐边界,以及局部变量区相对函数入口处栈顶的偏移。

38       X86FrameLowering::X86FrameLowering(const X86Subtarget &STI,

39                                          unsigned StackAlignOverride)

40           : TargetFrameLowering(StackGrowsDown, StackAlignOverride,

41                                 STI.is64Bit() ? -8 : -4),

42             STI(STI), TII(*STI.getInstrInfo()), TRI(STI.getRegisterInfo()) {

43         // Cache a bunch of frame-related predicates for this subtarget.

44         SlotSize = TRI->getSlotSize();

45         Is64Bit = STI.is64Bit();

46         IsLP64 = STI.isTarget64BitLP64();

47         // standard x86_64 and NaCl use 64-bit frame/stack pointers, x32 - 32-bit.

48        Uses64BitFramePtr = STI.isTarget64BitLP64() || STI.isTargetNaCl64();

49         StackPtr = TRI->getStackRegister();

50       }

基类TargetFrameLowering构造函数的定义则是:

53         TargetFrameLowering(StackDirection D, unsigned StackAl, int LAO,

54                             unsigned TransAl = 1, bool StackReal = true)

55           : StackDir(D), StackAlignment(StackAl), TransientStackAlignment(TransAl),

56             LocalAreaOffset(LAO), StackRealignable(StackReal) {}

X86FrameLowering构造函数的参数StackAlignOverride是initSubtargetFeatures()里设定的,如果没有特别要求,这个值是16。

4.4.3.5. GlobalISel的支持

V7.0X86Subtarget构造函数末尾追加了GlobalISel所需对象的初始化。

CallLoweringInfoX86Subtarget一个类型为std::unique_ptr<CallLowering>的成员,CallLowering作为基类,派生出了X86CallLowering,在这个构造的过程中它们都没有特别有趣的地方。

4.4.3.5.1. 合法化器

4.4.2.5.1.1. 基类的设置

类似的,LegalizerX86Subtarget一个类型为std::unique_ptr<LegalizerInfo>的成员,LegalizerInfo作为基类,派生出了X86LegalizerInfoX86LegalizerInfo构造函数为GlobalISel做了以下的准备:

58       X86LegalizerInfo::X86LegalizerInfo(const X86Subtarget &STI,

59                                          const X86TargetMachine &TM)

60           : Subtarget(STI), TM(TM) {

61      

62         setLegalizerInfo32bit();

63         setLegalizerInfo64bit();

64         setLegalizerInfoSSE1();

65         setLegalizerInfoSSE2();

66         setLegalizerInfoSSE41();

67         setLegalizerInfoAVX();

68         setLegalizerInfoAVX2();

69         setLegalizerInfoAVX512();

70         setLegalizerInfoAVX512DQ();

71         setLegalizerInfoAVX512BW();

72      

73         setLegalizeScalarToDifferentSizeStrategy(G_PHI, 0, widen_1);

74         for (unsigned BinOp : {G_SUB, G_MUL, G_AND, G_OR, G_XOR})

75           setLegalizeScalarToDifferentSizeStrategy(BinOp, 0, widen_1);

76         for (unsigned MemOp : {G_LOAD, G_STORE})

77           setLegalizeScalarToDifferentSizeStrategy(MemOp, 0,

78              narrowToSmallerAndWidenToSmallest);

79         setLegalizeScalarToDifferentSizeStrategy(

80             G_GEP, 1, widenToLargerTypesUnsupportedOtherwise);

81         setLegalizeScalarToDifferentSizeStrategy(

82             G_CONSTANT, 0, widenToLargerTypesAndNarrowToLargest);

83      

84         computeTables();

85         verify(*STI.getInstrInfo());

86       }

基类LegalizerInfo的构造函数用于构造类型合法信息。前面我们看过了在X86TargetLowering里配置的SelectionDAG的类型合法信息。这里对GlobalISel所做的要干净利落很多。另外,GlobalISel的实现还没有完成,这里的合法化的架构还在进一步完善中,下面我们会看到。

109     LegalizerInfo::LegalizerInfo() : TablesInitialized(false) {

110       // Set defaults.

111       // FIXME: these two (G_ANYEXT and G_TRUNC?) can be legalized to the

112       // fundamental load/store Jakob proposed. Once loads & stores are supported.

113       setScalarAction(TargetOpcode::G_ANYEXT, 1, {{1, Legal}});

114       setScalarAction(TargetOpcode::G_ZEXT, 1, {{1, Legal}});

115       setScalarAction(TargetOpcode::G_SEXT, 1, {{1, Legal}});

116       setScalarAction(TargetOpcode::G_TRUNC, 0, {{1, Legal}});

117       setScalarAction(TargetOpcode::G_TRUNC, 1, {{1, Legal}});

118    

119       setScalarAction(TargetOpcode::G_INTRINSIC, 0, {{1, Legal}});

120       setScalarAction(TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS, 0, {{1, Legal}});

121    

122       setLegalizeScalarToDifferentSizeStrategy(

123           TargetOpcode::G_IMPLICIT_DEF, 0, narrowToSmallerAndUnsupportedIfTooSmall);

124       setLegalizeScalarToDifferentSizeStrategy(

125           TargetOpcode::G_ADD, 0, widenToLargerTypesAndNarrowToLargest);

126       setLegalizeScalarToDifferentSizeStrategy(

127           TargetOpcode::G_OR, 0, widenToLargerTypesAndNarrowToLargest);

128       setLegalizeScalarToDifferentSizeStrategy(

129           TargetOpcode::G_LOAD, 0, narrowToSmallerAndUnsupportedIfTooSmall);

130       setLegalizeScalarToDifferentSizeStrategy(

131           TargetOpcode::G_STORE, 0, narrowToSmallerAndUnsupportedIfTooSmall);

132    

133       setLegalizeScalarToDifferentSizeStrategy(

134           TargetOpcode::G_BRCOND, 0, widenToLargerTypesUnsupportedOtherwise);

135       setLegalizeScalarToDifferentSizeStrategy(

136           TargetOpcode::G_INSERT, 0, narrowToSmallerAndUnsupportedIfTooSmall);

137       setLegalizeScalarToDifferentSizeStrategy(

138           TargetOpcode::G_EXTRACT, 0, narrowToSmallerAndUnsupportedIfTooSmall);

139       setLegalizeScalarToDifferentSizeStrategy(

140           TargetOpcode::G_EXTRACT, 1, narrowToSmallerAndUnsupportedIfTooSmall);

141       setScalarAction(TargetOpcode::G_FNEG, 0, {{1, Lower}});

142     }

setScalarAction()的参数SizeAndActions具有类型SizeAndActionsVec,这个类型是这样的定义:

763       using SizeAndAction = std::pair<uint16_t, LegalizeAction>;

764       using SizeAndActionsVec = std::vector<SizeAndAction>;

  它是所有自然数与一个Action之间的表示映射。自然数表示对应InstrAspect对象的比特大小。例如,对原生支持32位与64位加法的目标机器,你最好表示为:

  setScalarAction(G_ADD, 0,

            {{1, WidenScalar},  // bit sizes [1, 31)

             {32, Legal},       // bit sizes [32, 33)

             {33, WidenScalar}, // bit sizes [33, 64)

             {64, Legal},       // bit sizes [64, 65)

             {65, NarrowScalar} // bit sizes [65, +inf)

            });

 可能在你的目标机器上仅支持64位指针:

  setPointerAction(G_GEP, 0, LLT:pointer(1),

            {{1, Unsupported},  // bit sizes [1, 63)

             {64, Legal},       // bit sizes [64, 65)

             {65, Unsupported}, // bit sizes [65, +inf)

            });

通过setActions(),这些数据都保存在容器SmallVector<SizeAndActionsVec, 1> ScalarActions [LastOp - FirstOp + 1]中。

981       void setScalarAction(const unsigned Opcode, const unsigned TypeIndex,

982                            const SizeAndActionsVec &SizeAndActions) {

983         const unsigned OpcodeIdx = Opcode - FirstOp;

984         SmallVector<SizeAndActionsVec, 1> &Actions = ScalarActions[OpcodeIdx];

985         setActions(TypeIndex, Actions, SizeAndActions);

986       }

除了ScalarActions容器,另一个容器SpecifiedActions(其类型如下):

  using TypeMap = DenseMap<LLT, LegalizeAction>;

  SmallVector<TypeMap, 1> SpecifiedActions[LastOp - FirstOp + 1];

用于记录指令操作数不改变操作数大小的合法化方案,目前它基本只记录合法类型。这个容器由setAction()设置,在构建最终数据结构时使用。

上面122行的setLegalizeScalarToDifferentSizeStrategy()的参数S(类型SizeChangeStrategy,即std:: function<SizeAndActionsVec(const SizeAndActionsVec &v)>)则记录在类型大小需要修改为一个合法大小时要怎么做。比如以下语句:

setAction ({G_ADD, 0, LLT::scalar(32)}, Legal);

setLegalizeScalarToDifferentSizeStrategy(

                  G_ADD, 0, widenToLargerTypesAndNarrowToLargest);

将最终使得getAction({G_ADD, 0, T})来对不同的标量类型T返回以下合法化方案:

LLT::scalar(1)..LLT::scalar(31): {WidenScalar, 0, LLT::scalar(32)}

LLT::scalar(32):                 {Legal, 0, LLT::scalar(32)}

LLT::scalar(33)..:               {NarrowScalar, 0, LLT::scalar(32)}

如果没有通过这个函数定义SizeChangeAction,缺省由unsupportedForDifferentSizes()给出方案。

797       void setLegalizeScalarToDifferentSizeStrategy(const unsigned Opcode,

798                                                     const unsigned TypeIdx,

799                                                     SizeChangeStrategy S) {

800         const unsigned OpcodeIdx = Opcode - FirstOp;

801         if (ScalarSizeChangeStrategies[OpcodeIdx].size() <= TypeIdx)

802           ScalarSizeChangeStrategies[OpcodeIdx].resize(TypeIdx + 1);

803         ScalarSizeChangeStrategies[OpcodeIdx][TypeIdx] = S;

804       }

上面800行的FirstOp是一个静态变量,赋值为TargetOpcode::PRE_ISEL_GENERIC_OPCODE_START,它在TargetOpCode.h里定义为枚举值G_ADD(值0),即在这个文件里声明的第一条GlobalISel指令。

在基类构造函数中,在指令为G_IMPLICIT_DEFG_LOADG_STOREG_INSERTG_EXTRACT时,SizeChangeStrategynarrowToSmallerAndUnsupportedIfTooSmall()G_ADDG_ORG_BRCOND时,SizeChangeStrategywidenToLargerTypesUnsupportedOtherwise()

4.4.3.5.1.2. X8632位指令

X86LegalizerInfo构造函数里,开始目标机器相关的设置。首先是设置32位指令,在90~96行准备相应的LLT类型对象。

88       void X86LegalizerInfo::setLegalizerInfo32bit() {

89      

90         const LLT p0 = LLT::pointer(0, TM.getPointerSizeInBits(0));

91         const LLT s1 = LLT::scalar(1);

92         const LLT s8 = LLT::scalar(8);

93         const LLT s16 = LLT::scalar(16);

94         const LLT s32 = LLT::scalar(32);

95         const LLT s64 = LLT::scalar(64);

96         const LLT s128 = LLT::scalar(128);

97      

98         for (auto Ty : {p0, s1, s8, s16, s32})

99           setAction({G_IMPLICIT_DEF, Ty}, Legal);

100    

101       for (auto Ty : {s8, s16, s32, p0})

102         setAction({G_PHI, Ty}, Legal);

103    

104       for (unsigned BinOp : {G_ADD, G_SUB, G_MUL, G_AND, G_OR, G_XOR})

105         for (auto Ty : {s8, s16, s32})

106           setAction({BinOp, Ty}, Legal);

107    

108       for (unsigned Op : {G_UADDE}) {

109         setAction({Op, s32}, Legal);

110         setAction({Op, 1, s1}, Legal);

111       }

112    

113       for (unsigned MemOp : {G_LOAD, G_STORE}) {

114         for (auto Ty : {s8, s16, s32, p0})

115           setAction({MemOp, Ty}, Legal);

116    

117         // And everything's fine in addrspace 0.

118         setAction({MemOp, 1, p0}, Legal);

119       }

120    

121      // Pointer-handling

122       setAction({G_FRAME_INDEX, p0}, Legal);

123       setAction({G_GLOBAL_VALUE, p0}, Legal);

124    

125       setAction({G_GEP, p0}, Legal);

126       setAction({G_GEP, 1, s32}, Legal);

127    

128       if (!Subtarget.is64Bit()) {

129         getActionDefinitionsBuilder(G_PTRTOINT)

130             .legalForCartesianProduct({s1, s8, s16, s32}, {p0})

131             .maxScalar(0, s32)

132             .widenScalarToNextPow2(0, /*Min*/ 8);

133         getActionDefinitionsBuilder(G_INTTOPTR).legalFor({{p0, s32}});

134    

135         // Shifts and SDIV

136         getActionDefinitionsBuilder({G_SHL, G_LSHR, G_ASHR, G_SDIV})

137             .legalFor({s8, s16, s32})

138             .clampScalar(0, s8, s32);

139       }

140    

141       // Control-flow

142       setAction({G_BRCOND, s1}, Legal);

143    

144       // Constants

145       for (auto Ty : {s8, s16, s32, p0})

146         setAction({TargetOpcode::G_CONSTANT, Ty}, Legal);

147    

148      // Extensions

149       for (auto Ty : {s8, s16, s32}) {

150         setAction({G_ZEXT, Ty}, Legal);

151         setAction({G_SEXT, Ty}, Legal);

152         setAction({G_ANYEXT, Ty}, Legal);

153       }

154       setAction({G_ANYEXT, s128}, Legal);

155    

156      // Comparison

157       setAction({G_ICMP, s1}, Legal);

158    

159       for (auto Ty : {s8, s16, s32, p0})

160         setAction({G_ICMP, 1, Ty}, Legal);

161    

162      // Merge/Unmerge

163       for (const auto &Ty : {s16, s32, s64}) {

164         setAction({G_MERGE_VALUES, Ty}, Legal);

165         setAction({G_UNMERGE_VALUES, 1, Ty}, Legal);

166       }

167       for (const auto &Ty : {s8, s16, s32}) {

168         setAction({G_MERGE_VALUES, 1, Ty}, Legal);

169         setAction({G_UNMERGE_VALUES, Ty}, Legal);

170       }

171     }

上面在调用setAction()时,首先生成所需的InstrAspect对象。这是一个用于封装以下信息的简单结构体定义,其中Idx是类型索引号,这个类型索引号通常是01,其含义在后面说明。

101     struct InstrAspect {

102       unsigned Opcode;

103       unsigned Idx = 0;

104       LLT Type;

105    

106       InstrAspect(unsigned Opcode, LLT Type) : Opcode(Opcode), Type(Type) {}

107       InstrAspect(unsigned Opcode, unsigned Idx, LLT Type)

108           : Opcode(Opcode), Idx(Idx), Type(Type) {}

109    

110       bool operator==(const InstrAspect &RHS) const {

110         return Opcode == RHS.Opcode && Idx == RHS.Idx && Type == RHS.Type;

112       }

113     };

setAction()只用于设置不改变类型大小的合法化方案,在X86里则完全用于设置本身就合法的操作。需要进行其他合法化方案的类型由别的方法处理,参考下面。

772       void setAction(const InstrAspect &Aspect, LegalizeAction Action) {

773         assert(!needsLegalizingToDifferentSize(Action));

774         TablesInitialized = false;

775         const unsigned OpcodeIdx = Aspect.Opcode - FirstOp;

776         if (SpecifiedActions[OpcodeIdx].size() <= Aspect.Idx)

777           SpecifiedActions[OpcodeIdx].resize(Aspect.Idx + 1);

778         SpecifiedActions[OpcodeIdx][Aspect.Idx][Aspect.Type] = Action;

779       }

setLegalizerInfo32bit() 129行,如果目标机器不支持64位,对G_PTRTOINTG_INTTOPTRG_SHLG_LSHRG_ASHRG_SDIV调用下面两个方法之一返回对应的LegalizeRuleSet实例。LegalizeRuleSet提供完成合法化所需的规则集,它包含这些数据成员:

269       /// When non-zero, the opcode we are an alias of

270       unsigned AliasOf;

271       /// If true, there is another opcode that aliases this one

272       bool IsAliasedByAnother;

273       SmallVector<LegalizeRule, 2> Rules;

其中LegalizeRule规定了合法化适用的规则,它包含以下成员:

244       LegalityPredicate Predicate;

245       LegalizeAction Action;

246       LegalizeMutation Mutation

其中LegalityPredicate类型是std::function<bool (const LegalityQuery &)>,它用作判定合法化方案是否适用的谓词。LegalizeMutation是类型std::function <std::pair<unsigned, LLT>(const LegalityQuery &)>,如果不是空,它指出具体操作数合法化后的类型。

AliasOf则指向提供共用规则的指令,下面会看到。

从代码上看,LegalizeRuleSet/LegalizeRuleGlobalISel合法化今后发展的方向,因为它能提供比原有方案强大、灵活得多的处理手段。

290     LegalizeRuleSet &LegalizerInfo::getActionDefinitionsBuilder(unsigned Opcode) {

291       unsigned OpcodeIdx = getActionDefinitionsIdx(Opcode);

292       auto &Result = RulesForOpcode[OpcodeIdx];

293       assert(!Result.isAliasedByAnother() && "Modifying this opcode will modify aliases");

294       return Result;

295     }

296    

297     LegalizeRuleSet &LegalizerInfo::getActionDefinitionsBuilder(

298         std::initializer_list<unsigned> Opcodes) {

299       unsigned Representative = *Opcodes.begin();

300    

301       assert(Opcodes.begin() != Opcodes.end() &&

302              Opcodes.begin() + 1 != Opcodes.end() &&

303              "Initializer list must have at least two opcodes");

304    

305       for (auto I = Opcodes.begin() + 1, E = Opcodes.end(); I != E; ++I)

306         aliasActionDefinitions(Representative, *I);

307    

308       auto &Return = getActionDefinitionsBuilder(Representative);

309       Return.setIsAliasedByAnother();

310       return Return;

311     }

297行的版本构造一组规则用于Opcodes里的指令集合。集合中的第一条指令为代表,其他指令共享这条指令的规则(306行的aliasActionDefinitions()把这些指令的LegalizeRuleSet实例的aliasTo赋为第一条指令的操作码)。308行调用290行的版本返回与第一条指令对应的LegalizeRuleSet实例,由setIsAliasedByAnother()设置标记IsAliasedByAnother

上面292行的容器RulesForOpcode定义为LegalizeRuleSet RulesForOpcode[LastOp - FirstOp + 1],每条指令对应一个LegalizeRuleSet实例。

上面297行版本的getActionDefinitionsBuilder()把一组指令设置为领头指令的别名。实际上它们共用一组规则。

对返回的LegalizeRuleSet实例,legalForCartesianProduct()用于构造一系列表示Types0Types1这两个列表笛卡尔积的合法的LegalRule对象。

436       LegalizeRuleSet &legalForCartesianProduct(std::initializer_list<LLT> Types0,

437                                                 std::initializer_list<LLT> Types1) {

438         return actionForCartesianProduct(LegalizeAction::Legal, Types0, Types1);

439       }

实际工作由actionForCartesianProduct()完成,参数Action指明合法化的方案。

370       LegalizeRuleSet &

371       actionForCartesianProduct(LegalizeAction Action,

372                                 std::initializer_list<LLT> Types0,

373                                 std::initializer_list<LLT> Types1) {

374         using namespace LegalityPredicates;

375         return actionIf(Action, all(typeInSet(typeIdx(0), Types0),

376                                     typeInSet(typeIdx(1), Types1)));

377       }

actionIf()所需的函数对象由all()typeInSet()方法准备,显然其中Types0用作第一操作数的类型集合,Types1用作第二操作数的类型集合。在我们上下文里,指令是G_PTRTOINT,第一操作数可用类型是s1s8s16s32,第二操作数类型是p0

186     template<typename Predicate, typename... Args>

187     Predicate all(Predicate P0, Predicate P1, Args... args) {

188       return all(all(P0, P1), args...);

189     }

all()将返回一个λ表达式使用由参数P0P1指定的谓词检查第一、第二操作数是否为这些类型。

179     template<typename Predicate>

180     Predicate all(Predicate P0, Predicate P1) {

181       return [=](const LegalityQuery &Query) {

182         return P0(Query) && P1(Query);

183       };

184     }

这些谓词由typeInSet()返回,其中LegalityPredicatestd::function<bool (const LegalityQuery &)>

23       LegalityPredicate

24       LegalityPredicates::typeInSet(unsigned TypeIdx,

25                                     std::initializer_list<LLT> TypesInit) {

26         SmallVector<LLT, 4> Types = TypesInit;

27         return [=](const LegalityQuery &Query) {

28           return std::find(Types.begin(), Types.end(), Query.Types[TypeIdx]) != Types.end();

29         };

30       }

这个λ表达式接受一个LegalityQuery类型的参数,检查指定类型索引(上面是01)代表的类型是否在参数TypesInit这个集合里。

312       LegalizeRuleSet &actionIf(LegalizeAction Action,

313                                 LegalityPredicate Predicate) {

314         add({Predicate, Action});

315         return *this;

316       }

actionIf()将上面获得的λ表达式以及指定合法化方案传递给LegalizeRuleSet::add()

302       void add(const LegalizeRule &Rule) {

303         assert(AliasOf == 0 &&

304                "RuleSet is aliased, change the representative opcode instead");

305         Rules.push_back(Rule);

306       }

在完成规则添加后,legalForCartesianProduct()返回更改后的LegalizeRuleSet对象,在131行继续调用maxScalar()向这个LegalizeRuleSet添加规则确保第一个操作数类型小于s32

624       LegalizeRuleSet &maxScalar(unsigned TypeIdx, const LLT &Ty) {

625         using namespace LegalityPredicates;

626         using namespace LegalizeMutations;

627         return actionIf(LegalizeAction::NarrowScalar,

628                         widerThan(TypeIdx, Ty.getSizeInBits()),

629                         changeTo(typeIdx(TypeIdx), Ty));

630       }

628行的widerThan()返回一个λ表达式,这个表达式接受一个LegalityQuery对象,判定其中指定的类型是否为大于指定 比特大小的标量。

68       LegalityPredicate LegalityPredicates::widerThan(unsigned TypeIdx,

69                                                       unsigned Size) {

70         return [=](const LegalityQuery &Query) {

71           const LLT &QueryTy = Query.Types[TypeIdx];

72           return QueryTy.isScalar() && QueryTy.getSizeInBits() > Size;

73         };

74       }

629行的changeTo()也返回一个λ表达式,这个表达式接受一个LegalityQuery对象,不过不使用,它返回一个封装了类型索引与类型的std::pair,这个结果表示将指定索引处的类型改变为Ty的类型。

18       LegalizeMutation LegalizeMutations::changeTo(unsigned TypeIdx, LLT Ty) {

19         return

20             [=](const LegalityQuery &Query) { return std::make_pair(TypeIdx, Ty); };

21       }

接着,调用widenScalarToNextPow2()添加确保第一个操作数的比特数为2次幂的规则:

601       LegalizeRuleSet &widenScalarToNextPow2(unsigned TypeIdx,

602                                              unsigned MinSize = 0) {

603        using namespace LegalityPredicates;

604         return actionIf(LegalizeAction::WidenScalar, sizeNotPow2(typeIdx(TypeIdx)),

605                         LegalizeMutations::widenScalarToNextPow2(TypeIdx, MinSize));

606       }

显然sizeNotPow2()返回一个接受一个LegalityPredicates对象,判断其指定索引处类型比特数是否为2次幂的λ表达式。

76       LegalityPredicate LegalityPredicates::sizeNotPow2(unsigned TypeIdx) {

77         return [=](const LegalityQuery &Query) {

78           const LLT &QueryTy = Query.Types[TypeIdx];

79           return QueryTy.isScalar() && !isPowerOf2_32(QueryTy.getSizeInBits());

80         };

81       }

widenScalarToNextPow2()返回一个λ表达式,这个表达式查找一个比特位为不小于指定值最小2次幂的标量,然后返回封装了这个信息的std::pair

30       LegalizeMutation LegalizeMutations::widenScalarToNextPow2(unsigned TypeIdx,

31                                                                 unsigned Min) {

32         return [=](const LegalityQuery &Query) {

33           unsigned NewSizeInBits =

34               1 << Log2_32_Ceil(Query.Types[TypeIdx].getSizeInBits());

35           if (NewSizeInBits < Min)

36             NewSizeInBits = Min;

37           return std::make_pair(TypeIdx, LLT::scalar(NewSizeInBits));

38         };

39       }

注意,上面这系列调用在一个LegalizeRuleSet对象里添加这些规则。

setLegalizerInfo32bit()133行,getActionDefinitionsBuilder()返回相应的LegalizeRuleSet对象,接着调用该对象的legalFor()

412       LegalizeRuleSet &legalFor(std::initializer_list<LLT> Types) {

413         return actionFor(LegalizeAction::Legal, Types);

414       }

actionFor()只是调用actionIf()向所在的LegalizeRuleSet对象添加一条规则。在这个上下文里表示对G_INTTOPTR指令,第一个操作数的类型是p0s32都是合法的。

326       LegalizeRuleSet &actionFor(LegalizeAction Action,

327                                  std::initializer_list<LLT> Types) {

328         using namespace LegalityPredicates;

329         return actionIf(Action, typeInSet(typeIdx(0), Types));

330       }

clampScalar()则用于添加规则限定类型比特位的上下界。

648       LegalizeRuleSet &clampScalar(unsigned TypeIdx, const LLT &MinTy,

649                                    const LLT &MaxTy) {

650         assert(MinTy.isScalar() && MaxTy.isScalar() && "Expected scalar types");

651         return minScalar(TypeIdx, MinTy).maxScalar(TypeIdx, MaxTy);

652       }

minScalar()不出所料与maxScalar()非常类似:

615       LegalizeRuleSet &minScalar(unsigned TypeIdx, const LLT &Ty) {

616         using namespace LegalityPredicates;

617         using namespace LegalizeMutations;

618         return actionIf(LegalizeAction::WidenScalar,

619                         narrowerThan(TypeIdx, Ty.getSizeInBits()),

620                         changeTo(typeIdx(TypeIdx), Ty));

621       }

显然,narrowThan()是作用与widerThan()相反的谓词。

60       LegalityPredicate LegalityPredicates::narrowerThan(unsigned TypeIdx,

61                                                          unsigned Size) {

62         return [=](const LegalityQuery &Query) {

63           const LLT &QueryTy = Query.Types[TypeIdx];

64           return QueryTy.isScalar() && QueryTy.getSizeInBits() < Size;

65         };

66       }

setLegalizerInfo32bit()余下的代码没有特别的地方。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/236678.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

截断霍夫曼编码

截断霍夫曼编码是一种数据压缩技术&#xff0c;它基于霍夫曼编码的原理&#xff0c;通过截断霍夫曼树&#xff0c;减少编码中的冗余信息&#xff0c;实现更高效的数据压缩。在本文中&#xff0c;我们将详细探讨截断霍夫曼编码的原理、应用及其优势。 一、霍夫曼编码简介 霍夫曼…

Kubernetes集群内创建具有kubectl命令行工具的容器

Kubernetes 集群中创建一个包含 kubectl 命令的 Pod 通常用于管理和调试集群本身。这种 Pod 通常被称为“调试 Pod”或“管理 Pod”&#xff0c;它们的主要作用是允许从集群内部执行 Kubernetes 操作和管理任务。这可以在多种情况下非常有用&#xff1a; 集群管理和维护 内部…

12.21 汇编点亮STM32MP157小灯

.text .global _start _start: 时钟使能pb6 pf6 pe9LDR r0,0x50000A28LDR r1,[r0]ORR r1,r1,#(0x1<<4)ORR r1,r1,#(0x1<<5)ORR r1,r1,#(0x1<<1)STR r1,[r0]配置GPIO模式LDR r0,0x50006000LDR r1,[r0]BIC r1,r1,#(0x2<<20)ORR r1,r1,#(0x1<<20)B…

kubernetes集群应用 service进阶

kubernetes集群应用 Service进阶 一、场景 使用kubernetes集群运行工作负载时&#xff0c;由于Pod经常处于用后即焚状态&#xff0c;Pod对应的IP地址也会经常变化&#xff0c;因此我们不能直接访问Pod&#xff0c;可以通过Service对应的端点列表&#xff08;Endpoints&#x…

PaddleOCR Docker 容器快捷调用,快捷调用OCR API

文章目录 搞环境命令行测试Python调用测试转fastapi服务打包成镜像服务PaddleOCR 服务端模型总结&#xff0c;直接启动OCR服务 paddleOCR迎来大更新&#xff0c;搞一把新的api接口&#xff0c;直接用起来。 搞环境 搞容器&#xff1a; FROM nvidia/cuda:11.8.0-cudnn8-devel…

openlayers 截图

openlayers 截图 OK&#xff0c;我承认&#xff0c;这篇博文是一个水文。 最新做了一个功能&#xff0c;就是 openlayers 展示二维 GIS 数据后&#xff0c;可以把当前的视角导出图片。 直接写代码吧&#xff0c;没啥好说的&#xff1a; // 截图toImg() {if (this.map) {let ca…

【笔记】网络流算法模板

文章目录 EK求最大流题目描述输入格式输出格式数据范围 算法步骤算法时间复杂度 O ( n m 2 ) O(nm^2) O(nm2) AC CodeDinic/ISAP求最大流题目描述输入格式输出格式数据范围 算法步骤算法时间复杂度 O ( n 2 m ) O(n^2m) O(n2m) AC CodeDinic/ISAP求最小割EK求费用流题目描述输…

Python importlib模块详细教程

更多资料获取 &#x1f4da; 个人网站&#xff1a;ipengtao.com importlib模块是Python标准库中用于动态导入模块的工具。它提供了一系列函数&#xff0c;允许以编程方式加载、检查和操作模块。本文将深入探讨importlib的各种用法&#xff0c;并通过丰富的示例代码帮助你更好地…

华清作业day46

.text .global _start _start: led1 设置时钟使能 ldr r0,0x50000A28 ldr r1,[r0] orr r1,r1,#(0x1<<4) str r1,[r0]设置输出模式 ldr r0,0x50006000 ldr r1,[r0] bic r1,r1,#(0x3<<20) orr r1,r1,#(0x01<<20) str r1,[r0]设置推挽输出 ldr r0,0x5000600…

如何在Go中发起HTTP请求

引言 当一个程序需要与另一个程序通信时,许多开发人员会使用HTTP。Go的优势之一是其标准库的广度,HTTP也不例外。Go net/http包不仅支持[创建HTTP服务器],而且它还可以作为客户端进行HTTP请求。 在本教程中,您将创建一个程序,向HTTP服务器发出几种类型的HTTP请求。首先,…

在QT Creator下用CMake编译GEOS库

最近&#xff0c;想要在C下编一个可用GDAL模块的地图管理系统&#xff0c;找来找去&#xff0c;找到了GEOS。GEOS&#xff08;Geometry Engine-Open Source&#xff09;开源几何引擎 是一个用于计算几何的JTS库的 C/C实现&#xff0c;专注于地理信息系统 &#xff08;GIS&#…

obsidian + cloudreve 搭建个人云盘

obsidian 是什么&#xff1f;obsidian 是一款好用的笔记软件&#xff0c;拥有强大的第三方库&#xff0c;最重要的是支持WebDAV&#xff0c;可以自动同步笔记到云端服务器 cloudreve 是什么&#xff1f;cloudreve 是一款私人网盘系统&#xff0c;部署简单、界面简洁&#xff0…

11、Qt:创建/删除文件夹、拷贝文件

一、创建文件夹 声明&#xff1a; bool createPath(QString strPath); 定义&#xff1a; /** * brief MainWindow::CreatePath 创建文件夹 * param strPath 要创建的文件夹路径 * return 创建成功返回true&#xff0c;失败返回false */ bool MainWindow::createPath(QString s…

一篇文章概括!状态码分别是什么意思?

hello,我是小索奇&#xff0c;HTTP状态码被分为几个类别&#xff0c;每个类别代表着不同类型的响应。这里是100到500之间的状态码的大致含义&#xff1a; 1xx (信息性状态码) 100 Continue: 客户端应继续其请求。101 Switching Protocols: 请求者已要求服务器切换协议&#x…

速通Python基础语法--语句篇

缩进和代码块 一 条件语句if/elif if的基本语法 示例 条件语句嵌套 练习1 练习2 二 空语句 三 while循环 示例 打印1-10 求1-100的和 求5! 求1-5的阶乘之和 四 for循环 for的基本语法 1~range[ ,) 五 continue/break continue:结束当前循环,继续下一次循环 break:结束整个循…

《每天一分钟学习C语言·四》文本读写操作及二进制读写

fopen(参数1,参数2)&#xff0c;第一个参数是要打开的文件名&#xff0c;文件名字符串&#xff0c;第二个参数用于制定文件打开模式的一个字符串。 注&#xff1a;如果要打开某个盘的文本如F盘test文件夹下的test.txt文本&#xff0c;则fopen(“F:\test\test.txt”,”r”); 程序…

AcWing算法进阶课-1.1.2Dinic/ISAP求最大流

算法进阶课整理 CSDN个人主页&#xff1a;更好的阅读体验 原题链接 题目描述 给定一个包含 n n n 个点 m m m 条边的有向图&#xff0c;并给定每条边的容量&#xff0c;边的容量非负。 图中可能存在重边和自环。求从点 S S S 到点 T T T 的最大流。 输入格式 第一行包…

本地websocket服务端结合cpolar内网穿透实现公网访问

文章目录 1. Java 服务端demo环境2. 在pom文件引入第三包封装的netty框架maven坐标3. 创建服务端,以接口模式调用,方便外部调用4. 启动服务,出现以下信息表示启动成功,暴露端口默认99995. 创建隧道映射内网端口6. 查看状态->在线隧道,复制所创建隧道的公网地址加端口号7. 以…

黑马头条--day07--app文章搜索

目录 一.安装elasticsearch 1.拉取镜像 2.创建存放数据及配置文件的文件夹&#xff0c;启动时挂载。 4.修改文件夹权限 5.启动容器 5.1参数解释 6.安装ik分词器 6.2测试一下Ik分词器 二.添加文章索引库 1查询所有的文章信息&#xff0c;批量导入到es索引库中 2)测试 …

深度盘点:除了BRC20外 这些公链潜力铭文也值得关注

近日的铭文市场风起云涌&#xff0c;除BRC20占据着市场70%以上的份额外&#xff0c;其他公链的铭文也在快速发展