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