Changeset 103682 in vbox
- Timestamp:
- Mar 5, 2024 2:23:15 PM (13 months ago)
- svn:sync-xref-src-repo-rev:
- 162047
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/VMM/VMMAll/target-x86/IEMAllN8veEmit-x86.h
r103677 r103682 273 273 274 274 275 /** 276 * The AND instruction will clear OF, CF and AF (latter is undefined) and 277 * set the other flags according to the result. 278 */ 275 279 DECL_INLINE_THROW(uint32_t) 276 280 iemNativeEmit_and_r_r_efl(PIEMRECOMPILERSTATE pReNative, uint32_t off, 277 281 uint8_t idxVarDst, uint8_t idxVarSrc, uint8_t idxVarEfl, uint8_t cOpBits) 278 282 { 279 /*280 * The AND instruction will clear OF, CF and AF (latter is undefined),281 * so we don't need the initial destination value.282 *283 * On AMD64 we must use the correctly sized AND instructions to get the284 * right EFLAGS.SF value, while the rest will just lump 16-bit and 8-bit285 * in the 32-bit ones.286 */287 /** @todo we could use ANDS on ARM64 and get the ZF for free for all288 * variants, and SF for 32-bit and 64-bit. */289 283 uint8_t const idxRegDst = iemNativeVarRegisterAcquire(pReNative, idxVarDst, &off, true /*fInitialized*/); 290 284 uint8_t const idxRegSrc = iemNativeVarRegisterAcquire(pReNative, idxVarSrc, &off, true /*fInitialized*/); 291 //off = iemNativeEmitBrk(pReNative, off, 0x2222); 292 switch (cOpBits) 293 { 294 case 32: 295 #ifndef RT_ARCH_AMD64 296 case 16: 297 case 8: 298 #endif 299 off = iemNativeEmitAndGpr32ByGpr32(pReNative, off, idxRegDst, idxRegSrc); 300 break; 301 302 default: AssertFailed(); RT_FALL_THRU(); 303 case 64: 304 off = iemNativeEmitAndGprByGpr(pReNative, off, idxRegDst, idxRegSrc); 305 break; 306 307 #ifdef RT_ARCH_AMD64 308 case 16: 309 { 310 PIEMNATIVEINSTR pCodeBuf = iemNativeInstrBufEnsure(pReNative, off, 1); 311 pCodeBuf[off++] = X86_OP_PRF_SIZE_OP; 312 off = iemNativeEmitAndGpr32ByGpr32(pReNative, off, idxRegDst, idxRegSrc); 313 break; 314 } 315 316 case 8: 317 { 318 PIEMNATIVEINSTR pCodeBuf = iemNativeInstrBufEnsure(pReNative, off, 3); 319 if (idxRegDst >= 8 || idxRegSrc >= 8) 320 pCodeBuf[off++] = (idxRegDst >= 8 ? X86_OP_REX_R : 0) | (idxRegSrc >= 8 ? X86_OP_REX_B : 0); 321 else if (idxRegDst >= 4 || idxRegSrc >= 4) 322 pCodeBuf[off++] = X86_OP_REX; 323 pCodeBuf[off++] = 0x22; 324 pCodeBuf[off++] = X86_MODRM_MAKE(X86_MOD_REG, idxRegDst & 7, idxRegSrc & 7); 325 IEMNATIVE_ASSERT_INSTR_BUF_ENSURE(pReNative, off); 326 break; 327 } 328 #endif 329 } 285 #ifdef RT_ARCH_AMD64 286 /* On AMD64 we just use the correctly size AND instruction harvest the EFLAGS. */ 287 off = iemNativeEmitAmd64ModRmInstrRREx(iemNativeInstrBufEnsure(pReNative, off, 4), off, 288 0x22, 0x23, cOpBits, idxRegDst, idxRegSrc); 289 IEMNATIVE_ASSERT_INSTR_BUF_ENSURE(pReNative, off); 290 291 #elif defined(RT_ARCH_ARM64) 292 /* On ARM64 we use 32-bit AND for the 8-bit and 16-bit bit ones. */ 293 /** @todo we should use ANDS on ARM64 and get the ZF for free for all 294 * variants, and SF for 32-bit and 64-bit. */ 295 PIEMNATIVEINSTR const pCodeBuf = iemNativeInstrBufEnsure(pReNative, off, 1); 296 pCodeBuf[off++] = Armv8A64MkInstrAnd(idxRegDst, idxRegDst, idxRegSrc, cOpBits > 32 /*f64Bit*/); 297 IEMNATIVE_ASSERT_INSTR_BUF_ENSURE(pReNative, off); 298 299 #else 300 # error "Port me" 301 #endif 330 302 iemNativeVarRegisterRelease(pReNative, idxVarSrc); 331 303 … … 336 308 337 309 310 /** 311 * The TEST instruction will clear OF, CF and AF (latter is undefined) and 312 * set the other flags according to the result. 313 */ 338 314 DECL_INLINE_THROW(uint32_t) 339 315 iemNativeEmit_test_r_r_efl(PIEMRECOMPILERSTATE pReNative, uint32_t off, 340 316 uint8_t idxVarDst, uint8_t idxVarSrc, uint8_t idxVarEfl, uint8_t cOpBits) 341 317 { 342 /*343 * The TESTS instruction will clear OF, CF and AF (latter is undefined),344 * so we don't need the initial destination value.345 *346 * On AMD64 we use the matching native instruction.347 *348 * On ARM64 we need a real register for the AND result so we can calculate349 * PF correctly for it. This means that we have to use a three operand350 * AND variant, which makes the code widely different from AMD64.351 */352 /** @todo we could use ANDS on ARM64 and get the ZF for free for all353 * variants, and SF for 32-bit and 64-bit. */354 318 uint8_t const idxRegDst = iemNativeVarRegisterAcquire(pReNative, idxVarDst, &off, true /*fInitialized*/); 355 319 uint8_t const idxRegSrc = idxVarSrc == idxVarDst ? idxRegDst /* special case of 'test samereg,samereg' */ 356 320 : iemNativeVarRegisterAcquire(pReNative, idxVarSrc, &off, true /*fInitialized*/); 357 #ifndef RT_ARCH_AMD64 321 #ifdef RT_ARCH_AMD64 322 /* On AMD64 we just use the correctly size TEST instruction harvest the EFLAGS. */ 323 off = iemNativeEmitAmd64ModRmInstrRREx(iemNativeInstrBufEnsure(pReNative, off, 4), off, 324 0x84, 0x85, cOpBits, idxRegSrc, idxRegDst); 325 IEMNATIVE_ASSERT_INSTR_BUF_ENSURE(pReNative, off); 326 327 #elif defined(RT_ARCH_ARM64) 328 /* On ARM64 we use 32-bit AND for the 8-bit and 16-bit bit ones. We also 329 need to keep the result in order to calculate the flags. */ 330 /** @todo we should use ANDS on ARM64 and get the ZF for free for all 331 * variants, and SF for 32-bit and 64-bit. */ 358 332 uint8_t const idxRegResult = iemNativeRegAllocTmp(pReNative, &off); 359 #endif 360 // off = iemNativeEmitBrk(pReNative, off, 0x2222); 361 PIEMNATIVEINSTR const pCodeBuf = iemNativeInstrBufEnsure(pReNative, off, RT_ARCH_VAL == RT_ARCH_VAL_AMD64 ? 4 : 1); 362 #ifdef RT_ARCH_ARM64 333 PIEMNATIVEINSTR const pCodeBuf = iemNativeInstrBufEnsure(pReNative, off, 1); 363 334 pCodeBuf[off++] = Armv8A64MkInstrAnd(idxRegResult, idxRegDst, idxRegSrc, cOpBits > 32 /*f64Bit*/); 364 365 #elif defined(RT_ARCH_AMD64) 366 switch (cOpBits) 367 { 368 case 16: 369 pCodeBuf[off++] = X86_OP_PRF_SIZE_OP; 370 RT_FALL_THRU(); 371 case 32: 372 if (idxRegDst >= 8 || idxRegSrc >= 8) 373 pCodeBuf[off++] = (idxRegDst >= 8 ? X86_OP_REX_B : 0) | (idxRegSrc >= 8 ? X86_OP_REX_R : 0); 374 pCodeBuf[off++] = 0x85; 375 break; 376 377 default: AssertFailed(); RT_FALL_THRU(); 378 case 64: 379 pCodeBuf[off++] = X86_OP_REX_W | (idxRegDst >= 8 ? X86_OP_REX_B : 0) | (idxRegSrc >= 8 ? X86_OP_REX_R : 0); 380 pCodeBuf[off++] = 0x85; 381 break; 382 383 case 8: 384 if (idxRegDst >= 8 || idxRegSrc >= 8) 385 pCodeBuf[off++] = (idxRegDst >= 8 ? X86_OP_REX_B : 0) | (idxRegSrc >= 8 ? X86_OP_REX_R : 0); 386 else if (idxRegDst >= 4 || idxRegSrc >= 4) 387 pCodeBuf[off++] = X86_OP_REX; 388 pCodeBuf[off++] = 0x84; 389 break; 390 } 391 pCodeBuf[off++] = X86_MODRM_MAKE(X86_MOD_REG, idxRegSrc & 7, idxRegDst & 7); 392 #else 393 # error "port me" 394 #endif 395 IEMNATIVE_ASSERT_INSTR_BUF_ENSURE(pReNative, off); 335 IEMNATIVE_ASSERT_INSTR_BUF_ENSURE(pReNative, off); 336 337 #else 338 # error "Port me" 339 #endif 396 340 if (idxVarSrc != idxVarDst) 397 341 iemNativeVarRegisterRelease(pReNative, idxVarSrc); … … 408 352 409 353 354 /** 355 * The OR instruction will clear OF, CF and AF (latter is undefined) and 356 * set the other flags according to the result. 357 */ 410 358 DECL_INLINE_THROW(uint32_t) 411 359 iemNativeEmit_or_r_r_efl(PIEMRECOMPILERSTATE pReNative, uint32_t off, 412 360 uint8_t idxVarDst, uint8_t idxVarSrc, uint8_t idxVarEfl, uint8_t cOpBits) 413 361 { 414 /*415 * The OR instruction will clear OF, CF and AF (latter is undefined),416 * so we don't need the initial destination value.417 *418 * On AMD64 we must use the correctly sized OR instructions to get the419 * right EFLAGS.SF value, while the rest will just lump 16-bit and 8-bit420 * in the 32-bit ones.421 */422 362 uint8_t const idxRegDst = iemNativeVarRegisterAcquire(pReNative, idxVarDst, &off, true /*fInitialized*/); 423 363 uint8_t const idxRegSrc = iemNativeVarRegisterAcquire(pReNative, idxVarSrc, &off, true /*fInitialized*/); 424 //off = iemNativeEmitBrk(pReNative, off, 0x2222); 425 switch (cOpBits) 426 { 427 case 32: 428 #ifndef RT_ARCH_AMD64 429 case 16: 430 case 8: 431 #endif 432 off = iemNativeEmitOrGpr32ByGpr(pReNative, off, idxRegDst, idxRegSrc); 433 break; 434 435 default: AssertFailed(); RT_FALL_THRU(); 436 case 64: 437 off = iemNativeEmitOrGprByGpr(pReNative, off, idxRegDst, idxRegSrc); 438 break; 439 440 #ifdef RT_ARCH_AMD64 441 case 16: 442 { 443 PIEMNATIVEINSTR pCodeBuf = iemNativeInstrBufEnsure(pReNative, off, 1); 444 pCodeBuf[off++] = X86_OP_PRF_SIZE_OP; 445 off = iemNativeEmitOrGpr32ByGpr(pReNative, off, idxRegDst, idxRegSrc); 446 break; 447 } 448 449 case 8: 450 { 451 PIEMNATIVEINSTR pCodeBuf = iemNativeInstrBufEnsure(pReNative, off, 3); 452 if (idxRegDst >= 8 || idxRegSrc >= 8) 453 pCodeBuf[off++] = (idxRegDst >= 8 ? X86_OP_REX_R : 0) | (idxRegSrc >= 8 ? X86_OP_REX_B : 0); 454 else if (idxRegDst >= 4 || idxRegSrc >= 4) 455 pCodeBuf[off++] = X86_OP_REX; 456 pCodeBuf[off++] = 0x0a; 457 pCodeBuf[off++] = X86_MODRM_MAKE(X86_MOD_REG, idxRegDst & 7, idxRegSrc & 7); 458 IEMNATIVE_ASSERT_INSTR_BUF_ENSURE(pReNative, off); 459 break; 460 } 461 #endif 462 } 364 #ifdef RT_ARCH_AMD64 365 /* On AMD64 we just use the correctly size OR instruction harvest the EFLAGS. */ 366 off = iemNativeEmitAmd64ModRmInstrRREx(iemNativeInstrBufEnsure(pReNative, off, 4), off, 367 0x0a, 0x0b, cOpBits, idxRegDst, idxRegSrc); 368 IEMNATIVE_ASSERT_INSTR_BUF_ENSURE(pReNative, off); 369 370 #elif defined(RT_ARCH_ARM64) 371 /* On ARM64 we use 32-bit OR for the 8-bit and 16-bit bit ones. */ 372 PIEMNATIVEINSTR const pCodeBuf = iemNativeInstrBufEnsure(pReNative, off, 1); 373 pCodeBuf[off++] = Armv8A64MkInstrOrr(idxRegDst, idxRegDst, idxRegSrc, cOpBits > 32 /*f64Bit*/); 374 IEMNATIVE_ASSERT_INSTR_BUF_ENSURE(pReNative, off); 375 376 #else 377 # error "Port me" 378 #endif 463 379 iemNativeVarRegisterRelease(pReNative, idxVarSrc); 464 380 … … 469 385 470 386 387 /** 388 * The XOR instruction will clear OF, CF and AF (latter is undefined) and 389 * set the other flags according to the result. 390 */ 471 391 DECL_INLINE_THROW(uint32_t) 472 392 iemNativeEmit_xor_r_r_efl(PIEMRECOMPILERSTATE pReNative, uint32_t off, 473 393 uint8_t idxVarDst, uint8_t idxVarSrc, uint8_t idxVarEfl, uint8_t cOpBits) 474 394 { 475 /*476 * The XOR instruction will clear OF, CF and AF (latter is undefined),477 * so we don't need the initial destination value.478 *479 * On AMD64 we must use the correctly sizeed XOR instructions to get the480 * right EFLAGS.SF value, while the rest will just lump 16-bit and 8-bit481 * in the 32-bit ones.482 */483 395 uint8_t const idxRegDst = iemNativeVarRegisterAcquire(pReNative, idxVarDst, &off, true /*fInitialized*/); 484 396 uint8_t const idxRegSrc = iemNativeVarRegisterAcquire(pReNative, idxVarSrc, &off, true /*fInitialized*/); 485 //off = iemNativeEmitBrk(pReNative, off, 0x2222); 486 switch (cOpBits) 487 { 488 case 32: 489 #ifndef RT_ARCH_AMD64 490 case 16: 491 case 8: 492 #endif 493 off = iemNativeEmitXorGpr32ByGpr32(pReNative, off, idxRegDst, idxRegSrc); 494 break; 495 496 default: AssertFailed(); RT_FALL_THRU(); 497 case 64: 498 off = iemNativeEmitXorGprByGpr(pReNative, off, idxRegDst, idxRegSrc); 499 break; 500 501 #ifdef RT_ARCH_AMD64 502 case 16: 503 { 504 PIEMNATIVEINSTR pCodeBuf = iemNativeInstrBufEnsure(pReNative, off, 1); 505 pCodeBuf[off++] = X86_OP_PRF_SIZE_OP; 506 off = iemNativeEmitXorGpr32ByGpr32(pReNative, off, idxRegDst, idxRegSrc); 507 break; 508 } 509 510 case 8: 511 { 512 PIEMNATIVEINSTR pCodeBuf = iemNativeInstrBufEnsure(pReNative, off, 3); 513 if (idxRegDst >= 8 || idxRegSrc >= 8) 514 pCodeBuf[off++] = (idxRegDst >= 8 ? X86_OP_REX_R : 0) | (idxRegSrc >= 8 ? X86_OP_REX_B : 0); 515 else if (idxRegDst >= 4 || idxRegSrc >= 4) 516 pCodeBuf[off++] = X86_OP_REX; 517 pCodeBuf[off++] = 0x32; 518 pCodeBuf[off++] = X86_MODRM_MAKE(X86_MOD_REG, idxRegDst & 7, idxRegSrc & 7); 519 IEMNATIVE_ASSERT_INSTR_BUF_ENSURE(pReNative, off); 520 break; 521 } 522 #endif 523 } 397 #ifdef RT_ARCH_AMD64 398 /* On AMD64 we just use the correctly size OR instruction harvest the EFLAGS. */ 399 off = iemNativeEmitAmd64ModRmInstrRREx(iemNativeInstrBufEnsure(pReNative, off, 4), off, 400 0x32, 0x33, cOpBits, idxRegDst, idxRegSrc); 401 IEMNATIVE_ASSERT_INSTR_BUF_ENSURE(pReNative, off); 402 403 #elif defined(RT_ARCH_ARM64) 404 /* On ARM64 we use 32-bit OR for the 8-bit and 16-bit bit ones. */ 405 PIEMNATIVEINSTR const pCodeBuf = iemNativeInstrBufEnsure(pReNative, off, 1); 406 pCodeBuf[off++] = Armv8A64MkInstrEor(idxRegDst, idxRegDst, idxRegSrc, cOpBits > 32 /*f64Bit*/); 407 IEMNATIVE_ASSERT_INSTR_BUF_ENSURE(pReNative, off); 408 409 #else 410 # error "Port me" 411 #endif 524 412 iemNativeVarRegisterRelease(pReNative, idxVarSrc); 525 413 … … 560 448 uint8_t const idxRegSrc = iemNativeVarRegisterAcquire(pReNative, idxVarSrc, &off, true /*fInitialized*/); 561 449 562 #ifdef RT_ARCH_ARM64 450 #ifdef RT_ARCH_AMD64 451 /* On AMD64 we just use the correctly sized SUB instruction to get the right EFLAGS.SF value. */ 452 off = iemNativeEmitAmd64ModRmInstrRREx(iemNativeInstrBufEnsure(pReNative, off, 4), off, 453 0x2a, 0x2b, cOpBits, idxRegDst, idxRegSrc); 454 IEMNATIVE_ASSERT_INSTR_BUF_ENSURE(pReNative, off); 455 456 iemNativeVarRegisterRelease(pReNative, idxVarSrc); 457 iemNativeVarRegisterRelease(pReNative, idxVarDst); 458 459 off = iemNativeEmitEFlagsForArithmetic(pReNative, off, idxVarEfl); 460 461 #elif defined(RT_ARCH_ARM64) 563 462 /* On ARM64 we'll need the two input operands as well as the result in order 564 463 to calculate the right flags, even if we use SUBS and translates NZCV into 565 464 OF, CF, ZF and SF. */ 566 567 465 uint8_t const idxRegDstIn = iemNativeRegAllocTmp(pReNative, &off); 568 466 PIEMNATIVEINSTR const pCodeBuf = iemNativeInstrBufEnsure(pReNative, off, 4); … … 592 490 iemNativeVarRegisterRelease(pReNative, idxVarDst); 593 491 594 #elif defined(RT_ARCH_AMD64)595 /* On AMD64 we just use the correctly sized SUB instruction to get the right EFLAGS.SF value. */596 off = iemNativeEmitAmd64ModRmInstrRREx(iemNativeInstrBufEnsure(pReNative, off, 4), off,597 0x2a, 0x2b, cOpBits, idxRegDst, idxRegSrc);598 IEMNATIVE_ASSERT_INSTR_BUF_ENSURE(pReNative, off);599 600 iemNativeVarRegisterRelease(pReNative, idxVarSrc);601 iemNativeVarRegisterRelease(pReNative, idxVarDst);602 603 off = iemNativeEmitEFlagsForArithmetic(pReNative, off, idxVarEfl);604 605 492 #else 606 493 # error "port me" … … 620 507 uint8_t const idxRegSrc = iemNativeVarRegisterAcquire(pReNative, idxVarSrc, &off, true /*fInitialized*/); 621 508 622 #ifdef RT_ARCH_ARM64 509 #ifdef RT_ARCH_AMD64 510 /* On AMD64 we just use the correctly sized CMP instruction to get the right EFLAGS.SF value. */ 511 off = iemNativeEmitAmd64ModRmInstrRREx(iemNativeInstrBufEnsure(pReNative, off, 4), off, 512 0x3a, 0x3b, cOpBits, idxRegDst, idxRegSrc); 513 IEMNATIVE_ASSERT_INSTR_BUF_ENSURE(pReNative, off); 514 515 iemNativeVarRegisterRelease(pReNative, idxVarSrc); 516 iemNativeVarRegisterRelease(pReNative, idxVarDst); 517 518 off = iemNativeEmitEFlagsForArithmetic(pReNative, off, idxVarEfl); 519 520 #elif defined(RT_ARCH_ARM64) 623 521 /* On ARM64 we'll need the actual result as well as both input operands in order 624 522 to calculate the right flags, even if we use SUBS and translates NZCV into 625 523 OF, CF, ZF and SF. */ 626 627 524 uint8_t const idxRegResult = iemNativeRegAllocTmp(pReNative, &off); 628 525 PIEMNATIVEINSTR const pCodeBuf = iemNativeInstrBufEnsure(pReNative, off, 3); … … 648 545 iemNativeVarRegisterRelease(pReNative, idxVarDst); 649 546 650 #elif defined(RT_ARCH_AMD64)651 /* On AMD64 we just use the correctly sized CMP instruction to get the right EFLAGS.SF value. */652 off = iemNativeEmitAmd64ModRmInstrRREx(iemNativeInstrBufEnsure(pReNative, off, 4), off,653 0x3a, 0x3b, cOpBits, idxRegDst, idxRegSrc);654 IEMNATIVE_ASSERT_INSTR_BUF_ENSURE(pReNative, off);655 656 iemNativeVarRegisterRelease(pReNative, idxVarSrc);657 iemNativeVarRegisterRelease(pReNative, idxVarDst);658 659 off = iemNativeEmitEFlagsForArithmetic(pReNative, off, idxVarEfl);660 661 547 #else 662 548 # error "port me"
Note:
See TracChangeset
for help on using the changeset viewer.