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