LLVM Essentials-Packt 2016(读书笔记):TableGen讲解并不透彻,另外我还想知道后端优化步算法到底怎么编写?
来源:互联网 发布:c语言字符串如何结束 编辑:程序博客网 时间:2024/06/08 00:57
LLVM Essentials
目录
[隐藏]- 1 Playing with LLVM
- 2 Building LLVM IR
- 3 高级IR
- 4 基本IR变换
- 5 高级IR块变换
- 6 IR到Selection DAG阶段
- 7 为目标架构生成代码
Playing with LLVM[编辑]
- 寄存器变量(%var)、栈变量(alloca,%1 ...)、
- .c-->.bc:$ clang -emit-llvm -c main.c
- .bc-->.s:$ llc output.bc –o output.s
- .ll-->.bc:$ llvm-as add.ll –o add.bc
- opt
- -analyze选项:basicaa、da、instcount、loops、scalar evolution
Building LLVM IR[编辑]
static LLVMContext &Context = getGlobalContext();static Module *ModuleOb = new Module("my compiler", Context);
FunctionType *funcType = llvm::FunctionType::get(Builder.getInt32Ty(), false); //注意这里type被简写为Ty了Function *fooFunc = llvm::Function::Create(funcType, llvm::Function::ExternalLinkage, Name, ModuleOb);
这里的‘外部链接’实际上是指导出符号;
BasicBlock* bb = BasicBlock::Create(Context, Name, fooFunc);
全局变量:
ModuleOb->getOrInsertGlobal(Name, Builder.getInt32Ty());GlobalVariable *gVar = ModuleOb->getNamedGlobal(Name); ...//得到:@x = common global i32, align 4
插入返回值语句:
Builder.SetInsertPoint(entry); //注意,SetInsertPoint API显然是有状态的;Builder.CreateRet(Builder.getInt32(0));
设置函数参数:略
分支语句:需要phi merge节点
PHINode *Phi = Builder.CreatePHI(Type::getInt32Ty(getGlobalContext()), PhiBBSize, "iftmp");Phi->addIncoming(ThenVal, ThenBB);Phi->addIncoming(ElseVal, ElseBB); //注意这里由于SSA,bb本身就是value;
循环:略
...Builder.CreateCondBr(EndCond, LoopBB, AfterBB);...
高级IR[编辑]
- getelementptr:offset支持负值吗?
- load
- store
- insertelement(其实不就是给数组元素赋值吗?)
- extractelement
- %0 = extractelement <4 x i32> %a, i32 0 //注意这里数组类型的写法,类型写在变量的前面
基本IR变换[编辑]
- runOn{Passtype}: Module、Function、BasicBlock、Loop
- getAnalysisUsage:指定pass之间的依赖关系
- AU.addRequired<AliasAnalysis>(); //注意这里使用了成员函数模板
- addRequiredTransitive
- addPreserved
- 指令简化
- if (match(Op0, m_Not(m_Specific(Op1))) || match(Op1, m_Not(m_Specific(Op0)))) //注意这里的匹配模板写法
- instcombine:化简成等价且更少的指令
高级IR块变换[编辑]
- Loop processing
- CFG:dominate关系
- 循环规范化:增加preheader、exit block,只允许一个backedge等等
- LoopPass基类、LPPassManager(llvm的类方法命名总是喜欢突然来个缩写,fuck)
- LICM(循环不变式外提)
- 更多的循环优化:lib/Transforms/Scalar
- Scalar evolution(更高级的“抽象解释”?)
- $ opt -analyze -scalar-evolution scalevl.ll
- LLVM intrinsics(编译器内置函数)
- call void @llvm.memset.p0i8.i64(i8* %a2, i8 0, i64 20, i32 16, i1 false) //这让人感觉所谓的LLVM编译器其实只是解释器?(runtime函数)
- %1 = getelementptr inbounds [5 x i32], [5 x i32]* %a, i64 0, i64 0
- Vectorization(不是特别的清楚,“Loop-Aware SLP in GCC”by Ira Rosen, etc?)
- 2种类型:SLP、Loop vectorization
- SIMD
- $ opt -S -basicaa -slp-vectorizer -mtriple=aarch64-unknown-linuxgnu -mcpu=cortex-a57 addsub.ll –debug
IR到Selection DAG阶段[编辑]
- SelectionDAGBuilder:以%add = add nsw i32 %a, %b为例
- SelectionDAGBuilder::visit
- visitAdd
- visitBinary SDValue?
- Legalizing SelectionDAG(合法化,目标平台适配)
- 例:X86上sdiv扩展到sdivrem
- Optimizing SelectionDAG
- DAGCombiner
- AArch64DAGToDAGISel::Select
- Instruction Selection(注意,指令类型平台已经支持了,但是寄存器什么的还没分配呢)
- X86DAGToDAGISel::SelectCode() TableGen自动生成(llvm很难理解的地方就是TableGen的语法)
- Scheduling and emitting machine instructions
- InstrEmitter::EmitMachineNode:SDNode ==> MachineInstr(MachineBasicBlock)
- MachineInstrBuilder
- CreateVirtualRegisters(这里还是‘虚拟寄存器’?)
- virtual AdjustInstrPostInstrSelection
- Register allocation
- spilling
- SSA form deconstruction(phi到reg copy)
- 映射虚拟寄存器到物理寄存器:2种方法
- 直接映射:TargetRegisterInfo/MachineOperand(程序员自己实现?)
- 间接:VirtRegMap::assignVirt2Phys(llvm内置的?)
- llvm 4种分配技术:
- Basic
- Fast
- PBQP
- Greedy
- Code Emission:LLVM JIT和MC(生成obj格式的文件)
- AsmPrinter:使用平台特定的MCInstLowering接口如X86MCInstLower
- MCInst指令传递给MCStreamer对象
- 注意,the MC Layer is one of the big difference between LLVM and GCC.(GCC生成汇编格式的代码,依赖于平台外部汇编?)
- $ llc test.ll -show-mc-encoding -o -
见鬼,我还是没有明白SDAG的作用(LLVM IR里不是有循环吗?为什么SDAG就变成DAG了呢?)
为目标架构生成代码[编辑]
- 没有tablegen,llvm本身只具有学术意义,有了tablegen,llvm才变成了可工业使用的牛逼库
- pipeline:SelectionDAG --> MachineDAG --> MachineInstr --> MCInst
- 定义一个玩具后端:r0-3, sp, pc, cpsr(pc?)
- Defining registers and register sets
- 每个寄存器都有一个唯一编号,这要求平台指令中的寄存器位表示是一致的(当然,有些是隐含的比如push/pop)
- Defining the calling convention(ABI)
- def CC_TOY : CallingConv<[
- CCIfType<[i8, i16], CCPromoteToType<i32>>, //8位、16位的提升到32位
- CCIfType<[i32], CCAssignToReg<[R0, R1]>>,
- CCIfType<[i32], CCAssignToStack<4, 4>> //开始2个参数R0,R1寄存器传递,剩余的通过栈传递
- def CC_Save : CalleeSavedRegs<(add R2, R3)>;
- def CC_TOY : CallingConv<[
- Defining the instruction set
- def ADDrr : InstTOY<(outs GRRegs:$dst), (ins GRRegs:$src1, GRRegs:$src2), "add $dst, $src1,z$src2", [(set i32:$dst, (add i32:$src1, i32:$src2))]>;
- Implementing frame lowering
- Frame lowering involves emitting function prologue and epilogue.(llvm ir是直接定义函数的,包括ret指令)
- void TOYFrameLowering::emitPrologue(MachineFunction &MF) const {
- const TargetInstrInfo &TII = *MF.getSubtarget().getInstrInfo();
- MachineBasicBlock &MBB = MF.front();
- MachineBasicBlock::iterator MBBI = MBB.begin();
- uint64_t StackSize = computeStackSize(MF);
- unsigned StackReg = TOY::SP;
- unsigned OffsetReg = materializeOffset(MF, MBB, MBBI, (unsigned)StackSize);
- ... //略
- Lowering instructions
- 代码略
- Printing an instruction
- Registering a target(略)
0 0
- LLVM Essentials-Packt 2016(读书笔记):TableGen讲解并不透彻,另外我还想知道后端优化步算法到底怎么编写?
- React.js Essentials - Packt 2015(读书笔记)
- LLVM(三):Tablegen简介
- LLVM Cookbook读书笔记(本书的缺点是直接展示大量Sample代码,对SSA/phi并没有怎么解释,TableGen部分也没讲清楚)
- 编写LLVM的后端(一)
- LLVM TableGen介绍
- Mastering Python-Packt Publishing 2016(读书笔记)第1版(讲解3.5的coroutine、asyncio、metaclass等)
- Modular Programming with JavaScript-Packt Publishing 2016(读书笔记)
- LLVM中TableGen工具的使用
- LLVM(二):后端结构
- 我只是想知道怎么加积分。
- Mastering Microservices with Java-Packt Publishing(2016) 读书笔记
- 我只是想知道幾分到底怎麼來的= =、
- LLVM代码研读(3) --- LLVM后端(1): 概述
- 我到底怎么了?
- 我到底怎么啦
- AngularJS Directives-Packt 2013 读书笔记
- 史上最透彻的KMP算法讲解
- Storm命令行客户端
- 自定义绚丽水波纹效果
- 程序员如何优雅度过一生?
- 【转】C#时间格式
- Java synchronized(2)
- LLVM Essentials-Packt 2016(读书笔记):TableGen讲解并不透彻,另外我还想知道后端优化步算法到底怎么编写?
- android 网络编程--socket tcp/ip udp http之间的关系
- Javascript、Jquery获取浏览器和屏幕各种高度宽度
- OC中UIAlertController和UIAlertView用法
- 枚举类型的单例模式(java)
- [leetcode] 304. Range Sum Query 2D - Immutable
- jquery获取单选框复选框下拉框值
- Xcode: No matching provisioning profiles found
- 'ascii' codec can't decode byte 0xe4 in position 0: ordinal not in range(128)