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