1 #include "Jitter_CodeGen_AArch32.h"
2
3 using namespace Jitter;
4
GetMemory64Offset(CSymbol * symbol) const5 uint32 CCodeGen_AArch32::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 + m_stackLevel;
14 break;
15 default:
16 assert(false);
17 return 0;
18 break;
19 }
20 }
21
LoadMemory64LowInRegister(CAArch32Assembler::REGISTER registerId,CSymbol * symbol)22 void CCodeGen_AArch32::LoadMemory64LowInRegister(CAArch32Assembler::REGISTER registerId, CSymbol* symbol)
23 {
24 switch(symbol->m_type)
25 {
26 case SYM_RELATIVE64:
27 m_assembler.Ldr(registerId, g_baseRegister, CAArch32Assembler::MakeImmediateLdrAddress(symbol->m_valueLow + 0));
28 break;
29 case SYM_TEMPORARY64:
30 m_assembler.Ldr(registerId, CAArch32Assembler::rSP, CAArch32Assembler::MakeImmediateLdrAddress(symbol->m_stackLocation + m_stackLevel + 0));
31 break;
32 default:
33 assert(false);
34 break;
35 }
36 }
37
LoadMemory64HighInRegister(CAArch32Assembler::REGISTER registerId,CSymbol * symbol)38 void CCodeGen_AArch32::LoadMemory64HighInRegister(CAArch32Assembler::REGISTER registerId, CSymbol* symbol)
39 {
40 switch(symbol->m_type)
41 {
42 case SYM_RELATIVE64:
43 m_assembler.Ldr(registerId, g_baseRegister, CAArch32Assembler::MakeImmediateLdrAddress(symbol->m_valueLow + 4));
44 break;
45 case SYM_TEMPORARY64:
46 m_assembler.Ldr(registerId, CAArch32Assembler::rSP, CAArch32Assembler::MakeImmediateLdrAddress(symbol->m_stackLocation + m_stackLevel + 4));
47 break;
48 default:
49 assert(false);
50 break;
51 }
52 }
53
LoadMemory64InRegisters(CAArch32Assembler::REGISTER regLo,CAArch32Assembler::REGISTER regHi,CSymbol * symbol)54 void CCodeGen_AArch32::LoadMemory64InRegisters(CAArch32Assembler::REGISTER regLo, CAArch32Assembler::REGISTER regHi, CSymbol* symbol)
55 {
56 if(
57 ((regLo & 1) == 0) &&
58 (regHi == (regLo + 1)) &&
59 (GetMemory64Offset(symbol) < 0x100)
60 )
61 {
62 switch(symbol->m_type)
63 {
64 case SYM_RELATIVE64:
65 m_assembler.Ldrd(regLo, g_baseRegister, CAArch32Assembler::MakeImmediateLdrAddress(symbol->m_valueLow));
66 break;
67 case SYM_TEMPORARY64:
68 m_assembler.Ldrd(regLo, CAArch32Assembler::rSP, CAArch32Assembler::MakeImmediateLdrAddress(symbol->m_stackLocation + m_stackLevel));
69 break;
70 default:
71 assert(false);
72 break;
73 }
74 }
75 else
76 {
77 LoadMemory64LowInRegister(regLo, symbol);
78 LoadMemory64HighInRegister(regHi, symbol);
79 }
80 }
81
StoreRegistersInMemory64(CSymbol * symbol,CAArch32Assembler::REGISTER regLo,CAArch32Assembler::REGISTER regHi)82 void CCodeGen_AArch32::StoreRegistersInMemory64(CSymbol* symbol, CAArch32Assembler::REGISTER regLo, CAArch32Assembler::REGISTER regHi)
83 {
84 if(
85 ((regLo & 1) == 0) &&
86 (regHi == (regLo + 1)) &&
87 (GetMemory64Offset(symbol) < 0x100)
88 )
89 {
90 switch(symbol->m_type)
91 {
92 case SYM_RELATIVE64:
93 m_assembler.Strd(regLo, g_baseRegister, CAArch32Assembler::MakeImmediateLdrAddress(symbol->m_valueLow));
94 break;
95 case SYM_TEMPORARY64:
96 m_assembler.Strd(regLo, CAArch32Assembler::rSP, CAArch32Assembler::MakeImmediateLdrAddress(symbol->m_stackLocation + m_stackLevel));
97 break;
98 default:
99 assert(false);
100 break;
101 }
102 }
103 else
104 {
105 StoreRegisterInMemory64Low(symbol, regLo);
106 StoreRegisterInMemory64High(symbol, regHi);
107 }
108 }
109
StoreRegisterInMemory64Low(CSymbol * symbol,CAArch32Assembler::REGISTER registerId)110 void CCodeGen_AArch32::StoreRegisterInMemory64Low(CSymbol* symbol, CAArch32Assembler::REGISTER registerId)
111 {
112 switch(symbol->m_type)
113 {
114 case SYM_RELATIVE64:
115 m_assembler.Str(registerId, g_baseRegister, CAArch32Assembler::MakeImmediateLdrAddress(symbol->m_valueLow + 0));
116 break;
117 case SYM_TEMPORARY64:
118 m_assembler.Str(registerId, CAArch32Assembler::rSP, CAArch32Assembler::MakeImmediateLdrAddress(symbol->m_stackLocation + m_stackLevel + 0));
119 break;
120 default:
121 assert(false);
122 break;
123 }
124 }
125
StoreRegisterInMemory64High(CSymbol * symbol,CAArch32Assembler::REGISTER registerId)126 void CCodeGen_AArch32::StoreRegisterInMemory64High(CSymbol* symbol, CAArch32Assembler::REGISTER registerId)
127 {
128 switch(symbol->m_type)
129 {
130 case SYM_RELATIVE64:
131 m_assembler.Str(registerId, g_baseRegister, CAArch32Assembler::MakeImmediateLdrAddress(symbol->m_valueLow + 4));
132 break;
133 case SYM_TEMPORARY64:
134 m_assembler.Str(registerId, CAArch32Assembler::rSP, CAArch32Assembler::MakeImmediateLdrAddress(symbol->m_stackLocation + m_stackLevel + 4));
135 break;
136 default:
137 assert(false);
138 break;
139 }
140 }
141
Emit_Mov_Mem64Mem64(const STATEMENT & statement)142 void CCodeGen_AArch32::Emit_Mov_Mem64Mem64(const STATEMENT& statement)
143 {
144 auto dst = statement.dst->GetSymbol().get();
145 auto src1 = statement.src1->GetSymbol().get();
146
147 auto regLo = CAArch32Assembler::r0;
148 auto regHi = CAArch32Assembler::r1;
149 LoadMemory64InRegisters(regLo, regHi, src1);
150 StoreRegistersInMemory64(dst, regLo, regHi);
151 }
152
Emit_Mov_Mem64Cst64(const STATEMENT & statement)153 void CCodeGen_AArch32::Emit_Mov_Mem64Cst64(const STATEMENT& statement)
154 {
155 auto dst = statement.dst->GetSymbol().get();
156 auto src1 = statement.src1->GetSymbol().get();
157
158 auto regLo = CAArch32Assembler::r0;
159 auto regHi = CAArch32Assembler::r1;
160 LoadConstantInRegister(regLo, src1->m_valueLow);
161 LoadConstantInRegister(regHi, src1->m_valueHigh);
162 StoreRegistersInMemory64(dst, regLo, regHi);
163 }
164
Emit_ExtLow64VarMem64(const STATEMENT & statement)165 void CCodeGen_AArch32::Emit_ExtLow64VarMem64(const STATEMENT& statement)
166 {
167 auto dst = statement.dst->GetSymbol().get();
168 auto src1 = statement.src1->GetSymbol().get();
169
170 auto dstReg = PrepareSymbolRegisterDef(dst, CAArch32Assembler::r0);
171 LoadMemory64LowInRegister(dstReg, src1);
172 CommitSymbolRegister(dst, dstReg);
173 }
174
Emit_ExtHigh64VarMem64(const STATEMENT & statement)175 void CCodeGen_AArch32::Emit_ExtHigh64VarMem64(const STATEMENT& statement)
176 {
177 auto dst = statement.dst->GetSymbol().get();
178 auto src1 = statement.src1->GetSymbol().get();
179
180 auto dstReg = PrepareSymbolRegisterDef(dst, CAArch32Assembler::r0);
181 LoadMemory64HighInRegister(dstReg, src1);
182 CommitSymbolRegister(dst, dstReg);
183 }
184
Emit_MergeTo64_Mem64AnyAny(const STATEMENT & statement)185 void CCodeGen_AArch32::Emit_MergeTo64_Mem64AnyAny(const STATEMENT& statement)
186 {
187 auto dst = statement.dst->GetSymbol().get();
188 auto src1 = statement.src1->GetSymbol().get();
189 auto src2 = statement.src2->GetSymbol().get();
190
191 auto regLo = PrepareSymbolRegisterUse(src1, CAArch32Assembler::r0);
192 auto regHi = PrepareSymbolRegisterUse(src2, CAArch32Assembler::r1);
193
194 StoreRegistersInMemory64(dst, regLo, regHi);
195 }
196
Emit_Add64_MemMemMem(const STATEMENT & statement)197 void CCodeGen_AArch32::Emit_Add64_MemMemMem(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 regLo1 = CAArch32Assembler::r0;
204 auto regHi1 = CAArch32Assembler::r1;
205 auto regLo2 = CAArch32Assembler::r2;
206 auto regHi2 = CAArch32Assembler::r3;
207
208 LoadMemory64InRegisters(regLo1, regHi1, src1);
209 LoadMemory64InRegisters(regLo2, regHi2, src2);
210
211 m_assembler.Adds(regLo1, regLo1, regLo2);
212 m_assembler.Adc(regHi1, regHi1, regHi2);
213
214 StoreRegistersInMemory64(dst, regLo1, regHi1);
215 }
216
Emit_Add64_MemMemCst(const STATEMENT & statement)217 void CCodeGen_AArch32::Emit_Add64_MemMemCst(const STATEMENT& statement)
218 {
219 auto dst = statement.dst->GetSymbol().get();
220 auto src1 = statement.src1->GetSymbol().get();
221 auto src2 = statement.src2->GetSymbol().get();
222
223 auto regLo1 = CAArch32Assembler::r0;
224 auto regHi1 = CAArch32Assembler::r1;
225 auto regLo2 = CAArch32Assembler::r2;
226 auto regHi2 = CAArch32Assembler::r3;
227
228 LoadMemory64InRegisters(regLo1, regHi1, src1);
229 LoadConstantInRegister(regLo2, src2->m_valueLow);
230 LoadConstantInRegister(regHi2, src2->m_valueHigh);
231
232 //TODO: Improve this by using immediate operands instead of loading constants in registers
233 m_assembler.Adds(regLo1, regLo1, regLo2);
234 m_assembler.Adc(regHi1, regHi1, regHi2);
235
236 StoreRegistersInMemory64(dst, regLo1, regHi1);
237 }
238
Emit_Sub64_MemMemMem(const STATEMENT & statement)239 void CCodeGen_AArch32::Emit_Sub64_MemMemMem(const STATEMENT& statement)
240 {
241 auto dst = statement.dst->GetSymbol().get();
242 auto src1 = statement.src1->GetSymbol().get();
243 auto src2 = statement.src2->GetSymbol().get();
244
245 auto regLo1 = CAArch32Assembler::r0;
246 auto regHi1 = CAArch32Assembler::r1;
247 auto regLo2 = CAArch32Assembler::r2;
248 auto regHi2 = CAArch32Assembler::r3;
249
250 LoadMemory64InRegisters(regLo1, regHi1, src1);
251 LoadMemory64InRegisters(regLo2, regHi2, src2);
252
253 m_assembler.Subs(regLo1, regLo1, regLo2);
254 m_assembler.Sbc(regHi1, regHi1, regHi2);
255
256 StoreRegistersInMemory64(dst, regLo1, regHi1);
257 }
258
Emit_Sub64_MemMemCst(const STATEMENT & statement)259 void CCodeGen_AArch32::Emit_Sub64_MemMemCst(const STATEMENT& statement)
260 {
261 auto dst = statement.dst->GetSymbol().get();
262 auto src1 = statement.src1->GetSymbol().get();
263 auto src2 = statement.src2->GetSymbol().get();
264
265 auto regLo1 = CAArch32Assembler::r0;
266 auto regHi1 = CAArch32Assembler::r1;
267 auto regLo2 = CAArch32Assembler::r2;
268 auto regHi2 = CAArch32Assembler::r3;
269
270 LoadMemory64InRegisters(regLo1, regHi1, src1);
271 LoadConstantInRegister(regLo2, src2->m_valueLow);
272 LoadConstantInRegister(regHi2, src2->m_valueHigh);
273
274 //TODO: Improve this by using immediate operands instead of loading constants in registers
275 m_assembler.Subs(regLo1, regLo1, regLo2);
276 m_assembler.Sbc(regHi1, regHi1, regHi2);
277
278 StoreRegistersInMemory64(dst, regLo1, regHi1);
279 }
280
Emit_Sub64_MemCstMem(const STATEMENT & statement)281 void CCodeGen_AArch32::Emit_Sub64_MemCstMem(const STATEMENT& statement)
282 {
283 auto dst = statement.dst->GetSymbol().get();
284 auto src1 = statement.src1->GetSymbol().get();
285 auto src2 = statement.src2->GetSymbol().get();
286
287 auto regLo1 = CAArch32Assembler::r0;
288 auto regHi1 = CAArch32Assembler::r1;
289 auto regLo2 = CAArch32Assembler::r2;
290 auto regHi2 = CAArch32Assembler::r3;
291
292 LoadConstantInRegister(regLo1, src1->m_valueLow);
293 LoadConstantInRegister(regHi1, src1->m_valueHigh);
294 LoadMemory64InRegisters(regLo2, regHi2, src2);
295
296 //TODO: Improve this by using immediate operands instead of loading constants in registers
297 m_assembler.Subs(regLo1, regLo1, regLo2);
298 m_assembler.Sbc(regHi1, regHi1, regHi2);
299
300 StoreRegistersInMemory64(dst, regLo1, regHi1);
301 }
302
Emit_And64_MemMemMem(const STATEMENT & statement)303 void CCodeGen_AArch32::Emit_And64_MemMemMem(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 regLo1 = CAArch32Assembler::r0;
310 auto regHi1 = CAArch32Assembler::r1;
311 auto regLo2 = CAArch32Assembler::r2;
312 auto regHi2 = CAArch32Assembler::r3;
313
314 LoadMemory64InRegisters(regLo1, regHi1, src1);
315 LoadMemory64InRegisters(regLo2, regHi2, src2);
316
317 m_assembler.And(regLo1, regLo1, regLo2);
318 m_assembler.And(regHi1, regHi1, regHi2);
319
320 StoreRegistersInMemory64(dst, regLo1, regHi1);
321 }
322
Emit_Sl64Var_MemMem(CSymbol * dst,CSymbol * src,CAArch32Assembler::REGISTER saReg)323 void CCodeGen_AArch32::Emit_Sl64Var_MemMem(CSymbol* dst, CSymbol* src, CAArch32Assembler::REGISTER saReg)
324 {
325 //saReg will be modified by this function, do not use PrepareRegister
326
327 assert(saReg == CAArch32Assembler::r0);
328
329 auto lessThan32Label = m_assembler.CreateLabel();
330 auto doneLabel = m_assembler.CreateLabel();
331
332 m_assembler.And(saReg, saReg, CAArch32Assembler::MakeImmediateAluOperand(0x3F, 0));
333 m_assembler.Cmp(saReg, CAArch32Assembler::MakeImmediateAluOperand(32, 0));
334 m_assembler.BCc(CAArch32Assembler::CONDITION_LT, lessThan32Label);
335
336 //greaterThanOrEqual32:
337 {
338 auto workReg = CAArch32Assembler::r1;
339 auto dstLo = CAArch32Assembler::r2;
340 auto dstHi = CAArch32Assembler::r3;
341
342 LoadMemory64LowInRegister(workReg, src);
343
344 auto fixedSaReg = CAArch32Assembler::r0;
345 m_assembler.Sub(fixedSaReg, saReg, CAArch32Assembler::MakeImmediateAluOperand(32, 0));
346
347 auto shiftHi = CAArch32Assembler::MakeVariableShift(CAArch32Assembler::SHIFT_LSL, fixedSaReg);
348 m_assembler.Mov(dstHi, CAArch32Assembler::MakeRegisterAluOperand(workReg, shiftHi));
349
350 m_assembler.Mov(dstLo, CAArch32Assembler::MakeImmediateAluOperand(0, 0));
351
352 StoreRegistersInMemory64(dst, dstLo, dstHi);
353
354 m_assembler.BCc(CAArch32Assembler::CONDITION_AL, doneLabel);
355 }
356
357 //lessThan32:
358 m_assembler.MarkLabel(lessThan32Label);
359 {
360 auto dstReg = CAArch32Assembler::r1;
361 auto loReg = CAArch32Assembler::r2;
362 auto hiReg = CAArch32Assembler::r3;
363
364 //Lo part -> (lo << sa)
365 auto shiftLo = CAArch32Assembler::MakeVariableShift(CAArch32Assembler::SHIFT_LSL, saReg);
366 LoadMemory64LowInRegister(loReg, src);
367 m_assembler.Mov(dstReg, CAArch32Assembler::MakeRegisterAluOperand(loReg, shiftLo));
368 StoreRegisterInMemory64Low(dst, dstReg);
369
370 //Hi part -> (lo >> (32 - sa)) | (hi << sa)
371 auto shiftHi1 = CAArch32Assembler::MakeVariableShift(CAArch32Assembler::SHIFT_LSL, saReg);
372 LoadMemory64HighInRegister(hiReg, src);
373 m_assembler.Mov(dstReg, CAArch32Assembler::MakeRegisterAluOperand(hiReg, shiftHi1));
374
375 auto shiftHi2 = CAArch32Assembler::MakeVariableShift(CAArch32Assembler::SHIFT_LSR, saReg);
376 m_assembler.Rsb(saReg, saReg, CAArch32Assembler::MakeImmediateAluOperand(32, 0));
377 m_assembler.Mov(loReg, CAArch32Assembler::MakeRegisterAluOperand(loReg, shiftHi2));
378 m_assembler.Or(dstReg, dstReg, loReg);
379
380 StoreRegisterInMemory64High(dst, dstReg);
381 }
382
383 //done:
384 m_assembler.MarkLabel(doneLabel);
385 }
386
Emit_Sll64_MemMemVar(const STATEMENT & statement)387 void CCodeGen_AArch32::Emit_Sll64_MemMemVar(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 auto saReg = CAArch32Assembler::r0;
394
395 switch(src2->m_type)
396 {
397 case SYM_REGISTER:
398 m_assembler.Mov(saReg, g_registers[src2->m_valueLow]);
399 break;
400 case SYM_RELATIVE:
401 case SYM_TEMPORARY:
402 LoadMemoryInRegister(saReg, src2);
403 break;
404 default:
405 assert(0);
406 break;
407 }
408
409 Emit_Sl64Var_MemMem(dst, src1, saReg);
410 }
411
Emit_Sll64_MemMemCst(const STATEMENT & statement)412 void CCodeGen_AArch32::Emit_Sll64_MemMemCst(const STATEMENT& statement)
413 {
414 auto dst = statement.dst->GetSymbol().get();
415 auto src1 = statement.src1->GetSymbol().get();
416 auto src2 = statement.src2->GetSymbol().get();
417
418 auto shiftAmount = src2->m_valueLow & 0x3F;
419 assert(shiftAmount != 0);
420
421 auto srcLo = CAArch32Assembler::r0;
422 auto srcHi = CAArch32Assembler::r1;
423 auto dstLo = CAArch32Assembler::r2;
424 auto dstHi = CAArch32Assembler::r3;
425
426 if(shiftAmount >= 32)
427 {
428 shiftAmount -= 32;
429
430 LoadMemory64LowInRegister(srcLo, src1);
431
432 auto shiftHi = CAArch32Assembler::MakeConstantShift(CAArch32Assembler::SHIFT_LSL, shiftAmount);
433 m_assembler.Mov(dstHi, CAArch32Assembler::MakeRegisterAluOperand(srcLo, shiftHi));
434
435 m_assembler.Mov(dstLo, CAArch32Assembler::MakeImmediateAluOperand(0, 0));
436
437 StoreRegistersInMemory64(dst, dstLo, dstHi);
438 }
439 else //Amount < 32
440 {
441 LoadMemory64InRegisters(srcLo, srcHi, src1);
442
443 //Lo part -> (lo << sa)
444 auto shiftLo = CAArch32Assembler::MakeConstantShift(CAArch32Assembler::SHIFT_LSL, shiftAmount);
445
446 m_assembler.Mov(dstLo, CAArch32Assembler::MakeRegisterAluOperand(srcLo, shiftLo));
447
448 //Hi part -> (lo >> (32 - sa)) | (hi << sa)
449 auto shiftHi1 = CAArch32Assembler::MakeConstantShift(CAArch32Assembler::SHIFT_LSL, shiftAmount);
450 auto shiftHi2 = CAArch32Assembler::MakeConstantShift(CAArch32Assembler::SHIFT_LSR, 32 - shiftAmount);
451
452 m_assembler.Mov(srcHi, CAArch32Assembler::MakeRegisterAluOperand(srcHi, shiftHi1));
453 m_assembler.Mov(srcLo, CAArch32Assembler::MakeRegisterAluOperand(srcLo, shiftHi2));
454 m_assembler.Or(dstHi, srcLo, srcHi);
455
456 StoreRegistersInMemory64(dst, dstLo, dstHi);
457 }
458 }
459
Emit_Sr64Var_MemMem(CSymbol * dst,CSymbol * src,CAArch32Assembler::REGISTER saReg,CAArch32Assembler::SHIFT shiftType)460 void CCodeGen_AArch32::Emit_Sr64Var_MemMem(CSymbol* dst, CSymbol* src, CAArch32Assembler::REGISTER saReg, CAArch32Assembler::SHIFT shiftType)
461 {
462 assert((shiftType == CAArch32Assembler::SHIFT_ASR) || (shiftType == CAArch32Assembler::SHIFT_LSR));
463
464 //saReg will be modified by this function, do not use PrepareRegister
465
466 assert(saReg == CAArch32Assembler::r0);
467
468 auto lessThan32Label = m_assembler.CreateLabel();
469 auto doneLabel = m_assembler.CreateLabel();
470
471 m_assembler.And(saReg, saReg, CAArch32Assembler::MakeImmediateAluOperand(0x3F, 0));
472 m_assembler.Cmp(saReg, CAArch32Assembler::MakeImmediateAluOperand(32, 0));
473 m_assembler.BCc(CAArch32Assembler::CONDITION_LT, lessThan32Label);
474
475 //greaterThanOrEqual32:
476 {
477 auto workReg = CAArch32Assembler::r1;
478 auto dstLo = CAArch32Assembler::r2;
479 auto dstHi = CAArch32Assembler::r3;
480
481 LoadMemory64HighInRegister(workReg, src);
482
483 auto fixedSaReg = CAArch32Assembler::r0;
484 m_assembler.Sub(fixedSaReg, saReg, CAArch32Assembler::MakeImmediateAluOperand(32, 0));
485
486 auto shiftLo = CAArch32Assembler::MakeVariableShift(shiftType, fixedSaReg);
487 m_assembler.Mov(dstLo, CAArch32Assembler::MakeRegisterAluOperand(workReg, shiftLo));
488
489 if(shiftType == CAArch32Assembler::SHIFT_LSR)
490 {
491 m_assembler.Mov(dstHi, CAArch32Assembler::MakeImmediateAluOperand(0, 0));
492 }
493 else
494 {
495 auto shiftHi = CAArch32Assembler::MakeConstantShift(CAArch32Assembler::SHIFT_ASR, 31);
496 m_assembler.Mov(dstHi, CAArch32Assembler::MakeRegisterAluOperand(workReg, shiftHi));
497 }
498
499 StoreRegistersInMemory64(dst, dstLo, dstHi);
500
501 m_assembler.BCc(CAArch32Assembler::CONDITION_AL, doneLabel);
502 }
503
504 //lessThan32:
505 m_assembler.MarkLabel(lessThan32Label);
506 {
507 auto dstReg = CAArch32Assembler::r1;
508 auto loReg = CAArch32Assembler::r2;
509 auto hiReg = CAArch32Assembler::r3;
510
511 //Hi part -> (hi >> sa)
512 auto shiftHi = CAArch32Assembler::MakeVariableShift(shiftType, saReg);
513 LoadMemory64HighInRegister(hiReg, src);
514 m_assembler.Mov(dstReg, CAArch32Assembler::MakeRegisterAluOperand(hiReg, shiftHi));
515 StoreRegisterInMemory64High(dst, dstReg);
516
517 //Lo part -> (hi << (32 - sa)) | (lo >> sa)
518 auto shiftLo1 = CAArch32Assembler::MakeVariableShift(CAArch32Assembler::SHIFT_LSR, saReg);
519 LoadMemory64LowInRegister(loReg, src);
520 m_assembler.Mov(dstReg, CAArch32Assembler::MakeRegisterAluOperand(loReg, shiftLo1));
521
522 auto shiftLo2 = CAArch32Assembler::MakeVariableShift(CAArch32Assembler::SHIFT_LSL, saReg);
523 m_assembler.Rsb(saReg, saReg, CAArch32Assembler::MakeImmediateAluOperand(32, 0));
524 m_assembler.Mov(hiReg, CAArch32Assembler::MakeRegisterAluOperand(hiReg, shiftLo2));
525 m_assembler.Or(dstReg, dstReg, hiReg);
526
527 StoreRegisterInMemory64Low(dst, dstReg);
528 }
529
530 //done:
531 m_assembler.MarkLabel(doneLabel);
532 }
533
Emit_Sr64Cst_MemMem(CSymbol * dst,CSymbol * src,uint32 shiftAmount,CAArch32Assembler::SHIFT shiftType)534 void CCodeGen_AArch32::Emit_Sr64Cst_MemMem(CSymbol* dst, CSymbol* src, uint32 shiftAmount, CAArch32Assembler::SHIFT shiftType)
535 {
536 assert(shiftAmount < 0x40);
537 assert(shiftAmount != 0);
538
539 assert((shiftType == CAArch32Assembler::SHIFT_ASR) || (shiftType == CAArch32Assembler::SHIFT_LSR));
540
541 auto srcLo = CAArch32Assembler::r0;
542 auto srcHi = CAArch32Assembler::r1;
543 auto dstLo = CAArch32Assembler::r2;
544 auto dstHi = CAArch32Assembler::r3;
545
546 if(shiftAmount >= 32)
547 {
548 shiftAmount -= 32;
549
550 LoadMemory64HighInRegister(srcHi, src);
551
552 if(shiftAmount != 0)
553 {
554 auto shiftLo = CAArch32Assembler::MakeConstantShift(shiftType, shiftAmount);
555 m_assembler.Mov(dstLo, CAArch32Assembler::MakeRegisterAluOperand(srcHi, shiftLo));
556 }
557 else
558 {
559 m_assembler.Mov(dstLo, srcHi);
560 }
561
562 if(shiftType == CAArch32Assembler::SHIFT_LSR)
563 {
564 m_assembler.Mov(dstHi, CAArch32Assembler::MakeImmediateAluOperand(0, 0));
565 }
566 else
567 {
568 auto shiftHi = CAArch32Assembler::MakeConstantShift(CAArch32Assembler::SHIFT_ASR, 31);
569 m_assembler.Mov(dstHi, CAArch32Assembler::MakeRegisterAluOperand(srcHi, shiftHi));
570 }
571
572 StoreRegistersInMemory64(dst, dstLo, dstHi);
573 }
574 else //Amount < 32
575 {
576 LoadMemory64InRegisters(srcLo, srcHi, src);
577
578 //Hi part -> (hi >> sa)
579 auto shiftHi = CAArch32Assembler::MakeConstantShift(shiftType, shiftAmount);
580
581 m_assembler.Mov(dstHi, CAArch32Assembler::MakeRegisterAluOperand(srcHi, shiftHi));
582
583 //Lo part -> (hi << (32 - sa)) | (lo >> sa)
584 auto shiftLo1 = CAArch32Assembler::MakeConstantShift(CAArch32Assembler::SHIFT_LSR, shiftAmount);
585 auto shiftLo2 = CAArch32Assembler::MakeConstantShift(CAArch32Assembler::SHIFT_LSL, 32 - shiftAmount);
586
587 m_assembler.Mov(srcLo, CAArch32Assembler::MakeRegisterAluOperand(srcLo, shiftLo1));
588 m_assembler.Mov(srcHi, CAArch32Assembler::MakeRegisterAluOperand(srcHi, shiftLo2));
589 m_assembler.Or(dstLo, srcLo, srcHi);
590
591 StoreRegistersInMemory64(dst, dstLo, dstHi);
592 }
593 }
594
Emit_Srl64_MemMemVar(const STATEMENT & statement)595 void CCodeGen_AArch32::Emit_Srl64_MemMemVar(const STATEMENT& statement)
596 {
597 auto dst = statement.dst->GetSymbol().get();
598 auto src1 = statement.src1->GetSymbol().get();
599 auto src2 = statement.src2->GetSymbol().get();
600
601 auto saReg = CAArch32Assembler::r0;
602
603 switch(src2->m_type)
604 {
605 case SYM_REGISTER:
606 m_assembler.Mov(saReg, g_registers[src2->m_valueLow]);
607 break;
608 case SYM_RELATIVE:
609 case SYM_TEMPORARY:
610 LoadMemoryInRegister(saReg, src2);
611 break;
612 default:
613 assert(0);
614 break;
615 }
616
617 Emit_Sr64Var_MemMem(dst, src1, saReg, CAArch32Assembler::SHIFT_LSR);
618 }
619
Emit_Srl64_MemMemCst(const STATEMENT & statement)620 void CCodeGen_AArch32::Emit_Srl64_MemMemCst(const STATEMENT& statement)
621 {
622 auto dst = statement.dst->GetSymbol().get();
623 auto src1 = statement.src1->GetSymbol().get();
624 auto src2 = statement.src2->GetSymbol().get();
625
626 auto shiftAmount = src2->m_valueLow & 0x3F;
627
628 Emit_Sr64Cst_MemMem(dst, src1, shiftAmount, CAArch32Assembler::SHIFT_LSR);
629 }
630
Emit_Sra64_MemMemVar(const STATEMENT & statement)631 void CCodeGen_AArch32::Emit_Sra64_MemMemVar(const STATEMENT& statement)
632 {
633 auto dst = statement.dst->GetSymbol().get();
634 auto src1 = statement.src1->GetSymbol().get();
635 auto src2 = statement.src2->GetSymbol().get();
636
637 auto saReg = CAArch32Assembler::r0;
638
639 switch(src2->m_type)
640 {
641 case SYM_REGISTER:
642 m_assembler.Mov(saReg, g_registers[src2->m_valueLow]);
643 break;
644 case SYM_RELATIVE:
645 case SYM_TEMPORARY:
646 LoadMemoryInRegister(saReg, src2);
647 break;
648 default:
649 assert(0);
650 break;
651 }
652
653 Emit_Sr64Var_MemMem(dst, src1, saReg, CAArch32Assembler::SHIFT_ASR);
654 }
655
Emit_Sra64_MemMemCst(const STATEMENT & statement)656 void CCodeGen_AArch32::Emit_Sra64_MemMemCst(const STATEMENT& statement)
657 {
658 auto dst = statement.dst->GetSymbol().get();
659 auto src1 = statement.src1->GetSymbol().get();
660 auto src2 = statement.src2->GetSymbol().get();
661
662 auto shiftAmount = src2->m_valueLow & 0x3F;
663
664 Emit_Sr64Cst_MemMem(dst, src1, shiftAmount, CAArch32Assembler::SHIFT_ASR);
665 }
666
Cmp64_RegSymLo(CAArch32Assembler::REGISTER src1Reg,CSymbol * src2,CAArch32Assembler::REGISTER src2Reg)667 void CCodeGen_AArch32::Cmp64_RegSymLo(CAArch32Assembler::REGISTER src1Reg, CSymbol* src2, CAArch32Assembler::REGISTER src2Reg)
668 {
669 switch(src2->m_type)
670 {
671 case SYM_RELATIVE64:
672 case SYM_TEMPORARY64:
673 LoadMemory64LowInRegister(src2Reg, src2);
674 m_assembler.Cmp(src1Reg, src2Reg);
675 break;
676 case SYM_CONSTANT64:
677 Cmp_GenericRegCst(src1Reg, src2->m_valueLow, src2Reg);
678 break;
679 default:
680 assert(false);
681 break;
682 }
683 }
684
Cmp64_RegSymHi(CAArch32Assembler::REGISTER src1Reg,CSymbol * src2,CAArch32Assembler::REGISTER src2Reg)685 void CCodeGen_AArch32::Cmp64_RegSymHi(CAArch32Assembler::REGISTER src1Reg, CSymbol* src2, CAArch32Assembler::REGISTER src2Reg)
686 {
687 switch(src2->m_type)
688 {
689 case SYM_RELATIVE64:
690 case SYM_TEMPORARY64:
691 LoadMemory64HighInRegister(src2Reg, src2);
692 m_assembler.Cmp(src1Reg, src2Reg);
693 break;
694 case SYM_CONSTANT64:
695 Cmp_GenericRegCst(src1Reg, src2->m_valueHigh, src2Reg);
696 break;
697 default:
698 assert(false);
699 break;
700 }
701 }
702
Cmp64_Equal(const STATEMENT & statement)703 void CCodeGen_AArch32::Cmp64_Equal(const STATEMENT& statement)
704 {
705 auto dst = statement.dst->GetSymbol().get();
706 auto src1 = statement.src1->GetSymbol().get();
707 auto src2 = statement.src2->GetSymbol().get();
708
709 auto dstReg = PrepareSymbolRegisterDef(dst, CAArch32Assembler::r0);
710 auto src1Reg = CAArch32Assembler::r1;
711 auto src2Reg = CAArch32Assembler::r2;
712 auto tempValReg = CAArch32Assembler::r3;
713
714 /////////////////////////////////////////
715 //Check high order word
716 LoadMemory64HighInRegister(src1Reg, src1);
717 Cmp64_RegSymHi(src1Reg, src2, src2Reg);
718 Cmp_GetFlag(tempValReg, statement.jmpCondition);
719
720 /////////////////////////////////////////
721 //Check low order word
722 LoadMemory64LowInRegister(src1Reg, src1);
723 Cmp64_RegSymLo(src1Reg, src2, src2Reg);
724 Cmp_GetFlag(dstReg, statement.jmpCondition);
725
726 if(statement.jmpCondition == Jitter::CONDITION_EQ)
727 {
728 m_assembler.And(dstReg, dstReg, tempValReg);
729 }
730 else if(statement.jmpCondition == Jitter::CONDITION_NE)
731 {
732 m_assembler.Or(dstReg, dstReg, tempValReg);
733 }
734 else
735 {
736 //Shouldn't get here
737 assert(false);
738 }
739
740 CommitSymbolRegister(dst, dstReg);
741 }
742
Cmp64_Order(const STATEMENT & statement)743 void CCodeGen_AArch32::Cmp64_Order(const STATEMENT& statement)
744 {
745 auto dst = statement.dst->GetSymbol().get();
746 auto src1 = statement.src1->GetSymbol().get();
747 auto src2 = statement.src2->GetSymbol().get();
748
749 auto doneLabel = m_assembler.CreateLabel();
750 auto highOrderEqualLabel = m_assembler.CreateLabel();
751
752 auto dstReg = PrepareSymbolRegisterDef(dst, CAArch32Assembler::r0);
753 auto src1Reg = CAArch32Assembler::r1;
754 auto src2Reg = CAArch32Assembler::r2;
755
756 /////////////////////////////////////////
757 //Check high order word if equal
758
759 //Compare with constant?
760 LoadMemory64HighInRegister(src1Reg, src1);
761 Cmp64_RegSymHi(src1Reg, src2, src2Reg);
762
763 m_assembler.BCc(CAArch32Assembler::CONDITION_EQ, highOrderEqualLabel);
764
765 ///////////////////////////////////////////////////////////
766 //If they aren't equal, this comparaison decides of result
767
768 Cmp_GetFlag(dstReg, statement.jmpCondition);
769 m_assembler.BCc(CAArch32Assembler::CONDITION_AL, doneLabel);
770
771 ///////////////////////////////////////////////////////////
772 //If they are equal, next comparaison decides of result
773
774 //highOrderEqual: /////////////////////////////////////
775 m_assembler.MarkLabel(highOrderEqualLabel);
776
777 LoadMemory64LowInRegister(src1Reg, src1);
778 Cmp64_RegSymLo(src1Reg, src2, src2Reg);
779
780 auto unsignedCondition = Jitter::CONDITION_NEVER;
781 switch(statement.jmpCondition)
782 {
783 case Jitter::CONDITION_LT:
784 unsignedCondition = Jitter::CONDITION_BL;
785 break;
786 case Jitter::CONDITION_LE:
787 unsignedCondition = Jitter::CONDITION_BE;
788 break;
789 case Jitter::CONDITION_GT:
790 unsignedCondition = Jitter::CONDITION_AB;
791 break;
792 case Jitter::CONDITION_AB:
793 case Jitter::CONDITION_BL:
794 unsignedCondition = statement.jmpCondition;
795 break;
796 default:
797 assert(0);
798 break;
799 }
800
801 Cmp_GetFlag(dstReg, unsignedCondition);
802
803 //done: ///////////////////////////////////////////////
804 m_assembler.MarkLabel(doneLabel);
805
806 CommitSymbolRegister(dst, dstReg);
807 }
808
Emit_Cmp64_VarMemAny(const STATEMENT & statement)809 void CCodeGen_AArch32::Emit_Cmp64_VarMemAny(const STATEMENT& statement)
810 {
811 switch(statement.jmpCondition)
812 {
813 case CONDITION_BL:
814 case CONDITION_LT:
815 case CONDITION_LE:
816 case CONDITION_AB:
817 case CONDITION_GT:
818 case CONDITION_GE:
819 Cmp64_Order(statement);
820 break;
821 case CONDITION_NE:
822 case CONDITION_EQ:
823 Cmp64_Equal(statement);
824 break;
825 default:
826 assert(0);
827 break;
828 }
829 }
830
831 CCodeGen_AArch32::CONSTMATCHER CCodeGen_AArch32::g_64ConstMatchers[] =
832 {
833 { OP_EXTLOW64, MATCH_VARIABLE, MATCH_MEMORY64, MATCH_NIL, &CCodeGen_AArch32::Emit_ExtLow64VarMem64 },
834 { OP_EXTHIGH64, MATCH_VARIABLE, MATCH_MEMORY64, MATCH_NIL, &CCodeGen_AArch32::Emit_ExtHigh64VarMem64 },
835
836 { OP_MERGETO64, MATCH_MEMORY64, MATCH_ANY, MATCH_ANY, &CCodeGen_AArch32::Emit_MergeTo64_Mem64AnyAny },
837
838 { OP_ADD64, MATCH_MEMORY64, MATCH_MEMORY64, MATCH_MEMORY64, &CCodeGen_AArch32::Emit_Add64_MemMemMem },
839 { OP_ADD64, MATCH_MEMORY64, MATCH_MEMORY64, MATCH_CONSTANT64, &CCodeGen_AArch32::Emit_Add64_MemMemCst },
840
841 { OP_SUB64, MATCH_MEMORY64, MATCH_MEMORY64, MATCH_MEMORY64, &CCodeGen_AArch32::Emit_Sub64_MemMemMem },
842 { OP_SUB64, MATCH_MEMORY64, MATCH_MEMORY64, MATCH_CONSTANT64, &CCodeGen_AArch32::Emit_Sub64_MemMemCst, },
843 { OP_SUB64, MATCH_MEMORY64, MATCH_CONSTANT64, MATCH_MEMORY64, &CCodeGen_AArch32::Emit_Sub64_MemCstMem },
844
845 { OP_AND64, MATCH_MEMORY64, MATCH_MEMORY64, MATCH_MEMORY64, &CCodeGen_AArch32::Emit_And64_MemMemMem, },
846
847 { OP_SLL64, MATCH_MEMORY64, MATCH_MEMORY64, MATCH_VARIABLE, &CCodeGen_AArch32::Emit_Sll64_MemMemVar },
848 { OP_SLL64, MATCH_MEMORY64, MATCH_MEMORY64, MATCH_CONSTANT, &CCodeGen_AArch32::Emit_Sll64_MemMemCst },
849
850 { OP_SRL64, MATCH_MEMORY64, MATCH_MEMORY64, MATCH_VARIABLE, &CCodeGen_AArch32::Emit_Srl64_MemMemVar },
851 { OP_SRL64, MATCH_MEMORY64, MATCH_MEMORY64, MATCH_CONSTANT, &CCodeGen_AArch32::Emit_Srl64_MemMemCst },
852
853 { OP_SRA64, MATCH_MEMORY64, MATCH_MEMORY64, MATCH_VARIABLE, &CCodeGen_AArch32::Emit_Sra64_MemMemVar },
854 { OP_SRA64, MATCH_MEMORY64, MATCH_MEMORY64, MATCH_CONSTANT, &CCodeGen_AArch32::Emit_Sra64_MemMemCst },
855
856 { OP_CMP64, MATCH_VARIABLE, MATCH_MEMORY64, MATCH_MEMORY64, &CCodeGen_AArch32::Emit_Cmp64_VarMemAny },
857 { OP_CMP64, MATCH_VARIABLE, MATCH_MEMORY64, MATCH_CONSTANT64, &CCodeGen_AArch32::Emit_Cmp64_VarMemAny },
858
859 { OP_MOV, MATCH_MEMORY64, MATCH_MEMORY64, MATCH_NIL, &CCodeGen_AArch32::Emit_Mov_Mem64Mem64 },
860 { OP_MOV, MATCH_MEMORY64, MATCH_CONSTANT64, MATCH_NIL, &CCodeGen_AArch32::Emit_Mov_Mem64Cst64 },
861
862 { OP_MOV, MATCH_NIL, MATCH_NIL, MATCH_NIL, NULL },
863 };
864