VirtualBox

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

Last change on this file since 101247 was 101247, checked in by vboxsync, 19 months ago

VMM/IEM: Working on emitting native arm64 instructions... bugref:10370

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 21.1 KB
Line 
1/* $Id: IEMN8veRecompiler.h 101247 2023-09-22 23:48:24Z 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#ifdef RT_ARCH_AMD64
117# define IEMNATIVE_REG_FIXED_PVMCPU X86_GREG_xBX
118#elif RT_ARCH_ARM64
119# define IEMNATIVE_REG_FIXED_PVMCPU ARMV8_A64_REG_X28
120/** Dedicated temporary register.
121 * @todo replace this by a register allocator and content tracker. */
122# define IEMNATIVE_REG_FIXED_TMP0 ARMV8_A64_REG_X15
123#else
124# error "port me"
125#endif
126/** @} */
127
128/** Native code generator label types. */
129typedef enum
130{
131 kIemNativeLabelType_Invalid = 0,
132 kIemNativeLabelType_Return,
133 kIemNativeLabelType_NonZeroRetOrPassUp,
134 kIemNativeLabelType_End
135} IEMNATIVELABELTYPE;
136
137/** Native code generator label definition. */
138typedef struct IEMNATIVELABEL
139{
140 /** Code offset if defined, UINT32_MAX if it needs to be generated after/in
141 * the epilog. */
142 uint32_t off;
143 /** The type of label (IEMNATIVELABELTYPE). */
144 uint16_t enmType;
145 /** Additional label data, type specific. */
146 uint16_t uData;
147} IEMNATIVELABEL;
148/** Pointer to a label. */
149typedef IEMNATIVELABEL *PIEMNATIVELABEL;
150
151
152/** Native code generator fixup types. */
153typedef enum
154{
155 kIemNativeFixupType_Invalid = 0,
156#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)
157 /** AMD64 fixup: PC relative 32-bit with addend in bData. */
158 kIemNativeFixupType_Rel32,
159#elif defined(RT_ARCH_ARM64)
160#endif
161 kIemNativeFixupType_End
162} IEMNATIVEFIXUPTYPE;
163
164/** Native code generator fixup. */
165typedef struct IEMNATIVEFIXUP
166{
167 /** Code offset of the fixup location. */
168 uint32_t off;
169 /** The IEMNATIVELABEL this is a fixup for. */
170 uint16_t idxLabel;
171 /** The fixup type (IEMNATIVEFIXUPTYPE). */
172 uint8_t enmType;
173 /** Addend or other data. */
174 int8_t offAddend;
175} IEMNATIVEFIXUP;
176/** Pointer to a native code generator fixup. */
177typedef IEMNATIVEFIXUP *PIEMNATIVEFIXUP;
178
179/**
180 * Native recompiler state.
181 */
182typedef struct IEMRECOMPILERSTATE
183{
184 /** Size of the buffer that pbNativeRecompileBufR3 points to in
185 * IEMNATIVEINSTR units. */
186 uint32_t cInstrBufAlloc;
187 uint32_t uPadding; /* We don't keep track of this here... */
188 /** Fixed temporary code buffer for native recompilation. */
189 PIEMNATIVEINSTR pInstrBuf;
190
191 /** Actual number of labels in paLabels. */
192 uint32_t cLabels;
193 /** Max number of entries allowed in paLabels before reallocating it. */
194 uint32_t cLabelsAlloc;
195 /** Labels defined while recompiling (referenced by fixups). */
196 PIEMNATIVELABEL paLabels;
197
198 /** Actual number of fixups paFixups. */
199 uint32_t cFixups;
200 /** Max number of entries allowed in paFixups before reallocating it. */
201 uint32_t cFixupsAlloc;
202 /** Buffer used by the recompiler for recording fixups when generating code. */
203 PIEMNATIVEFIXUP paFixups;
204} IEMRECOMPILERSTATE;
205/** Pointer to a native recompiler state. */
206typedef IEMRECOMPILERSTATE *PIEMRECOMPILERSTATE;
207
208
209
210DECLHIDDEN(uint32_t) iemNativeMakeLabel(PIEMRECOMPILERSTATE pReNative, IEMNATIVELABELTYPE enmType,
211 uint32_t offWhere = UINT32_MAX, uint16_t uData = 0) RT_NOEXCEPT;
212DECLHIDDEN(bool) iemNativeAddFixup(PIEMRECOMPILERSTATE pReNative, uint32_t offWhere, uint32_t idxLabel,
213 IEMNATIVEFIXUPTYPE enmType, int8_t offAddend = 0) RT_NOEXCEPT;
214DECLHIDDEN(PIEMNATIVEINSTR) iemNativeInstrBufEnsureSlow(PIEMRECOMPILERSTATE pReNative, uint32_t off,
215 uint32_t cInstrReq) RT_NOEXCEPT;
216
217DECLHIDDEN(uint32_t) iemNativeEmitCheckCallRetAndPassUp(PIEMRECOMPILERSTATE pReNative, uint32_t off,
218 uint8_t idxInstr) RT_NOEXCEPT;
219
220
221/**
222 * Ensures that there is sufficient space in the instruction output buffer.
223 *
224 * This will reallocate the buffer if needed and allowed.
225 *
226 * @returns Pointer to the instruction output buffer on success, NULL on
227 * failure.
228 * @param pReNative The native recompile state.
229 * @param off Current instruction offset. Works safely for UINT32_MAX
230 * as well.
231 * @param cInstrReq Number of instruction about to be added. It's okay to
232 * overestimate this a bit.
233 */
234DECL_FORCE_INLINE(PIEMNATIVEINSTR) iemNativeInstrBufEnsure(PIEMRECOMPILERSTATE pReNative, uint32_t off, uint32_t cInstrReq)
235{
236 if (RT_LIKELY(off + (uint64_t)cInstrReq <= pReNative->cInstrBufAlloc))
237 return pReNative->pInstrBuf;
238 return iemNativeInstrBufEnsureSlow(pReNative, off, cInstrReq);
239}
240
241
242/**
243 * Emit a simple marker instruction to more easily tell where something starts
244 * in the disassembly.
245 */
246DECLINLINE(uint32_t) iemNativeEmitMarker(PIEMRECOMPILERSTATE pReNative, uint32_t off)
247{
248#ifdef RT_ARCH_AMD64
249 uint8_t *pbCodeBuf = iemNativeInstrBufEnsure(pReNative, off, 1);
250 AssertReturn(pbCodeBuf, UINT32_MAX);
251 /* nop */
252 pbCodeBuf[off++] = 0x90;
253
254#elif RT_ARCH_ARM64
255 uint32_t *pu32CodeBuf = iemNativeInstrBufEnsure(pReNative, off, 1);
256 AssertReturn(pu32CodeBuf, UINT32_MAX);
257 /* nop */
258 pu32CodeBuf[off++] = 0xd503201f;
259
260#else
261# error "port me"
262#endif
263 return off;
264}
265
266
267/**
268 * Emits setting a GPR to zero.
269 */
270DECLINLINE(uint32_t) iemNativeEmitGprZero(PIEMRECOMPILERSTATE pReNative, uint32_t off, uint8_t iGpr)
271{
272#ifdef RT_ARCH_AMD64
273 uint8_t *pbCodeBuf = iemNativeInstrBufEnsure(pReNative, off, 3);
274 AssertReturn(pbCodeBuf, UINT32_MAX);
275 /* xor gpr32, gpr32 */
276 if (iGpr >= 8)
277 pbCodeBuf[off++] = X86_OP_REX_R | X86_OP_REX_B;
278 pbCodeBuf[off++] = 0x33;
279 pbCodeBuf[off++] = X86_MODRM_MAKE(X86_MOD_REG, iGpr & 7, iGpr & 7);
280
281#elif RT_ARCH_ARM64
282 uint32_t *pu32CodeBuf = iemNativeInstrBufEnsure(pReNative, off, 1);
283 AssertReturn(pu32CodeBuf, UINT32_MAX);
284 /* mov gpr, #0x0 */
285 pu32CodeBuf[off++] = UINT32_C(0xd2800000) | iGpr;
286
287#else
288# error "port me"
289#endif
290 RT_NOREF(pReNative);
291 return off;
292}
293
294
295/**
296 * Emits loading a constant into a 64-bit GPR
297 */
298DECLINLINE(uint32_t) iemNativeEmitLoadGprImm64(PIEMRECOMPILERSTATE pReNative, uint32_t off, uint8_t iGpr, uint64_t uImm64)
299{
300 if (!uImm64)
301 return iemNativeEmitGprZero(pReNative, off, iGpr);
302
303#ifdef RT_ARCH_AMD64
304 if (uImm64 <= UINT32_MAX)
305 {
306 /* mov gpr, imm32 */
307 uint8_t *pbCodeBuf = iemNativeInstrBufEnsure(pReNative, off, 6);
308 AssertReturn(pbCodeBuf, UINT32_MAX);
309 if (iGpr >= 8)
310 pbCodeBuf[off++] = X86_OP_REX_B;
311 pbCodeBuf[off++] = 0xb8 + (iGpr & 7);
312 pbCodeBuf[off++] = RT_BYTE1(uImm64);
313 pbCodeBuf[off++] = RT_BYTE2(uImm64);
314 pbCodeBuf[off++] = RT_BYTE3(uImm64);
315 pbCodeBuf[off++] = RT_BYTE4(uImm64);
316 }
317 else
318 {
319 /* mov gpr, imm64 */
320 uint8_t *pbCodeBuf = iemNativeInstrBufEnsure(pReNative, off, 10);
321 AssertReturn(pbCodeBuf, UINT32_MAX);
322 if (iGpr < 8)
323 pbCodeBuf[off++] = X86_OP_REX_W;
324 else
325 pbCodeBuf[off++] = X86_OP_REX_W | X86_OP_REX_B;
326 pbCodeBuf[off++] = 0xb8 + (iGpr & 7);
327 pbCodeBuf[off++] = RT_BYTE1(uImm64);
328 pbCodeBuf[off++] = RT_BYTE2(uImm64);
329 pbCodeBuf[off++] = RT_BYTE3(uImm64);
330 pbCodeBuf[off++] = RT_BYTE4(uImm64);
331 pbCodeBuf[off++] = RT_BYTE5(uImm64);
332 pbCodeBuf[off++] = RT_BYTE6(uImm64);
333 pbCodeBuf[off++] = RT_BYTE7(uImm64);
334 pbCodeBuf[off++] = RT_BYTE8(uImm64);
335 }
336
337#elif RT_ARCH_ARM64
338 uint32_t *pu32CodeBuf = iemNativeInstrBufEnsure(pReNative, off, 4);
339 AssertReturn(pu32CodeBuf, UINT32_MAX);
340
341 /*
342 * We need to start this sequence with a 'mov grp, imm16, lsl #x' and
343 * supply remaining bits using 'movk grp, imm16, lsl #x'.
344 *
345 * The mov instruction is encoded 0xd2800000 + shift + imm16 + grp,
346 * while the movk is 0xf2800000 + shift + imm16 + grp, meaning the diff
347 * is 0x20000000 (bit 29). So, we keep this bit in a variable and set it
348 * after the first non-zero immediate component so we switch to movk for
349 * the remainder.
350 */
351 uint32_t fMovK = 0;
352 /* mov gpr, imm16 */
353 uint32_t uImmPart = ((uint32_t)((uImm64 >> 0) & UINT32_C(0xffff)) << 5);
354 if (uImmPart)
355 {
356 pu32CodeBuf[off++] = UINT32_C(0xd2800000) | (UINT32_C(0) << 21) | uImmPart | iGpr;
357 fMovK |= RT_BIT_32(29);
358 }
359 /* mov[k] gpr, imm16, lsl #16 */
360 uImmPart = ((uint32_t)((uImm64 >> 16) & UINT32_C(0xffff)) << 5);
361 if (uImmPart)
362 {
363 pu32CodeBuf[off++] = UINT32_C(0xd2800000) | fMovK | (UINT32_C(1) << 21) | uImmPart | iGpr;
364 fMovK |= RT_BIT_32(29);
365 }
366 /* mov[k] gpr, imm16, lsl #32 */
367 uImmPart = ((uint32_t)((uImm64 >> 32) & UINT32_C(0xffff)) << 5);
368 if (uImmPart)
369 {
370 pu32CodeBuf[off++] = UINT32_C(0xd2800000) | fMovK | (UINT32_C(2) << 21) | uImmPart | iGpr;
371 fMovK |= RT_BIT_32(29);
372 }
373 /* mov[k] gpr, imm16, lsl #48 */
374 uImmPart = ((uint32_t)((uImm64 >> 48) & UINT32_C(0xffff)) << 5);
375 if (uImmPart)
376 pu32CodeBuf[off++] = UINT32_C(0xd2800000) | fMovK | (UINT32_C(3) << 21) | uImmPart | iGpr;
377
378 /** @todo there is an inverted mask variant we might want to explore if it
379 * reduces the number of instructions... */
380 /** @todo load into 'w' register instead of 'x' when imm64 <= UINT32_MAX?
381 * clang 12.x does that, only to use the 'x' version for the
382 * addressing in the following ldr). */
383
384#else
385# error "port me"
386#endif
387 return off;
388}
389
390
391/**
392 * Emits a 32-bit GPR load of a VCpu value.
393 */
394DECLINLINE(uint32_t) iemNativeEmitLoadGprFromVCpuU32(PIEMRECOMPILERSTATE pReNative, uint32_t off, uint8_t iGpr, uint32_t offVCpu)
395{
396#ifdef RT_ARCH_AMD64
397 uint8_t *pbCodeBuf = iemNativeInstrBufEnsure(pReNative, off, 7);
398 AssertReturn(pbCodeBuf, UINT32_MAX);
399
400 /* mov reg32, mem32 */
401 if (iGpr >= 8)
402 pbCodeBuf[off++] = X86_OP_REX_R;
403 pbCodeBuf[off++] = 0x8b;
404 if (offVCpu < 128)
405 {
406 pbCodeBuf[off++] = X86_MODRM_MAKE(X86_MOD_MEM1, iGpr & 7, IEMNATIVE_REG_FIXED_PVMCPU);
407 pbCodeBuf[off++] = (uint8_t)offVCpu;
408 }
409 else
410 {
411 pbCodeBuf[off++] = X86_MODRM_MAKE(X86_MOD_MEM4, iGpr & 7, IEMNATIVE_REG_FIXED_PVMCPU);
412 pbCodeBuf[off++] = RT_BYTE1(offVCpu);
413 pbCodeBuf[off++] = RT_BYTE2(offVCpu);
414 pbCodeBuf[off++] = RT_BYTE3(offVCpu);
415 pbCodeBuf[off++] = RT_BYTE4(offVCpu);
416 }
417
418#elif RT_ARCH_ARM64
419 /*
420 * There are a couple of ldr variants that takes an immediate offset, so
421 * try use those if we can, otherwise we have to use the temporary register
422 * help with the addressing.
423 */
424 if (offVCpu < _16K)
425 {
426 /* Use the unsigned variant of ldr Wt, [<Xn|SP>, #off]. */
427 uint32_t *pu32CodeBuf = iemNativeInstrBufEnsure(pReNative, off, 1);
428 AssertReturn(pu32CodeBuf, UINT32_MAX);
429 pu32CodeBuf[off++] = UINT32_C(0xb9400000) | (offVCpu << 10) | (IEMNATIVE_REG_FIXED_PVMCPU << 5) | iGpr;
430 }
431 else
432 {
433 /* The offset is too large, so we must load it into a register and use
434 ldr Wt, [<Xn|SP>, (<Wm>|<Xm>). */
435 /** @todo reduce by offVCpu by >> 3 or >> 2? if it saves instructions? */
436 off = iemNativeEmitLoadGprImm64(pReNative, off, IEMNATIVE_REG_FIXED_TMP0, offVCpu);
437 uint32_t *pu32CodeBuf = iemNativeInstrBufEnsure(pReNative, off, 1);
438 AssertReturn(pu32CodeBuf, UINT32_MAX);
439 pu32CodeBuf[off++] = UINT32_C(0xb8600800) | ((uint32_t)IEMNATIVE_REG_FIXED_TMP0 << 16)
440 | ((uint32_t)IEMNATIVE_REG_FIXED_PVMCPU << 5) | iGpr;
441 }
442
443#else
444# error "port me"
445#endif
446 return off;
447}
448
449
450/**
451 * Emits a gprdst = gprsrc load.
452 */
453DECLINLINE(uint32_t) iemNativeEmitLoadGprFromGpr(PIEMRECOMPILERSTATE pReNative, uint32_t off, uint8_t iGprDst, uint8_t iGprSrc)
454{
455#ifdef RT_ARCH_AMD64
456 /* mov gprdst, gprsrc */
457 uint8_t *pbCodeBuf = iemNativeInstrBufEnsure(pReNative, off, 3);
458 AssertReturn(pbCodeBuf, UINT32_MAX);
459 if ((iGprDst | iGprSrc) >= 8)
460 pbCodeBuf[off++] = iGprDst < 8 ? X86_OP_REX_W | X86_OP_REX_B
461 : iGprSrc >= 8 ? X86_OP_REX_W | X86_OP_REX_R | X86_OP_REX_B
462 : X86_OP_REX_W | X86_OP_REX_R;
463 else
464 pbCodeBuf[off++] = X86_OP_REX_W;
465 pbCodeBuf[off++] = 0x8b;
466 pbCodeBuf[off++] = X86_MODRM_MAKE(X86_MOD_REG, iGprDst & 7, iGprSrc & 7);
467
468#elif RT_ARCH_ARM64
469 uint32_t *pu32CodeBuf = iemNativeInstrBufEnsure(pReNative, off, 1);
470 AssertReturn(pu32CodeBuf, UINT32_MAX);
471 /* mov dst, src; alias for: orr dst, xzr, src */
472 pu32CodeBuf[off++] = UINT32_C(0xaa000000) | ((uint32_t)iGprSrc << 16) | ((uint32_t)ARMV8_A64_REG_XZR << 5) | iGprDst;
473
474#else
475# error "port me"
476#endif
477 return off;
478}
479
480#ifdef RT_ARCH_AMD64
481/**
482 * Common bit of iemNativeEmitLoadGprByBp and friends.
483 */
484DECL_FORCE_INLINE(uint32_t) iemNativeEmitGprByBpDisp(uint8_t *pbCodeBuf, uint32_t off, uint8_t iGprReg, int32_t offDisp)
485{
486 if (offDisp < 128 && offDisp >= -128)
487 {
488 pbCodeBuf[off++] = X86_MODRM_MAKE(X86_MOD_MEM1, iGprReg & 7, X86_GREG_xBP);
489 pbCodeBuf[off++] = (uint8_t)(int8_t)offDisp;
490 }
491 else
492 {
493 pbCodeBuf[off++] = X86_MODRM_MAKE(X86_MOD_MEM4, iGprReg & 7, X86_GREG_xBP);
494 pbCodeBuf[off++] = RT_BYTE1((uint32_t)offDisp);
495 pbCodeBuf[off++] = RT_BYTE2((uint32_t)offDisp);
496 pbCodeBuf[off++] = RT_BYTE3((uint32_t)offDisp);
497 pbCodeBuf[off++] = RT_BYTE4((uint32_t)offDisp);
498 }
499 return off;
500}
501#endif
502
503
504#ifdef RT_ARCH_AMD64
505/**
506 * Emits a 64-bit GRP load instruction with an BP relative source address.
507 */
508DECLINLINE(uint32_t) iemNativeEmitLoadGprByBp(PIEMRECOMPILERSTATE pReNative, uint32_t off, uint8_t iGprDst, int32_t offDisp)
509{
510 /* mov gprdst, qword [rbp + offDisp] */
511 uint8_t *pbCodeBuf = iemNativeInstrBufEnsure(pReNative, off, 7);
512 if (iGprDst < 8)
513 pbCodeBuf[off++] = X86_OP_REX_W;
514 else
515 pbCodeBuf[off++] = X86_OP_REX_W | X86_OP_REX_R;
516 pbCodeBuf[off++] = 0x8b;
517 return iemNativeEmitGprByBpDisp(pbCodeBuf, off, iGprDst, offDisp);
518}
519#endif
520
521
522#ifdef RT_ARCH_AMD64
523/**
524 * Emits a 32-bit GRP load instruction with an BP relative source address.
525 */
526DECLINLINE(uint32_t) iemNativeEmitLoadGprByBpU32(PIEMRECOMPILERSTATE pReNative, uint32_t off, uint8_t iGprDst, int32_t offDisp)
527{
528 /* mov gprdst, dword [rbp + offDisp] */
529 uint8_t *pbCodeBuf = iemNativeInstrBufEnsure(pReNative, off, 7);
530 if (iGprDst >= 8)
531 pbCodeBuf[off++] = X86_OP_REX_R;
532 pbCodeBuf[off++] = 0x8b;
533 return iemNativeEmitGprByBpDisp(pbCodeBuf, off, iGprDst, offDisp);
534}
535#endif
536
537
538#ifdef RT_ARCH_AMD64
539/**
540 * Emits a load effective address to a GRP with an BP relative source address.
541 */
542DECLINLINE(uint32_t) iemNativeEmitLeaGrpByBp(PIEMRECOMPILERSTATE pReNative, uint32_t off, uint8_t iGprDst, int32_t offDisp)
543{
544 /* lea gprdst, [rbp + offDisp] */
545 uint8_t *pbCodeBuf = iemNativeInstrBufEnsure(pReNative, off, 7);
546 if (iGprDst < 8)
547 pbCodeBuf[off++] = X86_OP_REX_W;
548 else
549 pbCodeBuf[off++] = X86_OP_REX_W | X86_OP_REX_R;
550 pbCodeBuf[off++] = 0x8d;
551 return iemNativeEmitGprByBpDisp(pbCodeBuf, off, iGprDst, offDisp);
552}
553#endif
554
555
556#ifdef RT_ARCH_AMD64
557/**
558 * Emits a 64-bit GPR store with an BP relative destination address.
559 */
560DECLINLINE(uint32_t) iemNativeEmitStoreGprByBp(PIEMRECOMPILERSTATE pReNative, uint32_t off, int32_t offDisp, uint8_t iGprSrc)
561{
562 /* mov qword [rbp + offDisp], gprdst */
563 uint8_t *pbCodeBuf = iemNativeInstrBufEnsure(pReNative, off, 7);
564 if (iGprSrc < 8)
565 pbCodeBuf[off++] = X86_OP_REX_W;
566 else
567 pbCodeBuf[off++] = X86_OP_REX_W | X86_OP_REX_R;
568 pbCodeBuf[off++] = 0x89;
569 return iemNativeEmitGprByBpDisp(pbCodeBuf, off, iGprSrc, offDisp);
570}
571#endif
572
573
574#ifdef RT_ARCH_AMD64
575/**
576 * Emits a 64-bit GPR subtract with a signed immediate subtrahend.
577 */
578DECLINLINE(uint32_t) iemNativeEmitSubGprImm(PIEMRECOMPILERSTATE pReNative, uint32_t off, uint8_t iGprDst, int32_t iSubtrahend)
579{
580 /* sub gprdst, imm8/imm32 */
581 uint8_t *pbCodeBuf = iemNativeInstrBufEnsure(pReNative, off, 7);
582 if (iGprDst < 7)
583 pbCodeBuf[off++] = X86_OP_REX_W;
584 else
585 pbCodeBuf[off++] = X86_OP_REX_W | X86_OP_REX_B;
586 if (iSubtrahend < 128 && iSubtrahend >= -128)
587 {
588 pbCodeBuf[off++] = 0x83;
589 pbCodeBuf[off++] = X86_MODRM_MAKE(X86_MOD_REG, 5, iGprDst & 7);
590 pbCodeBuf[off++] = (uint8_t)iSubtrahend;
591 }
592 else
593 {
594 pbCodeBuf[off++] = 0x81;
595 pbCodeBuf[off++] = X86_MODRM_MAKE(X86_MOD_REG, 5, iGprDst & 7);
596 pbCodeBuf[off++] = RT_BYTE1(iSubtrahend);
597 pbCodeBuf[off++] = RT_BYTE2(iSubtrahend);
598 pbCodeBuf[off++] = RT_BYTE3(iSubtrahend);
599 pbCodeBuf[off++] = RT_BYTE4(iSubtrahend);
600 }
601 return off;
602}
603#endif
604
605/** @} */
606
607#endif /* !VMM_INCLUDED_SRC_include_IEMN8veRecompiler_h */
608
Note: See TracBrowser for help on using the repository browser.

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