1 #include "Jitter_CodeGen_x86_32.h"
2 #include <algorithm>
3
4 using namespace Jitter;
5
6 CX86Assembler::REGISTER CCodeGen_x86_32::g_registers[MAX_REGISTERS] =
7 {
8 CX86Assembler::rBX,
9 CX86Assembler::rSI,
10 CX86Assembler::rDI,
11 };
12
13 CX86Assembler::XMMREGISTER CCodeGen_x86_32::g_mdRegisters[MAX_MDREGISTERS] =
14 {
15 CX86Assembler::xMM4,
16 CX86Assembler::xMM5,
17 CX86Assembler::xMM6,
18 CX86Assembler::xMM7
19 };
20
21 CCodeGen_x86_32::CONSTMATCHER CCodeGen_x86_32::g_constMatchers[] =
22 {
23 { OP_PARAM, MATCH_NIL, MATCH_CONTEXT, MATCH_NIL, &CCodeGen_x86_32::Emit_Param_Ctx },
24 { OP_PARAM, MATCH_NIL, MATCH_MEMORY, MATCH_NIL, &CCodeGen_x86_32::Emit_Param_Mem },
25 { OP_PARAM, MATCH_NIL, MATCH_CONSTANT, MATCH_NIL, &CCodeGen_x86_32::Emit_Param_Cst },
26 { OP_PARAM, MATCH_NIL, MATCH_REGISTER, MATCH_NIL, &CCodeGen_x86_32::Emit_Param_Reg },
27 { OP_PARAM, MATCH_NIL, MATCH_MEMORY64, MATCH_NIL, &CCodeGen_x86_32::Emit_Param_Mem64 },
28 { OP_PARAM, MATCH_NIL, MATCH_CONSTANT64, MATCH_NIL, &CCodeGen_x86_32::Emit_Param_Cst64 },
29 { OP_PARAM, MATCH_NIL, MATCH_REGISTER128, MATCH_NIL, &CCodeGen_x86_32::Emit_Param_Reg128 },
30 { OP_PARAM, MATCH_NIL, MATCH_MEMORY128, MATCH_NIL, &CCodeGen_x86_32::Emit_Param_Mem128 },
31
32 { OP_PARAM_RET, MATCH_NIL, MATCH_MEMORY128, MATCH_NIL, &CCodeGen_x86_32::Emit_ParamRet_Mem128 },
33
34 { OP_CALL, MATCH_NIL, MATCH_CONSTANTPTR, MATCH_CONSTANT, &CCodeGen_x86_32::Emit_Call },
35
36 { OP_RETVAL, MATCH_TEMPORARY, MATCH_NIL, MATCH_NIL, &CCodeGen_x86_32::Emit_RetVal_Tmp },
37 { OP_RETVAL, MATCH_REGISTER, MATCH_NIL, MATCH_NIL, &CCodeGen_x86_32::Emit_RetVal_Reg },
38 { OP_RETVAL, MATCH_MEMORY64, MATCH_NIL, MATCH_NIL, &CCodeGen_x86_32::Emit_RetVal_Mem64 },
39
40 { OP_MOV, MATCH_MEMORY64, MATCH_MEMORY64, MATCH_NIL, &CCodeGen_x86_32::Emit_Mov_Mem64Mem64 },
41 { OP_MOV, MATCH_MEMORY64, MATCH_CONSTANT64, MATCH_NIL, &CCodeGen_x86_32::Emit_Mov_Mem64Cst64 },
42
43 { OP_ADD64, MATCH_MEMORY64, MATCH_MEMORY64, MATCH_MEMORY64, &CCodeGen_x86_32::Emit_Add64_MemMemMem },
44 { OP_ADD64, MATCH_MEMORY64, MATCH_MEMORY64, MATCH_CONSTANT64, &CCodeGen_x86_32::Emit_Add64_MemMemCst },
45
46 { OP_SUB64, MATCH_MEMORY64, MATCH_MEMORY64, MATCH_MEMORY64, &CCodeGen_x86_32::Emit_Sub64_MemMemMem },
47 { OP_SUB64, MATCH_MEMORY64, MATCH_MEMORY64, MATCH_CONSTANT64, &CCodeGen_x86_32::Emit_Sub64_MemMemCst },
48 { OP_SUB64, MATCH_MEMORY64, MATCH_CONSTANT64, MATCH_MEMORY64, &CCodeGen_x86_32::Emit_Sub64_MemCstMem },
49
50 { OP_AND64, MATCH_MEMORY64, MATCH_MEMORY64, MATCH_MEMORY64, &CCodeGen_x86_32::Emit_And64_MemMemMem },
51
52 { OP_SRL64, MATCH_MEMORY64, MATCH_MEMORY64, MATCH_REGISTER, &CCodeGen_x86_32::Emit_Srl64_MemMemReg },
53 { OP_SRL64, MATCH_MEMORY64, MATCH_MEMORY64, MATCH_MEMORY, &CCodeGen_x86_32::Emit_Srl64_MemMemMem },
54 { OP_SRL64, MATCH_MEMORY64, MATCH_MEMORY64, MATCH_CONSTANT, &CCodeGen_x86_32::Emit_Srl64_MemMemCst },
55
56 { OP_SRA64, MATCH_MEMORY64, MATCH_MEMORY64, MATCH_REGISTER, &CCodeGen_x86_32::Emit_Sra64_MemMemReg },
57 { OP_SRA64, MATCH_MEMORY64, MATCH_MEMORY64, MATCH_MEMORY, &CCodeGen_x86_32::Emit_Sra64_MemMemMem },
58 { OP_SRA64, MATCH_MEMORY64, MATCH_MEMORY64, MATCH_CONSTANT, &CCodeGen_x86_32::Emit_Sra64_MemMemCst },
59
60 { OP_SLL64, MATCH_MEMORY64, MATCH_MEMORY64, MATCH_REGISTER, &CCodeGen_x86_32::Emit_Sll64_MemMemReg },
61 { OP_SLL64, MATCH_MEMORY64, MATCH_MEMORY64, MATCH_MEMORY, &CCodeGen_x86_32::Emit_Sll64_MemMemMem },
62 { OP_SLL64, MATCH_MEMORY64, MATCH_MEMORY64, MATCH_CONSTANT, &CCodeGen_x86_32::Emit_Sll64_MemMemCst },
63
64 { OP_CMP64, MATCH_REGISTER, MATCH_RELATIVE64, MATCH_RELATIVE64, &CCodeGen_x86_32::Emit_Cmp64_RegRelRel },
65 { OP_CMP64, MATCH_RELATIVE, MATCH_RELATIVE64, MATCH_RELATIVE64, &CCodeGen_x86_32::Emit_Cmp64_RelRelRel },
66 { OP_CMP64, MATCH_REGISTER, MATCH_RELATIVE64, MATCH_CONSTANT64, &CCodeGen_x86_32::Emit_Cmp64_RegRelCst },
67 { OP_CMP64, MATCH_RELATIVE, MATCH_RELATIVE64, MATCH_CONSTANT64, &CCodeGen_x86_32::Emit_Cmp64_RelRelCst },
68 { OP_CMP64, MATCH_TEMPORARY, MATCH_RELATIVE64, MATCH_RELATIVE64, &CCodeGen_x86_32::Emit_Cmp64_TmpRelRoc },
69 { OP_CMP64, MATCH_TEMPORARY, MATCH_RELATIVE64, MATCH_CONSTANT64, &CCodeGen_x86_32::Emit_Cmp64_TmpRelRoc },
70
71 { OP_RELTOREF, MATCH_TMP_REF, MATCH_CONSTANT, MATCH_NIL, &CCodeGen_x86_32::Emit_RelToRef_TmpCst },
72
73 { OP_ADDREF, MATCH_MEM_REF, MATCH_MEM_REF, MATCH_REGISTER, &CCodeGen_x86_32::Emit_AddRef_MemMemReg },
74 { OP_ADDREF, MATCH_MEM_REF, MATCH_MEM_REF, MATCH_MEMORY, &CCodeGen_x86_32::Emit_AddRef_MemMemMem },
75 { OP_ADDREF, MATCH_MEM_REF, MATCH_MEM_REF, MATCH_CONSTANT, &CCodeGen_x86_32::Emit_AddRef_MemMemCst },
76
77 { OP_LOADFROMREF, MATCH_REGISTER, MATCH_TMP_REF, MATCH_NIL, &CCodeGen_x86_32::Emit_LoadFromRef_RegTmp },
78 { OP_LOADFROMREF, MATCH_MEMORY, MATCH_TMP_REF, MATCH_NIL, &CCodeGen_x86_32::Emit_LoadFromRef_MemTmp },
79 { OP_LOADFROMREF, MATCH_REGISTER128, MATCH_MEM_REF, MATCH_NIL, &CCodeGen_x86_32::Emit_LoadFromRef_Md_RegMem },
80 { OP_LOADFROMREF, MATCH_MEMORY128, MATCH_MEM_REF, MATCH_NIL, &CCodeGen_x86_32::Emit_LoadFromRef_Md_MemMem },
81
82 { OP_STOREATREF, MATCH_NIL, MATCH_TMP_REF, MATCH_REGISTER, &CCodeGen_x86_32::Emit_StoreAtRef_TmpReg },
83 { OP_STOREATREF, MATCH_NIL, MATCH_TMP_REF, MATCH_MEMORY, &CCodeGen_x86_32::Emit_StoreAtRef_TmpMem },
84 { OP_STOREATREF, MATCH_NIL, MATCH_TMP_REF, MATCH_CONSTANT, &CCodeGen_x86_32::Emit_StoreAtRef_TmpCst },
85 { OP_STOREATREF, MATCH_NIL, MATCH_MEM_REF, MATCH_REGISTER128, &CCodeGen_x86_32::Emit_StoreAtRef_Md_MemReg },
86 { OP_STOREATREF, MATCH_NIL, MATCH_MEM_REF, MATCH_MEMORY128, &CCodeGen_x86_32::Emit_StoreAtRef_Md_MemMem },
87
88 { OP_MOV, MATCH_NIL, MATCH_NIL, MATCH_NIL, NULL },
89 };
90
CCodeGen_x86_32()91 CCodeGen_x86_32::CCodeGen_x86_32()
92 {
93 CCodeGen_x86::m_registers = g_registers;
94 CCodeGen_x86::m_mdRegisters = g_mdRegisters;
95
96 for(CONSTMATCHER* constMatcher = g_constMatchers; constMatcher->emitter != NULL; constMatcher++)
97 {
98 MATCHER matcher;
99 matcher.op = constMatcher->op;
100 matcher.dstType = constMatcher->dstType;
101 matcher.src1Type = constMatcher->src1Type;
102 matcher.src2Type = constMatcher->src2Type;
103 matcher.emitter = std::bind(constMatcher->emitter, this, std::placeholders::_1);
104 m_matchers.insert(MatcherMapType::value_type(matcher.op, matcher));
105 }
106 }
107
~CCodeGen_x86_32()108 CCodeGen_x86_32::~CCodeGen_x86_32()
109 {
110
111 }
112
SetImplicitRetValueParamFixUpRequired(bool implicitRetValueParamFixUpRequired)113 void CCodeGen_x86_32::SetImplicitRetValueParamFixUpRequired(bool implicitRetValueParamFixUpRequired)
114 {
115 m_implicitRetValueParamFixUpRequired = implicitRetValueParamFixUpRequired;
116 }
117
Emit_Prolog(const StatementList & statements,unsigned int stackSize,uint32 registerUsage)118 void CCodeGen_x86_32::Emit_Prolog(const StatementList& statements, unsigned int stackSize, uint32 registerUsage)
119 {
120 //Compute the size needed to store all function call parameters
121 uint32 maxParamSize = 0;
122 uint32 maxParamSpillSize = 0;
123 {
124 uint32 currParamSize = 0;
125 uint32 currParamSpillSize = 0;
126 for(const auto& statement : statements)
127 {
128 switch(statement.op)
129 {
130 case OP_PARAM:
131 case OP_PARAM_RET:
132 {
133 CSymbol* src1 = statement.src1->GetSymbol().get();
134 switch(src1->m_type)
135 {
136 case SYM_CONTEXT:
137 case SYM_REGISTER:
138 case SYM_RELATIVE:
139 case SYM_CONSTANT:
140 case SYM_TEMPORARY:
141 case SYM_RELATIVE128:
142 case SYM_TEMPORARY128:
143 currParamSize += 4;
144 break;
145 case SYM_REGISTER128:
146 currParamSize += 4;
147 currParamSpillSize += 16;
148 break;
149 case SYM_CONSTANT64:
150 case SYM_TEMPORARY64:
151 case SYM_RELATIVE64:
152 currParamSize += 8;
153 break;
154 default:
155 assert(0);
156 break;
157 }
158 }
159 break;
160 case OP_CALL:
161 maxParamSize = std::max<uint32>(currParamSize, maxParamSize);
162 maxParamSpillSize = std::max<uint32>(currParamSpillSize, maxParamSpillSize);
163 currParamSize = 0;
164 currParamSpillSize = 0;
165 break;
166 }
167 }
168 }
169
170 assert((stackSize & 0x0F) == 0);
171 assert((maxParamSpillSize & 0x0F) == 0);
172 maxParamSize = ((maxParamSize + 0xF) & ~0xF);
173
174 //Fetch parameter
175 m_assembler.Push(CX86Assembler::rBP);
176 m_assembler.MovEd(CX86Assembler::rBP, CX86Assembler::MakeIndRegOffAddress(CX86Assembler::rSP, 8));
177
178 //Save registers
179 for(unsigned int i = 0; i < MAX_REGISTERS; i++)
180 {
181 if(registerUsage & (1 << i))
182 {
183 m_assembler.Push(m_registers[i]);
184 }
185 }
186
187 //Align stack
188 m_assembler.MovEd(CX86Assembler::rAX, CX86Assembler::MakeRegisterAddress(CX86Assembler::rSP));
189 m_assembler.AndId(CX86Assembler::MakeRegisterAddress(CX86Assembler::rSP), ~0x0F);
190 m_assembler.SubId(CX86Assembler::MakeRegisterAddress(CX86Assembler::rSP), 0x0C);
191 m_assembler.Push(CX86Assembler::rAX);
192
193 //Allocate stack space for temps
194 m_totalStackAlloc = stackSize + maxParamSize + maxParamSpillSize;
195 m_paramSpillBase = stackSize + maxParamSize;
196 m_stackLevel = maxParamSize;
197
198 //Allocate stack space
199 if(m_totalStackAlloc != 0)
200 {
201 m_assembler.SubId(CX86Assembler::MakeRegisterAddress(CX86Assembler::rSP), m_totalStackAlloc);
202 }
203
204 //-------------------------------
205 //Stack Frame
206 //-------------------------------
207 //(High address)
208 //------------------
209 //Saved registers + alignment adjustment
210 //------------------
211 //Saved rSP
212 //------------------ <----- aligned on 0x10
213 //Params spill space
214 //------------------ <----- rSP + m_paramSpillBase
215 //Temporary symbols (stackSize) + alignment adjustment
216 //------------------ <----- rSP + m_stackLevel
217 //Param space for callee
218 //------------------ <----- rSP
219 //(Low address)
220 }
221
Emit_Epilog(unsigned int stackSize,uint32 registerUsage)222 void CCodeGen_x86_32::Emit_Epilog(unsigned int stackSize, uint32 registerUsage)
223 {
224 if(m_totalStackAlloc != 0)
225 {
226 m_assembler.AddId(CX86Assembler::MakeRegisterAddress(CX86Assembler::rSP), m_totalStackAlloc);
227 }
228
229 m_assembler.Pop(CX86Assembler::rSP);
230
231 for(int i = MAX_REGISTERS - 1; i >= 0; i--)
232 {
233 if(registerUsage & (1 << i))
234 {
235 m_assembler.Pop(m_registers[i]);
236 }
237 }
238
239 m_assembler.Pop(CX86Assembler::rBP);
240 m_assembler.Ret();
241 }
242
GetAvailableRegisterCount() const243 unsigned int CCodeGen_x86_32::GetAvailableRegisterCount() const
244 {
245 return MAX_REGISTERS;
246 }
247
GetAvailableMdRegisterCount() const248 unsigned int CCodeGen_x86_32::GetAvailableMdRegisterCount() const
249 {
250 return MAX_MDREGISTERS;
251 }
252
CanHold128BitsReturnValueInRegisters() const253 bool CCodeGen_x86_32::CanHold128BitsReturnValueInRegisters() const
254 {
255 return false;
256 }
257
Emit_Param_Ctx(const STATEMENT & statement)258 void CCodeGen_x86_32::Emit_Param_Ctx(const STATEMENT& statement)
259 {
260 m_params.push_back(
261 [this] (CALL_STATE& state)
262 {
263 m_assembler.MovGd(CX86Assembler::MakeIndRegOffAddress(CX86Assembler::rSP, state.paramOffset), CX86Assembler::rBP);
264 state.paramOffset += 4;
265 }
266 );
267 }
268
Emit_Param_Reg(const STATEMENT & statement)269 void CCodeGen_x86_32::Emit_Param_Reg(const STATEMENT& statement)
270 {
271 auto src1 = statement.src1->GetSymbol().get();
272 m_params.push_back(
273 [this, src1] (CALL_STATE& state)
274 {
275 m_assembler.MovGd(CX86Assembler::MakeIndRegOffAddress(CX86Assembler::rSP, state.paramOffset), m_registers[src1->m_valueLow]);
276 state.paramOffset += 4;
277 }
278 );
279 }
280
Emit_Param_Mem(const STATEMENT & statement)281 void CCodeGen_x86_32::Emit_Param_Mem(const STATEMENT& statement)
282 {
283 auto src1 = statement.src1->GetSymbol().get();
284 m_params.push_back(
285 [this, src1] (CALL_STATE& state)
286 {
287 m_assembler.MovEd(CX86Assembler::rAX, MakeMemorySymbolAddress(src1));
288 m_assembler.MovGd(CX86Assembler::MakeIndRegOffAddress(CX86Assembler::rSP, state.paramOffset), CX86Assembler::rAX);
289 state.paramOffset += 4;
290 }
291 );
292 }
293
Emit_Param_Cst(const STATEMENT & statement)294 void CCodeGen_x86_32::Emit_Param_Cst(const STATEMENT& statement)
295 {
296 auto src1 = statement.src1->GetSymbol().get();
297 m_params.push_back(
298 [this, src1] (CALL_STATE& state)
299 {
300 m_assembler.MovId(CX86Assembler::MakeIndRegOffAddress(CX86Assembler::rSP, state.paramOffset), src1->m_valueLow);
301 state.paramOffset += 4;
302 }
303 );
304 }
305
Emit_Param_Mem64(const STATEMENT & statement)306 void CCodeGen_x86_32::Emit_Param_Mem64(const STATEMENT& statement)
307 {
308 auto src1 = statement.src1->GetSymbol().get();
309 m_params.push_back(
310 [this, src1] (CALL_STATE& state)
311 {
312 m_assembler.MovEd(CX86Assembler::rAX, MakeMemory64SymbolLoAddress(src1));
313 m_assembler.MovEd(CX86Assembler::rDX, MakeMemory64SymbolHiAddress(src1));
314 m_assembler.MovGd(CX86Assembler::MakeIndRegOffAddress(CX86Assembler::rSP, state.paramOffset + 0), CX86Assembler::rAX);
315 m_assembler.MovGd(CX86Assembler::MakeIndRegOffAddress(CX86Assembler::rSP, state.paramOffset + 4), CX86Assembler::rDX);
316 state.paramOffset += 8;
317 }
318 );
319 }
320
Emit_Param_Cst64(const STATEMENT & statement)321 void CCodeGen_x86_32::Emit_Param_Cst64(const STATEMENT& statement)
322 {
323 auto src1 = statement.src1->GetSymbol().get();
324 m_params.push_back(
325 [this, src1] (CALL_STATE& state)
326 {
327 m_assembler.MovId(CX86Assembler::MakeIndRegOffAddress(CX86Assembler::rSP, state.paramOffset + 0), src1->m_valueLow);
328 m_assembler.MovId(CX86Assembler::MakeIndRegOffAddress(CX86Assembler::rSP, state.paramOffset + 4), src1->m_valueHigh);
329 state.paramOffset += 8;
330 }
331 );
332 }
333
Emit_Param_Reg128(const STATEMENT & statement)334 void CCodeGen_x86_32::Emit_Param_Reg128(const STATEMENT& statement)
335 {
336 auto src1 = statement.src1->GetSymbol().get();
337 m_params.push_back(
338 [this, src1] (CALL_STATE& state)
339 {
340 auto paramTempAddr = CX86Assembler::MakeIndRegOffAddress(CX86Assembler::rSP, m_paramSpillBase + state.paramSpillOffset);
341
342 m_assembler.MovapsVo(paramTempAddr, m_mdRegisters[src1->m_valueLow]);
343 m_assembler.LeaGd(CX86Assembler::rAX, paramTempAddr);
344 m_assembler.MovGd(CX86Assembler::MakeIndRegOffAddress(CX86Assembler::rSP, state.paramOffset), CX86Assembler::rAX);
345
346 state.paramOffset += 4;
347 state.paramSpillOffset += 0x10;
348 }
349 );
350 }
351
Emit_Param_Mem128(const STATEMENT & statement)352 void CCodeGen_x86_32::Emit_Param_Mem128(const STATEMENT& statement)
353 {
354 auto src1 = statement.src1->GetSymbol().get();
355 m_params.push_back(
356 [this, src1] (CALL_STATE& state)
357 {
358 m_assembler.LeaGd(CX86Assembler::rAX, MakeMemory128SymbolAddress(src1));
359 m_assembler.MovGd(CX86Assembler::MakeIndRegOffAddress(CX86Assembler::rSP, state.paramOffset), CX86Assembler::rAX);
360 state.paramOffset += 4;
361 }
362 );
363 }
364
Emit_ParamRet_Mem128(const STATEMENT & statement)365 void CCodeGen_x86_32::Emit_ParamRet_Mem128(const STATEMENT& statement)
366 {
367 //Basically the same as Param_Mem128, but special care must be taken
368 //as System V ABI automatically cleans up that extra parameter that's
369 //used as return value
370 Emit_Param_Mem128(statement);
371 assert(!m_hasImplicitRetValueParam);
372 m_hasImplicitRetValueParam = true;
373 }
374
Emit_Call(const STATEMENT & statement)375 void CCodeGen_x86_32::Emit_Call(const STATEMENT& statement)
376 {
377 auto src1 = statement.src1->GetSymbol().get();
378 auto src2 = statement.src2->GetSymbol().get();
379
380 uint32 paramCount = src2->m_valueLow;
381 CALL_STATE callState;
382 for(unsigned int i = 0; i < paramCount; i++)
383 {
384 auto emitter(m_params.back());
385 m_params.pop_back();
386 emitter(callState);
387 }
388
389 m_assembler.MovId(CX86Assembler::rAX, src1->m_valueLow);
390 auto symbolRefLabel = m_assembler.CreateLabel();
391 m_assembler.MarkLabel(symbolRefLabel, -4);
392 m_symbolReferenceLabels.push_back(std::make_pair(src1->GetConstantPtr(), symbolRefLabel));
393 m_assembler.CallEd(CX86Assembler::MakeRegisterAddress(CX86Assembler::rAX));
394
395 if(m_hasImplicitRetValueParam && m_implicitRetValueParamFixUpRequired)
396 {
397 //Allocated stack space for the extra parameter is cleaned up by the callee.
398 //So adjust the amount of stack space we free up after the call
399 m_assembler.SubId(CX86Assembler::MakeRegisterAddress(CX86Assembler::rSP), 4);
400 }
401
402 m_hasImplicitRetValueParam = false;
403 }
404
Emit_RetVal_Tmp(const STATEMENT & statement)405 void CCodeGen_x86_32::Emit_RetVal_Tmp(const STATEMENT& statement)
406 {
407 CSymbol* dst = statement.dst->GetSymbol().get();
408
409 m_assembler.MovGd(MakeTemporarySymbolAddress(dst), CX86Assembler::rAX);
410 }
411
Emit_RetVal_Reg(const STATEMENT & statement)412 void CCodeGen_x86_32::Emit_RetVal_Reg(const STATEMENT& statement)
413 {
414 CSymbol* dst = statement.dst->GetSymbol().get();
415
416 assert(dst->m_type == SYM_REGISTER);
417
418 m_assembler.MovGd(CX86Assembler::MakeRegisterAddress(m_registers[dst->m_valueLow]), CX86Assembler::rAX);
419 }
420
Emit_RetVal_Mem64(const STATEMENT & statement)421 void CCodeGen_x86_32::Emit_RetVal_Mem64(const STATEMENT& statement)
422 {
423 CSymbol* dst = statement.dst->GetSymbol().get();
424
425 m_assembler.MovGd(MakeMemory64SymbolLoAddress(dst), CX86Assembler::rAX);
426 m_assembler.MovGd(MakeMemory64SymbolHiAddress(dst), CX86Assembler::rDX);
427 }
428
Emit_Mov_Mem64Mem64(const STATEMENT & statement)429 void CCodeGen_x86_32::Emit_Mov_Mem64Mem64(const STATEMENT& statement)
430 {
431 auto dst = statement.dst->GetSymbol().get();
432 auto src1 = statement.src1->GetSymbol().get();
433
434 m_assembler.MovEd(CX86Assembler::rAX, MakeMemory64SymbolLoAddress(src1));
435 m_assembler.MovEd(CX86Assembler::rDX, MakeMemory64SymbolHiAddress(src1));
436
437 m_assembler.MovGd(MakeMemory64SymbolLoAddress(dst), CX86Assembler::rAX);
438 m_assembler.MovGd(MakeMemory64SymbolHiAddress(dst), CX86Assembler::rDX);
439 }
440
Emit_Mov_Mem64Cst64(const STATEMENT & statement)441 void CCodeGen_x86_32::Emit_Mov_Mem64Cst64(const STATEMENT& statement)
442 {
443 auto dst = statement.dst->GetSymbol().get();
444 auto src1 = statement.src1->GetSymbol().get();
445
446 assert(src1->m_type == SYM_CONSTANT64);
447
448 m_assembler.MovId(MakeMemory64SymbolLoAddress(dst), src1->m_valueLow);
449 m_assembler.MovId(MakeMemory64SymbolHiAddress(dst), src1->m_valueHigh);
450 }
451
Emit_Add64_MemMemMem(const STATEMENT & statement)452 void CCodeGen_x86_32::Emit_Add64_MemMemMem(const STATEMENT& statement)
453 {
454 auto dst = statement.dst->GetSymbol().get();
455 auto src1 = statement.src1->GetSymbol().get();
456 auto src2 = statement.src2->GetSymbol().get();
457
458 m_assembler.MovEd(CX86Assembler::rAX, MakeMemory64SymbolLoAddress(src1));
459 m_assembler.MovEd(CX86Assembler::rDX, MakeMemory64SymbolHiAddress(src1));
460
461 m_assembler.AddEd(CX86Assembler::rAX, MakeMemory64SymbolLoAddress(src2));
462 m_assembler.AdcEd(CX86Assembler::rDX, MakeMemory64SymbolHiAddress(src2));
463
464 m_assembler.MovGd(MakeMemory64SymbolLoAddress(dst), CX86Assembler::rAX);
465 m_assembler.MovGd(MakeMemory64SymbolHiAddress(dst), CX86Assembler::rDX);
466 }
467
Emit_Add64_MemMemCst(const STATEMENT & statement)468 void CCodeGen_x86_32::Emit_Add64_MemMemCst(const STATEMENT& statement)
469 {
470 auto dst = statement.dst->GetSymbol().get();
471 auto src1 = statement.src1->GetSymbol().get();
472 auto src2 = statement.src2->GetSymbol().get();
473
474 assert(src2->m_type == SYM_CONSTANT64);
475
476 m_assembler.MovEd(CX86Assembler::rAX, MakeMemory64SymbolLoAddress(src1));
477 m_assembler.MovEd(CX86Assembler::rDX, MakeMemory64SymbolHiAddress(src1));
478
479 m_assembler.AddId(CX86Assembler::MakeRegisterAddress(CX86Assembler::rAX), src2->m_valueLow);
480 m_assembler.AdcId(CX86Assembler::MakeRegisterAddress(CX86Assembler::rDX), src2->m_valueHigh);
481
482 m_assembler.MovGd(MakeMemory64SymbolLoAddress(dst), CX86Assembler::rAX);
483 m_assembler.MovGd(MakeMemory64SymbolHiAddress(dst), CX86Assembler::rDX);
484 }
485
Emit_Sub64_MemMemMem(const STATEMENT & statement)486 void CCodeGen_x86_32::Emit_Sub64_MemMemMem(const STATEMENT& statement)
487 {
488 auto dst = statement.dst->GetSymbol().get();
489 auto src1 = statement.src1->GetSymbol().get();
490 auto src2 = statement.src2->GetSymbol().get();
491
492 m_assembler.MovEd(CX86Assembler::rAX, MakeMemory64SymbolLoAddress(src1));
493 m_assembler.MovEd(CX86Assembler::rDX, MakeMemory64SymbolHiAddress(src1));
494
495 m_assembler.SubEd(CX86Assembler::rAX, MakeMemory64SymbolLoAddress(src2));
496 m_assembler.SbbEd(CX86Assembler::rDX, MakeMemory64SymbolHiAddress(src2));
497
498 m_assembler.MovGd(MakeMemory64SymbolLoAddress(dst), CX86Assembler::rAX);
499 m_assembler.MovGd(MakeMemory64SymbolHiAddress(dst), CX86Assembler::rDX);
500 }
501
Emit_Sub64_MemMemCst(const STATEMENT & statement)502 void CCodeGen_x86_32::Emit_Sub64_MemMemCst(const STATEMENT& statement)
503 {
504 auto dst = statement.dst->GetSymbol().get();
505 auto src1 = statement.src1->GetSymbol().get();
506 auto src2 = statement.src2->GetSymbol().get();
507
508 assert(src2->m_type == SYM_CONSTANT64);
509
510 m_assembler.MovEd(CX86Assembler::rAX, MakeMemory64SymbolLoAddress(src1));
511 m_assembler.MovEd(CX86Assembler::rDX, MakeMemory64SymbolHiAddress(src1));
512
513 m_assembler.SubId(CX86Assembler::MakeRegisterAddress(CX86Assembler::rAX), src2->m_valueLow);
514 m_assembler.SbbId(CX86Assembler::MakeRegisterAddress(CX86Assembler::rDX), src2->m_valueHigh);
515
516 m_assembler.MovGd(MakeMemory64SymbolLoAddress(dst), CX86Assembler::rAX);
517 m_assembler.MovGd(MakeMemory64SymbolHiAddress(dst), CX86Assembler::rDX);
518 }
519
Emit_Sub64_MemCstMem(const STATEMENT & statement)520 void CCodeGen_x86_32::Emit_Sub64_MemCstMem(const STATEMENT& statement)
521 {
522 auto dst = statement.dst->GetSymbol().get();
523 auto src1 = statement.src1->GetSymbol().get();
524 auto src2 = statement.src2->GetSymbol().get();
525
526 assert(src1->m_type == SYM_CONSTANT64);
527
528 m_assembler.MovId(CX86Assembler::rAX, src1->m_valueLow);
529 m_assembler.MovId(CX86Assembler::rDX, src1->m_valueHigh);
530
531 m_assembler.SubEd(CX86Assembler::rAX, MakeMemory64SymbolLoAddress(src2));
532 m_assembler.SbbEd(CX86Assembler::rDX, MakeMemory64SymbolHiAddress(src2));
533
534 m_assembler.MovGd(MakeMemory64SymbolLoAddress(dst), CX86Assembler::rAX);
535 m_assembler.MovGd(MakeMemory64SymbolHiAddress(dst), CX86Assembler::rDX);
536 }
537
Emit_And64_MemMemMem(const STATEMENT & statement)538 void CCodeGen_x86_32::Emit_And64_MemMemMem(const STATEMENT& statement)
539 {
540 auto dst = statement.dst->GetSymbol().get();
541 auto src1 = statement.src1->GetSymbol().get();
542 auto src2 = statement.src2->GetSymbol().get();
543
544 m_assembler.MovEd(CX86Assembler::rAX, MakeMemory64SymbolLoAddress(src1));
545 m_assembler.MovEd(CX86Assembler::rDX, MakeMemory64SymbolHiAddress(src1));
546
547 m_assembler.AndEd(CX86Assembler::rAX, MakeMemory64SymbolLoAddress(src2));
548 m_assembler.AndEd(CX86Assembler::rDX, MakeMemory64SymbolHiAddress(src2));
549
550 m_assembler.MovGd(MakeMemory64SymbolLoAddress(dst), CX86Assembler::rAX);
551 m_assembler.MovGd(MakeMemory64SymbolHiAddress(dst), CX86Assembler::rDX);
552 }
553
554 //---------------------------------------------------------------------------------
555 //SR64
556 //---------------------------------------------------------------------------------
557
Emit_Sr64Var_MemMem(CSymbol * dst,CSymbol * src1,CX86Assembler::REGISTER shiftRegister,SHIFTRIGHT_TYPE shiftType)558 void CCodeGen_x86_32::Emit_Sr64Var_MemMem(CSymbol* dst, CSymbol* src1, CX86Assembler::REGISTER shiftRegister, SHIFTRIGHT_TYPE shiftType)
559 {
560 auto regLo = CX86Assembler::rAX;
561 auto regHi = CX86Assembler::rDX;
562 auto regSa = CX86Assembler::rCX;
563
564 auto lessThan32Label = m_assembler.CreateLabel();
565 auto endLabel = m_assembler.CreateLabel();
566
567 if(shiftRegister != regSa)
568 {
569 m_assembler.MovEd(regSa, CX86Assembler::MakeRegisterAddress(shiftRegister));
570 }
571
572 m_assembler.AndId(CX86Assembler::MakeRegisterAddress(regSa), 0x3F);
573 m_assembler.CmpId(CX86Assembler::MakeRegisterAddress(regSa), 32);
574 m_assembler.JbJx(lessThan32Label);
575
576 //greaterOrEqual:
577 //---------------------------------------------
578 m_assembler.MovEd(regLo, MakeMemory64SymbolHiAddress(src1));
579 m_assembler.AndId(CX86Assembler::MakeRegisterAddress(regSa), 0x1F);
580
581 if(shiftType == SHIFTRIGHT_LOGICAL)
582 {
583 m_assembler.ShrEd(CX86Assembler::MakeRegisterAddress(regLo));
584 m_assembler.XorEd(regHi, CX86Assembler::MakeRegisterAddress(regHi));
585 }
586 else if(shiftType == SHIFTRIGHT_ARITHMETIC)
587 {
588 m_assembler.MovEd(regHi, CX86Assembler::MakeRegisterAddress(regLo));
589 m_assembler.SarEd(CX86Assembler::MakeRegisterAddress(regHi), 31);
590 m_assembler.SarEd(CX86Assembler::MakeRegisterAddress(regLo));
591 }
592 else
593 {
594 assert(false);
595 }
596
597 m_assembler.JmpJx(endLabel);
598
599 //lessThan:
600 //---------------------------------------------
601 m_assembler.MarkLabel(lessThan32Label);
602
603 m_assembler.MovEd(regLo, MakeMemory64SymbolLoAddress(src1));
604 m_assembler.MovEd(regHi, MakeMemory64SymbolHiAddress(src1));
605
606 m_assembler.ShrdEd(CX86Assembler::MakeRegisterAddress(regLo), regHi);
607 if(shiftType == SHIFTRIGHT_LOGICAL)
608 {
609 m_assembler.ShrEd(CX86Assembler::MakeRegisterAddress(regHi));
610 }
611 else if(shiftType == SHIFTRIGHT_ARITHMETIC)
612 {
613 m_assembler.SarEd(CX86Assembler::MakeRegisterAddress(regHi));
614 }
615 else
616 {
617 assert(false);
618 }
619
620 //end:
621 //---------------------------------------------
622 m_assembler.MarkLabel(endLabel);
623
624 m_assembler.MovGd(MakeMemory64SymbolLoAddress(dst), regLo);
625 m_assembler.MovGd(MakeMemory64SymbolHiAddress(dst), regHi);
626 }
627
Emit_Sr64Cst_MemMem(CSymbol * dst,CSymbol * src1,uint32 shiftAmount,SHIFTRIGHT_TYPE shiftType)628 void CCodeGen_x86_32::Emit_Sr64Cst_MemMem(CSymbol* dst, CSymbol* src1, uint32 shiftAmount, SHIFTRIGHT_TYPE shiftType)
629 {
630 assert(dst->m_type == SYM_RELATIVE64);
631 assert(src1->m_type == SYM_RELATIVE64);
632
633 shiftAmount = shiftAmount & 0x3F;
634
635 auto regLo = CX86Assembler::rAX;
636 auto regHi = CX86Assembler::rDX;
637
638 if(shiftAmount >= 32)
639 {
640 m_assembler.MovEd(regLo, MakeMemory64SymbolHiAddress(src1));
641
642 if(shiftType == SHIFTRIGHT_LOGICAL)
643 {
644 if(shiftAmount != 32)
645 {
646 //shr reg, amount
647 m_assembler.ShrEd(CX86Assembler::MakeRegisterAddress(regLo), shiftAmount & 0x1F);
648 }
649
650 m_assembler.XorEd(regHi, CX86Assembler::MakeRegisterAddress(regHi));
651 }
652 else if(shiftType == SHIFTRIGHT_ARITHMETIC)
653 {
654 if(shiftAmount != 32)
655 {
656 //sar reg, amount
657 m_assembler.SarEd(CX86Assembler::MakeRegisterAddress(regLo), shiftAmount & 0x1F);
658 }
659
660 m_assembler.MovEd(regHi, CX86Assembler::MakeRegisterAddress(regLo));
661 m_assembler.SarEd(CX86Assembler::MakeRegisterAddress(regHi), 31);
662 }
663 else
664 {
665 assert(false);
666 }
667 }
668 else //Amount < 32
669 {
670 m_assembler.MovEd(regLo, MakeMemory64SymbolLoAddress(src1));
671 m_assembler.MovEd(regHi, MakeMemory64SymbolHiAddress(src1));
672
673 if(shiftAmount != 0)
674 {
675 //shrd nReg1, nReg2, nAmount
676 m_assembler.ShrdEd(CX86Assembler::MakeRegisterAddress(regLo), regHi, shiftAmount);
677
678 if(shiftType == SHIFTRIGHT_LOGICAL)
679 {
680 //shr nReg2, nAmount
681 m_assembler.ShrEd(CX86Assembler::MakeRegisterAddress(regHi), shiftAmount);
682 }
683 else if(shiftType == SHIFTRIGHT_ARITHMETIC)
684 {
685 //sar nReg2, nAmount
686 m_assembler.SarEd(CX86Assembler::MakeRegisterAddress(regHi), shiftAmount);
687 }
688 else
689 {
690 assert(false);
691 }
692 }
693 }
694
695 m_assembler.MovGd(MakeMemory64SymbolLoAddress(dst), regLo);
696 m_assembler.MovGd(MakeMemory64SymbolHiAddress(dst), regHi);
697 }
698
699 //---------------------------------------------------------------------------------
700 //SRL64
701 //---------------------------------------------------------------------------------
702
Emit_Srl64_MemMemReg(const STATEMENT & statement)703 void CCodeGen_x86_32::Emit_Srl64_MemMemReg(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 assert(src2->m_type == SYM_REGISTER);
710
711 Emit_Sr64Var_MemMem(dst, src1, g_registers[src2->m_valueLow], SHIFTRIGHT_LOGICAL);
712 }
713
Emit_Srl64_MemMemMem(const STATEMENT & statement)714 void CCodeGen_x86_32::Emit_Srl64_MemMemMem(const STATEMENT& statement)
715 {
716 auto dst = statement.dst->GetSymbol().get();
717 auto src1 = statement.src1->GetSymbol().get();
718 auto src2 = statement.src2->GetSymbol().get();
719
720 auto shiftAmount = CX86Assembler::rCX;
721 m_assembler.MovEd(shiftAmount, MakeMemorySymbolAddress(src2));
722
723 Emit_Sr64Var_MemMem(dst, src1, shiftAmount, SHIFTRIGHT_LOGICAL);
724 }
725
Emit_Srl64_MemMemCst(const STATEMENT & statement)726 void CCodeGen_x86_32::Emit_Srl64_MemMemCst(const STATEMENT& statement)
727 {
728 auto dst = statement.dst->GetSymbol().get();
729 auto src1 = statement.src1->GetSymbol().get();
730 auto src2 = statement.src2->GetSymbol().get();
731
732 Emit_Sr64Cst_MemMem(dst, src1, src2->m_valueLow, SHIFTRIGHT_LOGICAL);
733 }
734
735 //---------------------------------------------------------------------------------
736 //SRA64
737 //---------------------------------------------------------------------------------
738
Emit_Sra64_MemMemReg(const STATEMENT & statement)739 void CCodeGen_x86_32::Emit_Sra64_MemMemReg(const STATEMENT& statement)
740 {
741 auto dst = statement.dst->GetSymbol().get();
742 auto src1 = statement.src1->GetSymbol().get();
743 auto src2 = statement.src2->GetSymbol().get();
744
745 assert(src2->m_type == SYM_REGISTER);
746
747 Emit_Sr64Var_MemMem(dst, src1, g_registers[src2->m_valueLow], SHIFTRIGHT_ARITHMETIC);
748 }
749
Emit_Sra64_MemMemMem(const STATEMENT & statement)750 void CCodeGen_x86_32::Emit_Sra64_MemMemMem(const STATEMENT& statement)
751 {
752 auto dst = statement.dst->GetSymbol().get();
753 auto src1 = statement.src1->GetSymbol().get();
754 auto src2 = statement.src2->GetSymbol().get();
755
756 auto shiftAmount = CX86Assembler::rCX;
757 m_assembler.MovEd(shiftAmount, MakeMemorySymbolAddress(src2));
758
759 Emit_Sr64Var_MemMem(dst, src1, shiftAmount, SHIFTRIGHT_ARITHMETIC);
760 }
761
Emit_Sra64_MemMemCst(const STATEMENT & statement)762 void CCodeGen_x86_32::Emit_Sra64_MemMemCst(const STATEMENT& statement)
763 {
764 auto dst = statement.dst->GetSymbol().get();
765 auto src1 = statement.src1->GetSymbol().get();
766 auto src2 = statement.src2->GetSymbol().get();
767
768 Emit_Sr64Cst_MemMem(dst, src1, src2->m_valueLow, SHIFTRIGHT_ARITHMETIC);
769 }
770
771 //---------------------------------------------------------------------------------
772 //SLL64
773 //---------------------------------------------------------------------------------
774
Emit_Sll64_MemMemVar(const STATEMENT & statement,CX86Assembler::REGISTER shiftRegister)775 void CCodeGen_x86_32::Emit_Sll64_MemMemVar(const STATEMENT& statement, CX86Assembler::REGISTER shiftRegister)
776 {
777 CSymbol* dst = statement.dst->GetSymbol().get();
778 CSymbol* src1 = statement.src1->GetSymbol().get();
779
780 CX86Assembler::LABEL doneLabel = m_assembler.CreateLabel();
781 CX86Assembler::LABEL more32Label = m_assembler.CreateLabel();
782
783 CX86Assembler::REGISTER amountReg = CX86Assembler::rCX;
784 CX86Assembler::REGISTER resultLow = CX86Assembler::rAX;
785 CX86Assembler::REGISTER resultHigh = CX86Assembler::rDX;
786
787 if(shiftRegister != amountReg)
788 {
789 m_assembler.MovEd(amountReg, CX86Assembler::MakeRegisterAddress(shiftRegister));
790 }
791
792 m_assembler.MovEd(resultLow, MakeMemory64SymbolLoAddress(src1));
793 m_assembler.MovEd(resultHigh, MakeMemory64SymbolHiAddress(src1));
794
795 m_assembler.AndIb(CX86Assembler::MakeByteRegisterAddress(amountReg), 0x3F);
796 m_assembler.TestEb(amountReg, CX86Assembler::MakeByteRegisterAddress(amountReg));
797 m_assembler.JzJx(doneLabel);
798
799 m_assembler.CmpIb(CX86Assembler::MakeByteRegisterAddress(amountReg), 0x20);
800 m_assembler.JnbJx(more32Label);
801
802 m_assembler.ShldEd(CX86Assembler::MakeRegisterAddress(resultHigh), resultLow);
803 m_assembler.ShlEd(CX86Assembler::MakeRegisterAddress(resultLow));
804 m_assembler.JmpJx(doneLabel);
805
806 //$more32
807 m_assembler.MarkLabel(more32Label);
808
809 m_assembler.MovEd(resultHigh, CX86Assembler::MakeRegisterAddress(resultLow));
810 m_assembler.XorEd(resultLow, CX86Assembler::MakeRegisterAddress(resultLow));
811 m_assembler.AndIb(CX86Assembler::MakeByteRegisterAddress(amountReg), 0x1F);
812 m_assembler.ShlEd(CX86Assembler::MakeRegisterAddress(resultHigh));
813
814 //$done
815 m_assembler.MarkLabel(doneLabel);
816
817 m_assembler.MovGd(MakeMemory64SymbolLoAddress(dst), resultLow);
818 m_assembler.MovGd(MakeMemory64SymbolHiAddress(dst), resultHigh);
819 }
820
Emit_Sll64_MemMemReg(const STATEMENT & statement)821 void CCodeGen_x86_32::Emit_Sll64_MemMemReg(const STATEMENT& statement)
822 {
823 CSymbol* src2 = statement.src2->GetSymbol().get();
824
825 assert(src2->m_type == SYM_REGISTER);
826
827 Emit_Sll64_MemMemVar(statement, g_registers[src2->m_valueLow]);
828 }
829
Emit_Sll64_MemMemMem(const STATEMENT & statement)830 void CCodeGen_x86_32::Emit_Sll64_MemMemMem(const STATEMENT& statement)
831 {
832 CSymbol* src2 = statement.src2->GetSymbol().get();
833
834 CX86Assembler::REGISTER shiftAmount = CX86Assembler::rCX;
835
836 m_assembler.MovEd(shiftAmount, MakeMemorySymbolAddress(src2));
837
838 Emit_Sll64_MemMemVar(statement, shiftAmount);
839 }
840
Emit_Sll64_MemMemCst(const STATEMENT & statement)841 void CCodeGen_x86_32::Emit_Sll64_MemMemCst(const STATEMENT& statement)
842 {
843 auto dst = statement.dst->GetSymbol().get();
844 auto src1 = statement.src1->GetSymbol().get();
845 auto src2 = statement.src2->GetSymbol().get();
846
847 assert(src2->m_type == SYM_CONSTANT);
848
849 uint8 shiftAmount = static_cast<uint8>(src2->m_valueLow & 0x3F);
850
851 auto regLo = CX86Assembler::rAX;
852 auto regHi = CX86Assembler::rDX;
853
854 if(shiftAmount >= 32)
855 {
856 m_assembler.MovEd(regHi, MakeMemory64SymbolLoAddress(src1));
857
858 if(shiftAmount != 0)
859 {
860 //shl reg, amount
861 m_assembler.ShlEd(CX86Assembler::MakeRegisterAddress(regHi), shiftAmount & 0x1F);
862 }
863
864 m_assembler.XorEd(regLo, CX86Assembler::MakeRegisterAddress(regLo));
865 }
866 else //Amount < 32
867 {
868 m_assembler.MovEd(regLo, MakeMemory64SymbolLoAddress(src1));
869 m_assembler.MovEd(regHi, MakeMemory64SymbolHiAddress(src1));
870
871 //shld nReg2, nReg1, nAmount
872 m_assembler.ShldEd(CX86Assembler::MakeRegisterAddress(regHi), regLo, shiftAmount);
873
874 //shl nReg1, nAmount
875 m_assembler.ShlEd(CX86Assembler::MakeRegisterAddress(regLo), shiftAmount);
876 }
877
878 m_assembler.MovGd(MakeMemory64SymbolLoAddress(dst), regLo);
879 m_assembler.MovGd(MakeMemory64SymbolHiAddress(dst), regHi);
880 }
881
882 //---------------------------------------------------------------------------------
883 //CMP64
884 //---------------------------------------------------------------------------------
885
Cmp64_Equal(const STATEMENT & statement)886 void CCodeGen_x86_32::Cmp64_Equal(const STATEMENT& statement)
887 {
888 auto src1 = statement.src1->GetSymbol().get();
889 auto src2 = statement.src2->GetSymbol().get();
890
891 const auto cmpLo =
892 [this](CX86Assembler::REGISTER registerId, CSymbol* symbol)
893 {
894 switch(symbol->m_type)
895 {
896 case SYM_RELATIVE64:
897 m_assembler.CmpEd(registerId, MakeMemory64SymbolLoAddress(symbol));
898 break;
899 case SYM_CONSTANT64:
900 if(symbol->m_valueLow == 0)
901 {
902 m_assembler.TestEd(registerId, CX86Assembler::MakeRegisterAddress(registerId));
903 }
904 else
905 {
906 m_assembler.CmpId(CX86Assembler::MakeRegisterAddress(registerId), symbol->m_valueLow);
907 }
908 break;
909 default:
910 assert(0);
911 break;
912 }
913 };
914
915 const auto cmpHi =
916 [this](CX86Assembler::REGISTER registerId, CSymbol* symbol)
917 {
918 switch(symbol->m_type)
919 {
920 case SYM_RELATIVE64:
921 m_assembler.CmpEd(registerId, MakeMemory64SymbolHiAddress(symbol));
922 break;
923 case SYM_CONSTANT64:
924 if(symbol->m_valueHigh == 0)
925 {
926 m_assembler.TestEd(registerId, CX86Assembler::MakeRegisterAddress(registerId));
927 }
928 else
929 {
930 m_assembler.CmpId(CX86Assembler::MakeRegisterAddress(registerId), symbol->m_valueHigh);
931 }
932 break;
933 default:
934 assert(0);
935 break;
936 }
937 };
938
939 assert(src1->m_type == SYM_RELATIVE64);
940
941 bool isEqual = (statement.jmpCondition == CONDITION_EQ);
942
943 CX86Assembler::REGISTER valReg = CX86Assembler::rDX;
944 CX86Assembler::REGISTER res1Reg = CX86Assembler::rAX;
945 CX86Assembler::REGISTER res2Reg = CX86Assembler::rCX;
946
947 m_assembler.MovEd(valReg, MakeMemory64SymbolLoAddress(src1));
948 cmpLo(valReg, src2);
949
950 if(isEqual)
951 {
952 m_assembler.SeteEb(CX86Assembler::MakeRegisterAddress(res1Reg));
953 }
954 else
955 {
956 m_assembler.SetneEb(CX86Assembler::MakeRegisterAddress(res1Reg));
957 }
958
959 m_assembler.MovEd(valReg, MakeMemory64SymbolHiAddress(src1));
960 cmpHi(valReg, src2);
961
962 if(isEqual)
963 {
964 m_assembler.SeteEb(CX86Assembler::MakeRegisterAddress(res2Reg));
965 }
966 else
967 {
968 m_assembler.SetneEb(CX86Assembler::MakeRegisterAddress(res2Reg));
969 }
970
971 if(isEqual)
972 {
973 m_assembler.AndEd(res1Reg, CX86Assembler::MakeRegisterAddress(res2Reg));
974 }
975 else
976 {
977 m_assembler.OrEd(res1Reg, CX86Assembler::MakeRegisterAddress(res2Reg));
978 }
979
980 m_assembler.MovzxEb(res1Reg, CX86Assembler::MakeRegisterAddress(res1Reg));
981 }
982
983 struct CompareOrder64Less
984 {
985 typedef void (CX86Assembler::*OrderCheckFunction)(const CX86Assembler::CAddress&);
986
IsSignedCompareOrder64Less987 static bool IsSigned(Jitter::CONDITION condition)
988 {
989 return (condition == CONDITION_LE) || (condition == CONDITION_LT);
990 }
991
OrEqualCompareOrder64Less992 static bool OrEqual(Jitter::CONDITION condition)
993 {
994 return (condition == CONDITION_LE) || (condition == CONDITION_BE);
995 }
996
CheckOrderSignedCompareOrder64Less997 static OrderCheckFunction CheckOrderSigned()
998 {
999 return &CX86Assembler::SetlEb;
1000 }
1001
CheckOrderUnsignedCompareOrder64Less1002 static OrderCheckFunction CheckOrderUnsigned()
1003 {
1004 return &CX86Assembler::SetbEb;
1005 }
1006
CheckOrderOrEqualUnsignedCompareOrder64Less1007 static OrderCheckFunction CheckOrderOrEqualUnsigned()
1008 {
1009 return &CX86Assembler::SetbeEb;
1010 }
1011 };
1012
1013 struct CompareOrder64Greater
1014 {
1015 typedef void (CX86Assembler::*OrderCheckFunction)(const CX86Assembler::CAddress&);
1016
IsSignedCompareOrder64Greater1017 static bool IsSigned(Jitter::CONDITION condition)
1018 {
1019 return (condition == CONDITION_GE) || (condition == CONDITION_GT);
1020 }
1021
OrEqualCompareOrder64Greater1022 static bool OrEqual(Jitter::CONDITION condition)
1023 {
1024 return (condition == CONDITION_GE) || (condition == CONDITION_AE);
1025 }
1026
CheckOrderSignedCompareOrder64Greater1027 static OrderCheckFunction CheckOrderSigned()
1028 {
1029 return &CX86Assembler::SetgEb;
1030 }
1031
CheckOrderUnsignedCompareOrder64Greater1032 static OrderCheckFunction CheckOrderUnsigned()
1033 {
1034 return &CX86Assembler::SetaEb;
1035 }
1036
CheckOrderOrEqualUnsignedCompareOrder64Greater1037 static OrderCheckFunction CheckOrderOrEqualUnsigned()
1038 {
1039 return &CX86Assembler::SetaeEb;
1040 }
1041 };
1042
1043 template <typename CompareTraits>
Cmp64_Order(const STATEMENT & statement)1044 void CCodeGen_x86_32::Cmp64_Order(const STATEMENT& statement)
1045 {
1046 auto src1 = statement.src1->GetSymbol().get();
1047 auto src2 = statement.src2->GetSymbol().get();
1048
1049 CompareTraits compareTraits;
1050 (void)compareTraits;
1051
1052 const auto cmpLo =
1053 [this](CX86Assembler::REGISTER registerId, CSymbol* symbol)
1054 {
1055 switch(symbol->m_type)
1056 {
1057 case SYM_RELATIVE64:
1058 m_assembler.CmpEd(registerId, MakeMemory64SymbolLoAddress(symbol));
1059 break;
1060 case SYM_CONSTANT64:
1061 m_assembler.CmpId(CX86Assembler::MakeRegisterAddress(registerId), symbol->m_valueLow);
1062 break;
1063 default:
1064 assert(0);
1065 break;
1066 }
1067 };
1068
1069 const auto cmpHi =
1070 [this](CX86Assembler::REGISTER registerId, CSymbol* symbol)
1071 {
1072 switch(symbol->m_type)
1073 {
1074 case SYM_RELATIVE64:
1075 m_assembler.CmpEd(registerId, MakeMemory64SymbolHiAddress(symbol));
1076 break;
1077 case SYM_CONSTANT64:
1078 m_assembler.CmpId(CX86Assembler::MakeRegisterAddress(registerId), symbol->m_valueHigh);
1079 break;
1080 default:
1081 assert(0);
1082 break;
1083 }
1084 };
1085
1086 assert(src1->m_type == SYM_RELATIVE64);
1087
1088 CX86Assembler::REGISTER regLo = CX86Assembler::rAX;
1089 CX86Assembler::REGISTER regHi = CX86Assembler::rDX;
1090
1091 bool isSigned = compareTraits.IsSigned(statement.jmpCondition);
1092 bool orEqual = compareTraits.OrEqual(statement.jmpCondition);
1093
1094 CX86Assembler::LABEL highOrderEqualLabel = m_assembler.CreateLabel();
1095 CX86Assembler::LABEL doneLabel = m_assembler.CreateLabel();
1096
1097 /////////////////////////////////////////
1098 //Check high order word if equal
1099
1100 m_assembler.MovEd(regHi, MakeMemory64SymbolHiAddress(src1));
1101 cmpHi(regHi, src2);
1102
1103 //je highOrderEqual
1104 m_assembler.JzJx(highOrderEqualLabel);
1105
1106 ///////////////////////////////////////////////////////////
1107 //If they aren't equal, this comparaison decides of result
1108
1109 //setb/l reg[l]
1110 if(isSigned)
1111 {
1112 ((m_assembler).*(compareTraits.CheckOrderSigned()))(CX86Assembler::MakeByteRegisterAddress(regLo));
1113 }
1114 else
1115 {
1116 ((m_assembler).*(compareTraits.CheckOrderUnsigned()))(CX86Assembler::MakeByteRegisterAddress(regLo));
1117 }
1118
1119 //movzx reg, reg[l]
1120 m_assembler.MovzxEb(regLo, CX86Assembler::MakeByteRegisterAddress(regLo));
1121
1122 //jmp done
1123 m_assembler.JmpJx(doneLabel);
1124
1125 //highOrderEqual: /////////////////////////////////////
1126 m_assembler.MarkLabel(highOrderEqualLabel);
1127 //If they are equal, next comparaison decides of result
1128
1129 m_assembler.MovEd(regLo, MakeMemory64SymbolLoAddress(src1));
1130 cmpLo(regLo, src2);
1131
1132 //setb/be reg[l]
1133 if(orEqual)
1134 {
1135 ((m_assembler).*(compareTraits.CheckOrderOrEqualUnsigned()))(CX86Assembler::MakeByteRegisterAddress(regLo));
1136 }
1137 else
1138 {
1139 ((m_assembler).*(compareTraits.CheckOrderUnsigned()))(CX86Assembler::MakeByteRegisterAddress(regLo));
1140 }
1141
1142 //movzx reg, reg[l]
1143 m_assembler.MovzxEb(regLo, CX86Assembler::MakeByteRegisterAddress(regLo));
1144
1145 //done: ///////////////////////////////////////////////
1146 m_assembler.MarkLabel(doneLabel);
1147 }
1148
Cmp64_GenericRel(const STATEMENT & statement)1149 void CCodeGen_x86_32::Cmp64_GenericRel(const STATEMENT& statement)
1150 {
1151 switch(statement.jmpCondition)
1152 {
1153 case CONDITION_BL:
1154 case CONDITION_LT:
1155 case CONDITION_LE:
1156 Cmp64_Order<CompareOrder64Less>(statement);
1157 break;
1158 case CONDITION_AB:
1159 case CONDITION_GT:
1160 case CONDITION_GE:
1161 Cmp64_Order<CompareOrder64Greater>(statement);
1162 break;
1163 case CONDITION_NE:
1164 case CONDITION_EQ:
1165 Cmp64_Equal(statement);
1166 break;
1167 default:
1168 assert(0);
1169 break;
1170 }
1171 }
1172
Emit_Cmp64_RegRelRel(const STATEMENT & statement)1173 void CCodeGen_x86_32::Emit_Cmp64_RegRelRel(const STATEMENT& statement)
1174 {
1175 CSymbol* dst = statement.dst->GetSymbol().get();
1176
1177 assert(dst->m_type == SYM_REGISTER);
1178
1179 Cmp64_GenericRel(statement);
1180 m_assembler.MovGd(CX86Assembler::MakeRegisterAddress(m_registers[dst->m_valueLow]), CX86Assembler::rAX);
1181 }
1182
Emit_Cmp64_RelRelRel(const STATEMENT & statement)1183 void CCodeGen_x86_32::Emit_Cmp64_RelRelRel(const STATEMENT& statement)
1184 {
1185 CSymbol* dst = statement.dst->GetSymbol().get();
1186
1187 assert(dst->m_type == SYM_RELATIVE);
1188
1189 Cmp64_GenericRel(statement);
1190 m_assembler.MovGd(MakeRelativeSymbolAddress(dst), CX86Assembler::rAX);
1191 }
1192
Emit_Cmp64_RegRelCst(const STATEMENT & statement)1193 void CCodeGen_x86_32::Emit_Cmp64_RegRelCst(const STATEMENT& statement)
1194 {
1195 CSymbol* dst = statement.dst->GetSymbol().get();
1196
1197 assert(dst->m_type == SYM_REGISTER);
1198
1199 Cmp64_GenericRel(statement);
1200 m_assembler.MovGd(CX86Assembler::MakeRegisterAddress(m_registers[dst->m_valueLow]), CX86Assembler::rAX);
1201 }
1202
Emit_Cmp64_RelRelCst(const STATEMENT & statement)1203 void CCodeGen_x86_32::Emit_Cmp64_RelRelCst(const STATEMENT& statement)
1204 {
1205 CSymbol* dst = statement.dst->GetSymbol().get();
1206
1207 assert(dst->m_type == SYM_RELATIVE);
1208
1209 Cmp64_GenericRel(statement);
1210 m_assembler.MovGd(MakeRelativeSymbolAddress(dst), CX86Assembler::rAX);
1211 }
1212
Emit_Cmp64_TmpRelRoc(const STATEMENT & statement)1213 void CCodeGen_x86_32::Emit_Cmp64_TmpRelRoc(const STATEMENT& statement)
1214 {
1215 CSymbol* dst = statement.dst->GetSymbol().get();
1216
1217 assert(dst->m_type == SYM_TEMPORARY);
1218
1219 Cmp64_GenericRel(statement);
1220 m_assembler.MovGd(MakeTemporarySymbolAddress(dst), CX86Assembler::rAX);
1221 }
1222
Emit_RelToRef_TmpCst(const STATEMENT & statement)1223 void CCodeGen_x86_32::Emit_RelToRef_TmpCst(const STATEMENT& statement)
1224 {
1225 CSymbol* dst = statement.dst->GetSymbol().get();
1226 CSymbol* src1 = statement.src1->GetSymbol().get();
1227
1228 assert(dst->m_type == SYM_TMP_REFERENCE);
1229 assert(src1->m_type == SYM_CONSTANT);
1230
1231 CX86Assembler::REGISTER tmpReg = CX86Assembler::rAX;
1232 m_assembler.LeaGd(tmpReg, CX86Assembler::MakeIndRegOffAddress(CX86Assembler::rBP, src1->m_valueLow));
1233 m_assembler.MovGd(MakeTemporaryReferenceSymbolAddress(dst), tmpReg);
1234 }
1235
Emit_AddRef_MemMemReg(const STATEMENT & statement)1236 void CCodeGen_x86_32::Emit_AddRef_MemMemReg(const STATEMENT& statement)
1237 {
1238 CSymbol* dst = statement.dst->GetSymbol().get();
1239 CSymbol* src1 = statement.src1->GetSymbol().get();
1240 CSymbol* src2 = statement.src2->GetSymbol().get();
1241
1242 assert(src2->m_type == SYM_REGISTER);
1243
1244 CX86Assembler::REGISTER tmpReg = CX86Assembler::rAX;
1245 m_assembler.MovEd(tmpReg, MakeMemoryReferenceSymbolAddress(src1));
1246 m_assembler.AddEd(tmpReg, CX86Assembler::MakeRegisterAddress(m_registers[src2->m_valueLow]));
1247 m_assembler.MovGd(MakeMemoryReferenceSymbolAddress(dst), tmpReg);
1248 }
1249
Emit_AddRef_MemMemMem(const STATEMENT & statement)1250 void CCodeGen_x86_32::Emit_AddRef_MemMemMem(const STATEMENT& statement)
1251 {
1252 CSymbol* dst = statement.dst->GetSymbol().get();
1253 CSymbol* src1 = statement.src1->GetSymbol().get();
1254 CSymbol* src2 = statement.src2->GetSymbol().get();
1255
1256 auto tmpReg = CX86Assembler::rAX;
1257 m_assembler.MovEd(tmpReg, MakeMemoryReferenceSymbolAddress(src1));
1258 m_assembler.AddEd(tmpReg, MakeMemorySymbolAddress(src2));
1259 m_assembler.MovGd(MakeMemoryReferenceSymbolAddress(dst), tmpReg);
1260 }
1261
Emit_AddRef_MemMemCst(const STATEMENT & statement)1262 void CCodeGen_x86_32::Emit_AddRef_MemMemCst(const STATEMENT& statement)
1263 {
1264 CSymbol* dst = statement.dst->GetSymbol().get();
1265 CSymbol* src1 = statement.src1->GetSymbol().get();
1266 CSymbol* src2 = statement.src2->GetSymbol().get();
1267
1268 assert(src2->m_type == SYM_CONSTANT);
1269
1270 CX86Assembler::REGISTER tmpReg = CX86Assembler::rAX;
1271 m_assembler.MovEd(tmpReg, MakeMemoryReferenceSymbolAddress(src1));
1272 m_assembler.AddId(CX86Assembler::MakeRegisterAddress(tmpReg), src2->m_valueLow);
1273 m_assembler.MovGd(MakeMemoryReferenceSymbolAddress(dst), tmpReg);
1274 }
1275
Emit_LoadFromRef_RegTmp(const STATEMENT & statement)1276 void CCodeGen_x86_32::Emit_LoadFromRef_RegTmp(const STATEMENT& statement)
1277 {
1278 CSymbol* dst = statement.dst->GetSymbol().get();
1279 CSymbol* src1 = statement.src1->GetSymbol().get();
1280
1281 assert(dst->m_type == SYM_REGISTER);
1282 assert(src1->m_type == SYM_TMP_REFERENCE);
1283
1284 CX86Assembler::REGISTER tmpReg = CX86Assembler::rAX;
1285 m_assembler.MovEd(tmpReg, MakeTemporaryReferenceSymbolAddress(src1));
1286 m_assembler.MovEd(m_registers[dst->m_valueLow], CX86Assembler::MakeIndRegAddress(tmpReg));
1287 }
1288
Emit_LoadFromRef_MemTmp(const STATEMENT & statement)1289 void CCodeGen_x86_32::Emit_LoadFromRef_MemTmp(const STATEMENT& statement)
1290 {
1291 CSymbol* dst = statement.dst->GetSymbol().get();
1292 CSymbol* src1 = statement.src1->GetSymbol().get();
1293
1294 assert(src1->m_type == SYM_TMP_REFERENCE);
1295
1296 CX86Assembler::REGISTER addressReg = CX86Assembler::rAX;
1297 CX86Assembler::REGISTER valueReg = CX86Assembler::rDX;
1298
1299 m_assembler.MovEd(addressReg, MakeTemporaryReferenceSymbolAddress(src1));
1300 m_assembler.MovEd(valueReg, CX86Assembler::MakeIndRegAddress(addressReg));
1301 m_assembler.MovGd(MakeMemorySymbolAddress(dst), valueReg);
1302 }
1303
Emit_LoadFromRef_Md_RegMem(const STATEMENT & statement)1304 void CCodeGen_x86_32::Emit_LoadFromRef_Md_RegMem(const STATEMENT& statement)
1305 {
1306 auto dst = statement.dst->GetSymbol().get();
1307 auto src1 = statement.src1->GetSymbol().get();
1308
1309 auto addressReg = CX86Assembler::rAX;
1310
1311 m_assembler.MovEd(addressReg, MakeMemoryReferenceSymbolAddress(src1));
1312 m_assembler.MovapsVo(g_mdRegisters[dst->m_valueLow], CX86Assembler::MakeIndRegAddress(addressReg));
1313 }
1314
Emit_LoadFromRef_Md_MemMem(const STATEMENT & statement)1315 void CCodeGen_x86_32::Emit_LoadFromRef_Md_MemMem(const STATEMENT& statement)
1316 {
1317 auto dst = statement.dst->GetSymbol().get();
1318 auto src1 = statement.src1->GetSymbol().get();
1319
1320 auto addressReg = CX86Assembler::rAX;
1321 auto valueReg = CX86Assembler::xMM0;
1322
1323 m_assembler.MovEd(addressReg, MakeMemoryReferenceSymbolAddress(src1));
1324 m_assembler.MovapsVo(valueReg, CX86Assembler::MakeIndRegAddress(addressReg));
1325 m_assembler.MovapsVo(MakeMemory128SymbolAddress(dst), valueReg);
1326 }
1327
Emit_StoreAtRef_TmpReg(const STATEMENT & statement)1328 void CCodeGen_x86_32::Emit_StoreAtRef_TmpReg(const STATEMENT& statement)
1329 {
1330 CSymbol* src1 = statement.src1->GetSymbol().get();
1331 CSymbol* src2 = statement.src2->GetSymbol().get();
1332
1333 assert(src1->m_type == SYM_TMP_REFERENCE);
1334 assert(src2->m_type == SYM_REGISTER);
1335
1336 CX86Assembler::REGISTER addressReg = CX86Assembler::rAX;
1337
1338 m_assembler.MovEd(addressReg, MakeTemporaryReferenceSymbolAddress(src1));
1339 m_assembler.MovGd(CX86Assembler::MakeIndRegAddress(addressReg), m_registers[src2->m_valueLow]);
1340 }
1341
Emit_StoreAtRef_TmpMem(const STATEMENT & statement)1342 void CCodeGen_x86_32::Emit_StoreAtRef_TmpMem(const STATEMENT& statement)
1343 {
1344 CSymbol* src1 = statement.src1->GetSymbol().get();
1345 CSymbol* src2 = statement.src2->GetSymbol().get();
1346
1347 assert(src1->m_type == SYM_TMP_REFERENCE);
1348
1349 CX86Assembler::REGISTER addressReg = CX86Assembler::rAX;
1350 CX86Assembler::REGISTER valueReg = CX86Assembler::rDX;
1351
1352 m_assembler.MovEd(addressReg, MakeTemporaryReferenceSymbolAddress(src1));
1353 m_assembler.MovEd(valueReg, MakeMemorySymbolAddress(src2));
1354 m_assembler.MovGd(CX86Assembler::MakeIndRegAddress(addressReg), valueReg);
1355 }
1356
Emit_StoreAtRef_TmpCst(const STATEMENT & statement)1357 void CCodeGen_x86_32::Emit_StoreAtRef_TmpCst(const STATEMENT& statement)
1358 {
1359 CSymbol* src1 = statement.src1->GetSymbol().get();
1360 CSymbol* src2 = statement.src2->GetSymbol().get();
1361
1362 assert(src1->m_type == SYM_TMP_REFERENCE);
1363 assert(src2->m_type == SYM_CONSTANT);
1364
1365 CX86Assembler::REGISTER tmpReg = CX86Assembler::rAX;
1366 m_assembler.MovEd(tmpReg, MakeTemporaryReferenceSymbolAddress(src1));
1367 m_assembler.MovId(CX86Assembler::MakeIndRegAddress(tmpReg), src2->m_valueLow);
1368 }
1369
Emit_StoreAtRef_Md_MemReg(const STATEMENT & statement)1370 void CCodeGen_x86_32::Emit_StoreAtRef_Md_MemReg(const STATEMENT& statement)
1371 {
1372 auto src1 = statement.src1->GetSymbol().get();
1373 auto src2 = statement.src2->GetSymbol().get();
1374
1375 auto addressReg = CX86Assembler::rAX;
1376
1377 m_assembler.MovEd(addressReg, MakeMemoryReferenceSymbolAddress(src1));
1378 m_assembler.MovapsVo(CX86Assembler::MakeIndRegAddress(addressReg), g_mdRegisters[src2->m_valueLow]);
1379 }
1380
Emit_StoreAtRef_Md_MemMem(const STATEMENT & statement)1381 void CCodeGen_x86_32::Emit_StoreAtRef_Md_MemMem(const STATEMENT& statement)
1382 {
1383 auto src1 = statement.src1->GetSymbol().get();
1384 auto src2 = statement.src2->GetSymbol().get();
1385
1386 auto addressReg = CX86Assembler::rAX;
1387 auto valueReg = CX86Assembler::xMM0;
1388
1389 m_assembler.MovEd(addressReg, MakeMemoryReferenceSymbolAddress(src1));
1390 m_assembler.MovapsVo(valueReg, MakeMemory128SymbolAddress(src2));
1391 m_assembler.MovapsVo(CX86Assembler::MakeIndRegAddress(addressReg), valueReg);
1392 }
1393