• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Encoder library
2
3## Building
4
5Current realization is not building outside compiler.
6
7## Sub-modules description
8
9There are two major variable-parts - architecture and execution model. Current architecture has aim to make easy switching of this two directions.
10
11### Register file  (concrete implementation is architecture dependent)
12RegistersDescription - is class for get access for all possible information about registers, which are used in the target architecture: amount of available registers, theirs type and size. Description for special registers and temps. It also may holds low-level information about callee and caller-saved registers. Also it is useful to have conversation from abstract register to arch-special registers(for example for vixlReg).
13
14This file must not use other interfaces.
15
16### Encoder  (concrete implementation is architecture dependent)
17Encoder  - is class for emit main list of instructions - math and memory-usage.
18
19This class uses RegistersDescription.
20
21### Calling Convention   (concrete implementation is architecture dependent)
22CallingConvention - is class for control calls/jumps, for spill/fill registers and access for native parameters. That's why it contains Labels list for have possibility to know concrete address for special branch-target.
23
24This class uses Encoder and RegistersDescription classes.
25
26Current stack layout must be like next one:
27```
28----------+----------------------+
29 Caller   | Default calling convention frame:
30 Frame    | Caller saved + parameters, if they
31          | don't fit in registers
32          |
33----------+-Encoder-Frame-Start--+   For CallingConvention::Begin(FUNCTION):
34  --------+----------------------+   (CallConv::PushHeader) {
35   Pre    |         lr           |             |
36   Header |         fp           |             |
37          |     1-st param       |  - (method) |
38          |   allignment reg     | (push one reg for padding)
39  --------+----------------------+   } // (CallConv::PushHeader)
40  --------+----------------------+   (CallConv::PushRegs(GetCalleeSavedR + V)) {
41   Header | scalar registers     |             |
42   callee | + optional allign-reg|             |
43          | vector registers     |             |
44          | + optional allign-reg|             |
45  --------+----------------------+   } // (CallConv::PushRegs(GetCalleeSavedR + V))
46  --------+----------------------+   CallConv::IncrementStack(SIZE_IN_BYTES)
47          |                      |
48          |                      |    Memory, avaliable for user
49          |                      |
50  --------+----------------------+   CallingConvention::Begin(NATIVE):
51  --------+----------------------+   (CallConv::PushRegs(GetCallerSavedR + V)) {
52   Header | scalar registers     |             |
53   caller | + optional allign-reg|             |
54          | vector registers     |             |
55          | + optional allign-reg|             |
56  --------+----------------------+   } // (CallConv::PushRegs(GetCallerSavedR + V))
57   Param  | Here will be         |
58          | parameters, if they  |  Must be manually filled
59          | don't fit in regs    |
60          |                      |
61----------+-Encoder-Frame-End------+
62----------+------------------------+
63 Native   | Default calling convention frame:
64 Frame    | Callee saved ... e.t.c
65
66```
67
68
69### Execution model  (concrete implementation - must be architecture independent)
70ExecModel  - is class for control emitting instructions. It must to be able to create default headers for emitted code and implement execution-specific code, e.g interpreter-ExecState access values.
71
72This class uses all above classes.
73
74### Codegen  (concrete implementation - must be architecture independent)
75Codegen - must not be in Encode-library, not to make dependency from compiler. It also must not to make dependency from special architecture.
76
77This class also must use all of above classes and have possibility to switch between arc or models.
78
79## Operands
80
81### TypeInfo
82
83Class **TypeInfo** contains information about supported types: BOOL, INT8, INT16, INT32, INT64, FLOAT32, FLOAT64
84You can get next information about type: size, scalar or vector.
85Example:
86```
87    auto type = TypeInfo(FLOAT32); // TypeInfo for float type
88    ASSERT(type->GetSize() == 32 && type->IsFloat());
89```
90
91### Register
92
93Class **Reg** contains number of register(id) and **TypeInfo**.
94You can get next information about register: type, id, size, scalar or vector.
95
96Example:
97```
98    auto reg = Reg(0, TypeInfo(INT32)); // scalar word regster
99    ASSERT(reg->GetId() == 0 && reg->GetType() == TypeInfo(INT32) && reg->GetSize() == 32 && reg->IsScalar());
100```
101
102### Immediate
103
104Class **Imm** contains value of the following types: int8_t, int16_t, int32_t, int64_t, float, double
105You can get next information about immediate: type, value, size.
106
107Example:
108```
109    double value = 123.456;
110    auto imm = Imm(value); // double immediate
111    ASSERT(imm.GetValue<double>() == value && imm->GetType() == TypeInfo(FLOAT64) && imm->GetSize() == 64 &&
112           !imm->IsScalar());
113```
114
115### Memory
116
117Class **MemRef** contains base **Reg**, index **Reg**, scale **Imm** and disp **Imm**.
118The memory address is calculated using the following formula: `base + (index << scale) + disp`
119If a parameter is not defined, it is considered equal to 0. The base must be defined.
120
121Example:
122```
123    // memory with base register and disp
124    auto base_reg = Reg(5, TypeInfo(INT64));
125    auto disp = Imm(static_cast<int642>(16));
126    auto mem_disp = MemRef(base_reg, disp); // base_reg + disp
127    ASSERT(mem_disp.HasBase() && !mem_disp.HasIndex() && !mem_disp.HasScale() && mem_disp.HasDisp());
128    ASSERT(mem_disp.GetBase() == base_reg && mem_disp.GetDisp() == disp);
129    ASSERT(mem_disp.GetIndex() == INVALID_REGISTER && mem_disp.GetScale() == INVALID_IMM);
130
131    // memory with base , index registers and scale
132    auto base_reg = Reg(5, TypeInfo(INT64));
133    auto index_reg = Reg(6, TypeInfo(INT64));
134    auto scale = Imm(static_cast<int32>(3));
135    auto mem_scale = MemRef(base_reg, index_reg, scale); // base_reg + (index_reg << scale)
136    ASSERT(mem_scale.HasBase() && mem_scale.HasIndex() && mem_scale.HasScale() && !mem_scale.HasDisp());
137    ASSERT(mem_scale.GetBase() == base_reg && mem_scale.GetIndex() == index_reg && mem_scale.GetScale() == scale);
138    ASSERT(mem_scale.GetDisp() == INVALID_IMM);
139```
140
141## Code Example (WIP)
142
143```
144// Example of usage encode-library
145/* == Sequence for create and configure encoder ==*/
146// 1. Create encoder for special-architecture
147Encoder *enc= buildEncoder(Arch);
148// 2. Create execution model - must be target independent
149ExecModel* exec = buildExecutionModel(Model::JIT);
150// 3. Create Calling convention-model - architecture-dependent
151CallingConvention *callconv = buildCallingConvention(exec, Arch);
152// 4. Fill Encoder
153enc->Configure(exec, callconv);
154/*======= Here encoder is fully configured =======*/
155// Usage:
156
157
158// Method start header
159callconv->Begin(CallingConvention::Reason::StartMethod);
160callconv->CallerStart(CallingConvention::Reason::StartMethod); // (?)
161
162// Use encoding:
163// Get register information
164auto register_description = enc->GetRegisterDescription();
165// Get special registers data
166auto sp = register_description->GetSpecialRegister(SpecialReg::stack_pointer);
167ASSERT(sp.IsValid());
168// Get all un-reserved register list
169auto available_regs = register_description->GetRegAllocatable()
170
171// Build memory operand
172auto memory = enc->BuildMem(sp, callconv->GetParamOffset(2));
173
174auto tmp1 = available_regs[0];
175enc->EncodeLoad(tmp1, memory);
176
177auto tmp2 = available_regs[1];
178enc->EncodeMov(tmp2, Imm(0x123));
179
180enc->EncodeAdd(tmp1, tmp2, tmp1);
181
182auto label = callconv->CreateLabel();
183// or CreateLabel<type>
184
185callconv->EncodeJump(label, CallingConvention::Reason::Jump);
186
187callconv->BindLabel(label);
188enc->EncodeAdd(tmp1, tmp2, tmp1);
189
190enc->EncodeStore(tmp1, memory);
191callconv->EncodeBranch(label);
192
193callconv->CallerEnd(CallingConvention::Reason::ExitMethod); // (?)
194callconv->EncodeReturn(CallingConvention::Reason::ExitMethod);
195// End of method
196callconv->End(CallingConvention::Reason::EndMethod);
197
198enc->Finalize();
199auto code = enc->GetEncodeData();
200code_allocator->Allocate(code.start(), code.size());
201///Example from encoder-part
202
203void Aarch64Encoder::EncodeAShr(Reg dst, Reg src0, Reg src1) {
204if (dst.GetSize() < MAX_REG_SIZE) {
205__ And(VixlReg(src1), (VixlReg(src1), VixlImm(dsr.GetSize() - 1));
206}
207__ Asr(VixlReg(dst), VixlReg(src0), VixlReg(src1));
208}
209```
210