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