VirtualBox

source: vbox/trunk/src/VBox/VMM/include/IEMN8veRecompiler.h@ 101399

Last change on this file since 101399 was 101387, checked in by vboxsync, 16 months ago

VMM/IEM: Added a new class of threaded function variants, the 16f/32f/64f variants that will clear RF (and vbox internal friends) and check for TF (and vbox internal friends). The variants w/o the 'f' after the bitcount will skip this test+branch. The motivation of this was to deal with this issue that the threaded recompiler level rather than try optimize away the test+branch++ code when generating native code, make the IEM_MC_ADVANCE_RIP_AND_FINISH_THREADED_PC32 a very simple place to start emitting native code (compared to IEM_MC_ADVANCE_RIP_AND_FINISH_THREADED_PC32_WITH_FLAGS). bugref:10371

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 27.5 KB
Line 
1/* $Id: IEMN8veRecompiler.h 101387 2023-10-07 23:34:54Z vboxsync $ */
2/** @file
3 * IEM - Interpreted Execution Manager - Native Recompiler Internals.
4 */
5
6/*
7 * Copyright (C) 2011-2023 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28#ifndef VMM_INCLUDED_SRC_include_IEMN8veRecompiler_h
29#define VMM_INCLUDED_SRC_include_IEMN8veRecompiler_h
30#ifndef RT_WITHOUT_PRAGMA_ONCE
31# pragma once
32#endif
33
34
35/** @defgroup grp_iem_n8ve_re Native Recompiler Internals.
36 * @ingroup grp_iem_int
37 * @{
38 */
39
40/** @name Stack Frame Layout
41 *
42 * @{ */
43/** The size of the area for stack variables and spills and stuff. */
44#define IEMNATIVE_FRAME_VAR_SIZE 0x40
45#ifdef RT_ARCH_AMD64
46/** Number of stack arguments slots for calls made from the frame. */
47# define IEMNATIVE_FRAME_STACK_ARG_COUNT 4
48/** An stack alignment adjustment (between non-volatile register pushes and
49 * the stack variable area, so the latter better aligned). */
50# define IEMNATIVE_FRAME_ALIGN_SIZE 8
51/** Number of any shadow arguments (spill area) for calls we make. */
52# ifdef RT_OS_WINDOWS
53# define IEMNATIVE_FRAME_SHADOW_ARG_COUNT 4
54# else
55# define IEMNATIVE_FRAME_SHADOW_ARG_COUNT 0
56# endif
57
58/** Frame pointer (RBP) relative offset of the last push. */
59# ifdef RT_OS_WINDOWS
60# define IEMNATIVE_FP_OFF_LAST_PUSH (7 * -8)
61# else
62# define IEMNATIVE_FP_OFF_LAST_PUSH (5 * -8)
63# endif
64/** Frame pointer (RBP) relative offset of the stack variable area (the lowest
65 * address for it). */
66# define IEMNATIVE_FP_OFF_STACK_VARS (IEMNATIVE_FP_OFF_LAST_PUSH - IEMNATIVE_FRAME_ALIGN_SIZE - IEMNATIVE_FRAME_VAR_SIZE)
67/** Frame pointer (RBP) relative offset of the first stack argument for calls. */
68# define IEMNATIVE_FP_OFF_STACK_ARG0 (IEMNATIVE_FP_OFF_STACK_VARS - IEMNATIVE_FRAME_STACK_ARG_COUNT * 8)
69/** Frame pointer (RBP) relative offset of the second stack argument for calls. */
70# define IEMNATIVE_FP_OFF_STACK_ARG1 (IEMNATIVE_FP_OFF_STACK_ARG0 + 8)
71/** Frame pointer (RBP) relative offset of the third stack argument for calls. */
72# define IEMNATIVE_FP_OFF_STACK_ARG2 (IEMNATIVE_FP_OFF_STACK_ARG0 + 16)
73/** Frame pointer (RBP) relative offset of the fourth stack argument for calls. */
74# define IEMNATIVE_FP_OFF_STACK_ARG3 (IEMNATIVE_FP_OFF_STACK_ARG0 + 24)
75
76# ifdef RT_OS_WINDOWS
77/** Frame pointer (RBP) relative offset of the first incoming shadow argument. */
78# define IEMNATIVE_FP_OFF_IN_SHADOW_ARG0 (16)
79/** Frame pointer (RBP) relative offset of the second incoming shadow argument. */
80# define IEMNATIVE_FP_OFF_IN_SHADOW_ARG1 (24)
81/** Frame pointer (RBP) relative offset of the third incoming shadow argument. */
82# define IEMNATIVE_FP_OFF_IN_SHADOW_ARG2 (32)
83/** Frame pointer (RBP) relative offset of the fourth incoming shadow argument. */
84# define IEMNATIVE_FP_OFF_IN_SHADOW_ARG3 (40)
85# endif
86
87#elif RT_ARCH_ARM64
88/** No stack argument slots, enough got 8 registers for arguments. */
89# define IEMNATIVE_FRAME_STACK_ARG_COUNT 0
90/** There are no argument spill area. */
91# define IEMNATIVE_FRAME_SHADOW_ARG_COUNT 0
92
93/** Number of saved registers at the top of our stack frame.
94 * This includes the return address and old frame pointer, so x19 thru x30. */
95# define IEMNATIVE_FRAME_SAVE_REG_COUNT (12)
96/** The size of the save registered (IEMNATIVE_FRAME_SAVE_REG_COUNT). */
97# define IEMNATIVE_FRAME_SAVE_REG_SIZE (IEMNATIVE_FRAME_SAVE_REG_COUNT * 8)
98
99/** Frame pointer (BP) relative offset of the last push. */
100# define IEMNATIVE_FP_OFF_LAST_PUSH (7 * -8)
101
102/** Frame pointer (BP) relative offset of the stack variable area (the lowest
103 * address for it). */
104# define IEMNATIVE_FP_OFF_STACK_VARS (IEMNATIVE_FP_OFF_LAST_PUSH - IEMNATIVE_FRAME_ALIGN_SIZE - IEMNATIVE_FRAME_VAR_SIZE)
105
106#else
107# error "port me"
108#endif
109/** @} */
110
111
112/** @name Fixed Register Allocation(s)
113 * @{ */
114/** @def IEMNATIVE_REG_FIXED_PVMCPU
115 * The register number hold in pVCpu pointer. */
116/** @def IEMNATIVE_REG_FIXED_TMP0
117 * Dedicated temporary register.
118 * @todo replace this by a register allocator and content tracker. */
119#ifdef RT_ARCH_AMD64
120# define IEMNATIVE_REG_FIXED_PVMCPU X86_GREG_xBX
121# define IEMNATIVE_REG_FIXED_TMP0 X86_GREG_x11
122
123#elif defined(RT_ARCH_ARM64)
124# define IEMNATIVE_REG_FIXED_PVMCPU ARMV8_A64_REG_X28
125# define IEMNATIVE_REG_FIXED_TMP0 ARMV8_A64_REG_X15
126
127#else
128# error "port me"
129#endif
130/** @} */
131
132/** @name Call related registers.
133 * @{ */
134/** @def IEMNATIVE_CALL_RET_GREG
135 * The return value register. */
136/** @def IEMNATIVE_CALL_ARG_GREG_COUNT
137 * Number of arguments in registers. */
138/** @def IEMNATIVE_CALL_ARG0_GREG
139 * The general purpose register carrying argument \#0. */
140/** @def IEMNATIVE_CALL_ARG1_GREG
141 * The general purpose register carrying argument \#1. */
142/** @def IEMNATIVE_CALL_ARG2_GREG
143 * The general purpose register carrying argument \#2. */
144/** @def IEMNATIVE_CALL_ARG3_GREG
145 * The general purpose register carrying argument \#3. */
146#ifdef RT_ARCH_AMD64
147# define IEMNATIVE_CALL_RET_GREG X86_GREG_xAX
148
149# ifdef RT_OS_WINDOWS
150# define IEMNATIVE_CALL_ARG_GREG_COUNT 4
151# define IEMNATIVE_CALL_ARG0_GREG X86_GREG_xCX
152# define IEMNATIVE_CALL_ARG1_GREG X86_GREG_xDX
153# define IEMNATIVE_CALL_ARG2_GREG X86_GREG_x8
154# define IEMNATIVE_CALL_ARG3_GREG X86_GREG_x9
155# else
156# define IEMNATIVE_CALL_ARG_GREG_COUNT 6
157# define IEMNATIVE_CALL_ARG0_GREG X86_GREG_xDI
158# define IEMNATIVE_CALL_ARG1_GREG X86_GREG_xSI
159# define IEMNATIVE_CALL_ARG2_GREG X86_GREG_xDX
160# define IEMNATIVE_CALL_ARG3_GREG X86_GREG_xCX
161# define IEMNATIVE_CALL_ARG4_GREG X86_GREG_x8
162# define IEMNATIVE_CALL_ARG5_GREG X86_GREG_x9
163# endif
164
165#elif defined(RT_ARCH_ARM64)
166# define IEMNATIVE_CALL_RET_GREG ARMV8_A64_REG_X0
167# define IEMNATIVE_CALL_ARG_GREG_COUNT 8
168# define IEMNATIVE_CALL_ARG0_GREG ARMV8_A64_REG_X0
169# define IEMNATIVE_CALL_ARG1_GREG ARMV8_A64_REG_X1
170# define IEMNATIVE_CALL_ARG2_GREG ARMV8_A64_REG_X2
171# define IEMNATIVE_CALL_ARG3_GREG ARMV8_A64_REG_X3
172# define IEMNATIVE_CALL_ARG4_GREG ARMV8_A64_REG_X4
173# define IEMNATIVE_CALL_ARG5_GREG ARMV8_A64_REG_X5
174# define IEMNATIVE_CALL_ARG6_GREG ARMV8_A64_REG_X6
175# define IEMNATIVE_CALL_ARG7_GREG ARMV8_A64_REG_X7
176
177#endif
178
179/** @} */
180
181/** Native code generator label types. */
182typedef enum
183{
184 kIemNativeLabelType_Invalid = 0,
185 kIemNativeLabelType_Return,
186 kIemNativeLabelType_NonZeroRetOrPassUp,
187 kIemNativeLabelType_End
188} IEMNATIVELABELTYPE;
189
190/** Native code generator label definition. */
191typedef struct IEMNATIVELABEL
192{
193 /** Code offset if defined, UINT32_MAX if it needs to be generated after/in
194 * the epilog. */
195 uint32_t off;
196 /** The type of label (IEMNATIVELABELTYPE). */
197 uint16_t enmType;
198 /** Additional label data, type specific. */
199 uint16_t uData;
200} IEMNATIVELABEL;
201/** Pointer to a label. */
202typedef IEMNATIVELABEL *PIEMNATIVELABEL;
203
204
205/** Native code generator fixup types. */
206typedef enum
207{
208 kIemNativeFixupType_Invalid = 0,
209#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)
210 /** AMD64 fixup: PC relative 32-bit with addend in bData. */
211 kIemNativeFixupType_Rel32,
212#elif defined(RT_ARCH_ARM64)
213 /** ARM64 fixup: PC relative offset at bits 23:5 (CBZ, CBNZ). */
214 kIemNativeFixupType_RelImm19At5,
215#endif
216 kIemNativeFixupType_End
217} IEMNATIVEFIXUPTYPE;
218
219/** Native code generator fixup. */
220typedef struct IEMNATIVEFIXUP
221{
222 /** Code offset of the fixup location. */
223 uint32_t off;
224 /** The IEMNATIVELABEL this is a fixup for. */
225 uint16_t idxLabel;
226 /** The fixup type (IEMNATIVEFIXUPTYPE). */
227 uint8_t enmType;
228 /** Addend or other data. */
229 int8_t offAddend;
230} IEMNATIVEFIXUP;
231/** Pointer to a native code generator fixup. */
232typedef IEMNATIVEFIXUP *PIEMNATIVEFIXUP;
233
234/**
235 * Native recompiler state.
236 */
237typedef struct IEMRECOMPILERSTATE
238{
239 /** Size of the buffer that pbNativeRecompileBufR3 points to in
240 * IEMNATIVEINSTR units. */
241 uint32_t cInstrBufAlloc;
242 uint32_t uPadding; /* We don't keep track of this here... */
243 /** Fixed temporary code buffer for native recompilation. */
244 PIEMNATIVEINSTR pInstrBuf;
245
246 /** Actual number of labels in paLabels. */
247 uint32_t cLabels;
248 /** Max number of entries allowed in paLabels before reallocating it. */
249 uint32_t cLabelsAlloc;
250 /** Labels defined while recompiling (referenced by fixups). */
251 PIEMNATIVELABEL paLabels;
252
253 /** Actual number of fixups paFixups. */
254 uint32_t cFixups;
255 /** Max number of entries allowed in paFixups before reallocating it. */
256 uint32_t cFixupsAlloc;
257 /** Buffer used by the recompiler for recording fixups when generating code. */
258 PIEMNATIVEFIXUP paFixups;
259
260 /** The translation block being recompiled. */
261 PCIEMTB pTbOrg;
262} IEMRECOMPILERSTATE;
263/** Pointer to a native recompiler state. */
264typedef IEMRECOMPILERSTATE *PIEMRECOMPILERSTATE;
265
266
267/**
268 * Native recompiler worker for a threaded function.
269 *
270 * @returns New code buffer offset, UINT32_MAX in case of failure.
271 * @param pReNative The native recompiler state.
272 * @param off The current code buffer offset.
273 * @param pCallEntry The threaded call entry.
274 *
275 * @note This is not allowed to throw anything atm.
276 */
277typedef DECLCALLBACKTYPE(uint32_t, FNIEMNATIVERECOMPFUNC,(PIEMRECOMPILERSTATE pReNative, uint32_t off,
278 PCIEMTHRDEDCALLENTRY pCallEntry));
279/** Pointer to a native recompiler worker for a threaded function. */
280typedef FNIEMNATIVERECOMPFUNC *PFNIEMNATIVERECOMPFUNC;
281
282/** Defines a native recompiler worker for a threaded function. */
283#define IEM_DECL_IEMNATIVERECOMPFUNC_DEF(a_Name) \
284 DECLCALLBACK(uint32_t) a_Name(PIEMRECOMPILERSTATE pReNative, uint32_t off, PCIEMTHRDEDCALLENTRY pCallEntry)
285/** Prototypes a native recompiler function for a threaded function. */
286#define IEM_DECL_IEMNATIVERECOMPFUNC_PROTO(a_Name) FNIEMNATIVERECOMPFUNC a_Name
287
288
289DECLHIDDEN(uint32_t) iemNativeMakeLabel(PIEMRECOMPILERSTATE pReNative, IEMNATIVELABELTYPE enmType,
290 uint32_t offWhere = UINT32_MAX, uint16_t uData = 0) RT_NOEXCEPT;
291DECLHIDDEN(bool) iemNativeAddFixup(PIEMRECOMPILERSTATE pReNative, uint32_t offWhere, uint32_t idxLabel,
292 IEMNATIVEFIXUPTYPE enmType, int8_t offAddend = 0) RT_NOEXCEPT;
293DECLHIDDEN(PIEMNATIVEINSTR) iemNativeInstrBufEnsureSlow(PIEMRECOMPILERSTATE pReNative, uint32_t off,
294 uint32_t cInstrReq) RT_NOEXCEPT;
295
296DECLHIDDEN(uint32_t) iemNativeEmitCheckCallRetAndPassUp(PIEMRECOMPILERSTATE pReNative, uint32_t off,
297 uint8_t idxInstr) RT_NOEXCEPT;
298
299
300/**
301 * Ensures that there is sufficient space in the instruction output buffer.
302 *
303 * This will reallocate the buffer if needed and allowed.
304 *
305 * @returns Pointer to the instruction output buffer on success, NULL on
306 * failure.
307 * @param pReNative The native recompile state.
308 * @param off Current instruction offset. Works safely for UINT32_MAX
309 * as well.
310 * @param cInstrReq Number of instruction about to be added. It's okay to
311 * overestimate this a bit.
312 */
313DECL_FORCE_INLINE(PIEMNATIVEINSTR) iemNativeInstrBufEnsure(PIEMRECOMPILERSTATE pReNative, uint32_t off, uint32_t cInstrReq)
314{
315 if (RT_LIKELY(off + (uint64_t)cInstrReq <= pReNative->cInstrBufAlloc))
316 return pReNative->pInstrBuf;
317 return iemNativeInstrBufEnsureSlow(pReNative, off, cInstrReq);
318}
319
320
321/**
322 * Emit a simple marker instruction to more easily tell where something starts
323 * in the disassembly.
324 */
325DECLINLINE(uint32_t) iemNativeEmitMarker(PIEMRECOMPILERSTATE pReNative, uint32_t off)
326{
327#ifdef RT_ARCH_AMD64
328 uint8_t *pbCodeBuf = iemNativeInstrBufEnsure(pReNative, off, 1);
329 AssertReturn(pbCodeBuf, UINT32_MAX);
330 /* nop */
331 pbCodeBuf[off++] = 0x90;
332
333#elif RT_ARCH_ARM64
334 uint32_t *pu32CodeBuf = iemNativeInstrBufEnsure(pReNative, off, 1);
335 AssertReturn(pu32CodeBuf, UINT32_MAX);
336 /* nop */
337 pu32CodeBuf[off++] = 0xd503201f;
338
339#else
340# error "port me"
341#endif
342 return off;
343}
344
345
346/**
347 * Emits setting a GPR to zero.
348 */
349DECLINLINE(uint32_t) iemNativeEmitGprZero(PIEMRECOMPILERSTATE pReNative, uint32_t off, uint8_t iGpr)
350{
351#ifdef RT_ARCH_AMD64
352 uint8_t *pbCodeBuf = iemNativeInstrBufEnsure(pReNative, off, 3);
353 AssertReturn(pbCodeBuf, UINT32_MAX);
354 /* xor gpr32, gpr32 */
355 if (iGpr >= 8)
356 pbCodeBuf[off++] = X86_OP_REX_R | X86_OP_REX_B;
357 pbCodeBuf[off++] = 0x33;
358 pbCodeBuf[off++] = X86_MODRM_MAKE(X86_MOD_REG, iGpr & 7, iGpr & 7);
359
360#elif RT_ARCH_ARM64
361 uint32_t *pu32CodeBuf = iemNativeInstrBufEnsure(pReNative, off, 1);
362 AssertReturn(pu32CodeBuf, UINT32_MAX);
363 /* mov gpr, #0x0 */
364 pu32CodeBuf[off++] = UINT32_C(0xd2800000) | iGpr;
365
366#else
367# error "port me"
368#endif
369 RT_NOREF(pReNative);
370 return off;
371}
372
373
374/**
375 * Emits loading a constant into a 64-bit GPR
376 */
377DECLINLINE(uint32_t) iemNativeEmitLoadGprImm64(PIEMRECOMPILERSTATE pReNative, uint32_t off, uint8_t iGpr, uint64_t uImm64)
378{
379 if (!uImm64)
380 return iemNativeEmitGprZero(pReNative, off, iGpr);
381
382#ifdef RT_ARCH_AMD64
383 if (uImm64 <= UINT32_MAX)
384 {
385 /* mov gpr, imm32 */
386 uint8_t *pbCodeBuf = iemNativeInstrBufEnsure(pReNative, off, 6);
387 AssertReturn(pbCodeBuf, UINT32_MAX);
388 if (iGpr >= 8)
389 pbCodeBuf[off++] = X86_OP_REX_B;
390 pbCodeBuf[off++] = 0xb8 + (iGpr & 7);
391 pbCodeBuf[off++] = RT_BYTE1(uImm64);
392 pbCodeBuf[off++] = RT_BYTE2(uImm64);
393 pbCodeBuf[off++] = RT_BYTE3(uImm64);
394 pbCodeBuf[off++] = RT_BYTE4(uImm64);
395 }
396 else
397 {
398 /* mov gpr, imm64 */
399 uint8_t *pbCodeBuf = iemNativeInstrBufEnsure(pReNative, off, 10);
400 AssertReturn(pbCodeBuf, UINT32_MAX);
401 if (iGpr < 8)
402 pbCodeBuf[off++] = X86_OP_REX_W;
403 else
404 pbCodeBuf[off++] = X86_OP_REX_W | X86_OP_REX_B;
405 pbCodeBuf[off++] = 0xb8 + (iGpr & 7);
406 pbCodeBuf[off++] = RT_BYTE1(uImm64);
407 pbCodeBuf[off++] = RT_BYTE2(uImm64);
408 pbCodeBuf[off++] = RT_BYTE3(uImm64);
409 pbCodeBuf[off++] = RT_BYTE4(uImm64);
410 pbCodeBuf[off++] = RT_BYTE5(uImm64);
411 pbCodeBuf[off++] = RT_BYTE6(uImm64);
412 pbCodeBuf[off++] = RT_BYTE7(uImm64);
413 pbCodeBuf[off++] = RT_BYTE8(uImm64);
414 }
415
416#elif RT_ARCH_ARM64
417 uint32_t *pu32CodeBuf = iemNativeInstrBufEnsure(pReNative, off, 4);
418 AssertReturn(pu32CodeBuf, UINT32_MAX);
419
420 /*
421 * We need to start this sequence with a 'mov grp, imm16, lsl #x' and
422 * supply remaining bits using 'movk grp, imm16, lsl #x'.
423 *
424 * The mov instruction is encoded 0xd2800000 + shift + imm16 + grp,
425 * while the movk is 0xf2800000 + shift + imm16 + grp, meaning the diff
426 * is 0x20000000 (bit 29). So, we keep this bit in a variable and set it
427 * after the first non-zero immediate component so we switch to movk for
428 * the remainder.
429 */
430 uint32_t fMovK = 0;
431 /* mov gpr, imm16 */
432 uint32_t uImmPart = ((uint32_t)((uImm64 >> 0) & UINT32_C(0xffff)) << 5);
433 if (uImmPart)
434 {
435 pu32CodeBuf[off++] = UINT32_C(0xd2800000) | (UINT32_C(0) << 21) | uImmPart | iGpr;
436 fMovK |= RT_BIT_32(29);
437 }
438 /* mov[k] gpr, imm16, lsl #16 */
439 uImmPart = ((uint32_t)((uImm64 >> 16) & UINT32_C(0xffff)) << 5);
440 if (uImmPart)
441 {
442 pu32CodeBuf[off++] = UINT32_C(0xd2800000) | fMovK | (UINT32_C(1) << 21) | uImmPart | iGpr;
443 fMovK |= RT_BIT_32(29);
444 }
445 /* mov[k] gpr, imm16, lsl #32 */
446 uImmPart = ((uint32_t)((uImm64 >> 32) & UINT32_C(0xffff)) << 5);
447 if (uImmPart)
448 {
449 pu32CodeBuf[off++] = UINT32_C(0xd2800000) | fMovK | (UINT32_C(2) << 21) | uImmPart | iGpr;
450 fMovK |= RT_BIT_32(29);
451 }
452 /* mov[k] gpr, imm16, lsl #48 */
453 uImmPart = ((uint32_t)((uImm64 >> 48) & UINT32_C(0xffff)) << 5);
454 if (uImmPart)
455 pu32CodeBuf[off++] = UINT32_C(0xd2800000) | fMovK | (UINT32_C(3) << 21) | uImmPart | iGpr;
456
457 /** @todo there is an inverted mask variant we might want to explore if it
458 * reduces the number of instructions... */
459 /** @todo load into 'w' register instead of 'x' when imm64 <= UINT32_MAX?
460 * clang 12.x does that, only to use the 'x' version for the
461 * addressing in the following ldr). */
462
463#else
464# error "port me"
465#endif
466 return off;
467}
468
469
470/**
471 * Emits a 32-bit GPR load of a VCpu value.
472 */
473DECLINLINE(uint32_t) iemNativeEmitLoadGprFromVCpuU32(PIEMRECOMPILERSTATE pReNative, uint32_t off, uint8_t iGpr, uint32_t offVCpu)
474{
475#ifdef RT_ARCH_AMD64
476 uint8_t *pbCodeBuf = iemNativeInstrBufEnsure(pReNative, off, 7);
477 AssertReturn(pbCodeBuf, UINT32_MAX);
478
479 /* mov reg32, mem32 */
480 if (iGpr >= 8)
481 pbCodeBuf[off++] = X86_OP_REX_R;
482 pbCodeBuf[off++] = 0x8b;
483 if (offVCpu < 128)
484 {
485 pbCodeBuf[off++] = X86_MODRM_MAKE(X86_MOD_MEM1, iGpr & 7, IEMNATIVE_REG_FIXED_PVMCPU);
486 pbCodeBuf[off++] = (uint8_t)offVCpu;
487 }
488 else
489 {
490 pbCodeBuf[off++] = X86_MODRM_MAKE(X86_MOD_MEM4, iGpr & 7, IEMNATIVE_REG_FIXED_PVMCPU);
491 pbCodeBuf[off++] = RT_BYTE1(offVCpu);
492 pbCodeBuf[off++] = RT_BYTE2(offVCpu);
493 pbCodeBuf[off++] = RT_BYTE3(offVCpu);
494 pbCodeBuf[off++] = RT_BYTE4(offVCpu);
495 }
496
497#elif RT_ARCH_ARM64
498 /*
499 * There are a couple of ldr variants that takes an immediate offset, so
500 * try use those if we can, otherwise we have to use the temporary register
501 * help with the addressing.
502 */
503 if (offVCpu < _16K)
504 {
505 /* Use the unsigned variant of ldr Wt, [<Xn|SP>, #off]. */
506 uint32_t *pu32CodeBuf = iemNativeInstrBufEnsure(pReNative, off, 1);
507 AssertReturn(pu32CodeBuf, UINT32_MAX);
508 pu32CodeBuf[off++] = UINT32_C(0xb9400000) | (offVCpu << 10) | (IEMNATIVE_REG_FIXED_PVMCPU << 5) | iGpr;
509 }
510 else
511 {
512 /* The offset is too large, so we must load it into a register and use
513 ldr Wt, [<Xn|SP>, (<Wm>|<Xm>). */
514 /** @todo reduce by offVCpu by >> 3 or >> 2? if it saves instructions? */
515 off = iemNativeEmitLoadGprImm64(pReNative, off, IEMNATIVE_REG_FIXED_TMP0, offVCpu);
516 uint32_t *pu32CodeBuf = iemNativeInstrBufEnsure(pReNative, off, 1);
517 AssertReturn(pu32CodeBuf, UINT32_MAX);
518 pu32CodeBuf[off++] = UINT32_C(0xb8600800) | ((uint32_t)IEMNATIVE_REG_FIXED_TMP0 << 16)
519 | ((uint32_t)IEMNATIVE_REG_FIXED_PVMCPU << 5) | iGpr;
520 }
521
522#else
523# error "port me"
524#endif
525 return off;
526}
527
528
529/**
530 * Emits a gprdst = gprsrc load.
531 */
532DECLINLINE(uint32_t) iemNativeEmitLoadGprFromGpr(PIEMRECOMPILERSTATE pReNative, uint32_t off, uint8_t iGprDst, uint8_t iGprSrc)
533{
534#ifdef RT_ARCH_AMD64
535 /* mov gprdst, gprsrc */
536 uint8_t *pbCodeBuf = iemNativeInstrBufEnsure(pReNative, off, 3);
537 AssertReturn(pbCodeBuf, UINT32_MAX);
538 if ((iGprDst | iGprSrc) >= 8)
539 pbCodeBuf[off++] = iGprDst < 8 ? X86_OP_REX_W | X86_OP_REX_B
540 : iGprSrc >= 8 ? X86_OP_REX_W | X86_OP_REX_R | X86_OP_REX_B
541 : X86_OP_REX_W | X86_OP_REX_R;
542 else
543 pbCodeBuf[off++] = X86_OP_REX_W;
544 pbCodeBuf[off++] = 0x8b;
545 pbCodeBuf[off++] = X86_MODRM_MAKE(X86_MOD_REG, iGprDst & 7, iGprSrc & 7);
546
547#elif RT_ARCH_ARM64
548 uint32_t *pu32CodeBuf = iemNativeInstrBufEnsure(pReNative, off, 1);
549 AssertReturn(pu32CodeBuf, UINT32_MAX);
550 /* mov dst, src; alias for: orr dst, xzr, src */
551 pu32CodeBuf[off++] = UINT32_C(0xaa000000) | ((uint32_t)iGprSrc << 16) | ((uint32_t)ARMV8_A64_REG_XZR << 5) | iGprDst;
552
553#else
554# error "port me"
555#endif
556 return off;
557}
558
559#ifdef RT_ARCH_AMD64
560/**
561 * Common bit of iemNativeEmitLoadGprByBp and friends.
562 */
563DECL_FORCE_INLINE(uint32_t) iemNativeEmitGprByBpDisp(uint8_t *pbCodeBuf, uint32_t off, uint8_t iGprReg, int32_t offDisp)
564{
565 if (offDisp < 128 && offDisp >= -128)
566 {
567 pbCodeBuf[off++] = X86_MODRM_MAKE(X86_MOD_MEM1, iGprReg & 7, X86_GREG_xBP);
568 pbCodeBuf[off++] = (uint8_t)(int8_t)offDisp;
569 }
570 else
571 {
572 pbCodeBuf[off++] = X86_MODRM_MAKE(X86_MOD_MEM4, iGprReg & 7, X86_GREG_xBP);
573 pbCodeBuf[off++] = RT_BYTE1((uint32_t)offDisp);
574 pbCodeBuf[off++] = RT_BYTE2((uint32_t)offDisp);
575 pbCodeBuf[off++] = RT_BYTE3((uint32_t)offDisp);
576 pbCodeBuf[off++] = RT_BYTE4((uint32_t)offDisp);
577 }
578 return off;
579}
580#endif
581
582
583#ifdef RT_ARCH_AMD64
584/**
585 * Emits a 64-bit GRP load instruction with an BP relative source address.
586 */
587DECLINLINE(uint32_t) iemNativeEmitLoadGprByBp(PIEMRECOMPILERSTATE pReNative, uint32_t off, uint8_t iGprDst, int32_t offDisp)
588{
589 /* mov gprdst, qword [rbp + offDisp] */
590 uint8_t *pbCodeBuf = iemNativeInstrBufEnsure(pReNative, off, 7);
591 AssertReturn(pbCodeBuf, UINT32_MAX);
592 if (iGprDst < 8)
593 pbCodeBuf[off++] = X86_OP_REX_W;
594 else
595 pbCodeBuf[off++] = X86_OP_REX_W | X86_OP_REX_R;
596 pbCodeBuf[off++] = 0x8b;
597 return iemNativeEmitGprByBpDisp(pbCodeBuf, off, iGprDst, offDisp);
598}
599#endif
600
601
602#ifdef RT_ARCH_AMD64
603/**
604 * Emits a 32-bit GRP load instruction with an BP relative source address.
605 */
606DECLINLINE(uint32_t) iemNativeEmitLoadGprByBpU32(PIEMRECOMPILERSTATE pReNative, uint32_t off, uint8_t iGprDst, int32_t offDisp)
607{
608 /* mov gprdst, dword [rbp + offDisp] */
609 uint8_t *pbCodeBuf = iemNativeInstrBufEnsure(pReNative, off, 7);
610 AssertReturn(pbCodeBuf, UINT32_MAX);
611 if (iGprDst >= 8)
612 pbCodeBuf[off++] = X86_OP_REX_R;
613 pbCodeBuf[off++] = 0x8b;
614 return iemNativeEmitGprByBpDisp(pbCodeBuf, off, iGprDst, offDisp);
615}
616#endif
617
618
619#ifdef RT_ARCH_AMD64
620/**
621 * Emits a load effective address to a GRP with an BP relative source address.
622 */
623DECLINLINE(uint32_t) iemNativeEmitLeaGrpByBp(PIEMRECOMPILERSTATE pReNative, uint32_t off, uint8_t iGprDst, int32_t offDisp)
624{
625 /* lea gprdst, [rbp + offDisp] */
626 uint8_t *pbCodeBuf = iemNativeInstrBufEnsure(pReNative, off, 7);
627 AssertReturn(pbCodeBuf, UINT32_MAX);
628 if (iGprDst < 8)
629 pbCodeBuf[off++] = X86_OP_REX_W;
630 else
631 pbCodeBuf[off++] = X86_OP_REX_W | X86_OP_REX_R;
632 pbCodeBuf[off++] = 0x8d;
633 return iemNativeEmitGprByBpDisp(pbCodeBuf, off, iGprDst, offDisp);
634}
635#endif
636
637
638/**
639 * Emits a 64-bit GPR store with an BP relative destination address.
640 *
641 * @note May trash IEMNATIVE_REG_FIXED_TMP0.
642 */
643DECLINLINE(uint32_t) iemNativeEmitStoreGprByBp(PIEMRECOMPILERSTATE pReNative, uint32_t off, int32_t offDisp, uint8_t iGprSrc)
644{
645#ifdef RT_ARCH_AMD64
646 /* mov qword [rbp + offDisp], gprdst */
647 uint8_t *pbCodeBuf = iemNativeInstrBufEnsure(pReNative, off, 7);
648 AssertReturn(pbCodeBuf, UINT32_MAX);
649 if (iGprSrc < 8)
650 pbCodeBuf[off++] = X86_OP_REX_W;
651 else
652 pbCodeBuf[off++] = X86_OP_REX_W | X86_OP_REX_R;
653 pbCodeBuf[off++] = 0x89;
654 return iemNativeEmitGprByBpDisp(pbCodeBuf, off, iGprSrc, offDisp);
655
656#elif defined(RT_ARCH_ARM64)
657 if (offDisp >= 0 && offDisp < 4096 * 8 && !((uint32_t)offDisp & 7))
658 {
659 /* str w/ unsigned imm12 (scaled) */
660 uint32_t *pu32CodeBuf = iemNativeInstrBufEnsure(pReNative, off, 1);
661 AssertReturn(pu32CodeBuf, UINT32_MAX);
662 pu32CodeBuf[off++] = Armv8A64MkInstrStLdRUOff(kArmv8A64InstrLdStType_St_Dword, iGprSrc,
663 ARMV8_A64_REG_BP, (uint32_t)offDisp / 8);
664 }
665 else if (offDisp >= -256 && offDisp <= 256)
666 {
667 /* stur w/ signed imm9 (unscaled) */
668 uint32_t *pu32CodeBuf = iemNativeInstrBufEnsure(pReNative, off, 1);
669 AssertReturn(pu32CodeBuf, UINT32_MAX);
670 pu32CodeBuf[off++] = Armv8A64MkInstrSturLdur(kArmv8A64InstrLdStType_St_Dword, iGprSrc, ARMV8_A64_REG_BP, offDisp);
671 }
672 else
673 {
674 /* Use temporary indexing register. */
675 off = iemNativeEmitLoadGprImm64(pReNative, off, IEMNATIVE_REG_FIXED_TMP0, (uint32_t)offDisp);
676 uint32_t *pu32CodeBuf = iemNativeInstrBufEnsure(pReNative, off, 1);
677 AssertReturn(pu32CodeBuf, UINT32_MAX);
678 pu32CodeBuf[off++] = Armv8A64MkInstrStLdRegIdx(kArmv8A64InstrLdStType_St_Dword, iGprSrc, ARMV8_A64_REG_BP,
679 IEMNATIVE_REG_FIXED_TMP0, kArmv8A64InstrLdStExtend_Sxtw);
680 }
681 return off;
682
683#else
684# error "Port me!"
685#endif
686}
687
688
689/**
690 * Emits a 64-bit immediate store with an BP relative destination address.
691 *
692 * @note May trash IEMNATIVE_REG_FIXED_TMP0.
693 */
694DECLINLINE(uint32_t) iemNativeEmitStoreImm64ByBp(PIEMRECOMPILERSTATE pReNative, uint32_t off, int32_t offDisp, uint64_t uImm64)
695{
696#ifdef RT_ARCH_AMD64
697 if ((int64_t)uImm64 == (int32_t)uImm64)
698 {
699 /* mov qword [rbp + offDisp], imm32 - sign extended */
700 uint8_t *pbCodeBuf = iemNativeInstrBufEnsure(pReNative, off, 11);
701 AssertReturn(pbCodeBuf, UINT32_MAX);
702
703 pbCodeBuf[off++] = X86_OP_REX_W;
704 pbCodeBuf[off++] = 0xc7;
705 if (offDisp < 128 && offDisp >= -128)
706 {
707 pbCodeBuf[off++] = X86_MODRM_MAKE(X86_MOD_MEM1, 0, X86_GREG_xBP);
708 pbCodeBuf[off++] = (uint8_t)offDisp;
709 }
710 else
711 {
712 pbCodeBuf[off++] = X86_MODRM_MAKE(X86_MOD_MEM4, 0, X86_GREG_xBP);
713 pbCodeBuf[off++] = RT_BYTE1((uint32_t)offDisp);
714 pbCodeBuf[off++] = RT_BYTE2((uint32_t)offDisp);
715 pbCodeBuf[off++] = RT_BYTE3((uint32_t)offDisp);
716 pbCodeBuf[off++] = RT_BYTE4((uint32_t)offDisp);
717 }
718 pbCodeBuf[off++] = RT_BYTE1(uImm64);
719 pbCodeBuf[off++] = RT_BYTE2(uImm64);
720 pbCodeBuf[off++] = RT_BYTE3(uImm64);
721 pbCodeBuf[off++] = RT_BYTE4(uImm64);
722 return off;
723 }
724#endif
725
726 /* Load tmp0, imm64; Store tmp to bp+disp. */
727 off = iemNativeEmitLoadGprImm64(pReNative, off, IEMNATIVE_REG_FIXED_TMP0, uImm64);
728 return iemNativeEmitStoreGprByBp(pReNative, off, offDisp, IEMNATIVE_REG_FIXED_TMP0);
729}
730
731
732#ifdef RT_ARCH_AMD64
733/**
734 * Emits a 64-bit GPR subtract with a signed immediate subtrahend.
735 */
736DECLINLINE(uint32_t) iemNativeEmitSubGprImm(PIEMRECOMPILERSTATE pReNative, uint32_t off, uint8_t iGprDst, int32_t iSubtrahend)
737{
738 /* sub gprdst, imm8/imm32 */
739 uint8_t *pbCodeBuf = iemNativeInstrBufEnsure(pReNative, off, 7);
740 AssertReturn(pbCodeBuf, UINT32_MAX);
741 if (iGprDst < 7)
742 pbCodeBuf[off++] = X86_OP_REX_W;
743 else
744 pbCodeBuf[off++] = X86_OP_REX_W | X86_OP_REX_B;
745 if (iSubtrahend < 128 && iSubtrahend >= -128)
746 {
747 pbCodeBuf[off++] = 0x83;
748 pbCodeBuf[off++] = X86_MODRM_MAKE(X86_MOD_REG, 5, iGprDst & 7);
749 pbCodeBuf[off++] = (uint8_t)iSubtrahend;
750 }
751 else
752 {
753 pbCodeBuf[off++] = 0x81;
754 pbCodeBuf[off++] = X86_MODRM_MAKE(X86_MOD_REG, 5, iGprDst & 7);
755 pbCodeBuf[off++] = RT_BYTE1(iSubtrahend);
756 pbCodeBuf[off++] = RT_BYTE2(iSubtrahend);
757 pbCodeBuf[off++] = RT_BYTE3(iSubtrahend);
758 pbCodeBuf[off++] = RT_BYTE4(iSubtrahend);
759 }
760 return off;
761}
762#endif
763
764/** @} */
765
766#endif /* !VMM_INCLUDED_SRC_include_IEMN8veRecompiler_h */
767
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette