1 #include "Jitter_CodeGen_AArch32.h"
2 #include "ObjectFile.h"
3 #include "BitManip.h"
4 #ifdef __ANDROID__
5 #include <cpu-features.h>
6 #endif
7
8 using namespace Jitter;
9
10 CAArch32Assembler::REGISTER CCodeGen_AArch32::g_baseRegister = CAArch32Assembler::r11;
11 CAArch32Assembler::REGISTER CCodeGen_AArch32::g_callAddressRegister = CAArch32Assembler::r4;
12 CAArch32Assembler::REGISTER CCodeGen_AArch32::g_tempParamRegister0 = CAArch32Assembler::r4;
13 CAArch32Assembler::REGISTER CCodeGen_AArch32::g_tempParamRegister1 = CAArch32Assembler::r5;
14
15 CAArch32Assembler::REGISTER CCodeGen_AArch32::g_registers[MAX_REGISTERS] =
16 {
17 CAArch32Assembler::r4,
18 CAArch32Assembler::r5,
19 CAArch32Assembler::r6,
20 CAArch32Assembler::r7,
21 CAArch32Assembler::r8,
22 CAArch32Assembler::r10,
23 };
24
25 CAArch32Assembler::REGISTER CCodeGen_AArch32::g_paramRegs[MAX_PARAM_REGS] =
26 {
27 CAArch32Assembler::r0,
28 CAArch32Assembler::r1,
29 CAArch32Assembler::r2,
30 CAArch32Assembler::r3,
31 };
32
33 template <typename ALUOP>
Emit_Alu_GenericAnyAny(const STATEMENT & statement)34 void CCodeGen_AArch32::Emit_Alu_GenericAnyAny(const STATEMENT& statement)
35 {
36 auto dst = statement.dst->GetSymbol().get();
37 auto src1 = statement.src1->GetSymbol().get();
38 auto src2 = statement.src2->GetSymbol().get();
39
40 auto dstReg = PrepareSymbolRegisterDef(dst, CAArch32Assembler::r0);
41 auto src1Reg = PrepareSymbolRegisterUse(src1, CAArch32Assembler::r1);
42 auto src2Reg = PrepareSymbolRegisterUse(src2, CAArch32Assembler::r2);
43 ((m_assembler).*(ALUOP::OpReg()))(dstReg, src1Reg, src2Reg);
44 CommitSymbolRegister(dst, dstReg);
45 }
46
47 template <typename ALUOP>
Emit_Alu_GenericAnyCst(const STATEMENT & statement)48 void CCodeGen_AArch32::Emit_Alu_GenericAnyCst(const STATEMENT& statement)
49 {
50 auto dst = statement.dst->GetSymbol().get();
51 auto src1 = statement.src1->GetSymbol().get();
52 auto src2 = statement.src2->GetSymbol().get();
53
54 assert(src2->m_type == SYM_CONSTANT);
55
56 auto dstReg = PrepareSymbolRegisterDef(dst, CAArch32Assembler::r0);
57 auto src1Reg = PrepareSymbolRegisterUse(src1, CAArch32Assembler::r1);
58 uint32 cst = src2->m_valueLow;
59
60 bool supportsNegative = ALUOP::OpImmNeg() != NULL;
61 bool supportsComplement = ALUOP::OpImmNot() != NULL;
62
63 uint8 immediate = 0;
64 uint8 shiftAmount = 0;
65 if(TryGetAluImmediateParams(cst, immediate, shiftAmount))
66 {
67 ((m_assembler).*(ALUOP::OpImm()))(dstReg, src1Reg, CAArch32Assembler::MakeImmediateAluOperand(immediate, shiftAmount));
68 }
69 else if(supportsNegative && TryGetAluImmediateParams(-static_cast<int32>(cst), immediate, shiftAmount))
70 {
71 ((m_assembler).*(ALUOP::OpImmNeg()))(dstReg, src1Reg, CAArch32Assembler::MakeImmediateAluOperand(immediate, shiftAmount));
72 }
73 else if(supportsComplement && TryGetAluImmediateParams(~cst, immediate, shiftAmount))
74 {
75 ((m_assembler).*(ALUOP::OpImmNot()))(dstReg, src1Reg, CAArch32Assembler::MakeImmediateAluOperand(immediate, shiftAmount));
76 }
77 else
78 {
79 auto cstReg = PrepareSymbolRegisterUse(src2, CAArch32Assembler::r2);
80 assert(cstReg != dstReg && cstReg != src1Reg);
81 ((m_assembler).*(ALUOP::OpReg()))(dstReg, src1Reg, cstReg);
82 }
83
84 CommitSymbolRegister(dst, dstReg);
85 }
86
87 #define ALU_CONST_MATCHERS(ALUOP_CST, ALUOP) \
88 { ALUOP_CST, MATCH_ANY, MATCH_ANY, MATCH_CONSTANT, &CCodeGen_AArch32::Emit_Alu_GenericAnyCst<ALUOP> }, \
89 { ALUOP_CST, MATCH_ANY, MATCH_ANY, MATCH_ANY, &CCodeGen_AArch32::Emit_Alu_GenericAnyAny<ALUOP> },
90
91 #include "Jitter_CodeGen_AArch32_Div.h"
92
93 template <bool isSigned>
Emit_MulTmp64AnyAny(const STATEMENT & statement)94 void CCodeGen_AArch32::Emit_MulTmp64AnyAny(const STATEMENT& statement)
95 {
96 auto dst = statement.dst->GetSymbol().get();
97 auto src1 = statement.src1->GetSymbol().get();
98 auto src2 = statement.src2->GetSymbol().get();
99
100 auto resLoReg = CAArch32Assembler::r0;
101 auto resHiReg = CAArch32Assembler::r1;
102 auto src1Reg = PrepareSymbolRegisterUse(src1, CAArch32Assembler::r2);
103 auto src2Reg = PrepareSymbolRegisterUse(src2, CAArch32Assembler::r3);
104
105 assert(dst->m_type == SYM_TEMPORARY64);
106 assert(resLoReg != src1Reg && resLoReg != src2Reg);
107 assert(resHiReg != src1Reg && resHiReg != src2Reg);
108
109 if(isSigned)
110 {
111 m_assembler.Smull(resLoReg, resHiReg, src1Reg, src2Reg);
112 }
113 else
114 {
115 m_assembler.Umull(resLoReg, resHiReg, src1Reg, src2Reg);
116 }
117
118 m_assembler.Str(resLoReg, CAArch32Assembler::rSP, CAArch32Assembler::MakeImmediateLdrAddress(dst->m_stackLocation + m_stackLevel + 0));
119 m_assembler.Str(resHiReg, CAArch32Assembler::rSP, CAArch32Assembler::MakeImmediateLdrAddress(dst->m_stackLocation + m_stackLevel + 4));
120 }
121
122 template <CAArch32Assembler::SHIFT shiftType>
Emit_Shift_Generic(const STATEMENT & statement)123 void CCodeGen_AArch32::Emit_Shift_Generic(const STATEMENT& statement)
124 {
125 auto dst = statement.dst->GetSymbol().get();
126 auto src1 = statement.src1->GetSymbol().get();
127 auto src2 = statement.src2->GetSymbol().get();
128
129 auto dstReg = PrepareSymbolRegisterDef(dst, CAArch32Assembler::r0);
130 auto src1Reg = PrepareSymbolRegisterUse(src1, CAArch32Assembler::r1);
131 auto shift = GetAluShiftFromSymbol(shiftType, src2, CAArch32Assembler::r2);
132 m_assembler.Mov(dstReg, CAArch32Assembler::MakeRegisterAluOperand(src1Reg, shift));
133 CommitSymbolRegister(dst, dstReg);
134 }
135
136 CCodeGen_AArch32::CONSTMATCHER CCodeGen_AArch32::g_constMatchers[] =
137 {
138 { OP_LABEL, MATCH_NIL, MATCH_NIL, MATCH_NIL, &CCodeGen_AArch32::MarkLabel },
139
140 { OP_NOP, MATCH_NIL, MATCH_NIL, MATCH_NIL, &CCodeGen_AArch32::Emit_Nop },
141
142 { OP_MOV, MATCH_REGISTER, MATCH_REGISTER, MATCH_NIL, &CCodeGen_AArch32::Emit_Mov_RegReg },
143 { OP_MOV, MATCH_REGISTER, MATCH_MEMORY, MATCH_NIL, &CCodeGen_AArch32::Emit_Mov_RegMem },
144 { OP_MOV, MATCH_REGISTER, MATCH_CONSTANT, MATCH_NIL, &CCodeGen_AArch32::Emit_Mov_RegCst },
145 { OP_MOV, MATCH_MEMORY, MATCH_REGISTER, MATCH_NIL, &CCodeGen_AArch32::Emit_Mov_MemReg },
146 { OP_MOV, MATCH_MEMORY, MATCH_MEMORY, MATCH_NIL, &CCodeGen_AArch32::Emit_Mov_MemMem },
147 { OP_MOV, MATCH_MEMORY, MATCH_CONSTANT, MATCH_NIL, &CCodeGen_AArch32::Emit_Mov_MemCst },
148
149 ALU_CONST_MATCHERS(OP_ADD, ALUOP_ADD)
150 ALU_CONST_MATCHERS(OP_SUB, ALUOP_SUB)
151 ALU_CONST_MATCHERS(OP_AND, ALUOP_AND)
152 ALU_CONST_MATCHERS(OP_OR, ALUOP_OR)
153 ALU_CONST_MATCHERS(OP_XOR, ALUOP_XOR)
154
155 { OP_LZC, MATCH_VARIABLE, MATCH_VARIABLE, MATCH_NIL, &CCodeGen_AArch32::Emit_Lzc_VarVar },
156
157 { OP_SRL, MATCH_ANY, MATCH_ANY, MATCH_ANY, &CCodeGen_AArch32::Emit_Shift_Generic<CAArch32Assembler::SHIFT_LSR> },
158 { OP_SRA, MATCH_ANY, MATCH_ANY, MATCH_ANY, &CCodeGen_AArch32::Emit_Shift_Generic<CAArch32Assembler::SHIFT_ASR> },
159 { OP_SLL, MATCH_ANY, MATCH_ANY, MATCH_ANY, &CCodeGen_AArch32::Emit_Shift_Generic<CAArch32Assembler::SHIFT_LSL> },
160
161 { OP_PARAM, MATCH_NIL, MATCH_CONTEXT, MATCH_NIL, &CCodeGen_AArch32::Emit_Param_Ctx },
162 { OP_PARAM, MATCH_NIL, MATCH_REGISTER, MATCH_NIL, &CCodeGen_AArch32::Emit_Param_Reg },
163 { OP_PARAM, MATCH_NIL, MATCH_MEMORY, MATCH_NIL, &CCodeGen_AArch32::Emit_Param_Mem },
164 { OP_PARAM, MATCH_NIL, MATCH_CONSTANT, MATCH_NIL, &CCodeGen_AArch32::Emit_Param_Cst },
165 { OP_PARAM, MATCH_NIL, MATCH_MEMORY64, MATCH_NIL, &CCodeGen_AArch32::Emit_Param_Mem64 },
166 { OP_PARAM, MATCH_NIL, MATCH_CONSTANT64, MATCH_NIL, &CCodeGen_AArch32::Emit_Param_Cst64 },
167 { OP_PARAM, MATCH_NIL, MATCH_MEMORY128, MATCH_NIL, &CCodeGen_AArch32::Emit_Param_Mem128 },
168
169 { OP_PARAM_RET, MATCH_NIL, MATCH_TEMPORARY128, MATCH_NIL, &CCodeGen_AArch32::Emit_ParamRet_Tmp128 },
170
171 { OP_CALL, MATCH_NIL, MATCH_CONSTANTPTR, MATCH_CONSTANT, &CCodeGen_AArch32::Emit_Call },
172
173 { OP_RETVAL, MATCH_REGISTER, MATCH_NIL, MATCH_NIL, &CCodeGen_AArch32::Emit_RetVal_Reg },
174 { OP_RETVAL, MATCH_TEMPORARY, MATCH_NIL, MATCH_NIL, &CCodeGen_AArch32::Emit_RetVal_Tmp },
175 { OP_RETVAL, MATCH_MEMORY64, MATCH_NIL, MATCH_NIL, &CCodeGen_AArch32::Emit_RetVal_Mem64 },
176
177 { OP_JMP, MATCH_NIL, MATCH_NIL, MATCH_NIL, &CCodeGen_AArch32::Emit_Jmp },
178
179 { OP_CONDJMP, MATCH_NIL, MATCH_VARIABLE, MATCH_CONSTANT, &CCodeGen_AArch32::Emit_CondJmp_VarCst },
180 { OP_CONDJMP, MATCH_NIL, MATCH_VARIABLE, MATCH_VARIABLE, &CCodeGen_AArch32::Emit_CondJmp_VarVar },
181
182 { OP_CMP, MATCH_ANY, MATCH_ANY, MATCH_CONSTANT, &CCodeGen_AArch32::Emit_Cmp_AnyAnyCst },
183 { OP_CMP, MATCH_ANY, MATCH_ANY, MATCH_ANY, &CCodeGen_AArch32::Emit_Cmp_AnyAnyAny },
184
185 { OP_NOT, MATCH_REGISTER, MATCH_REGISTER, MATCH_NIL, &CCodeGen_AArch32::Emit_Not_RegReg },
186 { OP_NOT, MATCH_MEMORY, MATCH_REGISTER, MATCH_NIL, &CCodeGen_AArch32::Emit_Not_MemReg },
187 { OP_NOT, MATCH_MEMORY, MATCH_MEMORY, MATCH_NIL, &CCodeGen_AArch32::Emit_Not_MemMem },
188
189 { OP_DIV, MATCH_TEMPORARY64, MATCH_ANY, MATCH_ANY, &CCodeGen_AArch32::Emit_DivTmp64AnyAny<false> },
190 { OP_DIVS, MATCH_TEMPORARY64, MATCH_ANY, MATCH_ANY, &CCodeGen_AArch32::Emit_DivTmp64AnyAny<true> },
191
192 { OP_MUL, MATCH_TEMPORARY64, MATCH_ANY, MATCH_ANY, &CCodeGen_AArch32::Emit_MulTmp64AnyAny<false> },
193 { OP_MULS, MATCH_TEMPORARY64, MATCH_ANY, MATCH_ANY, &CCodeGen_AArch32::Emit_MulTmp64AnyAny<true> },
194
195 { OP_RELTOREF, MATCH_TMP_REF, MATCH_CONSTANT, MATCH_ANY, &CCodeGen_AArch32::Emit_RelToRef_TmpCst },
196
197 { OP_ADDREF, MATCH_TMP_REF, MATCH_MEM_REF, MATCH_ANY, &CCodeGen_AArch32::Emit_AddRef_TmpMemAny },
198
199 { OP_LOADFROMREF, MATCH_VARIABLE, MATCH_TMP_REF, MATCH_NIL, &CCodeGen_AArch32::Emit_LoadFromRef_VarTmp },
200
201 //Cannot use MATCH_ANY here because it will match SYM_RELATIVE128
202 { OP_STOREATREF, MATCH_NIL, MATCH_TMP_REF, MATCH_VARIABLE, &CCodeGen_AArch32::Emit_StoreAtRef_TmpAny },
203 { OP_STOREATREF, MATCH_NIL, MATCH_TMP_REF, MATCH_CONSTANT, &CCodeGen_AArch32::Emit_StoreAtRef_TmpAny },
204
205 { OP_MOV, MATCH_NIL, MATCH_NIL, MATCH_NIL, NULL },
206 };
207
CCodeGen_AArch32()208 CCodeGen_AArch32::CCodeGen_AArch32()
209 {
210 #ifdef __ANDROID__
211 auto cpuFeatures = android_getCpuFeatures();
212 if(cpuFeatures & ANDROID_CPU_ARM_FEATURE_IDIV_ARM)
213 {
214 m_hasIntegerDiv = true;
215 }
216 #endif
217
218 for(auto* constMatcher = g_constMatchers; constMatcher->emitter != nullptr; constMatcher++)
219 {
220 MATCHER matcher;
221 matcher.op = constMatcher->op;
222 matcher.dstType = constMatcher->dstType;
223 matcher.src1Type = constMatcher->src1Type;
224 matcher.src2Type = constMatcher->src2Type;
225 matcher.emitter = std::bind(constMatcher->emitter, this, std::placeholders::_1);
226 m_matchers.insert(MatcherMapType::value_type(matcher.op, matcher));
227 }
228
229 for(auto* constMatcher = g_64ConstMatchers; constMatcher->emitter != nullptr; constMatcher++)
230 {
231 MATCHER matcher;
232 matcher.op = constMatcher->op;
233 matcher.dstType = constMatcher->dstType;
234 matcher.src1Type = constMatcher->src1Type;
235 matcher.src2Type = constMatcher->src2Type;
236 matcher.emitter = std::bind(constMatcher->emitter, this, std::placeholders::_1);
237 m_matchers.insert(MatcherMapType::value_type(matcher.op, matcher));
238 }
239
240 for(auto* constMatcher = g_fpuConstMatchers; constMatcher->emitter != nullptr; constMatcher++)
241 {
242 MATCHER matcher;
243 matcher.op = constMatcher->op;
244 matcher.dstType = constMatcher->dstType;
245 matcher.src1Type = constMatcher->src1Type;
246 matcher.src2Type = constMatcher->src2Type;
247 matcher.emitter = std::bind(constMatcher->emitter, this, std::placeholders::_1);
248 m_matchers.insert(MatcherMapType::value_type(matcher.op, matcher));
249 }
250
251 for(auto* constMatcher = g_mdConstMatchers; constMatcher->emitter != nullptr; constMatcher++)
252 {
253 MATCHER matcher;
254 matcher.op = constMatcher->op;
255 matcher.dstType = constMatcher->dstType;
256 matcher.src1Type = constMatcher->src1Type;
257 matcher.src2Type = constMatcher->src2Type;
258 matcher.emitter = std::bind(constMatcher->emitter, this, std::placeholders::_1);
259 m_matchers.insert(MatcherMapType::value_type(matcher.op, matcher));
260 }
261 }
262
~CCodeGen_AArch32()263 CCodeGen_AArch32::~CCodeGen_AArch32()
264 {
265
266 }
267
GetAvailableRegisterCount() const268 unsigned int CCodeGen_AArch32::GetAvailableRegisterCount() const
269 {
270 return MAX_REGISTERS;
271 }
272
GetAvailableMdRegisterCount() const273 unsigned int CCodeGen_AArch32::GetAvailableMdRegisterCount() const
274 {
275 return 0;
276 }
277
CanHold128BitsReturnValueInRegisters() const278 bool CCodeGen_AArch32::CanHold128BitsReturnValueInRegisters() const
279 {
280 return false;
281 }
282
SetStream(Framework::CStream * stream)283 void CCodeGen_AArch32::SetStream(Framework::CStream* stream)
284 {
285 m_stream = stream;
286 m_assembler.SetStream(stream);
287 }
288
RegisterExternalSymbols(CObjectFile * objectFile) const289 void CCodeGen_AArch32::RegisterExternalSymbols(CObjectFile* objectFile) const
290 {
291 objectFile->AddExternalSymbol("_CodeGen_AArch32_div_unsigned", reinterpret_cast<uintptr_t>(&CodeGen_AArch32_div_unsigned));
292 objectFile->AddExternalSymbol("_CodeGen_AArch32_div_signed", reinterpret_cast<uintptr_t>(&CodeGen_AArch32_div_signed));
293 objectFile->AddExternalSymbol("_CodeGen_AArch32_mod_unsigned", reinterpret_cast<uintptr_t>(&CodeGen_AArch32_mod_unsigned));
294 objectFile->AddExternalSymbol("_CodeGen_AArch32_mod_signed", reinterpret_cast<uintptr_t>(&CodeGen_AArch32_mod_signed));
295 }
296
GenerateCode(const StatementList & statements,unsigned int stackSize)297 void CCodeGen_AArch32::GenerateCode(const StatementList& statements, unsigned int stackSize)
298 {
299 //Align stack size (must be aligned on 16 bytes boundary)
300 stackSize = (stackSize + 0xF) & ~0xF;
301
302 uint16 registerSave = GetSavedRegisterList(GetRegisterUsage(statements));
303
304 Emit_Prolog(stackSize, registerSave);
305
306 for(const auto& statement : statements)
307 {
308 bool found = false;
309 auto begin = m_matchers.lower_bound(statement.op);
310 auto end = m_matchers.upper_bound(statement.op);
311
312 for(auto matchIterator(begin); matchIterator != end; matchIterator++)
313 {
314 const MATCHER& matcher(matchIterator->second);
315 if(!SymbolMatches(matcher.dstType, statement.dst)) continue;
316 if(!SymbolMatches(matcher.src1Type, statement.src1)) continue;
317 if(!SymbolMatches(matcher.src2Type, statement.src2)) continue;
318 matcher.emitter(statement);
319 found = true;
320 break;
321 }
322 assert(found);
323 if(!found)
324 {
325 throw std::runtime_error("No suitable emitter found for statement.");
326 }
327 }
328
329 Emit_Epilog(stackSize, registerSave);
330
331 m_assembler.ResolveLabelReferences();
332 m_assembler.ClearLabels();
333 m_labels.clear();
334 }
335
GetSavedRegisterList(uint32 registerUsage)336 uint16 CCodeGen_AArch32::GetSavedRegisterList(uint32 registerUsage)
337 {
338 uint16 registerSave = 0;
339 for(unsigned int i = 0; i < MAX_REGISTERS; i++)
340 {
341 if((1 << i) & registerUsage)
342 {
343 registerSave |= (1 << g_registers[i]);
344 }
345 }
346 registerSave |= (1 << g_callAddressRegister);
347 registerSave |= (1 << g_baseRegister);
348 registerSave |= (1 << CAArch32Assembler::rLR);
349 return registerSave;
350 }
351
Emit_Prolog(unsigned int stackSize,uint16 registerSave)352 void CCodeGen_AArch32::Emit_Prolog(unsigned int stackSize, uint16 registerSave)
353 {
354 m_assembler.Stmdb(CAArch32Assembler::rSP, registerSave);
355 m_assembler.Mov(CAArch32Assembler::r11, CAArch32Assembler::r0);
356
357 //Align stack to 16 bytes boundary
358 m_assembler.Mov(CAArch32Assembler::r0, CAArch32Assembler::rSP);
359 m_assembler.Bic(CAArch32Assembler::rSP, CAArch32Assembler::rSP, CAArch32Assembler::MakeImmediateAluOperand(0xF, 0));
360 m_assembler.Sub(CAArch32Assembler::rSP, CAArch32Assembler::rSP, CAArch32Assembler::MakeImmediateAluOperand(0xC, 0));
361 m_assembler.Stmdb(CAArch32Assembler::rSP, (1 << CAArch32Assembler::r0));
362
363 if(stackSize != 0)
364 {
365 uint8 allocImm = 0, allocSa = 0;
366 bool succeeded = TryGetAluImmediateParams(stackSize, allocImm, allocSa);
367 if(succeeded)
368 {
369 m_assembler.Sub(CAArch32Assembler::rSP, CAArch32Assembler::rSP, CAArch32Assembler::MakeImmediateAluOperand(allocImm, allocSa));
370 }
371 else
372 {
373 auto stackResReg = CAArch32Assembler::r0;
374 LoadConstantInRegister(stackResReg, stackSize);
375 m_assembler.Sub(CAArch32Assembler::rSP, CAArch32Assembler::rSP, stackResReg);
376 }
377 }
378 m_stackLevel = 0;
379 }
380
Emit_Epilog(unsigned int stackSize,uint16 registerSave)381 void CCodeGen_AArch32::Emit_Epilog(unsigned int stackSize, uint16 registerSave)
382 {
383 if(stackSize != 0)
384 {
385 uint8 allocImm = 0, allocSa = 0;
386 bool succeeded = TryGetAluImmediateParams(stackSize, allocImm, allocSa);
387 if(succeeded)
388 {
389 m_assembler.Add(CAArch32Assembler::rSP, CAArch32Assembler::rSP, CAArch32Assembler::MakeImmediateAluOperand(allocImm, allocSa));
390 }
391 else
392 {
393 auto stackResReg = CAArch32Assembler::r0;
394 LoadConstantInRegister(stackResReg, stackSize);
395 m_assembler.Add(CAArch32Assembler::rSP, CAArch32Assembler::rSP, stackResReg);
396 }
397 }
398
399 //Restore previous unaligned SP
400 m_assembler.Ldmia(CAArch32Assembler::rSP, (1 << CAArch32Assembler::r0));
401 m_assembler.Mov(CAArch32Assembler::rSP, CAArch32Assembler::r0);
402
403 m_assembler.Ldmia(CAArch32Assembler::rSP, registerSave);
404 m_assembler.Bx(CAArch32Assembler::rLR);
405 }
406
RotateRight(uint32 value)407 uint32 CCodeGen_AArch32::RotateRight(uint32 value)
408 {
409 uint32 carry = value & 1;
410 value >>= 1;
411 value |= carry << 31;
412 return value;
413 }
414
RotateLeft(uint32 value)415 uint32 CCodeGen_AArch32::RotateLeft(uint32 value)
416 {
417 uint32 carry = value >> 31;
418 value <<= 1;
419 value |= carry;
420 return value;
421 }
422
TryGetAluImmediateParams(uint32 constant,uint8 & immediate,uint8 & shiftAmount)423 bool CCodeGen_AArch32::TryGetAluImmediateParams(uint32 constant, uint8& immediate, uint8& shiftAmount)
424 {
425 uint32 shadowConstant = constant;
426 shiftAmount = 0xFF;
427
428 for(unsigned int i = 0; i < 16; i++)
429 {
430 if((shadowConstant & 0xFF) == shadowConstant)
431 {
432 shiftAmount = i;
433 break;
434 }
435 shadowConstant = RotateLeft(shadowConstant);
436 shadowConstant = RotateLeft(shadowConstant);
437 }
438
439 if(shiftAmount != 0xFF)
440 {
441 immediate = static_cast<uint8>(shadowConstant);
442 return true;
443 }
444 else
445 {
446 return false;
447 }
448 }
449
LoadConstantInRegister(CAArch32Assembler::REGISTER registerId,uint32 constant)450 void CCodeGen_AArch32::LoadConstantInRegister(CAArch32Assembler::REGISTER registerId, uint32 constant)
451 {
452 //Try normal move
453 {
454 uint8 immediate = 0;
455 uint8 shiftAmount = 0;
456 if(TryGetAluImmediateParams(constant, immediate, shiftAmount))
457 {
458 m_assembler.Mov(registerId, CAArch32Assembler::MakeImmediateAluOperand(immediate, shiftAmount));
459 return;
460 }
461 }
462
463 //Try not move
464 {
465 uint8 immediate = 0;
466 uint8 shiftAmount = 0;
467 if(TryGetAluImmediateParams(~constant, immediate, shiftAmount))
468 {
469 m_assembler.Mvn(registerId, CAArch32Assembler::MakeImmediateAluOperand(immediate, shiftAmount));
470 return;
471 }
472 }
473
474 //Otherwise, use paired move
475 m_assembler.Movw(registerId, static_cast<uint16>(constant & 0xFFFF));
476 if((constant & 0xFFFF0000) != 0)
477 {
478 m_assembler.Movt(registerId, static_cast<uint16>(constant >> 16));
479 }
480 }
481
LoadConstantPtrInRegister(CAArch32Assembler::REGISTER registerId,uintptr_t constant)482 void CCodeGen_AArch32::LoadConstantPtrInRegister(CAArch32Assembler::REGISTER registerId, uintptr_t constant)
483 {
484 m_assembler.Movw(registerId, static_cast<uint16>(constant & 0xFFFF));
485 m_assembler.Movt(registerId, static_cast<uint16>(constant >> 16));
486
487 if(m_externalSymbolReferencedHandler)
488 {
489 auto position = m_stream->GetLength();
490 m_externalSymbolReferencedHandler(constant, position - 8);
491 }
492 }
493
LoadMemoryInRegister(CAArch32Assembler::REGISTER registerId,CSymbol * src)494 void CCodeGen_AArch32::LoadMemoryInRegister(CAArch32Assembler::REGISTER registerId, CSymbol* src)
495 {
496 switch(src->m_type)
497 {
498 case SYM_RELATIVE:
499 assert((src->m_valueLow & 0x03) == 0x00);
500 m_assembler.Ldr(registerId, g_baseRegister, CAArch32Assembler::MakeImmediateLdrAddress(src->m_valueLow));
501 break;
502 case SYM_TEMPORARY:
503 m_assembler.Ldr(registerId, CAArch32Assembler::rSP, CAArch32Assembler::MakeImmediateLdrAddress(src->m_stackLocation + m_stackLevel));
504 break;
505 default:
506 assert(0);
507 break;
508 }
509 }
510
StoreRegisterInMemory(CSymbol * dst,CAArch32Assembler::REGISTER registerId)511 void CCodeGen_AArch32::StoreRegisterInMemory(CSymbol* dst, CAArch32Assembler::REGISTER registerId)
512 {
513 switch(dst->m_type)
514 {
515 case SYM_RELATIVE:
516 assert((dst->m_valueLow & 0x03) == 0x00);
517 m_assembler.Str(registerId, g_baseRegister, CAArch32Assembler::MakeImmediateLdrAddress(dst->m_valueLow));
518 break;
519 case SYM_TEMPORARY:
520 m_assembler.Str(registerId, CAArch32Assembler::rSP, CAArch32Assembler::MakeImmediateLdrAddress(dst->m_stackLocation + m_stackLevel));
521 break;
522 default:
523 assert(0);
524 break;
525 }
526 }
527
LoadMemoryReferenceInRegister(CAArch32Assembler::REGISTER registerId,CSymbol * src)528 void CCodeGen_AArch32::LoadMemoryReferenceInRegister(CAArch32Assembler::REGISTER registerId, CSymbol* src)
529 {
530 switch(src->m_type)
531 {
532 case SYM_REL_REFERENCE:
533 LoadRelativeReferenceInRegister(registerId, src);
534 break;
535 case SYM_TMP_REFERENCE:
536 LoadTemporaryReferenceInRegister(registerId, src);
537 break;
538 default:
539 assert(false);
540 break;
541 }
542 }
543
LoadRelativeReferenceInRegister(CAArch32Assembler::REGISTER registerId,CSymbol * src)544 void CCodeGen_AArch32::LoadRelativeReferenceInRegister(CAArch32Assembler::REGISTER registerId, CSymbol* src)
545 {
546 assert(src->m_type == SYM_REL_REFERENCE);
547 assert((src->m_valueLow & 0x03) == 0x00);
548 m_assembler.Ldr(registerId, g_baseRegister, CAArch32Assembler::MakeImmediateLdrAddress(src->m_valueLow));
549 }
550
LoadTemporaryReferenceInRegister(CAArch32Assembler::REGISTER registerId,CSymbol * src)551 void CCodeGen_AArch32::LoadTemporaryReferenceInRegister(CAArch32Assembler::REGISTER registerId, CSymbol* src)
552 {
553 assert(src->m_type == SYM_TMP_REFERENCE);
554 m_assembler.Ldr(registerId, CAArch32Assembler::rSP, CAArch32Assembler::MakeImmediateLdrAddress(src->m_stackLocation + m_stackLevel));
555 }
556
StoreRegisterInTemporaryReference(CSymbol * dst,CAArch32Assembler::REGISTER registerId)557 void CCodeGen_AArch32::StoreRegisterInTemporaryReference(CSymbol* dst, CAArch32Assembler::REGISTER registerId)
558 {
559 assert(dst->m_type == SYM_TMP_REFERENCE);
560 m_assembler.Str(registerId, CAArch32Assembler::rSP, CAArch32Assembler::MakeImmediateLdrAddress(dst->m_stackLocation + m_stackLevel));
561 }
562
GetAluShiftFromSymbol(CAArch32Assembler::SHIFT shiftType,CSymbol * symbol,CAArch32Assembler::REGISTER preferedRegister)563 CAArch32Assembler::AluLdrShift CCodeGen_AArch32::GetAluShiftFromSymbol(CAArch32Assembler::SHIFT shiftType, CSymbol* symbol, CAArch32Assembler::REGISTER preferedRegister)
564 {
565 switch(symbol->m_type)
566 {
567 case SYM_REGISTER:
568 m_assembler.And(preferedRegister, g_registers[symbol->m_valueLow], CAArch32Assembler::MakeImmediateAluOperand(0x1F, 0));
569 return CAArch32Assembler::MakeVariableShift(shiftType, preferedRegister);
570 break;
571 case SYM_TEMPORARY:
572 case SYM_RELATIVE:
573 LoadMemoryInRegister(preferedRegister, symbol);
574 m_assembler.And(preferedRegister, preferedRegister, CAArch32Assembler::MakeImmediateAluOperand(0x1F, 0));
575 return CAArch32Assembler::MakeVariableShift(shiftType, preferedRegister);
576 break;
577 case SYM_CONSTANT:
578 return CAArch32Assembler::MakeConstantShift(shiftType, static_cast<uint8>(symbol->m_valueLow & 0x1F));
579 break;
580 default:
581 throw std::runtime_error("Invalid symbol type.");
582 break;
583 }
584 }
585
PrepareSymbolRegisterDef(CSymbol * symbol,CAArch32Assembler::REGISTER preferedRegister)586 CAArch32Assembler::REGISTER CCodeGen_AArch32::PrepareSymbolRegisterDef(CSymbol* symbol, CAArch32Assembler::REGISTER preferedRegister)
587 {
588 switch(symbol->m_type)
589 {
590 case SYM_REGISTER:
591 return g_registers[symbol->m_valueLow];
592 break;
593 case SYM_TEMPORARY:
594 case SYM_RELATIVE:
595 return preferedRegister;
596 break;
597 default:
598 throw std::runtime_error("Invalid symbol type.");
599 break;
600 }
601 }
602
PrepareSymbolRegisterUse(CSymbol * symbol,CAArch32Assembler::REGISTER preferedRegister)603 CAArch32Assembler::REGISTER CCodeGen_AArch32::PrepareSymbolRegisterUse(CSymbol* symbol, CAArch32Assembler::REGISTER preferedRegister)
604 {
605 switch(symbol->m_type)
606 {
607 case SYM_REGISTER:
608 return g_registers[symbol->m_valueLow];
609 break;
610 case SYM_TEMPORARY:
611 case SYM_RELATIVE:
612 LoadMemoryInRegister(preferedRegister, symbol);
613 return preferedRegister;
614 break;
615 case SYM_CONSTANT:
616 LoadConstantInRegister(preferedRegister, symbol->m_valueLow);
617 return preferedRegister;
618 break;
619 default:
620 throw std::runtime_error("Invalid symbol type.");
621 break;
622 }
623 }
624
CommitSymbolRegister(CSymbol * symbol,CAArch32Assembler::REGISTER usedRegister)625 void CCodeGen_AArch32::CommitSymbolRegister(CSymbol* symbol, CAArch32Assembler::REGISTER usedRegister)
626 {
627 switch(symbol->m_type)
628 {
629 case SYM_REGISTER:
630 assert(usedRegister == g_registers[symbol->m_valueLow]);
631 break;
632 case SYM_TEMPORARY:
633 case SYM_RELATIVE:
634 StoreRegisterInMemory(symbol, usedRegister);
635 break;
636 default:
637 throw std::runtime_error("Invalid symbol type.");
638 break;
639 }
640 }
641
PrepareParam(PARAM_STATE & paramState)642 CAArch32Assembler::REGISTER CCodeGen_AArch32::PrepareParam(PARAM_STATE& paramState)
643 {
644 assert(!paramState.prepared);
645 paramState.prepared = true;
646 if(paramState.index < MAX_PARAM_REGS)
647 {
648 return g_paramRegs[paramState.index];
649 }
650 else
651 {
652 return g_tempParamRegister0;
653 }
654 }
655
PrepareParam64(PARAM_STATE & paramState)656 CCodeGen_AArch32::ParamRegisterPair CCodeGen_AArch32::PrepareParam64(PARAM_STATE& paramState)
657 {
658 assert(!paramState.prepared);
659 paramState.prepared = true;
660 #ifdef __ANDROID__
661 //TODO: This needs to be an ABI flag or something
662 if(paramState.index & 1)
663 {
664 paramState.index++;
665 }
666 #endif
667 ParamRegisterPair result;
668 for(unsigned int i = 0; i < 2; i++)
669 {
670 if((paramState.index + i) < MAX_PARAM_REGS)
671 {
672 result[i] = g_paramRegs[paramState.index + i];
673 }
674 else
675 {
676 result[i] = (i == 0) ? g_tempParamRegister0 : g_tempParamRegister1;
677 }
678 }
679 return result;
680 }
681
CommitParam(PARAM_STATE & paramState)682 void CCodeGen_AArch32::CommitParam(PARAM_STATE& paramState)
683 {
684 assert(paramState.prepared);
685 paramState.prepared = false;
686 if(paramState.index < MAX_PARAM_REGS)
687 {
688 //Nothing to do
689 }
690 else
691 {
692 uint32 stackSlot = ((paramState.index - MAX_PARAM_REGS) + 1) * 4;
693 m_assembler.Str(g_tempParamRegister0, CAArch32Assembler::rSP,
694 CAArch32Assembler::MakeImmediateLdrAddress(m_stackLevel - stackSlot));
695 }
696 paramState.index++;
697 }
698
CommitParam64(PARAM_STATE & paramState)699 void CCodeGen_AArch32::CommitParam64(PARAM_STATE& paramState)
700 {
701 assert(paramState.prepared);
702 paramState.prepared = false;
703 uint32 stackPosition = std::max<int>((paramState.index - MAX_PARAM_REGS) + 2, 0);
704 for(unsigned int i = 0; i < 2; i++)
705 {
706 if(paramState.index < MAX_PARAM_REGS)
707 {
708 //Nothing to do
709 }
710 else
711 {
712 assert(stackPosition > 0);
713 auto tempParamReg = (i == 0) ? g_tempParamRegister0 : g_tempParamRegister1;
714 uint32 stackSlot = i;
715 if(stackPosition == 1)
716 {
717 //Special case for when parameters are spread between
718 //registers and stack
719 assert(i == 1);
720 stackSlot = 0;
721 }
722 m_assembler.Str(tempParamReg, CAArch32Assembler::rSP,
723 CAArch32Assembler::MakeImmediateLdrAddress(m_stackLevel - (stackPosition * 4) + (stackSlot * 4)));
724 }
725 }
726 paramState.index += 2;
727 }
728
GetLabel(uint32 blockId)729 CAArch32Assembler::LABEL CCodeGen_AArch32::GetLabel(uint32 blockId)
730 {
731 CAArch32Assembler::LABEL result;
732 auto labelIterator(m_labels.find(blockId));
733 if(labelIterator == m_labels.end())
734 {
735 result = m_assembler.CreateLabel();
736 m_labels[blockId] = result;
737 }
738 else
739 {
740 result = labelIterator->second;
741 }
742 return result;
743 }
744
MarkLabel(const STATEMENT & statement)745 void CCodeGen_AArch32::MarkLabel(const STATEMENT& statement)
746 {
747 auto label = GetLabel(statement.jmpBlock);
748 m_assembler.MarkLabel(label);
749 }
750
Emit_Nop(const STATEMENT & statement)751 void CCodeGen_AArch32::Emit_Nop(const STATEMENT& statement)
752 {
753
754 }
755
Emit_Param_Ctx(const STATEMENT & statement)756 void CCodeGen_AArch32::Emit_Param_Ctx(const STATEMENT& statement)
757 {
758 auto src1 = statement.src1->GetSymbol().get();
759
760 assert(src1->m_type == SYM_CONTEXT);
761
762 m_params.push_back(
763 [this] (PARAM_STATE& paramState)
764 {
765 auto paramReg = PrepareParam(paramState);
766 m_assembler.Mov(paramReg, g_baseRegister);
767 CommitParam(paramState);
768 }
769 );
770 }
771
Emit_Param_Reg(const STATEMENT & statement)772 void CCodeGen_AArch32::Emit_Param_Reg(const STATEMENT& statement)
773 {
774 auto src1 = statement.src1->GetSymbol().get();
775
776 assert(src1->m_type == SYM_REGISTER);
777
778 m_params.push_back(
779 [this, src1] (PARAM_STATE& paramState)
780 {
781 auto paramReg = PrepareParam(paramState);
782 m_assembler.Mov(paramReg, g_registers[src1->m_valueLow]);
783 CommitParam(paramState);
784 }
785 );
786 }
787
Emit_Param_Mem(const STATEMENT & statement)788 void CCodeGen_AArch32::Emit_Param_Mem(const STATEMENT& statement)
789 {
790 auto src1 = statement.src1->GetSymbol().get();
791
792 m_params.push_back(
793 [this, src1] (PARAM_STATE& paramState)
794 {
795 auto paramReg = PrepareParam(paramState);
796 LoadMemoryInRegister(paramReg, src1);
797 CommitParam(paramState);
798 }
799 );
800 }
801
Emit_Param_Cst(const STATEMENT & statement)802 void CCodeGen_AArch32::Emit_Param_Cst(const STATEMENT& statement)
803 {
804 auto src1 = statement.src1->GetSymbol().get();
805
806 assert(src1->m_type == SYM_CONSTANT);
807
808 m_params.push_back(
809 [this, src1] (PARAM_STATE& paramState)
810 {
811 auto paramReg = PrepareParam(paramState);
812 LoadConstantInRegister(paramReg, src1->m_valueLow);
813 CommitParam(paramState);
814 }
815 );
816 }
817
Emit_Param_Mem64(const STATEMENT & statement)818 void CCodeGen_AArch32::Emit_Param_Mem64(const STATEMENT& statement)
819 {
820 auto src1 = statement.src1->GetSymbol().get();
821
822 m_params.push_back(
823 [this, src1] (PARAM_STATE& paramState)
824 {
825 auto paramRegs = PrepareParam64(paramState);
826 LoadMemory64InRegisters(paramRegs[0], paramRegs[1], src1);
827 CommitParam64(paramState);
828 }
829 );
830 }
831
Emit_Param_Cst64(const STATEMENT & statement)832 void CCodeGen_AArch32::Emit_Param_Cst64(const STATEMENT& statement)
833 {
834 auto src1 = statement.src1->GetSymbol().get();
835
836 m_params.push_back(
837 [this, src1] (PARAM_STATE& paramState)
838 {
839 auto paramRegs = PrepareParam64(paramState);
840 LoadConstantInRegister(paramRegs[0], src1->m_valueLow);
841 LoadConstantInRegister(paramRegs[1], src1->m_valueHigh);
842 CommitParam64(paramState);
843 }
844 );
845 }
846
Emit_Param_Mem128(const STATEMENT & statement)847 void CCodeGen_AArch32::Emit_Param_Mem128(const STATEMENT& statement)
848 {
849 auto src1 = statement.src1->GetSymbol().get();
850
851 m_params.push_back(
852 [this, src1] (PARAM_STATE& paramState)
853 {
854 auto paramReg = PrepareParam(paramState);
855 LoadMemory128AddressInRegister(paramReg, src1);
856 CommitParam(paramState);
857 }
858 );
859 }
860
Emit_ParamRet_Tmp128(const STATEMENT & statement)861 void CCodeGen_AArch32::Emit_ParamRet_Tmp128(const STATEMENT& statement)
862 {
863 Emit_Param_Mem128(statement);
864 }
865
Emit_Call(const STATEMENT & statement)866 void CCodeGen_AArch32::Emit_Call(const STATEMENT& statement)
867 {
868 auto src1 = statement.src1->GetSymbol().get();
869 auto src2 = statement.src2->GetSymbol().get();
870
871 assert(src1->m_type == SYM_CONSTANTPTR);
872 assert(src2->m_type == SYM_CONSTANT);
873
874 unsigned int paramCount = src2->m_valueLow;
875 PARAM_STATE paramState;
876
877 for(unsigned int i = 0; i < paramCount; i++)
878 {
879 auto emitter(m_params.back());
880 m_params.pop_back();
881 emitter(paramState);
882 }
883
884 uint32 stackAlloc = (paramState.index > MAX_PARAM_REGS) ? ((paramState.index - MAX_PARAM_REGS) * 4) : 0;
885
886 if(stackAlloc != 0)
887 {
888 m_assembler.Sub(CAArch32Assembler::rSP, CAArch32Assembler::rSP,
889 CAArch32Assembler::MakeImmediateAluOperand(stackAlloc, 0));
890 }
891
892 //No value should be saved in r4 at this point (register is spilled before)
893 LoadConstantPtrInRegister(g_callAddressRegister, src1->GetConstantPtr());
894 m_assembler.Mov(CAArch32Assembler::rLR, CAArch32Assembler::rPC);
895 m_assembler.Mov(CAArch32Assembler::rPC, g_callAddressRegister);
896
897 if(stackAlloc != 0)
898 {
899 m_assembler.Add(CAArch32Assembler::rSP, CAArch32Assembler::rSP,
900 CAArch32Assembler::MakeImmediateAluOperand(stackAlloc, 0));
901 }
902 }
903
Emit_RetVal_Reg(const STATEMENT & statement)904 void CCodeGen_AArch32::Emit_RetVal_Reg(const STATEMENT& statement)
905 {
906 auto dst = statement.dst->GetSymbol().get();
907
908 assert(dst->m_type == SYM_REGISTER);
909
910 m_assembler.Mov(g_registers[dst->m_valueLow], CAArch32Assembler::r0);
911 }
912
Emit_RetVal_Tmp(const STATEMENT & statement)913 void CCodeGen_AArch32::Emit_RetVal_Tmp(const STATEMENT& statement)
914 {
915 auto dst = statement.dst->GetSymbol().get();
916
917 assert(dst->m_type == SYM_TEMPORARY);
918
919 StoreRegisterInMemory(dst, CAArch32Assembler::r0);
920 }
921
Emit_RetVal_Mem64(const STATEMENT & statement)922 void CCodeGen_AArch32::Emit_RetVal_Mem64(const STATEMENT& statement)
923 {
924 auto dst = statement.dst->GetSymbol().get();
925
926 StoreRegistersInMemory64(dst, CAArch32Assembler::r0, CAArch32Assembler::r1);
927 }
928
Emit_Mov_RegReg(const STATEMENT & statement)929 void CCodeGen_AArch32::Emit_Mov_RegReg(const STATEMENT& statement)
930 {
931 auto dst = statement.dst->GetSymbol().get();
932 auto src1 = statement.src1->GetSymbol().get();
933
934 m_assembler.Mov(g_registers[dst->m_valueLow], g_registers[src1->m_valueLow]);
935 }
936
Emit_Mov_RegMem(const STATEMENT & statement)937 void CCodeGen_AArch32::Emit_Mov_RegMem(const STATEMENT& statement)
938 {
939 auto dst = statement.dst->GetSymbol().get();
940 auto src1 = statement.src1->GetSymbol().get();
941
942 LoadMemoryInRegister(g_registers[dst->m_valueLow], src1);
943 }
944
Emit_Mov_RegCst(const STATEMENT & statement)945 void CCodeGen_AArch32::Emit_Mov_RegCst(const STATEMENT& statement)
946 {
947 auto dst = statement.dst->GetSymbol().get();
948 auto src1 = statement.src1->GetSymbol().get();
949
950 assert(dst->m_type == SYM_REGISTER);
951 assert(src1->m_type == SYM_CONSTANT);
952
953 LoadConstantInRegister(g_registers[dst->m_valueLow], src1->m_valueLow);
954 }
955
Emit_Mov_MemReg(const STATEMENT & statement)956 void CCodeGen_AArch32::Emit_Mov_MemReg(const STATEMENT& statement)
957 {
958 auto dst = statement.dst->GetSymbol().get();
959 auto src1 = statement.src1->GetSymbol().get();
960
961 assert(src1->m_type == SYM_REGISTER);
962
963 StoreRegisterInMemory(dst, g_registers[src1->m_valueLow]);
964 }
965
Emit_Mov_MemMem(const STATEMENT & statement)966 void CCodeGen_AArch32::Emit_Mov_MemMem(const STATEMENT& statement)
967 {
968 auto dst = statement.dst->GetSymbol().get();
969 auto src1 = statement.src1->GetSymbol().get();
970
971 auto tmpReg = CAArch32Assembler::r0;
972 LoadMemoryInRegister(tmpReg, src1);
973 StoreRegisterInMemory(dst, tmpReg);
974 }
975
Emit_Mov_MemCst(const STATEMENT & statement)976 void CCodeGen_AArch32::Emit_Mov_MemCst(const STATEMENT& statement)
977 {
978 auto dst = statement.dst->GetSymbol().get();
979 auto src1 = statement.src1->GetSymbol().get();
980
981 assert(src1->m_type == SYM_CONSTANT);
982
983 auto tmpReg = CAArch32Assembler::r0;
984 LoadConstantInRegister(tmpReg, src1->m_valueLow);
985 StoreRegisterInMemory(dst, tmpReg);
986 }
987
Emit_Lzc_VarVar(const STATEMENT & statement)988 void CCodeGen_AArch32::Emit_Lzc_VarVar(const STATEMENT& statement)
989 {
990 auto dst = statement.dst->GetSymbol().get();
991 auto src1 = statement.src1->GetSymbol().get();
992
993 auto dstRegister = PrepareSymbolRegisterDef(dst, CAArch32Assembler::r0);
994 auto src1Register = PrepareSymbolRegisterUse(src1, CAArch32Assembler::r1);
995
996 auto set32Label = m_assembler.CreateLabel();
997 auto startCountLabel = m_assembler.CreateLabel();
998 auto doneLabel = m_assembler.CreateLabel();
999
1000 m_assembler.Mov(dstRegister, src1Register);
1001 m_assembler.Tst(dstRegister, dstRegister);
1002 m_assembler.BCc(CAArch32Assembler::CONDITION_EQ, set32Label);
1003 m_assembler.BCc(CAArch32Assembler::CONDITION_PL, startCountLabel);
1004
1005 //reverse:
1006 m_assembler.Mvn(dstRegister, dstRegister);
1007 m_assembler.Tst(dstRegister, dstRegister);
1008 m_assembler.BCc(CAArch32Assembler::CONDITION_EQ, set32Label);
1009
1010 //startCount:
1011 m_assembler.MarkLabel(startCountLabel);
1012 m_assembler.Clz(dstRegister, dstRegister);
1013 m_assembler.Sub(dstRegister, dstRegister, CAArch32Assembler::MakeImmediateAluOperand(1, 0));
1014 m_assembler.BCc(CAArch32Assembler::CONDITION_AL, doneLabel);
1015
1016 //set32:
1017 m_assembler.MarkLabel(set32Label);
1018 LoadConstantInRegister(dstRegister, 0x1F);
1019
1020 //done
1021 m_assembler.MarkLabel(doneLabel);
1022
1023 CommitSymbolRegister(dst, dstRegister);
1024 }
1025
Emit_Jmp(const STATEMENT & statement)1026 void CCodeGen_AArch32::Emit_Jmp(const STATEMENT& statement)
1027 {
1028 m_assembler.BCc(CAArch32Assembler::CONDITION_AL, GetLabel(statement.jmpBlock));
1029 }
1030
Emit_CondJmp(const STATEMENT & statement)1031 void CCodeGen_AArch32::Emit_CondJmp(const STATEMENT& statement)
1032 {
1033 CAArch32Assembler::LABEL label(GetLabel(statement.jmpBlock));
1034
1035 switch(statement.jmpCondition)
1036 {
1037 case CONDITION_EQ:
1038 m_assembler.BCc(CAArch32Assembler::CONDITION_EQ, label);
1039 break;
1040 case CONDITION_NE:
1041 m_assembler.BCc(CAArch32Assembler::CONDITION_NE, label);
1042 break;
1043 case CONDITION_LT:
1044 m_assembler.BCc(CAArch32Assembler::CONDITION_LT, label);
1045 break;
1046 case CONDITION_LE:
1047 m_assembler.BCc(CAArch32Assembler::CONDITION_LE, label);
1048 break;
1049 case CONDITION_GT:
1050 m_assembler.BCc(CAArch32Assembler::CONDITION_GT, label);
1051 break;
1052 case CONDITION_GE:
1053 m_assembler.BCc(CAArch32Assembler::CONDITION_GE, label);
1054 break;
1055 default:
1056 assert(0);
1057 break;
1058 }
1059 }
1060
Emit_CondJmp_VarVar(const STATEMENT & statement)1061 void CCodeGen_AArch32::Emit_CondJmp_VarVar(const STATEMENT& statement)
1062 {
1063 auto src1 = statement.src1->GetSymbol().get();
1064 auto src2 = statement.src2->GetSymbol().get();
1065
1066 assert(src2->m_type != SYM_CONSTANT); //We can do better if we have a constant
1067
1068 auto src1Reg = PrepareSymbolRegisterUse(src1, CAArch32Assembler::r1);
1069 auto src2Reg = PrepareSymbolRegisterUse(src2, CAArch32Assembler::r2);
1070 m_assembler.Cmp(src1Reg, src2Reg);
1071 Emit_CondJmp(statement);
1072 }
1073
Emit_CondJmp_VarCst(const STATEMENT & statement)1074 void CCodeGen_AArch32::Emit_CondJmp_VarCst(const STATEMENT& statement)
1075 {
1076 auto src1 = statement.src1->GetSymbol().get();
1077 auto src2 = statement.src2->GetSymbol().get();
1078
1079 assert(src2->m_type == SYM_CONSTANT);
1080
1081 auto src1Reg = PrepareSymbolRegisterUse(src1, CAArch32Assembler::r1);
1082 Cmp_GenericRegCst(src1Reg, src2->m_valueLow, CAArch32Assembler::r2);
1083 Emit_CondJmp(statement);
1084 }
1085
Cmp_GetFlag(CAArch32Assembler::REGISTER registerId,Jitter::CONDITION condition)1086 void CCodeGen_AArch32::Cmp_GetFlag(CAArch32Assembler::REGISTER registerId, Jitter::CONDITION condition)
1087 {
1088 CAArch32Assembler::ImmediateAluOperand falseOperand(CAArch32Assembler::MakeImmediateAluOperand(0, 0));
1089 CAArch32Assembler::ImmediateAluOperand trueOperand(CAArch32Assembler::MakeImmediateAluOperand(1, 0));
1090 switch(condition)
1091 {
1092 case CONDITION_EQ:
1093 m_assembler.MovCc(CAArch32Assembler::CONDITION_NE, registerId, falseOperand);
1094 m_assembler.MovCc(CAArch32Assembler::CONDITION_EQ, registerId, trueOperand);
1095 break;
1096 case CONDITION_NE:
1097 m_assembler.MovCc(CAArch32Assembler::CONDITION_EQ, registerId, falseOperand);
1098 m_assembler.MovCc(CAArch32Assembler::CONDITION_NE, registerId, trueOperand);
1099 break;
1100 case CONDITION_LT:
1101 m_assembler.MovCc(CAArch32Assembler::CONDITION_GE, registerId, falseOperand);
1102 m_assembler.MovCc(CAArch32Assembler::CONDITION_LT, registerId, trueOperand);
1103 break;
1104 case CONDITION_LE:
1105 m_assembler.MovCc(CAArch32Assembler::CONDITION_GT, registerId, falseOperand);
1106 m_assembler.MovCc(CAArch32Assembler::CONDITION_LE, registerId, trueOperand);
1107 break;
1108 case CONDITION_GT:
1109 m_assembler.MovCc(CAArch32Assembler::CONDITION_LE, registerId, falseOperand);
1110 m_assembler.MovCc(CAArch32Assembler::CONDITION_GT, registerId, trueOperand);
1111 break;
1112 case CONDITION_BL:
1113 m_assembler.MovCc(CAArch32Assembler::CONDITION_CS, registerId, falseOperand);
1114 m_assembler.MovCc(CAArch32Assembler::CONDITION_CC, registerId, trueOperand);
1115 break;
1116 case CONDITION_BE:
1117 m_assembler.MovCc(CAArch32Assembler::CONDITION_HI, registerId, falseOperand);
1118 m_assembler.MovCc(CAArch32Assembler::CONDITION_LS, registerId, trueOperand);
1119 break;
1120 case CONDITION_AB:
1121 m_assembler.MovCc(CAArch32Assembler::CONDITION_LS, registerId, falseOperand);
1122 m_assembler.MovCc(CAArch32Assembler::CONDITION_HI, registerId, trueOperand);
1123 break;
1124 default:
1125 assert(0);
1126 break;
1127 }
1128 }
1129
Cmp_GenericRegCst(CAArch32Assembler::REGISTER src1Reg,uint32 src2,CAArch32Assembler::REGISTER src2Reg)1130 void CCodeGen_AArch32::Cmp_GenericRegCst(CAArch32Assembler::REGISTER src1Reg, uint32 src2, CAArch32Assembler::REGISTER src2Reg)
1131 {
1132 uint8 immediate = 0;
1133 uint8 shiftAmount = 0;
1134 if(TryGetAluImmediateParams(src2, immediate, shiftAmount))
1135 {
1136 m_assembler.Cmp(src1Reg, CAArch32Assembler::MakeImmediateAluOperand(immediate, shiftAmount));
1137 }
1138 else if(TryGetAluImmediateParams(-static_cast<int32>(src2), immediate, shiftAmount))
1139 {
1140 m_assembler.Cmn(src1Reg, CAArch32Assembler::MakeImmediateAluOperand(immediate, shiftAmount));
1141 }
1142 else
1143 {
1144 assert(src1Reg != src2Reg);
1145 LoadConstantInRegister(src2Reg, src2);
1146 m_assembler.Cmp(src1Reg, src2Reg);
1147 }
1148 }
1149
Emit_Cmp_AnyAnyAny(const STATEMENT & statement)1150 void CCodeGen_AArch32::Emit_Cmp_AnyAnyAny(const STATEMENT& statement)
1151 {
1152 auto dst = statement.dst->GetSymbol().get();
1153 auto src1 = statement.src1->GetSymbol().get();
1154 auto src2 = statement.src2->GetSymbol().get();
1155
1156 auto dstReg = PrepareSymbolRegisterDef(dst, CAArch32Assembler::r0);
1157 auto src1Reg = PrepareSymbolRegisterUse(src1, CAArch32Assembler::r1);
1158 auto src2Reg = PrepareSymbolRegisterUse(src2, CAArch32Assembler::r2);
1159
1160 m_assembler.Cmp(src1Reg, src2Reg);
1161 Cmp_GetFlag(dstReg, statement.jmpCondition);
1162 CommitSymbolRegister(dst, dstReg);
1163 }
1164
Emit_Cmp_AnyAnyCst(const STATEMENT & statement)1165 void CCodeGen_AArch32::Emit_Cmp_AnyAnyCst(const STATEMENT& statement)
1166 {
1167 auto dst = statement.dst->GetSymbol().get();
1168 auto src1 = statement.src1->GetSymbol().get();
1169 auto src2 = statement.src2->GetSymbol().get();
1170
1171 assert(src2->m_type == SYM_CONSTANT);
1172
1173 auto dstReg = PrepareSymbolRegisterDef(dst, CAArch32Assembler::r0);
1174 auto src1Reg = PrepareSymbolRegisterUse(src1, CAArch32Assembler::r1);
1175 auto cst = src2->m_valueLow;
1176
1177 Cmp_GenericRegCst(src1Reg, cst, CAArch32Assembler::r2);
1178 Cmp_GetFlag(dstReg, statement.jmpCondition);
1179 CommitSymbolRegister(dst, dstReg);
1180 }
1181
Emit_Not_RegReg(const STATEMENT & statement)1182 void CCodeGen_AArch32::Emit_Not_RegReg(const STATEMENT& statement)
1183 {
1184 auto dst = statement.dst->GetSymbol().get();
1185 auto src1 = statement.src1->GetSymbol().get();
1186
1187 assert(dst->m_type == SYM_REGISTER);
1188 assert(src1->m_type == SYM_REGISTER);
1189
1190 m_assembler.Mvn(g_registers[dst->m_valueLow], g_registers[src1->m_valueLow]);
1191 }
1192
Emit_Not_MemReg(const STATEMENT & statement)1193 void CCodeGen_AArch32::Emit_Not_MemReg(const STATEMENT& statement)
1194 {
1195 auto dst = statement.dst->GetSymbol().get();
1196 auto src1 = statement.src1->GetSymbol().get();
1197
1198 assert(src1->m_type == SYM_REGISTER);
1199
1200 auto dstReg = CAArch32Assembler::r1;
1201 m_assembler.Mvn(dstReg, g_registers[src1->m_valueLow]);
1202 StoreRegisterInMemory(dst, dstReg);
1203 }
1204
Emit_Not_MemMem(const STATEMENT & statement)1205 void CCodeGen_AArch32::Emit_Not_MemMem(const STATEMENT& statement)
1206 {
1207 auto dst = statement.dst->GetSymbol().get();
1208 auto src1 = statement.src1->GetSymbol().get();
1209
1210 auto srcReg = CAArch32Assembler::r0;
1211 auto dstReg = CAArch32Assembler::r1;
1212 LoadMemoryInRegister(srcReg, src1);
1213 m_assembler.Mvn(dstReg, srcReg);
1214 StoreRegisterInMemory(dst, dstReg);
1215 }
1216
Emit_RelToRef_TmpCst(const STATEMENT & statement)1217 void CCodeGen_AArch32::Emit_RelToRef_TmpCst(const STATEMENT& statement)
1218 {
1219 auto dst = statement.dst->GetSymbol().get();
1220 auto src1 = statement.src1->GetSymbol().get();
1221
1222 assert(src1->m_type == SYM_CONSTANT);
1223
1224 auto tmpReg = CAArch32Assembler::r0;
1225
1226 uint8 immediate = 0;
1227 uint8 shiftAmount = 0;
1228
1229 if(TryGetAluImmediateParams(src1->m_valueLow, immediate, shiftAmount))
1230 {
1231 m_assembler.Add(tmpReg, g_baseRegister, CAArch32Assembler::MakeImmediateAluOperand(immediate, shiftAmount));
1232 }
1233 else
1234 {
1235 LoadConstantInRegister(tmpReg, src1->m_valueLow);
1236 m_assembler.Add(tmpReg, tmpReg, g_baseRegister);
1237 }
1238
1239 StoreRegisterInTemporaryReference(dst, tmpReg);
1240 }
1241
Emit_AddRef_TmpMemAny(const STATEMENT & statement)1242 void CCodeGen_AArch32::Emit_AddRef_TmpMemAny(const STATEMENT& statement)
1243 {
1244 auto dst = statement.dst->GetSymbol().get();
1245 auto src1 = statement.src1->GetSymbol().get();
1246 auto src2 = statement.src2->GetSymbol().get();
1247
1248 auto tmpReg = CAArch32Assembler::r0;
1249 auto src2Reg = PrepareSymbolRegisterUse(src2, CAArch32Assembler::r1);
1250
1251 LoadMemoryReferenceInRegister(tmpReg, src1);
1252 m_assembler.Add(tmpReg, tmpReg, src2Reg);
1253 StoreRegisterInTemporaryReference(dst, tmpReg);
1254 }
1255
Emit_LoadFromRef_VarTmp(const STATEMENT & statement)1256 void CCodeGen_AArch32::Emit_LoadFromRef_VarTmp(const STATEMENT& statement)
1257 {
1258 auto dst = statement.dst->GetSymbol().get();
1259 auto src1 = statement.src1->GetSymbol().get();
1260
1261 auto addressReg = CAArch32Assembler::r0;
1262 auto dstReg = PrepareSymbolRegisterDef(dst, CAArch32Assembler::r1);
1263
1264 LoadTemporaryReferenceInRegister(addressReg, src1);
1265 m_assembler.Ldr(dstReg, addressReg, CAArch32Assembler::MakeImmediateLdrAddress(0));
1266
1267 CommitSymbolRegister(dst, dstReg);
1268 }
1269
Emit_StoreAtRef_TmpAny(const STATEMENT & statement)1270 void CCodeGen_AArch32::Emit_StoreAtRef_TmpAny(const STATEMENT& statement)
1271 {
1272 auto src1 = statement.src1->GetSymbol().get();
1273 auto src2 = statement.src2->GetSymbol().get();
1274
1275 assert(src1->m_type == SYM_TMP_REFERENCE);
1276
1277 auto addressReg = CAArch32Assembler::r0;
1278 auto valueReg = PrepareSymbolRegisterUse(src2, CAArch32Assembler::r1);
1279
1280 LoadTemporaryReferenceInRegister(addressReg, src1);
1281 m_assembler.Str(valueReg, addressReg, CAArch32Assembler::MakeImmediateLdrAddress(0));
1282 }
1283