寫一個LLVM後端 :轉換LLVM IR爲目標平臺的指令(彙編碼/機器碼-JIT)
https://releases.llvm.org/8.0.0/docs/WritingAnLLVMBackend.html#id33
- 建立新後端的七大步驟
- 描述特定目標平臺的屬性
- TargetMachine.cpp
- 描述特定目標平臺的寄存器
- TargetRegisterInfo.td:寄存器定義+寄存器別名+寄存器分類
- TargetRegisterInfo.cpp:寄存器分配和交互,include ”TargetGenRegisterInfo.inc”
- 描述特定目標平臺的指令集
- TargetInstrFormats.td:指令格式
- TargetInstrInfo.td:指令定義
- TargetInstrInfo.cpp:
- LLVM IR從DAG到目標平臺指令的選擇和轉換:指令選擇
- TargetISelDAGToDAG.cpp:模式匹配+DAGToDAG指令選擇
- TargetISelLowering.cpp:替換或刪除目標平臺不支持的數據和操作類型,即數據和操作合法化
- LLVM IR->GAS格式的彙編
- TargetAsmPrinter.cpp
- (可選)支持子目標平臺,允許使用-mcpu=和-mattr=命令行選項
- TargetSubtarget.cpp
- (可選)JIT即時編譯
- TargetJITInfo.cpp
- 描述特定目標平臺的屬性
- 目標機器
- getInstrInfo()
- getRegisterInfo()
- getFrameInfo():棧幀佈局
- getDataLayout():數據佈局(大小端序+數據類型+ABI對齊+首選對齊+數據大小)
- getSubtargetImpl()
- getTargetLowering()
- getJITInfo()
- Target Registration:目標登記註冊
- 寄存器
- 定義單個寄存器
- def F0 : Rf< 0, "F0">, DwarfRegNum<[32]>;
- 編碼,名稱,調試信息序號
- 定義寄存器類
- def FPRegs : RegisterClass<"SP", [f32], 32, (sequence "F%u", 0, 31)>;
- 命名空間,ValueType.td裏面的數據類型,數據對齊方式/大小 ,所屬寄存器F0~F31
- def DFPRegs : RegisterClass<"SP", [f64], 64, (add D0, D15)>;
- 實現TargetRegisterInfo的子類
- getCalleeSavedRegs—按所需的調用保存堆棧幀偏移量的順序返回調用保存的寄存器列表。
- getReservedRegs—返回一個按物理寄存器編號索引的位集,指示某個寄存器是否不可用。
- hasFP—返回一個布爾值,指示一個函數是否應該有一個專用的幀指針寄存器。
- eliminateCallFramePseudoInstr—如果使用了調用幀設置或銷燬僞指令,可以調用它來消除它們。
- eliminateFrameIndex—從可能使用它們的指令中刪除抽象的幀索引。
- emitPrologue—在函數中插入序言代碼。
- emitEpilogue—在函數中插入epilogue代碼。
- def FPRegs : RegisterClass<"SP", [f32], 32, (sequence "F%u", 0, 31)>;
- 定義指令集
- Target.td :指令、操作數、InstrInfo和其他基本類
- TargetSelectionDAG.td
- SelectionDAG節點(SDNode)
- Pattern, Pat, PatFrag, PatLeaf, ComplexPattern
- TargetInstrFormats.td
- 指令模板分類一般依據
- 單/雙/三/四寄存器類型
- 標量/矢量類型
- 分支/普通/Intrinsic/僞指令
- 指令操作數映射到指令中未綁定字段
- 定義操作數:bits<6>op1;bits<4>op2;bits<6>rd;bits<6>rs1;bits<6>rs2;
- 綁定字段:let Inst{31-26}=op1; let Inst{3-0}=op2;
- 指令操作數序號獲取支持
- getNamedOperandIdx獲取對應操作數的序號,從0開始
- 需要在TargetInstrInfo.cpp及其頭文件加上一些預處理宏
- 指令模板分類一般依據
- TargetInstrInfo.td
- 一條指令應該包含的基本描述
- 操作碼:可能多段,比如[31:26]+[3:0]
- 操作數:輸入和輸出dag,類型爲寄存器類或者操作數類
- 彙編字符串:
- DAG Pattern:模式匹配,SDNode,類型爲寄存器類或者PatLeaf類等
- Predicates:條件判斷是否選擇匹配
- 槽分配碼
- 額外屬性:是否可交換/是否訪存/是否爲僞指令/各種標誌位設定
- 相似指令描述技巧:multiclass + defm
- 指令間的關聯映射:InstrMapping類
- 一條指令應該包含的基本描述
- 定義單個寄存器
https://releases.llvm.org/8.0.0/docs/HowToUseInstrMappings.html
-
-
-
- 操作數類型def xxx:Operand<i32/i16/f64/OtherVT>;
- Schedule.td
- def ALU32_S_SLOT0 :InstrItinClass;
- def SLOT0 : FuncUnit;
- def TargetGenericItineraries :ProcessorItineraries<[SLOT0, SLOT1, SLOT2, SLOT3],[],[InstrItinData<ALU32_S_SLOT0, [InstrStage<1, [SLOT0]>]>,...
- 實現TargetInstrInfo的子類:TargeInstrInfo.cpp
- isLoadFromStackSlot—如果指定的機器指令是從堆棧插槽直接加載的,則返回目標的寄存器編號和堆棧插槽的幀索引。
- isStoreToStackSlot—如果指定的機器指令是直接存儲到堆棧槽的,則返回目標的寄存器編號和堆棧槽的幀索引。
- copyPhysReg—在一對物理寄存器之間拷貝值。
- storeRegToStackSlot—將寄存器值存儲到堆棧槽中。
- loadRegFromStackSlot—從堆棧槽加載寄存器值。
- storeRegToAddr—將寄存器值存儲到內存中。
- loadRegFromAddr—從內存中加載寄存器值。
- foldMemoryOperand—嘗試爲指定的操作數組合任何裝載或存儲指令的指令。
- 分支摺疊和條件轉換:TargetInstrInfo中的AnalyzeBranch方法可以用來檢查條件指令並刪除不必要的指令
-
- 指令選擇器
- TargetISelDAGToDAG.cpp
- 將非本機DAG指令轉換爲本機特定目標指令+匹配模式
- TargetInstrInfo.td->TargetGenDAGISel.inc(SelectCode方法)
- TargetCallingConv.td(函數調用和返回值約定)->TargetGenCallingConv.inc
- DAG各個階段可視化輔助:llc
- TargetISelLowering.cpp:替換或刪除目標平臺不支持的數據和操作類型,即數據和操作合法化
- 指定支持哪些類型:addRegisterClass(MVT::i32, SP::IntRegsRegisterClass);
- 對於本地/目標平臺不支持的類型的處理函數如下
- setOperationAction—一般操作。
- setLoadExtAction -加載擴展。
- setTruncStoreAction—截斷存儲。
- setIndexedLoadAction -索引加載。
- setIndexedStoreAction -索引存儲。
- setConvertAction -類型轉換,比如i1->i32
- setCondCodeAction—支持給定的條件代碼。
- 處理函數三個參數(ISD節點,MVT數據類型,處理方式4選1)
- Promote:i1->i8->i16->i32->i64;f32->f64
- Expand:
- 處理不支持的數據類型:i64->i32->i16->i8->i1
- 處理不支持的操作類型:用系統其他的操作替換
- Custom:自定義合法化處理函數,LowerFP_TO_SINT(Op, DAG)
- Legal:默認表示本地/目標平臺支持該類型或操作,很少用
- TargetCallingConv.td調用約定
- CCIfType<[f32,f64], CCAssignToReg<[R0, R1]>>
- CCIfType<[i1,i8,i16],CCPromoteToType<i32>>
- CCIfType<[i32],CCAssignToStack<16,4>>:首選棧大小16,首選對齊方式4Bytes=32bits,爲零的話則使用ABI大小和對齊方式
- CCDelegateTo<TargetCC>:如果TargetCC這個調用約定存在的話則調用/應用這個約定
- CCIf <謂詞,動作> -如果謂詞匹配,應用動作。
- CCIfInReg <action> -如果參數被標記爲“inreg”屬性,則應用該操作。
- CCIfNest <action>—如果參數被標記爲“nest”屬性,則應用該操作。
- CCIfNotVarArg <action>—如果當前函數沒有采用可變數量的參數,則應用該操作。類似於CCAssignToReg,但是有一個寄存器的影子列表。
- CCPassByVal <size, align>—將值賦給指定的最小大小和對齊方式的堆棧槽。
- CallingConv <[actions]> -定義支持的每個調用約定。
- TargetISelDAGToDAG.cpp
- 彙編打印器
- TargetInstPrinter.cpp:TargetInstrInfo.td->TargetGenAsmWriter.inc(printInstruction方法)
- printOperand
- printMemOperand
- printCCOperand (for conditional statements)
- printDataDirective
- printDeclare
- printImplicitDef
- printInlineAsm
- TargetAsmInfo.cpp+TargetAsmInfo.h
- TargetAsmPrinter.cpp:llvm IR->彙編代碼
- SetupMachineFunction
- EmitInstruction
- EmitConstantPool
- EmitJumpTableInfo
- EmitFunctionBodyStart
- EmitFunctionBodyEnd
- doFinalization
- TargetInstPrinter.cpp:TargetInstrInfo.td->TargetGenAsmWriter.inc(printInstruction方法)
-