VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMAll/target-x86/IEMAllN8veEmit-x86.h@ 103683

Last change on this file since 103683 was 103683, checked in by vboxsync, 11 months ago

VMM/IEM: Implemented iemNativeEmit_add_r_r_efl and enabled in on both hosts. bugref:10376

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 29.2 KB
Line 
1/* $Id: IEMAllN8veEmit-x86.h 103683 2024-03-05 15:02:10Z vboxsync $ */
2/** @file
3 * IEM - Native Recompiler, x86 Target - Code Emitters.
4 */
5
6/*
7 * Copyright (C) 2023-2024 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_VMMAll_target_x86_IEMAllN8veEmit_x86_h
29#define VMM_INCLUDED_SRC_VMMAll_target_x86_IEMAllN8veEmit_x86_h
30#ifndef RT_WITHOUT_PRAGMA_ONCE
31# pragma once
32#endif
33
34
35#ifdef RT_ARCH_AMD64
36DECL_FORCE_INLINE(uint32_t)
37iemNativeEmitAmd64ModRmInstrRREx(PIEMNATIVEINSTR pCodeBuf, uint32_t off, uint8_t bOpcode8, uint8_t bOpcodeOther,
38 uint8_t cOpBits, uint8_t idxRegReg, uint8_t idxRegRm)
39{
40 Assert(idxRegReg < 16); Assert(idxRegRm < 16);
41 switch (cOpBits)
42 {
43 case 16:
44 pCodeBuf[off++] = X86_OP_PRF_SIZE_OP;
45 RT_FALL_THRU();
46 case 32:
47 if (idxRegReg >= 8 || idxRegRm >= 8)
48 pCodeBuf[off++] = (idxRegReg >= 8 ? X86_OP_REX_R : 0) | (idxRegRm >= 8 ? X86_OP_REX_B : 0);
49 pCodeBuf[off++] = bOpcodeOther;
50 break;
51
52 default: AssertFailed(); RT_FALL_THRU();
53 case 64:
54 pCodeBuf[off++] = X86_OP_REX_W | (idxRegReg >= 8 ? X86_OP_REX_R : 0) | (idxRegRm >= 8 ? X86_OP_REX_B : 0);
55 pCodeBuf[off++] = bOpcodeOther;
56 break;
57
58 case 8:
59 if (idxRegReg >= 8 || idxRegRm >= 8)
60 pCodeBuf[off++] = (idxRegReg >= 8 ? X86_OP_REX_R : 0) | (idxRegRm >= 8 ? X86_OP_REX_B : 0);
61 else if (idxRegReg >= 4 || idxRegRm >= 4)
62 pCodeBuf[off++] = X86_OP_REX;
63 pCodeBuf[off++] = bOpcode8;
64 break;
65 }
66 pCodeBuf[off++] = X86_MODRM_MAKE(X86_MOD_REG, idxRegReg & 7, idxRegRm & 7);
67 return off;
68}
69#endif /* RT_ARCH_AMD64 */
70
71
72/**
73 * This is an implementation of IEM_EFL_UPDATE_STATUS_BITS_FOR_LOGICAL.
74 *
75 * It takes liveness stuff into account.
76 */
77DECL_INLINE_THROW(uint32_t)
78iemNativeEmitEFlagsForLogical(PIEMRECOMPILERSTATE pReNative, uint32_t off, uint8_t idxVarEfl,
79 uint8_t cOpBits, uint8_t idxRegResult)
80{
81#ifdef IEMNATIVE_WITH_LIVENESS_ANALYSIS
82 if (1) /** @todo check if all bits are clobbered. */
83#endif
84 {
85#ifdef RT_ARCH_AMD64
86 /*
87 * Collect flags and merge them with eflags.
88 */
89 /** @todo we could alternatively use SAHF here when host rax is free since,
90 * OF is cleared. */
91 PIEMNATIVEINSTR pCodeBuf = iemNativeInstrBufEnsure(pReNative, off, 1);
92 /* pushf - do this before any reg allocations as they may emit instructions too. */
93 pCodeBuf[off++] = 0x9c;
94
95 uint8_t const idxRegEfl = iemNativeVarRegisterAcquire(pReNative, idxVarEfl, &off, true /*fInitialized*/);
96 uint8_t const idxTmpReg = iemNativeRegAllocTmp(pReNative, &off);
97 pCodeBuf = iemNativeInstrBufEnsure(pReNative, off, 2 + 7 + 7 + 3);
98 /* pop tmp */
99 if (idxTmpReg >= 8)
100 pCodeBuf[off++] = X86_OP_REX_B;
101 pCodeBuf[off++] = 0x58 + (idxTmpReg & 7);
102 /* and tmp, X86_EFL_PF | X86_EFL_ZF | X86_EFL_SF */
103 off = iemNativeEmitAndGpr32ByImmEx(pCodeBuf, off, idxTmpReg, X86_EFL_PF | X86_EFL_ZF | X86_EFL_SF);
104 /* Clear the status bits in EFLs. */
105 off = iemNativeEmitAndGpr32ByImmEx(pCodeBuf, off, idxRegEfl, ~X86_EFL_STATUS_BITS);
106 /* OR in the flags we collected. */
107 off = iemNativeEmitOrGpr32ByGprEx(pCodeBuf, off, idxRegEfl, idxTmpReg);
108 iemNativeVarRegisterRelease(pReNative, idxVarEfl);
109 iemNativeRegFreeTmp(pReNative, idxTmpReg);
110 RT_NOREF(cOpBits, idxRegResult);
111
112#elif defined(RT_ARCH_ARM64)
113 /*
114 * Calculate flags.
115 */
116 uint8_t const idxRegEfl = iemNativeVarRegisterAcquire(pReNative, idxVarEfl, &off, true /*fInitialized*/);
117 uint8_t const idxTmpReg = iemNativeRegAllocTmp(pReNative, &off);
118 PIEMNATIVEINSTR const pCodeBuf = iemNativeInstrBufEnsure(pReNative, off, 15);
119
120 /* Clear the status bits. ~0x8D5 (or ~0x8FD) can't be AND immediate, so use idxTmpReg for constant. */
121 off = iemNativeEmitLoadGpr32ImmEx(pCodeBuf, off, idxTmpReg, ~X86_EFL_STATUS_BITS);
122 off = iemNativeEmitAndGpr32ByGpr32Ex(pCodeBuf, off, idxRegEfl, idxTmpReg);
123
124 /* Calculate zero: mov tmp, zf; cmp result,zero; csel.eq tmp,tmp,wxr */
125 if (cOpBits > 32)
126 off = iemNativeEmitCmpGprWithGprEx(pCodeBuf, off, idxRegResult, ARMV8_A64_REG_XZR);
127 else
128 off = iemNativeEmitCmpGpr32WithGprEx(pCodeBuf, off, idxRegResult, ARMV8_A64_REG_XZR);
129 pCodeBuf[off++] = Armv8A64MkInstrCSet(idxTmpReg, kArmv8InstrCond_Eq, false /*f64Bit*/);
130 pCodeBuf[off++] = Armv8A64MkInstrOrr(idxRegEfl, idxRegEfl, idxTmpReg, false /*f64Bit*/, X86_EFL_ZF_BIT);
131
132 /* Calculate signed: We could use the native SF flag, but it's just as simple to calculate it by shifting. */
133 pCodeBuf[off++] = Armv8A64MkInstrLsrImm(idxTmpReg, idxRegResult, cOpBits - 1, cOpBits > 32 /*f64Bit*/);
134# if 0 /* BFI and ORR hsould have the same performance characteristics, so use BFI like we'll have to do for SUB/ADD/++. */
135 pCodeBuf[off++] = Armv8A64MkInstrOrr(idxRegEfl, idxRegEfl, idxTmpReg, false /*f64Bit*/, X86_EFL_SF_BIT);
136# else
137 pCodeBuf[off++] = Armv8A64MkInstrBfi(idxRegEfl, idxTmpReg, X86_EFL_SF_BIT, 1, false /*f64Bit*/);
138# endif
139
140 /* Calculate 8-bit parity of the result. */
141 pCodeBuf[off++] = Armv8A64MkInstrEor(idxTmpReg, idxRegResult, idxRegResult, false /*f64Bit*/,
142 4 /*offShift6*/, kArmv8A64InstrShift_Lsr);
143 pCodeBuf[off++] = Armv8A64MkInstrEor(idxTmpReg, idxTmpReg, idxTmpReg, false /*f64Bit*/,
144 2 /*offShift6*/, kArmv8A64InstrShift_Lsr);
145 pCodeBuf[off++] = Armv8A64MkInstrEor(idxTmpReg, idxTmpReg, idxTmpReg, false /*f64Bit*/,
146 1 /*offShift6*/, kArmv8A64InstrShift_Lsr);
147 Assert(Armv8A64ConvertImmRImmS2Mask32(0, 0) == 1);
148 pCodeBuf[off++] = Armv8A64MkInstrEorImm(idxTmpReg, idxTmpReg, 0, 0, false /*f64Bit*/);
149 pCodeBuf[off++] = Armv8A64MkInstrBfi(idxRegEfl, idxTmpReg, X86_EFL_PF_BIT, 1, false /*f64Bit*/);
150
151 iemNativeVarRegisterRelease(pReNative, idxVarEfl);
152 iemNativeRegFreeTmp(pReNative, idxTmpReg);
153#else
154# error "port me"
155#endif
156 IEMNATIVE_ASSERT_INSTR_BUF_ENSURE(pReNative, off);
157 }
158 return off;
159}
160
161
162/**
163 * This is an implementation of IEM_EFL_UPDATE_STATUS_BITS_FOR_ARITHMETIC.
164 *
165 * It takes liveness stuff into account.
166 */
167DECL_FORCE_INLINE_THROW(uint32_t)
168iemNativeEmitEFlagsForArithmetic(PIEMRECOMPILERSTATE pReNative, uint32_t off, uint8_t idxVarEfl
169#ifndef RT_ARCH_AMD64
170 , uint8_t cOpBits, uint8_t idxRegResult, uint8_t idxRegDstIn, uint8_t idxRegSrc
171 , bool fNativeFlags, bool fInvertCarry
172#endif
173 )
174{
175#ifdef IEMNATIVE_WITH_LIVENESS_ANALYSIS
176 if (1) /** @todo check if all bits are clobbered. */
177#endif
178 {
179#ifdef RT_ARCH_AMD64
180 /*
181 * Collect flags and merge them with eflags.
182 */
183 PIEMNATIVEINSTR pCodeBuf = iemNativeInstrBufEnsure(pReNative, off, 1);
184 /* pushf - do this before any reg allocations as they may emit instructions too. */
185 pCodeBuf[off++] = 0x9c;
186
187 uint8_t const idxRegEfl = iemNativeVarRegisterAcquire(pReNative, idxVarEfl, &off, true /*fInitialized*/);
188 uint8_t const idxTmpReg = iemNativeRegAllocTmp(pReNative, &off);
189 pCodeBuf = iemNativeInstrBufEnsure(pReNative, off, 2 + 7 + 7 + 3);
190 /* pop tmp */
191 if (idxTmpReg >= 8)
192 pCodeBuf[off++] = X86_OP_REX_B;
193 pCodeBuf[off++] = 0x58 + (idxTmpReg & 7);
194 /* Isolate the flags we want. */
195 off = iemNativeEmitAndGpr32ByImmEx(pCodeBuf, off, idxTmpReg, X86_EFL_STATUS_BITS);
196 /* Clear the status bits in EFLs. */
197 off = iemNativeEmitAndGpr32ByImmEx(pCodeBuf, off, idxRegEfl, ~X86_EFL_STATUS_BITS);
198 /* OR in the flags we collected. */
199 off = iemNativeEmitOrGpr32ByGprEx(pCodeBuf, off, idxRegEfl, idxTmpReg);
200 iemNativeVarRegisterRelease(pReNative, idxVarEfl);
201 iemNativeRegFreeTmp(pReNative, idxTmpReg);
202
203#elif defined(RT_ARCH_ARM64)
204 /*
205 * Calculate flags.
206 */
207 uint8_t const idxRegEfl = iemNativeVarRegisterAcquire(pReNative, idxVarEfl, &off, true /*fInitialized*/);
208 uint8_t const idxTmpReg = iemNativeRegAllocTmp(pReNative, &off);
209 PIEMNATIVEINSTR const pCodeBuf = iemNativeInstrBufEnsure(pReNative, off, 18);
210
211 if (fNativeFlags && cOpBits >= 32)
212 {
213 /* Invert CF (stored inved on ARM) and load the flags into the temporary register. */
214 if (fInvertCarry)
215 pCodeBuf[off++] = ARMV8_A64_INSTR_CFINV;
216 pCodeBuf[off++] = Armv8A64MkInstrMrs(idxTmpReg, ARMV8_AARCH64_SYSREG_NZCV); /* Bits: 31=N; 30=Z; 29=C; 28=V; */
217
218 /* V -> OF */
219 pCodeBuf[off++] = Armv8A64MkInstrLsrImm(idxTmpReg, idxTmpReg, 28);
220 pCodeBuf[off++] = Armv8A64MkInstrBfi(idxRegEfl, idxTmpReg, X86_EFL_OF_BIT, 1, false /*f64Bit*/);
221
222 /* C -> CF */
223 pCodeBuf[off++] = Armv8A64MkInstrLsrImm(idxTmpReg, idxTmpReg, 1);
224 pCodeBuf[off++] = Armv8A64MkInstrBfi(idxRegEfl, idxTmpReg, X86_EFL_CF_BIT, 1, false /*f64Bit*/);
225
226 /* N,Z -> SF,ZF */
227 pCodeBuf[off++] = Armv8A64MkInstrLsrImm(idxTmpReg, idxTmpReg, 1);
228 pCodeBuf[off++] = Armv8A64MkInstrBfi(idxRegEfl, idxTmpReg, X86_EFL_ZF_BIT, 2, false /*f64Bit*/);
229 }
230 else
231 {
232#if 0
233 pCodeBuf[off++] = Armv8A64MkInstrSetF8SetF16(idxRegResult, cOpBits > 8);
234 pCodeBuf[off++] = Armv8A64MkInstrMrs(idxTmpReg, ARMV8_AARCH64_SYSREG_NZCV); /* Bits: 31=N; 30=Z; 29=C; 28=V; */
235
236 /* V -> OF */
237 pCodeBuf[off++] = Armv8A64MkInstrLsrImm(idxTmpReg, idxTmpReg, 28);
238 pCodeBuf[off++] = Armv8A64MkInstrBfi(idxRegEfl, idxTmpReg, X86_EFL_OF_BIT, 1, false /*f64Bit*/);
239
240 /* N,Z -> SF,ZF */
241 pCodeBuf[off++] = Armv8A64MkInstrLsrImm(idxTmpReg, idxTmpReg, 2);
242 pCodeBuf[off++] = Armv8A64MkInstrBfi(idxRegEfl, idxTmpReg, X86_EFL_ZF_BIT, 2, false /*f64Bit*/);
243#else
244 pCodeBuf[off++] = Armv8A64MkInstrBrk(0x1010);
245#endif
246 }
247
248 /* Calculate 8-bit parity of the result. */
249 pCodeBuf[off++] = Armv8A64MkInstrEor(idxTmpReg, idxRegResult, idxRegResult, false /*f64Bit*/,
250 4 /*offShift6*/, kArmv8A64InstrShift_Lsr);
251 pCodeBuf[off++] = Armv8A64MkInstrEor(idxTmpReg, idxTmpReg, idxTmpReg, false /*f64Bit*/,
252 2 /*offShift6*/, kArmv8A64InstrShift_Lsr);
253 pCodeBuf[off++] = Armv8A64MkInstrEor(idxTmpReg, idxTmpReg, idxTmpReg, false /*f64Bit*/,
254 1 /*offShift6*/, kArmv8A64InstrShift_Lsr);
255 Assert(Armv8A64ConvertImmRImmS2Mask32(0, 0) == 1);
256 pCodeBuf[off++] = Armv8A64MkInstrEorImm(idxTmpReg, idxTmpReg, 0, 0, false /*f64Bit*/);
257 pCodeBuf[off++] = Armv8A64MkInstrBfi(idxRegEfl, idxTmpReg, X86_EFL_PF_BIT, 1, false /*f64Bit*/);
258
259 /* Calculate auxilary carry/borrow. This is related to 8-bit BCD.*/
260 pCodeBuf[off++] = Armv8A64MkInstrEor(idxTmpReg, idxRegDstIn, idxRegSrc, false /*f64Bit*/);
261 pCodeBuf[off++] = Armv8A64MkInstrEor(idxTmpReg, idxTmpReg, idxRegResult, false /*f64Bit*/);
262 pCodeBuf[off++] = Armv8A64MkInstrLsrImm(idxTmpReg, idxTmpReg, X86_EFL_AF_BIT, false /*f64Bit*/);
263 pCodeBuf[off++] = Armv8A64MkInstrBfi(idxRegEfl, idxTmpReg, X86_EFL_AF_BIT, 1, false /*f64Bit*/);
264
265 iemNativeVarRegisterRelease(pReNative, idxVarEfl);
266 iemNativeRegFreeTmp(pReNative, idxTmpReg);
267#else
268# error "port me"
269#endif
270 IEMNATIVE_ASSERT_INSTR_BUF_ENSURE(pReNative, off);
271 }
272 return off;
273
274}
275
276
277/**
278 * The AND instruction will clear OF, CF and AF (latter is undefined) and
279 * set the other flags according to the result.
280 */
281DECL_INLINE_THROW(uint32_t)
282iemNativeEmit_and_r_r_efl(PIEMRECOMPILERSTATE pReNative, uint32_t off,
283 uint8_t idxVarDst, uint8_t idxVarSrc, uint8_t idxVarEfl, uint8_t cOpBits)
284{
285 uint8_t const idxRegDst = iemNativeVarRegisterAcquire(pReNative, idxVarDst, &off, true /*fInitialized*/);
286 uint8_t const idxRegSrc = iemNativeVarRegisterAcquire(pReNative, idxVarSrc, &off, true /*fInitialized*/);
287#ifdef RT_ARCH_AMD64
288 /* On AMD64 we just use the correctly size AND instruction harvest the EFLAGS. */
289 off = iemNativeEmitAmd64ModRmInstrRREx(iemNativeInstrBufEnsure(pReNative, off, 4), off,
290 0x22, 0x23, cOpBits, idxRegDst, idxRegSrc);
291 IEMNATIVE_ASSERT_INSTR_BUF_ENSURE(pReNative, off);
292
293#elif defined(RT_ARCH_ARM64)
294 /* On ARM64 we use 32-bit AND for the 8-bit and 16-bit bit ones. */
295 /** @todo we should use ANDS on ARM64 and get the ZF for free for all
296 * variants, and SF for 32-bit and 64-bit. */
297 PIEMNATIVEINSTR const pCodeBuf = iemNativeInstrBufEnsure(pReNative, off, 1);
298 pCodeBuf[off++] = Armv8A64MkInstrAnd(idxRegDst, idxRegDst, idxRegSrc, cOpBits > 32 /*f64Bit*/);
299 IEMNATIVE_ASSERT_INSTR_BUF_ENSURE(pReNative, off);
300
301#else
302# error "Port me"
303#endif
304 iemNativeVarRegisterRelease(pReNative, idxVarSrc);
305
306 off = iemNativeEmitEFlagsForLogical(pReNative, off, idxVarEfl, cOpBits, idxRegDst);
307 iemNativeVarRegisterRelease(pReNative, idxVarDst);
308 return off;
309}
310
311
312/**
313 * The TEST instruction will clear OF, CF and AF (latter is undefined) and
314 * set the other flags according to the result.
315 */
316DECL_INLINE_THROW(uint32_t)
317iemNativeEmit_test_r_r_efl(PIEMRECOMPILERSTATE pReNative, uint32_t off,
318 uint8_t idxVarDst, uint8_t idxVarSrc, uint8_t idxVarEfl, uint8_t cOpBits)
319{
320 uint8_t const idxRegDst = iemNativeVarRegisterAcquire(pReNative, idxVarDst, &off, true /*fInitialized*/);
321 uint8_t const idxRegSrc = idxVarSrc == idxVarDst ? idxRegDst /* special case of 'test samereg,samereg' */
322 : iemNativeVarRegisterAcquire(pReNative, idxVarSrc, &off, true /*fInitialized*/);
323#ifdef RT_ARCH_AMD64
324 /* On AMD64 we just use the correctly size TEST instruction harvest the EFLAGS. */
325 off = iemNativeEmitAmd64ModRmInstrRREx(iemNativeInstrBufEnsure(pReNative, off, 4), off,
326 0x84, 0x85, cOpBits, idxRegSrc, idxRegDst);
327 IEMNATIVE_ASSERT_INSTR_BUF_ENSURE(pReNative, off);
328
329#elif defined(RT_ARCH_ARM64)
330 /* On ARM64 we use 32-bit AND for the 8-bit and 16-bit bit ones. We also
331 need to keep the result in order to calculate the flags. */
332 /** @todo we should use ANDS on ARM64 and get the ZF for free for all
333 * variants, and SF for 32-bit and 64-bit. */
334 uint8_t const idxRegResult = iemNativeRegAllocTmp(pReNative, &off);
335 PIEMNATIVEINSTR const pCodeBuf = iemNativeInstrBufEnsure(pReNative, off, 1);
336 pCodeBuf[off++] = Armv8A64MkInstrAnd(idxRegResult, idxRegDst, idxRegSrc, cOpBits > 32 /*f64Bit*/);
337 IEMNATIVE_ASSERT_INSTR_BUF_ENSURE(pReNative, off);
338
339#else
340# error "Port me"
341#endif
342 if (idxVarSrc != idxVarDst)
343 iemNativeVarRegisterRelease(pReNative, idxVarSrc);
344 iemNativeVarRegisterRelease(pReNative, idxVarDst);
345
346#ifdef RT_ARCH_AMD64
347 off = iemNativeEmitEFlagsForLogical(pReNative, off, idxVarEfl, cOpBits, UINT8_MAX);
348#else
349 off = iemNativeEmitEFlagsForLogical(pReNative, off, idxVarEfl, cOpBits, idxRegResult);
350 iemNativeRegFreeTmp(pReNative, idxRegResult);
351#endif
352 return off;
353}
354
355
356/**
357 * The OR instruction will clear OF, CF and AF (latter is undefined) and
358 * set the other flags according to the result.
359 */
360DECL_INLINE_THROW(uint32_t)
361iemNativeEmit_or_r_r_efl(PIEMRECOMPILERSTATE pReNative, uint32_t off,
362 uint8_t idxVarDst, uint8_t idxVarSrc, uint8_t idxVarEfl, uint8_t cOpBits)
363{
364 uint8_t const idxRegDst = iemNativeVarRegisterAcquire(pReNative, idxVarDst, &off, true /*fInitialized*/);
365 uint8_t const idxRegSrc = iemNativeVarRegisterAcquire(pReNative, idxVarSrc, &off, true /*fInitialized*/);
366#ifdef RT_ARCH_AMD64
367 /* On AMD64 we just use the correctly size OR instruction harvest the EFLAGS. */
368 off = iemNativeEmitAmd64ModRmInstrRREx(iemNativeInstrBufEnsure(pReNative, off, 4), off,
369 0x0a, 0x0b, cOpBits, idxRegDst, idxRegSrc);
370 IEMNATIVE_ASSERT_INSTR_BUF_ENSURE(pReNative, off);
371
372#elif defined(RT_ARCH_ARM64)
373 /* On ARM64 we use 32-bit OR for the 8-bit and 16-bit bit ones. */
374 PIEMNATIVEINSTR const pCodeBuf = iemNativeInstrBufEnsure(pReNative, off, 1);
375 pCodeBuf[off++] = Armv8A64MkInstrOrr(idxRegDst, idxRegDst, idxRegSrc, cOpBits > 32 /*f64Bit*/);
376 IEMNATIVE_ASSERT_INSTR_BUF_ENSURE(pReNative, off);
377
378#else
379# error "Port me"
380#endif
381 iemNativeVarRegisterRelease(pReNative, idxVarSrc);
382
383 off = iemNativeEmitEFlagsForLogical(pReNative, off, idxVarEfl, cOpBits, idxRegDst);
384 iemNativeVarRegisterRelease(pReNative, idxVarDst);
385 return off;
386}
387
388
389/**
390 * The XOR instruction will clear OF, CF and AF (latter is undefined) and
391 * set the other flags according to the result.
392 */
393DECL_INLINE_THROW(uint32_t)
394iemNativeEmit_xor_r_r_efl(PIEMRECOMPILERSTATE pReNative, uint32_t off,
395 uint8_t idxVarDst, uint8_t idxVarSrc, uint8_t idxVarEfl, uint8_t cOpBits)
396{
397 uint8_t const idxRegDst = iemNativeVarRegisterAcquire(pReNative, idxVarDst, &off, true /*fInitialized*/);
398 uint8_t const idxRegSrc = iemNativeVarRegisterAcquire(pReNative, idxVarSrc, &off, true /*fInitialized*/);
399#ifdef RT_ARCH_AMD64
400 /* On AMD64 we just use the correctly size OR instruction harvest the EFLAGS. */
401 off = iemNativeEmitAmd64ModRmInstrRREx(iemNativeInstrBufEnsure(pReNative, off, 4), off,
402 0x32, 0x33, cOpBits, idxRegDst, idxRegSrc);
403 IEMNATIVE_ASSERT_INSTR_BUF_ENSURE(pReNative, off);
404
405#elif defined(RT_ARCH_ARM64)
406 /* On ARM64 we use 32-bit OR for the 8-bit and 16-bit bit ones. */
407 PIEMNATIVEINSTR const pCodeBuf = iemNativeInstrBufEnsure(pReNative, off, 1);
408 pCodeBuf[off++] = Armv8A64MkInstrEor(idxRegDst, idxRegDst, idxRegSrc, cOpBits > 32 /*f64Bit*/);
409 IEMNATIVE_ASSERT_INSTR_BUF_ENSURE(pReNative, off);
410
411#else
412# error "Port me"
413#endif
414 iemNativeVarRegisterRelease(pReNative, idxVarSrc);
415
416 off = iemNativeEmitEFlagsForLogical(pReNative, off, idxVarEfl, cOpBits, idxRegDst);
417 iemNativeVarRegisterRelease(pReNative, idxVarDst);
418 return off;
419}
420
421
422/**
423 * The ADD instruction will set all status flags.
424 */
425DECL_INLINE_THROW(uint32_t)
426iemNativeEmit_add_r_r_efl(PIEMRECOMPILERSTATE pReNative, uint32_t off,
427 uint8_t idxVarDst, uint8_t idxVarSrc, uint8_t idxVarEfl, uint8_t cOpBits)
428{
429 uint8_t const idxRegDst = iemNativeVarRegisterAcquire(pReNative, idxVarDst, &off, true /*fInitialized*/);
430 uint8_t const idxRegSrc = iemNativeVarRegisterAcquire(pReNative, idxVarSrc, &off, true /*fInitialized*/);
431
432#ifdef RT_ARCH_AMD64
433 /* On AMD64 we just use the correctly sized ADD instruction to get the right EFLAGS.SF value. */
434 off = iemNativeEmitAmd64ModRmInstrRREx(iemNativeInstrBufEnsure(pReNative, off, 4), off,
435 0x02, 0x03, cOpBits, idxRegDst, idxRegSrc);
436 IEMNATIVE_ASSERT_INSTR_BUF_ENSURE(pReNative, off);
437
438 iemNativeVarRegisterRelease(pReNative, idxVarSrc);
439 iemNativeVarRegisterRelease(pReNative, idxVarDst);
440
441 off = iemNativeEmitEFlagsForArithmetic(pReNative, off, idxVarEfl);
442
443#elif defined(RT_ARCH_ARM64)
444 /* On ARM64 we'll need the two input operands as well as the result in order
445 to calculate the right flags, even if we use ADDS and translates NZCV into
446 OF, CF, ZF and SF. */
447 uint8_t const idxRegDstIn = iemNativeRegAllocTmp(pReNative, &off);
448 PIEMNATIVEINSTR const pCodeBuf = iemNativeInstrBufEnsure(pReNative, off, 5);
449 if (cOpBits >= 32)
450 {
451 off = iemNativeEmitLoadGprFromGprEx(pCodeBuf, off, idxRegDstIn, idxRegDst);
452 pCodeBuf[off++] = Armv8A64MkInstrAddReg(idxRegDst, idxRegDst, idxRegSrc, cOpBits > 32 /*f64Bit*/, true /*fSetFlags*/);
453 }
454 else
455 {
456 /* Shift the operands up so we can perform a 32-bit operation and get all four flags. */
457 uint32_t const cShift = 32 - cOpBits;
458 pCodeBuf[off++] = Armv8A64MkInstrOrr(idxRegDstIn, ARMV8_A64_REG_XZR, idxRegDst, false /*f64Bit*/, cShift);
459 pCodeBuf[off++] = Armv8A64MkInstrAddReg(idxRegDst, idxRegDstIn, idxRegSrc, false /*f64Bit*/,
460 true /*fSetFlags*/, cShift);
461 pCodeBuf[off++] = Armv8A64MkInstrLsrImm(idxRegDstIn, idxRegDstIn, cShift, false /*f64Bit*/);
462 pCodeBuf[off++] = Armv8A64MkInstrLsrImm(idxRegDst, idxRegDst, cShift, false /*f64Bit*/);
463 cOpBits = 32;
464 }
465 IEMNATIVE_ASSERT_INSTR_BUF_ENSURE(pReNative, off);
466
467 /** @todo Explain why the carry flag shouldn't be inverted for ADDS. */
468 off = iemNativeEmitEFlagsForArithmetic(pReNative, off, idxVarEfl, cOpBits, idxRegDst,
469 idxRegDstIn, idxRegSrc, true /*fNativeFlags*/, false /*fInvertCarry*/);
470
471 iemNativeRegFreeTmp(pReNative, idxRegDstIn);
472 iemNativeVarRegisterRelease(pReNative, idxVarSrc);
473 iemNativeVarRegisterRelease(pReNative, idxVarDst);
474
475#else
476# error "port me"
477#endif
478 return off;
479}
480
481
482DECL_INLINE_THROW(uint32_t)
483iemNativeEmit_adc_r_r_efl(PIEMRECOMPILERSTATE pReNative, uint32_t off,
484 uint8_t idxVarDst, uint8_t idxVarSrc, uint8_t idxVarEfl, uint8_t cOpBits)
485{
486 RT_NOREF(idxVarDst, idxVarSrc, idxVarEfl, cOpBits);
487 AssertFailed();
488 return iemNativeEmitBrk(pReNative, off, 0x666);
489}
490
491
492/**
493 * The SUB instruction will set all status flags.
494 */
495DECL_INLINE_THROW(uint32_t)
496iemNativeEmit_sub_r_r_efl(PIEMRECOMPILERSTATE pReNative, uint32_t off,
497 uint8_t idxVarDst, uint8_t idxVarSrc, uint8_t idxVarEfl, uint8_t cOpBits)
498{
499 uint8_t const idxRegDst = iemNativeVarRegisterAcquire(pReNative, idxVarDst, &off, true /*fInitialized*/);
500 uint8_t const idxRegSrc = iemNativeVarRegisterAcquire(pReNative, idxVarSrc, &off, true /*fInitialized*/);
501
502#ifdef RT_ARCH_AMD64
503 /* On AMD64 we just use the correctly sized SUB instruction to get the right EFLAGS.SF value. */
504 off = iemNativeEmitAmd64ModRmInstrRREx(iemNativeInstrBufEnsure(pReNative, off, 4), off,
505 0x2a, 0x2b, cOpBits, idxRegDst, idxRegSrc);
506 IEMNATIVE_ASSERT_INSTR_BUF_ENSURE(pReNative, off);
507
508 iemNativeVarRegisterRelease(pReNative, idxVarSrc);
509 iemNativeVarRegisterRelease(pReNative, idxVarDst);
510
511 off = iemNativeEmitEFlagsForArithmetic(pReNative, off, idxVarEfl);
512
513#elif defined(RT_ARCH_ARM64)
514 /* On ARM64 we'll need the two input operands as well as the result in order
515 to calculate the right flags, even if we use SUBS and translates NZCV into
516 OF, CF, ZF and SF. */
517 uint8_t const idxRegDstIn = iemNativeRegAllocTmp(pReNative, &off);
518 PIEMNATIVEINSTR const pCodeBuf = iemNativeInstrBufEnsure(pReNative, off, 4);
519 if (cOpBits >= 32)
520 {
521 off = iemNativeEmitLoadGprFromGprEx(pCodeBuf, off, idxRegDstIn, idxRegDst);
522 pCodeBuf[off++] = Armv8A64MkInstrSubReg(idxRegDst, idxRegDst, idxRegSrc, cOpBits > 32 /*f64Bit*/, true /*fSetFlags*/);
523 }
524 else
525 {
526 /* Shift the operands up so we can perform a 32-bit operation and get all four flags. */
527 uint32_t const cShift = 32 - cOpBits;
528 pCodeBuf[off++] = Armv8A64MkInstrOrr(idxRegDstIn, ARMV8_A64_REG_XZR, idxRegDst, false /*f64Bit*/, cShift);
529 pCodeBuf[off++] = Armv8A64MkInstrSubReg(idxRegDst, idxRegDstIn, idxRegSrc, false /*f64Bit*/,
530 true /*fSetFlags*/, cShift);
531 pCodeBuf[off++] = Armv8A64MkInstrLsrImm(idxRegDstIn, idxRegDstIn, cShift, false /*f64Bit*/);
532 pCodeBuf[off++] = Armv8A64MkInstrLsrImm(idxRegDst, idxRegDst, cShift, false /*f64Bit*/);
533 cOpBits = 32;
534 }
535 IEMNATIVE_ASSERT_INSTR_BUF_ENSURE(pReNative, off);
536
537 off = iemNativeEmitEFlagsForArithmetic(pReNative, off, idxVarEfl, cOpBits, idxRegDst,
538 idxRegDstIn, idxRegSrc, true /*fNativeFlags*/, true /*fInvertCarry*/);
539
540 iemNativeRegFreeTmp(pReNative, idxRegDstIn);
541 iemNativeVarRegisterRelease(pReNative, idxVarSrc);
542 iemNativeVarRegisterRelease(pReNative, idxVarDst);
543
544#else
545# error "port me"
546#endif
547 return off;
548}
549
550
551/**
552 * The CMP instruction will set all status flags, but modifies no registers.
553 */
554DECL_INLINE_THROW(uint32_t)
555iemNativeEmit_cmp_r_r_efl(PIEMRECOMPILERSTATE pReNative, uint32_t off,
556 uint8_t idxVarDst, uint8_t idxVarSrc, uint8_t idxVarEfl, uint8_t cOpBits)
557{
558 uint8_t const idxRegDst = iemNativeVarRegisterAcquire(pReNative, idxVarDst, &off, true /*fInitialized*/);
559 uint8_t const idxRegSrc = iemNativeVarRegisterAcquire(pReNative, idxVarSrc, &off, true /*fInitialized*/);
560
561#ifdef RT_ARCH_AMD64
562 /* On AMD64 we just use the correctly sized CMP instruction to get the right EFLAGS.SF value. */
563 off = iemNativeEmitAmd64ModRmInstrRREx(iemNativeInstrBufEnsure(pReNative, off, 4), off,
564 0x3a, 0x3b, cOpBits, idxRegDst, idxRegSrc);
565 IEMNATIVE_ASSERT_INSTR_BUF_ENSURE(pReNative, off);
566
567 iemNativeVarRegisterRelease(pReNative, idxVarSrc);
568 iemNativeVarRegisterRelease(pReNative, idxVarDst);
569
570 off = iemNativeEmitEFlagsForArithmetic(pReNative, off, idxVarEfl);
571
572#elif defined(RT_ARCH_ARM64)
573 /* On ARM64 we'll need the actual result as well as both input operands in order
574 to calculate the right flags, even if we use SUBS and translates NZCV into
575 OF, CF, ZF and SF. */
576 uint8_t const idxRegResult = iemNativeRegAllocTmp(pReNative, &off);
577 PIEMNATIVEINSTR const pCodeBuf = iemNativeInstrBufEnsure(pReNative, off, 3);
578 if (cOpBits >= 32)
579 pCodeBuf[off++] = Armv8A64MkInstrSubReg(idxRegResult, idxRegDst, idxRegSrc, cOpBits > 32 /*f64Bit*/, true /*fSetFlags*/);
580 else
581 {
582 /* Shift the operands up so we can perform a 32-bit operation and get all four flags. */
583 uint32_t const cShift = 32 - cOpBits;
584 pCodeBuf[off++] = Armv8A64MkInstrOrr(idxRegResult, ARMV8_A64_REG_XZR, idxRegDst, false /*f64Bit*/, cShift);
585 pCodeBuf[off++] = Armv8A64MkInstrSubReg(idxRegResult, idxRegResult, idxRegSrc, false /*f64Bit*/,
586 true /*fSetFlags*/, cShift);
587 pCodeBuf[off++] = Armv8A64MkInstrLsrImm(idxRegResult, idxRegResult, cShift, false /*f64Bit*/);
588 cOpBits = 32;
589 }
590 IEMNATIVE_ASSERT_INSTR_BUF_ENSURE(pReNative, off);
591
592 off = iemNativeEmitEFlagsForArithmetic(pReNative, off, idxVarEfl, cOpBits, idxRegResult,
593 idxRegDst, idxRegSrc, true /*fNativeFlags*/, true /*fInvertCarry*/);
594
595 iemNativeRegFreeTmp(pReNative, idxRegResult);
596 iemNativeVarRegisterRelease(pReNative, idxVarSrc);
597 iemNativeVarRegisterRelease(pReNative, idxVarDst);
598
599#else
600# error "port me"
601#endif
602 return off;
603}
604
605
606DECL_INLINE_THROW(uint32_t)
607iemNativeEmit_sbb_r_r_efl(PIEMRECOMPILERSTATE pReNative, uint32_t off,
608 uint8_t idxVarDst, uint8_t idxVarSrc, uint8_t idxVarEfl, uint8_t cOpBits)
609{
610 RT_NOREF(idxVarDst, idxVarSrc, idxVarEfl, cOpBits);
611 AssertFailed();
612 return iemNativeEmitBrk(pReNative, off, 0x666);
613}
614
615
616DECL_INLINE_THROW(uint32_t)
617iemNativeEmit_imul_r_r_efl(PIEMRECOMPILERSTATE pReNative, uint32_t off,
618 uint8_t idxVarDst, uint8_t idxVarSrc, uint8_t idxVarEfl, uint8_t cOpBits)
619{
620 RT_NOREF(idxVarDst, idxVarSrc, idxVarEfl, cOpBits);
621 AssertFailed();
622 return iemNativeEmitBrk(pReNative, off, 0x666);
623}
624
625
626DECL_INLINE_THROW(uint32_t)
627iemNativeEmit_popcnt_r_r_efl(PIEMRECOMPILERSTATE pReNative, uint32_t off,
628 uint8_t idxVarDst, uint8_t idxVarSrc, uint8_t idxVarEfl, uint8_t cOpBits)
629{
630 RT_NOREF(idxVarDst, idxVarSrc, idxVarEfl, cOpBits);
631 AssertFailed();
632 return iemNativeEmitBrk(pReNative, off, 0x666);
633}
634
635
636DECL_INLINE_THROW(uint32_t)
637iemNativeEmit_tzcnt_r_r_efl(PIEMRECOMPILERSTATE pReNative, uint32_t off,
638 uint8_t idxVarDst, uint8_t idxVarSrc, uint8_t idxVarEfl, uint8_t cOpBits)
639{
640 RT_NOREF(idxVarDst, idxVarSrc, idxVarEfl, cOpBits);
641 AssertFailed();
642 return iemNativeEmitBrk(pReNative, off, 0x666);
643}
644
645
646DECL_INLINE_THROW(uint32_t)
647iemNativeEmit_lzcnt_r_r_efl(PIEMRECOMPILERSTATE pReNative, uint32_t off,
648 uint8_t idxVarDst, uint8_t idxVarSrc, uint8_t idxVarEfl, uint8_t cOpBits)
649{
650 RT_NOREF(idxVarDst, idxVarSrc, idxVarEfl, cOpBits);
651 AssertFailed();
652 return iemNativeEmitBrk(pReNative, off, 0x666);
653}
654
655
656#endif /* !VMM_INCLUDED_SRC_VMMAll_target_x86_IEMAllN8veEmit_x86_h */
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