• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.