Compare commits

...
221 Commits
Author SHA1 Message Date
Ryan Houdek 6a1ca654db Docs: Update for release FEX-2105 2021-05-05 17:53:55 -07:00
Ryan Houdek 623b29de8c Merge pull request #1014 from Sonicadvance1/fix_host_stacks
Fixes host thread stacks ending up in lower 32-bit VA
2021-05-05 15:51:40 -07:00
Ryan Houdek 9be67fb22a Merge pull request #1009 from Sonicadvance1/handle_self
Handle more cases of an application pinging self
2021-05-05 14:51:11 -07:00
Ryan Houdek cb9286c11e Merge pull request #1012 from Sonicadvance1/fix_ioctl_errors
Fixes ioctl returning error
2021-05-05 14:50:46 -07:00
Ryan Houdek 1e40148f60 Fixes host thread stacks ending up in lower 32-bit VA
Overriding glibc's mmap and munmap functions don't encapsulate that functions they use
for allocating stack data so it was falling down the system mmap/munmap path.
This was causing host side stacks to end up in the 32-bit VA space in 32-bit applications.
2021-05-04 22:15:46 -07:00
Ryan Houdek d9d5303aa0 Fixes ioctl returning error
Fixes evdev device description at the very least
2021-05-04 18:45:25 -07:00
Ryan Houdek 517b575783 Merge pull request #1010 from FEX-Emu/skmp/aotupdate-install-cmake
AOTIR: Add install rule for FEXUpdateAOTIRCache
2021-05-04 18:11:27 -07:00
Ryan Houdek 605994dca2 Merge pull request #1011 from FEX-Emu/skmp/fix-0xcd-breaks
JIT: Add reason 1 (0xCD) to OP_BREAK implementations
2021-05-04 18:11:17 -07:00
Ryan Houdek ac97c05271 Handle more cases of an application pinging self
AppImage uses this to inspect its own executable to ensure it is an AppImage file.
2021-05-04 18:09:15 -07:00
Stefanos Kornilios Mitsis Poiitidis c8bb02f3a6 JIT: Add reason 1 (0xCD) to OP_BREAK implementations 2021-05-04 13:22:00 +03:00
Stefanos Kornilios Mitsis Poiitidis 6b12c1768f AOTIR: Add install rule for FEXUpdateAOTIRCache 2021-05-04 12:33:59 +03:00
Stefanos Kornilios Mitsis Poiitidis 693097c5b1 Merge pull request #1008 from Sonicadvance1/fix_binfmt_misc
Updates binfmt_misc files to support AppImage
2021-05-04 11:14:49 +03:00
Ryan Houdek 47e823b773 Updates binfmt_misc files to support AppImage
AppImage files stick additional data in the ABI Version and PAD areas that it was getting blocked on.
2021-05-03 18:08:00 -07:00
Ryan Houdek fd6d33d197 Merge pull request #996 from FEX-Emu/skmp/aotirgen
AOTIR: Offline Generation
2021-05-03 15:58:57 -07:00
Stefanos Kornilios Mitsis Poiitidis d8b583bc51 Remove assert that was used in debugging 2021-05-04 01:47:39 +03:00
Stefanos Kornilios Mitsis Poiitidis be41f14452 Fix generation script 2021-05-03 18:16:43 +03:00
Stefanos Kornilios Mitsis Poiitidis cf5bd202d4 AOTIR: Update gen script to default to global fex installation 2021-05-03 06:15:25 +03:00
Stefanos Kornilios Mitsis Poiitidis 8893cc6a7d Undo xbyak update 2021-05-03 05:48:00 +03:00
Stefanos Kornilios Mitsis Poiitidis 1d82e9e59e JIT: Stub Break reasons 2, 3 2021-05-03 05:42:46 +03:00
Stefanos Kornilios Mitsis Poiitidis 5b017f9a66 Merge pull request #1007 from Sonicadvance1/more_ioctl32_emulation2
Adds Nouveau and Lima ioctl32 handlers
2021-05-03 05:10:21 +03:00
Ryan Houdek 3399052eaa Make sure to setup ioctl32 handler table 2021-05-02 14:30:23 -07:00
Ryan Houdek 3df951695e Adds Nouveau and Lima ioctl32 handlers 2021-05-02 13:05:46 -07:00
Ryan Houdek 8d1f9a9081 Merge pull request #1006 from Sonicadvance1/implement_clflush
Implements support for CLFLUSH
2021-05-02 12:27:54 -07:00
Ryan Houdek 68adb1ae12 Basic clflush test 2021-05-02 12:18:35 -07:00
Ryan Houdek 4961604807 Implements support for CLFLUSH
JRE requires this to run
2021-05-02 12:18:35 -07:00
Stefanos Kornilios Mitsis Poiitidis d6b7f32d33 AOTGen: Cleanup unwind symbol logic, add to x86-32 binaries 2021-05-02 11:08:12 +03:00
Stefanos Kornilios Mitsis Poiitidis 6dc69063f3 Merge pull request #1005 from Sonicadvance1/remove_numa
Remove reliance on librt and libnuma
2021-05-02 09:50:10 +03:00
Stefanos Kornilios Mitsis Poiitidis 2916c4f34c Merge pull request #1004 from Sonicadvance1/redirect_self
Redirect applications using execve with self
2021-05-02 09:49:55 +03:00
Stefanos Kornilios Mitsis Poiitidis 04137d0da5 Merge pull request #1002 from Sonicadvance1/sigtimedwait
Initial base implementation of sigtimedwait
2021-05-02 09:49:49 +03:00
Stefanos Kornilios Mitsis Poiitidis afa81294c9 Merge pull request #1001 from Sonicadvance1/more_ioctl32_emulation
More ioctl32 emulation
2021-05-02 09:49:44 +03:00
Ryan Houdek 86bdbe65e5 Implements missed x86-32 message queue syscalls
Nothing hit these but good to have them implemented
2021-05-01 17:40:33 -07:00
Ryan Houdek 63dee0e132 Remove reliance on librt and libnuma
These can fall down the raw syscall path
2021-05-01 17:40:33 -07:00
Ryan Houdek 6618bb809b Redirect applications using execve with self
Fixes a step in the Java JRE and shapez.io
2021-05-01 11:09:44 -07:00
Ryan Houdek d2b19c0b1c Disable gvisor sigtimedwait test 2021-05-01 10:19:13 -07:00
Ryan Houdek 90a8c4f114 Shuffle timed sigwait unit tests that have changed behaviour 2021-05-01 10:11:20 -07:00
Ryan Houdek 866baf66db Merge pull request #1003 from Sonicadvance1/cleaned_sendrecvmsg
Workaround fixes in sendmsg/recvmsg
2021-05-01 10:06:41 -07:00
Ryan Houdek 9498a41f9b More ioctl32 emulation
More DRM and i915 things, then wireless for some reason renderdoc relies on it
2021-05-01 09:40:02 -07:00
Ryan Houdek 1340ffabe4 Workaround fixes in sendmsg/recvmsg
Rebased and cleaned up #933
Needs to be larger allocations than what was originally proposed by #933
2021-05-01 09:37:01 -07:00
Ryan Houdek b5115e096f Initial base implementation of sigtimedwait 2021-05-01 09:35:29 -07:00
Ryan Houdek 235e05e8b9 Merge pull request #978 from Sonicadvance1/wip_allocator
64-bit allocator and ioctl emulation
2021-05-01 09:29:46 -07:00
Ryan Houdek 26b4bd80bf Force 32-bit allocator for CI 2021-05-01 09:19:55 -07:00
Ryan Houdek a8881e8835 Adds option to force 32-bit allocator 2021-05-01 09:19:55 -07:00
Ryan Houdek d1da1b0be5 Disables 20080723-1.c.gcc-target-test-32 CI test
This test consistently fails on the solid run board.
This requires some deep dive investigation
2021-05-01 09:06:39 -07:00
Ryan Houdek a19c0184a6 Keep using the 32-bit allocator if the kernel is old
Works around the Xavier boards running kernel 4.9
2021-05-01 09:06:39 -07:00
Ryan Houdek 2d0dced9e7 Work around old asound headers 2021-05-01 09:06:39 -07:00
Ryan Houdek 52cb96d630 Work around old DRM headers for i915 2021-05-01 09:06:39 -07:00
Ryan Houdek 94017d2e65 On old kernels, steal the 32-bit address space before the 64-bit
Increases speed of startup
2021-05-01 09:06:39 -07:00
Ryan Houdek 13b93ef6b5 Allow memory allocation to go through if the base was above the lower bound 2021-05-01 09:06:39 -07:00
Ryan Houdek c83a5d1bc3 Allow some more clone flags through with info log 2021-05-01 09:06:39 -07:00
Ryan Houdek c20777d558 Change these log messages so we know which one failed 2021-05-01 09:06:38 -07:00
Ryan Houdek 9a0fc4e7e8 Workaround quick with memory allocator. Aligned 4GB regions are hard to allocate 2021-05-01 07:39:14 -07:00
Ryan Houdek 417e8836a4 Arm64: Fixes some wrong sign extensions 2021-05-01 07:39:14 -07:00
Ryan Houdek 237865e064 Adds ioctl verification to struct verifier 2021-05-01 07:39:14 -07:00
Ryan Houdek 45223cc7e7 Adds initial ioctl emulation code 2021-05-01 07:39:14 -07:00
Ryan Houdek 8d34222556 Add vardecl type matching for ioctl verification 2021-05-01 07:39:14 -07:00
Ryan Houdek b6344c4753 Removes old 32-bit allocator usage
Replaces with using host side allocations since we always have a 64-bit allocator in this case
2021-05-01 07:39:14 -07:00
Ryan Houdek c5bda47b2a Adds more allocator hooking 2021-05-01 07:39:14 -07:00
Ryan Houdek 5067737052 Adds 64-bit allocator 2021-05-01 07:39:14 -07:00
Ryan Houdek 5143100a73 Switches more usages of memory allocation routines over to FEX internal 2021-05-01 07:39:14 -07:00
Stefanos Kornilios Mitsis Poiitidis 8b6e767742 Frontend: Slightly more resilient max instruction size handling 2021-05-01 09:40:50 +03:00
Stefanos Kornilios Mitsis Poiitidis 331549c64a RLSE: Use Constant, not inline constant, let ConstProp generate all inline consts 2021-05-01 09:40:50 +03:00
Stefanos Kornilios Mitsis Poiitidis be0b29bbc6 OpDisp: Convert more asserts to soft-errors 2021-05-01 09:40:50 +03:00
Stefanos Kornilios Mitsis Poiitidis ee8f8ed176 Improve error handling 2021-05-01 09:40:50 +03:00
Stefanos Kornilios Mitsis Poiitidis 5b8cbae1e1 Core/Frontend: Improve error handling 2021-05-01 09:40:50 +03:00
Stefanos Kornilios Mitsis Poiitidis b98ef9e48b Core/Frontend: Improve error handling 2021-05-01 09:40:50 +03:00
Stefanos Kornilios Mitsis Poiitidis fd724448ab Front End: Fix an error check 2021-05-01 09:40:50 +03:00
Stefanos Kornilios Mitsis Poiitidis f4083883ca Frontend: Fix ExternalBranches initialization 2021-05-01 09:40:50 +03:00
Stefanos Kornilios Mitsis Poiitidis 9a4fc758c1 AOTIR: FEXUpdateAOTIRCache.sh now passes compilation modifiers 2021-05-01 09:40:50 +03:00
Stefanos Kornilios Mitsis Poiitidis 40d2cd8992 Fix asserts 2021-05-01 09:40:50 +03:00
Stefanos Kornilios Mitsis Poiitidis ab44f800f7 AOTgen: Cleaner interfaces, use LogMan 2021-05-01 09:40:50 +03:00
Stefanos Kornilios Mitsis Poiitidis 1a5bc39d09 Rebase fixes 2021-05-01 09:40:50 +03:00
Stefanos Kornilios Mitsis Poiitidis 4bd997adaa AOT: Postfix ir files with .aotir 2021-05-01 09:40:50 +03:00
Stefanos Kornilios Mitsis Poiitidis 244ef94e9b AOTIR: Generate list of files with code, add Scripts/FEXUpdateAOTIRCache.sh to generate all files 2021-05-01 09:40:50 +03:00
Stefanos Kornilios Mitsis Poiitidis a85ef061d1 AOITR: Add AOTIRGenerate fo FEXLoader option that does generation 2021-05-01 09:40:50 +03:00
Stefanos Kornilios Mitsis Poiitidis 4e847d03b7 Remove more assertions for invalid code 2021-05-01 09:40:49 +03:00
Stefanos Kornilios Mitsis Poiitidis ce9324f50f Kinda-parse unwind table 2021-05-01 09:40:49 +03:00
Stefanos Kornilios Mitsis Poiitidis 0897fc4a0a pretrans wip 2021-05-01 09:40:49 +03:00
Ryan Houdek d256bc59fd Override glibc allocator functions 2021-04-30 18:28:45 -07:00
Ryan Houdek e0d6f4bc34 Make sure link jemalloc in FEXCore 2021-04-30 18:28:45 -07:00
Ryan Houdek 09284331a7 Adds pregen include directory for jemalloc 2021-04-30 18:28:45 -07:00
Ryan Houdek 73e61b0c8e Switches default logging output to stderr
stdout is too likely to break something
2021-04-30 18:28:45 -07:00
Ryan Houdek a30866a886 Merge pull request #976 from FEX-Emu/skmp/aotir-mmap
AOTIR: Switch over to mmap-based loading
2021-04-30 18:24:54 -07:00
Stefanos Kornilios Mitsis Poiitidis 3e1da51cae Merge pull request #998 from Sonicadvance1/remove_xxhash_check
Removes xxhash version check
2021-04-30 12:05:18 +03:00
Stefanos Kornilios Mitsis Poiitidis 4efe973b65 Merge pull request #999 from Sonicadvance1/fix_sdl2_interface_Again
Fixes SDL2 interface check...again.
2021-04-30 12:04:50 +03:00
Ryan Houdek f6cc75de87 Fixes SDL2 interface check...again. 2021-04-30 01:55:08 -07:00
Ryan Houdek 6b082f4ef7 Removes xxhash version check
xxhash doesn't yet have a version of the library with pkg-config giving
a version.
Debian has backported a change for this but Arch hasn't.
https://github.com/Cyan4973/xxHash/issues/524
2021-04-30 01:35:03 -07:00
Stefanos Kornilios Mitsis Poiitidis 8a73783a07 AOTIR: Use FEXCore::Allocator 2021-04-29 08:16:21 +03:00
Stefanos Kornilios Mitsis Poiitidis 32b4b02302 AOTIR: mmap based loading 2021-04-28 13:08:43 +03:00
Stefanos Kornilios Mitsis Poiitidis 528b01ad7a Merge pull request #988 from Sonicadvance1/memory_layout_optimizations
Memory layout optimizations
2021-04-28 12:31:53 +03:00
Stefanos Kornilios Mitsis Poiitidis cd0492a143 Merge pull request #994 from Sonicadvance1/enable_armv8.4
Enables ARMv8.4 CI runner
2021-04-28 09:53:47 +03:00
Ryan Houdek 26bf903b93 Enables ARMv8.4 CI runner
Requires #990 and #993 to be merged first
2021-04-27 23:16:39 -07:00
Stefanos Kornilios Mitsis Poiitidis aae4de106a Merge pull request #992 from Sonicadvance1/optimize_cpuid
Optimizes CPUID generation a bit
2021-04-28 09:12:09 +03:00
Stefanos Kornilios Mitsis Poiitidis c495d8120d Merge pull request #993 from Sonicadvance1/fix_sdl_missed_line
Oops: Missed line on FEXConfig SDL2
2021-04-28 09:10:52 +03:00
Stefanos Kornilios Mitsis Poiitidis a6d9425091 Merge pull request #990 from Sonicadvance1/fix_native_m1
Work around M1 Parallels hypervisor not showing CPU type
2021-04-28 09:09:08 +03:00
Ryan Houdek b06ebf486f Work around M1 Parallels hypervisor not showing CPU type
Parallels claims that the CPU is of implementor 0x41 and part number 0.
Easy enough to work around before real numbers get exposed
2021-04-27 22:26:35 -07:00
Ryan Houdek b17464d81a Oops: Missed line on FEXConfig SDL2 2021-04-27 16:51:12 -07:00
Ryan Houdek 2ab8a97055 Merge pull request #989 from Sonicadvance1/sdl2_fix
Only use SDL2 import target if it exists
2021-04-27 01:11:28 -07:00
Ryan Houdek 34a5eb6d6f Optimizes CPUID generation a bit
The flags calculation is fairly intensive and we were doing it for every core.
Do it once then duplicate it per core instead

Improves generation time quite significantly. A couple of milliseconds converted to half a millisecond
Slight improvement to startup time
2021-04-27 01:09:28 -07:00
Ryan Houdek 2a1a863c58 Only use SDL2 import target if it exists
Should fix Arch and Ubuntu 20.04 together
2021-04-27 00:45:20 -07:00
Ryan Houdek bab5927931 Merge pull request #981 from Sonicadvance1/optimize_long_divide
Adds Long Divide removal pass
2021-04-26 23:48:50 -07:00
Ryan Houdek 6255eba524 Memory layout optimizations
Some of these memory layouts weren't optimal for ARM loading.
This is now significantly improved
2021-04-26 23:48:22 -07:00
Ryan Houdek 37108058d1 Removes some unnecessary branching checks
It doesn't actually matter if the invalid node has has its linked list nodes changed
Faster to just set than to check while in a tight loop
2021-04-26 23:48:22 -07:00
Stefanos Kornilios Mitsis Poiitidis c3ad571062 Merge pull request #987 from Sonicadvance1/fix_assert_dumb_code
Changes LogMan assert to defines
2021-04-27 09:41:12 +03:00
Ryan Houdek 04e0baadc6 Changes LogMan assert to defines
C++ no-op functions can't optimize out the predicate arguments in all cases.
This was causing a problem where zero cost assertions weren't actually zero cost.

The only way to resolve this is to actually use macros sadly enough.

This will give a fairly hefty performance uplift with anything operating on IR.
2021-04-26 13:49:35 -07:00
Ryan Houdek 5ffbd97f01 IROp types can be marked const
Allows the compiler to know it can be optimized out without LTO
2021-04-26 13:45:37 -07:00
Ryan Houdek 7d4380fe6d Merge pull request #984 from FEX-Emu/skmp/relocation-fixes
IR: Fix RIP relocation edge-cases
2021-04-26 10:11:24 -07:00
Ryan Houdek 7d5157b602 Merge pull request #983 from FEX-Emu/skmp/faster-l1
LookupCache: Add new entries to L1C
2021-04-26 10:10:51 -07:00
Ryan Houdek e9a32da997 Merge pull request #986 from FEX-Emu/skmp/fix-20.04-build
Deps: Require xxhash 0.7.3, ubuntu 20.04 ships with that version
2021-04-26 10:05:35 -07:00
Stefanos Kornilios Mitsis Poiitidis b3564a4a48 IR: Fix RIP relocation edge-cases 2021-04-26 19:20:01 +03:00
Stefanos Kornilios Mitsis Poiitidis 2294419353 Deps: Require xxhash 0.7.3, ubuntu 20.04 ships with that version 2021-04-26 19:07:23 +03:00
Stefanos Kornilios Mitsis Poiitidis df8b78b327 Dispatcher: Use Also lookup L1C when dispatching interpreter 2021-04-26 19:06:11 +03:00
Stefanos Kornilios Mitsis Poiitidis 2ea6a2a141 LookupCache: Fix L1C to actually cache entries 2021-04-26 18:38:03 +03:00
Ryan Houdek db776fae4e Merge pull request #985 from FEX-Emu/skmp/rip-relative-compilation
IR: Remove Entry from OP_HEADER, pass as parameter to CompileCode
2021-04-25 18:27:37 -07:00
Stefanos Kornilios Mitsis Poiitidis b45b7c3441 IR: Remove Entry from OP_HEADER, pass as parameter to CompileCode 2021-04-25 13:15:23 +03:00
Stefanos Kornilios Mitsis Poiitidis 7805552edb LookupCache: Add new entries to L1C 2021-04-25 13:03:43 +03:00
Ryan Houdek 520dfd7edf Adds Long Divide removal pass
If the long divides don't have anything in the upper bits then they can be optimized away.
Teeworlds, SuperTuxKart, and RRootage were between 50%-55% getting removed
2021-04-24 23:10:59 -07:00
Stefanos Kornilios Mitsis Poiitidis 60671ee6cb Merge pull request #975 from Sonicadvance1/use_xxhash
Switch from fasthash64 to xxhash's XXH3
2021-04-23 09:49:06 +03:00
Stefanos Kornilios Mitsis Poiitidis 6635765ea9 Merge pull request #972 from Sonicadvance1/naked_mman
Naked mman usage removal
2021-04-22 09:47:41 +03:00
Stefanos Kornilios Mitsis Poiitidis 3e4ff23ab6 Merge pull request #977 from Sonicadvance1/fix_relative_elf
Fixes ELFCodeLoader2 loading relative ELF files
2021-04-22 09:40:08 +03:00
Ryan Houdek 93ed411899 Fixes ELFCodeLoader2 loading relative ELF files 2021-04-20 01:58:37 -07:00
Ryan Houdek 0b0db08ebf Switch from fasthash64 to xxhash's XXH3
Fixes #797
2021-04-18 18:13:27 -07:00
Stefanos Kornilios Mitsis Poiitidis 3419f40c00 Merge pull request #971 from Sonicadvance1/template_specialization
Declare missing template specialization for GetListIfExists
2021-04-19 00:03:25 +03:00
Stefanos Kornilios Mitsis Poiitidis 8260ddda13 Merge pull request #970 from Sonicadvance1/sdl2_target_imports
Use cmake SDL2 target properties
2021-04-19 00:02:59 +03:00
Stefanos Kornilios Mitsis Poiitidis 872e49f02a Merge pull request #969 from Sonicadvance1/mcpu_native
Use mcpu=native with Clang 12
2021-04-19 00:02:22 +03:00
Stefanos Kornilios Mitsis Poiitidis f0f6bc7a73 Merge pull request #973 from Sonicadvance1/fix_openat
Fixes OpenAt breaking with anonymous objects
2021-04-17 15:51:24 +03:00
Ryan Houdek 5820c251e8 Fixes OpenAt breaking with anonymous objects
Fixes #753
2021-04-16 21:21:08 -07:00
Ryan Houdek eff97509c0 Replaces naked mman usage in TestHarnessRunner 2021-04-16 21:01:59 -07:00
Ryan Houdek 3128d0c148 Replaces naked mman usage in SyscallHandler 2021-04-16 21:01:39 -07:00
Ryan Houdek 0216d7b552 Replaces naked mman usage in x86-64 syscalls 2021-04-16 21:01:07 -07:00
Ryan Houdek 87b473c7ee Replaces naked mman usage in IRLoader 2021-04-16 21:00:51 -07:00
Ryan Houdek f9d647c852 Replaces naked mman usage in HarnessHelpers 2021-04-16 21:00:19 -07:00
Ryan Houdek 2c175f1e0b Replaces naked mman usage in FEXLoader 2021-04-16 21:00:01 -07:00
Ryan Houdek 96813b0d6c Replaces naked mman usage in ELFCodeLoader 2021-04-16 20:59:27 -07:00
Ryan Houdek 967ac863be Replaces naked mman usage in X86Dispatcher 2021-04-16 20:50:14 -07:00
Ryan Houdek fa546fb492 Replaces naked mman usage in ELFSymbolDatabase 2021-04-16 20:50:09 -07:00
Ryan Houdek 99ab9864aa Replaces naked mman usage in X86HelperGen 2021-04-16 20:50:03 -07:00
Ryan Houdek 11246355e2 Replaces naked mman usage in LookupCache 2021-04-16 20:49:58 -07:00
Ryan Houdek 0d236940e0 Replaces naked mman usage in x86-64 JIT 2021-04-16 20:49:52 -07:00
Ryan Houdek a0afb4be5a Replaces naked mman usage in Arm64 JIT 2021-04-16 20:49:47 -07:00
Ryan Houdek ca45485d48 Adds new Allocator namespace for replace mmap and munmap
This is necessary for overriding these functions
2021-04-16 20:49:35 -07:00
Ryan Houdek c8bb0e2d51 Declare missing template specialization for GetListIfExists
Clang 12 picks up that this was missing
2021-04-16 18:54:16 -07:00
Ryan Houdek e9aeebb3a1 Use cmake SDL2 target properties
Some distros include generated cmake files instead of the two cmake files from the source.
Distros that use the generated cmake files only have SDL import properties, so we are required
to use those.
2021-04-16 18:45:06 -07:00
Ryan Houdek 1ad46c5af1 Use mcpu=native with Clang 12
Clang 12 fixes the bug with big.little configurations so we
can keep using mcpu=native past this point
2021-04-16 18:44:34 -07:00
Ryan Houdek 08bc7a8364 Merge pull request #967 from FEX-Emu/skmp/new-elf-loading
ELF: Simpler loader, uses mmap
2021-04-16 18:35:56 -07:00
Ryan Houdek e7179ff84b Merge pull request #968 from FEX-Emu/skmp/fix-self-exe-after-fork
Emulated Files: Don't precalculate /proc/pid path, it changes after fork
2021-04-15 13:01:41 -07:00
Stefanos Kornilios Mitsis Poiitidis 13bfdcad06 Emulated Files: Don't precalculate /proc/pid path, it changes after fork 2021-04-15 15:33:10 +03:00
Stefanos Kornilios Mitsis Poiitidis 38a707b38e Add missing functions to elfcodeloader2 2021-04-15 13:51:22 +03:00
Stefanos Kornilios Mitsis Poiitidis ada7915b01 Convert an assert to log 2021-04-15 13:40:28 +03:00
Stefanos Kornilios Mitsis Poiitidis 9775a2148e Fix rootfs interpreter loading 2021-04-15 12:16:33 +03:00
Stefanos Kornilios Mitsis Poiitidis bc8696828b More logging 2021-04-15 12:14:55 +03:00
Stefanos Kornilios Mitsis Poiitidis 7d792e65f0 Rootfs, assert fixes 2021-04-15 12:04:42 +03:00
Stefanos Kornilios Mitsis Poiitidis 14b5b881c5 Add more logging 2021-04-15 11:47:42 +03:00
Stefanos Kornilios Mitsis Poiitidis 830e41459c Fix build for test harness, irloader 2021-04-15 11:05:07 +03:00
Stefanos Kornilios Mitsis Poiitidis 0db99ea4f6 Use allocator for x32 2021-04-15 10:51:16 +03:00
Stefanos Kornilios Mitsis Poiitidis 22f1cf0e2a More wip 2021-04-15 10:05:59 +03:00
Stefanos Kornilios Mitsis Poiitidis 80493487db ELF Loading: Cleanups all around 2021-04-14 10:59:23 +03:00
Stefanos Kornilios Mitsis Poiitidis 59ce750af6 Elf: Add ELFCodeLoader2, with simplified loading logic 2021-04-13 15:59:36 +03:00
Stefanos Kornilios Mitsis Poiitidis 4ac81e22de Move some more files around 2021-04-13 15:59:36 +03:00
Stefanos Kornilios Mitsis Poiitidis a0a382cc5c Clear up file naming a big 2021-04-13 15:59:36 +03:00
Ryan Houdek 6cc7d065aa Merge pull request #964 from Sonicadvance1/paranoid_tso
First step in paranoid TSO mode
2021-04-12 23:34:54 -07:00
Ryan Houdek 93b9ca4bdb Merge pull request #965 from Sonicadvance1/add_jemalloc
Switches FEX over to using jemalloc
2021-04-08 14:04:12 -07:00
Ryan Houdek cc0c45cf47 Switches FEX over to using jemalloc
This is the first step that we need to do for correct 32-bit memory allocations.
2021-04-08 12:42:37 -07:00
Ryan Houdek 4a504bdd00 Merge pull request #939 from Sonicadvance1/hidden_visibility
Default hidden visibility and strip symbols
2021-04-06 18:56:28 -07:00
Ryan Houdek 66c8dd2013 First step in paranoid TSO mode
This moves vector ops down the GPR atomic backpatch path.
Next step after this is to add SIGBUS based handlers for these rather than backpatching.
Needs more work to treat aligned versus unaligned vector loadstores differently
2021-04-06 18:48:36 -07:00
Ryan Houdek 91ac4ccdd8 Adds LDAXP and STLXP backpatch handlers
This will be used in the next commit
2021-04-06 18:47:50 -07:00
Ryan Houdek 849b83bd02 Adds new ParanoidTSO option 2021-04-06 18:46:52 -07:00
Ryan Houdek 286f103dab Adds visibility attributes to everything we need to expose 2021-04-06 01:01:31 -07:00
Ryan Houdek 2a49037789 update external vixl 2021-04-06 00:39:03 -07:00
Ryan Houdek 235f6fbe39 Strip symbols and dead sections
These are unnecessary and just add some file bloat. Strip them out
2021-04-06 00:39:03 -07:00
Ryan Houdek b43db294ec Change our compilation visibility to hidden
This bloats our compilation with symbols that don't need to be visible
2021-04-06 00:39:03 -07:00
Stefanos Kornilios Mitsis Poiitidis 5e6c6adf8b Merge pull request #956 from Sonicadvance1/enable_gcc_32_tests
Enables GCC 32-bit unit tests
2021-04-06 09:48:38 +03:00
Stefanos Kornilios Mitsis Poiitidis 50c3ee047c Merge pull request #961 from Sonicadvance1/fix_segment_override
Fixes segment register override on string instructions.
2021-04-06 09:24:23 +03:00
Stefanos Kornilios Mitsis Poiitidis c0ef6da6a8 Merge pull request #960 from Sonicadvance1/more_cpuid
Adds some more CPUID functions
2021-04-06 09:23:13 +03:00
Stefanos Kornilios Mitsis Poiitidis 2063411443 Merge pull request #959 from Sonicadvance1/fix_tag_order
Fixes ordering problem of tag generation in release script
2021-04-06 09:22:12 +03:00
Stefanos Kornilios Mitsis Poiitidis 4a5eefec25 Merge pull request #958 from Sonicadvance1/fix_atomic_zext
Fixes Zext semantics on atomic ops with x64 JIT
2021-04-06 09:21:44 +03:00
Stefanos Kornilios Mitsis Poiitidis eaad9e99a9 Merge pull request #954 from Sonicadvance1/posix_tests_docs
Updates a couple POSIX test case failures
2021-04-06 09:18:18 +03:00
Stefanos Kornilios Mitsis Poiitidis 62406a45be Merge pull request #953 from Sonicadvance1/env_var_override
Allows overriding FEX folder locations with environment variables
2021-04-06 09:16:12 +03:00
Stefanos Kornilios Mitsis Poiitidis 03537d351d Merge pull request #952 from Sonicadvance1/add_asan_use_after_scope
Adds use-after-scope to the ASAN options
2021-04-06 09:09:09 +03:00
Ryan Houdek 0cb53fff89 Change kernel version error to not be fatal 2021-04-05 23:09:06 -07:00
Ryan Houdek 3e250fa071 Enables GCC 32-bit unit tests
Relies on #950 getting merged first
2021-04-05 23:09:06 -07:00
Stefanos Kornilios Mitsis Poiitidis 1d4b81f556 Merge pull request #951 from Sonicadvance1/fix_getenv_aotir
Removes getenv usage for aotir
2021-04-06 09:08:46 +03:00
Stefanos Kornilios Mitsis Poiitidis c26f19ed4d Merge pull request #950 from Sonicadvance1/fix_gcc_tests
Fixes GCC tests
2021-04-06 09:05:45 +03:00
Stefanos Kornilios Mitsis Poiitidis 9619cea097 Merge pull request #949 from Sonicadvance1/arm64_print
Adds support for Arm64 JIT to Print
2021-04-06 08:58:13 +03:00
Stefanos Kornilios Mitsis Poiitidis 44dbecc2ac Merge pull request #948 from Sonicadvance1/fix_leak
Fixes memory leak in CPU backends
2021-04-06 08:56:00 +03:00
Stefanos Kornilios Mitsis Poiitidis 415632209f Merge pull request #947 from Sonicadvance1/minimal_siginfo
Implements a minimal siginfo_t in the dispatcher's signal handler
2021-04-06 08:54:01 +03:00
Ryan Houdek b7e81e867d Fixes segment register override on string instructions.
The segment prefix only overrides one side of the string instruction.
Passing in the flags was causing the instruction to have the segment override on both sides of the copy.
So something like `movsb es:[rdi], fs:[rsi]` was being interpreted as `movsb fs:[rdi], fs:[rsi]`
Same for all the string ops which is now fixed.

We can't unit test these currently since we can't set host segment register for confirmed host behaviour.
2021-04-05 21:28:31 -07:00
Ryan Houdek 4f276aae82 Adds comment for LEA and segment registers
LEA doesn't give you the result with segment register applied to it.
Adds a comment to OpDispatcher to make it more clear
2021-04-05 21:28:25 -07:00
Ryan Houdek c80254f6f4 Adds some more CPUID functions
Noticed a game poking at these
2021-04-05 18:37:05 -07:00
Ryan Houdek 8adb1ca3a2 Fixes ordering problem of tag generation in release script
Wasn't actually creating an annotated tag with this order
2021-04-05 18:35:09 -07:00
Ryan Houdek 0dd1959d65 Fixes Zext semantics on atomic ops with x64 JIT
Fixes Factorio 1.1.30 on x86-64 hosts

Fixes #957
2021-04-05 18:19:15 -07:00
Ryan Houdek f4ab7cceab Updates a couple POSIX test case failures
The behaviour of these is broken but now they are documented in how they are broken
2021-04-05 04:27:52 -07:00
Ryan Houdek 8cc799ab65 Allows overriding FEX folder locations with environment variables
Introduces three new environment variables that need to live outside of the scope
of the regular argument loader path.
This will allow external applications to adjust FEX parameters in interesting ways.

FEX_APP_CONFIG: Allows you to override where Config.json lives
FEX_APP_CONFIG_LOCATION: Allows you to provide an entire folder of app profiles
FEX_APP_DATA_LOCATION: Allows you to override where the data gets stored and loaded from

Fixes #572
2021-04-05 04:09:41 -07:00
Ryan Houdek acb329b8e7 Adds use-after-scope to the ASAN options
Useful for seeing stack scoping problems that can crop up
2021-04-04 22:07:40 -07:00
Ryan Houdek 3020e39428 Remove DestSize from Print IR Op 2021-04-04 22:07:03 -07:00
Ryan Houdek 4a094c5dee Reenables new gcc unit tests that are no longer failing
Documents the few remaining tests with details as to why the test fails.
2021-04-04 22:05:55 -07:00
Ryan Houdek f8eabb4f33 Implements 64bit scalar VUMin on x86 JIT 2021-04-04 22:05:55 -07:00
Ryan Houdek 4da492d361 Fixes vector integer min and max on AArch64
These instructions don't have a 64bit element variant.
Switch the 64bit element variant over to a coded variant similar to float min/max
2021-04-04 22:05:55 -07:00
Ryan Houdek a200d2c91c Fixes packed shift ops
In the case of a shift value larger than the element size then the shift will zero the element.
Incoming shift amount is always a 64bit value which means that the value can become quite large on shifts.
Checks the incoming source and sets the maximum to be the element size, which works for AArch64's vector shifts
Which only operate on 8bit incoming shift amounts
2021-04-04 22:05:55 -07:00
Ryan Houdek f1663abe81 Removes getenv usage for aotir
We can't rely on `getenv("HOME")` always working.
Have the AOTIR code use the helper method for getting the data directory instead.
2021-04-04 21:43:14 -07:00
Ryan Houdek af205e9f5f Fixes PEXTRW
In the case of 16bit PEXTRW it will zext to 32bits which wasn't being done
2021-04-04 21:32:12 -07:00
Ryan Houdek 032d1fbba2 Fixes VFMIN/VFMax NaN behaviour
In a world with NaNs we were hitting some undefined behaviour with fmin/fmax
Needed to change these over to something more complex to handle the NaN case.

ARMv8.7 alternative FP mode would solve this for the scalar case, but it still doesn't work for the vecto case sadly.
2021-04-04 21:29:46 -07:00
Ryan Houdek 313c4bb784 Fixes bug in VectorImm
If passing in a 64bit immediate then movi doesn't behaviour how you would expect.

Instead to a tmp move + dup to implement it the way we want
2021-04-04 20:24:23 -07:00
Ryan Houdek ceb484fd3a Adds support for Arm64 JIT to Print
Useful for debugging, supports both vector and GPR
2021-04-04 20:22:44 -07:00
Ryan Houdek b98c7bd853 Moves AArch64's GetPhys to be a class function
No need for it to be static
2021-04-04 20:21:06 -07:00
Ryan Houdek 4c045148b6 Fixes memory leak in CPU backends
Dispatcher wasn't ever getting cleaned up.
Also ensures sharing it with the CompileService otherwise it crashes on use.
2021-04-04 20:19:35 -07:00
Ryan Houdek 9f29bba4aa Fixes missing virtual destructor on Dispatcher class 2021-04-04 20:10:58 -07:00
Ryan Houdek 2c592bd8a8 Implements a minimal siginfo_t in the dispatcher's signal handler
This lets Carrion get farther in game.
Seems like one of its threads hits sigsegv and it just...lets it die after checking siginfo?
2021-04-03 17:03:19 -07:00
Ryan Houdek 8319a85524 Merge pull request #946 from Sonicadvance1/fix_eventfd
Fixes eventfd and eventfd2
2021-04-03 06:52:32 -07:00
Ryan Houdek 8ad45071e4 Merge pull request #945 from Sonicadvance1/fix_truncate_creat
Fixes truncate and creat
2021-04-03 06:47:31 -07:00
Ryan Houdek 3379f3a8f9 Fixes eventfd and eventfd2
glibc function signature doesn't match kernel
2021-04-03 06:46:28 -07:00
Stefanos Kornilios Mitsis Poiitidis c76205040e Merge pull request #944 from Sonicadvance1/fix_clock_nanosleep
Fixes clock_nanosleep
2021-04-03 11:09:46 +03:00
Stefanos Kornilios Mitsis Poiitidis 648ef617cf Merge pull request #943 from Sonicadvance1/fix_fexconfig_unnamed_options
Fixes FEXConfig filling in unnamed options
2021-04-03 11:09:21 +03:00
Stefanos Kornilios Mitsis Poiitidis 5fac51f659 Merge pull request #942 from Sonicadvance1/implement_cmdline
Fixes wrapping cmdline arguments
2021-04-03 11:08:50 +03:00
Ryan Houdek 5d63dc179c Fixes truncate and creat
These were using the passthrough helper which doesn't was breaking the result value
2021-04-02 20:45:33 -07:00
Ryan Houdek 858566c356 Fixes clock_nanosleep
glibc version behaves slightly differently than kernel
2021-04-02 20:41:04 -07:00
Ryan Houdek fb94e62df1 Fixes FEXConfig filling in unnamed options
These aren't meant to be set by the user
2021-04-02 20:28:12 -07:00
Ryan Houdek 51e4fe7f0a Fixes wrapping cmdline arguments
In case an application checks this
2021-04-02 20:26:28 -07:00
Stefanos Kornilios Mitsis Poiitidis be03767c0b Merge pull request #941 from Sonicadvance1/pselect6_fix
Fixes pselect6 signal arg pack argument
2021-04-02 23:42:02 +03:00
Stefanos Kornilios Mitsis Poiitidis adeea56ea8 Merge pull request #940 from Sonicadvance1/update_release_script
Updates release script to match what I want it to be
2021-04-02 23:41:17 +03:00
Ryan Houdek 6923c47a70 Fixes pselect6 signal arg pack argument
This doesn't exactly match the glibc call so do the syscall directly
2021-04-02 13:23:07 -07:00
Ryan Houdek 26d9ddef9f Updates release script to match what I want it to be
Generates the current and previous tag automatically.
Checks to ensure the previous tag exists and that the current tag does not
2021-04-02 11:49:19 -07:00
192 changed files with 8366 additions and 2419 deletions

No files matched your search

+14 -1
View File
@@ -13,13 +13,14 @@ env:
BUILD_TYPE: Release
CC: clang
CXX: clang++
FEX_FORCE32BITALLOCATOR: 1
jobs:
build:
runs-on: ${{ matrix.arch }}
strategy:
matrix:
arch: [[self-hosted, x64], [self-hosted, ARMv8.0], [self-hosted, ARMv8.2]]
arch: [[self-hosted, x64], [self-hosted, ARMv8.0], [self-hosted, ARMv8.2], [self-hosted, ARMv8.4]]
fail-fast: false
steps:
@@ -116,6 +117,18 @@ jobs:
working-directory: ${{runner.workspace}}/build
run: mv ${{runner.workspace}}/build/Testing/Temporary/LastTest.log ${{runner.workspace}}/build/Testing/Temporary/LastTest_GCC64.log || true
- name: gcc target tests 32
working-directory: ${{runner.workspace}}/build
shell: bash
# Execute the gvisor tests
run: cmake --build . --config $BUILD_TYPE --target gcc_target_tests_32
- name: GCC32 Test Results move
if: ${{ always() }}
shell: bash
working-directory: ${{runner.workspace}}/build
run: mv ${{runner.workspace}}/build/Testing/Temporary/LastTest.log ${{runner.workspace}}/build/Testing/Temporary/LastTest_GCC32.log || true
- name: Struct verifier tests
working-directory: ${{runner.workspace}}/build
shell: bash
+3
View File
@@ -30,3 +30,6 @@
shallow = true
path = External/fex-gcc-target-tests-bins
url = https://github.com/FEX-Emu/fex-gcc-target-tests-bins.git
[submodule "External/jemalloc"]
path = External/jemalloc
url = https://github.com/FEX-Emu/jemalloc.git
+26 -12
View File
@@ -61,8 +61,8 @@ endif()
if (ENABLE_ASAN)
add_definitions(-DENABLE_ASAN=1)
add_compile_options(-fno-omit-frame-pointer -fsanitize=address)
link_libraries(-fno-omit-frame-pointer -fsanitize=address)
add_compile_options(-fno-omit-frame-pointer -fsanitize=address -fsanitize-address-use-after-scope)
link_libraries(-fno-omit-frame-pointer -fsanitize=address -fsanitize-address-use-after-scope)
endif()
if (ENABLE_TSAN)
@@ -103,11 +103,16 @@ if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
message(FATAL_ERROR "FEX doesn't support getting compiled with GCC!")
endif()
find_package(PkgConfig REQUIRED)
find_package(Python 3.0 REQUIRED COMPONENTS Interpreter)
pkg_check_modules(XXHASH libxxhash REQUIRED)
add_definitions(-Wno-trigraphs)
add_definitions(-DGLOBAL_DATA_DIRECTORY="${DATA_DIRECTORY}/")
add_subdirectory(External/jemalloc/)
include_directories(External/jemalloc/pregen/include/)
add_subdirectory(External/cpp-optparse/)
include_directories(External/cpp-optparse/)
@@ -158,18 +163,27 @@ if(ENABLE_WERROR OR ENABLE_STRICT_WERROR)
endif()
if(_M_ARM_64)
# Due to an oversight in llvm, it declares any reasonably new Kryo CPU to only be ARMv8.0
# Manually detect newer CPU revisions until clang and llvm fixes their bug
# This script will either provide a supported CPU or 'native'
# Additionally -march doesn't work under AArch64+Clang, so you have to use -mcpu or -mtune
execute_process(COMMAND python3 "${PROJECT_SOURCE_DIR}/Scripts/aarch64_fit_native.py" "/proc/cpuinfo"
OUTPUT_VARIABLE AARCH64_CPU)
if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 999999.0)
# Clang 12.0 fixed the -mcpu=native bug with mixed big.little implementers
# Clang can not currently check for native Apple M1 type in hypervisor. Currently disabled
check_cxx_compiler_flag("-mcpu=native" COMPILER_SUPPORTS_CPU_TYPE)
if(COMPILER_SUPPORTS_CPU_TYPE)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mcpu=native")
endif()
else()
# Due to an oversight in llvm, it declares any reasonably new Kryo CPU to only be ARMv8.0
# Manually detect newer CPU revisions until clang and llvm fixes their bug
# This script will either provide a supported CPU or 'native'
# Additionally -march doesn't work under AArch64+Clang, so you have to use -mcpu or -mtune
execute_process(COMMAND python3 "${PROJECT_SOURCE_DIR}/Scripts/aarch64_fit_native.py" "/proc/cpuinfo" "${CMAKE_CXX_COMPILER_VERSION}"
OUTPUT_VARIABLE AARCH64_CPU)
string(STRIP ${AARCH64_CPU} AARCH64_CPU)
string(STRIP ${AARCH64_CPU} AARCH64_CPU)
check_cxx_compiler_flag("-mcpu=${AARCH64_CPU}" COMPILER_SUPPORTS_CPU_TYPE)
if(COMPILER_SUPPORTS_CPU_TYPE)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mcpu=${AARCH64_CPU}")
check_cxx_compiler_flag("-mcpu=${AARCH64_CPU}" COMPILER_SUPPORTS_CPU_TYPE)
if(COMPILER_SUPPORTS_CPU_TYPE)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mcpu=${AARCH64_CPU}")
endif()
endif()
endif()
+35
View File
@@ -159,7 +159,42 @@ def print_man_environment(options):
default
)
print_man_environment_tail()
output_man.write(".El\n")
def print_man_environment_tail():
# Additional environment variables that live outside of the normal loop
print_man_env_option(
"FEX_APP_CONFIG_LOCATION",
[
"Allows the user to override where FEX looks for configuration files",
"By default FEX will look in {$HOME, $XDG_CONFIG_HOME}/.fex-emu/",
"This will override the full path",
],
"''")
print_man_env_option(
"FEX_APP_CONFIG",
[
"Allows the user to override where FEX looks for only the application config file",
"By default FEX will look in {$HOME, $XDG_CONFIG_HOME}/.fex-emu/Config.json",
"This will override this file location",
"One must be careful with this option as it will override any applications that load with execve as well"
"If you need to support applications that execve then use FEX_APP_CONFIG_LOCATION instead"
],
"''")
print_man_env_option(
"FEX_APP_DATA_LOCATION",
[
"Allows the user to override where FEX looks for data files",
"By default FEX will look in {$HOME, $XDG_DATA_HOME}/.fex-emu/",
"This will override the full path",
"This is the folder where FEX stores generated files like IR cache"
],
"''")
def print_man_header():
header ='''.Dd {0}
.Dt FEX
+25 -19
View File
@@ -108,10 +108,10 @@ def print_ir_sizes(ops, defines):
output_file.write("[[maybe_unused]] static size_t GetSize(IROps Op) { return IRSizes[Op]; }\n\n")
output_file.write("std::string_view const& GetName(IROps Op);\n")
output_file.write("uint8_t GetArgs(IROps Op);\n")
output_file.write("FEXCore::IR::RegisterClassType GetRegClass(IROps Op);\n\n")
output_file.write("bool HasSideEffects(IROps Op);\n")
output_file.write("__attribute__((const)) __attribute__((visibility(\"default\"))) std::string_view const& GetName(IROps Op);\n")
output_file.write("__attribute__((const)) __attribute__((visibility(\"default\"))) uint8_t GetArgs(IROps Op);\n")
output_file.write("__attribute__((const)) __attribute__((visibility(\"default\"))) FEXCore::IR::RegisterClassType GetRegClass(IROps Op);\n\n")
output_file.write("__attribute__((const)) __attribute__((visibility(\"default\"))) bool HasSideEffects(IROps Op);\n")
output_file.write("#undef IROP_SIZES\n")
output_file.write("#endif\n\n")
@@ -277,7 +277,7 @@ def print_ir_allocator_helpers(ops, defines):
output_file.write("\tusing IRPair = Wrapper<T>;\n\n")
output_file.write("\tIRPair<IROp_Header> AllocateRawOp(size_t HeaderSize) {\n")
output_file.write("\t\tauto Op = reinterpret_cast<IROp_Header*>(Data.Allocate(HeaderSize));\n")
output_file.write("\t\tauto Op = reinterpret_cast<IROp_Header*>(DualListData.DataAllocate(HeaderSize));\n")
output_file.write("\t\tmemset(Op, 0, HeaderSize);\n")
output_file.write("\t\tOp->Op = IROps::OP_DUMMY;\n")
output_file.write("\t\treturn IRPair<IROp_Header>{Op, CreateNode(Op)};\n")
@@ -286,7 +286,7 @@ def print_ir_allocator_helpers(ops, defines):
output_file.write("\ttemplate<class T, IROps T2>\n")
output_file.write("\tT *AllocateOrphanOp() {\n")
output_file.write("\t\tsize_t Size = FEXCore::IR::GetSize(T2);\n")
output_file.write("\t\tauto Op = reinterpret_cast<T*>(Data.Allocate(Size));\n")
output_file.write("\t\tauto Op = reinterpret_cast<T*>(DualListData.DataAllocate(Size));\n")
output_file.write("\t\tmemset(Op, 0, Size);\n")
output_file.write("\t\tOp->Header.Op = T2;\n")
output_file.write("\t\treturn Op;\n")
@@ -295,25 +295,25 @@ def print_ir_allocator_helpers(ops, defines):
output_file.write("\ttemplate<class T, IROps T2>\n")
output_file.write("\tIRPair<T> AllocateOp() {\n")
output_file.write("\t\tsize_t Size = FEXCore::IR::GetSize(T2);\n")
output_file.write("\t\tauto Op = reinterpret_cast<T*>(Data.Allocate(Size));\n")
output_file.write("\t\tauto Op = reinterpret_cast<T*>(DualListData.DataAllocate(Size));\n")
output_file.write("\t\tmemset(Op, 0, Size);\n")
output_file.write("\t\tOp->Header.Op = T2;\n")
output_file.write("\t\treturn IRPair<T>{Op, CreateNode(&Op->Header)};\n")
output_file.write("\t}\n\n")
output_file.write("\tuint8_t GetOpSize(OrderedNode *Op) const {\n")
output_file.write("\t\tauto HeaderOp = Op->Header.Value.GetNode(Data.Begin());\n")
output_file.write("\t\tauto HeaderOp = Op->Header.Value.GetNode(DualListData.DataBegin());\n")
output_file.write("\t\treturn HeaderOp->Size;\n")
output_file.write("\t}\n\n")
output_file.write("\tuint8_t GetOpElements(OrderedNode *Op) const {\n")
output_file.write("\t\tauto HeaderOp = Op->Header.Value.GetNode(Data.Begin());\n")
output_file.write("\t\tLogMan::Throw::A(HeaderOp->HasDest, \"Op %s has no dest\\n\", GetName(HeaderOp->Op));\n")
output_file.write("\t\tauto HeaderOp = Op->Header.Value.GetNode(DualListData.DataBegin());\n")
output_file.write("\t\tLOGMAN_THROW_A(HeaderOp->HasDest, \"Op %s has no dest\\n\", GetName(HeaderOp->Op));\n")
output_file.write("\t\treturn HeaderOp->Size / HeaderOp->ElementSize;\n")
output_file.write("\t}\n\n")
output_file.write("\tbool OpHasDest(OrderedNode *Op) const {\n")
output_file.write("\t\tauto HeaderOp = Op->Header.Value.GetNode(Data.Begin());\n")
output_file.write("\t\tauto HeaderOp = Op->Header.Value.GetNode(DualListData.DataBegin());\n")
output_file.write("\t\treturn HeaderOp->HasDest;\n")
output_file.write("\t}\n\n")
@@ -387,11 +387,14 @@ def print_ir_allocator_helpers(ops, defines):
output_file.write(") {\n")
output_file.write("\t\tauto Op = AllocateOp<IROp_%s, IROps::OP_%s>();\n" % (op_key, op_key.upper()))
output_file.write("\t\tOp.first->Header.NumArgs = %d;\n" % (SSAArgs))
if (SSAArgs != 0):
output_file.write("\t\tauto ListDataBegin = DualListData.ListBegin();\n")
for i in range(0, SSAArgs):
output_file.write("\t\tOp.first->Header.Args[%d] = ssa%d->Wrapped(ListDataBegin);\n" % (i, i))
if (SSAArgs != 0):
for i in range(0, SSAArgs):
output_file.write("\t\tOp.first->Header.Args[%d] = ssa%d->Wrapped(ListData.Begin());\n" % (i, i))
output_file.write("\t\tssa%d->AddUse();\n" % (i))
if (HasArgs):
@@ -399,11 +402,6 @@ def print_ir_allocator_helpers(ops, defines):
data_name = op_vals["Args"][i]
output_file.write("\t\tOp.first->%s = %s;\n" % (data_name, data_name))
if (HasFixedDestSize):
output_file.write("\t\tOp.first->Header.Size = %d;\n" % FixedDestSize)
if (HasDestSize):
output_file.write("\t\tOp.first->Header.Size = %s;\n" % DestSize)
if (HasDest):
# We can only infer a size if we have arguments
if not (HasFixedDestSize or HasDestSize):
@@ -412,10 +410,18 @@ def print_ir_allocator_helpers(ops, defines):
if (SSAArgs != 0):
for i in range(0, SSAArgs):
output_file.write("\t\tuint8_t Size%d = GetOpSize(ssa%s);\n" % (i, i))
for i in range(0, SSAArgs):
output_file.write("\t\tInferSize = std::max(InferSize, Size%d);\n" % (i))
output_file.write("\t\tOp.first->Header.Size = InferSize;\n")
output_file.write("\t\tOp.first->Header.NumArgs = %d;\n" % (SSAArgs))
if (HasFixedDestSize):
output_file.write("\t\tOp.first->Header.Size = %d;\n" % FixedDestSize)
if (HasDestSize):
output_file.write("\t\tOp.first->Header.Size = %s;\n" % DestSize)
output_file.write("\t\tOp.first->Header.ElementSize = Op.first->Header.Size / (%s);\n" % NumElements)
if (HasDest):
@@ -499,7 +505,7 @@ def print_ir_parser_allocator_helpers(ops, defines):
if (SSAArgs != 0):
for i in range(0, SSAArgs):
output_file.write("\t\tOp.first->Header.Args[%d] = ssa%d->Wrapped(ListData.Begin());\n" % (i, i))
output_file.write("\t\tOp.first->Header.Args[%d] = ssa%d->Wrapped(DualListData.ListBegin());\n" % (i, i))
output_file.write("\t\tssa%d->AddUse();\n" % (i))
if (HasArgs):
+22 -3
View File
@@ -114,6 +114,7 @@ set (SRCS
Interface/IR/Passes/DeadContextStoreElimination.cpp
Interface/IR/Passes/IRCompaction.cpp
Interface/IR/Passes/IRValidation.cpp
Interface/IR/Passes/LongDivideRemovalPass.cpp
Interface/IR/Passes/ValueDominanceValidation.cpp
Interface/IR/Passes/PhiValidation.cpp
Interface/IR/Passes/RedundantFlagCalculationElimination.cpp
@@ -121,7 +122,9 @@ set (SRCS
Interface/IR/Passes/StaticRegisterAllocationPass.cpp
Interface/IR/Passes/RegisterAllocationPass.cpp
Interface/IR/Passes/SyscallOptimization.cpp
Utils/ELFLoader.cpp
Utils/Allocator.cpp
Utils/Allocator/64BitAllocator.cpp
Utils/ELFContainer.cpp
Utils/ELFSymbolDatabase.cpp
Utils/LogManager.cpp
Utils/Threads.cpp
@@ -264,8 +267,11 @@ function(AddObject Name Type)
add_dependencies(${Name} IR_INC)
add_dependencies(${Name} CONFIG_INC)
target_link_libraries(${Name} pthread rt vixl ${LINUX_LIBS} dl)
target_link_libraries(${Name} pthread vixl dl xxhash FEX_jemalloc)
set_target_properties(${Name} PROPERTIES OUTPUT_NAME FEXCore)
set_target_properties(${Name} PROPERTIES C_VISIBILITY_PRESET hidden)
set_target_properties(${Name} PROPERTIES CXX_VISIBILITY_PRESET hidden)
set_target_properties(${Name} PROPERTIES VISIBILITY_INLINES_HIDDEN TRUE)
target_include_directories(${Name} PUBLIC "${CMAKE_CURRENT_BINARY_DIR}")
@@ -283,6 +289,7 @@ function(AddObject Name Type)
-Werror=implicit-fallthrough
-Wno-trigraphs
-ffunction-sections
)
if (GCC_COLOR)
@@ -299,12 +306,24 @@ endfunction()
function(AddLibrary Name Type)
add_library(${Name} ${Type} $<TARGET_OBJECTS:${PROJECT_NAME}_object>)
target_link_libraries(${Name} pthread rt vixl ${LINUX_LIBS} dl)
target_link_libraries(${Name} pthread vixl dl xxhash FEX_jemalloc)
set_target_properties(${Name} PROPERTIES OUTPUT_NAME FEXCore)
set_target_properties(${Name} PROPERTIES C_VISIBILITY_PRESET hidden)
set_target_properties(${Name} PROPERTIES CXX_VISIBILITY_PRESET hidden)
set_target_properties(${Name} PROPERTIES VISIBILITY_INLINES_HIDDEN TRUE)
target_include_directories(${Name} PUBLIC "${CMAKE_CURRENT_BINARY_DIR}")
target_include_directories(${Name} PUBLIC "${PROJECT_SOURCE_DIR}/include/")
target_include_directories(${Name} PUBLIC "${CMAKE_BINARY_DIR}/include/")
if (CMAKE_BUILD_TYPE MATCHES "RELEASE")
target_link_options(${Name}
PRIVATE
"LINKER:--gc-sections"
"LINKER:--strip-all"
"LINKER:--as-needed"
)
endif()
endfunction()
AddObject(${PROJECT_NAME}_object OBJECT)
+7 -6
View File
@@ -1,5 +1,6 @@
#pragma once
#include "Common/MathUtils.h"
#include <FEXCore/Utils/Allocator.h>
#include <FEXCore/Utils/LogManager.h>
#include <cstring>
@@ -16,16 +17,16 @@ struct BitSet final {
ElementType *Memory;
void Allocate(size_t Elements) {
size_t AllocateSize = AlignUp(Elements, MinimumSizeBits) / MinimumSize;
LogMan::Throw::A((AllocateSize * MinimumSize) >= Elements, "Fail");
Memory = static_cast<ElementType*>(malloc(AllocateSize));
LOGMAN_THROW_A((AllocateSize * MinimumSize) >= Elements, "Fail");
Memory = static_cast<ElementType*>(FEXCore::Allocator::malloc(AllocateSize));
}
void Realloc(size_t Elements) {
size_t AllocateSize = AlignUp(Elements, MinimumSizeBits) / MinimumSize;
LogMan::Throw::A((AllocateSize * MinimumSize) >= Elements, "Fail");
Memory = static_cast<ElementType*>(realloc(Memory, AllocateSize));
LOGMAN_THROW_A((AllocateSize * MinimumSize) >= Elements, "Fail");
Memory = static_cast<ElementType*>(FEXCore::Allocator::realloc(Memory, AllocateSize));
}
void Free() {
free(Memory);
FEXCore::Allocator::free(Memory);
Memory = nullptr;
}
bool Get(T Element) {
@@ -60,7 +61,7 @@ struct BitSetView final {
ElementType *Memory;
void GetView(BitSet<T> &Set, uint64_t ElementOffset) {
LogMan::Throw::A((ElementOffset % MinimumSize) == 0,
LOGMAN_THROW_A((ElementOffset % MinimumSize) == 0,
"Bitset view offset needs to be aligned to size of backing element");
Memory = &Set.Memory[ElementOffset / MinimumSizeBits];
}
+32 -5
View File
@@ -48,8 +48,15 @@ namespace FEXCore::Config {
else {
char const *HomeDir = GetHomeDirectory();
char const *ConfigXDG = getenv("XDG_CONFIG_HOME");
ConfigDir = ConfigXDG ? ConfigXDG : HomeDir;
ConfigDir += "/.fex-emu/";
char const *ConfigOverride = getenv("FEX_APP_CONFIG_LOCATION");
if (ConfigOverride) {
// Config override completely overrides the config directory
ConfigDir = ConfigOverride;
}
else {
ConfigDir = ConfigXDG ? ConfigXDG : HomeDir;
ConfigDir += "/.fex-emu/";
}
// Ensure the folder structure is created for our configuration
if (!std::filesystem::exists(ConfigDir) &&
@@ -64,7 +71,15 @@ namespace FEXCore::Config {
}
std::string GetConfigFileLocation() {
std::string ConfigFile = GetConfigDirectory(false) + "Config.json";
std::string ConfigFile{};
const char *AppConfig = getenv("FEX_APP_CONFIG");
if (AppConfig) {
// App config environment variable overwrites only the config file
ConfigFile = AppConfig;
}
else {
ConfigFile = GetConfigDirectory(false) + "Config.json";
}
return ConfigFile;
}
@@ -87,8 +102,15 @@ namespace FEXCore::Config {
char const *HomeDir = GetHomeDirectory();
char const *DataXDG = getenv("XDG_DATA_HOME");
DataDir = DataXDG ?: HomeDir;
DataDir += "/.fex-emu/";
char const *DataOverride = getenv("FEX_APP_DATA_LOCATION");
if (DataOverride) {
// Data override will override the complete directory
DataDir = DataOverride;
}
else {
DataDir = DataXDG ?: HomeDir;
DataDir += "/.fex-emu/";
}
return DataDir;
}
@@ -326,6 +348,10 @@ namespace FEXCore::Config {
Meta->Set(Option, Data);
}
void Erase(ConfigOption Option) {
Meta->Erase(Option);
}
void EraseSet(ConfigOption Option, std::string Data) {
Meta->EraseSet(Option, Data);
}
@@ -389,5 +415,6 @@ namespace FEXCore::Config {
*List = **Value;
}
}
template void Value<std::string>::GetListIfExists(FEXCore::Config::ConfigOption Option, std::list<std::string> *List);
}
+28 -1
View File
@@ -129,7 +129,18 @@
"Desc": [
"Disables optimizations passes for debugging."
]
},
"Force32BitAllocator": {
"Type": "bool",
"Default": "false",
"Desc": [
"Forces use of the 32-bit allocator on 32-bit applications",
"Used to work around ulimit problems of CI runner",
"Potentially useful for debugging memory problems",
"32-bit allocator is always used if your host kernel is older than 4.17"
]
}
},
"Logging": {
"SilentLog": {
@@ -142,7 +153,7 @@
},
"OutputLog": {
"Type": "str",
"Default": "stdout",
"Default": "stderr",
"ShortArg": "o",
"Desc": [
"File to write FEX output to.",
@@ -188,6 +199,14 @@
"Removes the calculation of the parity flag from GPR instructions.",
"Assuming no uses rely on it"
]
},
"ParanoidTSO": {
"Type": "bool",
"Default": "false",
"Desc": [
"Makes TSO operations even more strict.",
"Forces vector loadstores to also become atomic."
]
}
},
"Misc": {
@@ -199,6 +218,14 @@
"Captures both the loaded executable and libraries it loads."
]
},
"AOTIRGenerate": {
"Type": "bool",
"Default": "false",
"Desc": [
"Scans file for executable code and generates an AOT IR cache.",
"Does not run the executable."
]
},
"AOTIRLoad": {
"Type": "bool",
"Default": "false",
+8 -1
View File
@@ -50,6 +50,9 @@ namespace FEXCore::Context {
CTX->Step();
}
void CompileRIP(FEXCore::Context::Context *CTX, uint64_t GuestRIP) {
CTX->CompileBlock(CTX->ParentThread->CurrentFrame, GuestRIP);
}
FEXCore::Context::ExitReason RunUntilExit(FEXCore::Context::Context *CTX) {
return CTX->RunUntilExit();
@@ -142,7 +145,7 @@ namespace FEXCore::Context {
return CTX->CPUID.RunFunction(Function, Leaf);
}
void SetAOTIRLoader(FEXCore::Context::Context *CTX, std::function<std::unique_ptr<std::istream>(const std::string&)> CacheReader) {
void SetAOTIRLoader(FEXCore::Context::Context *CTX, std::function<int(const std::string&)> CacheReader) {
CTX->AOTIRLoader = CacheReader;
}
@@ -150,6 +153,10 @@ namespace FEXCore::Context {
return CTX->WriteAOTIRCache(CacheWriter);
}
void WriteFilesWithCode(FEXCore::Context::Context *CTX, std::function<void(const std::string& fileid, const std::string& filename)> Writer) {
CTX->WriteFilesWithCode(Writer);
}
void AddNamedRegion(FEXCore::Context::Context *CTX, uintptr_t Base, uintptr_t Length, uintptr_t Offset, const std::string& Name) {
return CTX->AddNamedRegion(Base, Length, Offset, Name);
}
+49 -19
View File
@@ -52,6 +52,39 @@ namespace FEXCore::Context {
MODE_SINGLESTEP = 1,
};
struct AOTIRCaptureCacheEntry {
uint64_t start;
uint64_t len;
uint64_t crc;
IR::IRListView *IR;
IR::RegisterAllocationData *RAData;
};
struct AOTIRInlineEntry {
uint64_t GuestHash;
uint64_t GuestLength;
/* RAData followed by IRData */
uint8_t InlineData[0];
IR::RegisterAllocationData *GetRAData();
IR::IRListView *GetIRData();
};
struct AOTIRInlineIndexEntry {
uint64_t GuestStart;
uint64_t DataOffset;
};
struct AOTIRInlineIndex {
uint64_t Count;
uint64_t DataBase;
AOTIRInlineIndexEntry Entries[0];
AOTIRInlineEntry *Find(uint64_t GuestStart);
AOTIRInlineEntry *GetInlineEntry(uint64_t DataOffset);
};
struct Context {
friend class FEXCore::HLE::SyscallHandler;
#ifdef JIT_ARM64
@@ -78,6 +111,7 @@ namespace FEXCore::Context {
FEX_CONFIG_OPT(ABILocalFlags, ABILOCALFLAGS);
FEX_CONFIG_OPT(ABINoPF, ABINOPF);
FEX_CONFIG_OPT(AOTIRCapture, AOTIRCAPTURE);
FEX_CONFIG_OPT(AOTIRGenerate, AOTIRGENERATE);
FEX_CONFIG_OPT(AOTIRLoad, AOTIRLOAD);
FEX_CONFIG_OPT(SMCChecks, SMCCHECKS);
FEX_CONFIG_OPT(Core, CORE);
@@ -113,26 +147,27 @@ namespace FEXCore::Context {
std::function<void(uint64_t ThreadId, FEXCore::Context::ExitReason)> CustomExitHandler;
struct AOTIRCacheEntry {
uint64_t start;
uint64_t len;
uint64_t crc;
IR::IRListView *IR;
IR::RegisterAllocationData *RAData;
AOTIRInlineIndex *Array;
void *mapping;
size_t size;
};
std::function<std::unique_ptr<std::istream>(const std::string&)> AOTIRLoader;
std::unordered_map<std::string, std::map<uint64_t, AOTIRCacheEntry>> AOTIRCache;
std::unordered_map<std::string, AOTIRCacheEntry> AOTIRCache;
std::function<int(const std::string&)> AOTIRLoader;
std::unordered_map<std::string, std::map<uint64_t, AOTIRCaptureCacheEntry>> AOTIRCaptureCache;
struct AddrToFileEntry {
uint64_t Start;
uint64_t Len;
uint64_t Offset;
std::string fileid;
std::string filename;
void *CachedFileEntry;
bool ContainsCode;
};
std::map<uint64_t, AddrToFileEntry> AddrToFile;
std::map<std::string, std::string> FilesWithCode;
#ifdef BLOCKSTATS
std::unique_ptr<FEXCore::BlockSamplingData> BlockData;
@@ -178,18 +213,18 @@ namespace FEXCore::Context {
bool GetDebugDataForRIP(uint64_t RIP, FEXCore::Core::DebugData *Data);
bool FindHostCodeForRIP(uint64_t RIP, uint8_t **Code);
// XXX:
// bool FindIRForRIP(uint64_t RIP, FEXCore::IR::IntrusiveIRList **ir);
// void SetIRForRIP(uint64_t RIP, FEXCore::IR::IntrusiveIRList *const ir);
void LoadEntryList();
std::tuple<FEXCore::IR::IRListView *, FEXCore::IR::RegisterAllocationData *, uint64_t, uint64_t, uint64_t, uint64_t> GenerateIR(FEXCore::Core::InternalThreadState *Thread, uint64_t GuestRIP);
std::tuple<void *, FEXCore::IR::IRListView *, FEXCore::Core::DebugData *, FEXCore::IR::RegisterAllocationData *, bool, uint64_t, uint64_t> CompileCode(FEXCore::Core::InternalThreadState *Thread, uint64_t GuestRIP);
uintptr_t CompileBlock(FEXCore::Core::CpuStateFrame *Frame, uint64_t GuestRIP);
// same as CompileBlock, but aborts on failure
void CompileBlockJit(FEXCore::Core::CpuStateFrame *Frame, uint64_t GuestRIP);
bool LoadAOTIRCache(std::istream &stream);
bool LoadAOTIRCache(int streamfd);
bool WriteAOTIRCache(std::function<std::unique_ptr<std::ostream>(const std::string&)> CacheWriter);
void WriteFilesWithCode(std::function<void(const std::string& fileid, const std::string& filename)> Writer);
// Used for thread creation from syscalls
void InitializeCompiler(FEXCore::Core::InternalThreadState* State, bool CompileThread);
FEXCore::Core::InternalThreadState* CreateThread(FEXCore::Core::CPUState *NewThreadState, uint64_t ParentTID);
@@ -226,11 +261,6 @@ namespace FEXCore::Context {
FEXCore::CodeLoader *LocalLoader{};
// Entry Cache
std::optional<std::string> GetFilenameHash(std::string const &Filename) const;
void AddThreadRIPsToEntryList(FEXCore::Core::InternalThreadState *Thread);
void SaveEntryList();
std::set<uint64_t> EntryList;
std::vector<uint64_t> InitLocations;
uint64_t StartingRIP;
std::mutex ExitMutex;
std::unique_ptr<GdbServer> DebugServer;
@@ -12,6 +12,12 @@ namespace FEXCore::ArchHelpers::Arm64 {
constexpr uint32_t ATOMIC_MEM_MASK = 0x3B200C00;
constexpr uint32_t ATOMIC_MEM_INST = 0x38200000;
constexpr uint32_t LDAXP_MASK = 0xBF'FF'80'00;
constexpr uint32_t LDAXP_INST = 0x88'7F'80'00;
constexpr uint32_t STLXP_MASK = 0xBF'E0'80'00;
constexpr uint32_t STLXP_INST = 0x88'20'80'00;
// Load ops are 4 bits
// Acquire and release bits are independent on the instruction
constexpr uint32_t ATOMIC_ADD_OP = 0b0000;
@@ -29,6 +29,17 @@ Arm64Emitter::Arm64Emitter(size_t size) : vixl::aarch64::Assembler(size, vixl::a
if (!SupportsAtomics) {
WARN_ONCE("Host CPU doesn't support atomics. Expect bad performance");
}
#ifdef _M_ARM_64
// We need to get the CPU's cache line size
// We expect sane targets that have correct cacheline sizes across clusters
uint64_t CTR;
__asm volatile ("mrs %[ctr], ctr_el0"
: [ctr] "=r"(CTR));
DCacheLineSize = 4 << ((CTR >> 16) & 0xF);
ICacheLineSize = 4 << (CTR & 0xF);
#endif
}
void Arm64Emitter::LoadConstant(vixl::aarch64::Register Reg, uint64_t Constant) {
@@ -69,6 +69,9 @@ protected:
void Align16B();
uint32_t SpillSlots{};
uint32_t DCacheLineSize{};
uint32_t ICacheLineSize{};
};
}
@@ -111,7 +111,7 @@ static inline void BackupContext(void* ucontext, T *Backup) {
// Host FPR state starts at _mcontext->reserved[0];
HostFPRState *HostState = reinterpret_cast<HostFPRState*>(&_mcontext->__reserved[0]);
LogMan::Throw::A(HostState->Head.Magic == FPR_MAGIC, "Wrong FPR Magic: 0x%08x", HostState->Head.Magic);
LOGMAN_THROW_A(HostState->Head.Magic == FPR_MAGIC, "Wrong FPR Magic: 0x%08x", HostState->Head.Magic);
Backup->FPSR = HostState->FPSR;
Backup->FPCR = HostState->FPCR;
memcpy(&Backup->FPRs[0], &HostState->FPRs[0], 32 * sizeof(__uint128_t));
@@ -126,7 +126,7 @@ static inline void RestoreContext(void* ucontext, T *Backup) {
auto _mcontext = GetMContext(ucontext);
HostFPRState *HostState = reinterpret_cast<HostFPRState*>(&_mcontext->__reserved[0]);
LogMan::Throw::A(HostState->Head.Magic == FPR_MAGIC, "Wrong FPR Magic: 0x%08x", HostState->Head.Magic);
LOGMAN_THROW_A(HostState->Head.Magic == FPR_MAGIC, "Wrong FPR Magic: 0x%08x", HostState->Head.Magic);
memcpy(&HostState->FPRs[0], &Backup->FPRs[0], 32 * sizeof(__uint128_t));
HostState->FPCR = Backup->FPCR;
HostState->FPSR = Backup->FPSR;
+49 -4
View File
@@ -124,7 +124,7 @@ FEXCore::CPUID::FunctionResults CPUIDEmu::Function_01h() {
(1 << 16) | // Page Attribute Table
(1 << 17) | // 36bit page size extension
(0 << 18) | // Processor serial number
(0 << 19) | // CLFLUSH
(1 << 19) | // CLFLUSH
(0 << 20) | // Reserved
(0 << 21) | // Debug store
(0 << 22) | // Thermal monitor and software controled clock
@@ -496,6 +496,45 @@ FEXCore::CPUID::FunctionResults CPUIDEmu::Function_8000_0007h() {
return Res;
}
// Virtual and physical address sizes
FEXCore::CPUID::FunctionResults CPUIDEmu::Function_8000_0008h() {
FEXCore::CPUID::FunctionResults Res{};
Res.eax =
(48 << 0) | // PhysAddrSize = 48-bit
(48 << 8) | // LinAddrSize = 48-bit
(0 << 16); // GuestPhysAddrSize == PhysAddrSize
Res.ebx =
(0 << 2) | // XSaveErPtr: Saving and restoring error pointers
(0 << 1) | // IRPerf: Instructions retired count support
(0 << 0); // CLZERO support
uint32_t CoreCount = Cores() - 1;
Res.ecx =
(0 << 16) | // PerfTscSize: Performance timestamp count size
(0 << 12) | // ApicIdSize: Number of bits in ApicID
(CoreCount << 0); // Count count subtract one
return Res;
}
// TLB 1GB page identifiers
FEXCore::CPUID::FunctionResults CPUIDEmu::Function_8000_0019h() {
FEXCore::CPUID::FunctionResults Res{};
Res.eax =
(0xF << 28) | // L1 DTLB associativity for 1GB pages
(64 << 16) | // L1 DTLB entry count for 1GB pages
(0xF << 12) | // L1 ITLB associativity for 1GB pages
(64 << 0); // L1 ITLB entry count for 1GB pages
Res.ebx =
(0 << 28) | // L2 DTLB associativity for 1GB pages
(0 << 16) | // L2 DTLB entry count for 1GB pages
(0 << 12) | // L2 ITLB associativity for 1GB pages
(0 << 0); // L2 ITLB entry count for 1GB pages
return Res;
}
FEXCore::CPUID::FunctionResults CPUIDEmu::Function_Reserved() {
FEXCore::CPUID::FunctionResults Res{};
return Res;
@@ -542,16 +581,22 @@ void CPUIDEmu::Init(FEXCore::Context::Context *ctx) {
RegisterFunction(0x8000'0004, std::bind(&CPUIDEmu::Function_8000_0004h, this));
// 0x8000'0005: L1 Cache and TLB identifiers
#ifdef CPUID_AMD
// This is full reserved on Intel platforms
RegisterFunction(0x8000'0005, std::bind(&CPUIDEmu::Function_8000_0005h, this));
#else
// This is full reserved on Intel platforms
RegisterFunction(0x8000'0005, std::bind(&CPUIDEmu::Function_Reserved, this));
#endif
// 0x8000'0006: L2 Cache identifiers
RegisterFunction(0x8000'0006, std::bind(&CPUIDEmu::Function_8000_0006h, this));
// Advanced power management information
RegisterFunction(0x8000'0007, std::bind(&CPUIDEmu::Function_8000_0007h, this));
// 0x8000'0008: Virtual and physical address sizes
// Virtual and physical address sizes
RegisterFunction(0x8000'0008, std::bind(&CPUIDEmu::Function_8000_0008h, this));
// 0x8000'000A: SVM Revision
// 0x8000'0019: TLB 1GB page identifiers
// TLB 1GB page identifiers
RegisterFunction(0x8000'0019, std::bind(&CPUIDEmu::Function_8000_0019h, this));
// 0x8000'001A: Performance optimization identifiers
// 0x8000'001B: Instruction based sampling identifiers
// 0x8000'001C: Lightweight profiling capabilities
+5 -1
View File
@@ -3,6 +3,7 @@
#include <unordered_map>
#include <FEXCore/Core/CPUID.h>
#include <FEXCore/Config/Config.h>
#include <FEXCore/Utils/LogManager.h>
namespace FEXCore {
@@ -37,6 +38,7 @@ public:
}
private:
FEXCore::Context::Context *CTX;
FEX_CONFIG_OPT(Cores, THREADS);
using FunctionHandler = std::function<FEXCore::CPUID::FunctionResults()>;
void RegisterFunction(uint32_t Function, FunctionHandler Handler) {
@@ -60,7 +62,9 @@ private:
FEXCore::CPUID::FunctionResults Function_8000_0005h();
FEXCore::CPUID::FunctionResults Function_8000_0006h();
FEXCore::CPUID::FunctionResults Function_8000_0007h();
FEXCore::CPUID::FunctionResults Function_8000_0008h();
FEXCore::CPUID::FunctionResults Function_8000_0009h();
FEXCore::CPUID::FunctionResults Function_8000_0019h();
FEXCore::CPUID::FunctionResults Function_Reserved();
};
}
+3 -3
View File
@@ -61,7 +61,7 @@ namespace FEXCore {
}
}
LogMan::Throw::A(CompileThreadData->LocalIRCache.size() == 0, "Compile service must never have LocalIRCache");
LOGMAN_THROW_A(CompileThreadData->LocalIRCache.size() == 0, "Compile service must never have LocalIRCache");
CompileMutex.unlock();
}
@@ -124,7 +124,7 @@ namespace FEXCore {
// If we had a work item then work on it
if (Item) {
// Make sure it's not in lookup cache by accident
LogMan::Throw::A(CompileThreadData->LookupCache->FindBlock(Item->RIP) == 0, "Compile Service must never have entries in the LookupCache");
LOGMAN_THROW_A(CompileThreadData->LookupCache->FindBlock(Item->RIP) == 0, "Compile Service must never have entries in the LookupCache");
// Code isn't in cache, compile now
// Set our thread state's RIP
@@ -132,7 +132,7 @@ namespace FEXCore {
auto [CodePtr, IRList, DebugData, RAData, Generated, StartAddr, Length] = CTX->CompileCode(CompileThreadData.get(), Item->RIP);
LogMan::Throw::A(Generated == true, "Compile Service doesn't have IR Cache");
LOGMAN_THROW_A(Generated == true, "Compile Service doesn't have IR Cache");
if (!CodePtr) {
// XXX: We currently have the expectation that compile service code will be significantly smaller than regular thread's code
+215 -254
View File
@@ -28,59 +28,22 @@ $end_info$
#include <FEXCore/Core/CPUBackend.h>
#include <FEXCore/Core/X86Enums.h>
#include <FEXCore/HLE/SyscallHandler.h>
#include <FEXCore/Utils/Allocator.h>
#include "Interface/HLE/Thunks/Thunks.h"
#include "FEXCore/Utils/Allocator.h"
#include <xxh3.h>
#include <fstream>
#include <unistd.h>
#include <filesystem>
#include <algorithm>
#include <sys/mman.h>
#include <unistd.h>
#include <sys/stat.h>
#include "Interface/Core/GdbServer.h"
namespace {
// Compression function for Merkle-Damgard construction.
// This function is generated using the framework provided.
#define mix(h) ({ \
(h) ^= (h) >> 23; \
(h) *= 0x2127599bf4325c37ULL; \
(h) ^= (h) >> 47; })
static uint64_t fasthash64(const void *buf, size_t len, uint64_t seed)
{
const uint64_t m = 0x880355f21e6d1965ULL;
const uint64_t *pos = (const uint64_t *)buf;
const uint64_t *end = pos + (len / 8);
const unsigned char *pos2;
uint64_t h = seed ^ (len * m);
uint64_t v;
while (pos != end) {
v = *pos++;
h ^= mix(v);
h *= m;
}
pos2 = (const unsigned char*)pos;
v = 0;
switch (len & 7) {
case 7: v ^= (uint64_t)pos2[6] << 48; [[fallthrough]];
case 6: v ^= (uint64_t)pos2[5] << 40; [[fallthrough]];
case 5: v ^= (uint64_t)pos2[4] << 32; [[fallthrough]];
case 4: v ^= (uint64_t)pos2[3] << 24; [[fallthrough]];
case 3: v ^= (uint64_t)pos2[2] << 16; [[fallthrough]];
case 2: v ^= (uint64_t)pos2[1] << 8; [[fallthrough]];
case 1: v ^= (uint64_t)pos2[0];
h ^= mix(v);
h *= m;
}
return mix(h);
}
#undef mix
}
namespace FEXCore::CPU {
bool CreateCPUCore(FEXCore::Context::Context *CTX) {
// This should be used for generating things that are shared between threads
@@ -167,7 +130,7 @@ namespace DefaultFallbackCore {
void Initialize() override {}
bool NeedsOpDispatch() override { return false; }
void *CompileCode(FEXCore::IR::IRListView const *IR, FEXCore::Core::DebugData *DebugData, FEXCore::IR::RegisterAllocationData *RAData) override {
void *CompileCode(uint64_t Entry, FEXCore::IR::IRListView const *IR, FEXCore::Core::DebugData *DebugData, FEXCore::IR::RegisterAllocationData *RAData) override {
LogMan::Msg::E("Fell back to default code handler at RIP: 0x%lx", ThreadState->CurrentFrame->State.rip);
return nullptr;
}
@@ -196,77 +159,6 @@ namespace FEXCore::Context {
}
}
std::optional<std::string> Context::GetFilenameHash(std::string const &Filename) const {
// Calculate a hash for the input file
std::ifstream Input(Filename, std::ios::in | std::ios::binary | std::ios::ate);
if (!Input) {
return std::nullopt;
}
const auto Size = static_cast<size_t>(Input.tellg());
Input.seekg(0, std::ios::beg);
std::string Data(Size, '\0');
Input.read(Data.data(), Size);
Input.close();
std::hash<std::string> string_hash;
return std::to_string(string_hash(Data));
}
void Context::AddThreadRIPsToEntryList(FEXCore::Core::InternalThreadState *Thread) {
for (auto &IR : Thread->LocalIRCache) {
EntryList.insert(IR.first);
}
}
void Context::SaveEntryList() {
std::string const &Filename = AppFilename();
if (auto const hash = GetFilenameHash(Filename)) {
auto DataPath = FEXCore::Paths::GetEntryCachePath();
DataPath += "Entries_" + *hash;
std::ofstream Output(DataPath, std::ios::out | std::ios::binary);
if (!Output) {
return;
}
for (auto Entry : EntryList) {
Output.write(reinterpret_cast<char const*>(&Entry), sizeof(Entry));
}
}
}
void Context::LoadEntryList() {
std::string const &Filename = AppFilename();
if (auto const hash = GetFilenameHash(Filename)) {
auto DataPath = FEXCore::Paths::GetEntryCachePath();
DataPath += "Entries_" + *hash;
std::ifstream Input(DataPath, std::ios::in | std::ios::binary | std::ios::ate);
if (!Input) {
return;
}
auto const Size = static_cast<size_t>(Input.tellg());
Input.seekg(0, std::ios::beg);
std::string Data(Size, '\0');
if (!Input.read(Data.data(), Size)) {
return;
}
Input.close();
size_t const EntryCount = Size / sizeof(uint64_t);
for (size_t i = 0; i < EntryCount; ++i) {
uint64_t Entry = 0;
std::memcpy(&Entry, &Data[i * sizeof(Entry)], sizeof(Entry));
EntryList.insert(Entry);
}
}
}
Context::~Context() {
{
for (auto &Thread : Threads) {
@@ -275,10 +167,6 @@ namespace FEXCore::Context {
}
}
for (auto &Thread : Threads) {
AddThreadRIPsToEntryList(Thread);
}
for (auto &Thread : Threads) {
if (Thread->CompileService) {
@@ -289,15 +177,17 @@ namespace FEXCore::Context {
Threads.clear();
}
SaveEntryList();
// AOTIRCache needs manual clear
for (auto &Mod: AOTIRCache) {
// AOTIRCaptureCache needs manual clear
for (auto &Mod: AOTIRCaptureCache) {
for (auto &Entry: Mod.second) {
delete Entry.second.IR;
free(Entry.second.RAData);
FEXCore::Allocator::free(Entry.second.RAData);
}
}
for (auto &Mod: AOTIRCache) {
FEXCore::Allocator::munmap(Mod.second.mapping, Mod.second.size);
}
}
bool Context::InitCore(FEXCore::CodeLoader *Loader) {
@@ -327,12 +217,7 @@ namespace FEXCore::Context {
// We are the parent thread
ParentThread = Thread;
Loader->MapMemoryRegion();
Thread->CurrentFrame->State.gregs[X86State::REG_RSP] = Loader->SetupStack();
Loader->LoadMemory();
Loader->GetInitLocations(&InitLocations);
Thread->CurrentFrame->State.gregs[X86State::REG_RSP] = Loader->GetStackPointer();
Thread->CurrentFrame->State.rip = StartingRIP = Loader->DefaultRIP();
@@ -542,12 +427,6 @@ namespace FEXCore::Context {
LocalLoader->AddIR(IRHandler);
// Compile all of our cached entries
LogMan::Msg::D("Precompiling: %ld blocks...", EntryList.size());
for (auto Entry : EntryList) {
CompileRIP(Thread, Entry);
}
LogMan::Msg::D("Done", EntryList.size());
}
struct ExecutionThreadHandler {
@@ -558,7 +437,7 @@ namespace FEXCore::Context {
static void *ThreadHandler(void* Data) {
ExecutionThreadHandler *Handler = reinterpret_cast<ExecutionThreadHandler*>(Data);
Handler->This->ExecutionThread(Handler->Thread);
free(Handler);
FEXCore::Allocator::free(Handler);
return nullptr;
}
@@ -566,7 +445,7 @@ namespace FEXCore::Context {
InitializeThreadData(Thread);
// This will create the execution thread but it won't actually start executing
ExecutionThreadHandler *Arg = reinterpret_cast<ExecutionThreadHandler*>(malloc(sizeof(ExecutionThreadHandler)));
ExecutionThreadHandler *Arg = reinterpret_cast<ExecutionThreadHandler*>(FEXCore::Allocator::malloc(sizeof(ExecutionThreadHandler)));
Arg->This = this;
Arg->Thread = Thread;
Thread->ExecutionThread = FEXCore::Threads::Thread::Create(ThreadHandler, Arg);
@@ -653,7 +532,7 @@ namespace FEXCore::Context {
std::lock_guard<std::mutex> lk(ThreadCreationMutex);
auto It = std::find(Threads.begin(), Threads.end(), Thread);
LogMan::Throw::A(It != Threads.end(), "Thread wasn't in Threads");
LOGMAN_THROW_A(It != Threads.end(), "Thread wasn't in Threads");
Threads.erase(It);
}
@@ -735,6 +614,8 @@ namespace FEXCore::Context {
Thread->OpDispatcher->BeginFunction(GuestRIP, CodeBlocks);
uint8_t GPRSize = Config.Is64BitMode ? 8 : 4;
for (size_t j = 0; j < CodeBlocks->size(); ++j) {
FEXCore::Frontend::Decoder::DecodedBlocks const &Block = CodeBlocks->at(j);
// Set the block entry point
@@ -749,8 +630,7 @@ namespace FEXCore::Context {
uint64_t InstsInBlock = Block.NumInstructions;
if (Block.HasInvalidInstruction) {
uint8_t GPRSize = Config.Is64BitMode ? 8 : 4;
Thread->OpDispatcher->_ExitFunction(Thread->OpDispatcher->_Constant(GPRSize * 8, Block.Entry));
Thread->OpDispatcher->_ExitFunction(Thread->OpDispatcher->_EntrypointOffset(Block.Entry - GuestRIP, GPRSize));
break;
}
@@ -775,7 +655,7 @@ namespace FEXCore::Context {
Thread->OpDispatcher->SetCurrentCodeBlock(CodeWasChangedBlock);
Thread->OpDispatcher->_RemoveCodeEntry();
Thread->OpDispatcher->_ExitFunction(Thread->OpDispatcher->_Constant(Block.Entry + BlockInstructionsLength));
Thread->OpDispatcher->_ExitFunction(Thread->OpDispatcher->_EntrypointOffset(Block.Entry + BlockInstructionsLength - GuestRIP, GPRSize));
auto NextOpBlock = Thread->OpDispatcher->CreateNewCodeBlockAfter(CurrentBlock);
@@ -786,12 +666,16 @@ namespace FEXCore::Context {
if (TableInfo->OpcodeDispatcher) {
auto Fn = TableInfo->OpcodeDispatcher;
Thread->OpDispatcher->HandledLock = false;
Thread->OpDispatcher->ResetDecodeFailure();
std::invoke(Fn, Thread->OpDispatcher, DecodedInfo);
if (Thread->OpDispatcher->HadDecodeFailure()) {
HadDispatchError = true;
}
else {
LogMan::Throw::A(Thread->OpDispatcher->HandledLock == IsLocked, "Missing LOCK HANDLER at 0x%lx{'%s'}\n", Block.Entry + BlockInstructionsLength, TableInfo->Name);
if (Thread->OpDispatcher->HandledLock != IsLocked) {
HadDispatchError = true;
LogMan::Msg::E("Missing LOCK HANDLER at 0x%lx{'%s'}", Block.Entry + BlockInstructionsLength, TableInfo->Name);
}
BlockInstructionsLength += DecodedInfo->InstSize;
TotalInstructionsLength += DecodedInfo->InstSize;
++TotalInstructions;
@@ -807,13 +691,13 @@ namespace FEXCore::Context {
if (TotalInstructions == 0) {
// Couldn't handle any instruction in op dispatcher
Thread->OpDispatcher->ResetWorkingList();
return { nullptr, nullptr, 0, 0, 0, 0};
return { nullptr, nullptr, 0, 0, 0, 0 };
}
else {
uint8_t GPRSize = Config.Is64BitMode ? 8 : 4;
// We had some instructions. Early exit
Thread->OpDispatcher->_ExitFunction(Thread->OpDispatcher->_Constant(GPRSize * 8, Block.Entry + BlockInstructionsLength));
Thread->OpDispatcher->_ExitFunction(Thread->OpDispatcher->_EntrypointOffset(Block.Entry + BlockInstructionsLength - GuestRIP, GPRSize));
break;
}
}
@@ -870,7 +754,7 @@ namespace FEXCore::Context {
out.seekg(0);
auto reparsed = IR::Parse(&out);
if (reparsed == nullptr) {
LogMan::Msg::A("Failed to parse ir\n");
LOGMAN_MSG_A("Failed to parse ir\n");
} else {
std::stringstream out2;
auto NewIR2 = reparsed->ViewIR();
@@ -878,7 +762,7 @@ namespace FEXCore::Context {
if (out.str() != out2.str()) {
LogMan::Msg::I("one:\n %s", out.str().c_str());
LogMan::Msg::I("two:\n %s", out2.str().c_str());
LogMan::Msg::A("Parsed ir doesn't match\n");
LOGMAN_MSG_A("Parsed ir doesn't match\n");
}
delete reparsed;
}
@@ -905,6 +789,41 @@ namespace FEXCore::Context {
return {IRList, RAData.release(), TotalInstructions, TotalInstructionsLength, Thread->FrontendDecoder->DecodedMinAddress, Thread->FrontendDecoder->DecodedMaxAddress - Thread->FrontendDecoder->DecodedMinAddress };
}
AOTIRInlineEntry *AOTIRInlineIndex::GetInlineEntry(uint64_t DataOffset) {
uintptr_t This = (uintptr_t)this;
return (AOTIRInlineEntry*)(This + DataBase + DataOffset);
}
AOTIRInlineEntry *AOTIRInlineIndex::Find(uint64_t GuestStart) {
ssize_t l = 0;
ssize_t r = Count - 1;
while (l <= r) {
size_t m = l + (r - l) / 2;
if (Entries[m].GuestStart == GuestStart)
return GetInlineEntry(Entries[m].DataOffset);
else if (Entries[m].GuestStart < GuestStart)
l = m + 1;
else
r = m - 1;
}
return nullptr;
}
IR::RegisterAllocationData *AOTIRInlineEntry::GetRAData() {
return (IR::RegisterAllocationData *)InlineData;
}
IR::IRListView *AOTIRInlineEntry::GetIRData() {
auto RAData = GetRAData();
auto Offset = RAData->Size(RAData->MapCount);
return (IR::IRListView *)&InlineData[Offset];
}
std::tuple<void *, FEXCore::IR::IRListView *, FEXCore::Core::DebugData *, FEXCore::IR::RegisterAllocationData *, bool, uint64_t, uint64_t> Context::CompileCode(FEXCore::Core::InternalThreadState *Thread, uint64_t GuestRIP) {
FEXCore::IR::IRListView *IRList {};
FEXCore::Core::DebugData *DebugData {};
@@ -928,35 +847,53 @@ namespace FEXCore::Context {
GeneratedIR = false;
}
{
std::lock_guard<std::mutex> lk(AOTIRCacheLock);
auto file = AddrToFile.lower_bound(GuestRIP);
if (file != AddrToFile.begin()) {
--file;
if (!file->second.ContainsCode) {
file->second.ContainsCode = true;
FilesWithCode[file->second.fileid] = file->second.filename;
}
}
}
if (IRList == nullptr && Config.AOTIRLoad) {
std::lock_guard<std::mutex> lk(AOTIRCacheLock);
auto file = AddrToFile.lower_bound(GuestRIP);
if (file != AddrToFile.begin()) {
--file;
auto Mod = (decltype(AOTIRCache)::value_type::second_type*) file->second.CachedFileEntry;
auto Mod = (AOTIRInlineIndex*)file->second.CachedFileEntry;
if (Mod == nullptr) {
file->second.CachedFileEntry = Mod = &AOTIRCache[file->second.fileid];
file->second.CachedFileEntry = Mod = AOTIRCache[file->second.fileid].Array;
}
auto AOTEntry = Mod->find(GuestRIP - file->second.Start + file->second.Offset);
if (Mod != nullptr)
{
auto AOTEntry = Mod->Find(GuestRIP - file->second.Start + file->second.Offset);
if (AOTEntry != Mod->end()) {
// verify hash
auto MappedStart = AOTEntry->second.start + file->second.Start - file->second.Offset;
auto hash = fasthash64((void*)MappedStart, AOTEntry->second.len, 0);
if (hash == AOTEntry->second.crc) {
IRList = AOTEntry->second.IR;
//LogMan::Msg::D("using %s + %lx -> %lx\n", file->second.fileid.c_str(), AOTEntry->first, GuestRIP);
// relocate
IRList->GetHeader()->Entry = GuestRIP;
if (AOTEntry) {
// verify hash
auto MappedStart = GuestRIP;
auto hash = XXH3_64bits((void*)MappedStart, AOTEntry->GuestLength);
if (hash == AOTEntry->GuestHash) {
IRList = AOTEntry->GetIRData();
//LogMan::Msg::D("using %s + %lx -> %lx\n", file->second.fileid.c_str(), AOTEntry->first, GuestRIP);
RAData = AOTEntry->second.RAData;
DebugData = new FEXCore::Core::DebugData();
StartAddr = MappedStart;
Length = AOTEntry->second.len;
GeneratedIR = true;
RAData = AOTEntry->GetRAData();;
DebugData = new FEXCore::Core::DebugData();
StartAddr = MappedStart;
Length = AOTEntry->GuestLength;
GeneratedIR = true;
} else {
LogMan::Msg::I("AOTIR: hash check failed %lx\n", MappedStart);
}
} else {
//LogMan::Msg::I("AOTIR: Failed to find %lx, %lx, %s\n", GuestRIP, GuestRIP - file->second.Start + file->second.Offset, file->second.fileid.c_str());
}
}
}
@@ -984,91 +921,63 @@ namespace FEXCore::Context {
GeneratedIR = true;
}
if (IRList == nullptr) {
return { nullptr, nullptr, nullptr, nullptr, false, 0, 0 };
}
// Attempt to get the CPU backend to compile this code
return { Thread->CPUBackend->CompileCode(IRList, DebugData, RAData), IRList, DebugData, RAData, GeneratedIR, StartAddr, Length};
return { Thread->CPUBackend->CompileCode(GuestRIP, IRList, DebugData, RAData), IRList, DebugData, RAData, GeneratedIR, StartAddr, Length};
}
bool Context::LoadAOTIRCache(std::istream &stream) {
std::lock_guard<std::mutex> lk(AOTIRCacheLock);
static bool readAll(int fd, void *data, size_t size) {
int rv = read(fd, data, size);
if (rv != size)
return false;
else
return true;
}
bool Context::LoadAOTIRCache(int streamfd) {
uint64_t tag;
stream.read((char*)&tag, sizeof(tag));
if (!stream || tag != 0xDEADBEEFC0D30002)
if (!readAll(streamfd, (char*)&tag, sizeof(tag)) || tag != 0xDEADBEEFC0D30003)
return false;
std::string Module;
uint64_t ModSize;
if (!readAll(streamfd, (char*)&ModSize, sizeof(ModSize)))
return false;
uint64_t ModCount;
stream.read((char*)&ModCount, sizeof(ModCount));
if (!stream)
Module.resize(ModSize);
if (!readAll(streamfd, (char*)&Module[0], Module.size()))
return false;
for (int ModIndex = 0; ModIndex < ModCount; ModIndex++) {
std::string Module;
uint64_t ModSize;
stream.read((char*)&ModSize, sizeof(ModSize));
if (!stream)
return false;
struct stat fileinfo;
if (fstat(streamfd, &fileinfo) < 0)
return false;
size_t Size = (fileinfo.st_size + 4095) & ~4095;
Module.resize(ModSize);
stream.read((char*)&Module[0], Module.size());
if (!stream)
return false;
void *FilePtr = FEXCore::Allocator::mmap(nullptr, Size, PROT_READ, MAP_SHARED, streamfd, 0);
auto &Mod = AOTIRCache[Module];
if (FilePtr == MAP_FAILED)
return false;
uint64_t FnCount;
stream.read((char*)&FnCount, sizeof(FnCount));
if (!stream)
return false;
auto Array = (AOTIRInlineIndex *)((char*)FilePtr + sizeof(tag) + sizeof(ModSize) + ((ModSize+31) & ~31));
LogMan::Msg::D("AOTIR: Module %s has %ld functions", Module.c_str(), FnCount);
for (int FnIndex = 0; FnIndex < FnCount; FnIndex++) {
uint64_t addr, start, crc, len;
stream.read((char*)&addr, sizeof(addr));
if (!stream)
return false;
AOTIRCache.insert({Module, {Array, FilePtr, Size}});
stream.read((char*)&start, sizeof(start));
if (!stream)
return false;
stream.read((char*)&len, sizeof(len));
if (!stream)
return false;
stream.read((char*)&crc, sizeof(crc));
if (!stream)
return false;
auto IR = new IR::IRListView(stream);
if (!stream) {
delete IR;
return false;
}
uint64_t RASize;
stream.read((char*)&RASize, sizeof(RASize));
if (!stream) {
delete IR;
return false;
}
IR::RegisterAllocationData *RAData = (IR::RegisterAllocationData *)malloc(IR::RegisterAllocationData::Size(RASize));
RAData->MapCount = RASize;
stream.read((char*)&RAData->Map[0], sizeof(RAData->Map[0]) * RASize);
if (!stream) {
delete IR;
return false;
}
stream.read((char*)&RAData->SpillSlotCount, sizeof(RAData->SpillSlotCount));
if (!stream) {
delete IR;
return false;
}
IR->IsShared = true;
RAData->IsShared = true;
Mod.insert({addr, {start, len, crc, IR, RAData}});
}
}
LogMan::Msg::D("AOTIR: Module %s has %ld functions", Module.c_str(), Array->Count);
return true;
}
void Context::WriteFilesWithCode(std::function<void(const std::string& fileid, const std::string& filename)> Writer) {
std::lock_guard<std::mutex> lk(AOTIRCacheLock);
for( const auto &File: FilesWithCode) {
Writer(File.first, File.second);
}
}
bool Context::WriteAOTIRCache(std::function<std::unique_ptr<std::ostream>(const std::string&)> CacheWriter) {
@@ -1076,7 +985,7 @@ namespace FEXCore::Context {
bool rv = true;
for (auto AOTModule: AOTIRCache) {
for (auto AOTModule: AOTIRCaptureCache) {
if (AOTModule.second.size() == 0) {
continue;
}
@@ -1085,35 +994,74 @@ namespace FEXCore::Context {
if (!*stream) {
rv = false;
}
uint64_t tag = 0xDEADBEEFC0D30002;
uint64_t tag = 0xDEADBEEFC0D30003;
stream->write((char*)&tag, sizeof(tag));
uint64_t ModCount = 1;
stream->write((char*)&ModCount, sizeof(ModCount));
auto ModSize = AOTModule.first.size();
stream->write((char*)&ModSize, sizeof(ModSize));
stream->write((char*)&AOTModule.first[0], ModSize);
auto Skip = ((ModSize + 31) & ~31) - ModSize;
char Zero = 0;
for (int i = 0; i < Skip; i++)
stream->write(&Zero, 1);
// AOTIRInlineIndex
auto FnCount = AOTModule.second.size();
stream->write((char*)&FnCount, sizeof(FnCount));
size_t DataBase = sizeof(FnCount) + sizeof(DataBase) + FnCount * sizeof(AOTIRInlineIndexEntry);
stream->write((char*)&DataBase, sizeof(DataBase));
size_t DataOffset = 0;
for (auto entry: AOTModule.second) {
//AOTIRInlineIndexEntry
// GuestStart
stream->write((char*)&entry.first, sizeof(entry.first));
stream->write((char*)&entry.second.start, sizeof(entry.second.start));
stream->write((char*)&entry.second.len, sizeof(entry.second.len));
// DataOffset
stream->write((char*)&DataOffset, sizeof(DataOffset));
DataOffset += sizeof(entry.second.crc);
DataOffset += sizeof(entry.second.len);
DataOffset += entry.second.RAData->Size(entry.second.RAData->MapCount);
DataOffset += entry.second.IR->GetInlineSize();
}
// AOTIRInlineEntry
for (auto entry: AOTModule.second) {
//GuestHash
stream->write((char*)&entry.second.crc, sizeof(entry.second.crc));
//GuestLength
stream->write((char*)&entry.second.len, sizeof(entry.second.len));
// RAData (inline)
stream->write((char*)entry.second.RAData, entry.second.RAData->Size(entry.second.RAData->MapCount));
// IRData (inline)
entry.second.IR->Serialize(*stream);
uint64_t RASize = entry.second.RAData->MapCount;
stream->write((char*)&RASize, sizeof(RASize));
stream->write((char*)&entry.second.RAData->Map[0], sizeof(entry.second.RAData->Map[0]) * RASize);
stream->write((char*)&entry.second.RAData->SpillSlotCount, sizeof(entry.second.RAData->SpillSlotCount));
}
}
return rv;
}
void Context::CompileBlockJit(FEXCore::Core::CpuStateFrame *Frame, uint64_t GuestRIP) {
auto NewBlock = CompileBlock(Frame, GuestRIP);
if (NewBlock == 0) {
LogMan::Msg::E("CompileBlockJit: Failed to compile code %lX - aborting process", GuestRIP);
abort();
}
}
uintptr_t Context::CompileBlock(FEXCore::Core::CpuStateFrame *Frame, uint64_t GuestRIP) {
auto Thread = Frame->Thread;
@@ -1166,7 +1114,11 @@ namespace FEXCore::Context {
Length = _Length;
}
LogMan::Throw::A(CodePtr != nullptr, "Failed to compile code %lX", GuestRIP);
if (CodePtr == nullptr) {
if (DecrementRefCount)
--Thread->CompileBlockReentrantRefCount;
return 0;
}
// The core managed to compile the code.
#if ENABLE_JITSYMBOLS
@@ -1187,19 +1139,19 @@ namespace FEXCore::Context {
Thread->LocalIRCache.insert({GuestRIP, std::move(Entry)});
// Add to AOT cache if aot generation is enabled
if (Config.AOTIRCapture && RAData) {
if ((Config.AOTIRCapture() || Config.AOTIRGenerate()) && RAData) {
std::lock_guard<std::mutex> lk(AOTIRCacheLock);
RAData->IsShared = true;
IRList->IsShared = true;
IRList->SetShared(true);
auto hash = fasthash64((void*)StartAddr, Length, 0);
auto hash = XXH3_64bits((void*)StartAddr, Length);
auto file = AddrToFile.lower_bound(StartAddr);
if (file != AddrToFile.begin()) {
--file;
if (file->second.Start <= StartAddr && (file->second.Start + file->second.Len) >= (StartAddr + Length)) {
AOTIRCache[file->second.fileid].insert({GuestRIP - file->second.Start + file->second.Offset, {StartAddr - file->second.Start + file->second.Offset, Length, hash, IRList, RAData}});
AOTIRCaptureCache[file->second.fileid].insert({GuestRIP - file->second.Start + file->second.Offset, {StartAddr - file->second.Start + file->second.Offset, Length, hash, IRList, RAData}});
}
}
}
@@ -1341,7 +1293,7 @@ namespace FEXCore::Context {
auto base_filename = std::filesystem::path(filename).filename().string();
if (base_filename.size()) {
auto filename_hash = fasthash64(filename.c_str(), filename.size(), 0xBAADF00D);
auto filename_hash = XXH3_64bits(filename.c_str(), filename.size());
auto fileid = base_filename + "-" + std::to_string(filename_hash) + "-";
@@ -1351,19 +1303,28 @@ namespace FEXCore::Context {
fileid += Config.ABILocalFlags ? "L" : "l";
fileid += Config.ABINoPF ? "p" : "P";
AddrToFile.insert({ Base, { Base, Size, Offset, fileid, nullptr } });
std::lock_guard<std::mutex> lk(AOTIRCacheLock);
AddrToFile.insert({ Base, { Base, Size, Offset, fileid, filename, nullptr, false} });
if (Config.AOTIRLoad && !AOTIRCache.contains(fileid) && AOTIRLoader) {
auto stream = AOTIRLoader(fileid);
if (*stream) {
LoadAOTIRCache(*stream);
auto streamfd = AOTIRLoader(fileid);
if (streamfd != -1) {
LoadAOTIRCache(streamfd);
close(streamfd);
}
}
}
}
void Context::RemoveNamedRegion(uintptr_t Base, uintptr_t Size) {
std::lock_guard<std::mutex> lk(AOTIRCacheLock);
// TODO: Support partial removing
AddrToFile.erase(Base);
}
void ConfigureAOTGen(FEXCore::Context::Context *CTX, std::set<uint64_t> *ExternalBranches, uint64_t SectionMaxAddress) {
CTX->ParentThread->FrontendDecoder->SetExternalBranches(ExternalBranches);
CTX->ParentThread->FrontendDecoder->SetSectionMaxAddress(SectionMaxAddress);
}
}
@@ -67,6 +67,7 @@ Arm64Dispatcher::Arm64Dispatcher(FEXCore::Context::Context *ctx, FEXCore::Core::
// We want to ensure that we are 16 byte aligned at the top of this loop
Align16B();
aarch64::Label FullLookup{};
aarch64::Label CallBlock{};
aarch64::Label LoopTop{};
aarch64::Label ExitSpillSRA{};
aarch64::Label ThreadPauseHandler{};
@@ -79,16 +80,19 @@ Arm64Dispatcher::Arm64Dispatcher(FEXCore::Context::Context *ctx, FEXCore::Core::
ldr(x2, MemOperand(STATE, offsetof(FEXCore::Core::CpuStateFrame, State.rip)));
auto RipReg = x2;
if (!config.ExecuteBlocksWithCall) {
// L1 Cache
ldr(x0, &l_L1Ptr);
// L1 Cache
ldr(x0, &l_L1Ptr);
and_(x3, RipReg, LookupCache::L1_ENTRIES_MASK);
add(x0, x0, Operand(x3, Shift::LSL, 4));
ldp(x1, x0, MemOperand(x0));
cmp(x0, RipReg);
b(&FullLookup, Condition::ne);
br(x1);
and_(x3, RipReg, LookupCache::L1_ENTRIES_MASK);
add(x0, x0, Operand(x3, Shift::LSL, 4));
ldp(x3, x0, MemOperand(x0));
cmp(x0, RipReg);
b(&FullLookup, Condition::ne);
if (!config.ExecuteBlocksWithCall) {
br(x3);
} else {
b(&CallBlock);
}
// L1C check failed, do a full lookup
@@ -136,40 +140,37 @@ Arm64Dispatcher::Arm64Dispatcher(FEXCore::Context::Context *ctx, FEXCore::Core::
// If we've made it here then we have a real compiled block
{
// update L1 cache
ldr(x0, &l_L1Ptr);
and_(x1, RipReg, LookupCache::L1_ENTRIES_MASK);
add(x0, x0, Operand(x1, Shift::LSL, 4));
stp(x3, x2, MemOperand(x0));
// Jump to the block
if (!config.ExecuteBlocksWithCall) {
// update L1 cache
ldr(x0, &l_L1Ptr);
and_(x1, RipReg, LookupCache::L1_ENTRIES_MASK);
add(x0, x0, Operand(x1, Shift::LSL, 4));
stp(x3, x2, MemOperand(x0));
br(x3);
} else {
bind(&CallBlock);
mov(x0, STATE);
blr(x3);
}
}
if (config.ExecuteBlocksWithCall) {
// Interpreter continues execution here
if (CTX->GetGdbServerStatus()) {
// If we have a gdb server running then run in a less efficient mode that checks if we need to exit
// This happens when single stepping
if (CTX->GetGdbServerStatus()) {
// If we have a gdb server running then run in a less efficient mode that checks if we need to exit
// This happens when single stepping
static_assert(sizeof(CTX->Config.RunningMode) == 4, "This is expected to be size of 4");
ldr(x0, &l_CTX);
ldr(w0, MemOperand(x0, offsetof(FEXCore::Context::Context, Config.RunningMode)));
// If the value == 0 then branch to the top
cbz(x0, &LoopTop);
// Else we need to pause now
b(&ThreadPauseHandler);
}
else {
// Unconditionally loop to the top
// We will only stop on error when compiling a block or signal
b(&LoopTop);
static_assert(sizeof(CTX->Config.RunningMode) == 4, "This is expected to be size of 4");
ldr(x0, &l_CTX);
ldr(w0, MemOperand(x0, offsetof(FEXCore::Context::Context, Config.RunningMode)));
// If the value == 0 then branch to the top
cbz(x0, &LoopTop);
// Else we need to pause now
b(&ThreadPauseHandler);
} else {
// Unconditionally loop to the top
// We will only stop on error when compiling a block or signal
b(&LoopTop);
}
}
}
}
@@ -350,7 +351,7 @@ void InterpreterCore::CreateAsmDispatch(FEXCore::Context::Context *ctx, FEXCore:
DispatcherConfig config;
config.ExecuteBlocksWithCall = true;
Dispatcher = new Arm64Dispatcher(ctx, Thread, config);
Dispatcher = std::make_unique<Arm64Dispatcher>(ctx, Thread, config);
DispatchPtr = Dispatcher->DispatchPtr;
CallbackPtr = Dispatcher->CallbackPtr;
@@ -108,7 +108,7 @@ bool Dispatcher::HandleGuestSignal(int Signal, void *info, void *ucontext, Guest
if (GuestAction->sa_flags & SA_SIGINFO) {
if (SRAEnabled) {
if (!IsAddressInJITCode(ArchHelpers::Context::GetPc(ucontext), false)) {
LogMan::Throw::A(!IsAddressInJITCode(ArchHelpers::Context::GetPc(ucontext), true), "Signals in dispatcher have unsynchronized context");
LOGMAN_THROW_A(!IsAddressInJITCode(ArchHelpers::Context::GetPc(ucontext), true), "Signals in dispatcher have unsynchronized context");
} else {
// We are in jit, SRA must be spilled
SpillSRA(ucontext);
@@ -121,7 +121,11 @@ bool Dispatcher::HandleGuestSignal(int Signal, void *info, void *ucontext, Guest
NewGuestSP -= sizeof(FEXCore::x86_64::ucontext_t);
uint64_t UContextLocation = NewGuestSP;
NewGuestSP -= sizeof(siginfo_t);
uint64_t SigInfoLocation = NewGuestSP;
FEXCore::x86_64::ucontext_t *guest_uctx = reinterpret_cast<FEXCore::x86_64::ucontext_t*>(UContextLocation);
siginfo_t *guest_siginfo = reinterpret_cast<siginfo_t*>(SigInfoLocation);
// We have extended float information
guest_uctx->uc_flags |= FEXCore::x86_64::UC_FP_XSTATE;
@@ -169,8 +173,21 @@ bool Dispatcher::HandleGuestSignal(int Signal, void *info, void *ucontext, Guest
guest_uctx->uc_stack.ss_sp = GuestStack->ss_sp;
guest_uctx->uc_stack.ss_size = GuestStack->ss_size;
// XXX: siginfo_t(RSI)
Frame->State.gregs[X86State::REG_RSI] = 0x4142434445460000;
// siginfo_t
siginfo_t *HostSigInfo = reinterpret_cast<siginfo_t*>(info);
guest_siginfo->si_signo = Signal;
switch (Signal) {
case SIGSEGV:
case SIGBUS:
guest_siginfo->si_code = HostSigInfo->si_code;
guest_siginfo->si_errno = HostSigInfo->si_errno;
// Macro expansion to get the si_addr
guest_siginfo->si_addr = HostSigInfo->si_addr;
break;
default: LogMan::Msg::D("Unhandled siginfo_t signal: %d", Signal); break;
}
Frame->State.gregs[X86State::REG_RSI] = SigInfoLocation;
Frame->State.gregs[X86State::REG_RDX] = UContextLocation;
}
else {
@@ -203,7 +220,7 @@ bool Dispatcher::HandleGuestSignal(int Signal, void *info, void *ucontext, Guest
else {
NewGuestSP -= 4;
*(uint32_t*)NewGuestSP = CTX->X86CodeGen.SignalReturn;
LogMan::Throw::A(CTX->X86CodeGen.SignalReturn < 0x1'0000'0000ULL, "This needs to be below 4GB");
LOGMAN_THROW_A(CTX->X86CodeGen.SignalReturn < 0x1'0000'0000ULL, "This needs to be below 4GB");
Frame->State.gregs[X86State::REG_RSP] = NewGuestSP;
}
@@ -247,7 +264,7 @@ bool Dispatcher::HandleSignalPause(int Signal, void *info, void *ucontext) {
} else {
if (SRAEnabled) {
// We are in non-jit, SRA is already spilled
LogMan::Throw::A(!IsAddressInJITCode(ArchHelpers::Context::GetPc(ucontext), true), "Signals in dispatcher have unsynchronized context");
LOGMAN_THROW_A(!IsAddressInJITCode(ArchHelpers::Context::GetPc(ucontext), true), "Signals in dispatcher have unsynchronized context");
}
ArchHelpers::Context::SetPc(ucontext, ThreadPauseHandlerAddress);
}
@@ -282,7 +299,7 @@ bool Dispatcher::HandleSignalPause(int Signal, void *info, void *ucontext) {
} else {
if (SRAEnabled) {
// We are in non-jit, SRA is already spilled
LogMan::Throw::A(!IsAddressInJITCode(ArchHelpers::Context::GetPc(ucontext), true), "Signals in dispatcher have unsynchronized context");
LOGMAN_THROW_A(!IsAddressInJITCode(ArchHelpers::Context::GetPc(ucontext), true), "Signals in dispatcher have unsynchronized context");
}
ArchHelpers::Context::SetPc(ucontext, ThreadStopHandlerAddress);
}
@@ -306,14 +323,14 @@ bool Dispatcher::HandleSignalPause(int Signal, void *info, void *ucontext) {
}
uint64_t Dispatcher::GetCompileBlockPtr() {
using ClassPtrType = uintptr_t (FEXCore::Context::Context::*)(FEXCore::Core::CpuStateFrame *, uint64_t);
using ClassPtrType = void (FEXCore::Context::Context::*)(FEXCore::Core::CpuStateFrame *, uint64_t);
union PtrCast {
ClassPtrType ClassPtr;
uintptr_t Data;
};
PtrCast CompileBlockPtr;
CompileBlockPtr.ClassPtr = &FEXCore::Context::Context::CompileBlock;
CompileBlockPtr.ClassPtr = &FEXCore::Context::Context::CompileBlockJit;
return CompileBlockPtr.Data;
}
@@ -18,6 +18,7 @@ struct DispatcherConfig {
class Dispatcher {
public:
virtual ~Dispatcher() = default;
CPUBackend::AsmDispatch DispatchPtr;
CPUBackend::JITCallback CallbackPtr;
FEXCore::Context::Context::IntCallbackReturn ReturnPtr;
@@ -81,4 +82,4 @@ private:
std::vector<std::tuple<uint64_t, uint64_t>> CodeBuffers; // Start, End
};
}
}
@@ -12,7 +12,7 @@ static constexpr size_t MAX_DISPATCHER_CODE_SIZE = 4096;
X86Dispatcher::X86Dispatcher(FEXCore::Context::Context *ctx, FEXCore::Core::InternalThreadState *Thread, DispatcherConfig &config)
: Dispatcher(ctx, Thread)
, Xbyak::CodeGenerator(MAX_DISPATCHER_CODE_SIZE) {
, Xbyak::CodeGenerator(MAX_DISPATCHER_CODE_SIZE, nullptr, this) {
using namespace Xbyak;
using namespace Xbyak::util;
@@ -66,6 +66,7 @@ X86Dispatcher::X86Dispatcher(FEXCore::Context::Context *ctx, FEXCore::Core::Inte
Label LoopTop;
Label FullLookup;
Label CallBlock;
Label NoBlock;
Label ExitBlock;
Label ThreadPauseHandler;
@@ -77,17 +78,20 @@ X86Dispatcher::X86Dispatcher(FEXCore::Context::Context *ctx, FEXCore::Core::Inte
// Load our RIP
mov(rdx, qword [STATE + offsetof(FEXCore::Core::CPUState, rip)]);
if (!config.ExecuteBlocksWithCall)
{
// L1 Cache
mov(r13, Thread->LookupCache->GetL1Pointer());
mov(rax, rdx);
// L1 Cache
mov(r13, Thread->LookupCache->GetL1Pointer());
mov(rax, rdx);
and_(rax, LookupCache::L1_ENTRIES_MASK);
shl(rax, 4);
cmp(qword[r13 + rax + 8], rdx);
jne(FullLookup);
and_(rax, LookupCache::L1_ENTRIES_MASK);
shl(rax, 4);
cmp(qword[r13 + rax + 8], rdx);
jne(FullLookup);
if (!config.ExecuteBlocksWithCall) {
jmp(qword[r13 + rax + 0]);
} else {
mov(rax, qword[r13 + rax + 0]);
jmp(CallBlock);
}
L(FullLookup);
@@ -122,19 +126,19 @@ X86Dispatcher::X86Dispatcher(FEXCore::Context::Context *ctx, FEXCore::Core::Inte
je(NoBlock);
// Update L1
if (config.ExecuteBlocksWithCall) {
mov(r13, Thread->LookupCache->GetL1Pointer());
mov(rcx, rdx);
and_(rcx, LookupCache::L1_ENTRIES_MASK);
shl(rcx, 1);
mov(qword[r13 + rcx*8 + 8], rdx);
mov(qword[r13 + rcx*8 + 0], rax);
}
mov(r13, Thread->LookupCache->GetL1Pointer());
mov(rcx, rdx);
and_(rcx, LookupCache::L1_ENTRIES_MASK);
shl(rcx, 1);
mov(qword[r13 + rcx*8 + 8], rdx);
mov(qword[r13 + rcx*8 + 0], rax);
// Real block if we made it here
if (!config.ExecuteBlocksWithCall) {
jmp(rax);
} else {
L(CallBlock);
mov(rdi, STATE);
call(rax);
@@ -177,19 +181,10 @@ X86Dispatcher::X86Dispatcher(FEXCore::Context::Context *ctx, FEXCore::Core::Inte
{
L(NoBlock);
using ClassPtrType = uintptr_t (FEXCore::Context::Context::*)(FEXCore::Core::CpuStateFrame *, uint64_t);
union PtrCast {
ClassPtrType ClassPtr;
uintptr_t Data;
};
PtrCast Ptr;
Ptr.ClassPtr = &FEXCore::Context::Context::CompileBlock;
// {rdi, rsi, rdx}
mov(rdi, reinterpret_cast<uint64_t>(CTX));
mov(rsi, STATE);
mov(rax, Ptr.Data);
mov(rax, GetCompileBlockPtr());
call(rax);
@@ -312,7 +307,7 @@ void InterpreterCore::CreateAsmDispatch(FEXCore::Context::Context *ctx, FEXCore:
DispatcherConfig config;
config.ExecuteBlocksWithCall = true;
Dispatcher = new X86Dispatcher(ctx, Thread, config);
Dispatcher = std::make_unique<X86Dispatcher>(ctx, Thread, config);
DispatchPtr = Dispatcher->DispatchPtr;
CallbackPtr = Dispatcher->CallbackPtr;
@@ -2,16 +2,26 @@
#include "Interface/Core/Dispatcher/Dispatcher.h"
#include <FEXCore/Utils/Allocator.h>
#define XBYAK64
#include <xbyak/xbyak.h>
namespace FEXCore::CPU {
class X86Dispatcher final : public Dispatcher, public Xbyak::CodeGenerator {
class X86Dispatcher final : public Dispatcher, public Xbyak::CodeGenerator, public Xbyak::Allocator {
public:
X86Dispatcher(FEXCore::Context::Context *ctx, FEXCore::Core::InternalThreadState *Thread, DispatcherConfig &config);
virtual ~X86Dispatcher() override;
// Xbyak::Allocator
Xbyak::uint8 *alloc(size_t size) override { Size = size; return reinterpret_cast<uint8_t*>(FEXCore::Allocator::mmap(nullptr, size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0)); }
void free(Xbyak::uint8 *p) override { FEXCore::Allocator::munmap(p, Size); }
bool useProtect() const override { return false; }
private:
size_t Size{};
};
}
}
+51 -18
View File
@@ -15,6 +15,7 @@ $end_info$
#include <FEXCore/Core/X86Enums.h>
#include <FEXCore/Debug/X86Tables.h>
#include <FEXCore/Utils/LogManager.h>
#include <set>
namespace FEXCore::Frontend {
using namespace FEXCore::X86Tables;
@@ -124,7 +125,7 @@ Decoder::Decoder(FEXCore::Context::Context *ctx)
uint8_t Decoder::ReadByte() {
uint8_t Byte = InstStream[InstructionSize];
LogMan::Throw::A(InstructionSize < MAX_INST_SIZE, "Max instruction size exceeded!");
LOGMAN_THROW_A(InstructionSize < MAX_INST_SIZE, "Max instruction size exceeded!");
Instruction[InstructionSize] = Byte;
InstructionSize++;
return Byte;
@@ -141,7 +142,7 @@ uint64_t Decoder::ReadData(uint8_t Size) {
}
if (Size > sizeof(uint64_t)) {
LogMan::Msg::A("Unknown data size to read");
LOGMAN_MSG_A("Unknown data size to read");
return 0;
}
@@ -284,7 +285,7 @@ void Decoder::DecodeModRM_64(X86Tables::DecodedOperand *Operand, X86Tables::ModR
Operand->TypeSIB.Base = MapModRMToReg(DecodeInst->Flags & DecodeFlags::FLAG_REX_XGPR_B ? 1 : 0, SIB.base, false, false, false, false, ModRM.mod == 0 ? 0b101 : 16);
uint64_t Literal {0};
LogMan::Throw::A(Displacement <= 4, "Number of bytes should be <= 4 for literal src");
LOGMAN_THROW_A(Displacement <= 4, "Number of bytes should be <= 4 for literal src");
Literal = ReadData(Displacement);
if (Displacement == 1) {
@@ -343,7 +344,7 @@ bool Decoder::NormalOp(FEXCore::X86Tables::X86InstInfo const *Info, uint16_t Op)
return false;
}
LogMan::Throw::A(!(Info->Type >= FEXCore::X86Tables::TYPE_GROUP_1 && Info->Type <= FEXCore::X86Tables::TYPE_GROUP_P),
LOGMAN_THROW_A(!(Info->Type >= FEXCore::X86Tables::TYPE_GROUP_1 && Info->Type <= FEXCore::X86Tables::TYPE_GROUP_P),
"Group Ops should have been decoded before this!");
uint8_t DestSize{};
@@ -466,7 +467,7 @@ bool Decoder::NormalOp(FEXCore::X86Tables::X86InstInfo const *Info, uint16_t Op)
}
if (HAS_NON_XMM_SUBFLAG(Info->Flags, FEXCore::X86Tables::InstFlags::FLAGS_SF_REX_IN_BYTE)) {
LogMan::Throw::A(!HasMODRM, "This instruction shouldn't have ModRM!");
LOGMAN_THROW_A(!HasMODRM, "This instruction shouldn't have ModRM!");
// If the REX is in the byte that means the lower nibble of the OP contains the destination GPR
// This also means that the destination is always a GPR on these ones
@@ -475,6 +476,9 @@ bool Decoder::NormalOp(FEXCore::X86Tables::X86InstInfo const *Info, uint16_t Op)
CurrentDest->TypeGPR.Type = DecodedOperand::TYPE_GPR;
DecodeInst->Dest.TypeGPR.HighBits = (Is8BitDest && !HasREX && (Op & 0b111) >= 0b100) || HasHighXMM;
CurrentDest->TypeGPR.GPR = MapModRMToReg(DecodeInst->Flags & DecodeFlags::FLAG_REX_XGPR_B ? 1 : 0, Op & 0b111, Is8BitDest, HasREX, false, false);
if (CurrentDest->TypeGPR.GPR == FEXCore::X86State::REG_INVALID)
return false;
}
uint8_t Bytes = Info->MoreBytes;
@@ -501,27 +505,36 @@ bool Decoder::NormalOp(FEXCore::X86Tables::X86InstInfo const *Info, uint16_t Op)
GPR.TypeGPR.HighBits = (GPR8Bit && ModRM.reg >= 0b100 && !HasREX) || HasHighXMM;
GPR.TypeGPR.GPR = MapModRMToReg(DecodeInst->Flags & DecodeFlags::FLAG_REX_XGPR_R ? 1 : 0, ModRM.reg, GPR8Bit, HasREX, HasXMMGPR, HasMMGPR);
if (GPR.TypeGPR.GPR == FEXCore::X86State::REG_INVALID)
return false;
// ModRM.mod == 0b11 == Register
// ModRM.Mod != 0b11 == Register-direct addressing
if (ModRM.mod == 0b11) {
NonGPR.TypeGPR.Type = DecodedOperand::TYPE_GPR;
NonGPR.TypeGPR.HighBits = (NonGPR8Bit && ModRM.rm >= 0b100 && !HasREX) || HasHighXMM;
NonGPR.TypeGPR.GPR = MapModRMToReg(DecodeInst->Flags & DecodeFlags::FLAG_REX_XGPR_B ? 1 : 0, ModRM.rm, NonGPR8Bit, HasREX, HasXMMNonGPR, HasMMNonGPR);
if (NonGPR.TypeGPR.GPR == FEXCore::X86State::REG_INVALID)
return false;
}
else {
auto Disp = DecodeModRMs_Disp[Has16BitAddressing];
(this->*Disp)(&NonGPR, ModRM);
}
return true;
};
size_t CurrentSrc = 0;
if (Info->Flags & FEXCore::X86Tables::InstFlags::FLAGS_MODRM) {
if (Info->Flags & FEXCore::X86Tables::InstFlags::FLAGS_SF_MOD_DST) {
ModRMOperand(DecodeInst->Src[CurrentSrc], DecodeInst->Dest, HasXMMSrc, HasXMMDst, HasMMSrc, HasMMDst, Is8BitSrc, Is8BitDest);
if (!ModRMOperand(DecodeInst->Src[CurrentSrc], DecodeInst->Dest, HasXMMSrc, HasXMMDst, HasMMSrc, HasMMDst, Is8BitSrc, Is8BitDest))
return false;
}
else {
ModRMOperand(DecodeInst->Dest, DecodeInst->Src[CurrentSrc], HasXMMDst, HasXMMSrc, HasMMDst, HasMMSrc, Is8BitDest, Is8BitSrc);
if (!ModRMOperand(DecodeInst->Dest, DecodeInst->Src[CurrentSrc], HasXMMDst, HasXMMSrc, HasMMDst, HasMMSrc, Is8BitDest, Is8BitSrc))
return false;
}
++CurrentSrc;
}
@@ -540,7 +553,7 @@ bool Decoder::NormalOp(FEXCore::X86Tables::X86InstInfo const *Info, uint16_t Op)
}
if (Bytes != 0) {
LogMan::Throw::A(Bytes <= 8, "Number of bytes should be <= 8 for literal src");
LOGMAN_THROW_A(Bytes <= 8, "Number of bytes should be <= 8 for literal src");
DecodeInst->Src[CurrentSrc].TypeLiteral.Size = Bytes;
@@ -566,7 +579,7 @@ bool Decoder::NormalOp(FEXCore::X86Tables::X86InstInfo const *Info, uint16_t Op)
DecodeInst->Src[CurrentSrc].TypeLiteral.Literal = Literal;
}
LogMan::Throw::A(Bytes == 0, "Inst at 0x%lx: 0x%04x '%s' Had an instruction of size %d with %d remaining", DecodeInst->PC, DecodeInst->OP, DecodeInst->TableInfo->Name, InstructionSize, Bytes);
LOGMAN_THROW_A(Bytes == 0, "Inst at 0x%lx: 0x%04x '%s' Had an instruction of size %d with %d remaining", DecodeInst->PC, DecodeInst->OP, DecodeInst->TableInfo->Name, InstructionSize, Bytes);
DecodeInst->InstSize = InstructionSize;
return true;
}
@@ -591,7 +604,7 @@ bool Decoder::NormalOpHeader(FEXCore::X86Tables::X86InstInfo const *Info, uint16
return false;
}
LogMan::Throw::A(Info->Type != FEXCore::X86Tables::TYPE_REX_PREFIX, "REX PREFIX should have been decoded before this!");
LOGMAN_THROW_A(Info->Type != FEXCore::X86Tables::TYPE_REX_PREFIX, "REX PREFIX should have been decoded before this!");
if (Info->Type >= FEXCore::X86Tables::TYPE_GROUP_1 &&
Info->Type <= FEXCore::X86Tables::TYPE_GROUP_11) {
@@ -647,7 +660,7 @@ bool Decoder::NormalOpHeader(FEXCore::X86Tables::X86InstInfo const *Info, uint16
3,
};
uint8_t Field = RegToField[ModRM.reg];
LogMan::Throw::A(Field != 255, "Invalid field selected!");
LOGMAN_THROW_A(Field != 255, "Invalid field selected!");
LocalOp = (Field << 3) | ModRM.rm;
return NormalOp(&SecondModRMTableOps[LocalOp], LocalOp);
@@ -681,7 +694,10 @@ bool Decoder::NormalOpHeader(FEXCore::X86Tables::X86InstInfo const *Info, uint16
uint8_t Byte2 = ReadByte();
pp = Byte2 & 0b11;
map_select = Byte1 & 0b11111;
LogMan::Throw::A(map_select >= 1 && map_select <= 3, "We don't understand a map_select of: %d", map_select);
if (!(map_select >= 1 && map_select <= 3)) {
LogMan::Msg::E("We don't understand a map_select of: %d", map_select);
return false;
}
}
uint16_t VEXOp = ReadByte();
@@ -729,6 +745,8 @@ bool Decoder::DecodeInstruction(uint64_t PC) {
DecodeInst->PC = PC;
for(;;) {
if (InstructionSize >= MAX_INST_SIZE)
return false;
uint8_t Op = ReadByte();
switch (Op) {
case 0x0F: {// Escape Op
@@ -879,7 +897,7 @@ bool Decoder::DecodeInstruction(uint64_t PC) {
auto Info = &FEXCore::X86Tables::BaseOps[Op];
if (Info->Type == FEXCore::X86Tables::TYPE_REX_PREFIX) {
LogMan::Throw::A(CTX->Config.Is64BitMode, "Got REX prefix in 32bit mode");
LOGMAN_THROW_A(CTX->Config.Is64BitMode, "Got REX prefix in 32bit mode");
DecodeInst->Flags |= DecodeFlags::FLAG_REX_PREFIX;
// Widening displacement
@@ -909,6 +927,10 @@ bool Decoder::DecodeInstruction(uint64_t PC) {
}
if (DecodeInst->Dest.TypeNone.Type == FEXCore::X86Tables::DecodedOperand::TYPE_GPR) {
assert(DecodeInst->Dest.TypeGPR.GPR != 255);
}
return true;
}
@@ -928,19 +950,23 @@ void Decoder::BranchTargetInMultiblockRange() {
// auto RIPOffset = LoadSource(Op, Op->Src[0], Op->Flags);
// auto RIPTargetConst = _Constant(Op->PC + Op->InstSize);
// Target offset is PC + InstSize + Literal
LogMan::Throw::A(DecodeInst->Src[0].TypeNone.Type == DecodedOperand::TYPE_LITERAL, "Had wrong operand type");
LOGMAN_THROW_A(DecodeInst->Src[0].TypeNone.Type == DecodedOperand::TYPE_LITERAL, "Had wrong operand type");
TargetRIP = DecodeInst->PC + DecodeInst->InstSize + DecodeInst->Src[0].TypeLiteral.Literal;
break;
}
case 0xE9:
case 0xEB: // Both are unconditional JMP instructions
LogMan::Throw::A(DecodeInst->Src[0].TypeNone.Type == DecodedOperand::TYPE_LITERAL, "Had wrong operand type");
LOGMAN_THROW_A(DecodeInst->Src[0].TypeNone.Type == DecodedOperand::TYPE_LITERAL, "Had wrong operand type");
TargetRIP = DecodeInst->PC + DecodeInst->InstSize + DecodeInst->Src[0].TypeLiteral.Literal;
Conditional = false;
break;
case 0xE8: // Call - Immediate target, We don't want to inline calls
if (ExternalBranches) {
ExternalBranches->insert(DecodeInst->PC + DecodeInst->InstSize);
}
[[fallthrough]];
case 0xC2: // RET imm
case 0xC3: // RET
case 0xE8: // Call - Immediate target, We don't want to inline calls
default:
return;
break;
@@ -970,6 +996,10 @@ void Decoder::BranchTargetInMultiblockRange() {
BlocksToDecode.find(TargetRIP) == BlocksToDecode.end()) {
BlocksToDecode.emplace(TargetRIP);
}
} else {
if (ExternalBranches) {
ExternalBranches->insert(TargetRIP);
}
}
}
@@ -993,7 +1023,7 @@ bool Decoder::DecodeInstructionsAtEntry(uint8_t const* _InstStream, uint64_t PC)
// If we don't have symbols available then we become a bit optimistic about multiblock ranges
if (!SymbolAvailable) {
// If we don't have a symbol available then assume all branches are valid for multiblock
SymbolMaxAddress = ~0ULL;
SymbolMaxAddress = SectionMaxAddress;
SymbolMinAddress = EntryPoint;
}
@@ -1023,7 +1053,10 @@ bool Decoder::DecodeInstructionsAtEntry(uint8_t const* _InstStream, uint64_t PC)
if (ErrorDuringDecoding) {
LogMan::Msg::D("Couldn't Decode something at 0x%lx, Started at 0x%lx", PC + PCOffset, PC);
LogMan::Throw::A(Blocks.size() != 1, "Decode Error in entry block");
if (Blocks.size() == 1) {
return false;
}
LOGMAN_THROW_A(Blocks.size() != 1, "Decode Error in entry block");
CurrentBlockDecoding.HasInvalidInstruction = true;
if (ErrorDuringDecoding && Blocks.size() != 1) {
+4
View File
@@ -33,6 +33,8 @@ public:
uint64_t DecodedMinAddress {};
uint64_t DecodedMaxAddress {~0ULL};
void SetSectionMaxAddress(uint64_t v) { SectionMaxAddress = v; }
void SetExternalBranches(std::set<uint64_t> *v) { ExternalBranches = v; }
private:
FEXCore::Context::Context *CTX;
@@ -65,10 +67,12 @@ private:
uint64_t MaxCondBranchBackwards {~0ULL};
uint64_t SymbolMaxAddress {};
uint64_t SymbolMinAddress {~0ULL};
uint64_t SectionMaxAddress {~0ULL};
std::vector<DecodedBlocks> Blocks;
std::set<uint64_t> BlocksToDecode;
std::set<uint64_t> HasBlocks;
std::set<uint64_t> *ExternalBranches {nullptr};
// ModRM rm decoding
using DecodeModRMPtr = void (FEXCore::Frontend::Decoder::*)(X86Tables::DecodedOperand *Operand, X86Tables::ModRMDecoded ModRM);
@@ -22,9 +22,8 @@ using DestMapType = std::vector<uint32_t>;
class InterpreterCore final : public CPUBackend {
public:
explicit InterpreterCore(FEXCore::Context::Context *ctx, FEXCore::Core::InternalThreadState *Thread, bool CompileThread);
~InterpreterCore() override;
std::string GetName() override { return "Interpreter"; }
void *CompileCode(FEXCore::IR::IRListView const *IR, FEXCore::Core::DebugData *DebugData, FEXCore::IR::RegisterAllocationData *RAData) override;
void *CompileCode(uint64_t Entry, FEXCore::IR::IRListView const *IR, FEXCore::Core::DebugData *DebugData, FEXCore::IR::RegisterAllocationData *RAData) override;
void *MapRegion(void* HostPtr, uint64_t, uint64_t) override { return HostPtr; }
@@ -46,7 +45,7 @@ private:
template<typename Res>
Res GetSrc(void* SSAData, IR::OrderedNodeWrapper Src);
Dispatcher *Dispatcher{};
std::unique_ptr<Dispatcher> Dispatcher{};
};
}
@@ -31,7 +31,7 @@ static void InterpreterExecution(FEXCore::Core::CpuStateFrame *Frame) {
auto LocalEntry = Thread->LocalIRCache.find(Thread->CurrentFrame->State.rip);
InterpreterOps::InterpretIR(Thread, LocalEntry->second.IR.get(), LocalEntry->second.DebugData.get());
InterpreterOps::InterpretIR(Thread, Thread->CurrentFrame->State.rip, LocalEntry->second.IR.get(), LocalEntry->second.DebugData.get());
}
bool InterpreterCore::HandleSIGBUS(int Signal, void *info, void *ucontext) {
@@ -111,13 +111,7 @@ InterpreterCore::InterpreterCore(FEXCore::Context::Context *ctx, FEXCore::Core::
}
}
InterpreterCore::~InterpreterCore() {
delete Dispatcher;
}
void *InterpreterCore::CompileCode([[maybe_unused]] FEXCore::IR::IRListView const *IR, [[maybe_unused]] FEXCore::Core::DebugData *DebugData, FEXCore::IR::RegisterAllocationData *RAData) {
void *InterpreterCore::CompileCode(uint64_t Entry, [[maybe_unused]] FEXCore::IR::IRListView const *IR, [[maybe_unused]] FEXCore::Core::DebugData *DebugData, FEXCore::IR::RegisterAllocationData *RAData) {
return reinterpret_cast<void*>(InterpreterExecution);
}
File diff suppressed because it is too large. Load diff
@@ -36,7 +36,7 @@ namespace FEXCore::CPU {
class InterpreterOps {
public:
static void InterpretIR(FEXCore::Core::InternalThreadState *Thread, FEXCore::IR::IRListView *CurrentIR, FEXCore::Core::DebugData *DebugData);
static void InterpretIR(FEXCore::Core::InternalThreadState *Thread, uint64_t Entry, FEXCore::IR::IRListView *CurrentIR, FEXCore::Core::DebugData *DebugData);
static bool GetFallbackHandler(IR::IROp_Header *IROp, FallbackInfo *Info);
};
};
+37 -38
View File
@@ -46,7 +46,7 @@ DEF_OP(TruncElementPair) {
mov(Dst.second, Src.second);
break;
}
default: LogMan::Msg::A("Unhandled Truncation size: %d", Op->Size); break;
default: LOGMAN_MSG_A("Unhandled Truncation size: %d", Op->Size); break;
}
}
@@ -59,7 +59,7 @@ DEF_OP(Constant) {
DEF_OP(EntrypointOffset) {
auto Op = IROp->C<IR::IROp_EntrypointOffset>();
auto Constant = IR->GetHeader()->Entry + Op->Offset;
auto Constant = Entry + Op->Offset;
auto Dst = GetReg<RA_64>(Node);
LoadConstant(Dst, Constant);
}
@@ -95,7 +95,7 @@ DEF_OP(Add) {
case 8:
add(GetReg<RA_64>(Node), GetReg<RA_64>(Op->Header.Args[0].ID()), Const);
break;
default: LogMan::Msg::A("Unsupported Add size: %d", OpSize);
default: LOGMAN_MSG_A("Unsupported Add size: %d", OpSize);
}
} else {
switch (OpSize) {
@@ -105,7 +105,7 @@ DEF_OP(Add) {
case 8:
add(GetReg<RA_64>(Node), GetReg<RA_64>(Op->Header.Args[0].ID()), GetReg<RA_64>(Op->Header.Args[1].ID()));
break;
default: LogMan::Msg::A("Unsupported Add size: %d", OpSize);
default: LOGMAN_MSG_A("Unsupported Add size: %d", OpSize);
}
}
}
@@ -121,7 +121,7 @@ DEF_OP(Sub) {
case 8:
sub(GRS(Node), GRS(Op->Header.Args[0].ID()), Const);
break;
default: LogMan::Msg::A("Unsupported Sub size: %d", OpSize);
default: LOGMAN_MSG_A("Unsupported Sub size: %d", OpSize);
}
} else {
switch (OpSize) {
@@ -131,7 +131,7 @@ DEF_OP(Sub) {
case 8:
sub(GetReg<RA_64>(Node), GetReg<RA_64>(Op->Header.Args[0].ID()), GetReg<RA_64>(Op->Header.Args[1].ID()));
break;
default: LogMan::Msg::A("Unsupported Sub size: %d", OpSize);
default: LOGMAN_MSG_A("Unsupported Sub size: %d", OpSize);
}
}
@@ -147,7 +147,7 @@ DEF_OP(Neg) {
case 8:
neg(GetReg<RA_64>(Node), GetReg<RA_64>(Op->Header.Args[0].ID()));
break;
default: LogMan::Msg::A("Unsupported Not size: %d", OpSize);
default: LOGMAN_MSG_A("Unsupported Not size: %d", OpSize);
}
}
@@ -159,12 +159,11 @@ DEF_OP(Mul) {
switch (OpSize) {
case 4:
mul(Dst.W(), GetReg<RA_32>(Op->Header.Args[0].ID()), GetReg<RA_32>(Op->Header.Args[1].ID()));
sxtw(Dst, Dst);
break;
case 8:
mul(Dst, GetReg<RA_64>(Op->Header.Args[0].ID()), GetReg<RA_64>(Op->Header.Args[1].ID()));
break;
default: LogMan::Msg::A("Unknown Sext size: %d", OpSize);
default: LOGMAN_MSG_A("Unknown Sext size: %d", OpSize);
}
}
@@ -180,7 +179,7 @@ DEF_OP(UMul) {
case 8:
mul(Dst, GetReg<RA_64>(Op->Header.Args[0].ID()), GetReg<RA_64>(Op->Header.Args[1].ID()));
break;
default: LogMan::Msg::A("Unknown Sext size: %d", OpSize);
default: LOGMAN_MSG_A("Unknown Sext size: %d", OpSize);
}
}
@@ -217,7 +216,7 @@ DEF_OP(Div) {
sdiv(GetReg<RA_64>(Node), GetReg<RA_64>(Op->Header.Args[0].ID()), GetReg<RA_64>(Op->Header.Args[1].ID()));
break;
}
default: LogMan::Msg::A("Unknown DIV Size: %d", Size); break;
default: LOGMAN_MSG_A("Unknown DIV Size: %d", Size); break;
}
}
@@ -244,7 +243,7 @@ DEF_OP(UDiv) {
udiv(GetReg<RA_64>(Node), GetReg<RA_64>(Op->Header.Args[0].ID()), GetReg<RA_64>(Op->Header.Args[1].ID()));
break;
}
default: LogMan::Msg::A("Unknown UDIV Size: %d", Size); break;
default: LOGMAN_MSG_A("Unknown UDIV Size: %d", Size); break;
}
}
@@ -291,7 +290,7 @@ DEF_OP(Rem) {
msub(GetReg<RA_64>(Node), TMP1, Divisor, Dividend);
break;
}
default: LogMan::Msg::A("Unknown REM Size: %d", OpSize); break;
default: LOGMAN_MSG_A("Unknown REM Size: %d", OpSize); break;
}
}
@@ -333,7 +332,7 @@ DEF_OP(URem) {
msub(GetReg<RA_64>(Node), TMP1, Divisor, Dividend);
break;
}
default: LogMan::Msg::A("Unknown UREM Size: %d", OpSize); break;
default: LOGMAN_MSG_A("Unknown UREM Size: %d", OpSize); break;
}
}
@@ -345,12 +344,12 @@ DEF_OP(MulH) {
sxtw(TMP1, GetReg<RA_64>(Op->Header.Args[0].ID()));
sxtw(TMP2, GetReg<RA_64>(Op->Header.Args[1].ID()));
mul(TMP1, TMP1, TMP2);
sbfx(GetReg<RA_64>(Node), TMP1, 32, 32);
ubfx(GetReg<RA_64>(Node), TMP1, 32, 32);
break;
case 8:
smulh(GetReg<RA_64>(Node), GetReg<RA_64>(Op->Header.Args[0].ID()), GetReg<RA_64>(Op->Header.Args[1].ID()));
break;
default: LogMan::Msg::A("Unknown Sext size: %d", OpSize);
default: LOGMAN_MSG_A("Unknown Sext size: %d", OpSize);
}
}
@@ -367,7 +366,7 @@ DEF_OP(UMulH) {
case 8:
umulh(GetReg<RA_64>(Node), GetReg<RA_64>(Op->Header.Args[0].ID()), GetReg<RA_64>(Op->Header.Args[1].ID()));
break;
default: LogMan::Msg::A("Unknown Sext size: %d", OpSize);
default: LOGMAN_MSG_A("Unknown Sext size: %d", OpSize);
}
}
@@ -463,7 +462,7 @@ DEF_OP(Ror) {
break;
}
default: LogMan::Msg::A("Unhandled ROR size: %d", OpSize);
default: LOGMAN_MSG_A("Unhandled ROR size: %d", OpSize);
}
} else {
switch (OpSize) {
@@ -476,7 +475,7 @@ DEF_OP(Ror) {
break;
}
default: LogMan::Msg::A("Unhandled ROR size: %d", OpSize);
default: LOGMAN_MSG_A("Unhandled ROR size: %d", OpSize);
}
}
}
@@ -495,7 +494,7 @@ DEF_OP(Extr) {
break;
}
default: LogMan::Msg::A("Unhandled EXTR size: %d", OpSize);
default: LOGMAN_MSG_A("Unhandled EXTR size: %d", OpSize);
}
}
@@ -540,7 +539,7 @@ DEF_OP(LDiv) {
mov(GetReg<RA_64>(Node), x0);
break;
}
default: LogMan::Msg::A("Unknown LDIV Size: %d", Size); break;
default: LOGMAN_MSG_A("Unknown LDIV Size: %d", Size); break;
}
}
@@ -583,7 +582,7 @@ DEF_OP(LUDiv) {
mov(GetReg<RA_64>(Node), x0);
break;
}
default: LogMan::Msg::A("Unknown LUDIV Size: %d", Size); break;
default: LOGMAN_MSG_A("Unknown LUDIV Size: %d", Size); break;
}
}
@@ -636,7 +635,7 @@ DEF_OP(LRem) {
mov(GetReg<RA_64>(Node), x0);
break;
}
default: LogMan::Msg::A("Unknown LREM Size: %d", Size); break;
default: LOGMAN_MSG_A("Unknown LREM Size: %d", Size); break;
}
}
@@ -686,7 +685,7 @@ DEF_OP(LURem) {
mov(GetReg<RA_64>(Node), x0);
break;
}
default: LogMan::Msg::A("Unknown LUREM Size: %d", OpSize); break;
default: LOGMAN_MSG_A("Unknown LUREM Size: %d", OpSize); break;
}
}
@@ -700,7 +699,7 @@ DEF_OP(Not) {
case 8:
mvn(GetReg<RA_64>(Node), GetReg<RA_64>(Op->Header.Args[0].ID()));
break;
default: LogMan::Msg::A("Unsupported Not size: %d", OpSize);
default: LOGMAN_MSG_A("Unsupported Not size: %d", OpSize);
}
}
@@ -731,7 +730,7 @@ DEF_OP(Popcount) {
// fmov has zero extended, unused bytes are zero
addv(VTMP1.B(), VTMP1.V8B());
break;
default: LogMan::Msg::A("Unsupported Popcount size: %d", OpSize);
default: LOGMAN_MSG_A("Unsupported Popcount size: %d", OpSize);
}
auto Dst = GetReg<RA_32>(Node);
@@ -780,7 +779,7 @@ DEF_OP(FindMSB) {
clz(Dst, GetReg<RA_64>(Op->Header.Args[0].ID()));
sub(Dst, TMP1, Dst);
break;
default: LogMan::Msg::A("Unknown REV size: %d", OpSize); break;
default: LOGMAN_MSG_A("Unknown REV size: %d", OpSize); break;
}
}
@@ -801,7 +800,7 @@ DEF_OP(FindTrailingZeros) {
rbit(GetReg<RA_64>(Node), GetReg<RA_64>(Op->Header.Args[0].ID()));
clz(GetReg<RA_64>(Node), GetReg<RA_64>(Node));
break;
default: LogMan::Msg::A("Unknown size: %d", OpSize); break;
default: LOGMAN_MSG_A("Unknown size: %d", OpSize); break;
}
}
@@ -820,7 +819,7 @@ DEF_OP(CountLeadingZeroes) {
case 8:
clz(GetReg<RA_64>(Node), GetReg<RA_64>(Op->Header.Args[0].ID()));
break;
default: LogMan::Msg::A("Unknown size: %d", OpSize); break;
default: LOGMAN_MSG_A("Unknown size: %d", OpSize); break;
}
}
@@ -838,7 +837,7 @@ DEF_OP(Rev) {
case 8:
rev(GetReg<RA_64>(Node), GetReg<RA_64>(Op->Header.Args[0].ID()));
break;
default: LogMan::Msg::A("Unknown REV size: %d", OpSize); break;
default: LOGMAN_MSG_A("Unknown REV size: %d", OpSize); break;
}
}
@@ -860,15 +859,15 @@ DEF_OP(Bfi) {
bfi(TMP1, GetReg<RA_64>(Op->Header.Args[1].ID()), Op->lsb, Op->Width);
mov(GetReg<RA_64>(Node), TMP1);
break;
default: LogMan::Msg::A("Unknown BFI size: %d", OpSize); break;
default: LOGMAN_MSG_A("Unknown BFI size: %d", OpSize); break;
}
}
DEF_OP(Bfe) {
auto Op = IROp->C<IR::IROp_Bfe>();
uint8_t OpSize = IROp->Size;
LogMan::Throw::A(OpSize <= 8, "OpSize is too large for BFE: %d", OpSize);
LogMan::Throw::A(Op->Width != 0, "Invalid BFE width of 0");
LOGMAN_THROW_A(OpSize <= 8, "OpSize is too large for BFE: %d", OpSize);
LOGMAN_THROW_A(Op->Width != 0, "Invalid BFE width of 0");
auto Dst = GetReg<RA_64>(Node);
ubfx(Dst, GetReg<RA_64>(Op->Header.Args[0].ID()), Op->lsb, Op->Width);
@@ -913,7 +912,7 @@ Condition MapSelectCC(IR::CondClassType Cond) {
case FEXCore::IR::COND_MI:
case FEXCore::IR::COND_PL:
default:
LogMan::Msg::A("Unsupported compare type");
LOGMAN_MSG_A("Unsupported compare type");
return Condition::nv;
}
}
@@ -931,7 +930,7 @@ DEF_OP(Select) {
} else if (IsFPR(Op->Cmp1.ID())) {
fcmp(GRFCMP(Op->Cmp1.ID()), GRFCMP(Op->Cmp2.ID()));
} else {
LogMan::Msg::A("Select: Expected GPR or FPR");
LOGMAN_MSG_A("Select: Expected GPR or FPR");
}
auto cc = MapSelectCC(Op->Cond);
@@ -942,7 +941,7 @@ DEF_OP(Select) {
if (is_const_true || is_const_false) {
if (is_const_false != true || is_const_true != true || const_true != 1 || const_false != 0) {
LogMan::Msg::A("Select: Unsupported compare inline parameters");
LOGMAN_MSG_A("Select: Unsupported compare inline parameters");
}
cset(GRS(Node), cc);
} else {
@@ -966,7 +965,7 @@ DEF_OP(VExtractToGPR) {
case 8:
umov(GetReg<RA_64>(Node), GetSrc(Op->Header.Args[0].ID()).V2D(), Op->Idx);
break;
default: LogMan::Msg::A("Unhandled ExtractElementSize: %d", OpSize);
default: LOGMAN_MSG_A("Unhandled ExtractElementSize: %d", OpSize);
}
}
@@ -1014,7 +1013,7 @@ DEF_OP(FCmp) {
bool set = false;
if (Op->Flags & (1 << IR::FCMP_FLAG_EQ)) {
LogMan::Throw::A(IR::FCMP_FLAG_EQ == 0, "IR::FCMP_FLAG_EQ must equal 0");
LOGMAN_THROW_A(IR::FCMP_FLAG_EQ == 0, "IR::FCMP_FLAG_EQ must equal 0");
// EQ or unordered
cset(Dst, Condition::eq); // Z = 1
csinc(Dst, Dst, xzr, Condition::vc); // IF !V ? Z : 1
@@ -34,7 +34,7 @@ DEF_OP(CASPair) {
mov(Dst.first, TMP3);
mov(Dst.second, TMP4);
break;
default: LogMan::Msg::A("Unsupported: %d", OpSize);
default: LOGMAN_MSG_A("Unsupported: %d", OpSize);
}
}
else {
@@ -89,7 +89,7 @@ DEF_OP(CASPair) {
bind(&LoopExpected);
break;
}
default: LogMan::Msg::A("Unsupported: %d", OpSize);
default: LOGMAN_MSG_A("Unsupported: %d", OpSize);
}
}
}
@@ -115,7 +115,7 @@ DEF_OP(CAS) {
case 2: casalh(TMP2.W(), Desired.W(), MemOperand(MemSrc)); break;
case 4: casal(TMP2.W(), Desired.W(), MemOperand(MemSrc)); break;
case 8: casal(TMP2.X(), Desired.X(), MemOperand(MemSrc)); break;
default: LogMan::Msg::A("Unsupported: %d", OpSize);
default: LOGMAN_MSG_A("Unsupported: %d", OpSize);
}
mov(GetReg<RA_64>(Node), TMP2);
}
@@ -206,7 +206,7 @@ DEF_OP(CAS) {
break;
}
default: LogMan::Msg::A("Unhandled Atomic size: %d", OpSize);
default: LOGMAN_MSG_A("Unhandled Atomic size: %d", OpSize);
}
}
}
@@ -222,7 +222,7 @@ DEF_OP(AtomicAdd) {
case 2: staddlh(GetReg<RA_32>(Op->Header.Args[1].ID()), MemOperand(MemSrc)); break;
case 4: staddl(GetReg<RA_32>(Op->Header.Args[1].ID()), MemOperand(MemSrc)); break;
case 8: staddl(GetReg<RA_64>(Op->Header.Args[1].ID()), MemOperand(MemSrc)); break;
default: LogMan::Msg::A("Unhandled Atomic size: %d", Op->Size);
default: LOGMAN_MSG_A("Unhandled Atomic size: %d", Op->Size);
}
}
else {
@@ -264,7 +264,7 @@ DEF_OP(AtomicAdd) {
cbnz(TMP2, &LoopTop);
break;
}
default: LogMan::Msg::A("Unhandled Atomic size: %d", Op->Size);
default: LOGMAN_MSG_A("Unhandled Atomic size: %d", Op->Size);
}
}
}
@@ -281,7 +281,7 @@ DEF_OP(AtomicSub) {
case 2: staddlh(TMP2.W(), MemOperand(MemSrc)); break;
case 4: staddl(TMP2.W(), MemOperand(MemSrc)); break;
case 8: staddl(TMP2.X(), MemOperand(MemSrc)); break;
default: LogMan::Msg::A("Unhandled Atomic size: %d", Op->Size);
default: LOGMAN_MSG_A("Unhandled Atomic size: %d", Op->Size);
}
}
else {
@@ -323,7 +323,7 @@ DEF_OP(AtomicSub) {
cbnz(TMP2, &LoopTop);
break;
}
default: LogMan::Msg::A("Unhandled Atomic size: %d", Op->Size);
default: LOGMAN_MSG_A("Unhandled Atomic size: %d", Op->Size);
}
}
}
@@ -340,7 +340,7 @@ DEF_OP(AtomicAnd) {
case 2: stclrlh(TMP2.W(), MemOperand(MemSrc)); break;
case 4: stclrl(TMP2.W(), MemOperand(MemSrc)); break;
case 8: stclrl(TMP2.X(), MemOperand(MemSrc)); break;
default: LogMan::Msg::A("Unhandled Atomic size: %d", Op->Size);
default: LOGMAN_MSG_A("Unhandled Atomic size: %d", Op->Size);
}
}
else {
@@ -382,7 +382,7 @@ DEF_OP(AtomicAnd) {
cbnz(TMP2, &LoopTop);
break;
}
default: LogMan::Msg::A("Unhandled Atomic size: %d", Op->Size);
default: LOGMAN_MSG_A("Unhandled Atomic size: %d", Op->Size);
}
}
}
@@ -398,7 +398,7 @@ DEF_OP(AtomicOr) {
case 2: stsetlh(GetReg<RA_32>(Op->Header.Args[1].ID()), MemOperand(MemSrc)); break;
case 4: stsetl(GetReg<RA_32>(Op->Header.Args[1].ID()), MemOperand(MemSrc)); break;
case 8: stsetl(GetReg<RA_64>(Op->Header.Args[1].ID()), MemOperand(MemSrc)); break;
default: LogMan::Msg::A("Unhandled Atomic size: %d", Op->Size);
default: LOGMAN_MSG_A("Unhandled Atomic size: %d", Op->Size);
}
}
else {
@@ -440,7 +440,7 @@ DEF_OP(AtomicOr) {
cbnz(TMP2, &LoopTop);
break;
}
default: LogMan::Msg::A("Unhandled Atomic size: %d", Op->Size);
default: LOGMAN_MSG_A("Unhandled Atomic size: %d", Op->Size);
}
}
}
@@ -456,7 +456,7 @@ DEF_OP(AtomicXor) {
case 2: steorlh(GetReg<RA_32>(Op->Header.Args[1].ID()), MemOperand(MemSrc)); break;
case 4: steorl(GetReg<RA_32>(Op->Header.Args[1].ID()), MemOperand(MemSrc)); break;
case 8: steorl(GetReg<RA_64>(Op->Header.Args[1].ID()), MemOperand(MemSrc)); break;
default: LogMan::Msg::A("Unhandled Atomic size: %d", Op->Size);
default: LOGMAN_MSG_A("Unhandled Atomic size: %d", Op->Size);
}
}
else {
@@ -498,7 +498,7 @@ DEF_OP(AtomicXor) {
cbnz(TMP2, &LoopTop);
break;
}
default: LogMan::Msg::A("Unhandled Atomic size: %d", Op->Size);
default: LOGMAN_MSG_A("Unhandled Atomic size: %d", Op->Size);
}
}
}
@@ -515,7 +515,7 @@ DEF_OP(AtomicSwap) {
case 2: swplh(TMP2.W(), GetReg<RA_32>(Node), MemOperand(MemSrc)); break;
case 4: swpl(TMP2.W(), GetReg<RA_32>(Node), MemOperand(MemSrc)); break;
case 8: swpl(TMP2.X(), GetReg<RA_64>(Node), MemOperand(MemSrc)); break;
default: LogMan::Msg::A("Unhandled Atomic size: %d", Op->Size);
default: LOGMAN_MSG_A("Unhandled Atomic size: %d", Op->Size);
}
}
else {
@@ -558,7 +558,7 @@ DEF_OP(AtomicSwap) {
mov(GetReg<RA_64>(Node), TMP2.X());
break;
}
default: LogMan::Msg::A("Unhandled Atomic size: %d", Op->Size);
default: LOGMAN_MSG_A("Unhandled Atomic size: %d", Op->Size);
}
}
}
@@ -573,7 +573,7 @@ DEF_OP(AtomicFetchAdd) {
case 2: ldaddalh(GetReg<RA_32>(Op->Header.Args[1].ID()), GetReg<RA_32>(Node), MemOperand(MemSrc)); break;
case 4: ldaddal(GetReg<RA_32>(Op->Header.Args[1].ID()), GetReg<RA_32>(Node), MemOperand(MemSrc)); break;
case 8: ldaddal(GetReg<RA_64>(Op->Header.Args[1].ID()), GetReg<RA_64>(Node), MemOperand(MemSrc)); break;
default: LogMan::Msg::A("Unhandled Atomic size: %d", Op->Size);
default: LOGMAN_MSG_A("Unhandled Atomic size: %d", Op->Size);
}
}
else {
@@ -619,7 +619,7 @@ DEF_OP(AtomicFetchAdd) {
mov(GetReg<RA_64>(Node), TMP2);
break;
}
default: LogMan::Msg::A("Unhandled Atomic size: %d", Op->Size);
default: LOGMAN_MSG_A("Unhandled Atomic size: %d", Op->Size);
}
}
}
@@ -635,7 +635,7 @@ DEF_OP(AtomicFetchSub) {
case 2: ldaddalh(TMP2.W(), GetReg<RA_32>(Node), MemOperand(MemSrc)); break;
case 4: ldaddal(TMP2.W(), GetReg<RA_32>(Node), MemOperand(MemSrc)); break;
case 8: ldaddal(TMP2.X(), GetReg<RA_64>(Node), MemOperand(MemSrc)); break;
default: LogMan::Msg::A("Unhandled Atomic size: %d", Op->Size);
default: LOGMAN_MSG_A("Unhandled Atomic size: %d", Op->Size);
}
}
else {
@@ -681,7 +681,7 @@ DEF_OP(AtomicFetchSub) {
mov(GetReg<RA_64>(Node), TMP2);
break;
}
default: LogMan::Msg::A("Unhandled Atomic size: %d", Op->Size);
default: LOGMAN_MSG_A("Unhandled Atomic size: %d", Op->Size);
}
}
}
@@ -697,7 +697,7 @@ DEF_OP(AtomicFetchAnd) {
case 2: ldclralh(TMP2.W(), GetReg<RA_32>(Node), MemOperand(MemSrc)); break;
case 4: ldclral(TMP2.W(), GetReg<RA_32>(Node), MemOperand(MemSrc)); break;
case 8: ldclral(TMP2.X(), GetReg<RA_64>(Node), MemOperand(MemSrc)); break;
default: LogMan::Msg::A("Unhandled Atomic size: %d", Op->Size);
default: LOGMAN_MSG_A("Unhandled Atomic size: %d", Op->Size);
}
}
else {
@@ -743,7 +743,7 @@ DEF_OP(AtomicFetchAnd) {
mov(GetReg<RA_64>(Node), TMP2);
break;
}
default: LogMan::Msg::A("Unhandled Atomic size: %d", Op->Size);
default: LOGMAN_MSG_A("Unhandled Atomic size: %d", Op->Size);
}
}
}
@@ -758,7 +758,7 @@ DEF_OP(AtomicFetchOr) {
case 2: ldsetalh(GetReg<RA_32>(Op->Header.Args[1].ID()), GetReg<RA_32>(Node), MemOperand(MemSrc)); break;
case 4: ldsetal(GetReg<RA_32>(Op->Header.Args[1].ID()), GetReg<RA_32>(Node), MemOperand(MemSrc)); break;
case 8: ldsetal(GetReg<RA_64>(Op->Header.Args[1].ID()), GetReg<RA_64>(Node), MemOperand(MemSrc)); break;
default: LogMan::Msg::A("Unhandled Atomic size: %d", Op->Size);
default: LOGMAN_MSG_A("Unhandled Atomic size: %d", Op->Size);
}
}
else {
@@ -804,7 +804,7 @@ DEF_OP(AtomicFetchOr) {
mov(GetReg<RA_64>(Node), TMP2);
break;
}
default: LogMan::Msg::A("Unhandled Atomic size: %d", Op->Size);
default: LOGMAN_MSG_A("Unhandled Atomic size: %d", Op->Size);
}
}
}
@@ -819,7 +819,7 @@ DEF_OP(AtomicFetchXor) {
case 2: ldeoralh(GetReg<RA_32>(Op->Header.Args[1].ID()), GetReg<RA_32>(Node), MemOperand(MemSrc)); break;
case 4: ldeoral(GetReg<RA_32>(Op->Header.Args[1].ID()), GetReg<RA_32>(Node), MemOperand(MemSrc)); break;
case 8: ldeoral(GetReg<RA_64>(Op->Header.Args[1].ID()), GetReg<RA_64>(Node), MemOperand(MemSrc)); break;
default: LogMan::Msg::A("Unhandled Atomic size: %d", Op->Size);
default: LOGMAN_MSG_A("Unhandled Atomic size: %d", Op->Size);
}
}
else {
@@ -865,7 +865,7 @@ DEF_OP(AtomicFetchXor) {
mov(GetReg<RA_64>(Node), TMP2);
break;
}
default: LogMan::Msg::A("Unhandled Atomic size: %d", Op->Size);
default: LOGMAN_MSG_A("Unhandled Atomic size: %d", Op->Size);
}
}
}
@@ -73,7 +73,7 @@ DEF_OP(ExitFunction) {
uint64_t NewRIP;
if (IsInlineConstant(Op->NewRIP, &NewRIP) || IsInlineEntrypointOffset(Op->NewRIP, &NewRIP)) {
Literal l_BranchHost{Dispatcher->ExitFunctionLinkerAddress};
Literal l_BranchHost{ThreadSharedData.Dispatcher->ExitFunctionLinkerAddress};
Literal l_BranchGuest{NewRIP};
ldr(x0, &l_BranchHost);
@@ -96,7 +96,7 @@ DEF_OP(ExitFunction) {
br(x1);
bind(&FullLookup);
LoadConstant(TMP1, Dispatcher->AbsoluteLoopTopAddress);
LoadConstant(TMP1, ThreadSharedData.Dispatcher->AbsoluteLoopTopAddress);
str(RipReg, MemOperand(STATE, offsetof(FEXCore::Core::CpuStateFrame, State.rip)));
br(TMP1);
}
@@ -142,7 +142,7 @@ Condition MapBranchCC(IR::CondClassType Cond) {
case FEXCore::IR::COND_MI:
case FEXCore::IR::COND_PL:
default:
LogMan::Msg::A("Unsupported compare type");
LOGMAN_MSG_A("Unsupported compare type");
return Condition::nv;
}
}
@@ -169,10 +169,10 @@ DEF_OP(CondJump) {
bool isConst = IsInlineConstant(Op->Cmp2, &Const);
if (isConst && Const == 0 && Op->Cond.Val == FEXCore::IR::COND_EQ) {
LogMan::Throw::A(IsGPR(Op->Cmp1.ID()), "CondJump: Expected GPR");
LOGMAN_THROW_A(IsGPR(Op->Cmp1.ID()), "CondJump: Expected GPR");
cbz(GRCMP(Op->Cmp1.ID()), TrueTargetLabel);
} else if (isConst && Const == 0 && Op->Cond.Val == FEXCore::IR::COND_NEQ) {
LogMan::Throw::A(IsGPR(Op->Cmp1.ID()), "CondJump: Expected GPR");
LOGMAN_THROW_A(IsGPR(Op->Cmp1.ID()), "CondJump: Expected GPR");
cbnz(GRCMP(Op->Cmp1.ID()), TrueTargetLabel);
} else {
if (IsGPR(Op->Cmp1.ID())) {
@@ -183,7 +183,7 @@ DEF_OP(CondJump) {
} else if (IsFPR(Op->Cmp1.ID())) {
fcmp(GRFCMP(Op->Cmp1.ID()), GRFCMP(Op->Cmp2.ID()));
} else {
LogMan::Msg::A("CondJump: Expected GPR or FPR");
LOGMAN_MSG_A("CondJump: Expected GPR or FPR");
}
b(TrueTargetLabel, MapBranchCC(Op->Cond));
@@ -262,7 +262,7 @@ DEF_OP(ValidateCode) {
int idx = 0;
LoadConstant(GetReg<RA_64>(Node), 0);
LoadConstant(x0, IR->GetHeader()->Entry + Op->Offset);
LoadConstant(x0, Entry + Op->Offset);
LoadConstant(x1, 1);
while (len >= 8)
@@ -311,7 +311,7 @@ DEF_OP(RemoveCodeEntry) {
PushDynamicRegsAndLR();
mov(x0, STATE);
LoadConstant(x1, IR->GetHeader()->Entry);
LoadConstant(x1, Entry);
LoadConstant(x2, reinterpret_cast<uintptr_t>(&Context::Context::RemoveCodeEntryFromJit));
SpillStaticRegs();
@@ -31,7 +31,7 @@ DEF_OP(VInsGPR) {
ins(GetDst(Node).V2D(), Op->Index, GetReg<RA_64>(Op->Header.Args[1].ID()));
break;
}
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
}
}
@@ -52,12 +52,12 @@ DEF_OP(VCastFromGPR) {
case 8:
fmov(GetDst(Node).D(), GetReg<RA_64>(Op->Header.Args[0].ID()).X());
break;
default: LogMan::Msg::A("Unknown castGPR element size: %d", Op->Header.ElementSize);
default: LOGMAN_MSG_A("Unknown castGPR element size: %d", Op->Header.ElementSize);
}
}
DEF_OP(Float_FromGPR_U) {
LogMan::Msg::A("Unimplemented");
LOGMAN_MSG_A("Unimplemented");
}
DEF_OP(Float_FromGPR_S) {
@@ -95,7 +95,7 @@ DEF_OP(Float_FToF) {
fcvt(GetDst(Node).S(), GetSrc(Op->Header.Args[0].ID()).D());
break;
}
default: LogMan::Msg::A("Unknown FCVT sizes: 0x%x", Conv);
default: LOGMAN_MSG_A("Unknown FCVT sizes: 0x%x", Conv);
}
}
@@ -108,7 +108,7 @@ DEF_OP(Vector_UToF) {
case 8:
ucvtf(GetDst(Node).V2D(), GetSrc(Op->Header.Args[0].ID()).V2D());
break;
default: LogMan::Msg::A("Unknown castGPR element size: %d", Op->Header.ElementSize);
default: LOGMAN_MSG_A("Unknown castGPR element size: %d", Op->Header.ElementSize);
}
}
@@ -121,7 +121,7 @@ DEF_OP(Vector_SToF) {
case 8:
scvtf(GetDst(Node).V2D(), GetSrc(Op->Header.Args[0].ID()).V2D());
break;
default: LogMan::Msg::A("Unknown castGPR element size: %d", Op->Header.ElementSize);
default: LOGMAN_MSG_A("Unknown castGPR element size: %d", Op->Header.ElementSize);
}
}
@@ -134,7 +134,7 @@ DEF_OP(Vector_FToZU) {
case 8:
fcvtzu(GetDst(Node).V2D(), GetSrc(Op->Header.Args[0].ID()).V2D());
break;
default: LogMan::Msg::A("Unknown castGPR element size: %d", Op->Header.ElementSize);
default: LOGMAN_MSG_A("Unknown castGPR element size: %d", Op->Header.ElementSize);
}
}
@@ -147,7 +147,7 @@ DEF_OP(Vector_FToZS) {
case 8:
fcvtzs(GetDst(Node).V2D(), GetSrc(Op->Header.Args[0].ID()).V2D());
break;
default: LogMan::Msg::A("Unknown castGPR element size: %d", Op->Header.ElementSize);
default: LOGMAN_MSG_A("Unknown castGPR element size: %d", Op->Header.ElementSize);
}
}
@@ -162,7 +162,7 @@ DEF_OP(Vector_FToU) {
frinti(GetDst(Node).V2D(), GetSrc(Op->Header.Args[0].ID()).V2D());
fcvtzu(GetDst(Node).V2D(), GetDst(Node).V2D());
break;
default: LogMan::Msg::A("Unknown castGPR element size: %d", Op->Header.ElementSize);
default: LOGMAN_MSG_A("Unknown castGPR element size: %d", Op->Header.ElementSize);
}
}
@@ -177,7 +177,7 @@ DEF_OP(Vector_FToS) {
frinti(GetDst(Node).V2D(), GetSrc(Op->Header.Args[0].ID()).V2D());
fcvtzs(GetDst(Node).V2D(), GetDst(Node).V2D());
break;
default: LogMan::Msg::A("Unknown castGPR element size: %d", Op->Header.ElementSize);
default: LOGMAN_MSG_A("Unknown castGPR element size: %d", Op->Header.ElementSize);
}
}
@@ -194,7 +194,7 @@ DEF_OP(Vector_FToF) {
fcvtn(GetDst(Node).V2S(), GetSrc(Op->Header.Args[0].ID()).V2D());
break;
}
default: LogMan::Msg::A("Unknown Conversion Type : 0%04x", Conv); break;
default: LOGMAN_MSG_A("Unknown Conversion Type : 0%04x", Conv); break;
}
}
+67 -32
View File
@@ -22,6 +22,7 @@ $end_info$
#include <FEXCore/Core/X86Enums.h>
#include <FEXCore/Core/UContext.h>
#include <FEXCore/Utils/Allocator.h>
#include "Interface/Core/Interpreter/InterpreterOps.h"
#include <sys/mman.h>
@@ -43,7 +44,7 @@ void Arm64JITCore::Op_Unhandled(FEXCore::IR::IROp_Header *IROp, uint32_t Node) {
FallbackInfo Info;
if (!InterpreterOps::GetFallbackHandler(IROp, &Info)) {
auto Name = FEXCore::IR::GetName(IROp->Op);
LogMan::Msg::A("Unhandled IR Op: %s", std::string(Name).c_str());
LOGMAN_MSG_A("Unhandled IR Op: %s", std::string(Name).c_str());
} else {
switch(Info.ABI) {
case FABI_VOID_U16:{
@@ -291,7 +292,7 @@ void Arm64JITCore::Op_Unhandled(FEXCore::IR::IROp_Header *IROp, uint32_t Node) {
case FABI_UNKNOWN:
default:
auto Name = FEXCore::IR::GetName(IROp->Op);
LogMan::Msg::A("Unhandled IR Fallback abi: %s %d", std::string(Name).c_str(), Info.ABI);
LOGMAN_MSG_A("Unhandled IR Fallback abi: %s %d", std::string(Name).c_str(), Info.ABI);
}
}
}
@@ -303,18 +304,18 @@ Arm64JITCore::CodeBuffer Arm64JITCore::AllocateNewCodeBuffer(size_t Size) {
CodeBuffer Buffer;
Buffer.Size = Size;
Buffer.Ptr = static_cast<uint8_t*>(
mmap(nullptr,
FEXCore::Allocator::mmap(nullptr,
Buffer.Size,
PROT_READ | PROT_WRITE | PROT_EXEC,
MAP_PRIVATE | MAP_ANONYMOUS,
-1, 0));
LogMan::Throw::A(!!Buffer.Ptr, "Couldn't allocate code buffer");
LOGMAN_THROW_A(!!Buffer.Ptr, "Couldn't allocate code buffer");
Dispatcher->RegisterCodeBuffer(Buffer.Ptr, Buffer.Size);
return Buffer;
}
void Arm64JITCore::FreeCodeBuffer(CodeBuffer Buffer) {
munmap(Buffer.Ptr, Buffer.Size);
FEXCore::Allocator::munmap(Buffer.Ptr, Buffer.Size);
Dispatcher->RemoveCodeBuffer(Buffer.Ptr);
}
@@ -359,6 +360,34 @@ bool Arm64JITCore::HandleSIGBUS(int Signal, void *info, void *ucontext) {
// Back up one instruction and have another go
ArchHelpers::Context::SetPc(ucontext, ArchHelpers::Context::GetPc(ucontext) - 4);
}
else if ((Instr & FEXCore::ArchHelpers::Arm64::LDAXP_MASK) == FEXCore::ArchHelpers::Arm64::LDAXP_INST) { // LDAXP
uint32_t DataReg2 = (Instr >> 10) & 0x1F;
// Convert to LDP
uint32_t LDP = 0b0010'1001'0100'0000'0000'0000'0000'0000;
LDP |= Size << 31;
LDP |= DataReg2 << 10;
LDP |= AddrReg << 5;
LDP |= DataReg;
PC[-1] = DMB;
PC[0] = LDP;
PC[1] = DMB;
// Back up one instruction and have another go
ArchHelpers::Context::SetPc(ucontext, ArchHelpers::Context::GetPc(ucontext) - 4);
}
else if ((Instr & FEXCore::ArchHelpers::Arm64::STLXP_MASK) == FEXCore::ArchHelpers::Arm64::STLXP_INST) { // STLXP
uint32_t DataReg2 = (Instr >> 10) & 0x1F;
// Convert to STP
uint32_t STP = 0b0010'1001'0000'0000'0000'0000'0000'0000;
STP |= Size << 31;
STP |= DataReg2 << 10;
STP |= AddrReg << 5;
STP |= DataReg;
PC[-1] = DMB;
PC[0] = STP;
PC[1] = DMB;
// Back up one instruction and have another go
ArchHelpers::Context::SetPc(ucontext, ArchHelpers::Context::GetPc(ucontext) - 4);
}
else if ((Instr & FEXCore::ArchHelpers::Arm64::CASPAL_MASK) == FEXCore::ArchHelpers::Arm64::CASPAL_INST) { // CASPAL
if (FEXCore::ArchHelpers::Arm64::HandleCASPAL(ucontext, info, Instr)) {
// Skip this instruction now
@@ -412,7 +441,7 @@ Arm64JITCore::Arm64JITCore(FEXCore::Context::Context *ctx, FEXCore::Core::Intern
config.ExitFunctionLinkThis = reinterpret_cast<uintptr_t>(this);
config.StaticRegisterAssignment = true;
Dispatcher = new Arm64Dispatcher(CTX, ThreadState, config);
Dispatcher = std::make_unique<Arm64Dispatcher>(CTX, ThreadState, config);
DispatchPtr = Dispatcher->DispatchPtr;
CallbackPtr = Dispatcher->CallbackPtr;
}
@@ -466,6 +495,7 @@ Arm64JITCore::Arm64JITCore(FEXCore::Context::Context *ctx, FEXCore::Core::Intern
if (!CompileThread) {
ThreadSharedData.SignalHandlerRefCounterPtr = &Dispatcher->SignalHandlerRefCounter;
ThreadSharedData.SignalReturnInstruction = Dispatcher->SignalHandlerReturnAddress;
ThreadSharedData.Dispatcher = Dispatcher.get();
// This will register the host signal handler per thread, which is fine
CTX->SignalDelegation->RegisterHostSignalHandler(SIGILL, [](FEXCore::Core::InternalThreadState *Thread, int Signal, void *info, void *ucontext) -> bool {
@@ -545,72 +575,76 @@ Arm64JITCore::~Arm64JITCore() {
FreeCodeBuffer(InitialCodeBuffer);
}
static IR::PhysicalRegister GetPhys(IR::RegisterAllocationData *RAData, uint32_t Node) {
IR::PhysicalRegister Arm64JITCore::GetPhys(uint32_t Node) {
auto PhyReg = RAData->GetNodeRegister(Node);
LogMan::Throw::A(!PhyReg.IsInvalid(), "Couldn't Allocate register for node: ssa%d. Class: %d", Node, PhyReg.Class);
LOGMAN_THROW_A(!PhyReg.IsInvalid(), "Couldn't Allocate register for node: ssa%d. Class: %d", Node, PhyReg.Class);
return PhyReg;
}
template<>
aarch64::Register Arm64JITCore::GetReg<Arm64JITCore::RA_32>(uint32_t Node) {
auto Reg = GetPhys(RAData, Node);
auto Reg = GetPhys(Node);
if (Reg.Class == IR::GPRFixedClass.Val) {
return SRA64[Reg.Reg].W();
} else if (Reg.Class == IR::GPRClass.Val) {
return RA64[Reg.Reg].W();
} else {
LogMan::Throw::A(false, "Unexpected Class: %d", Reg.Class);
LOGMAN_THROW_A(false, "Unexpected Class: %d", Reg.Class);
}
__builtin_unreachable();
}
template<>
aarch64::Register Arm64JITCore::GetReg<Arm64JITCore::RA_64>(uint32_t Node) {
auto Reg = GetPhys(RAData, Node);
auto Reg = GetPhys(Node);
if (Reg.Class == IR::GPRFixedClass.Val) {
return SRA64[Reg.Reg];
} else if (Reg.Class == IR::GPRClass.Val) {
return RA64[Reg.Reg];
} else {
LogMan::Throw::A(false, "Unexpected Class: %d", Reg.Class);
LOGMAN_THROW_A(false, "Unexpected Class: %d", Reg.Class);
}
__builtin_unreachable();
}
template<>
std::pair<aarch64::Register, aarch64::Register> Arm64JITCore::GetSrcPair<Arm64JITCore::RA_32>(uint32_t Node) {
uint32_t Reg = GetPhys(RAData, Node).Reg;
uint32_t Reg = GetPhys(Node).Reg;
return RA32Pair[Reg];
}
template<>
std::pair<aarch64::Register, aarch64::Register> Arm64JITCore::GetSrcPair<Arm64JITCore::RA_64>(uint32_t Node) {
uint32_t Reg = GetPhys(RAData, Node).Reg;
uint32_t Reg = GetPhys(Node).Reg;
return RA64Pair[Reg];
}
aarch64::VRegister Arm64JITCore::GetSrc(uint32_t Node) {
auto Reg = GetPhys(RAData, Node);
auto Reg = GetPhys(Node);
if (Reg.Class == IR::FPRFixedClass.Val) {
return SRAFPR[Reg.Reg];
} else if (Reg.Class == IR::FPRClass.Val) {
return RAFPR[Reg.Reg];
} else {
LogMan::Throw::A(false, "Unexpected Class: %d", Reg.Class);
LOGMAN_THROW_A(false, "Unexpected Class: %d", Reg.Class);
}
__builtin_unreachable();
}
aarch64::VRegister Arm64JITCore::GetDst(uint32_t Node) {
auto Reg = GetPhys(RAData, Node);
auto Reg = GetPhys(Node);
if (Reg.Class == IR::FPRFixedClass.Val) {
return SRAFPR[Reg.Reg];
} else if (Reg.Class == IR::FPRClass.Val) {
return RAFPR[Reg.Reg];
} else {
LogMan::Throw::A(false, "Unexpected Class: %d", Reg.Class);
LOGMAN_THROW_A(false, "Unexpected Class: %d", Reg.Class);
}
__builtin_unreachable();
}
@@ -635,7 +669,7 @@ bool Arm64JITCore::IsInlineEntrypointOffset(const IR::OrderedNodeWrapper& WNode,
if (OpHeader->Op == IR::IROps::OP_INLINEENTRYPOINTOFFSET) {
auto Op = OpHeader->C<IR::IROp_InlineEntrypointOffset>();
if (Value) {
*Value = IR->GetHeader()->Entry + Op->Offset;
*Value = Entry + Op->Offset;
}
return true;
} else {
@@ -644,7 +678,7 @@ bool Arm64JITCore::IsInlineEntrypointOffset(const IR::OrderedNodeWrapper& WNode,
}
FEXCore::IR::RegisterClassType Arm64JITCore::GetRegClass(uint32_t Node) {
return FEXCore::IR::RegisterClassType {GetPhys(RAData, Node).Class};
return FEXCore::IR::RegisterClassType {GetPhys(Node).Class};
}
@@ -660,17 +694,18 @@ bool Arm64JITCore::IsGPR(uint32_t Node) {
return Class == IR::GPRClass || Class == IR::GPRFixedClass;
}
void *Arm64JITCore::CompileCode([[maybe_unused]] FEXCore::IR::IRListView const *IR, [[maybe_unused]] FEXCore::Core::DebugData *DebugData, FEXCore::IR::RegisterAllocationData *RAData) {
void *Arm64JITCore::CompileCode(uint64_t Entry, [[maybe_unused]] FEXCore::IR::IRListView const *IR, [[maybe_unused]] FEXCore::Core::DebugData *DebugData, FEXCore::IR::RegisterAllocationData *RAData) {
using namespace aarch64;
JumpTargets.clear();
uint32_t SSACount = IR->GetSSACount();
this->Entry = Entry;
this->RAData = RAData;
auto HeaderOp = IR->GetHeader();
#ifndef NDEBUG
LoadConstant(x0, HeaderOp->Entry);
LoadConstant(x0, Entry);
#endif
this->IR = IR;
@@ -702,7 +737,7 @@ void *Arm64JITCore::CompileCode([[maybe_unused]] FEXCore::IR::IRListView const *
// X4-r18 = RA
auto Buffer = GetBuffer();
auto Entry = Buffer->GetOffsetAddress<uint64_t>(GetCursorOffset());
auto GuestEntry = Buffer->GetOffsetAddress<uint64_t>(GetCursorOffset());
if (CTX->GetGdbServerStatus()) {
aarch64::Label RunBlock;
@@ -719,17 +754,17 @@ void *Arm64JITCore::CompileCode([[maybe_unused]] FEXCore::IR::IRListView const *
cbz(w0, &RunBlock);
{
// Make sure RIP is syncronized to the context
LoadConstant(x0, HeaderOp->Entry);
LoadConstant(x0, Entry);
str(x0, MemOperand(STATE, offsetof(FEXCore::Core::CpuStateFrame, State.rip)));
// Stop the thread
LoadConstant(x0, Dispatcher->ThreadPauseHandlerAddressSpillSRA);
LoadConstant(x0, ThreadSharedData.Dispatcher->ThreadPauseHandlerAddressSpillSRA);
br(x0);
}
bind(&RunBlock);
}
//LogMan::Throw::A(RAData->HasFullRA(), "Arm64 JIT only works with RA");
//LOGMAN_THROW_A(RAData->HasFullRA(), "Arm64 JIT only works with RA");
SpillSlots = RAData->SpillSlots();
@@ -747,7 +782,7 @@ void *Arm64JITCore::CompileCode([[maybe_unused]] FEXCore::IR::IRListView const *
for (auto [BlockNode, BlockHeader] : IR->GetBlocks()) {
using namespace FEXCore::IR;
auto BlockIROp = BlockHeader->CW<FEXCore::IR::IROp_CodeBlock>();
LogMan::Throw::A(BlockIROp->Header.Op == IR::OP_CODEBLOCK, "IR type failed to be a code block");
LOGMAN_THROW_A(BlockIROp->Header.Op == IR::OP_CODEBLOCK, "IR type failed to be a code block");
{
uint32_t Node = IR->GetID(BlockNode);
@@ -793,15 +828,15 @@ void *Arm64JITCore::CompileCode([[maybe_unused]] FEXCore::IR::IRListView const *
FinalizeCode();
auto CodeEnd = Buffer->GetOffsetAddress<uint64_t>(GetCursorOffset());
CPU.EnsureIAndDCacheCoherency(reinterpret_cast<void*>(Entry), CodeEnd - reinterpret_cast<uint64_t>(Entry));
CPU.EnsureIAndDCacheCoherency(reinterpret_cast<void*>(GuestEntry), CodeEnd - reinterpret_cast<uint64_t>(GuestEntry));
if (DebugData) {
DebugData->HostCodeSize = reinterpret_cast<uintptr_t>(CodeEnd) - reinterpret_cast<uintptr_t>(Entry);
DebugData->HostCodeSize = reinterpret_cast<uintptr_t>(CodeEnd) - reinterpret_cast<uintptr_t>(GuestEntry);
}
this->IR = nullptr;
return reinterpret_cast<void*>(Entry);
return reinterpret_cast<void*>(GuestEntry);
}
uint64_t Arm64JITCore::ExitFunctionLink(Arm64JITCore *core, FEXCore::Core::CpuStateFrame *Frame, uint64_t *record) {
@@ -813,11 +848,11 @@ uint64_t Arm64JITCore::ExitFunctionLink(Arm64JITCore *core, FEXCore::Core::CpuSt
if (!HostCode) {
//printf("ExitFunctionLink: Aborting, %lX not in cache\n", GuestRip);
Frame->State.rip = GuestRip;
return core->Dispatcher->AbsoluteLoopTopAddress;
return core->ThreadSharedData.Dispatcher->AbsoluteLoopTopAddress;
}
uintptr_t branch = (uintptr_t)(record) - 8;
auto LinkerAddress = core->Dispatcher->ExitFunctionLinkerAddress;
auto LinkerAddress = core->ThreadSharedData.Dispatcher->ExitFunctionLinkerAddress;
auto offset = HostCode/4 - branch/4;
if (IsInt26(offset)) {
+11 -2
View File
@@ -47,7 +47,7 @@ public:
~Arm64JITCore() override;
std::string GetName() override { return "JIT"; }
void *CompileCode(FEXCore::IR::IRListView const *IR, FEXCore::Core::DebugData *DebugData, FEXCore::IR::RegisterAllocationData *RAData) override;
void *CompileCode(uint64_t Entry, FEXCore::IR::IRListView const *IR, FEXCore::Core::DebugData *DebugData, FEXCore::IR::RegisterAllocationData *RAData) override;
void *MapRegion(void* HostPtr, uint64_t, uint64_t) override { return HostPtr; }
@@ -63,11 +63,14 @@ public:
void CopyNecessaryDataForCompileThread(CPUBackend *Original) override;
private:
Dispatcher *Dispatcher;
FEX_CONFIG_OPT(ParanoidTSO, PARANOIDTSO);
std::unique_ptr<FEXCore::CPU::Dispatcher> Dispatcher;
Label *PendingTargetLabel;
FEXCore::Context::Context *CTX;
FEXCore::Core::InternalThreadState *ThreadState;
FEXCore::IR::IRListView const *IR;
uint64_t Entry;
std::map<IR::OrderedNodeWrapper::NodeOffsetType, aarch64::Label> JumpTargets;
@@ -113,6 +116,8 @@ private:
FEXCore::IR::RegisterClassType GetRegClass(uint32_t Node);
IR::PhysicalRegister GetPhys(uint32_t Node);
bool IsFPR(uint32_t Node);
bool IsGPR(uint32_t Node);
@@ -162,6 +167,7 @@ private:
uint64_t SignalReturnInstruction{};
uint32_t *SignalHandlerRefCounterPtr{};
FEXCore::CPU::Dispatcher *Dispatcher{};
};
CompilerSharedData ThreadSharedData;
@@ -300,8 +306,11 @@ private:
DEF_OP(StoreMem);
DEF_OP(LoadMemTSO);
DEF_OP(StoreMemTSO);
DEF_OP(ParanoidLoadMemTSO);
DEF_OP(ParanoidStoreMemTSO);
DEF_OP(VLoadMemElement);
DEF_OP(VStoreMemElement);
DEF_OP(CacheLineClear);
///< Misc ops
DEF_OP(EndBlock);
+226 -60
View File
@@ -29,7 +29,7 @@ DEF_OP(LoadContext) {
case 8:
ldr(GetReg<RA_64>(Node), MemOperand(STATE, Op->Offset));
break;
default: LogMan::Msg::A("Unhandled LoadContext size: %d", OpSize);
default: LOGMAN_MSG_A("Unhandled LoadContext size: %d", OpSize);
}
}
else {
@@ -50,7 +50,7 @@ DEF_OP(LoadContext) {
case 16:
ldr(Dst, MemOperand(STATE, Op->Offset));
break;
default: LogMan::Msg::A("Unhandled LoadContext size: %d", OpSize);
default: LOGMAN_MSG_A("Unhandled LoadContext size: %d", OpSize);
}
}
}
@@ -72,7 +72,7 @@ DEF_OP(StoreContext) {
case 8:
str(GetReg<RA_64>(Op->Header.Args[0].ID()), MemOperand(STATE, Op->Offset));
break;
default: LogMan::Msg::A("Unhandled StoreContext size: %d", OpSize);
default: LOGMAN_MSG_A("Unhandled StoreContext size: %d", OpSize);
}
}
else {
@@ -93,7 +93,7 @@ DEF_OP(StoreContext) {
case 16:
str(Src, MemOperand(STATE, Op->Offset));
break;
default: LogMan::Msg::A("Unhandled LoadContext size: %d", OpSize);
default: LOGMAN_MSG_A("Unhandled LoadContext size: %d", OpSize);
}
}
}
@@ -106,29 +106,29 @@ DEF_OP(LoadRegister) {
auto regId = (Op->Offset - offsetof(FEXCore::Core::CpuStateFrame, State.gregs[0])) / 8;
auto regOffs = Op->Offset & 7;
LogMan::Throw::A(regId < SRA64.size(), "out of range regId");
LOGMAN_THROW_A(regId < SRA64.size(), "out of range regId");
auto reg = SRA64[regId];
switch(Op->Header.Size) {
case 1:
LogMan::Throw::A(regOffs == 0 || regOffs == 1, "unexpected regOffs");
LOGMAN_THROW_A(regOffs == 0 || regOffs == 1, "unexpected regOffs");
ubfx(GetReg<RA_64>(Node), reg, regOffs * 8, 8);
break;
case 2:
LogMan::Throw::A(regOffs == 0, "unexpected regOffs");
LOGMAN_THROW_A(regOffs == 0, "unexpected regOffs");
ubfx(GetReg<RA_64>(Node), reg, 0, 16);
break;
case 4:
LogMan::Throw::A(regOffs == 0, "unexpected regOffs");
LOGMAN_THROW_A(regOffs == 0, "unexpected regOffs");
if (GetReg<RA_64>(Node).GetCode() != reg.GetCode())
mov(GetReg<RA_32>(Node), reg.W());
break;
case 8:
LogMan::Throw::A(regOffs == 0, "unexpected regOffs");
LOGMAN_THROW_A(regOffs == 0, "unexpected regOffs");
if (GetReg<RA_64>(Node).GetCode() != reg.GetCode())
mov(GetReg<RA_64>(Node), reg);
break;
@@ -137,24 +137,24 @@ DEF_OP(LoadRegister) {
auto regId = (Op->Offset - offsetof(FEXCore::Core::CpuStateFrame, State.xmm[0][0])) / 16;
auto regOffs = Op->Offset & 15;
LogMan::Throw::A(regId < SRAFPR.size(), "out of range regId");
LOGMAN_THROW_A(regId < SRAFPR.size(), "out of range regId");
auto guest = SRAFPR[regId];
auto host = GetSrc(Node);
switch(Op->Header.Size) {
case 1:
LogMan::Throw::A(regOffs == 0, "unexpected regOffs");
LOGMAN_THROW_A(regOffs == 0, "unexpected regOffs");
mov(host.B(), guest.B());
break;
case 2:
LogMan::Throw::A(regOffs == 0, "unexpected regOffs");
LOGMAN_THROW_A(regOffs == 0, "unexpected regOffs");
fmov(host.H(), guest.H());
break;
case 4:
LogMan::Throw::A((regOffs & 3) == 0, "unexpected regOffs");
LOGMAN_THROW_A((regOffs & 3) == 0, "unexpected regOffs");
if (regOffs == 0) {
if (host.GetCode() != guest.GetCode())
fmov(host.S(), guest.S());
@@ -164,7 +164,7 @@ DEF_OP(LoadRegister) {
break;
case 8:
LogMan::Throw::A((regOffs & 7) == 0, "unexpected regOffs");
LOGMAN_THROW_A((regOffs & 7) == 0, "unexpected regOffs");
if (regOffs == 0) {
if (host.GetCode() != guest.GetCode())
mov(host.D(), guest.D());
@@ -174,13 +174,13 @@ DEF_OP(LoadRegister) {
break;
case 16:
LogMan::Throw::A(regOffs == 0, "unexpected regOffs");
LOGMAN_THROW_A(regOffs == 0, "unexpected regOffs");
if (host.GetCode() != guest.GetCode())
mov(host.Q(), guest.Q());
break;
}
} else {
LogMan::Throw::A(false, "Unhandled Op->Class %d", Op->Class);
LOGMAN_THROW_A(false, "Unhandled Op->Class %d", Op->Class);
}
}
@@ -191,28 +191,28 @@ DEF_OP(StoreRegister) {
auto regId = Op->Offset / 8 - 1;
auto regOffs = Op->Offset & 7;
LogMan::Throw::A(regId < SRA64.size(), "out of range regId");
LOGMAN_THROW_A(regId < SRA64.size(), "out of range regId");
auto reg = SRA64[regId];
switch(Op->Header.Size) {
case 1:
LogMan::Throw::A(regOffs == 0 || regOffs == 1, "unexpected regOffs");
LOGMAN_THROW_A(regOffs == 0 || regOffs == 1, "unexpected regOffs");
bfi(reg, GetReg<RA_64>(Op->Value.ID()), regOffs * 8, 8);
break;
case 2:
LogMan::Throw::A(regOffs == 0, "unexpected regOffs");
LOGMAN_THROW_A(regOffs == 0, "unexpected regOffs");
bfi(reg, GetReg<RA_64>(Op->Value.ID()), 0, 16);
break;
case 4:
LogMan::Throw::A(regOffs == 0, "unexpected regOffs");
LOGMAN_THROW_A(regOffs == 0, "unexpected regOffs");
bfi(reg, GetReg<RA_64>(Op->Value.ID()), 0, 32);
break;
case 8:
LogMan::Throw::A(regOffs == 0, "unexpected regOffs");
LOGMAN_THROW_A(regOffs == 0, "unexpected regOffs");
if (GetReg<RA_64>(Op->Value.ID()).GetCode() != reg.GetCode())
mov(reg, GetReg<RA_64>(Op->Value.ID()));
break;
@@ -221,7 +221,7 @@ DEF_OP(StoreRegister) {
auto regId = (Op->Offset - offsetof(FEXCore::Core::CpuStateFrame, State.xmm[0][0])) / 16;
auto regOffs = Op->Offset & 15;
LogMan::Throw::A(regId < SRAFPR.size(), "regId out of range");
LOGMAN_THROW_A(regId < SRAFPR.size(), "regId out of range");
auto guest = SRAFPR[regId];
auto host = GetSrc(Op->Value.ID());
@@ -232,28 +232,28 @@ DEF_OP(StoreRegister) {
break;
case 2:
LogMan::Throw::A((regOffs & 1) == 0, "unexpected regOffs");
LOGMAN_THROW_A((regOffs & 1) == 0, "unexpected regOffs");
ins(guest.V8H(), regOffs/2, host.V8H(), 0);
break;
case 4:
LogMan::Throw::A((regOffs & 3) == 0, "unexpected regOffs");
LOGMAN_THROW_A((regOffs & 3) == 0, "unexpected regOffs");
ins(guest.V4S(), regOffs/4, host.V4S(), 0);
break;
case 8:
LogMan::Throw::A((regOffs & 7) == 0, "unexpected regOffs");
LOGMAN_THROW_A((regOffs & 7) == 0, "unexpected regOffs");
ins(guest.V2D(), regOffs / 8, host.V2D(), 0);
break;
case 16:
LogMan::Throw::A(regOffs == 0, "unexpected regOffs");
LOGMAN_THROW_A(regOffs == 0, "unexpected regOffs");
if (guest.GetCode() != host.GetCode())
mov(guest.Q(), host.Q());
break;
}
} else {
LogMan::Throw::A(false, "Unhandled Op->Class %d", Op->Class);
LOGMAN_THROW_A(false, "Unhandled Op->Class %d", Op->Class);
}
}
@@ -287,15 +287,15 @@ DEF_OP(LoadContextIndexed) {
ldr(GetReg<RA_64>(Node), MemOperand(TMP1, Op->BaseOffset));
break;
default:
LogMan::Msg::A("Unhandled LoadContextIndexed size: %d", Op->Size);
LOGMAN_MSG_A("Unhandled LoadContextIndexed size: %d", Op->Size);
}
break;
}
case 16:
LogMan::Msg::A("Invalid Class load of size 16");
LOGMAN_MSG_A("Invalid Class load of size 16");
break;
default:
LogMan::Msg::A("Unhandled LoadContextIndexed stride: %d", Op->Stride);
LOGMAN_MSG_A("Unhandled LoadContextIndexed stride: %d", Op->Stride);
}
}
else {
@@ -332,12 +332,12 @@ DEF_OP(LoadContextIndexed) {
}
break;
default:
LogMan::Msg::A("Unhandled LoadContextIndexed size: %d", Op->Size);
LOGMAN_MSG_A("Unhandled LoadContextIndexed size: %d", Op->Size);
}
break;
}
default:
LogMan::Msg::A("Unhandled LoadContextIndexed stride: %d", Op->Stride);
LOGMAN_MSG_A("Unhandled LoadContextIndexed stride: %d", Op->Stride);
}
}
}
@@ -373,15 +373,15 @@ DEF_OP(StoreContextIndexed) {
str(value, MemOperand(TMP1, Op->BaseOffset));
break;
default:
LogMan::Msg::A("Unhandled LoadContextIndexed size: %d", Op->Size);
LOGMAN_MSG_A("Unhandled LoadContextIndexed size: %d", Op->Size);
}
break;
}
case 16:
LogMan::Msg::A("Invalid Class load of size 16");
LOGMAN_MSG_A("Invalid Class load of size 16");
break;
default:
LogMan::Msg::A("Unhandled LoadContextIndexed stride: %d", Op->Stride);
LOGMAN_MSG_A("Unhandled LoadContextIndexed stride: %d", Op->Stride);
}
}
else {
@@ -420,12 +420,12 @@ DEF_OP(StoreContextIndexed) {
}
break;
default:
LogMan::Msg::A("Unhandled LoadContextIndexed size: %d", Op->Size);
LOGMAN_MSG_A("Unhandled LoadContextIndexed size: %d", Op->Size);
}
break;
}
default:
LogMan::Msg::A("Unhandled LoadContextIndexed stride: %d", Op->Stride);
LOGMAN_MSG_A("Unhandled LoadContextIndexed stride: %d", Op->Stride);
}
}
}
@@ -453,7 +453,7 @@ DEF_OP(SpillRegister) {
str(GetReg<RA_64>(Op->Header.Args[0].ID()), MemOperand(sp, SlotOffset));
break;
}
default: LogMan::Msg::A("Unhandled SpillRegister size: %d", OpSize);
default: LOGMAN_MSG_A("Unhandled SpillRegister size: %d", OpSize);
}
} else if (Op->Class == FEXCore::IR::FPRClass) {
switch (OpSize) {
@@ -469,10 +469,10 @@ DEF_OP(SpillRegister) {
str(GetSrc(Op->Header.Args[0].ID()), MemOperand(sp, SlotOffset));
break;
}
default: LogMan::Msg::A("Unhandled SpillRegister size: %d", OpSize);
default: LOGMAN_MSG_A("Unhandled SpillRegister size: %d", OpSize);
}
} else {
LogMan::Msg::A("Unhandled SpillRegister class: %d", Op->Class.Val);
LOGMAN_MSG_A("Unhandled SpillRegister class: %d", Op->Class.Val);
}
}
@@ -499,7 +499,7 @@ DEF_OP(FillRegister) {
ldr(GetReg<RA_64>(Node), MemOperand(sp, SlotOffset));
break;
}
default: LogMan::Msg::A("Unhandled SpillRegister size: %d", OpSize);
default: LOGMAN_MSG_A("Unhandled SpillRegister size: %d", OpSize);
}
} else if (Op->Class == FEXCore::IR::FPRClass) {
switch (OpSize) {
@@ -515,10 +515,10 @@ DEF_OP(FillRegister) {
ldr(GetDst(Node), MemOperand(sp, SlotOffset));
break;
}
default: LogMan::Msg::A("Unhandled SpillRegister size: %d", OpSize);
default: LOGMAN_MSG_A("Unhandled SpillRegister size: %d", OpSize);
}
} else {
LogMan::Msg::A("Unhandled FillRegister class: %d", Op->Class.Val);
LOGMAN_MSG_A("Unhandled FillRegister class: %d", Op->Class.Val);
}
}
@@ -538,7 +538,7 @@ MemOperand Arm64JITCore::GenerateMemOperand(uint8_t AccessSize, aarch64::Registe
return MemOperand(Base);
} else {
if (OffsetScale != 1 && OffsetScale != AccessSize) {
LogMan::Msg::A("Unhandled GenerateMemOperand OffsetScale: %d", OffsetScale);
LOGMAN_MSG_A("Unhandled GenerateMemOperand OffsetScale: %d", OffsetScale);
}
uint64_t Const;
if (IsInlineConstant(Offset, &Const)) {
@@ -550,7 +550,7 @@ MemOperand Arm64JITCore::GenerateMemOperand(uint8_t AccessSize, aarch64::Registe
case IR::MEM_OFFSET_UXTW.Val: return MemOperand(Base, RegOffset.W(), Extend::UXTW, (int)std::log2(OffsetScale) );
case IR::MEM_OFFSET_SXTW.Val: return MemOperand(Base, RegOffset.W(), Extend::SXTW, (int)std::log2(OffsetScale) );
default: LogMan::Msg::A("Unhandled GenerateMemOperand OffsetType: %d", OffsetType.Val); break;
default: LOGMAN_MSG_A("Unhandled GenerateMemOperand OffsetType: %d", OffsetType.Val); break;
}
}
}
@@ -578,7 +578,7 @@ DEF_OP(LoadMem) {
case 8:
ldr(Dst, MemSrc);
break;
default: LogMan::Msg::A("Unhandled LoadMem size: %d", Op->Size);
default: LOGMAN_MSG_A("Unhandled LoadMem size: %d", Op->Size);
}
}
else {
@@ -599,7 +599,7 @@ DEF_OP(LoadMem) {
case 16:
ldr(Dst, MemSrc);
break;
default: LogMan::Msg::A("Unhandled LoadMem size: %d", Op->Size);
default: LOGMAN_MSG_A("Unhandled LoadMem size: %d", Op->Size);
}
}
}
@@ -610,7 +610,7 @@ DEF_OP(LoadMemTSO) {
auto MemSrc = MemOperand(GetReg<RA_64>(Op->Header.Args[0].ID()));
if (!Op->Offset.IsInvalid()) {
LogMan::Msg::A("LoadMemTSO: No offset allowed");
LOGMAN_MSG_A("LoadMemTSO: No offset allowed");
}
if (SupportsRCPC && Op->Class == FEXCore::IR::GPRClass) {
@@ -633,7 +633,7 @@ DEF_OP(LoadMemTSO) {
case 8:
ldapr(Dst, MemSrc);
break;
default: LogMan::Msg::A("Unhandled LoadMem size: %d", Op->Size);
default: LOGMAN_MSG_A("Unhandled LoadMem size: %d", Op->Size);
}
nop();
}
@@ -658,7 +658,7 @@ DEF_OP(LoadMemTSO) {
case 8:
ldar(Dst, MemSrc);
break;
default: LogMan::Msg::A("Unhandled LoadMem size: %d", Op->Size);
default: LOGMAN_MSG_A("Unhandled LoadMem size: %d", Op->Size);
}
nop();
}
@@ -679,7 +679,7 @@ DEF_OP(LoadMemTSO) {
case 16:
ldr(Dst, MemSrc);
break;
default: LogMan::Msg::A("Unhandled LoadMem size: %d", Op->Size);
default: LOGMAN_MSG_A("Unhandled LoadMem size: %d", Op->Size);
}
dmb(InnerShareable, BarrierAll);
}
@@ -706,7 +706,7 @@ DEF_OP(StoreMem) {
case 8:
str(GetReg<RA_64>(Op->Header.Args[1].ID()), MemSrc);
break;
default: LogMan::Msg::A("Unhandled StoreMem size: %d", Op->Size);
default: LOGMAN_MSG_A("Unhandled StoreMem size: %d", Op->Size);
}
}
else {
@@ -727,7 +727,7 @@ DEF_OP(StoreMem) {
case 16:
str(Src, MemSrc);
break;
default: LogMan::Msg::A("Unhandled StoreMem size: %d", Op->Size);
default: LOGMAN_MSG_A("Unhandled StoreMem size: %d", Op->Size);
}
}
}
@@ -737,7 +737,7 @@ DEF_OP(StoreMemTSO) {
auto MemSrc = MemOperand(GetReg<RA_64>(Op->Header.Args[0].ID()));
if (!Op->Offset.IsInvalid()) {
LogMan::Msg::A("StoreMemTSO: No offset allowed");
LOGMAN_MSG_A("StoreMemTSO: No offset allowed");
}
if (Op->Class == FEXCore::IR::GPRClass) {
@@ -757,7 +757,7 @@ DEF_OP(StoreMemTSO) {
case 8:
stlr(GetReg<RA_64>(Op->Header.Args[1].ID()), MemSrc);
break;
default: LogMan::Msg::A("Unhandled StoreMem size: %d", Op->Size);
default: LOGMAN_MSG_A("Unhandled StoreMem size: %d", Op->Size);
}
nop();
}
@@ -781,18 +781,177 @@ DEF_OP(StoreMemTSO) {
case 16:
str(Src, MemSrc);
break;
default: LogMan::Msg::A("Unhandled StoreMem size: %d", Op->Size);
default: LOGMAN_MSG_A("Unhandled StoreMem size: %d", Op->Size);
}
dmb(InnerShareable, BarrierAll);
}
}
DEF_OP(ParanoidLoadMemTSO) {
auto Op = IROp->C<IR::IROp_LoadMemTSO>();
auto MemSrc = MemOperand(GetReg<RA_64>(Op->Header.Args[0].ID()));
if (!Op->Offset.IsInvalid()) {
LOGMAN_MSG_A("LoadMemTSO: No offset allowed");
}
if (Op->Class == FEXCore::IR::GPRClass) {
if (Op->Size == 1) {
// 8bit load is always aligned to natural alignment
auto Dst = GetReg<RA_64>(Node);
ldarb(Dst, MemSrc);
}
else {
auto Dst = GetReg<RA_64>(Node);
nop();
switch (Op->Size) {
case 2:
ldarh(Dst, MemSrc);
break;
case 4:
ldar(Dst.W(), MemSrc);
break;
case 8:
ldar(Dst, MemSrc);
break;
default: LOGMAN_MSG_A("Unhandled LoadMem size: %d", Op->Size);
}
nop();
}
}
else {
auto Dst = GetDst(Node);
switch (Op->Size) {
case 2:
nop();
ldarh(TMP1, MemSrc);
nop();
fmov(Dst, TMP1);
break;
case 4:
nop();
ldar(TMP1.W(), MemSrc);
nop();
fmov(Dst, TMP1);
break;
case 8:
nop();
ldar(TMP1, MemSrc);
nop();
fmov(Dst, TMP1);
break;
case 16:
nop();
ldaxp(TMP1, TMP2, MemSrc);
clrex();
mov(Dst.V2D(), 0, TMP1);
mov(Dst.V2D(), 1, TMP2);
break;
default: LOGMAN_MSG_A("Unhandled LoadMem size: %d", Op->Size);
}
}
}
DEF_OP(ParanoidStoreMemTSO) {
auto Op = IROp->C<IR::IROp_StoreMemTSO>();
auto MemSrc = MemOperand(GetReg<RA_64>(Op->Header.Args[0].ID()));
if (!Op->Offset.IsInvalid()) {
LOGMAN_MSG_A("StoreMemTSO: No offset allowed");
}
if (Op->Class == FEXCore::IR::GPRClass) {
if (Op->Size == 1) {
// 8bit load is always aligned to natural alignment
stlrb(GetReg<RA_64>(Op->Header.Args[1].ID()), MemSrc);
}
else {
nop();
switch (Op->Size) {
case 2:
stlrh(GetReg<RA_64>(Op->Header.Args[1].ID()), MemSrc);
break;
case 4:
stlr(GetReg<RA_32>(Op->Header.Args[1].ID()), MemSrc);
break;
case 8:
stlr(GetReg<RA_64>(Op->Header.Args[1].ID()), MemSrc);
break;
default: LOGMAN_MSG_A("Unhandled StoreMem size: %d", Op->Size);
}
nop();
}
}
else {
auto Src = GetSrc(Op->Header.Args[1].ID());
if (Op->Size == 1) {
// 8bit load is always aligned to natural alignment
mov(TMP1, Src.V4S(), 0);
stlrb(TMP1, MemSrc);
}
else {
switch (Op->Size) {
case 2:
mov(TMP1, Src.V4S(), 0);
nop();
stlrh(TMP1, MemSrc);
nop();
break;
case 4:
mov(TMP1, Src.V4S(), 0);
nop();
stlr(TMP1.W(), MemSrc);
nop();
break;
case 8:
mov(TMP1, Src.V2D(), 0);
nop();
stlr(TMP1, MemSrc);
nop();
break;
case 16: {
// Move vector to GPRs
mov(TMP1, Src.V2D(), 0);
mov(TMP2, Src.V2D(), 1);
Label B;
bind(&B);
nop(); // < Overwritten with DMB
// ldaxp must not have both the destination registers be the same
ldaxp(xzr, TMP3, MemSrc); // <- Can hit SIGBUS
nop(); // < Overwritten with DMB
stlxp(TMP3, TMP1, TMP2, MemSrc); // <- Can also hit SIGBUS
cbnz(TMP3, &B); // < Overwritten with DMB
break;
}
default: LOGMAN_MSG_A("Unhandled StoreMem size: %d", Op->Size);
}
}
}
}
DEF_OP(VLoadMemElement) {
LogMan::Msg::A("Unimplemented");
LOGMAN_MSG_A("Unimplemented");
}
DEF_OP(VStoreMemElement) {
LogMan::Msg::A("Unimplemented");
LOGMAN_MSG_A("Unimplemented");
}
DEF_OP(CacheLineClear) {
auto Op = IROp->C<IR::IROp_CacheLineClear>();
auto MemReg = GetReg<RA_64>(Op->Header.Args[0].ID());
// Clear dcache only
// icache doesn't matter here since the guest application shouldn't be calling clflush on JIT code.
mov(TMP1, MemReg);
for (size_t i = 0; i < std::max(1U, DCacheLineSize / 64U); ++i) {
dc(DataCacheOp::CVAU, TMP1);
add(TMP1, TMP1, DCacheLineSize);
}
dsb(InnerShareable, BarrierAll);
}
#undef DEF_OP
@@ -810,10 +969,17 @@ void Arm64JITCore::RegisterMemoryHandlers() {
REGISTER_OP(STOREFLAG, StoreFlag);
REGISTER_OP(LOADMEM, LoadMem);
REGISTER_OP(STOREMEM, StoreMem);
REGISTER_OP(LOADMEMTSO, LoadMemTSO);
REGISTER_OP(STOREMEMTSO, StoreMemTSO);
if (ParanoidTSO()) {
REGISTER_OP(LOADMEMTSO, ParanoidLoadMemTSO);
REGISTER_OP(STOREMEMTSO, ParanoidStoreMemTSO);
}
else {
REGISTER_OP(LOADMEMTSO, LoadMemTSO);
REGISTER_OP(STOREMEMTSO, StoreMemTSO);
}
REGISTER_OP(VLOADMEMELEMENT, VLoadMemElement);
REGISTER_OP(VSTOREMEMELEMENT, VStoreMemElement);
REGISTER_OP(CACHELINECLEAR, CacheLineClear);
#undef REGISTER_OP
}
}
@@ -7,6 +7,13 @@ $end_info$
#include "Interface/Core/JIT/Arm64/JITClass.h"
namespace FEXCore::CPU {
static void PrintValue(uint64_t Value) {
LogMan::Msg::D("Value: 0x%lx", Value);
}
static void PrintVectorValue(uint64_t Value, uint64_t ValueUpper) {
LogMan::Msg::D("Value: 0x%016lx'%016lx", ValueUpper, Value);
}
using namespace vixl;
using namespace vixl::aarch64;
@@ -24,7 +31,7 @@ DEF_OP(Fence) {
case IR::Fence_Store.Val:
dmb(FullSystem, BarrierWrites);
break;
default: LogMan::Msg::A("Unknown Fence: %d", Op->Fence); break;
default: LOGMAN_MSG_A("Unknown Fence: %d", Op->Fence); break;
}
}
@@ -35,6 +42,15 @@ DEF_OP(Break) {
case 5: // Guest ud2
hlt(4);
break;
case 1: // Int <imm8>
hlt(4);
break;
case 2: // overflow
hlt(4);
break;
case 3: // int 1
hlt(4);
break;
case 4: { // HLT
// Time to quit
// Set our stack to the starting stack location
@@ -42,18 +58,18 @@ DEF_OP(Break) {
add(sp, TMP1, 0);
// Now we need to jump to the thread stop handler
LoadConstant(TMP1, Dispatcher->ThreadStopHandlerAddressSpillSRA);
LoadConstant(TMP1, ThreadSharedData.Dispatcher->ThreadStopHandlerAddressSpillSRA);
br(TMP1);
break;
}
case 6: { // INT3
ResetStack();
LoadConstant(TMP1, Dispatcher->ThreadPauseHandlerAddressSpillSRA);
LoadConstant(TMP1, ThreadSharedData.Dispatcher->ThreadPauseHandlerAddressSpillSRA);
br(TMP1);
break;
}
default: LogMan::Msg::A("Unknown Break reason: %d", Op->Reason);
default: LOGMAN_MSG_A("Unknown Break reason: %d", Op->Reason);
}
}
@@ -115,6 +131,28 @@ DEF_OP(SetRoundingMode) {
msr(FPCR, TMP1);
}
DEF_OP(Print) {
auto Op = IROp->C<IR::IROp_Print>();
PushDynamicRegsAndLR();
if (IsGPR(Op->Header.Args[0].ID())) {
mov(x0, GetReg<RA_64>(Op->Header.Args[0].ID()));
LoadConstant(x3, reinterpret_cast<uint64_t>(PrintValue));
}
else {
fmov(x0, GetSrc(Op->Header.Args[0].ID()).V1D());
// Bug in vixl that source vector needs to b V1D rather than V2D?
fmov(x1, GetSrc(Op->Header.Args[0].ID()).V1D(), 1);
LoadConstant(x3, reinterpret_cast<uint64_t>(PrintVectorValue));
}
SpillStaticRegs();
blr(x3);
FillStaticRegs();
PopDynamicRegsAndLR();
}
#undef DEF_OP
void Arm64JITCore::RegisterMiscHandlers() {
#define REGISTER_OP(op, x) OpHandlers[FEXCore::IR::IROps::OP_##op] = &Arm64JITCore::Op_##x
@@ -127,7 +165,7 @@ void Arm64JITCore::RegisterMiscHandlers() {
REGISTER_OP(BREAK, Break);
REGISTER_OP(PHI, NoOp);
REGISTER_OP(PHIVALUE, NoOp);
REGISTER_OP(PRINT, Unhandled);
REGISTER_OP(PRINT, Print);
REGISTER_OP(GETROUNDINGMODE, GetRoundingMode);
REGISTER_OP(SETROUNDINGMODE, SetRoundingMode);
REGISTER_OP(INVALIDATEFLAGS, NoOp);
@@ -26,7 +26,7 @@ DEF_OP(ExtractElementPair) {
mov (GetReg<RA_64>(Node), Regs[Op->Element]);
break;
}
default: LogMan::Msg::A("Unknown Size"); break;
default: LOGMAN_MSG_A("Unknown Size"); break;
}
}
@@ -52,7 +52,7 @@ DEF_OP(CreateElementPair) {
RegTmp = x0;
break;
}
default: LogMan::Msg::A("Unknown Size"); break;
default: LOGMAN_MSG_A("Unknown Size"); break;
}
if (Dst.first.GetCode() != RegSecond.GetCode()) {
+151 -116
View File
@@ -22,7 +22,7 @@ DEF_OP(VectorZero) {
eor(GetDst(Node).V16B(), GetDst(Node).V16B(), GetDst(Node).V16B());
break;
}
default: LogMan::Msg::A("Unknown Element Size: %d", OpSize); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", OpSize); break;
}
}
@@ -32,21 +32,28 @@ DEF_OP(VectorImm) {
uint8_t OpSize = IROp->Size;
uint8_t Elements = OpSize / Op->Header.ElementSize;
movi(GetDst(Node).VCast(OpSize * 8, Elements), Op->Immediate);
if (Op->Header.ElementSize == 8) {
// movi with 64bit element size doesn't do what we want here
LoadConstant(TMP1.X(), Op->Immediate);
dup(GetDst(Node).V2D(), TMP1.X());
}
else {
movi(GetDst(Node).VCast(OpSize * 8, Elements), Op->Immediate);
}
}
DEF_OP(CreateVector2) {
LogMan::Msg::A("Unimplemented");
LOGMAN_MSG_A("Unimplemented");
}
DEF_OP(CreateVector4) {
LogMan::Msg::A("Unimplemented");
LOGMAN_MSG_A("Unimplemented");
}
DEF_OP(SplatVector2) {
auto Op = IROp->C<IR::IROp_SplatVector2>();
uint8_t OpSize = IROp->Size;
LogMan::Throw::A(OpSize <= 16, "Can't handle a vector of size: %d", OpSize);
LOGMAN_THROW_A(OpSize <= 16, "Can't handle a vector of size: %d", OpSize);
uint8_t ElementSize = OpSize / 2;
@@ -57,14 +64,14 @@ DEF_OP(SplatVector2) {
case 8:
dup(GetDst(Node).V2D(), GetSrc(Op->Header.Args[0].ID()).V2D(), 0);
break;
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.Size); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.Size); break;
}
}
DEF_OP(SplatVector4) {
auto Op = IROp->C<IR::IROp_SplatVector4>();
uint8_t OpSize = IROp->Size;
LogMan::Throw::A(OpSize <= 16, "Can't handle a vector of size: %d", OpSize);
LOGMAN_THROW_A(OpSize <= 16, "Can't handle a vector of size: %d", OpSize);
uint8_t ElementSize = OpSize / 4;
@@ -75,7 +82,7 @@ DEF_OP(SplatVector4) {
case 8:
dup(GetDst(Node).V2D(), GetSrc(Op->Header.Args[0].ID()).V2D(), 0);
break;
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.Size); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.Size); break;
}
}
@@ -111,7 +118,7 @@ DEF_OP(VMov) {
mov(GetDst(Node).V16B(), GetSrc(Op->Header.Args[0].ID()).V16B());
break;
}
default: LogMan::Msg::A("Unknown Element Size: %d", OpSize); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", OpSize); break;
}
}
@@ -149,7 +156,7 @@ DEF_OP(VAdd) {
add(GetDst(Node).V2D(), GetSrc(Op->Header.Args[0].ID()).V2D(), GetSrc(Op->Header.Args[1].ID()).V2D());
break;
}
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
}
}
@@ -172,7 +179,7 @@ DEF_OP(VSub) {
sub(GetDst(Node).V2D(), GetSrc(Op->Header.Args[0].ID()).V2D(), GetSrc(Op->Header.Args[1].ID()).V2D());
break;
}
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
}
}
@@ -195,7 +202,7 @@ DEF_OP(VUQAdd) {
uqadd(GetDst(Node).V2D(), GetSrc(Op->Header.Args[0].ID()).V2D(), GetSrc(Op->Header.Args[1].ID()).V2D());
break;
}
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
}
}
@@ -218,7 +225,7 @@ DEF_OP(VUQSub) {
uqsub(GetDst(Node).V2D(), GetSrc(Op->Header.Args[0].ID()).V2D(), GetSrc(Op->Header.Args[1].ID()).V2D());
break;
}
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
}
}
@@ -241,7 +248,7 @@ DEF_OP(VSQAdd) {
sqadd(GetDst(Node).V2D(), GetSrc(Op->Header.Args[0].ID()).V2D(), GetSrc(Op->Header.Args[1].ID()).V2D());
break;
}
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
}
}
@@ -264,7 +271,7 @@ DEF_OP(VSQSub) {
sqsub(GetDst(Node).V2D(), GetSrc(Op->Header.Args[0].ID()).V2D(), GetSrc(Op->Header.Args[1].ID()).V2D());
break;
}
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
}
}
@@ -286,7 +293,7 @@ DEF_OP(VAddP) {
addp(GetDst(Node).V2S(), GetSrc(Op->Header.Args[0].ID()).V2S(), GetSrc(Op->Header.Args[1].ID()).V2S());
break;
}
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
}
}
else {
@@ -307,7 +314,7 @@ DEF_OP(VAddP) {
addp(GetDst(Node).V2D(), GetSrc(Op->Header.Args[0].ID()).V2D(), GetSrc(Op->Header.Args[1].ID()).V2D());
break;
}
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
}
}
}
@@ -326,7 +333,7 @@ DEF_OP(VAddV) {
case 8:
addp(GetDst(Node).VCast(OpSize * 8, 1), GetSrc(Op->Header.Args[0].ID()).VCast(OpSize * 8, Elements));
break;
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
}
}
@@ -341,7 +348,7 @@ DEF_OP(VURAvg) {
urhadd(GetDst(Node).V8H(), GetSrc(Op->Header.Args[0].ID()).V8H(), GetSrc(Op->Header.Args[1].ID()).V8H());
break;
}
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
}
}
@@ -356,7 +363,7 @@ DEF_OP(VAbs) {
abs(GetDst(Node).D(), GetSrc(Op->Header.Args[0].ID()).D());
break;
}
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
}
}
else {
@@ -368,7 +375,7 @@ DEF_OP(VAbs) {
case 8:
abs(GetDst(Node).VCast(OpSize * 8, Elements), GetSrc(Op->Header.Args[0].ID()).VCast(OpSize * 8, Elements));
break;
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
}
}
}
@@ -387,7 +394,7 @@ DEF_OP(VFAdd) {
fadd(GetDst(Node).D(), GetSrc(Op->Header.Args[0].ID()).D(), GetSrc(Op->Header.Args[1].ID()).D());
break;
}
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
}
}
else {
@@ -401,7 +408,7 @@ DEF_OP(VFAdd) {
fadd(GetDst(Node).V2D(), GetSrc(Op->Header.Args[0].ID()).V2D(), GetSrc(Op->Header.Args[1].ID()).V2D());
break;
}
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
}
}
}
@@ -417,7 +424,7 @@ DEF_OP(VFAddP) {
faddp(GetDst(Node).V2D(), GetSrc(Op->Header.Args[0].ID()).V2D(), GetSrc(Op->Header.Args[1].ID()).V2D());
break;
}
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
}
}
@@ -435,7 +442,7 @@ DEF_OP(VFSub) {
fsub(GetDst(Node).D(), GetSrc(Op->Header.Args[0].ID()).D(), GetSrc(Op->Header.Args[1].ID()).D());
break;
}
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
}
}
else {
@@ -449,7 +456,7 @@ DEF_OP(VFSub) {
fsub(GetDst(Node).V2D(), GetSrc(Op->Header.Args[0].ID()).V2D(), GetSrc(Op->Header.Args[1].ID()).V2D());
break;
}
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
}
}
}
@@ -468,7 +475,7 @@ DEF_OP(VFMul) {
fmul(GetDst(Node).D(), GetSrc(Op->Header.Args[0].ID()).D(), GetSrc(Op->Header.Args[1].ID()).D());
break;
}
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
}
}
else {
@@ -482,7 +489,7 @@ DEF_OP(VFMul) {
fmul(GetDst(Node).V2D(), GetSrc(Op->Header.Args[0].ID()).V2D(), GetSrc(Op->Header.Args[1].ID()).V2D());
break;
}
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
}
}
}
@@ -501,7 +508,7 @@ DEF_OP(VFDiv) {
fdiv(GetDst(Node).D(), GetSrc(Op->Header.Args[0].ID()).D(), GetSrc(Op->Header.Args[1].ID()).D());
break;
}
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
}
}
else {
@@ -515,7 +522,7 @@ DEF_OP(VFDiv) {
fdiv(GetDst(Node).V2D(), GetSrc(Op->Header.Args[0].ID()).V2D(), GetSrc(Op->Header.Args[1].ID()).V2D());
break;
}
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
}
}
}
@@ -527,28 +534,36 @@ DEF_OP(VFMin) {
// Scalar
switch (Op->Header.ElementSize) {
case 4: {
fmin(GetDst(Node).S(), GetSrc(Op->Header.Args[0].ID()).S(), GetSrc(Op->Header.Args[1].ID()).S());
fcmp(GetSrc(Op->Header.Args[0].ID()).S(), GetSrc(Op->Header.Args[1].ID()).S());
fcsel(GetDst(Node).S(), GetSrc(Op->Header.Args[0].ID()).S(), GetSrc(Op->Header.Args[1].ID()).S(), Condition::mi);
break;
}
case 8: {
fmin(GetDst(Node).D(), GetSrc(Op->Header.Args[0].ID()).D(), GetSrc(Op->Header.Args[1].ID()).D());
fcmp(GetSrc(Op->Header.Args[0].ID()).D(), GetSrc(Op->Header.Args[1].ID()).D());
fcsel(GetDst(Node).D(), GetSrc(Op->Header.Args[0].ID()).D(), GetSrc(Op->Header.Args[1].ID()).D(), Condition::mi);
break;
}
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
}
}
else {
// Vector
switch (Op->Header.ElementSize) {
case 4: {
fmin(GetDst(Node).V4S(), GetSrc(Op->Header.Args[0].ID()).V4S(), GetSrc(Op->Header.Args[1].ID()).V4S());
fcmgt(VTMP1.V4S(), GetSrc(Op->Header.Args[1].ID()).V4S(), GetSrc(Op->Header.Args[0].ID()).V4S());
mov(VTMP2.V4S(), GetSrc(Op->Header.Args[0].ID()).V4S());
bif(VTMP2.V16B(), GetSrc(Op->Header.Args[1].ID()).V16B(), VTMP1.V16B());
mov(GetDst(Node).V4S(), VTMP2.V4S());
break;
}
case 8: {
fmin(GetDst(Node).V2D(), GetSrc(Op->Header.Args[0].ID()).V2D(), GetSrc(Op->Header.Args[1].ID()).V2D());
fcmgt(VTMP1.V2D(), GetSrc(Op->Header.Args[1].ID()).V2D(), GetSrc(Op->Header.Args[0].ID()).V2D());
mov(VTMP2.V2D(), GetSrc(Op->Header.Args[0].ID()).V2D());
bif(VTMP2.V16B(), GetSrc(Op->Header.Args[1].ID()).V16B(), VTMP1.V16B());
mov(GetDst(Node).V2D(), VTMP2.V2D());
break;
}
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
}
}
}
@@ -560,28 +575,36 @@ DEF_OP(VFMax) {
// Scalar
switch (Op->Header.ElementSize) {
case 4: {
fmax(GetDst(Node).S(), GetSrc(Op->Header.Args[0].ID()).S(), GetSrc(Op->Header.Args[1].ID()).S());
fcmp(GetSrc(Op->Header.Args[0].ID()).S(), GetSrc(Op->Header.Args[1].ID()).S());
fcsel(GetDst(Node).S(), GetSrc(Op->Header.Args[1].ID()).S(), GetSrc(Op->Header.Args[0].ID()).S(), Condition::mi);
break;
}
case 8: {
fmax(GetDst(Node).D(), GetSrc(Op->Header.Args[0].ID()).D(), GetSrc(Op->Header.Args[1].ID()).D());
fcmp(GetSrc(Op->Header.Args[0].ID()).D(), GetSrc(Op->Header.Args[1].ID()).D());
fcsel(GetDst(Node).D(), GetSrc(Op->Header.Args[1].ID()).D(), GetSrc(Op->Header.Args[0].ID()).D(), Condition::mi);
break;
}
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
}
}
else {
// Vector
switch (Op->Header.ElementSize) {
case 4: {
fmax(GetDst(Node).V4S(), GetSrc(Op->Header.Args[0].ID()).V4S(), GetSrc(Op->Header.Args[1].ID()).V4S());
fcmgt(VTMP1.V4S(), GetSrc(Op->Header.Args[1].ID()).V4S(), GetSrc(Op->Header.Args[0].ID()).V4S());
mov(VTMP2.V4S(), GetSrc(Op->Header.Args[0].ID()).V4S());
bit(VTMP2.V16B(), GetSrc(Op->Header.Args[1].ID()).V16B(), VTMP1.V16B());
mov(GetDst(Node).V4S(), VTMP2.V4S());
break;
}
case 8: {
fmax(GetDst(Node).V2D(), GetSrc(Op->Header.Args[0].ID()).V2D(), GetSrc(Op->Header.Args[1].ID()).V2D());
fcmgt(VTMP1.V2D(), GetSrc(Op->Header.Args[1].ID()).V2D(), GetSrc(Op->Header.Args[0].ID()).V2D());
mov(VTMP2.V2D(), GetSrc(Op->Header.Args[0].ID()).V2D());
bit(VTMP2.V16B(), GetSrc(Op->Header.Args[1].ID()).V16B(), VTMP1.V16B());
mov(GetDst(Node).V2D(), VTMP2.V2D());
break;
}
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
}
}
}
@@ -602,7 +625,7 @@ DEF_OP(VFRecp) {
fdiv(GetDst(Node).D(), VTMP1.D(), GetSrc(Op->Header.Args[0].ID()).D());
break;
}
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
}
}
else {
@@ -618,7 +641,7 @@ DEF_OP(VFRecp) {
fdiv(GetDst(Node).V2D(), VTMP1.V2D(), GetSrc(Op->Header.Args[0].ID()).V2D());
break;
}
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
}
}
}
@@ -637,7 +660,7 @@ DEF_OP(VFSqrt) {
fsqrt(GetDst(Node).D(), GetSrc(Op->Header.Args[0].ID()).D());
break;
}
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
}
}
else {
@@ -651,7 +674,7 @@ DEF_OP(VFSqrt) {
fsqrt(GetDst(Node).V2D(), GetSrc(Op->Header.Args[0].ID()).V2D());
break;
}
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
}
}
}
@@ -674,7 +697,7 @@ DEF_OP(VFRSqrt) {
fdiv(GetDst(Node).D(), VTMP1.D(), VTMP2.D());
break;
}
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
}
}
else {
@@ -692,7 +715,7 @@ DEF_OP(VFRSqrt) {
fdiv(GetDst(Node).V2D(), VTMP1.V2D(), VTMP2.V2D());
break;
}
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
}
}
}
@@ -713,7 +736,7 @@ DEF_OP(VNeg) {
case 8:
neg(GetDst(Node).V2D(), GetSrc(Op->Header.Args[0].ID()).V2D());
break;
default: LogMan::Msg::A("Unsupported Not size: %d", OpSize);
default: LOGMAN_MSG_A("Unsupported Not size: %d", OpSize);
}
}
@@ -727,7 +750,7 @@ DEF_OP(VFNeg) {
case 8:
fneg(GetDst(Node).V2D(), GetSrc(Op->Header.Args[0].ID()).V2D());
break;
default: LogMan::Msg::A("Unsupported Not size: %d", OpSize);
default: LOGMAN_MSG_A("Unsupported Not size: %d", OpSize);
}
}
@@ -752,10 +775,13 @@ DEF_OP(VUMin) {
break;
}
case 8: {
umin(GetDst(Node).V2D(), GetSrc(Op->Header.Args[0].ID()).V2D(), GetSrc(Op->Header.Args[1].ID()).V2D());
cmhi(VTMP1.V2D(), GetSrc(Op->Header.Args[1].ID()).V2D(), GetSrc(Op->Header.Args[0].ID()).V2D());
mov(VTMP2.V2D(), GetSrc(Op->Header.Args[0].ID()).V2D());
bif(VTMP2.V16B(), GetSrc(Op->Header.Args[1].ID()).V16B(), VTMP1.V16B());
mov(GetDst(Node).V2D(), VTMP2.V2D());
break;
}
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
}
}
@@ -775,10 +801,13 @@ DEF_OP(VSMin) {
break;
}
case 8: {
smin(GetDst(Node).V2D(), GetSrc(Op->Header.Args[0].ID()).V2D(), GetSrc(Op->Header.Args[1].ID()).V2D());
cmgt(VTMP1.V2D(), GetSrc(Op->Header.Args[1].ID()).V2D(), GetSrc(Op->Header.Args[0].ID()).V2D());
mov(VTMP2.V2D(), GetSrc(Op->Header.Args[0].ID()).V2D());
bif(VTMP2.V16B(), GetSrc(Op->Header.Args[1].ID()).V16B(), VTMP1.V16B());
mov(GetDst(Node).V2D(), VTMP2.V2D());
break;
}
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
}
}
@@ -798,10 +827,13 @@ DEF_OP(VUMax) {
break;
}
case 8: {
umax(GetDst(Node).V2D(), GetSrc(Op->Header.Args[0].ID()).V2D(), GetSrc(Op->Header.Args[1].ID()).V2D());
cmhi(VTMP1.V2D(), GetSrc(Op->Header.Args[1].ID()).V2D(), GetSrc(Op->Header.Args[0].ID()).V2D());
mov(VTMP2.V2D(), GetSrc(Op->Header.Args[0].ID()).V2D());
bit(VTMP2.V16B(), GetSrc(Op->Header.Args[1].ID()).V16B(), VTMP1.V16B());
mov(GetDst(Node).V2D(), VTMP2.V2D());
break;
}
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
}
}
@@ -821,10 +853,13 @@ DEF_OP(VSMax) {
break;
}
case 8: {
smax(GetDst(Node).V2D(), GetSrc(Op->Header.Args[0].ID()).V2D(), GetSrc(Op->Header.Args[1].ID()).V2D());
cmgt(VTMP1.V2D(), GetSrc(Op->Header.Args[1].ID()).V2D(), GetSrc(Op->Header.Args[0].ID()).V2D());
mov(VTMP2.V2D(), GetSrc(Op->Header.Args[0].ID()).V2D());
bit(VTMP2.V16B(), GetSrc(Op->Header.Args[1].ID()).V16B(), VTMP1.V16B());
mov(GetDst(Node).V2D(), VTMP2.V2D());
break;
}
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
}
}
@@ -845,7 +880,7 @@ DEF_OP(VZip) {
zip1(GetDst(Node).V2S(), GetSrc(Op->Header.Args[0].ID()).V2S(), GetSrc(Op->Header.Args[1].ID()).V2S());
break;
}
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
}
}
else {
@@ -866,7 +901,7 @@ DEF_OP(VZip) {
zip1(GetDst(Node).V2D(), GetSrc(Op->Header.Args[0].ID()).V2D(), GetSrc(Op->Header.Args[1].ID()).V2D());
break;
}
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
}
}
}
@@ -888,7 +923,7 @@ DEF_OP(VZip2) {
zip2(GetDst(Node).V2S(), GetSrc(Op->Header.Args[0].ID()).V2S(), GetSrc(Op->Header.Args[1].ID()).V2S());
break;
}
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
}
}
else {
@@ -909,7 +944,7 @@ DEF_OP(VZip2) {
zip2(GetDst(Node).V2D(), GetSrc(Op->Header.Args[0].ID()).V2D(), GetSrc(Op->Header.Args[1].ID()).V2D());
break;
}
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
}
}
}
@@ -942,7 +977,7 @@ DEF_OP(VCMPEQ) {
cmeq(GetDst(Node).D(), GetSrc(Op->Header.Args[0].ID()).D(), GetSrc(Op->Header.Args[1].ID()).D());
break;
}
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
}
}
else {
@@ -964,7 +999,7 @@ DEF_OP(VCMPEQ) {
cmeq(GetDst(Node).V2D(), GetSrc(Op->Header.Args[0].ID()).V2D(), GetSrc(Op->Header.Args[1].ID()).V2D());
break;
}
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
}
}
}
@@ -983,7 +1018,7 @@ DEF_OP(VCMPEQZ) {
cmeq(GetDst(Node).D(), GetSrc(Op->Header.Args[0].ID()).D(), 0);
break;
}
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
}
}
else {
@@ -1005,7 +1040,7 @@ DEF_OP(VCMPEQZ) {
cmeq(GetDst(Node).V2D(), GetSrc(Op->Header.Args[0].ID()).V2D(), 0);
break;
}
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
}
}
}
@@ -1024,7 +1059,7 @@ DEF_OP(VCMPGT) {
cmgt(GetDst(Node).D(), GetSrc(Op->Header.Args[0].ID()).D(), GetSrc(Op->Header.Args[1].ID()).D());
break;
}
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
}
}
else {
@@ -1046,7 +1081,7 @@ DEF_OP(VCMPGT) {
cmgt(GetDst(Node).V2D(), GetSrc(Op->Header.Args[0].ID()).V2D(), GetSrc(Op->Header.Args[1].ID()).V2D());
break;
}
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
}
}
}
@@ -1065,7 +1100,7 @@ DEF_OP(VCMPGTZ) {
cmgt(GetDst(Node).D(), GetSrc(Op->Header.Args[0].ID()).D(), 0);
break;
}
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
}
}
else {
@@ -1087,7 +1122,7 @@ DEF_OP(VCMPGTZ) {
cmgt(GetDst(Node).V2D(), GetSrc(Op->Header.Args[0].ID()).V2D(), 0);
break;
}
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
}
}
}
@@ -1106,7 +1141,7 @@ DEF_OP(VCMPLTZ) {
cmlt(GetDst(Node).D(), GetSrc(Op->Header.Args[0].ID()).D(), 0);
break;
}
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
}
}
else {
@@ -1128,7 +1163,7 @@ DEF_OP(VCMPLTZ) {
cmlt(GetDst(Node).V2D(), GetSrc(Op->Header.Args[0].ID()).V2D(), 0);
break;
}
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
}
}
}
@@ -1147,7 +1182,7 @@ DEF_OP(VFCMPEQ) {
fcmeq(GetDst(Node).D(), GetSrc(Op->Header.Args[0].ID()).D(), GetSrc(Op->Header.Args[1].ID()).D());
break;
}
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
}
}
else {
@@ -1165,7 +1200,7 @@ DEF_OP(VFCMPEQ) {
fcmeq(GetDst(Node).V2D(), GetSrc(Op->Header.Args[0].ID()).V2D(), GetSrc(Op->Header.Args[1].ID()).V2D());
break;
}
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
}
}
}
@@ -1184,7 +1219,7 @@ DEF_OP(VFCMPNEQ) {
fcmeq(GetDst(Node).D(), GetSrc(Op->Header.Args[0].ID()).D(), GetSrc(Op->Header.Args[1].ID()).D());
break;
}
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
}
mvn(GetDst(Node).V8B(), GetDst(Node).V8B());
}
@@ -1203,7 +1238,7 @@ DEF_OP(VFCMPNEQ) {
fcmeq(GetDst(Node).V2D(), GetSrc(Op->Header.Args[0].ID()).V2D(), GetSrc(Op->Header.Args[1].ID()).V2D());
break;
}
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
}
mvn(GetDst(Node).V16B(), GetDst(Node).V16B());
}
@@ -1223,7 +1258,7 @@ DEF_OP(VFCMPLT) {
fcmgt(GetDst(Node).D(), GetSrc(Op->Header.Args[1].ID()).D(), GetSrc(Op->Header.Args[0].ID()).D());
break;
}
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
}
}
else {
@@ -1241,7 +1276,7 @@ DEF_OP(VFCMPLT) {
fcmgt(GetDst(Node).V2D(), GetSrc(Op->Header.Args[1].ID()).V2D(), GetSrc(Op->Header.Args[0].ID()).V2D());
break;
}
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
}
}
}
@@ -1260,7 +1295,7 @@ DEF_OP(VFCMPGT) {
fcmgt(GetDst(Node).D(), GetSrc(Op->Header.Args[0].ID()).D(), GetSrc(Op->Header.Args[1].ID()).D());
break;
}
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
}
}
else {
@@ -1278,7 +1313,7 @@ DEF_OP(VFCMPGT) {
fcmgt(GetDst(Node).V2D(), GetSrc(Op->Header.Args[0].ID()).V2D(), GetSrc(Op->Header.Args[1].ID()).V2D());
break;
}
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
}
}
}
@@ -1297,7 +1332,7 @@ DEF_OP(VFCMPLE) {
fcmge(GetDst(Node).D(), GetSrc(Op->Header.Args[1].ID()).D(), GetSrc(Op->Header.Args[0].ID()).D());
break;
}
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
}
}
else {
@@ -1315,7 +1350,7 @@ DEF_OP(VFCMPLE) {
fcmge(GetDst(Node).V2D(), GetSrc(Op->Header.Args[1].ID()).V2D(), GetSrc(Op->Header.Args[0].ID()).V2D());
break;
}
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
}
}
}
@@ -1338,7 +1373,7 @@ DEF_OP(VFCMPORD) {
orr(GetDst(Node).V8B(), VTMP1.V8B(), VTMP2.V8B());
break;
}
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
}
}
else {
@@ -1362,7 +1397,7 @@ DEF_OP(VFCMPORD) {
orr(GetDst(Node).V16B(), VTMP1.V16B(), VTMP2.V16B());
break;
}
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
}
}
}
@@ -1387,7 +1422,7 @@ DEF_OP(VFCMPUNO) {
mvn(GetDst(Node).V8B(), GetDst(Node).V8B());
break;
}
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
}
}
else {
@@ -1414,21 +1449,21 @@ DEF_OP(VFCMPUNO) {
mvn(GetDst(Node).V16B(), GetDst(Node).V16B());
break;
}
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
}
}
}
DEF_OP(VUShl) {
LogMan::Msg::A("Unimplemented");
LOGMAN_MSG_A("Unimplemented");
}
DEF_OP(VUShr) {
LogMan::Msg::A("Unimplemented");
LOGMAN_MSG_A("Unimplemented");
}
DEF_OP(VSShr) {
LogMan::Msg::A("Unimplemented");
LOGMAN_MSG_A("Unimplemented");
}
DEF_OP(VUShlS) {
@@ -1455,7 +1490,7 @@ DEF_OP(VUShlS) {
ushl(GetDst(Node).V2D(), GetSrc(Op->Header.Args[0].ID()).V2D(), VTMP1.V2D());
break;
}
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
}
}
@@ -1487,7 +1522,7 @@ DEF_OP(VUShrS) {
ushl(GetDst(Node).V2D(), GetSrc(Op->Header.Args[0].ID()).V2D(), VTMP1.V2D());
break;
}
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
}
}
@@ -1519,7 +1554,7 @@ DEF_OP(VSShrS) {
sshl(GetDst(Node).V2D(), GetSrc(Op->Header.Args[0].ID()).V2D(), VTMP1.V2D());
break;
}
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
}
}
@@ -1550,7 +1585,7 @@ DEF_OP(VInsElement) {
mov(reg.V2D(), Op->DestIdx, GetSrc(Op->Header.Args[1].ID()).V2D(), Op->SrcIdx);
break;
}
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
}
if (GetDst(Node).GetCode() != reg.GetCode()) {
@@ -1585,7 +1620,7 @@ DEF_OP(VInsScalarElement) {
mov(reg.V2D(), Op->DestIdx, GetSrc(Op->Header.Args[1].ID()).V2D(), 0);
break;
}
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
}
if (GetDst(Node).GetCode() != reg.GetCode()) {
@@ -1609,7 +1644,7 @@ DEF_OP(VExtractElement) {
case 8:
mov(GetDst(Node).D(), GetSrc(Op->Header.Args[0].ID()).V2D(), Op->Index);
break;
default: LogMan::Msg::A("Unhandled ExtractElementSize: %d", OpSize);
default: LOGMAN_MSG_A("Unhandled ExtractElementSize: %d", OpSize);
}
}
@@ -1724,7 +1759,7 @@ DEF_OP(VUShrI) {
ushr(GetDst(Node).V2D(), GetSrc(Op->Header.Args[0].ID()).V2D(), Op->BitShift);
break;
}
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
}
}
}
@@ -1749,7 +1784,7 @@ DEF_OP(VSShrI) {
sshr(GetDst(Node).V2D(), GetSrc(Op->Header.Args[0].ID()).V2D(), std::min((uint8_t)(Op->Header.ElementSize * 8 - 1), Op->BitShift));
break;
}
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
}
}
@@ -1777,7 +1812,7 @@ DEF_OP(VShlI) {
shl(GetDst(Node).V2D(), GetSrc(Op->Header.Args[0].ID()).V2D(), Op->BitShift);
break;
}
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
}
}
}
@@ -1798,7 +1833,7 @@ DEF_OP(VUShrNI) {
shrn(GetDst(Node).V2S(), GetSrc(Op->Header.Args[0].ID()).V2D(), Op->BitShift);
break;
}
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
}
}
@@ -1818,7 +1853,7 @@ DEF_OP(VUShrNI2) {
shrn2(VTMP1.V4S(), GetSrc(Op->Header.Args[1].ID()).V2D(), Op->BitShift);
break;
}
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
}
mov(GetDst(Node), VTMP1);
@@ -1841,7 +1876,7 @@ DEF_OP(VSXTL) {
case 8:
sxtl(GetDst(Node).V2D(), GetSrc(Op->Header.Args[0].ID()).V2S());
break;
default: LogMan::Msg::A("Unknown element size: %d", Op->Header.ElementSize);
default: LOGMAN_MSG_A("Unknown element size: %d", Op->Header.ElementSize);
}
}
@@ -1857,7 +1892,7 @@ DEF_OP(VSXTL2) {
case 8:
sxtl2(GetDst(Node).V2D(), GetSrc(Op->Header.Args[0].ID()).V4S());
break;
default: LogMan::Msg::A("Unknown element size: %d", Op->Header.ElementSize);
default: LOGMAN_MSG_A("Unknown element size: %d", Op->Header.ElementSize);
}
}
@@ -1873,7 +1908,7 @@ DEF_OP(VUXTL) {
case 8:
uxtl(GetDst(Node).V2D(), GetSrc(Op->Header.Args[0].ID()).V2S());
break;
default: LogMan::Msg::A("Unknown element size: %d", Op->Header.ElementSize);
default: LOGMAN_MSG_A("Unknown element size: %d", Op->Header.ElementSize);
}
}
@@ -1889,7 +1924,7 @@ DEF_OP(VUXTL2) {
case 8:
uxtl2(GetDst(Node).V2D(), GetSrc(Op->Header.Args[0].ID()).V4S());
break;
default: LogMan::Msg::A("Unknown element size: %d", Op->Header.ElementSize);
default: LOGMAN_MSG_A("Unknown element size: %d", Op->Header.ElementSize);
}
}
@@ -1905,7 +1940,7 @@ DEF_OP(VSQXTN) {
case 4:
sqxtn(GetDst(Node).V2S(), GetSrc(Op->Header.Args[0].ID()).V2D());
break;
default: LogMan::Msg::A("Unknown element size: %d", Op->Header.ElementSize);
default: LOGMAN_MSG_A("Unknown element size: %d", Op->Header.ElementSize);
}
}
@@ -1927,7 +1962,7 @@ DEF_OP(VSQXTN2) {
sqxtn(VTMP2.V2S(), GetSrc(Op->Header.Args[1].ID()).V2D());
ins(VTMP1.V4S(), 1, VTMP2.V4S(), 0);
break;
default: LogMan::Msg::A("Unknown element size: %d", Op->Header.ElementSize);
default: LOGMAN_MSG_A("Unknown element size: %d", Op->Header.ElementSize);
}
}
else {
@@ -1941,7 +1976,7 @@ DEF_OP(VSQXTN2) {
case 4:
sqxtn2(VTMP1.V4S(), GetSrc(Op->Header.Args[1].ID()).V2D());
break;
default: LogMan::Msg::A("Unknown element size: %d", Op->Header.ElementSize);
default: LOGMAN_MSG_A("Unknown element size: %d", Op->Header.ElementSize);
}
}
mov(GetDst(Node), VTMP1);
@@ -1959,7 +1994,7 @@ DEF_OP(VSQXTUN) {
case 4:
sqxtun(GetDst(Node).V2S(), GetSrc(Op->Header.Args[0].ID()).V2D());
break;
default: LogMan::Msg::A("Unknown element size: %d", Op->Header.ElementSize);
default: LOGMAN_MSG_A("Unknown element size: %d", Op->Header.ElementSize);
}
}
@@ -1981,7 +2016,7 @@ DEF_OP(VSQXTUN2) {
sqxtun(VTMP2.V2S(), GetSrc(Op->Header.Args[1].ID()).V2D());
ins(VTMP1.V4S(), 1, VTMP2.V4S(), 0);
break;
default: LogMan::Msg::A("Unknown element size: %d", Op->Header.ElementSize);
default: LOGMAN_MSG_A("Unknown element size: %d", Op->Header.ElementSize);
}
}
else {
@@ -1995,7 +2030,7 @@ DEF_OP(VSQXTUN2) {
case 4:
sqxtun2(VTMP1.V4S(), GetSrc(Op->Header.Args[1].ID()).V2D());
break;
default: LogMan::Msg::A("Unknown element size: %d", Op->Header.ElementSize);
default: LOGMAN_MSG_A("Unknown element size: %d", Op->Header.ElementSize);
}
}
mov(GetDst(Node), VTMP1);
@@ -2020,7 +2055,7 @@ DEF_OP(VMul) {
mul(GetDst(Node).V2D(), GetSrc(Op->Header.Args[0].ID()).V2D(), GetSrc(Op->Header.Args[1].ID()).V2D());
break;
}
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
}
}
@@ -2039,7 +2074,7 @@ DEF_OP(VUMull) {
umull(GetDst(Node).V2D(), GetSrc(Op->Header.Args[0].ID()).V2S(), GetSrc(Op->Header.Args[1].ID()).V2S());
break;
}
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize >> 1); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize >> 1); break;
}
}
@@ -2058,7 +2093,7 @@ DEF_OP(VSMull) {
smull(GetDst(Node).V2D(), GetSrc(Op->Header.Args[0].ID()).V2S(), GetSrc(Op->Header.Args[1].ID()).V2S());
break;
}
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize >> 1); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize >> 1); break;
}
}
@@ -2077,7 +2112,7 @@ DEF_OP(VUMull2) {
umull2(GetDst(Node).V2D(), GetSrc(Op->Header.Args[0].ID()).V4S(), GetSrc(Op->Header.Args[1].ID()).V4S());
break;
}
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize >> 1); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize >> 1); break;
}
}
@@ -2096,7 +2131,7 @@ DEF_OP(VSMull2) {
smull2(GetDst(Node).V2D(), GetSrc(Op->Header.Args[0].ID()).V4S(), GetSrc(Op->Header.Args[1].ID()).V4S());
break;
}
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize >> 1); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize >> 1); break;
}
}
@@ -2113,7 +2148,7 @@ DEF_OP(VTBL1) {
tbl(GetDst(Node).V16B(), GetSrc(Op->Header.Args[0].ID()).V16B(), GetSrc(Op->Header.Args[1].ID()).V16B());
break;
}
default: LogMan::Msg::A("Unknown OpSize: %d", OpSize); break;
default: LOGMAN_MSG_A("Unknown OpSize: %d", OpSize); break;
}
}
+35 -35
View File
@@ -20,7 +20,7 @@ DEF_OP(TruncElementPair) {
mov(Dst.second, Src.second);
break;
}
default: LogMan::Msg::A("Unhandled Truncation size: %d", Op->Size); break;
default: LOGMAN_MSG_A("Unhandled Truncation size: %d", Op->Size); break;
}
}
@@ -32,7 +32,7 @@ DEF_OP(Constant) {
DEF_OP(EntrypointOffset) {
auto Op = IROp->C<IR::IROp_EntrypointOffset>();
auto Constant = IR->GetHeader()->Entry + Op->Offset;
auto Constant = Entry + Op->Offset;
mov(GetDst<RA_64>(Node), Constant);
}
@@ -70,7 +70,7 @@ DEF_OP(Add) {
case 8:
add(rax, Const);
break;
default: LogMan::Msg::A("Unhandled Add size: %d", OpSize);
default: LOGMAN_MSG_A("Unhandled Add size: %d", OpSize);
break;
}
} else {
@@ -81,7 +81,7 @@ DEF_OP(Add) {
case 8:
add(rax, GetSrc<RA_64>(Op->Header.Args[1].ID()));
break;
default: LogMan::Msg::A("Unhandled Add size: %d", OpSize);
default: LOGMAN_MSG_A("Unhandled Add size: %d", OpSize);
break;
}
}
@@ -103,7 +103,7 @@ DEF_OP(Sub) {
case 8:
sub(rax, Const);
break;
default: LogMan::Msg::A("Unhandled Sub size: %d", OpSize);
default: LOGMAN_MSG_A("Unhandled Sub size: %d", OpSize);
break;
}
} else {
@@ -114,7 +114,7 @@ DEF_OP(Sub) {
case 8:
sub(rax, GetSrc<RA_64>(Op->Header.Args[1].ID()));
break;
default: LogMan::Msg::A("Unhandled Sub size: %d", OpSize);
default: LOGMAN_MSG_A("Unhandled Sub size: %d", OpSize);
break;
}
}
@@ -136,7 +136,7 @@ DEF_OP(Neg) {
Src = GetSrc<RA_64>(Op->Header.Args[0].ID());
Dst = GetDst<RA_64>(Node);
break;
default: LogMan::Msg::A("Unhandled Neg size: %d", OpSize);
default: LOGMAN_MSG_A("Unhandled Neg size: %d", OpSize);
break;
}
mov(Dst, Src);
@@ -160,7 +160,7 @@ DEF_OP(Mul) {
imul(rax, GetSrc<RA_64>(Op->Header.Args[1].ID()));
mov(Dst, rax);
break;
default: LogMan::Msg::A("Unknown Sext size: %d", OpSize);
default: LOGMAN_MSG_A("Unknown Sext size: %d", OpSize);
}
}
@@ -179,7 +179,7 @@ DEF_OP(UMul) {
mul(GetSrc<RA_64>(Op->Header.Args[1].ID()));
mov(GetDst<RA_64>(Node), rax);
break;
default: LogMan::Msg::A("Unknown Sext size: %d", OpSize);
default: LOGMAN_MSG_A("Unknown Sext size: %d", OpSize);
}
}
@@ -218,7 +218,7 @@ DEF_OP(Div) {
mov(GetDst<RA_64>(Node), rax);
break;
}
default: LogMan::Msg::A("Unknown UDIV Size: %d", Size); break;
default: LOGMAN_MSG_A("Unknown UDIV Size: %d", Size); break;
}
}
@@ -261,7 +261,7 @@ DEF_OP(UDiv) {
mov(GetDst<RA_64>(Node), rax);
break;
}
default: LogMan::Msg::A("Unknown UDIV OpSize: %d", OpSize); break;
default: LOGMAN_MSG_A("Unknown UDIV OpSize: %d", OpSize); break;
}
}
@@ -298,7 +298,7 @@ DEF_OP(Rem) {
mov(GetDst<RA_64>(Node), rdx);
break;
}
default: LogMan::Msg::A("Unknown UDIV Size: %d", OpSize); break;
default: LOGMAN_MSG_A("Unknown UDIV Size: %d", OpSize); break;
}
}
@@ -341,7 +341,7 @@ DEF_OP(URem) {
mov(GetDst<RA_64>(Node), rdx);
break;
}
default: LogMan::Msg::A("Unknown UDIV OpSize: %d", OpSize); break;
default: LOGMAN_MSG_A("Unknown UDIV OpSize: %d", OpSize); break;
}
}
@@ -360,7 +360,7 @@ DEF_OP(MulH) {
imul(GetSrc<RA_64>(Op->Header.Args[1].ID()));
mov(GetDst<RA_64>(Node), rdx);
break;
default: LogMan::Msg::A("Unknown Sext size: %d", OpSize);
default: LOGMAN_MSG_A("Unknown Sext size: %d", OpSize);
}
}
@@ -379,7 +379,7 @@ DEF_OP(UMulH) {
mul(GetSrc<RA_64>(Op->Header.Args[1].ID()));
mov(GetDst<RA_64>(Node), rdx);
break;
default: LogMan::Msg::A("Unknown Sext size: %d", OpSize);
default: LOGMAN_MSG_A("Unknown Sext size: %d", OpSize);
}
}
@@ -441,7 +441,7 @@ DEF_OP(Lshl) {
mov(GetDst<RA_64>(Node), GetSrc<RA_64>(Op->Header.Args[0].ID()));
shl(GetDst<RA_64>(Node), Const);
break;
default: LogMan::Msg::A("Unknown LSHL Size: %d\n", OpSize); break;
default: LOGMAN_MSG_A("Unknown LSHL Size: %d\n", OpSize); break;
};
} else {
mov(rcx, GetSrc<RA_64>(Op->Header.Args[1].ID()));
@@ -456,7 +456,7 @@ DEF_OP(Lshl) {
mov(GetDst<RA_64>(Node), GetSrc<RA_64>(Op->Header.Args[0].ID()));
shl(GetDst<RA_64>(Node), cl);
break;
default: LogMan::Msg::A("Unknown LSHL Size: %d\n", OpSize); break;
default: LOGMAN_MSG_A("Unknown LSHL Size: %d\n", OpSize); break;
};
}
}
@@ -488,7 +488,7 @@ DEF_OP(Lshr) {
mov(GetDst<RA_64>(Node), GetSrc<RA_64>(Op->Header.Args[0].ID()));
shr(GetDst<RA_64>(Node), Const);
break;
default: LogMan::Msg::A("Unknown Size: %d\n", OpSize); break;
default: LOGMAN_MSG_A("Unknown Size: %d\n", OpSize); break;
};
} else {
@@ -512,7 +512,7 @@ DEF_OP(Lshr) {
mov(GetDst<RA_64>(Node), GetSrc<RA_64>(Op->Header.Args[0].ID()));
shr(GetDst<RA_64>(Node), cl);
break;
default: LogMan::Msg::A("Unknown Size: %d\n", OpSize); break;
default: LOGMAN_MSG_A("Unknown Size: %d\n", OpSize); break;
};
}
}
@@ -546,7 +546,7 @@ DEF_OP(Ashr) {
mov(GetDst<RA_64>(Node), GetSrc<RA_64>(Op->Header.Args[0].ID()));
sar(GetDst<RA_64>(Node), Const);
break;
default: LogMan::Msg::A("Unknown ASHR Size: %d\n", OpSize); break;
default: LOGMAN_MSG_A("Unknown ASHR Size: %d\n", OpSize); break;
};
} else {
@@ -571,7 +571,7 @@ DEF_OP(Ashr) {
mov(GetDst<RA_64>(Node), GetSrc<RA_64>(Op->Header.Args[0].ID()));
sar(GetDst<RA_64>(Node), cl);
break;
default: LogMan::Msg::A("Unknown ASHR Size: %d\n", OpSize); break;
default: LOGMAN_MSG_A("Unknown ASHR Size: %d\n", OpSize); break;
};
}
}
@@ -596,7 +596,7 @@ DEF_OP(Ror) {
ror(rax, Const);
break;
}
default: LogMan::Msg::A("Unknown ROR Size: %d\n", OpSize); break;
default: LOGMAN_MSG_A("Unknown ROR Size: %d\n", OpSize); break;
}
} else {
mov (rcx, GetSrc<RA_64>(Op->Header.Args[1].ID()));
@@ -612,7 +612,7 @@ DEF_OP(Ror) {
ror(rax, cl);
break;
}
default: LogMan::Msg::A("Unknown ROR Size: %d\n", OpSize); break;
default: LOGMAN_MSG_A("Unknown ROR Size: %d\n", OpSize); break;
}
}
mov(GetDst<RA_64>(Node), rax);
@@ -668,7 +668,7 @@ DEF_OP(LDiv) {
mov(GetDst<RA_64>(Node), rax);
break;
}
default: LogMan::Msg::A("Unknown LDIV OpSize: %d", OpSize); break;
default: LOGMAN_MSG_A("Unknown LDIV OpSize: %d", OpSize); break;
}
}
@@ -700,7 +700,7 @@ DEF_OP(LUDiv) {
mov(GetDst<RA_64>(Node), rax);
break;
}
default: LogMan::Msg::A("Unknown LUDIV OpSize: %d", OpSize); break;
default: LOGMAN_MSG_A("Unknown LUDIV OpSize: %d", OpSize); break;
}
}
@@ -732,7 +732,7 @@ DEF_OP(LRem) {
mov(GetDst<RA_64>(Node), rdx);
break;
}
default: LogMan::Msg::A("Unknown LREM OpSize: %d", OpSize); break;
default: LOGMAN_MSG_A("Unknown LREM OpSize: %d", OpSize); break;
}
}
@@ -764,7 +764,7 @@ DEF_OP(LURem) {
mov(GetDst<RA_64>(Node), rdx);
break;
}
default: LogMan::Msg::A("Unknown LUDIV OpSize: %d", OpSize); break;
default: LOGMAN_MSG_A("Unknown LUDIV OpSize: %d", OpSize); break;
}
}
@@ -829,7 +829,7 @@ DEF_OP(FindMSB) {
case 8:
bsr(GetDst<RA_64>(Node), GetSrc<RA_64>(Op->Header.Args[0].ID()));
break;
default: LogMan::Msg::A("Unknown OpSize: %d", OpSize);
default: LOGMAN_MSG_A("Unknown OpSize: %d", OpSize);
}
}
@@ -853,7 +853,7 @@ DEF_OP(FindTrailingZeros) {
mov(rax, 0x40);
cmovz(GetDst<RA_64>(Node), rax);
break;
default: LogMan::Msg::A("Unknown size: %d", OpSize); break;
default: LOGMAN_MSG_A("Unknown size: %d", OpSize); break;
}
}
@@ -876,7 +876,7 @@ DEF_OP(CountLeadingZeroes) {
lzcnt(GetDst<RA_64>(Node), GetSrc<RA_64>(Op->Header.Args[0].ID()));
break;
}
default: LogMan::Msg::A("Unknown size: %d", OpSize); break;
default: LOGMAN_MSG_A("Unknown size: %d", OpSize); break;
}
}
else {
@@ -915,7 +915,7 @@ DEF_OP(CountLeadingZeroes) {
mov(GetDst<RA_64>(Node), rax);
break;
}
default: LogMan::Msg::A("Unknown size: %d", OpSize); break;
default: LOGMAN_MSG_A("Unknown size: %d", OpSize); break;
}
}
}
@@ -937,7 +937,7 @@ DEF_OP(Rev) {
mov (GetDst<RA_64>(Node), GetSrc<RA_64>(Op->Header.Args[0].ID()));
bswap(GetDst<RA_64>(Node).cvt64());
break;
default: LogMan::Msg::A("Unknown REV size: %d", OpSize); break;
default: LOGMAN_MSG_A("Unknown REV size: %d", OpSize); break;
}
}
@@ -972,7 +972,7 @@ DEF_OP(Bfe) {
auto Op = IROp->C<IR::IROp_Bfe>();
uint8_t OpSize = IROp->Size;
LogMan::Throw::A(OpSize <= 8, "OpSize is too large for BFE: %d", OpSize);
LOGMAN_THROW_A(OpSize <= 8, "OpSize is too large for BFE: %d", OpSize);
auto Dst = GetDst<RA_64>(Node);
@@ -1073,7 +1073,7 @@ DEF_OP(Select) {
if (is_const_true || is_const_false) {
if (is_const_false != true || is_const_true != true || const_true != 1 || const_false != 0) {
LogMan::Msg::A("Select: Unsupported compare inline parameters");
LOGMAN_MSG_A("Select: Unsupported compare inline parameters");
}
(this->*SetCC)(al);
movzx(Dst, al);
@@ -1104,7 +1104,7 @@ DEF_OP(VExtractToGPR) {
pextrq(GetDst<RA_64>(Node), GetSrc(Op->Header.Args[0].ID()), Op->Idx);
break;
}
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
}
}
@@ -55,7 +55,7 @@ DEF_OP(CASPair) {
mov(Dst.second, rdx);
break;
}
default: LogMan::Msg::A("Unsupported: %d", OpSize);
default: LOGMAN_MSG_A("Unsupported: %d", OpSize);
}
}
@@ -74,7 +74,6 @@ DEF_OP(CAS) {
Xbyak::Reg MemReg = GetSrc<RA_64>(Op->Header.Args[2].ID());
mov(rdx, GetSrc<RA_64>(Op->Header.Args[1].ID()));
mov(rax, GetSrc<RA_64>(Op->Header.Args[0].ID()));
// RCX now contains pointer
@@ -82,31 +81,31 @@ DEF_OP(CAS) {
// RDX contains our desired
lock();
switch (OpSize) {
case 1: {
cmpxchg(byte [MemReg], dl);
movzx(rax, al);
cmpxchg(byte [MemReg], GetSrc<RA_8>(Op->Header.Args[1].ID()));
movzx(GetDst<RA_64>(Node), al);
break;
}
case 2: {
cmpxchg(word [MemReg], dx);
movzx(rax, ax);
cmpxchg(word [MemReg], GetSrc<RA_16>(Op->Header.Args[1].ID()));
movzx(GetDst<RA_64>(Node), ax);
break;
}
case 4: {
cmpxchg(dword [MemReg], edx);
cmpxchg(dword [MemReg], GetSrc<RA_32>(Op->Header.Args[1].ID()));
// RAX now contains the result
mov (GetDst<RA_64>(Node), eax);
break;
}
case 8: {
cmpxchg(qword [MemReg], rdx);
cmpxchg(qword [MemReg], GetSrc<RA_64>(Op->Header.Args[1].ID()));
// RAX now contains the result
mov (GetDst<RA_64>(Node), rax);
break;
}
default: LogMan::Msg::A("Unsupported: %d", OpSize);
default: LOGMAN_MSG_A("Unsupported: %d", OpSize);
}
// RAX now contains the result
mov (GetDst<RA_64>(Node), rax);
}
DEF_OP(AtomicAdd) {
@@ -128,7 +127,7 @@ DEF_OP(AtomicAdd) {
case 8:
add(qword [MemReg], GetSrc<RA_64>(Op->Header.Args[1].ID()));
break;
default: LogMan::Msg::A("Unhandled AtomicAdd size: %d", Op->Size);
default: LOGMAN_MSG_A("Unhandled AtomicAdd size: %d", Op->Size);
}
}
@@ -150,7 +149,7 @@ DEF_OP(AtomicSub) {
case 8:
sub(qword [MemReg], GetSrc<RA_64>(Op->Header.Args[1].ID()));
break;
default: LogMan::Msg::A("Unhandled AtomicAdd size: %d", Op->Size);
default: LOGMAN_MSG_A("Unhandled AtomicAdd size: %d", Op->Size);
}
}
@@ -172,7 +171,7 @@ DEF_OP(AtomicAnd) {
case 8:
and_(qword [MemReg], GetSrc<RA_64>(Op->Header.Args[1].ID()));
break;
default: LogMan::Msg::A("Unhandled AtomicAdd size: %d", Op->Size);
default: LOGMAN_MSG_A("Unhandled AtomicAdd size: %d", Op->Size);
}
}
@@ -194,7 +193,7 @@ DEF_OP(AtomicOr) {
case 8:
or_(qword [MemReg], GetSrc<RA_64>(Op->Header.Args[1].ID()));
break;
default: LogMan::Msg::A("Unhandled AtomicAdd size: %d", Op->Size);
default: LOGMAN_MSG_A("Unhandled AtomicAdd size: %d", Op->Size);
}
}
@@ -216,7 +215,7 @@ DEF_OP(AtomicXor) {
case 8:
xor_(qword [MemReg], GetSrc<RA_64>(Op->Header.Args[1].ID()));
break;
default: LogMan::Msg::A("Unhandled AtomicAdd size: %d", Op->Size);
default: LOGMAN_MSG_A("Unhandled AtomicAdd size: %d", Op->Size);
}
}
@@ -228,17 +227,17 @@ DEF_OP(AtomicSwap) {
switch (Op->Size) {
case 1:
mov(GetDst<RA_8>(Node), GetSrc<RA_8>(Op->Header.Args[1].ID()));
movzx(GetDst<RA_64>(Node), GetSrc<RA_8>(Op->Header.Args[1].ID()));
lock();
xchg(byte [MemReg], GetDst<RA_8>(Node));
break;
case 2:
mov(GetDst<RA_16>(Node), GetSrc<RA_16>(Op->Header.Args[1].ID()));
movzx(GetDst<RA_64>(Node), GetSrc<RA_16>(Op->Header.Args[1].ID()));
lock();
xchg(word [MemReg], GetDst<RA_16>(Node));
break;
case 4:
mov(GetDst<RA_32>(Node), GetSrc<RA_32>(Op->Header.Args[1].ID()));
mov(GetDst<RA_64>(Node), GetSrc<RA_32>(Op->Header.Args[1].ID()));
lock();
xchg(dword [MemReg], GetDst<RA_32>(Node));
break;
@@ -247,7 +246,7 @@ DEF_OP(AtomicSwap) {
lock();
xchg(qword [MemReg], GetDst<RA_64>(Node));
break;
default: LogMan::Msg::A("Unhandled AtomicAdd size: %d", Op->Size);
default: LOGMAN_MSG_A("Unhandled AtomicAdd size: %d", Op->Size);
}
}
@@ -257,13 +256,13 @@ DEF_OP(AtomicFetchAdd) {
Xbyak::Reg MemReg = GetSrc<RA_64>(Op->Header.Args[0].ID());
switch (Op->Size) {
case 1:
mov(cl, GetSrc<RA_8>(Op->Header.Args[1].ID()));
movzx(rcx, GetSrc<RA_8>(Op->Header.Args[1].ID()));
lock();
xadd(byte [MemReg], cl);
movzx(GetDst<RA_32>(Node), cl);
break;
case 2:
mov(cx, GetSrc<RA_16>(Op->Header.Args[1].ID()));
movzx(rcx, GetSrc<RA_16>(Op->Header.Args[1].ID()));
lock();
xadd(word [MemReg], cx);
movzx(GetDst<RA_32>(Node), cx);
@@ -272,7 +271,7 @@ DEF_OP(AtomicFetchAdd) {
mov(ecx, GetSrc<RA_32>(Op->Header.Args[1].ID()));
lock();
xadd(dword [MemReg], ecx);
mov(GetDst<RA_32>(Node), ecx);
mov(GetDst<RA_64>(Node), ecx);
break;
case 8:
mov(rcx, GetSrc<RA_64>(Op->Header.Args[1].ID()));
@@ -280,7 +279,7 @@ DEF_OP(AtomicFetchAdd) {
xadd(qword [MemReg], rcx);
mov(GetDst<RA_64>(Node), rcx);
break;
default: LogMan::Msg::A("Unhandled AtomicFetchAdd size: %d", Op->Size);
default: LOGMAN_MSG_A("Unhandled AtomicFetchAdd size: %d", Op->Size);
}
}
@@ -317,7 +316,7 @@ DEF_OP(AtomicFetchSub) {
xadd(qword [MemReg], rcx);
mov(GetDst<RA_64>(Node), rcx);
break;
default: LogMan::Msg::A("Unhandled AtomicFetchAdd size: %d", Op->Size);
default: LOGMAN_MSG_A("Unhandled AtomicFetchAdd size: %d", Op->Size);
}
}
@@ -395,7 +394,7 @@ DEF_OP(AtomicFetchAnd) {
mov(GetDst<RA_64>(Node), TMP3.cvt64());
break;
}
default: LogMan::Msg::A("Unhandled AtomicFetchAdd size: %d", Op->Size);
default: LOGMAN_MSG_A("Unhandled AtomicFetchAdd size: %d", Op->Size);
}
}
@@ -472,7 +471,7 @@ DEF_OP(AtomicFetchOr) {
mov(GetDst<RA_64>(Node), TMP3.cvt64());
break;
}
default: LogMan::Msg::A("Unhandled AtomicFetchAdd size: %d", Op->Size);
default: LOGMAN_MSG_A("Unhandled AtomicFetchAdd size: %d", Op->Size);
}
}
@@ -549,7 +548,7 @@ DEF_OP(AtomicFetchXor) {
mov(GetDst<RA_64>(Node), TMP3.cvt64());
break;
}
default: LogMan::Msg::A("Unhandled AtomicFetchAdd size: %d", Op->Size);
default: LOGMAN_MSG_A("Unhandled AtomicFetchAdd size: %d", Op->Size);
}
}
@@ -81,7 +81,7 @@ DEF_OP(ExitFunction) {
jmp(qword[rax]);
L(l_BranchHost);
dq(Dispatcher->ExitFunctionLinkerAddress);
dq(ThreadSharedData.Dispatcher->ExitFunctionLinkerAddress);
L(l_BranchGuest);
dq(NewRIP);
} else {
@@ -101,7 +101,7 @@ DEF_OP(ExitFunction) {
jmp(qword[LookupBase + 0]);
L(FullLookup);
mov(rax, Dispatcher->AbsoluteLoopTopAddress);
mov(rax, ThreadSharedData.Dispatcher->AbsoluteLoopTopAddress);
mov(qword [STATE + offsetof(FEXCore::Core::CpuStateFrame, State.rip)], RipReg);
jmp(rax);
}
@@ -253,7 +253,7 @@ DEF_OP(ValidateCode) {
int idx = 0;
xor_(GetDst<RA_64>(Node), GetDst<RA_64>(Node));
mov(rax, IR->GetHeader()->Entry + Op->Offset);
mov(rax, Entry + Op->Offset);
mov(rbx, 1);
while (len >= 4) {
cmp(dword[rax + idx], *(uint32_t*)(OldCode + idx));
@@ -286,7 +286,7 @@ DEF_OP(RemoveCodeEntry) {
sub(rsp, 8); // Align
mov(rdi, STATE);
mov(rax, IR->GetHeader()->Entry); // imm64 move
mov(rax, Entry); // imm64 move
mov(rsi, rax);
@@ -31,7 +31,7 @@ DEF_OP(VInsGPR) {
pinsrq(GetDst(Node), GetSrc<RA_64>(Op->Header.Args[1].ID()), Op->Index);
break;
}
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
}
}
@@ -52,12 +52,12 @@ DEF_OP(VCastFromGPR) {
case 8:
vmovq(GetDst(Node), GetSrc<RA_64>(Op->Header.Args[0].ID()).cvt64());
break;
default: LogMan::Msg::A("Unknown castGPR element size: %d", Op->Header.ElementSize);
default: LOGMAN_MSG_A("Unknown castGPR element size: %d", Op->Header.ElementSize);
}
}
DEF_OP(Float_FromGPR_U) {
LogMan::Msg::A("Unimplemented");
LOGMAN_MSG_A("Unimplemented");
}
DEF_OP(Float_FromGPR_S) {
@@ -95,12 +95,12 @@ DEF_OP(Float_FToF) {
cvtsd2ss(GetDst(Node), GetSrc(Op->Header.Args[0].ID()));
break;
}
default: LogMan::Msg::A("Unknown FCVT sizes: 0x%x", Conv);
default: LOGMAN_MSG_A("Unknown FCVT sizes: 0x%x", Conv);
}
}
DEF_OP(Vector_UToF) {
LogMan::Msg::A("Unimplemented");
LOGMAN_MSG_A("Unimplemented");
}
DEF_OP(Vector_SToF) {
@@ -121,12 +121,12 @@ DEF_OP(Vector_SToF) {
cvtsi2sd(xmm15, rax);
movlhps(GetDst(Node), xmm15);
break;
default: LogMan::Msg::A("Unknown castGPR element size: %d", Op->Header.ElementSize);
default: LOGMAN_MSG_A("Unknown castGPR element size: %d", Op->Header.ElementSize);
}
}
DEF_OP(Vector_FToZU) {
LogMan::Msg::A("Unimplemented");
LOGMAN_MSG_A("Unimplemented");
}
DEF_OP(Vector_FToZS) {
@@ -138,12 +138,12 @@ DEF_OP(Vector_FToZS) {
case 8:
cvttpd2dq(GetDst(Node), GetSrc(Op->Header.Args[0].ID()));
break;
default: LogMan::Msg::A("Unknown castGPR element size: %d", Op->Header.ElementSize);
default: LOGMAN_MSG_A("Unknown castGPR element size: %d", Op->Header.ElementSize);
}
}
DEF_OP(Vector_FToU) {
LogMan::Msg::A("Unimplemented");
LOGMAN_MSG_A("Unimplemented");
}
DEF_OP(Vector_FToS) {
@@ -155,7 +155,7 @@ DEF_OP(Vector_FToS) {
case 8:
cvtpd2dq(GetDst(Node), GetSrc(Op->Header.Args[0].ID()));
break;
default: LogMan::Msg::A("Unknown castGPR element size: %d", Op->Header.ElementSize);
default: LOGMAN_MSG_A("Unknown castGPR element size: %d", Op->Header.ElementSize);
}
}
@@ -172,7 +172,7 @@ DEF_OP(Vector_FToF) {
cvtpd2ps(GetDst(Node), GetSrc(Op->Header.Args[0].ID()));
break;
}
default: LogMan::Msg::A("Unknown Conversion Type : 0%04x", Conv); break;
default: LOGMAN_MSG_A("Unknown Conversion Type : 0%04x", Conv); break;
}
}
+23 -21
View File
@@ -15,6 +15,7 @@ $end_info$
#include <FEXCore/Core/X86Enums.h>
#include <FEXCore/Core/UContext.h>
#include <FEXCore/Utils/Allocator.h>
#include <cmath>
#include <signal.h>
@@ -30,17 +31,17 @@ CodeBuffer AllocateNewCodeBuffer(size_t Size) {
CodeBuffer Buffer;
Buffer.Size = Size;
Buffer.Ptr = static_cast<uint8_t*>(
mmap(nullptr,
FEXCore::Allocator::mmap(nullptr,
Buffer.Size,
PROT_READ | PROT_WRITE | PROT_EXEC,
MAP_PRIVATE | MAP_ANONYMOUS,
-1, 0));
LogMan::Throw::A(Buffer.Ptr != reinterpret_cast<uint8_t*>(~0ULL), "Couldn't allocate code buffer");
LOGMAN_THROW_A(Buffer.Ptr != reinterpret_cast<uint8_t*>(~0ULL), "Couldn't allocate code buffer");
return Buffer;
}
void FreeCodeBuffer(CodeBuffer Buffer) {
munmap(Buffer.Ptr, Buffer.Size);
FEXCore::Allocator::munmap(Buffer.Ptr, Buffer.Size);
}
}
@@ -84,7 +85,7 @@ void X86JITCore::Op_Unhandled(FEXCore::IR::IROp_Header *IROp, uint32_t Node) {
FallbackInfo Info;
if (!InterpreterOps::GetFallbackHandler(IROp, &Info)) {
auto Name = FEXCore::IR::GetName(IROp->Op);
LogMan::Msg::A("Unhandled IR Op: %s", std::string(Name).c_str());
LOGMAN_MSG_A("Unhandled IR Op: %s", std::string(Name).c_str());
} else {
switch(Info.ABI) {
case FABI_VOID_U16: {
@@ -282,7 +283,7 @@ void X86JITCore::Op_Unhandled(FEXCore::IR::IROp_Header *IROp, uint32_t Node) {
case FABI_UNKNOWN:
default:
auto Name = FEXCore::IR::GetName(IROp->Op);
LogMan::Msg::A("Unhandled IR Fallback abi: %s %d", std::string(Name).c_str(), Info.ABI);
LOGMAN_MSG_A("Unhandled IR Fallback abi: %s %d", std::string(Name).c_str(), Info.ABI);
}
}
}
@@ -330,13 +331,13 @@ X86JITCore::X86JITCore(FEXCore::Context::Context *ctx, FEXCore::Core::InternalTh
config.ExitFunctionLink = reinterpret_cast<uintptr_t>(&ExitFunctionLink);
config.ExitFunctionLinkThis = reinterpret_cast<uintptr_t>(this);
Dispatcher = new X86Dispatcher(CTX, ThreadState, config);
Dispatcher = std::make_unique<X86Dispatcher>(CTX, ThreadState, config);
DispatchPtr = Dispatcher->DispatchPtr;
CallbackPtr = Dispatcher->CallbackPtr;
ThreadSharedData.SignalHandlerRefCounterPtr = &Dispatcher->SignalHandlerRefCounter;
ThreadSharedData.SignalHandlerReturnAddress = Dispatcher->SignalHandlerReturnAddress;
ThreadSharedData.Dispatcher = Dispatcher.get();
// This will register the host signal handler per thread, which is fine
CTX->SignalDelegation->RegisterHostSignalHandler(SIGILL, [](FEXCore::Core::InternalThreadState *Thread, int Signal, void *info, void *ucontext) -> bool {
@@ -413,7 +414,7 @@ void X86JITCore::ClearCache() {
IR::PhysicalRegister X86JITCore::GetPhys(uint32_t Node) {
auto PhyReg = RAData->GetNodeRegister(Node);
LogMan::Throw::A(PhyReg.Raw != 255, "Couldn't Allocate register for node: ssa%d. Class: %d", Node, PhyReg.Class);
LOGMAN_THROW_A(PhyReg.Raw != 255, "Couldn't Allocate register for node: ssa%d. Class: %d", Node, PhyReg.Class);
return PhyReg;
}
@@ -529,7 +530,7 @@ bool X86JITCore::IsInlineEntrypointOffset(const IR::OrderedNodeWrapper& WNode, u
if (OpHeader->Op == IR::IROps::OP_INLINEENTRYPOINTOFFSET) {
auto Op = OpHeader->C<IR::IROp_InlineEntrypointOffset>();
if (Value) {
*Value = IR->GetHeader()->Entry + Op->Offset;
*Value = Entry + Op->Offset;
}
return true;
} else {
@@ -562,7 +563,7 @@ std::tuple<X86JITCore::SetCC, X86JITCore::CMovCC, X86JITCore::JCC> X86JITCore::G
case FEXCore::IR::COND_VS:
case FEXCore::IR::COND_VC:
default:
LogMan::Msg::A("Unsupported compare type");
LOGMAN_MSG_A("Unsupported compare type");
break;
}
@@ -570,10 +571,11 @@ std::tuple<X86JITCore::SetCC, X86JITCore::CMovCC, X86JITCore::JCC> X86JITCore::G
return { &CodeGenerator::sete , &CodeGenerator::cmove , &CodeGenerator::je };
}
void *X86JITCore::CompileCode([[maybe_unused]] FEXCore::IR::IRListView const *IR, [[maybe_unused]] FEXCore::Core::DebugData *DebugData, FEXCore::IR::RegisterAllocationData *RAData) {
void *X86JITCore::CompileCode(uint64_t Entry, [[maybe_unused]] FEXCore::IR::IRListView const *IR, [[maybe_unused]] FEXCore::Core::DebugData *DebugData, FEXCore::IR::RegisterAllocationData *RAData) {
JumpTargets.clear();
uint32_t SSACount = IR->GetSSACount();
this->Entry = Entry;
this->RAData = RAData;
// Fairly excessive buffer range to make sure we don't overflow
@@ -582,7 +584,7 @@ void *X86JITCore::CompileCode([[maybe_unused]] FEXCore::IR::IRListView const *IR
ThreadState->CTX->ClearCodeCache(ThreadState, false);
}
void *Entry = getCurr<void*>();
void *GuestEntry = getCurr<void*>();
this->IR = IR;
if (CTX->GetGdbServerStatus()) {
@@ -597,14 +599,14 @@ void *X86JITCore::CompileCode([[maybe_unused]] FEXCore::IR::IRListView const *IR
cmp(dword [rax + (offsetof(FEXCore::Context::Context, Config.RunningMode))], 0);
je(RunBlock);
// Else we need to pause now
mov(rax, Dispatcher->ThreadPauseHandlerAddress);
mov(rax, ThreadSharedData.Dispatcher->ThreadPauseHandlerAddress);
jmp(rax);
ud2();
L(RunBlock);
}
LogMan::Throw::A(RAData != nullptr, "Needs RA");
LOGMAN_THROW_A(RAData != nullptr, "Needs RA");
SpillSlots = RAData->SpillSlots();
@@ -613,7 +615,7 @@ void *X86JITCore::CompileCode([[maybe_unused]] FEXCore::IR::IRListView const *IR
}
#ifdef BLOCKSTATS
BlockSamplingData::BlockData *SamplingData = CTX->BlockData->GetBlockData(HeaderOp->Entry);
BlockSamplingData::BlockData *SamplingData = CTX->BlockData->GetBlockData(Entry);
if (GetSamplingData) {
mov(rcx, reinterpret_cast<uintptr_t>(SamplingData));
rdtsc();
@@ -661,7 +663,7 @@ void *X86JITCore::CompileCode([[maybe_unused]] FEXCore::IR::IRListView const *IR
using namespace FEXCore::IR;
{
auto BlockIROp = BlockHeader->CW<IROp_CodeBlock>();
LogMan::Throw::A(BlockIROp->Header.Op == IR::OP_CODEBLOCK, "IR type failed to be a code block");
LOGMAN_THROW_A(BlockIROp->Header.Op == IR::OP_CODEBLOCK, "IR type failed to be a code block");
uint32_t Node = IR->GetID(BlockNode);
auto IsTarget = JumpTargets.find(Node);
@@ -730,15 +732,15 @@ void *X86JITCore::CompileCode([[maybe_unused]] FEXCore::IR::IRListView const *IR
}
PendingTargetLabel = nullptr;
void *Exit = getCurr<void*>();
void *GuestExit = getCurr<void*>();
this->IR = nullptr;
ready();
if (DebugData) {
DebugData->HostCodeSize = reinterpret_cast<uintptr_t>(Exit) - reinterpret_cast<uintptr_t>(Entry);
DebugData->HostCodeSize = reinterpret_cast<uintptr_t>(GuestExit) - reinterpret_cast<uintptr_t>(GuestEntry);
}
return Entry;
return GuestEntry;
}
uint64_t X86JITCore::ExitFunctionLink(X86JITCore *core, FEXCore::Core::CpuStateFrame *Frame, uint64_t *record) {
@@ -749,10 +751,10 @@ uint64_t X86JITCore::ExitFunctionLink(X86JITCore *core, FEXCore::Core::CpuStateF
if (!HostCode) {
Thread->CurrentFrame->State.rip = GuestRip;
return core->Dispatcher->AbsoluteLoopTopAddress;
return core->ThreadSharedData.Dispatcher->AbsoluteLoopTopAddress;
}
auto LinkerAddress = core->Dispatcher->ExitFunctionLinkerAddress;
auto LinkerAddress = core->ThreadSharedData.Dispatcher->ExitFunctionLinkerAddress;
Thread->LookupCache->AddBlockLink(GuestRip, (uintptr_t)record, [record, LinkerAddress]{
// undo the link
record[0] = LinkerAddress;
@@ -66,7 +66,7 @@ public:
explicit X86JITCore(FEXCore::Context::Context *ctx, FEXCore::Core::InternalThreadState *Thread, CodeBuffer Buffer, bool CompileThread);
~X86JITCore() override;
std::string GetName() override { return "JIT"; }
void *CompileCode(FEXCore::IR::IRListView const *IR, FEXCore::Core::DebugData *DebugData, FEXCore::IR::RegisterAllocationData *RAData) override;
void *CompileCode(uint64_t Entry, FEXCore::IR::IRListView const *IR, FEXCore::Core::DebugData *DebugData, FEXCore::IR::RegisterAllocationData *RAData) override;
void *MapRegion(void* HostPtr, uint64_t, uint64_t) override { return HostPtr; }
@@ -83,7 +83,8 @@ private:
FEXCore::Context::Context *CTX;
FEXCore::Core::InternalThreadState *ThreadState;
FEXCore::IR::IRListView const *IR;
FEXCore::CPU::Dispatcher *Dispatcher;
std::unique_ptr<FEXCore::CPU::Dispatcher> Dispatcher;
uint64_t Entry;
std::unordered_map<IR::OrderedNodeWrapper::NodeOffsetType, Label> JumpTargets;
Xbyak::util::Cpu Features{};
@@ -161,6 +162,7 @@ private:
uint64_t SignalHandlerReturnAddress{};
uint32_t *SignalHandlerRefCounterPtr{};
FEXCore::CPU::Dispatcher *Dispatcher{};
};
CompilerSharedData ThreadSharedData;
@@ -306,6 +308,7 @@ private:
DEF_OP(StoreMem);
DEF_OP(VLoadMemElement);
DEF_OP(VStoreMemElement);
DEF_OP(CacheLineClear);
///< Misc ops
DEF_OP(EndBlock);
@@ -36,10 +36,10 @@ DEF_OP(LoadContext) {
}
break;
case 16: {
LogMan::Msg::A("Invalid GPR load of size 16");
LOGMAN_MSG_A("Invalid GPR load of size 16");
}
break;
default: LogMan::Msg::A("Unhandled LoadContext size: %d", OpSize);
default: LOGMAN_MSG_A("Unhandled LoadContext size: %d", OpSize);
}
}
else {
@@ -69,7 +69,7 @@ DEF_OP(LoadContext) {
movups(GetDst(Node), xword [STATE + Op->Offset]);
}
break;
default: LogMan::Msg::A("Unhandled LoadContext size: %d", OpSize);
default: LOGMAN_MSG_A("Unhandled LoadContext size: %d", OpSize);
}
}
}
@@ -100,7 +100,7 @@ DEF_OP(StoreContext) {
case 16:
LogMan::Msg::D("Invalid store size of 16");
break;
default: LogMan::Msg::A("Unhandled StoreContext size: %d", OpSize);
default: LOGMAN_MSG_A("Unhandled StoreContext size: %d", OpSize);
}
}
else {
@@ -129,7 +129,7 @@ DEF_OP(StoreContext) {
movups(xword [STATE + Op->Offset], GetSrc(Op->Header.Args[0].ID()));
}
break;
default: LogMan::Msg::A("Unhandled StoreContext size: %d", OpSize);
default: LOGMAN_MSG_A("Unhandled StoreContext size: %d", OpSize);
}
}
}
@@ -160,15 +160,15 @@ DEF_OP(LoadContextIndexed) {
mov(GetDst<RA_64>(Node), qword [rax + index * Op->Stride]);
break;
default:
LogMan::Msg::A("Unhandled LoadContextIndexed size: %d", Op->Size);
LOGMAN_MSG_A("Unhandled LoadContextIndexed size: %d", Op->Size);
}
break;
}
case 16:
LogMan::Msg::A("Invalid Class load of size 16");
LOGMAN_MSG_A("Invalid Class load of size 16");
break;
default:
LogMan::Msg::A("Unhandled LoadContextIndexed stride: %d", Op->Stride);
LOGMAN_MSG_A("Unhandled LoadContextIndexed stride: %d", Op->Stride);
}
}
@@ -195,7 +195,7 @@ DEF_OP(LoadContextIndexed) {
vmovq(GetDst(Node), qword [rax + index * Op->Stride]);
break;
default:
LogMan::Msg::A("Unhandled LoadContextIndexed size: %d", Op->Size);
LOGMAN_MSG_A("Unhandled LoadContextIndexed size: %d", Op->Size);
}
break;
}
@@ -223,12 +223,12 @@ DEF_OP(LoadContextIndexed) {
movups(GetDst(Node), xword [STATE + rax]);
break;
default:
LogMan::Msg::A("Unhandled LoadContextIndexed size: %d", Op->Size);
LOGMAN_MSG_A("Unhandled LoadContextIndexed size: %d", Op->Size);
}
break;
}
default:
LogMan::Msg::A("Unhandled LoadContextIndexed stride: %d", Op->Stride);
LOGMAN_MSG_A("Unhandled LoadContextIndexed stride: %d", Op->Stride);
}
}
}
@@ -248,13 +248,13 @@ DEF_OP(StoreContextIndexed) {
case 4:
case 8: {
if (!(size == 1 || size == 2 || size == 4 || size == 8)) {
LogMan::Msg::A("Unhandled StoreContextIndexed size: %d", Op->Size);
LOGMAN_MSG_A("Unhandled StoreContextIndexed size: %d", Op->Size);
}
mov(AddressFrame(Op->Size * 8) [rax + index * Op->Stride], value);
break;
}
default:
LogMan::Msg::A("Unhandled StoreContextIndexed stride: %d", Op->Stride);
LOGMAN_MSG_A("Unhandled StoreContextIndexed stride: %d", Op->Stride);
}
}
else {
@@ -279,7 +279,7 @@ DEF_OP(StoreContextIndexed) {
vmovq(AddressFrame(Op->Size * 8) [rax + index * Op->Stride], value);
break;
default:
LogMan::Msg::A("Unhandled StoreContextIndexed size: %d", size);
LOGMAN_MSG_A("Unhandled StoreContextIndexed size: %d", size);
}
break;
}
@@ -307,12 +307,12 @@ DEF_OP(StoreContextIndexed) {
movups(xword [STATE + rax], value);
break;
default:
LogMan::Msg::A("Unhandled StoreContextIndexed size: %d", size);
LOGMAN_MSG_A("Unhandled StoreContextIndexed size: %d", size);
}
break;
}
default:
LogMan::Msg::A("Unhandled StoreContextIndexed stride: %d", Op->Stride);
LOGMAN_MSG_A("Unhandled StoreContextIndexed stride: %d", Op->Stride);
}
}
}
@@ -340,7 +340,7 @@ DEF_OP(SpillRegister) {
mov(qword [rsp + SlotOffset], GetSrc<RA_64>(Op->Header.Args[0].ID()));
break;
}
default: LogMan::Msg::A("Unhandled SpillRegister size: %d", OpSize);
default: LOGMAN_MSG_A("Unhandled SpillRegister size: %d", OpSize);
}
} else if (Op->Class == FEXCore::IR::FPRClass) {
switch (OpSize) {
@@ -356,10 +356,10 @@ DEF_OP(SpillRegister) {
movaps(xword [rsp + SlotOffset], GetSrc(Op->Header.Args[0].ID()));
break;
}
default: LogMan::Msg::A("Unhandled SpillRegister size: %d", OpSize);
default: LOGMAN_MSG_A("Unhandled SpillRegister size: %d", OpSize);
}
} else {
LogMan::Msg::A("Unhandled SpillRegister class: %d", Op->Class.Val);
LOGMAN_MSG_A("Unhandled SpillRegister class: %d", Op->Class.Val);
}
@@ -388,7 +388,7 @@ DEF_OP(FillRegister) {
mov(GetDst<RA_64>(Node), qword [rsp + SlotOffset]);
break;
}
default: LogMan::Msg::A("Unhandled FillRegister size: %d", OpSize);
default: LOGMAN_MSG_A("Unhandled FillRegister size: %d", OpSize);
}
} else if (Op->Class == FEXCore::IR::FPRClass) {
switch (OpSize) {
@@ -404,10 +404,10 @@ DEF_OP(FillRegister) {
movaps(GetDst(Node), xword [rsp + SlotOffset]);
break;
}
default: LogMan::Msg::A("Unhandled FillRegister size: %d", OpSize);
default: LOGMAN_MSG_A("Unhandled FillRegister size: %d", OpSize);
}
} else {
LogMan::Msg::A("Unhandled FillRegister class: %d", Op->Class.Val);
LOGMAN_MSG_A("Unhandled FillRegister class: %d", Op->Class.Val);
}
}
@@ -430,11 +430,11 @@ Xbyak::RegExp X86JITCore::GenerateModRM(Xbyak::Reg Base, IR::OrderedNodeWrapper
return Base;
} else {
if (OffsetScale != 1 && OffsetScale != 2 && OffsetScale != 4 && OffsetScale != 8) {
LogMan::Msg::A("Unhandled GenerateModRM OffsetScale: %d", OffsetScale);
LOGMAN_MSG_A("Unhandled GenerateModRM OffsetScale: %d", OffsetScale);
}
if (OffsetType != IR::MEM_OFFSET_SXTX) {
LogMan::Msg::A("Unhandled GenerateModRM OffsetType: %d", OffsetType.Val);
LOGMAN_MSG_A("Unhandled GenerateModRM OffsetType: %d", OffsetType.Val);
}
uint64_t Const;
@@ -475,7 +475,7 @@ DEF_OP(LoadMem) {
mov(Dst, qword [MemPtr]);
}
break;
default: LogMan::Msg::A("Unhandled LoadMem size: %d", Op->Size);
default: LOGMAN_MSG_A("Unhandled LoadMem size: %d", Op->Size);
}
}
else
@@ -511,7 +511,7 @@ DEF_OP(LoadMem) {
}
}
break;
default: LogMan::Msg::A("Unhandled LoadMem size: %d", Op->Size);
default: LOGMAN_MSG_A("Unhandled LoadMem size: %d", Op->Size);
}
}
}
@@ -537,7 +537,7 @@ DEF_OP(StoreMem) {
case 8:
mov(qword [MemPtr], GetSrc<RA_64>(Op->Header.Args[1].ID()));
break;
default: LogMan::Msg::A("Unhandled StoreMem size: %d", Op->Size);
default: LOGMAN_MSG_A("Unhandled StoreMem size: %d", Op->Size);
}
}
else {
@@ -560,17 +560,25 @@ DEF_OP(StoreMem) {
else
movups(xword [MemPtr], GetSrc(Op->Header.Args[1].ID()));
break;
default: LogMan::Msg::A("Unhandled StoreMem size: %d", Op->Size);
default: LOGMAN_MSG_A("Unhandled StoreMem size: %d", Op->Size);
}
}
}
DEF_OP(VLoadMemElement) {
LogMan::Msg::A("Unimplemented");
LOGMAN_MSG_A("Unimplemented");
}
DEF_OP(VStoreMemElement) {
LogMan::Msg::A("Unimplemented");
LOGMAN_MSG_A("Unimplemented");
}
DEF_OP(CacheLineClear) {
auto Op = IROp->C<IR::IROp_CacheLineClear>();
Xbyak::Reg MemReg = GetSrc<RA_64>(Op->Addr.ID());
clflush(ptr [MemReg]);
}
#undef DEF_OP
@@ -592,6 +600,7 @@ void X86JITCore::RegisterMemoryHandlers() {
REGISTER_OP(STOREMEMTSO, StoreMem);
REGISTER_OP(VLOADMEMELEMENT, VLoadMemElement);
REGISTER_OP(VSTOREMEMELEMENT, VStoreMemElement);
REGISTER_OP(CACHELINECLEAR, CacheLineClear);
#undef REGISTER_OP
}
}
@@ -26,7 +26,7 @@ DEF_OP(Fence) {
case IR::Fence_Store.Val:
sfence();
break;
default: LogMan::Msg::A("Unknown Fence: %d", Op->Fence); break;
default: LOGMAN_MSG_A("Unknown Fence: %d", Op->Fence); break;
}
}
@@ -37,13 +37,22 @@ DEF_OP(Break) {
case 5: // Guest ud2
ud2();
break;
case 1: // Int <imm8>
ud2();
break;
case 2: // overflow
ud2();
break;
case 3: // int 1
ud2();
break;
case 4: { // HLT
// Time to quit
// Set our stack to the starting stack location
mov(rsp, qword [STATE + offsetof(FEXCore::Core::CpuStateFrame, ReturningStackLocation)]);
// Now we need to jump to the thread stop handler
mov(TMP1, Dispatcher->ThreadStopHandlerAddress);
mov(TMP1, ThreadSharedData.Dispatcher->ThreadStopHandlerAddress);
jmp(TMP1);
break;
}
@@ -56,7 +65,7 @@ DEF_OP(Break) {
}
// This jump target needs to be a constant offset here
mov(TMP1, Dispatcher->ThreadPauseHandlerAddress);
mov(TMP1, ThreadSharedData.Dispatcher->ThreadPauseHandlerAddress);
jmp(TMP1);
}
else {
@@ -65,12 +74,12 @@ DEF_OP(Break) {
mov(rsp, qword [STATE + offsetof(FEXCore::Core::CpuStateFrame, ReturningStackLocation)]);
// Now we need to jump to the thread stop handler
mov(TMP1, Dispatcher->ThreadStopHandlerAddress);
mov(TMP1, ThreadSharedData.Dispatcher->ThreadStopHandlerAddress);
jmp(TMP1);
}
break;
}
default: LogMan::Msg::A("Unknown Break reason: %d", Op->Reason);
default: LOGMAN_MSG_A("Unknown Break reason: %d", Op->Reason);
}
}
@@ -25,7 +25,7 @@ DEF_OP(ExtractElementPair) {
mov (GetDst<RA_64>(Node), Regs[Op->Element]);
break;
}
default: LogMan::Msg::A("Unknown Size"); break;
default: LOGMAN_MSG_A("Unknown Size"); break;
}
}
@@ -51,7 +51,7 @@ DEF_OP(CreateElementPair) {
RegTmp = rax;
break;
}
default: LogMan::Msg::A("Unknown Size"); break;
default: LOGMAN_MSG_A("Unknown Size"); break;
}
if (Dst.first != RegSecond) {
+119 -103
View File
@@ -62,24 +62,24 @@ DEF_OP(VectorImm) {
}
DEF_OP(CreateVector2) {
LogMan::Msg::A("Unimplemented");
LOGMAN_MSG_A("Unimplemented");
}
DEF_OP(CreateVector4) {
LogMan::Msg::A("Unimplemented");
LOGMAN_MSG_A("Unimplemented");
}
DEF_OP(SplatVector) {
auto Op = IROp->C<IR::IROp_SplatVector2>();
uint8_t OpSize = IROp->Size;
LogMan::Throw::A(OpSize <= 16, "Can't handle a vector of size: %d", OpSize);
LOGMAN_THROW_A(OpSize <= 16, "Can't handle a vector of size: %d", OpSize);
uint8_t Elements = 0;
switch (Op->Header.Op) {
case IR::OP_SPLATVECTOR4: Elements = 4; break;
case IR::OP_SPLATVECTOR2: Elements = 2; break;
default: LogMan::Msg::A("Uknown Splat size"); break;
default: LOGMAN_MSG_A("Uknown Splat size"); break;
}
uint8_t ElementSize = OpSize / Elements;
@@ -92,7 +92,7 @@ DEF_OP(SplatVector) {
case 8:
movddup(GetDst(Node), GetSrc(Op->Header.Args[0].ID()));
break;
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.Size); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.Size); break;
}
}
@@ -130,7 +130,7 @@ DEF_OP(VMov) {
movaps(GetDst(Node), GetSrc(Op->Header.Args[0].ID()));
break;
}
default: LogMan::Msg::A("Unknown Element Size: %d", OpSize); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", OpSize); break;
}
}
@@ -168,7 +168,7 @@ DEF_OP(VAdd) {
vpaddq(GetDst(Node), GetSrc(Op->Header.Args[0].ID()), GetSrc(Op->Header.Args[1].ID()));
break;
}
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
}
}
@@ -191,7 +191,7 @@ DEF_OP(VSub) {
vpsubq(GetDst(Node), GetSrc(Op->Header.Args[0].ID()), GetSrc(Op->Header.Args[1].ID()));
break;
}
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
}
}
@@ -206,7 +206,7 @@ DEF_OP(VUQAdd) {
vpaddusw(GetDst(Node), GetSrc(Op->Header.Args[0].ID()), GetSrc(Op->Header.Args[1].ID()));
break;
}
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
}
}
@@ -221,7 +221,7 @@ DEF_OP(VUQSub) {
vpsubusw(GetDst(Node), GetSrc(Op->Header.Args[0].ID()), GetSrc(Op->Header.Args[1].ID()));
break;
}
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
}
}
@@ -236,7 +236,7 @@ DEF_OP(VSQAdd) {
vpaddsw(GetDst(Node), GetSrc(Op->Header.Args[0].ID()), GetSrc(Op->Header.Args[1].ID()));
break;
}
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
}
}
@@ -251,7 +251,7 @@ DEF_OP(VSQSub) {
vpsubsw(GetDst(Node), GetSrc(Op->Header.Args[0].ID()), GetSrc(Op->Header.Args[1].ID()));
break;
}
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
}
}
@@ -288,7 +288,7 @@ DEF_OP(VAddP) {
case 4:
vphaddd(GetDst(Node), xmm15, xmm14);
break;
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
}
}
else {
@@ -317,7 +317,7 @@ DEF_OP(VAddP) {
case 4:
vphaddd(GetDst(Node), GetSrc(Op->Header.Args[0].ID()), GetSrc(Op->Header.Args[1].ID()));
break;
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
}
}
}
@@ -349,7 +349,7 @@ DEF_OP(VAddV) {
pinsrd(xmm15, eax, 0);
break;
}
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
}
movaps(Dest, xmm15);
@@ -366,7 +366,7 @@ DEF_OP(VURAvg) {
vpavgw(GetDst(Node), GetSrc(Op->Header.Args[0].ID()), GetSrc(Op->Header.Args[1].ID()));
break;
}
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
}
}
@@ -389,7 +389,7 @@ DEF_OP(VAbs) {
vpabsq(GetDst(Node), GetSrc(Op->Header.Args[0].ID()));
break;
}
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
}
}
@@ -408,7 +408,7 @@ DEF_OP(VFAdd) {
vaddsd(GetDst(Node), GetSrc(Op->Header.Args[0].ID()), GetSrc(Op->Header.Args[1].ID()));
break;
}
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
}
}
else {
@@ -422,7 +422,7 @@ DEF_OP(VFAdd) {
vaddpd(GetDst(Node), GetSrc(Op->Header.Args[0].ID()), GetSrc(Op->Header.Args[1].ID()));
break;
}
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
}
}
}
@@ -436,7 +436,7 @@ DEF_OP(VFAddP) {
case 8:
vhaddpd(GetDst(Node), GetSrc(Op->Header.Args[0].ID()), GetSrc(Op->Header.Args[1].ID()));
break;
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
}
}
@@ -455,7 +455,7 @@ DEF_OP(VFSub) {
vsubsd(GetDst(Node), GetSrc(Op->Header.Args[0].ID()), GetSrc(Op->Header.Args[1].ID()));
break;
}
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
}
}
else {
@@ -469,7 +469,7 @@ DEF_OP(VFSub) {
vsubpd(GetDst(Node), GetSrc(Op->Header.Args[0].ID()), GetSrc(Op->Header.Args[1].ID()));
break;
}
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
}
}
}
@@ -489,7 +489,7 @@ DEF_OP(VFMul) {
vmulsd(GetDst(Node), GetSrc(Op->Header.Args[0].ID()), GetSrc(Op->Header.Args[1].ID()));
break;
}
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
}
}
else {
@@ -503,7 +503,7 @@ DEF_OP(VFMul) {
vmulpd(GetDst(Node), GetSrc(Op->Header.Args[0].ID()), GetSrc(Op->Header.Args[1].ID()));
break;
}
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
}
}
}
@@ -523,7 +523,7 @@ DEF_OP(VFDiv) {
vdivsd(GetDst(Node), GetSrc(Op->Header.Args[0].ID()), GetSrc(Op->Header.Args[1].ID()));
break;
}
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
}
}
else {
@@ -537,7 +537,7 @@ DEF_OP(VFDiv) {
vdivpd(GetDst(Node), GetSrc(Op->Header.Args[0].ID()), GetSrc(Op->Header.Args[1].ID()));
break;
}
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
}
}
}
@@ -557,7 +557,7 @@ DEF_OP(VFMin) {
vminsd(GetDst(Node), GetSrc(Op->Header.Args[0].ID()), GetSrc(Op->Header.Args[1].ID()));
break;
}
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
}
}
else {
@@ -571,7 +571,7 @@ DEF_OP(VFMin) {
vminpd(GetDst(Node), GetSrc(Op->Header.Args[0].ID()), GetSrc(Op->Header.Args[1].ID()));
break;
}
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
}
}
}
@@ -591,7 +591,7 @@ DEF_OP(VFMax) {
vmaxsd(GetDst(Node), GetSrc(Op->Header.Args[0].ID()), GetSrc(Op->Header.Args[1].ID()));
break;
}
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
}
}
else {
@@ -605,7 +605,7 @@ DEF_OP(VFMax) {
vmaxpd(GetDst(Node), GetSrc(Op->Header.Args[0].ID()), GetSrc(Op->Header.Args[1].ID()));
break;
}
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
}
}
}
@@ -623,7 +623,7 @@ DEF_OP(VFRecp) {
vdivss(GetDst(Node), xmm15, GetSrc(Op->Header.Args[0].ID()));
break;
}
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
}
}
else {
@@ -636,7 +636,7 @@ DEF_OP(VFRecp) {
vdivps(GetDst(Node), xmm15, GetSrc(Op->Header.Args[0].ID()));
break;
}
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
}
}
}
@@ -656,7 +656,7 @@ DEF_OP(VFSqrt) {
vsqrtsd(GetDst(Node), GetSrc(Op->Header.Args[0].ID()), GetSrc(Op->Header.Args[0].ID()));
break;
}
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
}
}
else {
@@ -670,7 +670,7 @@ DEF_OP(VFSqrt) {
vsqrtpd(GetDst(Node), GetSrc(Op->Header.Args[0].ID()));
break;
}
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
}
}
}
@@ -696,7 +696,7 @@ DEF_OP(VFRSqrt) {
divsd(GetDst(Node), xmm15);
break;
}
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
}
}
else {
@@ -710,7 +710,7 @@ DEF_OP(VFRSqrt) {
divps(GetDst(Node), xmm15);
break;
}
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
}
}
}
@@ -735,7 +735,7 @@ DEF_OP(VNeg) {
vpsubq(GetDst(Node), xmm15, GetSrc(Op->Header.Args[0].ID()));
break;
}
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
}
}
@@ -756,7 +756,7 @@ DEF_OP(VFNeg) {
vxorpd(GetDst(Node), xmm15, GetSrc(Op->Header.Args[0].ID()));
break;
}
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
}
}
@@ -768,20 +768,36 @@ DEF_OP(VNot) {
DEF_OP(VUMin) {
auto Op = IROp->C<IR::IROp_VUMin>();
switch (Op->Header.ElementSize) {
case 1: {
vpminub(GetDst(Node), GetSrc(Op->Header.Args[0].ID()), GetSrc(Op->Header.Args[1].ID()));
break;
if (Op->Header.Size == Op->Header.ElementSize) {
switch (Op->Header.ElementSize) {
case 8: {
// This isn't very nice on x86 until AVX-512
pextrq(TMP1, GetSrc(Op->Header.Args[0].ID()), 0);
pextrq(TMP2, GetSrc(Op->Header.Args[1].ID()), 0);
cmp(TMP1, TMP2);
cmovb(TMP2, TMP1);
pinsrq(GetDst(Node), TMP2, 0);
break;
}
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
}
case 2: {
vpminuw(GetDst(Node), GetSrc(Op->Header.Args[0].ID()), GetSrc(Op->Header.Args[1].ID()));
break;
}
else {
switch (Op->Header.ElementSize) {
case 1: {
vpminub(GetDst(Node), GetSrc(Op->Header.Args[0].ID()), GetSrc(Op->Header.Args[1].ID()));
break;
}
case 2: {
vpminuw(GetDst(Node), GetSrc(Op->Header.Args[0].ID()), GetSrc(Op->Header.Args[1].ID()));
break;
}
case 4: {
vpminud(GetDst(Node), GetSrc(Op->Header.Args[0].ID()), GetSrc(Op->Header.Args[1].ID()));
break;
}
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
}
case 4: {
vpminud(GetDst(Node), GetSrc(Op->Header.Args[0].ID()), GetSrc(Op->Header.Args[1].ID()));
break;
}
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
}
}
@@ -800,7 +816,7 @@ DEF_OP(VSMin) {
vpminsd(GetDst(Node), GetSrc(Op->Header.Args[0].ID()), GetSrc(Op->Header.Args[1].ID()));
break;
}
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
}
}
@@ -819,7 +835,7 @@ DEF_OP(VUMax) {
vpmaxud(GetDst(Node), GetSrc(Op->Header.Args[0].ID()), GetSrc(Op->Header.Args[1].ID()));
break;
}
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
}
}
@@ -838,7 +854,7 @@ DEF_OP(VSMax) {
vpmaxsd(GetDst(Node), GetSrc(Op->Header.Args[0].ID()), GetSrc(Op->Header.Args[1].ID()));
break;
}
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
}
}
@@ -863,7 +879,7 @@ DEF_OP(VZip) {
punpcklqdq(xmm15, GetSrc(Op->Header.Args[1].ID()));
break;
}
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
}
movapd(GetDst(Node), xmm15);
}
@@ -890,7 +906,7 @@ DEF_OP(VZip2) {
vpunpckhdq(GetDst(Node), xmm15, xmm14);
break;
}
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
}
}
else {
@@ -911,7 +927,7 @@ DEF_OP(VZip2) {
punpckhqdq(xmm15, GetSrc(Op->Header.Args[1].ID()));
break;
}
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
}
movapd(GetDst(Node), xmm15);
}
@@ -940,7 +956,7 @@ DEF_OP(VCMPEQ) {
case 8:
vpcmpeqq(GetDst(Node), GetSrc(Op->Header.Args[0].ID()), GetSrc(Op->Header.Args[1].ID()));
break;
default: LogMan::Msg::A("Unsupported elementSize: %d", Op->Header.ElementSize);
default: LOGMAN_MSG_A("Unsupported elementSize: %d", Op->Header.ElementSize);
}
}
@@ -961,7 +977,7 @@ DEF_OP(VCMPEQZ) {
case 8:
vpcmpeqq(GetDst(Node), GetSrc(Op->Header.Args[0].ID()), xmm15);
break;
default: LogMan::Msg::A("Unsupported elementSize: %d", Op->Header.ElementSize);
default: LOGMAN_MSG_A("Unsupported elementSize: %d", Op->Header.ElementSize);
}
}
@@ -981,7 +997,7 @@ DEF_OP(VCMPGT) {
case 8:
vpcmpgtq(GetDst(Node), GetSrc(Op->Header.Args[0].ID()), GetSrc(Op->Header.Args[1].ID()));
break;
default: LogMan::Msg::A("Unsupported elementSize: %d", Op->Header.ElementSize);
default: LOGMAN_MSG_A("Unsupported elementSize: %d", Op->Header.ElementSize);
}
}
@@ -1002,7 +1018,7 @@ DEF_OP(VCMPGTZ) {
case 8:
vpcmpgtq(GetDst(Node), GetSrc(Op->Header.Args[0].ID()), xmm15);
break;
default: LogMan::Msg::A("Unsupported elementSize: %d", Op->Header.ElementSize);
default: LOGMAN_MSG_A("Unsupported elementSize: %d", Op->Header.ElementSize);
}
}
@@ -1023,7 +1039,7 @@ DEF_OP(VCMPLTZ) {
case 8:
vpcmpgtq(GetDst(Node), xmm15, GetSrc(Op->Header.Args[0].ID()));
break;
default: LogMan::Msg::A("Unsupported elementSize: %d", Op->Header.ElementSize);
default: LOGMAN_MSG_A("Unsupported elementSize: %d", Op->Header.ElementSize);
}
}
@@ -1039,7 +1055,7 @@ DEF_OP(VFCMPEQ) {
case 8:
vcmpsd(GetDst(Node), GetSrc(Op->Header.Args[0].ID()), GetSrc(Op->Header.Args[1].ID()), 0);
break;
default: LogMan::Msg::A("Unsupported elementSize: %d", Op->Header.ElementSize);
default: LOGMAN_MSG_A("Unsupported elementSize: %d", Op->Header.ElementSize);
}
}
else {
@@ -1050,7 +1066,7 @@ DEF_OP(VFCMPEQ) {
case 8:
vcmppd(GetDst(Node), GetSrc(Op->Header.Args[0].ID()), GetSrc(Op->Header.Args[1].ID()), 0);
break;
default: LogMan::Msg::A("Unsupported elementSize: %d", Op->Header.ElementSize);
default: LOGMAN_MSG_A("Unsupported elementSize: %d", Op->Header.ElementSize);
}
}
}
@@ -1067,7 +1083,7 @@ DEF_OP(VFCMPNEQ) {
case 8:
vcmpsd(GetDst(Node), GetSrc(Op->Header.Args[0].ID()), GetSrc(Op->Header.Args[1].ID()), 4);
break;
default: LogMan::Msg::A("Unsupported elementSize: %d", Op->Header.ElementSize);
default: LOGMAN_MSG_A("Unsupported elementSize: %d", Op->Header.ElementSize);
}
}
@@ -1079,7 +1095,7 @@ DEF_OP(VFCMPNEQ) {
case 8:
vcmppd(GetDst(Node), GetSrc(Op->Header.Args[0].ID()), GetSrc(Op->Header.Args[1].ID()), 4);
break;
default: LogMan::Msg::A("Unsupported elementSize: %d", Op->Header.ElementSize);
default: LOGMAN_MSG_A("Unsupported elementSize: %d", Op->Header.ElementSize);
}
}
}
@@ -1096,7 +1112,7 @@ DEF_OP(VFCMPLT) {
case 8:
vcmpsd(GetDst(Node), GetSrc(Op->Header.Args[0].ID()), GetSrc(Op->Header.Args[1].ID()), 1);
break;
default: LogMan::Msg::A("Unsupported elementSize: %d", Op->Header.ElementSize);
default: LOGMAN_MSG_A("Unsupported elementSize: %d", Op->Header.ElementSize);
}
}
else {
@@ -1107,7 +1123,7 @@ DEF_OP(VFCMPLT) {
case 8:
vcmppd(GetDst(Node), GetSrc(Op->Header.Args[0].ID()), GetSrc(Op->Header.Args[1].ID()), 1);
break;
default: LogMan::Msg::A("Unsupported elementSize: %d", Op->Header.ElementSize);
default: LOGMAN_MSG_A("Unsupported elementSize: %d", Op->Header.ElementSize);
}
}
}
@@ -1124,7 +1140,7 @@ DEF_OP(VFCMPGT) {
case 8:
vcmpsd(GetDst(Node), GetSrc(Op->Header.Args[1].ID()), GetSrc(Op->Header.Args[0].ID()), 1);
break;
default: LogMan::Msg::A("Unsupported elementSize: %d", Op->Header.ElementSize);
default: LOGMAN_MSG_A("Unsupported elementSize: %d", Op->Header.ElementSize);
}
}
else {
@@ -1135,7 +1151,7 @@ DEF_OP(VFCMPGT) {
case 8:
vcmppd(GetDst(Node), GetSrc(Op->Header.Args[1].ID()), GetSrc(Op->Header.Args[0].ID()), 1);
break;
default: LogMan::Msg::A("Unsupported elementSize: %d", Op->Header.ElementSize);
default: LOGMAN_MSG_A("Unsupported elementSize: %d", Op->Header.ElementSize);
}
}
}
@@ -1152,7 +1168,7 @@ DEF_OP(VFCMPLE) {
case 8:
vcmpsd(GetDst(Node), GetSrc(Op->Header.Args[0].ID()), GetSrc(Op->Header.Args[1].ID()), 2);
break;
default: LogMan::Msg::A("Unsupported elementSize: %d", Op->Header.ElementSize);
default: LOGMAN_MSG_A("Unsupported elementSize: %d", Op->Header.ElementSize);
}
}
else {
@@ -1163,7 +1179,7 @@ DEF_OP(VFCMPLE) {
case 8:
vcmppd(GetDst(Node), GetSrc(Op->Header.Args[0].ID()), GetSrc(Op->Header.Args[1].ID()), 2);
break;
default: LogMan::Msg::A("Unsupported elementSize: %d", Op->Header.ElementSize);
default: LOGMAN_MSG_A("Unsupported elementSize: %d", Op->Header.ElementSize);
}
}
}
@@ -1180,7 +1196,7 @@ DEF_OP(VFCMPORD) {
case 8:
vcmpsd(GetDst(Node), GetSrc(Op->Header.Args[0].ID()), GetSrc(Op->Header.Args[1].ID()), 7);
break;
default: LogMan::Msg::A("Unsupported elementSize: %d", Op->Header.ElementSize);
default: LOGMAN_MSG_A("Unsupported elementSize: %d", Op->Header.ElementSize);
}
}
else {
@@ -1191,7 +1207,7 @@ DEF_OP(VFCMPORD) {
case 8:
vcmppd(GetDst(Node), GetSrc(Op->Header.Args[0].ID()), GetSrc(Op->Header.Args[1].ID()), 7);
break;
default: LogMan::Msg::A("Unsupported elementSize: %d", Op->Header.ElementSize);
default: LOGMAN_MSG_A("Unsupported elementSize: %d", Op->Header.ElementSize);
}
}
}
@@ -1208,7 +1224,7 @@ DEF_OP(VFCMPUNO) {
case 8:
vcmpsd(GetDst(Node), GetSrc(Op->Header.Args[0].ID()), GetSrc(Op->Header.Args[1].ID()), 3);
break;
default: LogMan::Msg::A("Unsupported elementSize: %d", Op->Header.ElementSize);
default: LOGMAN_MSG_A("Unsupported elementSize: %d", Op->Header.ElementSize);
}
}
else {
@@ -1219,21 +1235,21 @@ DEF_OP(VFCMPUNO) {
case 8:
vcmppd(GetDst(Node), GetSrc(Op->Header.Args[0].ID()), GetSrc(Op->Header.Args[1].ID()), 3);
break;
default: LogMan::Msg::A("Unsupported elementSize: %d", Op->Header.ElementSize);
default: LOGMAN_MSG_A("Unsupported elementSize: %d", Op->Header.ElementSize);
}
}
}
DEF_OP(VUShl) {
LogMan::Msg::A("Unimplemented");
LOGMAN_MSG_A("Unimplemented");
}
DEF_OP(VUShr) {
LogMan::Msg::A("Unimplemented");
LOGMAN_MSG_A("Unimplemented");
}
DEF_OP(VSShr) {
LogMan::Msg::A("Unimplemented");
LOGMAN_MSG_A("Unimplemented");
}
DEF_OP(VUShlS) {
@@ -1252,7 +1268,7 @@ DEF_OP(VUShlS) {
vpsllq(GetDst(Node), GetSrc(Op->Header.Args[0].ID()), GetSrc(Op->Header.Args[1].ID()));
break;
}
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
}
}
@@ -1272,7 +1288,7 @@ DEF_OP(VUShrS) {
vpsrlq(GetDst(Node), GetSrc(Op->Header.Args[0].ID()), GetSrc(Op->Header.Args[1].ID()));
break;
}
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
}
}
@@ -1289,7 +1305,7 @@ DEF_OP(VSShrS) {
break;
}
case 8: // Doesn't exist on x86
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
}
}
@@ -1322,7 +1338,7 @@ DEF_OP(VInsElement) {
pinsrq(xmm15, rax, Op->DestIdx);
break;
}
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
}
movapd(GetDst(Node), xmm15);
@@ -1357,7 +1373,7 @@ DEF_OP(VInsScalarElement) {
pinsrq(xmm15, rax, Op->DestIdx);
break;
}
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
}
movapd(GetDst(Node), xmm15);
@@ -1387,7 +1403,7 @@ DEF_OP(VExtractElement) {
pinsrq(GetDst(Node), rax, 0);
break;
}
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
}
}
@@ -1438,7 +1454,7 @@ DEF_OP(VUShrI) {
psrlq(GetDst(Node), Op->BitShift);
break;
}
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
}
}
@@ -1454,7 +1470,7 @@ DEF_OP(VSShrI) {
psrad(GetDst(Node), Op->BitShift);
break;
}
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
}
}
@@ -1474,7 +1490,7 @@ DEF_OP(VShlI) {
psllq(GetDst(Node), Op->BitShift);
break;
}
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
}
}
@@ -1504,7 +1520,7 @@ DEF_OP(VUShrNI) {
mov(rcx, 0x80'80'80'80'80'80'80'80); // Upper
break;
}
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
}
vmovq(xmm15, rax);
@@ -1540,7 +1556,7 @@ DEF_OP(VUShrNI2) {
mov(rcx, 0x0B'0A'09'08'03'02'01'00); // Upper
break;
}
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
}
vmovq(xmm15, rax);
@@ -1567,7 +1583,7 @@ DEF_OP(VSXTL) {
case 8:
pmovsxdq(GetDst(Node), GetSrc(Op->Header.Args[0].ID()));
break;
default: LogMan::Msg::A("Unknown element size: %d", Op->Header.ElementSize);
default: LOGMAN_MSG_A("Unknown element size: %d", Op->Header.ElementSize);
}
}
@@ -1586,7 +1602,7 @@ DEF_OP(VSXTL2) {
case 8:
pmovsxdq(GetDst(Node), GetDst(Node));
break;
default: LogMan::Msg::A("Unknown element size: %d", Op->Header.ElementSize);
default: LOGMAN_MSG_A("Unknown element size: %d", Op->Header.ElementSize);
}
}
@@ -1602,7 +1618,7 @@ DEF_OP(VUXTL) {
case 8:
pmovzxdq(GetDst(Node), GetSrc(Op->Header.Args[0].ID()));
break;
default: LogMan::Msg::A("Unknown element size: %d", Op->Header.ElementSize);
default: LOGMAN_MSG_A("Unknown element size: %d", Op->Header.ElementSize);
}
}
@@ -1621,7 +1637,7 @@ DEF_OP(VUXTL2) {
case 8:
pmovzxdq(GetDst(Node), GetDst(Node));
break;
default: LogMan::Msg::A("Unknown element size: %d", Op->Header.ElementSize);
default: LOGMAN_MSG_A("Unknown element size: %d", Op->Header.ElementSize);
}
}
@@ -1634,7 +1650,7 @@ DEF_OP(VSQXTN) {
case 2:
packssdw(xmm15, GetSrc(Op->Header.Args[0].ID()));
break;
default: LogMan::Msg::A("Unknown element size: %d", Op->Header.ElementSize);
default: LOGMAN_MSG_A("Unknown element size: %d", Op->Header.ElementSize);
}
psrldq(xmm15, 8);
movaps(GetDst(Node), xmm15);
@@ -1653,7 +1669,7 @@ DEF_OP(VSQXTN2) {
case 2:
packssdw(xmm15, GetSrc(Op->Header.Args[1].ID()));
break;
default: LogMan::Msg::A("Unknown element size: %d", Op->Header.ElementSize);
default: LOGMAN_MSG_A("Unknown element size: %d", Op->Header.ElementSize);
}
if (OpSize == 8) {
@@ -1671,7 +1687,7 @@ DEF_OP(VSQXTUN) {
case 2:
packusdw(xmm15, GetSrc(Op->Header.Args[0].ID()));
break;
default: LogMan::Msg::A("Unknown element size: %d", Op->Header.ElementSize);
default: LOGMAN_MSG_A("Unknown element size: %d", Op->Header.ElementSize);
}
psrldq(xmm15, 8);
movaps(GetDst(Node), xmm15);
@@ -1690,7 +1706,7 @@ DEF_OP(VSQXTUN2) {
case 2:
packusdw(xmm15, GetSrc(Op->Header.Args[1].ID()));
break;
default: LogMan::Msg::A("Unknown element size: %d", Op->Header.ElementSize);
default: LOGMAN_MSG_A("Unknown element size: %d", Op->Header.ElementSize);
}
if (OpSize == 8) {
psrldq(xmm15, OpSize / 2);
@@ -1710,7 +1726,7 @@ DEF_OP(VMul) {
vpmulld(GetDst(Node), GetSrc(Op->Header.Args[0].ID()), GetSrc(Op->Header.Args[1].ID()));
break;
}
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
}
}
@@ -1741,7 +1757,7 @@ DEF_OP(VUMull) {
vpmuludq(GetDst(Node), xmm14, xmm15);
break;
}
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
}
}
@@ -1776,7 +1792,7 @@ DEF_OP(VSMull) {
vpmuldq(GetDst(Node), xmm14, xmm15);
break;
}
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
}
}
@@ -1812,7 +1828,7 @@ DEF_OP(VUMull2) {
vpmuludq(GetDst(Node), xmm14, xmm15);
break;
}
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
}
}
@@ -1852,7 +1868,7 @@ DEF_OP(VSMull2) {
vpmuldq(GetDst(Node), xmm14, xmm15);
break;
}
default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break;
default: LOGMAN_MSG_A("Unknown Element Size: %d", Op->Header.ElementSize); break;
}
}
@@ -1870,7 +1886,7 @@ DEF_OP(VTBL1) {
vpshufb(GetDst(Node), GetSrc(Op->Header.Args[0].ID()), GetSrc(Op->Header.Args[1].ID()));
break;
}
default: LogMan::Msg::A("Unknown OpSize: %d", OpSize); break;
default: LOGMAN_MSG_A("Unknown OpSize: %d", OpSize); break;
}
}
+10 -8
View File
@@ -8,6 +8,8 @@ $end_info$
#include "Interface/Context/Context.h"
#include "Interface/Core/Core.h"
#include "Interface/Core/LookupCache.h"
#include <FEXCore/Utils/Allocator.h>
#include <sys/mman.h>
namespace FEXCore {
@@ -26,27 +28,27 @@ LookupCache::LookupCache(FEXCore::Context::Context *CTX)
// Allocate a region of memory that we can use to back our block pointers
// We need one pointer per page of virtual memory
// At 64GB of virtual memory this will allocate 128MB of virtual memory space
PagePointer = reinterpret_cast<uintptr_t>(mmap(nullptr, ctx->Config.VirtualMemSize / 4096 * 8, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0));
PagePointer = reinterpret_cast<uintptr_t>(FEXCore::Allocator::mmap(nullptr, ctx->Config.VirtualMemSize / 4096 * 8, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0));
// Allocate our memory backing our pages
// We need 32KB per guest page (One pointer per byte)
// XXX: We can drop down to 16KB if we store 4byte offsets from the code base
// We currently limit to 128MB of real memory for caching for the total cache size.
// Can end up being inefficient if we compile a small number of blocks per page
PageMemory = reinterpret_cast<uintptr_t>(mmap(nullptr, CODE_SIZE, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0));
LogMan::Throw::A(PageMemory != -1ULL, "Failed to allocate page memory");
PageMemory = reinterpret_cast<uintptr_t>(FEXCore::Allocator::mmap(nullptr, CODE_SIZE, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0));
LOGMAN_THROW_A(PageMemory != -1ULL, "Failed to allocate page memory");
// L1 Cache
L1Pointer = reinterpret_cast<uintptr_t>(mmap(nullptr, L1_SIZE, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0));
LogMan::Throw::A(L1Pointer != -1ULL, "Failed to allocate L1Pointer");
L1Pointer = reinterpret_cast<uintptr_t>(FEXCore::Allocator::mmap(nullptr, L1_SIZE, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0));
LOGMAN_THROW_A(L1Pointer != -1ULL, "Failed to allocate L1Pointer");
VirtualMemSize = ctx->Config.VirtualMemSize;
}
LookupCache::~LookupCache() {
munmap(reinterpret_cast<void*>(PagePointer), ctx->Config.VirtualMemSize / 4096 * 8);
munmap(reinterpret_cast<void*>(PageMemory), CODE_SIZE);
munmap(reinterpret_cast<void*>(L1Pointer), L1_SIZE);
FEXCore::Allocator::munmap(reinterpret_cast<void*>(PagePointer), ctx->Config.VirtualMemSize / 4096 * 8);
FEXCore::Allocator::munmap(reinterpret_cast<void*>(PageMemory), CODE_SIZE);
FEXCore::Allocator::munmap(reinterpret_cast<void*>(L1Pointer), L1_SIZE);
}
void LookupCache::HintUsedRange(uint64_t Address, uint64_t Size) {
+8 -5
View File
@@ -39,13 +39,17 @@ public:
void AddBlockMapping(uint64_t Address, void *HostCode, uint64_t Start, uint64_t Length) {
auto InsertPoint = BlockList.emplace(Address, (uintptr_t)HostCode);
LogMan::Throw::A(InsertPoint.second == true, "Dupplicate block mapping added");
LOGMAN_THROW_A(InsertPoint.second == true, "Dupplicate block mapping added");
for (auto CurrentPage = Start >> 12, EndPage = (Start + Length) >> 12; CurrentPage <= EndPage; CurrentPage++) {
CodePages[CurrentPage].push_back(Address);
}
// no need to update L1 or L2, they will get updated on first lookup
// There is no need to update L1 or L2, they will get updated on first lookup
// However, adding to L1 here increases performance
auto &L1Entry = reinterpret_cast<LookupCacheEntry*>(L1Pointer)[Address & L1_ENTRIES_MASK];
L1Entry.GuestCode = Address;
L1Entry.HostCode = (uintptr_t)HostCode;
}
void Erase(uint64_t Address) {
@@ -105,9 +109,8 @@ private:
void CacheBlockMapping(uint64_t Address, uintptr_t HostCode) {
// Do L1
auto &L1Entry = reinterpret_cast<LookupCacheEntry*>(L1Pointer)[Address & L1_ENTRIES_MASK];
if (L1Entry.GuestCode == Address) {
L1Entry.GuestCode = L1Entry.HostCode = 0;
}
L1Entry.GuestCode = Address;
L1Entry.HostCode = HostCode;
// Do ful map
auto FullAddress = Address;
+180 -77
View File
@@ -130,6 +130,7 @@ void OpDispatchBuilder::ThunkOp(OpcodeArgs) {
}
void OpDispatchBuilder::LEAOp(OpcodeArgs) {
// LEA specifically ignores segment prefixes
if (CTX->Config.Is64BitMode) {
uint32_t DstSize = X86Tables::DecodeFlags::GetOpAddr(Op->Flags, 0) == X86Tables::DecodeFlags::FLAG_OPERAND_SIZE_LAST ? 2 :
X86Tables::DecodeFlags::GetOpAddr(Op->Flags, 0) == X86Tables::DecodeFlags::FLAG_WIDENING_SIZE_LAST ? 8 : 4;
@@ -188,7 +189,11 @@ RSP
SS
*/
void OpDispatchBuilder::IRETOp(OpcodeArgs) {
LogMan::Throw::A(CTX->Config.Is64BitMode == true, "IRET only implemented for x64");
if (CTX->Config.Is64BitMode == false) {
LogMan::Msg::E("IRET only implemented for x64");
DecodeFailure = true;
return;
}
uint8_t GPRSize = CTX->Config.Is64BitMode ? 8 : 4;
@@ -276,7 +281,7 @@ void OpDispatchBuilder::SecondaryALUOp(OpcodeArgs) {
break;
default:
IROp = FEXCore::IR::IROps::OP_LAST;
LogMan::Msg::A("Unknown ALU Op: 0x%x", Op->OP);
LOGMAN_MSG_A("Unknown ALU Op: 0x%x", Op->OP);
break;
};
#undef OPD
@@ -316,7 +321,7 @@ void OpDispatchBuilder::SecondaryALUOp(OpcodeArgs) {
Result = _Xor(Dest, Src);
break;
}
default: LogMan::Msg::A("Unknown Atomic IR Op: %d", IROp); break;
default: LOGMAN_MSG_A("Unknown Atomic IR Op: %d", IROp); break;
}
}
else {
@@ -871,7 +876,7 @@ OrderedNode *OpDispatchBuilder::SelectCC(uint8_t OP, OrderedNode *TrueValue, Ord
Check, OneConst, TrueValue, FalseValue);
break;
}
default: LogMan::Msg::A("Unknown CC Op: 0x%x\n", OP); return nullptr;
default: LOGMAN_MSG_A("Unknown CC Op: 0x%x\n", OP); return nullptr;
}
// Try folding the flags generation in the select op
@@ -997,7 +1002,7 @@ void OpDispatchBuilder::CondJUMPOp(OpcodeArgs) {
auto SrcCond = SelectCC(Op->OP & 0xF, TakeBranch, DoNotTakeBranch);
LogMan::Throw::A(Op->Src[0].TypeNone.Type == FEXCore::X86Tables::DecodedOperand::TYPE_LITERAL, "Src1 needs to be literal here");
LOGMAN_THROW_A(Op->Src[0].TypeNone.Type == FEXCore::X86Tables::DecodedOperand::TYPE_LITERAL, "Src1 needs to be literal here");
uint64_t Target = Op->PC + Op->InstSize + Op->Src[0].TypeLiteral.Literal;
@@ -1056,7 +1061,7 @@ void OpDispatchBuilder::CondJUMPRCXOp(OpcodeArgs) {
TakeBranch = _Constant(1);
DoNotTakeBranch = _Constant(0);
LogMan::Throw::A(Op->Src[0].TypeNone.Type == FEXCore::X86Tables::DecodedOperand::TYPE_LITERAL, "Src1 needs to be literal here");
LOGMAN_THROW_A(Op->Src[0].TypeNone.Type == FEXCore::X86Tables::DecodedOperand::TYPE_LITERAL, "Src1 needs to be literal here");
uint64_t Target = Op->PC + Op->InstSize + Op->Src[0].TypeLiteral.Literal;
@@ -1119,7 +1124,7 @@ void OpDispatchBuilder::LoopOp(OpcodeArgs) {
uint32_t SrcSize = (Op->Flags & X86Tables::DecodeFlags::FLAG_ADDRESS_SIZE) ? 4 : 8;
LogMan::Throw::A(Op->Src[1].TypeNone.Type == FEXCore::X86Tables::DecodedOperand::TYPE_LITERAL, "Src1 needs to be literal here");
LOGMAN_THROW_A(Op->Src[1].TypeNone.Type == FEXCore::X86Tables::DecodedOperand::TYPE_LITERAL, "Src1 needs to be literal here");
uint64_t Target = Op->PC + Op->InstSize + Op->Src[1].TypeLiteral.Literal;
@@ -1187,7 +1192,7 @@ void OpDispatchBuilder::JUMPOp(OpcodeArgs) {
// This is just an unconditional relative literal jump
if (Multiblock) {
LogMan::Throw::A(Op->Src[0].TypeNone.Type == FEXCore::X86Tables::DecodedOperand::TYPE_LITERAL, "Src1 needs to be literal here");
LOGMAN_THROW_A(Op->Src[0].TypeNone.Type == FEXCore::X86Tables::DecodedOperand::TYPE_LITERAL, "Src1 needs to be literal here");
uint64_t Target = Op->PC + Op->InstSize + Op->Src[0].TypeLiteral.Literal;
auto JumpBlock = JumpTargets.find(Target);
if (JumpBlock != JumpTargets.end()) {
@@ -1492,18 +1497,25 @@ void OpDispatchBuilder::MOVSegOp(OpcodeArgs) {
_StoreContext(GPRClass, 2, offsetof(FEXCore::Core::CPUState, ss), Src);
break;
case 6: // GS
LogMan::Throw::A(!CTX->Config.Is64BitMode, "We don't support modifying GS selector in 64bit mode!");
if (!CTX->Config.Is64BitMode) {
_StoreContext(GPRClass, 2, offsetof(FEXCore::Core::CPUState, gs), Src);
} else {
LogMan::Msg::E("We don't support modifying GS selector in 64bit mode!");
DecodeFailure = true;
}
break;
case 7: // FS
LogMan::Throw::A(!CTX->Config.Is64BitMode, "We don't support modifying FS selector in 64bit mode!");
if (!CTX->Config.Is64BitMode) {
_StoreContext(GPRClass, 2, offsetof(FEXCore::Core::CPUState, fs), Src);
} else {
LogMan::Msg::E("We don't support modifying FS selector in 64bit mode!");
DecodeFailure = true;
}
break;
default: LogMan::Msg::A("Unknown segment register: %d", Op->Dest.TypeGPR.GPR);
default:
LogMan::Msg::E("Unknown segment register: %d", Op->Dest.TypeGPR.GPR);
DecodeFailure = true;
break;
}
}
else {
@@ -1538,7 +1550,10 @@ void OpDispatchBuilder::MOVSegOp(OpcodeArgs) {
Segment = _LoadContext(2, offsetof(FEXCore::Core::CPUState, fs), GPRClass);
}
break;
default: LogMan::Msg::A("Unknown segment register: %d", Op->Src[0].TypeGPR.GPR);
default:
LogMan::Msg::E("Unknown segment register: %d", Op->Dest.TypeGPR.GPR);
DecodeFailure = true;
return;
}
StoreResult(GPRClass, Op, Segment, -1);
}
@@ -1621,7 +1636,7 @@ void OpDispatchBuilder::SHLOp(OpcodeArgs) {
void OpDispatchBuilder::SHLImmediateOp(OpcodeArgs) {
OrderedNode *Dest = LoadSource(GPRClass, Op, Op->Dest, Op->Flags, -1);
LogMan::Throw::A(Op->Src[1].TypeNone.Type == FEXCore::X86Tables::DecodedOperand::TYPE_LITERAL, "Src1 needs to be literal here");
LOGMAN_THROW_A(Op->Src[1].TypeNone.Type == FEXCore::X86Tables::DecodedOperand::TYPE_LITERAL, "Src1 needs to be literal here");
uint64_t Shift = Op->Src[1].TypeLiteral.Literal;
auto Size = GetSrcSize(Op) * 8;
@@ -1679,7 +1694,7 @@ void OpDispatchBuilder::SHROp(OpcodeArgs) {
void OpDispatchBuilder::SHRImmediateOp(OpcodeArgs) {
auto Dest = LoadSource(GPRClass, Op, Op->Dest, Op->Flags, -1);
LogMan::Throw::A(Op->Src[1].TypeNone.Type == FEXCore::X86Tables::DecodedOperand::TYPE_LITERAL, "Src1 needs to be literal here");
LOGMAN_THROW_A(Op->Src[1].TypeNone.Type == FEXCore::X86Tables::DecodedOperand::TYPE_LITERAL, "Src1 needs to be literal here");
uint64_t Shift = Op->Src[1].TypeLiteral.Literal;
auto Size = GetSrcSize(Op) * 8;
@@ -1756,7 +1771,7 @@ void OpDispatchBuilder::SHLDImmediateOp(OpcodeArgs) {
OrderedNode *Src = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags, -1);
OrderedNode *Dest = LoadSource(GPRClass, Op, Op->Dest, Op->Flags, -1);
LogMan::Throw::A(Op->Src[1].TypeNone.Type == FEXCore::X86Tables::DecodedOperand::TYPE_LITERAL, "Src1 needs to be literal here");
LOGMAN_THROW_A(Op->Src[1].TypeNone.Type == FEXCore::X86Tables::DecodedOperand::TYPE_LITERAL, "Src1 needs to be literal here");
uint64_t Shift = Op->Src[1].TypeLiteral.Literal;
auto Size = GetSrcSize(Op) * 8;
@@ -1845,7 +1860,7 @@ void OpDispatchBuilder::SHRDImmediateOp(OpcodeArgs) {
OrderedNode *Src = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags, -1);
OrderedNode *Dest = LoadSource(GPRClass, Op, Op->Dest, Op->Flags, -1);
LogMan::Throw::A(Op->Src[1].TypeNone.Type == FEXCore::X86Tables::DecodedOperand::TYPE_LITERAL, "Src1 needs to be literal here");
LOGMAN_THROW_A(Op->Src[1].TypeNone.Type == FEXCore::X86Tables::DecodedOperand::TYPE_LITERAL, "Src1 needs to be literal here");
uint64_t Shift = Op->Src[1].TypeLiteral.Literal;
auto Size = GetSrcSize(Op) * 8;
@@ -1916,7 +1931,7 @@ void OpDispatchBuilder::ASHROp(OpcodeArgs) {
void OpDispatchBuilder::ASHRImmediateOp(OpcodeArgs) {
OrderedNode *Dest = LoadSource(GPRClass, Op, Op->Dest, Op->Flags, -1);
LogMan::Throw::A(Op->Src[1].TypeNone.Type == FEXCore::X86Tables::DecodedOperand::TYPE_LITERAL, "Src1 needs to be literal here");
LOGMAN_THROW_A(Op->Src[1].TypeNone.Type == FEXCore::X86Tables::DecodedOperand::TYPE_LITERAL, "Src1 needs to be literal here");
uint64_t Shift = Op->Src[1].TypeLiteral.Literal;
auto Size = GetSrcSize(Op) * 8;
@@ -1984,7 +1999,7 @@ void OpDispatchBuilder::ROROp(OpcodeArgs) {
void OpDispatchBuilder::RORImmediateOp(OpcodeArgs) {
OrderedNode *Dest = LoadSource(GPRClass, Op, Op->Dest, Op->Flags, -1);
LogMan::Throw::A(Op->Src[1].TypeNone.Type == FEXCore::X86Tables::DecodedOperand::TYPE_LITERAL, "Src1 needs to be literal here");
LOGMAN_THROW_A(Op->Src[1].TypeNone.Type == FEXCore::X86Tables::DecodedOperand::TYPE_LITERAL, "Src1 needs to be literal here");
uint64_t Shift = Op->Src[1].TypeLiteral.Literal;
auto Size = GetSrcSize(Op) * 8;
@@ -2062,7 +2077,7 @@ void OpDispatchBuilder::ROLOp(OpcodeArgs) {
void OpDispatchBuilder::ROLImmediateOp(OpcodeArgs) {
OrderedNode *Dest = LoadSource(GPRClass, Op, Op->Dest, Op->Flags, -1);
LogMan::Throw::A(Op->Src[1].TypeNone.Type == FEXCore::X86Tables::DecodedOperand::TYPE_LITERAL, "Src1 needs to be literal here");
LOGMAN_THROW_A(Op->Src[1].TypeNone.Type == FEXCore::X86Tables::DecodedOperand::TYPE_LITERAL, "Src1 needs to be literal here");
uint64_t Shift = Op->Src[1].TypeLiteral.Literal;
auto Size = GetSrcSize(Op) * 8;
@@ -2783,7 +2798,11 @@ void OpDispatchBuilder::IMULOp(OpcodeArgs) {
_StoreContext(GPRClass, 8, offsetof(FEXCore::Core::CPUState, gregs[FEXCore::X86State::REG_RDX]), LocalResultHigh);
}
else if (Size == 8) {
LogMan::Throw::A(CTX->Config.Is64BitMode, "Doesn't exist in 32bit mode");
if (!CTX->Config.Is64BitMode) {
LogMan::Msg::E("Doesn't exist in 32bit mode");
DecodeFailure = true;
return;
}
// 64bits stored in RAX
// 64bits stored in RDX
ResultHigh = _MulH(Src1, Src2);
@@ -2828,7 +2847,11 @@ void OpDispatchBuilder::MULOp(OpcodeArgs) {
_StoreContext(GPRClass, GPRSize, offsetof(FEXCore::Core::CPUState, gregs[FEXCore::X86State::REG_RDX]), ResultHigh);
}
else if (Size == 8) {
LogMan::Throw::A(CTX->Config.Is64BitMode, "Doesn't exist in 32bit mode");
if (!CTX->Config.Is64BitMode) {
LogMan::Msg::E("Doesn't exist in 32bit mode");
DecodeFailure = true;
return;
}
// 64bits stored in RAX
// 64bits stored in RDX
ResultHigh = _UMulH(Src1, Src2);
@@ -2960,7 +2983,7 @@ void OpDispatchBuilder::WriteSegmentReg(OpcodeArgs) {
void OpDispatchBuilder::EnterOp(OpcodeArgs) {
uint8_t GPRSize = CTX->Config.Is64BitMode ? 8 : 4;
LogMan::Throw::A(Op->Src[0].TypeNone.Type == FEXCore::X86Tables::DecodedOperand::TYPE_LITERAL, "Src1 needs to be literal here");
LOGMAN_THROW_A(Op->Src[0].TypeNone.Type == FEXCore::X86Tables::DecodedOperand::TYPE_LITERAL, "Src1 needs to be literal here");
uint64_t Value = Op->Src[0].TypeLiteral.Literal;
uint16_t AllocSpace = Value & 0xFFFF;
@@ -3007,7 +3030,11 @@ void OpDispatchBuilder::RDTSCOp(OpcodeArgs) {
}
void OpDispatchBuilder::INCOp(OpcodeArgs) {
LogMan::Throw::A(!(Op->Flags & FEXCore::X86Tables::DecodeFlags::FLAG_REP_PREFIX), "Can't handle REP on this\n");
if (Op->Flags & FEXCore::X86Tables::DecodeFlags::FLAG_REP_PREFIX) {
LogMan::Msg::E("Can't handle REP on this");
DecodeFailure = true;
return;
}
OrderedNode *Dest;
OrderedNode *Result;
@@ -3038,7 +3065,11 @@ void OpDispatchBuilder::INCOp(OpcodeArgs) {
}
void OpDispatchBuilder::DECOp(OpcodeArgs) {
LogMan::Throw::A(!(Op->Flags & FEXCore::X86Tables::DecodeFlags::FLAG_REP_PREFIX), "Can't handle REP on this\n");
if (Op->Flags & FEXCore::X86Tables::DecodeFlags::FLAG_REP_PREFIX) {
LogMan::Msg::E("Can't handle REP on this");
DecodeFailure = true;
return;
}
OrderedNode *Dest;
OrderedNode *Result;
@@ -3069,8 +3100,17 @@ void OpDispatchBuilder::DECOp(OpcodeArgs) {
void OpDispatchBuilder::STOSOp(OpcodeArgs) {
uint8_t GPRSize = CTX->Config.Is64BitMode ? 8 : 4;
LogMan::Throw::A(!(Op->Flags & FEXCore::X86Tables::DecodeFlags::FLAG_REPNE_PREFIX), "Invalid REPNE on STOS");
LogMan::Throw::A(!(Op->Flags & FEXCore::X86Tables::DecodeFlags::FLAG_ADDRESS_SIZE), "Can't handle adddress size\n");
if (Op->Flags & FEXCore::X86Tables::DecodeFlags::FLAG_REPNE_PREFIX) {
LogMan::Msg::E("Invalid REPNE on STOS");
DecodeFailure = true;
return;
}
if (Op->Flags & FEXCore::X86Tables::DecodeFlags::FLAG_ADDRESS_SIZE) {
LogMan::Msg::E("Can't handle adddress size");
DecodeFailure = true;
return;
}
auto Size = GetSrcSize(Op);
bool Repeat = Op->Flags & FEXCore::X86Tables::DecodeFlags::FLAG_REP_PREFIX;
@@ -3080,7 +3120,7 @@ void OpDispatchBuilder::STOSOp(OpcodeArgs) {
OrderedNode *Dest = _LoadContext(GPRSize, offsetof(FEXCore::Core::CPUState, gregs[FEXCore::X86State::REG_RDI]), GPRClass);
// Only ES prefix
Dest = AppendSegmentOffset(Dest, Op->Flags, FEXCore::X86Tables::DecodeFlags::FLAG_ES_PREFIX, true);
Dest = AppendSegmentOffset(Dest, 0, FEXCore::X86Tables::DecodeFlags::FLAG_ES_PREFIX, true);
// Store to memory where RDI points
_StoreMemAutoTSO(GPRClass, Size, Dest, Src, Size);
@@ -3139,7 +3179,7 @@ void OpDispatchBuilder::STOSOp(OpcodeArgs) {
OrderedNode *Dest = _LoadContext(GPRSize, offsetof(FEXCore::Core::CPUState, gregs[FEXCore::X86State::REG_RDI]), GPRClass);
// Only ES prefix
Dest = AppendSegmentOffset(Dest, Op->Flags, FEXCore::X86Tables::DecodeFlags::FLAG_ES_PREFIX, true);
Dest = AppendSegmentOffset(Dest, 0, FEXCore::X86Tables::DecodeFlags::FLAG_ES_PREFIX, true);
// Store to memory where RDI points
_StoreMemAutoTSO(GPRClass, Size, Dest, Src, Size);
@@ -3169,8 +3209,16 @@ void OpDispatchBuilder::STOSOp(OpcodeArgs) {
void OpDispatchBuilder::MOVSOp(OpcodeArgs) {
uint8_t GPRSize = CTX->Config.Is64BitMode ? 8 : 4;
LogMan::Throw::A(!(Op->Flags & FEXCore::X86Tables::DecodeFlags::FLAG_REPNE_PREFIX), "Invalid REPNE on MOVS\n");
LogMan::Throw::A(!(Op->Flags & FEXCore::X86Tables::DecodeFlags::FLAG_ADDRESS_SIZE), "Can't handle adddress size\n");
if (Op->Flags & FEXCore::X86Tables::DecodeFlags::FLAG_REPNE_PREFIX) {
LogMan::Msg::E("Invalid REPNE on MOVS");
DecodeFailure = true;
return;
}
if (Op->Flags & FEXCore::X86Tables::DecodeFlags::FLAG_ADDRESS_SIZE) {
LogMan::Msg::E("Can't handle adddress size");
DecodeFailure = true;
return;
}
// RA now can handle these to be here, to avoud DF accesses
auto Size = GetSrcSize(Op);
@@ -3205,7 +3253,7 @@ void OpDispatchBuilder::MOVSOp(OpcodeArgs) {
{
OrderedNode *Src = _LoadContext(GPRSize, offsetof(FEXCore::Core::CPUState, gregs[FEXCore::X86State::REG_RSI]), GPRClass);
OrderedNode *Dest = _LoadContext(GPRSize, offsetof(FEXCore::Core::CPUState, gregs[FEXCore::X86State::REG_RDI]), GPRClass);
Dest = AppendSegmentOffset(Dest, Op->Flags, FEXCore::X86Tables::DecodeFlags::FLAG_ES_PREFIX, true);
Dest = AppendSegmentOffset(Dest, 0, FEXCore::X86Tables::DecodeFlags::FLAG_ES_PREFIX, true);
Src = AppendSegmentOffset(Src, Op->Flags, FEXCore::X86Tables::DecodeFlags::FLAG_DS_PREFIX);
Src = _LoadMemAutoTSO(GPRClass, Size, Src, Size);
@@ -3240,7 +3288,7 @@ void OpDispatchBuilder::MOVSOp(OpcodeArgs) {
else {
OrderedNode *RSI = _LoadContext(GPRSize, offsetof(FEXCore::Core::CPUState, gregs[FEXCore::X86State::REG_RSI]), GPRClass);
OrderedNode *RDI = _LoadContext(GPRSize, offsetof(FEXCore::Core::CPUState, gregs[FEXCore::X86State::REG_RDI]), GPRClass);
RDI= AppendSegmentOffset(RDI, Op->Flags, FEXCore::X86Tables::DecodeFlags::FLAG_ES_PREFIX, true);
RDI= AppendSegmentOffset(RDI, 0, FEXCore::X86Tables::DecodeFlags::FLAG_ES_PREFIX, true);
RSI = AppendSegmentOffset(RSI, Op->Flags, FEXCore::X86Tables::DecodeFlags::FLAG_DS_PREFIX);
auto Src = _LoadMemAutoTSO(GPRClass, Size, RSI, Size);
@@ -3259,7 +3307,12 @@ void OpDispatchBuilder::MOVSOp(OpcodeArgs) {
void OpDispatchBuilder::CMPSOp(OpcodeArgs) {
uint8_t GPRSize = CTX->Config.Is64BitMode ? 8 : 4;
LogMan::Throw::A(!(Op->Flags & FEXCore::X86Tables::DecodeFlags::FLAG_ADDRESS_SIZE), "Can't handle adddress size\n");
if (Op->Flags & FEXCore::X86Tables::DecodeFlags::FLAG_ADDRESS_SIZE) {
LogMan::Msg::E("Can't handle adddress size");
DecodeFailure = true;
return;
}
auto Size = GetSrcSize(Op);
bool Repeat = Op->Flags & (FEXCore::X86Tables::DecodeFlags::FLAG_REPNE_PREFIX | FEXCore::X86Tables::DecodeFlags::FLAG_REP_PREFIX);
@@ -3268,7 +3321,7 @@ void OpDispatchBuilder::CMPSOp(OpcodeArgs) {
OrderedNode *Dest_RSI = _LoadContext(GPRSize, offsetof(FEXCore::Core::CPUState, gregs[FEXCore::X86State::REG_RSI]), GPRClass);
// Only ES prefix
Dest_RDI = AppendSegmentOffset(Dest_RDI, Op->Flags, FEXCore::X86Tables::DecodeFlags::FLAG_ES_PREFIX, true);
Dest_RDI = AppendSegmentOffset(Dest_RDI, 0, FEXCore::X86Tables::DecodeFlags::FLAG_ES_PREFIX, true);
// Default DS prefix
Dest_RSI = AppendSegmentOffset(Dest_RSI, Op->Flags, FEXCore::X86Tables::DecodeFlags::FLAG_DS_PREFIX);
@@ -3325,7 +3378,7 @@ void OpDispatchBuilder::CMPSOp(OpcodeArgs) {
OrderedNode *Dest_RSI = _LoadContext(GPRSize, offsetof(FEXCore::Core::CPUState, gregs[FEXCore::X86State::REG_RSI]), GPRClass);
// Only ES prefix
Dest_RDI = AppendSegmentOffset(Dest_RDI, Op->Flags, FEXCore::X86Tables::DecodeFlags::FLAG_ES_PREFIX, true);
Dest_RDI = AppendSegmentOffset(Dest_RDI, 0, FEXCore::X86Tables::DecodeFlags::FLAG_ES_PREFIX, true);
// Default DS prefix
Dest_RSI = AppendSegmentOffset(Dest_RSI, Op->Flags, FEXCore::X86Tables::DecodeFlags::FLAG_DS_PREFIX);
@@ -3374,8 +3427,16 @@ void OpDispatchBuilder::CMPSOp(OpcodeArgs) {
void OpDispatchBuilder::LODSOp(OpcodeArgs) {
uint8_t GPRSize = CTX->Config.Is64BitMode ? 8 : 4;
LogMan::Throw::A(!(Op->Flags & FEXCore::X86Tables::DecodeFlags::FLAG_ADDRESS_SIZE), "Can't handle adddress size\n");
LogMan::Throw::A(!(Op->Flags & FEXCore::X86Tables::DecodeFlags::FLAG_REPNE_PREFIX), "LODS doesn't support REPNE");
if (Op->Flags & FEXCore::X86Tables::DecodeFlags::FLAG_REPNE_PREFIX) {
LogMan::Msg::E("Invalid REPNE on LODS");
DecodeFailure = true;
return;
}
if (Op->Flags & FEXCore::X86Tables::DecodeFlags::FLAG_ADDRESS_SIZE) {
LogMan::Msg::E("Can't handle adddress size");
DecodeFailure = true;
return;
}
auto Size = GetSrcSize(Op);
bool Repeat = Op->Flags & FEXCore::X86Tables::DecodeFlags::FLAG_REP_PREFIX;
@@ -3467,7 +3528,11 @@ void OpDispatchBuilder::LODSOp(OpcodeArgs) {
}
void OpDispatchBuilder::SCASOp(OpcodeArgs) {
LogMan::Throw::A(!(Op->Flags & FEXCore::X86Tables::DecodeFlags::FLAG_ADDRESS_SIZE), "Can't handle adddress size\n");
if (Op->Flags & FEXCore::X86Tables::DecodeFlags::FLAG_ADDRESS_SIZE) {
LogMan::Msg::E("Can't handle adddress size");
DecodeFailure = true;
return;
}
uint8_t GPRSize = CTX->Config.Is64BitMode ? 8 : 4;
@@ -3476,7 +3541,7 @@ void OpDispatchBuilder::SCASOp(OpcodeArgs) {
if (!Repeat) {
OrderedNode *Dest_RDI = _LoadContext(GPRSize, offsetof(FEXCore::Core::CPUState, gregs[FEXCore::X86State::REG_RDI]), GPRClass);
Dest_RDI = AppendSegmentOffset(Dest_RDI, Op->Flags, FEXCore::X86Tables::DecodeFlags::FLAG_ES_PREFIX, true);
Dest_RDI = AppendSegmentOffset(Dest_RDI, 0, FEXCore::X86Tables::DecodeFlags::FLAG_ES_PREFIX, true);
auto Src1 = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags, -1);
auto Src2 = _LoadMemAutoTSO(GPRClass, Size, Dest_RDI, Size);
@@ -3533,7 +3598,7 @@ void OpDispatchBuilder::SCASOp(OpcodeArgs) {
// Working loop
{
OrderedNode *Dest_RDI = _LoadContext(GPRSize, offsetof(FEXCore::Core::CPUState, gregs[FEXCore::X86State::REG_RDI]), GPRClass);
Dest_RDI = AppendSegmentOffset(Dest_RDI, Op->Flags, FEXCore::X86Tables::DecodeFlags::FLAG_ES_PREFIX, true);
Dest_RDI = AppendSegmentOffset(Dest_RDI, 0, FEXCore::X86Tables::DecodeFlags::FLAG_ES_PREFIX, true);
auto Src1 = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags, -1);
auto Src2 = _LoadMemAutoTSO(GPRClass, Size, Dest_RDI, Size);
@@ -3633,7 +3698,11 @@ void OpDispatchBuilder::POPFOp(OpcodeArgs) {
}
void OpDispatchBuilder::NEGOp(OpcodeArgs) {
LogMan::Throw::A(!DestIsLockedMem(Op), "Can't handle LOCK on NEG\n");
if (DestIsLockedMem(Op)) {
LogMan::Msg::E("Can't handle LOCK on NEG");
DecodeFailure = true;
return;
}
OrderedNode *Dest = LoadSource(GPRClass, Op, Op->Dest, Op->Flags, -1);
auto ZeroConst = _Constant(0);
OrderedNode *Result = _Sub(ZeroConst, Dest);
@@ -3684,7 +3753,11 @@ void OpDispatchBuilder::DIVOp(OpcodeArgs) {
_StoreContext(GPRClass, GPRSize, offsetof(FEXCore::Core::CPUState, gregs[FEXCore::X86State::REG_RDX]), URemOp);
}
else if (Size == 8) {
LogMan::Throw::A(CTX->Config.Is64BitMode, "Doesn't exist in 32bit mode");
if (!CTX->Config.Is64BitMode) {
LogMan::Msg::E("Doesn't exist in 32bit mode");
DecodeFailure = true;
return;
}
OrderedNode *Src1 = _LoadContext(Size, offsetof(FEXCore::Core::CPUState, gregs[FEXCore::X86State::REG_RAX]), GPRClass);
OrderedNode *Src2 = _LoadContext(Size, offsetof(FEXCore::Core::CPUState, gregs[FEXCore::X86State::REG_RDX]), GPRClass);
@@ -3735,7 +3808,11 @@ void OpDispatchBuilder::IDIVOp(OpcodeArgs) {
_StoreContext(GPRClass, GPRSize, offsetof(FEXCore::Core::CPUState, gregs[FEXCore::X86State::REG_RDX]), URemOp);
}
else if (Size == 8) {
LogMan::Throw::A(CTX->Config.Is64BitMode, "Doesn't exist in 32bit mode");
if (!CTX->Config.Is64BitMode) {
LogMan::Msg::E("Doesn't exist in 32bit mode");
DecodeFailure = true;
return;
}
OrderedNode *Src1 = _LoadContext(Size, offsetof(FEXCore::Core::CPUState, gregs[FEXCore::X86State::REG_RAX]), GPRClass);
OrderedNode *Src2 = _LoadContext(Size, offsetof(FEXCore::Core::CPUState, gregs[FEXCore::X86State::REG_RDX]), GPRClass);
@@ -4135,7 +4212,7 @@ void OpDispatchBuilder::PSHUFBOp(OpcodeArgs) {
template<size_t ElementSize, bool HalfSize, bool Low>
void OpDispatchBuilder::PSHUFDOp(OpcodeArgs) {
LogMan::Throw::A(ElementSize != 0, "What. No element size?");
LOGMAN_THROW_A(ElementSize != 0, "What. No element size?");
auto Size = GetSrcSize(Op);
OrderedNode *Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags, -1);
uint8_t Shuffle = Op->Src[1].TypeLiteral.Literal;
@@ -4163,7 +4240,7 @@ void OpDispatchBuilder::PSHUFDOp(OpcodeArgs) {
template<size_t ElementSize>
void OpDispatchBuilder::SHUFOp(OpcodeArgs) {
LogMan::Throw::A(ElementSize != 0, "What. No element size?");
LOGMAN_THROW_A(ElementSize != 0, "What. No element size?");
auto Size = GetSrcSize(Op);
OrderedNode *Src1 = LoadSource(FPRClass, Op, Op->Dest, Op->Flags, -1);
OrderedNode *Src2 = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags, -1);
@@ -4219,7 +4296,7 @@ void OpDispatchBuilder::PINSROp(OpcodeArgs) {
OrderedNode *Src = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags, -1);
OrderedNode *Dest = LoadSource_WithOpSize(FPRClass, Op, Op->Dest, GetDstSize(Op), Op->Flags, -1);
LogMan::Throw::A(Op->Src[1].TypeNone.Type == FEXCore::X86Tables::DecodedOperand::TYPE_LITERAL, "Src1 needs to be literal here");
LOGMAN_THROW_A(Op->Src[1].TypeNone.Type == FEXCore::X86Tables::DecodedOperand::TYPE_LITERAL, "Src1 needs to be literal here");
uint64_t Index = Op->Src[1].TypeLiteral.Literal;
uint8_t NumElements = Size / ElementSize;
@@ -4235,13 +4312,17 @@ void OpDispatchBuilder::PExtrOp(OpcodeArgs) {
auto Size = GetSrcSize(Op);
OrderedNode *Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags, -1);
LogMan::Throw::A(Op->Src[1].TypeNone.Type == FEXCore::X86Tables::DecodedOperand::TYPE_LITERAL, "Src1 needs to be literal here");
LOGMAN_THROW_A(Op->Src[1].TypeNone.Type == FEXCore::X86Tables::DecodedOperand::TYPE_LITERAL, "Src1 needs to be literal here");
uint64_t Index = Op->Src[1].TypeLiteral.Literal;
uint8_t NumElements = Size / ElementSize;
Index &= NumElements - 1;
auto Result = _VExtractToGPR(16, ElementSize, Src, Index);
OrderedNode *Result = _VExtractToGPR(16, ElementSize, Src, Index);
if (ElementSize < 4) {
Result = _Bfe(4, ElementSize * 8, 0, Result);
}
StoreResult(GPRClass, Op, Result, -1);
}
@@ -4532,14 +4613,14 @@ void OpDispatchBuilder::CreateJumpBlocks(std::vector<FEXCore::Frontend::Decoder:
void OpDispatchBuilder::BeginFunction(uint64_t RIP, std::vector<FEXCore::Frontend::Decoder::DecodedBlocks> const *Blocks) {
Entry = RIP;
auto IRHeader = _IRHeader(InvalidNode, RIP, 0);
auto IRHeader = _IRHeader(InvalidNode, 0);
Current_Header = IRHeader.first;
Current_HeaderNode = IRHeader;
CreateJumpBlocks(Blocks);
auto Block = GetNewJumpBlock(RIP);
SetCurrentCodeBlock(Block);
IRHeader.first->Blocks = Block->Wrapped(ListData.Begin());
IRHeader.first->Blocks = Block->Wrapped(DualListData.ListBegin());
}
void OpDispatchBuilder::Finalize() {
@@ -4547,8 +4628,8 @@ void OpDispatchBuilder::Finalize() {
// Node 0 is invalid node
OrderedNode *RealNode = reinterpret_cast<OrderedNode*>(GetNode(1));
FEXCore::IR::IROp_Header *IROp = RealNode->Op(Data.Begin());
LogMan::Throw::A(IROp->Op == OP_IRHEADER, "First op in function must be our header");
FEXCore::IR::IROp_Header *IROp = RealNode->Op(DualListData.DataBegin());
LOGMAN_THROW_A(IROp->Op == OP_IRHEADER, "First op in function must be our header");
// Let's walk the jump blocks and see if we have handled every block target
for (auto &Handler : JumpTargets) {
@@ -4556,7 +4637,7 @@ void OpDispatchBuilder::Finalize() {
// We haven't emitted. Dump out to the dispatcher
SetCurrentCodeBlock(Handler.second.BlockEntry);
_ExitFunction(_Constant(GPRSize * 8, Handler.first));
_ExitFunction(_EntrypointOffset(Handler.first - Entry, GPRSize));
}
}
@@ -4574,7 +4655,7 @@ uint8_t OpDispatchBuilder::GetDstSize(FEXCore::X86Tables::DecodedOp Op) {
uint32_t DstSizeFlag = FEXCore::X86Tables::DecodeFlags::GetSizeDstFlags(Op->Flags);
uint8_t Size = Sizes[DstSizeFlag];
LogMan::Throw::A(Size != 0, "Invalid destination size for op");
LOGMAN_THROW_A(Size != 0, "Invalid destination size for op");
return Size;
}
@@ -4592,7 +4673,7 @@ uint8_t OpDispatchBuilder::GetSrcSize(FEXCore::X86Tables::DecodedOp Op) {
uint32_t SrcSizeFlag = FEXCore::X86Tables::DecodeFlags::GetSizeSrcFlags(Op->Flags);
uint8_t Size = Sizes[SrcSizeFlag];
LogMan::Throw::A(Size != 0, "Invalid destination size for op");
LOGMAN_THROW_A(Size != 0, "Invalid destination size for op");
return Size;
}
@@ -4649,7 +4730,7 @@ OrderedNode *OpDispatchBuilder::AppendSegmentOffset(OrderedNode *Value, uint32_t
}
OrderedNode *OpDispatchBuilder::LoadSource_WithOpSize(FEXCore::IR::RegisterClassType Class, FEXCore::X86Tables::DecodedOp const& Op, FEXCore::X86Tables::DecodedOperand const& Operand, uint8_t OpSize, uint32_t Flags, int8_t Align, bool LoadData, bool ForceLoad) {
LogMan::Throw::A(Operand.TypeNone.Type == FEXCore::X86Tables::DecodedOperand::TYPE_GPR ||
LOGMAN_THROW_A(Operand.TypeNone.Type == FEXCore::X86Tables::DecodedOperand::TYPE_GPR ||
Operand.TypeNone.Type == FEXCore::X86Tables::DecodedOperand::TYPE_LITERAL ||
Operand.TypeNone.Type == FEXCore::X86Tables::DecodedOperand::TYPE_GPR_DIRECT ||
Operand.TypeNone.Type == FEXCore::X86Tables::DecodedOperand::TYPE_GPR_INDIRECT ||
@@ -4759,7 +4840,7 @@ OrderedNode *OpDispatchBuilder::LoadSource_WithOpSize(FEXCore::IR::RegisterClass
LoadableType = true;
}
else {
LogMan::Msg::A("Unknown Src Type: %d\n", Operand.TypeNone.Type);
LOGMAN_MSG_A("Unknown Src Type: %d\n", Operand.TypeNone.Type);
}
if ((LoadableType && LoadData) || ForceLoad) {
@@ -4777,7 +4858,7 @@ OrderedNode *OpDispatchBuilder::LoadSource_WithOpSize(FEXCore::IR::RegisterClass
OrderedNode *OpDispatchBuilder::GetDynamicPC(FEXCore::X86Tables::DecodedOp const& Op, int64_t Offset) {
uint8_t GPRSize = CTX->Config.Is64BitMode ? 8 : 4;
return _EntrypointOffset(Op->PC + Op->InstSize + Offset - Current_Header->Entry, GPRSize);
return _EntrypointOffset(Op->PC + Op->InstSize + Offset - Entry, GPRSize);
}
OrderedNode *OpDispatchBuilder::LoadSource(FEXCore::IR::RegisterClassType Class, FEXCore::X86Tables::DecodedOp const& Op, FEXCore::X86Tables::DecodedOperand const& Operand, uint32_t Flags, int8_t Align, bool LoadData, bool ForceLoad) {
@@ -4786,7 +4867,7 @@ OrderedNode *OpDispatchBuilder::LoadSource(FEXCore::IR::RegisterClassType Class,
}
void OpDispatchBuilder::StoreResult_WithOpSize(FEXCore::IR::RegisterClassType Class, FEXCore::X86Tables::DecodedOp Op, FEXCore::X86Tables::DecodedOperand const& Operand, OrderedNode *const Src, uint8_t OpSize, int8_t Align) {
LogMan::Throw::A((Operand.TypeNone.Type == FEXCore::X86Tables::DecodedOperand::TYPE_GPR ||
LOGMAN_THROW_A((Operand.TypeNone.Type == FEXCore::X86Tables::DecodedOperand::TYPE_GPR ||
Operand.TypeNone.Type == FEXCore::X86Tables::DecodedOperand::TYPE_LITERAL ||
Operand.TypeNone.Type == FEXCore::X86Tables::DecodedOperand::TYPE_GPR_DIRECT ||
Operand.TypeNone.Type == FEXCore::X86Tables::DecodedOperand::TYPE_GPR_INDIRECT ||
@@ -4819,11 +4900,11 @@ void OpDispatchBuilder::StoreResult_WithOpSize(FEXCore::IR::RegisterClassType Cl
// For all other sizes, the upper bits are guaranteed to already be zero
OrderedNode *Value = GetOpSize(Src) == 8 ? _Bfe(4, 32, 0, Src) : Src;
LogMan::Throw::A(!Operand.TypeGPR.HighBits, "Can't handle 32bit store to high 8bit register");
LOGMAN_THROW_A(!Operand.TypeGPR.HighBits, "Can't handle 32bit store to high 8bit register");
_StoreContext(Class, GPRSize, offsetof(FEXCore::Core::CPUState, gregs[Operand.TypeGPR.GPR]), Value);
}
else {
LogMan::Throw::A(!(GPRSize == 4 && OpSize > 4), "Oops had a %d GPR load", OpSize);
LOGMAN_THROW_A(!(GPRSize == 4 && OpSize > 4), "Oops had a %d GPR load", OpSize);
_StoreContext(Class, std::min(GPRSize, OpSize), offsetof(FEXCore::Core::CPUState, gregs[Operand.TypeGPR.GPR]) + (Operand.TypeGPR.HighBits ? 1 : 0), Src);
}
}
@@ -5067,7 +5148,7 @@ void OpDispatchBuilder::GenerateFlags_ADC(FEXCore::X86Tables::DecodedOp Op, Orde
case 64:
AndOp1 = _Bfe(1, 63, AndOp1);
break;
default: LogMan::Msg::A("Unknown BFESize: %d", Size); break;
default: LOGMAN_MSG_A("Unknown BFESize: %d", Size); break;
}
SetRFLAG<FEXCore::X86State::RFLAG_OF_LOC>(AndOp1);
}
@@ -5135,7 +5216,7 @@ void OpDispatchBuilder::GenerateFlags_SBB(FEXCore::X86Tables::DecodedOp Op, Orde
case 8:
AndOp1 = _Bfe(1, 63, AndOp1);
break;
default: LogMan::Msg::A("Unknown BFESize: %d", GetSrcSize(Op)); break;
default: LOGMAN_MSG_A("Unknown BFESize: %d", GetSrcSize(Op)); break;
}
SetRFLAG<FEXCore::X86State::RFLAG_OF_LOC>(AndOp1);
}
@@ -5258,7 +5339,7 @@ void OpDispatchBuilder::GenerateFlags_ADD(FEXCore::X86Tables::DecodedOp Op, Orde
case 8:
AndOp1 = _Bfe(1, 63, AndOp1);
break;
default: LogMan::Msg::A("Unknown BFESize: %d", GetSrcSize(Op)); break;
default: LOGMAN_MSG_A("Unknown BFESize: %d", GetSrcSize(Op)); break;
}
SetRFLAG<FEXCore::X86State::RFLAG_OF_LOC>(AndOp1);
}
@@ -5815,7 +5896,7 @@ void OpDispatchBuilder::ALUOp(OpcodeArgs) {
break;
default:
IROp = FEXCore::IR::IROps::OP_LAST;
LogMan::Msg::A("Unknown ALU Op: 0x%x", Op->OP);
LOGMAN_MSG_A("Unknown ALU Op: 0x%x", Op->OP);
break;
}
@@ -5857,7 +5938,7 @@ void OpDispatchBuilder::ALUOp(OpcodeArgs) {
Result = _Xor(Dest, Src);
break;
}
default: LogMan::Msg::A("Unknown Atomic IR Op: %d", IROp); break;
default: LOGMAN_MSG_A("Unknown Atomic IR Op: %d", IROp); break;
}
}
else {
@@ -5971,6 +6052,9 @@ void OpDispatchBuilder::PSRLDOp(OpcodeArgs) {
OrderedNode *Result{};
if (Scalar) {
// Incoming element size for the shift source is always 8
auto MaxShift = _VectorImm(ElementSize * 8, 8, 8);
Src = _VUMin(8, 8, MaxShift, Src);
Result = _VUShrS(Size, ElementSize, Dest, Src);
}
else {
@@ -5984,7 +6068,7 @@ template<size_t ElementSize>
void OpDispatchBuilder::PSRLI(OpcodeArgs) {
OrderedNode *Dest = LoadSource(FPRClass, Op, Op->Dest, Op->Flags, -1);
LogMan::Throw::A(Op->Src[1].TypeNone.Type == FEXCore::X86Tables::DecodedOperand::TYPE_LITERAL, "Src1 needs to be literal here");
LOGMAN_THROW_A(Op->Src[1].TypeNone.Type == FEXCore::X86Tables::DecodedOperand::TYPE_LITERAL, "Src1 needs to be literal here");
uint64_t ShiftConstant = Op->Src[1].TypeLiteral.Literal;
auto Size = GetSrcSize(Op);
@@ -5997,7 +6081,7 @@ template<size_t ElementSize>
void OpDispatchBuilder::PSLLI(OpcodeArgs) {
OrderedNode *Dest = LoadSource(FPRClass, Op, Op->Dest, Op->Flags, -1);
LogMan::Throw::A(Op->Src[1].TypeNone.Type == FEXCore::X86Tables::DecodedOperand::TYPE_LITERAL, "Src1 needs to be literal here");
LOGMAN_THROW_A(Op->Src[1].TypeNone.Type == FEXCore::X86Tables::DecodedOperand::TYPE_LITERAL, "Src1 needs to be literal here");
uint64_t ShiftConstant = Op->Src[1].TypeLiteral.Literal;
auto Size = GetSrcSize(Op);
@@ -6016,6 +6100,9 @@ void OpDispatchBuilder::PSLL(OpcodeArgs) {
OrderedNode *Result{};
if (Scalar) {
// Incoming element size for the shift source is always 8
auto MaxShift = _VectorImm(ElementSize * 8, 8, 8);
Src = _VUMin(8, 8, MaxShift, Src);
Result = _VUShlS(Size, ElementSize, Dest, Src);
}
else {
@@ -6035,6 +6122,9 @@ void OpDispatchBuilder::PSRAOp(OpcodeArgs) {
OrderedNode *Result{};
if (Scalar) {
// Incoming element size for the shift source is always 8
auto MaxShift = _VectorImm(ElementSize * 8, 8, 8);
Src = _VUMin(8, 8, MaxShift, Src);
Result = _VSShrS(Size, ElementSize, Dest, Src);
}
else {
@@ -6045,7 +6135,7 @@ void OpDispatchBuilder::PSRAOp(OpcodeArgs) {
}
void OpDispatchBuilder::PSRLDQ(OpcodeArgs) {
LogMan::Throw::A(Op->Src[1].TypeNone.Type == FEXCore::X86Tables::DecodedOperand::TYPE_LITERAL, "Src1 needs to be literal here");
LOGMAN_THROW_A(Op->Src[1].TypeNone.Type == FEXCore::X86Tables::DecodedOperand::TYPE_LITERAL, "Src1 needs to be literal here");
uint64_t Shift = Op->Src[1].TypeLiteral.Literal;
OrderedNode *Dest = LoadSource(FPRClass, Op, Op->Dest, Op->Flags, -1);
@@ -6057,7 +6147,7 @@ void OpDispatchBuilder::PSRLDQ(OpcodeArgs) {
}
void OpDispatchBuilder::PSLLDQ(OpcodeArgs) {
LogMan::Throw::A(Op->Src[1].TypeNone.Type == FEXCore::X86Tables::DecodedOperand::TYPE_LITERAL, "Src1 needs to be literal here");
LOGMAN_THROW_A(Op->Src[1].TypeNone.Type == FEXCore::X86Tables::DecodedOperand::TYPE_LITERAL, "Src1 needs to be literal here");
uint64_t Shift = Op->Src[1].TypeLiteral.Literal;
OrderedNode *Dest = LoadSource(FPRClass, Op, Op->Dest, Op->Flags, -1);
@@ -6070,7 +6160,7 @@ void OpDispatchBuilder::PSLLDQ(OpcodeArgs) {
template<size_t ElementSize>
void OpDispatchBuilder::PSRAIOp(OpcodeArgs) {
LogMan::Throw::A(Op->Src[1].TypeNone.Type == FEXCore::X86Tables::DecodedOperand::TYPE_LITERAL, "Src1 needs to be literal here");
LOGMAN_THROW_A(Op->Src[1].TypeNone.Type == FEXCore::X86Tables::DecodedOperand::TYPE_LITERAL, "Src1 needs to be literal here");
uint64_t Shift = Op->Src[1].TypeLiteral.Literal;
OrderedNode *Dest = LoadSource(FPRClass, Op, Op->Dest, Op->Flags, -1);
@@ -6412,7 +6502,7 @@ void OpDispatchBuilder::VFCMPOp(OpcodeArgs) {
case 0x07: case 0x0F: case 0x17: case 0x1F: // Ordered
Result = _VFCMPORD(Size, ElementSize, Src2, Src);
break;
default: LogMan::Msg::A("Unknown Comparison type: %d", CompType);
default: LOGMAN_MSG_A("Unknown Comparison type: %d", CompType);
}
if (Scalar) {
@@ -7500,7 +7590,7 @@ void OpDispatchBuilder::X87FCMOV(OpcodeArgs) {
Type = COMPARE_ZERO;
break;
default:
LogMan::Msg::A("Unhandled FCMOV op: 0x%x", Opcode);
LOGMAN_MSG_A("Unhandled FCMOV op: 0x%x", Opcode);
break;
}
@@ -8229,6 +8319,19 @@ void OpDispatchBuilder::FenceOp(OpcodeArgs) {
_Fence({FenceType});
}
void OpDispatchBuilder::StoreFenceOrCLFlush(OpcodeArgs) {
if (Op->ModRM == 0xF8) {
// 0xF8 is SFENCE
_Fence({FEXCore::IR::Fence_Store});
}
else {
// This is a CLFlush
OrderedNode *DestMem = LoadSource(GPRClass, Op, Op->Dest, Op->Flags, -1, false);
DestMem = AppendSegmentOffset(DestMem, Op->Flags);
_CacheLineClear(DestMem);
}
}
void OpDispatchBuilder::PSADBW(OpcodeArgs) {
// The documentation is actually incorrect in how this instruction operates
// It strongly implies that the `abs(dest[i] - src[i])` operates in 8bit space
@@ -8311,7 +8414,7 @@ void OpDispatchBuilder::AESDecLastOp(OpcodeArgs) {
void OpDispatchBuilder::AESKeyGenAssist(OpcodeArgs) {
OrderedNode *Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags, -1);
LogMan::Throw::A(Op->Src[1].TypeNone.Type == FEXCore::X86Tables::DecodedOperand::TYPE_LITERAL, "Src1 needs to be literal here");
LOGMAN_THROW_A(Op->Src[1].TypeNone.Type == FEXCore::X86Tables::DecodedOperand::TYPE_LITERAL, "Src1 needs to be literal here");
uint64_t RCON = Op->Src[1].TypeLiteral.Literal;
auto Res = _VAESKeyGenAssist(Src, RCON);
@@ -8928,7 +9031,7 @@ constexpr uint16_t PF_F2 = 3;
{OPD(FEXCore::X86Tables::TYPE_GROUP_15, PF_NONE, 3), 1, &OpDispatchBuilder::STMXCSR},
{OPD(FEXCore::X86Tables::TYPE_GROUP_15, PF_NONE, 5), 1, &OpDispatchBuilder::FenceOp<FEXCore::IR::Fence_Load.Val>}, //LFENCE
{OPD(FEXCore::X86Tables::TYPE_GROUP_15, PF_NONE, 6), 1, &OpDispatchBuilder::FenceOp<FEXCore::IR::Fence_LoadStore.Val>}, //MFENCE
{OPD(FEXCore::X86Tables::TYPE_GROUP_15, PF_NONE, 7), 1, &OpDispatchBuilder::FenceOp<FEXCore::IR::Fence_Store.Val>}, //SFENCE
{OPD(FEXCore::X86Tables::TYPE_GROUP_15, PF_NONE, 7), 1, &OpDispatchBuilder::StoreFenceOrCLFlush}, //SFENCE
{OPD(FEXCore::X86Tables::TYPE_GROUP_15, PF_F3, 0), 1, &OpDispatchBuilder::ReadSegmentReg<OpDispatchBuilder::Segment_FS>},
{OPD(FEXCore::X86Tables::TYPE_GROUP_15, PF_F3, 1), 1, &OpDispatchBuilder::ReadSegmentReg<OpDispatchBuilder::Segment_GS>},
@@ -9304,7 +9407,7 @@ constexpr uint16_t PF_F2 = 3;
auto OpNum = std::get<0>(Op);
auto Dispatcher = std::get<2>(Op);
for (uint8_t i = 0; i < std::get<1>(Op); ++i) {
LogMan::Throw::A(FinalTable[OpNum + i].OpcodeDispatcher == nullptr, "Duplicate Entry");
LOGMAN_THROW_A(FinalTable[OpNum + i].OpcodeDispatcher == nullptr, "Duplicate Entry");
FinalTable[OpNum + i].OpcodeDispatcher = Dispatcher;
if (Dispatcher)
++NumInsts;
@@ -9318,7 +9421,7 @@ constexpr uint16_t PF_F2 = 3;
OpNum = OpNum & 0x7FF;
auto Dispatcher = std::get<2>(Op);
for (uint8_t i = 0; i < std::get<1>(Op); ++i) {
LogMan::Throw::A(FinalTable[OpNum + i].OpcodeDispatcher == nullptr, "Duplicate Entry");
LOGMAN_THROW_A(FinalTable[OpNum + i].OpcodeDispatcher == nullptr, "Duplicate Entry");
FinalTable[OpNum + i].OpcodeDispatcher = Dispatcher;
// Flag to indicate if we need to repeat this op in {0x40, 0x80} ranges
+8 -5
View File
@@ -49,7 +49,7 @@ public:
OrderedNode* GetNewJumpBlock(uint64_t RIP) {
auto it = JumpTargets.find(RIP);
LogMan::Throw::A(it != JumpTargets.end(), "Couldn't find block generated for 0x%lx", RIP);
LOGMAN_THROW_A(it != JumpTargets.end(), "Couldn't find block generated for 0x%lx", RIP);
return it->second.BlockEntry;
}
@@ -59,7 +59,7 @@ public:
it->second.HaveEmitted = true;
if (CurrentCodeBlock->Wrapped(ListData.Begin()).ID() == it->second.BlockEntry->Wrapped(ListData.Begin()).ID()) return;
if (CurrentCodeBlock->Wrapped(DualListData.ListBegin()).ID() == it->second.BlockEntry->Wrapped(DualListData.ListBegin()).ID()) return;
// We have hit a RIP that is a jump target
// Thus we need to end up in a new block
@@ -81,14 +81,14 @@ public:
// rdi, 0x8
// cmp qword [rdi-8], 0
// jne .label
if (!BlockSetRIP) {
if (LastOp && !BlockSetRIP) {
auto it = JumpTargets.find(NextRIP);
if (it == JumpTargets.end() && LastOp) {
if (it == JumpTargets.end()) {
uint8_t GPRSize = CTX->Config.Is64BitMode ? 8 : 4;
// If we don't have a jump target to a new block then we have to leave
// Set the RIP to the next instruction and leave
auto RelocatedNextRIP = _EntrypointOffset(NextRIP - Current_Header->Entry, GPRSize);
auto RelocatedNextRIP = _EntrypointOffset(NextRIP - Entry, GPRSize);
_ExitFunction(RelocatedNextRIP);
}
else if (it != JumpTargets.end()) {
@@ -104,6 +104,7 @@ public:
OpDispatchBuilder(FEXCore::Context::Context *ctx);
void ResetWorkingList();
void ResetDecodeFailure() { DecodeFailure = false; }
bool HadDecodeFailure() { return DecodeFailure; }
void BeginFunction(uint64_t RIP, std::vector<FEXCore::Frontend::Decoder::DecodedBlocks> const *Blocks);
@@ -458,6 +459,8 @@ public:
template<uint8_t FenceType>
void FenceOp(OpcodeArgs);
void StoreFenceOrCLFlush(OpcodeArgs);
void PSADBW(OpcodeArgs);
void AESImcOp(OpcodeArgs);
+5 -4
View File
@@ -6,6 +6,7 @@ $end_info$
*/
#include "Interface/Core/X86HelperGen.h"
#include <FEXCore/Utils/Allocator.h>
#include <cstring>
#include <stdlib.h>
@@ -31,7 +32,7 @@ X86GeneratedCode::X86GeneratedCode() {
}
X86GeneratedCode::~X86GeneratedCode() {
munmap(CodePtr, CODE_SIZE);
FEXCore::Allocator::munmap(CodePtr, CODE_SIZE);
}
void* X86GeneratedCode::AllocateGuestCodeSpace(size_t Size) {
@@ -39,7 +40,7 @@ void* X86GeneratedCode::AllocateGuestCodeSpace(size_t Size) {
if (Is64BitMode()) {
// 64bit mode can have its sigret handler anywhere
return mmap(nullptr, Size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
return FEXCore::Allocator::mmap(nullptr, Size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
}
// First 64bit page
@@ -49,14 +50,14 @@ void* X86GeneratedCode::AllocateGuestCodeSpace(size_t Size) {
// We need to have the sigret handler in the lower 32bits of memory space
// Scan top down and try to allocate a location
for (size_t Location = 0xFFFF'E000; Location != 0x0; Location -= 0x1000) {
void *Ptr = mmap(reinterpret_cast<void*>(Location), Size, PROT_READ | PROT_WRITE, MAP_FIXED_NOREPLACE | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
void *Ptr = FEXCore::Allocator::mmap(reinterpret_cast<void*>(Location), Size, PROT_READ | PROT_WRITE, MAP_FIXED_NOREPLACE | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (Ptr != MAP_FAILED &&
reinterpret_cast<uintptr_t>(Ptr) >= LOCATION_MAX) {
// Failed to map in the lower 32bits
// Try again
// Can happen in the case that host kernel ignores MAP_FIXED_NOREPLACE
munmap(Ptr, Size);
FEXCore::Allocator::munmap(Ptr, Size);
continue;
}
@@ -33,7 +33,7 @@ static inline void GenerateTable(X86InstInfo *FinalTable, U8U8InfoStruct const *
auto OpNum = Op.first;
X86InstInfo const &Info = Op.Info;
for (uint32_t i = 0; i < Op.second; ++i) {
LogMan::Throw::A(FinalTable[OpNum + i].Type == TYPE_UNKNOWN, "Duplicate Entry %s->%s", FinalTable[OpNum + i].Name, Info.Name);
LOGMAN_THROW_A(FinalTable[OpNum + i].Type == TYPE_UNKNOWN, "Duplicate Entry %s->%s", FinalTable[OpNum + i].Name, Info.Name);
FinalTable[OpNum + i] = Info;
#ifndef NDEBUG
++Total;
@@ -50,7 +50,7 @@ static inline void GenerateTable(X86InstInfo *FinalTable, U16U8InfoStruct const
auto OpNum = Op.first;
X86InstInfo const &Info = Op.Info;
for (uint32_t i = 0; i < Op.second; ++i) {
LogMan::Throw::A(FinalTable[OpNum + i].Type == TYPE_UNKNOWN, "Duplicate Entry %s->%s", FinalTable[OpNum + i].Name, Info.Name);
LOGMAN_THROW_A(FinalTable[OpNum + i].Type == TYPE_UNKNOWN, "Duplicate Entry %s->%s", FinalTable[OpNum + i].Name, Info.Name);
FinalTable[OpNum + i] = Info;
#ifndef NDEBUG
++Total;
@@ -67,7 +67,7 @@ static inline void GenerateTableWithCopy(X86InstInfo *FinalTable, U8U8InfoStruct
auto OpNum = Op.first;
X86InstInfo const &Info = Op.Info;
for (uint32_t i = 0; i < Op.second; ++i) {
LogMan::Throw::A(FinalTable[OpNum + i].Type == TYPE_UNKNOWN, "Duplicate Entry %s->%s", FinalTable[OpNum + i].Name, Info.Name);
LOGMAN_THROW_A(FinalTable[OpNum + i].Type == TYPE_UNKNOWN, "Duplicate Entry %s->%s", FinalTable[OpNum + i].Name, Info.Name);
if (Info.Type == TYPE_COPY_OTHER) {
FinalTable[OpNum + i] = OtherLocal[OpNum + i];
}
@@ -89,7 +89,7 @@ static inline void GenerateX87Table(X86InstInfo *FinalTable, U16U8InfoStruct con
auto OpNum = Op.first;
X86InstInfo const &Info = Op.Info;
for (uint32_t i = 0; i < Op.second; ++i) {
LogMan::Throw::A(FinalTable[OpNum + i].Type == TYPE_UNKNOWN, "Duplicate Entry %s->%s", FinalTable[OpNum + i].Name, Info.Name);
LOGMAN_THROW_A(FinalTable[OpNum + i].Type == TYPE_UNKNOWN, "Duplicate Entry %s->%s", FinalTable[OpNum + i].Name, Info.Name);
if ((OpNum & 0b11'000'000) == 0b11'000'000) {
// If the mod field is 0b11 then it is a regular op
FinalTable[OpNum + i] = Info;
@@ -97,7 +97,7 @@ static inline void GenerateX87Table(X86InstInfo *FinalTable, U16U8InfoStruct con
else {
// If the mod field is !0b11 then this instruction is duplicated through the whole mod [0b00, 0b10] range
// and the modrm.rm space because that is used part of the instruction encoding
LogMan::Throw::A((OpNum & 0b11'000'000) == 0, "Only support mod field of zero in this path");
LOGMAN_THROW_A((OpNum & 0b11'000'000) == 0, "Only support mod field of zero in this path");
for (uint16_t mod = 0b00'000'000; mod < 0b11'000'000; mod += 0b01'000'000) {
for (uint16_t rm = 0b000; rm < 0b1'000; ++rm) {
FinalTable[(OpNum | mod | rm) + i] = Info;
+11 -2
View File
@@ -79,7 +79,6 @@
"Blocks"
],
"Args": [
"uint64_t", "Entry",
"uint32_t", "BlockCount"
]
},
@@ -793,6 +792,17 @@
]
},
"CacheLineClear": {
"Desc": ["Does a 64 byte cacheline clear at the address specified"
],
"HasSideEffects": true,
"OpClass": "Memory",
"SSAArgs": "1",
"SSANames": [
"Addr"
]
},
"Add": {
"Desc": [ "Integer Add",
"Will truncate to 64 or 32bits"
@@ -1563,7 +1573,6 @@
"Depending on backend, may only support GPR printing"
],
"OpClass": "Misc",
"DestSize": "GetOpSize(ssa0)",
"SSAArgs": "1",
"SSANames": [
"Value"
-1
View File
@@ -167,7 +167,6 @@ void Dump(std::stringstream *out, IRListView const* IR, IR::RegisterAllocationDa
++CurrentIndent;
AddIndent();
*out << "(%ssa0) " << "IRHeader ";
*out << "#0x" << std::hex << HeaderOp->Entry << ", ";
*out << "%ssa" << HeaderOp->Blocks.ID() << ", ";
*out << "#" << std::dec << HeaderOp->BlockCount << std::endl;
+16 -17
View File
@@ -9,18 +9,17 @@ $end_info$
namespace FEXCore::IR {
void IREmitter::ResetWorkingList() {
Data.Reset();
ListData.Reset();
DualListData.Reset();
CodeBlocks.clear();
CurrentWriteCursor = nullptr;
// This is necessary since we do "null" pointer checks
InvalidNode = reinterpret_cast<OrderedNode*>(ListData.Allocate(sizeof(OrderedNode)));
InvalidNode = reinterpret_cast<OrderedNode*>(DualListData.ListAllocate(sizeof(OrderedNode)));
memset(InvalidNode, 0, sizeof(OrderedNode));
CurrentCodeBlock = nullptr;
}
void IREmitter::ReplaceAllUsesWithRange(OrderedNode *Node, OrderedNode *NewNode, AllNodesIterator After, AllNodesIterator End) {
uintptr_t ListBegin = ListData.Begin();
uintptr_t ListBegin = DualListData.ListBegin();
auto NodeId = Node->Wrapped(ListBegin).ID();
while (After != End) {
@@ -45,8 +44,8 @@ void IREmitter::ReplaceAllUsesWithRange(OrderedNode *Node, OrderedNode *NewNode,
}
void IREmitter::ReplaceNodeArgument(OrderedNode *Node, uint8_t Arg, OrderedNode *NewArg) {
uintptr_t ListBegin = ListData.Begin();
uintptr_t DataBegin = Data.Begin();
uintptr_t ListBegin = DualListData.ListBegin();
uintptr_t DataBegin = DualListData.DataBegin();
FEXCore::IR::IROp_Header *IROp = Node->Op(DataBegin);
OrderedNodeWrapper OldArgWrapper = IROp->Args[Arg];
@@ -57,8 +56,8 @@ void IREmitter::ReplaceNodeArgument(OrderedNode *Node, uint8_t Arg, OrderedNode
}
void IREmitter::RemoveArgUses(OrderedNode *Node) {
uintptr_t ListBegin = ListData.Begin();
uintptr_t DataBegin = Data.Begin();
uintptr_t ListBegin = DualListData.ListBegin();
uintptr_t DataBegin = DualListData.DataBegin();
FEXCore::IR::IROp_Header *IROp = Node->Op(DataBegin);
@@ -72,7 +71,7 @@ void IREmitter::RemoveArgUses(OrderedNode *Node) {
void IREmitter::Remove(OrderedNode *Node) {
RemoveArgUses(Node);
Node->Unlink(ListData.Begin());
Node->Unlink(DualListData.ListBegin());
}
IREmitter::IRPair<IROp_CodeBlock> IREmitter::CreateNewCodeBlockAfter(OrderedNode* insertAfter) {
@@ -83,14 +82,14 @@ IREmitter::IRPair<IROp_CodeBlock> IREmitter::CreateNewCodeBlockAfter(OrderedNode
if (insertAfter) {
LinkCodeBlocks(insertAfter, CodeNode);
} else {
LogMan::Throw::A(CurrentCodeBlock != nullptr, "CurrentCodeBlock must not be null here");
LOGMAN_THROW_A(CurrentCodeBlock != nullptr, "CurrentCodeBlock must not be null here");
// Find last block
auto LastBlock = CurrentCodeBlock;
while (LastBlock->Header.Next.GetNode(ListData.Begin()) != InvalidNode)
LastBlock = LastBlock->Header.Next.GetNode(ListData.Begin());
while (LastBlock->Header.Next.GetNode(DualListData.ListBegin()) != InvalidNode)
LastBlock = LastBlock->Header.Next.GetNode(DualListData.ListBegin());
// Append it after the last block
LinkCodeBlocks(LastBlock, CodeNode);
}
@@ -102,12 +101,12 @@ IREmitter::IRPair<IROp_CodeBlock> IREmitter::CreateNewCodeBlockAfter(OrderedNode
void IREmitter::SetCurrentCodeBlock(OrderedNode *Node) {
CurrentCodeBlock = Node;
LogMan::Throw::A(Node->Op(Data.Begin())->Op == OP_CODEBLOCK, "Node wasn't codeblock. It was '%s'", std::string(IR::GetName(Node->Op(Data.Begin())->Op)).c_str());
SetWriteCursor(Node->Op(Data.Begin())->CW<IROp_CodeBlock>()->Begin.GetNode(ListData.Begin()));
LOGMAN_THROW_A(Node->Op(DualListData.DataBegin())->Op == OP_CODEBLOCK, "Node wasn't codeblock. It was '%s'", std::string(IR::GetName(Node->Op(DualListData.DataBegin())->Op)).c_str());
SetWriteCursor(Node->Op(DualListData.DataBegin())->CW<IROp_CodeBlock>()->Begin.GetNode(DualListData.ListBegin()));
}
void IREmitter::ReplaceWithConstant(OrderedNode *Node, uint64_t Value) {
auto Header = Node->Op(Data.Begin());
auto Header = Node->Op(DualListData.DataBegin());
if (IRSizes[Header->Op] >= sizeof(IROp_Constant)) {
// Unlink any arguments the node currently has
+7 -9
View File
@@ -497,13 +497,11 @@ class IRParser: public FEXCore::IR::IREmitter {
return false;
}
auto Entry = DecodeValue<uint64_t>(Def.Args[0]);
auto CodeBlockCount = DecodeValue<uint64_t>(Def.Args[2]);
auto CodeBlockCount = DecodeValue<uint64_t>(Def.Args[1]);
if (!CheckPrintError(Def, Entry.first)) return false;
if (!CheckPrintError(Def, CodeBlockCount.first)) return false;
IRHeader = _IRHeader(InvalidNode, Entry.second, CodeBlockCount.second);
IRHeader = _IRHeader(InvalidNode, CodeBlockCount.second);
}
SetWriteCursor(nullptr); // isolate the header from everything following
@@ -522,7 +520,7 @@ class IRParser: public FEXCore::IR::IREmitter {
if (i == 1) {
// First code block is the entry block
// Link the header to the first block
IRHeader.first->Blocks = CodeBlock.Node->Wrapped(ListData.Begin());
IRHeader.first->Blocks = CodeBlock.Node->Wrapped(DualListData.ListBegin());
}
CodeBlocks.emplace_back(CodeBlock.Node);
}
@@ -555,7 +553,7 @@ class IRParser: public FEXCore::IR::IREmitter {
}
CurrentBlock = Def.Node;
CurrentBlockOp = CurrentBlock->Op(Data.Begin())->CW<FEXCore::IR::IROp_CodeBlock>();
CurrentBlockOp = CurrentBlock->Op(DualListData.DataBegin())->CW<FEXCore::IR::IROp_CodeBlock>();
break;
}
@@ -573,7 +571,7 @@ class IRParser: public FEXCore::IR::IREmitter {
if (!CheckPrintError(Def, Adjust.first)) return false;
Def.Node = _BeginBlock(Adjust.second);
CurrentBlockOp->Begin = Def.Node->Wrapped(ListData.Begin());
CurrentBlockOp->Begin = Def.Node->Wrapped(DualListData.ListBegin());
break;
}
@@ -590,7 +588,7 @@ class IRParser: public FEXCore::IR::IREmitter {
if (!CheckPrintError(Def, Adjust.first)) return false;
Def.Node = _EndBlock(Adjust.second);
CurrentBlockOp->Last = Def.Node->Wrapped(ListData.Begin());
CurrentBlockOp->Last = Def.Node->Wrapped(DualListData.ListBegin());
CurrentBlock = nullptr;
CurrentBlockOp = nullptr;
@@ -617,7 +615,7 @@ class IRParser: public FEXCore::IR::IREmitter {
}
if (Def.HasDefinition) {
auto IROp = Def.Node->Op(Data.Begin());
auto IROp = Def.Node->Op(DualListData.DataBegin());
if (Def.Size.Elements()) {
IROp->Size = Def.Size.Bytes() * Def.Size.Elements();
IROp->ElementSize = Def.Size.Bytes();
+7
View File
@@ -19,6 +19,13 @@ void PassManager::AddDefaultPasses(bool InlineConstants, bool StaticRegisterAllo
if (!DisablePasses()) {
InsertPass(CreateContextLoadStoreElimination());
if (Is64BitMode()) {
// This needs to run after RCLSE
// This only matters for 64-bit code since these instructions don't exist in 32-bit
InsertPass(CreateLongDivideEliminationPass());
}
InsertPass(CreateDeadStoreElimination());
InsertPass(CreatePassDeadCodeElimination());
InsertPass(CreateConstProp(InlineConstants));
+3
View File
@@ -6,6 +6,7 @@ $end_info$
#pragma once
#include <FEXCore/Config/Config.h>
#include <FEXCore/IR/IntrusiveIRList.h>
#include <FEXCore/IR/IREmitter.h>
@@ -83,6 +84,8 @@ private:
ValidationPasses.emplace_back(Pass);
}
#endif
FEX_CONFIG_OPT(Is64BitMode, IS64BIT_MODE);
};
}
+1
View File
@@ -14,6 +14,7 @@ FEXCore::IR::Pass* CreatePassDeadCodeElimination();
FEXCore::IR::Pass* CreateIRCompaction();
FEXCore::IR::RegisterAllocationPass* CreateRegisterAllocationPass(FEXCore::IR::Pass* CompactionPass, bool OptimizeSRA);
FEXCore::IR::Pass* CreateStaticRegisterAllocationPass();
FEXCore::IR::Pass* CreateLongDivideEliminationPass();
namespace Validation {
FEXCore::IR::Pass* CreateIRValidation();
+3 -3
View File
@@ -260,7 +260,7 @@ bool ConstProp::Run(IREmitter *IREmit) {
auto ghf = IROp->CW<IR::IROp_GetHostFlag>();
auto fcmp = IREmit->GetOpHeader(ghf->GPR)->CW<IR::IROp_FCmp>();
LogMan::Throw::A(fcmp->Header.Op == OP_FCMP || fcmp->Header.Op == OP_F80CMP, "Unexpected OP_GETHOSTFLAG source");
LOGMAN_THROW_A(fcmp->Header.Op == OP_FCMP || fcmp->Header.Op == OP_F80CMP, "Unexpected OP_GETHOSTFLAG source");
if(fcmp->Header.Op == OP_FCMP) {
fcmp->Flags |= 1 << ghf->Flag;
}
@@ -463,7 +463,7 @@ bool ConstProp::Run(IREmitter *IREmit) {
if (IREmit->IsValueConstant(IROp->Args[0], &Constant1) &&
IREmit->IsValueConstant(IROp->Args[1], &Constant2)) {
LogMan::Msg::A("Could const prop op: %s", std::string(IR::GetName(IROp->Op)).c_str());
LOGMAN_MSG_A("Could const prop op: %s", std::string(IR::GetName(IROp->Op)).c_str());
}
break;
}
@@ -479,7 +479,7 @@ bool ConstProp::Run(IREmitter *IREmit) {
uint64_t Constant1;
if (IREmit->IsValueConstant(IROp->Args[0], &Constant1)) {
LogMan::Msg::A("Could const prop op: %s", std::string(IR::GetName(IROp->Op)).c_str());
LOGMAN_MSG_A("Could const prop op: %s", std::string(IR::GetName(IROp->Op)).c_str());
}
break;
}
@@ -211,18 +211,18 @@ namespace {
size_t ClassifiedStructSize{};
ContextClassificationInfo->Lookup.reserve(sizeof(FEXCore::Core::CPUState));
for (auto &it : *ContextClassification) {
LogMan::Throw::A(it.Class.Offset == ContextClassificationInfo->Lookup.size(), "Offset missmatch %d %d", it.Class.Offset == ContextClassificationInfo->Lookup.size());
LOGMAN_THROW_A(it.Class.Offset == ContextClassificationInfo->Lookup.size(), "Offset missmatch %d %d", it.Class.Offset == ContextClassificationInfo->Lookup.size());
for (int i = 0; i < it.Class.Size; i++) {
ContextClassificationInfo->Lookup.push_back(&it);
}
ClassifiedStructSize += it.Class.Size;
}
LogMan::Throw::A(ClassifiedStructSize == sizeof(FEXCore::Core::CPUState),
LOGMAN_THROW_A(ClassifiedStructSize == sizeof(FEXCore::Core::CPUState),
"Classified CPUStruct size doesn't match real CPUState struct size! %ld != %ld",
ClassifiedStructSize, sizeof(FEXCore::Core::CPUState));
LogMan::Throw::A(ContextClassificationInfo->Lookup.size() == sizeof(FEXCore::Core::CPUState),
LOGMAN_THROW_A(ContextClassificationInfo->Lookup.size() == sizeof(FEXCore::Core::CPUState),
"Classified CPUStruct size doesn't match real CPUState struct size! %ld != %ld",
ContextClassificationInfo->Lookup.size(), sizeof(FEXCore::Core::CPUState));
}
@@ -306,15 +306,15 @@ ContextMemberInfo *RCLSE::FindMemberInfo(ContextInfo *ContextClassificationInfo,
}
ContextMemberInfo *RCLSE::RecordAccess(ContextMemberInfo *Info, FEXCore::IR::RegisterClassType RegClass, uint32_t Offset, uint8_t Size, LastAccessType AccessType, FEXCore::IR::OrderedNode *Node, FEXCore::IR::OrderedNode *StoreNode) {
LogMan::Throw::A((Offset + Size) <= (Info->Class.Offset + Info->Class.Size), "Access to context item went over member size");
LogMan::Throw::A(Info->Accessed != ACCESS_INVALID, "Tried to access invalid member");
LOGMAN_THROW_A((Offset + Size) <= (Info->Class.Offset + Info->Class.Size), "Access to context item went over member size");
LOGMAN_THROW_A(Info->Accessed != ACCESS_INVALID, "Tried to access invalid member");
// If we aren't fully overwriting the member then it is a partial write that we need to track
if (Size < Info->Class.Size) {
AccessType = AccessType == ACCESS_WRITE ? ACCESS_PARTIAL_WRITE : ACCESS_PARTIAL_READ;
}
if (Size > Info->Class.Size) {
LogMan::Msg::A("Can't handle this");
LOGMAN_MSG_A("Can't handle this");
}
Info->Accessed = AccessType;
@@ -500,7 +500,7 @@ bool RCLSE::RedundantStoreLoadElimination(FEXCore::IR::IREmitter *IREmit) {
else if (LastClass == GPRClass) {
LastNode = IREmit->_Bfe(Info->AccessSize, TruncateSize * 8, 0, LastNode);
} else {
LogMan::Msg::A("Unhandled Register class");
LOGMAN_MSG_A("Unhandled Register class");
}
}
@@ -578,7 +578,7 @@ bool RCLSE::RedundantStoreLoadElimination(FEXCore::IR::IREmitter *IREmit) {
if (LastStoreNode != nullptr)
{
IREmit->SetWriteCursor(CodeNode);
RecordAccess(&LocalInfo, FEXCore::IR::GPRClass, offsetof(FEXCore::Core::CPUState, flags[0]) + F, 1, ACCESS_WRITE, IREmit->_InlineConstant(0), CodeNode);
RecordAccess(&LocalInfo, FEXCore::IR::GPRClass, offsetof(FEXCore::Core::CPUState, flags[0]) + F, 1, ACCESS_WRITE, IREmit->_Constant(0), CodeNode);
IREmit->Remove(LastStoreNode);
Changed = true;
@@ -106,7 +106,7 @@ uint64_t FPRBit(uint32_t Offset, uint32_t Size) {
else if (Size == 4)
return 1UL << (bitn);
else
LogMan::Msg::A("Unexpected FPR size %d", Size);
LOGMAN_MSG_A("Unexpected FPR size %d", Size);
return 7UL << (bitn); // Return maximum on failure case
}
@@ -66,7 +66,7 @@ bool IRCompaction::Run(IREmitter *IREmit) {
auto HeaderNode = CurrentIR.GetHeaderNode();
auto HeaderOp = CurrentIR.GetHeader();
LogMan::Throw::A(HeaderOp->Header.Op == OP_IRHEADER, "First op wasn't IRHeader");
LOGMAN_THROW_A(HeaderOp->Header.Op == OP_IRHEADER, "First op wasn't IRHeader");
// This compaction pass is something that we need to ensure correct ordering and distances between IROps
// Later on we assume that an IROp's SSA value live range is its Node locations
@@ -84,13 +84,13 @@ bool IRCompaction::Run(IREmitter *IREmit) {
// Zero is always zero(invalid)
OldToNewRemap[0].NodeID = 0;
auto LocalHeaderOp = LocalBuilder._IRHeader(OrderedNodeWrapper::WrapOffset(0).GetNode(ListBegin), HeaderOp->Entry, HeaderOp->BlockCount);
auto LocalHeaderOp = LocalBuilder._IRHeader(OrderedNodeWrapper::WrapOffset(0).GetNode(ListBegin), HeaderOp->BlockCount);
OldToNewRemap[CurrentIR.GetID(HeaderNode)].NodeID = LocalIR.GetID(LocalHeaderOp.Node);
{
// Generate our codeblocks and link them together
for (auto [BlockNode, BlockHeader] : CurrentIR.GetBlocks()) {
LogMan::Throw::A(BlockHeader->Op == OP_CODEBLOCK, "IR type failed to be a code block");
LOGMAN_THROW_A(BlockHeader->Op == OP_CODEBLOCK, "IR type failed to be a code block");
auto LocalBlockIRNode = LocalBuilder._CodeBlock(LocalHeaderOp, LocalHeaderOp); // Use LocalHeaderOp as a dummy arg for now
OldToNewRemap[CurrentIR.GetID(BlockNode)].NodeID = LocalIR.GetID(LocalBlockIRNode.Node);
@@ -154,7 +154,7 @@ bool IRCompaction::Run(IREmitter *IREmit) {
// Fixup the arguments of all the IROps
for (auto &Block : GeneratedCodeBlocks) {
auto BlockIROp = LocalIR.GetOp<FEXCore::IR::IROp_CodeBlock>(Block.NewNode);
LogMan::Throw::A(BlockIROp->Header.Op == OP_CODEBLOCK, "IR type failed to be a code block");
LOGMAN_THROW_A(BlockIROp->Header.Op == OP_CODEBLOCK, "IR type failed to be a code block");
for (auto [LocalNode, LocalIROp] : LocalIR.GetCode(Block.NewNode)) {
@@ -165,7 +165,7 @@ bool IRCompaction::Run(IREmitter *IREmit) {
for (uint8_t i = 0; i < NumArgs; ++i) {
uint32_t OldArg = LocalIROp->Args[i].ID();
#ifndef NDEBUG
LogMan::Throw::A(OldToNewRemap[OldArg].NodeID != ~0U, "Tried remapping unfound node %%ssa%d", OldArg);
LOGMAN_THROW_A(OldToNewRemap[OldArg].NodeID != ~0U, "Tried remapping unfound node %%ssa%d", OldArg);
#endif
LocalIROp->Args[i].NodeOffset = OldToNewRemap[OldArg].NodeID * sizeof(OrderedNode);
}
@@ -191,7 +191,7 @@ bool IRCompaction::Run(IREmitter *IREmit) {
// if (NewListSize > OldListSize ||
// NewDataSize > OldDataSize) {
// LogMan::Msg::A("Whoa. Compaction made the IR a different size when it shouldn't have. 0x%lx > 0x%lx or 0x%lx > 0x%lx",NewListSize, OldListSize, NewDataSize, OldDataSize);
// LOGMAN_MSG_A("Whoa. Compaction made the IR a different size when it shouldn't have. 0x%lx > 0x%lx or 0x%lx > 0x%lx",NewListSize, OldListSize, NewDataSize, OldDataSize);
// }
IREmit->CopyData(LocalBuilder);
@@ -55,7 +55,7 @@ bool IRValidation::Run(IREmitter *IREmit) {
std::vector<uint32_t> Uses(CurrentIR.GetSSACount(), 0);
auto HeaderOp = CurrentIR.GetHeader();
LogMan::Throw::A(HeaderOp->Header.Op == OP_IRHEADER, "First op wasn't IRHeader");
LOGMAN_THROW_A(HeaderOp->Header.Op == OP_IRHEADER, "First op wasn't IRHeader");
IR::RegisterAllocationData * RAData{};
if (Manager->HasRAPass()) {
@@ -66,7 +66,7 @@ bool IRValidation::Run(IREmitter *IREmit) {
for (auto [BlockNode, BlockHeader] : CurrentIR.GetBlocks()) {
auto BlockIROp = BlockHeader->CW<FEXCore::IR::IROp_CodeBlock>();
LogMan::Throw::A(BlockIROp->Header.Op == OP_CODEBLOCK, "IR type failed to be a code block");
LOGMAN_THROW_A(BlockIROp->Header.Op == OP_CODEBLOCK, "IR type failed to be a code block");
uint32_t BlockID = CurrentIR.GetID(BlockNode);
@@ -209,7 +209,7 @@ bool IRValidation::Run(IREmitter *IREmit) {
break;
}
default:
// LogMan::Msg::A("Unknown IR Op: %d(%s)", IROp->Op, FEXCore::IR::GetName(IROp->Op).data());
// LOGMAN_MSG_A("Unknown IR Op: %d(%s)", IROp->Op, FEXCore::IR::GetName(IROp->Op).data());
break;
}
}
@@ -0,0 +1,112 @@
/*
$info$
tags: ir|opts
desc: Long divide elimination pass
$end_info$
*/
#include "Interface/IR/PassManager.h"
#include <FEXCore/Utils/LogManager.h>
namespace FEXCore::IR {
class LongDivideEliminationPass final : public FEXCore::IR::Pass {
public:
bool Run(IREmitter *IREmit) override;
private:
bool IsZeroOp(IREmitter *IREmit, OrderedNodeWrapper Arg);
bool IsSextOp(IREmitter *IREmit, OrderedNodeWrapper Lower, OrderedNodeWrapper Upper);
};
bool LongDivideEliminationPass::IsZeroOp(IREmitter *IREmit, OrderedNodeWrapper Arg) {
auto IROp = IREmit->GetOpHeader(Arg);
uint64_t Value;
// XOR based zero
if (IROp->Op == OP_XOR) {
return IROp->Args[0] == IROp->Args[1];
}
else if (IREmit->IsValueConstant(Arg, &Value)) {
// Zero constant based zero op
return Value == 0;
}
return false;
}
bool LongDivideEliminationPass::IsSextOp(IREmitter *IREmit, OrderedNodeWrapper Lower, OrderedNodeWrapper Upper) {
// We need to check if the upper source is a sext of the lower source
auto UpperIROp = IREmit->GetOpHeader(Upper);
if (UpperIROp->Op == OP_SBFE) {
auto Op = UpperIROp->C<IR::IROp_Sbfe>();
if (Op->Width == 1 && Op->lsb == 63) {
// CQO: OrderedNode *Upper = _Sbfe(1, Size * 8 - 1, Src);
// If the lower is the upper in this case then it can be optimized
return Op->Header.Args[0] == Lower;
}
}
return false;
}
bool LongDivideEliminationPass::Run(IREmitter *IREmit) {
bool Changed = false;
auto CurrentIR = IREmit->ViewIR();
auto OriginalWriteCursor = IREmit->GetWriteCursor();
for (auto [BlockNode, BlockHeader] : CurrentIR.GetBlocks()) {
for (auto [CodeNode, IROp] : CurrentIR.GetCode(BlockNode)) {
if (IROp->Size == 8) {
if (IROp->Op == OP_LDIV ||
IROp->Op == OP_LREM) {
auto Op = IROp->C<IR::IROp_LDiv>();
// Check upper Op to see if it came from a CQO
// CQO: OrderedNode *Upper = _Sbfe(1, Size * 8 - 1, Src);
// If it does then it we only need a 64bit SDIV
if (IsSextOp(IREmit, Op->Lower, Op->Upper)) {
IREmit->SetWriteCursor(CodeNode);
OrderedNode *Lower = CurrentIR.GetNode(Op->Lower);
OrderedNode *Divisor = CurrentIR.GetNode(Op->Divisor);
OrderedNode *SDivOp{};
if (IROp->Op == OP_LDIV) {
SDivOp = IREmit->_Div(Lower, Divisor);
}
else {
SDivOp = IREmit->_Rem(Lower, Divisor);
}
IREmit->ReplaceAllUsesWith(CodeNode, SDivOp);
Changed = true;
}
}
else if (IROp->Op == OP_LUDIV ||
IROp->Op == OP_LUREM) {
auto Op = IROp->C<IR::IROp_LUDiv>();
// Check upper Op to see if it came from a xor zeroing op
// XOR: Result = _Xor(Dest, Src);
// If it does then it we only need a 64bit UDIV
if (IsZeroOp(IREmit, Op->Upper)) {
IREmit->SetWriteCursor(CodeNode);
OrderedNode *Lower = CurrentIR.GetNode(Op->Lower);
OrderedNode *Divisor = CurrentIR.GetNode(Op->Divisor);
OrderedNode *UDivOp{};
if (IROp->Op == OP_LUDIV) {
UDivOp = IREmit->_UDiv(Lower, Divisor);
}
else {
UDivOp = IREmit->_URem(Lower, Divisor);
}
IREmit->ReplaceAllUsesWith(CodeNode, UDivOp);
Changed = true;
}
}
}
}
}
IREmit->SetWriteCursor(OriginalWriteCursor);
return Changed;
}
FEXCore::IR::Pass* CreateLongDivideEliminationPass() {
return new LongDivideEliminationPass{};
}
}
@@ -8,6 +8,7 @@ $end_info$
#include "Interface/IR/Passes/RegisterAllocationPass.h"
#include "Interface/IR/Passes.h"
#include "Interface/Core/OpcodeDispatcher.h"
#include <FEXCore/Utils/Allocator.h>
#include <iterator>
#include <unordered_set>
@@ -65,7 +66,7 @@ namespace {
Enumerator(Item);
if (++i == Bucket->Size) {
LogMan::Throw::A(Bucket->Next != nullptr, "Interference bug");
LOGMAN_THROW_A(Bucket->Next != nullptr, "Interference bug");
Bucket = Bucket->Next.get();
i = 0;
}
@@ -86,7 +87,7 @@ namespace {
return true;
if (++i == Bucket->Size) {
LogMan::Throw::A(Bucket->Next != nullptr, "Bucket in bad state");
LOGMAN_THROW_A(Bucket->Next != nullptr, "Bucket in bad state");
Bucket = Bucket->Next.get();
i = 0;
}
@@ -130,7 +131,7 @@ namespace {
}
else if (++i == Size) {
i = 0;
LogMan::Throw::A(that->Next != nullptr, "Bucket::Erase but element not contained");
LOGMAN_THROW_A(that->Next != nullptr, "Bucket::Erase but element not contained");
that = that->Next.get();
}
}
@@ -262,7 +263,7 @@ namespace {
Graph->Nodes.resize(NodeCount);
Graph->VisitedNodePredecessors.clear();
Graph->AllocData.reset();
Graph->AllocData.reset((FEXCore::IR::RegisterAllocationData*)malloc(FEXCore::IR::RegisterAllocationData::Size(NodeCount)));
Graph->AllocData.reset((FEXCore::IR::RegisterAllocationData*)FEXCore::Allocator::malloc(FEXCore::IR::RegisterAllocationData::Size(NodeCount)));
memset(&Graph->AllocData->Map[0], INVALID_REGCLASS.Raw, NodeCount);
Graph->AllocData->MapCount = NodeCount;
Graph->AllocData->IsShared = false; // not shared by default
@@ -445,8 +446,8 @@ namespace FEXCore::IR {
}
void ConstrainedRAPass::AllocateRegisterSet(uint32_t RegisterCount, uint32_t ClassCount) {
LogMan::Throw::A(RegisterCount <= INVALID_REG, "Up to %d regs supported", INVALID_REG);
LogMan::Throw::A(ClassCount <= INVALID_CLASS, "Up to %d classes supported", INVALID_CLASS);
LOGMAN_THROW_A(RegisterCount <= INVALID_REG, "Up to %d regs supported", INVALID_REG);
LOGMAN_THROW_A(ClassCount <= INVALID_CLASS, "Up to %d classes supported", INVALID_CLASS);
Graph = AllocateRegisterGraph(ClassCount);
@@ -459,7 +460,7 @@ namespace FEXCore::IR {
}
void ConstrainedRAPass::AddRegisters(FEXCore::IR::RegisterClassType Class, uint32_t RegisterCount) {
LogMan::Throw::A(RegisterCount <= INVALID_REG, "Up to %d regs supported", INVALID_REG);
LOGMAN_THROW_A(RegisterCount <= INVALID_REG, "Up to %d regs supported", INVALID_REG);
AllocatePhysicalRegisters(Graph, Class, RegisterCount);
}
@@ -486,7 +487,7 @@ namespace FEXCore::IR {
auto Op = IROp->C<IROp_CodeBlock>();
LogMan::Throw::A(Op->Header.Op == OP_CODEBLOCK, "Block not defined by codeblock?");
LOGMAN_THROW_A(Op->Header.Op == OP_CODEBLOCK, "Block not defined by codeblock?");
LiveRange->Begin = std::min(LiveRange->Begin, Op->Begin.ID());
LiveRange->End = std::max(LiveRange->End, Op->Begin.ID());
@@ -514,7 +515,7 @@ namespace FEXCore::IR {
// If the destination hasn't yet been set then set it now
if (IROp->HasDest) {
LogMan::Throw::A(LiveRanges[Node].Begin == ~0U, "Node begin already defined?");
LOGMAN_THROW_A(LiveRanges[Node].Begin == ~0U, "Node begin already defined?");
LiveRanges[Node].Begin = Node;
// Default to ending right where after it starts
LiveRanges[Node].End = Node + 1;
@@ -546,7 +547,7 @@ namespace FEXCore::IR {
if (IR->GetOp<IROp_Header>(IROp->Args[i])->Op == OP_INLINEENTRYPOINTOFFSET) continue;
if (IR->GetOp<IROp_Header>(IROp->Args[i])->Op == OP_IRHEADER) continue;
uint32_t ArgNode = IROp->Args[i].ID();
LogMan::Throw::A(LiveRanges[ArgNode].Begin != ~0U, "%%ssa%d used by %%ssa%d before defined?", ArgNode, Node);
LOGMAN_THROW_A(LiveRanges[ArgNode].Begin != ~0U, "%%ssa%d used by %%ssa%d before defined?", ArgNode, Node);
auto ArgNodeBlockID = Graph->Nodes[ArgNode].Head.BlockID;
if (ArgNodeBlockID == BlockNodeID) {
@@ -600,7 +601,7 @@ namespace FEXCore::IR {
} else if (StaticClass == FPRFixedClass) {
return Size == 16;
} else {
LogMan::Throw::A(false, "Unexpected static class %d", StaticClass);
LOGMAN_THROW_A(false, "Unexpected static class %d", StaticClass);
}
return false; // Unknown
};
@@ -612,7 +613,7 @@ namespace FEXCore::IR {
} else if (StaticClass == FPRFixedClass) {
return (Size == 16 /*|| Size == 8 || Size == 4*/) && ((Offset & 15) == 0); // We need more meta info to support not-size-of-reg
} else {
LogMan::Throw::A(false, "Unexpected static class %d", StaticClass);
LOGMAN_THROW_A(false, "Unexpected static class %d", StaticClass);
}
return false; // Unknown
};
@@ -632,7 +633,7 @@ namespace FEXCore::IR {
auto reg = (Offset - beginFpr) / 16;
return PhysicalRegister(FPRFixedClass, reg);
} else {
LogMan::Throw::A(false, "Unexpected Offset %d", Offset);
LOGMAN_THROW_A(false, "Unexpected Offset %d", Offset);
return INVALID_REGCLASS;
}
};
@@ -656,7 +657,7 @@ namespace FEXCore::IR {
auto reg = (Offset - beginFpr) / 16;
return &StaticMaps[GprSize + reg];
} else {
LogMan::Throw::A(false, "Unexpected offset %d", Offset);
LOGMAN_THROW_A(false, "Unexpected offset %d", Offset);
return (LiveRange**)nullptr;
}
};
@@ -668,7 +669,7 @@ namespace FEXCore::IR {
} else if (PhyReg.Class == FPRFixedClass.Val) {
return &StaticMaps[GprSize + PhyReg.Reg];
} else {
LogMan::Throw::A(false, "Unexpected Class %d", PhyReg.Class);
LOGMAN_THROW_A(false, "Unexpected Class %d", PhyReg.Class);
return (LiveRange**)nullptr;
}
};
@@ -807,7 +808,7 @@ namespace FEXCore::IR {
for (auto [BlockNode, BlockHeader] : IR->GetBlocks()) {
auto BlockIROp = BlockHeader->CW<FEXCore::IR::IROp_CodeBlock>();
LogMan::Throw::A(BlockIROp->Header.Op == IR::OP_CODEBLOCK, "IR type failed to be a code block");
LOGMAN_THROW_A(BlockIROp->Header.Op == IR::OP_CODEBLOCK, "IR type failed to be a code block");
BlockInterferences *BlockInterferenceVector = &LocalBlockInterferences.try_emplace(IR->GetID(BlockNode)).first->second;
BlockInterferenceVector->reserve(BlockIROp->Last.ID() - BlockIROp->Begin.ID());
@@ -910,7 +911,7 @@ namespace FEXCore::IR {
SpanEnd.resize(NodeCount);
for (uint32_t i = 0; i < NodeCount; ++i) {
if (LiveRanges[i].Begin != ~0U) {
LogMan::Throw::A(LiveRanges[i].Begin < LiveRanges[i].End , "Span must Begin before Ending");
LOGMAN_THROW_A(LiveRanges[i].Begin < LiveRanges[i].End , "Span must Begin before Ending");
auto Class = GetClass(Graph->AllocData->Map[i]);
SpanStart[LiveRanges[i].Begin].Append(INFO_MAKE(i, Class));
@@ -938,7 +939,7 @@ namespace FEXCore::IR {
});
}
LogMan::Throw::A(Active.Items[0] == 0, "Interference bug");
LOGMAN_THROW_A(Active.Items[0] == 0, "Interference bug");
SpanStart.clear();
SpanEnd.clear();
}
@@ -957,7 +958,7 @@ namespace FEXCore::IR {
RegisterClass *RAClass = &Graph->Set.Classes[RegClass];
if (CurrentNode->Head.PhiPartner) {
LogMan::Msg::A("Phi nodes not supported");
LOGMAN_MSG_A("Phi nodes not supported");
#if 0
// In the case that we have a list of nodes that need the same register allocated we need to do something special
// We need to gather the data from the forward linked list and make sure they all match the virtual register
@@ -1156,7 +1157,7 @@ namespace FEXCore::IR {
// This would ensure something will spill earlier if its previous use and next use are farther away
auto InterferenceNodeNextUse = FindFirstUse(IREmit, InterferenceOrderedNode, NodeOpBeginIter, InterferenceNodeOpEndIter);
auto InterferenceNodePrevUse = FindLastUseBefore(IREmit, InterferenceOrderedNode, InterferenceNodeOpBeginIter, NodeOpBeginIter);
LogMan::Throw::A(InterferenceNodeNextUse != IR::NodeIterator::Invalid(), "Couldn't find next usage of op");
LOGMAN_THROW_A(InterferenceNodeNextUse != IR::NodeIterator::Invalid(), "Couldn't find next usage of op");
// If there is no use of the interference op prior to our op then it only has initial definition
if (InterferenceNodePrevUse == IR::NodeIterator::Invalid()) InterferenceNodePrevUse = InterferenceNodeOpBeginIter;
@@ -1322,7 +1323,7 @@ namespace FEXCore::IR {
LogMan::Msg::D("\tInt%d: %%ssa%d Remat: %d [%d, %d)", j++, InterferenceNode, InterferenceLiveRange->RematCost, InterferenceLiveRange->Begin, InterferenceLiveRange->End);
});
}
LogMan::Throw::A(InterferenceIdToSpill != 0, "Couldn't find Node to spill");
LOGMAN_THROW_A(InterferenceIdToSpill != 0, "Couldn't find Node to spill");
return InterferenceIdToSpill;
}
@@ -1357,7 +1358,7 @@ namespace FEXCore::IR {
auto LastCursor = IREmit->GetWriteCursor();
auto [CodeNode, IROp] = IR.at(SpillPointId)();
LogMan::Throw::A(IROp->HasDest, "Can't spill with no dest");
LOGMAN_THROW_A(IROp->HasDest, "Can't spill with no dest");
uint32_t Node = IR.GetID(CodeNode);
RegisterNode *CurrentNode = &Graph->Nodes[Node];
@@ -1381,7 +1382,7 @@ namespace FEXCore::IR {
// First op post Spill
auto NextIter = IR.at(CodeNode);
auto FirstUseLocation = FindFirstUse(IREmit, ConstantNode, NextIter, NodeIterator::Invalid());
LogMan::Throw::A(FirstUseLocation != IR::NodeIterator::Invalid(), "At %%ssa%d Spilling Op %%ssa%d but Failure to find op use", Node, InterferenceNode);
LOGMAN_THROW_A(FirstUseLocation != IR::NodeIterator::Invalid(), "At %%ssa%d Spilling Op %%ssa%d but Failure to find op use", Node, InterferenceNode);
if (FirstUseLocation != IR::NodeIterator::Invalid()) {
--FirstUseLocation;
auto [FirstUseOrderedNode, _] = FirstUseLocation();
@@ -1399,10 +1400,10 @@ namespace FEXCore::IR {
FEXCore::IR::RegisterClassType InterferenceRegClass = FEXCore::IR::RegisterClassType{Graph->AllocData->Map[InterferenceNode].Class};
uint32_t SpillSlot = FindSpillSlot(InterferenceNode, InterferenceRegClass);
RegisterNode *InterferenceRegisterNode = &Graph->Nodes[InterferenceNode];
LogMan::Throw::A(SpillSlot != ~0U, "Interference Node doesn't have a spill slot!");
//LogMan::Throw::A(InterferenceRegisterNode->Head.RegAndClass.Reg != INVALID_REG, "Interference node never assigned a register?");
LogMan::Throw::A(InterferenceRegClass != ~0U, "Interference node never assigned a register class?");
LogMan::Throw::A(InterferenceRegisterNode->Head.PhiPartner == nullptr, "We don't support spilling PHI nodes currently");
LOGMAN_THROW_A(SpillSlot != ~0U, "Interference Node doesn't have a spill slot!");
//LOGMAN_THROW_A(InterferenceRegisterNode->Head.RegAndClass.Reg != INVALID_REG, "Interference node never assigned a register?");
LOGMAN_THROW_A(InterferenceRegClass != ~0U, "Interference node never assigned a register class?");
LOGMAN_THROW_A(InterferenceRegisterNode->Head.PhiPartner == nullptr, "We don't support spilling PHI nodes currently");
// This is the op that we need to dump
auto [InterferenceOrderedNode, InterferenceIROp] = IR.at(InterferenceNode)();
@@ -1435,7 +1436,7 @@ namespace FEXCore::IR {
++FirstIter;
auto FirstUseLocation = FindFirstUse(IREmit, InterferenceOrderedNode, FirstIter, NodeIterator::Invalid());
LogMan::Throw::A(FirstUseLocation != NodeIterator::Invalid(), "At %%ssa%d Spilling Op %%ssa%d but Failure to find op use", Node, InterferenceNode);
LOGMAN_THROW_A(FirstUseLocation != NodeIterator::Invalid(), "At %%ssa%d Spilling Op %%ssa%d but Failure to find op use", Node, InterferenceNode);
if (FirstUseLocation != IR::NodeIterator::Invalid()) {
// We want to fill just before the first use
--FirstUseLocation;
@@ -22,7 +22,7 @@ bool IsStaticAllocGpr(uint32_t Offset, RegisterClassType Class) {
if (Offset >= begin && Offset < end) {
auto reg = (Offset - begin) / 8;
LogMan::Throw::A(Class == IR::GPRClass, "unexpected Class %d", Class);
LOGMAN_THROW_A(Class == IR::GPRClass, "unexpected Class %d", Class);
rv = reg < 16; // 0..15 -> 16 in total
}
@@ -37,7 +37,7 @@ bool IsStaticAllocFpr(uint32_t Offset, RegisterClassType Class, bool AllowGpr) {
if (Offset >= begin && Offset < end) {
auto reg = (Offset - begin)/16;
LogMan::Throw::A(Class == IR::FPRClass || (AllowGpr && Class == IR::GPRClass), "unexpected Class %d, AllowGpr %d", Class, AllowGpr);
LOGMAN_THROW_A(Class == IR::FPRClass || (AllowGpr && Class == IR::GPRClass), "unexpected Class %d, AllowGpr %d", Class, AllowGpr);
rv = reg < 16; // 0..15 -> 16 in total
}
+77
View File
@@ -0,0 +1,77 @@
#include "Utils/Allocator/HostAllocator.h"
#include <FEXCore/Utils/Allocator.h>
#include <sys/mman.h>
#include <jemalloc/jemalloc.h>
#include <memory>
extern "C" {
extern void *__libc_malloc(size_t size);
extern void *__libc_realloc(void *ptr, size_t size);
extern void __libc_free(void *ptr);
typedef void* (*mmap_hook_type)(
void *addr, size_t length, int prot, int flags,
int fd, off_t offset);
typedef int (*munmap_hook_type)(void *addr, size_t length);
extern mmap_hook_type __mmap_hook;
extern munmap_hook_type __munmap_hook;
}
namespace FEXCore::Allocator {
MMAP_Hook mmap {::mmap};
MUNMAP_Hook munmap {::munmap};
MALLOC_Hook malloc {::__libc_malloc};
REALLOC_Hook realloc {::__libc_realloc};
FREE_Hook free {::__libc_free};
std::unique_ptr<Alloc::HostAllocator> Alloc64{};
void *FEX_mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset) {
void *Result = Alloc64->Mmap(addr, length, prot, flags, fd, offset);
if (Result >= (void*)-4096) {
errno = -(uint64_t)Result;
return (void*)-1;
}
return Result;
}
int FEX_munmap(void *addr, size_t length) {
int Result = Alloc64->Munmap(addr, length);
if (Result != 0) {
errno = -Result;
return -1;
}
return Result;
}
void *FEX_malloc_hook(size_t size, const void *caller) {
return ::je_malloc(size);
}
void *FEX_realloc_hook(void *ptr, size_t size, const void *caller) {
return ::je_realloc(ptr, size);
}
void FEX_free_hook(void *ptr, const void *caller) {
return ::je_free(ptr);
}
void SetupHooks() {
Alloc64.reset(Alloc::OSAllocator::Create64BitAllocator());
__mmap_hook = FEX_mmap;
__munmap_hook = FEX_munmap;
FEXCore::Allocator::mmap = FEX_mmap;
FEXCore::Allocator::munmap = FEX_munmap;
FEXCore::Allocator::malloc = ::je_malloc;
FEXCore::Allocator::realloc = ::je_realloc;
FEXCore::Allocator::free = ::je_free;
}
}
extern "C" {
// Override the global functions
void *malloc(size_t size) { return FEXCore::Allocator::malloc(size); }
void *realloc(void *ptr, size_t size) { return FEXCore::Allocator::realloc(ptr, size); }
void free(void *ptr) { return FEXCore::Allocator::free(ptr); }
}
@@ -0,0 +1,715 @@
#include "Utils/Allocator/FlexBitSet.h"
#include "Utils/Allocator/HostAllocator.h"
#include "Utils/Allocator/IntrusiveArenaAllocator.h"
#include <FEXCore/Utils/LogManager.h>
#include <array>
#include <bit>
#include <bitset>
#include <cassert>
#include <cmath>
#include <cstdint>
#include <cstring>
#include <list>
#include <malloc.h>
#include <mutex>
#include <stdio.h>
#include <set>
#include <sys/mman.h>
#include <sys/utsname.h>
#include <sys/resource.h>
#include <syscall.h>
#include <vector>
static constexpr uint64_t PAGE_SHIFT = 12;
static constexpr uint64_t PAGE_MASK = (1 << PAGE_SHIFT) - 1;
namespace Alloc::OSAllocator {
class OSAllocator_64Bit final : public Alloc::HostAllocator {
public:
OSAllocator_64Bit();
virtual ~OSAllocator_64Bit();
void *AllocateSlab(size_t Size) override { return nullptr; }
void DeallocateSlab(void *Ptr, size_t Size) override {}
void *Mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset) override;
int Munmap(void *addr, size_t length) override;
private:
constexpr static uint64_t PAGE_SIZE = 4096;
// Upper bound is the maximum virtual address space of the host processor
uintptr_t UPPER_BOUND = (1ULL << 57);
// Lower bound is the starting of the range just past the lower 32bits
constexpr static uintptr_t LOWER_BOUND = 0x1'0000'0000ULL;
uintptr_t UPPER_BOUND_PAGE = UPPER_BOUND / PAGE_SIZE;
constexpr static uintptr_t LOWER_BOUND_PAGE = LOWER_BOUND / PAGE_SIZE;
struct ReservedVMARegion {
uintptr_t Base;
// Could be number of pages if we want to pack this in to 12 bytes
uint64_t RegionSize;
};
bool MergeReservedRegionIfPossible(ReservedVMARegion *Region, uintptr_t NextPtr, uint64_t NextSize) {
constexpr uint64_t MaxReservedRegionSize = 64ULL * 1024 * 1024 * 1024; // 64GB
uintptr_t RegionEnd = Region->Base + Region->RegionSize;
uint64_t NewRegionSize = Region->RegionSize + NextSize;
if (RegionEnd == NextPtr &&
NewRegionSize <= MaxReservedRegionSize) {
// Append the contiguous region
Region->RegionSize = NewRegionSize;
return true;
}
return false;
}
struct LiveVMARegion {
ReservedVMARegion *SlabInfo;
uint64_t FreeSpace{};
uint32_t LastPageAllocation{};
FlexBitSet<uint64_t> UsedPages;
// This returns the size of the LiveVMARegion in addition to the flex set that tracks the used data
// The LiveVMARegion lives at the start of the VMA region which means on initialization we need to set that
// tracked ranged as used immediately
static size_t GetSizeWithFlexSet(size_t Size) {
// One element per page
// 0x10'0000'0000 bytes
// 0x100'0000 Pages
// 1 bit per page for tracking means 0x20'0000 (Pages / 8) bytes of flex space
// Which is 2MB of tracking
uint64_t NumElements = (Size >> PAGE_SHIFT) * sizeof(uint64_t);
return sizeof(LiveVMARegion) + FlexBitSet<uint64_t>::Size(NumElements);
}
static void InitializeVMARegionUsed(LiveVMARegion *Region, size_t AdditionalSize) {
size_t SizeOfLiveRegion = AlignUp(LiveVMARegion::GetSizeWithFlexSet(Region->SlabInfo->RegionSize), PAGE_SIZE);
size_t SizePlusManagedData = SizeOfLiveRegion + AdditionalSize;
Region->FreeSpace = Region->SlabInfo->RegionSize - SizePlusManagedData;
size_t NumPages = SizePlusManagedData >> PAGE_SHIFT;
// Memset the full tracking to zero to state nothing used
Region->UsedPages.MemSet(Region->SlabInfo->RegionSize >> PAGE_SHIFT);
// Set our reserved pages
for (size_t i = 0; i < NumPages; ++i) {
// Set our used pages
Region->UsedPages.Set(i);
}
Region->LastPageAllocation = NumPages;
}
};
static_assert(std::is_trivially_copyable<LiveVMARegion>::value, "Needs to be trivially copyable");
static_assert(offsetof(LiveVMARegion, UsedPages) == sizeof(LiveVMARegion), "FlexBitSet needs to be at the end");
using ReservedRegionListType = std::pmr::list<ReservedVMARegion*>;
using LiveRegionListType = std::pmr::list<LiveVMARegion*>;
ReservedRegionListType *ReservedRegions{};
LiveRegionListType *LiveRegions{};
Alloc::ForwardOnlyIntrusiveArenaAllocator *ObjectAlloc{};
std::mutex AllocationMutex{};
void DetermineVASize();
LiveVMARegion *MakeRegionActive(ReservedRegionListType::iterator ReservedIterator, uint64_t UsedSize) {
ReservedVMARegion *ReservedRegion = *ReservedIterator;
ReservedRegions->erase(ReservedIterator);
// mprotect the new region we've allocated
size_t SizeOfLiveRegion = AlignUp(LiveVMARegion::GetSizeWithFlexSet(ReservedRegion->RegionSize), PAGE_SIZE);
size_t SizePlusManagedData = UsedSize + SizeOfLiveRegion;
mprotect(reinterpret_cast<void*>(ReservedRegion->Base), SizePlusManagedData, PROT_READ | PROT_WRITE);
LiveVMARegion *LiveRange = new (reinterpret_cast<void*>(ReservedRegion->Base)) LiveVMARegion();
// Copy over the reserved data
LiveRange->SlabInfo = ReservedRegion;
// Initialize VMA
LiveVMARegion::InitializeVMARegionUsed(LiveRange, UsedSize);
// Add to our active tracked ranges
auto LiveIter = LiveRegions->emplace_back(LiveRange);
return LiveIter;
}
// 32-bit old kernel workarounds
struct PtrCache {
uint32_t Ptr;
uint32_t Size;
};
PtrCache *Steal32BitIfOldKernel();
void Clear32BitOnOldKernel(PtrCache *Base);
};
void OSAllocator_64Bit::DetermineVASize() {
const std::vector<uintptr_t> TLBSizes = {{
1ULL << 57,
1ULL << 52,
1ULL << 48,
1ULL << 47,
1ULL << 42,
1ULL << 39,
1ULL << 36,
}};
for (auto Size : TLBSizes) {
// Just try allocating
// We can't actually determine VA size on ARM safely
auto Find = [](uintptr_t Size) -> bool {
for (int i = 0; i < 64; ++i) {
// Try grabbing a some of the top pages of the range
// x86 allocates some high pages in the top end
void *Ptr = ::mmap(reinterpret_cast<void*>(Size - PAGE_SIZE * i), PAGE_SIZE, PROT_NONE, MAP_FIXED_NOREPLACE | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (Ptr != (void*)~0ULL) {
::munmap(Ptr, PAGE_SIZE);
if (Ptr == (void*)(Size - PAGE_SIZE * i)) {
return true;
}
}
}
return false;
};
if (Find(Size)) {
UPPER_BOUND = Size;
UPPER_BOUND_PAGE = UPPER_BOUND / PAGE_SIZE;
break;
}
}
}
void *OSAllocator_64Bit::Mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset) {
if (addr != 0 &&
addr < reinterpret_cast<void*>(LOWER_BOUND)) {
// If we are asked to allocate something outside of the 64-bit space
// Then we need to just hand this to the OS
return ::mmap(addr, length, prot, flags, fd, offset);
}
uint64_t Addr = reinterpret_cast<uint64_t>(addr);
// Addr must be page aligned
if (Addr & PAGE_MASK) {
return reinterpret_cast<void*>(-EINVAL);
}
// If FD is provided then offset must also be page aligned
if (fd != -1 &&
offset & PAGE_MASK) {
return reinterpret_cast<void*>(-EINVAL);
}
// 64bit address overflow
if (Addr + length < Addr) {
return reinterpret_cast<void*>(-EOVERFLOW);
}
bool Fixed = (flags & MAP_FIXED) || (flags & MAP_FIXED_NOREPLACE);
length = AlignUp(length, PAGE_SIZE);
uint64_t AddrEnd = Addr + length;
size_t NumberOfPages = length / PAGE_SIZE;
// This needs a mutex to be thread safe
std::scoped_lock<std::mutex> lk{AllocationMutex};
uint64_t AllocatedOffset{};
LiveVMARegion *LiveRegion{};
if (Fixed || Addr != 0) {
// Check active slabs to see if we can fit this
for (auto it = LiveRegions->begin(); it != LiveRegions->end(); ++it) {
uintptr_t RegionBegin = (*it)->SlabInfo->Base;
uintptr_t RegionEnd = RegionBegin + (*it)->SlabInfo->RegionSize;
if (Addr >= RegionBegin &&
Addr < RegionEnd) {
LiveRegion = *it;
// Leave our loop
break;
}
}
// Couldn't find an active region that fit
// Check reserved regions
if (!LiveRegion) {
// Didn't have a slab that fit this range
// Check our reserved regions to see if we have one that fits
for (auto it = ReservedRegions->begin(); it != ReservedRegions->end(); ++it) {
ReservedVMARegion *ReservedRegion = *it;
uintptr_t RegionEnd = ReservedRegion->Base + ReservedRegion->RegionSize;
if (Addr >= ReservedRegion->Base &&
AddrEnd < RegionEnd) {
// Found one, let's make it active
LiveRegion = MakeRegionActive(it, 0);
break;
}
}
}
}
again:
auto CheckIfRangeFits = [&AllocatedOffset](LiveVMARegion *Region, uint64_t length, int prot, int flags, int fd, off_t offset, uint64_t StartingPosition = 0) -> std::pair<LiveVMARegion*, void*> {
uint64_t AllocatedPage{};
uint64_t NumberOfPages = length >> PAGE_SHIFT;
if (Region->FreeSpace >= length) {
uint64_t LastAllocation =
StartingPosition ?
(StartingPosition - Region->SlabInfo->Base) >> PAGE_SHIFT
: Region->LastPageAllocation;
size_t RegionNumberOfPages = Region->SlabInfo->RegionSize >> PAGE_SHIFT;
try_again:
for (size_t CurrentPage = LastAllocation;
CurrentPage < (RegionNumberOfPages - NumberOfPages);) {
// If we have enough free space, check if we have enough free pages that are contiguous
size_t Remaining = NumberOfPages;
assert((CurrentPage + Remaining - 1) < RegionNumberOfPages);
while (Remaining) {
if (Region->UsedPages[CurrentPage + Remaining - 1]) {
// Has an intersecting range
break;
}
--Remaining;
}
if (Remaining) {
// Didn't find a slab range
CurrentPage += Remaining;
}
else {
// We have a slab range
AllocatedPage = CurrentPage;
break;
}
}
if (!AllocatedPage && LastAllocation != 0) {
// Try again but starting from the beginning
LastAllocation = 0;
// Using goto so we don't have recursive mutex shenanigans
goto try_again;
}
if (AllocatedPage) {
AllocatedOffset = Region->SlabInfo->Base + AllocatedPage * PAGE_SIZE;
// We need to setup protections for this
void *MMapResult = ::mmap(reinterpret_cast<void*>(AllocatedOffset),
length,
prot,
(flags & ~MAP_FIXED_NOREPLACE) | MAP_FIXED,
fd, offset);
if (MMapResult == MAP_FAILED) {
return std::make_pair(Region, reinterpret_cast<void*>(-errno));
}
return std::make_pair(Region, MMapResult);
}
}
return std::make_pair(nullptr, nullptr);
};
if (Fixed) {
// Found a region let's allocate to it
if (LiveRegion) {
// Found a slab that fits this
if (flags & MAP_FIXED_NOREPLACE) {
auto Fits = CheckIfRangeFits(LiveRegion, length, prot, flags, fd, offset, Addr);
if (Fits.first && Fits.second == reinterpret_cast<void*>(Addr)) {
// We fit correctly
AllocatedOffset = Addr;
}
else {
// Intersected with something that already existed
return reinterpret_cast<void*>(-EEXIST);
}
}
else {
// We need to mmap the file to this location
void *MMapResult = ::mmap(reinterpret_cast<void*>(Addr),
length,
prot,
(flags & ~MAP_FIXED_NOREPLACE) | MAP_FIXED,
fd, offset);
if (MMapResult == MAP_FAILED) {
return reinterpret_cast<void*>(-errno);
}
AllocatedOffset = Addr;
}
// Fall through to live region tracking
}
}
else {
// Check our active slabs to see if we can fit the allocation
// Slightly different than fixed since it doesn't need exact placement
if (LiveRegion && Addr != 0) {
// We found a LiveRegion that could hold this address. Let's try to place it
// Check if this area is free
auto Fits = CheckIfRangeFits(LiveRegion, length, prot, flags, fd, offset, Addr);
if (Fits.first && Fits.second == reinterpret_cast<void*>(Addr)) {
// We fit correctly
AllocatedOffset = Addr;
}
else {
// Couldn't fit
// We can continue past this point still
LiveRegion = nullptr;
}
}
if (!LiveRegion) {
for (auto it = LiveRegions->begin(); it != LiveRegions->end(); ++it) {
auto Fits = CheckIfRangeFits(*it, length, prot, flags, fd, offset);
if (Fits.first && Fits.second == reinterpret_cast<void*>(AllocatedOffset)) {
// We fit correctly
LiveRegion = Fits.first;
break;
}
// Couldn't fit but mmap gave us an error
if (!Fits.first && Fits.second) {
return Fits.second;
}
// nullptr on both means no error and couldn't fit
}
}
if (!LiveRegion) {
// Couldn't find a fit in the live regions
// Allocate a new reserved region
size_t lengthOfLiveRegion = AlignUp(LiveVMARegion::GetSizeWithFlexSet(length), PAGE_SIZE);
size_t lengthPlusManagedData = length + lengthOfLiveRegion;
for (auto it = ReservedRegions->begin(); it != ReservedRegions->end(); ++it) {
if ((*it)->RegionSize >= lengthPlusManagedData) {
MakeRegionActive(it, 0);
goto again;
}
}
}
}
if (LiveRegion) {
// Mark the pages as used
uintptr_t RegionBegin = LiveRegion->SlabInfo->Base;
uintptr_t MappedBegin = (AllocatedOffset - RegionBegin) >> PAGE_SHIFT;
for (size_t i = 0; i < NumberOfPages; ++i) {
LiveRegion->UsedPages.Set(MappedBegin + i);
}
// Change our last allocation region
LiveRegion->LastPageAllocation = MappedBegin + NumberOfPages;
LiveRegion->FreeSpace -= length;
}
if (!AllocatedOffset) {
AllocatedOffset = -ENOMEM;
}
return reinterpret_cast<void*>(AllocatedOffset);
}
int OSAllocator_64Bit::Munmap(void *addr, size_t length) {
if (addr < reinterpret_cast<void*>(LOWER_BOUND)) {
// If we are asked to allocate something outside of the 64-bit space
// Then we need to just hand this to the OS
return ::munmap(addr, length);
}
uint64_t Addr = reinterpret_cast<uint64_t>(addr);
if (Addr & PAGE_MASK) {
return -EINVAL;
}
if (length & PAGE_MASK) {
return -EINVAL;
}
if (Addr + length < Addr) {
return -EOVERFLOW;
}
// This needs a mutex to be thread safe
std::scoped_lock<std::mutex> lk{AllocationMutex};
length = AlignUp(length, PAGE_SIZE);
uintptr_t PtrBegin = reinterpret_cast<uintptr_t>(addr);
uintptr_t PtrEnd = PtrBegin + length;
// Walk all of the live ranges and find this slab then delete it
for (auto it = LiveRegions->begin(); it != LiveRegions->end(); ++it) {
uintptr_t RegionBegin = (*it)->SlabInfo->Base;
uintptr_t RegionEnd = RegionBegin + (*it)->SlabInfo->RegionSize;
if (RegionBegin <= PtrBegin &&
RegionEnd > PtrEnd) {
// Live region fully encompasses slab range
uint64_t FreedPages{};
uint64_t SlabPageBegin = (PtrBegin - RegionBegin) >> PAGE_SHIFT;
uint64_t PagesToFree = length >> PAGE_SHIFT;
for (size_t i = 0; i < PagesToFree; ++i) {
FreedPages += (*it)->UsedPages.TestAndClear(SlabPageBegin + i) ? 1 : 0;
}
if (FreedPages != 0)
{
// If we were contiuous freeing then make sure to give back the physical address space
// If the region was locked then madvise won't remove the physical backing
// This woul be a bug in the frontend application
// So be careful with mlock/munlock
::madvise(addr, length, MADV_DONTNEED);
::mmap(addr, length, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0);
}
(*it)->FreeSpace += FreedPages * 4096;
// XXX: Move region back to reserved list
return 0;
}
}
// If it didn't match at all then no error
return 0;
}
OSAllocator_64Bit::PtrCache *OSAllocator_64Bit::Steal32BitIfOldKernel() {
// First calculate kernel version
struct utsname buf{};
if (uname(&buf) == -1) {
return nullptr;
}
int32_t Major{};
int32_t Minor{};
int32_t Patch{};
char Tmp{};
std::istringstream ss{buf.release};
ss >> Major;
ss.read(&Tmp, 1);
ss >> Minor;
ss.read(&Tmp, 1);
ss >> Patch;
ss.read(&Tmp, 1);
uint32_t Version = (Major << 24) | (Minor << 16) | Patch;
if (Version >= ((4 << 24) | (17 << 16) | 0)) {
// If the kernel is >= 4.17 then it supports MAP_FIXED_NOREPLACE
return nullptr;
}
OSAllocator_64Bit::PtrCache *Cache{};
uint32_t CacheSize{};
uint32_t CurrentCacheOffset = 0;
constexpr std::array<size_t, 6> ReservedVMARegionSizes = {{
1ULL * 1024 * 1024 * 1024, // 1GB
512ULL * 1024 * 1024, // 512MB
128ULL * 1024 * 1024, // 128MB
32ULL * 1024 * 1024, // 32MB
1ULL * 1024 * 1024, // 1MB
4096ULL // One page
}};
constexpr size_t AllocationSizeMaxIndex = ReservedVMARegionSizes.size() - 1;
uint64_t CurrentSizeIndex = 0;
constexpr size_t LOWER_BOUND_32 = 0x1'0000;
constexpr size_t UPPER_BOUND_32 = LOWER_BOUND;
for (size_t MemoryOffset = LOWER_BOUND_32; MemoryOffset < UPPER_BOUND_32;) {
size_t AllocationSize = ReservedVMARegionSizes[CurrentSizeIndex];
size_t MemoryOffsetUpper = MemoryOffset + AllocationSize;
// If we would go above the upper bound on size then try the next size
if (MemoryOffsetUpper > UPPER_BOUND_32) {
++CurrentSizeIndex;
continue;
}
void *Ptr = ::mmap(reinterpret_cast<void*>(MemoryOffset), AllocationSize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE, -1, 0);
// If we managed to allocate and not get the address we want then unmap it
// This happens with kernels older than 4.17
if (reinterpret_cast<uintptr_t>(Ptr) + AllocationSize > UPPER_BOUND_32) {
munmap(Ptr, AllocationSize);
Ptr = reinterpret_cast<void*>(~0ULL);
}
// If we failed to allocate and we are on the smallest allocation size then just continue onward
// This page was unmappable
if (reinterpret_cast<uintptr_t>(Ptr) == ~0ULL && CurrentSizeIndex == AllocationSizeMaxIndex) {
CurrentSizeIndex = 0;
MemoryOffset += AllocationSize;
continue;
}
// Congratulations we were able to map this bit
// Reset and claim it was available
if (reinterpret_cast<uintptr_t>(Ptr) != ~0ULL) {
if (!Cache) {
Cache = reinterpret_cast<OSAllocator_64Bit::PtrCache *>(Ptr);
CacheSize = AllocationSize;
}
else {
Cache[CurrentCacheOffset] = {
.Ptr = static_cast<uint32_t>(reinterpret_cast<uint64_t>(Ptr)),
.Size = static_cast<uint32_t>(AllocationSize)
};
++CurrentCacheOffset;
}
CurrentSizeIndex = 0;
MemoryOffset += AllocationSize;
continue;
}
// Couldn't allocate at this size
// Increase and continue
++CurrentSizeIndex;
}
Cache[CurrentCacheOffset] = {
.Ptr = static_cast<uint32_t>(reinterpret_cast<uint64_t>(Cache)),
.Size = CacheSize,
};
return Cache;
}
void OSAllocator_64Bit::Clear32BitOnOldKernel(OSAllocator_64Bit::PtrCache *Base) {
if (Base == nullptr) {
return;
}
for (size_t i = 0;; ++i) {
void *Ptr = reinterpret_cast<void*>(Base[i].Ptr);
size_t Size = Base[i].Size;
munmap(Ptr, Size);
if (Ptr == Base) {
break;
}
}
}
OSAllocator_64Bit::OSAllocator_64Bit() {
malloc_trim(0);
DetermineVASize();
auto ArrayPtr = Steal32BitIfOldKernel();
// On allocation try and steal the entire upper 64bits of address space for mapping
constexpr std::array<size_t, 8> ReservedVMARegionSizes = {{
// Anything larger than 64GB fails out
64ULL * 1024 * 1024 * 1024, // 64GB
32ULL * 1024 * 1024 * 1024, // 32GB
16ULL * 1024 * 1024 * 1024, // 16GB
4ULL * 1024 * 1024 * 1024, // 4GB
1ULL * 1024 * 1024 * 1024, // 1GB
512ULL * 1024 * 1024, // 512MB
128ULL * 1024 * 1024, // 128MB
4096ULL // One page
}};
constexpr size_t AllocationSizeMaxIndex = ReservedVMARegionSizes.size() - 1;
// Have the first region only be 4GB VMA
// Avoids conflicts with some tests
uint64_t CurrentSizeIndex = 3;
ReservedVMARegion *PrevReserved{};
for (size_t MemoryOffset = LOWER_BOUND; MemoryOffset < UPPER_BOUND;) {
size_t AllocationSize = ReservedVMARegionSizes[CurrentSizeIndex];
size_t MemoryOffsetUpper = MemoryOffset + AllocationSize;
// If we would go above the upper bound on size then try the next size
if (MemoryOffsetUpper > UPPER_BOUND) {
++CurrentSizeIndex;
continue;
}
void *Ptr = ::mmap(reinterpret_cast<void*>(MemoryOffset), AllocationSize, PROT_NONE, MAP_FIXED_NOREPLACE | MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE, -1, 0);
// If we managed to allocate and not get the address we want then unmap it
// This happens with kernels older than 4.17
if (reinterpret_cast<uintptr_t>(Ptr) != MemoryOffset &&
reinterpret_cast<uintptr_t>(Ptr) < LOWER_BOUND) {
munmap(Ptr, AllocationSize);
Ptr = reinterpret_cast<void*>(~0ULL);
}
// If we failed to allocate and we are on the smallest allocation size then just continue onward
// This page was unmappable
if (reinterpret_cast<uintptr_t>(Ptr) == ~0ULL && CurrentSizeIndex == AllocationSizeMaxIndex) {
CurrentSizeIndex = 0;
MemoryOffset += AllocationSize;
continue;
}
// Congratulations we were able to map this bit
// Reset and claim it was available
if (reinterpret_cast<uintptr_t>(Ptr) != ~0ULL) {
if (!ObjectAlloc) {
// Steal the first allocation for an intrusive allocator
// Will be mprotected correctly already
int Result = mprotect(Ptr, AllocationSize, PROT_READ | PROT_WRITE);
LogMan::Throw::A(Result == 0, "mprotect(%p, 0x%lx) -> %d (%s)", Ptr, AllocationSize, Result, strerror(errno));
ObjectAlloc = new (Ptr) Alloc::ForwardOnlyIntrusiveArenaAllocator(Ptr, AllocationSize);
ReservedRegions = ObjectAlloc->new_construct(ReservedRegions, ObjectAlloc);
LiveRegions = ObjectAlloc->new_construct(LiveRegions, ObjectAlloc);
}
else {
bool Merged = false;
if (PrevReserved) {
Merged = MergeReservedRegionIfPossible(PrevReserved, reinterpret_cast<uint64_t>(Ptr), AllocationSize);
}
if (!Merged) {
ReservedVMARegion *Region = ObjectAlloc->new_construct<ReservedVMARegion>();
Region->Base = reinterpret_cast<uint64_t>(Ptr);
Region->RegionSize = AllocationSize;
ReservedRegions->emplace_back(Region);
PrevReserved = Region;
}
}
CurrentSizeIndex = 0;
MemoryOffset += AllocationSize;
continue;
}
// Couldn't allocate at this size
// Increase and continue
++CurrentSizeIndex;
}
Clear32BitOnOldKernel(ArrayPtr);
}
OSAllocator_64Bit::~OSAllocator_64Bit() {
// For consistency, pull the mutex
std::scoped_lock<std::mutex> lk{AllocationMutex};
// Walk the pages and deallocate
// First walk the live regions
for (auto it = LiveRegions->begin(); it != LiveRegions->end(); ++it) {
::munmap(reinterpret_cast<void*>((*it)->SlabInfo->Base), (*it)->SlabInfo->RegionSize);
}
// Now walk the reserved regions
for (auto it = ReservedRegions->begin(); it != ReservedRegions->end(); ++it) {
::munmap(reinterpret_cast<void*>((*it)->Base), (*it)->RegionSize);
}
}
Alloc::HostAllocator *Create64BitAllocator() {
return new OSAllocator_64Bit{};
}
}
+50
View File
@@ -0,0 +1,50 @@
#pragma once
#include "HostAllocator.h"
#include <cstddef>
#include <cstdint>
#include <cstring>
#include <type_traits>
template<typename T>
struct FlexBitSet final {
using ElementType = T;
constexpr static size_t MinimumSize = sizeof(ElementType);
constexpr static size_t MinimumSizeBits = sizeof(ElementType) * 8;
T Memory[];
bool Get(T Element) {
return (Memory[Element / MinimumSizeBits] & (1ULL << (Element % MinimumSizeBits))) != 0;
}
bool TestAndClear(T Element) {
bool Value = Get(Element);
Memory[Element / MinimumSizeBits] &= ~(1ULL << (Element % MinimumSizeBits));
return Value;
}
void Set(T Element) {
Memory[Element / MinimumSizeBits] |= (1ULL << (Element % MinimumSizeBits));
}
void Clear(T Element) {
Memory[Element / MinimumSizeBits] &= ~(1ULL << (Element % MinimumSizeBits));
}
void MemClear(size_t Elements) {
memset(Memory, 0, Alloc::AlignUp(Elements / MinimumSizeBits, MinimumSizeBits));
}
void MemSet(size_t Elements) {
memset(Memory, 0xFF, Alloc::AlignUp(Elements / MinimumSizeBits, MinimumSizeBits));
}
// This very explicitly doesn't let you take an address
// Is only a getter
bool operator[](T Element) {
return Get(Element);
}
static size_t Size(T Elements) {
return Alloc::AlignUp(Elements / MinimumSizeBits, MinimumSizeBits);
}
};
static_assert(sizeof(FlexBitSet<uint64_t>) == 0, "This needs to be a flex member");
static_assert(std::is_trivially_copyable<FlexBitSet<uint64_t>>::value, "Needsto be trivially copyable");
+44
View File
@@ -0,0 +1,44 @@
#pragma once
#include <cstddef>
#include <cstdint>
#include <sys/types.h>
constexpr static uint64_t PAGE_SIZE = 4096;
namespace Alloc {
static inline uint64_t AlignUp(uint64_t value, uint64_t size) {
return value + (size - value % size) % size;
};
// HostAllocator is just a page pased slab allocator
// Similar to mmap and munmap only mapping at the page level
class HostAllocator {
public:
HostAllocator() = default;
virtual ~HostAllocator() = default;
virtual void *AllocateSlab(size_t Size) = 0;
virtual void DeallocateSlab(void *Ptr, size_t Size) = 0;
virtual void *Mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset) { return nullptr; }
virtual int Munmap(void *addr, size_t length) { return -1; }
};
class GlobalAllocator {
public:
HostAllocator *Alloc{};
GlobalAllocator(HostAllocator *_Alloc)
: Alloc {_Alloc} {}
virtual void *malloc(size_t Size) = 0;
virtual void *calloc(size_t num, size_t size) = 0;
virtual void *realloc(void *ptr, size_t size) = 0;
virtual void *memalign(size_t alignment, size_t size) = 0;
virtual void free(void *ptr) = 0;
};
GlobalAllocator *CreateBasicAllocator(HostAllocator *Alloc);
}
namespace Alloc::OSAllocator {
Alloc::HostAllocator *Create64BitAllocator();
}
@@ -0,0 +1,186 @@
#pragma once
#include "FlexBitSet.h"
#include "HostAllocator.h"
#include <bitset>
#include <cstddef>
#include <memory_resource>
#include <mutex>
#include <vector>
namespace Alloc {
class ForwardOnlyIntrusiveArenaAllocator final : public std::pmr::memory_resource {
public:
ForwardOnlyIntrusiveArenaAllocator(void* Ptr, size_t _Size)
: Begin {reinterpret_cast<uintptr_t>(Ptr)}
, Size {_Size} {
LastAllocation = sizeof(ForwardOnlyIntrusiveArenaAllocator);
}
~ForwardOnlyIntrusiveArenaAllocator() = default;
template<class U, class... Args>
U *new_construct(Args&&... args) {
void *Ptr = do_allocate(sizeof(U), std::alignment_of<U>::value);
return new (Ptr) U(args...);
}
template<class U, class... Args>
U *new_construct(U *Class, Args&&... args) {
void *Ptr = do_allocate(sizeof(U), std::alignment_of<U>::value);
return new (Ptr) U(args...);
}
size_t AmountAllocated() const { return LastAllocation; }
private:
void *do_allocate(std::size_t bytes, std::size_t alignment) override {
size_t PreviousAligned = Alloc::AlignUp(LastAllocation, alignment);
size_t NewOffset = PreviousAligned + bytes;
if (NewOffset > Size) {
return nullptr;
}
LastAllocation = NewOffset;
return reinterpret_cast<void*>(Begin + PreviousAligned);
}
void do_deallocate(void*, std::size_t, std::size_t) override {
// Do nothing
}
bool do_is_equal(const std::pmr::memory_resource& other) const noexcept override {
// Only if the allocator pointers are the same are they equal
if (this == &other) {
return true;
}
// We don't share state with another allocator so we can't share anything
return false;
}
uintptr_t Begin;
size_t Size;
size_t LastAllocation{};
};
class IntrusiveArenaAllocator final : public std::pmr::memory_resource {
public:
IntrusiveArenaAllocator(void* Ptr, size_t _Size)
: Begin {reinterpret_cast<uintptr_t>(Ptr)}
, Size {_Size} {
uint64_t NumberOfPages = _Size / PAGE_SIZE;
uint64_t UsedBits = Alloc::AlignUp(sizeof(IntrusiveArenaAllocator) +
Size / PAGE_SIZE / 8, PAGE_SIZE);
for (size_t i = 0; i < UsedBits; ++i) {
UsedPages.Set(i);
}
FreePages = NumberOfPages - UsedBits;
}
template<class U, class... Args>
U *new_construct(Args&&... args) {
void *Ptr = do_allocate(sizeof(U), std::alignment_of<U>::value);
return new (Ptr) U(args...);
}
template<class U, class... Args>
U *new_construct(U *Class, Args&&... args) {
void *Ptr = do_allocate(sizeof(U), std::alignment_of<U>::value);
return new (Ptr) U(args...);
}
uintptr_t GetSlabBase() const { return Begin; }
uint64_t GetSlabSize() const { return Size; }
uint64_t GetFreePages() const { return FreePages; }
private:
void *do_allocate(std::size_t bytes, std::size_t alignment) override {
std::scoped_lock<std::mutex> lk{AllocationMutex};
size_t NumberPages = Alloc::AlignUp(bytes, PAGE_SIZE) / PAGE_SIZE;
uintptr_t AllocatedOffset{};
try_again:
for (uintptr_t CurrentPage = LastAllocatedPageOffset; CurrentPage <= (Size - NumberPages);) {
size_t Remaining = NumberPages;
while (Remaining) {
if (UsedPages[CurrentPage + Remaining - 1]) {
// Has an intersecting range
break;
}
--Remaining;
}
if (Remaining) {
// Didn't find an allocation range
CurrentPage += Remaining;
}
else {
// We have a range to allocate
AllocatedOffset = CurrentPage;
break;
}
}
if (!AllocatedOffset && LastAllocatedPageOffset != 0) {
// Try again but starting from the beginning
LastAllocatedPageOffset = 0;
// Using goto so we don't have recursive mutex shenanigans
goto try_again;
}
// Allocated offset must be valid or zero at this point
if (AllocatedOffset) {
// Map the range as no longer available
for (size_t i = 0; i < NumberPages; ++i) {
UsedPages.Set(AllocatedOffset + i);
}
LastAllocatedPageOffset = AllocatedOffset + NumberPages;
// Now convert this base page to a pointer and return it
return reinterpret_cast<void*>(Begin + AllocatedOffset * PAGE_SIZE);
}
return nullptr;
}
void do_deallocate(void* p, std::size_t bytes, std::size_t alignment) override {
std::scoped_lock<std::mutex> lk{AllocationMutex};
uintptr_t PageOffset = (reinterpret_cast<uintptr_t>(p) - Begin) / PAGE_SIZE;
size_t NumPages = AlignUp(bytes, PAGE_SIZE) / PAGE_SIZE;
// Walk the allocation list and deallocate
uint64_t FreedPages{};
for (size_t i = 0; i < NumPages; ++i) {
FreedPages += UsedPages.TestAndClear(PageOffset + i) ? 1 : 0;
}
FreePages += FreedPages;
}
bool do_is_equal(const std::pmr::memory_resource& other) const noexcept override {
// Only if the allocator pointers are the same are they equal
if (this == &other) {
return true;
}
// We don't share state with another allocator so we can't share anything
return false;
}
uintptr_t Begin;
size_t Size;
uint64_t FreePages{};
size_t LastAllocatedPageOffset{};
std::mutex AllocationMutex{};
// For up to 64GB regions this will require up to 2MB tracking
// Needs to be the last element
FlexBitSet<uint64_t> UsedPages;
};
}
@@ -6,7 +6,7 @@ $end_info$
*/
#include <FEXCore/Utils/Common/MathUtils.h>
#include <FEXCore/Utils/ELFLoader.h>
#include <FEXCore/Utils/ELFContainer.h>
#include <FEXCore/Utils/LogManager.h>
#include <cstring>
#include <elf.h>
@@ -134,7 +134,7 @@ ELFContainer::ELFContainer(std::string const &Filename, std::string const &RootF
//PrintInitArray();
//PrintDynamicTable();
//LogMan::Throw::A(InterpreterHeader == nullptr, "Can only handle static programs");
//LOGMAN_THROW_A(InterpreterHeader == nullptr, "Can only handle static programs");
}
ELFContainer::~ELFContainer() {
@@ -196,8 +196,8 @@ bool ELFContainer::LoadELF_32() {
memcpy(&Header, reinterpret_cast<Elf32_Ehdr *>(&RawFile.at(0)),
sizeof(Elf32_Ehdr));
LogMan::Throw::A(Header._32.e_phentsize == sizeof(Elf32_Phdr), "PH Entry size wasn't correct size");
LogMan::Throw::A(Header._32.e_shentsize == sizeof(Elf32_Shdr), "PH Entry size wasn't correct size");
LOGMAN_THROW_A(Header._32.e_phentsize == sizeof(Elf32_Phdr), "PH Entry size wasn't correct size");
LOGMAN_THROW_A(Header._32.e_shentsize == sizeof(Elf32_Shdr), "PH Entry size wasn't correct size");
if (Header._32.e_machine != EM_386) {
LogMan::Msg::D("32bit ELF wasn't x86 based");
@@ -237,8 +237,8 @@ bool ELFContainer::LoadELF_64() {
memcpy(&Header, reinterpret_cast<Elf64_Ehdr *>(&RawFile.at(0)),
sizeof(Elf64_Ehdr));
LogMan::Throw::A(Header._64.e_phentsize == 56, "PH Entry size wasn't 56");
LogMan::Throw::A(Header._64.e_shentsize == 64, "PH Entry size wasn't 64");
LOGMAN_THROW_A(Header._64.e_phentsize == 56, "PH Entry size wasn't 56");
LOGMAN_THROW_A(Header._64.e_shentsize == 64, "PH Entry size wasn't 64");
if (Header._64.e_machine != EM_X86_64) {
LogMan::Msg::D("64bit ELF wasn't x86-64 based");
@@ -408,9 +408,9 @@ void ELFContainer::CalculateSymbols() {
uint64_t NumSymTabSymbols = 0;
uint64_t NumDynSymSymbols = 0;
if (SymTabHeader) {
LogMan::Throw::A(SymTabHeader->sh_link < SectionHeaders.size(),
LOGMAN_THROW_A(SymTabHeader->sh_link < SectionHeaders.size(),
"Symbol table string table section is wrong");
LogMan::Throw::A(SymTabHeader->sh_entsize == sizeof(Elf32_Sym),
LOGMAN_THROW_A(SymTabHeader->sh_entsize == sizeof(Elf32_Sym),
"Entry size doesn't match symbol entry");
StringTableHeader = SectionHeaders.at(SymTabHeader->sh_link)._32;
@@ -419,9 +419,9 @@ void ELFContainer::CalculateSymbols() {
}
if (DynSymTabHeader) {
LogMan::Throw::A(DynSymTabHeader->sh_link < SectionHeaders.size(),
LOGMAN_THROW_A(DynSymTabHeader->sh_link < SectionHeaders.size(),
"Symbol table string table section is wrong");
LogMan::Throw::A(DynSymTabHeader->sh_entsize == sizeof(Elf32_Sym),
LOGMAN_THROW_A(DynSymTabHeader->sh_entsize == sizeof(Elf32_Sym),
"Entry size doesn't match symbol entry");
DynStringTableHeader = SectionHeaders.at(DynSymTabHeader->sh_link)._32;
@@ -477,6 +477,36 @@ void ELFContainer::CalculateSymbols() {
}
}
}
Elf32_Shdr const *StrHeader = SectionHeaders.at(Header._32.e_shstrndx)._32;
char const *SHStrings = &RawFile.at(StrHeader->sh_offset);
for (uint32_t i = 0; i < SectionHeaders.size(); ++i) {
Elf32_Shdr const *hdr = SectionHeaders.at(i)._32;
if (strcmp(&SHStrings[hdr->sh_name], ".eh_frame_hdr") == 0) {
auto eh_frame_hdr = &RawFile.at(hdr->sh_offset);
// we only handle this specific unwind table encoding
if (eh_frame_hdr[0] == 1 && eh_frame_hdr[1] == 0x1B && eh_frame_hdr[2] == 0x3 && eh_frame_hdr[3] == 0x3b) {
// ptr enc : 4 bytes, signed, pcrel
// fde count : 4 bytes udata
// table enc : 4 bytes, signed, datarel
int fde_count = *(int*)(eh_frame_hdr + 8);
UnwindEntries.clear();
UnwindEntries.reserve(fde_count);
struct entry {
int32_t pc;
int32_t fde;
};
entry *Table = (entry*)(eh_frame_hdr+12);
for (int f = 0; f < fde_count; f++) {
uintptr_t Entry = (uintptr_t)(Table[f].pc + hdr->sh_offset);
UnwindEntries.push_back(Entry);
}
}
break;
}
}
}
else {
Elf64_Shdr const *SymTabHeader{nullptr};
@@ -511,9 +541,9 @@ void ELFContainer::CalculateSymbols() {
uint64_t NumSymTabSymbols = 0;
uint64_t NumDynSymSymbols = 0;
if (SymTabHeader) {
LogMan::Throw::A(SymTabHeader->sh_link < SectionHeaders.size(),
LOGMAN_THROW_A(SymTabHeader->sh_link < SectionHeaders.size(),
"Symbol table string table section is wrong");
LogMan::Throw::A(SymTabHeader->sh_entsize == sizeof(Elf64_Sym),
LOGMAN_THROW_A(SymTabHeader->sh_entsize == sizeof(Elf64_Sym),
"Entry size doesn't match symbol entry");
StringTableHeader = SectionHeaders.at(SymTabHeader->sh_link)._64;
@@ -522,9 +552,9 @@ void ELFContainer::CalculateSymbols() {
}
if (DynSymTabHeader) {
LogMan::Throw::A(DynSymTabHeader->sh_link < SectionHeaders.size(),
LOGMAN_THROW_A(DynSymTabHeader->sh_link < SectionHeaders.size(),
"Symbol table string table section is wrong");
LogMan::Throw::A(DynSymTabHeader->sh_entsize == sizeof(Elf64_Sym),
LOGMAN_THROW_A(DynSymTabHeader->sh_entsize == sizeof(Elf64_Sym),
"Entry size doesn't match symbol entry");
DynStringTableHeader = SectionHeaders.at(DynSymTabHeader->sh_link)._64;
@@ -580,6 +610,36 @@ void ELFContainer::CalculateSymbols() {
}
}
}
Elf64_Shdr const *StrHeader = SectionHeaders.at(Header._64.e_shstrndx)._64;
char const *SHStrings = &RawFile.at(StrHeader->sh_offset);
for (uint32_t i = 0; i < SectionHeaders.size(); ++i) {
Elf64_Shdr const *hdr = SectionHeaders.at(i)._64;
if (strcmp(&SHStrings[hdr->sh_name], ".eh_frame_hdr") == 0) {
auto eh_frame_hdr = &RawFile.at(hdr->sh_offset);
// we only handle this specific unwind table encoding
if (eh_frame_hdr[0] == 1 && eh_frame_hdr[1] == 0x1B && eh_frame_hdr[2] == 0x3 && eh_frame_hdr[3] == 0x3b) {
// ptr enc : 4 bytes, signed, pcrel
// fde count : 4 bytes udata
// table enc : 4 bytes, signed, datarel
int fde_count = *(int*)(eh_frame_hdr + 8);
UnwindEntries.clear();
UnwindEntries.reserve(fde_count);
struct entry {
int32_t pc;
int32_t fde;
};
entry *Table = (entry*)(eh_frame_hdr+12);
for (int f = 0; f < fde_count; f++) {
uintptr_t Entry = (uintptr_t)(Table[f].pc + hdr->sh_offset);
UnwindEntries.push_back(Entry);
}
}
break;
}
}
}
}
@@ -629,6 +689,11 @@ void ELFContainer::AddSymbols(SymbolAdder Adder) {
}
}
}
void ELFContainer::AddUnwindEntries(UnwindAdder Adder) {
for (auto Entry : UnwindEntries) {
Adder(Entry);
}
}
void ELFContainer::PrintHeader() const {
if (Mode == MODE_32BIT) {
@@ -665,7 +730,7 @@ void ELFContainer::PrintHeader() const {
void ELFContainer::PrintSectionHeaders() const {
if (Mode == MODE_32BIT) {
LogMan::Throw::A(Header._32.e_shstrndx < SectionHeaders.size(),
LOGMAN_THROW_A(Header._32.e_shstrndx < SectionHeaders.size(),
"String index section is wrong index!");
Elf32_Shdr const *StrHeader = SectionHeaders.at(Header._32.e_shstrndx)._32;
char const *SHStrings = &RawFile.at(StrHeader->sh_offset);
@@ -685,7 +750,7 @@ void ELFContainer::PrintSectionHeaders() const {
}
}
else {
LogMan::Throw::A(Header._64.e_shstrndx < SectionHeaders.size(),
LOGMAN_THROW_A(Header._64.e_shstrndx < SectionHeaders.size(),
"String index section is wrong index!");
Elf64_Shdr const *StrHeader = SectionHeaders.at(Header._64.e_shstrndx)._64;
char const *SHStrings = &RawFile.at(StrHeader->sh_offset);
@@ -708,7 +773,7 @@ void ELFContainer::PrintSectionHeaders() const {
void ELFContainer::PrintProgramHeaders() const {
if (Mode == MODE_32BIT) {
LogMan::Throw::A(Header._32.e_shstrndx < SectionHeaders.size(),
LOGMAN_THROW_A(Header._32.e_shstrndx < SectionHeaders.size(),
"String index section is wrong index!");
for (uint32_t i = 0; i < ProgramHeaders.size(); ++i) {
Elf32_Phdr const *hdr = ProgramHeaders.at(i)._32;
@@ -723,7 +788,7 @@ void ELFContainer::PrintProgramHeaders() const {
}
}
else {
LogMan::Throw::A(Header._64.e_shstrndx < SectionHeaders.size(),
LOGMAN_THROW_A(Header._64.e_shstrndx < SectionHeaders.size(),
"String index section is wrong index!");
for (uint32_t i = 0; i < ProgramHeaders.size(); ++i) {
Elf64_Phdr const *hdr = ProgramHeaders.at(i)._64;
@@ -757,9 +822,9 @@ void ELFContainer::PrintSymbolTable() const {
return;
}
LogMan::Throw::A(SymTabHeader->sh_link < SectionHeaders.size(),
LOGMAN_THROW_A(SymTabHeader->sh_link < SectionHeaders.size(),
"Symbol table string table section is wrong");
LogMan::Throw::A(SymTabHeader->sh_entsize == sizeof(Elf32_Sym),
LOGMAN_THROW_A(SymTabHeader->sh_entsize == sizeof(Elf32_Sym),
"Entry size doesn't match symbol entry");
StringTableHeader = SectionHeaders.at(SymTabHeader->sh_link)._32;
@@ -795,9 +860,9 @@ void ELFContainer::PrintSymbolTable() const {
return;
}
LogMan::Throw::A(SymTabHeader->sh_link < SectionHeaders.size(),
LOGMAN_THROW_A(SymTabHeader->sh_link < SectionHeaders.size(),
"Symbol table string table section is wrong");
LogMan::Throw::A(SymTabHeader->sh_entsize == sizeof(Elf64_Sym),
LOGMAN_THROW_A(SymTabHeader->sh_entsize == sizeof(Elf64_Sym),
"Entry size doesn't match symbol entry");
StringTableHeader = SectionHeaders.at(SymTabHeader->sh_link)._64;
@@ -842,12 +907,12 @@ void ELFContainer::PrintRelocationTable() const {
LogMan::Msg::D("Relocation Section: '%s'", &SHStrings[RelaHeader->sh_name]);
if (RelaHeader->sh_info != 0) {
LogMan::Throw::A(RelaHeader->sh_info < SectionHeaders.size(), "Rela header pointers to invalid GOT header");
LOGMAN_THROW_A(RelaHeader->sh_info < SectionHeaders.size(), "Rela header pointers to invalid GOT header");
GOTHeader = SectionHeaders.at(RelaHeader->sh_info)._64;
}
if (RelaHeader->sh_link != 0) {
LogMan::Throw::A(RelaHeader->sh_link < SectionHeaders.size(), "Rela header pointers to invalid dyndym header");
LOGMAN_THROW_A(RelaHeader->sh_link < SectionHeaders.size(), "Rela header pointers to invalid dyndym header");
DynSymHeader = SectionHeaders.at(RelaHeader->sh_link)._64;
StringTableHeader = SectionHeaders.at(DynSymHeader->sh_link)._64;
@@ -865,7 +930,7 @@ void ELFContainer::PrintRelocationTable() const {
LogMan::Msg::D("\toffset: 0x%lx", Entry->r_offset);
LogMan::Msg::D("\tSym: 0x%lx", Sym);
if (DynSymHeader && Sym != 0) {
LogMan::Throw::A(DynSymHeader->sh_entsize == sizeof(Elf64_Sym), "Oops, entry size doesn't match");
LOGMAN_THROW_A(DynSymHeader->sh_entsize == sizeof(Elf64_Sym), "Oops, entry size doesn't match");
uint64_t offset = DynSymHeader->sh_offset + Sym * DynSymHeader->sh_entsize;
Elf64_Sym const *Symbol =
@@ -928,12 +993,12 @@ void ELFContainer::FixupRelocations(void *ELFBase, uint64_t GuestELFBase, Symbol
RelaHeader = hdr;
if (RelaHeader->sh_info != 0) {
LogMan::Throw::A(RelaHeader->sh_info < SectionHeaders.size(), "Rela header pointers to invalid GOT header");
LOGMAN_THROW_A(RelaHeader->sh_info < SectionHeaders.size(), "Rela header pointers to invalid GOT header");
GOTHeader = SectionHeaders.at(RelaHeader->sh_info)._64;
}
if (RelaHeader->sh_link != 0) {
LogMan::Throw::A(RelaHeader->sh_link < SectionHeaders.size(), "Rela header pointers to invalid dyndym header");
LOGMAN_THROW_A(RelaHeader->sh_link < SectionHeaders.size(), "Rela header pointers to invalid dyndym header");
DynSymHeader = SectionHeaders.at(RelaHeader->sh_link)._64;
StringTableHeader = SectionHeaders.at(DynSymHeader->sh_link)._64;
@@ -950,7 +1015,7 @@ void ELFContainer::FixupRelocations(void *ELFBase, uint64_t GuestELFBase, Symbol
Elf64_Sym const *EntrySymbol {nullptr};
char const *EntrySymbolName {nullptr};
if (DynSymHeader && Sym != 0) {
LogMan::Throw::A(DynSymHeader->sh_entsize == sizeof(Elf64_Sym), "Oops, entry size doesn't match");
LOGMAN_THROW_A(DynSymHeader->sh_entsize == sizeof(Elf64_Sym), "Oops, entry size doesn't match");
uint64_t offset = DynSymHeader->sh_offset + Sym * DynSymHeader->sh_entsize;
EntrySymbol =
@@ -1286,5 +1351,4 @@ void ELFContainer::GetInitLocations(uint64_t GuestELFBase, std::vector<uint64_t>
}
}
} // namespace ELFLoader
+5 -4
View File
@@ -6,6 +6,7 @@ $end_info$
*/
#include <FEXCore/Utils/ELFSymbolDatabase.h>
#include <FEXCore/Utils/Allocator.h>
#include <FEXCore/Utils/LogManager.h>
#include <FEXCore/Utils/Common/MathUtils.h>
@@ -82,7 +83,7 @@ ELFSymbolDatabase::ELFSymbolDatabase(::ELFLoader::ELFContainer *file)
if (NameToELF.find(Lib) == NameToELF.end()) {
std::string LibraryPath;
bool Found = FindLibraryFile(&LibraryPath, Lib.c_str());
LogMan::Throw::A(Found, "Couldn't find library '%s'", Lib.c_str());
LOGMAN_THROW_A(Found, "Couldn't find library '%s'", Lib.c_str());
auto Info = DynamicELFInfo.emplace_back(new ELFInfo{});
Info->Name = Lib;
Info->Container = new ::ELFLoader::ELFContainer(LibraryPath, {}, true);
@@ -110,7 +111,7 @@ ELFSymbolDatabase::ELFSymbolDatabase(::ELFLoader::ELFContainer *file)
FillSymbols();
if (LocalInfo.Container->WasDynamic() && File->GetMode() == ELFContainer::MODE_64BIT) {
ELFBase = mmap(nullptr, ELFMemorySize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
ELFBase = FEXCore::Allocator::mmap(nullptr, ELFMemorySize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
FillMemoryLayouts(reinterpret_cast<uintptr_t>(ELFBase));
FillInitializationOrder();
FillSymbols();
@@ -121,7 +122,7 @@ ELFSymbolDatabase::ELFSymbolDatabase(::ELFLoader::ELFContainer *file)
ELFSymbolDatabase::~ELFSymbolDatabase() {
if (ELFBase) {
munmap(ELFBase, ELFMemorySize);
FEXCore::Allocator::munmap(ELFBase, ELFMemorySize);
ELFBase = nullptr;
}
}
@@ -164,7 +165,7 @@ void ELFSymbolDatabase::FillMemoryLayouts(uint64_t DefinedBase) {
uint64_t CurrentELFAlignedSize = AlignUp(std::get<2>(LocalInfo.CustomLayout), 4096);
if (CurrentELFBase < 0x10000) {
// We can't allocate memory in the first 16KB, Hopefully no elfs require this.
LogMan::Msg::A("Elf requires memory mapped in the first 16kb");
LOGMAN_MSG_A("Elf requires memory mapped in the first 16kb");
}
std::get<2>(LocalInfo.CustomLayout) = CurrentELFAlignedSize;
+68 -1
View File
@@ -1,15 +1,59 @@
#include <FEXCore/Utils/Allocator.h>
#include <FEXCore/Utils/LogManager.h>
#include <FEXCore/Utils/Threads.h>
#include <cstring>
#include <mutex>
#include <pthread.h>
#include <sys/mman.h>
#include <deque>
namespace FEXCore::Threads {
// Stack pool handling
struct StackPoolItem {
void *Ptr;
size_t Size;
};
std::mutex StackPoolMutex{};
std::deque<StackPoolItem> StackPool;
void *AllocateStackObject(size_t Size) {
std::unique_lock<std::mutex> lk{StackPoolMutex};
if (StackPool.size() == 0) {
// Nothing in the pool, just allocate
return FEXCore::Allocator::mmap(nullptr, Size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_GROWSDOWN, -1, 0);
}
// Keep the first item in the stack pool
auto Result = StackPool.front().Ptr;
StackPool.pop_front();
// Erase the rest as a garbage collection step
for (auto &Item : StackPool) {
FEXCore::Allocator::munmap(Item.Ptr, Item.Size);
}
return Result;
}
void AddStackToPool(void *Ptr, size_t Size) {
std::unique_lock<std::mutex> lk{StackPoolMutex};
StackPool.emplace_back(StackPoolItem{Ptr, Size});
}
void *InitializeThread(void *Ptr);
class PThread final : public Thread {
public:
PThread(FEXCore::Threads::ThreadFunc Func, void *Arg) {
PThread(FEXCore::Threads::ThreadFunc Func, void *Arg)
: UserFunc {Func}
, UserArg {Arg} {
pthread_attr_t Attr{};
Stack = AllocateStackObject(STACK_SIZE);
pthread_attr_init(&Attr);
pthread_attr_setstack(&Attr, Stack, STACK_SIZE);
pthread_create(&Thread, &Attr, Func, Arg);
pthread_attr_destroy(&Attr);
}
bool joinable() override {
@@ -38,10 +82,33 @@ namespace FEXCore::Threads {
return self == Thread;
}
void *Execute() {
return UserFunc(UserArg);
}
void FreeStack() {
AddStackToPool(Stack, STACK_SIZE);
}
private:
pthread_t Thread;
FEXCore::Threads::ThreadFunc UserFunc;
void *UserArg;
void *Stack{};
constexpr static size_t STACK_SIZE = 8 * 1024 * 1024;
};
void *InitializeThread(void *Ptr) {
PThread *Thread{reinterpret_cast<PThread*>(Ptr)};
// Run the user function
void *Result = Thread->Execute();
// Put the stack back in to the stack pool
Thread->FreeStack();
return Result;
}
std::unique_ptr<FEXCore::Threads::Thread> CreateThread_PThread(
ThreadFunc Func,
void* Arg) {
+21 -20
View File
@@ -54,15 +54,15 @@ namespace Type {
#undef P
}
std::string GetDataDirectory();
std::string GetConfigDirectory(bool Global);
std::string GetConfigFileLocation();
std::string GetApplicationConfig(std::string &Filename, bool Global);
__attribute__((visibility("default"))) std::string GetDataDirectory();
__attribute__((visibility("default"))) std::string GetConfigDirectory(bool Global);
__attribute__((visibility("default"))) std::string GetConfigFileLocation();
__attribute__((visibility("default"))) std::string GetApplicationConfig(std::string &Filename, bool Global);
using LayerValue = std::list<std::string>;
using LayerOptions = std::unordered_map<ConfigOption, LayerValue>;
class Layer {
class __attribute__((visibility("default"))) Layer {
public:
explicit Layer(const LayerType _Type);
virtual ~Layer();
@@ -102,35 +102,36 @@ namespace Type {
OptionMap[Option].emplace_back(Data);
}
void Erase(ConfigOption Option) {
OptionMap.erase(Option);
}
const LayerType GetLayerType() const { return Type; }
const LayerOptions &GetOptionMap() { return OptionMap; }
protected:
const LayerType Type;
LayerOptions OptionMap;
void Erase(ConfigOption Option) {
OptionMap.erase(Option);
}
};
void Initialize();
void Shutdown();
__attribute__((visibility("default"))) void Initialize();
__attribute__((visibility("default"))) void Shutdown();
void Load();
void ReloadMetaLayer();
__attribute__((visibility("default"))) void Load();
__attribute__((visibility("default"))) void ReloadMetaLayer();
void AddLayer(std::unique_ptr<FEXCore::Config::Layer> _Layer);
__attribute__((visibility("default"))) void AddLayer(std::unique_ptr<FEXCore::Config::Layer> _Layer);
bool Exists(ConfigOption Option);
std::optional<LayerValue*> All(ConfigOption Option);
std::optional<std::string*> Get(ConfigOption Option);
__attribute__((visibility("default"))) bool Exists(ConfigOption Option);
__attribute__((visibility("default"))) std::optional<LayerValue*> All(ConfigOption Option);
__attribute__((visibility("default"))) std::optional<std::string*> Get(ConfigOption Option);
void Set(ConfigOption Option, std::string Data);
void EraseSet(ConfigOption Option, std::string Data);
__attribute__((visibility("default"))) void Set(ConfigOption Option, std::string Data);
__attribute__((visibility("default"))) void Erase(ConfigOption Option);
__attribute__((visibility("default"))) void EraseSet(ConfigOption Option, std::string Data);
template<typename T>
class Value {
class __attribute__((visibility("default"))) Value {
public:
template <typename TT = T,
typename std::enable_if<!std::is_same<TT, std::string>::value, int>::type = 0>
+1 -1
View File
@@ -51,7 +51,7 @@ class LLVMCore;
* @return An executable function pointer that is theoretically compiled from this point.
* Is actually a function pointer of type `void (FEXCore::Core::ThreadState *Thread)
*/
virtual void *CompileCode(FEXCore::IR::IRListView const *IR, FEXCore::Core::DebugData *DebugData, FEXCore::IR::RegisterAllocationData *RAData) = 0;
virtual void *CompileCode(uint64_t Entry, FEXCore::IR::IRListView const *IR, FEXCore::Core::DebugData *DebugData, FEXCore::IR::RegisterAllocationData *RAData) = 0;
/**
* @brief Function for mapping memory in to the CPUBackend's visible space. Allows setting up virtual mappings if required
+7 -36
View File
@@ -1,6 +1,7 @@
#pragma once
#include <cstdint>
#include <functional>
#include <string>
#include <vector>
namespace FEXCore {
@@ -20,53 +21,23 @@ public:
* @brief CPU Core uses this to choose what the stack size should be for this code
*/
virtual uint64_t StackSize() const = 0;
/**
* @brief Allows the code loader to set up the stack the way it wants
*
* @param HostPtr The host facing pointer to the base of the stack.
* Size of memory will be at least the size that StackSize() returns
*
* @param GuestPtr The guest facing memory location where the base of the stack lives
*
* @return The location that the guest stack pointer register should be set to
*
* Probably will be GuestPtr + StackSize() - <Some amount>
* Returns the initial stack pointer
*/
virtual uint64_t SetupStack() = 0;
virtual uint64_t GetStackPointer() = 0;
/**
* @brief Function to return the guest RIP that the code should start out at
*/
virtual uint64_t DefaultRIP() const = 0;
virtual void GetInitLocations(std::vector<uint64_t> *Locations) {}
/**
* @brief Allows the loader to map memory regions that it needs
*
* Code loader is expected to call the Mapper function with a memory offset and size for mapping
*
* @param Mapper Returns the host facing pointer for memory setup if the codfe loader needs to do things to it
* @brief Maps and copies the executable, also sets up stack
*/
virtual void MapMemoryRegion() {}
virtual bool MapMemory(std::function<void *(void *addr, size_t length, int prot, int flags, int fd, off_t offset)> Mapper, std::function<int(void *addr, size_t length)> Unmapper) { return false; }
/**
* @brief Memory writer function for loading code in to guest memory
*
* First argument = Data to write
* Second argument = Guest memory data location
* Third argument = Guest memory size
*/
virtual void LoadMemory() = 0;
/**
* @brief Get the final RIP we are supposed to end up on in a debugger
*
* @return When the debugger reaches this RIP then we know that we have completed
*/
virtual uint64_t GetFinalRIP() { return ~0ULL; }
virtual char const *FindSymbolNameInRange(uint64_t Address) { return nullptr; }
virtual std::vector<std::string> const *GetApplicationArguments() { return nullptr; }
virtual void GetExecveArguments(std::vector<char const*> *Args) {}
virtual void GetAuxv(uint64_t& addr, uint64_t& size) {}
+43 -37
View File
@@ -9,6 +9,7 @@
#include <istream>
#include <ostream>
#include <memory>
#include <set>
namespace FEXCore {
class CodeLoader;
@@ -49,7 +50,7 @@ namespace FEXCore::Context {
/**
* @brief This initializes internal FEXCore state that is shared between contexts and requires overhead to setup
*/
void InitializeStaticTables(OperatingMode Mode = MODE_64BIT);
__attribute__((visibility("default"))) void InitializeStaticTables(OperatingMode Mode = MODE_64BIT);
/**
* @brief [[threadsafe]] Create a new FEXCore context object
@@ -58,7 +59,7 @@ namespace FEXCore::Context {
*
* @return a new context object
*/
FEXCore::Context::Context *CreateNewContext();
__attribute__((visibility("default"))) FEXCore::Context::Context *CreateNewContext();
/**
* @brief Post creation context initialization
@@ -68,14 +69,14 @@ namespace FEXCore::Context {
*
* @return true if we managed to initialize correctly
*/
bool InitializeContext(FEXCore::Context::Context *CTX);
__attribute__((visibility("default"))) bool InitializeContext(FEXCore::Context::Context *CTX);
/**
* @brief Destroy the context object
*
* @param CTX
*/
void DestroyContext(FEXCore::Context::Context *CTX);
__attribute__((visibility("default"))) void DestroyContext(FEXCore::Context::Context *CTX);
/**
* @brief Allows setting up in memory code and other things prior to launchign code execution
@@ -85,17 +86,17 @@ namespace FEXCore::Context {
*
* @return true if we loaded code
*/
bool InitCore(FEXCore::Context::Context *CTX, FEXCore::CodeLoader *Loader);
__attribute__((visibility("default"))) bool InitCore(FEXCore::Context::Context *CTX, FEXCore::CodeLoader *Loader);
void SetExitHandler(FEXCore::Context::Context *CTX, std::function<void(uint64_t ThreadId, FEXCore::Context::ExitReason)> handler);
std::function<void(uint64_t ThreadId, FEXCore::Context::ExitReason)> GetExitHandler(FEXCore::Context::Context *CTX);
__attribute__((visibility("default"))) void SetExitHandler(FEXCore::Context::Context *CTX, std::function<void(uint64_t ThreadId, FEXCore::Context::ExitReason)> handler);
__attribute__((visibility("default"))) std::function<void(uint64_t ThreadId, FEXCore::Context::ExitReason)> GetExitHandler(FEXCore::Context::Context *CTX);
/**
* @brief Pauses execution on the CPU core
*
* Blocks until all threads have paused.
*/
void Pause(FEXCore::Context::Context *CTX);
__attribute__((visibility("default"))) void Pause(FEXCore::Context::Context *CTX);
/**
* @brief Starts (or continues) the CPU core
@@ -104,7 +105,7 @@ namespace FEXCore::Context {
* Use RunUntilExit() for synchonous executions
*
*/
void Run(FEXCore::Context::Context *CTX);
__attribute__((visibility("default"))) void Run(FEXCore::Context::Context *CTX);
/**
* @brief Runs the CPU core until it exits
@@ -116,7 +117,9 @@ namespace FEXCore::Context {
*
* @return The ExitReason for the parentthread.
*/
ExitReason RunUntilExit(FEXCore::Context::Context *CTX);
__attribute__((visibility("default"))) ExitReason RunUntilExit(FEXCore::Context::Context *CTX);
__attribute__((visibility("default"))) void CompileRIP(FEXCore::Context::Context *CTX, uint64_t GuestRIP);
/**
* @brief Gets the program exit status
@@ -126,21 +129,21 @@ namespace FEXCore::Context {
*
* @return The program exit status
*/
int GetProgramStatus(FEXCore::Context::Context *CTX);
__attribute__((visibility("default"))) int GetProgramStatus(FEXCore::Context::Context *CTX);
/**
* @brief Tells the core to shutdown
*
* Blocks until shutdown
*/
void Stop(FEXCore::Context::Context *CTX);
__attribute__((visibility("default"))) void Stop(FEXCore::Context::Context *CTX);
/**
* @brief Executes one instruction
*
* Returns once execution is complete.
*/
void Step(FEXCore::Context::Context *CTX);
__attribute__((visibility("default"))) void Step(FEXCore::Context::Context *CTX);
/**
* @brief [[threadsafe]] Returns the ExitReason of the parent thread. Typically used for async result status
@@ -149,7 +152,7 @@ namespace FEXCore::Context {
*
* @return The ExitReason for the parentthread
*/
ExitReason GetExitReason(FEXCore::Context::Context *CTX);
__attribute__((visibility("default"))) ExitReason GetExitReason(FEXCore::Context::Context *CTX);
/**
* @brief [[theadsafe]] Checks if the Context is either done working or paused(in the case of single stepping)
@@ -160,7 +163,7 @@ namespace FEXCore::Context {
*
* @return true if the core is done or paused
*/
bool IsDone(FEXCore::Context::Context *CTX);
__attribute__((visibility("default"))) bool IsDone(FEXCore::Context::Context *CTX);
/**
* @brief Gets a copy the CPUState of the parent thread
@@ -168,7 +171,7 @@ namespace FEXCore::Context {
* @param CTX The context that we created
* @param State The state object to populate
*/
void GetCPUState(FEXCore::Context::Context *CTX, FEXCore::Core::CPUState *State);
__attribute__((visibility("default"))) void GetCPUState(FEXCore::Context::Context *CTX, FEXCore::Core::CPUState *State);
/**
* @brief Copies the CPUState provided to the parent thread
@@ -176,7 +179,7 @@ namespace FEXCore::Context {
* @param CTX The context that we created
* @param State The satate object to copy from
*/
void SetCPUState(FEXCore::Context::Context *CTX, FEXCore::Core::CPUState *State);
__attribute__((visibility("default"))) void SetCPUState(FEXCore::Context::Context *CTX, FEXCore::Core::CPUState *State);
/**
* @brief Allows the frontend to pass in a custom CPUBackend creation factory
@@ -186,7 +189,7 @@ namespace FEXCore::Context {
* @param CTX The context that we created
* @param Factory The factory that the context will call if the DefaultCore config ise set to CUSTOM
*/
void SetCustomCPUBackendFactory(FEXCore::Context::Context *CTX, CustomCPUFactoryType Factory);
__attribute__((visibility("default"))) void SetCustomCPUBackendFactory(FEXCore::Context::Context *CTX, CustomCPUFactoryType Factory);
/**
* @brief Sets up memory regions on the guest for mirroring within the guest's VM space
@@ -197,7 +200,7 @@ namespace FEXCore::Context {
*
* @return true when successfully mapped. false if there was an error adding
*/
bool AddVirtualMemoryMapping(FEXCore::Context::Context *CTX, uint64_t VirtualAddress, uint64_t PhysicalAddress, uint64_t Size);
__attribute__((visibility("default"))) bool AddVirtualMemoryMapping(FEXCore::Context::Context *CTX, uint64_t VirtualAddress, uint64_t PhysicalAddress, uint64_t Size);
/**
* @brief Allows the frontend to set a custom syscall handler
@@ -207,26 +210,29 @@ namespace FEXCore::Context {
* @param Syscall Which syscall ID to install a visitor to
* @param Visitor The Visitor to install
*/
void RegisterExternalSyscallVisitor(FEXCore::Context::Context *CTX, uint64_t Syscall, FEXCore::HLE::SyscallVisitor *Visitor);
__attribute__((visibility("default"))) void RegisterExternalSyscallVisitor(FEXCore::Context::Context *CTX, uint64_t Syscall, FEXCore::HLE::SyscallVisitor *Visitor);
void HandleCallback(FEXCore::Context::Context *CTX, uint64_t RIP);
__attribute__((visibility("default"))) void HandleCallback(FEXCore::Context::Context *CTX, uint64_t RIP);
void RegisterHostSignalHandler(FEXCore::Context::Context *CTX, int Signal, HostSignalDelegatorFunction Func);
void RegisterFrontendHostSignalHandler(FEXCore::Context::Context *CTX, int Signal, HostSignalDelegatorFunction Func);
__attribute__((visibility("default"))) void RegisterHostSignalHandler(FEXCore::Context::Context *CTX, int Signal, HostSignalDelegatorFunction Func);
__attribute__((visibility("default"))) void RegisterFrontendHostSignalHandler(FEXCore::Context::Context *CTX, int Signal, HostSignalDelegatorFunction Func);
FEXCore::Core::InternalThreadState* CreateThread(FEXCore::Context::Context *CTX, FEXCore::Core::CPUState *NewThreadState, uint64_t ParentTID);
void InitializeThread(FEXCore::Context::Context *CTX, FEXCore::Core::InternalThreadState *Thread);
void RunThread(FEXCore::Context::Context *CTX, FEXCore::Core::InternalThreadState *Thread);
void StopThread(FEXCore::Context::Context *CTX, FEXCore::Core::InternalThreadState *Thread);
void DestroyThread(FEXCore::Context::Context *CTX, FEXCore::Core::InternalThreadState *Thread);
void CleanupAfterFork(FEXCore::Context::Context *CTX, FEXCore::Core::InternalThreadState *Thread);
void SetSignalDelegator(FEXCore::Context::Context *CTX, FEXCore::SignalDelegator *SignalDelegation);
void SetSyscallHandler(FEXCore::Context::Context *CTX, FEXCore::HLE::SyscallHandler *Handler);
FEXCore::CPUID::FunctionResults RunCPUIDFunction(FEXCore::Context::Context *CTX, uint32_t Function, uint32_t Leaf);
__attribute__((visibility("default"))) FEXCore::Core::InternalThreadState* CreateThread(FEXCore::Context::Context *CTX, FEXCore::Core::CPUState *NewThreadState, uint64_t ParentTID);
__attribute__((visibility("default"))) void InitializeThread(FEXCore::Context::Context *CTX, FEXCore::Core::InternalThreadState *Thread);
__attribute__((visibility("default"))) void RunThread(FEXCore::Context::Context *CTX, FEXCore::Core::InternalThreadState *Thread);
__attribute__((visibility("default"))) void StopThread(FEXCore::Context::Context *CTX, FEXCore::Core::InternalThreadState *Thread);
__attribute__((visibility("default"))) void DestroyThread(FEXCore::Context::Context *CTX, FEXCore::Core::InternalThreadState *Thread);
__attribute__((visibility("default"))) void CleanupAfterFork(FEXCore::Context::Context *CTX, FEXCore::Core::InternalThreadState *Thread);
__attribute__((visibility("default"))) void SetSignalDelegator(FEXCore::Context::Context *CTX, FEXCore::SignalDelegator *SignalDelegation);
__attribute__((visibility("default"))) void SetSyscallHandler(FEXCore::Context::Context *CTX, FEXCore::HLE::SyscallHandler *Handler);
__attribute__((visibility("default"))) FEXCore::CPUID::FunctionResults RunCPUIDFunction(FEXCore::Context::Context *CTX, uint32_t Function, uint32_t Leaf);
void AddNamedRegion(FEXCore::Context::Context *CTX, uintptr_t Base, uintptr_t Length, uintptr_t Offset, const std::string& Name);
void RemoveNamedRegion(FEXCore::Context::Context *CTX, uintptr_t Base, uintptr_t Length);
void SetAOTIRLoader(FEXCore::Context::Context *CTX, std::function<std::unique_ptr<std::istream>(const std::string&)> CacheReader);
bool WriteAOTIR(FEXCore::Context::Context *CTX, std::function<std::unique_ptr<std::ostream>(const std::string&)> CacheWriter);
void FlushCodeRange(FEXCore::Core::InternalThreadState *Thread, uint64_t Start, uint64_t Length);
__attribute__((visibility("default"))) void AddNamedRegion(FEXCore::Context::Context *CTX, uintptr_t Base, uintptr_t Length, uintptr_t Offset, const std::string& Name);
__attribute__((visibility("default"))) void RemoveNamedRegion(FEXCore::Context::Context *CTX, uintptr_t Base, uintptr_t Length);
__attribute__((visibility("default"))) void SetAOTIRLoader(FEXCore::Context::Context *CTX, std::function<int(const std::string&)> CacheReader);
__attribute__((visibility("default"))) bool WriteAOTIR(FEXCore::Context::Context *CTX, std::function<std::unique_ptr<std::ostream>(const std::string&)> CacheWriter);
__attribute__((visibility("default"))) void WriteFilesWithCode(FEXCore::Context::Context *CTX, std::function<void(const std::string& fileid, const std::string& filename)> Writer);
__attribute__((visibility("default"))) void FlushCodeRange(FEXCore::Core::InternalThreadState *Thread, uint64_t Start, uint64_t Length);
__attribute__((visibility("default"))) void ConfigureAOTGen(FEXCore::Context::Context *CTX, std::set<uint64_t> *ExternalBranches, uint64_t SectionMaxAddress);
}
+2 -2
View File
@@ -51,6 +51,6 @@ namespace FEXCore::Core {
constexpr uint64_t PAGE_SIZE = 4096;
std::string_view const& GetFlagName(unsigned Flag);
std::string_view const& GetGRegName(unsigned Reg);
__attribute__((visibility("default"))) std::string_view const& GetFlagName(unsigned Flag);
__attribute__((visibility("default"))) std::string_view const& GetGRegName(unsigned Reg);
}
+18 -18
View File
@@ -455,29 +455,29 @@ constexpr size_t MAX_XOP_GROUP_TABLE_SIZE = (1 << 6);
constexpr size_t MAX_EVEX_TABLE_SIZE = 256;
extern X86InstInfo BaseOps[MAX_PRIMARY_TABLE_SIZE];
extern X86InstInfo SecondBaseOps[MAX_SECOND_TABLE_SIZE];
extern X86InstInfo RepModOps[MAX_REP_MOD_TABLE_SIZE];
extern X86InstInfo RepNEModOps[MAX_REPNE_MOD_TABLE_SIZE];
extern X86InstInfo OpSizeModOps[MAX_OPSIZE_MOD_TABLE_SIZE];
extern X86InstInfo PrimaryInstGroupOps[MAX_INST_GROUP_TABLE_SIZE];
extern X86InstInfo SecondInstGroupOps[MAX_INST_SECOND_GROUP_TABLE_SIZE];
extern X86InstInfo SecondModRMTableOps[MAX_SECOND_MODRM_TABLE_SIZE];
extern X86InstInfo X87Ops[MAX_X87_TABLE_SIZE];
extern X86InstInfo DDDNowOps[MAX_3DNOW_TABLE_SIZE];
extern X86InstInfo H0F38TableOps[MAX_0F_38_TABLE_SIZE];
extern X86InstInfo H0F3ATableOps[MAX_0F_3A_TABLE_SIZE];
extern __attribute__((visibility("default"))) X86InstInfo BaseOps[MAX_PRIMARY_TABLE_SIZE];
extern __attribute__((visibility("default"))) X86InstInfo SecondBaseOps[MAX_SECOND_TABLE_SIZE];
extern __attribute__((visibility("default"))) X86InstInfo RepModOps[MAX_REP_MOD_TABLE_SIZE];
extern __attribute__((visibility("default"))) X86InstInfo RepNEModOps[MAX_REPNE_MOD_TABLE_SIZE];
extern __attribute__((visibility("default"))) X86InstInfo OpSizeModOps[MAX_OPSIZE_MOD_TABLE_SIZE];
extern __attribute__((visibility("default"))) X86InstInfo PrimaryInstGroupOps[MAX_INST_GROUP_TABLE_SIZE];
extern __attribute__((visibility("default"))) X86InstInfo SecondInstGroupOps[MAX_INST_SECOND_GROUP_TABLE_SIZE];
extern __attribute__((visibility("default"))) X86InstInfo SecondModRMTableOps[MAX_SECOND_MODRM_TABLE_SIZE];
extern __attribute__((visibility("default"))) X86InstInfo X87Ops[MAX_X87_TABLE_SIZE];
extern __attribute__((visibility("default"))) X86InstInfo DDDNowOps[MAX_3DNOW_TABLE_SIZE];
extern __attribute__((visibility("default"))) X86InstInfo H0F38TableOps[MAX_0F_38_TABLE_SIZE];
extern __attribute__((visibility("default"))) X86InstInfo H0F3ATableOps[MAX_0F_3A_TABLE_SIZE];
// VEX
extern X86InstInfo VEXTableOps[MAX_VEX_TABLE_SIZE];
extern X86InstInfo VEXTableGroupOps[MAX_VEX_GROUP_TABLE_SIZE];
extern __attribute__((visibility("default"))) X86InstInfo VEXTableOps[MAX_VEX_TABLE_SIZE];
extern __attribute__((visibility("default"))) X86InstInfo VEXTableGroupOps[MAX_VEX_GROUP_TABLE_SIZE];
// XOP
extern X86InstInfo XOPTableOps[MAX_XOP_TABLE_SIZE];
extern X86InstInfo XOPTableGroupOps[MAX_XOP_GROUP_TABLE_SIZE];
extern __attribute__((visibility("default"))) X86InstInfo XOPTableOps[MAX_XOP_TABLE_SIZE];
extern __attribute__((visibility("default"))) X86InstInfo XOPTableGroupOps[MAX_XOP_GROUP_TABLE_SIZE];
// EVEX
extern X86InstInfo EVEXTableOps[MAX_EVEX_TABLE_SIZE];
extern __attribute__((visibility("default"))) X86InstInfo EVEXTableOps[MAX_EVEX_TABLE_SIZE];
void InitializeInfoTables(Context::OperatingMode Mode);
__attribute__((visibility("default"))) void InitializeInfoTables(Context::OperatingMode Mode);
}
+1 -1
View File
@@ -3,7 +3,7 @@
#include <stdint.h>
namespace FEXCore::HLE {
#define INVALID_OP { LogMan::Msg::A("Tried to syscall with unknown number of registers"); return 0; }
#define INVALID_OP { LOGMAN_MSG_A("Tried to syscall with unknown number of registers"); return 0; }
class SyscallVisitor {
public:
SyscallVisitor(uint32_t Mask) : SyscallVisitor(Mask, false) {}
+2 -4
View File
@@ -240,13 +240,11 @@ class OrderedNode final {
}
static void SetPrevious(uintptr_t Base, value_type Node, value_type New) {
if (Node.NodeOffset == 0) return;
OrderedNode *RealNode = Node.GetNode(Base);
RealNode->Header.Previous = New;
}
static void SetNext(uintptr_t Base, value_type Node, value_type New) {
if (Node.NodeOffset == 0) return;
OrderedNode *RealNode = Node.GetNode(Base);
RealNode->Header.Next = New;
}
@@ -465,8 +463,8 @@ public:
class IRListView;
class IREmitter;
void Dump(std::stringstream *out, IRListView const* IR, IR::RegisterAllocationData *RAData);
IREmitter* Parse(std::istream *in);
__attribute__((visibility("default"))) void Dump(std::stringstream *out, IRListView const* IR, IR::RegisterAllocationData *RAData);
__attribute__((visibility("default"))) IREmitter* Parse(std::istream *in);
template<typename Type>
inline uint32_t NodeWrapperBase<Type>::ID() const { return NodeOffset / sizeof(IR::OrderedNode); }
+63 -66
View File
@@ -16,13 +16,12 @@ friend class FEXCore::IR::PassManager;
public:
IREmitter()
: Data {8 * 1024 * 1024}
, ListData {8 * 1024 * 1024} {
: DualListData {8 * 1024 * 1024} {
ResetWorkingList();
}
IRListView ViewIR() { return IRListView(&Data, &ListData, false); }
IRListView *CreateIRCopy() { return new IRListView(&Data, &ListData, true); }
IRListView ViewIR() { return IRListView(&DualListData, false); }
IRListView *CreateIRCopy() { return new IRListView(&DualListData, true); }
void ResetWorkingList();
/**
@@ -54,7 +53,7 @@ friend class FEXCore::IR::PassManager;
Op.first->Header.ElementSize = ElementSize;
Op.first->Header.NumArgs = 1;
Op.first->Header.HasDest = true;
Op.first->Header.Args[0] = ssa0->Wrapped(ListData.Begin());
Op.first->Header.Args[0] = ssa0->Wrapped(DualListData.ListBegin());
ssa0->AddUse();
return Op;
}
@@ -364,72 +363,72 @@ friend class FEXCore::IR::PassManager;
void AddPhiValue(IR::IROp_Phi *Phi, OrderedNode *Value) {
// Got to do some bookkeeping first
Value->AddUse();
auto ValueIROp = Value->Op(Data.Begin())->C<IR::IROp_PhiValue>()->Value.GetNode(ListData.Begin())->Op(Data.Begin());
auto ValueIROp = Value->Op(DualListData.DataBegin())->C<IR::IROp_PhiValue>()->Value.GetNode(DualListData.ListBegin())->Op(DualListData.DataBegin());
Phi->Header.Size = ValueIROp->Size;
Phi->Header.ElementSize = ValueIROp->ElementSize;
if (!Phi->PhiBegin.ID()) {
Phi->PhiBegin = Phi->PhiEnd = Value->Wrapped(ListData.Begin());
Phi->PhiBegin = Phi->PhiEnd = Value->Wrapped(DualListData.ListBegin());
return;
}
auto PhiValueEndNode = Phi->PhiEnd.GetNode(ListData.Begin());
auto PhiValueEndOp = PhiValueEndNode->Op(Data.Begin())->CW<IR::IROp_PhiValue>();
PhiValueEndOp->Next = Value->Wrapped(ListData.Begin());
auto PhiValueEndNode = Phi->PhiEnd.GetNode(DualListData.ListBegin());
auto PhiValueEndOp = PhiValueEndNode->Op(DualListData.DataBegin())->CW<IR::IROp_PhiValue>();
PhiValueEndOp->Next = Value->Wrapped(DualListData.ListBegin());
}
void SetJumpTarget(IR::IROp_Jump *Op, OrderedNode *Target) {
LogMan::Throw::A(Target->Op(Data.Begin())->Op == OP_CODEBLOCK,
LOGMAN_THROW_A(Target->Op(DualListData.DataBegin())->Op == OP_CODEBLOCK,
"Tried setting Jump target to %%ssa%d %s",
Target->Wrapped(ListData.Begin()).ID(),
std::string(IR::GetName(Target->Op(Data.Begin())->Op)).c_str());
Target->Wrapped(DualListData.ListBegin()).ID(),
std::string(IR::GetName(Target->Op(DualListData.DataBegin())->Op)).c_str());
Op->Header.Args[0].NodeOffset = Target->Wrapped(ListData.Begin()).NodeOffset;
Op->Header.Args[0].NodeOffset = Target->Wrapped(DualListData.ListBegin()).NodeOffset;
}
void SetTrueJumpTarget(IR::IROp_CondJump *Op, OrderedNode *Target) {
LogMan::Throw::A(Target->Op(Data.Begin())->Op == OP_CODEBLOCK,
LOGMAN_THROW_A(Target->Op(DualListData.DataBegin())->Op == OP_CODEBLOCK,
"Tried setting CondJump target to %%ssa%d %s",
Target->Wrapped(ListData.Begin()).ID(),
std::string(IR::GetName(Target->Op(Data.Begin())->Op)).c_str());
Target->Wrapped(DualListData.ListBegin()).ID(),
std::string(IR::GetName(Target->Op(DualListData.DataBegin())->Op)).c_str());
Op->TrueBlock.NodeOffset = Target->Wrapped(ListData.Begin()).NodeOffset;
Op->TrueBlock.NodeOffset = Target->Wrapped(DualListData.ListBegin()).NodeOffset;
}
void SetFalseJumpTarget(IR::IROp_CondJump *Op, OrderedNode *Target) {
LogMan::Throw::A(Target->Op(Data.Begin())->Op == OP_CODEBLOCK,
LOGMAN_THROW_A(Target->Op(DualListData.DataBegin())->Op == OP_CODEBLOCK,
"Tried setting CondJump target to %%ssa%d %s",
Target->Wrapped(ListData.Begin()).ID(),
std::string(IR::GetName(Target->Op(Data.Begin())->Op)).c_str());
Target->Wrapped(DualListData.ListBegin()).ID(),
std::string(IR::GetName(Target->Op(DualListData.DataBegin())->Op)).c_str());
Op->FalseBlock.NodeOffset = Target->Wrapped(ListData.Begin()).NodeOffset;
Op->FalseBlock.NodeOffset = Target->Wrapped(DualListData.ListBegin()).NodeOffset;
}
void SetJumpTarget(IRPair<IROp_Jump> Op, OrderedNode *Target) {
LogMan::Throw::A(Target->Op(Data.Begin())->Op == OP_CODEBLOCK,
LOGMAN_THROW_A(Target->Op(DualListData.DataBegin())->Op == OP_CODEBLOCK,
"Tried setting Jump target to %%ssa%d %s",
Target->Wrapped(ListData.Begin()).ID(),
std::string(IR::GetName(Target->Op(Data.Begin())->Op)).c_str());
Target->Wrapped(DualListData.ListBegin()).ID(),
std::string(IR::GetName(Target->Op(DualListData.DataBegin())->Op)).c_str());
Op.first->Header.Args[0].NodeOffset = Target->Wrapped(ListData.Begin()).NodeOffset;
Op.first->Header.Args[0].NodeOffset = Target->Wrapped(DualListData.ListBegin()).NodeOffset;
}
void SetTrueJumpTarget(IRPair<IROp_CondJump> Op, OrderedNode *Target) {
LogMan::Throw::A(Target->Op(Data.Begin())->Op == OP_CODEBLOCK,
LOGMAN_THROW_A(Target->Op(DualListData.DataBegin())->Op == OP_CODEBLOCK,
"Tried setting CondJump target to %%ssa%d %s",
Target->Wrapped(ListData.Begin()).ID(),
std::string(IR::GetName(Target->Op(Data.Begin())->Op)).c_str());
Op.first->TrueBlock.NodeOffset = Target->Wrapped(ListData.Begin()).NodeOffset;
Target->Wrapped(DualListData.ListBegin()).ID(),
std::string(IR::GetName(Target->Op(DualListData.DataBegin())->Op)).c_str());
Op.first->TrueBlock.NodeOffset = Target->Wrapped(DualListData.ListBegin()).NodeOffset;
}
void SetFalseJumpTarget(IRPair<IROp_CondJump> Op, OrderedNode *Target) {
LogMan::Throw::A(Target->Op(Data.Begin())->Op == OP_CODEBLOCK,
LOGMAN_THROW_A(Target->Op(DualListData.DataBegin())->Op == OP_CODEBLOCK,
"Tried setting CondJump target to %%ssa%d %s",
Target->Wrapped(ListData.Begin()).ID(),
std::string(IR::GetName(Target->Op(Data.Begin())->Op)).c_str());
Op.first->FalseBlock.NodeOffset = Target->Wrapped(ListData.Begin()).NodeOffset;
Target->Wrapped(DualListData.ListBegin()).ID(),
std::string(IR::GetName(Target->Op(DualListData.DataBegin())->Op)).c_str());
Op.first->FalseBlock.NodeOffset = Target->Wrapped(DualListData.ListBegin()).NodeOffset;
}
/** @} */
bool IsValueConstant(OrderedNodeWrapper ssa, uint64_t *Constant = nullptr) {
OrderedNode *RealNode = ssa.GetNode(ListData.Begin());
FEXCore::IR::IROp_Header *IROp = RealNode->Op(Data.Begin());
OrderedNode *RealNode = ssa.GetNode(DualListData.ListBegin());
FEXCore::IR::IROp_Header *IROp = RealNode->Op(DualListData.DataBegin());
if (IROp->Op == OP_CONSTANT) {
auto Op = IROp->C<IR::IROp_Constant>();
if (Constant) *Constant = Op->Constant;
@@ -439,8 +438,8 @@ friend class FEXCore::IR::PassManager;
}
bool IsValueInlineConstant(OrderedNodeWrapper ssa) {
OrderedNode *RealNode = ssa.GetNode(ListData.Begin());
FEXCore::IR::IROp_Header *IROp = RealNode->Op(Data.Begin());
OrderedNode *RealNode = ssa.GetNode(DualListData.ListBegin());
FEXCore::IR::IROp_Header *IROp = RealNode->Op(DualListData.DataBegin());
if (IROp->Op == OP_INLINECONSTANT) {
return true;
}
@@ -448,20 +447,20 @@ friend class FEXCore::IR::PassManager;
}
FEXCore::IR::IROp_Header *GetOpHeader(OrderedNodeWrapper ssa) {
OrderedNode *RealNode = ssa.GetNode(ListData.Begin());
return RealNode->Op(Data.Begin());
OrderedNode *RealNode = ssa.GetNode(DualListData.ListBegin());
return RealNode->Op(DualListData.DataBegin());
}
OrderedNode *UnwrapNode(OrderedNodeWrapper ssa) {
return ssa.GetNode(ListData.Begin());
return ssa.GetNode(DualListData.ListBegin());
}
OrderedNodeWrapper WrapNode(OrderedNode *node) {
return node->Wrapped(ListData.Begin());
return node->Wrapped(DualListData.ListBegin());
}
NodeIterator GetIterator(OrderedNodeWrapper wrapper) {
return NodeIterator(ListData.Begin(), Data.Begin(), wrapper);
return NodeIterator(DualListData.ListBegin(), DualListData.DataBegin(), wrapper);
}
// Overwrite a node with a constant
@@ -472,22 +471,22 @@ friend class FEXCore::IR::PassManager;
void ReplaceAllUsesWithRange(OrderedNode *Node, OrderedNode *NewNode, AllNodesIterator After, AllNodesIterator End);
void ReplaceUsesWithAfter(OrderedNode *Node, OrderedNode *NewNode, AllNodesIterator After) {
ReplaceAllUsesWithRange(Node, NewNode, After, AllNodesIterator(ListData.Begin(), Data.Begin()));
ReplaceAllUsesWithRange(Node, NewNode, After, AllNodesIterator(DualListData.ListBegin(), DualListData.DataBegin()));
}
void ReplaceUsesWithAfter(OrderedNode *Node, OrderedNode *NewNode, OrderedNode *After) {
auto Wrapped = Node->Wrapped(ListData.Begin());
AllNodesIterator It = AllNodesIterator(ListData.Begin(), Data.Begin(), Wrapped);
auto Wrapped = Node->Wrapped(DualListData.ListBegin());
AllNodesIterator It = AllNodesIterator(DualListData.ListBegin(), DualListData.DataBegin(), Wrapped);
ReplaceUsesWithAfter(Node, NewNode, It);
}
void ReplaceAllUsesWith(OrderedNode *Node, OrderedNode *NewNode) {
auto Start = AllNodesIterator(ListData.Begin(), Data.Begin(), Node->Wrapped(ListData.Begin()));
auto Start = AllNodesIterator(DualListData.ListBegin(), DualListData.DataBegin(), Node->Wrapped(DualListData.ListBegin()));
ReplaceUsesWithAfter(Node, NewNode, Start);
LogMan::Throw::A(Node->NumUses == 0, "Node still used");
LOGMAN_THROW_A(Node->NumUses == 0, "Node still used");
// Since we have deleted ALL uses, we can safely delete the node.
Remove(Node);
@@ -501,15 +500,14 @@ friend class FEXCore::IR::PassManager;
OrderedNode *GetPackedRFLAG(bool Lower8);
void CopyData(IREmitter const &rhs) {
LogMan::Throw::A(rhs.Data.BackingSize() <= Data.BackingSize(), "Trying to take ownership of data that is too large");
LogMan::Throw::A(rhs.ListData.BackingSize() <= ListData.BackingSize(), "Trying to take ownership of data that is too large");
Data.CopyData(rhs.Data);
ListData.CopyData(rhs.ListData);
InvalidNode = rhs.InvalidNode->Wrapped(rhs.ListData.Begin()).GetNode(ListData.Begin());
LOGMAN_THROW_A(rhs.DualListData.DataBackingSize() <= DualListData.DataBackingSize(), "Trying to take ownership of data that is too large");
LOGMAN_THROW_A(rhs.DualListData.ListBackingSize() <= DualListData.ListBackingSize(), "Trying to take ownership of data that is too large");
DualListData.CopyData(rhs.DualListData);
InvalidNode = rhs.InvalidNode->Wrapped(rhs.DualListData.ListBegin()).GetNode(DualListData.ListBegin());
CurrentWriteCursor = rhs.CurrentWriteCursor;
CodeBlocks = rhs.CodeBlocks;
for (auto& CodeBlock: CodeBlocks) {
CodeBlock = CodeBlock->Wrapped(rhs.ListData.Begin()).GetNode(ListData.Begin());
CodeBlock = CodeBlock->Wrapped(rhs.DualListData.ListBegin()).GetNode(DualListData.ListBegin());
}
}
@@ -544,10 +542,10 @@ friend class FEXCore::IR::PassManager;
SetWriteCursor(nullptr);// Orphan from any future nodes
auto Begin = _BeginBlock(CodeNode);
CodeNode.first->Begin = Begin.Node->Wrapped(ListData.Begin());
CodeNode.first->Begin = Begin.Node->Wrapped(DualListData.ListBegin());
auto EndBlock = _EndBlock(CodeNode);
CodeNode.first->Last = EndBlock.Node->Wrapped(ListData.Begin());
CodeNode.first->Last = EndBlock.Node->Wrapped(DualListData.ListBegin());
return CodeNode;
}
@@ -564,10 +562,10 @@ friend class FEXCore::IR::PassManager;
* @{ */
/** @} */
void LinkCodeBlocks(OrderedNode *CodeNode, OrderedNode *Next) {
FEXCore::IR::IROp_CodeBlock *CurrentIROp = CodeNode->Op(Data.Begin())->CW<FEXCore::IR::IROp_CodeBlock>();
LogMan::Throw::A(CurrentIROp->Header.Op == IROps::OP_CODEBLOCK, "Invalid");
FEXCore::IR::IROp_CodeBlock *CurrentIROp = CodeNode->Op(DualListData.DataBegin())->CW<FEXCore::IR::IROp_CodeBlock>();
LOGMAN_THROW_A(CurrentIROp->Header.Op == IROps::OP_CODEBLOCK, "Invalid");
CodeNode->append(ListData.Begin(), Next);
CodeNode->append(DualListData.ListBegin(), Next);
}
IRPair<IROp_CodeBlock> CreateNewCodeBlockAtEnd() { return CreateNewCodeBlockAfter(nullptr); }
@@ -578,11 +576,11 @@ friend class FEXCore::IR::PassManager;
void RemoveArgUses(OrderedNode *Node);
OrderedNode *CreateNode(IROp_Header *Op) {
uintptr_t ListBegin = ListData.Begin();
uintptr_t ListBegin = DualListData.ListBegin();
size_t Size = sizeof(OrderedNode);
void *Ptr = ListData.Allocate(Size);
void *Ptr = DualListData.ListAllocate(Size);
OrderedNode *Node = new (Ptr) OrderedNode();
Node->Header.Value.SetOffset(Data.Begin(), reinterpret_cast<uintptr_t>(Op));
Node->Header.Value.SetOffset(DualListData.DataBegin(), reinterpret_cast<uintptr_t>(Op));
if (CurrentWriteCursor) {
CurrentWriteCursor->append(ListBegin, Node);
@@ -592,14 +590,14 @@ friend class FEXCore::IR::PassManager;
}
OrderedNode *GetNode(uint32_t SSANode) {
uintptr_t ListBegin = ListData.Begin();
uintptr_t ListBegin = DualListData.ListBegin();
OrderedNode *Node = reinterpret_cast<OrderedNode *>(ListBegin + SSANode * sizeof(OrderedNode));
return Node;
}
OrderedNode *EmplaceOrphanedNode(OrderedNode *OldNode) {
size_t Size = sizeof(OrderedNode);
OrderedNode *Ptr = reinterpret_cast<OrderedNode*>(ListData.Allocate(Size));
OrderedNode *Ptr = reinterpret_cast<OrderedNode*>(DualListData.ListAllocate(Size));
memcpy(Ptr, OldNode, Size);
return Ptr;
}
@@ -607,8 +605,7 @@ friend class FEXCore::IR::PassManager;
OrderedNode *CurrentWriteCursor = nullptr;
// These could be combined with a little bit of work to be more efficient with memory usage. Isn't a big deal
IntrusiveAllocator Data;
IntrusiveAllocator ListData;
DualIntrusiveAllocator DualListData;
OrderedNode *InvalidNode;
OrderedNode *CurrentCodeBlock{};
+120 -72
View File
@@ -1,6 +1,7 @@
#pragma once
#include "FEXCore/IR/IR.h"
#include <FEXCore/Utils/Allocator.h>
#include <FEXCore/Utils/LogManager.h>
#include <cassert>
@@ -19,121 +20,161 @@ namespace FEXCore::IR {
*
* Can potentially support reallocation if we are smart and make sure to invalidate anything holding a true pointer
*/
class IntrusiveAllocator final {
class DualIntrusiveAllocator final {
public:
IntrusiveAllocator() = delete;
IntrusiveAllocator(IntrusiveAllocator &&) = delete;
IntrusiveAllocator(size_t Size)
DualIntrusiveAllocator() = delete;
DualIntrusiveAllocator(DualIntrusiveAllocator &&) = delete;
DualIntrusiveAllocator(size_t Size)
: MemorySize {Size} {
Data = reinterpret_cast<uintptr_t>(malloc(Size));
Data = reinterpret_cast<uintptr_t>(FEXCore::Allocator::malloc(Size * 2));
List = reinterpret_cast<uintptr_t>(Data + Size);
}
~IntrusiveAllocator() {
free(reinterpret_cast<void*>(Data));
~DualIntrusiveAllocator() {
FEXCore::Allocator::free(reinterpret_cast<void*>(Data));
}
bool CheckSize(size_t Size) {
size_t NewOffset = CurrentOffset + Size;
bool DataCheckSize(size_t Size) {
size_t NewOffset = DataCurrentOffset + Size;
return NewOffset <= MemorySize;
}
void *Allocate(size_t Size) {
assert(CheckSize(Size) &&
"Ran out of space in IntrusiveAllocator during allocation");
size_t NewOffset = CurrentOffset + Size;
uintptr_t NewPointer = Data + CurrentOffset;
CurrentOffset = NewOffset;
bool ListCheckSize(size_t Size) {
size_t NewOffset = ListCurrentOffset + Size;
return NewOffset <= MemorySize;
}
void *DataAllocate(size_t Size) {
assert(DataCheckSize(Size) &&
"Ran out of space in DualIntrusiveAllocator during allocation");
size_t NewOffset = DataCurrentOffset + Size;
uintptr_t NewPointer = Data + DataCurrentOffset;
DataCurrentOffset = NewOffset;
return reinterpret_cast<void*>(NewPointer);
}
size_t Size() const { return CurrentOffset; }
size_t BackingSize() const { return MemorySize; }
void *ListAllocate(size_t Size) {
assert(ListCheckSize(Size) &&
"Ran out of space in DualIntrusiveAllocator during allocation");
size_t NewOffset = ListCurrentOffset + Size;
uintptr_t NewPointer = List + ListCurrentOffset;
ListCurrentOffset = NewOffset;
return reinterpret_cast<void*>(NewPointer);
}
uintptr_t const Begin() const { return Data; }
size_t DataSize() const { return DataCurrentOffset; }
size_t DataBackingSize() const { return MemorySize; }
void Reset() { CurrentOffset = 0; }
size_t ListSize() const { return ListCurrentOffset; }
size_t ListBackingSize() const { return MemorySize; }
void CopyData(IntrusiveAllocator const &rhs) {
CurrentOffset = rhs.CurrentOffset;
memcpy(reinterpret_cast<void*>(Data), reinterpret_cast<void*>(rhs.Data), CurrentOffset);
uintptr_t const DataBegin() const { return Data; }
uintptr_t const ListBegin() const { return List; }
void Reset() { DataCurrentOffset = 0; ListCurrentOffset = 0; }
void CopyData(DualIntrusiveAllocator const &rhs) {
DataCurrentOffset = rhs.DataCurrentOffset;
ListCurrentOffset = rhs.ListCurrentOffset;
memcpy(reinterpret_cast<void*>(Data), reinterpret_cast<void*>(rhs.Data), DataCurrentOffset);
memcpy(reinterpret_cast<void*>(List), reinterpret_cast<void*>(rhs.List), ListCurrentOffset);
}
private:
size_t CurrentOffset {0};
size_t MemorySize;
uintptr_t Data;
uintptr_t List;
size_t DataCurrentOffset {0};
size_t ListCurrentOffset {0};
size_t MemorySize;
};
class IRListView final {
enum Flags {
FLAG_IsCopy = 1,
FLAG_Shared = 2,
};
public:
IRListView() = delete;
IRListView(IRListView &&) = delete;
IRListView(IntrusiveAllocator *Data, IntrusiveAllocator *List, bool _IsCopy) : IsCopy(_IsCopy) {
DataSize = Data->Size();
ListSize = List->Size();
IRListView(DualIntrusiveAllocator *Data, bool _IsCopy) {
SetCopy(_IsCopy);
DataSize = Data->DataSize();
ListSize = Data->ListSize();
if (IsCopy) {
IRData = malloc(DataSize + ListSize);
ListData = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(IRData) + DataSize);
memcpy(IRData, reinterpret_cast<void*>(Data->Begin()), DataSize);
memcpy(ListData, reinterpret_cast<void*>(List->Begin()), ListSize);
if (_IsCopy) {
IRDataInternal = malloc(DataSize + ListSize);
ListDataInternal = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(IRDataInternal) + DataSize);
memcpy(IRDataInternal, reinterpret_cast<void*>(Data->DataBegin()), DataSize);
memcpy(ListDataInternal, reinterpret_cast<void*>(Data->ListBegin()), ListSize);
}
else {
// We are just pointing to the data
IRData = reinterpret_cast<void*>(Data->Begin());
ListData = reinterpret_cast<void*>(List->Begin());
IRDataInternal = reinterpret_cast<void*>(Data->DataBegin());
ListDataInternal = reinterpret_cast<void*>(Data->ListBegin());
}
}
IRListView(IRListView *Old, bool _IsCopy) : IsCopy(_IsCopy) {
IRListView(IRListView *Old, bool _IsCopy) {
SetCopy(_IsCopy);
DataSize = Old->DataSize;
ListSize = Old->ListSize;
if (IsCopy) {
IRData = malloc(DataSize + ListSize);
ListData = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(IRData) + DataSize);
memcpy(IRData, Old->IRData, DataSize);
memcpy(ListData, Old->ListData, ListSize);
if (_IsCopy) {
IRDataInternal = malloc(DataSize + ListSize);
ListDataInternal = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(IRDataInternal) + DataSize);
memcpy(IRDataInternal, Old->IRDataInternal, DataSize);
memcpy(ListDataInternal, Old->ListDataInternal, ListSize);
} else {
IRData = Old->IRData;
ListData = Old->ListData;
IRDataInternal = Old->IRDataInternal;
ListDataInternal = Old->ListDataInternal;
}
}
IRListView(std::istream& stream) : IsCopy(true) {
stream.read((char*)&DataSize, sizeof(DataSize));
stream.read((char*)&ListSize, sizeof(ListSize));
IRData = malloc(DataSize + ListSize);
ListData = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(IRData) + DataSize);
stream.read((char*)IRData, DataSize);
stream.read((char*)ListData, ListSize);
}
~IRListView() {
if (IsCopy) {
free (IRData);
if (IsCopy()) {
free (IRDataInternal);
// ListData is just offset from IRData
}
}
void Serialize(std::ostream& stream) {
void *nul = nullptr;
//void *IRDataInternal;
stream.write((char*)&nul, sizeof(nul));
//void *ListDataInternal;
stream.write((char*)&nul, sizeof(nul));
//size_t DataSize;
stream.write((char*)&DataSize, sizeof(DataSize));
//size_t ListSize;
stream.write((char*)&ListSize, sizeof(ListSize));
stream.write((char*)IRData, DataSize);
stream.write((char*)ListData, ListSize);
//uint64_t Flags;
uint64_t WrittenFlags = Flags | FLAG_Shared; //on disk format always has the Shared flag
stream.write((char*)&WrittenFlags, sizeof(WrittenFlags));
// inline data
stream.write((char*)GetData(), DataSize);
stream.write((char*)GetListData(), ListSize);
}
size_t GetInlineSize() {
static_assert(sizeof(*this) == 40);
return sizeof(*this) + DataSize + ListSize;
}
IRListView *CreateCopy() {
return new IRListView(this, true);
}
uintptr_t const GetData() const { return reinterpret_cast<uintptr_t>(IRData); }
uintptr_t const GetListData() const { return reinterpret_cast<uintptr_t>(ListData); }
size_t GetDataSize() const { return DataSize; }
size_t GetListSize() const { return ListSize; }
size_t GetSSACount() const { return ListSize / sizeof(OrderedNode); }
bool IsCopy() const { return Flags & FLAG_IsCopy; }
void SetCopy(bool Set) { if (Set) Flags |= FLAG_IsCopy; else Flags &= ~FLAG_IsCopy; }
bool IsShared() const { return Flags & FLAG_Shared; }
void SetShared(bool Set) { if (Set) Flags |= FLAG_Shared; else Flags &= ~FLAG_Shared; }
uint32_t GetID(OrderedNode *Node) const {
return Node->Wrapped(GetListData()).ID();
@@ -156,7 +197,7 @@ public:
// If we are casting to something narrower than just the header, check the opcode.
if constexpr (!std::is_same<T, IROp_Header>::value) {
LogMan::Throw::A(Op->OPCODE == Op->Header.Op, "Expected Node to be '%s'. Found '%s' instead", GetName(Op->OPCODE), GetName(Op->Header.Op));
LOGMAN_THROW_A(Op->OPCODE == Op->Header.Op, "Expected Node to be '%s'. Found '%s' instead", GetName(Op->OPCODE), GetName(Op->Header.Op));
}
return Op;
@@ -172,7 +213,6 @@ public:
return Wrapper.GetNode(GetListData());
}
bool IsShared {false};
private:
struct BlockRange {
using iterator = NodeIterator;
@@ -223,7 +263,6 @@ private:
}
};
public:
BlockRange GetBlocks() const {
@@ -244,7 +283,7 @@ public:
{
OrderedNodeWrapper Wrapped;
Wrapped.NodeOffset = sizeof(OrderedNode);
return iterator(reinterpret_cast<uintptr_t>(ListData), reinterpret_cast<uintptr_t>(IRData), Wrapped);
return iterator(reinterpret_cast<uintptr_t>(GetListData()), reinterpret_cast<uintptr_t>(GetData()), Wrapped);
}
/**
@@ -256,7 +295,7 @@ public:
{
OrderedNodeWrapper Wrapped;
Wrapped.NodeOffset = 0;
return iterator(reinterpret_cast<uintptr_t>(ListData), reinterpret_cast<uintptr_t>(IRData), Wrapped);
return iterator(reinterpret_cast<uintptr_t>(GetListData()), reinterpret_cast<uintptr_t>(GetData()), Wrapped);
}
/**
@@ -264,31 +303,40 @@ public:
* @return Iterator for this op
*/
iterator at(OrderedNodeWrapper Wrapped) const noexcept {
return iterator(reinterpret_cast<uintptr_t>(ListData), reinterpret_cast<uintptr_t>(IRData), Wrapped);
return iterator(reinterpret_cast<uintptr_t>(GetListData()), reinterpret_cast<uintptr_t>(GetData()), Wrapped);
}
iterator at(uint32_t ID) const noexcept {
OrderedNodeWrapper Wrapped;
Wrapped.NodeOffset = ID * sizeof(OrderedNode);
return iterator(reinterpret_cast<uintptr_t>(ListData), reinterpret_cast<uintptr_t>(IRData), Wrapped);
return iterator(reinterpret_cast<uintptr_t>(GetListData()), reinterpret_cast<uintptr_t>(GetData()), Wrapped);
}
iterator at(OrderedNode *Node) const noexcept {
auto Wrapped = Node->Wrapped(reinterpret_cast<uintptr_t>(ListData));
return iterator(reinterpret_cast<uintptr_t>(ListData), reinterpret_cast<uintptr_t>(IRData), Wrapped);
auto Wrapped = Node->Wrapped(reinterpret_cast<uintptr_t>(GetListData()));
return iterator(reinterpret_cast<uintptr_t>(GetListData()), reinterpret_cast<uintptr_t>(GetData()), Wrapped);
}
uintptr_t const GetData() const {
return reinterpret_cast<uintptr_t>(IRDataInternal ? IRDataInternal : InlineData);
}
uintptr_t const GetListData() const {
return reinterpret_cast<uintptr_t>(ListDataInternal ? ListDataInternal : &InlineData[DataSize]);
}
private:
void *IRData;
void *ListData;
void *IRDataInternal;
void *ListDataInternal;
size_t DataSize;
size_t ListSize;
bool IsCopy;
uint64_t Flags {0};
uint8_t InlineData[0];
};
struct IRListViewDeleter {
void operator()(IRListView* r) {
if (!r->IsShared) {
if (!r->IsShared()) {
delete r;
}
}
@@ -1,5 +1,6 @@
#pragma once
#include "IR.h"
#include <FEXCore/Utils/Allocator.h>
namespace FEXCore::IR {
@@ -47,9 +48,9 @@ class RegisterAllocationData {
struct RegisterAllocationDataDeleter {
void operator()(RegisterAllocationData* r) {
if (!r->IsShared) {
free(r);
FEXCore::Allocator::free(r);
}
}
};
}
}
+21
View File
@@ -0,0 +1,21 @@
#pragma once
#include <cstdint>
#include <functional>
namespace FEXCore::Allocator {
using MMAP_Hook = void*(*)(void*, size_t, int, int, int, off_t);
using MUNMAP_Hook = int(*)(void*, size_t);
using MALLOC_Hook = void*(*)(size_t);
using REALLOC_Hook = void*(*)(void*, size_t);
using FREE_Hook = void(*)(void*);
__attribute__((visibility("default"))) extern MMAP_Hook mmap;
__attribute__((visibility("default"))) extern MUNMAP_Hook munmap;
__attribute__((visibility("default"))) extern MALLOC_Hook malloc;
__attribute__((visibility("default"))) extern REALLOC_Hook realloc;
__attribute__((visibility("default"))) extern FREE_Hook free;
void SetupHooks();
}
@@ -83,8 +83,12 @@ public:
using SymbolAdder = std::function<void(ELFSymbol*)>;
void AddSymbols(SymbolAdder Adder);
using UnwindAdder = std::function<void(uintptr_t)>;
void AddUnwindEntries(UnwindAdder Adder);
void GetInitLocations(uint64_t GuestELFBase, std::vector<uint64_t> *Locations);
bool HasTLS() const { return TLSHeader._64 != nullptr; }
uint64_t GetTLSBase() const {
if (GetMode() == ELFMode::MODE_64BIT) {
@@ -151,6 +155,7 @@ private:
std::vector<SectionHeader> SectionHeaders;
std::vector<ProgramHeader> ProgramHeaders;
std::vector<ELFSymbol> Symbols;
std::vector<uintptr_t> UnwindEntries;
std::unordered_map<std::string, ELFSymbol *> SymbolMap;
std::map<uint64_t, ELFSymbol *> SymbolMapByAddress;
+222
View File
@@ -0,0 +1,222 @@
#pragma once
#include <vector>
#include <string>
#include <elf.h>
#include <fstream>
#include <fcntl.h>
#include <unistd.h>
#include "ELFContainer.h"
/*
Simpler elf parser, checks for the elf MAGIC COOKIE
and loads the phdrs
Also keeps an fd open
*/
struct ELFParser {
Elf64_Ehdr ehdr;
std::vector<Elf64_Phdr> phdrs;
::ELFLoader::ELFContainer::ELFType type {::ELFLoader::ELFContainer::TYPE_NONE};
std::string InterpreterElf;
int fd {-1};
bool ReadElf(const std::string &file) {
Closefd();
static_assert(EI_CLASS == 4);
type = ::ELFLoader::ELFContainer::TYPE_NONE;
std::ifstream elf(file);
fd = ::open(file.c_str(), O_RDONLY);
if (fd == -1) {
LogMan::Msg::E("Failed to open '%s'", file.c_str());
return false;
}
if (!elf.good()) {
LogMan::Msg::E("Failed to open (C++) '%s'", file.c_str());
return false;
}
uint8_t header[5];
elf.read((char*)header, sizeof(header));
if (!elf.good()) {
LogMan::Msg::E("Failed to read elf header from '%s'", file.c_str());
return false;
}
if (header[0] != ELFMAG0 || header[1] != ELFMAG1 || header[2] != ELFMAG2 || header[3] != ELFMAG3) {
LogMan::Msg::E("Elf header from '%s' doesn't match ELF MAGIC", file.c_str());
return false;
}
type = ::ELFLoader::ELFContainer::TYPE_OTHER_ELF;
// go to the beggining of the file
elf.seekg(0);
if (header[EI_CLASS] == ELFCLASS32) {
Elf32_Ehdr hdr32;
elf.read((char*)&hdr32, sizeof(hdr32));
if (!elf.good()) {
LogMan::Msg::E("Failed to read Ehdr32 from '%s'", file.c_str());
return false;
}
// do the sizes match up as expected?
// check elf header
if (hdr32.e_ehsize != sizeof(hdr32)) {
LogMan::Msg::E("Invalid e_ehsize32 from '%s'", file.c_str());
return false;
}
// check program header
if (hdr32.e_phentsize != sizeof(Elf32_Phdr)) {
LogMan::Msg::E("Invalid e_phentsize32 from '%s'", file.c_str());
return false;
}
// Convert to 64 bit header
for (int i = 0; i < EI_NIDENT; i++)
ehdr.e_ident[i] = hdr32.e_ident[i];
#define COPY(name) ehdr.name = hdr32.name
COPY(e_type);
COPY(e_machine);
COPY(e_version);
COPY(e_entry);
COPY(e_phoff);
COPY(e_shoff);
COPY(e_flags);
COPY(e_ehsize);
COPY(e_phentsize);
COPY(e_phnum);
COPY(e_shentsize);
COPY(e_shnum);
COPY(e_shstrndx);
#undef COPY
if (ehdr.e_machine != EM_386) {
LogMan::Msg::E("Invalid e_machine from '%s'", file.c_str());
return false;
}
type = ::ELFLoader::ELFContainer::TYPE_X86_32;
} else if (header[EI_CLASS] == ELFCLASS64) {
elf.read((char*)&ehdr, sizeof(ehdr));
if (!elf.good()) {
LogMan::Msg::E("Failed to read Ehdr64 from '%s'", file.c_str());
return false;
}
// do the sizes match up as expected?
// check elf header
if (ehdr.e_ehsize != sizeof(ehdr)) {
LogMan::Msg::E("Invalid e_ehsize64 from '%s'", file.c_str());
return false;
}
// check program header
if (ehdr.e_phentsize != sizeof(Elf64_Phdr)) {
LogMan::Msg::E("Invalid e_phentsize64 from '%s'", file.c_str());
return false;
}
if (ehdr.e_machine != EM_X86_64) {
LogMan::Msg::E("Invalid e_machine64 from '%s'", file.c_str());
return false;
}
type = ::ELFLoader::ELFContainer::TYPE_X86_64;
} else {
// Unexpected elf type
LogMan::Msg::E("Unexpected elf type from '%s'", file.c_str());
return false;
}
// seek to the program header offset
elf.seekg(ehdr.e_phoff);
// sanity check program header count
if (ehdr.e_phnum < 1 || ehdr.e_phnum > 65536 / ehdr.e_phentsize) {
LogMan::Msg::E("Too many program headers '%s'", file.c_str());
return false;
}
if (type == ::ELFLoader::ELFContainer::TYPE_X86_32) {
Elf32_Phdr phdrs32[ehdr.e_phnum];
elf.read((char*)phdrs32, sizeof(Elf32_Phdr) * ehdr.e_phnum);
if (!elf.good()) {
LogMan::Msg::E("Failed to read phdr32 from '%s'", file.c_str());
return false;
}
// Convert to 64 bit program headers
phdrs.resize(ehdr.e_phnum);
for (int i = 0; i < ehdr.e_phnum; i++) {
#define COPY(name) phdrs[i].name = phdrs32[i].name
COPY(p_type);
COPY(p_offset);
COPY(p_vaddr);
COPY(p_paddr);
COPY(p_filesz);
COPY(p_memsz);
COPY(p_flags);
COPY(p_align);
#undef COPY
}
} else {
phdrs.resize(ehdr.e_phnum);
elf.read((char*)&phdrs[0], sizeof(Elf64_Phdr) * ehdr.e_phnum);
if (!elf.good()) {
LogMan::Msg::E("Failed to read phdr64 from '%s'", file.c_str());
return false;
}
}
for (auto phdr : phdrs) {
if (phdr.p_type == PT_INTERP) {
elf.seekg(phdr.p_offset);
InterpreterElf.resize(phdr.p_filesz);
elf.read(&InterpreterElf[0], phdr.p_filesz);
if (!elf.good()) {
LogMan::Msg::E("Failed to read interpreter from '%s'", file.c_str());
return false;
}
}
}
return true;
}
void Closefd() {
if (fd != -1) {
close(fd);
fd = -1;
}
}
~ELFParser() {
Closefd();
}
};
+2 -2
View File
@@ -1,10 +1,10 @@
#pragma once
#include "ELFLoader.h"
#include "ELFContainer.h"
#include <vector>
#include <unordered_map>
namespace ELFLoader {
class ELFSymbolDatabase final {
class __attribute__((visibility("default"))) ELFSymbolDatabase final {
public:
ELFSymbolDatabase(::ELFLoader::ELFContainer *file);
~ELFSymbolDatabase();
+9 -5
View File
@@ -18,8 +18,8 @@ constexpr DebugLevels MSG_LEVEL = INFO;
namespace Throw {
using ThrowHandler = void(*)(char const *Message);
void InstallHandler(ThrowHandler Handler);
void UnInstallHandlers();
__attribute__((visibility("default"))) void InstallHandler(ThrowHandler Handler);
__attribute__((visibility("default"))) void UnInstallHandlers();
[[noreturn]] void M(const char *fmt, va_list args);
@@ -32,18 +32,20 @@ static inline void A(bool Value, const char *fmt, ...) {
va_end(args);
}
}
#define LOGMAN_THROW_A(pred, ...) do { LogMan::Throw::A(pred, __VA_ARGS__); } while (0)
#else
static inline void A(bool, const char*, ...) {}
#define LOGMAN_THROW_A(pred, ...) do {} while (0)
#endif
} // namespace Throw
namespace Msg {
using MsgHandler = void(*)(DebugLevels Level, char const *Message);
void InstallHandler(MsgHandler Handler);
void UnInstallHandlers();
__attribute__((visibility("default"))) void InstallHandler(MsgHandler Handler);
__attribute__((visibility("default"))) void UnInstallHandlers();
void M(DebugLevels Level, const char *fmt, va_list args);
__attribute__((visibility("default"))) void M(DebugLevels Level, const char *fmt, va_list args);
#if defined(ASSERTIONS_ENABLED) && ASSERTIONS_ENABLED
static inline void A(const char *fmt, ...) {
@@ -55,8 +57,10 @@ static inline void A(const char *fmt, ...) {
}
__builtin_trap();
}
#define LOGMAN_MSG_A(...) do { LogMan::Msg::A(__VA_ARGS__); } while (0)
#else
static inline void A(const char*, ...) {}
#define LOGMAN_MSG_A(...) do {} while(0)
#endif
static inline void E(const char *fmt, ...) {
Vendored Submodule
+1
Submodule External/jemalloc added at 2c7c069c8f.
+1 -1
+1 -1
+37
View File
@@ -0,0 +1,37 @@
#!/bin/bash
FEX=${1:-FEXLoader}
echo Using $FEX
for fileid in ~/.fex-emu/aotir/*.path; do
filename=`cat "$fileid"`
args=""
if [ "${fileid: -6 : 1}" == "P" ]; then
args="$args --no-abinopf"
else
args="$args --abinopf"
fi
if [ "${fileid: -7 : 1}" == "L" ]; then
args="$args --abilocalflags"
else
args="$args --no-abilocalflags"
fi
if [ "${fileid: -8 : 1}" == "T" ]; then
args="$args --tsoenabled"
else
args="$args --no-tsoenabled"
fi
if [ "${fileid: -9 : 1}" == "S" ]; then
args="$args --smc=full"
else
args="$args --smc=mman"
fi
if [ -f "${fileid%.path}.aotir" ]; then
echo "`basename $fileid` has already been generated"
else
echo "Processing `basename $fileid` ($filename) with $args"
$FEX --aotirgenerate $args "$filename"
fi
done
+111 -15
View File
@@ -16,6 +16,7 @@ class TypeDefinition:
TYPE_STRUCT = 1
TYPE_UNION = 2
TYPE_FIELD = 3
TYPE_VARDECL = 4
name: str
type: int
@@ -82,6 +83,19 @@ class FieldDefinition(TypeDefinition):
self.OffsetOf = OffsetOf
self.Alignment = Alignment
@dataclass
class VarDeclDefinition(TypeDefinition):
Size: int
Aliases: list
ExpectFEXMatch: bool
Value: str
def __init__(self, Name, Size):
super(VarDeclDefinition, self).__init__(Name, TypeDefinition.TYPE_VARDECL)
self.Size = Size
self.Aliases = []
self.ExpectFEXMatch = False
@dataclass
class ArchDB:
Parsed: bool
@@ -91,6 +105,7 @@ class ArchDB:
TU: TranslationUnit
Structs: dict
Unions: dict
VarDecls: dict
FieldDecls: list
def __init__(self, ArchName):
self.Parsed = True
@@ -100,6 +115,7 @@ class ArchDB:
self.TU = None
self.Structs = {}
self.Unions = {}
self.VarDecls = {}
self.FieldDecls = []
class DBList:
@@ -197,18 +213,62 @@ def HandleUnionDeclCursor(Arch, Cursor, NameOverride = ""):
return Arch
def HandleVarDeclCursor(Arch, Cursor):
CursorName = Cursor.spelling
DeclType = Cursor.type
Def = Cursor.get_definition()
VarDecl = VarDeclDefinition(
Name = CursorName,
Size = DeclType.get_size())
Arch.VarDecls[VarDecl.Name] = HandleVarDeclElements(Arch, VarDecl, Cursor)
return Arch
def HandleVarDeclElements(Arch, VarDecl, Cursor):
for Child in Cursor.get_children():
if (Child.kind == CursorKind.ANNOTATE_ATTR):
if (Child.spelling.startswith("ioctl-alias-")):
Sections = Child.spelling.split("-")
if (Sections[2] == "x86_32"):
VarDecl.Aliases.append(AliasType(Sections[3], AliasType.ALIAS_X86_32))
elif (Sections[2] == "x86_64"):
VarDecl.Aliases.append(AliasType(Sections[3], AliasType.ALIAS_X86_64))
elif (Sections[2] == "aarch64"):
VarDecl.Aliases.append(AliasType(Sections[3], AliasType.ALIAS_AARCH64))
elif (Sections[2] == "win32"):
VarDecl.Aliases.append(AliasType(Sections[3], AliasType.ALIAS_WIN32))
elif (Sections[2] == "win64"):
VarDecl.Aliases.append(AliasType(Sections[3], AliasType.ALIAS_WIN64))
else:
logging.critical ("Can't handle alias type '{0}'".format(Child.spelling))
Arch.Parsed = False
elif (Child.spelling == "fex-match"):
VarDecl.ExpectedFEXMatch = True
else:
# Unknown annotation
pass
elif (Child.kind == CursorKind.TYPE_REF or
Child.kind == CursorKind.UNEXPOSED_EXPR or
Child.kind == CursorKind.PAREN_EXPR or
Child.kind == CursorKind.BINARY_OPERATOR
):
pass
return VarDecl
def HandleTypeDefDeclCursor(Arch, Cursor):
TypeDefType = Cursor.underlying_typedef_type
CanonicalType = TypeDefType.get_canonical()
TypeDefName = Cursor.type.get_typedef_name()
if (TypeDefType.kind == TypeKind.ELABORATED and CanonicalType.kind == TypeKind.RECORD):
TypeDefName = Cursor.type.get_typedef_name()
if (len(TypeDefName) != 0):
logging.info ("Found Typedef Decl'{0}'".format(TypeDefName))
logging.info ("\tSize of type: {0}".format(CanonicalType.get_size()));
HandleTypeDefDecl(Arch, Cursor, TypeDefName)
# Append namespace
# Append namespace
Arch.NamespaceScope.append(TypeDefName)
SetNamespace(Arch)
@@ -225,11 +285,20 @@ def HandleTypeDefDeclCursor(Arch, Cursor):
# Pop namespace off
Arch.NamespaceScope.pop()
SetNamespace(Arch)
else:
if (len(TypeDefName) != 0):
Def = Cursor.get_definition()
VarDecl = VarDeclDefinition(
Name = TypeDefName,
Size = CanonicalType.get_size())
Arch.VarDecls[VarDecl.Name] = HandleVarDeclElements(Arch, VarDecl, Cursor)
return Arch
def HandleStructElements(Arch, Struct, Cursor):
for Child in Cursor.get_children():
logging.info ("\t\tStruct/Union Children: Cursor \"{0}{1}\" of kind {2}".format(Arch.CurrentNamespace, Child.spelling, Child.kind))
# logging.info ("\t\tStruct/Union Children: Cursor \"{0}{1}\" of kind {2}".format(Arch.CurrentNamespace, Child.spelling, Child.kind))
if (Child.kind == CursorKind.ANNOTATE_ATTR):
if (Child.spelling.startswith("alias-")):
Sections = Child.spelling.split("-")
@@ -245,6 +314,8 @@ def HandleStructElements(Arch, Struct, Cursor):
Struct.Aliases.append(AliasType(Sections[2], AliasType.ALIAS_WIN64))
else:
logging.critical ("Can't handle alias type '{0}'".format(Child.spelling))
Arch.Parsed = False
elif (Child.spelling == "fex-match"):
Struct.ExpectedFEXMatch = True
else:
@@ -259,10 +330,10 @@ def HandleStructElements(Arch, Struct, Cursor):
OffsetOf = ParentType.get_offset(Child.spelling),
Alignment = FieldType.get_align())
logging.info ("\t{0}".format(Child.spelling))
logging.info ("\t\tSize of type: {0}".format(FieldType.get_size()));
logging.info ("\t\tAlignment of type: {0}".format(FieldType.get_align()));
logging.info ("\t\tOffsetof of type: {0}".format(ParentType.get_offset(Child.spelling)));
#logging.info ("\t{0}".format(Child.spelling))
#logging.info ("\t\tSize of type: {0}".format(FieldType.get_size()));
#logging.info ("\t\tAlignment of type: {0}".format(FieldType.get_align()));
#logging.info ("\t\tOffsetof of type: {0}".format(ParentType.get_offset(Child.spelling)));
Struct.Members.append(Field)
Arch.FieldDecls.append(Field)
elif (Child.kind == CursorKind.STRUCT_DECL):
@@ -274,10 +345,10 @@ def HandleStructElements(Arch, Struct, Cursor):
OffsetOf = ParentType.get_offset(Child.spelling),
Alignment = FieldType.get_align())
logging.info ("\t{0}".format(Child.spelling))
logging.info ("\t\tSize of type: {0}".format(FieldType.get_size()));
logging.info ("\t\tAlignment of type: {0}".format(FieldType.get_align()));
logging.info ("\t\tOffsetof of type: {0}".format(ParentType.get_offset(Child.spelling)));
#logging.info ("\t{0}".format(Child.spelling))
#logging.info ("\t\tSize of type: {0}".format(FieldType.get_size()));
#logging.info ("\t\tAlignment of type: {0}".format(FieldType.get_align()));
#logging.info ("\t\tOffsetof of type: {0}".format(ParentType.get_offset(Child.spelling)));
Struct.Members.append(Field)
Arch.FieldDecls.append(Field)
Arch = HandleStructDeclCursor(Arch, Child)
@@ -333,7 +404,6 @@ def HandleCursor(Arch, Cursor):
return
for Child in Cursor.get_children():
logging.info ("\tCursor \"{0}\" of kind {1}".format(Child.spelling, Child.kind))
if (Child.kind == CursorKind.TRANSLATION_UNIT):
Arch = HandleCursor(Arch, Child)
elif (Child.kind == CursorKind.FIELD_DECL):
@@ -344,6 +414,8 @@ def HandleCursor(Arch, Cursor):
Arch = HandleStructDeclCursor(Arch, Child)
elif (Child.kind == CursorKind.TYPEDEF_DECL):
Arch = HandleTypeDefDeclCursor(Arch, Child)
elif (Child.kind == CursorKind.VAR_DECL):
Arch = HandleVarDeclCursor(Arch, Child)
elif (Child.kind == CursorKind.NAMESPACE):
# Append namespace
Arch.NamespaceScope.append(Child.spelling)
@@ -455,7 +527,8 @@ def CompareAliases(DB, DBs):
# XXX: Oops, shouldn't have anonymous structs
continue
logging.info ("Comparing Aliases {0}".format(StructDef.Name))
if (len(StructDef.Aliases) != 0):
logging.info ("Comparing Aliases {0}".format(StructDef.Name))
for Alias in StructDef.Aliases:
OtherDB = DBs.DBs[Alias.AliasType]
@@ -469,6 +542,29 @@ def CompareAliases(DB, DBs):
if not (ThisAlias):
logging.error ("Couldn't Alias to Arch {0} successfully".format(OtherDB.ArchName))
Passed &= ThisAlias
for VarDeclKey, VarDecl in DB.VarDecls.items():
if (len(VarDeclKey) == 0):
# XXX: Oops, shouldn't have anonymous vardecls
continue
for Alias in VarDecl.Aliases:
OtherDB = DBs.DBs[Alias.AliasType]
OtherAlias = OtherDB.VarDecls.get(Alias.Name)
if (OtherAlias == None):
logging.critical ("Couldn't find alias {0} in {1} DB".format(Alias.Name, OtherDB.ArchName))
Passed = False
continue
if (VarDecl.Size != OtherAlias.Size):
logging.critical("VarDecl: {0}/{1} didn't match {2}/{3}: {4:08X} != {5:08X}".format(VarDeclKey, DB.ArchName, Alias.Name,
OtherDB.ArchName,
VarDecl.Size, OtherAlias.Size))
Passed = False
continue
return Passed
def CompareCrossArch(DB1, DB2):
Loaded 100 of 192 files, more files were not shown because too many files have changed in this diff. Show more