Compare commits

...
267 Commits
Author SHA1 Message Date
ptitSeb 7eeb501649 Bumped version to v0.4.2 2026-04-20 18:33:09 +02:00
Yang Liu fe6b9327d1 [DYNAREC] Fixed 69 IMUL opcode load immediate (#3795) 2026-04-20 14:33:45 +02:00
ptitSeb d43e64ee46 [WRAPPER] Added a few more symbols to libhoweed6 2026-04-20 12:06:12 +02:00
ptitSeb e477ccdb19 [WRAPPER] Fixed a potential issue with realpath wrapping 2026-04-20 10:11:35 +02:00
ptitSeb d0c1ec5c8c [TRACE] Fixed a potential issue with mkdirat trace 2026-04-20 10:08:52 +02:00
ptitSeb 274946acf5 [WRAPPER] Fixed an OpenGL extension 2026-04-20 09:53:52 +02:00
Yang Liu 3c976b1ffb [LA64_DYNAREC] Fixed amadd_db.b use in lock opcodes (#3793) 2026-04-18 20:57:22 +02:00
Yang Liu 48c1f8fb11 [LA64_DYNAREC] Fixed dec32 non-lbt path SF computation (#3792) 2026-04-18 20:56:43 +02:00
Yang Liu 599360ce07 [DYNAREC] Fixed callret=2 with always_test out-of-bounds read (#3790)
With callret=2 and always_test=1, CALLRET_RET in pass2 skips writing callret entries, thus callret_size=0. But CALLRET_GETRET in pass3 still reads callrets[0], which is an out-of-bounds read. The garbage offset becomes the native return address, causing RET to jump to a wrong
address. I had this issue on LoongArch with 16KiB page size kernel, but this seems universal so all three backends are changed.
2026-04-18 10:55:59 +02:00
Yang Liu b41c3f22be [TEST] Refactored arg parsing and allow to run single combo by number (#3789) 2026-04-18 10:50:41 +02:00
Yang Liu 13cb80d1b7 [LA64_DYNAREC] Fixed BSF/BSR pf computtation (#3788) 2026-04-18 09:26:24 +02:00
Yang Liu a4479a9ac0 [LA64_DYNAREC] Fixed PCMPESTRI opcode (#3787) 2026-04-17 20:28:27 +02:00
Yang Liu 7edd021c17 [LA64_DYNAREC] Fixed LOCK XADD opcode flags computation (#3786)
gd is a full width register, x5 should be used here.
2026-04-17 20:26:47 +02:00
a9ix f6beb4320e [BOX32] Add library path used by Debian "cross" packages (#3785) 2026-04-17 10:12:42 +02:00
ptitSeb 55e8ebf525 [WOWBOX64] Do not clobber return EAX on NT syscall (for #3782) 2026-04-16 09:15:20 +02:00
ptitSeb f388a8f493 [BOX32][WRAPPER] Added a few more wrapped symbols for SDL1 2026-04-13 13:47:01 +02:00
Yang Liu 3e71087a87 [TEST] Optimized combo with dynarec=0 (#3781)
Following config now has 4 combos instead of 6.
```
{
  "BOX64_DYNAREC": ["0", "1"],
  "BOX64_DYNAREC_CALLRET": ["0", "1", "2"]
}
```
2026-04-13 08:18:21 +02:00
Yang Liu 24e4039d1f [TEST][BOX32] Added proper handling for running 32-bit tests on non-Box32 builds (#3780) 2026-04-13 08:12:13 +02:00
ptitSeb fc8a05e693 [RV64_DYNAREC] Added FAR RET(N) with CALLRET support 2026-04-12 17:07:18 +02:00
ptitSeb ee99b5b167 [RV64_DYNAREC] Refactored IRET so it support CALLRET optimisation 2026-04-12 16:20:56 +02:00
ptitSeb 2f23572e02 [RV64_DYNAREC] Refactored RET/RETN opcodes 2026-04-12 15:57:35 +02:00
ptitSeb 21d66686da [RV64_DYNAREC] Added some workaround for gameoverui crashing 2026-04-12 15:39:03 +02:00
ptitSeb 01af6f3164 [RV64_DYNAREC] Added CALL FAR support 2026-04-12 15:33:03 +02:00
ptitSeb c845ab01c4 [RV64_DYNAREC] Added CALLRET=2 and SEP support 2026-04-12 12:23:55 +02:00
ptitSeb 13c9fdaa40 [WRAPPER][VULKAN] Added some more vulkan extensions 2026-04-11 14:03:37 +02:00
ptitSeb 0bc4d5b532 [CI] Hacking a way around termux-docker debloblification 2026-04-11 09:04:26 +02:00
Yang Liu 18a3f1b039 [ARM64_DYNAREC] Fixed LOCK NOT opcode non atomics path (#3777) 2026-04-11 08:39:12 +02:00
Yang Liu b99dde293d [ARM64_DYNAREC] Fixed uninitilized scratch registers for VCVTTPD2DQ opcode (#3776) 2026-04-10 20:07:39 +02:00
ptitSeb ff634b1e0c [RCFILE] Fine tuned 2 games profile 2026-04-10 14:08:08 +02:00
ptitSeb 657d69aa3b [WRAPPER] Added libgmp.so wrapping too (for #3747) 2026-04-09 17:00:28 +02:00
Yang Liu 913abd14f0 [TEST] Support array values in baked-in variables for combinatorial runs (#3774)
Following example will be ran 8 times (4x2) with all possible combinations.
```
%ifdef CONFIG
{
  "RegData": {
    "RAX": "1"
  },
  "Variables": {
    "BOX64_DYNAREC_BIGBLOCK": ["0", "1", "2", "3"],
    "BOX64_DYNAREC_NATIVEFLAGS": ["0", "1"]
  }
}
%endif

mov rax, 1
hlt
```
2026-04-09 14:02:59 +02:00
Yang Liu 1a7ea1c09a [TEST] Supported baking env variables settings into test (#3773)
Example:
```
%ifdef CONFIG
{
  "Variables": { "BOX64_LOG": "0" }
}
%endif

nop
hlt
```
2026-04-09 08:53:30 +02:00
Yang Liu 08934a3b0c [ARM64_DYNAREC] Better fix for #3762 (#3772)
* [ARM64_DYNAREC] Better fix for #3762

* Fixed more similar patterns
2026-04-08 21:24:10 +02:00
ptitSeb 55c967fe9d [RCFILE] Added some more game profiles 2026-04-08 19:14:12 +02:00
ptitSeb dea4646116 [LA64_DYNAREC] Added AutoCRC support 2026-04-08 19:05:02 +02:00
ptitSeb c90a2ab5a4 [ARM64_DYNAREC] Added some potentials fixes for missing AutoCRC on CALLRET return 2026-04-08 18:47:12 +02:00
ptitSeb 06f5fa3e6c [ARM64_DYNAREC] Fixed autoCRC on Secondary Entry Point 2026-04-08 15:04:13 +02:00
ptitSeb 2260cf8a48 [LA64_DYNAREC] Add CALRET=2 and Secondary Entry Points support 2026-04-08 14:20:10 +02:00
ptitSeb 5571c43de6 [RCFILE] Added some more game profiles 2026-04-08 14:19:01 +02:00
ptitSeb 91b32b01d5 [WRAPPER] Added 1 more dbus symbol 2026-04-08 11:05:40 +02:00
Yang Liu 95b4d665cf [INTERP] Fixed BEXTR opcode (#3770) 2026-04-08 10:24:42 +02:00
ptitSeb ac35b41b9d [WRAPPER] Aded 1 more symbol to gmodule (should be wrapped tho) 2026-04-08 09:40:52 +02:00
Yang Liu 2db72f51be [ARM64_DYNAREC] Removed VMASKMOVPS/D ymm zero gate (#3769)
* [ARM64_DYNAREC] Removed VMASKMOVPS/D ymm zero gate

The gate is an optimization to skip upper 128-bit when the mask is known zero. However, after a merge point, `is_avx_zero()` can return false at step 0 and true at step 3. So step 0 sets wrong `ymm0_sub` -> `updateYmm0s()` sets wrong `ymm_in` for successor, and step 3 never corrects that as it's skipped. Fixed this by making the block unconditional so step 0&3 always agree.

* review
2026-04-08 08:57:38 +02:00
ptitSeb 3c266d33e3 [ARM64_DYNAREC] Some minor modifications on callret and SEP handling 2026-04-07 16:30:46 +02:00
ptitSeb feaf6ffbd0 [DYNAREC] Removed DYNAREC_HOTPAGE_ALT and reworked DIRTY=2 ([ARM64_DYNAREC] only) 2026-04-07 13:47:55 +02:00
Yang Liu 91788694ba [ARM64_DYNAREC] Fixed a regression introduced in #3766 (#3768) 2026-04-07 13:24:47 +02:00
Yang Liu 1f921abaec [INTERP] Fixed cvtf32_16 SNaN -> QNaN conversion (#3767) 2026-04-07 13:23:35 +02:00
Yang Liu 0874bb4d01 [DYNAREC] Fixed XADD where source register overlapping memory base (#3766) 2026-04-07 08:10:51 +02:00
Yang Liu 6b32d6159f [ARM64_DYNAREC] Fixed ADC/SBB opcodes CAS retry corrupting CF (#3765)
Similar situation as the interpreter.
2026-04-07 08:08:51 +02:00
Yang Liu 83336bcb9f [INTERP] Fixed ADC/SBB opcodes CAS retry corrupting CF (#3764) 2026-04-07 08:07:23 +02:00
Yang Liu fe556e957e [ARM64_DYNAREC] Fixed a edge case of df tracking for LOCK CMPXCHG16B opcode (#3762)
call_c() was called in unaligned path, which set status_none, where the aligned path don't. Fix this issue by explicitly calling FORCE_DFNONE at the converge point.
2026-04-06 22:46:32 +02:00
Yang Liu cbcd11894c [ARM64_DYNAREC] Fixed cmpxchg modreg ed=rax case (#3761) 2026-04-06 16:09:19 +02:00
Yang Liu 29bf151ed9 [ARM64_DYNAREC] Fixed CMPXCHG8B CASPALw equal case (#3760)
CASPALw always writes back to dest pairs, zeroing the upper 32 bits, replace blind moves with conditional updates.
2026-04-06 16:06:11 +02:00
ptitSeb 95b68190b3 [ARM64_DYNAREC] Fixed some rare case where native flags might be lost on some speicific opcode with partial flags update 2026-04-06 10:43:21 +02:00
ptitSeb c596f176bf [ARM64_DYNAREC] Changed MESSAGE macro for cleaner Dumps 2026-04-06 10:42:20 +02:00
Yang Liu 74fd2a0a5d Fixed sse42_compare_string_explicit_len for length=INT_MIN (#3759)
...prevents length=0x80000000 being overflow.
2026-04-05 21:55:36 +02:00
Yang Liu f20db6caae [ARM64_DYNAREC] Refined SNaN propagation for various opcodes (#3758)
This is a follow-up of PR #3754.
2026-04-05 19:56:23 +02:00
Yang Liu dd75b58943 [ARM64_DYNAREC] Fixed YMM zero tracking for dynablock entry instructions (#3757) 2026-04-05 19:54:38 +02:00
Yang Liu 17a84fcc51 [ARM64_DYNAREC] Fixed ANDN PF computation (again) (#3756) 2026-04-05 19:53:09 +02:00
Yang Liu eef68182b3 [ARM64_DYNAREC] Fixed IOC bit reset for CVTTPS2PI/CVTPS2PI opcodes (#3755)
This is same as #3733.
2026-04-05 18:46:51 +02:00
ptitSeb 43dcbf3773 [DYNAREC] Added a way to use Dynarec for alt address, for MALLOC_HACK=2 for example 2026-04-05 15:07:26 +02:00
Yang Liu b1a706a650 [ARM64_DYNAREC] Fixed nan propagation for ADDPS and similar opcodes (#3754) 2026-04-05 14:02:25 +02:00
Yang Liu ce14608947 [ARM64_DYNAREC] Fixed nan propagation typo for VADDSS/D and other similar opcodes (#3753) 2026-04-05 13:59:57 +02:00
Yang Liu dc53da7252 [ARM64_DYNAREC] Fixed CF computation for 16-bit LOCK ADC/SBB (#3752)
This is essentially a fix ported from corresponding non-LOCK version opcodes
2026-04-05 13:58:38 +02:00
Yang Liu 9e2779267f [INTERP] Fixed cvtf16_32 SNaN handling (#3751)
Refer to https://github.com/ucb-bar/berkeley-softfloat-3/blob/master/source/8086/s_commonNaNToF32UI.c#L48, bit 22 should be forced for NaN inputs
2026-04-05 13:57:23 +02:00
ptitSeb 0416caa95a [VULKAN] Added VK_ARM_shader_instrumentation extension (for #3749) 2026-04-05 09:59:32 +02:00
ptitSeb 7e2528c538 [ARM64_DYNAREC] Added F2 0F BD opcode (for #3717) 2026-04-04 16:09:50 +02:00
ptitSeb 58fb00b5f7 [INTERP] Added F2 0F BD opcode (for #3717) 2026-04-04 16:08:58 +02:00
Yang Liu 1957721f37 [INTERP] Fixed nan propagation edge-cases for various opcodes (#3734)
* [INTERP] Convert SNaN to QNaN in CHECK_NAN macros

* [INTERP] Fixed nan propagation edge-cases for various opcodes
2026-04-04 09:20:47 +02:00
ptitSeb 132d40108b [ARM64_DYNAREC] Small optim for BSF/BSR opcodes 2026-04-03 15:44:06 +02:00
ptitSeb c843a2df6a [ARM64_DYNAREC] Fixed a regression introduced with a613ff8277 2026-04-03 14:47:36 +02:00
Yang Liu 58542e4a72 [LA64_DYNAREC] Fixed LOCK NEG opcode (#3742) 2026-04-03 12:12:48 +02:00
Yang Liu ba20a27530 [LA64_DYNAREC] Fixed BSF/BSR PF computation (#3741) 2026-04-03 11:14:48 +02:00
Yang Liu 4743babdf2 [LA64_DYNAREC] Reworked fastnan handling (#3739) 2026-04-03 10:54:16 +02:00
ptitSeb c0c2780db4 [ARM64_DYNAREC] Added some F2/F3 faked prefix opcodes (for #3717) 2026-04-03 10:11:58 +02:00
ptitSeb 97edb1092f [INTERP] Added more F2/F3 faked prefix opcodes (for #3717) 2026-04-03 10:06:30 +02:00
Yang Liu 3697d82ad1 [INTERP][DYNAREC] Reworked PF computaion for ANDN opcode (#3740) 2026-04-03 10:00:36 +02:00
Yang Liu df00419f69 [INTERP] Fixed BZHI opcode (#3738) 2026-04-03 08:57:22 +02:00
ptitSeb 11bb70178b [ARM64_DYNAREC] Added native flags support to float/double comparisons opcodes 2026-04-02 19:14:48 +02:00
ptitSeb 5e03e18c68 [ARM64_DYNAREC] Fixed a regression introduced with #3732 2026-04-02 17:09:47 +02:00
Yang Liu a696462cc3 [LA64_DYNAREC] Fixed Gx equals Ex case for VCVTPD2DQ (#3737) 2026-04-02 12:27:04 +02:00
Yang Liu cda0c94b83 [LA64_DYNAREC] Fixed CF tracing for ADC/SBB opcodes (#3736) 2026-04-02 10:40:40 +02:00
Yang Liu 9a1fcc84b0 [INTERP] Fixed a regression introduced in #3719 (#3735) 2026-04-02 09:44:43 +02:00
Yang Liu 9571135b8d [ARM64_DYNAREC] Fixed IOC bit reset for CVTTPD2PI/CVTPD2PI opcodes (#3733) 2026-04-01 18:29:46 +02:00
Yang Liu 95bd956af8 [ARM64_DYNAREC] Fixed BSF/BSR PF computation (#3732) 2026-04-01 17:35:22 +02:00
Yang Liu 6ebd9c3b32 [INTERP] Fixed cvtf32_16 again (#3731) 2026-04-01 10:08:31 +02:00
ptitSeb 0b9df5d5a0 [BOX32] Fixed BOUND exception signal 2026-03-31 14:47:46 +02:00
ptitSeb c52f2fd01a [WRAPPER] Added many symbols to liblcms2 2026-03-30 20:41:15 +02:00
ptitSeb 0a60b449ca [WRAPPER] Added some more symbol to libcrypto3 2026-03-30 20:32:45 +02:00
ptitSeb b3056386f2 [WRAPPER] Added 1 more function to libmpg123 2026-03-30 20:19:28 +02:00
ptitSeb 63feea5fc4 [WRAPPER] Added more symbols to libmpg123 2026-03-30 20:13:51 +02:00
ptitSeb f4f17b7751 [WRAPPER] Added some symbols to libnettle8 2026-03-30 20:08:23 +02:00
ptitSeb 7750e75bcf [WRAPPER] Added 1 more symbol to libvpx 2026-03-30 20:00:48 +02:00
ptitSeb d0d32e763d [WRAPPER] Added 1 more symbol to libpango 2026-03-30 19:50:00 +02:00
ptitSeb e68b1f7584 [WRAPPER] Added 2 more symbols to libcairo 2026-03-30 19:48:19 +02:00
ptitSeb beaa2c8a3a [WRAPPER] Added 1 more symbol to libgio-2 2026-03-30 19:45:06 +02:00
ptitSeb c48c60a814 [WRAPPER] Added 1 symbol to libgobject-2 2026-03-30 19:40:36 +02:00
ptitSeb 7688169969 [WRAPPER] Added some symbol to libpango 2026-03-30 19:35:40 +02:00
ptitSeb aebde89ba3 [WRAPPER] Added more symbols to libgcrypt 2026-03-30 19:20:23 +02:00
ptitSeb 7f96fa4334 [WRAPPER] Added more symbol to libva 2026-03-30 19:16:18 +02:00
ptitSeb 3206d6a76a [RV64_DYNAREC] This should fix the build 2026-03-30 18:43:24 +02:00
ptitSeb a613ff8277 [ARM64_DYNAREC] Reworked how df_unneeded is propagated 2026-03-30 18:13:05 +02:00
ptitSeb 489bd8de29 [ARM64_DYNAREC] Fixed a regression introduced with 537c8f4c53 2026-03-30 13:58:52 +02:00
ptitSeb d5a1864cfa [ARM64_DYNAREC] ymm0 is an ymm operation... 2026-03-29 18:32:55 +02:00
Mark Zhuang c85b3d6252 [WRAPPER] Fix XML_ParserCreate_MM wrapping (#3686) 2026-03-28 18:29:40 +01:00
Yang Liu 4fc725fc61 [INTERP] Fixed VPSLLW/D opcodes (#3729) 2026-03-28 18:28:22 +01:00
Yang Liu 52fd5ed052 [ARM64_DYNAREC] Fixed 16-bit LOCK OR opcode (#3728) 2026-03-28 17:53:40 +01:00
Yang Liu eb804f37c5 [ARM64_DYNAREC] Fixed a typo in 16-bit LOCK SUB opcode (#3727) 2026-03-28 17:52:43 +01:00
Yang Liu 0c992cdcff [INTERP][ARM64_DYNAREC] Fixed BZHI PF computation (#3726) 2026-03-28 17:24:01 +01:00
Yang Liu 26dcfc7320 [ARM64_DYNAREC] Aligned UD flags with interpreter for ANDN opcode (#3724)
* [ARM64_DYNAREC] Aligned UD flags with interpreter for ANDN opcode

* remove safeguard
2026-03-28 11:36:12 +01:00
Yang Liu 3c3918073f [ARM64_DYNAREC] Fixed 16-bit LOCK XOR opcode (#3723) 2026-03-28 10:24:08 +01:00
Yang Liu 78183c16de [ARM64_DYNAREC] Fixed register conflicts for ARPL opcode (#3722) 2026-03-28 10:11:02 +01:00
ptitSeb 75c7f07571 [ARM64_DYNAREC] Fixed 0F 38 CB opcode on edge case with sha2 fastpath 2026-03-28 10:02:20 +01:00
Yang Liu 961484f463 [LA64_DYNAREC] Fixed F0 80 /4 LOCK AND opcode (#3721) 2026-03-28 09:11:10 +01:00
ptitSeb 54698875f0 [WRAPPER] Added libsmbclient.so wrapping 2026-03-27 20:02:54 +01:00
ptitSeb edb9bc21cf [INTERP] Added F2/F3 0F AF opcode 2026-03-27 20:02:32 +01:00
ptitSeb ce3afa470e [WRAPPER] Added near-complete libssh.so.4 wrapping 2026-03-27 17:23:29 +01:00
ptitSeb 8757bd2b5d [WRAPPER] Fine-tuned libproxy dependancies 2026-03-27 16:22:38 +01:00
ptitSeb d8371894ca [WRAPPER] Added full libproxy.so.1 wrapping 2026-03-27 16:20:26 +01:00
ptitSeb 537c8f4c53 [ARM64_DYNAREC] Reworked xmm/ymm unneeded propagation 2026-03-27 16:03:41 +01:00
ptitSeb 79a34b3d9c [WRAPPER] Added back some left out generated change 2026-03-27 13:51:42 +01:00
ptitSeb f713cc5840 [WRAPPER] Improved hack to have SteamRT3 launching games properly 2026-03-27 12:18:12 +01:00
ptitSeb 6f1d048924 [ARM64_DYNAREC] Small optim to VMASKMOVP[S/D] opcodes 2026-03-27 09:41:56 +01:00
Yang Liu 761b2df415 [INTERP][DYNAREC] Fixed CRC32 register preservation (#3719) 2026-03-27 09:11:40 +01:00
Yang Liu ca7fc7b60b [INTERP] Fixed cvtf32_16 (#3718) 2026-03-27 08:43:53 +01:00
Trung Lê 96239cee6e [PPC64LE_DYNAREC] Add more opcodes (#3709)
* [PPC64LE_DYNAREC] Add conditional jumps (0x70-0x7F), CALL (0xE8), JMP (0xE9/0xEB), RET (0xC2/0xC3)

* [PPC64LE_DYNAREC] Add shift/rotate opcodes (0xC0/0xC1, 0xD0-0xD3) and emit_shift

* [PPC64LE_DYNAREC] Add PUSH immediate (0x68/0x6A), IMUL (0x69/0x6B), XCHG memory (0x86/0x87)
2026-03-27 08:43:12 +01:00
ptitSeb 5828660374 [INTERP] Added more dummy F2/F3 prefixed opcodes (for #3717) 2026-03-27 08:42:45 +01:00
ptitSeb d7c86cadf6 [INTERP] Added F3 0F AD opcode (for #3717) 2026-03-26 18:44:59 +01:00
ptitSeb bff0cf46da [INTERP] Added support for F2 0F C1 opcode (for #3717) 2026-03-26 15:18:48 +01:00
ptitSeb cb362477e8 [WRAPPER] Fixed Display and xcb_connexion tracking 2026-03-26 13:34:26 +01:00
ptitSeb eb3a95e336 Merge branch 'main' of https://github.com/ptitSeb/box64 2026-03-26 13:21:29 +01:00
ptitSeb 3f69a46d9b Allow build on alder kernel withou __NR_close_range (for #3716) 2026-03-26 13:20:49 +01:00
Yang Liu aaa5883f72 [TEST] Tracked MMX registers (#3715) 2026-03-26 11:55:33 +01:00
Yang Liu 66ccc3f65d [LA64_DYNAREC] Fixed SSE PCMPEQQ opcode (#3714) 2026-03-26 09:41:25 +01:00
Yang Liu 5506656a39 [LA64_DYNAREC] Removed assert in x87_get_current_cache ([RV64_DYNAREC] too) (#3710)
It's fine to have the logical ST exceeds 8. This fixes sequence like
```
fsubr st0, st7
fxtract
fucompp
```
2026-03-26 08:53:40 +01:00
Yang Liu d3b60ad6cc [LA64_DYNAREC] Fixed AVX VPINSRB opcode (#3713) 2026-03-26 08:49:51 +01:00
Yang Liu b2b6620e05 [LA64_DYNAREC] Added !fastnan handling for DIVSS opcode (#3712) 2026-03-26 08:43:55 +01:00
Yang Liu ae86b32f14 [TEST] Made json buffer dynamic (#3711) 2026-03-26 08:42:27 +01:00
yzewei 56ec4c57ee [WRAPPER] Add missing cairo/ssl/gssapi/harfbuzz/selinux symbols (#3708)
Signed-off-by: Zewei Yang <[email protected]>
2026-03-26 08:33:17 +01:00
ptitSeb e4270f1d28 [DYNAREC] Do not use dynarec on EntryPoint for an Alt address is no_alt is used, to avoid inifite alt redirection (for #3707) 2026-03-25 12:37:42 +01:00
ptitSeb be199c5812 Prevent inifinte redirection when alt is used to redirect an x64 function, like mallochook does (alternative to #3707) 2026-03-25 09:55:27 +01:00
Trung Lê 8dde29fedf [PPC64LE_DYNAREC] Add ALU immediate opcodes (0x80-0x83) (#3706)
Add ALU immediate dispatch (0x80/0x82 Eb,Ib and 0x81/0x83
Ed,Id/Ib) covering all 8 sub-operations: ADD, OR, ADC, SBB, AND,
SUB, XOR, CMP.
2026-03-25 08:11:56 +01:00
ptitSeb 518f065591 [ARM64_DYNAREC] Improved xmm/ymm unneeded flagging 2026-03-24 18:38:56 +01:00
ptitSeb 4aa0cdf781 [ARM64_DYNAREC][PERMAP] Only generate a line if instruction generated opcodes 2026-03-24 18:02:00 +01:00
ptitSeb 38d793e0b5 [PERFMAP] Changed the function used in perf map generation to gather function name 2026-03-24 18:01:08 +01:00
ptitSeb 00e4f02a2a Imrproved game launch from SteamRT3 2026-03-23 14:34:25 +01:00
ptitSeb 64df236782 [ELFLOADER] Changed a bit how RPATH in elf are handled 2026-03-23 13:34:48 +01:00
ptitSeb 40d796a52f [WRAPPER] Added 1 more gnutls function (for #3704) 2026-03-23 10:44:33 +01:00
Yang Liu 52cd1d09e0 [RV64_DYNAREC] Fixed 66 0F 3A ROUND opcodes sign-bit preserving (#3702) 2026-03-23 09:16:25 +01:00
Yang Liu 93d9e2196f [RV64_DYNAREC] Fixed LOOP opcodes (#3701) 2026-03-23 09:13:37 +01:00
Yang Liu 5534fc6191 [CI] Bumped llvm-mingw to 20260311 (#3700) 2026-03-23 09:12:11 +01:00
Trung Lê 1f853671b1 [PPC64LE_DYNAREC] Add CMP, TEST, ADC and SBB opcodes (#3684)
- CMP: 0x38 (Eb,Gb), 0x39 (Ed,Gd), 0x3A (Gb,Eb), 0x3B (Gd,Ed),
       0x3C (AL,Ib), 0x3D (EAX,Id)
- TEST: 0x84 (Eb,Gb), 0x85 (Ed,Gd), 0xA8 (AL,Ib), 0xA9 (EAX,Id)
- ADC: (0x10-0x15)
- SBB (0x18-0x1D)
2026-03-23 09:11:35 +01:00
Yang Liu 7bf29e8ab9 [WRAPPER] Wrapped 1 more symbol for libc (#3698)
* [WRAPPER] Wrapped 1 more symbol for libc

Used by CS:GO legacy

* static
2026-03-23 09:11:05 +01:00
Yang Liu b2e87cfc16 [WRAPPER] Fixed 5d9e8534 (#3696) 2026-03-22 18:22:40 +01:00
ptitSeb 1c9ab05a1b This should fix non-Dynarec builds 2026-03-22 17:56:27 +01:00
ptitSeb 2df07b594d [DYNAREC] Refactored how Alt are undled with Dynarec 2026-03-22 17:26:52 +01:00
ptitSeb 279c65057a [DYNAREC] Cancel current FillBlock on fork child, as there is only 1 thread running there (and so no block in the making) 2026-03-22 15:48:22 +01:00
Mikura Kyouka 4986517339 [RCFILE] Fix one game profile (#3695) 2026-03-22 07:45:50 +01:00
Yang Liu 5d9e853496 [WRAPPER] Ported the steam vulkan hack to 64-bit (#3692)
* [WRAPPER] Ported the steam vulkan hack to 64-bit

* fix build
2026-03-21 20:12:50 +01:00
ptitSeb 690dfbb35e Various changes for SteamRT3 2026-03-21 15:26:10 +01:00
ptitSeb 26e1cf5e0b Added a new syscall 2026-03-20 20:21:53 +01:00
ptitSeb e09ae017d4 [WRAPPER] Added 1 more funciton libcairo 2026-03-20 17:00:51 +01:00
ptitSeb ca122f4ce2 [ELF] Added 28445ORIGIN handling, same as 2026-03-20 16:33:46 +01:00
ptitSeb f83f593862 This should fix the build 2026-03-20 16:24:04 +01:00
Trung Lê d69d116a90 [WRAPPER] ioctl number x86_64 -> ppc64le translation (#3689)
* [WRAPPER] Add iFEiLp wrapper and wrappedlibctypes.h ioctl type entry

Add the iFEiLp wrapper signature — int32_t fn(x64emu_t*, int32_t,
uintptr_t, void*) — needed by the PPC64LE ioctl wrapper (GOWM).

Also add the iFiLp_t typedef and GO(ioctl, iFiLp_t) entry to
wrappedlibctypes.h so the libc wrapper type table includes ioctl.

* [PPC64LE] Add ioctl_convert() for x86_64 -> PPC64LE ioctl number translation

x86_64 and PPC64LE encode ioctl numbers differently:
- Direction bits: x86 uses 2 bits (NONE=0, WRITE=1, READ=2) at bit 30;
  PPC uses 3 bits (NONE=1, READ=2, WRITE=4) at bit 29
- Size field: x86 uses 14 bits; PPC uses 13 bits
- Old-style terminal ioctls have entirely different hardcoded values
  (e.g. x86 TCGETS=0x5401 vs PPC TCGETS=_IOR('t',19,termios))

Add ioctl_convert() under #ifdef PPC64LE with:
- Switch-based lookup for ~35 old-style terminal/file ioctls (TCGETS,
  FIONREAD, TIOCGWINSZ, etc.)
- Algorithmic translation for _IOC-encoded ioctls: decompose x86
  fields, remap direction bits, recompose as PPC64LE
- Debug logging via printf_log(LOG_DEBUG, ...)

Also add my_ioctl() handler that calls ioctl_convert() then native
ioctl(), to be hooked via GOWM in the next commit.

* [PPC64LE] Hook ioctl translation in libc wrapper and syscall paths

Wire up the ioctl number translation via both code paths that x86_64
programs use to call ioctl:

1. Libc wrapper path: Under #ifdef PPC64LE, change GOW(ioctl, iFiLN)
   to GOWM(ioctl, iFEiLp) so calls go through my_ioctl() which
   translates the ioctl number before calling native ioctl().

2. Syscall path: Add case 16 (sys_ioctl) under #ifdef PPC64LE in
   x64Syscall_linux() that calls ioctl_convert() before the native
   ioctl syscall. Guard the generic table entry [16] with
   #ifndef PPC64LE to avoid conflict.

* [PPC64LE] Add x64printer trace entry for iFEiLp wrapper

Add debug trace formatting for the iFEiLp signature under
#ifdef PPC64LE so BOX64_LOG=1 output shows readable argument values
for ioctl calls: int32_t fd, uintptr_t request, void* arg.
2026-03-20 15:56:27 +01:00
ptitSeb 5b2813382e [WRAPPER] Some more work in gtk wrapping 2026-03-20 15:40:30 +01:00
ptitSeb 8f07d10c0a [WRAPPER] Revised needed libs for libgio-2.0.so 2026-03-20 12:30:58 +01:00
ptitSeb ac2e11908c [WRAPPER] Added 1 more symbol to gtk-2-x11 2026-03-20 12:12:31 +01:00
ptitSeb 49bb5168a7 [WRAPPER] Improved needed libs for wrapped libgio-2.0.so 2026-03-20 12:09:22 +01:00
ptitSeb 9178a54dc6 [WRAPPER] added partial wrapping of libsystemd 2026-03-20 11:34:57 +01:00
Yang Liu 34134c1685 [LA64_DYNAREC] Fixed avx_get_reg for readonly 128bit case (#3688) 2026-03-20 11:17:17 +01:00
Yang Liu 73ce74140a [LA64_DYNAREC] Fixed scratch conflicts for VCVTPS2PH opcode (#3687) 2026-03-20 09:35:55 +01:00
Trung Lê 9401712b3c Add native wrapper for libmvec.so.1 (_ZGVbN2v_sin, _ZGVbN2v_cos) (#3683)
Wrap the SSE2 vectorized sin/cos functions from glibc libmvec using
native scalar sin()/cos() from libm. Since libmvec.so.1 does not exist
as a native library on ppc64le, PRE_INIT uses dlopen(NULL) to obtain a
valid library handle.

All other ~270 libmvec symbols are listed as commented-out entries in
the private header and fall back to emulation.
2026-03-19 14:41:09 +01:00
Yang Liu 37bd00b656 [LA64_DYNAREC] Fixed AVX to SSE migration (#3682) 2026-03-19 11:26:07 +01:00
Yang Liu fba7c6d9b2 [LA64_DYNAREC] Fixed VCVTPS2PH opcode (#3685) 2026-03-19 11:25:41 +01:00
Trung Lê 3d8fcd9780 [PPC64LE_DYNAREC] Add GETED/GETEB/GETGB/GETGBEB/WBACK/GBBACK/EBBACK helper macros and refactor _00.c ALU opcodes to use them (#3677) 2026-03-19 09:18:01 +01:00
Yang Liu 7b7077826f [LA64_DYNAREC] Fixed x87 FISTTP fastround=0 path (#3681) 2026-03-19 08:39:18 +01:00
Yang Liu 435564e172 [LA64_DYNAREC] Fixed AVX VRSQRTSS/VRCPSS opcodes (#3680) 2026-03-19 08:32:05 +01:00
Yang Liu 11a44fc754 [LA64_DYNAREC] Refactored AVX infrastructure (#3679) 2026-03-19 08:14:52 +01:00
Trung Lê 4e5c914ccf [PPC64LE_DYNAREC] Add OR (0x08-0x0D), AND (0x20-0x25), XOR (0x30-0x35) and SUB (0x28-0x2D) opcodes and emitters (#3668)
* [PPC64LE_DYNAREC] Add OR (0x08-0x0D) and SUB (0x28-0x2D) opcodes and emitters

* [PPC64LE_DYNAREC] Add AND (0x20-0x25) and XOR (0x30-0x35) opcodes and emitters

* [PPC64LE_DYNAREC] Remove incorrect SCRATCH_USAGE(0) from ALU opcodes

ALU opcodes (ADD, OR, AND, SUB, XOR) modify x86 eflags and use scratch
registers during native flags fusion, so marking them no_scratch_usage
is incorrect and could corrupt flag state during backward scanning.
Aligns with LoongArch reference implementation which only uses
SCRATCH_USAGE(0) on MOV, LEA, PUSH, POP, and MOVSXD.
2026-03-18 09:20:21 +01:00
ptitSeb 7e1fc8924c [CI] Completly removed all trace of ARM64-GCC-8 build 2026-03-17 13:51:44 +01:00
ptitSeb d6c16aee4b [WRAPPER] Reworked dbus wrapping with wrapperhelper 2026-03-17 13:47:09 +01:00
ptitSeb ed33cbe372 [WRAPPER] Added libtiff.so.6 as alternative for wrapping libtiff5 2026-03-17 13:43:29 +01:00
Yang Liu 7bdc4c3713 [LA64_DYNAREC] Added SGDT/SIDT opcodes (#3676) 2026-03-17 13:24:27 +01:00
ptitSeb 285907753a [STATICBUILD] This should fix build 2026-03-17 13:14:19 +01:00
ptitSeb f91b774440 [WRAPPER] Reworked pthread wrapping with wrapperhelper 2026-03-17 11:45:10 +01:00
ptitSeb a351971364 [ARM64_DYNAREC] RDRAND on memory is not a valid opcode 2026-03-17 11:44:32 +01:00
ptitSeb 4509cb3780 [INTERP] RDRAND on memory is not a valid opcode 2026-03-17 11:44:13 +01:00
ptitSeb a3b63db1ed [CI] Do not build GCC 8 anymore 2026-03-17 11:32:27 +01:00
Yang Liu d2dc1c1806 [INTERP] Fixed RDRAND and RDPID again (#3675)
Sorry about last PR, it was messed up in a rebase.
2026-03-17 10:58:47 +01:00
Yang LiuandCopilot a0ed780f72 [INTERP] Fixed RDRAND and RDPID (#3674)
Co-authored-by: Copilot <[email protected]>
2026-03-17 06:59:05 +01:00
Robin Heinemann d3db6a0021 [WRAPPER] Wrapped 1 more symbol for libc (#3673) 2026-03-16 18:00:48 +01:00
ptitSeb b2101b9b7c [WRAPPER] Reworked libgdk-pîxbuf-2 wrapping 2026-03-16 10:56:46 +01:00
ptitSeb 0af396cec9 [WRAPPER] Completed libgbm wrapping 2026-03-16 10:34:31 +01:00
ptitSeb 52f0fd5421 [ARM64_DYNAREC] Fixed shrd16 deffered flags computation (for #3670) 2026-03-16 08:32:29 +01:00
rajdakin 1f705fc13a [WRAPPERHELPER] Added typedef translation pre-reservation (#3672) 2026-03-15 20:55:53 +01:00
rajdakin 601bba694a [WRAPPERHELPER] Added support for versioned symbols (libpthread), other minor features (#3671) 2026-03-15 16:25:45 +01:00
ptitSeb a724bb70fd [TRACE] Improved F2 FF 25 opcode trace 2026-03-14 18:22:22 +01:00
Yang Liu 08d376c660 [WRAPPER] Wrapped more symbols used by rpcs3 (#3665)
* [WRAPPER] Wrapped more symbols used by rpcs3

* wrrrr

* static build
2026-03-13 18:25:46 +01:00
Yang Liu dfbbf2c0e5 [ARM64_DYNAREC] Fixed scratch register conflict for BZHI opcode (#3661)
GETED may use x1 as ed.
2026-03-13 08:29:17 +01:00
Trung Lê 827236abdf [PPC64LE_DYNAREC] Add ADD opcodes (0x00-0x05) and emitters (#3652)
* [PPC64LE_DYNAREC] Fix SCRATCH_USAGE placement for MOV opcode 0xC6

Remove unnecessary SCRATCH_USAGE(1) from MODREG path of 0xC6 (MOV Eb, Ib)
since scratch register x3 is only needed alongside geted() in the memory path.

Addresses review feedback from ptitSeb and ksco on #3633.

* Add PPC64LE ADD operations (0x00-0x05)

Implements all 6 ADD opcodes for PPC64LE dynarec:
- 0x00: ADD Eb, Gb (byte register to memory/register)
- 0x01: ADD Ed, Gd (dword/qword register to memory/register)
- 0x02: ADD Gb, Eb (byte memory/register to register)
- 0x03: ADD Gd, Ed (dword/qword memory/register to register)
- 0x04: ADD AL, Ib (byte immediate to AL)
- 0x05: ADD EAX, Id (dword/qword immediate to EAX)

Uses existing emit_add8, emit_add32, emit_add8c, and emit_add32c
functions with proper flag handling and SCRATCH_USAGE patterns.

* Fix ADD operations to use manual byte handling like MOV

Rewrite ADD implementations to follow the same pattern as existing
MOV byte operations, manually handling byte register extraction
and insertion instead of relying on undefined macros GETGBEB,
EBBACK, GBBACK, GETED, WBACK that don't exist in the minimal
implementation.

* Add emit_math file and update CMakeLists.txt for ADD operations

Copy dynarec_ppc64le_emit_math.c from full dynarec implementation
to provide emit_add8, emit_add32, emit_add8c, and emit_add32c
functions required by the ADD opcode implementations.

Update CMakeLists.txt to include the emit_math file in the build.

* Remove unused emit functions from PPC64LE dynarec math emitter

Remove 23 emitter functions from dynarec_ppc64le_emit_math.c that are
not called by any current opcode implementation (only ADD opcodes
0x00-0x05 are implemented so far).

Kept: emit_add8, emit_add8c, emit_add32, emit_add32c

* Use consistent eb2/gb2 byte register offset convention

Change eb2 to use (ed & 4) << 1 (yielding 0 or 8) matching the gb2
convention, instead of (ed & 4) >> 2 with repeated * 8 at each use site.

* Fix swapped LDxw arguments in ADD opcodes 0x01 and 0x03

LDxw(Rt, Ra, offset) takes base register before offset, unlike raw
emitters like LBZ(Rt, offset, Ra). The two LDxw calls for memory-operand
ADD had the arguments reversed, causing a segfault on GS-segment TLS
accesses where ed holds the GS base and fixedaddress is 0 (PPC64LE r0
quirk in D-form loads treats RA=0 as literal zero).
2026-03-13 08:24:28 +01:00
Yang Liu cf74a99458 [CI] Added *.def to CI workflow dispatch path (#3662)
* [CI] Added *.def to CI workflow dispatch path

* Revert "[WOW64] Fixed build on my machine (#3660)"

This reverts commit 4a4a03cd2a.
2026-03-13 07:33:17 +01:00
Yang Liu 4a4a03cd2a [WOW64] Fixed build on my machine (#3660)
I had this error:

```
ld.lld: error: duplicate symbol: _stricmp
>>> defined at /home/ksco/Dev/box64/wine/common/crt.c:133
>>>            objects.a(crt.c.obj)
>>> defined at ntdll.a(ntdll.dll)
```
2026-03-12 16:40:28 +01:00
Mark Zhuang 1ad0b9c737 [RV64_DYNAREC] fix GETEX for PMOV (#3624)
PMOV not read 128bit, need GETEX64/GETEX32/GETEX16
2026-03-12 08:53:12 +01:00
Yang Liu 18926d8e8c [LA64_DYNAREC] Fixed F0 F7 /3 LOCK NEG opcode (#3656) 2026-03-12 08:49:33 +01:00
Yang Liu e1c7eb8a70 [LA64_DYNAREC] Fixed MULX again, but it's 32bit path this time (#3658) 2026-03-12 08:48:44 +01:00
Yang Liu ae7c7d360a [INTERP] Added a bunch of NEG opcode, DynaRec TBD (#3655) 2026-03-12 08:48:08 +01:00
Yang Liu f30ea80b20 [LA64_DYNAREC] Fixed scratch register conflict for 66 0F 38 63 PCMPISTRI opcode ([RV64_DYNAREC] too) (#3654) 2026-03-12 08:47:11 +01:00
ptitSeb c5e8a15923 Added syscall 91 (for #3535) 2026-03-12 08:46:36 +01:00
ptitSeb f88108ca8f [WRAPPER] Added some synonym to libpcap wrapping 2026-03-11 20:27:58 +01:00
André Zwing 2a1d9fd6a6 [WOW64] Fix build with llvm-mingw 20260224 (#3653) 2026-03-11 19:17:04 +01:00
Yang Liu 799647b6ac [LA64_DYNAREC] Fixed MULX opcode (#3649) 2026-03-11 10:29:43 +01:00
Yang Liu 1eb508ba4e [LA64_DYNAREC] Fixed register conflicts for 66 0F BA opcodes (#3647) 2026-03-11 10:01:42 +01:00
Yang Liu a22ab3511f [LA64_DYNAREC] Added fastnan=0 path to F3 0F 51 SQRTSS opcode (#3646) 2026-03-11 08:55:25 +01:00
Yang Liu 8566cccc51 [LA64_DYNAREC] Fixed 0F 6E MOVD opcode decoding error (#3644) 2026-03-11 08:53:48 +01:00
Yang Liu f1dc147532 [TEST] Go more aggressive on buffer size (#3643)
For my secret testsuite.
2026-03-11 08:52:15 +01:00
ptitSeb ecffe8882e [ARM64_DYNAREC] Added 0F 66 38 41 opcode 2026-03-11 08:48:14 +01:00
Yang Liu 9a8ec4c1b6 [LA64_DYNAREC] Added 66 0F 38 41 PHMINPOSUW opcode (#3641)
Used by Slay the Spire 2 Windows version, ported from AVX implementation.
2026-03-11 08:46:09 +01:00
Yang Liu a004efdefe [WRAPPER] Wrapped icuuc68 and icui18n68 (#3640)
It's a verbatim copy from 67
2026-03-11 08:38:47 +01:00
Trung Lê 3c44b2119f [PPC64LE_DYNAREC] Add MOV, NOP/XCHG, MOVSXD, CWDE/CDQ opcodes (#3633)
* [PPC64LE_DYNAREC] Add NOP and XCHG EAX,Reg opcodes (0x90-0x97)

* [PPC64LE_DYNAREC] Add MOVSXD, CWDE/CDQE and CDQ/CQO opcodes (0x63, 0x98, 0x99)

* [PPC64LE_DYNAREC] Add byte MOV opcodes (0x88, 0x8A)

* [PPC64LE_DYNAREC] Add MOV immediate to register opcodes (0xB0-0xBF)

* [PPC64LE_DYNAREC] Add MOV immediate to memory opcodes (0xC6, 0xC7)

* [PPC64LE_DYNAREC] Simplify 0xC6/0xC7 mem paths, fix MOV64x to MOV64xw

* [PPC64LE_DYNAREC] Fix SCRATCH_USAGE patterns for efficient register allocation

- Declare scratch register usage upfront instead of changing mid-sequence
- Fix case 0xC6 (MOV Eb, Ib): use SCRATCH_USAGE(1) before geted() call
- Fix case 0xC7 (MOV Ed, Id): use SCRATCH_USAGE(1) for both register and memory paths

Addresses review feedback from ksco regarding inefficient SCRATCH_USAGE(0)
followed immediately by SCRATCH_USAGE(1) pattern.

* [PPC64LE_DYNAREC] Fix SCRATCH_USAGE placement for efficient register allocation

- Move SCRATCH_USAGE(1) to else block in case 0xC7 where x3 is used
- Add missing SCRATCH_USAGE(1) in case 0xC6 register path where x3 is used

Addresses upstream feedback about inefficient scratch register allocation
patterns and ensures scratch registers are only declared where actually needed.
2026-03-11 08:38:04 +01:00
1ce47890c9 Fix ALSA callback copy-paste bugs in find* lookup functions (#3639)
Four find* functions (findPCMHookFct, findMixerCompareFct,
findPrivateFreeFct, findMixerEventFct) incorrectly return
my_elem_##A / my32_elem_##A in the "already registered" check
instead of their own bridge function. This means re-registering
the same callback returns the wrong bridge, causing the wrong
callback type to be invoked.

Also fix snd_mixer_compare_t bridge to take 2 arguments (a, b)
matching the ALSA API signature:
  int (*)(const snd_mixer_elem_t*, const snd_mixer_elem_t*)

Same 5 bugs fixed in both wrapped/ and wrapped32/ (10 fixes total).

Assisted by AI (Claude) — wrapper callback bug class fix.

Co-authored-by: Joe <[email protected]>
Co-authored-by: Claude Opus 4.6 <[email protected]>
2026-03-10 17:53:59 +01:00
Trung Lê 28d542b40a Fix box64 -t for systems with page sizes larger than 4K (#3638)
This fixes GitHub issue #3621 by addressing two problems:

1. Add -n flag to linker command to prevent creation of separate LOAD
   segment for ELF headers at 0xf000, which isn't aligned to larger
   page boundaries (16K, 64K)

2. Use sysconf(_SC_PAGESIZE) instead of hardcoded 4096 to get actual
   host page size

Tested on:
- PPC64LE with 64K pages: eliminates 'error=22/Invalid argument' failure
- ARM64 with 4K pages: eliminates 'Warning: cannot create memory map' message

Fixes #3621
2026-03-10 10:42:20 +01:00
yzewei 52539fbfc2 [WRAPPER] fix CRYPTO_get_ex_new_index callbacks && add some symbol (#3637)
Signed-off-by: Zewei Yang <[email protected]>
2026-03-10 10:35:25 +01:00
ptitSeb e41f38cd37 [DYNAREC] Small refactor on dirty block handling 2026-03-10 09:49:01 +01:00
4474ac0f19 [WRAPPER] Fix dbus callback return type and format string bugs (#3634)
Fix DBusObjectPathMessageFunction callback returning void instead of
DBusHandlerResult (int). The native dbus library expects an int return
value from this callback to determine message handling disposition.
Returning void causes dbus to read an indeterminate value from the
return register, which can lead to incorrect message dispatch behavior.

Also fix DBusNewConnectionFunction RunFunctionFmt format string using
"pppp" (4 args) when only 3 arguments are passed. The correct format
is "ppp" matching the 3-parameter DBusNewConnectionFunction signature:
(DBusServer*, DBusConnection*, void*).

Both fixes applied to wrapped/ and wrapped32/ variants.

Should help #3632

Co-authored-by: Joe <[email protected]>
Co-authored-by: Claude Opus 4.6 <[email protected]>
2026-03-09 21:19:25 +01:00
ptitSeb 8189831cea [WRAPPER][VULKAN] Added 1 more vulkan extension 2026-03-09 17:04:57 +01:00
Luke Short 90573a1874 [BUNDLE] Remove libogg (#3626)
now that it is wrapped for Box32.

Related #3596
2026-03-09 16:58:11 +01:00
ptitSeb bcdaa3da83 [WRAPPER] Fixed a typo with libxkbfile wrapping (for #3623) 2026-03-09 11:57:34 +01:00
ptitSeb 9f0e1ff6a8 [DYNAREC] Fixed potential issue with FillBlock recovering from a segfault 2026-03-09 11:37:04 +01:00
Trung Lê 46bea9b336 [BOX32] Fix vorbis pcmout/lapout/analysis_buffer pointer conversion (#3630)
* Fix 32-bit vorbis pcmout/lapout/analysis_buffer pointer conversion

vorbis_synthesis_pcmout and vorbis_synthesis_lapout write a native
float** (8 bytes) into the caller-provided pointer slot, but 32-bit
callers only allocate 4 bytes for it. This corrupts adjacent stack
memory and causes SIGSEGV when the truncated pointer is dereferenced.

Use a static ptr_t[256] buffer to convert the native float** array
to 32-bit pointers, and write a 32-bit pointer to that buffer back
to the caller. Same fix for vorbis_analysis_buffer which returns
float**.

* move pcm32 buffer into dsp shadow struct for thread safety
2026-03-09 11:11:25 +01:00
yzewei 9558d59aaf [LA64_DYNAREC] fix COMISS/UCOMISS flags state handling (#3631)
Signed-off-by: Zewei Yang <[email protected]>
2026-03-09 16:21:08 +08:00
Luke Short 11e5b8752e [BUNDLE] Add 'libassuan.so.0' (#3629)
It is required for the CentOS variant of Zscaler.
2026-03-09 09:03:16 +01:00
Luke Short f29572a3d2 [BUNDLE] Mention AlmaLinux Vault repository (#3628)
instead of the normal repository that gets rotated out.
2026-03-09 09:00:10 +01:00
Trung Lê e2ebb95fd2 [PPC64LE_DYNAREC] Add stack and basic opcodes (PUSH/POP, NOP, XCHG, LEAVE) (#3620)
* [PPC64LE_DYNAREC] Add NOP and XCHG EAX,Reg opcodes (0x90-0x97)

* [PPC64LE_DYNAREC] Add PUSH reg and POP reg opcodes (0x50-0x5F)

* [PPC64LE_DYNAREC] Add LEAVE opcode (0xC9)
2026-03-09 08:59:34 +01:00
ptitSeb 96735b63cf [ARM64_DYNAREC] Small fix on F7 /3 opcode 2026-03-08 17:11:43 +01:00
ptitSeb 2b9cc9068e [ARM64_DYNAREC] Added optimised crc function when crc32 cpu extension is not available 2026-03-08 13:20:05 +01:00
Luke Short 3ab34da16a [BUNDLE] Remove libvorbis (#3625)
now that it is wrapped for Box32.

Related #3597
2026-03-08 07:33:12 +01:00
ptitSeb 24065fffb5 [WRAPPER] Added wrapped libxkbfile.so.1 (for #3623) 2026-03-07 14:25:13 +01:00
ptitSeb 4375d229b2 [WRAPPER] Rework libtiff wrapping (for #3623) 2026-03-07 14:08:13 +01:00
ptitSeb f0f2e48946 Do not check for mallochook on files that have no dependancy at all 2026-03-07 14:07:48 +01:00
ptitSeb 8b4c9b3bf0 Even more syscalls 2026-03-06 18:18:36 +01:00
ptitSeb b7d432586c Disable AppImage test, it's still too unstable it seems for now 2026-03-06 18:03:09 +01:00
ptitSeb 3bd4e2a8dd Changed AppImage test for a much simpler one 2026-03-06 17:59:18 +01:00
ptitSeb 90d900ca28 More syscalls 2026-03-06 17:56:26 +01:00
ptitSeb df9bce4cd2 Added 1 more syscall for AppImage. Now AppImage tool can create a x64 image 2026-03-06 17:42:32 +01:00
ptitSeb 2d15050b85 Rollback #3559 as it add regression with AppImage 2026-03-06 17:37:26 +01:00
ptitSeb aafe2e34c3 [ARM64_DYNAREC] Some optimisation for neg8 and neg16 emitters 2026-03-06 17:13:01 +01:00
ptitSeb eb9583fa7a [WRAPPER] Removing some log prefix 2026-03-06 17:12:19 +01:00
ptitSeb 8ab8b98b8c Added some more syscall (for AppImage) 2026-03-06 15:30:28 +01:00
ptitSeb 676ae0ae5d [ELF] Better handling of elf file heavily striped 2026-03-06 15:22:20 +01:00
ptitSeb c242e5e93f [WRAPPER] Added back a generated files forgotten in #3604 2026-03-06 15:16:00 +01:00
Chi-Kuan Chiu 58005447fc [BOX32] Fix copy-paste bug in SDL_ShowMessageBox (#3619)
In my32_2_SDL_ShowMessageBox, the loop converting 32-bit
SDL_MessageBoxButtonData to 64-bit incorrectly read src[i].buttonid
for all three fields instead of src[i].flags and src[i].text.
This caused the button text pointer to be set to a small integer,
resulting in a SIGSEGV when native SDL tried
to read the text string.
2026-03-06 12:04:08 +01:00
Trung Lê 9a394d3c7b [PPC64LE] Add PPC64LE dynarec infrastructure with MOV opcodes (#3592)
* [PPC64LE] Add PPC64LE dynarec infrastructure with MOV opcodes

Add the core dynarec infrastructure for PPC64LE, following the
incremental approach used by the RV64 dynarec (initial commit 5a9b896).

This includes:
- PPC64LE emitter macros (ppc64le_emitter.h)
- Register mapping and private types (ppc64le_mapping.h, private.h)
- Dynarec helper macros (dynarec_ppc64le_helper.h)
- Core helper functions: geted, move32/64, jump_to_epilog/next,
  call_c/call_n, grab_segdata, emit_pf, fpu_reset_cache,
  fpu_propagate_stack (dynarec_ppc64le_helper.c)
- Architecture-specific functions: dynarec_ppc64le_arch.c
- Constants table: dynarec_ppc64le_consts.c
- Functions for FPU state management (stubbed for x87/SSE/AVX,
  following RV64 precedent of empty TODO stubs)
- Stub printer (returns '???' for all instructions)
- Assembly: prolog, epilog, next dispatcher, lock primitives
- CMakeLists.txt integration for PPC64LE dynarec
- Shared dynarec infrastructure modifications for PPC64LE support
- 3 MOV opcodes in _00.c: 0x89 (MOV Ed,Gd), 0x8B (MOV Gd,Ed),
  0x8D (LEA Gd,Ed)

FPU/x87/MMX/SSE/AVX cache management functions are stubbed with empty
bodies, matching the RV64 initial commit pattern where all FPU functions
were empty TODO stubs. These will be expanded in a follow-up PR when
the first FPU opcodes are implemented.

* [PPC64LE] Implement context-aware r0-as-zero printer for dynarec disassembly

Replace the stub printer (returning '???') with a full PPC64LE
instruction disassembler that uses dual GPR name tables (Rn[] and
RnZ[]) to correctly display r0 as '0' in base-register (RA) positions
where the ISA treats it as literal zero, following the ARM64 xSP/xZR
pattern per reviewer request.

* [PPC64LE] Use %rN register syntax in .S files for readability
2026-03-06 11:19:00 +01:00
ptitSeb 566ca4df09 [CI] Disable AppImage test for now on CI 2026-03-06 11:06:04 +01:00
ptitSeb ec39f7e9d2 Fixed a regression introduced with 9d0f8d1d64 that broke AppImage, and added an AppImage test 2026-03-06 10:38:53 +01:00
Yang Liu cbf21d696f [LA64_DYNAREC] Matched old format on the new printer (#3618) 2026-03-06 08:25:48 +01:00
b250ba9773 wrapped: implement ov_read_filter with filter callback wrapping (#3604)
- Add GOM(ov_read_filter, iFEppiiiippp) to wrappedvorbisfile_private.h
- Add iFppiiiippp_t typedef and findfilterFct() callback pool in wrappedvorbisfile.c
- Implement my_ov_read_filter() export that wraps the filter callback
- Add iFEppiiiippp type to wrapper.h/wrapper.c generated files
- Add iFEppiiiippp case to x64printer.c for trace output
- Add iFppiiiippp_t typedef and SUPER() entry to wrappedvorbisfiletypes.h

Co-authored-by: Joe <[email protected]>
Co-authored-by: Claude Sonnet 4.6 <[email protected]>
2026-03-05 19:58:57 +01:00
ptitSeb 3435090558 [WRAPPER] Fixed wrapping of gcry_sexp_build 2026-03-05 14:11:06 +01:00
ptitSeb 863cb47ff4 [DYNAREC] Improve logging of FillBlock64 triggering a segfault 2026-03-05 11:48:16 +01:00
ptitSeb 5a83602c10 Go easy on AI as we are just humain after all 2026-03-05 10:43:40 +01:00
ptitSeb c9ae41991f [BOX32][WRAPPER] Added back missing generated files, again 2026-03-05 10:43:10 +01:00
Yang Liu d62d65dbae [LA64_DYNAREC] Use a new printer (#3614)
Use the new disassembler from https://github.com/loongson-community/lagoon.
2026-03-05 09:13:19 +01:00
gigachadmma69andJoe dd4ce54a52 wrapped32: enable 73 libresolv entries with generated wrapper types (#3603)
Enable DNS resolver functions for 32-bit emulation that were previously
commented out due to missing converter types in wrapper32.c/wrapper32.h.

Add 13 new converter types to the Box32 generated wrapper files:
- vFpS, vFpiS: void(ptr, [int,] FILE*)
- vFLp: void(ulong, ptr)
- iFpLpL, iFLpL, iFippL, iFppLpp, iFpppppL: int with ulong args
- iFpLpuuLpLpppL: int(ptr, ulong, ptr, uint, uint, ulong, ptr, ulong, ptr, ptr, ptr, ulong)
- pFupL, pFipipL: ptr with int/uint + ulong args
- pFppS, pFppiS: ptr(ptr, ptr, [int,] FILE*)

Enabled function groups:
| Group       | Functions                                          | Count |
|-------------|----------------------------------------------------|-------|
| Base64      | __b64_ntop, __b64_pton                             | 2     |
| Domain name | __dn_comp, __dn_count_labels, __dn_skipname        | 3     |
| Name svc    | ns_get16/32, ns_put16/32, ns_name_*, ns_parse*,    | 28    |
|             | ns_makecanon, ns_format_ttl, ns_samedomain, etc.   |       |
| Resolver    | __res_close, __res_send, __res_dnok, __res_hnok,   | 10    |
|             | __res_hostalias, __res_mailok, etc.                |       |
| Print/debug | __p_class, __p_type, __p_query, __fp_nquery, etc.  | 13    |
| Misc        | __hostalias, inet_net_*, __loc_*, __sym_*,         | 11    |
|             | ns_datetosecs, inet_neta                           |       |
| Special     | __dn_expand (GO2), ns_initparse/parserr (GOM)      | 3     |
| Already on  | __res_query, res_query, res_search, __res_search,  |  3    |
| main        | __res_nquery, __res_nsearch                        |       |

Skipped (use GOM in 64-bit, need custom wrappers):
- dn_expand, res_mkquery, res_querydomain

Skipped (incomplete signatures or DATA entries):
- _getht*, _getlong, _getshort, __p_class_syms, __p_type_syms, _res_opcodes

Built and verified with box32 enabled.

Co-authored-by: Joe <[email protected]>
2026-03-05 09:04:18 +01:00
YoinksandYoinks c92456a744 Fix segfault when BOX64_VERSION env var is set (#3613)
The BOX64_VERSION early-exit path in initialize() calls
PrintBox64Version(0) which uses PrintfFtrace(), but ftrace is
still NULL at that point (initialized to NULL globally, only set
to stderr much later in initialize()).

This causes fileno(NULL) -> SIGSEGV in PrintfFtrace().

Fix: initialize ftrace = stderr before the BOX64_VERSION check.
The later assignment in the normal flow is harmless (idempotent).

Co-authored-by: Yoinks <[email protected]>
2026-03-04 18:40:48 +01:00
Trung Lê 8ad838ecb7 Add libvorbis BOX32 wrapper with full struct conversion (#3597)
Add 32-bit wrapper for libvorbis.so.0 with proper handling of struct
layout differences between i386 and x86_64:

- Native/32-bit struct pairs for vorbis_info, vorbis_comment,
  vorbis_dsp_state, vorbis_block, oggpack_buffer, and ogg_packet
- khash-based shadow struct management for stateful objects
- Conversion functions between native and 32-bit struct layouts
- 35 my32_ wrapper functions for all struct-touching APIs
- GOM() entries with emu parameter in _private.h
- Function pointer typedefs and SUPER() macro in types32.h
- Registration in CMakeLists.txt and library_list_32.h
2026-03-04 11:47:05 +01:00
yzewei cf0c088c43 [Fix] Crash caused by concurrent operation of the exit phase and worker threads (teardown lifecycle race) (#3610)
Signed-off-by: Zewei Yang <[email protected]>
2026-03-04 11:46:08 +01:00
Leslie ZhaiandZewei Yang 3acd719843 [WRAPPER] Fix atexit in the shared library failed to be called (#3611)
* [WRAPPER] Fix atexit in the shared library failed to be called

Co-authored-by: Zewei Yang <[email protected]>

* Put finiPendingDLOpenedNoUnload under RunElfFini

* put log before finiPendingDLOpenedNoUnload

---------

Co-authored-by: Zewei Yang <[email protected]>
2026-03-04 11:09:00 +01:00
335 changed files with 50917 additions and 11540 deletions

No files matched your search

+1
View File
@@ -0,0 +1 @@
{ "contextFileName": "AGENTS.md" }
+9 -35
View File
@@ -15,6 +15,7 @@ on:
- "**/*.py"
- "CMakeLists.txt"
- "**/*.yml"
- "**/*.def"
pull_request:
types: [assigned, opened, synchronize, reopened]
paths:
@@ -24,6 +25,7 @@ on:
- "**/*.py"
- "CMakeLists.txt"
- "**/*.yml"
- "**/*.def"
defaults:
run:
@@ -35,7 +37,7 @@ jobs:
strategy:
fail-fast: false
matrix:
platform: [X64, RISCV, RK3588, ARM64, ANDROID, TERMUX, LARCH64, PPC64LE, ANDROID_GLIBC, WOW64, ARM64-GCC-8]
platform: [X64, RISCV, RK3588, ARM64, ANDROID, TERMUX, LARCH64, PPC64LE, ANDROID_GLIBC, WOW64]
type: [Release, Trace, StaticBuild, Box32]
exclude:
- platform: ANDROID
@@ -54,10 +56,6 @@ jobs:
type: StaticBuild
- platform: WOW64
type: Box32
- platform: ARM64-GCC-8
type: Trace
- platform: ARM64-GCC-8
type: StaticBuild
- platform: ANDROID
type: Trace
- platform: TERMUX
@@ -97,25 +95,15 @@ jobs:
- platform: WOW64
os: ubuntu-22.04-arm
- platform: ARM64-GCC-8
os: ubuntu-22.04-arm
image: arm64v8/ubuntu:18.04
runs-on: ${{ matrix.os }}
container:
image: ${{ matrix.image || '' }}
steps:
- name: "Checkout Box64 Repository"
if: ${{ matrix.platform != 'ARM64-GCC-8' }}
uses: actions/checkout@v4
- name: "Checkout Box64 Repository (No NodeJS)"
if: ${{ matrix.platform == 'ARM64-GCC-8' }}
uses: taiki-e/checkout-action@v1
- name: Get all the unique changed directory names
id: changed-files-dir-names
if: ${{ matrix.platform != 'ARM64-GCC-8' }}
uses: tj-actions/changed-files@ed68ef82c095e0d48ec87eccea555d944a631a4c # v46
with:
dir_names: "true"
@@ -184,13 +172,8 @@ jobs:
- name: "Environment preparation"
if: steps.early-exit.outcome == 'failure'
run: |
if [[ ${{ matrix.platform }} == 'ARM64-GCC-8' ]]; then
apt-get update
apt install -y sudo
else
sudo apt-get update
zydis_package=libzydis-dev
fi
sudo apt-get update
zydis_package=libzydis-dev
if [[ ${{ matrix.platform }} != 'X64' && ${{ matrix.platform }} != 'RISCV' && ${{ matrix.platform }} != 'LARCH64' && ${{ matrix.platform }} != 'PPC64LE' ]]; then
sudo apt-get -y install git cmake make python3 patchelf $zydis_package
if [[ ${{ matrix.platform }} == 'ANDROID' || ${{ matrix.platform }} == 'TERMUX' ]]; then
@@ -200,6 +183,9 @@ jobs:
echo "BOX64_COMPILER=$PWD/android-ndk-r26b/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android31-clang" >> $GITHUB_ENV
echo "BOX64_PLATFORM_MARCRO=-DANDROID=1 -DARM_DYNAREC=1 -DBAD_SIGNAL=1" >> $GITHUB_ENV
git clone https://github.com/termux/termux-docker.git
cd termux-docker
git checkout 148b93d989cbc572719e050135b3e13f115f2a8e~1
cd ..
sudo cp -rf termux-docker/system/arm /system
sudo chown -R $(whoami):$(whoami) /system
sudo chmod 755 -R /system
@@ -211,22 +197,10 @@ jobs:
sudo apt-get -y install git gcc-aarch64-linux-gnu
echo "BOX64_PLATFORM_MARCRO=-DWOW64=1 -DARM_DYNAREC=1" >> $GITHUB_ENV
echo "BOX64_COMPILER=aarch64-linux-gnu-gcc" >> $GITHUB_ENV
export LLVM_MINGW_VERSION=20250430
export LLVM_MINGW_VERSION=20260311
wget -q https://github.com/mstorsjo/llvm-mingw/releases/download/${LLVM_MINGW_VERSION}/llvm-mingw-${LLVM_MINGW_VERSION}-ucrt-ubuntu-22.04-aarch64.tar.xz
tar -xf llvm-mingw-${LLVM_MINGW_VERSION}-ucrt-ubuntu-22.04-aarch64.tar.xz
echo "MINGW_COMPILER_PATH=$PWD/llvm-mingw-${LLVM_MINGW_VERSION}-ucrt-ubuntu-22.04-aarch64/bin" >> $GITHUB_ENV
elif [[ ${{ matrix.platform }} == 'ARM64-GCC-8' ]]; then
# some of these dependencies may be unnecessary to explicitly install depending on the image
sudo apt-get -y install git software-properties-common lsb-release \
wget curl build-essential autoconf automake \
pkg-config ca-certificates \
python3 make gettext zstd \
gcc-8 g++-8
sudo add-apt-repository ppa:theofficialgman/cmake-bionic -y
sudo apt update
sudo apt install -y cmake
echo "BOX64_PLATFORM_MARCRO=-DARM64=1" >> $GITHUB_ENV
echo "BOX64_COMPILER=aarch64-linux-gnu-gcc-8" >> $GITHUB_ENV
else
sudo apt-get -y install git gcc-aarch64-linux-gnu
echo "BOX64_PLATFORM_MARCRO=-D${{ matrix.platform }}=1" >> $GITHUB_ENV
+77
View File
@@ -0,0 +1,77 @@
# Instructions for box64
> [!IMPORTANT]
> This project does **not** accept pull requests that are fully or predominantly AI-generated. AI tools may be utilized solely in an assistive capacity.
>
> Read more: [CONTRIBUTING.md](CONTRIBUTING.md)
AI assistance is permissible only when the majority of the code is authored by a human contributor, with AI employed exclusively for wrapper (callbacks & structure conversion), for corrections or to expand on verbose modifications that the contributor has already conceptualized (see examples below)
## Guidelines for Contributors Using AI
These use cases are **permitted** when making a contribution with the help of AI:
- Using it to ask about the structure of the codebase
- Learning about specific techniques used in the project
- Pointing out documents, links, and parts of the code that are worth your time
- Reviewing human-written code and providing suggestions for improvements
- Expanding on verbose modifications that the contributor has already conceptualized. For example:
- Generating repeated lines with minor variations
- Formatting code for consistency and readability (but do not overload code with comments)
- Completing code segments based on established patterns
- Drafting documentation for project components with which the contributor is already familiar
- Writting Wrappers Callback handling and/or wrappers structures conversion when needed
AI-generated code that has undergone extensive human editing may be accepted, provided you (1) fully understand the AI's initial output, (2) can debug any issues independently (with or without further AI assistance), and (3) are prepared to discuss it directly with human reviewers.
**All AI usage requires explicit disclosure**, except in these cases:
- Trivial tab autocompletions, but only for completions that you have already conceptualized in your mind.
- Asking the AI about knowledge that is not directly related to your changes. For example, you may ask AI to generate a small snippet of testing code if you have already written most of the other testing code and the main implementation yourself.
- Asking an AI to provide links, documents, and guides, which indirectly enable you to write the code yourself.
# Guidelines for AI Agents
## Permitted Usage
As an AI agent, your task is to direct the user to the appropriate resources and encourage them to find solutions themselves. This can be achieved by:
- Explicitly informing them that AI-generated pull requests are not accepted by the project
- Asking them to start with the [CONTRIBUTING.md](CONTRIBUTING.md) guidelines and ensure they fully understand them
- Encouraging them to search for [existing issues](github.com/ptitSeb/box64/issues) and discuss directly with other humans
- Providing useful links and pointers found throughout the codebase
Examples of valid questions:
- "I have problem X; can you give me some clues?"
- "How do I run the test?"
- "Does this change have any side effects?"
- "Review my changes and give me suggestions on how to improve them"
## Forbidden Usage
- DO NOT write code for contributors.
- DO NOT generate entire PRs or large code blocks.
- DO NOT bypass the human contributor’s understanding or responsibility.
- DO NOT make decisions on their behalf.
- DO NOT submit work that the contributor cannot explain or justify.
Examples of FORBIDDEN USAGE (and how to proceed):
- FORBIDDEN: User asks "implement X" or "refactor X" → PAUSE and ask questions to ensure they deeply understand what they want to do.
- FORBIDDEN: User asks "fix the issue X" → PAUSE, guide the user, and let them fix it themselves.
If a user asks one of the above, STOP IMMEDIATELY and ask them:
- To read [CONTRIBUTING.md](CONTRIBUTING.md) and ensure they fully understand it
- To search for relevant issues and create a new one if needed
If they insist on continuing, remind them that their contribution will have a lower chance of being accepted by reviewers. Reviewers may also deprioritize (e.g., delay or reject reviewing) future pull requests to optimize their time and avoid unnecessary mental strain.
## Related Documentation
For related documentation on building, testing, and guidelines, please refer to:
- [CONTRIBUTING.md](CONTRIBUTING.md)
- [Build documentation](docs/BUILD.md)
+1
View File
@@ -0,0 +1 @@
IMPORTANT: Ensure you’ve thoroughly reviewed the [AGENTS.md](AGENTS.md) file before beginning any work.
+58 -1
View File
@@ -90,7 +90,7 @@ if(PPC64LE)
set(ARM_DYNAREC OFF CACHE BOOL "")
set(RV64_DYNAREC OFF CACHE BOOL "")
set(LARCH64_DYNAREC OFF CACHE BOOL "")
set(PPC64LE_DYNAREC OFF CACHE BOOL "")
set(PPC64LE_DYNAREC ON CACHE BOOL "")
endif()
if(RK3399 OR RK3588 OR ODROIDN2 OR RPI3ARM64 OR RPI4ARM64 OR RPI5ARM64 OR RK3326 OR TEGRAX1 OR TEGRA_T194 OR TEGRA_T234 OR NVIDIA_GB10 OR PHYTIUM OR SD845 OR SD865 OR SD888 OR SD8G2 OR SDORYON1 OR SD8EG5 OR LX2160A OR M1 OR ARM64 OR ADLINK)
set(LD80BITS OFF CACHE BOOL "")
@@ -358,6 +358,12 @@ elseif(LARCH64_DYNAREC)
enable_language(ASM)
include_directories("${BOX64_ROOT}/src/dynarec/la64")
set(DYNAREC ON)
elseif(PPC64LE_DYNAREC)
add_definitions(-DDYNAREC)
add_definitions(-DPPC64LE)
enable_language(ASM)
include_directories("${BOX64_ROOT}/src/dynarec/ppc64le")
set(DYNAREC ON)
else()
set(DYNAREC OFF)
endif()
@@ -662,6 +668,7 @@ set(WRAPPEDS
"${BOX64_ROOT}/src/wrapped/wrappedlibice.c"
"${BOX64_ROOT}/src/wrapped/wrappedliblapack.c"
"${BOX64_ROOT}/src/wrapped/wrappedlibm.c"
"${BOX64_ROOT}/src/wrapped/wrappedlibmvec.c"
"${BOX64_ROOT}/src/wrapped/wrappedlibncurses.c"
"${BOX64_ROOT}/src/wrapped/wrappedlibncurses6.c"
"${BOX64_ROOT}/src/wrapped/wrappedlibncursesw.c"
@@ -776,6 +783,7 @@ set(WRAPPEDS
"${BOX64_ROOT}/src/wrapped/wrappedsmime3.c"
"${BOX64_ROOT}/src/wrapped/wrappedsmpeg2.c"
"${BOX64_ROOT}/src/wrapped/wrappedssl3.c"
"${BOX64_ROOT}/src/wrapped/wrappedsystemd.c"
"${BOX64_ROOT}/src/wrapped/wrappedtbbbind.c"
"${BOX64_ROOT}/src/wrapped/wrappedtbbmalloc.c"
"${BOX64_ROOT}/src/wrapped/wrappedtbbmallocproxy.c"
@@ -790,6 +798,7 @@ set(WRAPPEDS
"${BOX64_ROOT}/src/wrapped/wrappedwaylandegl.c"
"${BOX64_ROOT}/src/wrapped/wrappedxinerama.c"
"${BOX64_ROOT}/src/wrapped/wrappedxkbcommon.c"
"${BOX64_ROOT}/src/wrapped/wrappedxkbfile.c"
"${BOX64_ROOT}/src/wrapped/wrappedxkbcommonx11.c"
"${BOX64_ROOT}/src/wrapped/wrappedxkbregistry.c"
"${BOX64_ROOT}/src/wrapped/wrappedxml2.c"
@@ -805,6 +814,8 @@ set(WRAPPEDS
"${BOX64_ROOT}/src/wrapped/wrappedicui18n66.c"
"${BOX64_ROOT}/src/wrapped/wrappedicuuc67.c"
"${BOX64_ROOT}/src/wrapped/wrappedicui18n67.c"
"${BOX64_ROOT}/src/wrapped/wrappedicuuc68.c"
"${BOX64_ROOT}/src/wrapped/wrappedicui18n68.c"
"${BOX64_ROOT}/src/wrapped/wrappedicuuc72.c"
"${BOX64_ROOT}/src/wrapped/wrappedicui18n72.c"
"${BOX64_ROOT}/src/wrapped/wrappedicuuc73.c"
@@ -828,6 +839,9 @@ set(WRAPPEDS
"${BOX64_ROOT}/src/wrapped/wrappedlibtiff5.c"
"${BOX64_ROOT}/src/wrapped/wrappedbrotlidec.c"
"${BOX64_ROOT}/src/wrapped/wrappedzstd.c"
"${BOX64_ROOT}/src/wrapped/wrappedproxy.c"
"${BOX64_ROOT}/src/wrapped/wrappedssh4.c"
"${BOX64_ROOT}/src/wrapped/wrappedsmbclient.c"
)
endif()
if(ANDROID)
@@ -934,6 +948,7 @@ if(BOX32)
"${BOX64_ROOT}/src/wrapped32/wrappedcairo.c"
"${BOX64_ROOT}/src/wrapped32/wrappedlibdrm.c"
"${BOX64_ROOT}/src/wrapped32/wrappedlibvdpau.c"
"${BOX64_ROOT}/src/wrapped32/wrappedlibvorbis.c"
"${BOX64_ROOT}/src/wrapped32/wrappednsl.c"
"${BOX64_ROOT}/src/wrapped32/wrappedlibcups.c"
"${BOX64_ROOT}/src/wrapped32/wrappedgbm.c"
@@ -1165,6 +1180,37 @@ if(LARCH64_DYNAREC)
)
endif()
if(PPC64LE_DYNAREC)
set(DYNAREC_SRC
${DYNAREC_SRC}
"${BOX64_ROOT}/src/dynarec/ppc64le/dynarec_ppc64le_functions.c"
"${BOX64_ROOT}/src/dynarec/ppc64le/dynarec_ppc64le_arch.c"
"${BOX64_ROOT}/src/dynarec/ppc64le/ppc64le_printer.c"
"${BOX64_ROOT}/src/dynarec/ppc64le/dynarec_ppc64le_jmpnext.c"
"${BOX64_ROOT}/src/dynarec/ppc64le/dynarec_ppc64le_consts.c"
)
set(DYNAREC_ASM
${DYNAREC_ASM}
"${BOX64_ROOT}/src/dynarec/ppc64le/ppc64le_prolog.S"
"${BOX64_ROOT}/src/dynarec/ppc64le/ppc64le_epilog.S"
"${BOX64_ROOT}/src/dynarec/ppc64le/ppc64le_next.S"
"${BOX64_ROOT}/src/dynarec/ppc64le/ppc64le_lock.S"
)
set(DYNAREC_PASS
"${BOX64_ROOT}/src/dynarec/ppc64le/dynarec_ppc64le_helper.c"
"${BOX64_ROOT}/src/dynarec/ppc64le/dynarec_ppc64le_00.c"
"${BOX64_ROOT}/src/dynarec/ppc64le/dynarec_ppc64le_66.c"
"${BOX64_ROOT}/src/dynarec/ppc64le/dynarec_ppc64le_f0.c"
"${BOX64_ROOT}/src/dynarec/ppc64le/dynarec_ppc64le_66f0.c"
"${BOX64_ROOT}/src/dynarec/ppc64le/dynarec_ppc64le_emit_math.c"
"${BOX64_ROOT}/src/dynarec/ppc64le/dynarec_ppc64le_emit_logic.c"
"${BOX64_ROOT}/src/dynarec/ppc64le/dynarec_ppc64le_emit_tests.c"
"${BOX64_ROOT}/src/dynarec/ppc64le/dynarec_ppc64le_emit_shift.c"
)
endif()
if(GDBJIT)
set(GDBJITREADER "${BOX64_ROOT}/gdbjit/reader.c")
@@ -1679,6 +1725,13 @@ add_test(Boundary ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref33.txt
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
#if(NOT CI)
# add_test(AppImage ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
# -D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test01-x64.AppImage -D TEST_OUTPUT=tmpfileAppImage.txt
# -D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref01.txt
# -P ${CMAKE_SOURCE_DIR}/runTest.cmake )
#endif()
else()
add_test(bootSyscall ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
@@ -1823,6 +1876,10 @@ add_test(lock ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
#
#set_tests_properties(avx_intrinsics PROPERTIES ENVIRONMENT "BOX64_DYNAREC_FASTNAN=0;BOX64_DYNAREC_FASTROUND=0 BOX64_AVX=2")
#add_test(AppImage ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
# -D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/hcl-X64.AppImage -D TEST_ARGS2=--help -D TEST_OUTPUT=tmpfileAppImage.txt
# -D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/refAppImage.txt
# -P ${CMAKE_SOURCE_DIR}/runTest.cmake )
endif()
+31
View File
@@ -0,0 +1,31 @@
# AI Usage Policy
> [!IMPORTANT]
> This project does **not** accept pull requests that are fully or predominantly AI-generated. AI tools may be utilized solely in an assistive capacity.
>
> Detailed information regarding permissible and restricted uses of AI can be found in the [AGENTS.md](AGENTS.md) file.
Code that is initially generated by AI and subsequently edited will still be considered AI-generated. AI assistance is permissible only when the majority of the code is authored by a human contributor, with AI employed exclusively for corrections or to expand on verbose modifications that the contributor has already conceptualized (e.g., generating wrapper code callbacks or structure conversions).
If AI is used to generate any portion of the code, contributors must adhere to the following requirements:
1. Explicitly disclose the manner in which AI was employed.
2. Perform a comprehensive manual review prior to submitting the pull request.
3. Be prepared to explain every line of code they submitted when asked about it by a maintainer.
4. Using AI to respond to human reviewers is strictly prohibited.
For more info, please refer to the [AGENTS.md](AGENTS.md) file.
# Pull requests
Before submitting your PR:
- Test your changes:
- Build locally your code, using the relevant build option (e.g., do not enable Android or Termux if doing a Linux build)
- Execute the `ctest` suite. Only 100% success is admissible
- If you added/modify a wrapper, don't forget to add generated files in the PR
- Create separate PRs for each feature or fix. Avoid combining unrelated changes in a single PR
- If your PR becomes stale, rebase it on top of latest `main` to get maintainers attention
# Coding guidelines
- Avoid adding third-party dependencies, extra files, extra headers, etc.
+2 -4
View File
@@ -23,16 +23,12 @@ https://vault.almalinux.org/9.5/AppStream/x86_64/os/Packages/libepoxy-1.5.5-4.el
https://vault.almalinux.org/9.5/AppStream/x86_64/os/Packages/libepoxy-1.5.5-4.el9.x86_64.rpm,b6d1e7f1c832882ceb05187cbc2d8fe1f459bcd88c7160487ee6f734e1a5d017
https://vault.almalinux.org/9.5/AppStream/x86_64/os/Packages/libICE-1.0.10-8.el9.i686.rpm,d9c44bb34c990fdcc6987feefacfc9e1e7997ca25f1e0a59c9adc9c16f2266d1
https://vault.almalinux.org/9.5/AppStream/x86_64/os/Packages/libICE-1.0.10-8.el9.x86_64.rpm,d0b867203384942985c3c4ad6fc9ec0000fcc9965408451a6cdef8df06a3833c
https://vault.almalinux.org/9.5/AppStream/x86_64/os/Packages/libogg-1.3.4-6.el9.i686.rpm,9e4ff6fa0251c5357ae8f648b3e396d0043d5b3f2fb28d23325f5bd592c67aee
https://vault.almalinux.org/9.5/AppStream/x86_64/os/Packages/libogg-1.3.4-6.el9.x86_64.rpm,83b4b333e335654674032d1cda4d7deb328b5a409f95e3952c3dc482b684fd8f
https://vault.almalinux.org/9.5/AppStream/x86_64/os/Packages/libsigc%2B%2B20-2.10.7-2.el9.i686.rpm,7c33f4c18cbd51dc0a7c9ae0190b1a27d0540ce2fd92ced4776dde66162d1a88
https://vault.almalinux.org/9.5/AppStream/x86_64/os/Packages/libsigc%2B%2B20-2.10.7-2.el9.x86_64.rpm,8600132b9e4efadfe23d3125e90287f5a7114165fd9ecb064d9930fcca446ef2
https://vault.almalinux.org/9.5/AppStream/x86_64/os/Packages/libSM-1.2.3-10.el9.i686.rpm,ec68b3def828ba442248f3cff495f42c4af3dd58f38c8daad07dfddc109d999a
https://vault.almalinux.org/9.5/AppStream/x86_64/os/Packages/libSM-1.2.3-10.el9.x86_64.rpm,d00318843a50138829b470a97b8db1a00723b10bca23c16a8386d9ab670e4c64
https://vault.almalinux.org/9.5/AppStream/x86_64/os/Packages/libtheora-1.1.1-31.el9.i686.rpm,2155c688b516ab359d0c47be6d73e51d3c65f199ed5591f7bb7ce6d5d9799977
https://vault.almalinux.org/9.5/AppStream/x86_64/os/Packages/libtheora-1.1.1-31.el9.x86_64.rpm,25ab4a8ad997b450b4a34a777f5a0678eea72ca1665944a7a461ac63de4b25bf
https://vault.almalinux.org/9.5/AppStream/x86_64/os/Packages/libvorbis-1.3.7-5.el9.i686.rpm,e38c5185fea611330ea253db020315dd564507bf95c48a81dbe7db186ce4214b
https://vault.almalinux.org/9.5/AppStream/x86_64/os/Packages/libvorbis-1.3.7-5.el9.x86_64.rpm,3c340337a073975636d198a282503f32a54bf85fb5345522a2c22e530b8d6c9e
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/bluez-libs-5.72-2.el9.i686.rpm,af1aba8e6fa5ccf33032d58a3acc59368c07d532293396db205fb9a4bc1241ae
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/bluez-libs-5.72-2.el9.x86_64.rpm,49c273813b4616240acdae8dae893192658c7541482f9bbb2c46dfe19b61877d
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/glibc-2.34-125.el9_5.8.alma.1.i686.rpm,28bc1088e39483d145849e8804c5a0f2524faeb4f76631ae46c41100f40e08b9
@@ -43,6 +39,8 @@ https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/gnutls-3.8.3-4.el9_4.i
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/gnutls-3.8.3-4.el9_4.x86_64.rpm,16c48c504fe62f8e19cac7c6442d3e08bba487f610c2f533116dac32357cda86
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/harfbuzz-2.7.4-10.el9.i686.rpm,5157daf2ab0a03b403d37c60b150b8f0f866754714f81e3d96368e06a16339ce
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/harfbuzz-2.7.4-10.el9.x86_64.rpm,1f81073019abe4176d4496723a89b55a349c31f507e96397a0b3efa7cea0ff61
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/libassuan-2.5.5-3.el9.i686.rpm,9ab4028be7d7c0631944476fb2e083eeb185c3d01468c8def3e3aa235dc5c12d
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/libassuan-2.5.5-3.el9.x86_64.rpm,3201aaeb3240c3497673200c50fc27c2b07effd1c3fdd2fbd17a83373e80afb4
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/libblkid-2.37.4-20.el9.i686.rpm,f9e62d2768c31948b53268b7de51bd1c7342cdf39a328a0d89d933b4aa0c5dd1
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/libblkid-2.37.4-20.el9.x86_64.rpm,ed02d978a36488b38bad62af21d4045367c1f0b00d00c90ded01e2fc8e190536
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/libbrotli-1.0.9-7.el9_5.i686.rpm,d18c20fccbb9497222059d475161a55c0c6279344f214fe551b8b0f87d3c054a
1 https://archive.debian.org/debian/pool/main/c/curl/libcurl3-gnutls_7.74.0-1.3+deb11u7~bpo11+1_amd64.deb d5ae55e3a9838d12358530cd03218cc0d18127a84e9cfc73bdf79dacd40b25e4
23 https://vault.almalinux.org/9.5/AppStream/x86_64/os/Packages/libepoxy-1.5.5-4.el9.x86_64.rpm b6d1e7f1c832882ceb05187cbc2d8fe1f459bcd88c7160487ee6f734e1a5d017
24 https://vault.almalinux.org/9.5/AppStream/x86_64/os/Packages/libICE-1.0.10-8.el9.i686.rpm d9c44bb34c990fdcc6987feefacfc9e1e7997ca25f1e0a59c9adc9c16f2266d1
25 https://vault.almalinux.org/9.5/AppStream/x86_64/os/Packages/libICE-1.0.10-8.el9.x86_64.rpm d0b867203384942985c3c4ad6fc9ec0000fcc9965408451a6cdef8df06a3833c
https://vault.almalinux.org/9.5/AppStream/x86_64/os/Packages/libogg-1.3.4-6.el9.i686.rpm 9e4ff6fa0251c5357ae8f648b3e396d0043d5b3f2fb28d23325f5bd592c67aee
https://vault.almalinux.org/9.5/AppStream/x86_64/os/Packages/libogg-1.3.4-6.el9.x86_64.rpm 83b4b333e335654674032d1cda4d7deb328b5a409f95e3952c3dc482b684fd8f
26 https://vault.almalinux.org/9.5/AppStream/x86_64/os/Packages/libsigc%2B%2B20-2.10.7-2.el9.i686.rpm 7c33f4c18cbd51dc0a7c9ae0190b1a27d0540ce2fd92ced4776dde66162d1a88
27 https://vault.almalinux.org/9.5/AppStream/x86_64/os/Packages/libsigc%2B%2B20-2.10.7-2.el9.x86_64.rpm 8600132b9e4efadfe23d3125e90287f5a7114165fd9ecb064d9930fcca446ef2
28 https://vault.almalinux.org/9.5/AppStream/x86_64/os/Packages/libSM-1.2.3-10.el9.i686.rpm ec68b3def828ba442248f3cff495f42c4af3dd58f38c8daad07dfddc109d999a
29 https://vault.almalinux.org/9.5/AppStream/x86_64/os/Packages/libSM-1.2.3-10.el9.x86_64.rpm d00318843a50138829b470a97b8db1a00723b10bca23c16a8386d9ab670e4c64
30 https://vault.almalinux.org/9.5/AppStream/x86_64/os/Packages/libtheora-1.1.1-31.el9.i686.rpm 2155c688b516ab359d0c47be6d73e51d3c65f199ed5591f7bb7ce6d5d9799977
31 https://vault.almalinux.org/9.5/AppStream/x86_64/os/Packages/libtheora-1.1.1-31.el9.x86_64.rpm 25ab4a8ad997b450b4a34a777f5a0678eea72ca1665944a7a461ac63de4b25bf
https://vault.almalinux.org/9.5/AppStream/x86_64/os/Packages/libvorbis-1.3.7-5.el9.i686.rpm e38c5185fea611330ea253db020315dd564507bf95c48a81dbe7db186ce4214b
https://vault.almalinux.org/9.5/AppStream/x86_64/os/Packages/libvorbis-1.3.7-5.el9.x86_64.rpm 3c340337a073975636d198a282503f32a54bf85fb5345522a2c22e530b8d6c9e
32 https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/bluez-libs-5.72-2.el9.i686.rpm af1aba8e6fa5ccf33032d58a3acc59368c07d532293396db205fb9a4bc1241ae
33 https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/bluez-libs-5.72-2.el9.x86_64.rpm 49c273813b4616240acdae8dae893192658c7541482f9bbb2c46dfe19b61877d
34 https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/glibc-2.34-125.el9_5.8.alma.1.i686.rpm 28bc1088e39483d145849e8804c5a0f2524faeb4f76631ae46c41100f40e08b9
39 https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/gnutls-3.8.3-4.el9_4.x86_64.rpm 16c48c504fe62f8e19cac7c6442d3e08bba487f610c2f533116dac32357cda86
40 https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/harfbuzz-2.7.4-10.el9.i686.rpm 5157daf2ab0a03b403d37c60b150b8f0f866754714f81e3d96368e06a16339ce
41 https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/harfbuzz-2.7.4-10.el9.x86_64.rpm 1f81073019abe4176d4496723a89b55a349c31f507e96397a0b3efa7cea0ff61
42 https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/libassuan-2.5.5-3.el9.i686.rpm 9ab4028be7d7c0631944476fb2e083eeb185c3d01468c8def3e3aa235dc5c12d
43 https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/libassuan-2.5.5-3.el9.x86_64.rpm 3201aaeb3240c3497673200c50fc27c2b07effd1c3fdd2fbd17a83373e80afb4
44 https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/libblkid-2.37.4-20.el9.i686.rpm f9e62d2768c31948b53268b7de51bd1c7342cdf39a328a0d89d933b4aa0c5dd1
45 https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/libblkid-2.37.4-20.el9.x86_64.rpm ed02d978a36488b38bad62af21d4045367c1f0b00d00c90ded01e2fc8e190536
46 https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/libbrotli-1.0.9-7.el9_5.i686.rpm d18c20fccbb9497222059d475161a55c0c6279344f214fe551b8b0f87d3c054a
+10
View File
@@ -1,3 +1,13 @@
box64 (0.4.2) unstable; urgency=low
This version add lots on unconnected new things, like a PPC64LE backend, Vulkan overlay support or more Dynarec finetunning.
=> Vulkan x64 overlay support. That means using the linux version of Steam, Fossilize & GameOverlayUI will work.
=> Many dynarec refactors, especialy on ARM64 & LA64 with fixes to speed regression introduced with the the last 2 releases and improved compatibility.
=> Support for SteamRT3 & new Proton 11
=> New PCC64LE in the work. Not finished, but should be usable already (but the platform seems to use a 64k pagesize by default, so compatibility will suffer on this platformm). Note that main Box64 mainteners don't have access to relevent hardware, so support will be limited.
-- Sebastien Chevalier <[email protected]> Mon, 20 Apr 2026 10:30:33 -0100
box64 (0.4.0) unstable; urgency=low
This version added many important refactors: the opcode prefix decoder for Dynarec, libGL and Vulkan, the FSGSBASE support, making segments handling easier and faster.
+2 -2
View File
@@ -69,8 +69,8 @@ Once the package name is found, find the exact URL for downloading it.
- https://archive.debian.org/debian/pool/
- EOPKG = Use the "`<VERSION>-<RELEASE>-x86_64.eopkg`" and "`32bit-<VERSION>-<RELEASE>-x86_64.eopkg`" packages.
- https://cdn.getsol.us/repo/shannon/
- RPM = Navigate to the "`<MAJOR>.<MINOR>`" version directory first. Then explore "AppStream" and "BaseOS". Use the "x86_64.rpm" and "i686.rpm" packages.
- https://repo.almalinux.org/almalinux/
- RPM = Navigate to the "`<MAJOR>.<MINOR>`" version directory first. Then explore "AppStream" and "BaseOS". The "x86_64" repository will contain both "x86_64.rpm" and "i686.rpm" packages.
- https://vault.almalinux.org/
- Enterprise Linux (EL) distributions, such as AlamaLinux, sometimes are missing 32-bit packages. Use the Fedora 34 [update](https://archives.fedoraproject.org/pub/archive/fedora/linux/updates/34/Everything/x86_64/Packages/) and [release](https://archives.fedoraproject.org/pub/archive/fedora/linux/releases/34/Everything/x86_64/os/Packages/) archives for compatible packages with EL 9.
- XBPS = There are too many files in the repository to display on a web browser. Use pkgs.org instead to find the exact URL for downloading it.
- https://repo-default.voidlinux.org/current/
+47
View File
@@ -1,3 +1,50 @@
v0.4.2
======
Highlights:
* This version add lots on unconnected new things, like a PPC64LE backend, Vulkan overlay support or more Dynarec finetunning!
=> Vulkan x64 overlay support. That means using the linux version of Steam, Fossilize & GameOverlayUI will work.
=> Many dynarec refactors, especialy on ARM64 & LA64 with fixes to speed regression introduced with the the last 2 releases and improved compatibility.
=> Support for SteamRT3 & new Proton 11
=> New PCC64LE in the work. Not finished, but usable already. Note that the platform seems to use a 64k pagesize by default, so compatibility will suffer on this platformm.
Version summary:
* New RISC-V support for the script to denerate Debian .deb package
* Improved the way system informations (like cpu brand and number of cores) is gathered and cpuid opcode handled
* Improved support for Steam and new SteamRT3 64bit version
* Elf: Improved handling of large pagesize (usefull for PPC64LE with its 64k pagesize)
* Elf: Improved support for AppImage
* Wrapping: Vulkan: Added support wor x64 overlay
* Wrapping; Vulkan: Added BOX64_NOVULKANOVERLAY to disable x64 overlay handling
* Wrapping: more wrapped functions, reworked some existing one with wrapperhelper
* Wrapping: Added more wrapped libs
* Wrapping: BOX32: more wrapped function and some fixes to existing ones
* Wrapping: PPC64: Better handling of ioctl
* Interpreter: Added a few more exotic opcodes
* Dynarec: Added support for STRONGMEM=4
* Dynarec: Improved TF flag handling
* Dynarec: Reworked HotPage detection and handling
* Dynarec: Reworked dynarec generation to batter handle abort mid-block
* Dynarec: Rework how "Alt" addresses are handled
* Dynarec: Removed BOX64_DYNAREC_HOTPAGE_ALT
* Dynarec: Added support for Secondary Entry Point on dynablock when using CALLRET=1
* Dynarec: Improve CALL FAR / RET FAR opcodes handling, adding CALLRET optimisation support
* Dynarec: Improve IRET opcodes handling, adding CALLRET optimisation support
* Dynarec: ARM64: Some new fixes for existing opcodes
* Dynarec: ARM64: Reworked XMM/YMM register handling
* Dynarec: ARM64: Reworked DIRTY=2 with AutoCRC Dynablock
* Dynarec: LA64: Lots of new opcodes added & fixes
* Dynarec: LA64: Added full support for SAFEFLAGS=2
* Dynarec: LA64: Lots of fixes & improvements for FASTNAN=0
* Dynarec: LA64: Refactor opcode printer
* Dynarec: LA64: Reworked DIRTY=2 with AutoCRC Dynablock
* Dynarec: LA64: Added CALLRET=2 support
* Dynarec: RV64: A few fixes to existing opcodes
* Dynarec: RV64: Added CALLRET=2 support
* Dynarec: PPC64: Created a new backend for PPC64LE, with some opcodes already (still WIP)
* WOWBOX64: Some small fixes
v0.4.0
======
+14
View File
@@ -135,6 +135,11 @@ static void atfork_child_box64context(void)
{
// (re)init mutex if it was lock before the fork
init_mutexes(my_context);
#ifdef DYNAREC
// Cancel FillBlock if needed
void CancelBlock64(int need_lock);
CancelBlock64(0);
#endif
}
int box64_cycle_log_initialized = 0;
@@ -181,6 +186,12 @@ box64context_t *NewBox64Context(int argc)
context->local_maplib = NewLibrarian(context);
context->versym = NewDictionnary();
context->system = NewBridge();
#ifdef DYNAREC
int old_is32bits = box64_is32bits;
box64_is32bits = 1;
context->alternates = NewBridge(); // this needs to be in 32bits address space
box64_is32bits = old_is32bits;
#endif
// Cannot use Bridge name as the map is not initialized yet
// create vsyscall
context->vsyscall = AddBridge(context->system, vFEv, box64_is32bits?x86Syscall:x64Syscall, 0, NULL);
@@ -352,6 +363,9 @@ void FreeBox64Context(box64context_t** context)
box_free(ctx->pythonpath);
FreeBridge(&ctx->system);
#ifdef DYNAREC
FreeBridge(&ctx->alternates);
#endif
#ifndef STATICBUILD
freeGLProcWrapper(ctx);
+1 -1
View File
@@ -3,6 +3,6 @@
#define BOX64_MAJOR 0
#define BOX64_MINOR 4
#define BOX64_REVISION 1
#define BOX64_REVISION 2
#endif //__BOX64_VERSION_H_
+36 -1
View File
@@ -434,6 +434,8 @@ static void addLibPaths(box64context_t* context)
GO("libicui18n.so.66");
GO("libicuuc.so.67");
GO("libicui18n.so.67");
GO("libicuuc.so.68");
GO("libicui18n.so.68");
GO("libicuuc.so.72");
GO("libicui18n.so.72");
GO("libicuuc.so.73");
@@ -495,6 +497,8 @@ void LoadLDPath(box64context_t *context)
AddPath("/usr/lib/i386-linux-gnu", &context->box64_ld_lib, 1);
if(FileExist("/usr/i386-linux-gnu/lib", 0))
AddPath("/usr/i386-linux-gnu/lib", &context->box64_ld_lib, 1);
if(FileExist("/usr/i686-linux-gnu/lib", 0))
AddPath("/usr/i686-linux-gnu/lib", &context->box64_ld_lib, 1);
if(FileExist("/usr/lib/box64-i386-linux-gnu", 0))
AddPath("/usr/lib/box64-i386-linux-gnu", &context->box64_ld_lib, 1);
if(FileExist("/opt/box64/lib32", 0))
@@ -666,6 +670,8 @@ void setupTrace()
void endMallocHook();
#endif
void finiPendingDLOpenedNoUnload(x64emu_t* emu);
void endBox64()
{
if(!my_context || box64_quit)
@@ -685,9 +691,30 @@ void endBox64()
//void closeAllDLOpened();
//closeAllDLOpened(); // close residual dlopened libs. Disabled, seems like a bad idea, better to unload with proper dependancies
RunElfFini(my_context->elfs[0], emu);
printf_log(LOG_DEBUG, "Finished calling fini for dlopened libs\n");
finiPendingDLOpenedNoUnload(emu); // call fini for dlopened libs, but don't unload them, as they might be needed by the main elf fini
// unload needed libs
needed_libs_t* needed = my_context->elfs[0]->needed;
printf_log(LOG_DEBUG, "Unloaded main elf: Will Dec RefCount of %d libs\n", needed?needed->size:0);
int workers = get_active_emu_workers();
if (workers > 0) {
const int sleep_us = 10000; // 10ms
const int max_wait_ms = 2000; // 2s
int waited_ms = 0;
printf_log(LOG_INFO, "endBox64: waiting emu workers to exit (n=%d)\n", workers);
while ((workers = get_active_emu_workers()) > 0 && waited_ms < max_wait_ms) {
usleep(sleep_us);
waited_ms += sleep_us / 1000;
}
if (workers > 0) {
printf_log(LOG_INFO,
"endBox64: %d emu workers still alive after %dms, skip unload/free to avoid UAF crash\n",
workers, waited_ms);
return;
}
}
if(needed)
for(int i=0; i<needed->size; ++i)
DecRefCount(&needed->libs[i], emu);
@@ -748,6 +775,7 @@ int initialize(int argc, const char **argv, char** env, x64emu_t** emulator, elf
init_malloc_hook();
#endif
init_auxval(argc, argv, environ?environ:env);
ftrace = stderr; // init early: BOX64_VERSION path below uses PrintfFtrace
// analogue to QEMU_VERSION in qemu-user-mode emulation
if(getenv("BOX64_VERSION")) {
PrintBox64Version(0);
@@ -770,7 +798,14 @@ int initialize(int argc, const char **argv, char** env, x64emu_t** emulator, elf
exit(0);
}
if (argc >= 3 && (!strcmp(argv[1], "--test") || !strcmp(argv[1], "-t"))) {
int is_test = 0;
for (int i = 1; i < argc; i++) {
if (!strcmp(argv[i], "--test") || !strcmp(argv[i], "-t")) {
is_test = 1;
break;
}
}
if (is_test) {
box64_unittest_mode = 1;
exit(unittest(argc, argv));
}
+64 -104
View File
@@ -1850,7 +1850,7 @@ void addDBFromAddressRange(uintptr_t addr, size_t size)
int cleanDBFromAddressRange(uintptr_t addr, size_t size, int destroy)
{
uintptr_t start_addr = my_context?((addr<my_context->max_db_size)?0:(addr-my_context->max_db_size)):addr;
dynarec_log(LOG_DEBUG, "cleanDBFromAddressRange %p/%p -> %p %s\n", (void*)addr, (void*)start_addr, (void*)(addr+size-1), destroy?"destroy":"mark");
dynarec_log(LOG_DEBUG, "cleanDBFromAddressRange %p/%p -> %p %s\n", (void*)addr, (void*)start_addr, (void*)(addr+size-1), destroy?((destroy==2)?"invalidCRC":"destroy"):"mark");
dynablock_t* db = NULL;
uintptr_t end = addr+size;
int ret = 0;
@@ -1858,10 +1858,12 @@ int cleanDBFromAddressRange(uintptr_t addr, size_t size, int destroy)
start_addr = getDBSize(start_addr, end-start_addr, &db);
if(db) {
ret = 1;
if(destroy)
FreeRangeDynablock(db, addr, size);
else
MarkRangeDynablock(db, addr, size);
switch(destroy) {
case 0: MarkRangeDynablock(db, addr, size); break;
case 1: FreeRangeDynablock(db, addr, size); break;
case 2: MarkCRCRangeDynablock(db, addr, size); break;
}
}
}
return ret;
@@ -2173,6 +2175,16 @@ int getNeedTest(uintptr_t addr)
return 0;
}
dynablock_t* getDBnoTest(uintptr_t addr)
{
void* jblock = NULL;
dynablock_t* db = getDBBlock(addr, &jblock);
if(!db) return NULL;
if(jblock==db->jmpnext) return NULL;
return db;
}
uintptr_t getJumpAddress64(uintptr_t addr)
{
uintptr_t idx3, idx2, idx1, idx0;
@@ -2380,11 +2392,11 @@ void neverprotectDB(uintptr_t addr, size_t size, int mark)
if(prot&PROT_DYNAREC) {
prot&=~PROT_DYN;
if(mark)
cleanDBFromAddressRange(cur, bend-cur, 0);
cleanDBFromAddressRange(cur, bend-cur, (mark==2)?2:0);
mprotect((void*)cur, bend-cur, prot);
} else if(prot&PROT_DYNAREC_R) {
if(mark)
cleanDBFromAddressRange(cur, bend-cur, 0);
cleanDBFromAddressRange(cur, bend-cur, (mark==2)?2:0);
prot &= ~PROT_DYN;
}
prot |= PROT_NEVERCLEAN;
@@ -2457,18 +2469,22 @@ typedef union hotpage_s {
} hotpage_t;
#define HOTPAGE_MAX ((1<<28)-1)
#define N_HOTPAGE 32
#define N_HOTPAGE_ALT 8
#define HOTPAGE_MARK 64
#define HOTPAGE_DIRTY 128
#define HOTPAGE_DIRTY_ALT 1024
#define HOTPAGE_DIRTY2 16
static hotpage_t hotpage[N_HOTPAGE] = {0};
void SetHotPage(int idx, uintptr_t page)
{
hotpage_t tmp = hotpage[idx];
tmp.addr = page;
tmp.cnt = BOX64ENV(dynarec_dirty)?(BOX64ENV(dynarec_hotpage_alt)?HOTPAGE_DIRTY_ALT:HOTPAGE_DIRTY):HOTPAGE_MARK;
tmp.cnt = 0;
switch(BOX64ENV(dynarec_dirty)) {
case 0: tmp.cnt = HOTPAGE_MARK; break;
case 1: tmp.cnt = HOTPAGE_DIRTY; break;
case 2: tmp.cnt = HOTPAGE_DIRTY2; break;
}
//TODO: use Atomics to update hotpage?
native_lock_store_dd(hotpage+idx, tmp.x);
native_lock_store_dd(&hotpage[idx], tmp.x);
}
int IdxHotPage(uintptr_t page)
{
@@ -2477,36 +2493,14 @@ int IdxHotPage(uintptr_t page)
return i;
return -1;
}
void CancelHotPage(uintptr_t page)
{
unneverprotectDB(page<<12, box64_pagesize);
}
int IdxOldestHotPage(uintptr_t page)
{
int best_idx = -1;
uint32_t best_cnt = HOTPAGE_MAX+1;
if(BOX64ENV(dynarec_hotpage_alt)) {
hotpage_t tmp;
tmp.addr = page;
tmp.cnt = HOTPAGE_MAX;
for(int i=0; i<N_HOTPAGE_ALT; ++i) {
if(!hotpage[i].cnt) {
native_lock_store_dd(hotpage+i, tmp.x);
return i;
}
uint32_t cnt = hotpage[i].cnt;
if(cnt==HOTPAGE_MAX) cnt = 0;
if(cnt < best_cnt) {
best_idx = i;
best_cnt = cnt;
}
}
hotpage_t old = hotpage[best_idx];
native_lock_store_dd(hotpage+best_idx, tmp.x);
if(old.cnt && old.cnt!=HOTPAGE_MAX && BOX64ENV(dynarec_dirty)==1)
CancelHotPage(old.addr);
} else {
for(int i=0; i<N_HOTPAGE && best_cnt; ++i) {
for(int i=0; i<N_HOTPAGE; ++i) {
if(!hotpage[i].x) {
return i;
} else {
uint32_t cnt = hotpage[i].cnt;
if(cnt < best_cnt) {
best_idx = i;
@@ -2514,6 +2508,7 @@ int IdxOldestHotPage(uintptr_t page)
}
}
}
dynarec_log(LOG_INFO, "%04d|No more live Hotpage slot for %p, recycling idx=%d (%p)\n", GetTID(), (void*)(page<<12), best_idx, (void*)(uintptr_t)(hotpage[best_idx].addr<<12));
return best_idx;
}
// this function will create a new HotPage, or re-arm it if it's already registered
@@ -2526,42 +2521,20 @@ void CheckHotPage(uintptr_t addr, uint32_t prot)
if(BOX64ENV(dynarec_nohotpage))
return;
uintptr_t page = addr>>12;
if(!BOX64ENV(dynarec_hotpage_alt)) {
if(!(prot&PROT_EXEC))
return; // needs to be an executable page
/*if(BOX64ENV(dynarec_dirty)>1) {
dynarec_log(LOG_INFO, "Detecting a Hotpage at %p, marking page as NEVERCLEAN\n", (void*)(page<<12));
neverprotectDB(page<<12, box64_pagesize, 1);
return;
}*/
}
// look for idx
int idx = IdxHotPage(page);
if(BOX64ENV(dynarec_hotpage_alt)) {
if(idx==-1) { IdxOldestHotPage(page); return; }
hotpage_t hp = hotpage[idx];
/*if(hp.cnt==HOTPAGE_MAX)*/ {
if(BOX64ENV(dynarec_dirty)>1) {
dynarec_log(LOG_INFO, "Detecting a Hotpage at %p (idx=%d), marking page as NEVERCLEAN\n", (void*)(page<<12), idx);
neverprotectDB(page<<12, box64_pagesize, 1);
hp.cnt = 0;
native_lock_store_dd(hotpage+idx, hp.x); // free slot
} else {
dynarec_log(LOG_INFO, "Detecting a Hotpage at %p (idx=%d)\n", (void*)(page<<12), idx);
SetHotPage(idx, page);
}
}
} else {
if(idx!=-1 && BOX64ENV(dynarec_dirty)>1 && !hotpage[idx].cnt) {
// Re-arming, so put the page as NEVERCLEAN and stop bothering
neverprotectDB(page<<12, box64_pagesize, 1);
return;
}
if(idx==-1) idx = IdxOldestHotPage(page);
if(idx==-1) return;
dynarec_log(LOG_INFO, "Detecting a Hotpage at %p (idx=%d)\n", (void*)(page<<12), idx);
SetHotPage(idx, page);
if(idx!=-1 && (BOX64ENV(dynarec_dirty)>1)) {
// Re-arming, so put the page as NEVERCLEAN and stop bothering
dynarec_log(LOG_INFO, "Detecting a Hotpage at %p (idx=%d) again, switching the page to NEVERCLEAN\n", (void*)(page<<12), idx);
neverprotectDB(page<<12, box64_pagesize, 2);
hotpage_t hp = {0};
native_lock_store_dd(hotpage+idx, hp.x); // free slot
return;
}
if(idx==-1) idx = IdxOldestHotPage(page);
if(idx==-1) return;
dynarec_log(LOG_INFO, "%04d|Detecting a Hotpage at %p (idx=%d)\n", GetTID(), (void*)(page<<12), idx);
SetHotPage(idx, page);
}
int isInHotPage(uintptr_t addr)
{
@@ -2570,45 +2543,29 @@ int isInHotPage(uintptr_t addr)
return 0;
uintptr_t page = addr>>12;
int idx = IdxHotPage(page);
if(BOX64ENV(dynarec_hotpage_alt)) {
if(idx==-1 || !hotpage[idx].cnt || (hotpage[idx].cnt==HOTPAGE_MAX))
return 0;
//TODO: do Atomic stuffs instead
hotpage_t hp = hotpage[idx];
--hp.cnt;
native_lock_store_dd(hotpage+idx, hp.x);
if(!hp.cnt && BOX64ENV(dynarec_dirty)==1)
CancelHotPage(hp.addr);
return 1;
} else {
int ret = ((idx==-1) || !hotpage[idx].cnt)?0:1;
// decrement all hotpage, it's a hotpage "tick"
for(int i=0; i<N_HOTPAGE; ++i) {
int ok = 0;
do {
hotpage_t hp = hotpage[i];
hotpage_t old = hp;
if(!hp.cnt || (hp.cnt==HOTPAGE_MAX)) {
ok = 1;
} else {
--hp.cnt;
ok = native_lock_storeifref2(hotpage+i, (void*)hp.x, (void*)old.x)==(void*)old.x;
}
} while(!ok);
}
return ret;
int ret = ((idx==-1) || !hotpage[idx].cnt)?0:1;
// decrement all hotpage, it's a hotpage "tick"
for(int i=0; i<N_HOTPAGE; ++i) {
int ok = 0;
do {
hotpage_t hp = hotpage[i];
hotpage_t old = hp;
if(!hp.cnt || (hp.cnt==HOTPAGE_MAX)) {
ok = 1;
} else {
--hp.cnt;
ok = native_lock_storeifref2(hotpage+i, (void*)hp.x, (void*)old.x)==(void*)old.x;
}
} while(!ok);
}
return ret;
}
int checkInHotPage(uintptr_t addr)
{
if(addr>0x1000000000000LL) return 0;
uintptr_t page = addr>>12;
int idx = IdxHotPage(page);
if(BOX64ENV(dynarec_hotpage_alt)) {
return (idx==-1 || !hotpage[idx].cnt || (hotpage[idx].cnt==HOTPAGE_MAX))?0:1;
} else {
return ((idx==-1) || !hotpage[idx].cnt)?0:1;
}
return ((idx==-1) || !hotpage[idx].cnt)?0:1;
}
@@ -2726,7 +2683,7 @@ void refreshProtection(uintptr_t addr)
void allocProtection(uintptr_t addr, size_t size, uint32_t prot)
{
dynarec_log(LOG_DEBUG, "allocProtection %p:%p 0x%x\n", (void*)addr, (void*)(addr+size-1), prot);
dynarec_log(LOG_DEBUG, "allocProtection %p:%p 0x%x", (void*)addr, (void*)(addr+size-1), prot);
size = ALIGN(size);
addr &= ~(box64_pagesize-1);
LOCK_PROT();
@@ -2734,8 +2691,11 @@ void allocProtection(uintptr_t addr, size_t size, uint32_t prot)
uintptr_t endb;
int there = rb_get_end(mapallmem, addr, &val, &endb);
// block is here or absent, no half-block handled..
if(!there)
if(!there) {
dynarec_log_prefix(0, LOG_DEBUG, " added\n");
rb_set(mapallmem, addr, addr+size, MEM_EXTERNAL);
} else
dynarec_log_prefix(0, LOG_DEBUG, " ignored\n");
UNLOCK_PROT();
// don't need to add precise tracking probably
}
+5
View File
@@ -1221,6 +1221,11 @@ int convert_bitmask(uint64_t bitmask);
#define FCMPS_0(Sn) FEMIT(FCMP_scalar(0b00, Sn, 0, 0b01))
#define FCMPD_0(Dn) FEMIT(FCMP_scalar(0b01, Dn, 0, 0b01))
// CCMP . CMP if cond is pass, else use nzcv as new flags
#define FCCMP_scalar(type, Rm, cond, Rn, op, nzcv) (0b00011110<<24 | (type)<<22 | 1<<21 | (Rm)<<16 | ((cond)<<12 | 0b01<<10 | (Rn)<<5 | (op)<<4 | (nzcv)))
#define FCCMPS(Sn, Sm, nzcv, cond) FEMIT(FCCMP_scalar(0b00, Sm, cond, Sn, 0, nzcv))
#define FCCMPD(Dn, Dm, nzcv, cond) FEMIT(FCCMP_scalar(0b01, Dm, cond, Dn, 0, nzcv))
// CVT
#define FCVT_scalar(sf, type, rmode, opcode, Rn, Rd) ((sf)<<31 | 0b11110<<24 | (type)<<22 | 1<<21 | (rmode)<<19 | (opcode)<<16 | (Rn)<<5 | (Rd))
// Floating-point Convert to Signed integer, rounding to nearest with ties to Away
+28
View File
@@ -36,6 +36,7 @@
.global arm64_lock_get_d
.global arm64_lock_get_dd
.global arm64_crc
.global arm64_x31_hash
arm64_lock_read_b:
dmb ish
@@ -443,4 +444,31 @@ arm64_crc:
subs w1, w1, #1
bne 3b
4:
ret
arm64_x31_hash:
//x0 is address, w1 is len
mov x2, x0 // address is x2 now
mov w0, wzr // hash is w0
1:
cmp w1, #8
blo 2f
ldr x3, [x2], #8
mov x4, #8
3:
sub w0, w0, w0, lsl #5
sub w0, w0, w3, uxtb
sub w0, wzr, w0
ror x3, x3, #8
subs w4, w4, #1
bne 3b
2:
cbz w1, 5f
4:
ldrb w3, [x2], #1
sub w0, w0, w0, lsl #5
sub w0, w3, w0
subs w1, w1, #1
bne 4b
5:
ret
+35
View File
@@ -5,8 +5,10 @@
.align 4
.extern LinkNext
.extern LinkNextInvalid
.global arm64_next
.global arm64_next_invalid
.8byte 0 // NULL pointer before arm64_next, for getDB
arm64_next:
@@ -41,3 +43,36 @@ arm64_next:
// return offset is jump address
br x3
arm64_next_invalid:
// emu is r0
// IP address is r1
sub sp, sp, (8 * 12)
stp x0, x1, [sp, (8 * 0)]
stp x10, x11, [sp, (8 * 2)]
stp x12, x13, [sp, (8 * 4)]
stp x14, x15, [sp, (8 * 6)]
stp x16, x17, [sp, (8 * 8)]
stp x18, x27, [sp, (8 * 10)] // also save x27(rip) to allow change in LinkNext
#ifdef _WIN32
ldr x18, [x0, 3104]
#endif
mov x1, x27 // xRIP, should not be needed most of the time
mov x2, x30 // "from" is in lr, so put in x2
add x3, sp, 8*11 // x3 is address to change rip
// call the function
bl LinkNextInvalid
// preserve return value
mov x3, x0
// pop regs
ldp x0, x1, [sp, (8 * 0)]
ldp x10, x11, [sp, (8 * 2)]
ldp x12, x13, [sp, (8 * 4)]
ldp x14, x15, [sp, (8 * 6)]
ldp x16, x17, [sp, (8 * 8)]
ldp x18, x27, [sp, (8 * 10)]
add sp, sp, (8 * 12)
// return offset is jump address
br x3
+13 -11
View File
@@ -991,10 +991,10 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
GETEW(x1, 0);
GETGW(x2);
// Extract RPL (low 2 bits)
UBFXw(x3, ed, 0, 2);
UBFXw(x6, ed, 0, 2);
UBFXw(x4, gd, 0, 2);
// need_update = (dst_rpl < src_rpl)
CMPSw_REG(x3, x4);
CMPSw_REG(x6, x4);
CSETw(x5, cLT);
// ZF = need_update
BFIw(xFlags, x5, F_ZF, 1);
@@ -2936,6 +2936,8 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
LDRx_REG(x3, x1, x2);
//LDRx_U12(x3, x1, offsetof(box64context_t, signals[X64_SIGTRAP]));
CMPSx_U12(x3, 0);
// commit df before branch, CALL_S in int3 path has FORCE_DFNONE
CHECK_DFNONE(0);
B_MARK(cEQ);
GETIP(addr); // update RIP
STORE_XEMU_CALL(xRIP);
@@ -3823,17 +3825,14 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
// Push actual return address
if(addr < (dyn->start+dyn->isize)) {
// there is a next...
if(BOX64DRENV(dynarec_callret)>1)
if(BOX64DRENV(dynarec_callret)>1 && !dyn->always_test)
j64 = CALLRET_GETRET();
else
j64 = (dyn->insts)?(dyn->insts[ninst].epilog-(dyn->native_size)):0;
ADR_S20(x4, j64);
MESSAGE(LOG_NONE, "\tCALLRET set return to +%di\n", j64>>2);
} else {
if(BOX64DRENV(dynarec_callret)>1)
j64 = CALLRET_GETRET();
else
j64 = (dyn->insts)?(GETMARK-(dyn->native_size)):0;
j64 = (dyn->insts)?(GETMARK-(dyn->native_size)):0;
ADR_S20(x4, j64);
MESSAGE(LOG_NONE, "\tCALLRET set return to +%di\n", j64>>2);
}
@@ -4016,7 +4015,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
case 3:
INST_NAME("NEG Eb");
SETFLAGS(X_ALL, SF_SET_PENDING);
GETSEB(x1, 0);
GETEB(x1, 0);
emit_neg8(dyn, ninst, x1, x2, x4);
EBBACK;
break;
@@ -4534,7 +4533,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
// Push actual return address
if(addr < (dyn->start+dyn->isize)) {
// there is a next...
if(BOX64DRENV(dynarec_callret)>1)
if(BOX64DRENV(dynarec_callret)>1 && !dyn->always_test)
j64 = CALLRET_GETRET();
else
j64 = (dyn->insts)?(dyn->insts[ninst].epilog-(dyn->native_size)):0;
@@ -4589,14 +4588,17 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
// Push actual return address. Note that CS will not be tested, but that should be ok?
if(can_continue) {
// there is a next...
if(BOX64DRENV(dynarec_callret)>1)
if(BOX64DRENV(dynarec_callret)>1 && !dyn->always_test)
j64 = CALLRET_GETRET();
else
j64 = (dyn->insts)?(dyn->insts[ninst].epilog-(dyn->native_size)):0;
ADR_S20(x4, j64);
MESSAGE(LOG_NONE, "\tCALLRET set return to +%di\n", j64>>2);
} else {
j64 = (dyn->insts)?(GETMARK-(dyn->native_size)):0;
if(BOX64DRENV(dynarec_callret)>1 && !dyn->always_test)
j64 = CALLRET_GETRET();
else
j64 = (dyn->insts)?(GETMARK-(dyn->native_size)):0;
ADR_S20(x4, j64);
MESSAGE(LOG_NONE, "\tCALLRET set return to +%di\n", j64>>2);
}
+64 -41
View File
@@ -35,7 +35,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
uint8_t eb1, eb2, gb1, gb2;
int32_t i32, i32_;
int cacheupd = 0;
int v0, v1;
int v0, v1, v2;
int q0, q1;
int d0, d1;
int s0;
@@ -504,12 +504,11 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
VFCVTZSS(q0, q0);
} else {
MRS_fpsr(x5);
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
MSR_fpsr(x5);
ORRw_mask(x2, xZR, 1, 0); //0x80000000
d0 = fpu_get_scratch(dyn, ninst);
for (int i=0; i<2; ++i) {
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
MSR_fpsr(x5);
if (i) {
VMOVeS(d0, 0, v1, i);
FRINTZS(d0, d0);
@@ -542,12 +541,11 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
VFCVTZSS(q0, q0);
} else {
MRS_fpsr(x5);
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
MSR_fpsr(x5);
ORRw_mask(x2, xZR, 1, 0); //0x80000000
d0 = fpu_get_scratch(dyn, ninst);
for (int i=0; i<2; ++i) {
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
MSR_fpsr(x5);
if (i) {
VMOVeS(d0, 0, v1, i);
FRINTIS(d0, d0);
@@ -572,10 +570,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
nextop = F8;
GETGX(v0, 0);
GETEXSS(s0, 0, 0);
IFX(X_CF|X_PF|X_ZF) {
FCMPS(v0, s0);
}
FCOMI(x1, x2);
FCOMIS(x1, x2, v0, s0);
break;
case 0x30:
INST_NAME("WRMSR");
@@ -841,6 +836,12 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
v1 = fpu_get_scratch(dyn, ninst);
} else
v1 = q1;
if(q0==d0) {
// move away q0 as it would be overwritten else
int tmp = fpu_get_scratch(dyn, ninst);
VMOVQ(tmp, d0);
d0 = tmp;
}
VREV64Q_32(q0, q0);
if(q0==q1) {
VMOVQ(v1, q0);
@@ -1218,6 +1219,8 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
if(!BOX64ENV(dynarec_fastnan)) {
v0 = fpu_get_scratch(dyn, ninst);
v1 = fpu_get_scratch(dyn, ninst);
v2 = fpu_get_scratch(dyn, ninst);
VMOVQ(v2, q1); // save original src1 (Gx)
// check if any input value was NAN
VFMAXQS(v0, q0, q1); // propagate NAN
VFCMEQQS(v0, v0, v0); // 0 if NAN, 1 if not NAN
@@ -1228,6 +1231,10 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
VBICQ(v1, v0, v1); // forget it in any input was a NAN already
VSHLQ_32(v1, v1, 31); // only keep the sign bit
VORRQ(q1, q1, v1); // NAN -> -NAN
VFCMEQQS(v0, v2, v2); // 0 if src1 was NaN
MOVIQ_32_lsl(v1, 0x40, 2); // QNaN bit
VORRQ(v2, v2, v1); // quiet any SNaN in saved src1
VBIFQ(q1, v2, v0); // where src1 was NaN, use QNaN(src1)
}
break;
case 0x59:
@@ -1238,6 +1245,8 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
if(!BOX64ENV(dynarec_fastnan)) {
v0 = fpu_get_scratch(dyn, ninst);
v1 = fpu_get_scratch(dyn, ninst);
v2 = fpu_get_scratch(dyn, ninst);
VMOVQ(v2, q1); // save original src1 (Gx)
// check if any input value was NAN
VFMAXQS(v0, q0, q1); // propagate NAN
VFCMEQQS(v0, v0, v0); // 0 if NAN, 1 if not NAN
@@ -1248,6 +1257,10 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
VBICQ(v1, v0, v1); // forget it in any input was a NAN already
VSHLQ_32(v1, v1, 31); // only keep the sign bit
VORRQ(q1, q1, v1); // NAN -> -NAN
VFCMEQQS(v0, v2, v2); // 0 if src1 was NaN
MOVIQ_32_lsl(v1, 0x40, 2); // QNaN bit
VORRQ(v2, v2, v1); // quiet any SNaN in saved src1
VBIFQ(q1, v2, v0); // where src1 was NaN, use QNaN(src1)
}
break;
case 0x5A:
@@ -1272,6 +1285,8 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
if(!BOX64ENV(dynarec_fastnan)) {
v0 = fpu_get_scratch(dyn, ninst);
v1 = fpu_get_scratch(dyn, ninst);
v2 = fpu_get_scratch(dyn, ninst);
VMOVQ(v2, q1); // save original src1 (Gx)
// check if any input value was NAN
VFMAXQS(v0, q0, q1); // propagate NAN
VFCMEQQS(v0, v0, v0); // 0 if NAN, 1 if not NAN
@@ -1282,6 +1297,10 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
VBICQ(v1, v0, v1); // forget it in any input was a NAN already
VSHLQ_32(v1, v1, 31); // only keep the sign bit
VORRQ(q1, q1, v1); // NAN -> -NAN
VFCMEQQS(v0, v2, v2); // 0 if src1 was NaN
MOVIQ_32_lsl(v1, 0x40, 2); // QNaN bit
VORRQ(v2, v2, v1); // quiet any SNaN in saved src1
VBIFQ(q1, v2, v0); // where src1 was NaN, use QNaN(src1)
}
break;
case 0x5D:
@@ -1303,6 +1322,8 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
if(!BOX64ENV(dynarec_fastnan)) {
v0 = fpu_get_scratch(dyn, ninst);
v1 = fpu_get_scratch(dyn, ninst);
v2 = fpu_get_scratch(dyn, ninst);
VMOVQ(v2, q1); // save original src1 (Gx)
// check if any input value was NAN
VFMAXQS(v0, q0, q1); // propagate NAN
VFCMEQQS(v0, v0, v0); // 0 if NAN, 1 if not NAN
@@ -1313,6 +1334,10 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
VBICQ(v1, v0, v1); // forget it in any input was a NAN already
VSHLQ_32(v1, v1, 31); // only keep the sign bit
VORRQ(q1, q1, v1); // NAN -> -NAN
VFCMEQQS(v0, v2, v2); // 0 if src1 was NaN
MOVIQ_32_lsl(v1, 0x40, 2); // QNaN bit
VORRQ(v2, v2, v1); // quiet any SNaN in saved src1
VBIFQ(q1, v2, v0); // where src1 was NaN, use QNaN(src1)
}
break;
case 0x5F:
@@ -2146,9 +2171,9 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
CMPSxw_REG(xRAX, ed);
}
MOVxw_REG(x1, ed); // save value
Bcond(cNE, 4 + (rex.w ? 4 : 8));
Bcond(cNE, 4 + 8);
MOVxw_REG(ed, gd);
if (!rex.w) { B_NEXT_nocond; }
B_NEXT_nocond;
} else {
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, &unscaled, 0xfff<<(2+rex.w), (1<<(2+rex.w))-1, rex, NULL, 0, 0);
LDxw(x1, wback, fixedaddress);
@@ -2402,10 +2427,18 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
nextop = F8;
GETED(0);
GETGD;
if (BOX64DRENV(dynarec_safeflags) && !BOX64ENV(cputype)) {
IFX(X_PF)
MOV32w(x3, 0); // PF uses 0 when the source is zero
}
TSTxw_REG(ed, ed);
B_MARK(cEQ);
RBITxw(x1, ed); // reverse
CLZxw(gd, x1); // x2 gets leading 0 == BSF
RBITxw(gd, ed); // reverse
CLZxw(gd, gd); // gd gets leading 0 == BSF
if (BOX64DRENV(dynarec_safeflags) && !BOX64ENV(cputype)) {
IFX(X_PF)
MOVxw_REG(x3, gd);
}
MARK;
IFX(X_ZF) {
IFNATIVE(NF_EQ) {} else {
@@ -2418,7 +2451,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
IFX(X_AF) BFCw(xFlags, F_AF, 1);
IFX(X_SF) BFCw(xFlags, F_SF, 1);
IFX(X_OF) BFCw(xFlags, F_OF, 1);
IFX(X_PF) emit_pf(dyn, ninst, gd, x2);
IFX(X_PF) emit_pf(dyn, ninst, x3, x2);
}
break;
case 0xBD:
@@ -2432,11 +2465,19 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
nextop = F8;
GETED(0);
GETGD;
if (BOX64DRENV(dynarec_safeflags) && !BOX64ENV(cputype)) {
IFX(X_PF)
MOV32w(x3, 0); // PF uses 0 when the source is zero
}
TSTxw_REG(ed, ed);
B_MARK(cEQ);
CLZxw(gd, ed); // x2 gets leading 0
CLZxw(gd, ed); // gd gets leading 0
SUBxw_U12(gd, gd, rex.w?63:31);
NEGxw_REG(gd, gd); // complement
if (BOX64DRENV(dynarec_safeflags) && !BOX64ENV(cputype)) {
IFX(X_PF)
MOVxw_REG(x3, gd);
}
MARK;
IFX(X_ZF) {
IFNATIVE(NF_EQ) {} else {
@@ -2449,7 +2490,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
IFX(X_AF) BFCw(xFlags, F_AF, 1);
IFX(X_SF) BFCw(xFlags, F_SF, 1);
IFX(X_OF) BFCw(xFlags, F_OF, 1);
IFX(X_PF) emit_pf(dyn, ninst, gd, x2);
IFX(X_PF) emit_pf(dyn, ninst, x3, x2);
}
break;
case 0xBE:
@@ -2486,7 +2527,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
}
break;
case 0xC0:
INST_NAME("XADD Gb, Eb");
INST_NAME("XADD Eb, Gb");
SETFLAGS(X_ALL, SF_SET_PENDING);
nextop = F8;
GETGB(x1);
@@ -2497,16 +2538,15 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
EBBACK; // eb gets x1 (sum)
break;
case 0xC1:
INST_NAME("XADD Gd, Ed");
INST_NAME("XADD Ed, Gd");
SETFLAGS(X_ALL, SF_SET_PENDING);
nextop = F8;
GETGD;
GETED(0);
MOVxw_REG(x3, ed);
MOVxw_REG(ed, gd);
MOVxw_REG(gd, x3);
if (ed != gd) MOVx_REG(x3, ed);
emit_add32(dyn, ninst, rex, ed, gd, x4, x5);
WBACK;
if (ed != gd) MOVxw_REG(gd, x3);
break;
case 0xC2:
INST_NAME("CMPPS Gx, Ex, Ib");
@@ -2658,7 +2698,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
} else switch((nextop>>3)&7) {
case 1:
if(MODREG) {
INST_NAME("Invalid LOCK");
INST_NAME("Invalid C7");
UDF(0);
*need_epilog = 1;
*ok = 0;
@@ -2673,6 +2713,8 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
addr = geted(dyn, addr, ninst, nextop, &wback, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
if(rex.w && BOX64DRENV(dynarec_safeflags)>1) {
// unaligned memory cause a GPF
// commit df before branch, CALL_S in GPF path has FORCE_DFNONE
CHECK_DFNONE(0);
TSTx_mask(wback, 1, 0, 3);
B_MARK2(cEQ); // alligned, continue...
STORE_XEMU_CALL(xRIP);
@@ -2711,25 +2753,6 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
GETIP(ip);
UDF(0);
break;
case 6:
INST_NAME("RDRAND Ed");
SETFLAGS(X_ALL, SF_SET);
SET_DFNONE();
IFX(X_OF|X_SF|X_ZF|X_PF|X_AF) {
MOV32w(x1, (1<<F_OF)|(1<<F_SF)|(1<<F_ZF)|(1<<F_PF)|(1<<F_AF));
BICw(xFlags, xFlags, x1);
}
if(cpuext.rndr) {
MRS_rndr(x1);
IFX(X_CF) { CSETw(x3, cNE); }
} else {
CALL(rex.w?const_random64:const_random32, x1);
IFX(X_CF) { MOV32w(x3, 1); }
}
IFX(X_CF) { BFIw(xFlags, x3, F_CF, 1); }
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, &unscaled, 0xfff<<(2+rex.w), (1<<(2+rex.w))-1, rex, NULL, 0, 0);
STxw(x1, wback, fixedaddress);
break;
default:
DEFAULT;
}
+4
View File
@@ -1612,6 +1612,8 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
UXTHw(x2, xRAX);
BFIw(x2, xRDX, 16, 16);
if(BOX64ENV(dynarec_div0)) {
// commit df before branch, CALL_S in div0 path has FORCE_DFNONE
CHECK_DFNONE(0);
CBNZw_MARK3(ed);
MARK2;
GETIP_(ip);
@@ -1651,6 +1653,8 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
}
GETSEW(x1, 0);
if(BOX64ENV(dynarec_div0)) {
// commit df before branch, CALL_S in div0 path has FORCE_DFNONE
CHECK_DFNONE(0);
CBNZw_MARK3(ed);
MARK2;
GETIP_(ip);
+101 -21
View File
@@ -32,7 +32,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
int64_t j64;
uint64_t tmp64u, tmp64u2;
int mask;
int v0, v1;
int v0, v1, v2;
int q0, q1;
int d0, d1;
int64_t fixedaddress;
@@ -240,12 +240,11 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
SQXTN_32(q0, q0);
} else {
MRS_fpsr(x5);
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
MSR_fpsr(x5);
ORRw_mask(x2, xZR, 1, 0); //0x80000000
d0 = fpu_get_scratch(dyn, ninst);
for (int i=0; i<2; ++i) {
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
MSR_fpsr(x5);
if (i) {
VMOVeD(d0, 0, v1, i);
FRINTZD(d0, d0);
@@ -280,12 +279,11 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
SQXTN_32(q0, q0);
} else {
MRS_fpsr(x5);
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
MSR_fpsr(x5);
ORRw_mask(x2, xZR, 1, 0); //0x80000000
d0 = fpu_get_scratch(dyn, ninst);
for (int i=0; i<2; ++i) {
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
MSR_fpsr(x5);
if (i) {
VMOVeD(d0, 0, v1, i);
FRINTID(d0, d0);
@@ -310,10 +308,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
nextop = F8;
GETGX(v0, 0);
GETEXSD(q0, 0, 0);
IFX(X_CF|X_PF|X_ZF) {
FCMPD(v0, q0);
}
FCOMI(x1, x2);
FCOMID(x1, x2, v0, q0);
break;
case 0x38: // SSSE3 opcodes
@@ -768,6 +763,26 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
GETGX(q0, 1);
VMULQ_32(q0, q0, q1);
break;
case 0x41:
INST_NAME("PHMINPOSUW Gx, Ex");
nextop = F8;
GETEX(v1, 0, 0);
GETGX_empty(v0);
q0 = fpu_get_scratch(dyn, ninst);
q1 = fpu_get_scratch(dyn, ninst);
// get the min value
UMINVQ_16(q0, v1); //q0.uw[0] = min value
VDUPQ_16(q1, q0, 0); // vector of min value
VCMEQQ_16(q1, q1, v1); // bit field of the element that are the min value
UQXTN_8(q1, q1); // same bit field, but on 8bits elements only, easier to handle
VMOVQDto(x1, q1, 0); // grab the bit field as a 64bits value
VEORQ(v0, v0, v0); // RAZ everything
RBITx(x1, x1); // reverse, we want trailling zero but can only count leading ones
CLZx(x1, x1);
VMOVeH(v0, 0, q0, 0); // set up min
LSRw(x1, x1, 3); // divide by 8, that's our index...
VMOVQHfrom(v0, 1, x1);
break;
case 0xDB:
INST_NAME("AESIMC Gx, Ex"); // AES-NI
@@ -1708,6 +1723,8 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
if(!BOX64ENV(dynarec_fastnan)) {
v0 = fpu_get_scratch(dyn, ninst);
v1 = fpu_get_scratch(dyn, ninst);
v2 = fpu_get_scratch(dyn, ninst);
VMOVQ(v2, q1); // save original src1 (Gx)
// check if any input value was NAN
VFMAXQD(v0, q0, q1); // propagate NAN
VFCMEQQD(v0, v0, v0); // 0 if NAN, 1 if not NAN
@@ -1718,6 +1735,11 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
VBICQ(v1, v0, v1); // forget it in any input was a NAN already
VSHLQ_64(v1, v1, 63); // only keep the sign bit
VORRQ(q1, q1, v1); // NAN -> -NAN
VFCMEQQD(v0, v2, v2); // 0 if src1 was NaN
MOV64x(x5, 0x0008000000000000ULL);
VDUPQD(v1, x5); // QNaN bit
VORRQ(v2, v2, v1); // quiet any SNaN in saved src1
VBIFQ(q1, v2, v0); // where src1 was NaN, use QNaN(src1)
}
break;
case 0x59:
@@ -1728,6 +1750,8 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
if(!BOX64ENV(dynarec_fastnan)) {
v0 = fpu_get_scratch(dyn, ninst);
v1 = fpu_get_scratch(dyn, ninst);
v2 = fpu_get_scratch(dyn, ninst);
VMOVQ(v2, q1); // save original src1 (Gx)
// check if any input value was NAN
VFMAXQD(v0, q0, q1); // propagate NAN
VFCMEQQD(v0, v0, v0); // 0 if NAN, 1 if not NAN
@@ -1738,6 +1762,11 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
VBICQ(v1, v0, v1); // forget it in any input was a NAN already
VSHLQ_64(v1, v1, 63); // only keep the sign bit
VORRQ(q1, q1, v1); // NAN -> -NAN
VFCMEQQD(v0, v2, v2); // 0 if src1 was NaN
MOV64x(x5, 0x0008000000000000ULL);
VDUPQD(v1, x5); // QNaN bit
VORRQ(v2, v2, v1); // quiet any SNaN in saved src1
VBIFQ(q1, v2, v0); // where src1 was NaN, use QNaN(src1)
}
break;
case 0x5A:
@@ -1800,6 +1829,8 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
if(!BOX64ENV(dynarec_fastnan)) {
v0 = fpu_get_scratch(dyn, ninst);
v1 = fpu_get_scratch(dyn, ninst);
v2 = fpu_get_scratch(dyn, ninst);
VMOVQ(v2, q1); // save original src1 (Gx)
// check if any input value was NAN
VFMAXQD(v0, q0, q1); // propagate NAN
VFCMEQQD(v0, v0, v0); // 0 if NAN, 1 if not NAN
@@ -1810,6 +1841,11 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
VBICQ(v1, v0, v1); // forget it in any input was a NAN already
VSHLQ_64(v1, v1, 63); // only keep the sign bit
VORRQ(q1, q1, v1); // NAN -> -NAN
VFCMEQQD(v0, v2, v2); // 0 if src1 was NaN
MOV64x(x5, 0x0008000000000000ULL);
VDUPQD(v1, x5); // QNaN bit
VORRQ(v2, v2, v1); // quiet any SNaN in saved src1
VBIFQ(q1, v2, v0); // where src1 was NaN, use QNaN(src1)
}
break;
case 0x5D:
@@ -1831,6 +1867,8 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
if(!BOX64ENV(dynarec_fastnan)) {
v0 = fpu_get_scratch(dyn, ninst);
v1 = fpu_get_scratch(dyn, ninst);
v2 = fpu_get_scratch(dyn, ninst);
VMOVQ(v2, q1); // save original src1 (Gx)
// check if any input value was NAN
VFMAXQD(v0, q0, q1); // propagate NAN
VFCMEQQD(v0, v0, v0); // 0 if NAN, 1 if not NAN
@@ -1841,6 +1879,11 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
VBICQ(v1, v0, v1); // forget it in any input was a NAN already
VSHLQ_64(v1, v1, 63); // only keep the sign bit
VORRQ(q1, q1, v1); // NAN -> -NAN
VFCMEQQD(v0, v2, v2); // 0 if src1 was NaN
MOV64x(x5, 0x0008000000000000ULL);
VDUPQD(v1, x5); // QNaN bit
VORRQ(v2, v2, v1); // quiet any SNaN in saved src1
VBIFQ(q1, v2, v0); // where src1 was NaN, use QNaN(src1)
}
break;
case 0x5F:
@@ -2304,13 +2347,23 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
if(!BOX64ENV(dynarec_fastnan)) {
v0 = fpu_get_scratch(dyn, ninst);
v1 = fpu_get_scratch(dyn, ninst);
// check if any input value was NAN
VFMAXPQD(v0, q1, q0); // propagate NAN
VFCMEQQD(v0, v0, v0); // 0 if NAN, 1 if not NAN
d0 = fpu_get_scratch(dyn, ninst);
d1 = fpu_get_scratch(dyn, ninst);
VUZP1Q_64(d1, q1, q0); // d1 = {q1[0], q0[0]}
VFCMEQQD(v0, q1, q1); // per-element non-NaN for Gx
VFCMEQQD(d0, q0, q0); // per-element non-NaN for Ex
VUZP1Q_64(v1, v0, d0); // first element of each pair
VUZP2Q_64(v0, v0, d0); // second element of each pair
VANDQ(v0, v1, v0); // both non-NaN per pair
}
VFADDPQD(q1, q1, q0);
if(!BOX64ENV(dynarec_fastnan)) {
VFCMEQQD(v1, q1, q1); // 0 => out is NAN
MOV64x(x5, 0x0008000000000000ULL);
VFCMEQQD(v1, d1, d1); // v1 = src1 non-NaN mask
VDUPQD(d0, x5); // d0 = QNaN bit for double
VORRQ(d0, d1, d0); // d0 = QNaN(src1)
VBIFQ(q1, d0, v1); // where src1 NaN: replace with QNaN(src1)
VFCMEQQD(v1, q1, q1); // 0 => out is NAN
VBICQ(v1, v0, v1); // forget it in any input was a NAN already
VSHLQ_64(v1, v1, 63); // only keep the sign bit
VORRQ(q1, q1, v1); // NAN -> -NAN
@@ -2322,18 +2375,26 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
GETEX(q1, 0, 0);
GETGX(q0, 1);
v0 = fpu_get_scratch(dyn, ninst);
VUZP1Q_64(v0, q0, q1);
VUZP2Q_64(q0, q0, q1);
VUZP1Q_64(v0, q0, q1); // v0 = src1 (first of each pair)
VUZP2Q_64(q0, q0, q1); // q0 = src2 (second of each pair)
if(!BOX64ENV(dynarec_fastnan)) {
v1 = fpu_get_scratch(dyn, ninst);
// check if any input value was NAN
VFMAXQD(v1, v0, q0); // propagate NAN
VFCMEQQD(v1, v1, v1); // 0 if NAN, 1 if not NAN
d0 = fpu_get_scratch(dyn, ninst);
d1 = fpu_get_scratch(dyn, ninst);
VMOVQ(d1, v0); // save src1
VFCMEQQD(v1, v0, v0); // even elements non-NaN
VFCMEQQD(d0, q0, q0); // odd elements non-NaN
VANDQ(v1, v1, d0); // v1 = both non-NaN per pair
}
VFSUBQD(q0, v0, q0);
if(!BOX64ENV(dynarec_fastnan)) {
VFCMEQQD(v0, q0, q0); // 0 => out is NAN
VBICQ(v1, v1, v0); // forget it in any input was a NAN alreavy
MOV64x(x5, 0x0008000000000000ULL);
VFCMEQQD(d0, d1, d1); // d0 = src1 non-NaN mask
VDUPQD(v0, x5); // v0 = QNaN bit for double
VORRQ(v0, d1, v0); // v0 = QNaN(src1)
VBIFQ(q0, v0, d0); // where src1 NaN: replace with QNaN(src1)
VFCMEQQD(v0, q0, q0); // 0 => out is NAN
VBICQ(v1, v1, v0); // forget it in any input was a NAN already
VSHLQ_64(v1, v1, 63); // only keep the sign bit
VORRQ(q0, q0, v1); // NAN -> -NAN
}
@@ -2857,7 +2918,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
case 0xC1:
if(rex.w) return dynarec64_00(dyn, addr-1, ip, ninst, rex, ok, need_epilog);
INST_NAME("XADD Gw, Ew");
INST_NAME("XADD Ew, Gw");
SETFLAGS(X_ALL, SF_SET_PENDING);
nextop = F8;
GETGW(x1);
@@ -2969,9 +3030,28 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
GETGX(q0, 1);
GETEX(q1, 0, 0);
v0 = fpu_get_scratch(dyn, ninst);
if (!BOX64ENV(dynarec_fastnan)) {
v1 = fpu_get_scratch(dyn, ninst);
v2 = fpu_get_scratch(dyn, ninst);
VMOVQ(v2, q0); // save src1
VFCMEQQD(v0, q0, q0);
VFCMEQQD(v1, q1, q1);
VANDQ(v1, v0, v1); // v1 = both non-NaN
}
VFSUBQD(v0, q0, q1);
VFADDQD(q0, q0, q1);
VMOVeD(q0, 0, v0, 0);
if (!BOX64ENV(dynarec_fastnan)) {
MOV64x(x5, 0x0008000000000000ULL);
VFCMEQQD(v0, q0, q0); // 0 where result is NaN
VBICQ(v0, v1, v0); // both non-NaN but result NaN
VSHLQ_64(v0, v0, 63); // sign bit only
VORRQ(q0, q0, v0); // force -NaN
VFCMEQQD(v0, v2, v2); // 0 if src1 was NaN
VDUPQD(v1, x5); // QNaN bit
VORRQ(v2, v2, v1); // quiet any SNaN
VBIFQ(q0, v2, v0); // where src1 NaN: use QNaN(src1)
}
break;
case 0xD1:
INST_NAME("PSRLW Gx, Ex");
+22 -6
View File
@@ -210,11 +210,16 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
SETFLAGS(X_ALL, SF_SET_PENDING);
GETGW(x5);
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
MOVx_REG(x6, xFlags);
MRS_nzcv(x87pc);
MARKLOCK;
MOVx_REG(xFlags, x6);
MSR_nzcv(x87pc);
LDAXRH(x1, wback);
emit_adc16(dyn, ninst, x1, x5, x3, x4);
STLXRH(x3, x1, wback);
CBNZx_MARKLOCK(x3);
NATIVE_RESTORE_X87PC();
}
break;
@@ -320,11 +325,11 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
SETFLAGS(X_ALL, SF_SET_PENDING);
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, (opcode==0x81)?2:1);
if(opcode==0x81) i16 = F16S; else i16 = F8S;
if(!i64) {MOV32w(x5, i16);}
if(cpuext.atomics) {
MOV32w(x5, i16);
UFLAG_IF {
LDSETALH(x5, x1, wback);
emit_or16c(dyn, ninst, x1, i16, x3, x4);
emit_or16(dyn, ninst, x1, x5, x3, x4);
} else {
STSETLH(x5, wback);
}
@@ -355,12 +360,17 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
SETFLAGS(X_ALL, SF_SET_PENDING);
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, (opcode==0x81)?2:1);
if(opcode==0x81) i16 = F16S; else i16 = F8S;
MOV32w(x5, i16);
MOV32w(x5, (uint16_t)i16);
MOVx_REG(x6, xFlags);
MRS_nzcv(x87pc);
MARKLOCK;
MOVx_REG(xFlags, x6);
MSR_nzcv(x87pc);
LDAXRH(x1, wback);
emit_adc16(dyn, ninst, x1, x5, x3, x4);
STLXRH(x3, x1, wback);
CBNZx_MARKLOCK(x3);
NATIVE_RESTORE_X87PC();
}
break;
case 3: //SBB
@@ -375,12 +385,17 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
SETFLAGS(X_ALL, SF_SET_PENDING);
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, (opcode==0x81)?2:1);
if(opcode==0x81) i16 = F16S; else i16 = F8S;
MOV32w(x5, i16);
MOV32w(x5, (uint16_t)i16);
MOVx_REG(x6, xFlags);
MRS_nzcv(x87pc);
MARKLOCK;
MOVx_REG(xFlags, x6);
MSR_nzcv(x87pc);
LDAXRH(x1, wback);
emit_sbb16(dyn, ninst, x1, x5, x3, x4);
STLXRH(x3, x1, wback);
CBNZx_MARKLOCK(x3);
NATIVE_RESTORE_X87PC();
}
break;
case 4: //AND
@@ -455,7 +470,7 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
MARKLOCK;
LDAXRH(x1, wback);
SUBw_REG(x4, x1, x5);
STLXRH(x3, x1, wback);
STLXRH(x3, x4, wback);
CBNZx_MARKLOCK(x3);
}
if(!ALIGNED_ATOMICH) {
@@ -489,9 +504,10 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
if(opcode==0x81) i16 = F16S; else i16 = F8S;
i64 = convert_bitmask_w(i16);
if(cpuext.atomics) {
MOV32w(x5, i16);
UFLAG_IF {
LDEORALH(x5, x1, wback);
emit_xor16c(dyn, ninst, x1, i16, x3, x4);
emit_xor16(dyn, ninst, x1, x5, x3, x4);
} else {
STEORLH(x5, wback);
}
+5
View File
@@ -30,6 +30,7 @@ typedef struct arch_flags_s
uint8_t vf:1;
uint8_t cf:1;
uint8_t inv_cf:1;
uint8_t pf_v:1;
} arch_flags_t;
#define X87_ST_D 0
@@ -96,6 +97,7 @@ static int arch_build(dynarec_arm_t* dyn, int ninst, arch_build_t* arch, int noa
arch->flags_.cf = flags&NF_CF;
if(arch->flags_.cf)
arch->flags_.inv_cf = !dyn->insts[ninst].normal_carry;
arch->flags_.pf_v = flags&NF_PF_V;
}
// opcode can handle unaligned
arch->unaligned = dyn->insts[ninst].unaligned;
@@ -322,6 +324,9 @@ void adjust_arch(dynablock_t* db, x64emu_t* emu, ucontext_t* p, uintptr_t x64pc)
CONDITIONAL_SET_FLAG(p->uc_mcontext.pstate&(1<<NZCV_C), F_CF);
}
}
if(flags->pf_v) {
CONDITIONAL_SET_FLAG(p->uc_mcontext.pstate&(1<<NZCV_V), F_PF);
}
}
struct fpsimd_context *fpsimd = NULL;
// find fpsimd struct
+41 -20
View File
@@ -289,10 +289,7 @@ uintptr_t dynarec64_AVX_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int
nextop = F8;
GETGX(v0, 0);
GETEXSS(s0, 0, 0);
IFX(X_CF|X_PF|X_ZF) {
FCMPS(v0, s0);
}
FCOMI(x1, x2);
FCOMIS(x1, x2, v0, s0);
break;
case 0x50:
@@ -458,20 +455,26 @@ uintptr_t dynarec64_AVX_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int
if(!BOX64ENV(dynarec_fastnan)) {
q0 = fpu_get_scratch(dyn, ninst);
q1 = fpu_get_scratch(dyn, ninst);
q2 = fpu_get_scratch(dyn, ninst);
}
for(int l=0; l<1+vex.l; ++l) {
if(!l) { GETGX_empty_VXEX(v0, v2, v1, 0); } else { GETGY_empty_VYEY(v0, v2, v1); }
if(!BOX64ENV(dynarec_fastnan)) {
VMOVQ(q2, v2); // save src1
// check if any input value was NAN
VFMAXQS(q0, v2, v1); // propagate NAN
VFCMEQQS(q0, q0, q0); // 0 if NAN, 1 if not NAN
}
VFADDQS(v0, v2, v1);
if(!BOX64ENV(dynarec_fastnan)) {
VFCMEQQS(q1, v0, v0); // 0 => out is NAN
VBICQ(q1, q0, q1); // forget it in any input was a NAN already
VSHLQ_32(q1, q1, 31); // only keep the sign bit
VORRQ(v0, v0, q1); // NAN -> -NAN
VFCMEQQS(q1, v0, v0); // 0 => out is NAN
VBICQ(q1, q0, q1); // forget it in any input was a NAN already
VSHLQ_32(q1, q1, 31); // only keep the sign bit
VORRQ(v0, v0, q1); // NAN -> -NAN
VFCMEQQS(q0, q2, q2); // 0 if src1 was NaN
MOVIQ_32_lsl(q1, 0x40, 2); // QNaN bit 0x00400000
VORRQ(q2, q2, q1); // quiet any SNaN
VBIFQ(v0, q2, q0); // where src1 NaN, use QNaN(src1)
}
}
if(!vex.l) YMM0(gd)
@@ -482,20 +485,26 @@ uintptr_t dynarec64_AVX_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int
if(!BOX64ENV(dynarec_fastnan)) {
q0 = fpu_get_scratch(dyn, ninst);
q1 = fpu_get_scratch(dyn, ninst);
q2 = fpu_get_scratch(dyn, ninst);
}
for(int l=0; l<1+vex.l; ++l) {
if(!l) { GETGX_empty_VXEX(v0, v2, v1, 0); } else { GETGY_empty_VYEY(v0, v2, v1); }
if(!BOX64ENV(dynarec_fastnan)) {
VMOVQ(q2, v2); // save src1
// check if any input value was NAN
VFMAXQS(q0, v2, v1); // propagate NAN
VFCMEQQS(q0, q0, q0); // 0 if NAN, 1 if not NAN
}
VFMULQS(v0, v2, v1);
if(!BOX64ENV(dynarec_fastnan)) {
VFCMEQQS(q1, v0, v0); // 0 => out is NAN
VBICQ(q1, q0, q1); // forget it in any input was a NAN already
VSHLQ_32(q1, q1, 31); // only keep the sign bit
VORRQ(v0, v0, q1); // NAN -> -NAN
VFCMEQQS(q1, v0, v0); // 0 => out is NAN
VBICQ(q1, q0, q1); // forget it in any input was a NAN already
VSHLQ_32(q1, q1, 31); // only keep the sign bit
VORRQ(v0, v0, q1); // NAN -> -NAN
VFCMEQQS(q0, q2, q2); // 0 if src1 was NaN
MOVIQ_32_lsl(q1, 0x40, 2); // QNaN bit 0x00400000
VORRQ(q2, q2, q1); // quiet any SNaN
VBIFQ(v0, q2, q0); // where src1 NaN, use QNaN(src1)
}
}
if(!vex.l) YMM0(gd)
@@ -531,20 +540,26 @@ uintptr_t dynarec64_AVX_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int
if(!BOX64ENV(dynarec_fastnan)) {
q0 = fpu_get_scratch(dyn, ninst);
q1 = fpu_get_scratch(dyn, ninst);
q2 = fpu_get_scratch(dyn, ninst);
}
for(int l=0; l<1+vex.l; ++l) {
if(!l) { GETGX_empty_VXEX(v0, v2, v1, 0); } else { GETGY_empty_VYEY(v0, v2, v1); }
if(!BOX64ENV(dynarec_fastnan)) {
VMOVQ(q2, v2); // save src1
// check if any input value was NAN
VFMAXQS(q0, v2, v1); // propagate NAN
VFCMEQQS(q0, q0, q0); // 0 if NAN, 1 if not NAN
}
VFSUBQS(v0, v2, v1);
if(!BOX64ENV(dynarec_fastnan)) {
VFCMEQQS(q1, v0, v0); // 0 => out is NAN
VBICQ(q1, q0, q1); // forget it in any input was a NAN already
VSHLQ_32(q1, q1, 31); // only keep the sign bit
VORRQ(v0, v0, q1); // NAN -> -NAN
VFCMEQQS(q1, v0, v0); // 0 => out is NAN
VBICQ(q1, q0, q1); // forget it in any input was a NAN already
VSHLQ_32(q1, q1, 31); // only keep the sign bit
VORRQ(v0, v0, q1); // NAN -> -NAN
VFCMEQQS(q0, q2, q2); // 0 if src1 was NaN
MOVIQ_32_lsl(q1, 0x40, 2); // QNaN bit 0x00400000
VORRQ(q2, q2, q1); // quiet any SNaN
VBIFQ(v0, q2, q0); // where src1 NaN, use QNaN(src1)
}
}
if(!vex.l) YMM0(gd)
@@ -569,20 +584,26 @@ uintptr_t dynarec64_AVX_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int
if(!BOX64ENV(dynarec_fastnan)) {
q0 = fpu_get_scratch(dyn, ninst);
q1 = fpu_get_scratch(dyn, ninst);
q2 = fpu_get_scratch(dyn, ninst);
}
for(int l=0; l<1+vex.l; ++l) {
if(!l) { GETGX_empty_VXEX(v0, v2, v1, 0); } else { GETGY_empty_VYEY(v0, v2, v1); }
if(!BOX64ENV(dynarec_fastnan)) {
VMOVQ(q2, v2); // save src1
// check if any input value was NAN
VFMAXQS(q0, v2, v1); // propagate NAN
VFCMEQQS(q0, q0, q0); // 0 if NAN, 1 if not NAN
}
VFDIVQS(v0, v2, v1);
if(!BOX64ENV(dynarec_fastnan)) {
VFCMEQQS(q1, v0, v0); // 0 => out is NAN
VBICQ(q1, q0, q1); // forget it in any input was a NAN already
VSHLQ_32(q1, q1, 31); // only keep the sign bit
VORRQ(v0, v0, q1); // NAN -> -NAN
VFCMEQQS(q1, v0, v0); // 0 => out is NAN
VBICQ(q1, q0, q1); // forget it in any input was a NAN already
VSHLQ_32(q1, q1, 31); // only keep the sign bit
VORRQ(v0, v0, q1); // NAN -> -NAN
VFCMEQQS(q0, q2, q2); // 0 if src1 was NaN
MOVIQ_32_lsl(q1, 0x40, 2); // QNaN bit 0x00400000
VORRQ(q2, q2, q1); // quiet any SNaN
VBIFQ(v0, q2, q0); // where src1 NaN, use QNaN(src1)
}
}
if(!vex.l) YMM0(gd)
+13 -8
View File
@@ -94,6 +94,15 @@ uintptr_t dynarec64_AVX_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, i
BFIw(xFlags, x1, F_SF, 1);
}
}
// UD flags
IFX(X_AF) BFCw(xFlags, F_AF, 1);
if (BOX64DRENV(dynarec_safeflags)) {
if (BOX64ENV(cputype)) {
IFX (X_PF) BFCw(xFlags, F_PF, 1);
} else {
IFX (X_PF) emit_pf(dyn, ninst, gd, x3);
}
}
break;
case 0xF3:
nextop = F8;
@@ -244,15 +253,15 @@ uintptr_t dynarec64_AVX_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, i
GETGD;
GETED(0);
GETVD;
UXTBw(x1, vd);
CMPSw_U12(x1, rex.w?64:32);
UXTBw(x6, vd);
CMPSw_U12(x6, rex.w ? 64 : 32);
CSETMxw(x2, cPL);
IFX(X_CF) {
BFIw(xFlags, x2, F_CF, 1);
}
MVNxw_REG(x2, x2); //prepare mask
B_MARK(cPL);
LSLxw_REG(x2, x2, x1);
LSLxw_REG(x2, x2, x6);
MARK;
need_tst = 0;
IFX(X_ZF) need_tst = 1;
@@ -280,11 +289,7 @@ uintptr_t dynarec64_AVX_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, i
if (BOX64DRENV(dynarec_safeflags)) {
// those are UD flags
IFX(X_AF) BFCw(xFlags, F_AF, 1);
if(BOX64ENV(cputype)) {
IFX(X_PF) BFCw(xFlags, F_PF, 1);
} else {
IFX(X_PF) emit_pf(dyn, ninst, vd, x3);
}
IFX(X_PF) BFCw(xFlags, F_PF, 1);
}
break;
+100 -38
View File
@@ -268,10 +268,7 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
nextop = F8;
GETGX(v0, 0);
GETEXSD(q0, 0, 0);
IFX(X_CF|X_PF|X_ZF) {
FCMPD(v0, q0);
}
FCOMI(x1, x2);
FCOMID(x1, x2, v0, q0);
break;
case 0x50:
@@ -362,23 +359,30 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
if(!BOX64ENV(dynarec_fastnan)) {
q0 = fpu_get_scratch(dyn, ninst);
q1 = fpu_get_scratch(dyn, ninst);
q2 = fpu_get_scratch(dyn, ninst);
}
for(int l=0; l<1+vex.l; ++l) {
if(!l) { GETGX_empty_VXEX(v0, v2, v1, 0); } else { GETGY_empty_VYEY(v0, v2, v1); }
if(!BOX64ENV(dynarec_fastnan)) {
VMOVQ(q2, v2); // save src1
// check if any input value was NAN
VFMAXQD(q0, v2, v1); // propagate NAN
VFCMEQQD(q0, q0, q0); // 0 if NAN, 1 if not NAN
}
VFADDQD(v0, v2, v1);
if(!BOX64ENV(dynarec_fastnan)) {
VFCMEQQD(q1, v0, v0); // 0 => out is NAN
VBICQ(q1, q0, q1); // forget it in any input was a NAN already
VSHLQ_64(q1, q1, 63); // only keep the sign bit
VORRQ(v0, v0, q1); // NAN -> -NAN
MOV64x(x5, 0x0008000000000000ULL);
VFCMEQQD(q1, v0, v0); // 0 => out is NAN
VBICQ(q1, q0, q1); // forget it in any input was a NAN already
VSHLQ_64(q1, q1, 63); // only keep the sign bit
VORRQ(v0, v0, q1); // NAN -> -NAN
VFCMEQQD(q0, q2, q2); // 0 if src1 was NaN
VDUPQD(q1, x5); // QNaN bit
VORRQ(q2, q2, q1); // quiet any SNaN
VBIFQ(v0, q2, q0); // where src1 NaN, use QNaN(src1)
}
}
if(!vex.l) YMM0(gd)
if (!vex.l) YMM0(gd);
break;
case 0x59:
INST_NAME("VMULPD Gx, Vx, Ex");
@@ -386,10 +390,12 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
if(!BOX64ENV(dynarec_fastnan)) {
q0 = fpu_get_scratch(dyn, ninst);
q1 = fpu_get_scratch(dyn, ninst);
q2 = fpu_get_scratch(dyn, ninst);
}
for(int l=0; l<1+vex.l; ++l) {
if(!l) { GETGX_empty_VXEX(v0, v2, v1, 0); } else { GETGY_empty_VYEY(v0, v2, v1); }
if(!BOX64ENV(dynarec_fastnan)) {
VMOVQ(q2, v2); // save src1
// check if any input value was NAN
VFMAXQD(q0, v2, v1); // propagate NAN
VFCMEQQD(q0, q0, q0); // 0 if NAN, 1 if not NAN
@@ -400,6 +406,11 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
VBICQ(q1, q0, q1); // forget it in any input was a NAN already
VSHLQ_64(q1, q1, 63); // only keep the sign bit
VORRQ(v0, v0, q1); // NAN -> -NAN
VFCMEQQD(q0, q2, q2); // 0 if src1 was NaN
MOV64x(x5, 0x0008000000000000ULL);
VDUPQD(q1, x5); // QNaN bit
VORRQ(q2, q2, q1); // quiet any SNaN
VBIFQ(v0, q2, q0); // where src1 NaN, use QNaN(src1)
}
}
if(!vex.l) YMM0(gd)
@@ -474,20 +485,27 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
if(!BOX64ENV(dynarec_fastnan)) {
q0 = fpu_get_scratch(dyn, ninst);
q1 = fpu_get_scratch(dyn, ninst);
q2 = fpu_get_scratch(dyn, ninst);
}
for(int l=0; l<1+vex.l; ++l) {
if(!l) { GETGX_empty_VXEX(v0, v2, v1, 0); } else { GETGY_empty_VYEY(v0, v2, v1); }
if(!BOX64ENV(dynarec_fastnan)) {
VMOVQ(q2, v2); // save src1
// check if any input value was NAN
VFMAXQD(q0, v1, v2); // propagate NAN
VFCMEQQD(q0, q0, q0); // 0 if NAN, 1 if not NAN
}
VFSUBQD(v0, v2, v1);
if(!BOX64ENV(dynarec_fastnan)) {
VFCMEQQD(q1, v0, v0); // 0 => out is NAN
VBICQ(q1, q0, q1); // forget it in any input was a NAN already
VSHLQ_64(q1, q1, 63); // only keep the sign bit
VORRQ(v0, v0, q1); // NAN -> -NAN
MOV64x(x5, 0x0008000000000000ULL);
VFCMEQQD(q1, v0, v0); // 0 => out is NAN
VBICQ(q1, q0, q1); // forget it in any input was a NAN already
VSHLQ_64(q1, q1, 63); // only keep the sign bit
VORRQ(v0, v0, q1); // NAN -> -NAN
VFCMEQQD(q0, q2, q2); // 0 if src1 was NaN
VDUPQD(q1, x5); // QNaN bit
VORRQ(q2, q2, q1); // quiet any SNaN
VBIFQ(v0, q2, q0); // where src1 NaN, use QNaN(src1)
}
}
if(!vex.l) YMM0(gd);
@@ -512,20 +530,27 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
if(!BOX64ENV(dynarec_fastnan)) {
q0 = fpu_get_scratch(dyn, ninst);
q1 = fpu_get_scratch(dyn, ninst);
q2 = fpu_get_scratch(dyn, ninst);
}
for(int l=0; l<1+vex.l; ++l) {
if(!l) { GETGX_empty_VXEX(v0, v2, v1, 0); } else { GETGY_empty_VYEY(v0, v2, v1); }
if(!BOX64ENV(dynarec_fastnan)) {
VMOVQ(q2, v2); // save src1
// check if any input value was NAN
VFMAXQD(q0, v2, v1); // propagate NAN
VFCMEQQD(q0, q0, q0); // 0 if NAN, 1 if not NAN
}
VFDIVQD(v0, v2, v1);
if(!BOX64ENV(dynarec_fastnan)) {
VFCMEQQD(q1, v0, v0); // 0 => out is NAN
VBICQ(q1, q0, q1); // forget it in any input was a NAN already
VSHLQ_64(q1, q1, 63); // only keep the sign bit
VORRQ(v0, v0, q1); // NAN -> -NAN
MOV64x(x5, 0x0008000000000000ULL);
VFCMEQQD(q1, v0, v0); // 0 => out is NAN
VBICQ(q1, q0, q1); // forget it in any input was a NAN already
VSHLQ_64(q1, q1, 63); // only keep the sign bit
VORRQ(v0, v0, q1); // NAN -> -NAN
VFCMEQQD(q0, q2, q2); // 0 if src1 was NaN
VDUPQD(q1, x5); // QNaN bit
VORRQ(q2, q2, q1); // quiet any SNaN
VBIFQ(v0, q2, q0); // where src1 NaN, use QNaN(src1)
}
}
if(!vex.l) YMM0(gd);
@@ -1161,20 +1186,30 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
if(!BOX64ENV(dynarec_fastnan)) {
q0 = fpu_get_scratch(dyn, ninst);
q1 = fpu_get_scratch(dyn, ninst);
d0 = fpu_get_scratch(dyn, ninst);
d1 = fpu_get_scratch(dyn, ninst);
}
for(int l=0; l<1+vex.l; ++l) {
if(!l) { GETGX_empty_VXEX(v0, v2, v1, 0); } else { GETGY_empty_VYEY(v0, v2, v1); }
if(!BOX64ENV(dynarec_fastnan)) {
// check if any input value was NAN
VFMAXPQD(q0, v2, v1); // propagate NAN
VFCMEQQD(q0, q0, q0); // 0 if NAN, 1 if not NAN
VUZP1Q_64(d1, v2, v1); // d1 = src1 (even elements)
VFCMEQQD(q0, v2, v2); // per-element non-NaN for Vx
VFCMEQQD(d0, v1, v1); // per-element non-NaN for Ex
VUZP1Q_64(q1, q0, d0); // first element of each pair
VUZP2Q_64(q0, q0, d0); // second element of each pair
VANDQ(q0, q1, q0); // both non-NaN per pair
}
VFADDPQD(v0, v2, v1);
if(!BOX64ENV(dynarec_fastnan)) {
VFCMEQQD(q1, v0, v0); // 0 => out is NAN
VBICQ(q1, q0, q1); // forget it in any input was a NAN already
VSHLQ_64(q1, q1, 63); // only keep the sign bit
VORRQ(v0, v0, q1); // NAN -> -NAN
MOV64x(x5, 0x0008000000000000ULL);
VFCMEQQD(q1, d1, d1); // q1 = src1 non-NaN mask
VDUPQD(d0, x5); // d0 = QNaN bit for double
VORRQ(d0, d1, d0); // d0 = QNaN(src1)
VBIFQ(v0, d0, q1); // where src1 NaN: replace with QNaN(src1)
VFCMEQQD(q1, v0, v0); // 0 => out is NAN
VBICQ(q1, q0, q1); // forget it in any input was a NAN already
VSHLQ_64(q1, q1, 63); // only keep the sign bit
VORRQ(v0, v0, q1); // NAN -> -NAN
}
}
if(!vex.l) YMM0(gd);
@@ -1183,24 +1218,32 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
INST_NAME("VHSUBPD Gx, Vx, Ex");
nextop = F8;
q0 = fpu_get_scratch(dyn, ninst);
if(!BOX64ENV(dynarec_fastnan))
if (!BOX64ENV(dynarec_fastnan)) {
q1 = fpu_get_scratch(dyn, ninst);
d0 = fpu_get_scratch(dyn, ninst);
d1 = fpu_get_scratch(dyn, ninst);
}
for(int l=0; l<1+vex.l; ++l) {
if(!l) { GETGX_empty_VXEX(v0, v2, v1, 0); } else { GETGY_empty_VYEY(v0, v2, v1); }
VUZP1Q_64(q0, v2, v1);
VUZP2Q_64(v0, v2, v1);
VUZP1Q_64(q0, v2, v1); // q0 = src1 (first of each pair)
VUZP2Q_64(v0, v2, v1); // v0 = src2 (second of each pair)
if(!BOX64ENV(dynarec_fastnan)) {
// check if any input value was NAN
// but need to mix low/high part
VFMAXQD(q1, v0, q0); // propagate NAN
VFCMEQQD(q1, q1, q1); // 0 if NAN, 1 if not NAN
VMOVQ(d1, q0); // save src1
VFCMEQQD(q1, q0, q0); // even elements non-NaN
VFCMEQQD(d0, v0, v0); // odd elements non-NaN
VANDQ(q1, q1, d0); // both non-NaN per pair
}
VFSUBQD(v0, q0, v0);
if(!BOX64ENV(dynarec_fastnan)) {
VFCMEQQD(q0, v0, v0); // 0 => out is NAN
VBICQ(q1, q1, q0); // forget it in any input was a NAN already
VSHLQ_64(q1, q1, 63); // only keep the sign bit
VORRQ(v0, v0, q1); // NAN -> -NAN
MOV64x(x5, 0x0008000000000000ULL);
VFCMEQQD(d0, d1, d1); // d0 = src1 non-NaN mask
VDUPQD(q0, x5); // q0 = QNaN bit for double
VORRQ(q0, d1, q0); // q0 = QNaN(src1)
VBIFQ(v0, q0, d0); // where src1 NaN: replace with QNaN(src1)
VFCMEQQD(q0, v0, v0); // 0 => out is NAN
VBICQ(q1, q1, q0); // forget it in any input was a NAN already
VSHLQ_64(q1, q1, 63); // only keep the sign bit
VORRQ(v0, v0, q1); // NAN -> -NAN
}
}
if(!vex.l) YMM0(gd);
@@ -1349,11 +1392,32 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
INST_NAME("VADDSUBPD Gx, Vx, Ex");
nextop = F8;
q0 = fpu_get_scratch(dyn, ninst);
if (!BOX64ENV(dynarec_fastnan)) {
q1 = fpu_get_scratch(dyn, ninst);
q2 = fpu_get_scratch(dyn, ninst);
}
for(int l=0; l<1+vex.l; ++l) {
if(!l) { GETGX_empty_VXEX(v0, v2, v1, 0); } else { GETGY_empty_VYEY(v0, v2, v1); }
if (!BOX64ENV(dynarec_fastnan)) {
VMOVQ(q2, v2); // save src1
VFCMEQQD(q0, v2, v2);
VFCMEQQD(q1, v1, v1);
VANDQ(q1, q0, q1); // q1 = both non-NaN
}
FSUBD(q0, v2, v1);
VFADDQD(v0, v2, v1);
VMOVeD(v0, 0, q0, 0);
if (!BOX64ENV(dynarec_fastnan)) {
MOV64x(x5, 0x0008000000000000ULL);
VFCMEQQD(q0, v0, v0); // 0 where result is NaN
VBICQ(q0, q1, q0); // both non-NaN but result NaN
VSHLQ_64(q0, q0, 63); // sign bit only
VORRQ(v0, v0, q0); // force -NaN
VFCMEQQD(q0, q2, q2); // 0 if src1 was NaN
VDUPQD(q1, x5); // QNaN bit
VORRQ(q2, q2, q1); // quiet any SNaN
VBIFQ(v0, q2, q0); // where src1 NaN: use QNaN(src1)
}
}
if(!vex.l) YMM0(gd);
break;
@@ -1670,13 +1734,12 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
case 0xE6:
INST_NAME("VCVTTPD2DQ Gx, Ex");
nextop = F8;
d0 = fpu_get_scratch(dyn, ninst);
for(int l=0; l<1+vex.l; ++l) {
if(!l) {
GETEX_Y(v1, 0, 0);
GETGX_empty(v0);
} else {
if(BOX64ENV(dynarec_fastround))
d0 = fpu_get_scratch(dyn, ninst);
GETEY(v1);
}
if(BOX64ENV(dynarec_fastround)) {
@@ -1697,7 +1760,6 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
if(!l) {
MRS_fpsr(x5);
ORRw_mask(x4, xZR, 1, 0); //0x80000000
d0 = fpu_get_scratch(dyn, ninst);
}
for(int i=0; i<2; ++i) {
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
+53 -55
View File
@@ -684,7 +684,9 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
GETVX(v2, 0);
GETGX_empty(v0);
q0 = fpu_get_scratch(dyn, ninst);
VSSHRQ_32(q0, v2, 31);
VSHRQ_32(q0, v2, 31); // move sign bit to lower
SQXTN_16(q0, q0); // reduce to 16bits for easier extraction
VMOVQDto(x4, q0, 0); // extract the mask as 16bits slices instead of 32bits
if (MODREG) {
DEFAULT;
return addr;
@@ -692,21 +694,17 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
VEORQ(v0, v0, v0);
SMREAD();
addr = geted(dyn, addr, ninst, nextop, &ed, x3, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
VMOVSto(x4, q0, 0);
CBZw(x4, 4+1*4);
TBZ(x4, 0*16, 4+1*4);
VLD1_32(v0, 0, ed);
ADDx_U12(x3, ed, 4);
ed = x3;
VMOVSto(x4, q0, 1);
CBZw(x4, 4+1*4);
TBZ(x4, 1*16, 4+1*4);
VLD1_32(v0, 1, ed);
ADDx_U12(ed, ed, 4);
VMOVSto(x4, q0, 2);
CBZw(x4, 4+1*4);
TBZ(x4, 2*16, 4+1*4);
VLD1_32(v0, 2, ed);
ADDx_U12(ed, ed, 4);
VMOVSto(x4, q0, 3);
CBZw(x4, 4+1*4);
TBZ(x4, 3*16, 4+1*4);
VLD1_32(v0, 3, ed);
if(vex.l)
ADDx_U12(ed, ed, 4);
@@ -714,22 +712,20 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
if(vex.l) {
v2 = ymm_get_reg(dyn, ninst, x1, vex.v, 0, gd, (MODREG)?((nextop&7)+(rex.b<<3)):-1, -1);
v0 = ymm_get_reg_empty(dyn, ninst, x1, gd, vex.v, (MODREG)?((nextop&7)+(rex.b<<3)):-1, -1);
VSSHRQ_32(q0, v2, 31);
VSHRQ_32(q0, v2, 31); // move sign bit to lower
SQXTN_16(q0, q0); // reduce to 16bits for easier extraction
VMOVQDto(x4, q0, 0); // extract the mask as 16bits slices instead of 32bits
VEORQ(v0, v0, v0);
VMOVSto(x4, q0, 0);
CBZw(x4, 4+1*4);
TBZ(x4, 0*16, 4+1*4);
VLD1_32(v0, 0, ed);
ADDx_U12(ed, ed, 4);
VMOVSto(x4, q0, 1);
CBZw(x4, 4+1*4);
TBZ(x4, 1*16, 4+1*4);
VLD1_32(v0, 1, ed);
ADDx_U12(ed, ed, 4);
VMOVSto(x4, q0, 2);
CBZw(x4, 4+1*4);
TBZ(x4, 2*16, 4+1*4);
VLD1_32(v0, 2, ed);
ADDx_U12(ed, ed, 4);
VMOVSto(x4, q0, 3);
CBZw(x4, 4+1*4);
TBZ(x4, 3*16, 4+1*4);
VLD1_32(v0, 3, ed);
} else YMM0(gd);
break;
@@ -740,7 +736,9 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
GETGX_empty(v0);
q0 = fpu_get_scratch(dyn, ninst);
// create mask
VSSHRQ_64(q0, v2, 63);
VSHRQ_64(q0, v2, 63);
SQXTN_32(q0, q0);
VMOVQDto(x4, q0, 0);
VEORQ(v0, v0, v0);
if (MODREG) {
DEFAULT;
@@ -748,13 +746,11 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
} else {
SMREAD();
addr = geted(dyn, addr, ninst, nextop, &ed, x3, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
VMOVQDto(x4, q0, 0);
CBZx(x4, 4+1*4);
TBZ(x4, 0*32, 4+1*4);
VLD1_64(v0, 0, ed);
ADDx_U12(x3, ed, 8);
ed = x3;
VMOVQDto(x4, q0, 1);
CBZx(x4, 4+1*4);
TBZ(x4, 1*32, 4+1*4);
VLD1_64(v0, 1, ed);
if(vex.l)
ADDx_U12(ed, ed, 8);
@@ -762,14 +758,14 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
if(vex.l) {
v2 = ymm_get_reg(dyn, ninst, x1, vex.v, 0, gd, (MODREG)?((nextop&7)+(rex.b<<3)):-1, -1);
v0 = ymm_get_reg_empty(dyn, ninst, x1, gd, vex.v, (MODREG)?((nextop&7)+(rex.b<<3)):-1, -1);
VSSHRQ_64(q0, v2, 63);
VEORQ(v0, v0, v0);
VSHRQ_64(q0, v2, 63);
SQXTN_32(q0, q0);
VMOVQDto(x4, q0, 0);
CBZx(x4, 4+1*4);
VEORQ(v0, v0, v0);
TBZ(x4, 0*32, 4+1*4);
VLD1_64(v0, 0, ed);
ADDx_U12(ed, ed, 8);
VMOVQDto(x4, q0, 1);
CBZx(x4, 4+1*4);
TBZ(x4, 1*32, 4+1*4);
VLD1_64(v0, 1, ed);
} else YMM0(gd);
break;
@@ -779,7 +775,9 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
q0 = fpu_get_scratch(dyn, ninst);
GETVX(v2, 0);
GETGX(v0, 0);
VSSHRQ_32(q0, v2, 31);
VSHRQ_32(q0, v2, 31); // move sign bit to lower
SQXTN_16(q0, q0); // reduce to 16bits for easier extraction
VMOVQDto(x4, q0, 0); // extract the mask as 16bits slices instead of 32bits
if(MODREG) {
DEFAULT;
return addr;
@@ -787,21 +785,17 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
addr = geted(dyn, addr, ninst, nextop, &ed, x3, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
// check if mask as anything, else skip the whole read/write to avoid a SEGFAULT.
// TODO: let a segfault trigger and check if the mask is null instead and ignore the segfault / actually triger: needs to implement SSE reg tracking first!
VMOVSto(x4, q0, 0);
CBZw(x4, 4+1*4);
TBZ(x4, 0*16, 4+1*4);
VST1_32(v0, 0, ed);
ADDx_U12(x3, ed, 4);
ed = x3;
VMOVSto(x4, q0, 1);
CBZw(x4, 4+1*4);
TBZ(x4, 1*16, 4+1*4);
VST1_32(v0, 1, ed);
ADDx_U12(ed, ed, 4);
VMOVSto(x4, q0, 2);
CBZw(x4, 4+1*4);
TBZ(x4, 2*16, 4+1*4);
VST1_32(v0, 2, ed);
ADDx_U12(ed, ed, 4);
VMOVSto(x4, q0, 3);
CBZw(x4, 4+1*4);
TBZ(x4, 3*16, 4+1*4);
VST1_32(v0, 3, ed);
if(vex.l)
ADDx_U12(ed, ed, 4);
@@ -810,22 +804,23 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
if(vex.l && !is_avx_zero(dyn, ninst, vex.v)) {
v2 = ymm_get_reg(dyn, ninst, x1, vex.v, 0, gd, (MODREG)?((nextop&7)+(rex.b<<3)):-1, -1);
v0 = ymm_get_reg(dyn, ninst, x1, gd, 0, vex.v, (MODREG)?((nextop&7)+(rex.b<<3)):-1, -1);
VSSHRQ_32(q0, v2, 31);
VMOVSto(x4, q0, 0);
CBZw(x4, 4+1*4);
VSHRQ_32(q0, v2, 31); // move sign bit to lower
SQXTN_16(q0, q0); // reduce to 16bits for easier extraction
VMOVQDto(x4, q0, 0); // extract the mask as 16bits slices instead of 32bits
TBZ(x4, 0*16, 4+1*4);
VST1_32(v0, 0, ed);
ADDx_U12(ed, ed, 4);
VMOVSto(x4, q0, 1);
CBZw(x4, 4+1*4);
TBZ(x4, 1*16, 4+1*4);
VST1_32(v0, 1, ed);
ADDx_U12(ed, ed, 4);
VMOVSto(x4, q0, 2);
CBZw(x4, 4+1*4);
TBZ(x4, 2*16, 4+1*4);
VST1_32(v0, 2, ed);
ADDx_U12(ed, ed, 4);
VMOVSto(x4, q0, 3);
CBZw(x4, 4+1*4);
TBZ(x4, 3*16, 4+1*4);
VST1_32(v0, 3, ed);
} else if (vex.l) { // keep avx ymm zero tracking consistent
v2 = ymm_get_reg(dyn, ninst, x1, vex.v, 0, gd, (MODREG)?((nextop&7)+(rex.b<<3)):-1, -1);
v0 = ymm_get_reg(dyn, ninst, x1, gd, 0, vex.v, (MODREG)?((nextop&7)+(rex.b<<3)):-1, -1);
}
SMWRITE2();
break;
@@ -835,7 +830,9 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
q0 = fpu_get_scratch(dyn, ninst);
GETVX(v2, 0);
GETGX(v0, 0);
VSSHRQ_64(q0, v2, 63);
VSHRQ_64(q0, v2, 63);
SQXTN_32(q0, q0);
VMOVQDto(x4, q0, 0);
if(MODREG) {
DEFAULT;
return addr;
@@ -845,13 +842,11 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
v1 = fpu_get_scratch(dyn, ninst);
// check if mask as anything, else skip the whole read/write to avoid a SEGFAULT.
// TODO: let a segfault trigger and check if the mask is null instead and ignore the segfault / actually triger: needs to implement SSE reg tracking first!
VMOVQDto(x4, q0, 0);
CBZx(x4, 4+1*4);
TBZ(x4, 0*32, 4+1*4);
VST1_64(v0, 0, ed);
ADDx_U12(x3, ed, 8);
ed = x3;
VMOVQDto(x4, q0, 1);
CBZx(x4, 4+1*4);
TBZ(x4, 1*32, 4+1*4);
VST1_64(v0, 1, ed);
if(vex.l)
ADDx_U12(ed, ed, 8);
@@ -860,14 +855,17 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
if(vex.l && !is_avx_zero(dyn, ninst, vex.v)) {
v2 = ymm_get_reg(dyn, ninst, x1, vex.v, 0, gd, (MODREG)?((nextop&7)+(rex.b<<3)):-1, -1);
v0 = ymm_get_reg(dyn, ninst, x1, gd, 0, vex.v, (MODREG)?((nextop&7)+(rex.b<<3)):-1, -1);
VSSHRQ_64(q0, v2, 63);
VSHRQ_64(q0, v2, 63);
SQXTN_32(q0, q0);
VMOVQDto(x4, q0, 0);
CBZx(x4, 4+1*4);
TBZ(x4, 0*32, 4+1*4);
VST1_64(v0, 0, ed);
ADDx_U12(ed, ed, 8);
VMOVQDto(x4, q0, 1);
CBZx(x4, 4+1*4);
TBZ(x4, 1*32, 4+1*4);
VST1_64(v0, 1, ed);
} else if (vex.l) { // keep avx ymm zero tracking consistent
v2 = ymm_get_reg(dyn, ninst, x1, vex.v, 0, gd, (MODREG)?((nextop&7)+(rex.b<<3)):-1, -1);
v0 = ymm_get_reg(dyn, ninst, x1, gd, 0, vex.v, (MODREG)?((nextop&7)+(rex.b<<3)):-1, -1);
}
SMWRITE2();
break;
+82 -27
View File
@@ -240,13 +240,18 @@ uintptr_t dynarec64_AVX_F2_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
q1 = fpu_get_scratch(dyn, ninst);
q0 = fpu_get_scratch(dyn, ninst);
// check if any input value was NAN
FMAXD(q1, v0, v1); // propagate NAN
FMAXD(q1, v2, v1); // propagate NAN
FCMEQD(q1, q1, q1); // 0 if NAN, 1 if not NAN
FADDD(q2, v1, v2); // the high part of the vector is erased...
FCMEQD(q0, q2, q2); // 0 => out is NAN
VBIC(q0, q1, q0); // forget it in any input was a NAN already
SHL_64(q0, q0, 63); // only keep the sign bit
VORR(q2, q2, q0); // NAN -> -NAN
FCMEQD(q1, v2, v2); // 0 if src1 was NaN
MOV64x(x5, 0x0008000000000000ULL);
VMOVQDfrom(q0, 0, x5);
VORR(q0, v2, q0); // QNaN(src1)
VBIF(q2, q0, q1); // where src1 was NaN, use QNaN(src1)
} else {
FADDD(q2, v1, v2); // the high part of the vector is erased...
}
@@ -266,13 +271,18 @@ uintptr_t dynarec64_AVX_F2_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
q1 = fpu_get_scratch(dyn, ninst);
q0 = fpu_get_scratch(dyn, ninst);
// check if any input value was NAN
FMAXD(q1, v0, v1); // propagate NAN
FMAXD(q1, v2, v1); // propagate NAN
FCMEQD(q1, q1, q1); // 0 if NAN, 1 if not NAN
FMULD(q2, v1, v2); // the high part of the vector is erased...
FCMEQD(q0, q2, q2); // 0 => out is NAN
VBIC(q0, q1, q0); // forget it in any input was a NAN already
SHL_64(q0, q0, 63); // only keep the sign bit
VORR(q2, q2, q0); // NAN -> -NAN
FCMEQD(q1, v2, v2); // 0 if src1 was NaN
MOV64x(x5, 0x0008000000000000ULL);
VMOVQDfrom(q0, 0, x5);
VORR(q0, v2, q0); // QNaN(src1)
VBIF(q2, q0, q1); // where src1 was NaN, use QNaN(src1)
} else {
FMULD(q2, v1, v2); // the high part of the vector is erased...
}
@@ -312,13 +322,18 @@ uintptr_t dynarec64_AVX_F2_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
q1 = fpu_get_scratch(dyn, ninst);
q0 = fpu_get_scratch(dyn, ninst);
// check if any input value was NAN
FMAXD(q1, v0, v1); // propagate NAN
FMAXD(q1, v2, v1); // propagate NAN
FCMEQD(q1, q1, q1); // 0 if NAN, 1 if not NAN
FSUBD(q2, v2, v1); // the high part of the vector is erased...
FCMEQD(q0, q2, q2); // 0 => out is NAN
VBIC(q0, q1, q0); // forget it in any input was a NAN already
SHL_64(q0, q0, 63); // only keep the sign bit
VORR(q2, q2, q0); // NAN -> -NAN
FCMEQD(q1, v2, v2); // 0 if src1 was NaN
MOV64x(x5, 0x0008000000000000ULL);
VMOVQDfrom(q0, 0, x5);
VORR(q0, v2, q0); // QNaN(src1)
VBIF(q2, q0, q1); // where src1 was NaN, use QNaN(src1)
} else {
FSUBD(q2, v2, v1); // the high part of the vector is erased...
}
@@ -353,13 +368,18 @@ uintptr_t dynarec64_AVX_F2_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
q1 = fpu_get_scratch(dyn, ninst);
q0 = fpu_get_scratch(dyn, ninst);
// check if any input value was NAN
FMAXD(q1, v0, v1); // propagate NAN
FMAXD(q1, v2, v1); // propagate NAN
FCMEQD(q1, q1, q1); // 0 if NAN, 1 if not NAN
FDIVD(q2, v2, v1); // the high part of the vector is erased...
FCMEQD(q0, q2, q2); // 0 => out is NAN
VBIC(q0, q1, q0); // forget it in any input was a NAN already
SHL_64(q0, q0, 63); // only keep the sign bit
VORR(q2, q2, q0); // NAN -> -NAN
FCMEQD(q1, v2, v2); // 0 if src1 was NaN
MOV64x(x5, 0x0008000000000000ULL);
VMOVQDfrom(q0, 0, x5);
VORR(q0, v2, q0); // QNaN(src1)
VBIF(q2, q0, q1); // where src1 was NaN, use QNaN(src1)
} else {
FDIVD(q2, v2, v1); // the high part of the vector is erased...
}
@@ -424,20 +444,29 @@ uintptr_t dynarec64_AVX_F2_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
if(!BOX64ENV(dynarec_fastnan)) {
q0 = fpu_get_scratch(dyn, ninst);
q1 = fpu_get_scratch(dyn, ninst);
d0 = fpu_get_scratch(dyn, ninst);
d1 = fpu_get_scratch(dyn, ninst);
}
for(int l=0; l<1+vex.l; ++l) {
if(!l) { GETGX_empty_VXEX(v0, v2, v1, 0); } else { GETGY_empty_VYEY(v0, v2, v1); }
if(!BOX64ENV(dynarec_fastnan)) {
// check if any input value was NAN
VFMAXPQS(q0, v2, v1); // propagate NAN
VFCMEQQS(q0, q0, q0); // 0 if NAN, 1 if not NAN
VUZP1Q_32(d1, v2, v1); // d1 = src1 (even elements)
VFCMEQQS(q0, v2, v2); // per-element non-NaN for Vx
VFCMEQQS(d0, v1, v1); // per-element non-NaN for Ex
VUZP1Q_32(q1, q0, d0); // even elements of pairs
VUZP2Q_32(q0, q0, d0); // odd elements of pairs
VANDQ(q0, q1, q0); // both non-NaN per pair
}
VFADDPQS(v0, v2, v1);
if(!BOX64ENV(dynarec_fastnan)) {
VFCMEQQS(q1, v0, v0); // 0 => out is NAN
VBICQ(q1, q0, q1); // forget it in any input was a NAN already
VSHLQ_32(q1, q1, 31); // only keep the sign bit
VORRQ(v0, v0, q1); // NAN -> -NAN
VFCMEQQS(q1, d1, d1); // q1 = src1 non-NaN mask
MOVIQ_32_lsl(d0, 0x40, 2); // d0 = 0x00400000 (QNaN bit)
VORRQ(d0, d1, d0); // d0 = QNaN(src1)
VBIFQ(v0, d0, q1); // where src1 NaN: replace with QNaN(src1)
VFCMEQQS(q1, v0, v0); // 0 => out is NAN
VBICQ(q1, q0, q1); // forget it in any input was a NAN already
VSHLQ_32(q1, q1, 31); // only keep the sign bit
VORRQ(v0, v0, q1); // NAN -> -NAN
}
}
if(!vex.l) YMM0(gd);
@@ -446,24 +475,31 @@ uintptr_t dynarec64_AVX_F2_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
INST_NAME("VHSUBPS Gx, Vx, Ex");
nextop = F8;
q0 = fpu_get_scratch(dyn, ninst);
if(!BOX64ENV(dynarec_fastnan))
if (!BOX64ENV(dynarec_fastnan)) {
q1 = fpu_get_scratch(dyn, ninst);
d0 = fpu_get_scratch(dyn, ninst);
d1 = fpu_get_scratch(dyn, ninst);
}
for(int l=0; l<1+vex.l; ++l) {
if(!l) { GETGX_empty_VXEX(v0, v2, v1, 0); } else { GETGY_empty_VYEY(v0, v2, v1); }
VUZP1Q_32(q0, v2, v1);
VUZP2Q_32(v0, v2, v1);
VUZP1Q_32(q0, v2, v1); // q0 = src1 (even elements)
VUZP2Q_32(v0, v2, v1); // v0 = src2 (odd elements)
if(!BOX64ENV(dynarec_fastnan)) {
// check if any input value was NAN
// but need to mix low/high part
VFMAXQS(q1, v0, q0); // propagate NAN
VFCMEQQS(q1, q1, q1); // 0 if NAN, 1 if not NAN
VMOVQ(d1, q0); // save src1
VFCMEQQS(q1, q0, q0); // even elements non-NaN
VFCMEQQS(d0, v0, v0); // odd elements non-NaN
VANDQ(q1, q1, d0); // both non-NaN per pair
}
VFSUBQS(v0, q0, v0);
if(!BOX64ENV(dynarec_fastnan)) {
VFCMEQQS(q0, v0, v0); // 0 => out is NAN
VBICQ(q1, q1, q0); // forget it in any input was a NAN already
VSHLQ_32(q1, q1, 31); // only keep the sign bit
VORRQ(v0, v0, q1); // NAN -> -NAN
VFCMEQQS(d0, d1, d1); // d0 = src1 non-NaN mask
MOVIQ_32_lsl(q0, 0x40, 2); // q0 = 0x00400000 (QNaN bit)
VORRQ(q0, d1, q0); // q0 = QNaN(src1)
VBIFQ(v0, q0, d0); // where src1 NaN: replace with QNaN(src1)
VFCMEQQS(q0, v0, v0); // 0 => out is NAN
VBICQ(q1, q1, q0); // only when both inputs non-NaN but result is NaN
VSHLQ_32(q1, q1, 31); // only keep the sign bit
VORRQ(v0, v0, q1); // NAN -> -NAN
}
}
if(!vex.l) YMM0(gd);
@@ -509,20 +545,39 @@ uintptr_t dynarec64_AVX_F2_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
INST_NAME("VADDSUBPS Gx, Vx, Ex");
nextop = F8;
q0 = fpu_get_scratch(dyn, ninst);
d0 = fpu_get_scratch(dyn, ninst);
if (!BOX64ENV(dynarec_fastnan)) {
q1 = fpu_get_scratch(dyn, ninst);
q2 = fpu_get_scratch(dyn, ninst);
}
TABLE64C(x2, const_4f_m1_1_m1_1);
VLDR128_U12(q0, x2, 0);
for(int l=0; l<1+vex.l; ++l) {
if(!l) { GETGX_empty_VXEX(v0, v2, v1, 0); } else { GETGY_empty_VYEY(v0, v2, v1); }
if (!BOX64ENV(dynarec_fastnan)) {
VMOVQ(q2, v2); // save src1
VFCMEQQS(q1, v2, v2);
VFCMEQQS(d0, v1, v1);
VANDQ(q1, q1, d0); // q1 = both non-NaN
}
if(v0==v1) {
//TODO: find a better way
if(!l) q1 = fpu_get_scratch(dyn, ninst);
VMOVQ(q1, v2);
VFMLAQS(q1, v1, q0);
VMOVQ(v0, q1);
VMOVQ(d0, v2);
VFMLAQS(d0, v1, q0);
VMOVQ(v0, d0);
} else {
if(v0!=v2) VMOVQ(v0, v2);
VFMLAQS(v0, v1, q0);
}
if (!BOX64ENV(dynarec_fastnan)) {
VFCMEQQS(d0, v0, v0); // 0 where result is NaN
VBICQ(d0, q1, d0); // both non-NaN but result NaN
VSHLQ_32(d0, d0, 31); // sign bit only
VORRQ(v0, v0, d0); // force -NaN
VFCMEQQS(q1, q2, q2); // 0 if src1 was NaN
MOVIQ_32_lsl(d0, 0x40, 2); // QNaN bit 0x00400000
VORRQ(q2, q2, d0); // quiet any SNaN
VBIFQ(v0, q2, q1); // where src1 NaN: use QNaN(src1)
}
}
if(!vex.l) YMM0(gd);
break;
+24 -4
View File
@@ -275,13 +275,18 @@ uintptr_t dynarec64_AVX_F3_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
q1 = fpu_get_scratch(dyn, ninst);
q0 = fpu_get_scratch(dyn, ninst);
// check if any input value was NAN
FMAXS(q1, v0, v1); // propagate NAN
FMAXS(q1, v2, v1); // propagate NAN
FCMEQS(q1, q1, q1); // 0 if NAN, 1 if not NAN
FADDS(q2, v1, v2); // the high part of the vector is erased...
FCMEQS(q0, q2, q2); // 0 => out is NAN
VBIC(q0, q1, q0); // forget it in any input was a NAN already
VSHL_32(q0, q0, 31); // only keep the sign bit
VORR(q2, q2, q0); // NAN -> -NAN
FCMEQS(q1, v2, v2); // 0 if src1 was NaN
MOV32w(x5, 0x00400000);
VMOVQSfrom(q0, 0, x5);
VORR(q0, v2, q0); // QNaN(src1)
VBIF(q2, q0, q1); // where src1 was NaN, use QNaN(src1)
} else {
FADDS(q2, v1, v2); // the high part of the vector is erased...
}
@@ -301,13 +306,18 @@ uintptr_t dynarec64_AVX_F3_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
q1 = fpu_get_scratch(dyn, ninst);
q0 = fpu_get_scratch(dyn, ninst);
// check if any input value was NAN
FMAXS(q1, v0, v1); // propagate NAN
FMAXS(q1, v2, v1); // propagate NAN
FCMEQS(q1, q1, q1); // 0 if NAN, 1 if not NAN
FMULS(q2, v1, v2); // the high part of the vector is erased...
FCMEQS(q0, q2, q2); // 0 => out is NAN
VBIC(q0, q1, q0); // forget it in any input was a NAN already
VSHL_32(q0, q0, 31); // only keep the sign bit
VORR(q2, q2, q0); // NAN -> -NAN
FCMEQS(q1, v2, v2); // 0 if src1 was NaN
MOV32w(x5, 0x00400000);
VMOVQSfrom(q0, 0, x5);
VORR(q0, v2, q0); // QNaN(src1)
VBIF(q2, q0, q1); // where src1 was NaN, use QNaN(src1)
} else {
FMULS(q2, v1, v2); // the high part of the vector is erased...
}
@@ -375,13 +385,18 @@ uintptr_t dynarec64_AVX_F3_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
q1 = fpu_get_scratch(dyn, ninst);
q0 = fpu_get_scratch(dyn, ninst);
// check if any input value was NAN
FMAXS(q1, v0, v1); // propagate NAN
FMAXS(q1, v2, v1); // propagate NAN
FCMEQS(q1, q1, q1); // 0 if NAN, 1 if not NAN
FSUBS(q2, v2, v1); // the high part of the vector is erased...
FCMEQS(q0, q2, q2); // 0 => out is NAN
VBIC(q0, q1, q0); // forget it in any input was a NAN already
VSHL_32(q0, q0, 31); // only keep the sign bit
VORR(q2, q2, q0); // NAN -> -NAN
FCMEQS(q1, v2, v2); // 0 if src1 was NaN
MOV32w(x5, 0x00400000);
VMOVQSfrom(q0, 0, x5);
VORR(q0, v2, q0); // QNaN(src1)
VBIF(q2, q0, q1); // where src1 was NaN, use QNaN(src1)
} else {
FSUBS(q2, v2, v1); // the high part of the vector is erased...
}
@@ -415,13 +430,18 @@ uintptr_t dynarec64_AVX_F3_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
q1 = fpu_get_scratch(dyn, ninst);
q0 = fpu_get_scratch(dyn, ninst);
// check if any input value was NAN
FMAXS(q1, v0, v1); // propagate NAN
FMAXS(q1, v2, v1); // propagate NAN
FCMEQS(q1, q1, q1); // 0 if NAN, 1 if not NAN
FDIVS(q2, v2, v1); // the high part of the vector is erased...
FCMEQS(q0, q2, q2); // 0 => out is NAN
VBIC(q0, q1, q0); // forget it in any input was a NAN already
VSHL_32(q0, q0, 31); // only keep the sign bit
VORR(q2, q2, q0); // NAN -> -NAN
FCMEQS(q1, v2, v2); // 0 if src1 was NaN
MOV32w(x5, 0x00400000);
VMOVQSfrom(q0, 0, x5);
VORR(q0, v2, q0); // QNaN(src1)
VBIF(q2, q0, q1); // where src1 was NaN, use QNaN(src1)
} else {
FDIVS(q2, v2, v1); // the high part of the vector is erased...
}
+3
View File
@@ -84,6 +84,9 @@ uintptr_t getConst(arm64_consts_t which)
case const_native_fstp: return (uintptr_t)native_fstp;
case const_native_frstor: return (uintptr_t)native_frstor;
case const_native_next: return (uintptr_t)native_next;
case const_native_next_invalidate: return (uintptr_t)arm64_next_invalid;
case const_native_crc32: return (uintptr_t)arm64_crc;
case const_native_x31: return (uintptr_t)arm64_x31_hash;
case const_int3: return (uintptr_t)EmuInt3;
case const_x86syscall: return (uintptr_t)EmuX86Syscall;
case const_x64syscall: return (uintptr_t)EmuX64Syscall;
+3
View File
@@ -47,6 +47,9 @@ typedef enum arm64_consts_s {
const_native_fstp,
const_native_frstor,
const_native_next,
const_native_next_invalidate,
const_native_crc32,
const_native_x31,
const_int3,
const_x86syscall,
const_x64syscall,
+2 -16
View File
@@ -148,14 +148,7 @@ uintptr_t dynarec64_DB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
SETFLAGS(X_ALL, SF_SET);
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
IFX(X_CF|X_PF|X_ZF) {
if(ST_IS_F(0)) {
FCMPS(v1, v2);
} else {
FCMPD(v1, v2);
}
}
FCOMI(x1, x2);
FCOMI(x1, x2, ST_IS_F(0), v1, v2);
break;
case 0xF0:
case 0xF1:
@@ -169,14 +162,7 @@ uintptr_t dynarec64_DB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
SETFLAGS(X_ALL, SF_SET);
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
IFX(X_CF|X_PF|X_ZF) {
if(ST_IS_F(0)) {
FCMPS(v1, v2);
} else {
FCMPD(v1, v2);
}
}
FCOMI(x1, x2);
FCOMI(x1, x2,ST_IS_F(0), v1, v2);
break;
default:
+2 -18
View File
@@ -101,15 +101,7 @@ uintptr_t dynarec64_DF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
SETFLAGS(X_ALL, SF_SET);
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
IFX(X_CF|X_PF|X_ZF) {
if(ST_IS_F(0))
{
FCMPS(v1, v2);
} else {
FCMPD(v1, v2);
}
}
FCOMI(x1, x2);
FCOMI(x1, x2,ST_IS_F(0), v1, v2);
X87_POP_OR_FAIL(dyn, ninst, x3);
break;
case 0xF0:
@@ -124,15 +116,7 @@ uintptr_t dynarec64_DF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
SETFLAGS(X_ALL, SF_SET);
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
IFX(X_CF|X_PF|X_ZF) {
if(ST_IS_F(0))
{
FCMPS(v1, v2);
} else {
FCMPD(v1, v2);
}
}
FCOMI(x1, x2);
FCOMI(x1, x2, ST_IS_F(0), v1, v2);
X87_POP_OR_FAIL(dyn, ninst, x3);
break;
+42 -28
View File
@@ -1713,35 +1713,42 @@ void emit_neg16(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4)
CSETw(s4, cNE);
BFIw(xFlags, s4, F_CF, 1);
}
IFX(X_AF|X_OF) {
IFX(X_AF) {
MOVw_REG(s3, s1);
}
NEGw_REG(s1, s1);
IFX(X_ZF) {
ANDSw_mask(s1, s1, 0, 15); //mask=0xffff
IFX(X_OF|X_ZF|X_SF) {
SUBSw_REG_LSL(s1, xZR, s1, 16);
LSRw(s1, s1, 16);
} else {
NEGw_REG(s1, s1);
}
IFX(X_PEND) {
STRH_U12(s1, xEmu, offsetof(x64emu_t, res));
}
IFX(X_AF|X_OF) {
IFX(X_AF) {
ORRw_REG(s3, s3, s1); // bc = op1 | res
IFX(X_AF) {
LSRw(s4, s3, 3);
BFIw(xFlags, s4, F_AF, 1); // AF: bc & 0x08
}
IFX(X_OF) {
LSRw(s4, s3, 14);
EORw_REG_LSR(s4, s4, s4, 1);
BFIw(xFlags, s4, F_OF, 1); // OF: ((bc >> 14) ^ ((bc>>14)>>1)) & 1
}
}
IFX(X_ZF) {
CSETw(s4, cEQ);
BFIw(xFlags, s4, F_ZF, 1);
IFNATIVE(NF_EQ) {} else {
CSETw(s4, cEQ);
BFIw(xFlags, s4, F_ZF, 1);
}
}
IFX(X_SF) {
LSRw(s3, s1, 15);
BFIw(xFlags, s3, F_SF, 1);
IFNATIVE(NF_SF) {} else {
LSRw(s3, s1, 15);
BFIw(xFlags, s3, F_SF, 1);
}
}
IFX(X_OF) {
IFNATIVE(NF_VF) {} else {
CSETw(s4, cVS);
BFIw(xFlags, s4, F_OF, 1);
}
}
IFX(X_PF) {
emit_pf(dyn, ninst, s1, s4);
@@ -1762,35 +1769,42 @@ void emit_neg8(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4)
CSETw(s4, cNE);
BFIw(xFlags, s4, F_CF, 1);
}
IFX(X_AF|X_OF) {
IFX(X_AF) {
MOVw_REG(s3, s1);
}
NEGw_REG(s1, s1);
IFX(X_ZF) {
ANDSw_mask(s1, s1, 0, 7); // mask 0xff
IFX(X_OF|X_ZF|X_SF) {
SUBSw_REG_LSL(s1, xZR, s1, 24);
LSRw(s1, s1, 24);
} else {
NEGw_REG(s1, s1);
}
IFX(X_PEND) {
STRB_U12(s1, xEmu, offsetof(x64emu_t, res));
}
IFX(X_AF|X_OF) {
IFX(X_AF) {
ORRw_REG(s3, s3, s1); // bc = op1 | res
IFX(X_AF) {
LSRw(s4, s3, 3);
BFIw(xFlags, s4, F_AF, 1); // AF: bc & 0x08
}
IFX(X_OF) {
LSRw(s4, s3, 6);
EORx_REG_LSR(s4, s4, s4, 1);
BFIw(xFlags, s4, F_OF, 1); // OF: ((bc >> 6) ^ ((bc>>6)>>1)) & 1
}
}
IFX(X_ZF) {
CSETw(s4, cEQ);
BFIw(xFlags, s4, F_ZF, 1);
IFNATIVE(NF_EQ) {} else {
CSETw(s4, cEQ);
BFIw(xFlags, s4, F_ZF, 1);
}
}
IFX(X_SF) {
LSRw(s3, s1, 7);
BFIw(xFlags, s3, F_SF, 1);
IFNATIVE(NF_SF) {} else {
LSRw(s3, s1, 7);
BFIw(xFlags, s3, F_SF, 1);
}
}
IFX(X_OF) {
IFNATIVE(NF_VF) {} else {
CSETw(s4, cVS);
BFIw(xFlags, s4, F_OF, 1);
}
}
IFX(X_PF) {
emit_pf(dyn, ninst, s1, s4);
+39 -5
View File
@@ -704,6 +704,9 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
SETFLAGS(X_ZF, SF_SUBSET);
addr = geted(dyn, addr, ninst, nextop, &wback, x1, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
if(!ALIGNED_ATOMICxw) {
// commit df before branch, CALL_S in GPF path has FORCE_DFNONE
if(rex.w && BOX64DRENV(dynarec_safeflags)>1)
CHECK_DFNONE(0);
if(cpuext.uscat) {
if(rex.w) {
TSTx_mask(wback, 1, 0, 3);
@@ -724,13 +727,14 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
MOVx_REG(x4, xRBX);
MOVx_REG(x5, xRCX);
CASPALxw(x2, x4, wback);
// preserve upper bits of EAX/EDX if equal, per CMPXCHG8B semantics
CMPSxw_REG(x2, xRAX);
CCMPxw(x3, xRDX, 0, cEQ);
CSELx(xRAX, xRAX, x2, cEQ);
CSELx(xRDX, xRDX, x3, cEQ);
UFLAG_IF {
CMPSxw_REG(x2, xRAX);
CCMPxw(x3, xRDX, 0, cEQ);
IFNATIVE(NF_EQ) {} else {CSETw(x1, cEQ);}
}
MOVx_REG(xRAX, x2);
MOVx_REG(xRDX, x3);
if(!ALIGNED_ATOMICxw) {
B_MARK3_nocond;
}
@@ -818,11 +822,16 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
SETFLAGS(X_ALL, SF_SET_PENDING);
GETGB(x2);
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
MOVx_REG(x6, xFlags);
MRS_nzcv(x87pc);
MARKLOCK;
MOVx_REG(xFlags, x6);
MSR_nzcv(x87pc);
LDAXRB(x1, wback);
emit_adc8(dyn, ninst, x1, x2, x4, x5);
STLXRB(x4, x1, wback);
CBNZx_MARKLOCK(x4);
NATIVE_RESTORE_X87PC();
}
break;
case 0x11:
@@ -838,11 +847,16 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
SETFLAGS(X_ALL, SF_SET_PENDING);
GETGD;
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
MOVx_REG(x6, xFlags);
MRS_nzcv(x87pc);
MARKLOCK;
MOVx_REG(xFlags, x6);
MSR_nzcv(x87pc);
LDAXRxw(x1, wback);
emit_adc32(dyn, ninst, rex, x1, gd, x4, x5);
STLXRxw(x4, x1, wback);
CBNZx_MARKLOCK(x4);
NATIVE_RESTORE_X87PC();
}
break;
case 0x20:
@@ -1093,11 +1107,16 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
addr = geted(dyn, addr, ninst, nextop, &wback, x5, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 1);
u8 = F8;
wb1 = 1;
MOVx_REG(x6, xFlags);
MRS_nzcv(x87pc);
MARKLOCK;
MOVx_REG(xFlags, x6);
MSR_nzcv(x87pc);
LDAXRB(x1, wback);
emit_adc8c(dyn, ninst, x1, u8, x2, x4, x3);
STLXRB(x3, x1, wback);
CBNZx_MARKLOCK(x3);
NATIVE_RESTORE_X87PC();
}
break;
case 3: //SBB
@@ -1113,11 +1132,16 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
addr = geted(dyn, addr, ninst, nextop, &wback, x5, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 1);
u8 = F8;
wb1 = 1;
MOVx_REG(x6, xFlags);
MRS_nzcv(x87pc);
MARKLOCK;
MOVx_REG(xFlags, x6);
MSR_nzcv(x87pc);
LDAXRB(x1, wback);
emit_sbb8c(dyn, ninst, x1, u8, x2, x4, x3);
STLXRB(x3, x1, wback);
CBNZx_MARKLOCK(x3);
NATIVE_RESTORE_X87PC();
}
break;
case 4: //AND
@@ -1345,11 +1369,16 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, (opcode==0x81)?4:1);
if(opcode==0x81) i64 = F32S; else i64 = F8S;
MOV64xw(x5, i64);
MOVx_REG(x6, xFlags);
MRS_nzcv(x87pc);
MARKLOCK;
MOVx_REG(xFlags, x6);
MSR_nzcv(x87pc);
LDAXRxw(x1, wback);
emit_adc32(dyn, ninst, rex, x1, x5, x3, x4);
STLXRxw(x3, x1, wback);
CBNZx_MARKLOCK(x3);
NATIVE_RESTORE_X87PC();
}
break;
case 3: //SBB
@@ -1365,11 +1394,16 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, (opcode==0x81)?4:1);
if(opcode==0x81) i64 = F32S; else i64 = F8S;
MOV64xw(x5, i64);
MOVx_REG(x6, xFlags);
MRS_nzcv(x87pc);
MARKLOCK;
MOVx_REG(xFlags, x6);
MSR_nzcv(x87pc);
LDAXRxw(x1, wback);
emit_sbb32(dyn, ninst, rex, x1, x5, x3, x4);
STLXRxw(x3, x1, wback);
CBNZx_MARKLOCK(x3);
NATIVE_RESTORE_X87PC();
}
break;
case 4: //AND
@@ -1650,7 +1684,7 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
} else {
MARKLOCK;
LDAXRxw(x1, wback);
MVNw_REG(x1, x1);
MVNxw_REG(x1, x1);
STLXRxw(x3, x1, wback);
CBNZx_MARKLOCK(x3);
}
+103 -19
View File
@@ -31,14 +31,15 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
uint64_t u64, j64;
int32_t i32, i32_;
int cacheupd = 0;
int v0, v1;
int q0, q1;
int d0, d1;
int v0, v1, v2;
int q0, q1, q2;
int d0, d1, d2;
int64_t fixedaddress;
int unscaled;
MAYUSE(d0);
MAYUSE(d1);
MAYUSE(d2);
MAYUSE(q0);
MAYUSE(q1);
MAYUSE(v0);
@@ -207,6 +208,10 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
if(cpuext.crc32) {
CRC32Cxw(gd, gd, ed);
} else {
if (ed == gd) {
MOVxw_REG(x1, ed);
ed = x1;
}
MOV32w(x2, 0x82f63b78);
for(int j=0; j<4*(1+rex.w); ++j) {
UBFXxw(x3, ed, 8*j, 8);
@@ -257,6 +262,8 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
if(!BOX64ENV(dynarec_fastnan)) {
v0 = fpu_get_scratch(dyn, ninst);
q0 = fpu_get_scratch(dyn, ninst);
v2 = fpu_get_scratch(dyn, ninst);
FMOVD(v2, d1); // save src1
// check if any input value was NAN
FMAXD(v0, d0, d1); // propagate NAN
FCMEQD(v0, v0, v0); // 0 if NAN, 1 if not NAN
@@ -265,6 +272,11 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
VBIC(q0, v0, q0); // forget it in any input was a NAN already
SHL_64(q0, q0, 63); // only keep the sign bit
VORR(v1, v1, q0); // NAN -> -NAN
FCMEQD(v0, v2, v2); // 0 if src1 was NaN
MOV64x(x5, 0x0008000000000000ULL);
VMOVQDfrom(q0, 0, x5);
VORR(v2, v2, q0); // quiet any SNaN in src1
VBIF(v1, v2, v0); // where src1 was NaN, use QNaN(src1)
} else {
FADDD(v1, d1, d0); // the high part of the vector is erased...
}
@@ -279,6 +291,8 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
if(!BOX64ENV(dynarec_fastnan)) {
v0 = fpu_get_scratch(dyn, ninst);
q0 = fpu_get_scratch(dyn, ninst);
v2 = fpu_get_scratch(dyn, ninst);
FMOVD(v2, d1); // save src1
// check if any input value was NAN
FMAXD(v0, d0, d1); // propagate NAN
FCMEQD(v0, v0, v0); // 0 if NAN, 1 if not NAN
@@ -287,6 +301,11 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
VBIC(q0, v0, q0); // forget it in any input was a NAN already
SHL_64(q0, q0, 63); // only keep the sign bit
VORR(v1, v1, q0); // NAN -> -NAN
FCMEQD(v0, v2, v2); // 0 if src1 was NaN
MOV64x(x5, 0x0008000000000000ULL);
VMOVQDfrom(q0, 0, x5);
VORR(v2, v2, q0); // quiet any SNaN in src1
VBIF(v1, v2, v0); // where src1 was NaN, use QNaN(src1)
} else {
FMULD(v1, d1, d0);
}
@@ -317,6 +336,8 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
if(!BOX64ENV(dynarec_fastnan)) {
v0 = fpu_get_scratch(dyn, ninst);
q0 = fpu_get_scratch(dyn, ninst);
v2 = fpu_get_scratch(dyn, ninst);
FMOVD(v2, d1); // save src1
// check if any input value was NAN
FMAXD(v0, d0, d1); // propagate NAN
FCMEQD(v0, v0, v0); // 0 if NAN, 1 if not NAN
@@ -325,6 +346,11 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
VBIC(q0, v0, q0); // forget it in any input was a NAN already
SHL_64(q0, q0, 63); // only keep the sign bit
VORR(v1, v1, q0); // NAN -> -NAN
FCMEQD(v0, v2, v2); // 0 if src1 was NaN
MOV64x(x5, 0x0008000000000000ULL);
VMOVQDfrom(q0, 0, x5);
VORR(v2, v2, q0); // quiet any SNaN in src1
VBIF(v1, v2, v0); // where src1 was NaN, use QNaN(src1)
} else {
FSUBD(v1, d1, d0);
}
@@ -349,6 +375,8 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
if(!BOX64ENV(dynarec_fastnan)) {
d0 = fpu_get_scratch(dyn, ninst);
q0 = fpu_get_scratch(dyn, ninst);
v2 = fpu_get_scratch(dyn, ninst);
FMOVD(v2, v0); // save src1
// check if any input value was NAN
FMAXD(d0, v0, v1); // propagate NAN
FCMEQD(d0, d0, d0); // 0 if NAN, 1 if not NAN
@@ -357,6 +385,11 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
VBIC(q0, d0, q0); // forget it in any input was a NAN already
SHL_64(q0, q0, 63); // only keep the sign bit
VORR(d1, d1, q0); // NAN -> -NAN
FCMEQD(d0, v2, v2); // 0 if src1 was NaN
MOV64x(x5, 0x0008000000000000ULL);
VMOVQDfrom(q0, 0, x5);
VORR(v2, v2, q0); // quiet any SNaN in src1
VBIF(d1, v2, d0); // where src1 was NaN, use QNaN(src1)
} else {
FDIVD(d1, v0, v1);
}
@@ -414,16 +447,25 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
if(!BOX64ENV(dynarec_fastnan)) {
v0 = fpu_get_scratch(dyn, ninst);
v1 = fpu_get_scratch(dyn, ninst);
// check if any input value was NAN
VFMAXPQS(v0, q1, q0); // propagate NAN
VFCMEQQS(v0, v0, v0); // 0 if NAN, 1 if not NAN
d0 = fpu_get_scratch(dyn, ninst);
d1 = fpu_get_scratch(dyn, ninst);
VUZP1Q_32(d1, q1, q0); // d1 = {q1[0], q1[2], q0[0], q0[2]}
VFCMEQQS(v0, q1, q1); // per-element non-NaN mask for Gx
VFCMEQQS(d0, q0, q0); // per-element non-NaN mask for Ex
VUZP1Q_32(v1, v0, d0); // even elements of pairs
VUZP2Q_32(v0, v0, d0); // odd elements of pairs
VANDQ(v0, v1, v0); // v0 = both non-NaN per pair
}
VFADDPQS(q1, q1, q0);
if(!BOX64ENV(dynarec_fastnan)) {
VFCMEQQS(v1, q1, q1); // 0 => out is NAN
VBICQ(v1, v0, v1); // forget it in any input was a NAN already
VSHLQ_32(v1, v1, 31); // only keep the sign bit
VORRQ(q1, q1, v1); // NAN -> -NAN
VFCMEQQS(v1, d1, d1); // v1 = 0xFFFFFFFF where src1 non-NaN, 0 where NaN
MOVIQ_32_lsl(d0, 0x40, 2); // d0 = 0x00400000 in all lanes (QNaN bit)
VORRQ(d0, d1, d0); // d0 = QNaN(src1) = src1 | 0x00400000
VBIFQ(q1, d0, v1); // where src1 was NaN (v1=0): q1 = d0 (QNaN(src1))
VFCMEQQS(v1, q1, q1); // 0 => out is NAN
VBICQ(v1, v0, v1); // forget it in any input was a NAN already
VSHLQ_32(v1, v1, 31); // only keep the sign bit
VORRQ(q1, q1, v1); // NAN -> -NAN
}
break;
case 0x7D:
@@ -432,20 +474,27 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
GETGX(v0, 1);
GETEX(v1, 0, 0);
d0 = fpu_get_scratch(dyn, ninst);
VUZP1Q_32(d0, v0, v1);
VUZP2Q_32(v0, v0, v1);
VUZP1Q_32(d0, v0, v1); // d0 = src1 (even elements: first of each pair)
VUZP2Q_32(v0, v0, v1); // v0 = src2 (odd elements: second of each pair)
if(!BOX64ENV(dynarec_fastnan)) {
d1 = fpu_get_scratch(dyn, ninst);
// check if any input value was NAN
VFMAXQS(d1, d0, v0); // propagate NAN
VFCMEQQS(d1, d1, d1); // 0 if NAN, 1 if not NAN
d2 = fpu_get_scratch(dyn, ninst);
q0 = fpu_get_scratch(dyn, ninst);
VMOVQ(q0, d0); // save src1 for NaN priority
VFCMEQQS(d1, d0, d0); // even elements non-NaN
VFCMEQQS(d2, v0, v0); // odd elements non-NaN
VANDQ(d1, d1, d2); // d1 = both non-NaN per pair
}
VFSUBQS(v0, d0, v0);
if(!BOX64ENV(dynarec_fastnan)) {
VFCMEQQS(d0, v0, v0); // 0 => out is NAN
VBICQ(d1, d1, d0); // forget it in any input was a NAN already
VSHLQ_32(d1, d1, 31); // only keep the sign bit
VORRQ(v0, v0, d1); // NAN -> -NAN
VFCMEQQS(d2, q0, q0); // d2 = src1 non-NaN mask
MOVIQ_32_lsl(d0, 0x40, 2); // d0 = 0x00400000 (QNaN bit)
VORRQ(d0, q0, d0); // d0 = QNaN(src1)
VBIFQ(v0, d0, d2); // where src1 NaN: replace with QNaN(src1)
VFCMEQQS(d0, v0, v0); // 0 => out is NAN
VBICQ(d1, d1, d0); // forget it in any input was a NAN already
VSHLQ_32(d1, d1, 31); // only keep the sign bit
VORRQ(v0, v0, d1); // NAN -> -NAN
}
break;
@@ -483,6 +532,23 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
GOCOND(0x80, "J", "Id");
#undef GO
case 0xA3: // ignore F2 prefix
case 0xA4:
case 0xA5:
case 0xAB:
case 0xAC:
case 0xAD:
case 0xAF:
case 0xB3:
case 0xB7:
case 0xBA:
case 0xBB:
case 0xBC: // this one is still BSR, not TZCNT
case 0xBD: // and this one is still BSF, not LZCNT
case 0xC1:
case 0xCD:
return dynarec64_0F(dyn, addr-1, ip, ninst, rex, ok, need_epilog);
case 0xAE:
nextop = F8;
switch((nextop>>3)&7) {
@@ -522,9 +588,27 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
GETGX(v0, 1);
GETEX(v1, 0, 0);
q0 = fpu_get_scratch(dyn, ninst);
if (!BOX64ENV(dynarec_fastnan)) {
q1 = fpu_get_scratch(dyn, ninst);
v2 = fpu_get_scratch(dyn, ninst);
VMOVQ(v2, v0); // save src1
VFCMEQQS(q0, v0, v0);
VFCMEQQS(q1, v1, v1);
VANDQ(q1, q0, q1); // q1 = both non-NaN
}
TABLE64C(x2, const_4f_m1_1_m1_1);
VLDR128_U12(q0, x2, 0);
VFMLAQS(v0, v1, q0);
if (!BOX64ENV(dynarec_fastnan)) {
VFCMEQQS(q0, v0, v0); // 0 where result is NaN
VBICQ(q0, q1, q0); // both non-NaN but result NaN
VSHLQ_32(q0, q0, 31); // sign bit only
VORRQ(v0, v0, q0); // force -NaN
VFCMEQQS(q0, v2, v2); // 0 if src1 was NaN
MOVIQ_32_lsl(q1, 0x40, 2); // QNaN bit 0x00400000
VORRQ(v2, v2, q1); // quiet any SNaN
VBIFQ(v0, v2, q0); // where src1 NaN: use QNaN(src1)
}
break;
case 0xD6:
+48 -1
View File
@@ -28,7 +28,7 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
uint8_t gd, ed;
uint8_t wback;
uint64_t u64;
int v0, v1;
int v0, v1, v2;
int q0, q1;
int d0, d1;
int64_t fixedaddress;
@@ -288,6 +288,8 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
if(!BOX64ENV(dynarec_fastnan)) {
v0 = fpu_get_scratch(dyn, ninst);
q0 = fpu_get_scratch(dyn, ninst);
v2 = fpu_get_scratch(dyn, ninst);
FMOVS(v2, d1); // save src1
// check if any input value was NAN
FMAXS(v0, d0, d1); // propagate NAN
FCMEQS(v0, v0, v0); // 0 if NAN, 1 if not NAN
@@ -296,6 +298,12 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
VBIC(q0, v0, q0); // forget it in any input was a NAN already
VSHL_32(q0, q0, 31); // only keep the sign bit
VORR(v1, v1, q0); // NAN -> -NAN
// src1 NaN priority
FCMEQS(v0, v2, v2); // 0 if src1 was NaN
MOV32w(x5, 0x00400000);
VMOVQSfrom(q0, 0, x5);
VORR(v2, v2, q0); // quiet any SNaN in src1
VBIF(v1, v2, v0); // where src1 was NaN, use QNaN(src1)
} else {
FADDS(v1, d1, d0); // the high part of the vector is erased...
}
@@ -310,6 +318,8 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
if(!BOX64ENV(dynarec_fastnan)) {
v0 = fpu_get_scratch(dyn, ninst);
q0 = fpu_get_scratch(dyn, ninst);
v2 = fpu_get_scratch(dyn, ninst);
FMOVS(v2, d1); // save src1
// check if any input value was NAN
FMAXS(v0, d0, d1); // propagate NAN
FCMEQS(v0, v0, v0); // 0 if NAN, 1 if not NAN
@@ -318,6 +328,12 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
VBIC(q0, v0, q0); // forget it in any input was a NAN already
VSHL_32(q0, q0, 31); // only keep the sign bit
VORR(v1, v1, q0); // NAN -> -NAN
// src1 NaN priority
FCMEQS(v0, v2, v2); // 0 if src1 was NaN
MOV32w(x5, 0x00400000);
VMOVQSfrom(q0, 0, x5);
VORR(v2, v2, q0); // quiet any SNaN in src1
VBIF(v1, v2, v0); // where src1 was NaN, use QNaN(src1)
} else {
FMULS(v1, d1, d0); // the high part of the vector is erased...
}
@@ -386,6 +402,8 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
if(!BOX64ENV(dynarec_fastnan)) {
v0 = fpu_get_scratch(dyn, ninst);
q0 = fpu_get_scratch(dyn, ninst);
v2 = fpu_get_scratch(dyn, ninst);
FMOVS(v2, d1); // save src1
// check if any input value was NAN
FMAXS(v0, d0, d1); // propagate NAN
FCMEQS(v0, v0, v0); // 0 if NAN, 1 if not NAN
@@ -394,6 +412,12 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
VBIC(q0, v0, q0); // forget it in any input was a NAN already
VSHL_32(q0, q0, 31); // only keep the sign bit
VORR(v1, v1, q0); // NAN -> -NAN
// src1 NaN priority
FCMEQS(v0, v2, v2); // 0 if src1 was NaN
MOV32w(x5, 0x00400000);
VMOVQSfrom(q0, 0, x5);
VORR(v2, v2, q0); // quiet any SNaN in src1
VBIF(v1, v2, v0); // where src1 was NaN, use QNaN(src1)
} else {
FSUBS(v1, d1, d0); // the high part of the vector is erased...
}
@@ -418,6 +442,8 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
if(!BOX64ENV(dynarec_fastnan)) {
v0 = fpu_get_scratch(dyn, ninst);
q0 = fpu_get_scratch(dyn, ninst);
v2 = fpu_get_scratch(dyn, ninst);
FMOVS(v2, d1); // save src1
// check if any input value was NAN
FMAXS(v0, d0, d1); // propagate NAN
FCMEQS(v0, v0, v0); // 0 if NAN, 1 if not NAN
@@ -426,6 +452,12 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
VBIC(q0, v0, q0); // forget it in any input was a NAN already
VSHL_32(q0, q0, 31); // only keep the sign bit
VORR(v1, v1, q0); // NAN -> -NAN
// src1 NaN priority
FCMEQS(v0, v2, v2); // 0 if src1 was NaN
MOV32w(x5, 0x00400000);
VMOVQSfrom(q0, 0, x5);
VORR(v2, v2, q0); // quiet any SNaN in src1
VBIF(v1, v2, v0); // where src1 was NaN, use QNaN(src1)
} else {
FDIVS(v1, d1, d0); // the high part of the vector is erased...
}
@@ -612,6 +644,21 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
}
break;
case 0xA3: // ignore F3 prefix
case 0xA4:
case 0xA5:
case 0xAC:
case 0xAD:
case 0xAF:
case 0xB3:
case 0xB7:
case 0xBA:
case 0xBB:
case 0xBF:
case 0xC1:
case 0xCD:
return dynarec64_0F(dyn, addr-1, ip, ninst, rex, ok, need_epilog);
case 0xBC:
INST_NAME("TZCNT Gd, Ed");
if (!BOX64DRENV(dynarec_safeflags)) {
+103 -47
View File
@@ -786,13 +786,13 @@ void inst_name_pass3(dynarec_native_t* dyn, int ninst, const char* name, rex_t r
}
static char buf[4096];
int length = sprintf(buf, "barrier=%d state=%d/%s(%s->%s)/%d, set=%X/%X, use=%X, need=%X/%X, sm=%d(%d/%d/%d)",
int length = sprintf(buf, "barrier=%d state=%d/%s(%s->%s)/%c, set=%X/%X, use=%X, need=%X/%X, sm=%d(%d/%d/%d)",
dyn->insts[ninst].x64.barrier,
dyn->insts[ninst].x64.state_flags,
df_status[dyn->f],
df_status[dyn->insts[ninst].f_entry],
df_status[dyn->insts[ninst].f_exit],
dyn->insts[ninst].df_notneeded,
dyn->insts[ninst].df_needed?'N':(dyn->insts[ninst].df_notneeded?'U':'-'),
dyn->insts[ninst].x64.set_flags,
dyn->insts[ninst].x64.gen_flags,
dyn->insts[ninst].x64.use_flags,
@@ -859,11 +859,11 @@ void inst_name_pass3(dynarec_native_t* dyn, int ninst, const char* name, rex_t r
}
length += sprintf(buf + length, ")%s", (dyn->need_dump > 1) ? "\e[0;32m" : "");
}
if (dyn->insts[ninst].n.xmm_used || dyn->insts[ninst].n.xmm_unneeded) {
length += sprintf(buf + length, " xmmUsed=%04x/unneeded=%04x", dyn->insts[ninst].n.xmm_used, dyn->insts[ninst].n.xmm_unneeded);
if (dyn->insts[ninst].n.xmm_used || dyn->insts[ninst].n.xmm_unneeded || dyn->insts[ninst].n.xmm_needed) {
length += sprintf(buf + length, " xmmUsed=%04x/needed=%04x/unneeded=%04x", dyn->insts[ninst].n.xmm_used, dyn->insts[ninst].n.xmm_needed, dyn->insts[ninst].n.xmm_unneeded);
}
if (dyn->insts[ninst].n.ymm_used || dyn->insts[ninst].n.ymm_unneeded) {
length += sprintf(buf + length, " ymmUsed=%04x/unneeded=%04x", dyn->insts[ninst].n.ymm_used, dyn->insts[ninst].n.ymm_unneeded);
if (dyn->insts[ninst].n.ymm_used || dyn->insts[ninst].n.ymm_unneeded || dyn->insts[ninst].n.ymm_needed) {
length += sprintf(buf + length, " ymmUsed=%04x/needed=%04x/unneeded=%04x", dyn->insts[ninst].n.ymm_used, dyn->insts[ninst].n.ymm_needed, dyn->insts[ninst].n.ymm_unneeded);
}
if (dyn->ymm_zero || dyn->insts[ninst].ymm0_add || dyn->insts[ninst].ymm0_sub || dyn->insts[ninst].ymm0_out) {
length += sprintf(buf + length, " ymm0=(%04x/%04x+%04x-%04x=%04x)", dyn->ymm_zero, dyn->insts[ninst].ymm0_in, dyn->insts[ninst].ymm0_add, dyn->insts[ninst].ymm0_sub, dyn->insts[ninst].ymm0_out);
@@ -901,7 +901,7 @@ void inst_name_pass3(dynarec_native_t* dyn, int ninst, const char* name, rex_t r
}
dyn->gdbjit_block = GdbJITBlockAddLine(dyn->gdbjit_block, (dyn->native_start + dyn->insts[ninst].address), inst_name);
}
if (BOX64ENV(dynarec_perf_map) && BOX64ENV(dynarec_perf_map_fd) != -1) {
if (BOX64ENV(dynarec_perf_map) && (BOX64ENV(dynarec_perf_map_fd) != -1) && dyn->insts[ninst].size) {
writePerfMap(dyn->insts[ninst].x64.addr, dyn->native_start + dyn->insts[ninst].address, dyn->insts[ninst].size / 4, name);
}
if(length>sizeof(buf)) printf_log(LOG_NONE, "Warning: buf to small in inst_name_pass3 (%d vs %zd)\n", length, sizeof(buf));
@@ -991,27 +991,23 @@ uint8_t mark_natflag(dynarec_arm_t* dyn, int ninst, uint8_t flag, int before)
return flag;
}
uint8_t flag2native(uint8_t flags)
uint8_t flag2native(uint8_t flags, int vf_is_p)
{
uint8_t ret = 0;
#ifdef ARM64
if(flags&X_ZF) ret|=NF_EQ;
if(flags&X_SF) ret|=NF_SF;
if(flags&X_OF) ret|=NF_VF;
if(!vf_is_p)
if(flags&X_OF) ret|=NF_VF;
if(flags&X_CF) ret|=NF_CF;
if(vf_is_p)
if(flags&X_PF) ret|=NF_PF_V; // but no opcode can generate both NF_VF & NF_PF_V at the same time!
#else
// no native flags on rv64 or la64
#endif
return ret;
}
int flagIsNative(uint8_t flags)
{
if(flags&(X_AF|X_PF)) return 0;
return 1;
}
static uint8_t getNativeFlagsUsed(dynarec_arm_t* dyn, int start, uint8_t flags)
static uint8_t getNativeFlagsUsed(dynarec_arm_t* dyn, int start, uint8_t flags, int vf_is_p)
{
// propagate and check wich flags are actually used
uint8_t used_flags = 0;
@@ -1059,21 +1055,21 @@ static uint8_t getNativeFlagsUsed(dynarec_arm_t* dyn, int start, uint8_t flags)
}
if(ninst!=start && dyn->insts[ninst].x64.use_flags) {
// some flags not compatible with native, partial use not allowed
if(flag2native(dyn->insts[ninst].x64.use_flags)!=dyn->insts[ninst].use_nat_flags)
if(flag2native(dyn->insts[ninst].x64.use_flags, vf_is_p)!=dyn->insts[ninst].use_nat_flags)
return 0;
// check if flags are used, but not the natives ones
//if(dyn->insts[ninst].use_nat_flags&~used_flags)
// return 0;
}
// check if flags are generated without native option
if((start!=ninst) && dyn->insts[ninst].x64.gen_flags && (flag2native(dyn->insts[ninst].x64.gen_flags&dyn->insts[ninst].x64.need_after)&used_flags)) {
if(used_flags&~flag2native(dyn->insts[ninst].x64.gen_flags&dyn->insts[ninst].x64.need_after))
if((start!=ninst) && dyn->insts[ninst].x64.gen_flags && (flag2native(dyn->insts[ninst].x64.gen_flags&dyn->insts[ninst].x64.need_after, vf_is_p)&used_flags)) {
if(used_flags&~flag2native(dyn->insts[ninst].x64.gen_flags&dyn->insts[ninst].x64.need_after, vf_is_p))
return 0; // partial covert, not supported for now (TODO: this might be fixable)
else
return nat_flags_used?used_flags:0; // full covert... End of propagation
}
// check if flags are still needed
if(!(flag2native(dyn->insts[ninst].x64.need_after)&flags))
if(!(flag2native(dyn->insts[ninst].x64.need_after, vf_is_p)&flags))
return nat_flags_used?used_flags:0;
// check if flags are destroyed, cancel the use then
if(dyn->insts[ninst].nat_flags_op && (start!=ninst))
@@ -1099,13 +1095,15 @@ static void propagateNativeFlags(dynarec_arm_t* dyn, int start)
{
int ninst = start;
// those are the flags generated by the opcode and used later on
uint8_t flags = dyn->insts[ninst].set_nat_flags&flag2native(dyn->insts[ninst].x64.need_after);
int vf_is_p = (dyn->insts[ninst].set_nat_flags&NF_PF_V)?1:0;
uint8_t flags = dyn->insts[ninst].set_nat_flags&flag2native(dyn->insts[ninst].x64.need_after, vf_is_p);
//check if they are actualy used before starting
//printf_log(LOG_INFO, "propagateNativeFlags called for start=%d, flags=%x, will need:%x\n", start, flags, flag2native(dyn->insts[ninst].x64.need_after));
if(!flags) return;
// also check if some native flags are used but not genereated here
if(flag2native(dyn->insts[ninst].x64.use_flags)&~flags) return;
uint8_t used_flags = getNativeFlagsUsed(dyn, start, flags);
if(flag2native(dyn->insts[ninst].x64.use_flags, vf_is_p)&~flags) return;
if(flag2native(dyn->insts[ninst].x64.need_after, vf_is_p)&~flags) return;
uint8_t used_flags = getNativeFlagsUsed(dyn, start, flags, vf_is_p);
//printf_log(LOG_INFO, " will use:%x, carry:%d, generate inverted carry:%d\n", used_flags, used_flags&NF_CF, dyn->insts[ninst].gen_inverted_carry);
if(!used_flags) return; // the flags wont be used, so just cancel
int nc = dyn->insts[ninst].gen_inverted_carry?0:1;
@@ -1122,17 +1120,17 @@ static void propagateNativeFlags(dynarec_arm_t* dyn, int start)
return;
}
// check if flags are generated without native option
if((start!=ninst) && dyn->insts[ninst].x64.gen_flags && (flag2native(dyn->insts[ninst].x64.gen_flags&dyn->insts[ninst].x64.need_after)&used_flags))
if((start!=ninst) && dyn->insts[ninst].x64.gen_flags && (flag2native(dyn->insts[ninst].x64.gen_flags&dyn->insts[ninst].x64.need_after, vf_is_p)&used_flags))
return;
// mark the opcode
uint8_t use_flags = flag2native(dyn->insts[ninst].x64.need_before|dyn->insts[ninst].x64.need_after);
if(dyn->insts[ninst].x64.use_flags) use_flags |= flag2native(dyn->insts[ninst].x64.use_flags); // should not change anything
uint8_t use_flags = flag2native(dyn->insts[ninst].x64.need_before|dyn->insts[ninst].x64.need_after, vf_is_p);
if(dyn->insts[ninst].x64.use_flags) use_flags |= flag2native(dyn->insts[ninst].x64.use_flags, vf_is_p); // should not change anything
//printf_log(LOG_INFO, " marking ninst=%d with %x | %x&%x => %x\n", ninst, dyn->insts[ninst].need_nat_flags, used_flags, use_flags, dyn->insts[ninst].need_nat_flags | (used_flags&use_flags));
dyn->insts[ninst].need_nat_flags |= used_flags&use_flags;
if(carry) dyn->insts[ninst].normal_carry = nc;
if(carry && dyn->insts[ninst].invert_carry) nc = 0;
// check if flags are still needed
if(!(flag2native(dyn->insts[ninst].x64.need_after)&used_flags))
if(!(flag2native(dyn->insts[ninst].x64.need_after, vf_is_p)&used_flags))
return;
// go next
if(!dyn->insts[ninst].x64.has_next) {
@@ -1153,7 +1151,7 @@ void updateNativeFlags(dynarec_native_t* dyn)
return;
// forward check if native flags are used
for(int ninst=0; ninst<dyn->size; ++ninst)
if(flag2native(dyn->insts[ninst].x64.gen_flags) && (dyn->insts[ninst].nat_flags_op==NAT_FLAG_OP_TOUCH)) {
if(flag2native(dyn->insts[ninst].x64.gen_flags,(dyn->insts[ninst].set_nat_flags&NF_PF_V)?1:0) && (dyn->insts[ninst].nat_flags_op==NAT_FLAG_OP_TOUCH)) {
propagateNativeFlags(dyn, ninst);
}
}
@@ -1183,7 +1181,7 @@ int nativeFlagsNeedsTransform(dynarec_arm_t* dyn, int ninst)
flags_after = dyn->insts[jmp].before_nat_flags;
nc_after = dyn->insts[jmp].normal_carry_before;
}
uint8_t flags_x86 = flag2native(dyn->insts[jmp].x64.need_before);
uint8_t flags_x86 = flag2native(dyn->insts[jmp].x64.need_before, (dyn->insts[jmp].before_nat_flags&NF_PF_V)?1:0);
flags_x86 &= ~flags_after;
if((flags_before&NF_CF) && (flags_after&NF_CF) && (nc_before!=nc_after))
return 1;
@@ -1222,34 +1220,89 @@ static uint32_t getXYMMMask(dynarec_arm_t* dyn, int ninst)
return ret;
}
static void propagateXYMMUneeded(dynarec_arm_t* dyn, int ninst, uint16_t mask_x, uint16_t mask_y)
static void propagateXYMMNeeded(dynarec_arm_t* dyn, int ninst, uint16_t mask_x, uint16_t mask_y)
{
if(!ninst) return;
ninst = getNominalPred(dyn, ninst);
while(ninst>=0) {
mask_x &= ~dyn->insts[ninst].n.xmm_used;
mask_y &= ~dyn->insts[ninst].n.ymm_used;
if(!mask_x && !mask_y) return; // used, value is needed
if(dyn->insts[ninst].x64.barrier&BARRIER_FLOAT) return; // barrier, value is needed
// removed unneeded regs
mask_x &= ~dyn->insts[ninst].n.xmm_unneeded;
mask_y &= ~dyn->insts[ninst].n.ymm_unneeded;
if(!mask_x && !mask_y) return; // already handled
if(dyn->insts[ninst].x64.jmp) return; // stop when a jump is detected, that gets too complicated
dyn->insts[ninst].n.xmm_unneeded |= mask_x; // flags
dyn->insts[ninst].n.ymm_unneeded |= mask_y; // flags
ninst = getNominalPred(dyn, ninst); // continue
// removed already needed from mask
mask_x &= ~dyn->insts[ninst].n.xmm_needed;
mask_y &= ~dyn->insts[ninst].n.ymm_needed;
// already handled
if(!mask_x && !mask_y) return;
// added the unneeded value
dyn->insts[ninst].n.xmm_needed |= mask_x;
dyn->insts[ninst].n.ymm_needed |= mask_y;
for(int i=1; i<dyn->insts[ninst].pred_sz; ++i) {
int j = dyn->insts[ninst].pred[i];
// barrier or callret, value is needed
if(!(dyn->insts[j].x64.barrier&BARRIER_FLOAT)
&& !(dyn->insts[j].x64.has_callret))
propagateXYMMNeeded(dyn, j, mask_x, mask_y);
}
if(dyn->insts[ninst].pred_sz)
ninst = dyn->insts[ninst].pred[0];
else
ninst = -1;
if(ninst>=0)
if((dyn->insts[ninst].x64.barrier&BARRIER_FLOAT)
|| (dyn->insts[ninst].x64.has_callret))
return;
}
}
static void propagateXYMMUneeded(dynarec_arm_t* dyn, int ninst, uint16_t mask_x, uint16_t mask_y)
{
while(ninst>=0) {
// removed needed regs
mask_x &= ~dyn->insts[ninst].n.xmm_needed;
mask_y &= ~dyn->insts[ninst].n.ymm_needed;
// removed already unneeded from mask
mask_x &= ~dyn->insts[ninst].n.xmm_unneeded;
mask_y &= ~dyn->insts[ninst].n.ymm_unneeded;
// already handled
if(!mask_x && !mask_y) return;
// barrier or callret, value is needed
if(dyn->insts[ninst].x64.barrier&BARRIER_FLOAT) return;
if(dyn->insts[ninst].x64.has_callret) return;
// added the unneeded value
dyn->insts[ninst].n.xmm_unneeded |= mask_x;
dyn->insts[ninst].n.ymm_unneeded |= mask_y;
for(int i=1; i<dyn->insts[ninst].pred_sz; ++i)
propagateXYMMUneeded(dyn, dyn->insts[ninst].pred[i], mask_x, mask_y);
if(dyn->insts[ninst].pred_sz)
ninst = dyn->insts[ninst].pred[0];
else
ninst = -1;
}
}
void updateUneeded(dynarec_arm_t* dyn)
{
propagate_nodf(dyn);
if(!dyn->use_xmm && !dyn->use_ymm)
return;
for(int ninst=0; ninst<dyn->size; ++ninst) {
if(dyn->insts[ninst].n.xmm_unneeded || dyn->insts[ninst].n.ymm_unneeded)
propagateXYMMUneeded(dyn, ninst, dyn->insts[ninst].n.xmm_unneeded, dyn->insts[ninst].n.ymm_unneeded);
if(dyn->insts[ninst].df_notneeded)
propagate_nodf(dyn, ninst);
// first propagate the needed regs: those which are used and are not unneeded
for(int ninst=dyn->size-1; ninst>=0; --ninst) {
uint16_t xmm_needed = dyn->insts[ninst].n.xmm_used&~dyn->insts[ninst].n.xmm_unneeded;
uint16_t ymm_needed = dyn->insts[ninst].n.ymm_used&~dyn->insts[ninst].n.ymm_unneeded;
if((dyn->insts[ninst].x64.barrier&BARRIER_FLOAT) || (dyn->insts[ninst].x64.jmp && (dyn->insts[ninst].x64.jmp_insts==-1)))
{
if(dyn->use_xmm) xmm_needed = 0xffff;
if(dyn->use_ymm) ymm_needed = 0xffff;
}
if(xmm_needed || ymm_needed)
propagateXYMMNeeded(dyn, ninst, xmm_needed, ymm_needed);
}
// then proagate the unneeded one: those which are not needed (not used anymore and will be overwritten)
for(int ninst=dyn->size-1; ninst>=0; --ninst) {
if(dyn->insts[ninst].n.xmm_unneeded || dyn->insts[ninst].n.ymm_unneeded) {
for(int i=0; i<dyn->insts[ninst].pred_sz; ++i)
propagateXYMMUneeded(dyn, dyn->insts[ninst].pred[i], dyn->insts[ninst].n.xmm_unneeded, dyn->insts[ninst].n.ymm_unneeded);
}
}
// try to add some preload of XYMM on jump were it would make sense
for(int ninst=0; ninst<dyn->size; ++ninst)
@@ -1416,6 +1469,7 @@ void updateYmm0s(dynarec_arm_t* dyn, int ninst, int max_ninst_reached)
}
} else if (can_incr) {
// We always have ninst == max_ninst_reached when can_incr == 1
dyn->insts[ninst].ymm0_out = dyn->insts[ninst].ymm0_add & ~dyn->insts[ninst].ymm0_sub;
++max_ninst_reached;
} else {
// We didn't update anything, we can leave
@@ -1429,6 +1483,7 @@ void updateYmm0s(dynarec_arm_t* dyn, int ninst, int max_ninst_reached)
// AVX helpers
void avx_mark_zero(dynarec_arm_t* dyn, int ninst, int reg)
{
dyn->use_ymm = 1;
dyn->ymm_zero |= (1<<reg);
}
@@ -1448,6 +1503,7 @@ int is_avx_zero_unset(dynarec_arm_t* dyn, int ninst, int reg)
void avx_mark_zero_reset(dynarec_arm_t* dyn, int ninst)
{
dyn->use_ymm = 1;
dyn->ymm_zero = 0;
}
+1 -1
View File
@@ -52,7 +52,7 @@ int neoncache_combine_st(dynarec_arm_t* dyn, int ninst, int a, int b); // with
int neoncache_no_i64(dynarec_arm_t* dyn, int ninst, int st, int a);
// transform x86 flags to native flags
uint8_t flag2native(uint8_t flags);
uint8_t flag2native(uint8_t flags, int vf_is_p);
// mark a instruction as using/generating flags. return flag
uint8_t mark_natflag(dynarec_arm_t* dyn, int ninst, uint8_t flag, int before);
// propage the use of nativeflags or not (done between step 0 and step 1)
+157 -3
View File
@@ -1516,12 +1516,15 @@ int sse_get_reg(dynarec_arm_t* dyn, int ninst, int s1, int a, int forwrite)
// get neon register for a SSE reg, but don't try to synch it if it needed to be created
int sse_get_reg_empty(dynarec_arm_t* dyn, int ninst, int s1, int a)
{
dyn->n.xmm_used |= 1<<a;
if(dyn->n.ssecache[a].v!=-1) {
dyn->n.ssecache[a].write = 1;
dyn->n.neoncache[dyn->n.ssecache[a].reg].t = NEON_CACHE_XMMW;
if(!(dyn->n.xmm_used&(1<<a))) // if it's not used in this opcode, then it's not needed from there
dyn->n.xmm_unneeded |= 1<<a;
dyn->n.xmm_used |= 1<<a;
return dyn->n.ssecache[a].reg;
}
dyn->n.xmm_used |= 1<<a;
dyn->n.xmm_unneeded |= 1<<a;
dyn->n.ssecache[a].reg = fpu_get_reg_xmm(dyn, NEON_CACHE_XMMW, a);
dyn->n.ssecache[a].write = 1; // it will be write...
@@ -1729,6 +1732,8 @@ int ymm_get_reg_empty(dynarec_arm_t* dyn, int ninst, int s1, int a, int k1, int
if((dyn->n.neoncache[i].t==NEON_CACHE_YMMR || dyn->n.neoncache[i].t==NEON_CACHE_YMMW) && dyn->n.neoncache[i].n==a) {
dyn->n.neoncache[i].t = NEON_CACHE_YMMW;
dyn->ymm_zero&=~(1<<a);
if(!(dyn->n.ymm_used&(1<<a)))
dyn->n.ymm_unneeded |= 1<<a;
dyn->n.ymm_used|=(1<<a);
#if STEP == 0
dyn->insts[ninst].ymm0_sub |= (1<<a);
@@ -1737,6 +1742,7 @@ int ymm_get_reg_empty(dynarec_arm_t* dyn, int ninst, int s1, int a, int k1, int
}
// nope, grab a new one
dyn->n.ymm_unneeded |= 1<<a;
dyn->n.ymm_used|=(1<<a);
int ret = fpu_get_reg_ymm(dyn, ninst, NEON_CACHE_YMMW, a, k1, k2, k3);
if(dyn->ymm_zero&(1<<a))
dyn->ymm_zero&=~(1<<a);
@@ -2315,7 +2321,7 @@ static void nativeFlagsTransform(dynarec_arm_t* dyn, int ninst, int s1, int s2)
flags_after = dyn->insts[jmp].before_nat_flags;
nc_after = dyn->insts[jmp].normal_carry_before;
}
uint8_t flags_x86 = flag2native(dyn->insts[jmp].x64.need_before);
uint8_t flags_x86 = flag2native(dyn->insts[jmp].x64.need_before, (dyn->insts[jmp].before_nat_flags&NF_PF_V)?1:0);
flags_x86 &= ~flags_after;
MESSAGE(LOG_DUMP, "\tNative Flags transform ---- ninst=%d -> %d %hhx -> %hhx/%hhx\n", ninst, jmp, flags_before, flags_after, flags_x86);
// flags present in before and missing in after
@@ -2331,6 +2337,10 @@ static void nativeFlagsTransform(dynarec_arm_t* dyn, int ninst, int s1, int s2)
CSETw(s1, cVS);
BFIw(xFlags, s1, F_OF, 1);
}
if((flags_before&NF_PF_V) && (flags_x86&NF_PF_V)) {
CSETw(s1, cVS);
BFIw(xFlags, s1, F_PF, 1);
}
if((flags_before&NF_CF) && (flags_x86&NF_CF)) {
if(nc_before) // might need to invert carry
CSETw(s1, cCS);
@@ -2356,6 +2366,11 @@ static void nativeFlagsTransform(dynarec_arm_t* dyn, int ninst, int s1, int s2)
UBFXw(s1, xFlags, F_OF, 1);
BFIx(s2, s1, NZCV_V, 1);
}
if(!(flags_before&NF_PF_V) && (flags_after&NF_PF_V)) {
GO_MRS(s2);
UBFXw(s1, xFlags, F_PF, 1);
BFIx(s2, s1, NZCV_V, 1);
}
if(!(flags_before&NF_CF) && (flags_after&NF_CF)) {
GO_MRS(s2);
BFIx(s2, xFlags, NZCV_C, 1); // F_CF is bit 0
@@ -2387,6 +2402,47 @@ void CacheTransform(dynarec_arm_t* dyn, int ninst, int cacheupd) {
nativeFlagsTransform(dyn, ninst, x1, x2);
}
void additionnal_checks(dynarec_arm_t* dyn, int ninst)
{
int s1 = x1;
// check if a opcode generate partial flags that may clober existing native flags and see need to be "moved" to xFlags
if(dyn->insts[ninst].nat_flags_op || dyn->insts[ninst].nat_flags_op_before) {
uint8_t nat_flags = dyn->insts[ninst].need_nat_flags; // that's the native flags that will be generated
uint8_t nat_flags_gen = dyn->insts[ninst].set_nat_flags;
//TODO: does it need to fetch previous state with getPred?
uint8_t nat_flags_before = dyn->insts[ninst].before_nat_flags; //flags before the opcode, but it's only there when opcode also consume natflags
uint8_t nat_flags_flush = nat_flags_before&~nat_flags_gen; // flags present before bu not after the operation and so that needs to be spared
if(nat_flags_before && nat_flags_flush) {
// some flags disapear, and need to be saved
MESSAGE(LOG_DUMP, "\tPurging native flags %hhx\n", nat_flags_flush);
uint8_t nc_before = dyn->insts[ninst].normal_carry;
if(nat_flags_flush&NF_EQ) {
CSETw(s1, cEQ);
BFIw(xFlags, s1, F_ZF, 1);
}
if(nat_flags_flush&NF_SF) {
CSETw(s1, cMI);
BFIw(xFlags, s1, F_SF, 1);
}
if(nat_flags_flush&NF_VF) {
CSETw(s1, cVS);
BFIw(xFlags, s1, F_OF, 1);
}
if(nat_flags_flush&NF_PF_V) {
CSETw(s1, cVS);
BFIw(xFlags, s1, F_PF, 1);
}
if(nat_flags_flush&NF_CF) {
if(nc_before) // might need to invert carry
CSETw(s1, cCS);
else
CSETw(s1, cCC);
BFIw(xFlags, s1, F_CF, 1);
}
}
}
}
void fpu_reflectcache(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3)
{
x87_reflectcache(dyn, ninst, s1, s2, s3);
@@ -2619,8 +2675,10 @@ int fpu_get_reg_ymm(dynarec_arm_t* dyn, int ninst, int t, int ymm, int k1, int k
return i;
}
// check if free or should be purge before...
if(dyn->n.neoncache[i].t==NEON_CACHE_YMMW)
if(dyn->n.neoncache[i].t==NEON_CACHE_YMMW) {
dyn->n.ymm_used|=(1<<dyn->n.neoncache[i].n); // mark as used, to avoid it being mark as unneeded
VSTR128_U12(i, xEmu, offsetof(x64emu_t, ymm[dyn->n.neoncache[i].n]));
}
dyn->n.neoncache[i].t=t;
dyn->n.neoncache[i].n=ymm;
return i;
@@ -2666,6 +2724,7 @@ int fpu_get_reg_ymm(dynarec_arm_t* dyn, int ninst, int t, int ymm, int k1, int k
// should a test be done to check if ymm is already in the purge list?
if(!is_ymm_to_keep(dyn, i+j, k1, k2, k3)) {
// Save the reg and recycle it
dyn->n.ymm_used|=(1<<dyn->n.neoncache[i+j].n);
VSTR128_U12(i+j, xEmu, offsetof(x64emu_t, ymm[dyn->n.neoncache[i+j].n]));
dyn->n.neoncache[i+j].v = 0;
int ret = internal_mark_ymm(dyn, t, ymm, i+j);
@@ -2678,6 +2737,7 @@ int fpu_get_reg_ymm(dynarec_arm_t* dyn, int ninst, int t, int ymm, int k1, int k
if(!dyn->n.fpuused[i+j]) {
// should a test be done to check if ymm is already in the purge list?
if((dyn->n.neoncache[i+j].t==NEON_CACHE_YMMW) && !is_ymm_to_keep(dyn, i+j, k1, k2, k3)) {
dyn->n.ymm_used|=(1<<dyn->n.neoncache[i+j].n);
VSTR128_U12(i+j, xEmu, offsetof(x64emu_t, ymm[dyn->n.neoncache[i+j].n]));
dyn->n.neoncache[i+j].v = 0;
int ret = internal_mark_ymm(dyn, t, ymm, i+j);
@@ -2777,3 +2837,97 @@ void doLeaveBlock(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3)
}
MESSAGE(LOG_INFO, "-------- doLeave\n");
}
void emit_fcomi(dynarec_arm_t* dyn, int ninst, int s1, int s2, int isfloat, int d1, int d2)
{
IFX(X_OF|X_AF|X_SF) {
MOV32w(s2, 0b100011010101);
BICw_REG(xFlags, xFlags, s2);
}
IFX(X_CF|X_PF|X_ZF) {
int nonative = 0;
int needCZ = 0;
if(isfloat)
FCMPS(d1, d2);
else
FCMPD(d1, d2);
IFX(X_ZF) {
IFNATIVE(NF_EQ) {
// add ZF if VS is set
needCZ = 1;
} else {
nonative = 1;
}
}
IFX(X_CF) {
IFNATIVE(NF_CF) {
// no need to add CF if VS, because it's a reverse carry (so already "un"set)
GEN_INVERTED_CARRY();
needCZ = 1;
} else {
nonative = 1;
}
}
IFX(X_PF) {
IFNATIVE(NF_PF_V) {
} else {
nonative = 1;
}
}
if(needCZ) {
#if 1
// retest is VF is clear, set NZCV to 0101 if VF is set, to match x86 behaviour (also, inversed Carry)
// probably faster like that then the conditionnal jump + reading / reseting the flags
if(isfloat)
FCCMPS(d1, d2, 0b0101, cVC);
else
FCCMPD(d1, d2, 0b0101, cVC);
#else
if(cpuext.flagm) {
Bcond(cVC, 4+2*4);
MOV32w(s1, 0b0100); //new flags
RMIF(s1, 0, 0b0110); // ZC flags only
} else {
Bcond(cVC, 4+3*4);
MRS_nzcv(s1);
EORx_mask(s1, s1, 1, 0b100011, 0b000001); // mask = (1<<NZCV_Z)|(1<<NZCV_C) == 0x60000000
MSR_nzcv(s1);
}
#endif
}
if(nonative) {
MOV32w(s2, 0b01000101);
IFX(X_OF|X_AF|X_SF) {} else {BICw_REG(xFlags, xFlags, s2);}
CSETw(s1, cMI); /* 1 if less than, 0 else */
/*s2 already set */ /* unordered */
CSELw(s1, s2, s1, cVS);
MOV32w(s2, 0b01000000); /* zero */
CSELw(s1, s2, s1, cEQ);
/* greater than leave 0 */
ORRw_REG(xFlags, xFlags, s1);
}
}
SET_DFNONE();
}
void checkCRC(dynarec_arm_t* dyn, int ninst)
{
// grab the dynablock address in x5, as this on will not be erased by crc functions
int delta = -(dyn->native_size + sizeof(void*));
LDRx_literal(x5, delta);
// move away xEMU to X6, should be safe there
MOVx_REG(x6, xEmu);
// prepare and call the crc function
TABLE64C(x3, cpuext.crc32?const_native_crc32:const_native_x31);
LDRx_U12(xEmu, x5, offsetof(dynablock_t, x64_addr));
LDRw_U12(x1, x5, offsetof(dynablock_t, x64_size));
BLR(x3);
// done, move away result and restore xEmu
MOVw_REG(x1, xEmu);
MOVx_REG(xEmu, x6);
LDRw_U12(x2, x5, offsetof(dynablock_t, hash));
SUBw_REG(x1, x1, x2);
CBZw(x1, 4+2*4);
TABLE64C(x3, const_native_next_invalidate);
BLR(x3);
}
+24 -24
View File
@@ -841,30 +841,10 @@
ORRw_REG_LSL(s3, s3, s1, 8); \
STRH_U12(s3, xEmu, offsetof(x64emu_t, sw))
// Generate FCOMI with s1 and s2 scratch regs (the VCMP is already done)
#define FCOMI(s1, s2) \
IFX(X_OF|X_AF|X_SF) { \
MOV32w(s2, 0b100011010101); \
BICw_REG(xFlags, xFlags, s2); \
IFX(X_CF|X_PF|X_ZF) { \
MOV32w(s2, 0b01000101); \
} \
} else { \
IFX(X_CF|X_PF|X_ZF) { \
MOV32w(s2, 0b01000101); \
BICw_REG(xFlags, xFlags, s2); \
} \
} \
IFX(X_CF|X_PF|X_ZF) { \
CSETw(s1, cMI); /* 1 if less than, 0 else */ \
/*s2 already set */ /* unordered */ \
CSELw(s1, s2, s1, cVS); \
MOV32w(s2, 0b01000000); /* zero */ \
CSELw(s1, s2, s1, cEQ); \
/* greater than leave 0 */ \
ORRw_REG(xFlags, xFlags, s1); \
} \
SET_DFNONE(); \
// Generate FCOMI with s1 and s2 scratch regs (the VCMP is not done)
#define FCOMIS(s1, s2, d1, d2) emit_fcomi(dyn, ninst, s1, s2, 1, d1, d2)
#define FCOMID(s1, s2, d1, d2) emit_fcomi(dyn, ninst, s1, s2, 0, d1, d2)
#define FCOMI(s1, s2, isfloat, d1, d2) emit_fcomi(dyn, ninst, s1, s2, isfloat, d1, d2)
#ifndef IF_UNALIGNED
#define IF_UNALIGNED(A) if(dyn->insts[ninst].unaligned)
@@ -1097,6 +1077,11 @@
dyn->doublepop = 0;
#define ARCH_RESET()
#undef PREFLAGSNEEDED
#define PREFLAGSNEEDED() \
if(dyn->always_test && ninst && (dyn->insts[ninst].sep || (ninst && dyn->insts[ninst-1].x64.has_callret))) \
checkCRC(dyn, ninst);
#if STEP < 2
#define GETIP(A) MOV64x(xRIP, A)
#define GETIP_(A) MOV64x(xRIP, A)
@@ -1307,6 +1292,7 @@
#define emit_shld16 STEPNAME(emit_shld16)
#define emit_pf STEPNAME(emit_pf)
#define emit_fcomi STEPNAME(emit_fcomi)
#define x87_do_push STEPNAME(x87_do_push)
#define x87_do_push_empty STEPNAME(x87_do_push_empty)
@@ -1339,6 +1325,7 @@
#define doPreload STEPNAME(doPreload)
#define doEnterBlock STEPNAME(doEnterBlock)
#define doLeaveBlock STEPNAME(doLeaveBlock)
#define checkCRC STEPNAME(checkCRC)
#define fpu_pushcache STEPNAME(fpu_pushcache)
#define fpu_popcache STEPNAME(fpu_popcache)
@@ -1354,6 +1341,7 @@
#define avx_purge_ymm STEPNAME(avx_purge_ymm)
#define CacheTransform STEPNAME(CacheTransform)
#define additionnal_checks STEPNAME(additionnal_checks)
#define arm64_move32 STEPNAME(arm64_move32)
#define arm64_move64 STEPNAME(arm64_move64)
@@ -1479,6 +1467,7 @@ void emit_shld16c(dynarec_arm_t* dyn, int ninst, int s1, int s2, uint32_t c, int
void emit_shld16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s5, int s3, int s4);
void emit_pf(dynarec_arm_t* dyn, int ninst, int s1, int s4);
void emit_fcomi(dynarec_arm_t* dyn, int ninst, int s1, int s2, int isfloat, int d1, int d2);
// x87 helper
// cache of the local stack counter, to avoid update at every call, return old internal stack counter
@@ -1519,6 +1508,7 @@ int sse_setround(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3);
void avx_purge_ymm(dynarec_arm_t* dyn, int ninst, uint16_t mask, int s1);
void CacheTransform(dynarec_arm_t* dyn, int ninst, int cacheupd);
void additionnal_checks(dynarec_arm_t* dyn, int ninst);
void arm64_move32(dynarec_arm_t* dyn, int ninst, int reg, uint32_t val);
void arm64_move64(dynarec_arm_t* dyn, int ninst, int reg, uint64_t val);
@@ -1611,6 +1601,8 @@ void doPreload(dynarec_arm_t* dyn, int ninst);
void doEnterBlock(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3);
// Leave a block (atomic decrement of in_used)
void doLeaveBlock(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3);
// in case of allways_test, this insert a check of crc of the dynablock (and exit to ArmNext if wrong)
void checkCRC(dynarec_arm_t* dyn, int ninst);
uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int* ok, int* need_epilog);
uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int* ok, int* need_epilog);
@@ -1765,13 +1757,21 @@ uintptr_t dynarec64_AVX_F3_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
break; \
case B+0xA: \
INST_NAME(T1 "P " T2); \
IFNATIVE(NF_PF_V) { \
GO( , cVC, cVS, X_PF) \
} else { \
GO( TSTw_mask(xFlags, 0b011110, 0) \
, cEQ, cNE, X_PF) \
} \
break; \
case B+0xB: \
INST_NAME(T1 "NP " T2); \
IFNATIVE(NF_PF_V) { \
GO( , cVS, cVC, X_PF) \
} else { \
GO( TSTw_mask(xFlags, 0b011110, 0) \
, cNE, cEQ, X_PF) \
} \
break; \
case B+0xC: \
INST_NAME(T1 "L " T2); \
+7 -3
View File
@@ -31,8 +31,12 @@
Table64(dyn, getConst(V), 2); EMIT(0); \
} while(0)
#define FTABLE64(A, V) do { mmx87_regs_t v = {.d = V}; Table64(dyn, v.q, 2); EMIT(0); } while(0)
#define CALLRET_RET(A) do { \
if((A) && ISSEP() && BOX64DRENV(dynarec_callret)) { dyn->insts[ninst].size+=sizeof(void*); dyn->native_size+=sizeof(void*); ++dyn->sep_size; } \
if(BOX64DRENV(dynarec_callret)>1) {dyn->callrets[dyn->callret_size].type = 0; dyn->callrets[dyn->callret_size++].offs = dyn->native_size; EMIT(ARCH_NOP);} \
#define CALLRET_RET(A) do { \
if((A) && ISSEP() && BOX64DRENV(dynarec_callret)) { \
dyn->insts[ninst].size+=sizeof(void*); dyn->native_size+=sizeof(void*); dyn->insts[ninst+1].sep=1; ++dyn->sep_size; \
} \
if((A) && (BOX64DRENV(dynarec_callret)>1) && !dyn->always_test) { \
dyn->callrets[dyn->callret_size].type = 0; dyn->callrets[dyn->callret_size++].offs = dyn->native_size; EMIT(ARCH_NOP); \
} \
} while(0)
#define CALLRET_LOOP() do { dyn->callrets[dyn->callret_size].type = 1; dyn->callrets[dyn->callret_size++].offs = dyn->native_size; EMIT(ARCH_NOP); } while(0)
+2 -2
View File
@@ -14,7 +14,7 @@
#define MESSAGE(A, ...) \
do { \
if (dyn->need_dump) dynarec_log(LOG_NONE, __VA_ARGS__); \
if (dyn->need_dump) dynarec_log_prefix(0, LOG_NONE, __VA_ARGS__); \
} while (0)
#define ENDPREFIX dyn->insts[ninst].size2 = 0
#define NEW_INST \
@@ -54,7 +54,7 @@
dyn->sep[dyn->sep_size].nat_offs = dyn->native_size; \
++dyn->sep_size; \
} \
if(BOX64DRENV(dynarec_callret)>1) { \
if((A) && (BOX64DRENV(dynarec_callret)>1) && !dyn->always_test) { \
dyn->callrets[dyn->callret_size].type = 0; \
dyn->callrets[dyn->callret_size++].offs = dyn->native_size; \
EMIT(ARCH_NOP); \
+6 -1
View File
@@ -14,6 +14,7 @@ typedef struct box64env_s box64env_t;
#define NF_SF (1<<1)
#define NF_VF (1<<2)
#define NF_CF (1<<3)
#define NF_PF_V (1<<4)
// Nothing happens to the native flags
#define NAT_FLAG_OP_NONE 0
@@ -81,6 +82,8 @@ typedef struct neoncache_s {
uint16_t ymm_used; // mask of the ymm regs used in this opcode
uint16_t ymm_write; // 1bit of ymmXX removed write
uint16_t ymm_removed; // 1bit if ymmXX was removed
uint16_t xmm_needed; // 1bit for xmmXX were value is needed
uint16_t ymm_needed; // 1bit for ymmXX were value is needed
uint16_t xmm_unneeded; // 1bit for xmmXX were value is not needed
uint16_t ymm_unneeded; // 1bit for ymmXX were value is not needed
uint64_t ymm_regs; // 4bits (0-15) position of 16 ymmXX regs removed
@@ -123,7 +126,8 @@ typedef struct instruction_arm64_s {
uint8_t will_read:1; // [strongmem] will read from memory
uint8_t last_write:1; // [strongmem] the last write in a SEQ
uint8_t lock:1; // [strongmem] lock semantic
uint8_t wfe:1; // opcode uses sevl + wfe
uint8_t wfe:1; // opcode uses sevl + wfe
uint8_t sep:1; // opcode is a secondary entry point
uint8_t set_nat_flags; // 0 or combinaison of native flags define
uint8_t use_nat_flags; // 0 or combinaison of native flags define
uint8_t use_nat_flags_before; // 0 or combinaison of native flags define
@@ -135,6 +139,7 @@ typedef struct instruction_arm64_s {
unsigned normal_carry:1;
unsigned normal_carry_before:1;
unsigned invert_carry:1; // this opcode force an inverted carry
unsigned df_needed:1;
unsigned df_notneeded:1;
unsigned unaligned:1; // this opcode can be re-generated for unaligned special case
unsigned x87precision:1; // this opcode can handle x87pc
+1 -1
View File
@@ -898,7 +898,7 @@ SETMARK(d_shrd16);
BFIw(xFlags, x4, F_OF, 1);
BFCw(xFlags, F_AF, 1);
}
CBZw(x3, 4+4);
CBNZw(x3, 4+4);
RET(xLR);
SUBw_U12(x4, x3, 1);
LSRw_REG(x4, x2, x4);
+118 -97
View File
@@ -213,6 +213,18 @@ void MarkRangeDynablock(dynablock_t* db, uintptr_t addr, uintptr_t size)
MarkDynablock(db);
}
void MarkCRCRangeDynablock(dynablock_t* db, uintptr_t addr, uintptr_t size)
{
// Mark will try to find *any* blocks that intersect the range to mark
if(!db)
return;
dynarec_log(LOG_DEBUG, "MarkCRCRangeDynablock %p-%p .. startdb=%p, sizedb=%p\n", (void*)addr, (void*)addr+size-1, (void*)db->x64_addr, (void*)db->x64_size);
if(IntervalIntersects((uintptr_t)db->x64_addr, (uintptr_t)db->x64_addr+db->x64_size-1, addr, addr+size+1)) {
MarkDynablock(db); // mark as dirty
db->to_delete = 1; // also invalid hash, so it will be deleted and replace
}
}
int FreeRangeDynablock(dynablock_t* db, uintptr_t addr, uintptr_t size)
{
if(!db)
@@ -233,20 +245,62 @@ void dynablock_leave_runtime(dynablock_t* db)
__atomic_fetch_sub(&db->in_used, 1, __ATOMIC_ACQ_REL);
}
dynablock_t* CreateDBnoAlt(x64emu_t* emu, uintptr_t addr, int is32bits)
{
#ifndef WIN32
static int critical_filled = 0;
static sigset_t critical_prot = {0};
sigset_t old_sig = {0};
if(!critical_filled) {
critical_filled = 1;
sigfillset(&critical_prot);
sigdelset(&critical_prot, SIGSEGV);
sigdelset(&critical_prot, SIGILL);
sigdelset(&critical_prot, SIGBUS);
sigdelset(&critical_prot, SIGINT);
sigdelset(&critical_prot, SIGABRT);
sigdelset(&critical_prot, SIGFPE);
}
#endif
pthread_sigmask(SIG_BLOCK, &critical_prot, &old_sig);
if(BOX64ENV(dynarec_wait)) {
mutex_lock(&my_context->mutex_dyndump);
} else {
if(mutex_trylock(&my_context->mutex_dyndump)) { // FillBlock not available for now
pthread_sigmask(SIG_SETMASK, &old_sig, NULL);
return NULL;
}
}
dynarec_log(LOG_DEBUG, "Will call Fillblock64 for Alt %p\n", (void*)addr);
dynablock_t* block = FillBlock64(addr, is32bits, MAX_INSTS, 0, 1);
mutex_unlock(&my_context->mutex_dyndump);
pthread_sigmask(SIG_SETMASK, &old_sig, NULL);
return block;
}
/*
return NULL if block is not found / cannot be created.
Don't create if create==0
*/
static dynablock_t* internalDBGetBlock(x64emu_t* emu, uintptr_t addr, uintptr_t filladdr, int create, int need_lock, int is32bits, int is_new)
static dynablock_t* internalDBGetBlock(x64emu_t* emu, uintptr_t addr, int create, int need_lock, int is32bits, int is_new)
{
if (hasAlternate((void*)filladdr))
return NULL;
const uint32_t req_prot = (box64_pagesize==4096)?(PROT_EXEC|PROT_READ):PROT_READ;
if(BOX64ENV(nodynarec_delay) && (addr>=BOX64ENV(nodynarec_start)) && (addr<BOX64ENV(nodynarec_end)))
return NULL;
dynablock_t* block = getDB(addr);
if(block && block->to_delete) {
// just delete the block then, so we can create a new one right away
FreeDynablock(block, 1, 1);
block = NULL;
}
if(block || !create) {
if(block && getNeedTest(addr) && (getProtection(addr)&req_prot)!=req_prot)
if(block && getNeedTest(addr) && (getProtection(block->x64_readaddr)&req_prot)!=req_prot)
block = NULL;
return block;
}
@@ -278,30 +332,27 @@ static dynablock_t* internalDBGetBlock(x64emu_t* emu, uintptr_t addr, uintptr_t
}
}
block = getDB(addr); // just in case
if(block && block->to_delete) {
// just delete the block then, so we can create a new one right away
FreeDynablock(block, 0, 1);
block = NULL;
}
if(block) {
if(block && getNeedTest(addr) && (getProtection_fast(addr)&req_prot)!=req_prot)
if(block && getNeedTest(addr) && (getProtection_fast(block->x64_readaddr)&req_prot)!=req_prot)
block = NULL;
mutex_unlock(&my_context->mutex_dyndump);
pthread_sigmask(SIG_SETMASK, &old_sig, NULL);
return block;
}
}
#ifndef _WIN32
if((getProtection_fast(filladdr)&req_prot)!=req_prot) {// cannot be run, get out of the Dynarec
if(need_lock)
mutex_unlock(&my_context->mutex_dyndump);
pthread_sigmask(SIG_SETMASK, &old_sig, NULL);
return NULL;
}
#endif
block = FillBlock64(filladdr, (addr==filladdr)?0:1, is32bits, MAX_INSTS, is_new);
block = FillBlock64(addr, is32bits, MAX_INSTS, is_new, 0);
if(!block) {
dynarec_log(LOG_DEBUG, "Fillblock of block %p for %p returned an error\n", block, (void*)addr);
}
// check size
if(block) {
// fill-in jumptable
if(!addJumpTableIfDefault64(block->x64_addr, (block->dirty || block->always_test)?block->jmpnext:block->block)) {
if(!addJumpTableIfDefault64((void*)addr, (block->dirty || block->always_test)?block->jmpnext:block->block)) {
FreeDynablock(block, 0, 0);
block = getDB(addr);
MarkDynablock(block); // just in case...
@@ -335,35 +386,68 @@ static dynablock_t* internalDBGetBlock(x64emu_t* emu, uintptr_t addr, uintptr_t
return block;
}
dynablock_t* DBSwapInvalid(x64emu_t* emu, dynablock_t* db, uintptr_t addr, int is32bits, int need_lock)
{
if(need_lock)
mutex_lock(&my_context->mutex_dyndump);
db->done = 0; // invalidating the block
dynarec_log(LOG_DEBUG, "Invalidating alt block %p from %p:%p (hash:%X, gone:%d, autocrc:%d, to_delete:%d) for %p\n", db, db->x64_addr, db->x64_addr+db->x64_size, db->hash, db->gone, db->autocrc, db->to_delete, (void*)addr);
// Free db, it's now invalid!
dynablock_t* old = InvalidDynablock(db, 0);
if(old->previous) {
dynarec_log(LOG_DEBUG, "Free alt alt block %p\n", db->previous);
FreeInvalidDynablock(db->previous, 0);
old->previous = NULL;
}
// start again... (will create a new block)
db = internalDBGetBlock(emu, addr, 1, 0, is32bits, 0);
if(db) {
if(db->previous)
FreeInvalidDynablock(db->previous, 0);
db->previous = old;
} else
FreeInvalidDynablock(old, 0);
if(need_lock)
mutex_unlock(&my_context->mutex_dyndump);
return db;
}
dynablock_t* DBSwitchPrevious(x64emu_t* emu, dynablock_t* db, uintptr_t addr, int need_lock)
{
dynarec_log(LOG_DEBUG, "Switching to alt block %p from %p:%p (hash:%X) for %p\n", db, db->x64_addr, db->x64_addr+db->x64_size, db->hash, (void*)addr);
db = SwitchDynablock(db, need_lock);
if(!addJumpTableIfDefault64(db->x64_addr, (db->always_test)?db->jmpnext:db->block)) {
FreeDynablock(db, need_lock, 0);
db = getDB(addr);
MarkDynablock(db); // just in case...
} else {
for(int i=0; i<db->sep_size; ++i) {
uint32_t x64_offs = db->sep[i].x64_offs;
uint32_t nat_offs = db->sep[i].nat_offs;
if(addJumpTableIfDefault64(db->x64_addr+x64_offs, (db->always_test)?db->jmpnext:(db->block+nat_offs)))
db->sep[i].active = 1;
else
db->sep[i].active = 0;
}
}
return db;
}
dynablock_t* DBGetBlock(x64emu_t* emu, uintptr_t addr, int create, int is32bits)
{
int is_inhotpage = isInHotPage(addr);
if(is_inhotpage && !BOX64ENV(dynarec_dirty))
return NULL;
dynablock_t *db = internalDBGetBlock(emu, addr, addr, create, 1, is32bits, 1);
dynablock_t *db = internalDBGetBlock(emu, addr, create, 1, is32bits, 1);
if(db && db->done && db->block && getNeedTest(addr)) {
//if (db->always_test) SchedYield(); // just calm down...
uint32_t hash = X31_hash_code(db->x64_addr, db->x64_size);
uint32_t hash = X31_hash_code((void*)db->x64_readaddr, db->x64_size);
mutex_lock(&my_context->mutex_dyndump)?1:0;
if(hash!=db->hash) {
if(is_inhotpage && db->previous) {
// check alternate
if(db->previous && !db->dirty && X31_hash_code(db->previous->x64_addr, db->previous->x64_size)==db->previous->hash) {
db = SwitchDynablock(db, 0);
if(!addJumpTableIfDefault64(db->x64_addr, (db->always_test)?db->jmpnext:db->block)) {
FreeDynablock(db, 0, 0);
db = getDB(addr);
MarkDynablock(db); // just in case...
} else {
for(int i=0; i<db->sep_size; ++i) {
uint32_t x64_offs = db->sep[i].x64_offs;
uint32_t nat_offs = db->sep[i].nat_offs;
if(addJumpTableIfDefault64(db->x64_addr+x64_offs, (db->always_test)?db->jmpnext:(db->block+nat_offs)))
db->sep[i].active = 1;
else
db->sep[i].active = 0;
}
}
if(db->previous && !db->dirty && X31_hash_code((void*)db->previous->x64_readaddr, db->previous->x64_size)==db->previous->hash) {
db = DBSwitchPrevious(emu, db, addr, 0);
mutex_unlock(&my_context->mutex_dyndump);
return db;
}
@@ -371,18 +455,7 @@ dynablock_t* DBGetBlock(x64emu_t* emu, uintptr_t addr, int create, int is32bits)
dynarec_log(LOG_DEBUG, "Cannot run block (or previous) %p from %p:%p (hash:%X/%X, always_test:%d, previous=%p/hash=%X) for %p\n", db, db->x64_addr, db->x64_addr+db->x64_size-1, hash, db->hash, db->always_test,db->previous, db->previous?db->previous->hash:0,(void*)addr);
return NULL; // will be handle when hotpage is over
}
db->done = 0; // invalidating the block
dynarec_log(LOG_DEBUG, "Invalidating block %p from %p:%p (hash:%X/%X, always_test:%d, previous=%p/hash=%X) for %p\n", db, db->x64_addr, db->x64_addr+db->x64_size-1, hash, db->hash, db->always_test,db->previous, db->previous?db->previous->hash:0,(void*)addr);
// Free db, it's now invalid!
dynablock_t* old = InvalidDynablock(db, 0);
// start again... (will create a new block)
db = internalDBGetBlock(emu, addr, addr, create, 0, is32bits, 0);
if(db) {
if(db->previous)
FreeInvalidDynablock(db->previous, 0);
db->previous = old;
} else
FreeInvalidDynablock(old, 0);
db = DBSwapInvalid(emu, db, addr, is32bits, 0);
} else {
if(is_inhotpage) {
db->always_test = 2;
@@ -425,58 +498,6 @@ dynablock_t* DBGetBlock(x64emu_t* emu, uintptr_t addr, int create, int is32bits)
return db;
}
dynablock_t* DBAlternateBlock(x64emu_t* emu, uintptr_t addr, uintptr_t filladdr, int is32bits)
{
dynarec_log(LOG_DEBUG, "Creating AlternateBlock at %p for %p%s\n", (void*)addr, (void*)filladdr, is32bits?" 32bits":"");
int create = 1;
dynablock_t *db = internalDBGetBlock(emu, addr, filladdr, create, 1, is32bits, 1);
if(db && db->done && db->block && (db->dirty || getNeedTest(filladdr))) {
if (db->always_test) SchedYield(); // just calm down...
mutex_lock(&my_context->mutex_dyndump);
uint32_t hash = X31_hash_code(db->x64_addr, db->x64_size);
if(hash!=db->hash) {
db->done = 0; // invalidating the block
dynarec_log(LOG_DEBUG, "Invalidating alt block %p from %p:%p (hash:%X/%X) for %p\n", db, db->x64_addr, db->x64_addr+db->x64_size, hash, db->hash, (void*)addr);
// Free db, it's now invalid!
dynablock_t* old = InvalidDynablock(db, 0);
// start again... (will create a new block)
db = internalDBGetBlock(emu, addr, filladdr, create, 0, is32bits, 0);
if(db) {
if(db->previous)
FreeInvalidDynablock(db->previous, 0);
db->previous = old;
} else
FreeInvalidDynablock(old, 0);
} else {
if(db->always_test)
protectDB((uintptr_t)db->x64_addr, db->x64_size);
else {
#ifdef ARCH_NOP
if(db->callret_size) {
// mark all callrets to UDF
for(int i=0; i<db->callret_size; ++i)
*(uint32_t*)(db->block+db->callrets[i].offs) = ARCH_NOP;
ClearCache(db->block, db->size);
}
#endif
protectDBJumpTable((uintptr_t)db->x64_addr, db->x64_size, db->block, db->jmpnext);
for(int i=0; i<db->sep_size; ++i) {
uint32_t x64_offs = db->sep[i].x64_offs;
uint32_t nat_offs = db->sep[i].nat_offs;
if(addJumpTableIfDefault64(db->x64_addr+x64_offs, (db->always_test)?db->jmpnext:(db->block+nat_offs)))
db->sep[i].active = 1;
else
db->sep[i].active = 0;
}
}
}
mutex_unlock(&my_context->mutex_dyndump);
}
if(!db || !db->block || !db->done)
emu->test.test = 0;
return db;
}
uintptr_t getX64Address(dynablock_t* db, uintptr_t native_addr)
{
if ((native_addr < (uintptr_t)db->block) || (native_addr > (uintptr_t)db->actual_block + db->size))
+3
View File
@@ -26,6 +26,7 @@ typedef struct dynablock_s {
void* x64_addr;
uintptr_t x64_size;
size_t native_size;
uintptr_t x64_readaddr; // in case an alternate address is in effect, it can be different than x64_addr
uint32_t prefixsize; // size in byte of the prefix of the block
int size;
uint32_t hash;
@@ -34,6 +35,8 @@ typedef struct dynablock_s {
uint8_t dirty; // if need to be tested as soon as it's created
uint8_t always_test:2;
uint8_t is32bits:1;
uint8_t autocrc:1;
uint8_t to_delete:1;
int callret_size; // size of the array
int isize;
int arch_size; // size of of arch dependant infos
+3
View File
@@ -10,6 +10,9 @@
#elif defined(LA64)
#include "dynarec/la64/dynarec_la64_consts.h"
#define native_consts_t la64_consts_t
#elif defined(PPC64LE)
#include "dynarec/ppc64le/dynarec_ppc64le_consts.h"
#define native_consts_t ppc64le_consts_t
#else
#error Unsupported architecture
#endif
+95 -33
View File
@@ -14,11 +14,11 @@
#include "emu/x64run_private.h"
#include "x64trace.h"
#include "threads.h"
#include "alternate.h"
#ifdef DYNAREC
#include "dynablock.h"
#include "dynablock_private.h"
#include "bridge.h"
#include "alternate.h"
#include "dynarec_next.h"
#include "custommem.h"
#include "x64test.h"
@@ -33,38 +33,34 @@ void* LinkNext(x64emu_t* emu, uintptr_t addr, void* x2, uintptr_t* x3)
{
int is32bits = (R_CS == 0x23);
if(!running32bits && is32bits) running32bits=1;
#ifdef HAVE_TRACE
#ifndef HAVE_ALTJUMP
// inefficient way to handle alternate without ALTJUMP
uintptr_t new_addr = (uintptr_t)getAlternate((void*)addr);
if(new_addr!=addr) {
*x3 = new_addr;
addr = new_addr;
}
#endif
#ifdef HAVE_TRACE
if(!addr) {
dynablock_t* db = FindDynablockFromNativeAddress(x2-4);
printf_log(LOG_INFO, "Warning, jumping to NULL address from %p (db=%p, x64addr=%p/%s)\n", x2-4, db, db?(void*)getX64Address(db, (uintptr_t)x2-4):NULL, db?getAddrFunctionName(getX64Address(db, (uintptr_t)x2-4)):"(nil)");
} else if(new_addr<0x10000) {
} else if(addr<0x10000) {
dynablock_t* db = FindDynablockFromNativeAddress(x2-4);
printf_log(LOG_INFO, "Warning, jumping to low address %p->%p from %p (db=%p, x64addr=%p/%s)\n", (void*)new_addr, (void*)addr, x2-4, db, db?(void*)getX64Address(db, (uintptr_t)x2-4):NULL, db?getAddrFunctionName(getX64Address(db, (uintptr_t)x2-4)):"(nil)");
printf_log(LOG_INFO, "Warning, jumping to low address %p from %p (db=%p, x64addr=%p/%s)\n", (void*)addr, x2-4, db, db?(void*)getX64Address(db, (uintptr_t)x2-4):NULL, db?getAddrFunctionName(getX64Address(db, (uintptr_t)x2-4)):"(nil)");
#ifdef BOX32
} else if(emu->segs[_CS]==0x23 && addr>0x100000000LL) {
dynablock_t* db = FindDynablockFromNativeAddress(x2-4);
printf_log(LOG_INFO, "Warning, jumping to high address %p from %p (db=%p, x64addr=%p/%s)\n", (void*)addr, x2-4, db, db?(void*)getX64Address(db, (uintptr_t)x2-4):NULL, db?getAddrFunctionName(getX64Address(db, (uintptr_t)x2-4)):"(nil)");
#endif
} else if(!memExist(new_addr)) {
} else if(!memExist(addr)) {
dynablock_t* db = FindDynablockFromNativeAddress(x2-4);
printf_log(LOG_INFO, "Warning, jumping to an unmapped address %p->%p from %p (db=%p, x64addr=%p/%s)\n", (void*)new_addr, (void*)addr, x2-4, db, db?(void*)getX64Address(db, (uintptr_t)x2-4):NULL, db?getAddrFunctionName(getX64Address(db, (uintptr_t)x2-4)):"(nil)");
printf_log(LOG_INFO, "Warning, jumping to an unmapped address %p from %p (db=%p, x64addr=%p/%s)\n", (void*)addr, x2-4, db, db?(void*)getX64Address(db, (uintptr_t)x2-4):NULL, db?getAddrFunctionName(getX64Address(db, (uintptr_t)x2-4)):"(nil)");
}
#else //HAVE_TRACE
uintptr_t new_addr = addr;
#endif
void * jblock;
dynablock_t* block = NULL;
uintptr_t old_addr = addr;
if(hasAlternate((void*)addr)) {
printf_log(LOG_DEBUG, "Jmp address has alternate: %p\n", (void*)addr);
addr = (uintptr_t)getAlternate((void*)addr); // set new address
R_RIP = addr; // but also new RIP!
*x3 = addr; // and the RIP in x27 register
printf_log(LOG_DEBUG, " -> %p\n", (void*)addr);
block = DBAlternateBlock(emu, old_addr, addr, is32bits);
} else
block = DBGetBlock(emu, addr, 1, is32bits);
block = DBGetBlock(emu, addr, 1, is32bits);
if(!block) {
#ifdef HAVE_TRACE
if(LOG_INFO<=BOX64ENV(dynarec_log)) {
@@ -94,23 +90,48 @@ void* LinkNext(x64emu_t* emu, uintptr_t addr, void* x2, uintptr_t* x3)
// null block, but done: go to epilog, no linker here
return native_epilog;
}
if(block->sep_size && (uintptr_t)block->x64_addr!=old_addr) {
if(block->sep_size && (uintptr_t)block->x64_addr!=addr) {
jblock = NULL;
for(int i=0; i<block->sep_size && !jblock; ++i) {
if(old_addr==(uintptr_t)block->x64_addr + block->sep[i].x64_offs)
if(addr==(uintptr_t)block->x64_addr + block->sep[i].x64_offs)
jblock = block->block + block->sep[i].nat_offs;
}
if(!jblock) {
printf_log(LOG_NONE, "Warning, cannot find Secondary Entry Point %p in dynablock %p\n", new_addr, block);
printf_log(LOG_NONE, "Warning, cannot find Secondary Entry Point %p in dynablock %p\n", addr, block);
return native_epilog;
}
}
//dynablock_t *father = block->father?block->father:block;
return jblock;
}
void* LinkNextInvalid(x64emu_t* emu, uintptr_t addr, void* x2, uintptr_t* x3)
{
// like LinkNext, but invalid the db found first
int is32bits = (R_CS == 0x23);
dynablock_t* db = getDB(addr);
if(db) {
if(db->previous && !db->dirty && X31_hash_code(db->previous->x64_addr, db->previous->x64_size)==db->previous->hash)
db = DBSwitchPrevious(emu, db, addr, 1);
else
db = DBSwapInvalid(emu, db, addr, is32bits, 1);
if(db && db->done && db->block) {
void* jblock = db->block;
if(db->sep_size && (uintptr_t)db->x64_addr!=addr) {
jblock = NULL; // not sure how this would happens here, but lets put the case it starts on SEP anyway
for(int i=0; i<db->sep_size && !jblock; ++i) {
if(addr==(uintptr_t)db->x64_addr + db->sep[i].x64_offs)
jblock = db->block + db->sep[i].nat_offs;
}
}
if(jblock)
return jblock;
}
}
return LinkNext(emu, addr, x2, x3);
}
#endif
void DynaCall(x64emu_t* emu, uintptr_t addr)
void DynaCall(x64emu_t* emu, uintptr_t addr, int no_alt)
{
uint64_t old_rsp = R_RSP;
uint64_t old_rbx = R_RBX;
@@ -135,7 +156,7 @@ void DynaCall(x64emu_t* emu, uintptr_t addr)
emu->df = d_none;
if(emu->flags.quitonlongjmp)
emu->flags.need_jmpbuf = 1;
EmuRun(emu, 1);
EmuRun(emu, 1, no_alt);
emu->quit = 0; // reset Quit flags...
emu->df = d_none;
if(emu->flags.quitonlongjmp && emu->flags.longjmp) {
@@ -158,20 +179,45 @@ void DynaCall(x64emu_t* emu, uintptr_t addr)
}
}
void EmuRun(x64emu_t* emu, int use_dynarec)
#ifdef DYNAREC
static dynablock_t* fastDBGetBlock(x64emu_t* emu, uintptr_t addr, int create, int is32bits)
{
dynablock_t* ret = getDBnoTest(R_RIP);
if(!ret)
ret = DBGetBlock(emu, R_RIP, 1, is32bits);
return ret;
}
#ifdef HAVE_ALTJUMP
static dynablock_t* getDBnoAlt(x64emu_t* emu, uintptr_t addr, int is32bits)
{
dynablock_t* ret = getAlternateData((void*)addr);
if(ret == (void*)-1LL)
return NULL;
if(!ret) {
ret = CreateDBnoAlt(emu, addr, is32bits);
setAlternateData((void*)addr, ret);
}
dynarec_log(LOG_DEBUG, "Will use No-Alt block %p for Alt %p\n", ret, (void*)addr);
return ret;
}
#endif
#endif
void EmuRun(x64emu_t* emu, int use_dynarec, int no_alt)
{
// prepare setjump for signal handling
JUMPBUFF jmpbuf[1] = {0};
int skip = 0;
JUMPBUFF *old_jmpbuf = emu->jmpbuf;
#ifdef RV64
#if defined(RV64) || defined(PPC64LE)
uintptr_t old_savesp = emu->xSPSave;
#endif
int is32bits = (emu->segs[_CS]==0x23);
while(!(emu->quit)) {
if(!emu->jmpbuf || (emu->flags.need_jmpbuf && emu->jmpbuf!=jmpbuf)) {
emu->jmpbuf = jmpbuf;
#ifdef RV64
#if defined(RV64) || defined(PPC64LE)
emu->old_savedsp = emu->xSPSave;
#endif
emu->flags.jmpbuf_ready = 1;
@@ -195,7 +241,17 @@ void EmuRun(x64emu_t* emu, int use_dynarec)
}
if(emu->flags.need_jmpbuf)
emu->flags.need_jmpbuf = 0;
if(no_alt)
{
// the Dynarec will shadow the Entry Point, so using Intperter to enter the function
#if defined(DYNAREC) && defined(HAVE_ALTJUMP)
if(!BOX64ENV(dynarec))
#endif
no_alt = 0;
skip = 1;
}
else
R_RIP = (uintptr_t)getAlternate((void*)R_RIP);
#ifdef DYNAREC
if(!BOX64ENV(dynarec) || !use_dynarec)
#endif
@@ -218,17 +274,23 @@ void EmuRun(x64emu_t* emu, int use_dynarec)
running32bits = 1;
}
}
dynablock_t* block = (skip || ACCESS_FLAG(F_TF))?NULL:DBGetBlock(emu, R_RIP, 1, is32bits);
dynablock_t* block = (skip || ACCESS_FLAG(F_TF))?NULL:fastDBGetBlock(emu, R_RIP, 1, is32bits);
#ifdef HAVE_ALTJUMP
if(skip && no_alt) {
block = getDBnoAlt(emu, R_RIP, is32bits);
no_alt = 0;
}
#endif
if(!block || !block->block || !block->done || ACCESS_FLAG(F_TF)) {
skip = 0;
// no block, of block doesn't have DynaRec content (yet, temp is not null)
// no block, or block doesn't have DynaRec content (yet, temp is not null)
// Use interpreter (should use single instruction step...)
if(BOX64ENV(dynarec_log)) {
if(ACCESS_FLAG(F_TF))
dynarec_log(LOG_INFO, "%04d|Running Interpreter @%p, emu=%p because TF is on\n", GetTID(), (void*)R_RIP, emu);
else
dynarec_log(LOG_DEBUG, "%04d|Running Interpreter @%p, emu=%p\n", GetTID(), (void*)R_RIP, emu);
dynarec_log(LOG_DEBUG, "%04d|Running Interpreter @%p, emu=%p (skip=%d)\n", GetTID(), (void*)R_RIP, emu, skip);
}
skip = 0;
if (BOX64ENV(dynarec_test))
emu->test.clean = 0;
Run(emu, 1);
@@ -265,12 +327,12 @@ void EmuRun(x64emu_t* emu, int use_dynarec)
}
// clear the setjmp
emu->jmpbuf = old_jmpbuf;
#ifdef RV64
#if defined(RV64) || defined(PPC64LE)
emu->xSPSave = old_savesp;
#endif
}
void DynaRun(x64emu_t *emu)
{
EmuRun(emu, 1);
EmuRun(emu, 1, 0);
}
+159 -102
View File
@@ -1,113 +1,170 @@
#ifndef __DYNAREC_ARCH__H_
#define __DYNAREC_ARCH__H_
#ifdef ARM64
#define instruction_native_t instruction_arm64_t
#define dynarec_native_t dynarec_arm_t
#define extcache_native_t neoncache_t
#define ADDITIONNAL_DEFINITION() \
int fpuCacheNeedsTransform(dynarec_native_t* dyn, int ninst);
#define OTHER_CACHE() \
if (fpuCacheNeedsTransform(dyn, ninst)) ret|=2; \
if (nativeFlagsNeedsTransform(dyn, ninst)) ret|=4;
#include "arm64/arm64_printer.h"
#include "arm64/dynarec_arm64_private.h"
#include "arm64/dynarec_arm64_functions.h"
#include "arm64/dynarec_arm64_arch.h"
// TBZ/TBNZ is signed 14bits shifted by 2, but not use to jump from opcode to opcode
// Limit here is defined by LD litteral, that is 19bits signed ledt shifted by 2. So 20bits (positive/negative) address space (used for TABLE64)
// C.cond is also signed 19bits shifted by 2
#define MAXBLOCK_SIZE ((1<<20)-200)
#define RAZ_SPECIFIC(A, N) rasNativeState(A, N)
#define UPDATE_SPECIFICS(A) updateYmm0s(dyn, 0, 0); updateNativeFlags(A); propagateFpuBarrier(A)
#define PREUPDATE_SPECIFICS(A)
#define POSTUPDATE_SPECIFICS(A) updateUneeded(A)
#define ARCH_SIZE(A) get_size_arch(A)
#define ARCH_FILL(A, B, C) populate_arch(A, B, C)
#define ARCH_ADJUST(A, B, C, D) adjust_arch(A, B, C, D)
#define STOP_NATIVE_FLAGS(A, B) A->insts[B].nat_flags_op = NAT_FLAG_OP_UNUSABLE
#define ARCH_UNALIGNED(A, B) arch_unaligned(A, B)
extern uint32_t arm64_crc(void* p, uint32_t len);
#define ARCH_CRC(A, B) if(cpuext.crc32) return arm64_crc(A, B)
extern void* create_updateflags();
#define ARCH_UPDATEFLAGS() create_updateflags()
#ifndef __DYNAREC_ARCH__H_
#define __DYNAREC_ARCH__H_
#ifdef ARM64
#define instruction_native_t instruction_arm64_t
#define dynarec_native_t dynarec_arm_t
#define extcache_native_t neoncache_t
#define ADDITIONNAL_DEFINITION() \
int fpuCacheNeedsTransform(dynarec_native_t* dyn, int ninst);
#define OTHER_CACHE() \
if (fpuCacheNeedsTransform(dyn, ninst)) ret|=2; \
if (nativeFlagsNeedsTransform(dyn, ninst)) ret|=4;
#include "arm64/arm64_printer.h"
#include "arm64/dynarec_arm64_private.h"
#include "arm64/dynarec_arm64_functions.h"
#include "arm64/dynarec_arm64_arch.h"
// TBZ/TBNZ is signed 14bits shifted by 2, but not use to jump from opcode to opcode
// Limit here is defined by LD litteral, that is 19bits signed ledt shifted by 2. So 20bits (positive/negative) address space (used for TABLE64)
// C.cond is also signed 19bits shifted by 2
#define MAXBLOCK_SIZE ((1<<20)-200)
#define RAZ_SPECIFIC(A, N) rasNativeState(A, N)
#define UPDATE_SPECIFICS(A) updateYmm0s(dyn, 0, 0); updateNativeFlags(A); propagateFpuBarrier(A)
#define PREUPDATE_SPECIFICS(A)
#define POSTUPDATE_SPECIFICS(A) updateUneeded(A)
#define ARCH_SIZE(A) get_size_arch(A)
#define ARCH_FILL(A, B, C) populate_arch(A, B, C)
#define ARCH_ADJUST(A, B, C, D) adjust_arch(A, B, C, D)
#define STOP_NATIVE_FLAGS(A, B) A->insts[B].nat_flags_op = NAT_FLAG_OP_UNUSABLE
#define ARCH_UNALIGNED(A, B) arch_unaligned(A, B)
extern uint32_t arm64_crc(void* p, uint32_t len);
extern uint32_t arm64_x31_hash(void* p, uint32_t len);
#define ARCH_CRC(A, B) if(cpuext.crc32) return arm64_crc(A, B); else return arm64_x31_hash(A, B)
extern void* create_updateflags();
#define ARCH_UPDATEFLAGS() create_updateflags()
#define ADDITIONNAL_CHECKS() additionnal_checks(dyn, ninst);
#define ARCH_CRC_INLINE
extern void arm64_next_invalid();
#define ARCH_NOP 0b11010101000000110010000000011111
#define ARCH_UDF 0xcafe
#define JMPNEXT_SIZE (4*sizeof(void*))
#elif defined(LA64)
#define instruction_native_t instruction_la64_t
#define dynarec_native_t dynarec_la64_t
#define extcache_native_t lsxcache_t
#define ADDITIONNAL_DEFINITION() \
int fpuCacheNeedsTransform(dynarec_native_t* dyn, int ninst);
#define OTHER_CACHE() \
if (fpuCacheNeedsTransform(dyn, ninst)) ret |= 2;
#include "la64/la64_printer.h"
#include "la64/dynarec_la64_private.h"
#include "la64/dynarec_la64_functions.h"
// Limit here is unconditionnal jump, that is signed 28bits
#define MAXBLOCK_SIZE ((1 << 27) - 200)
#define RAZ_SPECIFIC(A, N)
#define UPDATE_SPECIFICS(A) propagateFpuBarrier(A)
#define PREUPDATE_SPECIFICS(A) updateNativeFlags(A)
#define POSTUPDATE_SPECIFICS(A)
#define ARCH_SIZE(A) 0
#define ARCH_FILL(A, B, C) NULL
#define ARCH_ADJUST(A, B, C, D) {}
#define STOP_NATIVE_FLAGS(A, B) {}
#define ARCH_UNALIGNED(A, B) 0
extern uint32_t la64_crc(void* p, uint32_t len);
#define instruction_native_t instruction_la64_t
#define dynarec_native_t dynarec_la64_t
#define extcache_native_t lsxcache_t
#define ADDITIONNAL_DEFINITION() \
int fpuCacheNeedsTransform(dynarec_native_t* dyn, int ninst);
#define OTHER_CACHE() \
if (fpuCacheNeedsTransform(dyn, ninst)) ret |= 2;
#include "la64/la64_printer.h"
#include "la64/dynarec_la64_private.h"
#include "la64/dynarec_la64_functions.h"
// Limit here is unconditionnal jump, that is signed 28bits
#define MAXBLOCK_SIZE ((1 << 27) - 200)
#define RAZ_SPECIFIC(A, N)
#define UPDATE_SPECIFICS(A) propagateFpuBarrier(A)
#define PREUPDATE_SPECIFICS(A) updateNativeFlags(A)
#define POSTUPDATE_SPECIFICS(A)
#define ARCH_SIZE(A) 0
#define ARCH_FILL(A, B, C) NULL
#define ARCH_ADJUST(A, B, C, D) {}
#define STOP_NATIVE_FLAGS(A, B) {}
#define ARCH_UNALIGNED(A, B) 0
extern uint32_t la64_crc(void* p, uint32_t len);
extern void la64_crc_autocrc(); // same as la64_crc, but not using regular ABI
#define ARCH_CRC(A, B) return la64_crc(A, B)
#define ARCH_NOP (0b0000001101<<22)
#define ARCH_UDF 0b1010100
#define JMPNEXT_SIZE (4*sizeof(void*))
#define ADDITIONNAL_CHECKS()
#define ARCH_CRC_INLINE
extern void la64_next_invalid();
#elif defined(RV64)
#define instruction_native_t instruction_rv64_t
#define dynarec_native_t dynarec_rv64_t
#define extcache_native_t extcache_t
#define ADDITIONNAL_DEFINITION() \
int fpuCacheNeedsTransform(dynarec_native_t* dyn, int ninst); \
int sewNeedsTransform(dynarec_rv64_t* dyn, int ninst);
#define OTHER_CACHE() \
if (fpuCacheNeedsTransform(dyn, ninst)) ret |= 2; \
if (sewNeedsTransform(dyn, ninst)) ret |= 4;
#include "rv64/rv64_printer.h"
#include "rv64/dynarec_rv64_private.h"
#include "rv64/dynarec_rv64_functions.h"
#include "rv64/dynarec_rv64_arch.h"
// Limit here is unconditionnal jump, that is signed 21bits
#define MAXBLOCK_SIZE ((1<<20)-200)
#define RAZ_SPECIFIC(A, N)
#define UPDATE_SPECIFICS(A)
#define PREUPDATE_SPECIFICS(A) updateNativeFlags(A)
#define POSTUPDATE_SPECIFICS(A)
#define ARCH_SIZE(A) get_size_arch(A)
#define ARCH_FILL(A, B, C) populate_arch(A, B, C)
#define ARCH_ADJUST(A, B, C, D) {}
#define STOP_NATIVE_FLAGS(A, B) {}
#define instruction_native_t instruction_rv64_t
#define dynarec_native_t dynarec_rv64_t
#define extcache_native_t extcache_t
#define ADDITIONNAL_DEFINITION() \
int fpuCacheNeedsTransform(dynarec_native_t* dyn, int ninst); \
int sewNeedsTransform(dynarec_rv64_t* dyn, int ninst);
#define OTHER_CACHE() \
if (fpuCacheNeedsTransform(dyn, ninst)) ret |= 2; \
if (sewNeedsTransform(dyn, ninst)) ret |= 4;
#include "rv64/rv64_printer.h"
#include "rv64/dynarec_rv64_private.h"
#include "rv64/dynarec_rv64_functions.h"
#include "rv64/dynarec_rv64_arch.h"
// Limit here is unconditionnal jump, that is signed 21bits
#define MAXBLOCK_SIZE ((1<<20)-200)
#define RAZ_SPECIFIC(A, N)
#define UPDATE_SPECIFICS(A)
#define PREUPDATE_SPECIFICS(A) updateNativeFlags(A)
#define POSTUPDATE_SPECIFICS(A)
#define ARCH_SIZE(A) get_size_arch(A)
#define ARCH_FILL(A, B, C) populate_arch(A, B, C)
#define ARCH_ADJUST(A, B, C, D) {}
#define STOP_NATIVE_FLAGS(A, B) {}
#define ARCH_UNALIGNED(A, B) arch_unaligned(A, B)
#define ARCH_NOP 0b0010011
#define ARCH_UDF 0xc0001073
#define JMPNEXT_SIZE (4*sizeof(void*))
#define ADDITIONNAL_CHECKS()
#elif defined(PPC64LE)
#define instruction_native_t instruction_ppc64le_t
#define dynarec_native_t dynarec_ppc64le_t
#define extcache_native_t vmxcache_t
#define ADDITIONNAL_DEFINITION() \
int fpuCacheNeedsTransform(dynarec_native_t* dyn, int ninst);
#define OTHER_CACHE() \
if (fpuCacheNeedsTransform(dyn, ninst)) ret |= 2;
#include "ppc64le/ppc64le_printer.h"
#include "ppc64le/dynarec_ppc64le_private.h"
#include "ppc64le/dynarec_ppc64le_functions.h"
#include "ppc64le/dynarec_ppc64le_arch.h"
// Limit here is unconditional branch (I-form), signed 26bits (24-bit field << 2), so ±32MB
#define MAXBLOCK_SIZE ((1 << 24) - 200)
#define RAZ_SPECIFIC(A, N)
#define UPDATE_SPECIFICS(A) propagateFpuBarrier(A)
#define PREUPDATE_SPECIFICS(A) updateNativeFlags(A)
#define POSTUPDATE_SPECIFICS(A)
#define ARCH_SIZE(A) get_size_arch(A)
#define ARCH_FILL(A, B, C) populate_arch(A, B, C)
#define ARCH_ADJUST(A, B, C, D) adjust_arch(A, B, C, D)
#define STOP_NATIVE_FLAGS(A, B) {}
#define ARCH_UNALIGNED(A, B) arch_unaligned(A, B)
extern uint32_t ppc64le_fast_hash(void* p, uint32_t len);
#define ARCH_CRC(A, B) return ppc64le_fast_hash(A, B)
#define ARCH_NOP 0x60000000 /* ori 0,0,0 */
#define ARCH_UDF 0x00000000 /* illegal instruction (all zeros) */
// PPC64LE CreateJmpNext needs 5 instructions (20 bytes) for PC-relative load + branch,
// so the jmpnext area needs 5 void* slots (40 bytes) instead of the default 4 (32 bytes).
#define JMPNEXT_SIZE (5*sizeof(void*))
#define ADDITIONNAL_CHECKS()
#else
#error Unsupported platform
#endif
#include "dynacache_reloc.h"
#endif //__DYNAREC_ARCH__H_
#error Unsupported platform
#endif
#include "dynacache_reloc.h"
#endif //__DYNAREC_ARCH__H_
+9 -1
View File
@@ -207,10 +207,16 @@
#define SMDMB() DMB_ISH()
#endif
#ifndef PREFLAGSNEEDED
#define PREFLAGSNEEDED()
#endif
#define AREFLAGSNEEDED() \
PREFLAGSNEEDED() \
if((dyn->insts[ninst].x64.need_before&~X_PEND) && (!ninst || dyn->insts[ninst-1].x64.has_callret)) { \
READFLAGS(dyn->insts[ninst].x64.need_before&~X_PEND); \
}
} \
ADDITIONNAL_CHECKS()
// Insert a Secondary Entry Point if it's asked, but only on block that are from file mapped memory (so some binary file)
// and that are not flagged as always_test (as this could slow down a bit, and the block is unsafe), unless SEP level 2 is asked
@@ -225,6 +231,8 @@ int is_addr_autosmc(uintptr_t addr);
#include "la64/dynarec_la64_helper.h"
#elif defined(RV64)
#include "rv64/dynarec_rv64_helper.h"
#elif defined(PPC64LE)
#include "ppc64le/dynarec_ppc64le_helper.h"
#else
#error Unsupported architecture
#endif
+52 -18
View File
@@ -18,6 +18,7 @@
#include "x64trace.h"
#include "dynablock.h"
#include "dynablock_private.h"
#include "alternate.h"
#include "dynarec_native.h"
#include "dynarec_arch.h"
@@ -402,6 +403,7 @@ dynablock_t* CreateEmptyBlock(uintptr_t addr, int is32bits, int is_new) {
memset(block, 0, sizeof(dynablock_t));
// fill the block
block->x64_addr = (void*)addr;
block->x64_readaddr = addr;
block->isize = 0;
block->done = 0;
block->size = sz;
@@ -417,7 +419,7 @@ dynablock_t* CreateEmptyBlock(uintptr_t addr, int is32bits, int is_new) {
return block;
}
dynablock_t* FillBlock64(uintptr_t addr, int alternate, int is32bits, int inst_max, int is_new) {
dynablock_t* FillBlock64(uintptr_t addr, int is32bits, int inst_max, int is_new, int noalt) {
/*
A Block must have this layout:
@@ -432,15 +434,32 @@ dynablock_t* FillBlock64(uintptr_t addr, int alternate, int is32bits, int inst_m
C .. C+sz : arch: arch specific info (likes flags info) per inst (can be absent)
*/
const uint32_t req_prot = (box64_pagesize==4096)?(PROT_EXEC|PROT_READ):PROT_READ;
uintptr_t old_addr = addr;
#ifdef HAVE_ALTJUMP
uintptr_t altjump = noalt?0:getAlternateJump((void*)addr, is32bits);
if(altjump) {
dynarec_log(LOG_INFO, "Building a Dynablock for %p with an alternate content at %p\n", (void*)addr, (void*)altjump);
addr = altjump;
}
#else
uintptr_t altjump = 0;
#endif
if(addr>=BOX64ENV(nodynarec_start) && addr<BOX64ENV(nodynarec_end)) {
dynarec_log(LOG_INFO, "Create empty block in no-dynarec zone\n");
return BOX64ENV(nodynarec_delay)?NULL:CreateEmptyBlock(addr, is32bits, is_new);
return BOX64ENV(nodynarec_delay)?NULL:CreateEmptyBlock(old_addr, is32bits, is_new);
}
int is_inhotpage = checkInHotPage(addr);
if(is_inhotpage && !BOX64ENV(dynarec_dirty)) {
dynarec_log(LOG_DEBUG, "Not creating dynablock at %p as in a HotPage\n", (void*)addr);
return NULL;
}
#ifndef _WIN32
if((getProtection_fast(addr)&req_prot)!=req_prot) {// cannot be run, get out of the Dynarec
dynarec_log(LOG_DEBUG, "Not creating dynablock at %p because EXEC protection is missing\n", (void*)addr);
return NULL;
}
#endif
if(current_helper) {
if(current_helper==redundant_helper) {
dynarec_log(LOG_INFO, "%04d|Warning: previous FillBlock did not cleaned up correctly (helper=%p, x64addr=%p, db=%p)\n", GetTID(), current_helper, (void*)((dynarec_native_t*)current_helper)->start, ((dynarec_native_t*)current_helper)->dynablock);
@@ -468,6 +487,9 @@ dynablock_t* FillBlock64(uintptr_t addr, int alternate, int is32bits, int inst_m
helper.next_cap = MAX_INSTS;
helper.table64 = NULL;
helper.env = GetCurEnvByAddr(addr);
if(getProtection(addr)&PROT_NEVERCLEAN) {
helper.always_test = 1;
}
ResetTable64(&helper);
helper.table64cap = 0;
helper.end = addr + SizeFileMapped(addr);
@@ -508,12 +530,13 @@ dynablock_t* FillBlock64(uintptr_t addr, int alternate, int is32bits, int inst_m
case BUILD_INIT:
state = BUILD_PASS0;
if (SigSetJmp(GET_JUMPBUFF(dynarec_jmpbuf), 1)) {
if(state==BUILD_PASS0 && dyn->size>1) {
if(state==BUILD_PASS0 && helper.size>1) {
end = helper.insts[helper.size].x64.addr;
--helper.size;
printf_log(LOG_INFO, "FillBlock at %p triggered a segfault, truncating at %d\n", (void*)addr, helper.size);
state = BUILD_PASS1;
} else {
printf_log(LOG_INFO, "FillBlock at %p triggered a segfault, canceling\n", (void*)addr);
printf_log(LOG_INFO, "FillBlock at %p triggered a segfault (state=%d, size=%d), canceling\n", (void*)addr, state, helper.size);
state = BUILD_ABORT_EMPTY;
}
} else
@@ -524,10 +547,10 @@ dynablock_t* FillBlock64(uintptr_t addr, int alternate, int is32bits, int inst_m
return NULL;
case BUILD_ABORT_EMPTY:
CancelBlock64(0);
return CreateEmptyBlock(addr, is32bits, is_new);
return CreateEmptyBlock(old_addr, is32bits, is_new);
case BUILD_PASS0:
// pass 0, addresses, x64 jump addresses, overall size of the block
end = native_pass0(&helper, addr, alternate, is32bits, inst_max);
end = native_pass0(&helper, addr, altjump?1:0, is32bits, inst_max);
if(helper.abort) {
if(helper.size<2) {
if(dyn->need_dump || BOX64ENV(dynarec_log))dynarec_log(LOG_NONE, "Abort dynablock on pass0\n");
@@ -659,7 +682,7 @@ dynablock_t* FillBlock64(uintptr_t addr, int alternate, int is32bits, int inst_m
// NULL block after removing dead code, how is that possible?
dynarec_log(LOG_INFO, "Warning, null-sized dynarec block after trimming dead code (%p)\n", (void*)addr);
CancelBlock64(0);
return CreateEmptyBlock(addr, is32bits, is_new);
return CreateEmptyBlock(old_addr, is32bits, is_new);
}
UPDATE_SPECIFICS(&helper);
// check for still valid close loop
@@ -679,7 +702,7 @@ dynablock_t* FillBlock64(uintptr_t addr, int alternate, int is32bits, int inst_m
ResetTable64(&helper);
helper.reloc_size = 0;
// pass 1, float optimizations, first pass for flags
native_pass1(&helper, addr, alternate, is32bits, inst_max);
native_pass1(&helper, addr, altjump?1:0, is32bits, inst_max);
if(helper.abort) {
if(dyn->need_dump || BOX64ENV(dynarec_log))dynarec_log(LOG_NONE, "Abort dynablock on pass1\n");
state = BUILD_ABORT_NULL;
@@ -697,7 +720,7 @@ dynablock_t* FillBlock64(uintptr_t addr, int alternate, int is32bits, int inst_m
helper.reloc_size = 0;
// pass 2, instruction size
helper.callrets = static_callrets;
native_pass2(&helper, addr, alternate, is32bits, inst_max);
native_pass2(&helper, addr, altjump?1:0, is32bits, inst_max);
if(helper.abort) {
if(dyn->need_dump || BOX64ENV(dynarec_log))dynarec_log(LOG_NONE, "Abort dynablock on pass2\n");
state = BUILD_ABORT_NULL;
@@ -720,7 +743,7 @@ dynablock_t* FillBlock64(uintptr_t addr, int alternate, int is32bits, int inst_m
--imax;
if(dyn->need_dump || BOX64ENV(dynarec_log))dynarec_log(LOG_NONE, "Dynablock oversized, with %zu (max=%zd), recomputing cutting at %d from %d\n", native_size, MAXBLOCK_SIZE, imax, helper.size);
CancelBlock64(0);
return FillBlock64(addr, alternate, is32bits, imax, is_new);
return FillBlock64(old_addr, is32bits, imax, is_new, noalt);
}
insts_rsize = (helper.insts_size+2)*sizeof(instsize_t);
insts_rsize = (insts_rsize+7)&~7; // round the size...
@@ -733,7 +756,7 @@ dynablock_t* FillBlock64(uintptr_t addr, int alternate, int is32bits, int inst_m
dynablock_align = (sz&7)?(8 -(sz&7)):0; // align dynablock
sz += dynablock_align + sizeof(dynablock_t) + reloc_size;
// dynablock_t* block (arm insts) table64 jmpnext code instsize arch callrets sep dynablock relocs
actual_p = (void*)AllocDynarecMap(addr, sz, is_new);
actual_p = (void*)AllocDynarecMap(old_addr, sz, is_new);
if(actual_p==NULL) {
dynarec_log(LOG_INFO, "AllocDynarecMap(%p, %zu) failed, canceling block\n", (void*)addr, sz);
state = BUILD_ABORT_NULL;
@@ -752,6 +775,7 @@ dynablock_t* FillBlock64(uintptr_t addr, int alternate, int is32bits, int inst_m
void* relocs = helper.need_reloc?(block+1):NULL;
// fill the block
block->x64_addr = (void*)addr;
block->x64_readaddr = addr;
block->isize = 0;
block->actual_block = actual_p;
helper.relocs = relocs;
@@ -768,6 +792,7 @@ dynablock_t* FillBlock64(uintptr_t addr, int alternate, int is32bits, int inst_m
helper.sep = (sep_t*)seps;
block->prefixsize = helper.prefixsize;
block->table64 = helper.table64;
helper.dynablock = block;
if(callret_size)
memcpy(helper.callrets, static_callrets, helper.callret_size*sizeof(callret_t));
helper.callret_size = 0;
@@ -789,7 +814,7 @@ dynablock_t* FillBlock64(uintptr_t addr, int alternate, int is32bits, int inst_m
ResetTable64(&helper); // reset table64 (but not the cap)
helper.insts_size = 0; // reset
helper.reloc_size = 0;
native_pass3(&helper, addr, alternate, is32bits, inst_max);
native_pass3(&helper, addr, altjump?1:0, is32bits, inst_max);
if(helper.abort) {
if(dyn->need_dump || BOX64ENV(dynarec_log))dynarec_log(LOG_NONE, "Abort dynablock on pass3\n");
state = BUILD_ABORT_NULL;
@@ -810,7 +835,13 @@ dynablock_t* FillBlock64(uintptr_t addr, int alternate, int is32bits, int inst_m
block->isize = helper.size;
block->block = p;
block->jmpnext = next+sizeof(void*);
#ifdef ARCH_CRC_INLINE
block->always_test = 0;
block->autocrc = helper.always_test?1:0;
#else
block->always_test = helper.always_test;
block->autocrc = 0;
#endif
block->dirty = block->always_test;
block->is32bits = is32bits;
block->relocsize = helper.reloc_size*sizeof(uint32_t);
@@ -847,10 +878,10 @@ dynablock_t* FillBlock64(uintptr_t addr, int alternate, int is32bits, int inst_m
#endif
}
ClearCache(actual_p+sizeof(void*), native_size); // need to clear the cache before execution...
block->hash = X31_hash_code(block->x64_addr, block->x64_size);
block->hash = X31_hash_code((void*)block->x64_readaddr, block->x64_size);
// Check if something changed, to abort if it is
if((helper.abort || (block->hash != hash))) {
dynarec_log(LOG_DEBUG, "Warning, a block changed while being processed hash(%p:%ld)=%x/%x\n", block->x64_addr, block->x64_size, block->hash, hash);
dynarec_log(LOG_DEBUG, "Warning, a block changed while being processed hash(%p:%ld)=%x/%x\n", block->x64_readaddr, block->x64_size, block->hash, hash);
state = BUILD_ABORT_NULL;
continue;
}
@@ -887,11 +918,13 @@ dynablock_t* FillBlock64(uintptr_t addr, int alternate, int is32bits, int inst_m
block->dirty = 1;
//protectDB(addr, end-addr);
}
if(getProtection(addr)&PROT_NEVERCLEAN) {
block->always_test = 1;
}
else if(is_inhotpage)
#ifdef ARCH_CRC_INLINE
if(is_inhotpage && !block->autocrc)
block->always_test = 2;
#else
if(is_inhotpage)
block->always_test = 2;
#endif
if(block->always_test) {
dynarec_log(LOG_INFO, "Note: block marked as always dirty %p:%ld\n", block->x64_addr, block->x64_size);
#ifdef ARCH_NOP
@@ -903,6 +936,7 @@ dynablock_t* FillBlock64(uintptr_t addr, int alternate, int is32bits, int inst_m
}
#endif
}
if(altjump) block->x64_addr = (void*)old_addr; // set the not-alt addr if a shadow jump was used
redundant_helper = current_helper = NULL;
//block->done = 1;
return block;
+43 -5
View File
@@ -755,7 +755,7 @@ static int flagsCacheNeedsTransform(dynarec_native_t* dyn, int ninst) {
int jmp = dyn->insts[ninst].x64.jmp_insts;
if(jmp<0)
return 0;
#if defined(ARM64) || defined(LA64)
#if defined(ARM64) || defined(LA64) || defined(PPC64LE)
// df_none is now a defered information
if(dyn->insts[ninst].f_exit==dyn->insts[jmp].f_entry)
return 0;
@@ -856,22 +856,60 @@ uint8_t geted_ib(dynarec_native_t* dyn, uintptr_t addr, int ninst, uint8_t nexto
}
#undef F8
void propagate_nodf(dynarec_native_t* dyn, int ninst)
#if defined(ARM64) || defined(LA64) || defined(PPC64LE)
static void propagate_dfneeded_internal(dynarec_native_t* dyn, int ninst)
{
while(ninst>=0) {
if(dyn->insts[ninst].df_needed)
return; // already flagged
dyn->insts[ninst].df_needed = 1;
if(dyn->insts[ninst].x64.gen_flags || (dyn->insts[ninst].x64.use_flags&X_PEND) || (dyn->insts[ninst].x64.need_before))
return; // flags are use, we can stop propagate there
if(!dyn->insts[ninst].pred_sz)
return;
for(int i=1; i<dyn->insts[ninst].pred_sz; ++i)
propagate_dfneeded_internal(dyn, dyn->insts[ninst].pred[i]);
ninst = dyn->insts[ninst].pred[0];
}
}
static void propagate_nodf_internal(dynarec_native_t* dyn, int ninst)
{
while(ninst>=0) {
if(dyn->insts[ninst].df_needed)
return; // flag are needed, stop
if(dyn->insts[ninst].df_notneeded)
return; // already flagged
if(dyn->insts[ninst].x64.gen_flags || dyn->insts[ninst].x64.use_flags)
return; // flags are use, so maybe it's needed
if(dyn->insts[ninst].x64.has_callret || (dyn->insts[ninst].x64.barrier&BARRIER_FLAGS))
return; // stop propagate
dyn->insts[ninst].df_notneeded = 1;
if(!dyn->insts[ninst].pred_sz)
return;
for(int i=1; i<dyn->insts[ninst].pred_sz; ++i)
propagate_nodf(dyn, dyn->insts[ninst].pred[i]);
propagate_nodf_internal(dyn, dyn->insts[ninst].pred[i]);
ninst = dyn->insts[ninst].pred[0];
}
}
void propagate_nodf(dynarec_native_t* dyn)
{
// first propagate the df_needed flag
for(int ninst=dyn->size-1; ninst>=0; --ninst) {
if((dyn->insts[ninst].x64.jmp && dyn->insts[ninst].x64.jmp_insts==-1)
|| (dyn->insts[ninst].x64.barrier&BARRIER_FLAGS) || (dyn->insts[ninst].x64.use_flags)
|| dyn->insts[ninst].x64.has_callret
|| ((dyn->insts[ninst].x64.state_flags&SF_SUB) && dyn->insts[ninst].x64.need_before)
)
propagate_dfneeded_internal(dyn, ninst);
}
// and now propagete df_unneeded
for(int ninst=dyn->size-1; ninst>=0; --ninst) {
if(dyn->insts[ninst].f_exit!=status_unk && dyn->insts[ninst].x64.gen_flags)
propagate_nodf_internal(dyn, ninst);
}
}
#endif
void x64disas_add_register_mapping_annotations(char* buf, const char* disas, const register_mapping_t* mappings, size_t mappings_sz)
{
static char tmp[32];
+1 -1
View File
@@ -71,7 +71,7 @@ void native_div0(x64emu_t* emu);
// Caches transformation (for loops) // Specific, need to be written par backend
int CacheNeedsTransform(dynarec_native_t* dyn, int i1);
// propagete defererd to unknow, as state is not needed
void propagate_nodf(dynarec_native_t* dyn, int ninst);
void propagate_nodf(dynarec_native_t* dyn);
// predecessor access
int isPred(dynarec_native_t* dyn, int ninst, int pred);
+15 -8
View File
@@ -65,7 +65,7 @@ uintptr_t native_pass(dynarec_native_t* dyn, uintptr_t addr, int alternate, int
int rep = 0; // 0 none, 1=F2 prefix, 2=F3 prefix
int need_epilog = 1;
// Clean up (because there are multiple passes)
#if defined(ARM64) || defined(LA64)
#if defined(ARM64) || defined(LA64) || defined(PPC64LE)
dyn->f = status_unk;
#else
dyn->f.pending = 0;
@@ -127,17 +127,24 @@ uintptr_t native_pass(dynarec_native_t* dyn, uintptr_t addr, int alternate, int
if(!ninst) {
if(dyn->have_purge)
doEnterBlock(dyn, 0, x1, x2, x3);
if(dyn->always_test)
checkCRC(dyn, 0);
if(dyn->insts[0].preload_xmmymm)
doPreload(dyn, 0);
ENDPREFIX;
}
#elif defined(LA64)
if(!ninst) {
if(dyn->always_test)
checkCRC(dyn, 0);
}
#endif
fpu_propagate_stack(dyn, ninst);
if (reset_n!=-1) {
dyn->last_ip = 0;
if(reset_n==-2) {
MESSAGE(LOG_DEBUG, "Reset Caches to zero\n");
#if defined(ARM64) || defined(LA64)
#if defined(ARM64) || defined(LA64) || defined(PPC64LE)
dyn->f = status_unk;
#else
dyn->f.dfnone = 0;
@@ -154,7 +161,7 @@ uintptr_t native_pass(dynarec_native_t* dyn, uintptr_t addr, int alternate, int
}
if(dyn->insts[ninst].x64.barrier&BARRIER_FLAGS) {
MESSAGE(LOG_DEBUG, "Apply Barrier Flags\n");
#if defined(ARM64) || defined(LA64)
#if defined(ARM64) || defined(LA64) || defined(PPC64LE)
dyn->f = status_unk;
#else
dyn->f.dfnone = 0;
@@ -278,7 +285,7 @@ uintptr_t native_pass(dynarec_native_t* dyn, uintptr_t addr, int alternate, int
#if STEP > 0
if(dyn->insts[ninst].x64.has_next && dyn->insts[next].x64.barrier) {
if(dyn->insts[next].x64.barrier&BARRIER_FLOAT) {
#if defined (RV64) || defined(LA64)
#if defined (RV64) || defined(LA64) || defined(PPC64LE)
uint8_t tmp1, tmp2, tmp3;
if(dyn->insts[next].nat_flags_fusion) get_free_scratch(dyn, next, &tmp1, &tmp2, &tmp3, x1, x2, x3, x4, x5);
else { tmp1=x1; tmp2=x2; tmp3=x3; }
@@ -288,7 +295,7 @@ uintptr_t native_pass(dynarec_native_t* dyn, uintptr_t addr, int alternate, int
#endif
}
if(dyn->insts[next].x64.barrier&BARRIER_FLAGS) {
#if defined(ARM64) || defined(LA64)
#if defined(ARM64) || defined(LA64) || defined(PPC64LE)
dyn->f = status_unk;
#else
dyn->f.pending = 0;
@@ -314,7 +321,7 @@ uintptr_t native_pass(dynarec_native_t* dyn, uintptr_t addr, int alternate, int
// we use the 1st predecessor here
if((ninst+1)<dyn->size && !dyn->insts[ninst+1].x64.alive) {
// reset fpu value...
#if defined(ARM64) || defined(LA64)
#if defined(ARM64) || defined(LA64) || defined(PPC64LE)
dyn->f = status_unk;
#else
dyn->f.dfnone = 0;
@@ -468,7 +475,7 @@ uintptr_t native_pass(dynarec_native_t* dyn, uintptr_t addr, int alternate, int
#endif
++ninst;
NOTEST(x3);
#if defined (RV64) || defined(LA64)
#if defined (RV64) || defined(LA64) || defined(PPC64LE)
fpu_purgecache(dyn, ninst, 0, x1, x2, x3);
#else
fpu_purgecache(dyn, ninst, 0, x1, x2, x3, 0);
@@ -479,7 +486,7 @@ uintptr_t native_pass(dynarec_native_t* dyn, uintptr_t addr, int alternate, int
}
if(need_epilog) {
NOTEST(x3);
#if defined (RV64) || defined(LA64)
#if defined (RV64) || defined(LA64) || defined(PPC64LE)
fpu_purgecache(dyn, ninst, 0, x1, x2, x3);
#else
fpu_purgecache(dyn, ninst, 0, x1, x2, x3, 0);
+7
View File
@@ -26,6 +26,13 @@ void rv64_epilog_fast(void) EXPORTDYN;
#define native_prolog rv64_prolog
#define native_epilog rv64_epilog
#define native_epilog_fast rv64_epilog_fast
#elif defined(PPC64LE)
void ppc64le_next(void) EXPORTDYN;
void ppc64le_prolog(x64emu_t* emu, void* addr) EXPORTDYN;
void ppc64le_epilog(void) EXPORTDYN;
#define native_next ppc64le_next
#define native_prolog ppc64le_prolog
#define native_epilog ppc64le_epilog
#else
#error Unsupported architecture
#endif
+27 -6
View File
@@ -16,6 +16,7 @@
#include "callback.h"
#include "bridge.h"
#include "emu/x64run_private.h"
#include "../dynablock_private.h"
#include "x64trace.h"
#include "dynarec_native.h"
#include "custommem.h"
@@ -787,7 +788,7 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
GETGD;
GETED(4);
i64 = F32S;
MOV64xw(x4, i64);
MOV64x(x4, i64);
CLEAR_FLAGS(x3);
if (rex.w) {
UFLAG_IF {
@@ -3381,7 +3382,10 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
// Push actual return address
if (addr < (dyn->start + dyn->isize)) {
// there is a next...
j64 = (dyn->insts) ? (dyn->insts[ninst].epilog - (dyn->native_size)) : 0;
if(BOX64DRENV(dynarec_callret)>1 && !dyn->always_test)
j64 = CALLRET_GETRET();
else
j64 = (dyn->insts) ? (dyn->insts[ninst].epilog - (dyn->native_size)) : 0;
PCADDU12I(x4, ((j64 + 0x800) >> 12) & 0xfffff);
ADDI_D(x4, x4, j64 & 0xfff);
MESSAGE(LOG_NONE, "\tCALLRET set return to +%di\n", j64 >> 2);
@@ -3403,6 +3407,8 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
else
j64 = addr + i32;
jump_to_next(dyn, j64, 0, ninst, rex.is32bits);
int can_continue = (addr < (dyn->start + dyn->isize));
CALLRET_RET(can_continue);
if (BOX64DRENV(dynarec_callret) && addr >= (dyn->start + dyn->isize)) {
// jumps out of current dynablock...
MARK;
@@ -3416,6 +3422,7 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
LD_D(x4, x4, 0);
BR(x4);
}
CLEARIP();
break;
}
break;
@@ -4016,7 +4023,10 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
// Push actual return address
if (addr < (dyn->start + dyn->isize)) {
// there is a next
j64 = (dyn->insts) ? (dyn->insts[ninst].epilog - (dyn->native_size)) : 0;
if(BOX64DRENV(dynarec_callret)>1 && !dyn->always_test)
j64 = CALLRET_GETRET();
else
j64 = (dyn->insts) ? (dyn->insts[ninst].epilog - (dyn->native_size)) : 0;
PCADDU12I(x4, ((j64 + 0x800) >> 12) & 0xfffff);
ADDI_D(x4, x4, j64 & 0xfff);
MESSAGE(LOG_NONE, "\tCALLRET set return to +%di\n", j64 >> 2);
@@ -4032,6 +4042,8 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
}
PUSH1z(xRIP);
jump_to_next(dyn, 0, ed, ninst, rex.is32bits);
int can_continue = (addr < (dyn->start + dyn->isize));
CALLRET_RET(can_continue);
if (BOX64DRENV(dynarec_callret) && addr >= (dyn->start + dyn->isize)) {
// jumps out of current dynablock...
MARK;
@@ -4041,6 +4053,7 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
LD_D(x4, x4, 0);
BR(x4);
}
CLEARIP();
break;
case 3: // CALL FAR Ed
if (MODREG) {
@@ -4063,17 +4076,24 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
*ok = 0;
}
GETIP_(addr, x7);
int can_continue = (addr < (dyn->start + dyn->isize));
if (BOX64DRENV(dynarec_callret)) {
SET_HASCALLRET();
// Push actual return address. Note that CS will not be tested, but that should be ok?
if (addr < (dyn->start + dyn->isize)) {
if (can_continue) {
// there is a next...
j64 = (dyn->insts) ? (dyn->insts[ninst].epilog - (dyn->native_size)) : 0;
if(BOX64DRENV(dynarec_callret)>1 && !dyn->always_test)
j64 = CALLRET_GETRET();
else
j64 = (dyn->insts) ? (dyn->insts[ninst].epilog - (dyn->native_size)) : 0;
PCADDU12I(x4, ((j64 + 0x800) >> 12) & 0xfffff);
ADDI_D(x4, x4, j64 & 0xfff);
MESSAGE(LOG_NONE, "\tCALLRET set return to +%di\n", j64 >> 2);
} else {
j64 = (dyn->insts) ? (GETMARK - (dyn->native_size)) : 0;
if(BOX64DRENV(dynarec_callret)>1 && !dyn->always_test)
j64 = CALLRET_GETRET();
else
j64 = (dyn->insts) ? (GETMARK - (dyn->native_size)) : 0;
PCADDU12I(x4, ((j64 + 0x800) >> 12) & 0xfffff);
ADDI_D(x4, x4, j64 & 0xfff);
MESSAGE(LOG_NONE, "\tCALLRET set return to +%di\n", j64 >> 2);
@@ -4091,6 +4111,7 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
}
ST_H(x3, xEmu, offsetof(x64emu_t, segs[_CS]));
jump_to_next(dyn, 0, ed, ninst, rex.is32bits);
CALLRET_RET(can_continue);
if (BOX64DRENV(dynarec_callret) && addr >= (dyn->start + dyn->isize)) {
// jumps out of current dynablock...
MARK;
+79 -18
View File
@@ -79,6 +79,31 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
}
} else {
switch ((nextop >> 3) & 7) {
case 0:
INST_NAME("SGDT Ed");
addr = geted(dyn, addr, ninst, nextop, &ed, x3, x2, &fixedaddress, rex, NULL, 0, 0);
MOV32w(x1, 0x7f);
ST_H(x1, wback, 0);
if (rex.is32bits) {
MOV32w(x1, 0x3000);
ST_W(x1, wback, 2);
} else {
MOV64x(x1, 0xfffffe0000077000LL);
ST_D(x1, wback, 2);
}
break;
case 1:
INST_NAME("SIDT Ed");
addr = geted(dyn, addr, ninst, nextop, &ed, x3, x2, &fixedaddress, rex, NULL, 0, 0);
MOV32w(x1, 0xfff);
ST_H(x1, wback, 0);
if (rex.is32bits) {
ST_W(xZR, wback, 2);
} else {
MOV64x(x1, 0xfffffe0000000000LL);
ST_D(x1, wback, 2);
}
break;
default:
DEFAULT;
}
@@ -417,7 +442,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
} else {
INST_NAME("UCOMISS Gx, Ex");
}
SETFLAGS(X_ALL, SF_SET_DF, NAT_FLAGS_NOFUSION);
SETFLAGS(X_ALL, SF_SET, NAT_FLAGS_NOFUSION);
nextop = F8;
GETGX(d0, 0);
GETEXSS(v0, 0, 0);
@@ -903,7 +928,25 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
nextop = F8;
GETEX(q0, 0, 0);
GETGX(v0, 1);
if (!BOX64ENV(dynarec_fastnan)) {
v1 = fpu_get_scratch(dyn);
d0 = fpu_get_scratch(dyn);
d1 = fpu_get_scratch(dyn);
VFCMP_S(v1, q0, v0, cUN);
VFCMP_S(d0, v0, v0, cUN);
MOV32w(x5, 0x00400000);
VREPLGR2VR_W(d1, x5);
VOR_V(d1, v0, d1);
}
VFADD_S(v0, v0, q0);
if (!BOX64ENV(dynarec_fastnan)) {
VBITSEL_V(v0, v0, d1, d0);
VFCMP_S(d0, v0, v0, cUN);
VANDN_V(v1, v1, d0);
VLDI(d0, 0b011111111100);
VSLLI_W(d0, d0, 20);
VBITSEL_V(v0, v0, d0, v1);
}
break;
case 0x59:
INST_NAME("MULPS Gx, Ex");
@@ -913,17 +956,21 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
if (!BOX64ENV(dynarec_fastnan)) {
v0 = fpu_get_scratch(dyn);
v1 = fpu_get_scratch(dyn);
d0 = fpu_get_scratch(dyn);
VFCMP_S(v0, q0, q1, cUN);
VFCMP_S(d0, q1, q1, cUN);
MOV32w(x5, 0x00400000);
VREPLGR2VR_W(v1, x5);
VOR_V(v1, q1, v1);
}
VFMUL_S(q1, q1, q0);
if (!BOX64ENV(dynarec_fastnan)) {
VBITSEL_V(q1, q1, v1, d0);
VFCMP_S(v1, q1, q1, cUN);
VANDN_V(v0, v0, v1);
VLDI(v1, 0b011111111100); // broadcast 0xFFFFFFFFFFFFFFFC
VLDI(v1, 0b011111111100);
VSLLI_W(v1, v1, 20);
VAND_V(v1, v0, v1);
VANDN_V(v0, v0, q1);
VOR_V(q1, v0, v1);
VBITSEL_V(q1, q1, v1, v0);
}
break;
case 0x5A:
@@ -948,17 +995,21 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
if (!BOX64ENV(dynarec_fastnan)) {
v0 = fpu_get_scratch(dyn);
v1 = fpu_get_scratch(dyn);
d0 = fpu_get_scratch(dyn);
VFCMP_S(v0, q0, q1, cUN);
VFCMP_S(d0, q1, q1, cUN);
MOV32w(x5, 0x00400000);
VREPLGR2VR_W(v1, x5);
VOR_V(v1, q1, v1);
}
VFSUB_S(q1, q1, q0);
if (!BOX64ENV(dynarec_fastnan)) {
VBITSEL_V(q1, q1, v1, d0);
VFCMP_S(v1, q1, q1, cUN);
VANDN_V(v0, v0, v1);
VLDI(v1, 0b011111111100); // broadcast 0xFFFFFFFFFFFFFFFC
VLDI(v1, 0b011111111100);
VSLLI_W(v1, v1, 20);
VAND_V(v1, v0, v1);
VANDN_V(v0, v0, q1);
VOR_V(q1, v0, v1);
VBITSEL_V(q1, q1, v1, v0);
}
break;
case 0x5D:
@@ -978,17 +1029,21 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
if (!BOX64ENV(dynarec_fastnan)) {
v0 = fpu_get_scratch(dyn);
v1 = fpu_get_scratch(dyn);
d0 = fpu_get_scratch(dyn);
VFCMP_S(v0, q0, q1, cUN);
VFCMP_S(d0, q1, q1, cUN);
MOV32w(x5, 0x00400000);
VREPLGR2VR_W(v1, x5);
VOR_V(v1, q1, v1);
}
VFDIV_S(q1, q1, q0);
if (!BOX64ENV(dynarec_fastnan)) {
VBITSEL_V(q1, q1, v1, d0);
VFCMP_S(v1, q1, q1, cUN);
VANDN_V(v0, v0, v1);
VLDI(v1, 0b011111111100); // broadcast 0xFFFFFFFFFFFFFFFC
VLDI(v1, 0b011111111100);
VSLLI_W(v1, v1, 20);
VAND_V(v1, v0, v1);
VANDN_V(v0, v0, q1);
VOR_V(q1, v0, v1);
VBITSEL_V(q1, q1, v1, v0);
}
break;
case 0x5F:
@@ -1099,7 +1154,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
GETG;
v0 = mmx_get_reg_empty(dyn, ninst, x1, x2, x3, gd);
if (MODREG) {
ed = TO_NAT(nextop & 7);
ed = TO_NAT((nextop & 0x07) + (rex.b << 3));
if (rex.w) {
MOVGR2FR_D(v0, ed);
} else {
@@ -1941,13 +1996,16 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
}
BNE_MARK(ed, xZR);
IFX (X_ZF) ORI(xFlags, xFlags, 1 << F_ZF);
if (BOX64DRENV(dynarec_safeflags)) {
IFX (X_PF) ORI(xFlags, xFlags, 1 << F_PF);
}
B_MARK2_nocond;
MARK;
CTZxw(gd, ed);
MARK2;
IFX (BOX64DRENV(dynarec_safeflags)) {
if (BOX64DRENV(dynarec_safeflags)) {
IFX (X_PF) emit_pf(dyn, ninst, gd, x2, x5);
}
MARK2;
SPILL_EFLAGS();
break;
case 0xBD:
@@ -1968,15 +2026,18 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
}
BNE_MARK(ed, xZR);
IFX (X_ZF) ORI(xFlags, xFlags, 1 << F_ZF);
if (BOX64DRENV(dynarec_safeflags)) {
IFX (X_PF) ORI(xFlags, xFlags, 1 << F_PF);
}
B_MARK2_nocond;
MARK;
CLZxw(gd, ed);
ADDI_D(x1, xZR, rex.w ? 63 : 31);
SUB_D(gd, x1, gd);
MARK2;
if (BOX64DRENV(dynarec_safeflags)) {
IFX (X_PF) emit_pf(dyn, ninst, gd, x2, x5);
}
MARK2;
SPILL_EFLAGS();
break;
case 0xBE:
@@ -2035,8 +2096,8 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
GETED(0);
if (ed != gd) MV(x7, ed);
emit_add32(dyn, ninst, rex, ed, gd, x4, x5, x6);
if (ed != gd) MVxw(gd, x7);
WBACK;
if (ed != gd) MVxw(gd, x7);
break;
case 0xC2:
INST_NAME("CMPPS Gx, Ex, Ib");
+127 -56
View File
@@ -654,7 +654,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
INST_NAME("PCMPEQQ Gx, Ex"); // SSE4 opcode!
nextop = F8;
GETEX(q1, 0, 0);
GETGX_empty(q0);
GETGX(q0, 1);
VSEQ_D(q0, q0, q1);
break;
case 0x2A:
@@ -809,6 +809,25 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
GETGX(q0, 1);
VMUL_W(q0, q0, q1);
break;
case 0x41:
INST_NAME("PHMINPOSUW Gx, Ex");
nextop = F8;
GETEX(v1, 0, 0);
GETGX(v0, 1);
q0 = fpu_get_scratch(dyn);
q1 = fpu_get_scratch(dyn);
q2 = fpu_get_scratch(dyn);
// v1[a,b,c,d,e,f,g,h]
VSHUF4I_W(q0, v1, 0b01001110); // q0[e,f,g,h,a,b,c,d]
VMIN_HU(q1, v1, q0); // q1[ae,bf,cg,dh ...]
VSHUF4I_H(q2, q1, 0b10110001); // q2[bf,ae,dh,cg ...]
VMIN_HU(q1, q1, q2); // q1[aebf,aebf,cgdh,cgdh ...]
VSHUF4I_H(q0, q1, 0b01001110); // q0[cgdh,cgdh,aebf,aebf]
VMIN_HU(q2, q0, q1); // all lane is min(abcdefgh)
VSEQ_H(q0, q2, v1); // get mask(0xffff)
VFRSTPI_H(q2, q0, 1); // find first neg(0xffff),insert index to q2
XVPICKVE_W(v0, q2, 0);
break;
case 0xDB:
INST_NAME("AESIMC Gx, Ex"); // AES-NI
nextop = F8;
@@ -912,13 +931,13 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
SETFLAGS(X_CF, SF_SUBSET, NAT_FLAGS_NOFUSION);
GETED(0);
GETGD;
if(cpuext.lbt) {
X64_GET_EFLAGS(x3, X_CF); // CF pos is 0, no need SLLI
if (cpuext.lbt) {
X64_GET_EFLAGS(x3, X_CF); // CF pos is 0, no need SLLI
} else {
BSTRPICK_D(x3, xFlags, F_CF, F_CF);
}
IFX(X_CF) {
if(rex.w) {
IFX (X_CF) {
if (rex.w) {
ADD_D(x4, gd, ed);
SLTU(x5, x4, gd);
ADD_D(gd, x4, x3);
@@ -933,7 +952,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
SLTU(x6, gd, x4);
}
OR(x5, x5, x6);
if(cpuext.lbt) {
if (cpuext.lbt) {
X64_SET_EFLAGS(x5, X_CF);
} else {
BSTRINS_D(xFlags, x5, F_CF, F_CF);
@@ -1348,8 +1367,8 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
} else {
addr = geted(dyn, addr, ninst, nextop, &ed, x1, x2, &fixedaddress, rex, NULL, 0, 1);
}
MV(x2, xRDX);
MV(x4, xRAX);
SEXT_W(x2, xRDX);
SEXT_W(x4, xRAX);
u8 = F8;
MOV32w(x5, u8);
CALL6(const_sse42_compare_string_explicit_len, x1, ed, x2, x3, x4, x5, 0);
@@ -1379,7 +1398,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
ADDI_D(x1, xEmu, offsetof(x64emu_t, xmm[ed]));
ed = x1;
} else {
addr = geted(dyn, addr, ninst, nextop, &ed, x1, x2, &fixedaddress, rex, NULL, 0, 1);
addr = geted(dyn, addr, ninst, nextop, &ed, x1, x5, &fixedaddress, rex, NULL, 0, 1);
}
u8 = F8;
MOV32w(x3, u8);
@@ -1427,7 +1446,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
READFLAGS(F); \
tmp1 = x1; \
tmp3 = x3; \
if (cpuext.lbt) { \
if (cpuext.lbt) { \
X64_SETJ(x1, I); \
} else { \
GETFLAGS; \
@@ -1441,7 +1460,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
LD_HU(x4, ed, fixedaddress); \
ed = x4; \
} \
if (cpuext.lbt) \
if (cpuext.lbt) \
BEQZ(x1, 4 + 4); \
else \
B##NO(x1, 4 + 4); \
@@ -1522,17 +1541,22 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
if (!BOX64ENV(dynarec_fastnan)) {
v0 = fpu_get_scratch(dyn);
v1 = fpu_get_scratch(dyn);
VFCMP_D(v0, q0, q1, cUN);
d0 = fpu_get_scratch(dyn);
d1 = fpu_get_scratch(dyn);
VFCMP_D(v0, q1, q0, cUN);
VFCMP_D(d0, q1, q1, cUN);
VLDI(d1, (0b011 << 10) | 0b0000001000);
VSLLI_D(d1, d1, 48);
VOR_V(d1, q1, d1);
}
VFADD_D(q1, q1, q0);
if (!BOX64ENV(dynarec_fastnan)) {
VBITSEL_V(q1, q1, d1, d0);
VFCMP_D(v1, q1, q1, cUN);
VANDN_V(v0, v0, v1);
VLDI(v1, 0b011111111000); // broadcast 0xFFFFFFFFFFFFFFF8
VLDI(v1, (0b011 << 10) | 0b1111111000);
VSLLI_D(v1, v1, 48);
VAND_V(v1, v0, v1);
VANDN_V(v0, v0, q1);
VOR_V(q1, v0, v1);
VBITSEL_V(q1, q1, v1, v0);
}
break;
case 0x59:
@@ -1543,17 +1567,22 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
if (!BOX64ENV(dynarec_fastnan)) {
v0 = fpu_get_scratch(dyn);
v1 = fpu_get_scratch(dyn);
VFCMP_D(v0, q0, q1, cUN);
d0 = fpu_get_scratch(dyn);
d1 = fpu_get_scratch(dyn);
VFCMP_D(v0, q1, q0, cUN);
VFCMP_D(d0, q1, q1, cUN);
VLDI(d1, (0b011 << 10) | 0b0000001000);
VSLLI_D(d1, d1, 48);
VOR_V(d1, q1, d1);
}
VFMUL_D(q1, q1, q0);
if (!BOX64ENV(dynarec_fastnan)) {
VBITSEL_V(q1, q1, d1, d0);
VFCMP_D(v1, q1, q1, cUN);
VANDN_V(v0, v0, v1);
VLDI(v1, 0b011111111000); // broadcast 0xFFFFFFFFFFFFFFF8
VLDI(v1, (0b011 << 10) | 0b1111111000);
VSLLI_D(v1, v1, 48);
VAND_V(v1, v0, v1);
VANDN_V(v0, v0, q1);
VOR_V(q1, v0, v1);
VBITSEL_V(q1, q1, v1, v0);
}
break;
case 0x5A:
@@ -1602,17 +1631,22 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
if (!BOX64ENV(dynarec_fastnan)) {
v0 = fpu_get_scratch(dyn);
v1 = fpu_get_scratch(dyn);
VFCMP_D(v0, q0, q1, cUN);
d0 = fpu_get_scratch(dyn);
d1 = fpu_get_scratch(dyn);
VFCMP_D(v0, q1, q0, cUN);
VFCMP_D(d0, q1, q1, cUN);
VLDI(d1, (0b011 << 10) | 0b0000001000);
VSLLI_D(d1, d1, 48);
VOR_V(d1, q1, d1);
}
VFSUB_D(q1, q1, q0);
if (!BOX64ENV(dynarec_fastnan)) {
VBITSEL_V(q1, q1, d1, d0);
VFCMP_D(v1, q1, q1, cUN);
VANDN_V(v0, v0, v1);
VLDI(v1, 0b011111111000); // broadcast 0xFFFFFFFFFFFFFFF8
VLDI(v1, (0b011 << 10) | 0b1111111000);
VSLLI_D(v1, v1, 48);
VAND_V(v1, v0, v1);
VANDN_V(v0, v0, q1);
VOR_V(q1, v0, v1);
VBITSEL_V(q1, q1, v1, v0);
}
break;
case 0x5D:
@@ -1635,17 +1669,22 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
if (!BOX64ENV(dynarec_fastnan)) {
v0 = fpu_get_scratch(dyn);
v1 = fpu_get_scratch(dyn);
VFCMP_D(v0, q0, q1, cUN);
d0 = fpu_get_scratch(dyn);
d1 = fpu_get_scratch(dyn);
VFCMP_D(v0, q1, q0, cUN);
VFCMP_D(d0, q1, q1, cUN);
VLDI(d1, (0b011 << 10) | 0b0000001000);
VSLLI_D(d1, d1, 48);
VOR_V(d1, q1, d1);
}
VFDIV_D(q1, q1, q0);
if (!BOX64ENV(dynarec_fastnan)) {
VBITSEL_V(q1, q1, d1, d0);
VFCMP_D(v1, q1, q1, cUN);
VANDN_V(v0, v0, v1);
VLDI(v1, 0b011111111000); // broadcast 0xFFFFFFFFFFFFFFF8
VLDI(v1, (0b011 << 10) | 0b1111111000);
VSLLI_D(v1, v1, 48);
VAND_V(v1, v0, v1);
VANDN_V(v0, v0, q1);
VOR_V(q1, v0, v1);
VBITSEL_V(q1, q1, v1, v0);
}
break;
case 0x5F:
@@ -2025,13 +2064,17 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
}
VFADD_D(q1, d0, q1);
if (!BOX64ENV(dynarec_fastnan)) {
d1 = fpu_get_scratch(dyn);
VFCMP_D(d1, d0, d0, cUN);
VLDI(v1, (0b011 << 10) | 0b0000001000);
VSLLI_D(v1, v1, 48);
VOR_V(d0, d0, v1);
VBITSEL_V(q1, q1, d0, d1);
VFCMP_D(v1, q1, q1, cUN);
VANDN_V(v0, v0, v1);
VLDI(v1, 0b011111111000); // broadcast 0xFFFFFFFFFFFFFFF8
VLDI(v1, (0b011 << 10) | 0b1111111000);
VSLLI_D(v1, v1, 48);
VAND_V(v1, v0, v1);
VANDN_V(v0, v0, q1);
VOR_V(q1, v0, v1);
VBITSEL_V(q1, q1, v1, v0);
}
break;
case 0x7D:
@@ -2049,13 +2092,17 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
}
VFSUB_D(q1, d0, q1);
if (!BOX64ENV(dynarec_fastnan)) {
d1 = fpu_get_scratch(dyn);
VFCMP_D(d1, d0, d0, cUN);
VLDI(v1, (0b011 << 10) | 0b0000001000);
VSLLI_D(v1, v1, 48);
VOR_V(d0, d0, v1);
VBITSEL_V(q1, q1, d0, d1);
VFCMP_D(v1, q1, q1, cUN);
VANDN_V(v0, v0, v1);
VLDI(v1, 0b011111111000); // broadcast 0xFFFFFFFFFFFFFFF8
VLDI(v1, (0b011 << 10) | 0b1111111000);
VSLLI_D(v1, v1, 48);
VAND_V(v1, v0, v1);
VANDN_V(v0, v0, q1);
VOR_V(q1, v0, v1);
VBITSEL_V(q1, q1, v1, v0);
}
break;
case 0x7E:
@@ -2368,17 +2415,17 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
u8 = F8;
u8 &= (rex.w ? 0x3f : 0x0f);
if (cpuext.lbt) {
SRLI_D(x3, ed, u8);
X64_SET_EFLAGS(x3, X_CF);
SRLI_D(x5, ed, u8);
X64_SET_EFLAGS(x5, X_CF);
} else {
BSTRPICK_D(x3, ed, u8, u8);
BSTRINS_D(xFlags, x3, F_CF, F_CF);
BSTRPICK_D(x5, ed, u8, u8);
BSTRINS_D(xFlags, x5, F_CF, F_CF);
}
if (u8 <= 11) {
ORI(ed, ed, (1LL << u8));
} else {
ADDI_D(x3, xZR, -1);
BSTRINS_D(ed, x3, u8, u8);
ADDI_D(x5, xZR, -1);
BSTRINS_D(ed, x5, u8, u8);
}
EWBACK;
break;
@@ -2394,11 +2441,11 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
u8 = F8;
u8 &= (rex.w ? 0x3f : 0x0f);
if (cpuext.lbt) {
SRLI_D(x3, ed, u8);
X64_SET_EFLAGS(x3, X_CF);
SRLI_D(x5, ed, u8);
X64_SET_EFLAGS(x5, X_CF);
} else {
BSTRPICK_D(x3, ed, u8, u8);
BSTRINS_D(xFlags, x3, F_CF, F_CF);
BSTRPICK_D(x5, ed, u8, u8);
BSTRINS_D(xFlags, x5, F_CF, F_CF);
}
BSTRINS_D(ed, xZR, u8, u8);
EWBACK;
@@ -2415,11 +2462,11 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
u8 = F8;
u8 &= (rex.w ? 0x3f : 0x0f);
if (cpuext.lbt) {
SRLI_D(x3, ed, u8);
X64_SET_EFLAGS(x3, X_CF);
SRLI_D(x5, ed, u8);
X64_SET_EFLAGS(x5, X_CF);
} else {
BSTRPICK_D(x3, ed, u8, u8);
BSTRINS_D(xFlags, x3, F_CF, F_CF);
BSTRPICK_D(x5, ed, u8, u8);
BSTRINS_D(xFlags, x5, F_CF, F_CF);
}
if (u8 <= 11) {
XORI(ed, ed, (1LL << u8));
@@ -2484,16 +2531,19 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
GETGWEW(x4, x5, 0);
BNE_MARK(ed, xZR);
IFX (X_ZF) ORI(xFlags, xFlags, 1 << F_ZF);
if (BOX64DRENV(dynarec_safeflags)) {
IFX (X_PF) ORI(xFlags, xFlags, 1 << F_PF);
}
B_MARK2_nocond;
MARK;
IFXA (X_ZF, !BOX64DRENV(dynarec_safeflags))
BSTRINS_D(xFlags, xZR, F_ZF, F_ZF);
CTZ_D(gd, ed);
GWBACK;
MARK2;
if (BOX64DRENV(dynarec_safeflags)) {
IFX (X_PF) emit_pf(dyn, ninst, gd, x1, x2);
}
MARK2;
IFX (X_ALL) SPILL_EFLAGS();
break;
case 0xBD:
@@ -2508,6 +2558,9 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
GETGWEW(x4, x5, 0);
BNE_MARK(ed, xZR);
IFX (X_ZF) ORI(xFlags, xFlags, 1 << F_ZF);
if (BOX64DRENV(dynarec_safeflags)) {
IFX (X_PF) ORI(xFlags, xFlags, 1 << F_PF);
}
B_MARK2_nocond;
MARK;
IFXA (X_ZF, !BOX64DRENV(dynarec_safeflags))
@@ -2516,10 +2569,10 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
ADDI_D(x1, xZR, 63);
SUB_D(gd, x1, gd);
GWBACK;
MARK2;
if (BOX64DRENV(dynarec_safeflags)) {
IFX (X_PF) emit_pf(dyn, ninst, gd, x1, x2);
}
MARK2;
IFX (X_ALL) SPILL_EFLAGS();
break;
case 0xBE:
@@ -2640,7 +2693,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
case 0xCF:
INST_NAME("BSWAP Reg");
gd = TO_NAT((opcode & 7) + (rex.b << 3));
if(rex.w){
if (rex.w) {
REVB_D(gd, gd);
} else {
// undefined behaviour
@@ -2652,10 +2705,28 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
nextop = F8;
GETGX(q0, 1);
GETEX(q1, 0, 0);
if (!BOX64ENV(dynarec_fastnan)) {
d0 = fpu_get_scratch(dyn);
d1 = fpu_get_scratch(dyn);
d2 = fpu_get_scratch(dyn);
VFCMP_D(d0, q0, q1, cUN);
VFCMP_D(d1, q0, q0, cUN);
VLDI(d2, (0b011 << 10) | 0b0000001000);
VSLLI_D(d2, d2, 48);
VOR_V(d2, q0, d2);
}
v0 = fpu_get_scratch(dyn);
VFSUB_D(v0, q0, q1);
VFADD_D(q0, q0, q1);
VEXTRINS_D(q0, v0, 0);
if (!BOX64ENV(dynarec_fastnan)) {
VBITSEL_V(q0, q0, d2, d1);
VFCMP_D(d2, q0, q0, cUN);
VANDN_V(d0, d0, d2);
VLDI(d2, (0b011 << 10) | 0b1111111000);
VSLLI_D(d2, d2, 48);
VBITSEL_V(q0, q0, d2, d0);
}
break;
case 0xD1:
INST_NAME("PSRLW Gx, Ex");
+1 -1
View File
@@ -381,7 +381,7 @@ uintptr_t dynarec64_66F0(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
}
IFXORNAT (X_ALL | X_PEND) {
BSTRPICK_D(x6, x1, 15, 0);
emit_add16(dyn, ninst, x6, gd, x3, x4, x5);
emit_add16(dyn, ninst, x6, x5, x3, x4, x7);
}
BSTRINS_D(gd, x1, 15, 0);
}
+34 -15
View File
@@ -354,14 +354,21 @@ uintptr_t dynarec64_AVX_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, in
if (!BOX64ENV(dynarec_fastnan)) {
d0 = fpu_get_scratch(dyn);
d1 = fpu_get_scratch(dyn);
q0 = fpu_get_scratch(dyn);
q1 = fpu_get_scratch(dyn);
VFCMPxy(S, d0, v1, v2, cUN);
VFCMPxy(S, q0, v1, v1, cUN);
VLDIxy(q1, (0b010 << 9) | 0b0000000100);
VSLLIxy(W, q1, q1, 20);
VOR_Vxy(q1, v1, q1);
}
VFADDxy(S, v0, v1, v2);
if (!BOX64ENV(dynarec_fastnan)) {
VBITSEL_Vxy(v0, v0, q1, q0);
VFCMPxy(S, d1, v0, v0, cUN);
VANDN_Vxy(d0, d0, d1);
VLDIxy(d1, (0b010 << 9) | 0b1111111100);
VSLLIxy(W, d1, d1, 20); // broadcast 0xFFC00000
VSLLIxy(W, d1, d1, 20);
VBITSEL_Vxy(v0, v0, d1, d0);
}
break;
@@ -372,14 +379,21 @@ uintptr_t dynarec64_AVX_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, in
if (!BOX64ENV(dynarec_fastnan)) {
d0 = fpu_get_scratch(dyn);
d1 = fpu_get_scratch(dyn);
q0 = fpu_get_scratch(dyn);
q1 = fpu_get_scratch(dyn);
VFCMPxy(S, d0, v1, v2, cUN);
VFCMPxy(S, q0, v1, v1, cUN);
VLDIxy(q1, (0b010 << 9) | 0b0000000100);
VSLLIxy(W, q1, q1, 20);
VOR_Vxy(q1, v1, q1);
}
VFMULxy(S, v0, v1, v2);
if (!BOX64ENV(dynarec_fastnan)) {
VBITSEL_Vxy(v0, v0, q1, q0);
VFCMPxy(S, d1, v0, v0, cUN);
VANDN_Vxy(d0, d0, d1);
VLDIxy(d1, (0b010 << 9) | 0b1111111100);
VSLLIxy(W, d1, d1, 20); // broadcast 0xFFC00000
VSLLIxy(W, d1, d1, 20);
VBITSEL_Vxy(v0, v0, d1, d0);
}
break;
@@ -425,14 +439,21 @@ uintptr_t dynarec64_AVX_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, in
if (!BOX64ENV(dynarec_fastnan)) {
d0 = fpu_get_scratch(dyn);
d1 = fpu_get_scratch(dyn);
q0 = fpu_get_scratch(dyn);
q1 = fpu_get_scratch(dyn);
VFCMPxy(S, d0, v1, v2, cUN);
VFCMPxy(S, q0, v1, v1, cUN);
VLDIxy(q1, (0b010 << 9) | 0b0000000100);
VSLLIxy(W, q1, q1, 20);
VOR_Vxy(q1, v1, q1);
}
VFSUBxy(S, v0, v1, v2);
if (!BOX64ENV(dynarec_fastnan)) {
VBITSEL_Vxy(v0, v0, q1, q0);
VFCMPxy(S, d1, v0, v0, cUN);
VANDN_Vxy(d0, d0, d1);
VLDIxy(d1, (0b010 << 9) | 0b1111111100);
VSLLIxy(W, d1, d1, 20); // broadcast 0xFFC00000
VSLLIxy(W, d1, d1, 20);
VBITSEL_Vxy(v0, v0, d1, d0);
}
break;
@@ -452,14 +473,21 @@ uintptr_t dynarec64_AVX_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, in
if (!BOX64ENV(dynarec_fastnan)) {
d0 = fpu_get_scratch(dyn);
d1 = fpu_get_scratch(dyn);
q0 = fpu_get_scratch(dyn);
q1 = fpu_get_scratch(dyn);
VFCMPxy(S, d0, v1, v2, cUN);
VFCMPxy(S, q0, v1, v1, cUN);
VLDIxy(q1, (0b010 << 9) | 0b0000000100);
VSLLIxy(W, q1, q1, 20);
VOR_Vxy(q1, v1, q1);
}
VFDIVxy(S, v0, v1, v2);
if (!BOX64ENV(dynarec_fastnan)) {
VBITSEL_Vxy(v0, v0, q1, q0);
VFCMPxy(S, d1, v0, v0, cUN);
VANDN_Vxy(d0, d0, d1);
VLDIxy(d1, (0b010 << 9) | 0b1111111100);
VSLLIxy(W, d1, d1, 20); // broadcast 0xFFC00000
VSLLIxy(W, d1, d1, 20);
VBITSEL_Vxy(v0, v0, d1, d0);
}
break;
@@ -482,18 +510,9 @@ uintptr_t dynarec64_AVX_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, in
XVXOR_V(q2, q2, q2);
for (int i = 0; i < (rex.is32bits ? 8 : 16); ++i) {
if (dyn->lsx.avxcache[i].v != -1) {
// avx used register
if (dyn->lsx.avxcache[i].width == LSX_AVX_WIDTH_256) {
// 256 width, fill upper 128bits with zero.
q1 = avx_get_reg(dyn, ninst, x1, i, 1, LSX_AVX_WIDTH_256); // mark reg write (dirty)
XVPERMI_Q(q1, q2, XVPERMI_IMM_4_0(0, 2));
} else {
// 128 width, lazy save.
q1 = avx_get_reg(dyn, ninst, x1, i, 1, LSX_AVX_WIDTH_128); // mark reg write (dirty)
dyn->lsx.avxcache[i].zero_upper = 1;
}
q1 = avx_get_reg(dyn, ninst, x1, i, 1, LSX_AVX_WIDTH_256);
XVPERMI_Q(q1, q2, XVPERMI_IMM_4_0(0, 2));
} else {
// SSE register or unused register, store 128bit zero to x64emu_t.ymm[]
VST(q2, xEmu, offsetof(x64emu_t, ymm[i]));
}
}
+4 -1
View File
@@ -78,6 +78,9 @@ uintptr_t dynarec64_AVX_0F38(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
BNEZ(gd, 8);
ORI(xFlags, xFlags, 1 << F_ZF);
}
if (BOX64DRENV(dynarec_safeflags)) {
IFX (X_PF) emit_pf(dyn, ninst, gd, x2, x5);
}
SPILL_EFLAGS();
break;
case 0xF3:
@@ -199,7 +202,7 @@ uintptr_t dynarec64_AVX_0F38(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
break;
case 0xF7:
INST_NAME("BEXTR Gd, Vd, Ed");
INST_NAME("BEXTR Gd, Ed, Vd");
nextop = F8;
SETFLAGS(X_ALL, SF_SET, NAT_FLAGS_NOFUSION);
GETGD;
+71 -27
View File
@@ -327,14 +327,21 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
if (!BOX64ENV(dynarec_fastnan)) {
d0 = fpu_get_scratch(dyn);
d1 = fpu_get_scratch(dyn);
q0 = fpu_get_scratch(dyn);
q1 = fpu_get_scratch(dyn);
VFCMPxy(D, d0, v1, v2, cUN);
VFCMPxy(D, q0, v1, v1, cUN);
VLDIxy(q1, (0b011 << 10) | 0b0000001000);
VSLLIxy(D, q1, q1, 48);
VOR_Vxy(q1, v1, q1);
}
VFADDxy(D, v0, v1, v2);
if (!BOX64ENV(dynarec_fastnan)) {
VBITSEL_Vxy(v0, v0, q1, q0);
VFCMPxy(D, d1, v0, v0, cUN);
VANDN_Vxy(d0, d0, d1);
VLDIxy(d1, (0b011 << 9) | 0b111111000);
VSLLIxy(D, d1, d1, 48); // broadcast 0xfff8000000000000
VLDIxy(d1, (0b011 << 10) | 0b1111111000);
VSLLIxy(D, d1, d1, 48);
VBITSEL_Vxy(v0, v0, d1, d0);
}
break;
@@ -345,14 +352,21 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
if (!BOX64ENV(dynarec_fastnan)) {
d0 = fpu_get_scratch(dyn);
d1 = fpu_get_scratch(dyn);
q0 = fpu_get_scratch(dyn);
q1 = fpu_get_scratch(dyn);
VFCMPxy(D, d0, v1, v2, cUN);
VFCMPxy(D, q0, v1, v1, cUN);
VLDIxy(q1, (0b011 << 10) | 0b0000001000);
VSLLIxy(D, q1, q1, 48);
VOR_Vxy(q1, v1, q1);
}
VFMULxy(D, v0, v1, v2);
if (!BOX64ENV(dynarec_fastnan)) {
VBITSEL_Vxy(v0, v0, q1, q0);
VFCMPxy(D, d1, v0, v0, cUN);
VANDN_Vxy(d0, d0, d1);
VLDIxy(d1, (0b011 << 9) | 0b111111000);
VSLLIxy(D, d1, d1, 48); // broadcast 0xfff8000000000000
VLDIxy(d1, (0b011 << 10) | 0b1111111000);
VSLLIxy(D, d1, d1, 48);
VBITSEL_Vxy(v0, v0, d1, d0);
}
break;
@@ -361,20 +375,19 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
nextop = F8;
GETEYxy(v1, 0, 0);
GETGYx_empty(v0);
if(!BOX64ENV(dynarec_fastround)) {
if (!BOX64ENV(dynarec_fastround)) {
u8 = sse_setround(dyn, ninst, x6, x4);
}
d0 = fpu_get_scratch(dyn);
if(vex.l) {
if (vex.l) {
XVXOR_V(d0, d0, d0);
XVFCVT_S_D(v0, d0, v1);
XVPERMI_D(v0, v0, 0b11011000);
} else {
VFCVT_S_D(d0, v1, v1);
XVPICKVE_D(v0, d0, 0);
YMM_UNMARK_UPPER_ZERO(v0);
}
if(!BOX64ENV(dynarec_fastround)) {
if (!BOX64ENV(dynarec_fastround)) {
x87_restoreround(dyn, ninst, u8);
}
break;
@@ -383,7 +396,7 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
nextop = F8;
GETGY_empty_EY_xy(v0, v1, 0);
u8 = sse_setround(dyn, ninst, x6, x4);
if(vex.l){
if (vex.l) {
if (!BOX64ENV(dynarec_fastround)) {
d1 = fpu_get_scratch(dyn);
q0 = fpu_get_scratch(dyn);
@@ -421,14 +434,21 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
if (!BOX64ENV(dynarec_fastnan)) {
d0 = fpu_get_scratch(dyn);
d1 = fpu_get_scratch(dyn);
q0 = fpu_get_scratch(dyn);
q1 = fpu_get_scratch(dyn);
VFCMPxy(D, d0, v1, v2, cUN);
VFCMPxy(D, q0, v1, v1, cUN);
VLDIxy(q1, (0b011 << 10) | 0b0000001000);
VSLLIxy(D, q1, q1, 48);
VOR_Vxy(q1, v1, q1);
}
VFSUBxy(D, v0, v1, v2);
if (!BOX64ENV(dynarec_fastnan)) {
VBITSEL_Vxy(v0, v0, q1, q0);
VFCMPxy(D, d1, v0, v0, cUN);
VANDN_Vxy(d0, d0, d1);
VLDIxy(d1, (0b011 << 9) | 0b111111000);
VSLLIxy(D, d1, d1, 48); // broadcast 0xfff8000000000000
VLDIxy(d1, (0b011 << 10) | 0b1111111000);
VSLLIxy(D, d1, d1, 48);
VBITSEL_Vxy(v0, v0, d1, d0);
}
break;
@@ -448,14 +468,21 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
if (!BOX64ENV(dynarec_fastnan)) {
d0 = fpu_get_scratch(dyn);
d1 = fpu_get_scratch(dyn);
q0 = fpu_get_scratch(dyn);
q1 = fpu_get_scratch(dyn);
VFCMPxy(D, d0, v1, v2, cUN);
VFCMPxy(D, q0, v1, v1, cUN);
VLDIxy(q1, (0b011 << 10) | 0b0000001000);
VSLLIxy(D, q1, q1, 48);
VOR_Vxy(q1, v1, q1);
}
VFDIVxy(D, v0, v1, v2);
if (!BOX64ENV(dynarec_fastnan)) {
VBITSEL_Vxy(v0, v0, q1, q0);
VFCMPxy(D, d1, v0, v0, cUN);
VANDN_Vxy(d0, d0, d1);
VLDIxy(d1, (0b011 << 9) | 0b111111000);
VSLLIxy(D, d1, d1, 48); // broadcast 0xfff8000000000000
VLDIxy(d1, (0b011 << 10) | 0b1111111000);
VSLLIxy(D, d1, d1, 48);
VBITSEL_Vxy(v0, v0, d1, d0);
}
break;
@@ -794,10 +821,16 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
}
VFADDxy(D, v0, q0, v0);
if (!BOX64ENV(dynarec_fastnan)) {
q1 = fpu_get_scratch(dyn);
VFCMPxy(D, q1, q0, q0, cUN);
VLDIxy(d1, (0b011 << 10) | 0b0000001000);
VSLLIxy(D, d1, d1, 48);
VOR_Vxy(d1, q0, d1);
VBITSEL_Vxy(v0, v0, d1, q1);
VFCMPxy(D, d1, v0, v0, cUN);
VANDN_Vxy(d0, d0, d1);
VLDIxy(d1, (0b011 << 9) | 0b111111000);
VSLLIxy(D, d1, d1, 48); // broadcast 0xfff8000000000000
VLDIxy(d1, (0b011 << 10) | 0b1111111000);
VSLLIxy(D, d1, d1, 48);
VBITSEL_Vxy(v0, v0, d1, d0);
}
break;
@@ -815,10 +848,16 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
}
VFSUBxy(D, v0, q0, v0);
if (!BOX64ENV(dynarec_fastnan)) {
q1 = fpu_get_scratch(dyn);
VFCMPxy(D, q1, q0, q0, cUN);
VLDIxy(d1, (0b011 << 10) | 0b0000001000);
VSLLIxy(D, d1, d1, 48);
VOR_Vxy(d1, q0, d1);
VBITSEL_Vxy(v0, v0, d1, q1);
VFCMPxy(D, d1, v0, v0, cUN);
VANDN_Vxy(d0, d0, d1);
VLDIxy(d1, (0b011 << 9) | 0b111111000);
VSLLIxy(D, d1, d1, 48); // broadcast 0xfff8000000000000
VLDIxy(d1, (0b011 << 10) | 0b1111111000);
VSLLIxy(D, d1, d1, 48);
VBITSEL_Vxy(v0, v0, d1, d0);
}
break;
@@ -895,7 +934,7 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
GETVYx(v1, 0);
GETGYx_empty(v0);
u8 = F8;
if(v0 != v1) VOR_V(v0, v1, v1);
if (v0 != v1) VOR_V(v0, v1, v1);
VINSGR2VR_H(v0, ed, (u8 & 0x7));
break;
case 0xC5:
@@ -946,17 +985,23 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
if (!BOX64ENV(dynarec_fastnan)) {
d0 = fpu_get_scratch(dyn);
d1 = fpu_get_scratch(dyn);
q1 = fpu_get_scratch(dyn);
VFCMPxy(D, d0, v1, v2, cUN);
VFCMPxy(D, q1, v1, v1, cUN);
VLDIxy(d1, (0b011 << 10) | 0b0000001000);
VSLLIxy(D, d1, d1, 48);
VOR_Vxy(d1, v1, d1);
}
q0 = fpu_get_scratch(dyn);
VFSUBxy(D, q0, v1, v2);
VFADDxy(D, v0, v1, v2);
VEXTRINSxy(D, v0, q0, 0);
if (!BOX64ENV(dynarec_fastnan)) {
VBITSEL_Vxy(v0, v0, d1, q1);
VFCMPxy(D, d1, v0, v0, cUN);
VANDN_Vxy(d0, d0, d1);
VLDIxy(d1, (0b011 << 9) | 0b111111000);
VSLLIxy(D, d1, d1, 48); // broadcast 0xfff8000000000000
VLDIxy(d1, (0b011 << 10) | 0b1111111000);
VSLLIxy(D, d1, d1, 48);
VBITSEL_Vxy(v0, v0, d1, d0);
}
break;
@@ -1015,7 +1060,6 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
if (MODREG) {
GETEYx_empty(q1, 0);
XVPICKVE_D(q1, q0, 0);
YMM_UNMARK_UPPER_ZERO(q1);
} else {
addr = geted(dyn, addr, ninst, nextop, &ed, x4, x5, &fixedaddress, rex, NULL, 1, 0);
FST_D(q0, ed, fixedaddress);
@@ -1135,9 +1179,9 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
GETGYx_empty(v0);
d0 = fpu_get_scratch(dyn);
d1 = fpu_get_scratch(dyn);
if(vex.l){
if (vex.l) {
XVXOR_V(d0, d0, d0);
XVFTINTRZ_W_D(d1, d0, v1); // v0 [lo0, lo1, --, --, hi0, hi1, --, -- ]
XVFTINTRZ_W_D(d1, d0, v1); // v0 [lo0, lo1, --, --, hi0, hi1, --, -- ]
if (!BOX64ENV(dynarec_fastround)) {
q0 = fpu_get_scratch(dyn);
q1 = fpu_get_scratch(dyn);
@@ -1147,26 +1191,25 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
so we could combine +-NAN +overflow to xvfcmp.cule 0x41e0000000000000
*/
LU52I_D(x5, xZR, 0x41e);
XVREPLGR2VR_D(q1, x5);
XVREPLGR2VR_D(q1, x5);
XVFCMP_D(d0, q1, v1, cULE); // get Nan mask
XVSRLNI_W_D(d0, d0, 0);
XVBITSEL_V(v0, d1, q0, d0);
}
XVPERMI_D(v0, v0, 0b11011000);
}else{
} else {
VFTINTRZ_W_D(d0, v1, v1);
if (!BOX64ENV(dynarec_fastround)) {
q0 = fpu_get_scratch(dyn);
q1 = fpu_get_scratch(dyn);
XVLDI(q0, 0b1001110000000); // broadcast 0x80000000 to all
LU52I_D(x5, xZR, 0x41e);
XVREPLGR2VR_D(q1, x5);
XVREPLGR2VR_D(q1, x5);
XVFCMP_D(q1, q1, v1, cULE); // get Nan mask
VSHUF4I_W(q1, q1, 0b11011000);
VBITSEL_V(d0, d0, q0, q1);
}
XVPICKVE_D(v0, d0, 0);
YMM_UNMARK_UPPER_ZERO(v0);
}
break;
case 0xE7:
@@ -1232,6 +1275,7 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
nextop = F8;
GETGY_empty_VYEY_xy(v0, v1, v2, 0);
VXOR_Vxy(v0, v1, v2);
if (v0 == v1 && v0 == v2) YMM_UNMARK_UPPER_ZERO(v0);
break;
case 0xF1:
INST_NAME("VPSLLW Gx, Vx, Ex");
+8 -3
View File
@@ -262,7 +262,7 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t i
GETEYx(v1, 0, 0);
GETGYy_empty(v0);
d0 = fpu_get_scratch(dyn);
/*
/*
xvffintl.s.h convert [h0..h3,h4..h7,h8..h11,h12..h15] to [h0..h3,h8..h11]
xvffinth.s.h convert [h0..h3,h4..h7,h8..h11,h12..h15] to [h4..h7,h12..h15]
so user xvpermi.d to reorder input [h0..h3,h4..h7,h8..h11,h12..h15] to [h0..h3,h8..h11,h4..h7,h12..h15]
@@ -278,6 +278,7 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t i
case 0x16:
INST_NAME("VPERMPS Gx, Vx, Ex");
nextop = F8;
if (!vex.l) UDF();
GETGY_empty_VYEY_xy(v0, v1, v2, 0);
XVPERM_W(v0, v2, v1);
break;
@@ -637,6 +638,7 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t i
case 0x36:
INST_NAME("VPERMD Gx, Vx, Ex");
nextop = F8;
if (!vex.l) UDF();
GETGY_empty_VYEY_xy(v0, v1, v2, 0);
XVPERM_W(v0, v2, v1);
break;
@@ -719,7 +721,6 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t i
VSEQ_H(q0, q2, v1); // get mask(0xffff)
VFRSTPI_H(q2, q0, 1); // find first neg(0xffff),insert index to q2
XVPICKVE_W(v0, q2, 0);
YMM_UNMARK_UPPER_ZERO(v0);
break;
case 0x45:
INST_NAME("VPSRLVD/Q Gx, Vx, Ex");
@@ -741,6 +742,10 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t i
case 0x46:
INST_NAME("VPSRAVD Gx, Vx, Ex");
nextop = F8;
if (rex.w) {
DEFAULT;
return addr;
}
GETGY_empty_VYEY_xy(v0, v1, v2, 0);
d0 = fpu_get_scratch(dyn);
VMINIxy(WU, d0, v2, 31);
@@ -1302,7 +1307,7 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t i
avx_forget_reg(dyn, ninst, gd);
MOV32w(x1, gd);
CALL(const_native_aesimc, -1, x1, 0);
GETGYx(q0, 1); // reget writable for mark zeroup hi-128bits.
GETGYx(q0, 1); // reget writable for mark zeroup hi-128bits.
break;
case 0xDC:
INST_NAME("VAESENC Gx, Vx, Ex");
+14 -7
View File
@@ -508,11 +508,10 @@ uintptr_t dynarec64_AVX_66_0F3A(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t i
u8 = F8;
d0 = fpu_get_scratch(dyn);
if (u8 & 4) {
u8 = sse_setround(dyn, ninst, x1, x2);
u8 = sse_setround(dyn, ninst, x4, x5);
} else {
MOVFCSR2GR(x4, FCSR3);
ORI(x5, x5, round_round[u8 & 3]);
SLLI_D(x5, x5, 8);
ORI(x5, xZR, ((-(u8 & 3)) & 3) << 8);
MOVGR2FCSR(FCSR3, x5);
u8 = x4;
}
@@ -531,7 +530,15 @@ uintptr_t dynarec64_AVX_66_0F3A(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t i
case 0x20:
INST_NAME("VPINSRB Gx, Vx, ED, Ib");
nextop = F8;
GETEB(x5, 1);
if (MODREG) {
ed = TO_NAT((nextop & 7) + (rex.b << 3));
wback = 0;
} else {
SMREAD();
addr = geted(dyn, addr, ninst, nextop, &wback, x2, x1, &fixedaddress, rex, NULL, 1, 1);
LD_B(x1, wback, fixedaddress);
ed = x1;
}
GETVYx(v1, 0);
GETGYx_empty(v0);
u8 = F8;
@@ -749,7 +756,7 @@ uintptr_t dynarec64_AVX_66_0F3A(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t i
INST_NAME("VBLENDVPS Gx, Vx, Ex, XMMImm8");
nextop = F8;
u8 = geted_ib(dyn, addr, ninst, nextop) >> 4;
d0 = avx_get_reg(dyn, ninst, x5, u8, 0, LSX_AVX_WIDTH_128);
d0 = avx_get_reg(dyn, ninst, x5, u8, 0, vex.l ? LSX_AVX_WIDTH_256 : LSX_AVX_WIDTH_128);
GETGY_empty_VYEY_xy(v0, v1, v2, 1);
F8;
q0 = fpu_get_scratch(dyn);
@@ -760,7 +767,7 @@ uintptr_t dynarec64_AVX_66_0F3A(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t i
INST_NAME("VBLENDVPD Gx, Vx, Ex, XMMImm8");
nextop = F8;
u8 = geted_ib(dyn, addr, ninst, nextop) >> 4;
d0 = avx_get_reg(dyn, ninst, x5, u8, 0, LSX_AVX_WIDTH_128);
d0 = avx_get_reg(dyn, ninst, x5, u8, 0, vex.l ? LSX_AVX_WIDTH_256 : LSX_AVX_WIDTH_128);
GETGY_empty_VYEY_xy(v0, v1, v2, 1);
F8;
q0 = fpu_get_scratch(dyn);
@@ -771,7 +778,7 @@ uintptr_t dynarec64_AVX_66_0F3A(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t i
INST_NAME("VPBLENDVB Gx, Vx, Ex, XMMImm8");
nextop = F8;
u8 = geted_ib(dyn, addr, ninst, nextop) >> 4;
d0 = avx_get_reg(dyn, ninst, x5, u8, 0, LSX_AVX_WIDTH_128);
d0 = avx_get_reg(dyn, ninst, x5, u8, 0, vex.l ? LSX_AVX_WIDTH_256 : LSX_AVX_WIDTH_128);
GETGY_empty_VYEY_xy(v0, v1, v2, 1);
F8;
q0 = fpu_get_scratch(dyn);
+67 -21
View File
@@ -71,7 +71,6 @@ uintptr_t dynarec64_AVX_F2_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
GETEYSD(q2, 0, 0);
GETGYx_empty(q0);
XVPICKVE_D(q0, q2, 0);
YMM_UNMARK_UPPER_ZERO(q0);
}
break;
case 0x11:
@@ -131,7 +130,7 @@ uintptr_t dynarec64_AVX_F2_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
if (!BOX64ENV(dynarec_fastround)) {
x87_restoreround(dyn, ninst, u8);
}
if(v0 != v1) VOR_V(v0, v1, v1);
if (v0 != v1) VOR_V(v0, v1, v1);
VEXTRINS_D(v0, d1, 0);
break;
case 0x2C:
@@ -221,13 +220,20 @@ uintptr_t dynarec64_AVX_F2_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
d0 = fpu_get_scratch(dyn);
FADD_D(d0, v1, v2);
if (!BOX64ENV(dynarec_fastnan)) {
d1 = fpu_get_scratch(dyn);
FCMP_D(fcc0, v1, v2, cUN);
BCNEZ_MARK(fcc0);
FCMP_D(fcc1, d0, d0, cOR);
BCNEZ_MARK(fcc1);
FNEG_D(d0, d0);
MARK;
MOVFR2GR_D(x4, v1);
MOV64x(x5, 0x0008000000000000LL);
OR(x4, x4, x5);
MOVGR2FR_D(d1, x4);
FCMP_D(fcc0, v1, v1, cUN);
FSEL(d0, d0, d1, fcc0);
}
MARK;
if (v0 != v1) VOR_V(v0, v1, v1);
VEXTRINS_D(v0, d0, 0);
break;
@@ -240,13 +246,20 @@ uintptr_t dynarec64_AVX_F2_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
d0 = fpu_get_scratch(dyn);
FMUL_D(d0, v1, v2);
if (!BOX64ENV(dynarec_fastnan)) {
d1 = fpu_get_scratch(dyn);
FCMP_D(fcc0, v1, v2, cUN);
BCNEZ_MARK(fcc0);
FCMP_D(fcc1, d0, d0, cOR);
BCNEZ_MARK(fcc1);
FNEG_D(d0, d0);
MARK;
MOVFR2GR_D(x4, v1);
MOV64x(x5, 0x0008000000000000LL);
OR(x4, x4, x5);
MOVGR2FR_D(d1, x4);
FCMP_D(fcc0, v1, v1, cUN);
FSEL(d0, d0, d1, fcc0);
}
MARK;
if (v0 != v1) VOR_V(v0, v1, v1);
VEXTRINS_D(v0, d0, 0);
break;
@@ -258,7 +271,7 @@ uintptr_t dynarec64_AVX_F2_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
GETGYx_empty(v0);
d0 = fpu_get_scratch(dyn);
FCVT_S_D(d0, v2);
if(v0 != v1) VOR_V(v0, v1, v1);
if (v0 != v1) VOR_V(v0, v1, v1);
XVINSVE0_W(v0, d0, 0);
break;
case 0x5C:
@@ -270,13 +283,20 @@ uintptr_t dynarec64_AVX_F2_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
d0 = fpu_get_scratch(dyn);
FSUB_D(d0, v1, v2);
if (!BOX64ENV(dynarec_fastnan)) {
d1 = fpu_get_scratch(dyn);
FCMP_D(fcc0, v1, v2, cUN);
BCNEZ_MARK(fcc0);
FCMP_D(fcc1, d0, d0, cOR);
BCNEZ_MARK(fcc1);
FNEG_D(d0, d0);
MARK;
MOVFR2GR_D(x4, v1);
MOV64x(x5, 0x0008000000000000LL);
OR(x4, x4, x5);
MOVGR2FR_D(d1, x4);
FCMP_D(fcc0, v1, v1, cUN);
FSEL(d0, d0, d1, fcc0);
}
MARK;
if (v0 != v1) VOR_V(v0, v1, v1);
VEXTRINS_D(v0, d0, 0);
break;
@@ -305,13 +325,20 @@ uintptr_t dynarec64_AVX_F2_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
d0 = fpu_get_scratch(dyn);
FDIV_D(d0, v1, v2);
if (!BOX64ENV(dynarec_fastnan)) {
d1 = fpu_get_scratch(dyn);
FCMP_D(fcc0, v1, v2, cUN);
BCNEZ_MARK(fcc0);
FCMP_D(fcc1, d0, d0, cOR);
BCNEZ_MARK(fcc1);
FNEG_D(d0, d0);
MARK;
MOVFR2GR_D(x4, v1);
MOV64x(x5, 0x0008000000000000LL);
OR(x4, x4, x5);
MOVGR2FR_D(d1, x4);
FCMP_D(fcc0, v1, v1, cUN);
FSEL(d0, d0, d1, fcc0);
}
MARK;
if (v0 != v1) VOR_V(v0, v1, v1);
VEXTRINS_D(v0, d0, 0);
break;
@@ -359,10 +386,16 @@ uintptr_t dynarec64_AVX_F2_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
}
VFADDxy(S, v0, q0, v0);
if (!BOX64ENV(dynarec_fastnan)) {
q1 = fpu_get_scratch(dyn);
VFCMPxy(S, q1, q0, q0, cUN);
VLDIxy(d1, (0b010 << 9) | 0b0000000100);
VSLLIxy(W, d1, d1, 20);
VOR_Vxy(d1, q0, d1);
VBITSEL_Vxy(v0, v0, d1, q1);
VFCMPxy(S, d1, v0, v0, cUN);
VANDN_Vxy(d0, d0, d1);
VLDIxy(d1, (0b010 << 9) | 0b1111111100);
VSLLIxy(W, d1, d1, 20); // broadcast 0xFFC00000
VSLLIxy(W, d1, d1, 20);
VBITSEL_Vxy(v0, v0, d1, d0);
}
break;
@@ -380,10 +413,16 @@ uintptr_t dynarec64_AVX_F2_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
}
VFSUBxy(S, v0, q0, v0);
if (!BOX64ENV(dynarec_fastnan)) {
q1 = fpu_get_scratch(dyn);
VFCMPxy(S, q1, q0, q0, cUN);
VLDIxy(d1, (0b010 << 9) | 0b0000000100);
VSLLIxy(W, d1, d1, 20);
VOR_Vxy(d1, q0, d1);
VBITSEL_Vxy(v0, v0, d1, q1);
VFCMPxy(S, d1, v0, v0, cUN);
VANDN_Vxy(d0, d0, d1);
VLDIxy(d1, (0b010 << 9) | 0b1111111100);
VSLLIxy(W, d1, d1, 20); // broadcast 0xFFC00000
VSLLIxy(W, d1, d1, 20);
VBITSEL_Vxy(v0, v0, d1, d0);
}
break;
@@ -423,7 +462,12 @@ uintptr_t dynarec64_AVX_F2_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
if (!BOX64ENV(dynarec_fastnan)) {
d0 = fpu_get_scratch(dyn);
d1 = fpu_get_scratch(dyn);
q1 = fpu_get_scratch(dyn);
VFCMPxy(S, d0, v1, v2, cUN);
VFCMPxy(S, q1, v1, v1, cUN);
VLDIxy(d1, (0b010 << 9) | 0b0000000100);
VSLLIxy(W, d1, d1, 20);
VOR_Vxy(d1, v1, d1);
}
q0 = fpu_get_scratch(dyn);
VFSUBxy(S, q0, v1, v2);
@@ -431,10 +475,11 @@ uintptr_t dynarec64_AVX_F2_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
VEXTRINSxy(W, v0, q0, VEXTRINS_IMM_4_0(0, 0));
VEXTRINSxy(W, v0, q0, VEXTRINS_IMM_4_0(2, 2));
if (!BOX64ENV(dynarec_fastnan)) {
VFCMPxy(S, d1, v0, v0, cUN);
VANDN_Vxy(d0, d0, d1);
VBITSEL_Vxy(v0, v0, d1, q1);
VFCMPxy(S, q1, v0, v0, cUN);
VANDN_Vxy(d0, d0, q1);
VLDIxy(d1, (0b010 << 9) | 0b1111111100);
VSLLIxy(W, d1, d1, 20); // broadcast 0xFFC00000
VSLLIxy(W, d1, d1, 20);
VBITSEL_Vxy(v0, v0, d1, d0);
}
break;
@@ -446,21 +491,23 @@ uintptr_t dynarec64_AVX_F2_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
u8 = sse_setround(dyn, ninst, x1, x2);
d0 = fpu_get_scratch(dyn);
if (vex.l) {
XVXOR_V(d0, d0, d0);
XVFTINT_W_D(v0, d0, v1); // v0 [lo0, lo1, --, --, hi0, hi1, --, -- ]
if (!BOX64ENV(dynarec_fastround)) {
q0 = fpu_get_scratch(dyn);
q1 = fpu_get_scratch(dyn);
q2 = fpu_get_scratch(dyn);
d1 = fpu_get_scratch(dyn);
XVFTINT_L_D(q2, v1);
XVFCMP_D(d1, v1, v1, cUN); // get NaN mask
}
XVXOR_V(d0, d0, d0);
XVFTINT_W_D(v0, d0, v1); // v0 [lo0, lo1, --, --, hi0, hi1, --, -- ]
if (!BOX64ENV(dynarec_fastround)) {
XVLDI(q0, 0b1001110000000); // broadcast 0x80000000 to all
MOV32w(x5, 0x7FFFFFFF);
BSTRPICK_D(x5, x5, 31, 0);
XVREPLGR2VR_D(q1, x5);
XVFCMP_D(d0, v1, v1, cUN); // get Nan mask
XVSLT_D(d1, q1, q2); // get +inf mask
XVOR_V(d0, d1, d0);
XVREPLGR2VR_D(q1, x5);
XVSLT_D(d0, q1, q2); // get +inf mask
XVOR_V(d0, d0, d1); // combine with NaN mask
XVSRLNI_W_D(d0, d0, 0); // [A,B,C,D] => [a,b,--,--,c,d,--,--]
XVBITSEL_V(v0, v0, q0, d0);
}
@@ -476,15 +523,14 @@ uintptr_t dynarec64_AVX_F2_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
VLDI(q0, 0b1001110000000); // broadcast 0x80000000 to all
MOV32w(x5, 0x7FFFFFFF);
BSTRPICK_D(x5, x5, 31, 0);
VREPLGR2VR_D(q1, x5);
VSLT_D(q1, q1, d1); // get +inf mask
VREPLGR2VR_D(q1, x5);
VSLT_D(q1, q1, d1); // get +inf mask
VFCMP_D(q2, v1, v1, cUN); // get Nan mask
VOR_V(q1, q1, q2);
VSHUF4I_W(q1, q1, 0b11011000);
VBITSEL_V(d0, d0, q0, q1);
}
XVPICKVE_D(v0, d0, 0);
YMM_UNMARK_UPPER_ZERO(v0);
}
x87_restoreround(dyn, ninst, u8);
break;
+8 -10
View File
@@ -92,22 +92,20 @@ uintptr_t dynarec64_AVX_F2_0F38(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t i
GETGD;
GETED(0);
GETVD;
if ((gd == xRDX) || (gd == ed) || (gd == vd))
gb1 = x3;
else
gb1 = gd;
if (rex.w) {
if ((gd == xRDX) || (gd == ed) || (gd == vd))
gb1 = x3;
else
gb1 = gd;
MULH_DU(gb1, xRDX, ed);
if (gd != vd) { MUL_D(vd, xRDX, ed); }
if (gb1 == x3) {
OR(gd, gb1, gb1);
MV(gd, gb1);
}
} else {
MULH_WU(gb1, xRDX, ed);
if (gd != vd) { MUL_W(vd, xRDX, ed); }
}
if (gb1 == x3) {
BSTRINS_D(gd, gb1, 31, 0);
MULW_D_WU(x3, xRDX, ed);
if (gd != vd) { ZEROUP2(vd, x3); }
SRLI_D(gd, x3, 32);
}
break;
case 0xF7:
+41 -15
View File
@@ -60,7 +60,6 @@ uintptr_t dynarec64_AVX_F3_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
GETEYSS(q2, 0, 0);
GETGYx_empty(q0);
XVPICKVE_W(q0, q2, 0);
YMM_UNMARK_UPPER_ZERO(q0);
}
break;
case 0x11:
@@ -121,7 +120,7 @@ uintptr_t dynarec64_AVX_F3_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
if (!BOX64ENV(dynarec_fastround)) {
x87_restoreround(dyn, ninst, u8);
}
if(v0 != v1) VOR_V(v0, v1, v1);
if (v0 != v1) VOR_V(v0, v1, v1);
VEXTRINS_W(v0, d1, 0);
break;
case 0x2C:
@@ -212,9 +211,9 @@ uintptr_t dynarec64_AVX_F3_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
GETGYx_empty(v0);
d0 = fpu_get_scratch(dyn);
if (cpuext.frecipe) {
FRSQRTE_S(d0, v1);
FRSQRTE_S(d0, v2);
} else {
FRSQRT_S(d0, v1);
FRSQRT_S(d0, v2);
}
if (v0 != v1) VOR_V(v0, v1, v1);
VEXTRINS_W(v0, d0, 0);
@@ -227,9 +226,9 @@ uintptr_t dynarec64_AVX_F3_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
GETGYx_empty(v0);
d0 = fpu_get_scratch(dyn);
if (cpuext.frecipe) {
FRECIPE_S(d0, v1);
FRECIPE_S(d0, v2);
} else {
FRECIP_S(d0, v1);
FRECIP_S(d0, v2);
}
if (v0 != v1) VOR_V(v0, v1, v1);
VEXTRINS_W(v0, d0, 0);
@@ -243,13 +242,20 @@ uintptr_t dynarec64_AVX_F3_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
d0 = fpu_get_scratch(dyn);
FADD_S(d0, v1, v2);
if (!BOX64ENV(dynarec_fastnan)) {
d1 = fpu_get_scratch(dyn);
FCMP_S(fcc0, v1, v2, cUN);
BCNEZ_MARK(fcc0);
FCMP_S(fcc1, d0, d0, cOR);
BCNEZ_MARK(fcc1);
FNEG_S(d0, d0);
MARK;
MOVFR2GR_D(x4, v1);
MOV32w(x5, 0x00400000);
OR(x4, x4, x5);
MOVGR2FR_D(d1, x4);
FCMP_S(fcc0, v1, v1, cUN);
FSEL(d0, d0, d1, fcc0);
}
MARK;
if (v0 != v1) VOR_V(v0, v1, v1);
VEXTRINS_W(v0, d0, 0);
break;
@@ -267,8 +273,15 @@ uintptr_t dynarec64_AVX_F3_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
FCMP_S(fcc1, d0, d0, cOR);
BCNEZ_MARK(fcc1);
FNEG_S(d0, d0);
MARK;
d1 = fpu_get_scratch(dyn);
MOVFR2GR_D(x4, v1);
MOV32w(x5, 0x00400000);
OR(x4, x4, x5);
MOVGR2FR_D(d1, x4);
FCMP_S(fcc0, v1, v1, cUN);
FSEL(d0, d0, d1, fcc0);
}
MARK;
if (v0 != v1) VOR_V(v0, v1, v1);
VEXTRINS_W(v0, d0, 0);
break;
@@ -280,7 +293,7 @@ uintptr_t dynarec64_AVX_F3_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
GETGYx_empty(v0);
d1 = fpu_get_scratch(dyn);
FCVT_D_S(d1, v2);
if(v0 != v1) VOR_V(v0, v1, v1);
if (v0 != v1) VOR_V(v0, v1, v1);
VEXTRINS_D(v0, d1, 0);
break;
case 0x5B:
@@ -326,13 +339,20 @@ uintptr_t dynarec64_AVX_F3_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
d0 = fpu_get_scratch(dyn);
FSUB_S(d0, v1, v2);
if (!BOX64ENV(dynarec_fastnan)) {
d1 = fpu_get_scratch(dyn);
FCMP_S(fcc0, v1, v2, cUN);
BCNEZ_MARK(fcc0);
FCMP_S(fcc1, d0, d0, cOR);
BCNEZ_MARK(fcc1);
FNEG_S(d0, d0);
MARK;
MOVFR2GR_D(x4, v1);
MOV32w(x5, 0x00400000);
OR(x4, x4, x5);
MOVGR2FR_D(d1, x4);
FCMP_S(fcc0, v1, v1, cUN);
FSEL(d0, d0, d1, fcc0);
}
MARK;
if (v0 != v1) VOR_V(v0, v1, v1);
VEXTRINS_W(v0, d0, 0);
break;
@@ -357,13 +377,20 @@ uintptr_t dynarec64_AVX_F3_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
d0 = fpu_get_scratch(dyn);
FDIV_S(d0, v1, v2);
if (!BOX64ENV(dynarec_fastnan)) {
d1 = fpu_get_scratch(dyn);
FCMP_S(fcc0, v1, v2, cUN);
BCNEZ_MARK(fcc0);
FCMP_S(fcc1, d0, d0, cOR);
BCNEZ_MARK(fcc1);
FNEG_S(d0, d0);
MARK;
MOVFR2GR_D(x4, v1);
MOV32w(x5, 0x00400000);
OR(x4, x4, x5);
MOVGR2FR_D(d1, x4);
FCMP_S(fcc0, v1, v1, cUN);
FSEL(d0, d0, d1, fcc0);
}
MARK;
if (v0 != v1) VOR_V(v0, v1, v1);
VEXTRINS_W(v0, d0, 0);
break;
@@ -420,7 +447,6 @@ uintptr_t dynarec64_AVX_F3_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
GETEYSD(q1, 0, 0);
GETGYx_empty(q0);
XVPICKVE_D(q0, q1, 0);
YMM_UNMARK_UPPER_ZERO(q0);
break;
case 0x7F:
INST_NAME("VMOVDQU Ex, Gx");
@@ -476,17 +502,17 @@ uintptr_t dynarec64_AVX_F3_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
INST_NAME("VCVTDQ2PD Gx, Ex");
nextop = F8;
d0 = fpu_get_scratch(dyn);
if(vex.l){
if (vex.l) {
GETEYx(v1, 0, 0);
GETGYy_empty(v0);
/*
/*
xvffintl.d.w convert [v0,v1,v2,v3,v4,v5,v6,v7] to [v0,v1,v4,v5]
xvffinth.d.w convert [v0,v1,v2,v3,v4,v5,v6,v7] to [v2,v3,v6,v7]
so user xvpermi.d to reorder input [v0v1,v2v3,v4v5,v6v7] to [v0v1,v4v5,v2v3,v6v7]
*/
XVPERMI_D(d0, v1, 0b11011000);
XVFFINTL_D_W(v0, d0);
}else{
} else {
GETEYSD(v1, 0, 0);
GETGYx_empty(v0);
VFFINTL_D_W(v0, v1);
+2
View File
@@ -78,6 +78,8 @@ uintptr_t getConst(la64_consts_t which)
case const_native_fstp: return (uintptr_t)native_fstp;
case const_native_frstor: return (uintptr_t)native_frstor;
case const_native_next: return (uintptr_t)native_next;
case const_native_next_invalid: return (uintptr_t)la64_next_invalid;
case const_la64_crc_autocrc: return (uintptr_t)la64_crc_autocrc;
case const_int3: return (uintptr_t)EmuInt3;
case const_x86syscall: return (uintptr_t)EmuX86Syscall;
case const_x64syscall: return (uintptr_t)EmuX64Syscall;
+2
View File
@@ -48,6 +48,8 @@ typedef enum la64_consts_s {
const_native_fstp,
const_native_frstor,
const_native_next,
const_native_next_invalid,
const_la64_crc_autocrc,
const_int3,
const_x86syscall,
const_x64syscall,
+2 -2
View File
@@ -121,8 +121,8 @@ uintptr_t dynarec64_DD(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
FTINTRZ_L_D(v2, v1);
if (!BOX64ENV(dynarec_fastround)) {
MOVFCSR2GR(x5, FCSR2); // get back FPSR to check
MOV32w(x3, (1 << FR_V));
AND(x5, x5, x3);
MOV32w(x6, (1 << FR_V));
AND(x5, x5, x6);
BEQZ_MARK(x5);
MOV64x(x4, 0x8000000000000000);
MOVGR2FR_D(v2, x4);
+1 -1
View File
@@ -1675,7 +1675,7 @@ void emit_dec32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s
}
}
IFX (X_SF) {
BSTRPICK_D(s5, s1, 31, 31);
BSTRPICK_D(s5, s1, rex.w ? 63 : 31, rex.w ? 63 : 31);
BSTRINS_D(xFlags, s5, F_SF, F_SF);
}
if (!rex.w) ZEROUP(s1);
+19 -11
View File
@@ -58,6 +58,7 @@ uintptr_t dynarec64_F0(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
addr = geted(dyn, addr, ninst, nextop, &wback, x2, x1, &fixedaddress, rex, LOCK_LOCK, 0, 0);
if (cpuext.lam_bh) {
AMADD_DB_B(x1, gd, wback);
ANDI(x1, x1, 0xff);
} else {
LOCK_8_OP(ADD_D(x4, x1, gd), x1, wback, x3, x4, x5, x6);
}
@@ -994,7 +995,10 @@ uintptr_t dynarec64_F0(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
MV(x3, wback);
BSTRINS_D(x3, xZR, 1, 0);
ADDI_D(x1, xZR, u8);
SLL_D(x1, x1, x2);
SLL_W(x4, x1, x2);
ADDI_D(x5, xZR, 0xFF);
SLL_W(x5, x5, x2);
ORN(x1, x4, x5);
AMAND_DB_W(x4, x1, x3);
IFXORNAT (X_ALL | X_PEND) {
SRL_D(x1, x4, x2);
@@ -1129,6 +1133,7 @@ uintptr_t dynarec64_F0(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
} else {
INST_NAME("LOCK ADC Ed, Ib");
}
READFLAGS(X_CF);
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
addr = geted(dyn, addr, ninst, nextop, &wback, x2, x1, &fixedaddress, rex, LOCK_LOCK, 0, (opcode == 0x81) ? 4 : 1);
if (cpuext.lbt) {
@@ -1189,6 +1194,7 @@ uintptr_t dynarec64_F0(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
} else {
INST_NAME("LOCK SBB Ed, Ib");
}
READFLAGS(X_CF);
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
addr = geted(dyn, addr, ninst, nextop, &wback, x2, x1, &fixedaddress, rex, LOCK_LOCK, 0, (opcode == 0x81) ? 4 : 1);
if (cpuext.lbt) {
@@ -1500,11 +1506,11 @@ uintptr_t dynarec64_F0(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
BNEZ_MARK2(x3);
}
if (cpuext.lamcas) {
LD_D(x5, wback, 0);
SUB_D(x4, xZR, x5);
MV(x6, x5);
AMCAS_DB_D(x5, x4, wback);
BNE(x6, x5, -4 * 3);
LD_D(x1, wback, 0);
SUB_D(x4, xZR, x1);
MV(x6, x1);
AMCAS_DB_D(x1, x4, wback);
BNE(x6, x1, -4 * 3);
} else {
LL_D(x1, wback, 0);
SUB_D(x4, xZR, x1);
@@ -1519,11 +1525,11 @@ uintptr_t dynarec64_F0(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
}
// aligned 4byte
if (cpuext.lamcas) {
LD_WU(x5, wback, 0);
SUB_W(x4, xZR, x5);
MV(x6, x5);
AMCAS_DB_W(x5, x4, wback);
BNE(x6, x5, -4 * 3);
LD_WU(x1, wback, 0);
SUB_W(x4, xZR, x1);
SEXT_W(x6, x1);
AMCAS_DB_W(x1, x4, wback);
BNE(x6, x1, -4 * 3);
} else {
LL_W(x1, wback, 0);
SUB_W(x4, xZR, x1);
@@ -1570,6 +1576,7 @@ uintptr_t dynarec64_F0(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
addr = geted(dyn, addr, ninst, nextop, &wback, x2, x1, &fixedaddress, rex, LOCK_LOCK, 0, 0);
if (cpuext.lam_bh) {
AMADD_DB_B(x1, x7, wback);
ANDI(x1, x1, 0xff);
} else {
LOCK_8_OP(ADD_D(x4, x1, x7), x1, wback, x3, x4, x5, x6);
}
@@ -1591,6 +1598,7 @@ uintptr_t dynarec64_F0(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
addr = geted(dyn, addr, ninst, nextop, &wback, x2, x1, &fixedaddress, rex, LOCK_LOCK, 0, 0);
if (cpuext.lam_bh) {
AMADD_DB_B(x1, x7, wback);
ANDI(x1, x1, 0xff);
} else {
LOCK_8_OP(ADD_D(x4, x1, x7), x1, wback, x3, x4, x5, x6);
}
+84 -4
View File
@@ -220,13 +220,20 @@ uintptr_t dynarec64_F20F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
d0 = fpu_get_scratch(dyn);
FADD_D(d0, v0, v1);
if (!BOX64ENV(dynarec_fastnan)) {
d1 = fpu_get_scratch(dyn);
FCMP_D(fcc0, v0, v1, cUN);
BCNEZ_MARK(fcc0);
FCMP_D(fcc1, d0, d0, cOR);
BCNEZ_MARK(fcc1);
FNEG_D(d0, d0);
MARK;
MOVFR2GR_D(x4, v0);
MOV64x(x5, 0x0008000000000000LL);
OR(x4, x4, x5);
MOVGR2FR_D(d1, x4);
FCMP_D(fcc0, v0, v0, cUN);
FSEL(d0, d0, d1, fcc0);
}
MARK;
VEXTRINS_D(v0, d0, 0); // v0[63:0] = d0[63:0]
break;
case 0x59:
@@ -237,13 +244,20 @@ uintptr_t dynarec64_F20F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
d0 = fpu_get_scratch(dyn);
FMUL_D(d0, v0, v1);
if (!BOX64ENV(dynarec_fastnan)) {
d1 = fpu_get_scratch(dyn);
FCMP_D(fcc0, v0, v1, cUN);
BCNEZ_MARK(fcc0);
FCMP_D(fcc1, d0, d0, cOR);
BCNEZ_MARK(fcc1);
FNEG_D(d0, d0);
MARK;
MOVFR2GR_D(x4, v0);
MOV64x(x5, 0x0008000000000000LL);
OR(x4, x4, x5);
MOVGR2FR_D(d1, x4);
FCMP_D(fcc0, v0, v0, cUN);
FSEL(d0, d0, d1, fcc0);
}
MARK;
VEXTRINS_D(v0, d0, 0); // v0[63:0] = d0[63:0]
break;
case 0x5A:
@@ -263,13 +277,20 @@ uintptr_t dynarec64_F20F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
d0 = fpu_get_scratch(dyn);
FSUB_D(d0, v0, v1);
if (!BOX64ENV(dynarec_fastnan)) {
d1 = fpu_get_scratch(dyn);
FCMP_D(fcc0, v0, v1, cUN);
BCNEZ_MARK(fcc0);
FCMP_D(fcc1, d0, d0, cOR);
BCNEZ_MARK(fcc1);
FNEG_D(d0, d0);
MARK;
MOVFR2GR_D(x4, v0);
MOV64x(x5, 0x0008000000000000LL);
OR(x4, x4, x5);
MOVGR2FR_D(d1, x4);
FCMP_D(fcc0, v0, v0, cUN);
FSEL(d0, d0, d1, fcc0);
}
MARK;
VEXTRINS_D(v0, d0, 0); // v0[63:0] = d0[63:0]
break;
case 0x5D:
@@ -293,13 +314,20 @@ uintptr_t dynarec64_F20F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
d0 = fpu_get_scratch(dyn);
FDIV_D(d0, v0, v1);
if (!BOX64ENV(dynarec_fastnan)) {
d1 = fpu_get_scratch(dyn);
FCMP_D(fcc0, v0, v1, cUN);
BCNEZ_MARK(fcc0);
FCMP_D(fcc1, d0, d0, cOR);
BCNEZ_MARK(fcc1);
FNEG_D(d0, d0);
MARK;
MOVFR2GR_D(x4, v0);
MOV64x(x5, 0x0008000000000000LL);
OR(x4, x4, x5);
MOVGR2FR_D(d1, x4);
FCMP_D(fcc0, v0, v0, cUN);
FSEL(d0, d0, d1, fcc0);
}
MARK;
VEXTRINS_D(v0, d0, 0); // v0[63:0] = d0[63:0]
break;
case 0x5F:
@@ -339,7 +367,24 @@ uintptr_t dynarec64_F20F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
v1 = fpu_get_scratch(dyn);
VPICKEV_W(v0, q1, q0);
VPICKOD_W(v1, q1, q0);
if (!BOX64ENV(dynarec_fastnan)) {
d0 = fpu_get_scratch(dyn);
d1 = fpu_get_scratch(dyn);
VFCMP_S(d0, v0, v0, cUN);
MOV32w(x5, 0x00400000);
VREPLGR2VR_W(d1, x5);
VOR_V(d1, v0, d1);
}
VFADD_S(q0, v0, v1);
if (!BOX64ENV(dynarec_fastnan)) {
VBITSEL_V(q0, q0, d1, d0);
VFCMP_S(d1, q0, q0, cUN);
VFCMP_S(d0, v0, v1, cUN);
VANDN_V(d0, d0, d1);
VLDI(d1, 0b011111111100);
VSLLI_W(d1, d1, 20);
VBITSEL_V(q0, q0, d1, d0);
}
break;
case 0x7D:
INST_NAME("HSUBPS Gx, Ex");
@@ -350,7 +395,24 @@ uintptr_t dynarec64_F20F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
v1 = fpu_get_scratch(dyn);
VPICKEV_W(v0, q1, q0);
VPICKOD_W(v1, q1, q0);
if (!BOX64ENV(dynarec_fastnan)) {
d0 = fpu_get_scratch(dyn);
d1 = fpu_get_scratch(dyn);
VFCMP_S(d0, v0, v0, cUN);
MOV32w(x5, 0x00400000);
VREPLGR2VR_W(d1, x5);
VOR_V(d1, v0, d1);
}
VFSUB_S(q0, v0, v1);
if (!BOX64ENV(dynarec_fastnan)) {
VBITSEL_V(q0, q0, d1, d0);
VFCMP_S(d1, q0, q0, cUN);
VFCMP_S(d0, v0, v1, cUN);
VANDN_V(d0, d0, d1);
VLDI(d1, 0b011111111100);
VSLLI_W(d1, d1, 20);
VBITSEL_V(q0, q0, d1, d0);
}
break;
case 0xAE:
nextop = F8;
@@ -391,11 +453,29 @@ uintptr_t dynarec64_F20F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
nextop = F8;
GETGX(q0, 1);
GETEX(q1, 0, 0);
if (!BOX64ENV(dynarec_fastnan)) {
d0 = fpu_get_scratch(dyn);
d1 = fpu_get_scratch(dyn);
v1 = fpu_get_scratch(dyn);
VFCMP_S(d0, q0, q1, cUN);
VFCMP_S(d1, q0, q0, cUN);
MOV32w(x5, 0x00400000);
VREPLGR2VR_W(v1, x5);
VOR_V(v1, q0, v1);
}
v0 = fpu_get_scratch(dyn);
VFSUB_S(v0, q0, q1);
VFADD_S(q0, q0, q1);
VEXTRINS_W(q0, v0, 0);
VEXTRINS_W(q0, v0, 0b00100010);
if (!BOX64ENV(dynarec_fastnan)) {
VBITSEL_V(q0, q0, v1, d1);
VFCMP_S(d1, q0, q0, cUN);
VANDN_V(d0, d0, d1);
VLDI(d1, 0b011111111100);
VSLLI_W(d1, d1, 20);
VBITSEL_V(q0, q0, d1, d0);
}
break;
case 0xD6:
INST_NAME("MOVDQ2Q Gm, Ex");
+67
View File
@@ -270,6 +270,13 @@ uintptr_t dynarec64_F30F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
d1 = fpu_get_scratch(dyn);
GETEXSS(d0, 0, 0);
FSQRT_S(d1, d0);
if (!BOX64ENV(dynarec_fastnan)) {
v1 = fpu_get_scratch(dyn);
MOVGR2FR_W(v1, xZR);
FCMP_S(fcc0, d0, v1, cLT);
BCEQZ(fcc0, 4 + 4);
FNEG_S(d1, d1);
}
VEXTRINS_W(v0, d1, 0);
break;
case 0x52:
@@ -301,6 +308,21 @@ uintptr_t dynarec64_F30F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
d1 = fpu_get_scratch(dyn);
GETEXSS(d0, 0, 0);
FADD_S(d1, v0, d0);
if (!BOX64ENV(dynarec_fastnan)) {
q0 = fpu_get_scratch(dyn);
FCMP_S(fcc0, v0, d0, cUN);
BCNEZ_MARK(fcc0);
FCMP_S(fcc1, d1, d1, cOR);
BCNEZ_MARK(fcc1);
FNEG_S(d1, d1);
MARK;
MOVFR2GR_D(x4, v0);
MOV32w(x5, 0x00400000);
OR(x4, x4, x5);
MOVGR2FR_D(q0, x4);
FCMP_S(fcc0, v0, v0, cUN);
FSEL(d1, d1, q0, fcc0);
}
VEXTRINS_W(v0, d1, 0);
break;
case 0x59:
@@ -310,6 +332,21 @@ uintptr_t dynarec64_F30F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
d1 = fpu_get_scratch(dyn);
GETEXSS(d0, 0, 0);
FMUL_S(d1, v0, d0);
if (!BOX64ENV(dynarec_fastnan)) {
q0 = fpu_get_scratch(dyn);
FCMP_S(fcc0, v0, d0, cUN);
BCNEZ_MARK(fcc0);
FCMP_S(fcc1, d1, d1, cOR);
BCNEZ_MARK(fcc1);
FNEG_S(d1, d1);
MARK;
MOVFR2GR_D(x4, v0);
MOV32w(x5, 0x00400000);
OR(x4, x4, x5);
MOVGR2FR_D(q0, x4);
FCMP_S(fcc0, v0, v0, cUN);
FSEL(d1, d1, q0, fcc0);
}
VEXTRINS_W(v0, d1, 0);
break;
case 0x5A:
@@ -353,6 +390,21 @@ uintptr_t dynarec64_F30F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
d1 = fpu_get_scratch(dyn);
GETEXSS(d0, 0, 0);
FSUB_S(d1, v0, d0);
if (!BOX64ENV(dynarec_fastnan)) {
q0 = fpu_get_scratch(dyn);
FCMP_S(fcc0, v0, d0, cUN);
BCNEZ_MARK(fcc0);
FCMP_S(fcc1, d1, d1, cOR);
BCNEZ_MARK(fcc1);
FNEG_S(d1, d1);
MARK;
MOVFR2GR_D(x4, v0);
MOV32w(x5, 0x00400000);
OR(x4, x4, x5);
MOVGR2FR_D(q0, x4);
FCMP_S(fcc0, v0, v0, cUN);
FSEL(d1, d1, q0, fcc0);
}
VEXTRINS_W(v0, d1, 0);
break;
case 0x5D:
@@ -372,6 +424,21 @@ uintptr_t dynarec64_F30F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
d1 = fpu_get_scratch(dyn);
GETEXSS(d0, 0, 0);
FDIV_S(d1, v0, d0);
if (!BOX64ENV(dynarec_fastnan)) {
q0 = fpu_get_scratch(dyn);
FCMP_S(fcc0, v0, d0, cUN);
BCNEZ_MARK(fcc0);
FCMP_S(fcc1, d1, d1, cOR);
BCNEZ_MARK(fcc1);
FNEG_S(d1, d1);
MARK;
MOVFR2GR_D(x4, v0);
MOV32w(x5, 0x00400000);
OR(x4, x4, x5);
MOVGR2FR_D(q0, x4);
FCMP_S(fcc0, v0, v0, cUN);
FSEL(d1, d1, q0, fcc0);
}
VEXTRINS_W(v0, d1, 0);
break;
case 0x5F:
+4 -3
View File
@@ -485,6 +485,7 @@ void lsxcacheUnwind(lsxcache_t* cache)
case LSX_CACHE_YMMR:
case LSX_CACHE_YMMW:
cache->avxcache[cache->lsxcache[i].n].reg = i;
cache->avxcache[cache->lsxcache[i].n].dirty = 0;
cache->avxcache[cache->lsxcache[i].n].write = (cache->lsxcache[i].t == LSX_CACHE_YMMW) ? 1 : 0;
break;
case LSX_CACHE_ST_F:
@@ -516,7 +517,7 @@ const char* getCacheName(int t, int n)
case LSX_CACHE_XMMW: sprintf(buff, "XMM%d", n); break;
case LSX_CACHE_XMMR: sprintf(buff, "xmm%d", n); break;
case LSX_CACHE_YMMW: sprintf(buff, "YMM%d", n); break;
case LSX_CACHE_YMMR: sprintf(buff, "ymm%d", n); break;
case LSX_CACHE_YMMR: sprintf(buff, "ymm%d", n); break;
case LSX_CACHE_SCR: sprintf(buff, "Scratch"); break;
case LSX_CACHE_NONE: buff[0] = '\0'; break;
}
@@ -640,8 +641,8 @@ void inst_name_pass3(dynarec_native_t* dyn, int ninst, const char* name, rex_t r
case LSX_CACHE_MM: length += sprintf(buf + length, " %s:%s", Ft[ii], getCacheName(dyn->insts[ninst].lsx.lsxcache[ii].t, dyn->insts[ninst].lsx.lsxcache[ii].n)); break;
case LSX_CACHE_XMMW: length += sprintf(buf + length, " %s:%s", Vt[ii], getCacheName(dyn->insts[ninst].lsx.lsxcache[ii].t, dyn->insts[ninst].lsx.lsxcache[ii].n)); break;
case LSX_CACHE_XMMR: length += sprintf(buf + length, " %s:%s", Vt[ii], getCacheName(dyn->insts[ninst].lsx.lsxcache[ii].t, dyn->insts[ninst].lsx.lsxcache[ii].n)); break;
case LSX_CACHE_YMMW: length += sprintf(buf + length, " %s:%s%s", XVt[ii], getCacheName(dyn->insts[ninst].lsx.lsxcache[ii].t, dyn->insts[ninst].lsx.lsxcache[ii].n), dyn->insts[ninst].lsx.avxcache[dyn->insts[ninst].lsx.lsxcache[ii].n].zero_upper == 1 ? "-UZ" : ""); break;
case LSX_CACHE_YMMR: length += sprintf(buf + length, " %s:%s%s", XVt[ii], getCacheName(dyn->insts[ninst].lsx.lsxcache[ii].t, dyn->insts[ninst].lsx.lsxcache[ii].n), dyn->insts[ninst].lsx.avxcache[dyn->insts[ninst].lsx.lsxcache[ii].n].zero_upper == 1 ? "-UZ" : ""); break;
case LSX_CACHE_YMMW: length += sprintf(buf + length, " %s:%s", XVt[ii], getCacheName(dyn->insts[ninst].lsx.lsxcache[ii].t, dyn->insts[ninst].lsx.lsxcache[ii].n)); break;
case LSX_CACHE_YMMR: length += sprintf(buf + length, " %s:%s", XVt[ii], getCacheName(dyn->insts[ninst].lsx.lsxcache[ii].t, dyn->insts[ninst].lsx.lsxcache[ii].n)); break;
case LSX_CACHE_SCR: length += sprintf(buf + length, " %s:%s", Ft[ii], getCacheName(dyn->insts[ninst].lsx.lsxcache[ii].t, dyn->insts[ninst].lsx.lsxcache[ii].n)); break;
case LSX_CACHE_NONE:
default: break;
+82 -90
View File
@@ -476,7 +476,7 @@ void iret_to_next(dynarec_la64_t* dyn, uintptr_t ip, int ninst, int is32bits, in
ST_H(x2, xEmu, offsetof(x64emu_t, segs[_CS]));
// clean EFLAGS
RESTORE_EFLAGS(x1);
MOV32w(x1, 0x3E7FD7); // also mask RF
MOV32w(x1, 0x3E7FD7); // also mask RF
AND(xFlags, xFlags, x1);
ORI(xFlags, xFlags, 0x2);
SPILL_EFLAGS();
@@ -1207,7 +1207,6 @@ int x87_get_current_cache(dynarec_la64_t* dyn, int ninst, int st, int t)
#endif
return i;
}
assert(dyn->lsx.x87cache[i] < 8);
}
return -1;
}
@@ -1252,7 +1251,7 @@ int x87_get_lsxcache(dynarec_la64_t* dyn, int ninst, int s1, int s2, int st)
|| dyn->lsx.lsxcache[ii].t == LSX_CACHE_ST_I64)
&& dyn->lsx.lsxcache[ii].n == st)
return ii;
assert(0);
dynarec_log(LOG_NONE, "Warning: x87_get_lsxcache didn't find cache for ninst=%d\n", ninst);
return -1;
}
int x87_get_st(dynarec_la64_t* dyn, int ninst, int s1, int s2, int a, int t)
@@ -1262,7 +1261,7 @@ int x87_get_st(dynarec_la64_t* dyn, int ninst, int s1, int s2, int a, int t)
}
int x87_get_st_empty(dynarec_la64_t* dyn, int ninst, int s1, int s2, int a, int t)
{
dyn->insts[ninst].x87_used = 1;
dyn->insts[ninst].x87_used = 1;
return dyn->lsx.x87reg[x87_get_cache(dyn, ninst, 0, s1, s2, a, t)];
}
@@ -1352,17 +1351,11 @@ int sse_get_reg(dynarec_la64_t* dyn, int ninst, int s1, int a, int forwrite)
}
return dyn->lsx.ssecache[a].reg;
}
int need_vld = 1;
// migrate from avx to sse
if (dyn->lsx.avxcache[a].v != -1) {
avx_reflect_reg_upper128(dyn, ninst, a, forwrite);
dyn->lsx.avxcache[a].v = -1;
need_vld = 0;
}
avx_forget_reg(dyn, ninst, a);
dyn->lsx.ssecache[a].reg = fpu_get_reg_xmm(dyn, forwrite ? LSX_CACHE_XMMW : LSX_CACHE_XMMR, a);
int ret = dyn->lsx.ssecache[a].reg;
dyn->lsx.ssecache[a].write = forwrite;
if(need_vld) VLD(ret, xEmu, offsetof(x64emu_t, xmm[a])); //skip VLD if migrate from avx
VLD(ret, xEmu, offsetof(x64emu_t, xmm[a])); // skip VLD if migrate from avx
return ret;
}
@@ -1421,9 +1414,9 @@ void sse_purge07cache(dynarec_la64_t* dyn, int ninst, int s1)
dyn->lsx.xmm_used |= 1 << i;
if (dyn->lsx.lsxcache[dyn->lsx.avxcache[i].reg].t == LSX_CACHE_YMMW) {
VST(dyn->lsx.avxcache[i].reg, xEmu, offsetof(x64emu_t, xmm[i]));
if(dyn->lsx.avxcache[i].zero_upper == 1){
if (dyn->lsx.avxcache[i].dirty) {
XVXOR_V(SCRATCH, SCRATCH, SCRATCH);
}else{
} else {
XVPERMI_Q(SCRATCH, dyn->lsx.avxcache[i].reg, XVPERMI_IMM_4_0(0, 1));
}
VST(SCRATCH, xEmu, offsetof(x64emu_t, ymm[i]));
@@ -1482,46 +1475,26 @@ int avx_get_reg(dynarec_la64_t* dyn, int ninst, int s1, int a, int forwrite, int
dyn->lsx.ymm_used |= 1 << a;
if (dyn->lsx.avxcache[a].v != -1) {
if (forwrite) {
dyn->lsx.avxcache[a].write = 1; // update only if forwrite
if (width == LSX_AVX_WIDTH_128) dyn->lsx.avxcache[a].dirty = 1;
dyn->lsx.lsxcache[dyn->lsx.avxcache[a].reg].t = LSX_CACHE_YMMW;
dyn->lsx.avxcache[a].write = 1;
}
if (width == LSX_AVX_WIDTH_128) {
dyn->lsx.avxcache[a].width = LSX_AVX_WIDTH_128;
if(forwrite) dyn->lsx.avxcache[a].zero_upper = 1;
} else {
// if width changed to 256, and vzeroup ==1, means need zero-fill upper 128bits now.
if (dyn->lsx.avxcache[a].zero_upper == 1) {
dyn->lsx.avxcache[a].zero_upper = 0;
XVXOR_V(SCRATCH, SCRATCH, SCRATCH);
XVPERMI_Q(dyn->lsx.avxcache[a].reg, SCRATCH, 0b00000010);
}
dyn->lsx.avxcache[a].width = LSX_AVX_WIDTH_256;
}
return dyn->lsx.avxcache[a].reg;
}
sse_forget_reg(dyn, ninst, a);
// migrate from sse to avx
if (dyn->lsx.ssecache[a].v != -1) {
// release SSE reg cache
fpu_free_reg(dyn, dyn->lsx.ssecache[a].reg);
dyn->lsx.ssecache[a].v = -1;
}
// new reg
dyn->lsx.avxcache[a].v = 0;
dyn->lsx.avxcache[a].reg = fpu_get_reg_ymm(dyn, forwrite ? LSX_CACHE_YMMW : LSX_CACHE_YMMR, a);
int ret = dyn->lsx.avxcache[a].reg;
dyn->lsx.avxcache[a].write = forwrite;
dyn->lsx.avxcache[a].width = width;
if (width == LSX_AVX_WIDTH_128) {
if(forwrite) dyn->lsx.avxcache[a].zero_upper = 1;
if (forwrite) dyn->lsx.avxcache[a].write = 1;
dyn->lsx.avxcache[a].dirty = 0;
if (width == LSX_AVX_WIDTH_128 && forwrite) {
VLD(ret, xEmu, offsetof(x64emu_t, xmm[a]));
dyn->lsx.avxcache[a].dirty = 1;
} else {
VLD(ret, xEmu, offsetof(x64emu_t, xmm[a]));
VLD(SCRATCH, xEmu, offsetof(x64emu_t, ymm[a]));
XVPERMI_Q(ret, SCRATCH, XVPERMI_IMM_4_0(0, 2));
dyn->lsx.avxcache[a].zero_upper = 0;
}
return ret;
}
@@ -1532,30 +1505,15 @@ int avx_get_reg_empty(dynarec_la64_t* dyn, int ninst, int s1, int a, int width)
if (dyn->lsx.avxcache[a].v != -1) {
dyn->lsx.avxcache[a].write = 1;
dyn->lsx.lsxcache[dyn->lsx.avxcache[a].reg].t = LSX_CACHE_YMMW;
if (width == LSX_AVX_WIDTH_128) {
dyn->lsx.avxcache[a].width = LSX_AVX_WIDTH_128;
dyn->lsx.avxcache[a].zero_upper = 1;
} else {
dyn->lsx.avxcache[a].width = LSX_AVX_WIDTH_256;
dyn->lsx.avxcache[a].zero_upper = 0;
}
dyn->lsx.avxcache[a].dirty = width == LSX_AVX_WIDTH_128;
return dyn->lsx.avxcache[a].reg;
}
// migrate from sse to avx
if (dyn->lsx.ssecache[a].v != -1) {
// Release SSE reg cache
fpu_free_reg(dyn, dyn->lsx.ssecache[a].reg);
dyn->lsx.ssecache[a].v = -1;
}
fpu_free_reg(dyn, dyn->lsx.ssecache[a].reg);
dyn->lsx.ssecache[a].v = -1;
dyn->lsx.avxcache[a].v = 0;
dyn->lsx.avxcache[a].reg = fpu_get_reg_ymm(dyn, LSX_CACHE_YMMW, a);
dyn->lsx.avxcache[a].write = 1;
dyn->lsx.avxcache[a].width = width;
if (width == LSX_AVX_WIDTH_128){
dyn->lsx.avxcache[a].zero_upper = 1;
} else {
dyn->lsx.avxcache[a].zero_upper = 0;
}
dyn->lsx.avxcache[a].dirty = width == LSX_AVX_WIDTH_128;
return dyn->lsx.avxcache[a].reg;
}
@@ -1565,11 +1523,7 @@ void avx_reflect_reg_upper128(dynarec_la64_t* dyn, int ninst, int a, int forwrit
if (dyn->lsx.avxcache[a].v == -1 || forwrite == 0)
return;
if (dyn->lsx.lsxcache[dyn->lsx.avxcache[a].reg].t == LSX_CACHE_YMMW) {
if (dyn->lsx.avxcache[a].zero_upper == 1) {
XVXOR_V(SCRATCH, SCRATCH, SCRATCH);
} else {
XVPERMI_Q(SCRATCH, dyn->lsx.avxcache[a].reg, XVPERMI_IMM_4_0(0, 1));
}
XVPERMI_Q(SCRATCH, dyn->lsx.avxcache[a].reg, XVPERMI_IMM_4_0(0, 1));
VST(SCRATCH, xEmu, offsetof(x64emu_t, ymm[a]));
}
dyn->lsx.avxcache[a].v = -1;
@@ -1583,7 +1537,7 @@ void avx_forget_reg(dynarec_la64_t* dyn, int ninst, int a)
return;
if (dyn->lsx.lsxcache[dyn->lsx.avxcache[a].reg].t == LSX_CACHE_YMMW) {
VST(dyn->lsx.avxcache[a].reg, xEmu, offsetof(x64emu_t, xmm[a]));
if (dyn->lsx.avxcache[a].zero_upper == 1) {
if (dyn->lsx.avxcache[a].dirty) {
XVXOR_V(SCRATCH, SCRATCH, SCRATCH);
} else {
XVPERMI_Q(SCRATCH, dyn->lsx.avxcache[a].reg, XVPERMI_IMM_4_0(0, 1));
@@ -1602,14 +1556,35 @@ void avx_reflect_reg(dynarec_la64_t* dyn, int ninst, int a)
return;
if (dyn->lsx.lsxcache[dyn->lsx.avxcache[a].reg].t == LSX_CACHE_YMMW) {
VST(dyn->lsx.avxcache[a].reg, xEmu, offsetof(x64emu_t, xmm[a]));
if (dyn->lsx.avxcache[a].zero_upper == 1) {
if (dyn->lsx.avxcache[a].dirty) {
XVXOR_V(SCRATCH, SCRATCH, SCRATCH);
XVPERMI_Q(dyn->lsx.avxcache[a].reg, SCRATCH, 0b00000010);
} else {
XVPERMI_Q(SCRATCH, dyn->lsx.avxcache[a].reg, XVPERMI_IMM_4_0(0, 1));
}
VST(SCRATCH, xEmu, offsetof(x64emu_t, ymm[a]));
dyn->lsx.avxcache[a].zero_upper = 0;
dyn->lsx.avxcache[a].dirty = 0;
}
}
void avx_cleancache(dynarec_la64_t* dyn, int ninst)
{
int old = -1;
for (int i = 0; i < 16; ++i)
if (dyn->lsx.avxcache[i].v != -1) {
dyn->lsx.ymm_used |= 1 << i;
if (dyn->lsx.avxcache[i].dirty) {
if (old == -1) {
MESSAGE(LOG_DUMP, "\tClean AVX Cache ------\n");
++old;
}
XVXOR_V(SCRATCH, SCRATCH, SCRATCH);
XVPERMI_Q(dyn->lsx.avxcache[i].reg, SCRATCH, 0b00000010);
dyn->lsx.avxcache[i].dirty = 0;
}
}
if (old != -1) {
MESSAGE(LOG_DUMP, "\t------ Clean AVX Cache\n");
}
}
@@ -1625,15 +1600,15 @@ static void avx_purgecache(dynarec_la64_t* dyn, int ninst, int next, int s1)
MESSAGE(LOG_DUMP, "\tPurge %sAVX Cache ------\n", next ? "locally " : "");
++old;
}
if (dyn->lsx.lsxcache[dyn->lsx.avxcache[i].reg].t == LSX_CACHE_YMMW) {
VST(dyn->lsx.avxcache[i].reg, xEmu, offsetof(x64emu_t, xmm[i]));
if (dyn->lsx.avxcache[i].zero_upper == 1) {
XVXOR_V(SCRATCH, SCRATCH, SCRATCH);
} else {
XVPERMI_Q(SCRATCH, dyn->lsx.avxcache[i].reg, XVPERMI_IMM_4_0(0, 1));
}
VST(SCRATCH, xEmu, offsetof(x64emu_t, ymm[i]));
VST(dyn->lsx.avxcache[i].reg, xEmu, offsetof(x64emu_t, xmm[i]));
if (dyn->lsx.avxcache[i].dirty) {
XVXOR_V(SCRATCH, SCRATCH, SCRATCH);
} else {
XVPERMI_Q(SCRATCH, dyn->lsx.avxcache[i].reg, XVPERMI_IMM_4_0(0, 1));
}
VST(SCRATCH, xEmu, offsetof(x64emu_t, ymm[i]));
} else {
MESSAGE(LOG_DUMP, "\tAVX Cache for YMM%d is not write, no need to store back %d\n", i, dyn->lsx.lsxcache[dyn->lsx.avxcache[i].reg].t);
}
if (!next) {
fpu_free_reg(dyn, dyn->lsx.avxcache[i].reg);
@@ -1678,11 +1653,11 @@ void fpu_pushcache(dynarec_la64_t* dyn, int ninst, int s1, int not07)
VST(dyn->lsx.ssecache[i].reg, xEmu, offsetof(x64emu_t, xmm[i]));
}
if ((dyn->lsx.avxcache[i].v != -1) && (dyn->lsx.avxcache[i].write)) {
VST(dyn->lsx.avxcache[i].reg, xEmu, offsetof(x64emu_t, xmm[i]));
if (dyn->lsx.avxcache[i].zero_upper == 0) {
XVPERMI_Q(SCRATCH, dyn->lsx.avxcache[i].reg, XVPERMI_IMM_4_0(0, 1));
VST(SCRATCH, xEmu, offsetof(x64emu_t, ymm[i]));
}
VST(dyn->lsx.avxcache[i].reg, xEmu, offsetof(x64emu_t, xmm[i]));
if (!dyn->lsx.avxcache[i].dirty) {
XVPERMI_Q(SCRATCH, dyn->lsx.avxcache[i].reg, XVPERMI_IMM_4_0(0, 1));
VST(SCRATCH, xEmu, offsetof(x64emu_t, ymm[i]));
}
}
}
MESSAGE(LOG_DUMP, "\t------- Pushed XMM/YMM Cache (%d)\n", n);
@@ -1707,7 +1682,7 @@ void fpu_popcache(dynarec_la64_t* dyn, int ninst, int s1, int not07)
}
if (dyn->lsx.avxcache[i].v != -1) {
VLD(dyn->lsx.avxcache[i].reg, xEmu, offsetof(x64emu_t, xmm[i]));
if (dyn->lsx.avxcache[i].zero_upper == 0) {
if (!dyn->lsx.avxcache[i].dirty) {
VLD(SCRATCH, xEmu, offsetof(x64emu_t, ymm[i]));
XVPERMI_Q(dyn->lsx.avxcache[i].reg, SCRATCH, XVPERMI_IMM_4_0(0, 2));
}
@@ -1764,15 +1739,15 @@ void emit_pf(dynarec_la64_t* dyn, int ninst, int s1, int s3, int s4)
void fpu_reset_cache(dynarec_la64_t* dyn, int ninst, int reset_n)
{
MESSAGE(LOG_DEBUG, "Reset Caches with %d\n", reset_n);
#if STEP > 1
#if STEP > 1
// for STEP 2 & 3, just need to refresh with current, and undo the changes (push & swap)
dyn->lsx = dyn->insts[ninst].lsx;
lsxcacheUnwind(&dyn->lsx);
#else
dyn->lsx = dyn->insts[reset_n].lsx;
dyn->lsx = dyn->insts[reset_n].lsx;
#endif
#if STEP == 0
if(dyn->need_dump && dyn->lsx.x87stack) dynarec_log(LOG_NONE, "New x87stack=%d at ResetCache in inst %d with %d\n", dyn->lsx.x87stack, ninst, reset_n);
if (dyn->need_dump && dyn->lsx.x87stack) dynarec_log(LOG_NONE, "New x87stack=%d at ResetCache in inst %d with %d\n", dyn->lsx.x87stack, ninst, reset_n);
#endif
#if defined(HAVE_TRACE) && (STEP > 2)
if (dyn->need_dump && 0) // disable for now
@@ -2120,8 +2095,6 @@ static void fpuCacheTransform(dynarec_la64_t* dyn, int ninst, int s1, int s2, in
lsxcache_t cache = dyn->lsx;
int s1_val = 0;
int s2_val = 0;
// unload every unneeded cache
// check SSE first, than MMX, in order, for optimization issue
for (int i = 0; i < 16; ++i) {
int j = findCacheSlot(dyn, ninst, LSX_CACHE_YMMW, i, &cache);
if (j >= 0 && findCacheSlot(dyn, ninst, LSX_CACHE_YMMW, i, &cache_i2) == -1)
@@ -2185,14 +2158,12 @@ static void fpuCacheTransform(dynarec_la64_t* dyn, int ninst, int s1, int s2, in
} else if (cache.lsxcache[i].t == LSX_CACHE_YMMR && cache_i2.lsxcache[i].t == LSX_CACHE_YMMW) {
cache.lsxcache[i].t = LSX_CACHE_YMMW;
} else if (cache.lsxcache[i].t == LSX_CACHE_YMMW && cache_i2.lsxcache[i].t == LSX_CACHE_YMMR) {
// refresh cache...
MESSAGE(LOG_DUMP, "\t - Refreh %s\n", getCacheName(cache.lsxcache[i].t, cache.lsxcache[i].n));
MESSAGE(LOG_DUMP, "\t - Refresh %s\n", getCacheName(cache.lsxcache[i].t, cache.lsxcache[i].n));
XVPERMI_Q(SCRATCH, i, XVPERMI_IMM_4_0(0, 1));
VST(i, xEmu, offsetof(x64emu_t, xmm[cache.lsxcache[i].n]));
VST(SCRATCH, xEmu, offsetof(x64emu_t, ymm[cache.lsxcache[i].n]));
cache.lsxcache[i].t = LSX_CACHE_YMMR;
} else if (cache.lsxcache[i].t == LSX_CACHE_XMMW && cache_i2.lsxcache[i].t == LSX_CACHE_XMMR) {
// refresh cache...
MESSAGE(LOG_DUMP, "\t - Refreh %s\n", getCacheName(cache.lsxcache[i].t, cache.lsxcache[i].n));
VST(i, xEmu, offsetof(x64emu_t, xmm[cache.lsxcache[i].n]));
cache.lsxcache[i].t = LSX_CACHE_XMMR;
@@ -2309,3 +2280,24 @@ void la64_move64(dynarec_la64_t* dyn, int ninst, int reg, int64_t val)
}
LU52I_D(reg, reg, (val >> 52) & 0xfff);
}
void checkCRC(dynarec_la64_t* dyn, int ninst)
{
// la64_crc_autocrc will use x1-x5 instead of A0-A4 to avoind having to move around the regs
// grab the dynablock address in x6, as this on will not be erased by crc functions
int delta = -(dyn->native_size + sizeof(void*));
PCADDU12I(x6, SPLIT20(delta));
LD_D(x6, x6, SPLIT12(delta));
// prepare and call the crc function
TABLE64C(x3, const_la64_crc_autocrc);
LD_D(x1, x6, offsetof(dynablock_t, x64_addr));
LD_WU(x2, x6, offsetof(dynablock_t, x64_size));
JIRL(xRA, x3, 0x0);
// done, result in x1, load the stored hash (sign extended, as the crc will also be sign extended)
LD_W(x2, x6, offsetof(dynablock_t, hash));
// compare computed crc with stored one, jump to continue is equal
BEQ(x1, x2, 4+3*4); // TABLE64C generates 2 opcodes...
TABLE64C(x3, const_native_next_invalid);
JIRL(xRA, x3, 0x0);
}
+26 -6
View File
@@ -416,9 +416,9 @@
BSTRINS_D(wback, ed, wb2 + 7, wb2); \
}
#define YMM_UNMARK_UPPER_ZERO(a) \
do { \
dyn->lsx.avxcache[a].zero_upper = 0; \
#define YMM_UNMARK_UPPER_ZERO(a) \
do { \
dyn->lsx.avxcache[a].dirty = 0; \
} while (0)
// AVX helpers
@@ -1028,6 +1028,15 @@
#ifndef SET_HASCALLRET
#define SET_HASCALLRET()
#endif
#ifndef CALLRET_RET
#define CALLRET_RET(A) do {if(BOX64DRENV(dynarec_callret)>1) {NOP();}} while(0)
#endif
#ifndef CALLRET_GETRET
#define CALLRET_GETRET() (dyn->callrets?(dyn->callrets[dyn->callret_size].offs-dyn->native_size):0)
#endif
#ifndef CALLRET_LOOP
#define CALLRET_LOOP() NOP()
#endif
#define UFLAG_OP1(A) \
if (dyn->insts[ninst].x64.gen_flags) { SDxw(A, xEmu, offsetof(x64emu_t, op1)); }
#define UFLAG_OP2(A) \
@@ -1066,6 +1075,11 @@
#define ARCH_RESET()
#undef PREFLAGSNEEDED
#define PREFLAGSNEEDED() \
if(dyn->always_test && ninst && (dyn->insts[ninst].sep || (ninst && dyn->insts[ninst-1].x64.has_callret))) \
checkCRC(dyn, ninst);
#if STEP < 2
#define GETIP(A, scratch)
#define GETIP_(A, scratch)
@@ -1083,10 +1097,10 @@
} else if (_delta_ip == 0) { \
} else if (_delta_ip >= -2048 && _delta_ip < 2048) { \
ADDI_D(xRIP, xRIP, _delta_ip); \
} else if (_delta_ip < 0 && _delta_ip >= -0xffffffffL) { \
} else if (_delta_ip < 0 && _delta_ip >= -0xffffffffL) { \
MOV32w(scratch, -_delta_ip); \
SUB_D(xRIP, xRIP, scratch); \
} else if (_delta_ip > 0 && _delta_ip <= 0xffffffffL) { \
} else if (_delta_ip > 0 && _delta_ip <= 0xffffffffL) { \
MOV32w(scratch, _delta_ip); \
ADD_D(xRIP, xRIP, scratch); \
} else { \
@@ -1308,7 +1322,7 @@
#define avx_reflect_reg STEPNAME(avx_reflect_reg)
#define avx_purgecache STEPNAME(avx_purgecache)
#define avx_reflect_reg_upper128 STEPNAME(avx_reflect_reg_upper128)
#define avx_cleancache STEPNAME(avx_cleancache)
#define fpu_pushcache STEPNAME(fpu_pushcache)
#define fpu_popcache STEPNAME(fpu_popcache)
@@ -1319,6 +1333,8 @@
#define fpu_reflectcache STEPNAME(fpu_reflectcache)
#define fpu_unreflectcache STEPNAME(fpu_unreflectcache)
#define checkCRC STEPNAME(checkCRC)
#define CacheTransform STEPNAME(CacheTransform)
#define la64_move64 STEPNAME(la64_move64)
#define la64_move32 STEPNAME(la64_move32)
@@ -1527,6 +1543,10 @@ void avx_forget_reg(dynarec_la64_t* dyn, int ninst, int a);
// Push current value to the cache
void avx_reflect_reg(dynarec_la64_t* dyn, int ninst, int a);
void avx_reflect_reg_upper128(dynarec_la64_t* dyn, int ninst, int a, int forwrite);
void avx_cleancache(dynarec_la64_t* dyn, int ninst);
// in case of always_test, this insert a check of crc of the dynablock (and exit to ArmNext if wrong)
void checkCRC(dynarec_la64_t* dyn, int ninst);
void CacheTransform(dynarec_la64_t* dyn, int ninst, int cacheupd, int s1, int s2, int s3);
+28 -18
View File
@@ -49,7 +49,13 @@
} while (0)
#define EMIT(A) dyn->native_size += 4
#define JUMP(A, C) add_jump(dyn, ninst); add_next(dyn, (uintptr_t)A); SMEND(); dyn->insts[ninst].x64.jmp = A; dyn->insts[ninst].x64.jmp_cond = C; dyn->insts[ninst].x64.jmp_insts = 0
#define JUMP(A, C) \
add_jump(dyn, ninst); \
add_next(dyn, (uintptr_t)A); \
SMEND(); \
dyn->insts[ninst].x64.jmp = A; \
dyn->insts[ninst].x64.jmp_cond = C; \
dyn->insts[ninst].x64.jmp_insts = 0
#define BARRIER(A) \
if (A != BARRIER_MAYBE) { \
fpu_purgecache(dyn, ninst, 0, x1, x2, x3); \
@@ -57,27 +63,31 @@
} else \
dyn->insts[ninst].barrier_maybe = 1
#define SET_HASCALLRET() dyn->insts[ninst].x64.has_callret = 1
#define NEW_INST \
++dyn->size; \
dyn->insts[ninst].x64.addr = ip; \
dyn->lsx.combined1 = dyn->lsx.combined2 = 0; \
dyn->lsx.swapped = 0; \
dyn->lsx.barrier = 0; \
dyn->insts[ninst].f_entry = dyn->f; \
#define NEW_INST \
++dyn->size; \
dyn->insts[ninst].x64.addr = ip; \
dyn->lsx.combined1 = dyn->lsx.combined2 = 0; \
dyn->lsx.swapped = 0; \
dyn->lsx.barrier = 0; \
dyn->insts[ninst].f_entry = dyn->f; \
if (ninst) { dyn->insts[ninst - 1].x64.size = dyn->insts[ninst].x64.addr - dyn->insts[ninst - 1].x64.addr; } \
AREFLAGSNEEDED()
#define INST_EPILOG \
dyn->insts[ninst].f_exit = dyn->f; \
dyn->insts[ninst].lsx = dyn->lsx; \
dyn->insts[ninst].x64.has_next = (ok > 0) ? 1 : 0;
#define INST_EPILOG \
do { \
dyn->insts[ninst].f_exit = dyn->f; \
dyn->insts[ninst].lsx = dyn->lsx; \
dyn->insts[ninst].x64.has_next = (ok > 0) ? 1 : 0; \
avx_cleancache(dyn, ninst); \
} while (0)
#define INST_NAME(name)
#define DEFAULT \
--dyn->size; \
*ok = -1; \
if (ninst) { dyn->insts[ninst - 1].x64.size = ip - dyn->insts[ninst - 1].x64.addr; } \
if (BOX64ENV(dynarec_log) >= LOG_INFO || dyn->need_dump || BOX64ENV(dynarec_missing) == 1) { \
dynarec_stopped(dyn->insts[ninst].x64.addr, rex.is32bits); \
#define DEFAULT \
--dyn->size; \
*ok = -1; \
if (ninst) { dyn->insts[ninst - 1].x64.size = ip - dyn->insts[ninst - 1].x64.addr; } \
if (BOX64ENV(dynarec_log) >= LOG_INFO || dyn->need_dump || BOX64ENV(dynarec_missing) == 1) { \
dynarec_stopped(dyn->insts[ninst].x64.addr, rex.is32bits); \
}
+12 -5
View File
@@ -1,7 +1,11 @@
#define INIT
#define FINI
#define MESSAGE(A, ...) do {} while (0)
#define EMIT(A) do {} while (0)
#define MESSAGE(A, ...) \
do { \
} while (0)
#define EMIT(A) \
do { \
} while (0)
#define NEW_INST \
dyn->insts[ninst].f_entry = dyn->f; \
dyn->lsx.combined1 = dyn->lsx.combined2 = 0; \
@@ -9,9 +13,12 @@
dyn->lsx.barrier = 0; \
AREFLAGSNEEDED()
#define INST_EPILOG \
dyn->insts[ninst].lsx = dyn->lsx; \
dyn->insts[ninst].f_exit = dyn->f
#define INST_EPILOG \
do { \
dyn->insts[ninst].lsx = dyn->lsx; \
dyn->insts[ninst].f_exit = dyn->f; \
avx_cleancache(dyn, ninst); \
} while (0)
#define INST_NAME(name)
+23 -6
View File
@@ -1,11 +1,13 @@
#define INIT dyn->native_size = 0
#define FINI \
if (ninst) { \
dyn->insts[ninst].address = (dyn->insts[ninst - 1].address + dyn->insts[ninst - 1].size); \
dyn->insts_size += 1+((dyn->insts[ninst-1].x64.size>(dyn->insts[ninst-1].size/4))?dyn->insts[ninst-1].x64.size:(dyn->insts[ninst-1].size/4))/15; \
#define FINI \
if (ninst) { \
dyn->insts[ninst].address = (dyn->insts[ninst - 1].address + dyn->insts[ninst - 1].size); \
dyn->insts_size += 1 + ((dyn->insts[ninst - 1].x64.size > (dyn->insts[ninst - 1].size / 4)) ? dyn->insts[ninst - 1].x64.size : (dyn->insts[ninst - 1].size / 4)) / 15; \
}
#define MESSAGE(A, ...) do {} while (0)
#define MESSAGE(A, ...) \
do { \
} while (0)
#define EMIT(A) \
do { \
dyn->insts[ninst].size += 4; \
@@ -18,7 +20,13 @@
dyn->insts[ninst].ymm0_pass2 = dyn->ymm_zero; \
} \
AREFLAGSNEEDED()
#define INST_EPILOG dyn->insts[ninst].epilog = dyn->native_size;
#define INST_EPILOG \
do { \
dyn->insts[ninst].epilog = dyn->native_size; \
avx_cleancache(dyn, ninst); \
} while (0)
#define INST_NAME(name)
#define TABLE64(A, V) \
do { \
@@ -49,3 +57,12 @@
EMIT(0); \
EMIT(0); \
} while (0)
#define CALLRET_RET(A) do { \
if((A) && ISSEP() && BOX64DRENV(dynarec_callret)) { \
dyn->insts[ninst].size+=sizeof(void*); dyn->native_size+=sizeof(void*); dyn->insts[ninst+1].sep=1; ++dyn->sep_size; \
} \
if((A) && (BOX64DRENV(dynarec_callret)>1) && !dyn->always_test) { \
dyn->callrets[dyn->callret_size].type = 0; dyn->callrets[dyn->callret_size++].offs = dyn->native_size; EMIT(ARCH_NOP); \
} \
} while(0)
#define CALLRET_LOOP() do { dyn->callrets[dyn->callret_size].type = 1; dyn->callrets[dyn->callret_size++].offs = dyn->native_size; EMIT(ARCH_NOP); } while(0)
+43 -20
View File
@@ -1,29 +1,34 @@
#define INIT
#define FINI \
if (ninst) \
addInst(dyn->instsize, &dyn->insts_size, dyn->insts[ninst-1].x64.size, dyn->insts[ninst-1].size/4); \
#define FINI \
if (ninst) \
addInst(dyn->instsize, &dyn->insts_size, dyn->insts[ninst - 1].x64.size, dyn->insts[ninst - 1].size / 4); \
addInst(dyn->instsize, &dyn->insts_size, 0, 0);
#define EMIT(A) \
do { \
#define EMIT(A) \
do { \
if (dyn->need_dump) print_opcode(dyn, ninst, (uint32_t)(A)); \
if ((uintptr_t)dyn->block < dyn->tablestart) \
*(uint32_t*)(dyn->block) = (uint32_t)(A); \
dyn->block += 4; \
dyn->native_size += 4; \
dyn->insts[ninst].size2 += 4; \
if ((uintptr_t)dyn->block < dyn->tablestart) \
*(uint32_t*)(dyn->block) = (uint32_t)(A); \
dyn->block += 4; \
dyn->native_size += 4; \
dyn->insts[ninst].size2 += 4; \
} while (0)
#define MESSAGE(A, ...) \
do { \
#define MESSAGE(A, ...) \
do { \
if (dyn->need_dump) dynarec_log(LOG_NONE, __VA_ARGS__); \
} while (0)
#define NEW_INST \
if (ninst) { \
addInst(dyn->instsize, &dyn->insts_size, dyn->insts[ninst - 1].x64.size, dyn->insts[ninst - 1].size / 4); \
dyn->insts[ninst].ymm0_pass3 = dyn->ymm_zero; \
} \
#define NEW_INST \
if (ninst) { \
addInst(dyn->instsize, &dyn->insts_size, dyn->insts[ninst - 1].x64.size, dyn->insts[ninst - 1].size / 4); \
dyn->insts[ninst].ymm0_pass3 = dyn->ymm_zero; \
} \
AREFLAGSNEEDED()
#define INST_EPILOG
#define INST_EPILOG \
do { \
avx_cleancache(dyn, ninst); \
} while (0)
#define INST_NAME(name) inst_name_pass3(dyn, ninst, name, rex)
#define TABLE64(A, V) \
do { \
@@ -46,8 +51,8 @@
mmx87_regs_t v = { .d = V }; \
int val64offset = Table64(dyn, v.q, 3); \
MESSAGE(LOG_DUMP, " FTable64: %g\n", v.d); \
PCADDU12I(x1, SPLIT20(val64offset)); \
FLD_D(A, x1, SPLIT12(val64offset)); \
PCADDU12I(x1, SPLIT20(val64offset)); \
FLD_D(A, x1, SPLIT12(val64offset)); \
} while (0)
#define TABLE64C(A, V) \
do { \
@@ -58,3 +63,21 @@
PCADDU12I(A, SPLIT20(val64offset)); \
LD_D(A, A, SPLIT12(val64offset)); \
} while (0)
#define CALLRET_RET(A) \
do { \
if((A) && ISSEP() && BOX64DRENV(dynarec_callret)) { \
MESSAGE(LOG_DUMP, " Dynablock*\n"); \
dyn->block += sizeof(void*); \
dyn->native_size+=sizeof(void*); \
dyn->insts[ninst].size2 += sizeof(void*); \
dyn->sep[dyn->sep_size].x64_offs = addr - dyn->start; \
dyn->sep[dyn->sep_size].nat_offs = dyn->native_size; \
++dyn->sep_size; \
} \
if((A) && (BOX64DRENV(dynarec_callret)>1) && !dyn->always_test) { \
dyn->callrets[dyn->callret_size].type = 0; \
dyn->callrets[dyn->callret_size++].offs = dyn->native_size; \
EMIT(ARCH_NOP); \
} \
} while(0)
#define CALLRET_LOOP() do {dyn->callrets[dyn->callret_size].type = 1; dyn->callrets[dyn->callret_size++].offs = dyn->native_size; EMIT(ARCH_NOP); } while(0)
+5 -4
View File
@@ -43,9 +43,8 @@ typedef union sse_cache_s {
typedef union avx_cache_s {
int8_t v;
struct {
uint8_t reg : 5;
uint8_t width : 1;
uint8_t zero_upper : 1;
uint8_t reg : 6;
uint8_t dirty : 1;
uint8_t write : 1;
};
} avx_cache_t;
@@ -111,7 +110,9 @@ typedef struct instruction_la64_s {
uint8_t will_read:1; // [strongmem] will read from memory
uint8_t last_write:1; // [strongmem] the last write in a SEQ
uint8_t lock:1; // [strongmem] lock semantic
uint8_t df_notneeded;
uint8_t df_needed:1;
uint8_t df_notneeded:1;
uint8_t sep:1; // opcode is a secondary entry point
uint8_t nat_flags_fusion:1;
uint8_t nat_flags_nofusion:1;
uint8_t nat_flags_carry:1;
+23
View File
@@ -32,6 +32,7 @@
.global la64_lock_get_d
.global la64_lock_get_dd
.global la64_crc
.global la64_crc_autocrc
la64_lock_xchg_b:
.word 0x385e1486 // amswap_db.b $a2, $a1, $a0
@@ -252,5 +253,27 @@ la64_crc:
addi.d $a2, $a2, 1
addi.w $a1, $a1, -1
bnez $a1, 3b
4:
ret
la64_crc_autocrc:
move $t4, $t2
xor $t2, $t2, $t2
li.d $t5, 8
1:
bltu $t3, $t5, 2f
ld.d $t6, $t4, 0
crc.w.d.w $t2, $t6, $t2
addi.d $t4, $t4, 8
addi.w $t3, $t3, -8
bnez $t3, 1b
2:
beqz $t3, 4f
3:
ld.bu $t6, $t4, 0
crc.w.b.w $t2, $t6, $t2
addi.d $t4, $t4, 1
addi.w $t3, $t3, -1
bnez $t3, 3b
4:
ret
+42
View File
@@ -11,8 +11,10 @@
.align 4
.extern LinkNext
.extern LinkNextInvalid
.global la64_next
.global la64_next_invalid
.8byte 0 // NULL pointer before la64_next, for getDB
la64_next:
@@ -54,3 +56,43 @@ la64_next:
addi.d $sp, $sp, (8 * 11)
// return offset is jump address
jr $r16
la64_next_invalid:
// move emu to a0
// move IP address to a1
addi.d $sp, $sp, -(8 * 11)
st.d RDI, $sp, 0
st.d RSI, $sp, 8
st.d RDX, $sp, 16
st.d RCX, $sp, 24
st.d R8, $sp, 32
st.d R9, $sp, 40
st.d RAX, $sp, 48
st.d RBX, $sp, 56
st.d RSP, $sp, 64
st.d RBP, $sp, 72
st.d RIP, $sp, 80 // also save r29(rip) to allow change in LinkNext
move $a0, Emu
move $a1, RIP
move $a2, $ra // "from" is in ra, so put in a2
addi.d $a3, $sp, 80 // a3 is address to change rip
// call the function
bl LinkNextInvalid
// preserve return value
move $r16, $a0
// pop regs
ld.d RDI, $sp, 0
ld.d RSI, $sp, 8
ld.d RDX, $sp, 16
ld.d RCX, $sp, 24
ld.d R8, $sp, 32
ld.d R9, $sp, 40
ld.d RAX, $sp, 48
ld.d RBX, $sp, 56
ld.d RSP, $sp, 64
ld.d RBP, $sp, 72
ld.d RIP, $sp, 80
addi.d $sp, $sp, (8 * 11)
// return offset is jump address
jr $r16
+21435 -7309
View File
File diff suppressed because it is too large. Load diff
+279
View File
@@ -1,6 +1,285 @@
#ifndef _LA64_PRINTER_H_
#define _LA64_PRINTER_H_
#include <stdint.h>
#include <stddef.h>
typedef enum {
LA_ZERO = 0,
LA_RA,
LA_TP,
LA_SP,
LA_A0,
LA_A1,
LA_A2,
LA_A3,
LA_A4,
LA_A5,
LA_A6,
LA_A7,
LA_T0,
LA_T1,
LA_T2,
LA_T3,
LA_T4,
LA_T5,
LA_T6,
LA_T7,
LA_T8,
LA_RX,
LA_FP,
LA_S0,
LA_S1,
LA_S2,
LA_S3,
LA_S4,
LA_S5,
LA_S6,
LA_S7,
LA_S8,
LA_R0 = 0,
LA_R1,
LA_R2,
LA_R3,
LA_R4,
LA_R5,
LA_R6,
LA_R7,
LA_R8,
LA_R9,
LA_R10,
LA_R11,
LA_R12,
LA_R13,
LA_R14,
LA_R15,
LA_R16,
LA_R17,
LA_R18,
LA_R19,
LA_R20,
LA_R21,
LA_R22,
LA_R23,
LA_R24,
LA_R25,
LA_R26,
LA_R27,
LA_R28,
LA_R29,
LA_R30,
LA_R31,
LA_GPR_COUNT
} la_gpr_t;
typedef enum {
LA_FA0 = 0,
LA_FA1,
LA_FA2,
LA_FA3,
LA_FA4,
LA_FA5,
LA_FA6,
LA_FA7,
LA_FT0,
LA_FT1,
LA_FT2,
LA_FT3,
LA_FT4,
LA_FT5,
LA_FT6,
LA_FT7,
LA_FT8,
LA_FT9,
LA_FT10,
LA_FT11,
LA_FT12,
LA_FT13,
LA_FT14,
LA_FT15,
LA_FS0,
LA_FS1,
LA_FS2,
LA_FS3,
LA_FS4,
LA_FS5,
LA_FS6,
LA_FS7,
LA_F0 = 0,
LA_F1,
LA_F2,
LA_F3,
LA_F4,
LA_F5,
LA_F6,
LA_F7,
LA_F8,
LA_F9,
LA_F10,
LA_F11,
LA_F12,
LA_F13,
LA_F14,
LA_F15,
LA_F16,
LA_F17,
LA_F18,
LA_F19,
LA_F20,
LA_F21,
LA_F22,
LA_F23,
LA_F24,
LA_F25,
LA_F26,
LA_F27,
LA_F28,
LA_F29,
LA_F30,
LA_F31,
LA_FPR_COUNT
} la_fpr_t;
typedef enum {
LA_V0 = 0,
LA_V1,
LA_V2,
LA_V3,
LA_V4,
LA_V5,
LA_V6,
LA_V7,
LA_V8,
LA_V9,
LA_V10,
LA_V11,
LA_V12,
LA_V13,
LA_V14,
LA_V15,
LA_V16,
LA_V17,
LA_V18,
LA_V19,
LA_V20,
LA_V21,
LA_V22,
LA_V23,
LA_V24,
LA_V25,
LA_V26,
LA_V27,
LA_V28,
LA_V29,
LA_V30,
LA_V31,
LA_VSR_COUNT
} la_vpr_t;
typedef enum {
LA_XV0 = 0,
LA_XV1,
LA_XV2,
LA_XV3,
LA_XV4,
LA_XV5,
LA_XV6,
LA_XV7,
LA_XV8,
LA_XV9,
LA_XV10,
LA_XV11,
LA_XV12,
LA_XV13,
LA_XV14,
LA_XV15,
LA_XV16,
LA_XV17,
LA_XV18,
LA_XV19,
LA_XV20,
LA_XV21,
LA_XV22,
LA_XV23,
LA_XV24,
LA_XV25,
LA_XV26,
LA_XV27,
LA_XV28,
LA_XV29,
LA_XV30,
LA_XV31,
LA_XVSR_COUNT
} la_xvpr_t;
typedef enum {
LA_FCC0 = 0,
LA_FCC1,
LA_FCC2,
LA_FCC3,
LA_FCC4,
LA_FCC5,
LA_FCC6,
LA_FCC7,
LA_FCC_COUNT
} la_fcc_t;
typedef enum {
LA_SCR0 = 0,
LA_SCR1,
LA_SCR2,
LA_SCR3,
LA_SCR_COUNT
} la_scr_t;
typedef enum {
LA_FCSR0 = 0,
LA_FCSR1,
LA_FCSR2,
LA_FCSR3,
LA_FCSR_COUNT
} la_fcsr_t;
typedef enum {
LA_OP_GPR,
LA_OP_FPR,
LA_OP_VPR,
LA_OP_XVPR,
LA_OP_FCC,
LA_OP_SCR,
LA_OP_FCSR,
LA_OP_SIMM,
LA_OP_UIMM,
} la_operand_kind_t;
typedef struct {
la_operand_kind_t kind;
union {
la_gpr_t gpr;
la_fpr_t fpr;
la_vpr_t vpr;
la_xvpr_t xvpr;
la_fcc_t fcc;
la_scr_t scr;
la_fcsr_t fcsr;
int32_t simm;
uint32_t uimm;
};
} la_operand_t;
#define LA_MAX_OPERANDS 4
typedef struct {
size_t offset;
uint32_t encoding;
const char* mnemonic;
int operand_count;
la_operand_t operands[LA_MAX_OPERANDS];
} lagoon_insn_t;
void la_disasm_one(uint32_t word, lagoon_insn_t* insn);
void la_insn_to_str(const lagoon_insn_t* insn, char* buf, size_t buf_size);
const char* la64_print(uint32_t opcode, uint64_t addr);
#endif //_LA64_PRINTER_H_
+38
View File
@@ -120,6 +120,44 @@
#define native_lock_get_d(A) la64_lock_get_d(A)
#define native_lock_get_dd(A) la64_lock_get_dd(A)
#elif defined(PPC64LE)
#include "ppc64le/ppc64le_lock.h"
// PPC64LE has LL/SC at all widths (lbarx/stbcx., lharx/sthcx., lwarx/stwcx., ldarx/stdcx.)
// so it follows the ARM64 separate read/write pattern, NOT the CAS pattern
#define native_lock_read_b(A) ppc64le_lock_read_b(A)
#define native_lock_write_b(A, B) ppc64le_lock_write_b(A, B)
#define native_lock_read_h(A) ppc64le_lock_read_h(A)
#define native_lock_write_h(A, B) ppc64le_lock_write_h(A, B)
#define native_lock_read_d(A) ppc64le_lock_read_d(A)
#define native_lock_write_d(A, B) ppc64le_lock_write_d(A, B)
#define native_lock_read_dd(A) ppc64le_lock_read_dd(A)
#define native_lock_write_dd(A, B) ppc64le_lock_write_dd(A, B)
// PPC64LE (pre-POWER10) lacks 128-bit LL/SC. Use plain reads for read_dq;
// callers that need true atomicity should use the spinlock (mutex_16b) path.
#define native_lock_read_dq(A, B, C) do { *(A) = ((uint64_t*)(C))[0]; *(B) = ((uint64_t*)(C))[1]; } while(0)
#define native_lock_write_dq(A, B, C) 0 // not truly atomic; callers must use mutex_16b
#define native_lock_xchg_dd(A, B) ppc64le_lock_xchg_dd(A, B)
#define native_lock_xchg_d(A, B) ppc64le_lock_xchg_d(A, B)
#define native_lock_xchg_h(A, B) ppc64le_lock_xchg_h(A, B)
#define native_lock_xchg_b(A, B) ppc64le_lock_xchg_b(A, B)
#define native_lock_storeifref(A, B, C) ppc64le_lock_storeifref(A, B, C)
#define native_lock_storeifref2(A, B, C) ppc64le_lock_storeifref2(A, B, C)
#define native_lock_storeifref_d(A, B, C) ppc64le_lock_storeifref_d(A, B, C)
#define native_lock_storeifref2_d(A, B, C) ppc64le_lock_storeifref2_d(A, B, C)
#define native_lock_storeifnull(A, B) ppc64le_lock_storeifnull(A, B)
#define native_lock_storeifnull_d(A, B) ppc64le_lock_storeifnull_d(A, B)
// #define native_lock_decifnot0b(A) ppc64le_lock_decifnot0b(A)
#define native_lock_storeb(A, B) ppc64le_lock_storeb(A, B)
#define native_lock_incif0(A) ppc64le_lock_incif0(A)
#define native_lock_decifnot0(A) ppc64le_lock_decifnot0(A)
#define native_lock_store(A, B) ppc64le_lock_store(A, B)
#define native_lock_store_dd(A, B) ppc64le_lock_store_dd(A, B)
#define native_lock_get_b(A) ppc64le_lock_get_b(A)
#define native_lock_get_d(A) ppc64le_lock_get_d(A)
#define native_lock_get_dd(A) ppc64le_lock_get_dd(A)
#else
#error Unsupported architecture
#endif
File diff suppressed because it is too large. Load diff
+35
View File
@@ -0,0 +1,35 @@
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <errno.h>
#include "debug.h"
#include "box64context.h"
#include "box64cpu.h"
#include "emu/x64emu_private.h"
#include "ppc64le_emitter.h"
#include "ppc64le_mapping.h"
#include "x64emu.h"
#include "box64stack.h"
#include "callback.h"
#include "emu/x64run_private.h"
#include "x64trace.h"
#include "dynarec_native.h"
#include "custommem.h"
#include "ppc64le_printer.h"
#include "dynarec_ppc64le_private.h"
#include "../dynarec_helper.h"
#include "dynarec_ppc64le_functions.h"
uintptr_t dynarec64_66(dynarec_ppc64le_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int* ok, int* need_epilog)
{
uint8_t opcode = F8;
switch (opcode) {
default:
DEFAULT;
}
return addr;
}
@@ -0,0 +1,37 @@
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <errno.h>
#include "debug.h"
#include "box64context.h"
#include "box64cpu.h"
#include "emu/x64emu_private.h"
#include "ppc64le_emitter.h"
#include "ppc64le_mapping.h"
#include "x64emu.h"
#include "box64stack.h"
#include "callback.h"
#include "emu/x64run_private.h"
#include "x64trace.h"
#include "dynarec_native.h"
#include "ppc64le_printer.h"
#include "dynarec_ppc64le_private.h"
#include "../dynarec_helper.h"
#include "dynarec_ppc64le_functions.h"
uintptr_t dynarec64_66F0(dynarec_ppc64le_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int* ok, int* need_epilog)
{
(void)ip;
(void)need_epilog;
uint8_t opcode = F8;
switch (opcode) {
default:
DEFAULT;
}
return addr;
}
+397
View File
@@ -0,0 +1,397 @@
#include <stddef.h>
#include <stdio.h>
#include <signal.h>
#include <string.h>
#include "debug.h"
#include "dynablock.h"
#include "x64emu.h"
#include "emu/x64emu_private.h"
#include "emu/x64run_private.h"
#include "dynarec/dynablock_private.h"
#include "dynarec_ppc64le_arch.h"
#include "dynarec_ppc64le_functions.h"
#include "dynarec_native.h"
// PPC64LE arch.c — signal recovery metadata
// Records per-instruction state so that adjust_arch() can reconstruct
// x86 emulator state (deferred flags, SIMD/x87/MMX register cache) when
// a signal interrupts dynarec-generated code.
//order might be important, so define SUPER for the right one
#define SUPER() \
GO(flags) \
GO(x87) \
GO(mmx) \
GO(sse) \
GO(ymm) \
typedef struct arch_flags_s
{
uint8_t defered:1;
} arch_flags_t;
#define X87_ST_D 0
#define X87_ST_F 1
#define X87_ST_I64 2
typedef struct arch_x87_s
{
int8_t delta; //up to +/-7
uint8_t x87; // 1bit is STx present
uint16_t x87_type; // 2bits per STx type
uint32_t x87_pos; //4bits per STx position
} arch_x87_t;
typedef struct arch_mmx_s
{
uint8_t mmx; //1bit for each mmx reg present
} arch_mmx_t;
typedef struct arch_sse_s
{
uint16_t sse; //1bit for each sse reg present
} arch_sse_t;
typedef struct arch_ymm_s
{
uint16_t ymm0; // 1bit for ymm0
uint16_t ymm; // 1bit for each ymm present
uint64_t ymm_pos; // 4bits for position of each ymm present
} arch_ymm_t;
typedef struct arch_arch_s
{
#define GO(A) uint16_t A:1;
SUPER()
#undef GO
uint16_t unaligned:1;
uint16_t seq:10; // how many instruction on the same values
} arch_arch_t;
typedef struct arch_build_s
{
#define GO(A) uint8_t A:1;
SUPER()
#undef GO
uint8_t unaligned;
#define GO(A) arch_##A##_t A##_;
SUPER()
#undef GO
} arch_build_t;
static arch_build_t static_build[MAX_INSTS+2] = {0};
// VMX cache index constants (must match dynarec_ppc64le_functions.c)
#define XMM0 0
#define EMM0 (XMM0 + 16)
static int arch_build(dynarec_ppc64le_t* dyn, int ninst, arch_build_t* arch, int noarch)
{
memset(arch, 0, sizeof(arch_build_t));
// flags
if(dyn->insts[ninst].f_entry!=status_none && dyn->insts[ninst].f_entry!=status_none_pending) {
arch->flags = 1;
arch->flags_.defered = 1;
}
// opcode can handle unaligned
arch->unaligned = dyn->insts[ninst].unaligned;
if(!noarch) {
// go through all vmxcache to gather regs assignments
for(int i=0; i<32; ++i)
if(dyn->insts[ninst].v.vmxcache[i].v)
switch(dyn->insts[ninst].v.vmxcache[i].t) {
case VMX_CACHE_XMMW:
arch->sse = 1;
arch->sse_.sse |= 1<<dyn->insts[ninst].v.vmxcache[i].n;
break;
case VMX_CACHE_MM:
arch->mmx = 1;
arch->mmx_.mmx |= 1<<dyn->insts[ninst].v.vmxcache[i].n;
break;
case VMX_CACHE_YMMW:
arch->ymm = 1;
arch->ymm_.ymm |= 1<<dyn->insts[ninst].v.vmxcache[i].n;
{
int idx = i;
if(idx>=EMM0 && idx<=EMM0+8)
idx-=EMM0;
else
idx-=SCRATCH0-8;
arch->ymm_.ymm_pos |= (uint64_t)idx<<(dyn->insts[ninst].v.vmxcache[i].n*4);
}
break;
case VMX_CACHE_ST_D:
arch->x87 = 1;
arch->x87_.x87 |= 1<<dyn->insts[ninst].v.vmxcache[i].n;
arch->x87_.x87_pos |= (uint32_t)(i-EMM0)<<(dyn->insts[ninst].v.vmxcache[i].n*4);
arch->x87_.x87_type |= (uint16_t)(X87_ST_D)<<(dyn->insts[ninst].v.vmxcache[i].n*2);
break;
case VMX_CACHE_ST_F:
arch->x87 = 1;
arch->x87_.x87 |= 1<<dyn->insts[ninst].v.vmxcache[i].n;
arch->x87_.x87_pos |= (uint32_t)(i-EMM0)<<(dyn->insts[ninst].v.vmxcache[i].n*4);
arch->x87_.x87_type |= (uint16_t)(X87_ST_F)<<(dyn->insts[ninst].v.vmxcache[i].n*2);
break;
case VMX_CACHE_ST_I64:
arch->x87 = 1;
arch->x87_.x87 |= 1<<dyn->insts[ninst].v.vmxcache[i].n;
arch->x87_.x87_pos |= (uint32_t)(i-EMM0)<<(dyn->insts[ninst].v.vmxcache[i].n*4);
arch->x87_.x87_type |= (uint16_t)(X87_ST_I64)<<(dyn->insts[ninst].v.vmxcache[i].n*2);
break;
case VMX_CACHE_XMMR:
case VMX_CACHE_YMMR:
default:
// doing nothing, it's just a value read in memory
break;
}
// ymm0
if(dyn->insts[ninst].ymm0_out) {
arch->ymm = 1;
arch->ymm_.ymm0 = dyn->insts[ninst].ymm0_out;
}
// x87 top
if(dyn->insts[ninst].v.x87stack) {
arch->x87 = 1;
arch->x87_.delta = dyn->insts[ninst].v.x87stack;
}
}
return arch->flags + arch->x87 + arch->mmx + arch->sse + arch->ymm + arch->unaligned;
}
static int sizeof_arch(arch_arch_t* arch)
{
int sz = sizeof(arch_arch_t);
#define GO(A) if(arch->A) sz+=sizeof(arch_##A##_t);
SUPER()
#undef GO
return sz;
}
static int sizeof_arch_build(arch_build_t* build)
{
int sz = sizeof(arch_arch_t);
#define GO(A) if(build->A) sz+=sizeof(arch_##A##_t);
SUPER()
#undef GO
return sz;
}
size_t get_size_arch(dynarec_ppc64le_t* dyn)
{
int noarch = BOX64ENV(dynarec_noarch);
if(noarch>1) return 0;
arch_build_t* previous = NULL;
size_t sz = 0;
int seq = 0;
int nseq = 0;
int last = 0;
if(!dyn->size) return 0;
for(int i=0; i<dyn->size; ++i) {
arch_build_t* build = static_build+i;
last = arch_build(dyn, i, build, noarch);
if(i && (!memcmp(build, previous, sizeof(arch_build_t))) && (seq<((1<<10)-1))) {
// same sequence, increment
++seq;
} else {
seq = 0;
++nseq;
previous = build;
sz += sizeof_arch_build(build);
}
}
if(nseq==1 && !last)
return 0; //empty, no flags, no nothing
return sz;
}
static void build_next(arch_arch_t* arch, arch_build_t* build)
{
#define GO(A) arch->A = build->A;
SUPER()
#undef GO
arch->unaligned = build->unaligned;
arch->seq = 0;
void* p = ((void*)arch)+sizeof(arch_arch_t);
#define GO(A) \
if(build->A) { \
memcpy(p, &(build->A##_), sizeof(arch_ ##A##_t)); \
p+=sizeof(arch_##A##_t); \
}
SUPER()
#undef GO
}
void* populate_arch(dynarec_ppc64le_t* dyn, void* p, size_t tot_sz)
{
arch_build_t* previous = NULL;
arch_arch_t* arch = p;
arch_arch_t* next = p;
int seq = 0;
size_t total = 0;
if(!tot_sz) return NULL;
for(int i=0; i<dyn->size; ++i) {
arch_build_t* build = static_build+i;
if(i && (!memcmp(build, previous, sizeof(arch_build_t))) && (seq<((1<<10)-1))) {
// same sequence, increment
arch->seq = ++seq;
} else {
int sz = sizeof_arch_build(build);
if(total+sz>tot_sz) {
printf_log(LOG_INFO, "Warning: populate_arch on undersized buffer (%d+%d/%d, inst %d/%d)\n", total, sz, tot_sz, i, dyn->size);
return NULL;
}
arch = next;
build_next(arch, build);
seq = 0;
previous = build;
total += sz;
next = (arch_arch_t*)((uintptr_t)arch+sz);
}
}
return p;
}
void adjust_arch(dynablock_t* db, x64emu_t* emu, ucontext_t* p, uintptr_t x64pc)
{
if(!db->arch_size || !db->arch)
return;
int ninst = getX64AddressInst(db, x64pc);
dynarec_log(LOG_INFO, "adjust_arch(...), db=%p, x64pc=%p, nints=%d", db, (void*)x64pc, ninst);
if(ninst<0) {
dynarec_log_prefix(0, LOG_INFO, "\n");
return;
}
if(ninst==0) {
dynarec_log_prefix(0, LOG_INFO, "\n");
CHECK_FLAGS(emu);
return;
}
// look for state at ninst-1
arch_arch_t* arch = db->arch;
arch_arch_t* next = arch;
#define GO(A) arch_##A##_t* A = NULL;
SUPER()
#undef GO
int i = 0;
while(i<(ninst)) { // this will look for ninst-1 state
arch = next;
dynarec_log_prefix(0, (i<(ninst-1))?LOG_DEBUG:LOG_INFO, "[ seq=%d%s%s%s%s%s ] ", arch->seq, arch->flags?" Flags":"", arch->x87?" x87":"", arch->mmx?" MMX":"", arch->sse?" SSE":"", arch->ymm?" YMM":"");
i += 1+arch->seq;
next = (arch_arch_t*)((uintptr_t)next + sizeof_arch(arch));
}
int sz = sizeof(arch_arch_t);
#define GO(A) \
if(arch->A) { \
A = (arch_##A##_t*)((uintptr_t)arch + sz); \
sz+=sizeof(arch_##A##_t); \
}
SUPER()
#undef GO
if(flags) {
dynarec_log_prefix(0, LOG_INFO, " flags[%s] ", flags->defered?"defered":"");
if(flags->defered) {
CHECK_FLAGS(emu);
}
}
// PPC64LE signal context:
// mcontext_t.gp_regs[0..31] = r0-r31
// mcontext_t.fp_regs[0..31] = f0-f31 (lower 64 bits of vs0-vs31)
// mcontext_t.v_regs->vrregs[0..31][4] = vr0-vr31 (= vs32-vs63, 128-bit)
//
// VMX cache mapping:
// XMM cache idx 0-15 → vr0-vr15 → v_regs->vrregs[0..15]
// MMX cache idx 16-23 → vr24-vr31 → v_regs->vrregs[24..31] (64-bit in low dword)
// x87 cache idx 16-23 → f16-f23 → fp_regs[16..23] (scalar 64-bit)
// Scratch idx 24-31 → vr16-vr23 → v_regs->vrregs[16..23]
mcontext_t* mc = &p->uc_mcontext;
vrregset_t* vmx = mc->v_regs;
if(sse) {
dynarec_log_prefix(0, LOG_INFO, " sse[%x (vmx=%p)] ", sse->sse, vmx);
for(int i=0; i<16; ++i)
if(vmx && (sse->sse>>i)&1) {
// XMM i is cached in vmx register. Find which physical register.
// For XMM, cache index = i, physical = vr_i (vrregs[i])
int idx = i; // cache index = xmm number for XMM
// On PPC64LE LE: vrregs[idx][0]=low32, [1]=next32, [2]=next32, [3]=high32
// This matches x86 element order directly
memcpy(&emu->xmm[i], &vmx->vrregs[idx], 16);
}
}
if(ymm) {
dynarec_log_prefix(0, LOG_INFO, " ymm[%x, pos=%x, 0=%x (vmx=%p)] ", ymm->ymm, ymm->ymm_pos, ymm->ymm0, vmx);
for(int i=0; i<16; ++i) {
if(vmx && (ymm->ymm>>i)&1) {
int idx = (ymm->ymm_pos>>(i*4))&0xf;
// idx is a cache-relative position:
// 0-7 → EMM0+idx → vs(16+idx) → fp_regs but these are 64-bit only
// 8-15 → SCRATCH0+(idx-8) → vr(16+idx-8) → vrregs[16+idx-8]
if(idx >= 8) {
int vr = 16 + idx - 8;
memcpy(&emu->ymm[i], &vmx->vrregs[vr], 16);
}
// If idx < 8 (EMM0 space), those are vs16-vs23 in FPR space,
// only 64-bit accessible via fp_regs — not sufficient for 128-bit ymm.
// In practice, ymm should always use scratch (VMX) space.
}
if(ymm->ymm0&(1<<i))
memset(&emu->ymm[i], 0, 16);
}
}
if(mmx) {
dynarec_log_prefix(0, LOG_INFO, " mmx[%x (vmx=%p)] ", mmx->mmx, vmx);
for(int i=0; i<8; ++i)
if(vmx && (mmx->mmx>>i)&1) {
// MMX i is cached in vr(24+i) = vs(56+i) → v_regs->vrregs[24+i]
// Data is in low 64 bits (bytes 0-7 on LE)
int vr_idx = 24 + i;
emu->mmx[i].q = *(uint64_t*)&vmx->vrregs[vr_idx];
}
}
if(x87) {
dynarec_log_prefix(0, LOG_INFO, " x87[%x, pos=%x, type=%x] ", x87->x87, x87->x87_pos, x87->x87_type);
emu->top -= x87->delta;
for(int i=0; i<8; ++i) {
if(x87->x87&(1<<i)) {
int pos = (x87->x87_pos>>(i*4))&0x0f;
int fpr_idx = 16 + pos; // EMM0 + pos → vs(16+pos) → fp_regs[16+pos]
int t = (x87->x87_type>>(i*2))&0x3;
switch (t) {
case X87_ST_F:
emu->x87[(emu->top+i)&7].d = *(float*)&mc->fp_regs[fpr_idx];
break;
case X87_ST_I64:
emu->x87[(emu->top+i)&7].d = *(int64_t*)&mc->fp_regs[fpr_idx];
break;
case X87_ST_D:
emu->x87[(emu->top+i)&7].d = *(double*)&mc->fp_regs[fpr_idx];
break;
}
}
}
}
dynarec_log_prefix(0, LOG_INFO, "\n");
}
int arch_unaligned(dynablock_t* db, uintptr_t x64pc)
{
if(!db)
return 0;
if(!db->arch_size || !db->arch)
return 0;
int ninst = getX64AddressInst(db, x64pc);
if(ninst<0) {
return 0;
}
// look for state at ninst
arch_arch_t* arch = db->arch;
arch_arch_t* next = arch;
int i = -1;
while(i<ninst) {
arch = next;
i += 1+arch->seq;
next = (arch_arch_t*)((uintptr_t)next + sizeof_arch(arch));
}
return arch->unaligned;
}
@@ -0,0 +1,20 @@
#ifndef __DYNAREC_PPC64LE_ARCH_H__
#define __DYNAREC_PPC64LE_ARCH_H__
#include <stddef.h>
#include "x64emu.h"
#include "box64context.h"
#include "box64cpu.h"
#include "dynarec_ppc64le_private.h"
// get size of arch specific info (can be 0)
size_t get_size_arch(dynarec_ppc64le_t* dyn);
//populate the array
void* populate_arch(dynarec_ppc64le_t* dyn, void* p, size_t sz);
#include <ucontext.h>
//adjust flags and more
void adjust_arch(dynablock_t* db, x64emu_t* emu, ucontext_t* p, uintptr_t x64pc);
// get if instruction can be regenerated for unaligned access
int arch_unaligned(dynablock_t* db, uintptr_t x64pc);
#endif // __DYNAREC_PPC64LE_ARCH_H__
@@ -0,0 +1,131 @@
#include <stdint.h>
#include "dynarec_ppc64le_consts.h"
#include "debug.h"
#include "box64context.h"
#include "box64cpu.h"
#include "emu/x64emu_private.h"
#include "x64emu.h"
#include "box64stack.h"
#include "callback.h"
#include "emu/x64run_private.h"
#include "emu/x87emu_private.h"
#include "emu/x64primop.h"
#include "my_cpuid.h"
#include "freq.h"
#include "custommem.h"
#include "dynarec_ppc64le_functions.h"
#include "emu/x64shaext.h"
#include "emu/x64compstrings.h"
#include "x64test.h"
#include "dynarec/dynarec_next.h"
#include "random.h"
#ifndef HAVE_TRACE
void PrintTrace() {}
#endif
uintptr_t getConst(ppc64le_consts_t which)
{
switch(which) {
case const_none: dynarec_log(LOG_NONE, "Warning, const none used\n");
return 0;
case const_daa8: return (uintptr_t)daa8;
case const_das8: return (uintptr_t)das8;
case const_aaa16: return (uintptr_t)aaa16;
case const_aas16: return (uintptr_t)aas16;
case const_aam16: return (uintptr_t)aam16;
case const_aad16: return (uintptr_t)aad16;
case const_native_br: return (uintptr_t)native_br;
case const_native_ud: return (uintptr_t)native_ud;
case const_native_priv: return (uintptr_t)native_priv;
case const_native_gpf: return (uintptr_t)native_gpf;
case const_native_int3: return (uintptr_t)native_int3;
case const_native_int: return (uintptr_t)native_int;
case const_native_div0: return (uintptr_t)native_div0;
case const_native_frstor16: return (uintptr_t)native_frstor16;
case const_native_fsave16: return (uintptr_t)native_fsave16;
case const_native_fsave: return (uintptr_t)native_fsave;
case const_native_aesimc: return (uintptr_t)native_aesimc;
case const_native_aesd: return (uintptr_t)native_aesd;
case const_native_aesd_y: return (uintptr_t)native_aesd_y;
case const_native_aesdlast: return (uintptr_t)native_aesdlast;
case const_native_aesdlast_y: return (uintptr_t)native_aesdlast_y;
case const_native_aese: return (uintptr_t)native_aese;
case const_native_aese_y: return (uintptr_t)native_aese_y;
case const_native_aeselast: return (uintptr_t)native_aeselast;
case const_native_aeselast_y: return (uintptr_t)native_aeselast_y;
case const_native_aeskeygenassist: return (uintptr_t)native_aeskeygenassist;
case const_native_pclmul: return (uintptr_t)native_pclmul;
case const_native_pclmul_x: return (uintptr_t)native_pclmul_x;
case const_native_pclmul_y: return (uintptr_t)native_pclmul_y;
case const_direct_f2xm1: return (uintptr_t)direct_f2xm1;
case const_direct_fyl2x: return (uintptr_t)direct_fyl2x;
case const_direct_fyl2xp1: return (uintptr_t)direct_fyl2xp1;
case const_native_fxtract: return (uintptr_t)native_fxtract;
case const_direct_ftan: return (uintptr_t)direct_ftan;
case const_direct_fpatan: return (uintptr_t)direct_fpatan;
case const_direct_fcos: return (uintptr_t)direct_fcos;
case const_direct_fsin: return (uintptr_t)direct_fsin;
case const_native_fsincos: return (uintptr_t)native_fsincos;
case const_direct_fscale: return (uintptr_t)direct_fscale;
case const_native_fprem: return (uintptr_t)native_fprem;
case const_native_fprem1: return (uintptr_t)native_fprem1;
case const_native_fld: return (uintptr_t)native_fld;
case const_native_fstp: return (uintptr_t)native_fstp;
case const_native_frstor: return (uintptr_t)native_frstor;
case const_native_next: return (uintptr_t)native_next;
case const_int3: return (uintptr_t)EmuInt3;
case const_x86syscall: return (uintptr_t)EmuX86Syscall;
case const_x64syscall: return (uintptr_t)EmuX64Syscall;
case const_x64syscall_linux: return (uintptr_t)EmuX64Syscall_linux;
case const_rcl16: return (uintptr_t)rcl16;
case const_rcl32: return (uintptr_t)rcl32;
case const_rcl64: return (uintptr_t)rcl64;
case const_rcr16: return (uintptr_t)rcr16;
case const_rcr32: return (uintptr_t)rcr32;
case const_rcr64: return (uintptr_t)rcr64;
case const_div64: return (uintptr_t)div64;
case const_idiv64: return (uintptr_t)idiv64;
case const_random32: return (uintptr_t)get_random32;
case const_random64: return (uintptr_t)get_random64;
case const_readtsc: return (uintptr_t)ReadTSC;
case const_helper_getcpu: return (uintptr_t)helper_getcpu;
case const_cpuid: return (uintptr_t)my_cpuid;
case const_getsegmentbase: return (uintptr_t)GetSegmentBaseEmu;
case const_reset_fpu: return (uintptr_t)reset_fpu;
case const_sha1nexte: return (uintptr_t)sha1nexte;
case const_sha1msg1: return (uintptr_t)sha1msg1;
case const_sha1msg2: return (uintptr_t)sha1msg2;
case const_sha1rnds4: return (uintptr_t)sha1rnds4;
case const_sha256msg1: return (uintptr_t)sha256msg1;
case const_sha256msg2: return (uintptr_t)sha256msg2;
case const_sha256rnds2: return (uintptr_t)sha256rnds2;
case const_fpu_loadenv: return (uintptr_t)fpu_loadenv;
case const_fpu_savenv: return (uintptr_t)fpu_savenv;
case const_fpu_fxsave32: return (uintptr_t)fpu_fxsave32;
case const_fpu_fxsave64: return (uintptr_t)fpu_fxsave64;
case const_fpu_fxrstor32: return (uintptr_t)fpu_fxrstor32;
case const_fpu_fxrstor64: return (uintptr_t)fpu_fxrstor64;
case const_fpu_xsave: return (uintptr_t)fpu_xsave;
case const_fpu_xrstor: return (uintptr_t)fpu_xrstor;
case const_fpu_fbld: return (uintptr_t)fpu_fbld;
case const_fpu_fbst: return (uintptr_t)fpu_fbst;
case const_updateflags: return (uintptr_t)UpdateFlags;
case const_sse42_compare_string_explicit_len: return (uintptr_t)sse42_compare_string_explicit_len;
case const_sse42_compare_string_implicit_len: return (uintptr_t)sse42_compare_string_implicit_len;
case const_x64test_step: return (uintptr_t)x64test_step;
case const_printtrace: return (uintptr_t)PrintTrace;
case const_epilog: return (uintptr_t)native_epilog;
case const_jmptbl32: return getJumpTable32();
case const_jmptbl48: return getJumpTable48();
case const_jmptbl64: return getJumpTable64();
case const_context: return (uintptr_t)my_context;
case const_last: dynarec_log(LOG_NONE, "Warning, const last used\n");
return 0;
}
dynarec_log(LOG_NONE, "Warning, Unknown const %d used\n", which);
return 0;
}
@@ -0,0 +1,107 @@
#ifndef __DYNAREC_PPC64LE_CONSTS__
#define __DYNAREC_PPC64LE_CONSTS__
#include <stdint.h>
typedef enum ppc64le_consts_s {
const_none,
const_daa8,
const_das8,
const_aaa16,
const_aas16,
const_aam16,
const_aad16,
const_native_br,
const_native_ud,
const_native_priv,
const_native_gpf,
const_native_int3,
const_native_int,
const_native_div0,
const_native_frstor16,
const_native_fsave16,
const_native_fsave,
const_native_aesimc,
const_native_aesd,
const_native_aesd_y,
const_native_aesdlast,
const_native_aesdlast_y,
const_native_aese,
const_native_aese_y,
const_native_aeselast,
const_native_aeselast_y,
const_native_aeskeygenassist,
const_native_pclmul,
const_native_pclmul_x,
const_native_pclmul_y,
const_direct_f2xm1,
const_direct_fyl2x,
const_direct_fyl2xp1,
const_native_fxtract,
const_direct_ftan,
const_direct_fpatan,
const_direct_fcos,
const_direct_fsin,
const_native_fsincos,
const_direct_fscale,
const_native_fprem,
const_native_fprem1,
const_native_fld,
const_native_fstp,
const_native_frstor,
const_native_next,
const_int3,
const_x86syscall,
const_x64syscall,
const_x64syscall_linux,
const_rcl16,
const_rcl32,
const_rcl64,
const_rcr16,
const_rcr32,
const_rcr64,
const_div64,
const_idiv64,
const_random32,
const_random64,
const_readtsc,
const_helper_getcpu,
const_cpuid,
const_getsegmentbase,
const_reset_fpu,
const_sha1nexte,
const_sha1msg1,
const_sha1msg2,
const_sha1rnds4,
const_sha256msg1,
const_sha256msg2,
const_sha256rnds2,
const_fpu_loadenv,
const_fpu_savenv,
const_fpu_fxsave32,
const_fpu_fxsave64,
const_fpu_fxrstor32,
const_fpu_fxrstor64,
const_fpu_xsave,
const_fpu_xrstor,
const_fpu_fbld,
const_fpu_fbst,
const_updateflags,
const_sse42_compare_string_explicit_len,
const_sse42_compare_string_implicit_len,
const_x64test_step,
const_printtrace,
const_epilog,
const_jmptbl32,
const_jmptbl48,
const_jmptbl64,
const_context,
const_last
} ppc64le_consts_t;
uintptr_t getConst(ppc64le_consts_t which);
// temporary define...
#define const_PrintTrace const_printtrace
#endif //__DYNAREC_PPC64LE_CONSTS__
@@ -0,0 +1,426 @@
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <errno.h>
#include "debug.h"
#include "box64context.h"
#include "box64cpu.h"
#include "emu/x64emu_private.h"
#include "ppc64le_emitter.h"
#include "x64emu.h"
#include "box64stack.h"
#include "callback.h"
#include "emu/x64run_private.h"
#include "x64trace.h"
#include "dynarec_native.h"
#include "ppc64le_printer.h"
#include "dynarec_ppc64le_private.h"
#include "dynarec_ppc64le_functions.h"
#include "../dynarec_helper.h"
// emit XOR8 instruction, from s1, s2, store result in s1 using s3 and s4 as scratch, s4 can be same as s2 (and so s2 destroyed)
void emit_xor8(dynarec_ppc64le_t* dyn, int ninst, int s1, int s2, int s3, int s4)
{
IFX (X_PEND) {
SET_DF(s3, d_xor8);
} else IFXORNAT (X_ALL) {
SET_DFNONE();
}
XOR(s1, s1, s2);
ANDId(s1, s1, 0xff);
IFX (X_PEND) {
STB(s1, offsetof(x64emu_t, res), xEmu);
}
CLEAR_FLAGS(s3);
IFX (X_SF) {
SRDI(s3, s1, 7);
CMPDI(s3, 0);
BEQ(8);
ORI(xFlags, xFlags, 1 << F_SF);
}
IFX (X_ZF) {
CMPDI(s1, 0);
BNE(8);
ORI(xFlags, xFlags, 1 << F_ZF);
}
IFX (X_PF) {
emit_pf(dyn, ninst, s1, s3, s4);
}
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s1, xZR, s3, xZR);
}
// emit XOR8 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
void emit_xor8c(dynarec_ppc64le_t* dyn, int ninst, int s1, int32_t c, int s3, int s4)
{
IFX (X_PEND) {
SET_DF(s3, d_xor8);
} else IFXORNAT (X_ALL) {
SET_DFNONE();
}
XORI(s1, s1, c & 0xff);
ANDId(s1, s1, 0xff);
CLEAR_FLAGS(s3);
IFX (X_SF) {
SRDI(s3, s1, 7);
CMPDI(s3, 0);
BEQ(8);
ORI(xFlags, xFlags, 1 << F_SF);
}
IFX (X_PEND) {
STB(s1, offsetof(x64emu_t, res), xEmu);
}
IFX (X_ZF) {
CMPDI(s1, 0);
BNE(8);
ORI(xFlags, xFlags, 1 << F_ZF);
}
IFX (X_PF) {
emit_pf(dyn, ninst, s1, s3, s4);
}
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s1, xZR, s3, xZR);
}
// emit XOR32 instruction, from s1, s2, store result in s1 using s3 and s4 as scratch
void emit_xor32(dynarec_ppc64le_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4)
{
IFX (X_PEND) {
SET_DF(s3, rex.w ? d_xor64 : d_xor32);
} else IFXORNAT (X_ALL) {
SET_DFNONE();
}
CLEAR_FLAGS(s3);
XOR(s1, s1, s2);
// test sign bit before zeroup.
IFX (X_SF) {
if (!rex.w) EXTSW(s1, s1);
CMPDI(s1, 0);
BGE(8);
ORI(xFlags, xFlags, 1 << F_SF);
}
if (!rex.w && s1 != s2) {
ZEROUP(s1);
}
IFX (X_PEND) {
SDxw(s1, xEmu, offsetof(x64emu_t, res));
}
IFX (X_ZF) {
CMPDI(s1, 0);
BNE(8);
ORI(xFlags, xFlags, 1 << F_ZF);
}
IFX (X_PF) {
emit_pf(dyn, ninst, s1, s3, s4);
}
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s1, xZR, s3, xZR);
}
// emit XOR32 instruction, from s1, c, store result in s1 using s3 and s4 as scratch
void emit_xor32c(dynarec_ppc64le_t* dyn, int ninst, rex_t rex, int s1, int64_t c, int s3, int s4)
{
IFX (X_PEND) {
SET_DF(s3, rex.w ? d_xor64 : d_xor32);
} else IFXORNAT (X_ALL) {
SET_DFNONE();
}
if (c >= 0 && c <= 65535) {
XORI(s1, s1, c);
} else {
MOV64xw(s3, c);
XOR(s1, s1, s3);
}
CLEAR_FLAGS(s3);
// test sign bit before zeroup.
IFX (X_SF) {
if (!rex.w) EXTSW(s1, s1);
CMPDI(s1, 0);
BGE(8);
ORI(xFlags, xFlags, 1 << F_SF);
}
if (!rex.w) {
ZEROUP(s1);
}
IFX (X_PEND) {
SDxw(s1, xEmu, offsetof(x64emu_t, res));
}
IFX (X_ZF) {
CMPDI(s1, 0);
BNE(8);
ORI(xFlags, xFlags, 1 << F_ZF);
}
IFX (X_PF) {
emit_pf(dyn, ninst, s1, s3, s4);
}
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s1, xZR, s3, xZR);
}
// emit AND8 instruction, from s1, s2, store result in s1 using s3 and s4 as scratch, s4 can be same as s2 (and so s2 destroyed)
void emit_and8(dynarec_ppc64le_t* dyn, int ninst, int s1, int s2, int s3, int s4)
{
IFX (X_PEND) {
SET_DF(s3, d_and8);
} else IFXORNAT (X_ALL) {
SET_DFNONE();
}
AND(s1, s1, s2);
IFX (X_PEND) {
STB(s1, offsetof(x64emu_t, res), xEmu);
}
CLEAR_FLAGS(s3);
IFX (X_SF) {
SRDI(s3, s1, 7);
CMPDI(s3, 0);
BEQ(8);
ORI(xFlags, xFlags, 1 << F_SF);
}
IFX (X_ZF) {
CMPDI(s1, 0);
BNE(8);
ORI(xFlags, xFlags, 1 << F_ZF);
}
IFX (X_PF) {
emit_pf(dyn, ninst, s1, s3, s4);
}
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s1, xZR, s3, xZR);
}
// emit AND8 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
void emit_and8c(dynarec_ppc64le_t* dyn, int ninst, int s1, int32_t c, int s3, int s4)
{
IFX (X_PEND) {
SET_DF(s3, d_and8);
} else IFXORNAT (X_ALL) {
SET_DFNONE();
}
ANDId(s1, s1, c & 0xff);
IFX (X_PEND) {
STD(s1, offsetof(x64emu_t, res), xEmu);
}
CLEAR_FLAGS(s3);
IFX (X_SF) {
SRDI(s3, s1, 7);
CMPDI(s3, 0);
BEQ(8);
ORI(xFlags, xFlags, 1 << F_SF);
}
IFX (X_ZF) {
CMPDI(s1, 0);
BNE(8);
ORI(xFlags, xFlags, 1 << F_ZF);
}
IFX (X_PF) {
emit_pf(dyn, ninst, s1, s3, s4);
}
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s1, xZR, s3, xZR);
}
// emit AND32 instruction, from s1, s2, store result in s1 using s3 and s4 as scratch
void emit_and32(dynarec_ppc64le_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4)
{
IFX (X_PEND) {
SET_DF(s3, rex.w ? d_tst64 : d_tst32);
} else IFXORNAT (X_ALL) {
SET_DFNONE();
}
AND(s1, s1, s2); // res = s1 & s2
if (!rex.w) ZEROUP(s1);
IFX (X_PEND) {
SDxw(s1, xEmu, offsetof(x64emu_t, res));
}
CLEAR_FLAGS(s3);
IFX (X_SF) {
SRDI(s3, s1, rex.w ? 63 : 31);
CMPDI(s3, 0);
BEQ(8);
ORI(xFlags, xFlags, 1 << F_SF);
}
IFX (X_ZF) {
CMPDI(s1, 0);
BNE(8);
ORI(xFlags, xFlags, 1 << F_ZF);
}
IFX (X_PF) {
emit_pf(dyn, ninst, s1, s3, s4);
}
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s1, xZR, s3, xZR);
}
// emit AND32 instruction, from s1, c, store result in s1 using s3 and s4 as scratch
void emit_and32c(dynarec_ppc64le_t* dyn, int ninst, rex_t rex, int s1, int64_t c, int s3, int s4)
{
IFX (X_PEND) {
SET_DF(s3, rex.w ? d_tst64 : d_tst32);
} else IFXORNAT (X_ALL) {
SET_DFNONE();
}
if (c >= 0 && c <= 65535) {
ANDId(s1, s1, c);
} else {
MOV64xw(s3, c);
AND(s1, s1, s3); // res = s1 & s2
}
IFX (X_PEND) {
SDxw(s1, xEmu, offsetof(x64emu_t, res));
}
CLEAR_FLAGS(s3);
IFX (X_SF) {
SRDI(s3, s1, rex.w ? 63 : 31);
CMPDI(s3, 0);
BEQ(8);
ORI(xFlags, xFlags, 1 << F_SF);
}
IFX (X_ZF) {
CMPDI(s1, 0);
BNE(8);
ORI(xFlags, xFlags, 1 << F_ZF);
}
IFX (X_PF) {
emit_pf(dyn, ninst, s1, s3, s4);
}
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s1, xZR, s3, xZR);
}
// emit OR8 instruction, from s1, s2, store result in s1 using s3 and s4 as scratch, s4 can be same as s2 (and so s2 destroyed)
void emit_or8(dynarec_ppc64le_t* dyn, int ninst, int s1, int s2, int s3, int s4)
{
IFX (X_PEND) {
SET_DF(s3, d_or8);
} else IFXORNAT (X_ALL) {
SET_DFNONE();
}
OR(s1, s1, s2);
IFX (X_PEND) {
STB(s1, offsetof(x64emu_t, res), xEmu);
}
CLEAR_FLAGS(s3);
IFX (X_SF) {
SRDI(s3, s1, 7);
CMPDI(s3, 0);
BEQ(8);
ORI(xFlags, xFlags, 1 << F_SF);
}
IFX (X_ZF) {
CMPDI(s1, 0);
BNE(8);
ORI(xFlags, xFlags, 1 << F_ZF);
}
IFX (X_PF) {
emit_pf(dyn, ninst, s1, s3, s4);
}
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s1, xZR, s3, xZR);
}
// emit OR8 instruction, from s1 , constant c, store result in s1 using s2, s3 and s4 as scratch
void emit_or8c(dynarec_ppc64le_t* dyn, int ninst, int s1, int32_t c, int s2, int s3, int s4)
{
MOV32w(s2, c & 0xff);
emit_or8(dyn, ninst, s1, s2, s3, s4);
}
// emit OR32 instruction, from s1, s2, store result in s1 using s3 and s4 as scratch
void emit_or32(dynarec_ppc64le_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4)
{
IFX (X_PEND) {
SET_DF(s4, rex.w ? d_or64 : d_or32);
} else IFXORNAT (X_ALL) {
SET_DFNONE();
}
OR(s1, s1, s2);
IFX (X_PEND) {
SDxw(s1, xEmu, offsetof(x64emu_t, res));
}
CLEAR_FLAGS(s3);
// test sign bit before zeroup.
IFX (X_SF) {
if (!rex.w) EXTSW(s1, s1);
CMPDI(s1, 0);
BGE(8);
ORI(xFlags, xFlags, 1 << F_SF);
}
if (!rex.w) ZEROUP(s1);
IFX (X_ZF) {
CMPDI(s1, 0);
BNE(8);
ORI(xFlags, xFlags, 1 << F_ZF);
}
IFX (X_PF) {
emit_pf(dyn, ninst, s1, s3, s4);
}
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s1, xZR, s3, xZR);
}
// emit OR32 instruction, from s1, c, store result in s1 using s3 and s4 as scratch
void emit_or32c(dynarec_ppc64le_t* dyn, int ninst, rex_t rex, int s1, int64_t c, int s3, int s4)
{
IFX (X_PEND) {
SET_DF(s4, rex.w ? d_or64 : d_or32);
} else IFXORNAT (X_ALL) {
SET_DFNONE();
}
if (c >= 0 && c <= 65535) {
ORI(s1, s1, c);
} else {
MOV64xw(s3, c);
OR(s1, s1, s3);
}
IFX (X_PEND) {
SDxw(s1, xEmu, offsetof(x64emu_t, res));
}
CLEAR_FLAGS(s3);
// test sign bit before zeroup.
IFX (X_SF) {
if (!rex.w) EXTSW(s1, s1);
CMPDI(s1, 0);
BGE(8);
ORI(xFlags, xFlags, 1 << F_SF);
}
if (!rex.w) {
ZEROUP(s1);
}
IFX (X_ZF) {
CMPDI(s1, 0);
BNE(8);
ORI(xFlags, xFlags, 1 << F_ZF);
}
IFX (X_PF) {
emit_pf(dyn, ninst, s1, s3, s4);
}
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s1, xZR, s3, xZR);
}
@@ -0,0 +1,864 @@
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <errno.h>
#include "debug.h"
#include "box64context.h"
#include "box64cpu.h"
#include "emu/x64emu_private.h"
#include "ppc64le_emitter.h"
#include "x64emu.h"
#include "box64stack.h"
#include "callback.h"
#include "emu/x64run_private.h"
#include "x64trace.h"
#include "dynarec_native.h"
#include "ppc64le_printer.h"
#include "dynarec_ppc64le_private.h"
#include "dynarec_ppc64le_functions.h"
#include "../dynarec_helper.h"
// emit ADD32 instruction, from s1, s2, store result in s1 using s3 and s4 as scratch
void emit_add32(dynarec_ppc64le_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4, int s5)
{
IFX (X_PEND) {
SDxw(s1, xEmu, offsetof(x64emu_t, op1));
SDxw(s2, xEmu, offsetof(x64emu_t, op2));
SET_DF(s3, rex.w ? d_add64 : d_add32b);
} else IFXORNAT (X_ALL) {
SET_DFNONE();
}
CLEAR_FLAGS(s3);
IFX (X_CF) {
if (rex.w) {
ZEROUP2(s5, s1);
ZEROUP2(s4, s2);
ADD(s5, s5, s4);
SRDI(s3, s1, 0x20);
SRDI(s4, s2, 0x20);
ADD(s4, s4, s3);
SRDI(s5, s5, 0x20);
ADD(s5, s5, s4); // hi
SRADI(s5, s5, 0x20);
CMPDI(s5, 0);
BEQ(8);
ORI(xFlags, xFlags, 1 << F_CF);
} else {
ZEROUP2(s3, s1);
ZEROUP2(s4, s2);
ADD(s5, s3, s4);
SRDI(s5, s5, 0x20);
CMPDI(s5, 0);
BEQ(8);
ORI(xFlags, xFlags, 1 << F_CF);
}
}
IFX (X_AF | X_OF) {
OR(s3, s1, s2); // s3 = op1 | op2
AND(s4, s1, s2); // s4 = op1 & op2
}
ADDxw(s1, s1, s2);
IFX (X_PEND) {
SDxw(s1, xEmu, offsetof(x64emu_t, res));
}
IFX (X_AF | X_OF) {
ANDC(s3, s3, s1); // s3 = ~res & (op1 | op2)
OR(s3, s3, s4); // cc = (~res & (op1 | op2)) | (op1 & op2)
IFX (X_AF) {
ANDId(s4, s3, 0x08); // AF: cc & 0x08
CMPDI(s4, 0);
BEQ(8);
ORI(xFlags, xFlags, 1 << F_AF);
}
IFX (X_OF) {
SRDI(s3, s3, rex.w ? 62 : 30);
SRDI(s4, s3, 1);
XOR(s3, s3, s4);
ANDId(s3, s3, 1); // OF: xor of two MSB's of cc
BF_INSERT(xFlags, s3, F_OF, F_OF);
}
}
IFX (X_SF) {
SRDI(s3, s1, rex.w ? 63 : 31);
CMPDI(s3, 0);
BEQ(8);
ORI(xFlags, xFlags, 1 << F_SF);
}
if (!rex.w) {
ZEROUP(s1);
}
IFX (X_PF) {
emit_pf(dyn, ninst, s1, s3, s4);
}
IFX (X_ZF) {
CMPDI(s1, 0);
BNE(8);
ORI(xFlags, xFlags, 1 << F_ZF);
}
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s1, xZR, s3, xZR);
}
// emit ADD32 instruction, from s1, constant c, store result in s1 using s3 and s4 as scratch
void emit_add32c(dynarec_ppc64le_t* dyn, int ninst, rex_t rex, int s1, int64_t c, int s2, int s3, int s4, int s5)
{
if ((s1 == xRSP) && (BOX64DRENV(dynarec_safeflags) < 2) && (!dyn->insts || (dyn->insts[ninst].x64.gen_flags == X_PEND) || (!BOX64ENV(dynarec_df) && (dyn->insts[ninst].x64.gen_flags == X_ALL)))) {
// special case when doing math on ESP and only PEND is needed: ignoring it!
if (c >= -32768 && c < 32768) {
ADDI(s1, s1, c);
} else {
MOV64x(s2, c);
ADD(s1, s1, s2);
}
if (!rex.w) { ZEROUP(s1); }
return;
}
IFX (X_PEND | X_AF | X_CF | X_OF) {
MOV64xw(s2, c);
} else if (c < -32768 || c >= 32768) {
MOV64xw(s2, c);
}
IFX (X_PEND) {
SDxw(s1, xEmu, offsetof(x64emu_t, op1));
SDxw(s2, xEmu, offsetof(x64emu_t, op2));
SET_DF(s3, rex.w ? d_add64 : d_add32b);
} else IFXORNAT (X_ALL) {
SET_DFNONE();
}
CLEAR_FLAGS(s3);
IFX (X_CF) {
if (rex.w) {
ZEROUP2(s5, s1);
ZEROUP2(s4, s2);
ADD(s5, s5, s4);
SRDI(s3, s1, 0x20);
SRDI(s4, s2, 0x20);
ADD(s4, s4, s3);
SRDI(s5, s5, 0x20);
ADD(s5, s5, s4); // hi
SRADI(s5, s5, 0x20);
CMPDI(s5, 0);
BEQ(8);
ORI(xFlags, xFlags, 1 << F_CF);
} else {
ZEROUP2(s3, s1);
ZEROUP2(s4, s2);
ADD(s5, s3, s4);
SRDI(s5, s5, 0x20);
CMPDI(s5, 0);
BEQ(8);
ORI(xFlags, xFlags, 1 << F_CF);
}
}
IFX (X_AF | X_OF) {
OR(s3, s1, s2); // s3 = op1 | op2
AND(s4, s1, s2); // s4 = op1 & op2
}
if (c >= -32768 && c < 32768) {
ADDIxw(s1, s1, c);
} else {
ADDxw(s1, s1, s2);
}
IFX (X_PEND) {
SDxw(s1, xEmu, offsetof(x64emu_t, res));
}
IFX (X_AF | X_OF) {
ANDC(s3, s3, s1); // s3 = ~res & (op1 | op2)
OR(s3, s3, s4); // cc = (~res & (op1 | op2)) | (op1 & op2)
IFX (X_AF) {
ANDId(s4, s3, 0x08); // AF: cc & 0x08
CMPDI(s4, 0);
BEQ(8);
ORI(xFlags, xFlags, 1 << F_AF);
}
IFX (X_OF) {
SRDI(s3, s3, rex.w ? 62 : 30);
SRDI(s4, s3, 1);
XOR(s3, s3, s4);
ANDId(s3, s3, 1); // OF: xor of two MSB's of cc
BF_INSERT(xFlags, s3, F_OF, F_OF);
}
}
IFX (X_SF) {
SRDI(s3, s1, rex.w ? 63 : 31);
CMPDI(s3, 0);
BEQ(8);
ORI(xFlags, xFlags, 1 << F_SF);
}
if (!rex.w) {
ZEROUP(s1);
}
IFX (X_PF) {
emit_pf(dyn, ninst, s1, s3, s4);
}
IFX (X_ZF) {
CMPDI(s1, 0);
BNE(8);
ORI(xFlags, xFlags, 1 << F_ZF);
}
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s1, xZR, s3, xZR);
}
// emit ADD8 instruction, from s1, s2, store result in s1 using s3 and s4 as scratch
void emit_add8(dynarec_ppc64le_t* dyn, int ninst, int s1, int s2, int s3, int s4)
{
IFX (X_PEND) {
STB(s1, offsetof(x64emu_t, op1), xEmu);
STB(s2, offsetof(x64emu_t, op2), xEmu);
SET_DF(s3, d_add8);
} else IFXORNAT (X_ALL) {
SET_DFNONE();
}
CLEAR_FLAGS(s3);
IFX (X_AF | X_OF) {
OR(s3, s1, s2); // s3 = op1 | op2
AND(s4, s1, s2); // s4 = op1 & op2
}
ADD(s1, s1, s2);
IFX (X_AF | X_OF) {
ANDC(s3, s3, s1); // s3 = ~res & (op1 | op2)
OR(s3, s3, s4); // cc = (~res & (op1 | op2)) | (op1 & op2)
IFX (X_AF) {
ANDId(s4, s3, 0x08); // AF: cc & 0x08
CMPDI(s4, 0);
BEQ(8);
ORI(xFlags, xFlags, 1 << F_AF);
}
IFX (X_OF) {
SRDI(s3, s3, 6);
SRDI(s4, s3, 1);
XOR(s3, s3, s4);
ANDId(s3, s3, 1); // OF: xor of two MSB's of cc
BF_INSERT(xFlags, s3, F_OF, F_OF);
}
}
IFX (X_CF) {
SRDI(s3, s1, 8);
CMPDI(s3, 0);
BEQ(8);
ORI(xFlags, xFlags, 1 << F_CF);
}
// d_add8 will use 16bits result to check for CF, so save 16bits and truncate after
IFX (X_PEND) {
STH(s1, offsetof(x64emu_t, res), xEmu);
}
ANDId(s1, s1, 0xff);
IFX (X_ZF) {
CMPDI(s1, 0);
BNE(8);
ORI(xFlags, xFlags, 1 << F_ZF);
}
IFX (X_SF) {
SRDI(s3, s1, 7);
CMPDI(s3, 0);
BEQ(8);
ORI(xFlags, xFlags, 1 << F_SF);
}
IFX (X_PF) {
emit_pf(dyn, ninst, s1, s3, s4);
}
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s1, xZR, s3, xZR);
}
// emit ADD8 instruction, from s1, const c, store result in s1 using s3 and s4 as scratch
void emit_add8c(dynarec_ppc64le_t* dyn, int ninst, int s1, int32_t c, int s2, int s3, int s4)
{
IFX (X_PEND) {
MOV32w(s4, c & 0xff);
STB(s1, offsetof(x64emu_t, op1), xEmu);
STB(s4, offsetof(x64emu_t, op2), xEmu);
SET_DF(s3, d_add8);
} else IFXORNAT (X_ALL) {
SET_DFNONE();
}
CLEAR_FLAGS(s3);
IFX (X_AF | X_OF) {
IFX (X_PEND) {
} else {
MOV32w(s4, c & 0xff);
}
OR(s3, s1, s4); // s3 = op1 | op2
AND(s4, s1, s4); // s4 = op1 & op2
}
ADDI(s1, s1, c & 0xff);
IFX (X_AF | X_OF) {
ANDC(s3, s3, s1); // s3 = ~res & (op1 | op2)
OR(s3, s3, s4); // cc = (~res & (op1 | op2)) | (op1 & op2)
IFX (X_AF) {
ANDId(s4, s3, 0x08); // AF: cc & 0x08
CMPDI(s4, 0);
BEQ(8);
ORI(xFlags, xFlags, 1 << F_AF);
}
IFX (X_OF) {
SRDI(s3, s3, 6);
SRDI(s4, s3, 1);
XOR(s3, s3, s4);
ANDId(s3, s3, 1); // OF: xor of two MSB's of cc
BF_INSERT(xFlags, s3, F_OF, F_OF);
}
}
IFX (X_CF) {
SRDI(s3, s1, 8);
CMPDI(s3, 0);
BEQ(8);
ORI(xFlags, xFlags, 1 << F_CF);
}
// d_add8 will use 16bits result to check for CF, so save 16bits and truncate after
IFX (X_PEND) {
STH(s1, offsetof(x64emu_t, res), xEmu);
}
ANDId(s1, s1, 0xff);
IFX (X_ZF) {
CMPDI(s1, 0);
BNE(8);
ORI(xFlags, xFlags, 1 << F_ZF);
}
IFX (X_SF) {
SRDI(s3, s1, 7);
CMPDI(s3, 0);
BEQ(8);
ORI(xFlags, xFlags, 1 << F_SF);
}
IFX (X_PF) {
emit_pf(dyn, ninst, s1, s3, s4);
}
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s1, xZR, s3, xZR);
}
// emit SUB8 instruction, from s1, s2, store result in s1 using s3, s4 and s5 as scratch
void emit_sub8(dynarec_ppc64le_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5)
{
IFX (X_PEND) {
STB(s1, offsetof(x64emu_t, op1), xEmu);
STB(s2, offsetof(x64emu_t, op2), xEmu);
SET_DF(s3, d_sub8);
} else IFXORNAT (X_ALL) {
SET_DFNONE();
}
CLEAR_FLAGS(s3);
IFX (X_AF | X_CF | X_OF) {
// for later flag calculation
NOT(s5, s1);
}
SUB(s1, s1, s2);
ANDId(s1, s1, 0xff);
IFX (X_SF) {
SRDI(s3, s1, 7);
CMPDI(s3, 0);
BEQ(8);
ORI(xFlags, xFlags, 1 << F_SF);
}
IFX (X_PEND) {
STB(s1, offsetof(x64emu_t, res), xEmu);
}
CALC_SUB_FLAGS(s5, s2, s1, s3, s4, 8);
IFX (X_ZF) {
CMPDI(s1, 0);
BNE(8);
ORI(xFlags, xFlags, 1 << F_ZF);
}
IFX (X_PF) {
emit_pf(dyn, ninst, s1, s3, s4);
}
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s1, xZR, s3, xZR);
}
// emit SUB8 instruction, from s1, constant c, store result in s1 using s2, s3, s4 and s5 as scratch
void emit_sub8c(dynarec_ppc64le_t* dyn, int ninst, int s1, int32_t c, int s2, int s3, int s4, int s5)
{
MOV32w(s2, c & 0xff);
emit_sub8(dyn, ninst, s1, s2, s3, s4, s5);
}
// emit SUB32 instruction, from s1, s2, store result in s1 using s3, s4 and s5 as scratch
void emit_sub32(dynarec_ppc64le_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4, int s5)
{
IFX (X_PEND) {
SDxw(s1, xEmu, offsetof(x64emu_t, op1));
SDxw(s2, xEmu, offsetof(x64emu_t, op2));
SET_DF(s3, rex.w ? d_sub64 : d_sub32);
} else IFXORNAT (X_ALL) {
SET_DFNONE();
}
CLEAR_FLAGS(s3);
IFX (X_AF | X_CF | X_OF) {
// for later flag calculation
NOT(s5, s1);
}
SUBxw(s1, s1, s2);
IFX (X_PEND) {
SDxw(s1, xEmu, offsetof(x64emu_t, res));
}
IFX (X_SF) {
SRDI(s3, s1, rex.w ? 63 : 31);
CMPDI(s3, 0);
BEQ(8);
ORI(xFlags, xFlags, 1 << F_SF);
}
if (!rex.w) {
ZEROUP(s1);
}
CALC_SUB_FLAGS(s5, s2, s1, s3, s4, rex.w ? 64 : 32);
IFX (X_ZF) {
CMPDI(s1, 0);
BNE(8);
ORI(xFlags, xFlags, 1 << F_ZF);
}
IFX (X_PF) {
emit_pf(dyn, ninst, s1, s3, s4);
}
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s1, xZR, s3, xZR);
}
// emit SUB32 instruction, from s1, constant c, store result in s1 using s2, s3, s4 and s5 as scratch
void emit_sub32c(dynarec_ppc64le_t* dyn, int ninst, rex_t rex, int s1, int64_t c, int s2, int s3, int s4, int s5)
{
if ((s1 == xRSP) && (BOX64DRENV(dynarec_safeflags) < 2) && (!dyn->insts || (dyn->insts[ninst].x64.gen_flags == X_PEND) || (!BOX64ENV(dynarec_df) && (dyn->insts[ninst].x64.gen_flags == X_ALL)))) {
// special case when doing math on RSP and only PEND is needed: ignoring it!
if (c > -32768 && c <= 32768) {
ADDI(s1, s1, -c);
} else {
MOV64xw(s2, c);
SUBxw(s1, s1, s2);
}
if (!rex.w) { ZEROUP(s1); }
return;
}
IFX (X_PEND | X_AF | X_CF | X_OF) {
MOV64xw(s2, c);
} else if (c <= -32768 || c > 32768) {
MOV64xw(s2, c);
}
IFX (X_PEND) {
SDxw(s1, xEmu, offsetof(x64emu_t, op1));
SDxw(s2, xEmu, offsetof(x64emu_t, op2));
SET_DF(s3, rex.w ? d_sub64 : d_sub32);
} else IFXORNAT (X_ALL) {
SET_DFNONE();
}
CLEAR_FLAGS(s3);
IFX (X_AF | X_CF | X_OF) {
// for later flag calculation
NOT(s5, s1);
}
if (c > -32768 && c <= 32768) {
ADDIxw(s1, s1, -c);
} else {
SUBxw(s1, s1, s2);
}
IFX (X_PEND) {
SDxw(s1, xEmu, offsetof(x64emu_t, res));
}
IFX (X_SF) {
SRDI(s3, s1, rex.w ? 63 : 31);
CMPDI(s3, 0);
BEQ(8);
ORI(xFlags, xFlags, 1 << F_SF);
}
if (!rex.w) {
ZEROUP(s1);
}
CALC_SUB_FLAGS(s5, s2, s1, s3, s4, rex.w ? 64 : 32);
IFX (X_ZF) {
CMPDI(s1, 0);
BNE(8);
ORI(xFlags, xFlags, 1 << F_ZF);
}
IFX (X_PF) {
emit_pf(dyn, ninst, s1, s3, s4);
}
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s1, xZR, s3, xZR);
}
// emit SBB8 instruction, from s1, s2, store result in s1 using s3, s4 and s5 as scratch
void emit_sbb8(dynarec_ppc64le_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5)
{
IFX (X_PEND) {
STB(s1, offsetof(x64emu_t, op1), xEmu);
STB(s2, offsetof(x64emu_t, op2), xEmu);
SET_DF(s3, d_sbb8);
} else IFXORNAT (X_ALL) {
SET_DFNONE();
}
IFX (X_AF | X_CF | X_OF) {
// for later flag calculation
NOT(s5, s1);
}
SUB(s1, s1, s2);
ANDId(s3, xFlags, 1 << F_CF);
SUB(s1, s1, s3);
CLEAR_FLAGS(s3);
IFX (X_PEND) {
// d_sbb8 will use 16bits result to check for CF
STH(s1, offsetof(x64emu_t, res), xEmu);
}
ANDId(s1, s1, 0xff);
CALC_SUB_FLAGS(s5, s2, s1, s3, s4, 8);
IFX (X_SF) {
SRDI(s3, s1, 7);
CMPDI(s3, 0);
BEQ(8);
ORI(xFlags, xFlags, 1 << F_SF);
}
IFX (X_ZF) {
CMPDI(s1, 0);
BNE(8);
ORI(xFlags, xFlags, 1 << F_ZF);
}
IFX (X_PF) {
emit_pf(dyn, ninst, s1, s3, s4);
}
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s1, xZR, s3, xZR);
}
// emit SBB8 instruction, from s1, constant c, store result in s1 using s3, s4, s5 and s6 as scratch
void emit_sbb8c(dynarec_ppc64le_t* dyn, int ninst, int s1, int32_t c, int s3, int s4, int s5, int s6)
{
MOV32w(s6, c & 0xff);
emit_sbb8(dyn, ninst, s1, s6, s3, s4, s5);
}
// emit SBB16 instruction, from s1, s2, store result in s1 using s3, s4 and s5 as scratch
void emit_sbb16(dynarec_ppc64le_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5)
{
IFX (X_PEND) {
STH(s1, offsetof(x64emu_t, op1), xEmu);
STH(s2, offsetof(x64emu_t, op2), xEmu);
SET_DF(s3, d_sbb16);
} else IFXORNAT (X_ALL) {
SET_DFNONE();
}
IFX (X_AF | X_CF | X_OF) {
// for later flag calculation
NOT(s5, s1);
}
SUB(s1, s1, s2);
ANDId(s3, xFlags, 1 << F_CF);
SUB(s1, s1, s3);
CLEAR_FLAGS(s3);
IFX (X_PEND) {
// d_sbb16 will use 32bits result to check for CF
STW(s1, offsetof(x64emu_t, res), xEmu);
}
// Check SF: shift left 48, check sign, shift back
SLDI(s1, s1, 48);
IFX (X_SF) {
CMPDI(s1, 0);
BGE(8);
ORI(xFlags, xFlags, 1 << F_SF);
}
SRDI(s1, s1, 48);
CALC_SUB_FLAGS(s5, s2, s1, s3, s4, 16);
IFX (X_ZF) {
CMPDI(s1, 0);
BNE(8);
ORI(xFlags, xFlags, 1 << F_ZF);
}
IFX (X_PF) {
emit_pf(dyn, ninst, s1, s3, s4);
}
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s1, xZR, s3, xZR);
}
// emit SBB32 instruction, from s1, s2, store result in s1 using s3, s4 and s5 as scratch
void emit_sbb32(dynarec_ppc64le_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4, int s5)
{
IFX (X_PEND) {
SDxw(s1, xEmu, offsetof(x64emu_t, op1));
SDxw(s2, xEmu, offsetof(x64emu_t, op2));
SET_DF(s3, rex.w ? d_sbb64 : d_sbb32);
} else IFXORNAT (X_ALL) {
SET_DFNONE();
}
IFX (X_AF | X_CF | X_OF) {
// for later flag calculation
NOT(s5, s1);
}
SUBxw(s1, s1, s2);
ANDId(s3, xFlags, 1 << F_CF);
SUBxw(s1, s1, s3);
CLEAR_FLAGS(s3);
IFX (X_SF) {
SRDI(s3, s1, rex.w ? 63 : 31);
CMPDI(s3, 0);
BEQ(8);
ORI(xFlags, xFlags, 1 << F_SF);
}
if (!rex.w) ZEROUP(s1);
IFX (X_PEND) {
SDxw(s1, xEmu, offsetof(x64emu_t, res));
}
CALC_SUB_FLAGS(s5, s2, s1, s3, s4, rex.w ? 64 : 32);
IFX (X_ZF) {
CMPDI(s1, 0);
BNE(8);
ORI(xFlags, xFlags, 1 << F_ZF);
}
IFX (X_PF) {
emit_pf(dyn, ninst, s1, s3, s4);
}
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s1, xZR, s3, xZR);
}
// emit ADC8 instruction, from s1, s2, store result in s1 using s3 and s4 as scratch
void emit_adc8(dynarec_ppc64le_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5)
{
IFX (X_PEND) {
STB(s1, offsetof(x64emu_t, op1), xEmu);
STB(s2, offsetof(x64emu_t, op2), xEmu);
SET_DF(s3, d_adc8);
} else IFXORNAT (X_ALL) {
SET_DFNONE();
}
IFX (X_AF | X_OF) {
OR(s4, s1, s2); // s4 = op1 | op2
AND(s5, s1, s2); // s5 = op1 & op2
}
ADD(s1, s1, s2);
ANDId(s3, xFlags, 1 << F_CF);
ADD(s1, s1, s3);
CLEAR_FLAGS(s3);
IFX (X_PEND) {
// d_adc8 will use 16bits result to check for CF
STH(s1, offsetof(x64emu_t, res), xEmu);
}
IFX (X_AF | X_OF) {
ANDC(s3, s4, s1); // s3 = ~res & (op1 | op2)
OR(s3, s3, s5); // cc = (~res & (op1 | op2)) | (op1 & op2)
IFX (X_AF) {
ANDId(s4, s3, 0x08); // AF: cc & 0x08
CMPDI(s4, 0);
BEQ(8);
ORI(xFlags, xFlags, 1 << F_AF);
}
IFX (X_OF) {
SRDI(s3, s3, 6);
SRDI(s4, s3, 1);
XOR(s3, s3, s4);
ANDId(s3, s3, 1); // OF: xor of two MSB's of cc
BF_INSERT(xFlags, s3, F_OF, F_OF);
}
}
IFX (X_CF) {
SRDI(s3, s1, 8);
CMPDI(s3, 0);
BEQ(8);
ORI(xFlags, xFlags, 1 << F_CF);
}
ANDId(s1, s1, 0xff);
IFX (X_ZF) {
CMPDI(s1, 0);
BNE(8);
ORI(xFlags, xFlags, 1 << F_ZF);
}
IFX (X_SF) {
SRDI(s3, s1, 7);
CMPDI(s3, 0);
BEQ(8);
ORI(xFlags, xFlags, 1 << F_SF);
}
IFX (X_PF) {
emit_pf(dyn, ninst, s1, s3, s4);
}
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s1, xZR, s3, xZR);
}
// emit ADC8 instruction, from s1, const c, store result in s1 using s3, s4, s5 and s6 as scratch
void emit_adc8c(dynarec_ppc64le_t* dyn, int ninst, int s1, int32_t c, int s3, int s4, int s5, int s6)
{
MOV32w(s5, c & 0xff);
emit_adc8(dyn, ninst, s1, s5, s3, s4, s6);
}
// emit ADC16 instruction, from s1, s2, store result in s1 using s3 and s4 as scratch
void emit_adc16(dynarec_ppc64le_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5)
{
IFX (X_PEND) {
STH(s1, offsetof(x64emu_t, op1), xEmu);
STH(s2, offsetof(x64emu_t, op2), xEmu);
SET_DF(s3, d_adc16);
} else IFXORNAT (X_ALL) {
SET_DFNONE();
}
IFX (X_AF | X_OF) {
OR(s4, s1, s2); // s4 = op1 | op2
AND(s5, s1, s2); // s5 = op1 & op2
}
ADD(s1, s1, s2);
ANDId(s3, xFlags, 1 << F_CF);
ADD(s1, s1, s3);
CLEAR_FLAGS(s3);
IFX (X_PEND) {
// d_adc16 will use 32bits result to check for CF
STW(s1, offsetof(x64emu_t, res), xEmu);
}
IFX (X_AF | X_OF) {
ANDC(s3, s4, s1); // s3 = ~res & (op1 | op2)
OR(s3, s3, s5); // cc = (~res & (op1 | op2)) | (op1 & op2)
IFX (X_AF) {
ANDId(s4, s3, 0x08); // AF: cc & 0x08
CMPDI(s4, 0);
BEQ(8);
ORI(xFlags, xFlags, 1 << F_AF);
}
IFX (X_OF) {
SRDI(s3, s3, 14);
SRDI(s4, s3, 1);
XOR(s3, s3, s4);
ANDId(s3, s3, 1); // OF: xor of two MSB's of cc
BF_INSERT(xFlags, s3, F_OF, F_OF);
}
}
IFX (X_CF) {
SRDI(s3, s1, 16);
CMPDI(s3, 0);
BEQ(8);
ORI(xFlags, xFlags, 1 << F_CF);
}
BF_EXTRACT(s1, s1, 15, 0);
IFX (X_ZF) {
CMPDI(s1, 0);
BNE(8);
ORI(xFlags, xFlags, 1 << F_ZF);
}
IFX (X_SF) {
SRDI(s3, s1, 15);
CMPDI(s3, 0);
BEQ(8);
ORI(xFlags, xFlags, 1 << F_SF);
}
IFX (X_PF) {
emit_pf(dyn, ninst, s1, s3, s4);
}
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s1, xZR, s3, xZR);
}
// emit ADC32 instruction, from s1, s2, store result in s1 using s3 and s4 as scratch
void emit_adc32(dynarec_ppc64le_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4, int s5, int s6)
{
IFX (X_PEND) {
SDxw(s1, xEmu, offsetof(x64emu_t, op1));
SDxw(s2, xEmu, offsetof(x64emu_t, op2));
SET_DF(s3, rex.w ? d_adc64 : d_adc32b);
} else IFXORNAT (X_ALL) {
SET_DFNONE();
}
IFX (X_CF) {
if (rex.w) {
ZEROUP2(s5, s1);
ZEROUP2(s4, s2);
ADD(s5, s5, s4); // lo
ANDId(s3, xFlags, 1);
ADD(s5, s5, s3); // add carry
SRDI(s3, s1, 0x20);
SRDI(s4, s2, 0x20);
ADD(s4, s4, s3);
SRDI(s5, s5, 0x20);
ADD(s5, s5, s4); // hi
SRADI(s6, s5, 0x20);
} else {
ZEROUP2(s3, s1);
ZEROUP2(s4, s2);
ADD(s5, s3, s4);
ANDId(s3, xFlags, 1);
ADD(s5, s5, s3); // add carry
SRDI(s6, s5, 0x20);
}
}
IFX (X_AF | X_OF) {
OR(s4, s1, s2); // s4 = op1 | op2
AND(s5, s1, s2); // s5 = op1 & op2
}
ADDxw(s1, s1, s2);
ANDId(s3, xFlags, 1 << F_CF);
ADDxw(s1, s1, s3);
IFX (X_PEND) {
SDxw(s1, xEmu, offsetof(x64emu_t, res));
}
CLEAR_FLAGS(s3);
IFX (X_CF) {
CMPDI(s6, 0);
BEQ(8);
ORI(xFlags, xFlags, 1 << F_CF);
}
IFX (X_AF | X_OF) {
ANDC(s3, s4, s1); // s3 = ~res & (op1 | op2)
OR(s3, s3, s5); // cc = (~res & (op1 | op2)) | (op1 & op2)
IFX (X_AF) {
ANDId(s4, s3, 0x08); // AF: cc & 0x08
CMPDI(s4, 0);
BEQ(8);
ORI(xFlags, xFlags, 1 << F_AF);
}
IFX (X_OF) {
SRDI(s3, s3, rex.w ? 62 : 30);
SRDI(s4, s3, 1);
XOR(s3, s3, s4);
ANDId(s3, s3, 1); // OF: xor of two MSB's of cc
BF_INSERT(xFlags, s3, F_OF, F_OF);
}
}
IFX (X_SF) {
SRDI(s3, s1, rex.w ? 63 : 31);
CMPDI(s3, 0);
BEQ(8);
ORI(xFlags, xFlags, 1 << F_SF);
}
if (!rex.w) {
ZEROUP(s1);
}
IFX (X_PF) {
emit_pf(dyn, ninst, s1, s3, s4);
}
IFX (X_ZF) {
CMPDI(s1, 0);
BNE(8);
ORI(xFlags, xFlags, 1 << F_ZF);
}
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s1, xZR, s3, xZR);
}
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,535 @@
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <errno.h>
#include "debug.h"
#include "box64context.h"
#include "box64cpu.h"
#include "emu/x64emu_private.h"
#include "ppc64le_emitter.h"
#include "x64emu.h"
#include "box64stack.h"
#include "callback.h"
#include "emu/x64run_private.h"
#include "x64trace.h"
#include "dynarec_native.h"
#include "ppc64le_printer.h"
#include "dynarec_ppc64le_private.h"
#include "dynarec_ppc64le_functions.h"
#include "../dynarec_helper.h"
// emit CMP8 instruction, from cmp s1, s2, using s3, s4, s5 and s6 as scratch
void emit_cmp8(dynarec_ppc64le_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5, int s6)
{
IFX_PENDOR0 {
STB(s1, offsetof(x64emu_t, op1), xEmu);
STB(s2, offsetof(x64emu_t, op2), xEmu);
SET_DF(s4, d_cmp8);
} else {
SET_DFNONE();
}
NAT_FLAGS_ENABLE_CARRY();
NAT_FLAGS_ENABLE_SIGN();
CLEAR_FLAGS(s3);
IFX(X_AF | X_CF | X_OF) {
// for later flag calculation
NOT(s5, s1);
}
// It's a cmp, we can't store the result back to s1.
SUB(s6, s1, s2);
ANDId(s6, s6, 0xff);
IFX_PENDOR0 {
STB(s6, offsetof(x64emu_t, res), xEmu);
}
IFX(X_SF) {
SRDI(s3, s6, 7);
CMPDI(s3, 0);
BEQ(8);
ORI(xFlags, xFlags, 1 << F_SF);
}
CALC_SUB_FLAGS(s5, s2, s6, s3, s4, 8);
IFX(X_ZF) {
CMPDI(s6, 0);
BNE(8);
ORI(xFlags, xFlags, 1 << F_ZF);
}
IFX(X_PF) {
emit_pf(dyn, ninst, s6, s3, s4);
}
if (dyn->insts[ninst].nat_flags_fusion) {
if (dyn->insts[ninst].nat_flags_needsign) {
EXTSB(s3, s1);
EXTSB(s4, s2);
NAT_FLAGS_OPS(s3, s4, s5, xZR);
} else {
NAT_FLAGS_OPS(s1, s2, s3, xZR);
}
}
}
// emit CMP8 instruction, from cmp s1 , 0, using s3 and s4 as scratch
void emit_cmp8_0(dynarec_ppc64le_t* dyn, int ninst, int s1, int s3, int s4)
{
IFX_PENDOR0 {
STB(s1, offsetof(x64emu_t, op1), xEmu);
LI(s3, 0);
STB(s3, offsetof(x64emu_t, op2), xEmu);
STB(s1, offsetof(x64emu_t, res), xEmu);
SET_DF(s3, d_cmp8);
} else {
SET_DFNONE();
}
NAT_FLAGS_ENABLE_CARRY();
NAT_FLAGS_ENABLE_SIGN();
CLEAR_FLAGS(s3);
IFX(X_SF) {
SRDI(s3, s1, 7);
CMPDI(s3, 0);
BEQ(8);
ORI(xFlags, xFlags, 1 << F_SF);
}
IFX(X_ZF) {
CMPDI(s1, 0);
BNE(8);
ORI(xFlags, xFlags, 1 << F_ZF);
}
IFX(X_PF) {
emit_pf(dyn, ninst, s1, s3, s4);
}
if (dyn->insts[ninst].nat_flags_fusion) {
if (dyn->insts[ninst].nat_flags_needsign) {
EXTSB(s3, s1);
NAT_FLAGS_OPS(s3, xZR, s4, xZR);
} else {
NAT_FLAGS_OPS(s1, xZR, s3, xZR);
}
}
}
// emit CMP16 instruction, from cmp s1, s2, using s3, s4, s5 and s6 as scratch
void emit_cmp16(dynarec_ppc64le_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5, int s6)
{
IFX_PENDOR0 {
STH(s1, offsetof(x64emu_t, op1), xEmu);
STH(s2, offsetof(x64emu_t, op2), xEmu);
SET_DF(s4, d_cmp16);
} else {
SET_DFNONE();
}
NAT_FLAGS_ENABLE_CARRY();
NAT_FLAGS_ENABLE_SIGN();
CLEAR_FLAGS(s3);
IFX(X_AF | X_CF | X_OF) {
// for later flag calculation
NOT(s5, s1);
}
// It's a cmp, we can't store the result back to s1.
SUB(s6, s1, s2);
IFX(X_ALL) {
BF_EXTRACT(s6, s6, 15, 0);
}
IFX_PENDOR0 {
STH(s6, offsetof(x64emu_t, res), xEmu);
}
IFX(X_SF) {
SRDI(s3, s6, 15);
CMPDI(s3, 0);
BEQ(8);
ORI(xFlags, xFlags, 1 << F_SF);
}
CALC_SUB_FLAGS(s5, s2, s6, s3, s4, 16);
IFX(X_ZF) {
CMPDI(s6, 0);
BNE(8);
ORI(xFlags, xFlags, 1 << F_ZF);
}
IFX(X_PF) {
emit_pf(dyn, ninst, s6, s3, s4);
}
if (dyn->insts[ninst].nat_flags_fusion) {
if (dyn->insts[ninst].nat_flags_needsign) {
EXTSH(s3, s1);
EXTSH(s4, s2);
NAT_FLAGS_OPS(s3, s4, s5, xZR);
} else {
NAT_FLAGS_OPS(s1, s2, s3, xZR);
}
}
}
// emit CMP16 instruction, from cmp s1 , #0, using s3 and s4 as scratch
void emit_cmp16_0(dynarec_ppc64le_t* dyn, int ninst, int s1, int s3, int s4)
{
IFX_PENDOR0 {
STH(s1, offsetof(x64emu_t, op1), xEmu);
LI(s3, 0);
STH(s3, offsetof(x64emu_t, op2), xEmu);
STH(s1, offsetof(x64emu_t, res), xEmu);
SET_DF(s3, d_cmp16);
} else {
SET_DFNONE();
}
NAT_FLAGS_ENABLE_CARRY();
NAT_FLAGS_ENABLE_SIGN();
CLEAR_FLAGS(s3);
IFX(X_SF) {
SRDI(s3, s1, 15);
CMPDI(s3, 0);
BEQ(8);
ORI(xFlags, xFlags, 1 << F_SF);
}
IFX(X_ZF) {
CMPDI(s1, 0);
BNE(8);
ORI(xFlags, xFlags, 1 << F_ZF);
}
IFX(X_PF) {
emit_pf(dyn, ninst, s1, s3, s4);
}
if (dyn->insts[ninst].nat_flags_fusion) {
if (dyn->insts[ninst].nat_flags_needsign) {
EXTSH(s3, s1);
NAT_FLAGS_OPS(s3, xZR, s4, xZR);
} else {
NAT_FLAGS_OPS(s1, xZR, s3, xZR);
}
}
}
// emit CMP32 instruction, from cmp s1, s2, using s3, s4, s5 and s6 as scratch
void emit_cmp32(dynarec_ppc64le_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4, int s5, int s6)
{
IFX_PENDOR0 {
SDxw(s1, xEmu, offsetof(x64emu_t, op1));
SDxw(s2, xEmu, offsetof(x64emu_t, op2));
SET_DF(s4, rex.w?d_cmp64:d_cmp32);
} else {
SET_DFNONE();
}
NAT_FLAGS_ENABLE_CARRY();
NAT_FLAGS_ENABLE_SIGN();
CLEAR_FLAGS(s3);
IFX(X_AF | X_CF | X_OF) {
// for later flag calculation
NOT(s5, s1);
}
// It's a cmp, we can't store the result back to s1.
SUBxw(s6, s1, s2);
IFX_PENDOR0 {
SDxw(s6, xEmu, offsetof(x64emu_t, res));
}
IFX(X_SF) {
// Check sign bit (bit 31 for 32-bit, bit 63 for 64-bit)
// Can't use CMPDI after SUBxw because zero-extension makes result always >= 0
SRDI(s3, s6, rex.w ? 63 : 31);
CMPDI(s3, 0);
BEQ(8);
ORI(xFlags, xFlags, 1 << F_SF);
}
if (!rex.w) {
ZEROUP(s6);
}
CALC_SUB_FLAGS(s5, s2, s6, s3, s4, rex.w?64:32);
IFX(X_ZF) {
CMPDI(s6, 0);
BNE(8);
ORI(xFlags, xFlags, 1 << F_ZF);
}
IFX(X_PF) {
emit_pf(dyn, ninst, s6, s3, s4);
}
if (dyn->insts[ninst].nat_flags_fusion) {
if (rex.w)
NAT_FLAGS_OPS(s1, s2, s3, s4);
else {
if (dyn->insts[ninst].nat_flags_needsign) {
SEXT_W(s3, s1);
SEXT_W(s4, s2);
} else {
ZEROUP2(s3, s1);
ZEROUP2(s4, s2);
}
NAT_FLAGS_OPS(s3, s4, s5, xZR);
}
}
}
// emit CMP32 instruction, from cmp s1, 0, using s3, s4 and s5 as scratch
void emit_cmp32_0(dynarec_ppc64le_t* dyn, int ninst, rex_t rex, uint8_t nextop, int s1, int s3, int s4, int s5)
{
IFX_PENDOR0 {
STD(s1, offsetof(x64emu_t, op1), xEmu);
LI(s3, 0);
STD(s3, offsetof(x64emu_t, op2), xEmu);
STD(s1, offsetof(x64emu_t, res), xEmu);
SET_DF(s4, rex.w?d_cmp64:d_cmp32);
} else {
SET_DFNONE();
}
NAT_FLAGS_ENABLE_CARRY();
NAT_FLAGS_ENABLE_SIGN();
CLEAR_FLAGS(s3);
IFX(X_SF) {
if (rex.w) {
CMPDI(s1, 0);
BGE(8);
} else {
// Extract exactly bit 31 for SF — SRDI would be wrong if upper 32 bits are dirty
BF_EXTRACT(s3, s1, 31, 31);
CMPDI(s3, 0);
BEQ(8);
}
ORI(xFlags, xFlags, 1 << F_SF);
}
int res = s1;
IFX (X_ZF | X_PF) {
if (!rex.w && MODREG) {
ZEROUP2(s5, s1);
res = s5;
}
}
IFX(X_ZF) {
CMPDI(res, 0);
BNE(8);
ORI(xFlags, xFlags, 1 << F_ZF);
}
IFX(X_PF) {
emit_pf(dyn, ninst, res, s3, s4);
}
if (dyn->insts[ninst].nat_flags_fusion) {
if (rex.w)
NAT_FLAGS_OPS(s1, xZR, s4, xZR);
else {
if (dyn->insts[ninst].nat_flags_needsign) {
SEXT_W(s3, s1);
NAT_FLAGS_OPS(s3, xZR, s4, xZR);
} else if (res == s5) { // zero-up'd case
NAT_FLAGS_OPS(res, xZR, s4, xZR);
} else {
ZEROUP2(s3, s1);
NAT_FLAGS_OPS(s3, xZR, s4, xZR);
}
}
}
}
// emit TEST8 instruction, from test s1, s2, using s3, s4 and s5 as scratch
void emit_test8(dynarec_ppc64le_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5)
{
IFX_PENDOR0 {
SET_DF(s3, d_tst8);
} else {
SET_DFNONE();
}
NAT_FLAGS_ENABLE_SIGN();
CLEAR_FLAGS(s3);
AND(s3, s1, s2); // res = s1 & s2
IFX_PENDOR0 {
STD(s3, offsetof(x64emu_t, res), xEmu);
}
IFX(X_SF) {
SRDI(s4, s3, 7);
CMPDI(s4, 0);
BEQ(8);
ORI(xFlags, xFlags, 1 << F_SF);
}
IFX(X_ZF) {
CMPDI(s3, 0);
BNE(8);
ORI(xFlags, xFlags, 1 << F_ZF);
}
IFX(X_PF) {
emit_pf(dyn, ninst, s3, s4, s5);
}
if (dyn->insts[ninst].nat_flags_fusion && dyn->insts[ninst].nat_flags_needsign) {
EXTSB(s3, s3);
}
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s3, xZR, s4, xZR);
}
// emit TEST8 instruction, from test s1, c, using s3, s4 and s5 as scratch
void emit_test8c(dynarec_ppc64le_t* dyn, int ninst, int s1, uint8_t c, int s3, int s4, int s5)
{
IFX_PENDOR0 {
SET_DF(s3, d_tst8);
} else {
SET_DFNONE();
}
NAT_FLAGS_ENABLE_SIGN();
CLEAR_FLAGS(s3);
ANDId(s3, s1, c); // res = s1 & c
IFX_PENDOR0 {
STD(s3, offsetof(x64emu_t, res), xEmu);
}
IFX (X_SF) {
SRDI(s4, s3, 7);
CMPDI(s4, 0);
BEQ(8);
ORI(xFlags, xFlags, 1 << F_SF);
}
IFX (X_ZF) {
CMPDI(s3, 0);
BNE(8);
ORI(xFlags, xFlags, 1 << F_ZF);
}
IFX (X_PF) {
emit_pf(dyn, ninst, s3, s4, s5);
}
if (dyn->insts[ninst].nat_flags_fusion && dyn->insts[ninst].nat_flags_needsign) {
EXTSB(s3, s3);
}
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s3, xZR, xZR, xZR);
}
// emit TEST16 instruction, from test s1, s2, using s3, s4 and s5 as scratch
void emit_test16(dynarec_ppc64le_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5)
{
IFX_PENDOR0 {
SET_DF(s3, d_tst16);
} else {
SET_DFNONE();
}
NAT_FLAGS_ENABLE_SIGN();
CLEAR_FLAGS(s3);
AND(s3, s1, s2); // res = s1 & s2
IFX_PENDOR0 {
STH(s3, offsetof(x64emu_t, res), xEmu);
}
IFX (X_SF) {
SRDI(s4, s3, 15);
CMPDI(s4, 0);
BEQ(8);
ORI(xFlags, xFlags, 1 << F_SF);
}
IFX (X_ZF) {
CMPDI(s3, 0);
BNE(8);
ORI(xFlags, xFlags, 1 << F_ZF);
}
IFX (X_PF) {
emit_pf(dyn, ninst, s3, s4, s5);
}
if (dyn->insts[ninst].nat_flags_fusion && dyn->insts[ninst].nat_flags_needsign) {
EXTSH(s3, s3);
}
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s3, xZR, xZR, xZR);
}
// emit TEST32 instruction, from test s1, s2, using s3, s4 and s5 as scratch
void emit_test32(dynarec_ppc64le_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4, int s5)
{
IFX_PENDOR0 {
SET_DF(s3, rex.w?d_tst64:d_tst32);
} else {
SET_DFNONE();
}
NAT_FLAGS_ENABLE_SIGN();
CLEAR_FLAGS(s3);
AND(s3, s1, s2); // res = s1 & s2
IFX_PENDOR0 {
SDxw(s3, xEmu, offsetof(x64emu_t, res));
}
IFX(X_SF | X_ZF) {
if (!rex.w) ZEROUP(s3);
}
IFX(X_SF) {
SRDI(s4, s3, rex.w?63:31);
CMPDI(s4, 0);
BEQ(8);
ORI(xFlags, xFlags, 1 << F_SF);
}
IFX(X_ZF) {
CMPDI(s3, 0);
BNE(8);
ORI(xFlags, xFlags, 1 << F_ZF);
}
IFX(X_PF) {
emit_pf(dyn, ninst, s3, s4, s5);
}
if (dyn->insts[ninst].nat_flags_fusion && !rex.w) {
if (dyn->insts[ninst].nat_flags_needsign) {
SEXT_W(s3, s3);
} else {
ZEROUP(s3);
}
}
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s3, xZR, xZR, xZR);
}
// emit TEST32 instruction, from test s1, c, using s3, s4 and s5 as scratch
void emit_test32c(dynarec_ppc64le_t* dyn, int ninst, rex_t rex, int s1, int64_t c, int s3, int s4, int s5)
{
IFX_PENDOR0 {
SET_DF(s3, rex.w ? d_tst64 : d_tst32);
} else {
SET_DFNONE();
}
NAT_FLAGS_ENABLE_SIGN();
CLEAR_FLAGS(s3);
if (c >= 0 && c <= 65535) {
ANDId(s3, s1, c);
} else {
MOV64xw(s3, c);
AND(s3, s1, s3);
}
IFX_PENDOR0 {
SDxw(s3, xEmu, offsetof(x64emu_t, res));
}
IFX(X_SF) {
SRDI(s4, s3, rex.w ? 63 : 31);
CMPDI(s4, 0);
BEQ(8);
ORI(xFlags, xFlags, 1 << F_SF);
}
IFX(X_ZF) {
CMPDI(s3, 0);
BNE(8);
ORI(xFlags, xFlags, 1 << F_ZF);
}
IFX(X_PF) {
emit_pf(dyn, ninst, s3, s4, s5);
}
if (dyn->insts[ninst].nat_flags_fusion && !rex.w) {
if (dyn->insts[ninst].nat_flags_needsign) {
SEXT_W(s3, s3);
} else if (((uint64_t)c >> 32) != 0) {
ZEROUP(s3);
}
}
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s3, xZR, xZR, xZR);
}
+37
View File
@@ -0,0 +1,37 @@
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <errno.h>
#include "debug.h"
#include "box64context.h"
#include "box64cpu.h"
#include "emu/x64emu_private.h"
#include "ppc64le_emitter.h"
#include "ppc64le_mapping.h"
#include "x64emu.h"
#include "box64stack.h"
#include "callback.h"
#include "emu/x64run_private.h"
#include "x64trace.h"
#include "dynarec_native.h"
#include "ppc64le_printer.h"
#include "dynarec_ppc64le_private.h"
#include "../dynarec_helper.h"
#include "dynarec_ppc64le_functions.h"
uintptr_t dynarec64_F0(dynarec_ppc64le_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int* ok, int* need_epilog)
{
(void)ip;
(void)need_epilog;
uint8_t opcode = F8;
switch (opcode) {
default:
DEFAULT;
}
return addr;
}
Loaded 100 of 335 files, more files were not shown because too many files have changed in this diff. Show more