1 #include "Jitter_CodeGen_AArch64.h"
2
3 using namespace Jitter;
4
GetMemory64Offset(CSymbol * symbol) const5 uint32 CCodeGen_AArch64::GetMemory64Offset(CSymbol* symbol) const
6 {
7 switch(symbol->m_type)
8 {
9 case SYM_RELATIVE64:
10 return symbol->m_valueLow;
11 break;
12 case SYM_TEMPORARY64:
13 return symbol->m_stackLocation;
14 break;
15 default:
16 assert(false);
17 return 0;
18 break;
19 }
20 }
21
LoadMemory64InRegister(CAArch64Assembler::REGISTER64 registerId,CSymbol * src)22 void CCodeGen_AArch64::LoadMemory64InRegister(CAArch64Assembler::REGISTER64 registerId, CSymbol* src)
23 {
24 switch(src->m_type)
25 {
26 case SYM_RELATIVE64:
27 assert((src->m_valueLow & 0x07) == 0x00);
28 m_assembler.Ldr(registerId, g_baseRegister, src->m_valueLow);
29 break;
30 case SYM_TEMPORARY64:
31 assert((src->m_stackLocation & 0x07) == 0x00);
32 m_assembler.Ldr(registerId, CAArch64Assembler::xSP, src->m_stackLocation);
33 break;
34 default:
35 assert(0);
36 break;
37 }
38 }
39
StoreRegisterInMemory64(CSymbol * dst,CAArch64Assembler::REGISTER64 registerId)40 void CCodeGen_AArch64::StoreRegisterInMemory64(CSymbol* dst, CAArch64Assembler::REGISTER64 registerId)
41 {
42 switch(dst->m_type)
43 {
44 case SYM_RELATIVE64:
45 assert((dst->m_valueLow & 0x07) == 0x00);
46 m_assembler.Str(registerId, g_baseRegister, dst->m_valueLow);
47 break;
48 case SYM_TEMPORARY64:
49 assert((dst->m_stackLocation & 0x07) == 0x00);
50 m_assembler.Str(registerId, CAArch64Assembler::xSP, dst->m_stackLocation);
51 break;
52 default:
53 assert(0);
54 break;
55 }
56 }
57
LoadConstant64InRegister(CAArch64Assembler::REGISTER64 registerId,uint64 constant)58 void CCodeGen_AArch64::LoadConstant64InRegister(CAArch64Assembler::REGISTER64 registerId, uint64 constant)
59 {
60 if(constant == 0)
61 {
62 m_assembler.Movz(registerId, 0, 0);
63 return;
64 }
65 //TODO: Check if "movn" could be used to load constants
66 bool loaded = false;
67 static const uint64 masks[4] =
68 {
69 0x000000000000FFFFULL,
70 0x00000000FFFF0000ULL,
71 0x0000FFFF00000000ULL,
72 0xFFFF000000000000ULL
73 };
74 for(unsigned int i = 0; i < 4; i++)
75 {
76 if((constant & masks[i]) != 0)
77 {
78 if(loaded)
79 {
80 m_assembler.Movk(registerId, constant >> (i * 16), i);
81 }
82 else
83 {
84 m_assembler.Movz(registerId, constant >> (i * 16), i);
85 }
86 loaded = true;
87 }
88 }
89 assert(loaded);
90 }
91
LoadMemory64LowInRegister(CAArch64Assembler::REGISTER32 registerId,CSymbol * symbol)92 void CCodeGen_AArch64::LoadMemory64LowInRegister(CAArch64Assembler::REGISTER32 registerId, CSymbol* symbol)
93 {
94 switch(symbol->m_type)
95 {
96 case SYM_RELATIVE64:
97 m_assembler.Ldr(registerId, g_baseRegister, symbol->m_valueLow + 0);
98 break;
99 case SYM_TEMPORARY64:
100 m_assembler.Ldr(registerId, CAArch64Assembler::xSP, symbol->m_stackLocation + 0);
101 break;
102 default:
103 assert(false);
104 break;
105 }
106 }
107
LoadMemory64HighInRegister(CAArch64Assembler::REGISTER32 registerId,CSymbol * symbol)108 void CCodeGen_AArch64::LoadMemory64HighInRegister(CAArch64Assembler::REGISTER32 registerId, CSymbol* symbol)
109 {
110 switch(symbol->m_type)
111 {
112 case SYM_RELATIVE64:
113 m_assembler.Ldr(registerId, g_baseRegister, symbol->m_valueLow + 4);
114 break;
115 case SYM_TEMPORARY64:
116 m_assembler.Ldr(registerId, CAArch64Assembler::xSP, symbol->m_stackLocation + 4);
117 break;
118 default:
119 assert(false);
120 break;
121 }
122 }
123
LoadSymbol64InRegister(CAArch64Assembler::REGISTER64 registerId,CSymbol * symbol)124 void CCodeGen_AArch64::LoadSymbol64InRegister(CAArch64Assembler::REGISTER64 registerId, CSymbol* symbol)
125 {
126 switch(symbol->m_type)
127 {
128 case SYM_RELATIVE64:
129 case SYM_TEMPORARY64:
130 LoadMemory64InRegister(registerId, symbol);
131 break;
132 case SYM_CONSTANT64:
133 LoadConstant64InRegister(registerId, symbol->GetConstant64());
134 break;
135 default:
136 assert(false);
137 break;
138 }
139 }
140
StoreRegistersInMemory64(CSymbol * symbol,CAArch64Assembler::REGISTER32 regLo,CAArch64Assembler::REGISTER32 regHi)141 void CCodeGen_AArch64::StoreRegistersInMemory64(CSymbol* symbol, CAArch64Assembler::REGISTER32 regLo, CAArch64Assembler::REGISTER32 regHi)
142 {
143 if(GetMemory64Offset(symbol) < 0x100)
144 {
145 switch(symbol->m_type)
146 {
147 case SYM_RELATIVE64:
148 m_assembler.Stp(regLo, regHi, g_baseRegister, symbol->m_valueLow);
149 break;
150 case SYM_TEMPORARY64:
151 m_assembler.Stp(regLo, regHi, CAArch64Assembler::xSP, symbol->m_stackLocation);
152 break;
153 default:
154 assert(false);
155 break;
156 }
157 }
158 else
159 {
160 switch(symbol->m_type)
161 {
162 case SYM_RELATIVE64:
163 m_assembler.Str(regLo, g_baseRegister, symbol->m_valueLow + 0);
164 m_assembler.Str(regHi, g_baseRegister, symbol->m_valueLow + 4);
165 break;
166 case SYM_TEMPORARY64:
167 m_assembler.Str(regLo, CAArch64Assembler::xSP, symbol->m_stackLocation + 0);
168 m_assembler.Str(regHi, CAArch64Assembler::xSP, symbol->m_stackLocation + 4);
169 break;
170 default:
171 assert(false);
172 break;
173 }
174 }
175 }
176
Emit_ExtLow64VarMem64(const STATEMENT & statement)177 void CCodeGen_AArch64::Emit_ExtLow64VarMem64(const STATEMENT& statement)
178 {
179 auto dst = statement.dst->GetSymbol().get();
180 auto src1 = statement.src1->GetSymbol().get();
181
182 auto dstReg = PrepareSymbolRegisterDef(dst, GetNextTempRegister());
183 LoadMemory64LowInRegister(dstReg, src1);
184 CommitSymbolRegister(dst, dstReg);
185 }
186
Emit_ExtHigh64VarMem64(const STATEMENT & statement)187 void CCodeGen_AArch64::Emit_ExtHigh64VarMem64(const STATEMENT& statement)
188 {
189 auto dst = statement.dst->GetSymbol().get();
190 auto src1 = statement.src1->GetSymbol().get();
191
192 auto dstReg = PrepareSymbolRegisterDef(dst, GetNextTempRegister());
193 LoadMemory64HighInRegister(dstReg, src1);
194 CommitSymbolRegister(dst, dstReg);
195 }
196
Emit_MergeTo64_Mem64AnyAny(const STATEMENT & statement)197 void CCodeGen_AArch64::Emit_MergeTo64_Mem64AnyAny(const STATEMENT& statement)
198 {
199 auto dst = statement.dst->GetSymbol().get();
200 auto src1 = statement.src1->GetSymbol().get();
201 auto src2 = statement.src2->GetSymbol().get();
202
203 auto regLo = PrepareSymbolRegisterUse(src1, GetNextTempRegister());
204 auto regHi = PrepareSymbolRegisterUse(src2, GetNextTempRegister());
205
206 StoreRegistersInMemory64(dst, regLo, regHi);
207 }
208
Emit_Add64_MemMemMem(const STATEMENT & statement)209 void CCodeGen_AArch64::Emit_Add64_MemMemMem(const STATEMENT& statement)
210 {
211 auto dst = statement.dst->GetSymbol().get();
212 auto src1 = statement.src1->GetSymbol().get();
213 auto src2 = statement.src2->GetSymbol().get();
214
215 auto dstReg = GetNextTempRegister64();
216 auto src1Reg = GetNextTempRegister64();
217 auto src2Reg = GetNextTempRegister64();
218
219 LoadMemory64InRegister(src1Reg, src1);
220 LoadMemory64InRegister(src2Reg, src2);
221 m_assembler.Add(dstReg, src1Reg, src2Reg);
222 StoreRegisterInMemory64(dst, dstReg);
223 }
224
Emit_Add64_MemMemCst(const STATEMENT & statement)225 void CCodeGen_AArch64::Emit_Add64_MemMemCst(const STATEMENT& statement)
226 {
227 auto dst = statement.dst->GetSymbol().get();
228 auto src1 = statement.src1->GetSymbol().get();
229 auto src2 = statement.src2->GetSymbol().get();
230
231 auto dstReg = GetNextTempRegister64();
232 auto src1Reg = GetNextTempRegister64();
233
234 LoadMemory64InRegister(src1Reg, src1);
235 auto constant = src2->GetConstant64();
236
237 ADDSUB_IMM_PARAMS addSubImmParams;
238 if(TryGetAddSub64ImmParams(constant, addSubImmParams))
239 {
240 m_assembler.Add(dstReg, src1Reg, addSubImmParams.imm, addSubImmParams.shiftType);
241 }
242 else if(TryGetAddSub64ImmParams(-static_cast<int64>(constant), addSubImmParams))
243 {
244 m_assembler.Sub(dstReg, src1Reg, addSubImmParams.imm, addSubImmParams.shiftType);
245 }
246 else
247 {
248 auto src2Reg = GetNextTempRegister64();
249 LoadConstant64InRegister(src2Reg, constant);
250 m_assembler.Add(dstReg, src1Reg, src2Reg);
251 }
252
253 StoreRegisterInMemory64(dst, dstReg);
254 }
255
Emit_Sub64_MemAnyMem(const STATEMENT & statement)256 void CCodeGen_AArch64::Emit_Sub64_MemAnyMem(const STATEMENT& statement)
257 {
258 auto dst = statement.dst->GetSymbol().get();
259 auto src1 = statement.src1->GetSymbol().get();
260 auto src2 = statement.src2->GetSymbol().get();
261
262 auto dstReg = GetNextTempRegister64();
263 auto src1Reg = GetNextTempRegister64();
264 auto src2Reg = GetNextTempRegister64();
265
266 LoadSymbol64InRegister(src1Reg, src1);
267 LoadMemory64InRegister(src2Reg, src2);
268 m_assembler.Sub(dstReg, src1Reg, src2Reg);
269 StoreRegisterInMemory64(dst, dstReg);
270 }
271
Emit_Sub64_MemMemCst(const STATEMENT & statement)272 void CCodeGen_AArch64::Emit_Sub64_MemMemCst(const STATEMENT& statement)
273 {
274 auto dst = statement.dst->GetSymbol().get();
275 auto src1 = statement.src1->GetSymbol().get();
276 auto src2 = statement.src2->GetSymbol().get();
277
278 auto dstReg = GetNextTempRegister64();
279 auto src1Reg = GetNextTempRegister64();
280
281 LoadMemory64InRegister(src1Reg, src1);
282 auto constant = src2->GetConstant64();
283
284 ADDSUB_IMM_PARAMS addSubImmParams;
285 if(TryGetAddSub64ImmParams(constant, addSubImmParams))
286 {
287 m_assembler.Sub(dstReg, src1Reg, addSubImmParams.imm, addSubImmParams.shiftType);
288 }
289 else if(TryGetAddSub64ImmParams(-static_cast<int64>(constant), addSubImmParams))
290 {
291 m_assembler.Add(dstReg, src1Reg, addSubImmParams.imm, addSubImmParams.shiftType);
292 }
293 else
294 {
295 auto src2Reg = GetNextTempRegister64();
296 LoadConstant64InRegister(src2Reg, constant);
297 m_assembler.Sub(dstReg, src1Reg, src2Reg);
298 }
299
300 StoreRegisterInMemory64(dst, dstReg);
301 }
302
Emit_Cmp64_VarAnyMem(const STATEMENT & statement)303 void CCodeGen_AArch64::Emit_Cmp64_VarAnyMem(const STATEMENT& statement)
304 {
305 auto dst = statement.dst->GetSymbol().get();
306 auto src1 = statement.src1->GetSymbol().get();
307 auto src2 = statement.src2->GetSymbol().get();
308
309 auto dstReg = PrepareSymbolRegisterDef(dst, GetNextTempRegister());
310 auto src1Reg = GetNextTempRegister64();
311 auto src2Reg = GetNextTempRegister64();
312
313 LoadMemory64InRegister(src1Reg, src1);
314 LoadMemory64InRegister(src2Reg, src2);
315 m_assembler.Cmp(src1Reg, src2Reg);
316 Cmp_GetFlag(dstReg, statement.jmpCondition);
317 CommitSymbolRegister(dst, dstReg);
318 }
319
Emit_Cmp64_VarMemCst(const STATEMENT & statement)320 void CCodeGen_AArch64::Emit_Cmp64_VarMemCst(const STATEMENT& statement)
321 {
322 auto dst = statement.dst->GetSymbol().get();
323 auto src1 = statement.src1->GetSymbol().get();
324 auto src2 = statement.src2->GetSymbol().get();
325
326 assert(src2->m_type == SYM_CONSTANT64);
327
328 auto dstReg = PrepareSymbolRegisterDef(dst, GetNextTempRegister());
329 auto src1Reg = GetNextTempRegister64();
330
331 LoadMemory64InRegister(src1Reg, src1);
332 uint64 src2Cst = src2->GetConstant64();
333
334 ADDSUB_IMM_PARAMS addSubImmParams;
335 if(TryGetAddSub64ImmParams(src2Cst, addSubImmParams))
336 {
337 m_assembler.Cmp(src1Reg, addSubImmParams.imm, addSubImmParams.shiftType);
338 }
339 else if(TryGetAddSub64ImmParams(-static_cast<int64>(src2Cst), addSubImmParams))
340 {
341 m_assembler.Cmn(src1Reg, addSubImmParams.imm, addSubImmParams.shiftType);
342 }
343 else
344 {
345 auto src2Reg = GetNextTempRegister64();
346 LoadConstant64InRegister(src2Reg, src2Cst);
347 m_assembler.Cmp(src1Reg, src2Reg);
348 }
349
350 Cmp_GetFlag(dstReg, statement.jmpCondition);
351 CommitSymbolRegister(dst, dstReg);
352 }
353
Emit_And64_MemMemMem(const STATEMENT & statement)354 void CCodeGen_AArch64::Emit_And64_MemMemMem(const STATEMENT& statement)
355 {
356 auto dst = statement.dst->GetSymbol().get();
357 auto src1 = statement.src1->GetSymbol().get();
358 auto src2 = statement.src2->GetSymbol().get();
359
360 auto dstReg = GetNextTempRegister64();
361 auto src1Reg = GetNextTempRegister64();
362 auto src2Reg = GetNextTempRegister64();
363
364 LoadMemory64InRegister(src1Reg, src1);
365 LoadMemory64InRegister(src2Reg, src2);
366 m_assembler.And(dstReg, src1Reg, src2Reg);
367 StoreRegisterInMemory64(dst, dstReg);
368 }
369
370 template <typename Shift64Op>
Emit_Shift64_MemMemVar(const STATEMENT & statement)371 void CCodeGen_AArch64::Emit_Shift64_MemMemVar(const STATEMENT& statement)
372 {
373 auto dst = statement.dst->GetSymbol().get();
374 auto src1 = statement.src1->GetSymbol().get();
375 auto src2 = statement.src2->GetSymbol().get();
376
377 auto dstReg = GetNextTempRegister64();
378 auto src1Reg = GetNextTempRegister64();
379 auto src2Reg = PrepareSymbolRegisterUse(src2, GetNextTempRegister());
380
381 LoadMemory64InRegister(src1Reg, src1);
382 ((m_assembler).*(Shift64Op::OpReg()))(dstReg, src1Reg, static_cast<CAArch64Assembler::REGISTER64>(src2Reg));
383 StoreRegisterInMemory64(dst, dstReg);
384 }
385
386 template <typename Shift64Op>
Emit_Shift64_MemMemCst(const STATEMENT & statement)387 void CCodeGen_AArch64::Emit_Shift64_MemMemCst(const STATEMENT& statement)
388 {
389 auto dst = statement.dst->GetSymbol().get();
390 auto src1 = statement.src1->GetSymbol().get();
391 auto src2 = statement.src2->GetSymbol().get();
392
393 assert(src2->m_type == SYM_CONSTANT);
394
395 auto dstReg = GetNextTempRegister64();
396 auto src1Reg = GetNextTempRegister64();
397
398 LoadMemory64InRegister(src1Reg, src1);
399 ((m_assembler).*(Shift64Op::OpImm()))(dstReg, src1Reg, src2->m_valueLow);
400 StoreRegisterInMemory64(dst, dstReg);
401 }
402
Emit_Mov_Mem64Mem64(const STATEMENT & statement)403 void CCodeGen_AArch64::Emit_Mov_Mem64Mem64(const STATEMENT& statement)
404 {
405 auto dst = statement.dst->GetSymbol().get();
406 auto src1 = statement.src1->GetSymbol().get();
407
408 auto tmpReg = GetNextTempRegister64();
409 LoadMemory64InRegister(tmpReg, src1);
410 StoreRegisterInMemory64(dst, tmpReg);
411 }
412
Emit_Mov_Mem64Cst64(const STATEMENT & statement)413 void CCodeGen_AArch64::Emit_Mov_Mem64Cst64(const STATEMENT& statement)
414 {
415 auto dst = statement.dst->GetSymbol().get();
416 auto src1 = statement.src1->GetSymbol().get();
417
418 auto tmpReg = GetNextTempRegister64();
419 LoadConstant64InRegister(tmpReg, src1->GetConstant64());
420 StoreRegisterInMemory64(dst, tmpReg);
421 }
422
423 CCodeGen_AArch64::CONSTMATCHER CCodeGen_AArch64::g_64ConstMatchers[] =
424 {
425 { OP_EXTLOW64, MATCH_VARIABLE, MATCH_MEMORY64, MATCH_NIL, &CCodeGen_AArch64::Emit_ExtLow64VarMem64 },
426 { OP_EXTHIGH64, MATCH_VARIABLE, MATCH_MEMORY64, MATCH_NIL, &CCodeGen_AArch64::Emit_ExtHigh64VarMem64 },
427
428 { OP_MERGETO64, MATCH_MEMORY64, MATCH_ANY, MATCH_ANY, &CCodeGen_AArch64::Emit_MergeTo64_Mem64AnyAny },
429
430 { OP_ADD64, MATCH_MEMORY64, MATCH_MEMORY64, MATCH_MEMORY64, &CCodeGen_AArch64::Emit_Add64_MemMemMem },
431 { OP_ADD64, MATCH_MEMORY64, MATCH_MEMORY64, MATCH_CONSTANT64, &CCodeGen_AArch64::Emit_Add64_MemMemCst },
432
433 { OP_SUB64, MATCH_MEMORY64, MATCH_ANY, MATCH_MEMORY64, &CCodeGen_AArch64::Emit_Sub64_MemAnyMem },
434 { OP_SUB64, MATCH_MEMORY64, MATCH_MEMORY64, MATCH_CONSTANT64, &CCodeGen_AArch64::Emit_Sub64_MemMemCst },
435
436 { OP_CMP64, MATCH_VARIABLE, MATCH_ANY, MATCH_MEMORY64, &CCodeGen_AArch64::Emit_Cmp64_VarAnyMem },
437 { OP_CMP64, MATCH_VARIABLE, MATCH_ANY, MATCH_CONSTANT64, &CCodeGen_AArch64::Emit_Cmp64_VarMemCst },
438
439 { OP_AND64, MATCH_MEMORY64, MATCH_MEMORY64, MATCH_MEMORY64, &CCodeGen_AArch64::Emit_And64_MemMemMem },
440
441 { OP_SLL64, MATCH_MEMORY64, MATCH_MEMORY64, MATCH_VARIABLE, &CCodeGen_AArch64::Emit_Shift64_MemMemVar<SHIFT64OP_LSL> },
442 { OP_SRL64, MATCH_MEMORY64, MATCH_MEMORY64, MATCH_VARIABLE, &CCodeGen_AArch64::Emit_Shift64_MemMemVar<SHIFT64OP_LSR> },
443 { OP_SRA64, MATCH_MEMORY64, MATCH_MEMORY64, MATCH_VARIABLE, &CCodeGen_AArch64::Emit_Shift64_MemMemVar<SHIFT64OP_ASR> },
444
445 { OP_SLL64, MATCH_MEMORY64, MATCH_MEMORY64, MATCH_CONSTANT, &CCodeGen_AArch64::Emit_Shift64_MemMemCst<SHIFT64OP_LSL> },
446 { OP_SRL64, MATCH_MEMORY64, MATCH_MEMORY64, MATCH_CONSTANT, &CCodeGen_AArch64::Emit_Shift64_MemMemCst<SHIFT64OP_LSR> },
447 { OP_SRA64, MATCH_MEMORY64, MATCH_MEMORY64, MATCH_CONSTANT, &CCodeGen_AArch64::Emit_Shift64_MemMemCst<SHIFT64OP_ASR> },
448
449 { OP_MOV, MATCH_MEMORY64, MATCH_MEMORY64, MATCH_NIL, &CCodeGen_AArch64::Emit_Mov_Mem64Mem64 },
450 { OP_MOV, MATCH_MEMORY64, MATCH_CONSTANT64, MATCH_NIL, &CCodeGen_AArch64::Emit_Mov_Mem64Cst64 },
451 };
452