1# Code generator 2## Overview 3Codegen is the backend for current compiler implementation. It was implemented with the main idea - to be independent of specific encoder-architecture and have the possibility to work with different calling-conventions. It was designed to be independence from target-architecture - also, for this target - was created special compiler-independent library - encoder ([encoder.md](../optimizer/code_generator/encoder.md)). 4 5## Dependence 6 7It is needed Regalloc-pass and LinearOrder-analysis for codegen-work. First - because it is needed to fill register for each operand, second - because of needed jump-instruction generation for major edges. 8 9## Implementation details 10 11List of major codegen-dependency: 121. Encoder library (calling convention, encoder, and register description). 132. CodeBuilder - contain binary data and hold header with information for stack-walker. 143. CFrameLayout - is responsible for stack-frame layout in runtime(class described in `libpandabase/utils`). 154. SlowPath - class, which is responsible for side exits. 16 17Codegen internal-implementation is responsibility for: 181. Conversions from IR to encoder structures (like conditions, immediate, registers, etc). 192. Filling meta-info for recovery frame-information in exceptions (state stamps, which used in stack-walker). 203. Getting information from runtime about current methods and objects. 214. Supporting logic for build AOT-code (there are needed runtime calls during aot-code execution). 225. Correct parameter transferring. 23 24## Logic of work 25 26Constructor makes additional work - it walks through call-instructions and calculates parameters count (they need for reserve stack-slots). 27 28The main logic was made in RunImpl-method: 291. Generates Calling-Convention prologue. 302. Creates encode-visitor and visits each instruction in linear order by blocks. 313. After that - side exits (SlowPath) are emitted (also for OSR). 324. Generate epilog for correctness exit from method 335. At the end - there is the finalization of the encoder(emit real offsets for each branch) and CodeBuilder-header filling. 34 35## Additional features 36 37Also, there is implemented ScopedDisasmPrinter(for print disassembly), EncodeVisitor (for generating special opcodes). 38 39Example of disasm-dump: 40``` 41- START_METHOD 420000: stp x0, x20, [sp, #-32]! 430004: stp x29, x30, [sp, #16] 440008: add x29, sp, #0x10 (16) 45... 46- CallRuntime 470014: mov x16, #0xcbd4 480018: movk x16, #0x52, lsl #16 49001c: blr x16 500020: ldp x30, xzr, [sp], #16 51... 52``` 53 54## Pseudocode 55codegen.cpp: 56``` 57void Codegen::RunImpl() { 58 GetCallingConvention()->BeginMethod(); // emit moves from parameters to dst-regs etc. 59 60 for (auto bb : GetGraph()->GetBlocksLinearOrder()) { 61 GetEncoder()->BindLabel(bb->GetId()); 62 for (auto inst : bb->AllInsts()) { 63 visitor.VisitInstruction(inst); 64 } 65 } 66 67 EmitSlowPaths(); // Emit code, which responsibility for side exits. 68 GetEncoder()->Finalize(); // After that - it is possible to use generated code. 69 GetGraph()->SetData(EncodeDataType(code_entry, code_size)); // This data(entry and code) was used in code-cache 70} 71 72void Codegen::CreateCall(inst) { 73 auto callconv = GetCallingConvention(); 74 auto dst_reg = ConvertRegister(call_inst->GetDstReg(), call_inst->GetType()); 75 // 1-st parameter register 76 Reg param = GetRegfile()->GetSpecialRegister(SpecialReg::DEFAULT_PARAMETER); 77 if (GetGraph()->IsAotMode()) { 78 ... // AOT code 79 } else { 80 GetEncoder()->SaveCallerRegisters(); 81 SetCallParameters(call_inst); 82 auto method = ...->GetMethodById(...->GetMethod(), call_inst->GetCallMethodId()); 83 // Move immediate-value to parameter 84 GetEncoder()->EncodeMov(param_0, Imm(method)); 85 } 86 // Get offset of 87 size_t entry_point_offset = ...->GetCompiledEntryPointOffset(); 88 // Major call instruction 89 GetEncoder()->MakeCall(MemRef(param_0, entry_point_offset)); 90 ... 91 GetEncoder()->LoadCallerRegisters(dst_reg); 92} 93 94class EncodeVisitor : public GraphVisitor { 95 /* VisitAdd, VisitSub, VisitMul etc... */ 96 VisitInstruction(inst) { 97 switch (inst->Opc()) { 98 case (Opcode::Add) VisitAdd(inst); break; 99 case (Opcode::Cmp) VisitCmp(inst); break; 100 case (Opcode::Call) VisitCallStatic(inst); break; 101 ... 102 } 103 } 104 105 // Full logic for generate one instruction: 106 void VisitAdd(inst) { 107 auto dst = GetCodegen()->ConvertRegister(inst->GetDstReg(), type); 108 auto src0 = GetCodegen()->ConvertRegister(inst->GetSrcReg(0), type); 109 enc->GetEncoder()->EncodeAdd(dst, src0); 110 } 111 112 void EncodeVisitor::VisitCallStatic(inst) { 113 GetCodegen()->CreateCall(inst); 114 } 115 116 void EncodeVisitor::VisitCmp(GraphVisitor* visitor, Inst* inst) { 117 auto* enc = static_cast<EncodeVisitor*>(visitor); 118 auto cmp_inst = inst->CastToCmp(); 119 auto dst = GetCodegen()->ConvertRegister(inst->GetDstReg()); 120 auto src0 = GetCodegen()->ConvertRegister(inst->GetSrcReg(0)); 121 auto src1 = GetCodegen()->ConvertRegister(inst->GetSrcReg(1)); 122 Condition cc = ... 123 GetEncoder()->EncodeCmp(dst, src0, src1, cc); 124 } 125 126} 127``` 128 129And them will have different encoding for each architecture: 130``` 131target/aarch32/encode.cpp: 132void Aarch32Encoder::EncodeCompare(Reg dst, Reg src0, Reg src1, Condition cc) { 133 CompareHelper(src0, src1, &cc); // Method for calculate flags for each src1 and src2 types 134 __ Mov(Convert(cc), VixlReg(dst), 0x1); 135 __ Mov(Convert(cc).Negate(), VixlReg(dst), 0x0); 136} 137 138target/aarch64/encode.cpp: 139void Aarch64Encoder::EncodeCompare(Reg dst, Reg src0, Reg src1, Condition cc) { 140 __ Cmp(VixlReg(src0), VixlReg(src1)); 141 __ Cset(VixlReg(dst), Convert(cc)); 142} 143``` 144 145## Links 146 147[codegen.cpp](../optimizer/code_generator/codegen.cpp) 148[codegen.h](../optimizer/code_generator/codegen.h) 149[slow_path.cpp](../optimizer/code_generator/slow_path.cpp) 150[slow_path.h](../optimizer/code_generator/slow_path.h) 151 152Tests: 153[codegen_test.cpp](../tests/codegen_test.cpp), [inst_generator_test.cpp](../tests/inst_generator_test.cpp) - test with generation each instruction.