1 #include "Jitter_CodeGen_AArch32.h"
2 
3 using namespace Jitter;
4 
LoadMemoryFpSingleInRegister(CTempRegisterContext & tempRegContext,CAArch32Assembler::SINGLE_REGISTER reg,CSymbol * symbol)5 void CCodeGen_AArch32::LoadMemoryFpSingleInRegister(CTempRegisterContext& tempRegContext, CAArch32Assembler::SINGLE_REGISTER reg, CSymbol* symbol)
6 {
7 	switch(symbol->m_type)
8 	{
9 	case SYM_FP_REL_SINGLE:
10 		LoadRelativeFpSingleInRegister(tempRegContext, reg, symbol);
11 		break;
12 	case SYM_FP_TMP_SINGLE:
13 		LoadTemporaryFpSingleInRegister(tempRegContext, reg, symbol);
14 		break;
15 	default:
16 		assert(false);
17 		break;
18 	}
19 }
20 
StoreRegisterInMemoryFpSingle(CTempRegisterContext & tempRegContext,CSymbol * symbol,CAArch32Assembler::SINGLE_REGISTER reg)21 void CCodeGen_AArch32::StoreRegisterInMemoryFpSingle(CTempRegisterContext& tempRegContext, CSymbol* symbol, CAArch32Assembler::SINGLE_REGISTER reg)
22 {
23 	switch(symbol->m_type)
24 	{
25 	case SYM_FP_REL_SINGLE:
26 		StoreRelativeFpSingleInRegister(tempRegContext, symbol, reg);
27 		break;
28 	case SYM_FP_TMP_SINGLE:
29 		StoreTemporaryFpSingleInRegister(tempRegContext, symbol, reg);
30 		break;
31 	default:
32 		assert(false);
33 		break;
34 	}
35 }
36 
LoadRelativeFpSingleInRegister(CTempRegisterContext & tempRegContext,CAArch32Assembler::SINGLE_REGISTER reg,CSymbol * symbol)37 void CCodeGen_AArch32::LoadRelativeFpSingleInRegister(CTempRegisterContext& tempRegContext, CAArch32Assembler::SINGLE_REGISTER reg, CSymbol* symbol)
38 {
39 	assert(symbol->m_type == SYM_FP_REL_SINGLE);
40 	if((symbol->m_valueLow / 4) < 0x100)
41 	{
42 		m_assembler.Vldr(reg, g_baseRegister, CAArch32Assembler::MakeImmediateLdrAddress(symbol->m_valueLow));
43 	}
44 	else
45 	{
46 		auto offsetRegister = tempRegContext.Allocate();
47 		LoadConstantInRegister(offsetRegister, symbol->m_valueLow);
48 		m_assembler.Add(offsetRegister, offsetRegister, g_baseRegister);
49 		m_assembler.Vldr(reg, offsetRegister, CAArch32Assembler::MakeImmediateLdrAddress(0));
50 		tempRegContext.Release(offsetRegister);
51 	}
52 }
53 
StoreRelativeFpSingleInRegister(CTempRegisterContext & tempRegContext,CSymbol * symbol,CAArch32Assembler::SINGLE_REGISTER reg)54 void CCodeGen_AArch32::StoreRelativeFpSingleInRegister(CTempRegisterContext& tempRegContext, CSymbol* symbol, CAArch32Assembler::SINGLE_REGISTER reg)
55 {
56 	assert(symbol->m_type == SYM_FP_REL_SINGLE);
57 	if((symbol->m_valueLow / 4) < 0x100)
58 	{
59 		m_assembler.Vstr(reg, g_baseRegister, CAArch32Assembler::MakeImmediateLdrAddress(symbol->m_valueLow));
60 	}
61 	else
62 	{
63 		auto offsetRegister = tempRegContext.Allocate();
64 		LoadConstantInRegister(offsetRegister, symbol->m_valueLow);
65 		m_assembler.Add(offsetRegister, offsetRegister, g_baseRegister);
66 		m_assembler.Vstr(reg, offsetRegister, CAArch32Assembler::MakeImmediateLdrAddress(0));
67 		tempRegContext.Release(offsetRegister);
68 	}
69 }
70 
LoadTemporaryFpSingleInRegister(CTempRegisterContext & tempRegContext,CAArch32Assembler::SINGLE_REGISTER reg,CSymbol * symbol)71 void CCodeGen_AArch32::LoadTemporaryFpSingleInRegister(CTempRegisterContext& tempRegContext, CAArch32Assembler::SINGLE_REGISTER reg, CSymbol* symbol)
72 {
73 	assert(symbol->m_type == SYM_FP_TMP_SINGLE);
74 	auto offset = symbol->m_stackLocation + m_stackLevel;
75 	if((offset / 4) < 0x100)
76 	{
77 		m_assembler.Vldr(reg, CAArch32Assembler::rSP, CAArch32Assembler::MakeImmediateLdrAddress(symbol->m_stackLocation + m_stackLevel));
78 	}
79 	else
80 	{
81 		auto offsetRegister = tempRegContext.Allocate();
82 		LoadConstantInRegister(offsetRegister, offset);
83 		m_assembler.Add(offsetRegister, offsetRegister, CAArch32Assembler::rSP);
84 		m_assembler.Vldr(reg, offsetRegister, CAArch32Assembler::MakeImmediateLdrAddress(0));
85 		tempRegContext.Release(offsetRegister);
86 	}
87 }
88 
StoreTemporaryFpSingleInRegister(CTempRegisterContext & tempRegContext,CSymbol * symbol,CAArch32Assembler::SINGLE_REGISTER reg)89 void CCodeGen_AArch32::StoreTemporaryFpSingleInRegister(CTempRegisterContext& tempRegContext, CSymbol* symbol, CAArch32Assembler::SINGLE_REGISTER reg)
90 {
91 	assert(symbol->m_type == SYM_FP_TMP_SINGLE);
92 	auto offset = symbol->m_stackLocation + m_stackLevel;
93 	if((offset / 4) < 0x100)
94 	{
95 		m_assembler.Vstr(reg, CAArch32Assembler::rSP, CAArch32Assembler::MakeImmediateLdrAddress(symbol->m_stackLocation + m_stackLevel));
96 	}
97 	else
98 	{
99 		auto offsetRegister = tempRegContext.Allocate();
100 		LoadConstantInRegister(offsetRegister, offset);
101 		m_assembler.Add(offsetRegister, offsetRegister,CAArch32Assembler::rSP);
102 		m_assembler.Vstr(reg, offsetRegister, CAArch32Assembler::MakeImmediateLdrAddress(0));
103 		tempRegContext.Release(offsetRegister);
104 	}
105 }
106 
107 template <typename FPUOP>
Emit_Fpu_MemMem(const STATEMENT & statement)108 void CCodeGen_AArch32::Emit_Fpu_MemMem(const STATEMENT& statement)
109 {
110 	auto dst = statement.dst->GetSymbol().get();
111 	auto src1 = statement.src1->GetSymbol().get();
112 
113 	CTempRegisterContext tempRegisterContext;
114 
115 	LoadMemoryFpSingleInRegister(tempRegisterContext, CAArch32Assembler::s0, src1);
116 	((m_assembler).*(FPUOP::OpReg()))(CAArch32Assembler::s1, CAArch32Assembler::s0);
117 	StoreRegisterInMemoryFpSingle(tempRegisterContext, dst, CAArch32Assembler::s1);
118 }
119 
120 template <typename FPUOP>
Emit_Fpu_MemMemMem(const STATEMENT & statement)121 void CCodeGen_AArch32::Emit_Fpu_MemMemMem(const STATEMENT& statement)
122 {
123 	auto dst = statement.dst->GetSymbol().get();
124 	auto src1 = statement.src1->GetSymbol().get();
125 	auto src2 = statement.src2->GetSymbol().get();
126 
127 	CTempRegisterContext tempRegisterContext;
128 
129 	LoadMemoryFpSingleInRegister(tempRegisterContext, CAArch32Assembler::s0, src1);
130 	LoadMemoryFpSingleInRegister(tempRegisterContext, CAArch32Assembler::s1, src2);
131 	((m_assembler).*(FPUOP::OpReg()))(CAArch32Assembler::s2, CAArch32Assembler::s0, CAArch32Assembler::s1);
132 	StoreRegisterInMemoryFpSingle(tempRegisterContext, dst, CAArch32Assembler::s2);
133 }
134 
135 template <typename FPUMDOP>
Emit_FpuMd_MemMemMem(const STATEMENT & statement)136 void CCodeGen_AArch32::Emit_FpuMd_MemMemMem(const STATEMENT& statement)
137 {
138 	auto dst = statement.dst->GetSymbol().get();
139 	auto src1 = statement.src1->GetSymbol().get();
140 	auto src2 = statement.src2->GetSymbol().get();
141 
142 	CTempRegisterContext tempRegisterContext;
143 
144 	LoadMemoryFpSingleInRegister(tempRegisterContext, CAArch32Assembler::s0, src1);
145 	LoadMemoryFpSingleInRegister(tempRegisterContext, CAArch32Assembler::s4, src2);
146 	((m_assembler).*(FPUMDOP::OpReg()))(CAArch32Assembler::q2, CAArch32Assembler::q0, CAArch32Assembler::q1);
147 	StoreRegisterInMemoryFpSingle(tempRegisterContext, dst, CAArch32Assembler::s8);
148 }
149 
Emit_Fp_Rcpl_MemMem(const STATEMENT & statement)150 void CCodeGen_AArch32::Emit_Fp_Rcpl_MemMem(const STATEMENT& statement)
151 {
152 	auto dst = statement.dst->GetSymbol().get();
153 	auto src1 = statement.src1->GetSymbol().get();
154 
155 	CTempRegisterContext tempRegisterContext;
156 
157 	LoadMemoryFpSingleInRegister(tempRegisterContext, CAArch32Assembler::s0, src1);
158 	m_assembler.Vrecpe_F32(CAArch32Assembler::q1, CAArch32Assembler::q0);
159 	m_assembler.Vrecps_F32(CAArch32Assembler::q2, CAArch32Assembler::q1, CAArch32Assembler::q0);
160 	m_assembler.Vmul_F32(CAArch32Assembler::s4, CAArch32Assembler::s4, CAArch32Assembler::s8);
161 	StoreRegisterInMemoryFpSingle(tempRegisterContext, dst, CAArch32Assembler::s4);
162 }
163 
Emit_Fp_Rsqrt_MemMem(const STATEMENT & statement)164 void CCodeGen_AArch32::Emit_Fp_Rsqrt_MemMem(const STATEMENT& statement)
165 {
166 	auto dst = statement.dst->GetSymbol().get();
167 	auto src1 = statement.src1->GetSymbol().get();
168 
169 	CTempRegisterContext tempRegisterContext;
170 
171 	LoadMemoryFpSingleInRegister(tempRegisterContext, CAArch32Assembler::s0, src1);
172 	m_assembler.Vrsqrte_F32(CAArch32Assembler::q1, CAArch32Assembler::q0);
173 	m_assembler.Vmul_F32(CAArch32Assembler::s8, CAArch32Assembler::s0, CAArch32Assembler::s4);
174 	m_assembler.Vrsqrts_F32(CAArch32Assembler::q3, CAArch32Assembler::q2, CAArch32Assembler::q1);
175 	m_assembler.Vmul_F32(CAArch32Assembler::s4, CAArch32Assembler::s4, CAArch32Assembler::s12);
176 	StoreRegisterInMemoryFpSingle(tempRegisterContext, dst, CAArch32Assembler::s4);
177 }
178 
Emit_Fp_Cmp_AnyMemMem(const STATEMENT & statement)179 void CCodeGen_AArch32::Emit_Fp_Cmp_AnyMemMem(const STATEMENT& statement)
180 {
181 	auto dst = statement.dst->GetSymbol().get();
182 	auto src1 = statement.src1->GetSymbol().get();
183 	auto src2 = statement.src2->GetSymbol().get();
184 
185 	CTempRegisterContext tempRegisterContext;
186 
187 	auto tmpReg = tempRegisterContext.Allocate();
188 	auto dstReg = PrepareSymbolRegisterDef(dst, tmpReg);
189 
190 	m_assembler.Mov(dstReg, CAArch32Assembler::MakeImmediateAluOperand(0, 0));
191 	LoadMemoryFpSingleInRegister(tempRegisterContext, CAArch32Assembler::s0, src1);
192 	LoadMemoryFpSingleInRegister(tempRegisterContext, CAArch32Assembler::s1, src2);
193 	m_assembler.Vcmp_F32(CAArch32Assembler::s0, CAArch32Assembler::s1);
194 	m_assembler.Vmrs(CAArch32Assembler::rPC);	//Move to general purpose status register
195 	switch(statement.jmpCondition)
196 	{
197 	case Jitter::CONDITION_AB:
198 		m_assembler.MovCc(CAArch32Assembler::CONDITION_GT, dstReg, CAArch32Assembler::MakeImmediateAluOperand(1, 0));
199 		break;
200 	case Jitter::CONDITION_BE:
201 		m_assembler.MovCc(CAArch32Assembler::CONDITION_LS, dstReg, CAArch32Assembler::MakeImmediateAluOperand(1, 0));
202 		break;
203 	case Jitter::CONDITION_BL:
204 		m_assembler.MovCc(CAArch32Assembler::CONDITION_MI, dstReg, CAArch32Assembler::MakeImmediateAluOperand(1, 0));
205 		break;
206 	case Jitter::CONDITION_EQ:
207 		m_assembler.MovCc(CAArch32Assembler::CONDITION_EQ, dstReg, CAArch32Assembler::MakeImmediateAluOperand(1, 0));
208 		break;
209 	default:
210 		assert(0);
211 		break;
212 	}
213 
214 	CommitSymbolRegister(dst, dstReg);
215 	tempRegisterContext.Release(tmpReg);
216 }
217 
Emit_Fp_Mov_MemSRelI32(const STATEMENT & statement)218 void CCodeGen_AArch32::Emit_Fp_Mov_MemSRelI32(const STATEMENT& statement)
219 {
220 	auto dst = statement.dst->GetSymbol().get();
221 	auto src1 = statement.src1->GetSymbol().get();
222 
223 	assert(src1->m_type == SYM_FP_REL_INT32);
224 
225 	CTempRegisterContext tempRegisterContext;
226 
227 	auto dstReg = CAArch32Assembler::s0;
228 	auto src1Reg = CAArch32Assembler::s1;
229 
230 	m_assembler.Vldr(src1Reg, g_baseRegister, CAArch32Assembler::MakeImmediateLdrAddress(src1->m_valueLow));
231 	m_assembler.Vcvt_F32_S32(dstReg, src1Reg);
232 	StoreRegisterInMemoryFpSingle(tempRegisterContext, dst, dstReg);
233 }
234 
Emit_Fp_ToIntTrunc_MemMem(const STATEMENT & statement)235 void CCodeGen_AArch32::Emit_Fp_ToIntTrunc_MemMem(const STATEMENT& statement)
236 {
237 	auto dst = statement.dst->GetSymbol().get();
238 	auto src1 = statement.src1->GetSymbol().get();
239 
240 	CTempRegisterContext tempRegisterContext;
241 
242 	auto dstReg = CAArch32Assembler::s0;
243 	auto src1Reg = CAArch32Assembler::s1;
244 
245 	LoadMemoryFpSingleInRegister(tempRegisterContext, src1Reg, src1);
246 	m_assembler.Vcvt_S32_F32(dstReg, src1Reg);
247 	StoreRegisterInMemoryFpSingle(tempRegisterContext, dst, dstReg);
248 }
249 
Emit_Fp_LdCst_TmpCst(const STATEMENT & statement)250 void CCodeGen_AArch32::Emit_Fp_LdCst_TmpCst(const STATEMENT& statement)
251 {
252 	auto dst = statement.dst->GetSymbol().get();
253 	auto src1 = statement.src1->GetSymbol().get();
254 
255 	assert(dst->m_type  == SYM_FP_TMP_SINGLE);
256 	assert(src1->m_type == SYM_CONSTANT);
257 
258 	LoadConstantInRegister(CAArch32Assembler::r0, src1->m_valueLow);
259 	m_assembler.Str(CAArch32Assembler::r0, CAArch32Assembler::rSP, CAArch32Assembler::MakeImmediateLdrAddress(dst->m_stackLocation + m_stackLevel));
260 }
261 
262 CCodeGen_AArch32::CONSTMATCHER CCodeGen_AArch32::g_fpuConstMatchers[] =
263 {
264 	{ OP_FP_ADD, MATCH_MEMORY_FP_SINGLE, MATCH_MEMORY_FP_SINGLE, MATCH_MEMORY_FP_SINGLE, MATCH_NIL, &CCodeGen_AArch32::Emit_Fpu_MemMemMem<FPUOP_ADD> },
265 	{ OP_FP_SUB, MATCH_MEMORY_FP_SINGLE, MATCH_MEMORY_FP_SINGLE, MATCH_MEMORY_FP_SINGLE, MATCH_NIL, &CCodeGen_AArch32::Emit_Fpu_MemMemMem<FPUOP_SUB> },
266 	{ OP_FP_MUL, MATCH_MEMORY_FP_SINGLE, MATCH_MEMORY_FP_SINGLE, MATCH_MEMORY_FP_SINGLE, MATCH_NIL, &CCodeGen_AArch32::Emit_Fpu_MemMemMem<FPUOP_MUL> },
267 	{ OP_FP_DIV, MATCH_MEMORY_FP_SINGLE, MATCH_MEMORY_FP_SINGLE, MATCH_MEMORY_FP_SINGLE, MATCH_NIL, &CCodeGen_AArch32::Emit_Fpu_MemMemMem<FPUOP_DIV> },
268 
269 	{ OP_FP_CMP, MATCH_ANY, MATCH_MEMORY_FP_SINGLE, MATCH_MEMORY_FP_SINGLE, MATCH_NIL, &CCodeGen_AArch32::Emit_Fp_Cmp_AnyMemMem },
270 
271 	{ OP_FP_MIN, MATCH_MEMORY_FP_SINGLE, MATCH_MEMORY_FP_SINGLE, MATCH_MEMORY_FP_SINGLE, MATCH_NIL, &CCodeGen_AArch32::Emit_FpuMd_MemMemMem<FPUMDOP_MIN> },
272 	{ OP_FP_MAX, MATCH_MEMORY_FP_SINGLE, MATCH_MEMORY_FP_SINGLE, MATCH_MEMORY_FP_SINGLE, MATCH_NIL, &CCodeGen_AArch32::Emit_FpuMd_MemMemMem<FPUMDOP_MAX> },
273 
274 	{ OP_FP_RCPL,  MATCH_MEMORY_FP_SINGLE, MATCH_MEMORY_FP_SINGLE, MATCH_NIL, MATCH_NIL, &CCodeGen_AArch32::Emit_Fp_Rcpl_MemMem         },
275 	{ OP_FP_SQRT,  MATCH_MEMORY_FP_SINGLE, MATCH_MEMORY_FP_SINGLE, MATCH_NIL, MATCH_NIL, &CCodeGen_AArch32::Emit_Fpu_MemMem<FPUOP_SQRT> },
276 	{ OP_FP_RSQRT, MATCH_MEMORY_FP_SINGLE, MATCH_MEMORY_FP_SINGLE, MATCH_NIL, MATCH_NIL, &CCodeGen_AArch32::Emit_Fp_Rsqrt_MemMem        },
277 
278 	{ OP_FP_ABS, MATCH_MEMORY_FP_SINGLE, MATCH_MEMORY_FP_SINGLE, MATCH_NIL, MATCH_NIL, &CCodeGen_AArch32::Emit_Fpu_MemMem<FPUOP_ABS> },
279 	{ OP_FP_NEG, MATCH_MEMORY_FP_SINGLE, MATCH_MEMORY_FP_SINGLE, MATCH_NIL, MATCH_NIL, &CCodeGen_AArch32::Emit_Fpu_MemMem<FPUOP_NEG> },
280 
281 	{ OP_MOV,            MATCH_MEMORY_FP_SINGLE, MATCH_RELATIVE_FP_INT32, MATCH_NIL, MATCH_NIL, &CCodeGen_AArch32::Emit_Fp_Mov_MemSRelI32    },
282 	{ OP_FP_TOINT_TRUNC, MATCH_MEMORY_FP_SINGLE, MATCH_MEMORY_FP_SINGLE,  MATCH_NIL, MATCH_NIL, &CCodeGen_AArch32::Emit_Fp_ToIntTrunc_MemMem },
283 
284 	{ OP_FP_LDCST, MATCH_TEMPORARY_FP_SINGLE, MATCH_CONSTANT, MATCH_NIL, MATCH_NIL, &CCodeGen_AArch32::Emit_Fp_LdCst_TmpCst },
285 
286 	{ OP_MOV, MATCH_NIL, MATCH_NIL, MATCH_NIL, MATCH_NIL, NULL },
287 };
288