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.0在X86Subtarget构造函数末尾追加了GlobalISel所需对象的初始化。
CallLoweringInfo是X86Subtarget一个类型为std::unique_ptr<CallLowering>的成员,CallLowering作为基类,派生出了X86CallLowering,在这个构造的过程中它们都没有特别有趣的地方。
4.4.3.5.1. 合法化器
4.4.2.5.1.1. 基类的设置
类似的,Legalizer是X86Subtarget一个类型为std::unique_ptr<LegalizerInfo>的成员,LegalizerInfo作为基类,派生出了X86LegalizerInfo。X86LegalizerInfo构造函数为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_DEF、G_LOAD、G_STORE、G_INSERT、G_EXTRACT时,SizeChangeStrategy为narrowToSmallerAndUnsupportedIfTooSmall()。G_ADD、G_OR、G_BRCOND时,SizeChangeStrategy为widenToLargerTypesUnsupportedOtherwise()。
4.4.3.5.1.2. X86的32位指令
在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是类型索引号,这个类型索引号通常是0或1,其含义在后面说明。
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_PTRTOINT、G_INTTOPTR、G_SHL、G_LSHR、G_ASHR、G_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/LegalizeRule是GlobalISel合法化今后发展的方向,因为它能提供比原有方案强大、灵活得多的处理手段。
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()用于构造一系列表示Types0与Types1这两个列表笛卡尔积的合法的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,第一操作数可用类型是s1、s8、s16与s32,第二操作数类型是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()将返回一个λ表达式使用由参数P0与P1指定的谓词检查第一、第二操作数是否为这些类型。
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()返回,其中LegalityPredicate是std::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类型的参数,检查指定类型索引(上面是0或1)代表的类型是否在参数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指令,第一个操作数的类型是p0及s32都是合法的。
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()余下的代码没有特别的地方。