LLVM Cookbook读书笔记(本书的缺点是直接展示大量Sample代码,对SSA/phi并没有怎么解释,TableGen部分也没讲清楚)
2015-08-26 16:44
639 查看
LLVM Cookbook(Packt,2015)
*重新理解 value --> use(每个IR就是一个value,SSA)builder.GetInsertBlock(); //Codegen: 先有cfg框架,TDD?
if-then-else及for循环:需用PHI合并?(重点)
优化步(IR层)
$ clang -S -O0 -emit-llvm test.cpp
$ opt -O1 -S test.ll (注意:中间分析结果可以共享,如以文件数据库的形式,或VS里的.pdb)
3层概念:Function::iterator --> BasicBlock::iterator --> i->getOpcodeName()
别名分析(AA)
AliasAnalysis:导出AliasResult、ModRefResult(*)
alias(a,b):--> MustAlias(肯定是)、PartialAlias、MayAlias、NoAlias
getAdjustedAnalysisPointer:当用多继承实现了分析接口?
$ opt
--aa-eval ...
--print-dom-info ... (什么是dominator tree?)
--count-aa -basicaa -licm ...
ImmutablePass --> 转换步
LLVMPassManagerRef PM: unwrap(PM)->add(pass);
例,实现DCE(死代码终止),主要思路:开始假设所有IR为dead,然后从根开始,传播liveness
for(Use& OI : inst->operands()) {
if(Instruction* inst_refed = dyn_cast<Instruction>(OI)){ ... //记录到livelist
} for(Instruction& I : inst_range(F)) { ...//第2遍,过滤;
I.dropAllReferences();
} for(Instruction*& I : deadlist)
I->eraseFromParent();
//注意这里的多遍遍历的处理代码;这让我想起了jQuery作者用正则表达式多遍替换实现的Processing.js
函数调用内联
class MyInliner : public Inliner {
...bool runOnSCC(CallGraphSCC& );
InlineCost: getAlways()/getNever() //这算枚举常量吗
Function* callee = callsite.getCalledFunction();
$ opt -memcpyopt
转换前:call void @llvm.memcpy.p0i8.p0i8.i64(i8* %arr_i8, i8* bitcast([3 x i32] * @cst to i8*), i64 12, i32 4, i1 false);
转换后:call void @llvm.memset.p0i8.i64(..., i8 -1, i64 12, ...);
Combining IR(指令序列的替换,Machine dep.)
高效的模式匹配是关键!
LICM(循环不变式外提)
其他:loop-rotate/-unswitch/-unroll
重结合表达式(注意,这些都是标量变换)
Vectorizing IR
? bool matchFlatReduction(PHINode*, BinaryOp*, *DL);
目标无关的代码生成
SelectionDAG合法化
SDNode: target lowering
--> MachineSDNode(.td -->tablegen .inc)拓扑排序/线性化(‘指令调度’?)
寄存器分配
Code emission
addPassesToEmitFile
AsmPrinter
'llc'
MCStreamer
寄存器分配
* 可视化CFG:GraphViz
TableGen(最难理解的东西就是这个!)
class SAMPLEReg< bits<16> Enc, string n> : Register<n> { //每个实例代表一个寄存器;
foreach i=0-3 in { //注意这里的in,参考了ML的语法?
def R#i : R<i, "r"#i>;
...
*定义指令集:#see X86InstrInfo.td
MachineFunction, MachineBasicBlock, MachineInstr(addOperand/MemOperand,隐式参数??)
实现MachineInstrBuilder
BuildMI*
实现MBB
Predecessors/Successors
SplitCriticalEdge*
实现MF
-ConstantPool, -FrameInfo, -FunctionInfo, -RegisterInfo, ...
编写一个指令选择器
Legalizing SelectionDAG(如i64-->i32)
Optimizing SelectionDAG
DAGCombine.cpp ?
从DAG选择指令:SelectionDAGISel(注意这里诡异的ISel后缀,代表指令选择的意思)
指令调度(线性化):DFS,TopSort
优化机器代码:到这里,仍然是SSA形式?
dce, cse(编译原理里面所谓的‘窥孔优化’?):类似于IR,只是多了约束检查(比如RISC流水线/延迟槽?)
分析live intervals(活跃区间)
分配寄存器/SSA解构:phi -> copy
*插入prologue-epilogue代码
TCO
Sibling CO(C++11里的完美转发?)
*编写LLVM后端(除非是做CPU,否则实际中用不到):a Toy backend with r0~r3 + sp + lr(不能再简单了!)
定义calling convention(cc)
定义指令集
frame lowering(?)
sub target(如ARM Neon,Intel SSE/***X)
lowering到多个指令(汇编语言中的‘伪指’)
注册target
LLVM应用
异常:__cxa_throw/begin_catch/end_catch
santizer:shadow内存(hook malloc/free),--> Valgrind
GC:@llvm.gcroot / .statepoint
toJS
bugpoint(类似于git bisect,用于定位LLVM Pass的实现错误)
LLDB(操作的是LLVM最终生成的目标平台机器指令?)
utility步
ClangStaticAnalyzer:符号执行(all path?);ExplodedGraph
相关文章推荐
- myeclipse 中查看jar包的源码
- PHP中使用参数化查询
- [python] UDP客户端/服务器端
- C++ 面向对象 知识点 小结
- java进程 线程分析
- Java多线程 -- 线程的调度-让步
- K2 如何和 Java 做整合?
- JAVA利用JXL导出/生成 EXCEL
- Java如何读取XML文件 具体实现
- java.text.NumberFormat的用法实例
- c#委托、事件
- java
- python email mime使用
- MyEclipse快捷键
- 启动php-fpm报错:please specify user and group other than root
- 通过代码实现---Switch Ribbon Category
- C#中virtual 方法和abstract方法的区别 .
- MyEclipse快捷键大全
- Java多线程 -- 线程的调度优先级
- C++中的引用与指针的区别