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