1 #include <algorithm>
2 #include "Jitter_CodeGen_x86_64.h"
3 #include <stdexcept>
4 
5 using namespace Jitter;
6 
7 CX86Assembler::REGISTER CCodeGen_x86_64::g_systemVRegisters[SYSTEMV_MAX_REGISTERS] =
8 {
9 	CX86Assembler::rBX,
10 	CX86Assembler::r12,
11 	CX86Assembler::r13,
12 	CX86Assembler::r14,
13 	CX86Assembler::r15,
14 };
15 
16 CX86Assembler::REGISTER CCodeGen_x86_64::g_systemVParamRegs[SYSTEMV_MAX_PARAMS] =
17 {
18 	CX86Assembler::rDI,
19 	CX86Assembler::rSI,
20 	CX86Assembler::rDX,
21 	CX86Assembler::rCX,
22 	CX86Assembler::r8,
23 	CX86Assembler::r9,
24 };
25 
26 CX86Assembler::REGISTER CCodeGen_x86_64::g_win32Registers[WIN32_MAX_REGISTERS] =
27 {
28 	CX86Assembler::rBX,
29 	CX86Assembler::rSI,
30 	CX86Assembler::rDI,
31 	CX86Assembler::r12,
32 	CX86Assembler::r13,
33 	CX86Assembler::r14,
34 	CX86Assembler::r15,
35 };
36 
37 CX86Assembler::REGISTER CCodeGen_x86_64::g_win32ParamRegs[WIN32_MAX_PARAMS] =
38 {
39 	CX86Assembler::rCX,
40 	CX86Assembler::rDX,
41 	CX86Assembler::r8,
42 	CX86Assembler::r9,
43 };
44 
45 //xMM0->xMM3 are used internally for temporary uses
46 CX86Assembler::XMMREGISTER CCodeGen_x86_64::g_mdRegisters[MAX_MDREGISTERS] =
47 {
48 	CX86Assembler::xMM4,
49 	CX86Assembler::xMM5,
50 	CX86Assembler::xMM6,
51 	CX86Assembler::xMM7,
52 	CX86Assembler::xMM8,
53 	CX86Assembler::xMM9,
54 	CX86Assembler::xMM10,
55 	CX86Assembler::xMM11,
56 	CX86Assembler::xMM12,
57 	CX86Assembler::xMM13,
58 	CX86Assembler::xMM14,
59 	CX86Assembler::xMM15
60 };
61 
CombineConstant64(uint32 cstLow,uint32 cstHigh)62 static uint64 CombineConstant64(uint32 cstLow, uint32 cstHigh)
63 {
64 	return (static_cast<uint64>(cstHigh) << 32) | static_cast<uint64>(cstLow);
65 }
66 
67 //ALUOP
68 //-------------------------------------------------------------------
69 
70 template <typename ALUOP>
Emit_Alu64_MemMemMem(const STATEMENT & statement)71 void CCodeGen_x86_64::Emit_Alu64_MemMemMem(const STATEMENT& statement)
72 {
73 	CSymbol* dst = statement.dst->GetSymbol().get();
74 	CSymbol* src1 = statement.src1->GetSymbol().get();
75 	CSymbol* src2 = statement.src2->GetSymbol().get();
76 
77 	CX86Assembler::REGISTER tmpReg = CX86Assembler::rAX;
78 
79 	m_assembler.MovEq(tmpReg, MakeMemory64SymbolAddress(src1));
80 	((m_assembler).*(ALUOP::OpEq()))(tmpReg, MakeMemory64SymbolAddress(src2));
81 	m_assembler.MovGq(MakeMemory64SymbolAddress(dst), tmpReg);
82 }
83 
84 template <typename ALUOP>
Emit_Alu64_MemMemCst(const STATEMENT & statement)85 void CCodeGen_x86_64::Emit_Alu64_MemMemCst(const STATEMENT& statement)
86 {
87 	CSymbol* dst = statement.dst->GetSymbol().get();
88 	CSymbol* src1 = statement.src1->GetSymbol().get();
89 	CSymbol* src2 = statement.src2->GetSymbol().get();
90 
91 	assert(src2->m_type == SYM_CONSTANT64);
92 
93 	CX86Assembler::REGISTER tmpReg = CX86Assembler::rAX;
94 	uint64 constant = CombineConstant64(src2->m_valueLow, src2->m_valueHigh);
95 
96 	m_assembler.MovEq(tmpReg, MakeMemory64SymbolAddress(src1));
97 	if(CX86Assembler::GetMinimumConstantSize64(constant) >= 4)
98 	{
99 		auto cstReg = CX86Assembler::rCX;
100 		m_assembler.MovIq(cstReg, constant);
101 		((m_assembler).*(ALUOP::OpEq()))(tmpReg, CX86Assembler::MakeRegisterAddress(cstReg));
102 	}
103 	else
104 	{
105 		((m_assembler).*(ALUOP::OpIq()))(CX86Assembler::MakeRegisterAddress(tmpReg), constant);
106 	}
107 	m_assembler.MovGq(MakeMemory64SymbolAddress(dst), tmpReg);
108 }
109 
110 template <typename ALUOP>
Emit_Alu64_MemCstMem(const STATEMENT & statement)111 void CCodeGen_x86_64::Emit_Alu64_MemCstMem(const STATEMENT& statement)
112 {
113 	CSymbol* dst = statement.dst->GetSymbol().get();
114 	CSymbol* src1 = statement.src1->GetSymbol().get();
115 	CSymbol* src2 = statement.src2->GetSymbol().get();
116 
117 	assert(src1->m_type == SYM_CONSTANT64);
118 
119 	CX86Assembler::REGISTER tmpReg = CX86Assembler::rAX;
120 	uint64 constant = CombineConstant64(src1->m_valueLow, src1->m_valueHigh);
121 
122 	m_assembler.MovIq(tmpReg, constant);
123 	((m_assembler).*(ALUOP::OpEq()))(tmpReg, MakeMemory64SymbolAddress(src2));
124 	m_assembler.MovGq(MakeMemory64SymbolAddress(dst), tmpReg);
125 }
126 
127 #define ALU64_CONST_MATCHERS(ALUOP_CST, ALUOP) \
128 	{ ALUOP_CST, MATCH_MEMORY64, MATCH_MEMORY64,   MATCH_MEMORY64,   MATCH_NIL, &CCodeGen_x86_64::Emit_Alu64_MemMemMem<ALUOP> }, \
129 	{ ALUOP_CST, MATCH_MEMORY64, MATCH_MEMORY64,   MATCH_CONSTANT64, MATCH_NIL, &CCodeGen_x86_64::Emit_Alu64_MemMemCst<ALUOP> }, \
130 	{ ALUOP_CST, MATCH_MEMORY64, MATCH_CONSTANT64, MATCH_MEMORY64,   MATCH_NIL, &CCodeGen_x86_64::Emit_Alu64_MemCstMem<ALUOP> },
131 
132 //SHIFTOP
133 //-------------------------------------------------------------------
134 
135 template <typename SHIFTOP>
Emit_Shift64_RelRelReg(const STATEMENT & statement)136 void CCodeGen_x86_64::Emit_Shift64_RelRelReg(const STATEMENT& statement)
137 {
138 	CSymbol* dst = statement.dst->GetSymbol().get();
139 	CSymbol* src1 = statement.src1->GetSymbol().get();
140 	CSymbol* src2 = statement.src2->GetSymbol().get();
141 
142 	assert(dst->m_type  == SYM_RELATIVE64);
143 	assert(src1->m_type == SYM_RELATIVE64);
144 	assert(src2->m_type == SYM_REGISTER);
145 
146 	CX86Assembler::REGISTER tmpReg = CX86Assembler::rAX;
147 	CX86Assembler::REGISTER shiftReg = CX86Assembler::rCX;
148 
149 	m_assembler.MovEq(tmpReg, MakeRelative64SymbolAddress(src1));
150 	m_assembler.MovEd(shiftReg, CX86Assembler::MakeRegisterAddress(m_registers[src2->m_valueLow]));
151 	((m_assembler).*(SHIFTOP::OpVar()))(CX86Assembler::MakeRegisterAddress(tmpReg));
152 	m_assembler.MovGq(MakeRelative64SymbolAddress(dst), tmpReg);
153 }
154 
155 template <typename SHIFTOP>
Emit_Shift64_RelRelMem(const STATEMENT & statement)156 void CCodeGen_x86_64::Emit_Shift64_RelRelMem(const STATEMENT& statement)
157 {
158 	CSymbol* dst = statement.dst->GetSymbol().get();
159 	CSymbol* src1 = statement.src1->GetSymbol().get();
160 	CSymbol* src2 = statement.src2->GetSymbol().get();
161 
162 	assert(dst->m_type  == SYM_RELATIVE64);
163 	assert(src1->m_type == SYM_RELATIVE64);
164 
165 	CX86Assembler::REGISTER tmpReg = CX86Assembler::rAX;
166 	CX86Assembler::REGISTER shiftReg = CX86Assembler::rCX;
167 
168 	m_assembler.MovEq(tmpReg, MakeRelative64SymbolAddress(src1));
169 	m_assembler.MovEd(shiftReg, MakeMemorySymbolAddress(src2));
170 	((m_assembler).*(SHIFTOP::OpVar()))(CX86Assembler::MakeRegisterAddress(tmpReg));
171 	m_assembler.MovGq(MakeRelative64SymbolAddress(dst), tmpReg);
172 }
173 
174 template <typename SHIFTOP>
Emit_Shift64_RelRelCst(const STATEMENT & statement)175 void CCodeGen_x86_64::Emit_Shift64_RelRelCst(const STATEMENT& statement)
176 {
177 	CSymbol* dst = statement.dst->GetSymbol().get();
178 	CSymbol* src1 = statement.src1->GetSymbol().get();
179 	CSymbol* src2 = statement.src2->GetSymbol().get();
180 
181 	assert(dst->m_type  == SYM_RELATIVE64);
182 	assert(src1->m_type == SYM_RELATIVE64);
183 	assert(src2->m_type == SYM_CONSTANT);
184 
185 	CX86Assembler::REGISTER tmpReg = CX86Assembler::rAX;
186 
187 	m_assembler.MovEq(tmpReg, MakeRelative64SymbolAddress(src1));
188 	((m_assembler).*(SHIFTOP::OpCst()))(CX86Assembler::MakeRegisterAddress(tmpReg), static_cast<uint8>(src2->m_valueLow));
189 	m_assembler.MovGq(MakeRelative64SymbolAddress(dst), tmpReg);
190 }
191 
192 #define SHIFT64_CONST_MATCHERS(SHIFTOP_CST, SHIFTOP) \
193 	{ SHIFTOP_CST, MATCH_RELATIVE64, MATCH_RELATIVE64, MATCH_REGISTER, MATCH_NIL, &CCodeGen_x86_64::Emit_Shift64_RelRelReg<SHIFTOP> }, \
194 	{ SHIFTOP_CST, MATCH_RELATIVE64, MATCH_RELATIVE64, MATCH_MEMORY,   MATCH_NIL, &CCodeGen_x86_64::Emit_Shift64_RelRelMem<SHIFTOP> }, \
195 	{ SHIFTOP_CST, MATCH_RELATIVE64, MATCH_RELATIVE64, MATCH_CONSTANT, MATCH_NIL, &CCodeGen_x86_64::Emit_Shift64_RelRelCst<SHIFTOP> },
196 
197 CCodeGen_x86_64::CONSTMATCHER CCodeGen_x86_64::g_constMatchers[] =
198 {
199 	{ OP_PARAM, MATCH_NIL, MATCH_CONTEXT,     MATCH_NIL, MATCH_NIL, &CCodeGen_x86_64::Emit_Param_Ctx    },
200 	{ OP_PARAM, MATCH_NIL, MATCH_REGISTER,    MATCH_NIL, MATCH_NIL, &CCodeGen_x86_64::Emit_Param_Reg    },
201 	{ OP_PARAM, MATCH_NIL, MATCH_MEMORY,      MATCH_NIL, MATCH_NIL, &CCodeGen_x86_64::Emit_Param_Mem    },
202 	{ OP_PARAM, MATCH_NIL, MATCH_CONSTANT,    MATCH_NIL, MATCH_NIL, &CCodeGen_x86_64::Emit_Param_Cst    },
203 	{ OP_PARAM, MATCH_NIL, MATCH_MEMORY64,    MATCH_NIL, MATCH_NIL, &CCodeGen_x86_64::Emit_Param_Mem64  },
204 	{ OP_PARAM, MATCH_NIL, MATCH_CONSTANT64,  MATCH_NIL, MATCH_NIL, &CCodeGen_x86_64::Emit_Param_Cst64  },
205 	{ OP_PARAM, MATCH_NIL, MATCH_REGISTER128, MATCH_NIL, MATCH_NIL, &CCodeGen_x86_64::Emit_Param_Reg128 },
206 	{ OP_PARAM, MATCH_NIL, MATCH_MEMORY128,   MATCH_NIL, MATCH_NIL, &CCodeGen_x86_64::Emit_Param_Mem128 },
207 
208 	{ OP_PARAM_RET, MATCH_NIL, MATCH_MEMORY128, MATCH_NIL, MATCH_NIL, &CCodeGen_x86_64::Emit_Param_Mem128 },
209 
210 	{ OP_CALL, MATCH_NIL, MATCH_CONSTANTPTR, MATCH_CONSTANT, MATCH_NIL, &CCodeGen_x86_64::Emit_Call },
211 
212 	{ OP_RETVAL, MATCH_REGISTER,    MATCH_NIL, MATCH_NIL, MATCH_NIL, &CCodeGen_x86_64::Emit_RetVal_Reg    },
213 	{ OP_RETVAL, MATCH_MEMORY,      MATCH_NIL, MATCH_NIL, MATCH_NIL, &CCodeGen_x86_64::Emit_RetVal_Mem    },
214 	{ OP_RETVAL, MATCH_MEMORY64,    MATCH_NIL, MATCH_NIL, MATCH_NIL, &CCodeGen_x86_64::Emit_RetVal_Mem64  },
215 	{ OP_RETVAL, MATCH_REGISTER128, MATCH_NIL, MATCH_NIL, MATCH_NIL, &CCodeGen_x86_64::Emit_RetVal_Reg128 },
216 	{ OP_RETVAL, MATCH_MEMORY128,   MATCH_NIL, MATCH_NIL, MATCH_NIL, &CCodeGen_x86_64::Emit_RetVal_Mem128 },
217 
218 	{ OP_EXTERNJMP,     MATCH_NIL, MATCH_CONSTANTPTR, MATCH_NIL, MATCH_NIL, &CCodeGen_x86_64::Emit_ExternJmp },
219 	{ OP_EXTERNJMP_DYN, MATCH_NIL, MATCH_CONSTANTPTR, MATCH_NIL, MATCH_NIL, &CCodeGen_x86_64::Emit_ExternJmp },
220 
221 	{ OP_MOV, MATCH_MEMORY64,   MATCH_MEMORY64,   MATCH_NIL, MATCH_NIL, &CCodeGen_x86_64::Emit_Mov_Mem64Mem64 },
222 	{ OP_MOV, MATCH_RELATIVE64, MATCH_CONSTANT64, MATCH_NIL, MATCH_NIL, &CCodeGen_x86_64::Emit_Mov_Rel64Cst64 },
223 
224 	{ OP_MOV, MATCH_REG_REF, MATCH_MEM_REF, MATCH_NIL, MATCH_NIL, &CCodeGen_x86_64::Emit_Mov_RegRefMemRef },
225 
226 	ALU64_CONST_MATCHERS(OP_ADD64, ALUOP64_ADD)
227 	ALU64_CONST_MATCHERS(OP_SUB64, ALUOP64_SUB)
228 	ALU64_CONST_MATCHERS(OP_AND64, ALUOP64_AND)
229 
230 	SHIFT64_CONST_MATCHERS(OP_SLL64, SHIFTOP64_SLL)
231 	SHIFT64_CONST_MATCHERS(OP_SRL64, SHIFTOP64_SRL)
232 	SHIFT64_CONST_MATCHERS(OP_SRA64, SHIFTOP64_SRA)
233 
234 	{ OP_CMP, MATCH_VARIABLE, MATCH_VARIABLE, MATCH_VARIABLE, MATCH_NIL, &CCodeGen_x86_64::Emit_Cmp_VarVarVar },
235 	{ OP_CMP, MATCH_VARIABLE, MATCH_VARIABLE, MATCH_CONSTANT, MATCH_NIL, &CCodeGen_x86_64::Emit_Cmp_VarVarCst },
236 
237 	{ OP_CMP64, MATCH_REGISTER, MATCH_RELATIVE64, MATCH_RELATIVE64, MATCH_NIL, &CCodeGen_x86_64::Emit_Cmp64_RegRelRel },
238 	{ OP_CMP64, MATCH_REGISTER, MATCH_RELATIVE64, MATCH_CONSTANT64, MATCH_NIL, &CCodeGen_x86_64::Emit_Cmp64_RegRelCst },
239 	{ OP_CMP64, MATCH_MEMORY,   MATCH_RELATIVE64, MATCH_RELATIVE64, MATCH_NIL, &CCodeGen_x86_64::Emit_Cmp64_MemRelRel },
240 	{ OP_CMP64, MATCH_MEMORY,   MATCH_RELATIVE64, MATCH_CONSTANT64, MATCH_NIL, &CCodeGen_x86_64::Emit_Cmp64_MemRelCst },
241 
242 	{ OP_RELTOREF, MATCH_VAR_REF, MATCH_CONSTANT, MATCH_NIL, MATCH_NIL, &CCodeGen_x86_64::Emit_RelToRef_VarCst },
243 
244 	{ OP_ADDREF, MATCH_VAR_REF, MATCH_VAR_REF, MATCH_VARIABLE, MATCH_NIL, &CCodeGen_x86_64::Emit_AddRef_VarVarVar },
245 	{ OP_ADDREF, MATCH_VAR_REF, MATCH_VAR_REF, MATCH_CONSTANT, MATCH_NIL, &CCodeGen_x86_64::Emit_AddRef_VarVarCst },
246 
247 	{ OP_ISREFNULL, MATCH_VARIABLE, MATCH_VAR_REF, MATCH_NIL, MATCH_NIL, &CCodeGen_x86_64::Emit_IsRefNull_VarVar },
248 
249 	{ OP_LOADFROMREF, MATCH_MEMORY64, MATCH_VAR_REF, MATCH_NIL, MATCH_NIL, &CCodeGen_x86_64::Emit_LoadFromRef_64_MemVar },
250 	{ OP_LOADFROMREF, MATCH_VAR_REF, MATCH_VAR_REF, MATCH_NIL, MATCH_NIL, &CCodeGen_x86_64::Emit_LoadFromRef_Ref_VarVar },
251 
252 	{ OP_STOREATREF, MATCH_NIL, MATCH_VAR_REF, MATCH_MEMORY64, MATCH_NIL, &CCodeGen_x86_64::Emit_StoreAtRef_64_VarMem },
253 	{ OP_STOREATREF, MATCH_NIL, MATCH_VAR_REF, MATCH_CONSTANT64, MATCH_NIL, &CCodeGen_x86_64::Emit_StoreAtRef_64_VarCst },
254 
255 	{ OP_STORE8ATREF, MATCH_NIL, MATCH_VAR_REF, MATCH_VARIABLE, MATCH_NIL, &CCodeGen_x86_64::Emit_Store8AtRef_VarVar },
256 
257 	{ OP_CONDJMP, MATCH_NIL, MATCH_VAR_REF, MATCH_CONSTANT, MATCH_NIL, &CCodeGen_x86_64::Emit_CondJmp_Ref_VarCst },
258 
259 	{ OP_MOV, MATCH_NIL, MATCH_NIL, MATCH_NIL, MATCH_NIL, nullptr },
260 };
261 
CCodeGen_x86_64()262 CCodeGen_x86_64::CCodeGen_x86_64()
263 {
264 	SetPlatformAbi(PLATFORM_ABI_SYSTEMV);
265 	CCodeGen_x86::m_mdRegisters = g_mdRegisters;
266 
267 	for(CONSTMATCHER* constMatcher = g_constMatchers; constMatcher->emitter != NULL; constMatcher++)
268 	{
269 		MATCHER matcher;
270 		matcher.op       = constMatcher->op;
271 		matcher.dstType  = constMatcher->dstType;
272 		matcher.src1Type = constMatcher->src1Type;
273 		matcher.src2Type = constMatcher->src2Type;
274 		matcher.src3Type = constMatcher->src3Type;
275 		matcher.emitter  = std::bind(constMatcher->emitter, this, std::placeholders::_1);
276 		m_matchers.insert(MatcherMapType::value_type(matcher.op, matcher));
277 	}
278 }
279 
SetPlatformAbi(PLATFORM_ABI platformAbi)280 void CCodeGen_x86_64::SetPlatformAbi(PLATFORM_ABI platformAbi)
281 {
282 	m_platformAbi = platformAbi;
283 	switch(m_platformAbi)
284 	{
285 	case PLATFORM_ABI_SYSTEMV:
286 		CCodeGen_x86::m_registers    = g_systemVRegisters;
287 		m_paramRegs                  = g_systemVParamRegs;
288 		m_maxRegisters               = SYSTEMV_MAX_REGISTERS;
289 		m_maxParams                  = SYSTEMV_MAX_PARAMS;
290 		m_hasMdRegRetValues          = true;
291 		break;
292 	case PLATFORM_ABI_WIN32:
293 		CCodeGen_x86::m_registers    = g_win32Registers;
294 		m_paramRegs                  = g_win32ParamRegs;
295 		m_maxRegisters               = WIN32_MAX_REGISTERS;
296 		m_maxParams                  = WIN32_MAX_PARAMS;
297 		m_hasMdRegRetValues          = false;
298 		break;
299 	default:
300 		throw std::runtime_error("Unsupported ABI.");
301 		break;
302 	}
303 }
304 
GetAvailableRegisterCount() const305 unsigned int CCodeGen_x86_64::GetAvailableRegisterCount() const
306 {
307 	return m_maxRegisters;
308 }
309 
GetAvailableMdRegisterCount() const310 unsigned int CCodeGen_x86_64::GetAvailableMdRegisterCount() const
311 {
312 	return MAX_MDREGISTERS;
313 }
314 
CanHold128BitsReturnValueInRegisters() const315 bool CCodeGen_x86_64::CanHold128BitsReturnValueInRegisters() const
316 {
317 	return m_hasMdRegRetValues;
318 }
319 
GetPointerSize() const320 uint32 CCodeGen_x86_64::GetPointerSize() const
321 {
322 	return 8;
323 }
324 
Emit_Prolog(const StatementList & statements,unsigned int stackSize)325 void CCodeGen_x86_64::Emit_Prolog(const StatementList& statements, unsigned int stackSize)
326 {
327 	m_params.clear();
328 
329 	//Compute the size needed to store all function call parameters
330 	uint32 maxParamSpillSize = 0;
331 	{
332 		uint32 currParamSpillSize = 0;
333 		for(const auto& statement : statements)
334 		{
335 			switch(statement.op)
336 			{
337 			case OP_PARAM:
338 			case OP_PARAM_RET:
339 				{
340 					CSymbol* src1 = statement.src1->GetSymbol().get();
341 					switch(src1->m_type)
342 					{
343 					case SYM_REGISTER128:
344 						currParamSpillSize += 16;
345 						break;
346 					}
347 				}
348 				break;
349 			case OP_CALL:
350 				maxParamSpillSize = std::max<uint32>(currParamSpillSize, maxParamSpillSize);
351 				currParamSpillSize = 0;
352 				break;
353 			default:
354 				break;
355 			}
356 		}
357 	}
358 
359 	assert((maxParamSpillSize & 0x0F) == 0);
360 	assert((stackSize & 0x0F) == 0);
361 
362 	m_assembler.Push(CX86Assembler::rBP);
363 	m_assembler.MovEq(CX86Assembler::rBP, CX86Assembler::MakeRegisterAddress(m_paramRegs[0]));
364 
365 	uint32 savedSize = 0;
366 	for(unsigned int i = 0; i < m_maxRegisters; i++)
367 	{
368 		if(m_registerUsage & (1 << i))
369 		{
370 			m_assembler.Push(m_registers[i]);
371 			savedSize += 8;
372 		}
373 	}
374 
375 	uint32 savedRegAlignAdjust = (savedSize != 0) ? (0x10 - (savedSize & 0xF)) : 0;
376 
377 	m_totalStackAlloc = savedRegAlignAdjust + maxParamSpillSize + stackSize;
378 	m_totalStackAlloc += 0x20;
379 
380 	m_stackLevel = 0x20;
381 	m_paramSpillBase = 0x20 + stackSize;
382 
383 	m_assembler.SubIq(CX86Assembler::MakeRegisterAddress(CX86Assembler::rSP), m_totalStackAlloc);
384 
385 	//-------------------------------
386 	//Stack Frame
387 	//-------------------------------
388 	//(High address)
389 	//------------------
390 	//Saved registers + align adjustment
391 	//------------------
392 	//Params spill space
393 	//------------------			<----- rSP + m_paramSpillBase
394 	//Temporary symbols (stackSize) + align adjustment
395 	//------------------			<----- rSP + m_stackLevel
396 	//Param spill area for callee (0x20 bytes)
397 	//------------------			<----- rSP
398 	//(Low address)
399 }
400 
Emit_Epilog()401 void CCodeGen_x86_64::Emit_Epilog()
402 {
403 	m_assembler.AddIq(CX86Assembler::MakeRegisterAddress(CX86Assembler::rSP), m_totalStackAlloc);
404 
405 	for(int i = m_maxRegisters - 1; i >= 0; i--)
406 	{
407 		if(m_registerUsage & (1 << i))
408 		{
409 			m_assembler.Pop(m_registers[i]);
410 		}
411 	}
412 
413 	m_assembler.Pop(CX86Assembler::rBP);
414 }
415 
MakeConstant128Address(const LITERAL128 & constant)416 CX86Assembler::CAddress CCodeGen_x86_64::MakeConstant128Address(const LITERAL128& constant)
417 {
418 	auto literalId = m_assembler.CreateLiteral128(constant);
419 	return CX86Assembler::MakeLiteral128Address(literalId);
420 }
421 
Emit_Param_Ctx(const STATEMENT & statement)422 void CCodeGen_x86_64::Emit_Param_Ctx(const STATEMENT& statement)
423 {
424 	assert(m_params.size() < m_maxParams);
425 
426 	m_params.push_back(
427 		[this] (CX86Assembler::REGISTER paramReg, uint32)
428 		{
429 			m_assembler.MovEq(paramReg, CX86Assembler::MakeRegisterAddress(CX86Assembler::rBP));
430 			return 0;
431 		}
432 	);
433 }
434 
Emit_Param_Reg(const STATEMENT & statement)435 void CCodeGen_x86_64::Emit_Param_Reg(const STATEMENT& statement)
436 {
437 	assert(m_params.size() < m_maxParams);
438 
439 	auto src1 = statement.src1->GetSymbol().get();
440 
441 	m_params.push_back(
442 		[this, src1] (CX86Assembler::REGISTER paramReg, uint32)
443 		{
444 			m_assembler.MovEd(paramReg, CX86Assembler::MakeRegisterAddress(m_registers[src1->m_valueLow]));
445 			return 0;
446 		}
447 	);
448 }
449 
Emit_Param_Mem(const STATEMENT & statement)450 void CCodeGen_x86_64::Emit_Param_Mem(const STATEMENT& statement)
451 {
452 	assert(m_params.size() < m_maxParams);
453 
454 	auto src1 = statement.src1->GetSymbol().get();
455 
456 	m_params.push_back(
457 		[this, src1] (CX86Assembler::REGISTER paramReg, uint32)
458 		{
459 			m_assembler.MovEd(paramReg, MakeMemorySymbolAddress(src1));
460 			return 0;
461 		}
462 	);
463 }
464 
Emit_Param_Cst(const STATEMENT & statement)465 void CCodeGen_x86_64::Emit_Param_Cst(const STATEMENT& statement)
466 {
467 	assert(m_params.size() < m_maxParams);
468 
469 	auto src1 = statement.src1->GetSymbol().get();
470 
471 	m_params.push_back(
472 		[this, src1] (CX86Assembler::REGISTER paramReg, uint32)
473 		{
474 			m_assembler.MovId(paramReg, src1->m_valueLow);
475 			return 0;
476 		}
477 	);
478 }
479 
Emit_Param_Mem64(const STATEMENT & statement)480 void CCodeGen_x86_64::Emit_Param_Mem64(const STATEMENT& statement)
481 {
482 	assert(m_params.size() < m_maxParams);
483 
484 	auto src1 = statement.src1->GetSymbol().get();
485 
486 	m_params.push_back(
487 		[this, src1] (CX86Assembler::REGISTER paramReg, uint32)
488 		{
489 			m_assembler.MovEq(paramReg, MakeMemory64SymbolAddress(src1));
490 			return 0;
491 		}
492 	);
493 }
494 
Emit_Param_Cst64(const STATEMENT & statement)495 void CCodeGen_x86_64::Emit_Param_Cst64(const STATEMENT& statement)
496 {
497 	assert(m_params.size() < m_maxParams);
498 
499 	auto src1 = statement.src1->GetSymbol().get();
500 
501 	m_params.push_back(
502 		[this, src1] (CX86Assembler::REGISTER paramReg, uint32)
503 		{
504 			m_assembler.MovIq(paramReg, CombineConstant64(src1->m_valueLow, src1->m_valueHigh));
505 			return 0;
506 		}
507 	);
508 }
509 
Emit_Param_Reg128(const STATEMENT & statement)510 void CCodeGen_x86_64::Emit_Param_Reg128(const STATEMENT& statement)
511 {
512 	assert(m_params.size() < m_maxParams);
513 
514 	auto src1 = statement.src1->GetSymbol().get();
515 
516 	m_params.push_back(
517 		[this, src1] (CX86Assembler::REGISTER paramReg, uint32 paramSpillOffset)
518 		{
519 			auto paramTempAddr = CX86Assembler::MakeIndRegOffAddress(CX86Assembler::rSP, m_paramSpillBase + paramSpillOffset);
520 			m_assembler.MovapsVo(paramTempAddr, m_mdRegisters[src1->m_valueLow]);
521 			m_assembler.LeaGq(paramReg, paramTempAddr);
522 			return 0x10;
523 		}
524 	);
525 }
526 
Emit_Param_Mem128(const STATEMENT & statement)527 void CCodeGen_x86_64::Emit_Param_Mem128(const STATEMENT& statement)
528 {
529 	assert(m_params.size() < m_maxParams);
530 
531 	auto src1 = statement.src1->GetSymbol().get();
532 
533 	m_params.push_back(
534 		[this, src1] (CX86Assembler::REGISTER paramReg, uint32)
535 		{
536 			m_assembler.LeaGq(paramReg, MakeMemory128SymbolAddress(src1));
537 			return 0;
538 		}
539 	);
540 }
541 
Emit_Call(const STATEMENT & statement)542 void CCodeGen_x86_64::Emit_Call(const STATEMENT& statement)
543 {
544 	const auto& src1 = statement.src1->GetSymbol().get();
545 	const auto& src2 = statement.src2->GetSymbol().get();
546 
547 	unsigned int paramCount = src2->m_valueLow;
548 	uint32 paramSpillOffset = 0;
549 
550 	for(unsigned int i = 0; i < paramCount; i++)
551 	{
552 		auto emitter(m_params.back());
553 		m_params.pop_back();
554 		paramSpillOffset += emitter(m_paramRegs[i], paramSpillOffset);
555 	}
556 
557 	m_assembler.MovIq(CX86Assembler::rAX, CombineConstant64(src1->m_valueLow, src1->m_valueHigh));
558 	auto symbolRefLabel = m_assembler.CreateLabel();
559 	m_assembler.MarkLabel(symbolRefLabel, -8);
560 	m_symbolReferenceLabels.push_back(std::make_pair(src1->GetConstantPtr(), symbolRefLabel));
561 	m_assembler.CallEd(CX86Assembler::MakeRegisterAddress(CX86Assembler::rAX));
562 }
563 
Emit_RetVal_Reg(const STATEMENT & statement)564 void CCodeGen_x86_64::Emit_RetVal_Reg(const STATEMENT& statement)
565 {
566 	CSymbol* dst = statement.dst->GetSymbol().get();
567 
568 	assert(dst->m_type == SYM_REGISTER);
569 
570 	m_assembler.MovGd(CX86Assembler::MakeRegisterAddress(m_registers[dst->m_valueLow]), CX86Assembler::rAX);
571 }
572 
Emit_RetVal_Mem(const STATEMENT & statement)573 void CCodeGen_x86_64::Emit_RetVal_Mem(const STATEMENT& statement)
574 {
575 	CSymbol* dst = statement.dst->GetSymbol().get();
576 	m_assembler.MovGd(MakeMemorySymbolAddress(dst), CX86Assembler::rAX);
577 }
578 
Emit_RetVal_Mem64(const STATEMENT & statement)579 void CCodeGen_x86_64::Emit_RetVal_Mem64(const STATEMENT& statement)
580 {
581 	CSymbol* dst = statement.dst->GetSymbol().get();
582 	m_assembler.MovGq(MakeMemory64SymbolAddress(dst), CX86Assembler::rAX);
583 }
584 
Emit_RetVal_Reg128(const STATEMENT & statement)585 void CCodeGen_x86_64::Emit_RetVal_Reg128(const STATEMENT& statement)
586 {
587 	auto dst = statement.dst->GetSymbol().get();
588 
589 	//TODO: Use only integer operations
590 	m_assembler.MovqVo(m_mdRegisters[dst->m_valueLow], CX86Assembler::MakeRegisterAddress(CX86Assembler::rAX));
591 	m_assembler.MovqVo(CX86Assembler::xMM0, CX86Assembler::MakeRegisterAddress(CX86Assembler::rDX));
592 	m_assembler.ShufpsVo(m_mdRegisters[dst->m_valueLow], CX86Assembler::MakeXmmRegisterAddress(CX86Assembler::xMM0), 0x44);
593 }
594 
Emit_RetVal_Mem128(const STATEMENT & statement)595 void CCodeGen_x86_64::Emit_RetVal_Mem128(const STATEMENT& statement)
596 {
597 	CSymbol* dst = statement.dst->GetSymbol().get();
598 	m_assembler.MovGq(MakeMemory128SymbolElementAddress(dst, 0), CX86Assembler::rAX);
599 	m_assembler.MovGq(MakeMemory128SymbolElementAddress(dst, 2), CX86Assembler::rDX);
600 }
601 
Emit_ExternJmp(const STATEMENT & statement)602 void CCodeGen_x86_64::Emit_ExternJmp(const STATEMENT& statement)
603 {
604 	auto src1 = statement.src1->GetSymbol().get();
605 
606 	m_assembler.MovEq(m_paramRegs[0], CX86Assembler::MakeRegisterAddress(g_baseRegister));
607 	Emit_Epilog();
608 	m_assembler.MovIq(CX86Assembler::rAX, CombineConstant64(src1->m_valueLow, src1->m_valueHigh));
609 	auto symbolRefLabel = m_assembler.CreateLabel();
610 	m_assembler.MarkLabel(symbolRefLabel, -8);
611 	m_symbolReferenceLabels.push_back(std::make_pair(src1->GetConstantPtr(), symbolRefLabel));
612 	m_assembler.JmpEd(CX86Assembler::MakeRegisterAddress(CX86Assembler::rAX));
613 }
614 
Emit_Mov_Mem64Mem64(const STATEMENT & statement)615 void CCodeGen_x86_64::Emit_Mov_Mem64Mem64(const STATEMENT& statement)
616 {
617 	CSymbol* dst = statement.dst->GetSymbol().get();
618 	CSymbol* src1 = statement.src1->GetSymbol().get();
619 
620 	m_assembler.MovEq(CX86Assembler::rAX, MakeMemory64SymbolAddress(src1));
621 	m_assembler.MovGq(MakeMemory64SymbolAddress(dst), CX86Assembler::rAX);
622 }
623 
Emit_Mov_Rel64Cst64(const STATEMENT & statement)624 void CCodeGen_x86_64::Emit_Mov_Rel64Cst64(const STATEMENT& statement)
625 {
626 	CSymbol* dst = statement.dst->GetSymbol().get();
627 	CSymbol* src1 = statement.src1->GetSymbol().get();
628 
629 	assert(dst->m_type  == SYM_RELATIVE64);
630 	assert(src1->m_type == SYM_CONSTANT64);
631 
632 	uint64 constant = CombineConstant64(src1->m_valueLow, src1->m_valueHigh);
633 	CX86Assembler::REGISTER tmpReg = CX86Assembler::rAX;
634 
635 	if(constant == 0)
636 	{
637 		m_assembler.XorGq(CX86Assembler::MakeRegisterAddress(tmpReg), tmpReg);
638 	}
639 	else
640 	{
641 		m_assembler.MovIq(tmpReg, constant);
642 	}
643 	m_assembler.MovGq(MakeRelative64SymbolAddress(dst), tmpReg);
644 }
645 
Emit_Mov_RegRefMemRef(const STATEMENT & statement)646 void CCodeGen_x86_64::Emit_Mov_RegRefMemRef(const STATEMENT& statement)
647 {
648 	auto dst = statement.dst->GetSymbol().get();
649 	auto src1 = statement.src1->GetSymbol().get();
650 
651 	assert(dst->m_type == SYM_REG_REFERENCE);
652 
653 	m_assembler.MovEq(m_registers[dst->m_valueLow], MakeMemoryReferenceSymbolAddress(src1));
654 }
655 
Emit_Cmp_VarVarVar(const STATEMENT & statement)656 void CCodeGen_x86_64::Emit_Cmp_VarVarVar(const STATEMENT& statement)
657 {
658 	auto dst = statement.dst->GetSymbol().get();
659 	auto src1 = statement.src1->GetSymbol().get();
660 	auto src2 = statement.src2->GetSymbol().get();
661 
662 	auto dstReg = PrepareSymbolRegisterDef(dst, CX86Assembler::rCX);
663 	auto src1Reg = PrepareSymbolRegisterUse(src1, CX86Assembler::rDX);
664 
665 	m_assembler.CmpEd(src1Reg, MakeVariableSymbolAddress(src2));
666 	Cmp_GetFlag(CX86Assembler::MakeRegisterAddress(dstReg), statement.jmpCondition);
667 	m_assembler.MovzxEb(dstReg, CX86Assembler::MakeRegisterAddress(dstReg));
668 
669 	CommitSymbolRegister(dst, dstReg);
670 }
671 
Emit_Cmp_VarVarCst(const STATEMENT & statement)672 void CCodeGen_x86_64::Emit_Cmp_VarVarCst(const STATEMENT& statement)
673 {
674 	auto dst = statement.dst->GetSymbol().get();
675 	auto src1 = statement.src1->GetSymbol().get();
676 	auto src2 = statement.src2->GetSymbol().get();
677 
678 	auto dstReg = PrepareSymbolRegisterDef(dst, CX86Assembler::rCX);
679 
680 	m_assembler.CmpId(MakeVariableSymbolAddress(src1), src2->m_valueLow);
681 	Cmp_GetFlag(CX86Assembler::MakeRegisterAddress(dstReg), statement.jmpCondition);
682 	m_assembler.MovzxEb(dstReg, CX86Assembler::MakeRegisterAddress(dstReg));
683 
684 	CommitSymbolRegister(dst, dstReg);
685 }
686 
Cmp64_RelRel(CX86Assembler::REGISTER dstReg,const STATEMENT & statement)687 void CCodeGen_x86_64::Cmp64_RelRel(CX86Assembler::REGISTER dstReg, const STATEMENT& statement)
688 {
689 	auto src1 = statement.src1->GetSymbol().get();
690 	auto src2 = statement.src2->GetSymbol().get();
691 
692 	assert(src1->m_type == SYM_RELATIVE64);
693 	assert(src2->m_type == SYM_RELATIVE64);
694 
695 	m_assembler.XorEd(dstReg, CX86Assembler::MakeRegisterAddress(dstReg));
696 
697 	auto tmpReg = CX86Assembler::rCX;
698 	m_assembler.MovEq(tmpReg, MakeRelative64SymbolAddress(src1));
699 	m_assembler.CmpEq(tmpReg, MakeRelative64SymbolAddress(src2));
700 
701 	Cmp_GetFlag(CX86Assembler::MakeRegisterAddress(dstReg), statement.jmpCondition);
702 }
703 
Cmp64_RelCst(CX86Assembler::REGISTER dstReg,const STATEMENT & statement)704 void CCodeGen_x86_64::Cmp64_RelCst(CX86Assembler::REGISTER dstReg, const STATEMENT& statement)
705 {
706 	auto src1 = statement.src1->GetSymbol().get();
707 	auto src2 = statement.src2->GetSymbol().get();
708 
709 	assert(src1->m_type == SYM_RELATIVE64);
710 	assert(src2->m_type == SYM_CONSTANT64);
711 
712 	uint64 constant = CombineConstant64(src2->m_valueLow, src2->m_valueHigh);
713 
714 	m_assembler.XorEd(dstReg, CX86Assembler::MakeRegisterAddress(dstReg));
715 
716 	auto tmpReg = CX86Assembler::rCX;
717 	m_assembler.MovEq(tmpReg, MakeRelative64SymbolAddress(src1));
718 	if(constant == 0)
719 	{
720 		auto cstReg = CX86Assembler::rDX;
721 		m_assembler.XorGq(CX86Assembler::MakeRegisterAddress(cstReg), cstReg);
722 		m_assembler.CmpEq(tmpReg, CX86Assembler::MakeRegisterAddress(cstReg));
723 	}
724 	else if(CX86Assembler::GetMinimumConstantSize64(constant) == 8)
725 	{
726 		auto cstReg = CX86Assembler::rDX;
727 		m_assembler.MovIq(cstReg, constant);
728 		m_assembler.CmpEq(tmpReg, CX86Assembler::MakeRegisterAddress(cstReg));
729 	}
730 	else
731 	{
732 		m_assembler.CmpIq(CX86Assembler::MakeRegisterAddress(tmpReg), constant);
733 	}
734 
735 	Cmp_GetFlag(CX86Assembler::MakeRegisterAddress(dstReg), statement.jmpCondition);
736 }
737 
Emit_Cmp64_RegRelRel(const STATEMENT & statement)738 void CCodeGen_x86_64::Emit_Cmp64_RegRelRel(const STATEMENT& statement)
739 {
740 	CSymbol* dst = statement.dst->GetSymbol().get();
741 	assert(dst->m_type == SYM_REGISTER);
742 	Cmp64_RelRel(m_registers[dst->m_valueLow], statement);
743 }
744 
Emit_Cmp64_RegRelCst(const STATEMENT & statement)745 void CCodeGen_x86_64::Emit_Cmp64_RegRelCst(const STATEMENT& statement)
746 {
747 	CSymbol* dst = statement.dst->GetSymbol().get();
748 	assert(dst->m_type == SYM_REGISTER);
749 	Cmp64_RelCst(m_registers[dst->m_valueLow], statement);
750 }
751 
Emit_Cmp64_MemRelRel(const STATEMENT & statement)752 void CCodeGen_x86_64::Emit_Cmp64_MemRelRel(const STATEMENT& statement)
753 {
754 	CSymbol* dst = statement.dst->GetSymbol().get();
755 	CX86Assembler::REGISTER tmpReg = CX86Assembler::rAX;
756 	Cmp64_RelRel(tmpReg, statement);
757 	m_assembler.MovGd(MakeMemorySymbolAddress(dst), tmpReg);
758 }
759 
Emit_Cmp64_MemRelCst(const STATEMENT & statement)760 void CCodeGen_x86_64::Emit_Cmp64_MemRelCst(const STATEMENT& statement)
761 {
762 	CSymbol* dst = statement.dst->GetSymbol().get();
763 	CX86Assembler::REGISTER tmpReg = CX86Assembler::rAX;
764 	Cmp64_RelCst(tmpReg, statement);
765 	m_assembler.MovGd(MakeMemorySymbolAddress(dst), tmpReg);
766 }
767 
Emit_RelToRef_VarCst(const STATEMENT & statement)768 void CCodeGen_x86_64::Emit_RelToRef_VarCst(const STATEMENT& statement)
769 {
770 	auto dst = statement.dst->GetSymbol().get();
771 	auto src1 = statement.src1->GetSymbol().get();
772 
773 	assert(src1->m_type == SYM_CONSTANT);
774 
775 	auto dstReg = PrepareRefSymbolRegisterDef(dst, CX86Assembler::rAX);
776 	m_assembler.LeaGq(dstReg, CX86Assembler::MakeIndRegOffAddress(g_baseRegister, src1->m_valueLow));
777 	CommitRefSymbolRegister(dst, dstReg);
778 }
779 
Emit_AddRef_VarVarVar(const STATEMENT & statement)780 void CCodeGen_x86_64::Emit_AddRef_VarVarVar(const STATEMENT& statement)
781 {
782 	auto dst = statement.dst->GetSymbol().get();
783 	auto src1 = statement.src1->GetSymbol().get();
784 	auto src2 = statement.src2->GetSymbol().get();
785 
786 	//TODO: Sign extend this, or we might get in trouble
787 	auto offsetReg = PrepareSymbolRegisterUse(src2, CX86Assembler::rCX);
788 	auto dstReg = PrepareRefSymbolRegisterDef(dst, CX86Assembler::rAX);
789 
790 	if(!dst->Equals(src1))
791 	{
792 		m_assembler.MovEq(dstReg, MakeVariableReferenceSymbolAddress(src1));
793 	}
794 
795 	m_assembler.AddEq(dstReg, CX86Assembler::MakeRegisterAddress(offsetReg));
796 	CommitRefSymbolRegister(dst, dstReg);
797 }
798 
Emit_AddRef_VarVarCst(const STATEMENT & statement)799 void CCodeGen_x86_64::Emit_AddRef_VarVarCst(const STATEMENT& statement)
800 {
801 	auto dst = statement.dst->GetSymbol().get();
802 	auto src1 = statement.src1->GetSymbol().get();
803 	auto src2 = statement.src2->GetSymbol().get();
804 
805 	assert(src2->m_type == SYM_CONSTANT);
806 
807 	auto dstReg = PrepareRefSymbolRegisterDef(dst, CX86Assembler::rAX);
808 
809 	if(!dst->Equals(src1))
810 	{
811 		m_assembler.MovEq(dstReg, MakeVariableReferenceSymbolAddress(src1));
812 	}
813 
814 	m_assembler.AddIq(CX86Assembler::MakeRegisterAddress(dstReg), src2->m_valueLow);
815 	CommitRefSymbolRegister(dst, dstReg);
816 }
817 
Emit_IsRefNull_VarVar(const STATEMENT & statement)818 void CCodeGen_x86_64::Emit_IsRefNull_VarVar(const STATEMENT& statement)
819 {
820 	auto dst = statement.dst->GetSymbol().get();
821 	auto src1 = statement.src1->GetSymbol().get();
822 
823 	auto addressReg = PrepareRefSymbolRegisterUse(src1, CX86Assembler::rAX);
824 	auto dstReg = PrepareSymbolRegisterDef(dst, CX86Assembler::rDX);
825 
826 	m_assembler.XorEd(dstReg, CX86Assembler::MakeRegisterAddress(dstReg));
827 	m_assembler.TestEq(addressReg, CX86Assembler::MakeRegisterAddress(addressReg));
828 	m_assembler.SeteEb(CX86Assembler::MakeRegisterAddress(dstReg));
829 
830 	CommitSymbolRegister(dst, dstReg);
831 }
832 
Emit_LoadFromRef_64_MemVar(const STATEMENT & statement)833 void CCodeGen_x86_64::Emit_LoadFromRef_64_MemVar(const STATEMENT& statement)
834 {
835 	auto dst = statement.dst->GetSymbol().get();
836 	auto src1 = statement.src1->GetSymbol().get();
837 
838 	auto addressReg = PrepareRefSymbolRegisterUse(src1, CX86Assembler::rAX);
839 	auto dstReg = CX86Assembler::rCX;
840 
841 	m_assembler.MovEq(dstReg, CX86Assembler::MakeIndRegAddress(addressReg));
842 	m_assembler.MovGq(MakeMemory64SymbolAddress(dst), dstReg);
843 }
844 
Emit_LoadFromRef_Ref_VarVar(const STATEMENT & statement)845 void CCodeGen_x86_64::Emit_LoadFromRef_Ref_VarVar(const STATEMENT& statement)
846 {
847 	auto dst = statement.dst->GetSymbol().get();
848 	auto src1 = statement.src1->GetSymbol().get();
849 
850 	auto addressReg = PrepareRefSymbolRegisterUse(src1, CX86Assembler::rAX);
851 	auto dstReg = PrepareRefSymbolRegisterDef(dst, CX86Assembler::rDX);
852 
853 	m_assembler.MovEq(dstReg, CX86Assembler::MakeIndRegAddress(addressReg));
854 
855 	CommitRefSymbolRegister(dst, dstReg);
856 }
857 
Emit_StoreAtRef_64_VarMem(const STATEMENT & statement)858 void CCodeGen_x86_64::Emit_StoreAtRef_64_VarMem(const STATEMENT& statement)
859 {
860 	auto src1 = statement.src1->GetSymbol().get();
861 	auto src2 = statement.src2->GetSymbol().get();
862 
863 	auto addressReg = PrepareRefSymbolRegisterUse(src1, CX86Assembler::rAX);
864 	auto valueReg = CX86Assembler::rDX;
865 
866 	m_assembler.MovEq(valueReg, MakeMemory64SymbolAddress(src2));
867 	m_assembler.MovGq(CX86Assembler::MakeIndRegAddress(addressReg), valueReg);
868 }
869 
Emit_StoreAtRef_64_VarCst(const STATEMENT & statement)870 void CCodeGen_x86_64::Emit_StoreAtRef_64_VarCst(const STATEMENT& statement)
871 {
872 	auto src1 = statement.src1->GetSymbol().get();
873 	auto src2 = statement.src2->GetSymbol().get();
874 
875 	auto addressReg = PrepareRefSymbolRegisterUse(src1, CX86Assembler::rAX);
876 	auto valueReg = CX86Assembler::rDX;
877 
878 	m_assembler.MovIq(valueReg, src2->GetConstant64());
879 	m_assembler.MovGq(CX86Assembler::MakeIndRegAddress(addressReg), valueReg);
880 }
881 
Emit_Store8AtRef_VarVar(const STATEMENT & statement)882 void CCodeGen_x86_64::Emit_Store8AtRef_VarVar(const STATEMENT& statement)
883 {
884 	auto src1 = statement.src1->GetSymbol().get();
885 	auto src2 = statement.src2->GetSymbol().get();
886 
887 	auto addressReg = PrepareRefSymbolRegisterUse(src1, CX86Assembler::rAX);
888 	auto valueReg = PrepareSymbolRegisterUse(src2, CX86Assembler::rDX);
889 	m_assembler.MovGb(CX86Assembler::MakeIndRegAddress(addressReg), valueReg);
890 }
891 
Emit_CondJmp_Ref_VarCst(const STATEMENT & statement)892 void CCodeGen_x86_64::Emit_CondJmp_Ref_VarCst(const STATEMENT& statement)
893 {
894 	auto src1 = statement.src1->GetSymbol().get();
895 	auto src2 = statement.src2->GetSymbol().get();
896 
897 	assert(src2->m_type == SYM_CONSTANT);
898 	assert(src2->m_valueLow == 0);
899 	assert((statement.jmpCondition == CONDITION_NE) || (statement.jmpCondition == CONDITION_EQ));
900 
901 	auto addressReg = PrepareRefSymbolRegisterUse(src1, CX86Assembler::rAX);
902 
903 	m_assembler.TestEq(addressReg, CX86Assembler::MakeRegisterAddress(addressReg));
904 
905 	CondJmp_JumpTo(GetLabel(statement.jmpBlock), statement.jmpCondition);
906 }
907 
PrepareRefSymbolRegisterDef(CSymbol * symbol,CX86Assembler::REGISTER preferedRegister)908 CX86Assembler::REGISTER CCodeGen_x86_64::PrepareRefSymbolRegisterDef(CSymbol* symbol, CX86Assembler::REGISTER preferedRegister)
909 {
910 	switch(symbol->m_type)
911 	{
912 	case SYM_REG_REFERENCE:
913 		return m_registers[symbol->m_valueLow];
914 		break;
915 	case SYM_TMP_REFERENCE:
916 	case SYM_REL_REFERENCE:
917 		return preferedRegister;
918 		break;
919 	default:
920 		throw std::runtime_error("Invalid symbol type.");
921 		break;
922 	}
923 }
924 
PrepareRefSymbolRegisterUse(CSymbol * symbol,CX86Assembler::REGISTER preferedRegister)925 CX86Assembler::REGISTER CCodeGen_x86_64::PrepareRefSymbolRegisterUse(CSymbol* symbol, CX86Assembler::REGISTER preferedRegister)
926 {
927 	switch(symbol->m_type)
928 	{
929 	case SYM_REG_REFERENCE:
930 		return m_registers[symbol->m_valueLow];
931 		break;
932 	case SYM_TMP_REFERENCE:
933 	case SYM_REL_REFERENCE:
934 		m_assembler.MovEq(preferedRegister, MakeMemoryReferenceSymbolAddress(symbol));
935 		return preferedRegister;
936 		break;
937 	default:
938 		throw std::runtime_error("Invalid symbol type.");
939 		break;
940 	}
941 }
942 
CommitRefSymbolRegister(CSymbol * symbol,CX86Assembler::REGISTER usedRegister)943 void CCodeGen_x86_64::CommitRefSymbolRegister(CSymbol* symbol, CX86Assembler::REGISTER usedRegister)
944 {
945 	switch(symbol->m_type)
946 	{
947 	case SYM_REG_REFERENCE:
948 		assert(usedRegister == m_registers[symbol->m_valueLow]);
949 		break;
950 	case SYM_TMP_REFERENCE:
951 	case SYM_REL_REFERENCE:
952 		m_assembler.MovGq(MakeMemoryReferenceSymbolAddress(symbol), usedRegister);
953 		break;
954 	default:
955 		throw std::runtime_error("Invalid symbol type.");
956 		break;
957 	}
958 }
959