LLVM学习笔记
文章平均质量分 87
wuhui_gdnt
这个作者很懒,什么都没留下…
展开
-
LLVM学习笔记(65)
X86Subtarget成员FrameLowering的类型是X86FrameLowering,它派生自TargetFrameLowering。比如栈的生长方向,每个函数入口已知的栈对齐边界,以及局部变量区相对函数入口处栈顶的偏移。X86FrameLowering构造函数的参数StackAlignOverride是initSubtargetFeatures()里设定的,如果没有特别要求,这个值是16。的实现还没有完成,这里的合法化的架构还在进一步完善中,下面我们会看到。构造函数里,开始目标机器相关的设置。原创 2023-12-20 15:58:12 · 724 阅读 · 0 评论 -
LLVM学习笔记(64)
因此,如果要求的类型不是由2的幂个元素组成,就需要使用这么多个元素大小的类型来替换(868行条件)。因此对扩展无望的类型,就会谋求分裂类型,即通过多个更小的向量类型来支持。对于TypeSplitVector操作,源向量类型必须是2幂次大小,getVectorTypeBreakdownMVT()获取可能的分裂类型,它的返回值是所需寄存器的个数。在1216行,getPow2VectorType()返回大小为2次幂且最接近VT的上级类型,如果VT本身不是2次幂大小,就要提升到这个类型。原创 2023-12-07 13:39:50 · 248 阅读 · 0 评论 -
LLVM学习笔记(63)
它设置循环对齐大小。另外,如果目标机器支持乱序执行,把PredictableSelectIsExpensive设为true,因为乱序CPU可以试探执行一个预测分支后的代码,但条件移动(所谓的select)会被前面的操作阻止。接下来则是通过setTargetDAGCombine()设置通过TargetDAGCombineArray容器记录的期望回调PerformDAGCombine()的LLVM IR操作(这与X86TargetLowering::PerformDAGCombine()对应)。原创 2023-11-30 17:40:15 · 279 阅读 · 0 评论 -
LLVM学习笔记(62)
上面所调用的AddPromotedToType()是将指定的操作,指定的操作数类型,与提升类型关联。维持这个关联关系的容器是PromoteToType(类型std::map<std::pair<unsigned, MVT::SimpleValueType>, MVT::SimpleValueType>,其中std::pair记录操作与操作数原始类型)。下面Expand的含义是建议将操作数分为较小的两部分。做了不小的改动,改进了代码的结构,修改了一些指令的设置。,并修改了一些指令与指定类型操作数的处理。原创 2023-11-22 14:49:39 · 290 阅读 · 0 评论 -
LLVM学习笔记(62)
应该假设目标机器将根据对齐限制,首先使用尽可能多的最大的储存操作,然后如果需要较小的操作。接下来的代码将个别的操作设置为Expand,下面会看到X86的派生类型还会进行自己的改写。分别表示函数的最小对齐要求(用于优化代码大小时,防止显式提供的对齐要求导致错误代码),函数的期望对齐要求(用于没有对齐要求且优化速度时),以及期望的循环对齐要求。它是一个位图,每个LLVM IR操作对应一个位,如果是1,表示该操作期望使用目标机器的回调方法PerformDAGCombine()来执行指令合并。原创 2023-11-17 14:20:43 · 245 阅读 · 0 评论 -
LLVM学习笔记(54)
3.11.2.2.匹配表的生成对象GlobalISelEmitter::run() 4267行循环遍历前面生成的所有PatternToMatch对象(PatternToMatch的生成参考DAG指令选择器的生成代码一节),对每个PatternToMatch对象调用下面的方法来构建对应的Matcher实例(类似于SelectionDAG生成代码时构建的另一个版本的Matcher)。在下面383...原创 2020-01-10 11:56:01 · 1304 阅读 · 0 评论 -
LLVM学习笔记(53)
3.11.2.模式分析GlobalISel是以DAG指令选择的TD定义处理与分析为基础的。因此,GlobalISelEmitter包含了一个CodeGenDAGPatterns类型的const成员CGP(一旦创建完成,就是只读的),在GlobalISelEmitter构造函数中将完成DAG指令选择令人眼花缭乱的准备工作(参考DAG指令选择器的生成代码一节,直到Match对象序列的优化为止),...原创 2020-01-03 11:19:08 · 594 阅读 · 0 评论 -
LLVM学习笔记(52)
3.11.GlobalISel代码的自动生成(v7.0)3.11.1.概述GlobalISel是LLVM的一个新锐指令选择器。关于它的描述,首先是LLVM的在线文档: 第一部分参考v7.0的变化一节。 通用机器IR 机器IR工作在物理寄存器、寄存器类,以及(大部分情形)目标机器特定指令上。 为了填补LLVM IR的空缺,GlobalISel引入了机器I...原创 2019-12-27 10:46:38 · 1651 阅读 · 0 评论 -
LLVM学习笔记(51)
3.10.X86折叠表的生成(v7.0)指令折叠是在寄存器分配过程中执行的优化,目的是删除不必要的拷贝指令。例如,这样的一组指令:%EBX = LOAD %mem_address%EAX = COPY %EBX可以被安全地替换为单条指令:%EAX = LOAD %mem_address通常,后者较前者更小,更快。在X86中,许多指令有内存形式与寄存器形式,即通过内存或...原创 2019-12-20 11:31:46 · 376 阅读 · 0 评论 -
LLVM学习笔记(50)
3.9.X86 EVEX2VEX映射表的生成(v7.0)VEX编码方案支持现有指令编码的扩展或修改,以及新指令定义。(维基)EVEX方案是VEX方案的一个4字节扩展,它支持AVX-512指令集,并允许访问新的512位ZMM寄存器以及新的掩码寄存器。(维基)这个X86特定的TableGen处理生成一张表,将EVEX编码的指令映射到等价VEX编码指令。这样做通常可以将指令长度减少2字节。...原创 2019-12-13 15:34:20 · 622 阅读 · 0 评论 -
LLVM学习笔记(49)
3.8. RegisterBank代码的自动生成(v7.0)3.8.1. 数据结构选项“-gen-register-bank”用于生成辅助目标机器RegisterBank类(对X86是X86RegisterBankInfo)处理的代码。目前,RegisterBank代码的自动生成程度还不高,相当部分的代码计划在未来将由TableGen生成。以下内容来自https://2pi.dk/ll...原创 2019-12-06 11:24:33 · 689 阅读 · 0 评论 -
LLVM学习笔记(44-2)
V7.0的变化——resolveSchedClass()等 V7.0在这里引入了相当剧烈的变化,因为x86也开始使用SchedVar,SchedWriteVariant,以及SchedWriteVariant,resolveSchedClass()开始有意义了。 1593 void SubtargetEmitter::EmitSchedModelHelpers(const st...原创 2019-11-08 13:46:39 · 421 阅读 · 0 评论 -
LLVM学习笔记(43-2)
V7.0的变化 V7.0的 SubtargetEmitter::EmitProcessorModels()改写颇多,因为对处理器的描述进行了相当程度的增强。 1344 void SubtargetEmitter::EmitProcessorModels(raw_ostream &OS) { 1345 // For each processor model....原创 2019-11-08 13:41:22 · 601 阅读 · 0 评论 -
LLVM学习笔记(41)
3.6.2.2.资源及其使用的描述我们已经知道有两个方式可以描述指令的执行。一种是执行步骤,Itinerary,它包括了一系列包含一组InstrStage定义的InstrItinData定义,将InstrItinData与指令定义关联起来的InstrItinClass,以及一个把有关定义组合起来的ProcessorItineraries定义。另一种则是通过描述资源使用情形,它由一系列相互关联...原创 2018-09-14 12:01:06 · 984 阅读 · 0 评论 -
LLVM学习笔记(40)
3.6. 描述目标机器的数据结构描述目标机器的数据结构由TableGen的“-gen-subtarget”选项生成。以X86来说,生成文件是X86GenSubtargetInfo.Inc。3.6.1. 对目标机器描述的解析这个选项的处理入口是下面的方法:1154 void EmitSubtarget(RecordKeeper &RK, raw_ostream &O...原创 2018-08-24 11:35:50 · 640 阅读 · 0 评论 -
LLVM学习笔记(39)
3.5.2.3.指令描述数组这部分代码输出指令描述数组。首先看到385行的getInstructionsByEnumValue(),指令的这个遍历次序很重要。接着,我们看到387行的SequenceToOffsetTable类型的变量InstrNames,这意味着我们将要进行差分编码。391行则告诉我们,要进行差分编码的是指令的名字。InstrInfoEmitter::run(续)3...原创 2018-08-17 12:10:54 · 773 阅读 · 0 评论 -
LLVM学习笔记(37)
3.5.1.7.2. 从InstRW定义推导InstRW为一组指令重新绑定SchedReadWrite。在前面CodeGenSchedModels的createInstRWClass()方法里已经为InstRW定义准备了CodeGenSchedClass对象,并在CodeGenSchedClass对象的InstRWs容器里记录了该InstRW定义的Record实例。但对InstRW定义的处理并...原创 2018-08-03 11:21:31 · 623 阅读 · 0 评论 -
LLVM学习笔记(42)
3.6.2.4. 资源描述的调度3.6.2.4.1. SchedReadWrite数据的收集描述类似SandyBridge处理器指令执行细节的方法不同于Atom这样的处理器,上面的处理对这些处理器不适用。这些处理器使用WriteRes或SchedWriteRes描述SchedWrite对资源的使用,依靠ReadAdvance或SchedReadAdvance来描述对特定的SchedWrit...原创 2018-09-21 11:50:34 · 653 阅读 · 0 评论 -
LLVM学习笔记(38)
3.5.2.代码生成这部分代码输出到文件X86GenInstrInfo.inc中。3.5.2.1.枚举常量从InstrInfoEmitter的构造函数返回到EmitInstrInfo(),接下来调用的InstrInfoEmitter::run()方法来输出相关的代码。342 void InstrInfoEmitter::run(raw_ostream &a...原创 2018-08-10 11:28:57 · 773 阅读 · 0 评论 -
LLVM学习笔记(36)
3.5.1.7.推导调度类型前面,我们已经各种相关的定义通过CodeGenSchedModels中的各式容器关联起来。现在我们将根据这些定义推导出所有的调度类型。在840行遍历所有的调度类型。注意,这个遍历的终止条件SchedClasses.size()是动态的,包括了新添加的类型,因为在下面的处理里会向该容器添加新的调度类型。836 void CodeGenSchedModel...原创 2018-06-29 12:09:03 · 775 阅读 · 0 评论 -
LLVM学习笔记(34)
3.5. 指令信息的生成选项-gen-instr-info使得TableGen根据TD文件的描述,生成目标机器的指令描述代码。比如,前面指令选择成功时生成的MachineSDNode的操作码就是在这一步生成的。3.5.1.CodeGenSchedModels对象一如既往,TableGen对这个选项的入口函数看起来很简单。参数RK就是保存了所有class与def定义的Record实例的...原创 2018-06-08 11:36:43 · 674 阅读 · 0 评论 -
LLVM学习笔记(14)补3
3.3.6.4.6. X86GenRegisterInfo的构造函数接下来这段代码生成目标机器的寄存器描述类型的构造函数,对于X86目标机器,这个类型是X86GenRegisterInfo。1387行的EmitRegMappingTables()方法在前面已经被调用来生成LLVM寄存器编码到GCC/GDB寄存器编码的映射表,而这次的调用参数isCtor是true,因此只产生了这些数组的一个ex...原创 2019-03-22 11:51:32 · 451 阅读 · 0 评论 -
LLVM学习笔记(35)
3.5.1.3.初步构建调度类型每条指令定义中的成员Itinerary是InstrItinClass类型,用以描述该指令的执行步骤。前面我们已经看过一些X86指令定义的例子,其中成员Itinerary被设置为InstrItinClass的派生定义,比如用在指令LOCK_ArithBinOp8mr的IIC_ALU_NONMEM。另外,指令定义里的成员SchedRW(类型list<Sc...原创 2018-06-22 12:01:11 · 793 阅读 · 0 评论 -
LLVM学习笔记(43)
3.6.2.5. 输出代码与数据结构3.6.2.5.1. 资源使用与时延SchedTables保存在WriteProcResources,WriteLatencies,ReadAdvanceEntries以及WriterNames容器里的数据是所有处理器公用的,因此下面的方法首先输出包含这些公用数据的数组。1070 void SubtargetEmitter::EmitSchedCl...原创 2018-10-26 11:31:32 · 594 阅读 · 1 评论 -
LLVM学习笔记(44)
3.6.2.5.3. 处理器特征数据TD文件里通过SubTargetFeature定义来描述处理器所支持的指令集。反映到LLVM上,就体现为类型X86Subtarget(是下面输出X86GenSubtargetInfo类型的派生类)里的一系列开关。对每个处理器,显然会有一个对应的X86Subtarget实例。SubtargetEmitter::run(续)1468 OS <...原创 2018-11-02 11:37:20 · 656 阅读 · 1 评论 -
LLVM学习笔记(45)
3.7.描述调用惯例的数据结构选项“-gen-callingconv”用于生成处理函数调用惯例的代码。调用惯例是函数调用者与被调用者之间关于参数及返回值传递方式的一个共识。存在多个调用惯例,以适合各种机器架构。LLVM目前已经基本能完全通过TableGen生成处理调用惯例的代码。3.7.1.TD的基本类型与描述在文件TargetCallingConv.td里,首先出现...原创 2018-11-16 11:52:54 · 958 阅读 · 0 评论 -
LLVM学习笔记(9)
3.TableGen生成的代码3.1. 概述在编译LLVM时,首先会调用TableGen解析TD文件,产生C++源代码,然后这些C++源代码与LLVM的其他源代码一起被编译为LLVM执行文件。需要解析哪些TD文件是由LLVM/lib/target/target下的Cmakelists.txt文件指定。比如X86机器使用的TD文件有:tablegen(LLVM X86Gen...原创 2017-04-20 11:39:51 · 2771 阅读 · 0 评论 -
LLVM学习笔记(30-2)
3.4.4.3.选择过程3.4.4.3.1. 概述现在我们先看一下下面这个MatcherTable的片段如何指引指令选择。/*0*/ OPC_SwitchOpcode /*284 cases */, 41|128,120/*15401*/, TARGET_VAL(ISD::STORE),// ->15406/*5*/ OPC_RecordMemR...原创 2019-07-26 11:57:16 · 1105 阅读 · 0 评论 -
LLVM学习笔记(17)补
3.4.2.4.3.2. 简化回到TreePattern::InferAllTypes,既然现在类型有可能已经具体化了,那么通过下面的方法尝试简化这棵TreePattern树。2216 static bool SimplifyTree(TreePatternNode *&N) {2217 if (N->isLeaf())2218 return fal...原创 2019-04-12 11:55:09 · 581 阅读 · 0 评论 -
LLVM学习笔记(16)补
2.4.2.4.2.PatFrag的展开在第一步完成后,我们为所有的PatFrag生成了TreePattern实例。接着,2490行的for循环对其中的片段进行展开。在第一次调用ParsePatternFragments()时(CodeGenDAGPatterns构造函数的2355行),展开输入模式。在第二次调用时(CodeGenDAGPatterns构造函数的2358行),展开输出模式(O...原创 2019-04-04 15:03:25 · 492 阅读 · 0 评论 -
LLVM学习笔记(14)补2
3.3.6.4.5. 定义获取权重及压力数据方法目标机器需要提供以下方法来让CodeGen获取权重以及压力数据:getRegPressureLimit(),getRegClassWeight(),getRegUnitWeight(),getNumRegPressureSets(),getRegPressureSetName(),getRegPressureSetLimit(),getReg...原创 2019-03-22 11:49:33 · 437 阅读 · 0 评论 -
LLVM学习笔记(14)补1
3.3.6.4.3. 定义composeSubRegIndicesImpl()方法前面我们已经输出了寄存器索引的数据,这里面包括了复合寄存器索引。我们已经知道复合寄存器索引是两个寄存器索引共同在一个寄存器上作用的结果,它与这两个索引是等价的。比如,R:a:b与R:c都是指向寄存器同一个部分的索引,我们需要一个方法来确定R:a:b与R:c援引的是同一个东西。为此,LLVM提供了一个方法Targe...原创 2019-03-22 11:48:09 · 515 阅读 · 0 评论 -
LLVM学习笔记(47)
3.7.3.TableGen的处理3.7.3.1. 基本数据结构在文件CallingConvLower.h中定义了两个基本的数据结构:CCValAssign与CCState。CCValAssign在编译期间用于记录参数或返回值向寄存器或栈赋值的细节,它定义了以下成员:32 class CCValAssign {33 public:34 ...原创 2018-12-07 11:42:32 · 1039 阅读 · 0 评论 -
LLVM学习笔记(48)
4. 指令选择 4.1. 总述4.1.1. LLVM IR语法这部分内容翻译自《Getting Started with LLVM Core Libraries》一书的第5章第3小节,部分删节。观察Clang编译sum.c文件int sum(int a, int b) { return a+b;}得到的LLVM IR汇编文件,sum.ll:target d...原创 2018-12-14 11:46:36 · 7006 阅读 · 0 评论 -
LLVM学习笔记(46)
3.7.2.2.参数传递惯例接下来定义参数的传递惯例。首先是64位的C传递惯例。251 def CC_X86_64_C : CallingConv<[252 // Handles byval parameters.253 CCIfByVal<CCPassByVal<8, 8>>,254 255 ...原创 2018-11-30 11:03:47 · 773 阅读 · 0 评论 -
LLVM学习笔记(31)
3.4.4.3.3. OPC_SwitchOpcode与OPC_SwitchType等在OPC_MoveChild处,NodeStack记录下子节点,而在OPC_MoveParent处,NodeStack释放栈顶元素。另外,在OPC_RecordNode及OPC_RecordChildN处RecordedNodes记录下这个节点与其父节点,如果父节点存在的话(OPC_CheckComplexP...原创 2018-04-28 11:49:39 · 726 阅读 · 0 评论 -
LLVM学习笔记(16)
3.4.2.4. PatFrag的处理3.4.2.4.1. 模式树的构建PatFrag是一个可重用的构件,TableGen会在PatFrag出现的地方展开其定义,有点像C/C++中的宏。为此,CodeGenDAGPatterns将每个可能嵌入PatFrag的定义——Instruction,Pattern,Pat以及PatFrag,构建为一棵TreePattern树,并在适当的时候将其中包含...原创 2017-08-18 12:05:32 · 2037 阅读 · 0 评论 -
LLVM学习笔记(20)
3.4.3.3. Match对象序列的优化回到DAGISelEmitter::run。注意PatternMatchers中每个项都是一条Matcher对象链,对应一条指令。在160行生成一个ScopeMatcher对象,把这些项设为自己的孩子。在下面生成的MatcherTable里,它产生的内容将使得SelectCommon方法在匹配一个孩子(即一条指令)失败时,继续进行下一个孩子原创 2017-08-18 11:49:42 · 777 阅读 · 0 评论 -
LLVM学习笔记(15)
3.4. DAG指令选择器的生成代码3.4.1. 概述选项-gen-dag-isel用于产生DAG指令选择器,处理这个选项的入口在EmitDAGISel()。TableGen首先根据对指令的描述,为指令定义中的匹配模板(亦称源模板,它指出长怎么样的IR代码片段能匹配这条指令)以及结果模板(它指出匹配成功后指令应该输出怎样的结果,这个结果包含隐含的寄存器的变化)构建DAG实例(下文的展开的T...原创 2017-08-04 11:39:09 · 2145 阅读 · 0 评论 -
LLVM学习笔记(14)
3.3.6.4.CodeGen使用的寄存器描述这部分可视为MC对寄存器信息描述的延伸。MC对寄存器信息的描述也是目标机器所需要的,但MC本身不关心寄存器分配。下面这个函数及其调用的函数将产生一系列重要的数据结构,它们将以C++语言进一步勾画寄存器与寄存器类。这些都将是寄存器分配的算法构成部分。1122 void1123 RegisterInfoEmitter::runTarget...原创 2017-07-14 11:41:46 · 998 阅读 · 0 评论