交叉编译 llvm

转自:  llvm - 韦任的维基百科 

www.cs.nctu.edu.tw

 

編譯 LLVM
使用 llvm-top。
# llvm-top 抓取的是 svn 版本,而非 release 版本。
# --enable-optimized=no 可以建置除錯版本。
$ svn co http://llvm.org/svn/llvm-project/llvm-top/trunk/ llvm-top
$ cd llvm-top
$ ./build OPTIMIZED=1 PREFIX=$INSTALL llvm llvm-gcc-4.2
或是手動。
# git clone http://llvm.org/git/llvm.git
$ wget http://llvm.org/releases/2.8/llvm-2.8.tgz; tar xvf llvm-2.8.tgz;
# 如果要編譯 clang。下載源碼至 tools/clang。
$ wget http://llvm.org/releases/2.8/clang-2.8.tgz -P llvm-2.8/tools/clang
$ mkdir build; cd build
# env CFLAGS=-fno-strict-aliasing CXXFLAGS=-fno-strict-aliasing cmake -i ../llvm-2.8
# 建議加上 --enable-targets 指定目標平台。$BUILD/Release/bin 裡面有些工具不會安裝到 $INSTALL。
$ ../llvm-2.8/configure --prefix=$INSTALL --enable-optimized
$ make install
交叉編譯
在 x86_64 上編譯出可以在 arm 上運行的 LLVM 執行檔和函式庫

[LLVMdev] Compilation error while cross compiling LLVM for ARM
[LLVMdev] Compilation error while cross compiling LLVM for ARM - the __clear_cache issue
make[4]: Entering directory `/nfs_home/chenwj/test/cross-build/arm2xbuild/tools/clang/tools/c-index-test'
llvm[4]: Linking Debug executable c-index-test
/nfs_home/chenwj/x-tools/arm2/lib/gcc/arm-unknown-linux-gnueabi/4.4.1/../../../../arm-unknown-linux-gnueabi/bin/ld: /nfs_home/chenwj/test/cross-build/arm2xbuild/Debug/bin/c-index-test: hidden symbol `__sync_val_compare_and_swap_4' in /nfs_home/chenwj/x-tools/arm2/lib/gcc/arm-unknown-linux-gnueabi/4.4.1/libgcc.a(linux-atomic.o) is referenced by DSO
/nfs_home/chenwj/x-tools/arm2/lib/gcc/arm-unknown-linux-gnueabi/4.4.1/../../../../arm-unknown-linux-gnueabi/bin/ld: final link failed: Nonrepresentable section on output
collect2: ld returned 1 exit status
下載交叉編譯工具鏈或是使用 crosstool-NG 自行編譯工具鏈
# http://www.codesourcery.com/sgpp/lite/arm
$ wget http://www.codesourcery.com/sgpp/lite/arm/portal/package8739/public/arm-none-linux-gnueabi/arm-2011.03-41-arm-none-linux-gnueabi-i686-pc-linux-gnu.tar.bz2
$ tar xvf arm-2011.03-41-arm-none-linux-gnueabi-i686-pc-linux-gnu.tar.bz2
$ export PATH=/PATH/TO/arm-2011.03/bin:$PATH
下載 LLVM
$ wget http://llvm.org/releases/2.9/llvm-2.9.tgz; tar xvf llvm-2.9.tgz
$ wget http://llvm.org/releases/2.9/llvm-gcc4.2-2.9-x86_64-linux.tar.bz2; tar xvf llvm-gcc4.2-2.9-x86_64-linux.tar.bz2
# 如有需要 LLVM gold plugin,再下載支援 plugin 的 binutils
$ wget http://ftp.gnu.org/gnu/binutils/binutils-2.21.1.tar.gz; tar xvf binutils-2.21.1.tar.gz -C llvm-2.9
編譯支援 plugin 的 binutils (可選)
$ cd llvm-2.9/binutils-2.21.1
$ ./configure --target=arm-linux --prefix=/tmp/chenwj/llvm-2.9/arm --disable-optimized --enable-bindings=none \
--disable-multilib --disable-bootstrap --with-sysroot=/tmp/chenwj/llvm-2.9/arms/sys-root \
--with-binutils-include=/tmp/chenwj/llvm-2.9/binutils-2.21/include/ \
--with-llvmgccdir=/tmp/chenwj/llvm-gcc4.2-2.9-x86_64-linux
$ make && make install
編譯 LLVM。arm-none-linux-gnueabi 依照 toolchain 的名稱設置,否則 config 會找不到該 toolchain。
–target 代表為該目標編譯 LLVM
–host 代表編譯出來的 LLVM 所運行的平台。
–with-sysroot 編譯一個依賴於較多函式庫的程式時,用于指定編譯所需要的頭文件,及鏈接庫。
$ cd ../../; make build; cd build
$ ../llvm-2.9/configure --target=arm-none-linux-gnueabi \
--host=arm-none-linux-gnueabi \
--prefix=$INSTALL \
--enable-targets=arm \
--disable-optimized --enable-bindings=none --disable-multilib --disable-bootstrap \
LLVM-GCC
LLVM-GCC 由 gcc-4.2 修改而來,建議使用 dragonegg 或是 clang。configure 時所下的參數務必參考預編好的執行檔。

$ llvm-gcc -v
或是下載預編好的執行檔。

$ wget http://llvm.org/releases/2.8/llvm-gcc4.2-2.8-x86_64-linux.tar.bz2
在 Linux/PS3 上編譯時,請參考 Building LLVM-GCC on Linux/PowerPC failed 。

$ wget http://llvm.org/releases/2.8/llvm-gcc-4.2-2.8.source.tgz; tar vxf llvm-gcc-4.2-2.8.source.tgz
$ mkdir build; cd build
$ ../llvm-gcc-4.2-2.8.source/configure --prefix=/path/to/install \
--program-prefix=llvm- \
--enable-llvm=/path/to/llvm-obj \
--enable-languages=c,c++ \
--disable-bootstrap \
--disable-libmudflap \
--disable-multilib \
--disable-libgomp
$ make install
PowerPC32/64 的函式庫目前無法同時存在。編譯 llvm-gcc 會出現類似以下訊息,需要加上 –disable-multilib 要求其編譯時只編譯 32/64 其中之一的函式庫。

../../llvm-gcc-4.2-2.8.source/gcc/crtstuff.c:1: error: -m64 requires a
PowerPC64 cpu
make[5]: *** [32/crtbegin.o] Error 1
交叉編譯
[LLVMdev] llvm-gcc cross compiling for ARM
[LLVMdev] linker errors when trying to link llvm-gcc
以上皆為在 x86 運行產生 arm binary 的 llvm-gcc
# llvm-g++ 還不成功
# llvm-gcc -emit-llvm ok
# 但無法生成 arm binary
TRIPLE="arm-unknown-linux-gnueabi"
PREFIX="arm-unknown-linux-gnueabi-armv6l-gcc441"
XTOOL="${HOME}/x-tools/${PREFIX}/bin"
XXX="${HOME}/x-tools/${PREFIX}/arm-unknown-linux-gnueabi"
 
PATH="/usr/local/bin:/usr/bin:/bin:/opt/bin:/usr/x86_64-pc-linux-gnu/gcc-bin/4.4.2"
export PATH=${XTOOL}:$PATH
 
INSTALL="${HOME}/test/install"
 
../llvm-gcc-4.2-2.9.source/configure --build=x86_64-unknown-linux-gnu \
--target=arm-unknown-linux-gnueabi \
--host=arm-unknown-linux-gnueabi \
--program-prefix=llvm- \
--enable-llvm=$HOME/test/llvm-obj \
--prefix=$INSTALL \
--with-gnu-ld=${XXX}/bin/ld \
--with-gnu-as=${XXX}/bin/as \
--with-gnu-ar=${XXX}/bin/ar \
--with-sysroot=${XXX}/sysroot \
--disable-bootstrap -disable-optimized --disable-multilib --enable-checking \
--disable-shared --enable-languages=c
確定 build、target 和 host 皆正確。
../../llvm-gcc-4.2-2.7.source/gcc/config/arm/lib1funcs.asm: Assembler messages:
../../llvm-gcc-4.2-2.7.source/gcc/config/arm/lib1funcs.asm:1004:
Error: backward ref to unknown label "8:"
ELLCC - The Embedded LLVM Compiler Collection
自舉
如何判斷 GCC 或是 LLVM 有問題 1) ?

編譯 LLVM 失敗,代表 GCC 有問題。
先用 GCC 編譯 LLVM + Clang,再用該編譯好的 LLVM + Clang 編譯 LLVM + Clang,最後執行 `make check` 2)
先用 GCC 編譯 LLVM + Clang
$ wget http://llvm.org/releases/2.9/llvm-2.9.tgz; tar xvf llvm-2.9.tgz
$ cd llvm-2.9/tools
$ wget http://llvm.org/releases/2.9/clang-2.9.tgz; tar xvf clang-2.9.tgz
$ mv clang-2.9 clang
# 注意! 檢查 clang/lib/Frontend/InitHeaderSearch.cpp 是否有加入本機 C++ 標頭檔搜尋路徑
$ mkdir build; cd build
$ ../llvm-2.9/configure --prefix=$INSTALL --enable-optimized
$ make; make install
再用該編譯好的 LLVM + Clang 編譯 LLVM + Clang。必須先下載必要的標頭檔3)4)。
$ wget http://home.roadrunner.com/~hinnant/libcppabi.zip; unzip libcppabi.zip
$ cp cxxabi.h $INSTALL/lib/clang/2.9/include
$ CC=/path/to/clang CXX=/path/to/clang++ ../llvm-2.9/configure --prefix=$INSTALL --enable-optimized
$ make
使用範例
輸出 LLVM 組語。

$ llvm-gcc -S -emit-llvm hello.c -o hello.ll
組譯 LLVM 組語。

$ llvm-as hello.ll -o hello.bc
以直譯的方式 (若平台支援 JIT,使用 JIT) 執行。

$ lli hello.bc
如果想要使用 LLVM 的標頭檔和函式庫。

$ gcc `llvm-config --cxxflags --ldflags` foo.c `llvm-config --libs`
LLVM IR
Go to http://llvm.org/demo/
Click "Show LLVM C\+\+ API code"
Click "Compile Source Code"
'call' Instruction
  // = call [*] () [fn attrs]
  %0 = call i32 (i8*, ...)* @printf(i8* noalias getelementptr inbounds ([3 x i8]* @.str, i64 0, i64 0)) nounwind
  // 準備 printf 的 prototype,即 i32 (i8*, ...)。
  PointerType* PointerTy_4 = PointerType::get(IntegerType::get(mod->getContext(), 8), 0);
 
  std::vector FuncTy_8_args;
  FuncTy_8_args.push_back(PointerTy_4);
  FunctionType* FuncTy_8 = FunctionType::get(
    /*Result=*/IntegerType::get(mod->getContext(), 32),
    /*Params=*/FuncTy_8_args,
    /*isVarArg=*/true);
 
  Function* func_printf = mod->getFunction("printf");
  // 如果當前 module 並無 printf,就自己建一個 printf 空殼。
  // 等之後 JIT 產生 native code 並與 C 函式庫鏈結時再做解析。
  if (!func_printf) {
    func_printf = Function::Create(
      /*Type=*/FuncTy_8,
      /*Linkage=*/GlobalValue::ExternalLinkage,
      /*Name=*/"printf", mod); // (external, no body)
    func_printf->setCallingConv(CallingConv::C);
  }
  AttrListPtr func_printf_PAL;
  func_printf->setAttributes(func_printf_PAL);
 
  // 準備參數 const_ptr_12,並呼叫 printf。
  CallInst::Create(func_printf, const_ptr_12, "", BB);
[LLVMdev] insert printf into IR
[LLVMdev] inserting a print statement into IR
[LLVMdev] How to create a CallInst that calls a standard c function like "printf"
LLVM Internal
請見 Chapter 11. LLVM 和 Design and Implementation of a TriCore Backend for the LLVM Compiler Framework。

LLVM IR 並非平台中立。請見 More Target Independent LLVM Bitcode 和 [LLVMdev] LLVM IR is a compiler IR。

Pass
請見 Writing an LLVM Pass 和 Demystifying The LLVM Pass Manager。

$ opt -load=install/lib/libLLVMHello.so -hello < hello.bc > /dev/null
如果出現底下錯誤訊息,請確定 opt 和 libLLVMHello.so 是同一份源碼和設定建置而成。

Error opening 'install/lib/libLLVMHello.so': install/lib/libLLVMHello.so: undefined symbol: _ZN4llvm4Pass26getAdjustedAnalysisPointerEPKv
  -load request ignored.
LLVM's Analysis and Transform Passes
JIT
目前支援 JIT 的平台請見 Target Feature Matrix。基本上只有 x86 的 JIT 確定可以運作,其它平台未知。

Adding LLVM JIT facility to your program
$(LLVM_SRC_ROOT)/examples/HowToUseJIT
Building An Ef cient JIT
JIT Support
目前 PowerPC 似乎有問題5)6)。

The PowerPC backend
PowerPC assembly
A developer's guide to the POWER architecture
Understanding 64-bit PowerPC architecture
64-bit PowerPC ELF Application Binary Interface Supplement 1.9
Code Generator
如同 Design and Implementation of a TriCore Backend for the LLVM Compiler Framework 第 12 頁所展示的,LLVM 後端的流程如下:

LLVM IR -> DAG Lowering -> non-legalized DAGs -> DAG Legalization -> legalized DAGs
  -> Instruction Selection -> DAGs (native instructions, MI) -> Scheduling
  -> SSA Form -> SSA-based Opt -> SSA Form -> Register Allocation
  -> native instrictions with phys reg -> Post Allocation
  -> Prolog/Epilog Code Insertion -> resolved stack reference
  -> Peehole Opt -> Assembly Printing -> assembly
Tutorial: Building a backend in 24 hours (2012) 第 3 頁展示各個階段分別為何種形式的中介碼。

Overview
LLVM IR → SelectionDAG: 這一步驟是為了將來方便做 instruction selection 和 instruction scheduling。SelectionDAG 此一結構適合自動產生的 instruction selector (dynamic-programming based optimal pattern matching selectors),LLVM 透過 tblgen 部分產生 instruction selector,其餘部分需客製化。請見 Introduction to SelectionDAGs。又分為底下幾個步驟:
透過 SelectionDAGLowering 將 LLVM IR 轉成 SelectionDAG,簡稱 DAG。所得到的 DAG 可能會出現目標平台不支援的型別或是運算,因此稱此階段的 DAG 為 Non-legalized DAG。請見 Initial SelectionDAG Construction。做一次 SelectionDAG Optimization,其目的是做一些簡單的優化。
將 non-legalized DAG 轉成 legalized DAG。請見 SelectionDAG LegalizeTypes Phase 和 SelectionDAG Legalize Phase。先將目標平台不支援的型別消除,做一次 SelectionDAG Optimization,其目的是清除一些圾垃代碼。再消除目標平台不支援的運算,再做一次 SelectionDAG Optimization。請見 SelectionDAG Optimization Phase: the DAG Combiner。
SelectionDAG → DAG (Machine Code): 請見 SelectionDAG Select Phase。注意! 此階段所得的目標代碼仍使用 virtual register,留待之後 register allocation 配置暫存器。
DAG (Machine Code) → MachineInstr: 對所得 DAG 進行 scheduling,這裡會根據目標平台的一些限制指定節點之間的順序,最終得到一串 MachineInstr (SSA),並銷毀 DAG。請見 SelectionDAG Scheduling and Formation Phase。
MachineInstr (SSA): 對所得 MachineInstr 進行 SSA 相關優化。
[LLVMdev] Code instruction selection based on SSA-graphs
LLVM 是利用 tblgen 讀取目標平台特定的 td 檔生成 instruction selector,instruction scheduling,register allocation 和 assembly printing。請見 TableGen Fundamentals。

$ cd ${LLVM_SRC}/utils/TableGen
# 生成 x86 指令描述
$ tblgen -I ../../include/ -I ../../lib/Target/X86/ -gen-instr-desc ../../lib/Target/X86/X86.td
LLVM 後端基本上有三類 IR (LLVM + ARM = ?),由上至下依序是:

SelectionDAG
MachineInstr (MI)
MachineCode (MCInst)
後兩者的名稱容易被混淆。關於 MachineInstr 請見 Machine code description classes; 關於 MachineCode 請見 The "MC" Layer。以下就這兩者作簡單介紹:

MachineInstr: SelectionDAG 最終會轉成 MachineInstr。MachineInstr 是目標機器碼的抽象,可以表示成 SSA 和 non-SSA 形式。在 register allocation 之前/後,分別為 SSA 和 non-SSA 形式。
MachineCode: Code Emission 負責將 MachineInst 轉成 MachineCode。MachineCode 處理最後生成的機器碼 。
SelectionDAG
${LLVM_SRC}/Target/TargetSelectionDAG.td 定義了 LLVM IR 對應的 SDNode。SelectionDAG 主要由 SDNode 構成,其運算元為 SDUse,其輸出為 SDValue。SDNode 之間有 data 或 control (chain) dependency,CodeGen Overview and Focus on SelectionDAGs 中黑色箭頭代表 data dependency,藍色箭頭代表 control dependency。EntryToken 和 TokenFactor 負責 control dependency。GraphRoot 代表 SelectionDAG 的最底層。PTXInstrInfo.td 再將 SDNode 轉成相應的 machine code。SelectionDAG 主要有底下幾個流程:

Lower: 將 LLVM IR 轉換成 SelectionDAG
Combine: peephole opt,將若干 SDNode 合成一個 SDNode。
Legalize: 將 target machine 不支援的運算轉換成支援的運算。
Combine: 更多的優化。
Select: instruction selection。
Schedule: instruction scheduling。
Instruction scheduling 的單位是 SUnit。

The LLVM Target-Independent Code Generator
Tutorial: Building a backend in 24 hours
[LLVMdev] Traverse SelectionDAG in gdb
[LLVMdev] Understanding SelectionDAG construction
Understanding and writing an LLVM compiler back-end
LLVM Code Generator
[LLVMdev] What CCAssignToXXXWithShadow means?
針對 ARM 体系結构的應用程序二進制接口 (ABI)
Procedure Call Standard for the ARM Architecture (AAPCS)
Register Allocation
LLVM Register Allocation (2008)
Future Works in LLVM Register Allocation (2009)
Register Allocation in LLVM 3.0 (2011)
Writing Backend
http://people.cs.nctu.edu.tw/~chenwj/slide/LLVM/LLVM-how-to-add-backend.txt
欲寫一個後端,基本上需要底下幾個檔案 (Tutorial: Building a backend in 24 hours (2012)),以 MIPS architecture 為例:
FooTargetMachine.[ch]: 後端的主要類別,負責膠合其它後端類別並負責控制後端管線。請見 Target Machine。
FooSubtarget.[ch]: 一個 TargetMachine 可能有多個子目標,控制不同子目標的特性。請見 Subtarget Support。
FooRegisterInfo.td: 定義目標平台的暫存器和暫存器組,暫存器組指對某一類指令而言,該暫存器組會被以相同方式對待。請見 Register Set and Register Classes
// 基本樣板類 MipsReg,供後續類別繼承。MipsReg 繼承 Register (include/llvm/Target/Target.td)。
// We have banks of 32 registers each.
class MipsReg : Register {
  field bits<5> Num; // 每一個暫存器皆可用 5 bit 的識別符表示。
  let Namespace = "Mips";
}

// 通用暫存器,共 32 個。
// Mips CPU Registers
class MipsGPRReg num, string n> : MipsReg {
  let Num = num;
}

// ZERO 是該暫存器的別稱。DwarfRegNum 其值用來生成除錯資訊。
let Namespace = "Mips" in {
  // General Purpose Registers
  def ZERO : MipsGPRReg< 0, "zero">, DwarfRegNum<[0]>;
  def AT   : MipsGPRReg< 1, "at">,   DwarfRegNum<[1]>;

  ... 略 ...
}

// 定義暫存器類。
// "Mips" 表所在的命名空間,[i32] 代表此類暫存器皆為 32 int,32 代表從內存讀或寫的對齊要求,最後指定有哪些暫存器屬於此類。
def CPURegs : RegisterClass<"Mips", [i32], 32, (add
  // Reserved
  ZERO, AT,
  // Return Values and Arguments
  V0, V1, A0, A1, A2, A3,
  // Not preserved across procedure calls
  T0, T1, T2, T3, T4, T5, T6, T7,
  // Callee save
  S0, S1, S2, S3, S4, S5, S6, S7,
  // Not preserved across procedure calls
  T8, T9,
  // Reserved
  K0, K1, GP, SP, FP, RA)>;
FooRegisterInfo.[ch]: 部分由 FooRegisterInfo.td 生成。提供關於暫存器組的各項資訊,諸如: 被調用方保存暫存器,暫存器分配次序等等。
FooInstrFormats.td: 描述如何從 DAG 對應到目標指令。參閱 include/llvm/Target/Target.td,從 DAG (MI) 轉成目標匯編。
class Format val> {
  bits<4> Value = val;
}

// Generic Mips Format
class MipsInst pattern,
               InstrItinClass itin, Format f>: Instruction
{
  // MIPS 指令長度為 32 bit。
  field bits<32> Inst;
  Format Form = f;

  let Namespace = "Mips";

  bits<6> Opcode = 0;

  // Top 6 bits are the 'opcode' field
  let Inst{31-26} = Opcode;

  let OutOperandList = outs; // An dag containing the MI def operand list.
  let InOperandList  = ins;  // An dag containing the MI use operand list.

  let AsmString   = asmstr;  // The .s format to print the instruction with.
  let Pattern     = pattern; // Set to the DAG pattern for this instruction.
  let Itinerary   = itin;    // Execution steps used for scheduling.

  //
  // Attributes specific to Mips instructions...
  //
  bits<4> FormBits = Form.Value;

  // TSFlags layout should be kept in sync with MipsInstrInfo.h.
  let TSFlags{3-0}   = FormBits;
}
FooISelLowering.[ch]: 負責將 LLVM IR 降轉成近似目標平台中介碼的主要類別,以便後續選取指令。
FooISelDAGToDAG.cpp: 負責指令選取。請見 Instruction Set。
FooInstrInfo.[ch]
FooInstrInfo.td: include/llvm/Target/TargetSelectionDAG.td 定義各種 SDNode 型別。請見 Instruction Set。
// 自訂義 SDTypeProfile 描述該 SDNode 各項屬性: 輸出/入個數等等。
def SDT_MipsJmpLink      : SDTypeProfile<0, 1, [SDTCisVT<0, iPTR>]>;

// 自訂義 SDNode。"MipsISD::JmpLink" 為 opcode, SDT_MipsJmpLink 為其屬性
// Call
def MipsJmpLink : SDNode<"MipsISD::JmpLink",SDT_MipsJmpLink,
                         [SDNPHasChain, SDNPOutGlue, SDNPOptInGlue,
                          SDNPVariadic]>;


// Arithmetic and logical instructions with 3 register operands.
class ArithLogicR op, bits<6> func, string instr_asm, SDNode OpNode,
                  InstrItinClass itin, RegisterClass RC, bit isComm = 0>:
  //
  //
  // outs RC:$rd - 輸出
  // ins RC:$rs, RC:$rt - 輸入
  // !strconcat(instr_asm, "\t$rd, $rs, $rt") - 組語
  // [(set RC:$rd, (OpNode RC:$rs, RC:$rt))] - 將運算結果存至 RC:$rd
  // itin - 指定調度順序
  FR      !strconcat(instr_asm, "\t$rd, $rs, $rt"),
     [(set RC:$rd, (OpNode RC:$rs, RC:$rt))], itin> {
  let shamt = 0;
  let isCommutable = isComm;
  let isReMaterializable = 1;
}

/// Arithmetic Instructions (3-Operand, R-Type)
def ADDu    : ArithLogicR<0x00, 0x21, "addu", add, IIAlu, CPURegs, 1>;
FooCallingConv.td: 調用約定。請見 Instruction Selector。
FooFrameLowering.[ch]
FooMCInstPrinter
修改 include/llvm/ADT/Triple.h 和 lib/Support/Triple.cpp 添加新增的後端。
基本上需要底下幾樣:
Registers: 定義目標的暫存器和暫存器組。
Calling Convention: 定義目標的調用約定。
include/llvm/Target/TargetSelectionDAG.td 定義各種 SDNode 型別。
// SDTypeProfile - This profile describes the type requirements of a Selection
// DAG node.
class SDTypeProfile                     list constraints> {
  int NumResults = numresults; // 輸出個數。
  int NumOperands = numoperands; // 輸入個數。
  list Constraints = constraints; // 有何限制。
}

// SDTCisInt - The specified operand has integer type.
class SDTCisInt : SDTypeConstraint;

// SDTCisSameAs - The two specified operands have identical types.
class SDTCisSameAs : SDTypeConstraint {
  int OtherOperandNum = OtherOp;
}

// 一個輸出,兩個輸入,輸出和輸入的型別皆一致,輸入 0 必須為整型。
def SDTIntBinOp : SDTypeProfile<1, 2, [     // add, and, or, xor, udiv, etc.
  SDTCisSameAs<0, 1>, SDTCisSameAs<0, 2>, SDTCisInt<0>
]>;

// 可以自定義 SDNode。
class SDNode              list props = [], string sdclass = "SDNode">
             : SDPatternOperator {
  string Opcode  = opcode;
  string SDClass = sdclass;
  list Properties = props;
  SDTypeProfile TypeProfile = typeprof;
}
include/llvm/Target/TargetItinerary.td 定義指令調度順序。
lib/Target/Mips/MipsSchedule.td 定義 Mips 指令調度順序。
//===----------------------------------------------------------------------===//
// Functional units across Mips chips sets. Based on GCC/Mips backend files.
//===----------------------------------------------------------------------===//
def ALU     : FuncUnit;
def IMULDIV : FuncUnit;

//===----------------------------------------------------------------------===//
// Instruction Itinerary classes used for Mips
//===----------------------------------------------------------------------===//
def IIAlu              : InstrItinClass;

... 略 ...

// Mips Generic instruction itineraries.
//===----------------------------------------------------------------------===//
def MipsGenericItineraries : ProcessorItineraries<[ALU, IMULDIV], [], [
  InstrItinData]>,
  InstrItinData]>,
  InstrItinData]>,
  InstrItinData]>,
  InstrItinData]>,
  InstrItinData]>,
  InstrItinData]>,
  InstrItinData]>,
  InstrItinData]>,
  InstrItinData]>,
  InstrItinData]>,
  InstrItinData]>,
  InstrItinData]>,
  InstrItinData]>,
  InstrItinData]>,
  InstrItinData]>,
  InstrItinData]>,
  InstrItinData]>,
  InstrItinData]>
]>;
Writing an LLVM Compiler Backend
Tutorial: Building a backend in 24 hours (2009)
Understanding and writing an LLVM compiler back-end
The LLVM Target-Independent Code Generator
Tutorial: Building a backend in 24 hours (2012)
Write a llvm backend
https://github.com/Jonathan2251/lbd.git
Data Layout
Assembler
The LLVM Assembler & Machine Code Infrastructure
LLVM MC In Practice
Linker
LLVM Linker
Object Files in LLVM
Object Code Emission & llvm-mc
[LLVMdev] Native linker
MCLinker - An LLVM Integrated Linker
[LLVMdev] Proposal: MCLinker - an LLVM integrated linker
其它
請到 LLVMdev 訂閱郵件列表。過去的郵件列表請見 The LLVMdev Archives 和 LLVM - Old Nabble。

# 查看 macro 展開後的結果
$ gcc -E $(llvm-config --cppflags) lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
SROA (Scalar Replacement of Aggregates)
LLVM 子計畫
clang
Address Sanitizer
DragonEgg - 前端為 gcc45,優化和代碼生成使用 LLVM 的元件。
llvm-mc
The x86 Disassembler
Intro to the LLVM MC Project
The LLVM Assembler & Machine Code Infrastructure
[LLVMdev] MC-JIT Design
[LLVMdev] MC-JIT
[LLVMdev] MC-JIT (any progress?)
PoolAlloc
[LLVMdev] LLVM Automatic Pool Allocation
GSoC 2011- LLVM PTX Back-End - PTX 目前還不成熟 7)。
PTX target for LLVM?
PTX target for LLVM!
Status of PTX Backend
PTX Backend for LLVM 採取撰寫 pass 將 LLVM IR 轉成 PTX IR。目前在 LLVM 代碼中的是採取撰寫 backend 的方式。
Polly: Polyhedral optimizations for LLVM
Clay Programming Language
Exception Handling
處理例外的代碼位於 landingpad。

The new LLVM exception handling scheme
Exception Handling in LLVM
LLVM 3.0 Exception Handling Redesign
[LLVMdev] landingpad instruction documentation is vague
CFG
請先安裝 graphviz 以便將 dot 轉成圖檔。opt 以函式為單位輸出 dot 檔。

$ llvm-gcc -emit-llvm -o hello.bc -c hello.c
# -dot-cfg-only 不會產生 LLVM IR
$ opt -dot-cfg hello.bc
$ dot -Tpng cfg.main.dot > cfg.main.png
[LLVMdev] CFG Manipulation is LLVM
[LLVMdev] CFG using LLVM
[LLVMdev] Help : CFG in LLVM ( Implementation)
ParFor Clang Wiki
MC/MCDisassembler.h 是否能把 binary 轉成 CodeGen/MachineLoopInfo.h 看得懂的東西?

論文
Ef cient Pro ling in the LLVM Compiler Infrastructure
Implementation of Path Profiling in the Low-Level Virtual-Machine (LLVM) Compiler Infrastructure
Profiling & Instrument
$ llvm-gcc -emit-llvm -c hello.c -o hello.bc
$ opt -insert-path-profiling -o hello.pp.bc hello.bc
$ llvm-dis hello.bc
$ llvm-dis hello.pp.bc
$ vimdiff hello.bc hello.pp.bc
可以看出 path profiling 的確會插入一些 instrument code。其它 instrument 選項請見 LLVM's Analysis and Transform Passes。

$ llvm-ld -L=/tmp/chenwj/install/lib -lprofile_rt -native -o hello hello.pp.bc
$ export LD_LIBRARY_PATH=/path/to/lib/
# 預設輸出檔名為 llvmprof.out
$ ./hello
$ llvm-prof hello.bc llvmprof.out
可以用更簡便的方式執行上述流程。

$ ./${LLVM_SOURCE}/utils/profile.pl hello.bc
Determine branch coverage information
LLVM profiling
Online opt style code pass / profiling possible in LLVM JIT?
LTO
LLVM Link Time Optimization: Design and Implementation
LLVM gold plugin
測試
詳細請見 LLVM Testing Infrastructure Guide。

Regression Test
7.7 回歸測試(Regression Test)
$ cd ${LLVM_SOURCE}
# make check 跑所有的測試程式
$ ./configure; make; make check
# 直接運行 llvm-lit 跑特定的測試程式
$ ./Release/bin/llvm-lit -v test/CodeGen/PTX/options.ll
Test Suite
請見 Test suite Structure 和 Running the test suite。似乎需要安裝 tcl/tclsh。

安裝 virtualenv。How to install Virtualenv in Linux
$ sudo apt-get install python-virtualenv
下載 LLVM 和 LLVM Test Suite
$ wget http://llvm.org/releases/2.9/llvm-2.9.tgz; tar xvf llvm-2.9.tgz
$ cd llvm-2.9/projects
$ wget http://llvm.org/releases/2.9/llvm-test-2.9.tgz; tar xvf llvm-test-2.9.tgz
$ mv llvm-test-2.9 test-suite
下載 LLVM-GCC
$ wget http://llvm.org/releases/2.9/llvm-gcc4.2-2.9-x86_64-linux.tar.bz2
$ tar xvf llvm-gcc4.2-2.9-x86_64-linux.tar.bz2 -C $INSTALL
$ export PATH=$INSTALL/llvm-gcc4.2-2.9-x86_64-linux/bin:$PATH
編譯 LLVM
# 如果 PATH 已包含 LLVM-GCC 路徑,則不需要 --with-llvmgccdir 參數
$ ../llvm-2.9/configure --with-llvmgccdir=$INSTALL
$ make
運行 test suite
$ cd projects/test-suite
# 運行所有 test suite
$ make
# 運行特定 test suite。例如存在 TEST.jit.Makefile 此檔,則可下底下指令。但並非所有 TEST..Makefile 皆適用。
# 若是 TEST 給錯名稱,錯誤訊息會給出可使用的 TEST 名稱。
$ make TEST=jit
# 忽略編譯錯誤
$ make -i
# 強烈建議只在子目錄底下運行 test case,以免花太多時間。
$ cd SingleSource/Regression
$ TARGET_LLVMGCC=/path/to/llvm-gcc TARGET_LLVMGXX=/path/to/llvm-g++ make -i TEST=jit report
# 使用 clang 而非 llvm-gcc
$ TARGET_LLVMGCC=/path/to/clang TARGET_LLVMGXX=/path/to/clang++ make -i TEST=jit report
LLVM 3.0 之後改用 LNT,LNT 預設針對 release 版本進行測試,只吃完整路徑 8)。Python 的虛擬環境及多版本開發利器─Virtualenv 與 Pythonbrew
$ virtualenv ~/mysandbox
$ svn co http://llvm.org/svn/llvm-project/lnt/trunk ~/lnt
$ ~/mysandbox/bin/python ~/lnt/setup.py develop
# cd mysandbox/local
$ cd mysandbox
$ source bin/activate
# 不可用 ../llvm.obj/Release/bin/clang
$ lnt runtest nt \
    --sandbox SANDBOX \
    --cc ~/llvm.obj/Release/bin/clang \
    --cxx ~/llvm.obj.64/Release+Asserts/bin/clang++ \
    --llvm-src ~/llvm \
    --llvm-obj ~/llvm.obj.64 \
    --test-suite ~/llvm-test-suite \
    -j 2 --only-test SingleSource
需要安裝 flex 和 bison。
觀察效能。
$ lnt create ~/myperfdb
$ cd ~/myperfdb
# 測試 builtin server
$ ./lnt.wsgi
[LLVMdev] LLVM / CLANG Test Infrastructure Question
[LLVMdev] SPEC CPU2006 bitcode files
FileCheck
Buildbot
How To Add Your Build Configuration To LLVM Buildbot Infrastructure
補丁 & 臭蟲
臭蟲請發送到這裡 並先閱讀 How To Submit A Bug。以 [llvm-commits][PATCH] 為標題且補丁為附件 (Linux 內核要求則不同 Linux kernel patch format) 發送至 llvm-commits 郵件列表,並請先閱讀 Making a Patch。範例標題: [llvm-commits][PATCH][Target/PTX]。

LLVM bugpoint tool
bugpoint
Submitted Patch
ARM JIT9)10)。

後端
[LLVMdev] Early-clobber constraint in TableGen
如果一條指令的源暫存器和目的暫存器不能相同,用 @earlyclobber。
Q & A
是否有介面可用來指定保留平台特定暫存器以供其它用途使用?
似乎不能,必須修改 TargetRegisterInfo.cpp 要求保留特定暫存器。Pinning registers in LLVM11)12)
JIT 是否能支援 inline assembly?
基本上,JIT 不支援 inline assembly,因為這需要 JIT 有內建的組譯器才能將 inline assembly 解譯。目前僅有 x86 以手寫編碼的方式支援少部分的 inline assembly。目前有 MC-JIT 被提出並進行非常初步的實作,其作法是將組譯器和 LLVM 整合在一起。相關訊息請見 Intro to the LLVM MC Project 和 The x86 Disassembler13)14)15)。
LLVM 為何不使用 C++ 的 RTTI?
請見 What can make RTTI undesirable。
目標平台的向量指令需要前端或是中端支持嗎?
請見 [LLVMdev] is it possible to use gcc vectorizer ?。前端或是中端必須先將純量指令轉成 LLVM 向量指令,目標平台的向量指令才能派上用場。
llvm-ld 和 llvm-link 有何不同?
請見 llvm-ld 和 llvm-link。llvm-link 僅將 LLVM 數個 bitcode 鏈結成一個 bitcode。llvm-ld 能夠鏈結一般目地檔並做 LTO。
LLVM cross compile?
請見 [LLVMdev] How to Cross compile llvm to ARM?,[LLVMdev] JIT on ARM,[LLVMdev] Fwd: JIT on ARM 。
在 PowerPC 平台上請調低編譯器優化等級。2.6 請用 -O0。16)
$ ../configure --prefix=$INSTALL --enable-optimized --with-optimize-option=-O2
atomic 指令支援?
請見 Proposed LLVM IR Memory Model 和 Proposal for a new LLVM concurrency memory model [LLVMdev] Reviving the new LLVM concurrency model [LLVMdev] LLVM Concurrency and Undef。
例外處理?
請見 [LLVMdev] RFC: Exception Handling Rewrite 和 [LLVMdev] Exception Handling Rewrite Branch。
LLVM 如何解析 built-in 或是外部函式?
請見 [LLVMdev] Understanding resolving external/built-in function references。
如何判斷 GCC 或是 LLVM 有問題?

編譯 LLVM 失敗,代表 GCC 有問題。
先用 GCC 編譯 LLVM + Clang,再用該編譯好的 LLVM + Clang 編譯 LLVM + Clang,最後執行 `make check` 17)。
VLIW 支援?
請見 [LLVMdev] VLIW Ports 和 [LLVMdev] RFC: Machine Instruction Bundle。
[LLVMdev] if llvm can translate and generate the function in parallel with multithread
[llvm-commits] [PATCH] BasicBlock Autovectorization Pass
[LLVMdev] The nsw story Re: [LLVMdev] The nsw story [LLVMdev] nsw is still logically inconsistent
[LLVMdev] How to free memory of JIT'd function
[LLVMdev] Identifying loop variables18)
[LLVMdev] (Newbie) Using lli with clang\+\+?
文章
Trident: From High-Level Language to Hardware Circuitry
Compiling for EDGE Architectures
EDA with LLVM
Explicit Data Graph Execution
你好,LLVM 3.0
LLVM (Low Level Virtual Machine) 筆記
Create a working compiler with the LLVM framework, Part 1
計畫
Intel SPMD Program Compiler
AMD IL Code Generator Backend for OpenCL
SAFECode
LLVMdev] Instrument examples
http://code.google.com/p/15745-project-dswp/
Vellvm: Formalizing the LLVM Intermediate Representation for Verified Program Transformations
外部連結
The LLVM Compiler Infrastructure
LLVM Developers' Meeting
拖稿很久的 LLVM 使用文
How the LLVM Compiler Infrastructure Works
LLVM筆記(0):在一切開始之前
learning plus
http://code.google.com/p/llvmdoc-cn-trans/

--------------------------------------------------------------------------------

1) http://lists.cs.uiuc.edu/pipermail/llvmdev/2011-July/042089.html
2) http://www.cs.nctu.edu.tw/~chenwj/log/baldrick-2011-07-29.log
3) http://lists.cs.uiuc.edu/pipermail/cfe-dev/2010-June/009669.html
4) http://lists.cs.uiuc.edu/pipermail/llvmdev/2011-July/042063.html
5) http://lists.cs.uiuc.edu/pipermail/llvmdev/2011-March/038935.html
6) http://llvm.org/bugs/show_bug.cgi?id=9605
7) http://lists.cs.uiuc.edu/pipermail/llvmdev/2011-March/038578.html
8) http://lists.cs.uiuc.edu/pipermail/llvmdev/2012-April/048800.html
9) http://lists.cs.uiuc.edu/pipermail/llvmdev/2011-July/041214.html
10) http://www.cs.nctu.edu.tw/~chenwj/log/echristo-2011-07-22.txt
11) http://www.nondot.org/sabre/LLVMNotes/GlobalRegisterVariables.txt
12) http://groups.google.com/group/llvm-dev/browse_thread/thread/a02b8ca664dd4b0b
13) http://lists.cs.uiuc.edu/pipermail/llvmdev/2011-March/038956.html
14) http://nondot.org/sabre/LLVMNotes/InlineAsm.txt
15) http://llvm.org/docs/LangRef.html#inlineasm
16) http://comments.gmane.org/gmane.comp.compilers.llvm.devel/37185
17) http://www.cs.nctu.edu.tw/~chenwj/log/baldrick-2011-07-29.log
18) http://people.cs.nctu.edu.tw/~chenwj/log/LLVM/baldrick-2012-01-17.txt

你可能感兴趣的:(编译器)