235 Commits
Author SHA1 Message Date
Flyinghead 392a429e8b boxart: replace invalid utf-8 chars instead of failing when saving
Open (and truncate) the file only after json serialization.
2026-01-07 14:28:32 +01:00
Flyinghead 0491f2e6a5 reios: check boot file destination ptr before loading
Abort load if ptr is null (size > 0xff0000)
Fixes MINIDUMP-7W9 MINIDUMP-84B MINIDUMP-87V
2026-01-07 09:50:35 +01:00
Flyinghead 33d9a58cf9 emu: don't crash if unexpected state in Emulator::start()
Simply log and ignore. Happens on android under some undetermined
conditions.
Fixes MINIDUMP-2Q MINIDUMP-3SG
2026-01-07 08:52:36 +01:00
Flyinghead 401332d520 sdl: don't run haptic sine effect if rumblePower is 0 2026-01-06 16:23:47 +01:00
Flyinghead 8511d1ad3c dreamconn: only build on win32. remove unused code 2026-01-06 16:21:35 +01:00
Craig d794b53512 webOS: disable OPENMP as not available until webOS 3.9.2 (#2188)
[ci skip]
2026-01-04 21:10:03 +01:00
Craig 594d82b223 add webOS to CMakeLists (#2167)
[ci skip]
2026-01-04 10:55:23 +01:00
Flyinghead 74cbee908f arm64 rec: proper fix for MINIDUMP-7W0
ModeImmediateHelper can generate code, resulting in the Mov op being
generated twice.
Fixes MINIDUMP-7W0
2026-01-02 11:51:23 +01:00
Flyinghead 4886dcb1c2 enable rtt2vram for Jikkyo Powerful Pro Yakyu
Issue #2182
2025-12-29 20:20:15 +01:00
Rikki Gibson 16fc172ffc DreamConn: fix compat issue involving slot 2 VMU support (#2172)
* Do not create a shared_ptr from destructor
* Fall back when MDC_DeviceRequest message does not have an expected response
* Assume the device type for physical DreamConn controllers
* DreamConn controllers do not support physical VMU memory
* Do not maple_ReconnectDevices for DreamConn controller
2025-12-27 19:40:13 +01:00
Flyinghead dfb2ae8987 android: touch mouse may be null so check before delivering events
Fixes MINIDUMP-6S6
[ci skip]
2025-12-27 19:36:51 +01:00
Flyinghead 4529a31372 don't save state when game filename is empty
Happens on android apparently due to issues with automatic savestate and
app pausing.
2025-12-27 19:35:30 +01:00
Flyinghead 5a29ac489f sdl: fix DreamPicoPort crash
io_context_thread can be null in the destructor.
Fixes MINIDUMP-83F
2025-12-27 19:31:32 +01:00
github-actions[bot] c4c3c2ae93 Fetch translations & Recreate libretro_core_options_intl.h 2025-12-26 22:21:56 +00:00
Edward Li f65907a256 Remove custom_texture.terminate() during TexCache.Clear() 2025-12-15 12:27:57 +01:00
github-actions[bot] 37a9077304 Fetch translations & Recreate libretro_core_options_intl.h 2025-12-12 22:21:51 +00:00
Flyinghead 27a913fc02 arm recs: ensure block linking size doesn't depend on mmu mode
Due to d0ec876936 the mmu enabled path may
be taken when the emu is pausing, so make sure block linking uses the
same number of ops in both branches.
Fixes MINIDUMP-82C MINIDUMP-7T2 MINIDUMP-7W0
2025-12-12 16:49:50 +01:00
Flyinghead 97442c0411 terminate game id at first null character
Fixes MINIDUMP-7YW MINIDUMP-800
2025-12-12 16:13:44 +01:00
Flyinghead 5b12f9ca68 boxart: catch-all handler for scraper thread
Fixes MINIDUMP-7YW
2025-12-12 16:07:22 +01:00
Flyinghead 6a298289a9 ice: guard against null icePipe
Fixes MINIDUMP-7ZF
2025-12-12 16:03:44 +01:00
Flyinghead 59ef8579d2 ui: disable imgui debug tools
Fixes MINIDUMP-7RF
2025-12-12 16:01:52 +01:00
Flyinghead 14f759eeb7 ice: fix crash when loading a state without being connected 2025-12-09 14:36:53 +01:00
github-actions[bot] 230d971d4d Fetch translations & Recreate libretro_core_options_intl.h 2025-12-05 22:22:07 +00:00
Flyinghead 5a150f4121 Merge remote-tracking branch 'origin/dev' 2025-12-03 19:23:43 +01:00
vkedwardli f178e5d76e Custom texture preloading (#2116)
* Creating a `CustomTextureSource` interface for subclassing
* `DumpReplacedTextures` option
* `PreloadCustomTextures` option
2025-12-02 17:02:19 +01:00
James 9222fa8442 Fix: DreamPicoPort locks up and causes flycast to hang (#2124)
* Use DreamPicoPort-API 1.0.2 which automatically clears USB stalls
* Getting condition in order to detect controller seems to be problematic
* Use the libusb implementation of DreamPicoPort-API on Windows because WinRT is buggy
2025-12-01 16:50:02 +01:00
Flyinghead 77359cefb2 ui: add char filter for dns names and IP addresses text input 2025-12-01 16:49:13 +01:00
Flyinghead a6dc38a35b switch: use sync keyboard applet for keyboard input 2025-11-30 18:23:15 +01:00
Flyinghead eab952fcbe ui: UWP keyboard fix. Fix DPad nav & scrolling with child windows
Detect UWP on-screen keyboard hiding and validate imgui text edit (code
by @danprice142).
Don't use list boxes for paths in Settings > General since child windows
cause issues with DPad/cursor keys navigation and thumbstick scrolling.
2025-11-29 18:06:21 +01:00
Flyinghead 1666eb0875 android: ignore touchpad axes (dualshock 4)
The touchpad also reports motion events on the same axis numbers, but
the range source is different so ignore them.
Override known axes in mapping when the gamepad is connected.
Issue #2109
2025-11-22 11:34:36 +01:00
Flyinghead 5bce763f66 Merge remote-tracking branch 'origin/dev' 2025-11-21 12:49:47 +01:00
Flyinghead 0f4fca415b ui: set VMUPath and SavePath options a single path instead of a list
Fix naming of arcade flash save files when using a custom path.
Get rid of legacy net:nvmem option.
Issue #2111
2025-11-20 16:43:27 +01:00
Flyinghead f2fe918379 android: Virtual Gamepad and Touch Mouse duplicated after app pause
These devices were recreated every time the app is unpaused.
2025-11-20 09:43:53 +01:00
Flyinghead a9be4d111c Use nowide::remove instead of unlink or std::remove 2025-11-20 09:37:04 +01:00
danprice142 ce07a7fbf5 Add user-defined paths for boxart, mappings & cheats (#2108)
* Add user-configurable paths for boxart, mappings, and cheats

Introduces new configuration options for Boxart path, Mappings path, and Cheat path, allowing users to specify custom folders for box art, controller mappings, and cheat files.
2025-11-19 15:30:30 +01:00
Flyinghead e44c03fa0e ui: reset button state when closing mapping popup and on map/unmap
Fixes button state staying on until app restart.
2025-11-19 15:29:15 +01:00
Flyinghead 1dac3695fd imgui: ImguiStyleVar must be deleted before the end of the window 2025-11-18 18:58:44 +01:00
Flyinghead 997f6179dd android: normalize axis value using min and range. Use event.actionIndex
Normalize analog axis values using InputDevice.MotionRange.min and
InputDevice.MotionRange.range.
Specify Event.actionIndex when getting axis values like SDL does.
Issue #2109
2025-11-18 18:57:02 +01:00
Flyinghead bed524f0d0 imgui: ImguiStyleVar must be deleted before the end of the window 2025-11-17 19:18:55 +01:00
Flyinghead 410b37b041 naomi: add dc microphone to king of route 66. Add cd-mic switch binding
King of route 66 uses a maple microphone for the CB-MIC feature.
Also define the mic switch button binding (button 6).
Don't add VMUs to naomi2 games since no game uses them afaik
2025-11-17 19:13:45 +01:00
Flyinghead ead4b51d6f fix savestate regression due to custom path
Issue #2111
2025-11-16 11:45:23 +01:00
Flyinghead 043bb5ee99 Merge remote-tracking branch 'origin/master' into dev 2025-11-16 11:41:40 +01:00
Flyinghead 4747e61908 vgamepad: enable touch mouse for mouse/rotary encoders arcade games
Issue #2110
2025-11-15 15:49:26 +01:00
github-actions[bot] 548cf6fe2e Fetch translations & Recreate libretro_core_options_intl.h 2025-11-14 22:21:15 +00:00
Edward Li 339d288dfb macOS: update Syphon library 2025-11-14 17:13:35 +01:00
Flyinghead 8f7e4bf2d3 aica: fix ALFO and PLFO random waveform
Fixes skating sound in Jet Set Radio
Issue #2107
2025-11-14 17:12:58 +01:00
Flyinghead 922ca3e54b cue: read pregap length from cue file and adjust track start
Use the INDEX 01 mm:ss:ff tag to determine the pregap size and add it to
the track start FAD.
Remove previous +02:00 hack for audio tracks.
Fixes Sonic Team jingle cut off in ChuChu Rocket redump cue.
Issue #2103
2025-11-14 11:12:44 +01:00
Flyinghead 4b09de2fc1 vulkan: recreate swap chain when the vulkan context becomes invalid
Fixes freeze when switching to fullscreen on gentoo.
Issue #2082
2025-11-14 10:57:14 +01:00
Flyinghead 98db7a6cd5 android: vgamepad LT and RT not set to minimum when released
LT and RT were left to 50% depressed when released.
Regression due to 7b0c106fc2
Issue #2104
2025-11-13 10:06:16 +01:00
Flyinghead 3405b5b2a6 aica: use member functions for ChannelEx instead of static ones
More enums
No functional changes
2025-11-12 20:50:31 +01:00
Flyinghead 4320685ff8 uwp: simplify activation and exit URIs handling
Use http::urlDecode to decode URIs.
Move exit URI handling to dc_exit() so that all exit paths are covered.
2025-11-12 13:40:07 +01:00
Flyinghead cd3fe7393c http: add urlDecode and tests for urlEncode and urlDecode 2025-11-11 20:43:13 +01:00
Flyinghead 2da0d392fd move oslib/directory.h function defs into a .cpp file 2025-11-11 19:24:12 +01:00
Flyinghead 8d1bf3382c android: add customisable bios and texture pack folders 2025-11-11 19:15:59 +01:00
Bobby Smith b1489d665e [Libretro] Update AV info when switching a PAL game to 60Hz 2025-11-10 14:16:02 +01:00
Flyinghead fc56bd283e fix double-nested game folder when dumping textures
Change TextureDumpPath to a single path instead of a list
Issue #305
2025-11-10 14:11:14 +01:00
Flyinghead 807e4a20ed aica: yet another LPF improvement
Use more bits for coefficients and formula closer to original hardware.
2025-11-10 13:52:21 +01:00
Flyinghead 943311752e cheats: increase max code length and input text height 2025-11-10 11:50:40 +01:00
Flyinghead e7ad12b031 rend: convert palette textures for area 1 on cpu
Only one palette is supported in the shader, so convert area 1 palette
textures (2-volume mode) on the cpu and handle them normally in the
shader.
Issue #1528
2025-11-09 15:44:48 +01:00
danprice142 b2bc6251c7 Add configurable paths for BIOS, VMU, saves, textures & dumps (#2097)
* Add configurable paths for BIOS, VMU, saves, textures & dumps

Introduces new options for user-defined folders for BIOS, VMU, savestates, game saves, texture packs, and texture dumps. Updates path resolution logic in oslib.cpp to prioritize user-specified paths before falling back to defaults.

* Add UWP support for directory and file access

Introduces UWP-specific implementations for directory handling and file access in core/oslib, including custom opendir, readdir, and closedir functions, this is so we can see subfolders properly on UWP

* Custom Paths section hidden on Android and iOS
2025-11-08 15:06:47 +01:00
Flyinghead 6f38dc3210 msvc build fix 2025-10-28 12:23:22 +01:00
danprice142 4bb32466bd Add UWP protocol activation support for ROM loading from UWP Frontends (#2095)
Adds UWP protocol activation support for ROM loading from UWP Frontends/Browsers, allows launching ROMs via SDL's `SDL_WinRTGetProtocolActivationURI()` and redirection using the 'launchOnExit' URI parameter from protocol activation in SDL_WinRTApp, Closing a Rom/Game from the quick menu or closing the app will make use of `launchOnExit` and redirect to the specified app

Implements launching a URI via Windows.System.Launcher after the game is stopped from the Exit button in the quick menu, enabling return to sender/redirection on UWP

Update SDL submodule to include SDL_WinRTGetProtocolActivationURI()
2025-10-28 11:37:16 +01:00
Rikki Gibson e26d356265 DreamConn: allow using a VMU in slot 2 (#2094) 2025-10-28 11:34:31 +01:00
Flyinghead 265c5c6c3d aica: fix EG rate and LSA > LEA behaviour from real hw tests
EG rate formula specified in the doc is correct but FRS+OCT is ignored
if negative.
If LSA > LEA, playback continues after LEA until reaching LSA. Then CA
is reset and playback stops (including looping sounds). Get rid of
Legacy of Kain hack.
2025-10-27 17:26:42 +01:00
Flyinghead 2b1eb55daa maple: flush VMU files when unloading a game
destroy maple devices when unloading a game to flush and close VMU
files.
2025-10-24 15:31:22 +02:00
Flyinghead bd136b1856 ice: vonot support
ice::term() ice on emu termination
2025-10-24 15:29:12 +02:00
Flyinghead bd8adf1da1 delete outdated dreampi dcnet binary 2025-10-22 15:35:51 +02:00
Flyinghead 11625176c2 ggpo: catch serialization exception when saving state 2025-10-22 15:33:10 +02:00
Flyinghead c64441a02f pvr: avoid pure blue video border color. change to black
Hides blue vertical bars in dinosaur king.
Issue #1246
2025-10-22 15:29:35 +02:00
Flyinghead 8e9eee246d Merge remote-tracking branch 'origin/master' into dev 2025-10-21 15:26:52 +02:00
Flyinghead d0ec876936 arm32/64 dynarec: fix crash when disabling mmu
With block linking, CpuRunning isn't tested immediately so add a special
case in DynaRBI::Relink()
Issue #893
Fixes MINIDUMP-56 MINIDUMP-6V MINIDUMP-6X MINIDUMP-CA
Fixes MINIDUMP-H8 MINIDUMP-K6 MINIDUMP-QN MINIDUMP-YZ
Fixes MINIDUMP-YM MINIDUMP-148
2025-10-21 15:24:31 +02:00
Flyinghead b19cbcbf29 android: clean up openmp stuff 2025-10-21 15:18:48 +02:00
John Lansing bf2bd7efed Move duplicate Exception class to SerializeBase 2025-10-21 12:48:39 +02:00
John Lansing d15d5be44a libretro: detect and communicate buffer overflow on save state serialization 2025-10-21 12:48:39 +02:00
Flyinghead 70c8d1d22b vk: handle acquireNextImageKHR error when resizing window
Ignoring the error leads to a deadlock since the imageAcquired semaphore
can't be signaled.
Fixes freeze when resizing window.
Issue #1620
2025-10-21 12:47:46 +02:00
JamesandRikki Gibson 3917c0181b DreamPicoPort API Update (#2079)
Co-authored-by: Rikki Gibson <[email protected]>
2025-10-20 10:48:23 +02:00
Flyinghead 6f58d204b6 arm, arm64 dynarecs: check FPU enabled after PC and block checks
Fixes hang/crash in Sega Rally 2 when exiting the Records menu.
Issue #1877
2025-10-20 10:46:30 +02:00
Flyinghead d450c84a14 rend: disable texture upscaling on mobile. hide option on desktop 2025-10-20 10:31:35 +02:00
Flyinghead 3b7036d14a android: fix init crash on 32-bit platforms 2025-10-19 15:45:40 +02:00
Flyinghead 5d628f8167 naomi: default eeprom for clubkprz. default nvmem for smarinef
Use clubk2k3 eeprom for clubk2kp and clubk2kpa.
Issue #2086
2025-10-18 18:09:29 +02:00
github-actions[bot] d1ed878446 Fetch translations & Recreate libretro_core_options_intl.h 2025-10-17 22:20:56 +00:00
Flyinghead 28ea3dc69c arcade: add CRC for all working roms. Fix mushik2k bios
All roms can now be loaded by CRC value.
Issue #1952
Fix mushik2k to use the multi-region hacked bios set to Korean region
2025-10-16 18:11:16 +02:00
Flyinghead 031a645ffc move HideCdromDrives check into ui/game_scanner 2025-10-16 18:07:09 +02:00
Flyinghead 0a526d7c94 gdb: fix race condition when stepping. Improve vCont handling
Work around race condition when stepping (CpuRunning still true in
Sh4Executor::Step() on emu thread since Step() hasn't be called yet in
main thread).
Don't advertise vCont commands that aren't supported.
Range stepping end is exclusive.
2025-10-16 17:56:39 +02:00
Flyinghead 3d594054eb libretro build fix 2025-10-15 20:30:23 +02:00
Flyinghead 3b651463dc New [config]HideCdromDrives setting to ignore physical CD/DVD drives 2025-10-15 20:00:30 +02:00
Flyinghead 4e6b5b270b vk: remove image barrier at end of oit pipeline
It seems to cause issues on snapdragon 8 elite (SM8750-AB). These GPUs
never cease to amaze me....
Partial revert of b4b4b3ab1e
Issue #2083
2025-10-15 19:58:41 +02:00
Flyinghead fd8f2e24b8 android: switch to sdk 35, min 21, ndk 29
Drop support for Android 4.* (kitkat, jelly bean)
Minimum SDK 21 (Android 5.0, lollipop)
Target SDK 35 (Android 15)
Build with NDK 29 for 16KB-page by default. Issue #1864
2025-10-14 16:47:50 +02:00
Flyinghead 82b4c55f09 fix gdb server networking
Issue #2081
2025-10-14 14:43:47 +02:00
Flyinghead 8176646c5a android: don't set section name for dynarec code cache
Use #define to declare platform-specific dynarec code buffers
Don't set section name on android to avoid error "W+E load segments are
not allowed"
2025-10-13 19:19:48 +02:00
Flyinghead 3f0dd626c1 android: update oboe to 1.10.0 2025-10-13 19:11:12 +02:00
Flyinghead 8edd8fc447 Merge remote-tracking branch 'origin/dev' 2025-10-13 16:58:06 +02:00
Flyinghead 0c7dca9cb7 sdl: move mapping parser into its own class. Add tests 2025-10-13 16:20:34 +02:00
Flyinghead 086e8bc20c android: exclude libz.so from apk 2025-10-13 16:06:47 +02:00
Flyinghead 11880bca30 atomiswave: fix lightgun games button labels
Issue #2080
2025-10-13 10:25:30 +02:00
scribam 37187467e7 cmake: lower minimum requirement 2025-10-12 11:55:35 +02:00
Flyinghead 7b0c106fc2 input: axes handling improvements
Range for all axes, including triggers, is now [-32768,32767]
Detect trigger direction when mapping and store in mapping file.
sdl: parse controller bindings string to correctly map axes.
Issue #2014
2025-10-12 11:54:16 +02:00
github-actions[bot] fd654614ae Fetch translations & Recreate libretro_core_options_intl.h 2025-10-10 22:20:45 +00:00
Flyinghead 4ee24ca612 vk: test automation fix 2025-10-10 09:01:31 +02:00
scribam 4b3704953f ci: use freebsd 14.3 2025-10-09 19:24:16 +02:00
Flyinghead 6ea9a34e8a macOS CI: update vulkan sdk version 2025-10-08 17:09:05 +02:00
Flyinghead c018d46d00 atomiswave: reset maple devices register during reset
Reset aw_maple_devs to 0 during reset.
Fixes analog controls not working after playing a mouse/trackball or
lightgun game.
Issue #2072
2025-10-06 19:39:31 +02:00
Flyinghead 400da2bdfe vk: add yet another image barrier for libretro (nvidia 30xx issue)
Also add image barrier in endFrame for libretro
Issue #1631
2025-10-06 15:42:52 +02:00
Flyinghead 3b5536dd43 new system sp games: btlracer, monomedal 2025-10-06 15:39:20 +02:00
Flyinghead 34e2f426ac build fix 2025-10-05 15:53:24 +02:00
Flyinghead a246964a99 fix some warnings 2025-10-05 15:35:52 +02:00
Flyinghead b4b4b3ab1e vk: add image barrier to work around nvidia 30xx issue
Add image barrier in VulkanContext::PresentFrame() for nvidia gpus.
Tentative fix for square glitches on nvidia 30xx series.
Issue #1631
oit: Add dependency from external to subpass 2 since vulkan's implicit
one is too relaxed.
2025-10-05 15:34:18 +02:00
github-actions[bot] af5f67c15d Fetch translations & Recreate libretro_core_options_intl.h 2025-10-03 22:21:01 +00:00
Rikki GibsonandJames 909ea496ac DreamPotato connectivity (#1989)
Co-authored-by: James <[email protected]>
2025-10-03 14:34:25 +02:00
Flyinghead 3347dc1a46 custom textures: reset available flag when initializing
Fixes crash when starting a new game without custom texture after one
that has some.
Fixes MINIDUMP-6C9
2025-10-03 14:28:31 +02:00
Flyinghead dd5e148e2b input: don't handle button input when port is set to none
Fixes physical keyboard usage on android, where the keyboard is also
handled as a gamepad and must be disabled.
2025-10-03 14:12:23 +02:00
Flyinghead 1f818ca750 naomi: fix zombrvn and zombrvne default eeproms
zombrvn: Disable free play, do analog calibration
zombrvne: Select 2-player cab
Issue #1980
2025-10-03 11:10:44 +02:00
Flyinghead ab6b95ff4d naomi: spawn needs the region number in its eeprom
The current region must be set in the eeprom, otherwise the eeprom is
reset to default and network settings are ignored.
Issue #696
2025-09-27 17:28:20 +02:00
github-actions[bot] 760c62a3da Fetch translations & Recreate libretro_core_options_intl.h 2025-09-26 22:20:52 +00:00
Flyinghead b2d8ad633d boxart: use flycast-content github repo for arcade games screenshots 2025-09-26 15:30:01 +02:00
Flyinghead f9b47b6f91 boxart: use correct file extension for images 2025-09-23 15:55:36 +02:00
Flyinghead 372ef91211 opengl: per-pixel support for GLES
Issue #2034
2025-09-23 15:53:14 +02:00
scribam 3375f6c476 deps: update sdl to version 2.32.10 2025-09-22 09:57:07 +02:00
scribam c5396a041e cmake: add windows setupapi lib 2025-09-22 09:56:56 +02:00
github-actions[bot] 851dd22664 Fetch translations & Recreate libretro_core_options_intl.h 2025-09-19 22:21:19 +00:00
github-actions[bot] ac32a80352 Fetch translations & Recreate libretro_core_options_intl.h 2025-09-12 22:20:41 +00:00
Flyinghead eff11d6a07 Merge remote-tracking branch 'origin/master' into dev 2025-09-12 18:15:23 +02:00
scribam b6c135b0c6 macOS: update libomp to version 21.1.1 2025-09-12 13:44:50 +02:00
scribam 0fe7073496 macOS: remove workaround with local/pinned/cmake from openmp formula 2025-09-12 13:44:50 +02:00
Edward Li d5c5839a92 macOS libomp: Use local/pinned/cmake in homebrew formula, update libomp to 21.1 2025-09-09 14:38:25 +02:00
Clownacy 7ac45a7e46 Remove -DCMAKE_BUILD_TYPE=Release from .gitlab-ci.yml.
There is no longer a need to set this explicitly, as libretro's CI templates have been corrected to not leave it undefined.

See this commit: https://git.libretro.com/libretro-infrastructure/ci-templates/-/commit/0241726e188a7c077dcff6cd7c1739039a79a7fb
2025-09-08 10:39:53 +02:00
github-actions[bot] 0243f81c26 Fetch translations & Recreate libretro_core_options_intl.h 2025-08-29 22:20:49 +00:00
Flyinghead 2dfa647445 naomi: cab linking support for sgtetris 2025-08-29 09:12:55 +02:00
Flyinghead 9c5408a6d3 macOS build fix
Work around brew change: https://github.com/Homebrew/brew/pull/20414
2025-08-20 14:55:37 +02:00
Eric Warmenhoven d3dcb13ef9 Update .gitlab-ci.yml 2025-08-18 14:40:14 +02:00
Flyinghead 2cb2ac23e0 force real bios for wsb2k2
Issue #1757
2025-08-18 14:39:39 +02:00
Flyinghead e38b0ac01f naomi: delete some unnecessary eeproms
Issue #2023
Fix some warnings
2025-08-14 14:30:20 +02:00
Flyinghead 09b27ddd5c maple: use PantherDC id for full controller. ui: buttons and axes state
Use actual Panther DC identifier for full controller. Fixes KISS: Psycho
Circus.
Issue #2026
Show current state of mapped gamepad buttons and axes in controller
mapping.
2025-08-13 18:26:26 +02:00
Flyinghead 33833cfd1e vonot: don't disable VM when acting as master
Issue #2037
2025-08-12 17:30:22 +02:00
Edward Li 3c5c1e0b66 Indentation should use <space> in imgui_impl_vulkan.cpp 2025-08-12 15:40:14 +02:00
Edward Li 3f446a5835 Use target_compile_definitions to disable imgui shell functions for Switch 2025-08-12 15:40:14 +02:00
Edward Li df3c676a04 chmod 644 2025-08-12 15:40:14 +02:00
Edward Li 9ff3ab618c Fix OpenGL3 and Vulkan backend 2025-08-12 15:40:14 +02:00
Edward Li ba33b8c3f7 IMGUI_DISABLE_DEFAULT_SHELL_FUNCTIONS for Switch 2025-08-12 15:40:14 +02:00
Edward Li eab13e85bc minor fixes 2025-08-12 15:40:14 +02:00
Edward Li a1f1c9825a Fix EllipsisCharCount
Fonts: Rasterizing ellipsis character from dot as one glyph + avoid preloading if it not needed. https://github.com/ocornut/imgui/commit/4ff1631b316fe849da9a649cf30a79aad752d8bb
2025-08-12 15:40:14 +02:00
Edward Li 43a9c1384a Replace ImFont->FontSize with ImFont->LegacySize 2025-08-12 15:40:14 +02:00
Edward Li b4ab21a768 Reapply ImGuiWindowFlags_DragScrolling 2025-08-12 15:40:14 +02:00
Edward Li 30365d13ef replace with upstream v1.92.1 files 2025-08-12 15:40:14 +02:00
scribam f7eae0ff9e deps: update glslang (#1920) 2025-08-11 17:23:33 +02:00
sonninnos e26f170558 Libretro updates (#2033)
Add -Wno-misleading-indentation
Libretro av_info fps timing correction
Stop forcing audio muting on libretro fast-forward
Allow less strict chd extensions
2025-08-11 09:38:59 +02:00
github-actions[bot] 40e400ab08 Fetch translations & Recreate libretro_core_options_intl.h 2025-08-01 22:21:35 +00:00
github-actions[bot] 5743502cdd Fetch translations & Recreate libretro_core_options_intl.h 2025-07-25 22:21:43 +00:00
Flyinghead 8f33b63153 linux build: fix AppImageTool location 2025-07-22 15:37:54 +02:00
Flyinghead 6fca05f00e sdl: set default axis direction for all axes
Fixes regression with known gamepads.
Only use initial state for unknown controllers.
Issue #2014
2025-07-22 15:24:05 +02:00
Flyinghead 8c07a2e1d6 sdl: detect half-axes using initial state. Fix axis range and direction
Assume that full axes are roughly centered at start up and determine
which axis are half ones, and the axis direction.
Fixes driving wheel pedals range to the expected [0, 32767].
Issue #2014
2025-07-18 11:38:15 +02:00
desyn ffbe266413 bump minimal rcheevos 2025-07-15 15:52:07 +02:00
Flyinghead 5d3b7fae6b libretro: boot dreamcast bios when loading core without content
Get rid of "Boot to BIOS" core setting.
Issue #2007
2025-07-15 15:49:32 +02:00
Flyinghead 738b95d2be miniupnpc: include cstddef before miniupnpc headers
Issue #2010
2025-07-15 15:30:15 +02:00
github-actions[bot] 48c58dbd18 Fetch translations & Recreate libretro_core_options_intl.h 2025-07-11 22:21:51 +00:00
James 54b06a5c34 Recover DreamLink hardware after load state (#2003) 2025-07-10 20:32:00 +02:00
Flyinghead d3a46a1e33 windows: fix crash caused by regression
introduced by 6ea61b9
Issue #2001
2025-07-08 12:36:52 +02:00
Rikki Gibson 4fe2f4760f DreamConn: do not lock mutex multiple times 2025-07-07 11:28:27 +02:00
Flyinghead c0809d771d dcnet: support for Pro Yakyuu Team de Asobou Net!
Delete fakeTCP power smash cheat (not needed)
Add pro yakyuu team cheats
dcnet: Use same port as power smash for pro yakyuu team
2025-07-07 11:26:08 +02:00
Flyinghead 54ed92e2b0 fix ggpo regression
introduced by 4baf529ff7
2025-07-06 22:18:58 +02:00
Flyinghead 6ea61b9084 android: support 4KB and 16KB page sizes on 64-bit platforms 2025-07-06 22:16:06 +02:00
Flyinghead f3e0f09ca9 upgrade oboe and libadrenotools to latest 2025-07-06 18:51:51 +02:00
scribam 301b1a0f00 input: set InputMapping::INVALID_CODE as constexpr 2025-07-06 18:09:23 +02:00
scribam b787427446 android: update gradle and agp 2025-07-06 18:08:54 +02:00
Flyinghead 5df5c70994 dcnet: Power Smash support 2025-07-03 17:18:46 +02:00
Shockblast 75defb590b fix: added missing addrspace inclusion in settings.cpp for GDB_SERVER 2025-07-01 19:29:16 +02:00
scribam fbeaf8ba16 ci: fix switch libretro artifact location 2025-06-30 21:34:41 +02:00
github-actions[bot] 3f79b6baed Fetch translations & Recreate libretro_core_options_intl.h 2025-06-27 22:21:54 +00:00
Flyinghead 34f095a91e mingw build fix 2025-06-24 17:19:12 +02:00
Flyinghead 09247b4503 picotcp: use random local UDP port if already in use
Bind to random local UDP port if requested one is in use.
Log to NETWORK instead of MODEM.
Fix get_last_error name conflict with asio.
2025-06-24 16:54:57 +02:00
scribam 109e084e18 deps: update glslang (#1920) 2025-06-24 16:54:29 +02:00
Isaac Marovitz af043c55cd CMake Refactors (#1979)
Signed-off-by: Isaac Marovitz <[email protected]>
2025-06-24 16:33:12 +02:00
Flyinghead 04999d8969 sh4: fix wince api trace calls 2025-06-21 10:25:52 +02:00
Flyinghead 26b8684e78 serial: don't depend on SerialPTY option on windows
On windows, open serial console window when config::SerialConsole is
enabled. Ignore config::SerialPTY.
2025-06-21 10:23:22 +02:00
Flyinghead eefcb0e05d picotcp: improve ppp dump time resolution 2025-06-21 10:17:09 +02:00
github-actions[bot] 449d256995 Fetch translations & Recreate libretro_core_options_intl.h 2025-06-20 22:21:29 +00:00
Flyinghead 0897f0ed8a ui: split settings into their own files 2025-06-19 23:13:47 +02:00
Flyinghead 9bdb90e605 vk: add missing pp_Texture vertex param (naomi 2) 2025-06-19 17:48:20 +02:00
Flyinghead 5b75975237 naomi: fix zombie revenge analog stick for P2
Issue #1980
2025-06-19 17:29:25 +02:00
Flyinghead c73336a86f boxart: don't save absolute paths for images
Issue #1935
2025-06-17 17:13:27 +02:00
Flyinghead 27318443a7 more atomiswave code into its own files 2025-06-16 22:21:10 +02:00
Flyinghead df93c069f2 sdl: add sdl_gamepad.cpp 2025-06-16 18:50:37 +02:00
Flyinghead 7358f29556 naomi: refactor midiffb into its own file 2025-06-16 18:13:36 +02:00
Flyinghead 8801b2ae16 haptic: add sine effect. implement spring for midi FFB
Add sine effect to haptic api and stop using maple rumble for naomi FFB.
Emulate spring in midi FFB. Thanks to njz3 for his help on decoding the
protocol.
Don't use exponential scale for rumble when using haptic sine effect.

serialize Sh4OCache::writeBack/ThroughBufferCycles
2025-06-16 17:50:36 +02:00
github-actions[bot] b10db5a078 Fetch translations & Recreate libretro_core_options_intl.h 2025-06-13 22:21:19 +00:00
xander-will 71341a27e4 Integer Scaling + Screen-Level Linear Interpolation Options (#1976) 2025-06-13 11:59:15 +02:00
Flyinghead 7e7f645f37 sdl: use SDL_HAPTIC_STEERING_AXIS instead of SDL_HAPTIC_CARTESIAN
tentative fix for Issue #1962
2025-06-13 11:58:19 +02:00
oltolm 146e90dae6 Fix MSYS2 build (#1975)
* fix GCC build
* revert c53a1c42c6
it was fixed in https://sourceforge.net/p/mingw-w64/mingw-w64/ci/251fc7e1c3bd3509e291c1862ee745fce8550360
2025-06-13 09:55:41 +02:00
Flyinghead bb5bd71437 Merge remote-tracking branch 'origin/master' into dev 2025-06-07 16:08:03 +02:00
Flyinghead e8217ca0c5 fix input mapping regressions
Emulator keyboard bindings no longer working when UI is open (Exit).
All-ports mapping not being loaded correctly.
All-ports mapping not working on ports B,C and D.
Restore automatic binding of opposite key/axis.
caused by 64b9e51af0
2025-06-07 16:05:34 +02:00
github-actions[bot] 8f033723a1 Fetch translations & Recreate libretro_core_options_intl.h 2025-06-06 22:21:35 +00:00
Flyinghead b097aa3331 dropping iOS support
well done Gabe!
2025-06-06 09:08:14 +02:00
nexus382andJames Smith 64b9e51af0 button mapping multi binds (#1938)
Add button combination mappping support
- Implement tracking of pressed buttons in GamepadDevice
- Add ability to detect button combinations- Fix mapping system to preserve individual button mappings
- Ensure buttons can work both individually and as part of combinations
- Ensured trigger buttons can be the first button in a combination
- Maintained detection state when binding multiple buttons
- Added special handling to recognize both original and normalized trigger codes

---------

Co-authored-by: James Smith <[email protected]>
2025-06-03 16:28:51 +02:00
nexus382andJames Smith 9b91430513 Flycast UI Themes (#1929)
Added a Theme selection system.
---------
Co-authored-by: James Smith <[email protected]>
2025-06-01 19:03:42 +02:00
Flyinghead d9ec0cb3ab map dinoking P2 rock button to P1 button 4. Show on vgamepad
Remap player 2 Rock button to player 1 button 4 and display on vgamepad
so it's accessible on mobile devices.
Issue #1969
2025-06-01 10:57:59 +02:00
Flyinghead 39d68ec7fa sdl: don't reset haptic gain to 0 on exit
Issue #1963
2025-06-01 10:52:29 +02:00
github-actions[bot] a1a782df38 Fetch translations & Recreate libretro_core_options_intl.h 2025-05-30 22:21:39 +00:00
scribam acc106e988 cmake: disable link option --execute-only on openbsd 2025-05-30 18:45:55 +02:00
Flyinghead 11de0eda13 dx9: half-pixel shift left, not right
Fixes shifting of doom64 screen melt effect
Issue #1939
2025-05-30 18:45:18 +02:00
scribam a7148ad7ae cmake: use c++ extensions for alloca on netbsd/arm64 2025-05-26 19:27:55 +02:00
Flyinghead 27f19a5b54 rend: fix dithering kernel
Use the actual PVR2 dithering kernel (standard 4x4 Bayer matrix) used on
real hardware.
Fixes the screen melt effect of Doom64 (per-pixel only).
Issue #1939
2025-05-26 19:27:02 +02:00
scribam b973453317 ci: build uwp for ARM64 and Win32 2025-05-24 19:24:24 +02:00
github-actions[bot] ffaada9e9d Fetch translations & Recreate libretro_core_options_intl.h 2025-05-23 22:21:23 +00:00
Flyinghead 1953eb0eea outtrigger (US) widescreen cheat. Propeller arena modem string patch 2025-05-22 20:23:23 +02:00
scribam c3275d3c6f ci: update bsd workflows 2025-05-21 23:22:47 +02:00
Flyinghead 5e769d5cd2 Merge remote-tracking branch 'origin/master' into dev 2025-05-21 23:21:49 +02:00
Flyinghead f26e10e44a modem string patch for Mobile Suit Gundam: Federation vs.Zeon
Set minimum tx and rx speed to 0.
2025-05-21 08:28:29 +02:00
Flyinghead 3d60fc8c60 Revert "core/deps/picotcp/modules/pico_tcp.c: More checks for correct header sizes"
This reverts commit ffc32d2d86.
PR #1937
2025-05-21 08:22:35 +02:00
Flyinghead 7adeb53aee arm64 rec: fix typo in FTRC implementation
Issue #1905
2025-05-20 08:52:09 +02:00
James eacadf24a6 DreamPicoPort Mapping Updates (for maraca support) (#1940)
Add rightx and righty for DreamPicoPort (for maraca support)
Add secondary d-pad to dreampicoport mapping
Allow DreamLink device to dictate button/axis name; set custom button names in DreamPicoPort to known codes
2025-05-19 10:37:03 +02:00
Flyinghead 8e14c7f394 Merge remote-tracking branch 'origin/master' into dev 2025-05-18 20:28:41 +02:00
Flyinghead a842edb09e naomi: add mushi2k3 rom 2025-05-18 12:40:49 +02:00
github-actions[bot] e2247e4872 Fetch translations & Recreate libretro_core_options_intl.h 2025-05-16 22:21:04 +00:00
Flyinghead eb662da389 flash: add bba settings if missing. cheats for outtrigger and bomberman
Add bba config information to flash if missing. Fixes outtrigger.
cheat: Enable automode in modem connection string for Bomberman Online
and Outtrigger (US)
cheat: disable dricas auth for outtrigger (JP)
2025-05-15 16:46:54 +02:00
Flyinghead 2b79f93d6b ui: dcnet is no longer experimental 2025-05-14 19:50:14 +02:00
npt-1707 ffc32d2d86 core/deps/picotcp/modules/pico_tcp.c: More checks for correct header sizes 2025-05-10 20:56:59 +02:00
Flyinghead 892cdb7cea x86 dynarec: fix crash
Regression due to e394840344
Fixes MINIDUMP-6RC
2025-05-10 20:56:21 +02:00
Flyinghead 90ed30f70c appimage: fix some missing shared libraries
Issue #1930
2025-05-08 21:43:40 +02:00
scribam 34f8ab292f deps: update sdl to version 2.32.6 2025-05-04 20:57:18 +02:00
Flyinghead e1ab9af89d oit: incorrect color used when src=OTHER_COLOR if dest is 2nd accum
Using src=OTHER_COLOR with destination secondary accumulator should use
the secondary accumulator color, not the final one.
Fixes dark gun in Doom 64 with Ultra graphics (bump mapping).
Issue #1771
2025-05-02 17:46:29 +02:00
Flyinghead 3330225de4 vk: (mali) add subpass dependency from subpass 2 to external
Add subpass dependency from the last subpass to external/top of pipe.
Fix glitches in upper left corner when using OIT on Mali GPUs.
Issue #1014
Issue #1234
Issue #1356
Issue #1497
Issue #1852
2025-05-02 15:37:29 +02:00
Flyinghead 58ce9a4159 vk: (mali) add memory barrier in GetLastFrame
Add memory barrier between drawing and transfer.
Fix savestate thumbnail image corruption.
Issue #1922
2025-05-02 15:30:45 +02:00
Flyinghead 1b5c8678a4 dreampi: select best access point when connecting 2025-04-30 23:02:41 +02:00
Flyinghead c20ec680a8 Merge remote-tracking branch 'origin/master' into dev 2025-04-30 22:58:14 +02:00
nexus382 f62582a4bd Screen position bug fix with multiple monitors (#1916) 2025-04-28 18:58:33 +02:00
James Smith 1273c06d4b Load mapping for sdl_gamepad through loadMapping() and getDefaultMapping() instead of custom implementation 2025-04-16 21:05:40 +02:00
Flyinghead 332be9c8aa linux AppImage build needs libfuse 2025-04-12 09:52:54 +02:00
Flyinghead 77776be20b upgrade xBRZ to 1.8 2025-04-12 09:34:39 +02:00
Flyinghead f7676faa68 ci: build AppImage with ubuntu 22 2025-04-12 09:33:26 +02:00
Flyinghead 10a5ed6cec network: ICE improvements
F355: flush tx buffer every 34 bytes
Flush tx/rx buffers when loading a state
Use moving average for stats
2025-04-08 21:40:26 +02:00
Flyinghead b9ba3f1e63 libretro and switch build fixes 2025-04-07 19:43:12 +02:00
JamesandNexus382 34fda43d9c DreamPicoPort fixes/enhancements (#1892)
* added getFunctionDefinitions
* Set DreamPort device default deadzone to 0% while preserving user customization
* Fixed default dead zone 0% for DreamPicoPort; set UsePhysicalVmuMemory default to true
* Use DisabledScope for UsePhysicalVmuMemory; moved DreamLinkGamepad::getDefaultMapping() to protected scope to match parent
* Set unique ID for DreamPicoPort devices so they enumerate the same way by flycast on every load
* Implement DreamLinkGamepad::resetMappingToDefault() and set C, D, and Z buttons for DreamPicoPort
---------
Co-authored-by: Nexus382 <[email protected]>
2025-04-07 19:23:14 +02:00
Flyinghead b602cc9c57 network: add ice/websocket match code system for battle cable 2025-04-07 19:22:02 +02:00
Flyinghead 63534c5d56 add websocket++ and libjuice as submodules 2025-04-07 18:06:44 +02:00
Flyinghead 0267de4997 upgrade xbyak to 7.23.1. Convert to git submodule 2025-04-07 17:58:21 +02:00
353 changed files with 37608 additions and 44213 deletions

No files matched your search

+1 -1
View File
@@ -11,7 +11,7 @@ jobs:
- name: Set up build environment
run: |
sudo apt-get update
sudo apt-get -y install ccache libcurl4-openssl-dev ninja-build
sudo apt-get -y install ccache cmake libcurl4-openssl-dev ninja-build
- uses: actions/checkout@v4
with:
+6 -6
View File
@@ -13,14 +13,14 @@ jobs:
architecture: [ arm64, x86-64 ]
include:
- operating_system: freebsd
version: '14.2'
pkginstall: sudo pkg install -y alsa-lib ccache cmake evdev-proto git libao libevdev libudev-devd libzip lua54 miniupnpc ninja pkgconf pulseaudio sdl2 libcdio
version: '14.3'
pkginstall: sudo pkg update && sudo pkg install -y alsa-lib ccache cmake evdev-proto git libao libevdev libudev-devd libzip lua54 miniupnpc ninja pkgconf pulseaudio sdl2 libcdio
- operating_system: netbsd
version: '10.1'
pkginstall: sudo pkgin update && sudo pkgin -y install alsa-lib ccache cmake gcc12 git libao libzip lua54 miniupnpc ninja-build pkgconf pulseaudio SDL2 libcdio && export PATH=/usr/pkg/gcc12/bin:$PATH
pkginstall: sudo pkgin update && sudo pkgin -y install alsa-lib ccache clang cmake git libao libzip lua54 miniupnpc ninja-build pkgconf pulseaudio SDL2 libcdio
- operating_system: openbsd
version: '7.6'
pkginstall: sudo pkg_add ccache cmake git libao libzip miniupnpc ninja pkgconf pulseaudio sdl2 libcdio
version: '7.7'
pkginstall: sudo pkg_add -u && sudo pkg_add ccache cmake git libao libzip miniupnpc ninja pkgconf pulseaudio sdl2 libcdio
exclude:
- architecture: arm64
@@ -36,7 +36,7 @@ jobs:
key: ccache-${{ matrix.operating_system }}-${{ matrix.architecture }}-${{ github.sha }}
restore-keys: ccache-${{ matrix.operating_system }}-${{ matrix.architecture }}-
- uses: cross-platform-actions/[email protected]7.0
- uses: cross-platform-actions/[email protected]9.0
with:
operating_system: ${{ matrix.operating_system }}
architecture: ${{ matrix.architecture }}
+2 -7
View File
@@ -19,7 +19,6 @@ jobs:
config:
- {name: i686-pc-windows-msvc, os: windows-latest, shell: cmd, arch: x86, cmakeArgs: -G Ninja, buildType: Release}
- {name: apple-darwin, os: macos-latest, shell: sh, cmakeArgs: -G Xcode -DUSE_DISCORD=ON, destDir: osx, buildType: RelWithDebInfo}
- {name: apple-ios, os: macos-latest, shell: sh, cmakeArgs: -DCMAKE_SYSTEM_NAME=iOS -G Xcode, destDir: ios, buildType: Release}
- {name: x86_64-pc-linux-gnu, os: ubuntu-22.04, shell: sh, cmakeArgs: -G Ninja -DUSE_DISCORD=ON -DUSE_LIBCDIO=ON, destDir: linux, buildType: RelWithDebInfo}
- {name: x86_64-pc-windows-msvc, os: windows-latest, shell: cmd, arch: x64, cmakeArgs: -G Ninja -DUSE_DISCORD=ON, buildType: Release}
- {name: x86_64-w64-mingw32, os: windows-latest, shell: 'msys2 {0}', cmakeArgs: -G Ninja -DUSE_DISCORD=ON -DUSE_LIBCDIO=ON, destDir: win, buildType: RelWithDebInfo}
@@ -34,7 +33,7 @@ jobs:
brew update || :
brew install libao ldid pulseaudio
brew uninstall --ignore-dependencies zstd
VULKAN_VER=1.3.261.1 && aria2c https://sdk.lunarg.com/sdk/download/$VULKAN_VER/mac/vulkansdk-macos-$VULKAN_VER.dmg
VULKAN_VER=1.3.290.0 && aria2c https://sdk.lunarg.com/sdk/download/$VULKAN_VER/mac/vulkansdk-macos-$VULKAN_VER.dmg
hdiutil attach ./vulkansdk-macos-*.dmg -mountpoint /Volumes/VulkanSDK
sudo /Volumes/VulkanSDK/InstallVulkan.app/Contents/MacOS/InstallVulkan --root $HOME/VulkanSDK --accept-licenses --default-answer --confirm-command install
hdiutil detach /Volumes/VulkanSDK
@@ -73,13 +72,9 @@ jobs:
submodules: recursive
- name: Compile a universal OpenMP (macOS)
run: HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK=1 brew reinstall --build-from-source --formula ./shell/apple/libomp.rb
run: HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK=1 HOMEBREW_DEVELOPER=1 brew reinstall --build-from-source --formula ./shell/apple/libomp.rb
if: matrix.config.name == 'apple-darwin'
- name: Compile OpenMP.xcframework (iOS)
run: ./shell/apple/emulator-ios/OpenMP/build_ios_openmp.sh --disableSimulator
if: matrix.config.name == 'apple-ios'
- uses: actions/cache@v4
with:
path: ${{ env.CCACHE_DIR }}
+4 -2
View File
@@ -18,7 +18,7 @@ jobs:
- name: Set up build environment
run: |
sudo apt-get update
sudo apt-get -y install ccache
sudo apt-get -y install ccache cmake
- uses: actions/checkout@v4
with:
@@ -42,7 +42,9 @@ jobs:
- uses: actions/upload-artifact@v4
with:
name: flycast-switch-${{ matrix.config.name }}
path: artifact/bin
path: |
artifact/bin
artifact/lib/libretro
- name: Package app
run: zip -m artifact/bin/flycast.nro.zip artifact/bin/flycast.nro
+8 -4
View File
@@ -7,6 +7,10 @@ jobs:
name: UWP
runs-on: windows-latest
strategy:
matrix:
arch: [ Win32, x64, ARM64 ]
steps:
- uses: actions/checkout@v4
with:
@@ -15,7 +19,7 @@ jobs:
- name: CMake
run: |
cmake -B build -DCMAKE_BUILD_TYPE=Release -G "Visual Studio 17 2022" -A x64 -DCMAKE_SYSTEM_NAME=WindowsStore -DCMAKE_SYSTEM_VERSION=10.0.22000.0
cmake -B build -DCMAKE_BUILD_TYPE=Release -G "Visual Studio 17 2022" -A ${{ matrix.arch }} -DCMAKE_SYSTEM_NAME=WindowsStore -DCMAKE_SYSTEM_VERSION=10.0.22000.0
cmake --build build --config Release -- /m
shell: cmd
@@ -24,7 +28,7 @@ jobs:
- name: Package app
run: |
mkdir build\artifact
cd build\AppPackages\flycast\flycast_*_x64_Test
cd build\AppPackages\flycast\flycast_*_Test
mkdir tmp
ren *.msix flycast.msix
makeappx.exe unpack /p .\flycast.msix /d tmp
@@ -37,7 +41,7 @@ jobs:
- uses: actions/upload-artifact@v4
with:
name: flycast-uwp
name: flycast-uwp-${{ matrix.arch }}
path: build/artifact
- name: Setup Rclone
@@ -48,4 +52,4 @@ jobs:
- name: Upload to S3
run: rclone copy build/artifact scaleway:flycast-builds/xbox/${GITHUB_REF#refs/}-$GITHUB_SHA
shell: bash
if: github.repository == 'flyinghead/flycast' && github.event_name == 'push'
if: github.repository == 'flyinghead/flycast' && github.event_name == 'push' && matrix.arch == 'x64'
+13 -6
View File
@@ -9,34 +9,38 @@
variables:
GIT_SUBMODULE_STRATEGY: recursive
CORENAME: flycast
CORE_ARGS: -DLIBRETRO=ON -DUSE_LIBCDIO=ON -DCMAKE_BUILD_TYPE=Release
CORE_ARGS: -DLIBRETRO=ON -DUSE_LIBCDIO=ON
.core-defs-linux:
extends: .core-defs
variables:
CORE_ARGS: -DLIBRETRO=ON -DUSE_LIBCDIO=ON -DCMAKE_POSITION_INDEPENDENT_CODE=TRUE -DCMAKE_BUILD_TYPE=Release
CORE_ARGS: -DLIBRETRO=ON -DUSE_LIBCDIO=ON -DCMAKE_POSITION_INDEPENDENT_CODE=TRUE
CC: /usr/bin/gcc-12
CXX: /usr/bin/g++-12
.core-defs-osx-x64:
extends: .core-defs
variables:
CORE_ARGS: -DLIBRETRO=ON -G Xcode -DCMAKE_BUILD_TYPE=Release -DCMAKE_OSX_ARCHITECTURES=x86_64
CORE_ARGS: -DLIBRETRO=ON -G Xcode -DCMAKE_OSX_ARCHITECTURES=x86_64
EXTRA_PATH: Release
.core-defs-osx-arm64:
extends: .core-defs
variables:
CORE_ARGS: -DLIBRETRO=ON -G Xcode -DCMAKE_BUILD_TYPE=Release
CORE_ARGS: -DLIBRETRO=ON -G Xcode
EXTRA_PATH: Release
.core-defs-ios-arm64:
extends: .core-defs
variables:
CORE_ARGS: -DLIBRETRO=ON -DCMAKE_BUILD_TYPE=Release
CORE_ARGS: -DLIBRETRO=ON -DUSE_OPENMP=OFF -DCMAKE_OSX_DEPLOYMENT_TARGET=13.0
IOS_MINVER: 13.0
MINVER: 13.0
.core-defs-android:
extends: .core-defs
script:
- cmake -DLIBRETRO=ON -DCMAKE_BUILD_TYPE=Release -DANDROID_PLATFORM=android-$API_LEVEL -DCMAKE_TOOLCHAIN_FILE=$NDK_ROOT/build/cmake/android.toolchain.cmake -DANDROID_STL=c++_static -DANDROID_ABI=$ANDROID_ABI -DANDROID_ARM_MODE=arm "$CMAKE_SOURCE_ROOT" -B$BUILD_DIR
- cmake -DLIBRETRO=ON -DUSE_OPENMP=OFF -DANDROID_PLATFORM=android-$API_LEVEL -DCMAKE_TOOLCHAIN_FILE=$NDK_ROOT/build/cmake/android.toolchain.cmake -DANDROID_STL=c++_static -DANDROID_ABI=$ANDROID_ABI -DANDROID_ARM_MODE=arm "$CMAKE_SOURCE_ROOT" -B$BUILD_DIR
- cmake --build $BUILD_DIR --target ${CORENAME}_libretro --config Release -- -j $NUMPROC
- mv $BUILD_DIR/${CORENAME}_libretro.so $LIBNAME
- if [ $STRIP_CORE_LIB -eq 1 ]; then $NDK_ROOT/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-strip $LIBNAME; fi
@@ -108,12 +112,14 @@ libretro-build-linux-x64:
extends:
- .libretro-linux-cmake-x86_64
- .core-defs-linux
image: $CI_SERVER_HOST:5050/libretro-infrastructure/libretro-build-amd64-ubuntu:backports
# Linux 32-bit
libretro-build-linux-i686:
extends:
- .libretro-linux-cmake-x86
- .core-defs-linux
image: $CI_SERVER_HOST:5050/libretro-infrastructure/libretro-build-i386-ubuntu:backports
# MacOS 64-bit
libretro-build-osx-x64:
@@ -171,3 +177,4 @@ libretro-build-tvos-arm64:
extends:
- .libretro-tvos-cmake-arm64
- .core-defs-ios-arm64
+15
View File
@@ -44,3 +44,18 @@
[submodule "core/deps/asio"]
path = core/deps/asio
url = https://github.com/flyinghead/asio.git
[submodule "core/deps/xbyak"]
path = core/deps/xbyak
url = https://github.com/herumi/xbyak.git
[submodule "core/deps/libjuice"]
path = core/deps/libjuice
url = https://github.com/paullouisageneau/libjuice.git
[submodule "core/deps/websocketpp"]
path = core/deps/websocketpp
url = https://github.com/zaphoyd/websocketpp.git
[submodule "core/deps/DreamPicoPort-API"]
path = core/deps/DreamPicoPort-API
url = https://github.com/OrangeFox86/DreamPicoPort-API.git
[submodule "core/deps/libusb-cmake"]
path = core/deps/libusb-cmake
url = https://github.com/libusb/libusb-cmake.git
+117 -477
View File
@@ -1,4 +1,10 @@
cmake_minimum_required(VERSION 3.10.2)
if(APPLE AND NOT LIBRETRO)
# Requirement from SDL
# Minimum version for $<LINK_LIBRARY:feature,library-list>
cmake_minimum_required(VERSION 3.24)
else()
cmake_minimum_required(VERSION 3.22.1)
endif()
find_program(CCACHE_PROGRAM ccache)
if(CCACHE_PROGRAM)
@@ -10,6 +16,11 @@ set(SENTRY_UPLOAD_URL "" CACHE STRING "Sentry upload URL")
set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/shell/cmake")
# Set WINDOWS_STORE flag for UWP builds
if(CMAKE_SYSTEM_NAME STREQUAL "WindowsStore")
set(WINDOWS_STORE TRUE)
endif()
if(APPLE)
if(CMAKE_SYSTEM_NAME STREQUAL iOS)
set(CMAKE_OSX_DEPLOYMENT_TARGET "12.0" CACHE STRING "Minimum iOS deployment version")
@@ -18,7 +29,7 @@ if(APPLE)
set(CMAKE_OSX_DEPLOYMENT_TARGET "12.0" CACHE STRING "Minimum tvOS deployment version")
set(CMAKE_OSX_ARCHITECTURES "arm64" CACHE STRING "")
else()
set(CMAKE_OSX_DEPLOYMENT_TARGET "10.13" CACHE STRING "Minimum macOS deployment version")
set(CMAKE_OSX_DEPLOYMENT_TARGET "10.15" CACHE STRING "Minimum macOS deployment version")
set(CMAKE_OSX_ARCHITECTURES "x86_64;arm64" CACHE STRING "")
endif()
set(ZLIB_LIBRARY "-lz" CACHE STRING "Use generic linker flag for Xcode to support multiple SDKs")
@@ -32,7 +43,7 @@ endif()
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
if(NINTENDO_SWITCH)
if(CMAKE_SYSTEM_NAME STREQUAL "NetBSD" OR NINTENDO_SWITCH)
set(CMAKE_CXX_EXTENSIONS ON)
else()
set(CMAKE_CXX_EXTENSIONS OFF)
@@ -44,6 +55,11 @@ if(NOT DEFINED ARCHITECTURE)
endif()
message(STATUS "Target architecture: ${ARCHITECTURE}")
if(CMAKE_CXX_COMPILER MATCHES "webos" OR
CMAKE_CXX_COMPILER MATCHES "starfish")
set(WEBOS ON)
endif()
set(USE_HOST_SDL_DEFAULT OFF)
if(NOT APPLE AND (NOT UNIX OR CMAKE_SYSTEM_NAME MATCHES "(FreeBSD|OpenBSD|NetBSD)"))
set(USE_HOST_SDL_DEFAULT ON)
@@ -83,6 +99,12 @@ if(IOS AND NOT LIBRETRO)
set(USE_VULKAN OFF CACHE BOOL "Force vulkan off" FORCE)
endif()
if(WEBOS)
set(USE_GLES2 ON CACHE BOOL "Use GLES2 API" FORCE)
set(USE_OPENMP OFF CACHE BOOL "Force openmp off" FORCE)
set(USE_VULKAN OFF CACHE BOOL "Force vulkan off" FORCE)
endif()
include(GNUInstallDirs)
include(CMakeRC)
@@ -153,7 +175,8 @@ if(NINTENDO_SWITCH)
ASIO_DISABLE_SERIAL_PORT
ESHUTDOWN=110
SA_RESTART=0
SA_NOCLDWAIT=0)
SA_NOCLDWAIT=0
IMGUI_DISABLE_DEFAULT_SHELL_FUNCTIONS)
elseif(LIBRETRO)
add_library(${PROJECT_NAME} SHARED core/emulator.cpp)
@@ -172,12 +195,13 @@ elseif(LIBRETRO)
set(CMAKE_SHARED_LIBRARY_PREFIX "")
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
target_compile_definitions(${PROJECT_NAME} PRIVATE LIBRETRO)
target_compile_options(${PROJECT_NAME} PRIVATE -Wno-misleading-indentation)
if(APPLE)
find_library(FOUNDATION Foundation)
target_link_libraries(${PROJECT_NAME} PRIVATE ${FOUNDATION})
endif()
if(ANDROID OR USE_GLES)
target_compile_definitions(${PROJECT_NAME} PRIVATE GLES GLES3 HAVE_OPENGLES HAVE_OPENGLES3)
target_compile_definitions(${PROJECT_NAME} PRIVATE GLES GLES3 HAVE_OPENGLES HAVE_OPENGLES3 HAVE_OIT)
elseif(IOS)
target_compile_definitions(${PROJECT_NAME} PRIVATE GLES GLES3 HAVE_OPENGLES HAVE_OPENGLES3)
find_library(OPENGLES OpenGLES)
@@ -265,6 +289,8 @@ target_compile_definitions(${PROJECT_NAME} PRIVATE
$<$<BOOL:${MSVC}>:_WINSOCK_DEPRECATED_NO_WARNING>
$<$<BOOL:${MSVC}>:NOMINMAX>
$<$<BOOL:${TEST_AUTOMATION}>:TEST_AUTOMATION>
$<$<BOOL:${WINDOWS_STORE}>:WINDOWS_STORE>
$<$<BOOL:${WINDOWS_STORE}>:TARGET_UWP>
$<$<BOOL:${WINDOWS_STORE}>:NOCRYPT>
$<$<BOOL:${WINDOWS_STORE}>:_WIN32_WINNT=0x0A00>
$<$<OR:$<BOOL:${MINGW}>,$<BOOL:${MSVC}>>:_USE_MATH_DEFINES>)
@@ -286,6 +312,10 @@ if(NINTENDO_SWITCH)
target_include_directories(${PROJECT_NAME} PRIVATE shell/switch)
endif()
if(CMAKE_SYSTEM_NAME STREQUAL "OpenBSD")
target_link_options(${PROJECT_NAME} PRIVATE "-Wl,--no-execute-only")
endif()
if(USE_BREAKPAD AND NOT LIBRETRO)
find_program(SH_EXECUTABLE sh)
if((ANDROID AND NOT CMAKE_HOST_SYSTEM_NAME STREQUAL "Windows") OR (MINGW AND SH_EXECUTABLE) OR (CMAKE_SYSTEM_NAME STREQUAL "Linux"))
@@ -373,6 +403,10 @@ if(USE_BREAKPAD AND NOT LIBRETRO)
endif()
if(USE_OPENMP)
if(APPLE AND IS_DIRECTORY "/opt/homebrew/opt/libomp")
list(PREPEND CMAKE_PREFIX_PATH "/opt/homebrew/opt/libomp")
message(STATUS "Found and using Homebrew libomp hint.")
endif()
find_package(OpenMP)
if(OpenMP_CXX_FOUND)
if(MINGW)
@@ -387,22 +421,6 @@ if(USE_OPENMP)
target_link_libraries(${PROJECT_NAME} PRIVATE OpenMP::OpenMP_CXX)
endif()
endif()
if(IOS)
message("-- Finding OpenMP.xcframework for iOS")
set(OPENMP_XCFRAMEWORK "${CMAKE_CURRENT_SOURCE_DIR}/shell/apple/emulator-ios/OpenMP/OpenMP.xcframework")
if(IS_DIRECTORY ${OPENMP_XCFRAMEWORK})
# CMake does not support linking xcframework directly atm. (see https://gitlab.kitware.com/cmake/cmake/-/issues/21752)
set(OPENMP_FRAMEWORK ${OPENMP_XCFRAMEWORK}/ios-arm64_arm64e/OpenMP.framework/Versions/A/libomp.a)
if(EXISTS ${OPENMP_FRAMEWORK})
message("-- Found OpenMP.xcframework: ${OPENMP_FRAMEWORK} (Linking static library before CMake support linking xcframework)")
target_link_libraries(${PROJECT_NAME} PRIVATE ${OPENMP_FRAMEWORK})
target_include_directories(${PROJECT_NAME} PRIVATE ${OPENMP_XCFRAMEWORK}/ios-arm64_arm64e/OpenMP.framework/Versions/A/Headers)
target_compile_options(${PROJECT_NAME} PRIVATE $<$<COMPILE_LANGUAGE:CXX>:-Xclang -fopenmp>)
endif()
else()
message("-- Could NOT find OpenMP.xcframework, compile it using shell/apple/emulator-ios/OpenMP/build_ios_openmp.sh")
endif()
endif()
endif()
option(BUILD_SHARED_LIBS "Build shared library" OFF)
@@ -419,14 +437,12 @@ if(USE_VULKAN)
find_package(glslang REQUIRED)
else()
option(BUILD_EXTERNAL "Build external dependencies in /External" OFF)
option(SKIP_GLSLANG_INSTALL "Skip installation" ON)
option(ENABLE_SPVREMAPPER "Enables building of SPVRemapper" OFF)
option(ENABLE_GLSLANG_BINARIES "Builds glslang and spirv-remap" OFF)
option(ENABLE_HLSL "Enables HLSL input support" OFF)
option(ENABLE_OPT "Enables spirv-opt capability if present" OFF)
option(ENABLE_PCH "Enables Precompiled header" OFF)
add_subdirectory(core/deps/glslang EXCLUDE_FROM_ALL)
add_library(glslang::glslang-default-resource-limits ALIAS glslang-default-resource-limits)
add_library(glslang::SPIRV ALIAS SPIRV)
endif()
target_link_libraries(${PROJECT_NAME} PRIVATE glslang::glslang-default-resource-limits glslang::SPIRV)
endif()
@@ -450,6 +466,32 @@ if(NOT LIBRETRO)
endif()
if(NOT ANDROID AND NOT IOS)
if (NOT NINTENDO_SWITCH)
# DreamLink enabled for non-mobile Linux, MacOS, and Windows
target_compile_definitions(${PROJECT_NAME} PRIVATE USE_DREAMLINK_DEVICES=1)
set(USE_DREAMLINK_DEVICES ON) # Must be set before adding core/sdl
if (WINDOWS_STORE)
# Use winrt implementation of the DreamPicoPort-API
option(DREAMPICOPORT_WITH_LIBUSB "Use libusb to access DreamPicoPort-API" OFF)
elseif (CMAKE_SYSTEM_NAME STREQUAL "FreeBSD")
# A version of libusb is installed in FreeBSD
find_package(PkgConfig REQUIRED)
pkg_check_modules(LIBUSB REQUIRED libusb-1.0)
set(DREAMPICOPORT_LIBUSB_LIBRARIES "${LIBUSB_LIBRARIES}" CACHE STRING "Name of the libusb library to link against")
set(DREAMPICOPORT_LIBUSB_INCLUDE_DIRS "${LIBUSB_INCLUDE_DIRS}" CACHE STRING "Path to libusb include directory, when applicable")
else()
# libusb
add_subdirectory(core/deps/libusb-cmake)
endif()
# DreamPicoPort-API
option(DREAMPICOPORT_ADD_LIBUSB "Add internal libusb library" OFF) # Already included above, when applicable
add_subdirectory(core/deps/DreamPicoPort-API)
target_link_libraries(${PROJECT_NAME} PRIVATE dream_pico_port_api)
endif()
if(USE_HOST_SDL)
find_package(SDL2 2.0.9)
endif()
@@ -475,18 +517,7 @@ if(NOT LIBRETRO)
endif()
target_compile_definitions(${PROJECT_NAME} PRIVATE USE_SDL USE_SDL_AUDIO)
target_sources(${PROJECT_NAME} PRIVATE
core/sdl/sdl.cpp
core/sdl/sdl.h
core/sdl/sdl_gamepad.h
core/sdl/sdl_keyboard.h
core/sdl/sdl_keyboard_mac.h
core/sdl/dreamlink.cpp
core/sdl/dreamlink.h
core/sdl/dreampicoport.cpp
core/sdl/dreampicoport.h
core/sdl/dreamconn.cpp
core/sdl/dreamconn.h)
add_subdirectory(core/sdl)
if((UNIX AND NOT APPLE) OR NINTENDO_SWITCH)
find_package(CURL REQUIRED)
@@ -726,6 +757,32 @@ if(WIN32)
target_include_directories(${PROJECT_NAME} PRIVATE core/deps/dirent)
endif()
if(NOT LIBRETRO AND NOT NINTENDO_SWITCH)
target_compile_definitions(${PROJECT_NAME} PRIVATE USE_ICE)
# libjuice
option(BUILD_SHARED_LIBS "Build shared libraries" OFF)
option(NO_SERVER "Disable server support" ON)
option(NO_TESTS "Disable tests build" ON)
add_subdirectory(core/deps/libjuice EXCLUDE_FROM_ALL)
target_link_libraries(${PROJECT_NAME} PRIVATE LibJuice::LibJuiceStatic)
# websocket++
target_include_directories(${PROJECT_NAME} PRIVATE core/deps/websocketpp)
target_compile_definitions(${PROJECT_NAME} PRIVATE ASIO_STANDALONE)
if (MSVC)
target_compile_definitions(${PROJECT_NAME} PRIVATE
_WEBSOCKETPP_CPP11_FUNCTIONAL_
_WEBSOCKETPP_CPP11_SYSTEM_ERROR_
_WEBSOCKETPP_CPP11_RANDOM_DEVICE_
_WEBSOCKETPP_CPP11_MEMORY_
_WEBSOCKETPP_CPP11_TYPE_TRAITS_)
elseif(MINGW)
target_compile_definitions(${PROJECT_NAME} PRIVATE _WEBSOCKETPP_CPP11_THREAD_)
else()
target_compile_definitions(${PROJECT_NAME} PRIVATE _WEBSOCKETPP_CPP11_STL_)
endif()
endif()
target_include_directories(${PROJECT_NAME} PRIVATE core/deps/picotcp/include core/deps/picotcp/modules)
target_sources(${PROJECT_NAME} PRIVATE
core/deps/picotcp/include/arch/pico_arm9.h
@@ -791,7 +848,10 @@ target_sources(${PROJECT_NAME} PRIVATE core/deps/lzma/7zArcIn.c core/deps/lzma/7
add_subdirectory(core/deps/libelf)
target_link_libraries(${PROJECT_NAME} PRIVATE elf)
if(NOT LIBRETRO)
target_compile_definitions(${PROJECT_NAME} PRIVATE IMGUI_DISABLE_DEMO_WINDOWS IMGUI_DEFINE_MATH_OPERATORS)
target_compile_definitions(${PROJECT_NAME} PRIVATE
IMGUI_DISABLE_DEMO_WINDOWS
IMGUI_DISABLE_DEBUG_TOOLS
IMGUI_DEFINE_MATH_OPERATORS)
target_include_directories(${PROJECT_NAME} PRIVATE core/deps/imgui core/deps/imgui/backends)
target_sources(${PROJECT_NAME} PRIVATE
core/deps/imgui/imgui.cpp
@@ -819,10 +879,8 @@ if(USE_DISCORD AND NOT LIBRETRO)
target_include_directories(${PROJECT_NAME} PRIVATE core/deps/discord-rpc/include)
target_link_libraries(${PROJECT_NAME} PRIVATE discord-rpc)
target_compile_definitions(${PROJECT_NAME} PRIVATE USE_DISCORD)
target_sources(${PROJECT_NAME} PRIVATE core/ui/discord.cpp)
endif()
cmrc_add_resource_library(flycast-resources ALIAS flycast::res NAMESPACE flycast)
target_link_libraries(${PROJECT_NAME} PRIVATE flycast::res)
if(LIBRETRO)
@@ -869,274 +927,23 @@ if(LIBRETRO)
endif()
endif()
target_sources(${PROJECT_NAME} PRIVATE
core/archive/7zArchive.cpp
core/archive/7zArchive.h
core/archive/archive.cpp
core/archive/archive.h
core/archive/rzip.cpp
core/archive/rzip.h
core/archive/ZipArchive.cpp
core/archive/ZipArchive.h
core/cfg/option.h)
add_subdirectory(core/archive)
add_subdirectory(core/cfg)
add_subdirectory(core/hw)
add_subdirectory(core/imgread)
add_subdirectory(core/input)
add_subdirectory(core/log)
add_subdirectory(core/network)
add_subdirectory(core/oslib)
add_subdirectory(core/audio)
add_subdirectory(core/reios)
add_subdirectory(core/achievements)
add_subdirectory(core/ui)
add_subdirectory(core/lua)
add_subdirectory(core/profiler)
add_subdirectory(core/wsi)
if(NOT LIBRETRO)
target_sources(${PROJECT_NAME} PRIVATE
core/cfg/cfg.cpp
core/cfg/cfg.h
core/cfg/cl.cpp
core/cfg/ini.cpp
core/cfg/ini.h
core/cfg/option.cpp)
endif()
target_sources(${PROJECT_NAME} PRIVATE
core/hw/hwreg.h
core/hw/aica/aica.cpp
core/hw/aica/aica.h
core/hw/aica/aica_if.cpp
core/hw/aica/aica_if.h
core/hw/aica/aica_mem.cpp
core/hw/aica/aica_mem.h
core/hw/aica/dsp.cpp
core/hw/aica/dsp.h
core/hw/aica/dsp_arm32.cpp
core/hw/aica/dsp_arm64.cpp
core/hw/aica/dsp_interp.cpp
core/hw/aica/dsp_x64.cpp
core/hw/aica/dsp_x86.cpp
core/hw/aica/sgc_if.cpp
core/hw/aica/sgc_if.h
core/hw/arm7/arm7.cpp
core/hw/arm7/arm7.h
core/hw/arm7/arm_mem.cpp
core/hw/arm7/arm_mem.h
core/hw/arm7/arm7_rec_arm32.cpp
core/hw/arm7/arm7_rec_arm64.cpp
core/hw/arm7/arm7_rec_x64.cpp
core/hw/arm7/arm7_rec.cpp
core/hw/arm7/arm7_rec.h
core/hw/arm7/arm-new.h
core/hw/bba/bba.h
core/hw/bba/bba.cpp
core/hw/bba/rtl8139c.h
core/hw/bba/rtl8139c.cpp
core/hw/flashrom/at93cxx.cpp
core/hw/flashrom/at93cxx.h
core/hw/flashrom/flashrom.cpp
core/hw/flashrom/flashrom.h
core/hw/flashrom/nvmem.cpp
core/hw/flashrom/nvmem.h
core/hw/flashrom/x76f100.cpp
core/hw/flashrom/x76f100.h
core/hw/gdrom/gdrom_if.h
core/hw/gdrom/gdrom_response.cpp
core/hw/gdrom/gdromv3.cpp
core/hw/gdrom/gdromv3.h
core/hw/holly/holly_intc.cpp
core/hw/holly/holly_intc.h
core/hw/holly/sb.cpp
core/hw/holly/sb.h
core/hw/holly/sb_mem.cpp
core/hw/holly/sb_mem.h
core/hw/maple/maple_cfg.cpp
core/hw/maple/maple_cfg.h
core/hw/maple/maple_devs.cpp
core/hw/maple/maple_devs.h
core/hw/maple/maple_helper.cpp
core/hw/maple/maple_helper.h
core/hw/maple/maple_if.cpp
core/hw/maple/maple_if.h
core/hw/maple/maple_jvs.cpp
core/hw/mem/addrspace.cpp
core/hw/mem/addrspace.h
core/hw/mem/mem_watch.cpp
core/hw/mem/mem_watch.h
core/hw/modem/modem.cpp
core/hw/modem/modem.h
core/hw/modem/modem_regs.h
core/hw/naomi/awave_regs.h
core/hw/naomi/awcartridge.cpp
core/hw/naomi/awcartridge.h
core/hw/naomi/decrypt.cpp
core/hw/naomi/decrypt.h
core/hw/naomi/gdcartridge.cpp
core/hw/naomi/gdcartridge.h
core/hw/naomi/m1cartridge.cpp
core/hw/naomi/m1cartridge.h
core/hw/naomi/m4cartridge.cpp
core/hw/naomi/m4cartridge.h
core/hw/naomi/multiboard.h
core/hw/naomi/multiboard.cpp
core/hw/naomi/naomi_cart.cpp
core/hw/naomi/naomi_cart.h
core/hw/naomi/naomi_flashrom.cpp
core/hw/naomi/naomi_flashrom.h
core/hw/naomi/naomi_m3comm.cpp
core/hw/naomi/naomi_m3comm.h
core/hw/naomi/naomi.cpp
core/hw/naomi/naomi.h
core/hw/naomi/naomi_regs.h
core/hw/naomi/naomi_roms.cpp
core/hw/naomi/naomi_roms.h
core/hw/naomi/naomi_roms_input.h
core/hw/naomi/netdimm.cpp
core/hw/naomi/netdimm.h
core/hw/naomi/card_reader.h
core/hw/naomi/card_reader.cpp
core/hw/naomi/touchscreen.h
core/hw/naomi/touchscreen.cpp
core/hw/naomi/printer.h
core/hw/naomi/printer.cpp
core/hw/naomi/systemsp.h
core/hw/naomi/systemsp.cpp
core/hw/naomi/hopper.h
core/hw/naomi/hopper.cpp
core/hw/pvr/elan.cpp
core/hw/pvr/elan.h
core/hw/pvr/elan_struct.h
core/hw/pvr/pvr.cpp
core/hw/pvr/pvr.h
core/hw/pvr/pvr_mem.cpp
core/hw/pvr/pvr_mem.h
core/hw/pvr/pvr_regs.cpp
core/hw/pvr/pvr_regs.h
core/hw/pvr/pvr_sb_regs.cpp
core/hw/pvr/pvr_sb_regs.h
core/hw/pvr/Renderer_if.cpp
core/hw/pvr/Renderer_if.h
core/hw/pvr/spg.cpp
core/hw/pvr/spg.h
core/hw/pvr/ta_const_df.h
core/hw/pvr/ta.cpp
core/hw/pvr/ta_ctx.cpp
core/hw/pvr/ta_ctx.h
core/hw/pvr/ta.h
core/hw/pvr/ta_structs.h
core/hw/pvr/ta_util.cpp
core/hw/pvr/ta_vtx.cpp
core/hw/sh4/dyna/blockmanager.cpp
core/hw/sh4/dyna/blockmanager.h
core/hw/sh4/dyna/decoder.cpp
core/hw/sh4/dyna/decoder.h
core/hw/sh4/dyna/decoder_opcodes.h
core/hw/sh4/dyna/driver.cpp
core/hw/sh4/dyna/ngen.h
core/hw/sh4/dyna/shil_canonical.h
core/hw/sh4/dyna/shil.cpp
core/hw/sh4/dyna/shil.h
core/hw/sh4/dyna/ssa.cpp
core/hw/sh4/dyna/ssa.h
core/hw/sh4/dyna/ssa_regalloc.h
core/hw/sh4/fsca-table.h
core/hw/sh4/interpr/sh4_fpu.cpp
core/hw/sh4/interpr/sh4_interpreter.cpp
core/hw/sh4/interpr/sh4_opcodes.cpp
core/hw/sh4/interpr/sh4_opcodes.h
core/hw/sh4/modules/bsc.cpp
core/hw/sh4/modules/ccn.cpp
core/hw/sh4/modules/ccn.h
core/hw/sh4/modules/cpg.cpp
core/hw/sh4/modules/dmac.cpp
core/hw/sh4/modules/dmac.h
core/hw/sh4/modules/fastmmu.cpp
core/hw/sh4/modules/intc.cpp
core/hw/sh4/modules/mmu.cpp
core/hw/sh4/modules/mmu.h
core/hw/sh4/modules/modules.h
core/hw/sh4/modules/rtc.cpp
core/hw/sh4/modules/serial.cpp
core/hw/sh4/modules/tmu.cpp
core/hw/sh4/modules/ubc.cpp
core/hw/sh4/modules/wince.h
core/hw/sh4/sh4_cache.h
core/hw/sh4/sh4_cycles.cpp
core/hw/sh4/sh4_cycles.h
core/hw/sh4/sh4_core.h
core/hw/sh4/sh4_core_regs.cpp
core/hw/sh4/sh4_if.h
core/hw/sh4/sh4_interpreter.h
core/hw/sh4/sh4_interrupts.cpp
core/hw/sh4/sh4_interrupts.h
core/hw/sh4/sh4_mem.cpp
core/hw/sh4/sh4_mem.h
core/hw/sh4/sh4_mmr.cpp
core/hw/sh4/sh4_mmr.h
core/hw/sh4/sh4_opcode_list.cpp
core/hw/sh4/sh4_opcode_list.h
core/hw/sh4/sh4_rom.cpp
core/hw/sh4/sh4_rom.h
core/hw/sh4/sh4_sched.cpp
core/hw/sh4/sh4_sched.h
core/hw/sh4/storeq.cpp)
cmrc_add_resources(flycast-resources
WHENCE resources
resources/flash/alienfnt.nvmem.zip # network settings
resources/flash/gunsur2.nvmem.zip
resources/flash/mazan.nvmem.zip # free play, calibrated
resources/flash/otrigger.nvmem.zip
resources/flash/wldkicks.nvmem.zip # free play
resources/flash/wldkicksj.nvmem.zip # free play
resources/flash/wldkicksu.nvmem.zip # free play
resources/flash/f355.nvmem.zip # printer on
resources/flash/f355twin.nvmem.zip # printer on
resources/flash/f355twn2.nvmem.zip # printer on
resources/flash/dirtypig.nvmem.zip # 4 players
resources/flash/dirtypig.nvmem2.zip
resources/flash/vf4.nvmem.zip # card all day, stage select
resources/flash/vf4evob.nvmem.zip # card all day, stage select
resources/flash/vf4tuned.nvmem.zip # card all day, stage select, 45 sec time limit, 3 match
resources/flash/magicpop.nvmem.zip # debug: comm and all errors disabled
resources/flash/ochaken.nvmem.zip # debug: comm and all errors disabled
resources/flash/puyomedal.nvmem.zip # debug: comm and all errors disabled
resources/flash/unomedal.nvmem.zip # debug: comm and all errors disabled
resources/flash/westdrmg.nvmem.zip # debug: comm and all errors disabled
resources/picture/f355_print_template.png)
cmrc_add_resources(flycast-resources
fonts/printer_ascii8x16.bin.zip
fonts/printer_ascii12x24.bin.zip
fonts/printer_kanji16x16.bin.zip
fonts/printer_kanji24x24.bin.zip)
if(NOT LIBRETRO)
cmrc_add_resources(flycast-resources
fonts/Roboto-Medium.ttf.zip
fonts/Roboto-Regular.ttf.zip
fonts/fa-solid-900.ttf.zip)
if(ANDROID OR IOS)
cmrc_add_resources(flycast-resources
WHENCE resources
resources/picture/buttons.png
resources/picture/buttons-arcade.png)
endif()
endif()
target_sources(${PROJECT_NAME} PRIVATE
core/imgread/cdi.cpp
core/imgread/cdio.cpp
core/imgread/chd.cpp
core/imgread/common.cpp
core/imgread/common.h
core/imgread/cue.cpp
core/imgread/gdi.cpp
core/imgread/ImgReader.cpp
core/imgread/iso9660.h
core/imgread/isofs.cpp
core/imgread/isofs.h)
if(NOT LIBRETRO)
target_sources(${PROJECT_NAME} PRIVATE
core/input/gamepad.h
core/input/gamepad_device.cpp
core/input/gamepad_device.h
core/input/keyboard_device.h
core/input/mapping.cpp
core/input/mapping.h
core/input/mouse.cpp
core/input/mouse.h)
endif()
include(cmake/resources.cmake)
if(WIN32)
target_sources(${PROJECT_NAME} PRIVATE
@@ -1151,14 +958,7 @@ else()
core/linux/posix_vmem.cpp
core/linux/unwind_info.cpp)
if(NINTENDO_SWITCH)
target_sources(${PROJECT_NAME} PRIVATE
shell/switch/libnx_vmem.cpp
shell/switch/stubs.c
shell/switch/context_switch.S
shell/switch/nswitch.h
shell/switch/switch_gamepad.h
shell/switch/switch_main.cpp
shell/switch/ucontext.h)
add_subdirectory(shell/switch)
endif()
endif()
@@ -1172,109 +972,6 @@ if(NOT LIBRETRO)
core/linux-dist/x11_keyboard.h)
endif()
target_sources(${PROJECT_NAME} PRIVATE
core/log/BitSet.h
core/log/Log.h
core/log/StringUtil.h)
if(NOT LIBRETRO)
target_sources(${PROJECT_NAME} PRIVATE
core/log/ConsoleListener.h
core/log/ConsoleListenerDroid.cpp
core/log/ConsoleListenerNix.cpp
core/log/ConsoleListenerWin.cpp
core/log/LogManager.cpp
core/log/LogManager.h)
endif()
target_sources(${PROJECT_NAME} PRIVATE
core/network/alienfnt_modem.cpp
core/network/alienfnt_modem.h
core/network/dns.cpp
core/network/ggpo.cpp
core/network/ggpo.h
core/network/miniupnp.cpp
core/network/miniupnp.h
core/network/naomi_network.cpp
core/network/naomi_network.h
core/network/net_handshake.cpp
core/network/net_handshake.h
core/network/net_platform.h
core/network/output.cpp
core/network/output.h
core/network/picoppp.cpp
core/network/picoppp.h
core/network/netservice.cpp
core/network/netservice.h
core/network/dcnet.cpp
core/network/dcnet.h)
if(ANDROID)
target_sources(${PROJECT_NAME} PRIVATE
core/network/ifaddrs.c)
endif()
if(NOT LIBRETRO)
target_sources(${PROJECT_NAME} PRIVATE
core/audio/audiobackend_alsa.cpp
core/audio/audiobackend_coreaudio.cpp
core/audio/audiobackend_directsound.cpp
core/audio/audiobackend_libao.cpp
core/audio/audiobackend_null.cpp
core/audio/audiobackend_oboe.cpp
core/audio/audiobackend_omx.cpp
core/audio/audiobackend_oss.cpp
core/audio/audiobackend_pulseaudio.cpp
core/audio/audiobackend_sdl2.cpp
core/audio/audiostream.cpp
core/oslib/http_client.cpp
core/oslib/http_client.h
core/oslib/oslib.cpp)
endif()
target_sources(${PROJECT_NAME} PRIVATE
core/audio/audiostream.h
core/oslib/directory.h
core/oslib/host_context.h
core/oslib/oslib.h
core/oslib/resources.cpp
core/oslib/resources.h
core/oslib/storage.cpp
core/oslib/storage.h
core/oslib/unwind_info.h
core/oslib/virtmem.h
core/lua/lua.cpp
core/lua/lua.h)
if (ENABLE_DC_PROFILER)
target_sources(${PROJECT_NAME} PRIVATE
core/profiler/dc_profiler.cpp
core/profiler/dc_profiler.h)
target_compile_definitions(${PROJECT_NAME} PRIVATE DC_PROFILER)
endif()
if (ENABLE_FC_PROFILER)
target_sources(${PROJECT_NAME} PRIVATE
core/profiler/fc_profiler.cpp
core/profiler/fc_profiler.h)
target_compile_definitions(${PROJECT_NAME} PRIVATE FC_PROFILER)
endif()
target_sources(${PROJECT_NAME} PRIVATE
core/reios/descrambl.cpp
core/reios/descrambl.h
core/reios/gdrom_hle.cpp
core/reios/gdrom_hle.h
core/reios/reios.cpp
core/reios/reios.h
core/reios/reios_elf.cpp
core/reios/reios_elf.h)
cmrc_add_resources(flycast-resources fonts/biosfont.bin.zip)
target_sources(${PROJECT_NAME} PRIVATE
core/achievements/achievements.cpp
core/achievements/achievements.h)
if(NOT LIBRETRO)
target_sources(${PROJECT_NAME} PRIVATE
core/deps/rcheevos/src/rc_client_raintegration.c
@@ -1310,23 +1007,8 @@ if(NOT LIBRETRO)
target_compile_definitions(${PROJECT_NAME} PRIVATE USE_RACHIEVEMENTS RC_DISABLE_LUA)
endif()
target_sources(${PROJECT_NAME} PRIVATE
core/wsi/context.h
core/wsi/libretro.cpp
core/wsi/libretro.h
core/wsi/switcher.cpp)
if(USE_OPENGL)
target_compile_definitions(${PROJECT_NAME} PRIVATE USE_OPENGL)
target_sources(${PROJECT_NAME} PRIVATE
core/wsi/egl.cpp
core/wsi/egl.h
core/wsi/gl_context.cpp
core/wsi/gl_context.h
core/wsi/osx.cpp
core/wsi/osx.h
core/wsi/sdl.cpp
core/wsi/sdl.h)
target_sources(${PROJECT_NAME} PRIVATE
core/rend/gles/glcache.h
@@ -1348,7 +1030,7 @@ if(USE_OPENGL)
core/rend/gles/opengl_driver.h)
endif()
if(NOT (APPLE OR ANDROID OR USE_GLES OR USE_GLES2))
if(NOT (APPLE OR USE_GLES2))
target_sources(${PROJECT_NAME} PRIVATE
core/rend/gl4/abuffer.cpp
core/rend/gl4/gl4.h
@@ -1385,29 +1067,6 @@ target_sources(${PROJECT_NAME} PRIVATE
core/rend/texconv.cpp
core/rend/texconv.h
core/rend/norend/norend.cpp)
if(NOT LIBRETRO)
target_sources(${PROJECT_NAME} PRIVATE
core/ui/game_scanner.cpp
core/ui/game_scanner.h
core/ui/imgui_driver.h
core/ui/gui.cpp
core/ui/gui.h
core/ui/gui_achievements.cpp
core/ui/vgamepad.cpp
core/ui/vgamepad.h
core/ui/gui_chat.h
core/ui/gui_cheats.cpp
core/ui/gui_util.cpp
core/ui/gui_util.h
core/ui/mainui.cpp
core/ui/mainui.h
core/ui/boxart/boxart.cpp
core/ui/boxart/boxart.h
core/ui/boxart/gamesdb.cpp
core/ui/boxart/gamesdb.h
core/ui/boxart/scraper.cpp
core/ui/boxart/scraper.h)
endif()
if(USE_VULKAN)
target_compile_definitions(${PROJECT_NAME} PUBLIC VK_ENABLE_BETA_EXTENSIONS VK_NO_PROTOTYPES)
@@ -1867,7 +1526,6 @@ if(NOT LIBRETRO)
endif()
elseif(WIN32)
target_sources(${PROJECT_NAME} PRIVATE
core/windows/clock.c
core/windows/rawinput.cpp
core/windows/rawinput.h)
if(NOT BUILD_TESTING)
@@ -1907,32 +1565,14 @@ if(NOT LIBRETRO)
endif()
target_sources(${PROJECT_NAME} PRIVATE shell/windows/flycast.rc)
target_link_libraries(${PROJECT_NAME} PRIVATE dsound winmm ws2_32 wsock32 xinput9_1_0 cfgmgr32 wininet psapi)
target_link_libraries(${PROJECT_NAME} PRIVATE dsound winmm ws2_32 wsock32 xinput9_1_0 cfgmgr32 wininet psapi setupapi)
endif()
endif()
endif()
if(BUILD_TESTING)
option(BUILD_GMOCK "Builds the googlemock subproject" OFF)
option(INSTALL_GTEST "Enable installation of googletest. (Projects embedding googletest may want to turn this OFF.)" OFF)
if(WIN32)
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
endif()
add_subdirectory(core/deps/googletest EXCLUDE_FROM_ALL)
target_link_libraries(${PROJECT_NAME} PRIVATE GTest::gtest_main)
target_sources(${PROJECT_NAME} PRIVATE
tests/src/CheatManagerTest.cpp
tests/src/ConfigFileTest.cpp
tests/src/div32_test.cpp
tests/src/test_stubs.cpp
tests/src/serialize_test.cpp
tests/src/AicaArmTest.cpp
tests/src/Sh4InterpreterTest.cpp
tests/src/MmuTest.cpp
tests/src/util/PeriodicThreadTest.cpp
tests/src/util/TsQueueTest.cpp
tests/src/util/WorkerThreadTest.cpp)
add_subdirectory(tests)
endif()
if(NINTENDO_SWITCH)
+4
View File
@@ -38,6 +38,10 @@ Install Flycast from [**Google Play**](https://play.google.com/store/apps/detail
`brew install --cask flycast`
### iOS
Due to persistent harassment from an iOS user, support for this platform has been dropped.
### Xbox One/Series ![xbox logo](https://flyinghead.github.io/flycast-builds/xbox.png)
Grab the latest build from [**the builds page**](https://flyinghead.github.io/flycast-builds/), or the [**GitHub Actions**](https://github.com/flyinghead/flycast/actions/workflows/uwp.yml). Then install it using the **Xbox Device Portal**.
+47
View File
@@ -0,0 +1,47 @@
cmrc_add_resource_library(flycast-resources ALIAS flycast::res NAMESPACE flycast)
cmrc_add_resources(flycast-resources
WHENCE resources
resources/flash/alienfnt.nvmem.zip # network settings
resources/flash/gunsur2.nvmem.zip
resources/flash/mazan.nvmem.zip # free play, calibrated
resources/flash/otrigger.nvmem.zip
resources/flash/wldkicks.nvmem.zip # free play
resources/flash/wldkicksj.nvmem.zip # free play
resources/flash/wldkicksu.nvmem.zip # free play
resources/flash/f355.nvmem.zip # printer on
resources/flash/f355twin.nvmem.zip # printer on
resources/flash/f355twn2.nvmem.zip # printer on
resources/flash/dirtypig.nvmem.zip # 4 players
resources/flash/dirtypig.nvmem2.zip
resources/flash/vf4.nvmem.zip # card all day, stage select
resources/flash/vf4evob.nvmem.zip # card all day, stage select
resources/flash/vf4tuned.nvmem.zip # card all day, stage select, 45 sec time limit, 3 match
resources/flash/magicpop.nvmem.zip # debug: comm and all errors disabled
resources/flash/ochaken.nvmem.zip # debug: comm and all errors disabled
resources/flash/puyomedal.nvmem.zip # debug: comm and all errors disabled
resources/flash/unomedal.nvmem.zip # debug: comm and all errors disabled
resources/flash/westdrmg.nvmem.zip # debug: comm and all errors disabled
resources/flash/smarinef.nvmem.zip # standard cabinet
resources/picture/f355_print_template.png)
cmrc_add_resources(flycast-resources
fonts/printer_ascii8x16.bin.zip
fonts/printer_ascii12x24.bin.zip
fonts/printer_kanji16x16.bin.zip
fonts/printer_kanji24x24.bin.zip)
if(NOT LIBRETRO)
cmrc_add_resources(flycast-resources
fonts/Roboto-Medium.ttf.zip
fonts/Roboto-Regular.ttf.zip
fonts/fa-solid-900.ttf.zip)
if(ANDROID OR IOS)
cmrc_add_resources(flycast-resources
WHENCE resources
resources/picture/buttons.png
resources/picture/buttons-arcade.png)
endif()
endif()
cmrc_add_resources(flycast-resources fonts/biosfont.bin.zip)
+3
View File
@@ -0,0 +1,3 @@
target_sources(${PROJECT_NAME} PRIVATE
achievements.cpp
achievements.h)
+9
View File
@@ -0,0 +1,9 @@
target_sources(${PROJECT_NAME} PRIVATE
7zArchive.cpp
7zArchive.h
archive.cpp
archive.h
rzip.cpp
rzip.h
ZipArchive.cpp
ZipArchive.h)
+17
View File
@@ -0,0 +1,17 @@
target_sources(${PROJECT_NAME} PRIVATE
audiostream.h)
if(NOT LIBRETRO)
target_sources(${PROJECT_NAME} PRIVATE
audiobackend_alsa.cpp
audiobackend_coreaudio.cpp
audiobackend_directsound.cpp
audiobackend_libao.cpp
audiobackend_null.cpp
audiobackend_oboe.cpp
audiobackend_omx.cpp
audiobackend_oss.cpp
audiobackend_pulseaudio.cpp
audiobackend_sdl2.cpp
audiostream.cpp)
endif()
+1 -1
View File
@@ -98,7 +98,7 @@
#ifdef _WIN32
#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP)
#define TARGET_UWP
#define TARGET_UWP 1
#endif
#ifdef HAVE_D3D11
#define USE_DX11
+12
View File
@@ -0,0 +1,12 @@
target_sources(${PROJECT_NAME} PRIVATE
option.h)
if(NOT LIBRETRO)
target_sources(${PROJECT_NAME} PRIVATE
cfg.cpp
cfg.h
cl.cpp
ini.cpp
ini.h
option.cpp)
endif()
+24 -2
View File
@@ -40,6 +40,7 @@ Option<bool> ForceFreePlay("ForceFreePlay", true);
Option<bool, false> FetchBoxart("FetchBoxart", true);
Option<bool, false> BoxartDisplayMode("BoxartDisplayMode", true);
Option<int, false> UIScaling("UIScaling", 100);
Option<int, false> UITheme("UITheme", 0);
// Sound
@@ -71,11 +72,13 @@ Option<bool> ShowFPS("rend.ShowFPS");
Option<bool> RenderToTextureBuffer("rend.RenderToTextureBuffer");
Option<bool> TranslucentPolygonDepthMask("rend.TranslucentPolygonDepthMask");
Option<bool> ModifierVolumes("rend.ModifierVolumes", true);
Option<int> TextureUpscale("rend.TextureUpscale", 1);
Option<int> TextureUpscale("rend.TextureUpscale2", 1);
Option<int> MaxFilteredTextureSize("rend.MaxFilteredTextureSize", 256);
Option<float> ExtraDepthScale("rend.ExtraDepthScale", 1.f);
Option<bool> CustomTextures("rend.CustomTextures");
Option<bool> PreloadCustomTextures("rend.PreloadCustomTextures");
Option<bool> DumpTextures("rend.DumpTextures");
Option<bool> DumpReplacedTextures("rend.DumpReplacedTextures");
Option<int> ScreenStretching("rend.ScreenStretching", 100);
Option<bool> Fog("rend.Fog", true);
Option<bool> FloatVMUs("rend.FloatVMUs");
@@ -98,6 +101,8 @@ Option<int> SkipFrame("ta.skip");
Option<int> MaxThreads("pvr.MaxThreads", 3);
Option<int> AutoSkipFrame("pvr.AutoSkipFrame", 0);
Option<int> RenderResolution("rend.Resolution", 480);
Option<bool> IntegerScale("rend.IntegerScale", false);
Option<bool> LinearInterpolation("rend.LinearInterpolation", true);
Option<bool> VSync("rend.vsync", true);
Option<int64_t> PixelBufferSize("rend.PixelBufferSize", 512_MB);
Option<int> AnisotropicFiltering("rend.AnisotropicFiltering", 1);
@@ -133,6 +138,15 @@ Option<bool> RamMod32MB("Dreamcast.RamMod32MB", false);
Option<bool> OpenGlChecks("OpenGlChecks", false, "validate");
Option<std::vector<std::string>, false> ContentPath("Dreamcast.ContentPath");
Option<std::vector<std::string>, false> BiosPath("Dreamcast.BiosPath");
Option<std::string, false> VMUPath("Dreamcast.VMUPath");
Option<std::vector<std::string>, false> SavestatePath("Dreamcast.SavestatePath");
Option<std::string, false> SavePath("Dreamcast.SavePath");
Option<std::vector<std::string>, false> TexturePath("Dreamcast.TexturePath");
Option<std::string, false> TextureDumpPath("Dreamcast.TextureDumpPath");
Option<std::string, false> BoxartPath("Dreamcast.BoxartPath");
Option<std::vector<std::string>, false> MappingsPath("Dreamcast.MappingsPath");
Option<std::vector<std::string>, false> CheatPath("Dreamcast.CheatPath");
Option<bool, false> HideLegacyNaomiRoms("Dreamcast.HideLegacyNaomiRoms", true);
Option<bool, false> UploadCrashLogs("UploadCrashLogs", true);
Option<bool, false> DiscordPresence("DiscordPresence", true);
@@ -199,11 +213,19 @@ std::array<std::array<Option<MapleDeviceType>, 2>, 4> MapleExpansionDevices {{
{{Option<MapleDeviceType>("device4.1", MDT_None, "input"),
Option<MapleDeviceType>("device4.2", MDT_None, "input")}},
}};
std::array<Option<bool>, 4> UseNetworkExpansionDevices{
Option<bool>("device1.UseNetworkExpansionDevices", false, "input"),
Option<bool>("device2.UseNetworkExpansionDevices", false, "input"),
Option<bool>("device3.UseNetworkExpansionDevices", false, "input"),
Option<bool>("device4.UseNetworkExpansionDevices", false, "input"),
};
Option<bool> PerGameVmu("PerGameVmu", false, "config");
#ifdef _WIN32
Option<bool, false> UseRawInput("RawInput", false, "input");
#endif
Option<bool> UsePhysicalVmuMemory("UsePhysicalVmuMemory", false);
Option<bool> UsePhysicalVmuMemory("UsePhysicalVmuMemory", true);
#ifdef USE_LUA
Option<std::string, false> LuaFileName("LuaFileName", "flycast.lua");
+15
View File
@@ -367,6 +367,7 @@ extern Option<bool> ForceFreePlay;
extern Option<bool, false> FetchBoxart;
extern Option<bool, false> BoxartDisplayMode;
extern Option<int, false> UIScaling;
extern Option<int, false> UITheme; // 0 -> Dark, 1 -> Light, 2 -> Dreamcast, 3 -> High Contrast, 4 -> Nintendo, 5 -> Aqua Chill
// Sound
@@ -445,7 +446,9 @@ extern Option<int> PerPixelLayers;
#endif
extern Option<float> ExtraDepthScale;
extern Option<bool> CustomTextures;
extern Option<bool> PreloadCustomTextures;
extern Option<bool> DumpTextures;
extern Option<bool> DumpReplacedTextures;
extern Option<int> ScreenStretching; // in percent. 150 means stretch from 4/3 to 6/3
extern Option<bool> Fog;
extern Option<bool> FloatVMUs;
@@ -459,6 +462,8 @@ extern Option<int> SkipFrame;
extern Option<int> MaxThreads;
extern Option<int> AutoSkipFrame; // 0: none, 1: some, 2: more
extern Option<int> RenderResolution;
extern Option<bool> IntegerScale;
extern Option<bool> LinearInterpolation;
extern Option<bool> VSync;
extern Option<int64_t> PixelBufferSize;
extern Option<int> AnisotropicFiltering;
@@ -489,6 +494,15 @@ extern Option<bool> RamMod32MB;
extern Option<bool> OpenGlChecks;
extern Option<std::vector<std::string>, false> ContentPath;
extern Option<std::vector<std::string>, false> BiosPath;
extern Option<std::string, false> VMUPath;
extern Option<std::vector<std::string>, false> SavestatePath;
extern Option<std::string, false> SavePath;
extern Option<std::vector<std::string>, false> TexturePath;
extern Option<std::string, false> TextureDumpPath;
extern Option<std::string, false> BoxartPath;
extern Option<std::vector<std::string>, false> MappingsPath;
extern Option<std::vector<std::string>, false> CheatPath;
extern Option<bool, false> HideLegacyNaomiRoms;
extern Option<bool, false> UploadCrashLogs;
extern Option<bool, false> DiscordPresence;
@@ -537,6 +551,7 @@ extern Option<int> VirtualGamepadVibration;
extern Option<int> VirtualGamepadTransparency;
extern std::array<Option<MapleDeviceType>, 4> MapleMainDevices;
extern std::array<std::array<Option<MapleDeviceType>, 2>, 4> MapleExpansionDevices;
extern std::array<Option<bool>, 4> UseNetworkExpansionDevices;
extern Option<bool> PerGameVmu;
#ifdef _WIN32
extern Option<bool, false> UseRawInput;
+79
View File
@@ -169,6 +169,7 @@ const WidescreenCheat CheatManager::widescreen_cheats[] =
// { "T-9502D-50", nullptr, { 0xBDE9B0, 0xBDE9C4 }, { 0x3F400000, 0x3FA00000 } }, // Nightmare Creatures II (PAL)
{ "MK-5110250", nullptr, { 0x87B5A4 }, { 0x43700000 } }, // Outtrigger (PAL)
{ "HDR-0118", nullptr, { 0x83E284 }, { 0x43700000 } }, // Outtrigger (JP)
{ "MK-51102", nullptr, { 0x83E284 }, { 0x43700000 } }, // Outtrigger (US)
{ "T15103D 50", nullptr, { 0x1EEE78 }, { 0x3F400000 } }, // PenPen (PAL)
{ "T17001M", nullptr, { 0x1C3828 }, { 0x3F400000 } }, // PenPen TriIcelon (JP)
{ "MK-5110050", nullptr, { 0x548E04, 0x0923C0 }, { 0x43E80000, 0x3F966666 } }, // Phantasy Star Online (PAL) TODO
@@ -445,13 +446,42 @@ void CheatManager::reset(const std::string& gameId)
cheats.clear();
setActive(false);
this->gameId = gameId;
#ifndef LIBRETRO
if (!settings.raHardcoreMode)
{
std::string cheatFile = cfgLoadStr("cheats", gameId, "");
if (!cheatFile.empty())
loadCheatFile(cheatFile);
else
{
// Try to auto-locate a cheat file in user-defined CheatPath
std::string romName = settings.content.fileName;
const char* exts[] = { ".cht", ".txt" };
for (const auto& base : config::CheatPath.get())
{
if (base.empty())
continue;
for (const char* ext : exts)
{
try
{
std::string candidate = hostfs::storage().getSubPath(base, romName + ext);
if (hostfs::storage().exists(candidate))
{
loadCheatFile(candidate);
cfgSaveStr("cheats", gameId, candidate);
goto found_cheats;
}
}
catch (const hostfs::StorageException&)
{
}
}
}
}
}
found_cheats:
#endif
size_t cheatCount = cheats.size();
if (gameId == "Fixed BOOT strapper") // Extreme Hunting 2
@@ -542,6 +572,55 @@ void CheatManager::reset(const std::string& gameId)
cheats.emplace_back(Cheat::Type::runNextIfEq, "bypass speed ifeq", true, 32, 0x0016d5d4, 0x2f862fe6, true);
cheats.emplace_back(Cheat::Type::setValue, "bypass speed check", true, 32, 0x0016d5d4, 0xe001000b, true);
}
else if (gameId == "MK-51065") { // Bomberman Online
cheats.emplace_back(Cheat::Type::runNextIfEq, "modem automode ifeq", true, 32, 0x00196da8, 0x2c302c30, true); // 0,0,
cheats.emplace_back(Cheat::Type::setValue, "modem automode set", true, 32, 0x00196da8, 0x2c302c31, true); // 1,0,
}
else if (gameId == "MK-51102") { // Outtrigger (US)
cheats.emplace_back(Cheat::Type::runNextIfEq, "modem automode ifeq", true, 32, 0x001bdb48, 0x2c302c30, true); // 0,0,
cheats.emplace_back(Cheat::Type::setValue, "modem automode set", true, 32, 0x001bdb48, 0x2c302c31, true); // 1,0,
}
else if (gameId == "HDR-0118") { // Outtrigger (JP)
cheats.emplace_back(Cheat::Type::runNextIfEq, "bypass auth ifeq", true, 32, 0x00139f54, 0x2fd62fe6, true);
cheats.emplace_back(Cheat::Type::setValue, "bypass dricas auth", true, 32, 0x00139f54, 0xe000000b, true);
}
else if (gameId == "T13306M") // Mobile Suit Gundam: Federation vs. Zeon
{
cheats.emplace_back(Cheat::Type::runNextIfEq, "modem rxspeed ifeq", true, 32, 0x0016e710, 0x3434312c, true); // ",144"
cheats.emplace_back(Cheat::Type::setValue, "modem rxspeed set", true, 32, 0x0016e710, 0x2020202c, true); // ", "
cheats.emplace_back(Cheat::Type::runNextIfEq, "modem txspeed ifeq", true, 32, 0x0016e71c, 0x3434312c, true); // ",144"
cheats.emplace_back(Cheat::Type::setValue, "modem txspeed set", true, 32, 0x0016e71c, 0x2020202c, true); // ", "
}
else if (gameId == "MK-51162") // Propeller Arena
{
// 0c1f56f0: ,0,28800,28800,28800,28800\\r"\n
// 0c1f5770: ,0,28800,28800,28800,28800\\r"\n
for (u32 addr = 0x001f56f0; addr <= 0x001f5770; addr += 0x80)
{
cheats.emplace_back(Cheat::Type::runNextIfEq, "modem automode1 ifeq", true, 32, addr + 0x00, 0x322c302c, true); // ",0,2"
cheats.emplace_back(Cheat::Type::setValue, "modem automode1 set", true, 32, addr + 0x00, 0x202c312c, true); // ",1, "
cheats.emplace_back(Cheat::Type::runNextIfEq, "modem automode2 ifeq", true, 32, addr + 0x04, 0x30303838, true); // "8800"
cheats.emplace_back(Cheat::Type::setValue, "modem automode2 set", true, 32, addr + 0x04, 0x30202020, true); // " 0"
cheats.emplace_back(Cheat::Type::runNextIfEq, "modem automode3 ifeq", true, 32, addr + 0x0c, 0x322c3030, true); // "00,2"
cheats.emplace_back(Cheat::Type::setValue, "modem automode3 set", true, 32, addr + 0x0c, 0x202c3030, true); // "00, "
cheats.emplace_back(Cheat::Type::runNextIfEq, "modem automode4 ifeq", true, 32, addr + 0x10, 0x30303838, true); // "8800"
cheats.emplace_back(Cheat::Type::setValue, "modem automode4 set", true, 32, addr + 0x10, 0x30202020, true); // " 0"
}
}
else if (gameId == "HDR-0113") // Power Smash
{
cheats.emplace_back(Cheat::Type::runNextIfEq, "no dupe SYN ifeq", true, 16, 0x14d258, 0xbbce, true); // bsr SendNormalSYN
cheats.emplace_back(Cheat::Type::setValue, "no dupe SYN set", true, 16, 0x14d258, 0x0009, true); // nop
cheats.emplace_back(Cheat::Type::runNextIfEq, "no dupe ACK ifeq", true, 16, 0x14af42, 0x430b, true); // jsr TCPInternalSendPacket
cheats.emplace_back(Cheat::Type::setValue, "no dupe ACK set", true, 16, 0x14af42, 0x0009, true); // nop
}
else if (gameId == "HDR-0091") // Pro Yakyuu Team de Asobou Net!
{
cheats.emplace_back(Cheat::Type::runNextIfEq, "no dupe SYN ifeq", true, 16, 0xe13e0c, 0xbbce, true); // bsr SendNormalSYN
cheats.emplace_back(Cheat::Type::setValue, "no dupe SYN set", true, 16, 0xe13e0c, 0x0009, true); // nop
cheats.emplace_back(Cheat::Type::runNextIfEq, "no dupe ACK ifeq", true, 16, 0xe11af6, 0x430b, true); // jsr TCPInternalSendPacket
cheats.emplace_back(Cheat::Type::setValue, "no dupe ACK set", true, 16, 0xe11af6, 0x0009, true); // nop
}
if (cheats.size() > cheatCount)
setActive(true);
+57 -44
View File
@@ -69,6 +69,22 @@ public:
asio::placeholders::bytes_transferred));
}
void send(const std::string& msg)
{
if (!msg.empty())
{
if (!outMessage.empty()) {
WARN_LOG(COMMON, "Message dropped: %s. Already sending: %s", msg.c_str(), outMessage.c_str());
return;
}
outMessage = msg;
asio::async_write(socket, asio::buffer(outMessage),
std::bind(&Connection::writeDone, shared_from_this(),
asio::placeholders::error,
asio::placeholders::bytes_transferred));
}
}
private:
Connection(GdbServer& server, asio::io_context& io_context)
: server(server), io_context(io_context), socket(io_context) {
@@ -101,30 +117,18 @@ private:
void handlePacket(const std::error_code& ec, size_t len);
void send(const std::string& msg)
{
if (msg.empty())
start();
else
asio::async_write(socket, asio::buffer(msg),
std::bind(&Connection::writeDone, shared_from_this(),
asio::placeholders::error,
asio::placeholders::bytes_transferred));
}
void writeDone(const std::error_code& ec, size_t len)
{
if (ec)
WARN_LOG(COMMON, "Write error: %s", ec.message().c_str());
else
start();
outMessage.clear();
}
GdbServer& server;
asio::io_context& io_context;
asio::ip::tcp::socket socket;
std::string message;
std::string outMessage;
friend super;
};
@@ -213,7 +217,9 @@ public:
if (!attached)
return;
agent.debugTrap(event);
reportException();
std::string pkt = handleCommand("?"); // report exception
if (connection)
io_context->post([this, pkt]() { connection->send(pkt); });
postDebugTrapNeeded = true;
throw Stop();
}
@@ -234,6 +240,7 @@ private:
ERROR_LOG(COMMON, "Gdb server exception: %s", e.what());
}
attached = false;
connection.reset();
}
std::string handleCommand(const std::string& packet)
@@ -390,6 +397,7 @@ private:
} catch (const Error& e) {
ERROR_LOG(COMMON, "%s", e.what());
attached = false;
connection.reset();
throw e;
}
}
@@ -659,25 +667,21 @@ private:
if (pkt.rfind("vAttach;", 0) == 0)
return { "S05" };
else if (pkt.rfind("vCont?", 0) == 0)
// supported vCont actions - (c)ontinue, (C)ontinue with signal, (s)tep, (S)tep with signal, (r)ange-step
return { "vCont;c;C;s;S;t;r" };
// supported vCont actions - (c)ontinue, (s)tep, (r)ange-step
return { "vCont;c;s;r" };
else if (pkt.rfind("vCont", 0) == 0)
{
std::string vContCmd = pkt.substr(strlen("vCont;"));
std::vector<std::string> replies;
switch (vContCmd[0])
{
case 'c':
case 'C':
doContinue(vContCmd);
doContinue(vContCmd.substr(0, 1));
return {};
case 's':
return { step(EXCEPT_NONE) };
case 'S':
replies.push_back(step());
[[fallthrough]];
case 'r':
{
std::vector<std::string> replies;
u32 from, to;
if (sscanf(vContCmd.c_str(), "r%x,%x", &from, &to) == 2)
{
@@ -722,7 +726,8 @@ private:
}
else
{
WARN_LOG(COMMON, "unknown v packet: %s", pkt.c_str());
if (pkt != "vMustReplyEmpty")
WARN_LOG(COMMON, "unknown v packet: %s", pkt.c_str());
return { "" };
}
}
@@ -744,7 +749,10 @@ private:
std::vector<std::string> stepRange(u32 from, u32 to)
{
try {
agent.stepRange(from, to);
if (from + 2 >= to)
agent.step();
else
agent.stepRange(from, to);
return { "OK", "S05" };
} catch (const FlycastException& e) {
throw Error(e.what());
@@ -858,8 +866,9 @@ private:
}
}
void clientConnected() {
void clientConnected(Connection::Ptr connection) {
attached = true;
this->connection = connection;
agentInterrupt();
}
@@ -889,6 +898,7 @@ private:
std::thread thread;
std::unique_ptr<asio::io_context> io_context;
int port = DEFAULT_PORT;
Connection::Ptr connection;
friend class TcpAcceptor;
friend class Connection;
@@ -901,7 +911,7 @@ static GdbServer gdbServer;
void TcpAcceptor::handleAccept(Connection::Ptr newConnection, const std::error_code& error)
{
if (!error) {
server.clientConnected();
server.clientConnected(newConnection);
newConnection->start();
}
start();
@@ -921,27 +931,30 @@ void Connection::handlePacket(const std::error_code& ec, size_t len)
try {
if (msg[0] == '\03') { // break
send(server.handleCommand(msg));
return;
}
if (msg[0] != '$') {
else if (msg[0] != '$') {
// Ignore unexpected chars
send("");
return;
}
u8 cksum = 0;
for (unsigned i = 1; i < len - 3; i++)
cksum += (u8)msg[i];
if (cksum != (unpack(msg[len - 2]) << 4 | unpack(msg[len - 1]))) {
// Invalid checksum
WARN_LOG(COMMON, "Connection::handlePacket: invalid checksum: [%s]", msg.c_str());
send("-");
}
else {
// Positive ack
std::string reply = "+";
reply += server.handleCommand(msg.substr(1, msg.length() - 4));
send(reply);
else
{
u8 cksum = 0;
for (unsigned i = 1; i < len - 3; i++)
cksum += (u8)msg[i];
if (cksum != (unpack(msg[len - 2]) << 4 | unpack(msg[len - 1])))
{
// Invalid checksum
WARN_LOG(COMMON, "Connection::handlePacket: invalid checksum: [%s]", msg.c_str());
send("-");
}
else
{
// Positive ack
std::string reply = "+";
reply += server.handleCommand(msg.substr(1, msg.length() - 4));
send(reply);
}
}
start();
} catch (...) {
// terminate the connection
}
@@ -222,7 +222,7 @@ void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data)
glcache.Scissor((int)clip_rect.x, (int)clip_rect.y, (int)clip_rect.z, (int)clip_rect.w); // Support for GL 4.5's glClipControl(GL_UPPER_LEFT)
// Bind texture, Draw
glcache.BindTexture(GL_TEXTURE_2D, (GLuint)(intptr_t)pcmd->TextureId);
glcache.BindTexture(GL_TEXTURE_2D, (GLuint)(intptr_t)pcmd->GetTexID());
glDrawElements(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, (void*)(intptr_t)(pcmd->IdxOffset * sizeof(ImDrawIdx)));
}
}
@@ -255,7 +255,7 @@ static bool ImGui_ImplOpenGL3_CreateFontsTexture()
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
// Store our identifier
io.Fonts->TexID = (ImTextureID)(intptr_t)g_FontTexture;
io.Fonts->SetTexID((ImTextureID)g_FontTexture);
return true;
}
@@ -266,7 +266,6 @@ static void ImGui_ImplOpenGL3_DestroyFontsTexture()
{
ImGuiIO& io = ImGui::GetIO();
glcache.DeleteTextures(1, &g_FontTexture);
io.Fonts->TexID = 0;
g_FontTexture = 0;
}
}
@@ -586,14 +586,14 @@ void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer comm
vkCmdSetScissor(command_buffer, 0, 1, &scissor);
// Bind DescriptorSet with font or user texture
VkDescriptorSet desc_set[1] = { (VkDescriptorSet)pcmd->TextureId };
VkDescriptorSet desc_set = (VkDescriptorSet)pcmd->GetTexID();
if (sizeof(ImTextureID) < sizeof(ImU64))
{
// We don't support texture switches if ImTextureID hasn't been redefined to be 64-bit. Do a flaky check that other textures haven't been used.
IM_ASSERT(pcmd->TextureId == (ImTextureID)bd->FontDescriptorSet);
desc_set[0] = bd->FontDescriptorSet;
IM_ASSERT(pcmd->GetTexID() == (ImTextureID)bd->FontDescriptorSet);
desc_set = bd->FontDescriptorSet;
}
vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, bd->PipelineLayout, 0, 1, desc_set, 0, nullptr);
vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, bd->PipelineLayout, 0, 1, &desc_set, 0, nullptr);
// Draw
vkCmdDrawIndexed(command_buffer, pcmd->ElemCount, 1, pcmd->IdxOffset + global_idx_offset, pcmd->VtxOffset + global_vtx_offset, 0);
@@ -820,7 +820,6 @@ void ImGui_ImplVulkan_DestroyFontsTexture()
{
ImGui_ImplVulkan_RemoveTexture(bd->FontDescriptorSet);
bd->FontDescriptorSet = VK_NULL_HANDLE;
io.Fonts->SetTexID(0);
}
if (bd->FontView) { vkDestroyImageView(v->Device, bd->FontView, v->Allocator); bd->FontView = VK_NULL_HANDLE; }
+23 -9
View File
@@ -21,14 +21,14 @@
//---- Define attributes of all API symbols declarations, e.g. for DLL under Windows
// Using Dear ImGui via a shared library is not recommended, because of function call overhead and because we don't guarantee backward nor forward ABI compatibility.
// DLL users: heaps and globals are not shared across DLL boundaries! You will need to call SetCurrentContext() + SetAllocatorFunctions()
// for each static/DLL boundary you are calling from. Read "Context and Memory Allocators" section of imgui.cpp for more details.
//#define IMGUI_API __declspec( dllexport )
//#define IMGUI_API __declspec( dllimport )
// - Windows DLL users: heaps and globals are not shared across DLL boundaries! You will need to call SetCurrentContext() + SetAllocatorFunctions()
// for each static/DLL boundary you are calling from. Read "Context and Memory Allocators" section of imgui.cpp for more details.
//#define IMGUI_API __declspec(dllexport) // MSVC Windows: DLL export
//#define IMGUI_API __declspec(dllimport) // MSVC Windows: DLL import
//#define IMGUI_API __attribute__((visibility("default"))) // GCC/Clang: override visibility when set is hidden
//---- Don't define obsolete functions/enums/behaviors. Consider enabling from time to time after updating to clean your code of obsolete function/names.
//#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS
//#define IMGUI_DISABLE_OBSOLETE_KEYIO // 1.87+ disable legacy io.KeyMap[]+io.KeysDown[] in favor io.AddKeyEvent(). This is automatically done by IMGUI_DISABLE_OBSOLETE_FUNCTIONS.
//---- Disable all of Dear ImGui or don't implement standard windows/tools.
// It is very strongly recommended to NOT disable the demo windows and debug tool during development. They are extremely useful in day to day work. Please read comments in imgui_demo.cpp.
@@ -42,21 +42,29 @@
//#define IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS // [Win32] [Default with non-Visual Studio compilers] Don't implement default IME handler (won't require imm32.lib/.a)
//#define IMGUI_DISABLE_WIN32_FUNCTIONS // [Win32] Won't use and link with any Win32 function (clipboard, IME).
//#define IMGUI_ENABLE_OSX_DEFAULT_CLIPBOARD_FUNCTIONS // [OSX] Implement default OSX clipboard handler (need to link with '-framework ApplicationServices', this is why this is not the default).
//#define IMGUI_DISABLE_DEFAULT_SHELL_FUNCTIONS // Don't implement default platform_io.Platform_OpenInShellFn() handler (Win32: ShellExecute(), require shell32.lib/.a, Mac/Linux: use system("")).
//#define IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS // Don't implement ImFormatString/ImFormatStringV so you can implement them yourself (e.g. if you don't want to link with vsnprintf)
//#define IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS // Don't implement ImFabs/ImSqrt/ImPow/ImFmod/ImCos/ImSin/ImAcos/ImAtan2 so you can implement them yourself.
//#define IMGUI_DISABLE_FILE_FUNCTIONS // Don't implement ImFileOpen/ImFileClose/ImFileRead/ImFileWrite and ImFileHandle at all (replace them with dummies)
//#define IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS // Don't implement ImFileOpen/ImFileClose/ImFileRead/ImFileWrite and ImFileHandle so you can implement them yourself if you don't want to link with fopen/fclose/fread/fwrite. This will also disable the LogToTTY() function.
//#define IMGUI_DISABLE_DEFAULT_ALLOCATORS // Don't implement default allocators calling malloc()/free() to avoid linking with them. You will need to call ImGui::SetAllocatorFunctions().
//#define IMGUI_DISABLE_DEFAULT_FONT // Disable default embedded font (ProggyClean.ttf), remove ~9.5 KB from output binary. AddFontDefault() will assert.
//#define IMGUI_DISABLE_SSE // Disable use of SSE intrinsics even if available
//---- Enable Test Engine / Automation features.
//#define IMGUI_ENABLE_TEST_ENGINE // Enable imgui_test_engine hooks. Generally set automatically by include "imgui_te_config.h", see Test Engine for details.
//---- Include imgui_user.h at the end of imgui.h as a convenience
// May be convenient for some users to only explicitly include vanilla imgui.h and have extra stuff included.
//#define IMGUI_INCLUDE_IMGUI_USER_H
//#define IMGUI_USER_H_FILENAME "my_folder/my_imgui_user.h"
//---- Pack colors to BGRA8 instead of RGBA8 (to avoid converting from one to another)
//---- Pack vertex colors as BGRA8 instead of RGBA8 (to avoid converting from one to another). Need dedicated backend support.
//#define IMGUI_USE_BGRA_PACKED_COLOR
//---- Use legacy CRC32-adler tables (used before 1.91.6), in order to preserve old .ini data that you cannot afford to invalidate.
//#define IMGUI_USE_LEGACY_CRC32_ADLER
//---- Use 32-bit for ImWchar (default is 16-bit) to support Unicode planes 1-16. (e.g. point beyond 0xFFFF like emoticons, dingbats, symbols, shapes, ancient languages, etc...)
//#define IMGUI_USE_WCHAR32
@@ -78,10 +86,12 @@
// On Windows you may use vcpkg with 'vcpkg install freetype --triplet=x64-windows' + 'vcpkg integrate install'.
//#define IMGUI_ENABLE_FREETYPE
//---- Use FreeType+lunasvg library to render OpenType SVG fonts (SVGinOT)
// Requires lunasvg headers to be available in the include path + program to be linked with the lunasvg library (not provided).
//---- Use FreeType + plutosvg or lunasvg to render OpenType SVG fonts (SVGinOT)
// Only works in combination with IMGUI_ENABLE_FREETYPE.
// (implementation is based on Freetype's rsvg-port.c which is licensed under CeCILL-C Free Software License Agreement)
// - plutosvg is currently easier to install, as e.g. it is part of vcpkg. It will support more fonts and may load them faster. See misc/freetype/README for instructions.
// - Both require headers to be available in the include path + program to be linked with the library code (not provided).
// - (note: lunasvg implementation is based on Freetype's rsvg-port.c which is licensed under CeCILL-C Free Software License Agreement)
//#define IMGUI_ENABLE_FREETYPE_PLUTOSVG
//#define IMGUI_ENABLE_FREETYPE_LUNASVG
//---- Use stb_truetype to build and rasterize the font atlas (default)
@@ -119,6 +129,10 @@
//#define IM_DEBUG_BREAK IM_ASSERT(0)
//#define IM_DEBUG_BREAK __debugbreak()
//---- Debug Tools: Enable highlight ID conflicts _before_ hovering items. When io.ConfigDebugHighlightIdConflicts is set.
// (THIS WILL SLOW DOWN DEAR IMGUI. Only use occasionally and disable after use)
//#define IMGUI_DEBUG_HIGHLIGHT_ALL_ID_CONFLICTS
//---- Debug Tools: Enable slower asserts
//#define IMGUI_DEBUG_PARANOID
+3373 -1631
View File
File diff suppressed because it is too large. Load diff
+1202 -466
View File
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
+3
View File
@@ -8,6 +8,7 @@
// https://github.com/ocornut/imgui/wiki/Useful-Extensions#cness
#include "imgui.h"
#ifndef IMGUI_DISABLE
#include "imgui_stdlib.h"
// Clang warnings with -Weverything
@@ -83,3 +84,5 @@ bool ImGui::InputTextWithHint(const char* label, const char* hint, std::string*
#if defined(__clang__)
#pragma clang diagnostic pop
#endif
#endif // #ifndef IMGUI_DISABLE
+4
View File
@@ -9,6 +9,8 @@
#pragma once
#ifndef IMGUI_DISABLE
#include <string>
namespace ImGui
@@ -19,3 +21,5 @@ namespace ImGui
IMGUI_API bool InputTextMultiline(const char* label, std::string* str, const ImVec2& size = ImVec2(0, 0), ImGuiInputTextFlags flags = 0, ImGuiInputTextCallback callback = nullptr, void* user_data = nullptr);
IMGUI_API bool InputTextWithHint(const char* label, const char* hint, std::string* str, ImGuiInputTextFlags flags = 0, ImGuiInputTextCallback callback = nullptr, void* user_data = nullptr);
}
#endif // #ifndef IMGUI_DISABLE
+212 -101
View File
@@ -1,4 +1,4 @@
// dear imgui, v1.90.8
// dear imgui, v1.92.1
// (tables and columns code)
/*
@@ -221,6 +221,7 @@ Index of this file:
#pragma clang diagnostic ignored "-Wunknown-pragmas" // warning: unknown warning group 'xxx'
#pragma clang diagnostic ignored "-Wold-style-cast" // warning: use of old-style cast // yes, they are more terse.
#pragma clang diagnostic ignored "-Wfloat-equal" // warning: comparing floating point with == or != is unsafe // storing and comparing against same constants (typically 0.0f) is ok.
#pragma clang diagnostic ignored "-Wformat" // warning: format specifies type 'int' but the argument has type 'unsigned int'
#pragma clang diagnostic ignored "-Wformat-nonliteral" // warning: format string is not a string literal // passing non-literal to vsnformat(). yes, user passing incorrect format strings can crash the code.
#pragma clang diagnostic ignored "-Wsign-conversion" // warning: implicit conversion changes signedness
#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" // warning: zero as null pointer constant // some standard header variations use #define NULL 0
@@ -229,9 +230,15 @@ Index of this file:
#pragma clang diagnostic ignored "-Wdeprecated-enum-enum-conversion"// warning: bitwise operation between different enumeration types ('XXXFlags_' and 'XXXFlagsPrivate_') is deprecated
#pragma clang diagnostic ignored "-Wimplicit-int-float-conversion" // warning: implicit conversion from 'xxx' to 'float' may lose precision
#pragma clang diagnostic ignored "-Wunsafe-buffer-usage" // warning: 'xxx' is an unsafe pointer used for buffer access
#pragma clang diagnostic ignored "-Wnontrivial-memaccess" // warning: first argument in call to 'memset' is a pointer to non-trivially copyable type
#pragma clang diagnostic ignored "-Wswitch-default" // warning: 'switch' missing 'default' label
#elif defined(__GNUC__)
#pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind
#pragma GCC diagnostic ignored "-Wfloat-equal" // warning: comparing floating-point with '==' or '!=' is unsafe
#pragma GCC diagnostic ignored "-Wformat-nonliteral" // warning: format not a string literal, format string not checked
#pragma GCC diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function
#pragma GCC diagnostic ignored "-Wformat" // warning: format '%p' expects argument of type 'int'/'void*', but argument X has type 'unsigned int'/'ImGuiWindow*'
#pragma GCC diagnostic ignored "-Wstrict-overflow"
#pragma GCC diagnostic ignored "-Wclass-memaccess" // [__GNUC__ >= 8] warning: 'memset/memcpy' clearing/writing an object of type 'xxxx' with no trivial copy-assignment; use assignment or value-initialization instead
#endif
@@ -328,13 +335,14 @@ bool ImGui::BeginTableEx(const char* name, ImGuiID id, int columns_count, ImG
// - always performing the GetOrAddByKey() O(log N) query in g.Tables.Map[].
const bool use_child_window = (flags & (ImGuiTableFlags_ScrollX | ImGuiTableFlags_ScrollY)) != 0;
const ImVec2 avail_size = GetContentRegionAvail();
const ImVec2 actual_outer_size = CalcItemSize(outer_size, ImMax(avail_size.x, 1.0f), use_child_window ? ImMax(avail_size.y, 1.0f) : 0.0f);
const ImVec2 actual_outer_size = ImTrunc(CalcItemSize(outer_size, ImMax(avail_size.x, 1.0f), use_child_window ? ImMax(avail_size.y, 1.0f) : 0.0f));
const ImRect outer_rect(outer_window->DC.CursorPos, outer_window->DC.CursorPos + actual_outer_size);
const bool outer_window_is_measuring_size = (outer_window->AutoFitFramesX > 0) || (outer_window->AutoFitFramesY > 0); // Doesn't apply to AlwaysAutoResize windows!
if (use_child_window && IsClippedEx(outer_rect, 0) && !outer_window_is_measuring_size)
{
ItemSize(outer_rect);
ItemAdd(outer_rect, id);
g.NextWindowData.ClearFlags();
return false;
}
@@ -369,6 +377,7 @@ bool ImGui::BeginTableEx(const char* name, ImGuiID id, int columns_count, ImG
table->ColumnsCount = columns_count;
table->IsLayoutLocked = false;
table->InnerWidth = inner_width;
table->NavLayer = (ImS8)outer_window->DC.NavLayerCurrent;
temp_data->UserOuterSize = outer_size;
// Instance data (for instance 0, TableID == TableInstanceID)
@@ -409,11 +418,15 @@ bool ImGui::BeginTableEx(const char* name, ImGuiID id, int columns_count, ImG
// Reset scroll if we are reactivating it
if ((previous_flags & (ImGuiTableFlags_ScrollX | ImGuiTableFlags_ScrollY)) == 0)
SetNextWindowScroll(ImVec2(0.0f, 0.0f));
if ((g.NextWindowData.HasFlags & ImGuiNextWindowDataFlags_HasScroll) == 0)
SetNextWindowScroll(ImVec2(0.0f, 0.0f));
// Create scrolling region (without border and zero window padding)
ImGuiWindowFlags child_flags = (flags & ImGuiTableFlags_ScrollX) ? ImGuiWindowFlags_HorizontalScrollbar : ImGuiWindowFlags_None;
BeginChildEx(name, instance_id, outer_rect.GetSize(), false, child_flags);
ImGuiChildFlags child_child_flags = (g.NextWindowData.HasFlags & ImGuiNextWindowDataFlags_HasChildFlags) ? g.NextWindowData.ChildFlags : ImGuiChildFlags_None;
ImGuiWindowFlags child_window_flags = (g.NextWindowData.HasFlags & ImGuiNextWindowDataFlags_HasWindowFlags) ? g.NextWindowData.WindowFlags : ImGuiWindowFlags_None;
if (flags & ImGuiTableFlags_ScrollX)
child_window_flags |= ImGuiWindowFlags_HorizontalScrollbar;
BeginChildEx(name, instance_id, outer_rect.GetSize(), child_child_flags, child_window_flags);
table->InnerWindow = g.CurrentWindow;
table->WorkRect = table->InnerWindow->WorkRect;
table->OuterRect = table->InnerWindow->Rect();
@@ -438,6 +451,7 @@ bool ImGui::BeginTableEx(const char* name, ImGuiID id, int columns_count, ImG
// But at this point we do NOT have a correct value for .Max.y (unless a height has been explicitly passed in). It will only be updated in EndTable().
table->WorkRect = table->OuterRect = table->InnerRect = outer_rect;
table->HasScrollbarYPrev = table->HasScrollbarYCurr = false;
table->InnerWindow->DC.TreeDepth++; // This is designed to always linking ImGuiTreeNodeFlags_DrawLines linking accross a table
}
// Push a standardized ID for both child-using and not-child-using tables
@@ -460,16 +474,27 @@ bool ImGui::BeginTableEx(const char* name, ImGuiID id, int columns_count, ImG
temp_data->HostBackupItemWidthStackSize = outer_window->DC.ItemWidthStack.Size;
inner_window->DC.PrevLineSize = inner_window->DC.CurrLineSize = ImVec2(0.0f, 0.0f);
// Make left and top borders not overlap our contents by offsetting HostClipRect (#6765)
// Make borders not overlap our contents by offsetting HostClipRect (#6765, #7428, #3752)
// (we normally shouldn't alter HostClipRect as we rely on TableMergeDrawChannels() expanding non-clipped column toward the
// limits of that rectangle, in order for ImDrawListSplitter::Merge() to merge the draw commands. However since the overlap
// problem only affect scrolling tables in this case we can get away with doing it without extra cost).
if (inner_window != outer_window)
{
// FIXME: Because inner_window's Scrollbar doesn't know about border size, since it's not encoded in window->WindowBorderSize,
// it already overlaps it and doesn't need an extra offset. Ideally we should be able to pass custom border size with
// different x/y values to BeginChild().
if (flags & ImGuiTableFlags_BordersOuterV)
{
table->HostClipRect.Min.x = ImMin(table->HostClipRect.Min.x + TABLE_BORDER_SIZE, table->HostClipRect.Max.x);
if (inner_window->DecoOuterSizeX2 == 0.0f)
table->HostClipRect.Max.x = ImMax(table->HostClipRect.Max.x - TABLE_BORDER_SIZE, table->HostClipRect.Min.x);
}
if (flags & ImGuiTableFlags_BordersOuterH)
{
table->HostClipRect.Min.y = ImMin(table->HostClipRect.Min.y + TABLE_BORDER_SIZE, table->HostClipRect.Max.y);
if (inner_window->DecoOuterSizeY2 == 0.0f)
table->HostClipRect.Max.y = ImMax(table->HostClipRect.Max.y - TABLE_BORDER_SIZE, table->HostClipRect.Min.y);
}
}
// Padding and Spacing
@@ -497,7 +522,7 @@ bool ImGui::BeginTableEx(const char* name, ImGuiID id, int columns_count, ImG
table->InnerClipRect = (inner_window == outer_window) ? table->WorkRect : inner_window->ClipRect;
table->InnerClipRect.ClipWith(table->WorkRect); // We need this to honor inner_width
table->InnerClipRect.ClipWithFull(table->HostClipRect);
table->InnerClipRect.Max.y = (flags & ImGuiTableFlags_NoHostExtendY) ? ImMin(table->InnerClipRect.Max.y, inner_window->WorkRect.Max.y) : inner_window->ClipRect.Max.y;
table->InnerClipRect.Max.y = (flags & ImGuiTableFlags_NoHostExtendY) ? ImMin(table->InnerClipRect.Max.y, inner_window->WorkRect.Max.y) : table->HostClipRect.Max.y;
table->RowPosY1 = table->RowPosY2 = table->WorkRect.Min.y; // This is needed somehow
table->RowTextBaseline = 0.0f; // This will be cleared again by TableBeginRow()
@@ -555,6 +580,7 @@ bool ImGui::BeginTableEx(const char* name, ImGuiID id, int columns_count, ImG
// Initialize
table->SettingsOffset = -1;
table->IsSortSpecsDirty = true;
table->IsSettingsDirty = true; // Records itself into .ini file even when in default state (#7934)
table->InstanceInteracted = -1;
table->ContextPopupColumn = -1;
table->ReorderColumn = table->ResizedColumn = table->LastResizedColumn = -1;
@@ -855,7 +881,7 @@ void ImGui::TableUpdateLayout(ImGuiTable* table)
// Calculate ideal/auto column width (that's the width required for all contents to be visible without clipping)
// Combine width from regular rows + width from headers unless requested not to.
if (!column->IsPreserveWidthAuto)
if (!column->IsPreserveWidthAuto && table->InstanceCurrent == 0)
column->WidthAuto = TableGetColumnWidthAuto(table, column);
// Non-resizable columns keep their requested width (apply user value regardless of IsPreserveWidthAuto)
@@ -954,7 +980,7 @@ void ImGui::TableUpdateLayout(ImGuiTable* table)
// [Part 4] Apply final widths based on requested widths
const ImRect work_rect = table->WorkRect;
const float width_spacings = (table->OuterPaddingX * 2.0f) + (table->CellSpacingX1 + table->CellSpacingX2) * (table->ColumnsEnabledCount - 1);
const float width_removed = (table->HasScrollbarYPrev && !table->InnerWindow->ScrollbarY) ? g.Style.ScrollbarSize : 0.0f; // To synchronize decoration width of synched tables with mismatching scrollbar state (#5920)
const float width_removed = (table->HasScrollbarYPrev && !table->InnerWindow->ScrollbarY) ? g.Style.ScrollbarSize : 0.0f; // To synchronize decoration width of synced tables with mismatching scrollbar state (#5920)
const float width_avail = ImMax(1.0f, (((table->Flags & ImGuiTableFlags_ScrollX) && table->InnerWidth == 0.0f) ? table->InnerClipRect.GetWidth() : work_rect.GetWidth()) - width_removed);
const float width_avail_for_stretched_columns = width_avail - width_spacings - sum_width_requests;
float width_remaining_for_stretched_columns = width_avail_for_stretched_columns;
@@ -1033,7 +1059,8 @@ void ImGui::TableUpdateLayout(ImGuiTable* table)
const int column_n = table->DisplayOrderToIndex[order_n];
ImGuiTableColumn* column = &table->Columns[column_n];
column->NavLayerCurrent = (ImS8)(table->FreezeRowsCount > 0 ? ImGuiNavLayer_Menu : ImGuiNavLayer_Main); // Use Count NOT request so Header line changes layer when frozen
// Initial nav layer: using FreezeRowsCount, NOT FreezeRowsRequest, so Header line changes layer when frozen
column->NavLayerCurrent = (ImS8)(table->FreezeRowsCount > 0 ? ImGuiNavLayer_Menu : (ImGuiNavLayer)table->NavLayer);
if (offset_x_frozen && table->FreezeColumnsCount == visible_n)
{
@@ -1059,16 +1086,12 @@ void ImGui::TableUpdateLayout(ImGuiTable* table)
continue;
}
// Detect hovered column
if (is_hovering_table && mouse_skewed_x >= column->ClipRect.Min.x && mouse_skewed_x < column->ClipRect.Max.x)
table->HoveredColumnBody = (ImGuiTableColumnIdx)column_n;
// Lock start position
column->MinX = offset_x;
// Lock width based on start position and minimum/maximum width for this position
float max_width = TableGetMaxColumnWidth(table, column_n);
column->WidthGiven = ImMin(column->WidthGiven, max_width);
column->WidthMax = TableCalcMaxColumnWidth(table, column_n);
column->WidthGiven = ImMin(column->WidthGiven, column->WidthMax);
column->WidthGiven = ImMax(column->WidthGiven, ImMin(column->WidthRequest, table->MinColumnWidth));
column->MaxX = offset_x + column->WidthGiven + table->CellSpacingX1 + table->CellSpacingX2 + table->CellPaddingX * 2.0f;
@@ -1117,8 +1140,13 @@ void ImGui::TableUpdateLayout(ImGuiTable* table)
column->Flags |= ImGuiTableColumnFlags_IsVisible;
if (column->SortOrder != -1)
column->Flags |= ImGuiTableColumnFlags_IsSorted;
if (table->HoveredColumnBody == column_n)
// Detect hovered column
if (is_hovering_table && mouse_skewed_x >= column->ClipRect.Min.x && mouse_skewed_x < column->ClipRect.Max.x)
{
column->Flags |= ImGuiTableColumnFlags_IsHovered;
table->HoveredColumnBody = (ImGuiTableColumnIdx)column_n;
}
// Alignment
// FIXME-TABLE: This align based on the whole column width, not per-cell, and therefore isn't useful in
@@ -1148,7 +1176,7 @@ void ImGui::TableUpdateLayout(ImGuiTable* table)
}
// Don't decrement auto-fit counters until container window got a chance to submit its items
if (table->HostSkipItems == false)
if (table->HostSkipItems == false && table->InstanceCurrent == 0)
{
column->AutoFitQueue >>= 1;
column->CannotSkipItemsQueue >>= 1;
@@ -1223,7 +1251,7 @@ void ImGui::TableUpdateLayout(ImGuiTable* table)
// [Part 11] Default context menu
// - To append to this menu: you can call TableBeginContextMenuPopup()/.../EndPopup().
// - To modify or replace this: set table->IsContextPopupNoDefaultContents = true, then call TableBeginContextMenuPopup()/.../EndPopup().
// - To modify or replace this: set table->DisableDefaultContextMenu = true, then call TableBeginContextMenuPopup()/.../EndPopup().
// - You may call TableDrawDefaultContextMenu() with selected flags to display specific sections of the default menu,
// e.g. TableDrawDefaultContextMenu(table, table->Flags & ~ImGuiTableFlags_Hideable) will display everything EXCEPT columns visibility options.
if (table->DisableDefaultContextMenu == false && TableBeginContextMenuPopup(table))
@@ -1249,7 +1277,7 @@ void ImGui::TableUpdateLayout(ImGuiTable* table)
if (table->Flags & ImGuiTableFlags_NoClip)
table->DrawSplitter->SetCurrentChannel(inner_window->DrawList, TABLE_DRAW_CHANNEL_NOCLIP);
else
inner_window->DrawList->PushClipRect(inner_window->ClipRect.Min, inner_window->ClipRect.Max, false);
inner_window->DrawList->PushClipRect(inner_window->InnerClipRect.Min, inner_window->InnerClipRect.Max, false); // FIXME: use table->InnerClipRect?
}
// Process hit-testing on resizing borders. Actual size change will be applied in EndTable()
@@ -1319,7 +1347,11 @@ void ImGui::EndTable()
{
ImGuiContext& g = *GImGui;
ImGuiTable* table = g.CurrentTable;
IM_ASSERT(table != NULL && "Only call EndTable() if BeginTable() returns true!");
if (table == NULL)
{
IM_ASSERT_USER_ERROR(table != NULL, "EndTable() call should only be done while in BeginTable() scope!");
return;
}
// This assert would be very useful to catch a common error... unfortunately it would probably trigger in some
// cases, and for consistency user may sometimes output empty tables (and still benefit from e.g. outer border)
@@ -1361,7 +1393,7 @@ void ImGui::EndTable()
// Setup inner scrolling range
// FIXME: This ideally should be done earlier, in BeginTable() SetNextWindowContentSize call, just like writing to inner_window->DC.CursorMaxPos.y,
// but since the later is likely to be impossible to do we'd rather update both axises together.
// but since the later is likely to be impossible to do we'd rather update both axes together.
if (table->Flags & ImGuiTableFlags_ScrollX)
{
const float outer_padding_for_border = (table->Flags & ImGuiTableFlags_BordersOuterV) ? TABLE_BORDER_SIZE : 0.0f;
@@ -1471,12 +1503,15 @@ void ImGui::EndTable()
if (inner_window != outer_window)
{
short backup_nav_layers_active_mask = inner_window->DC.NavLayersActiveMask;
inner_window->DC.NavLayersActiveMask |= 1 << ImGuiNavLayer_Main; // So empty table don't appear to navigate differently.
inner_window->DC.NavLayersActiveMask |= 1 << table->NavLayer; // So empty table don't appear to navigate differently.
g.CurrentTable = NULL; // To avoid error recovery recursing
EndChild();
g.CurrentTable = table;
inner_window->DC.NavLayersActiveMask = backup_nav_layers_active_mask;
}
else
{
table->InnerWindow->DC.TreeDepth--;
ItemSize(table->OuterRect.GetSize());
ItemAdd(table->OuterRect, 0);
}
@@ -1534,14 +1569,43 @@ void ImGui::EndTable()
NavUpdateCurrentWindowIsScrollPushableX();
}
// Called in TableSetupColumn() when initializing and in TableLoadSettings() for defaults before applying stored settings.
// 'init_mask' specify which fields to initialize.
static void TableInitColumnDefaults(ImGuiTable* table, ImGuiTableColumn* column, ImGuiTableColumnFlags init_mask)
{
ImGuiTableColumnFlags flags = column->Flags;
if (init_mask & ImGuiTableFlags_Resizable)
{
float init_width_or_weight = column->InitStretchWeightOrWidth;
column->WidthRequest = ((flags & ImGuiTableColumnFlags_WidthFixed) && init_width_or_weight > 0.0f) ? init_width_or_weight : -1.0f;
column->StretchWeight = (init_width_or_weight > 0.0f && (flags & ImGuiTableColumnFlags_WidthStretch)) ? init_width_or_weight : -1.0f;
if (init_width_or_weight > 0.0f) // Disable auto-fit if an explicit width/weight has been specified
column->AutoFitQueue = 0x00;
}
if (init_mask & ImGuiTableFlags_Reorderable)
column->DisplayOrder = (ImGuiTableColumnIdx)table->Columns.index_from_ptr(column);
if (init_mask & ImGuiTableFlags_Hideable)
column->IsUserEnabled = column->IsUserEnabledNextFrame = (flags & ImGuiTableColumnFlags_DefaultHide) ? 0 : 1;
if (init_mask & ImGuiTableFlags_Sortable)
{
// Multiple columns using _DefaultSort will be reassigned unique SortOrder values when building the sort specs.
column->SortOrder = (flags & ImGuiTableColumnFlags_DefaultSort) ? 0 : -1;
column->SortDirection = (flags & ImGuiTableColumnFlags_DefaultSort) ? ((flags & ImGuiTableColumnFlags_PreferSortDescending) ? (ImS8)ImGuiSortDirection_Descending : (ImU8)(ImGuiSortDirection_Ascending)) : (ImS8)ImGuiSortDirection_None;
}
}
// See "COLUMNS SIZING POLICIES" comments at the top of this file
// If (init_width_or_weight <= 0.0f) it is ignored
void ImGui::TableSetupColumn(const char* label, ImGuiTableColumnFlags flags, float init_width_or_weight, ImGuiID user_id)
{
ImGuiContext& g = *GImGui;
ImGuiTable* table = g.CurrentTable;
IM_ASSERT(table != NULL && "Need to call TableSetupColumn() after BeginTable()!");
IM_ASSERT(table->IsLayoutLocked == false && "Need to call call TableSetupColumn() before first row!");
if (table == NULL)
{
IM_ASSERT_USER_ERROR(table != NULL, "Call should only be done while in BeginTable() scope!");
return;
}
IM_ASSERT(table->IsLayoutLocked == false && "Need to call TableSetupColumn() before first row!");
IM_ASSERT((flags & ImGuiTableColumnFlags_StatusMask_) == 0 && "Illegal to pass StatusMask values to TableSetupColumn()");
if (table->DeclColumnsCount >= table->ColumnsCount)
{
@@ -1558,7 +1622,7 @@ void ImGui::TableSetupColumn(const char* label, ImGuiTableColumnFlags flags, flo
IM_ASSERT(init_width_or_weight <= 0.0f && "Can only specify width/weight if sizing policy is set explicitly in either Table or Column.");
// When passing a width automatically enforce WidthFixed policy
// (whereas TableSetupColumnFlags would default to WidthAuto if table is not Resizable)
// (whereas TableSetupColumnFlags would default to WidthAuto if table is not resizable)
if ((flags & ImGuiTableColumnFlags_WidthMask_) == 0 && init_width_or_weight > 0.0f)
if ((table->Flags & ImGuiTableFlags_SizingMask_) == ImGuiTableFlags_SizingFixedFit || (table->Flags & ImGuiTableFlags_SizingMask_) == ImGuiTableFlags_SizingFixedSame)
flags |= ImGuiTableColumnFlags_WidthFixed;
@@ -1576,27 +1640,10 @@ void ImGui::TableSetupColumn(const char* label, ImGuiTableColumnFlags flags, flo
column->InitStretchWeightOrWidth = init_width_or_weight;
if (table->IsInitializing)
{
// Init width or weight
ImGuiTableFlags init_flags = ~table->SettingsLoadedFlags;
if (column->WidthRequest < 0.0f && column->StretchWeight < 0.0f)
{
if ((flags & ImGuiTableColumnFlags_WidthFixed) && init_width_or_weight > 0.0f)
column->WidthRequest = init_width_or_weight;
if (flags & ImGuiTableColumnFlags_WidthStretch)
column->StretchWeight = (init_width_or_weight > 0.0f) ? init_width_or_weight : -1.0f;
// Disable auto-fit if an explicit width/weight has been specified
if (init_width_or_weight > 0.0f)
column->AutoFitQueue = 0x00;
}
// Init default visibility/sort state
if ((flags & ImGuiTableColumnFlags_DefaultHide) && (table->SettingsLoadedFlags & ImGuiTableFlags_Hideable) == 0)
column->IsUserEnabled = column->IsUserEnabledNextFrame = false;
if (flags & ImGuiTableColumnFlags_DefaultSort && (table->SettingsLoadedFlags & ImGuiTableFlags_Sortable) == 0)
{
column->SortOrder = 0; // Multiple columns using _DefaultSort will be reassigned unique SortOrder values when building the sort specs.
column->SortDirection = (column->Flags & ImGuiTableColumnFlags_PreferSortDescending) ? (ImS8)ImGuiSortDirection_Descending : (ImU8)(ImGuiSortDirection_Ascending);
}
init_flags |= ImGuiTableFlags_Resizable;
TableInitColumnDefaults(table, column, init_flags);
}
// Store name (append with zero-terminator in contiguous buffer)
@@ -1605,7 +1652,7 @@ void ImGui::TableSetupColumn(const char* label, ImGuiTableColumnFlags flags, flo
if (label != NULL && label[0] != 0)
{
column->NameOffset = (ImS16)table->ColumnsNames.size();
table->ColumnsNames.append(label, label + strlen(label) + 1);
table->ColumnsNames.append(label, label + ImStrlen(label) + 1);
}
}
@@ -1614,7 +1661,11 @@ void ImGui::TableSetupScrollFreeze(int columns, int rows)
{
ImGuiContext& g = *GImGui;
ImGuiTable* table = g.CurrentTable;
IM_ASSERT(table != NULL && "Need to call TableSetupColumn() after BeginTable()!");
if (table == NULL)
{
IM_ASSERT_USER_ERROR(table != NULL, "Call should only be done while in BeginTable() scope!");
return;
}
IM_ASSERT(table->IsLayoutLocked == false && "Need to call TableSetupColumn() before first row!");
IM_ASSERT(columns >= 0 && columns < IMGUI_TABLE_MAX_COLUMNS);
IM_ASSERT(rows >= 0 && rows < 128); // Arbitrary limit
@@ -1691,9 +1742,11 @@ void ImGui::TableSetColumnEnabled(int column_n, bool enabled)
{
ImGuiContext& g = *GImGui;
ImGuiTable* table = g.CurrentTable;
IM_ASSERT(table != NULL);
if (!table)
if (table == NULL)
{
IM_ASSERT_USER_ERROR(table != NULL, "Call should only be done while in BeginTable() scope!");
return;
}
IM_ASSERT(table->Flags & ImGuiTableFlags_Hideable); // See comments above
if (column_n < 0)
column_n = table->CurrentColumn;
@@ -1900,7 +1953,10 @@ void ImGui::TableEndRow(ImGuiTable* table)
IM_ASSERT(table->IsInsideRow);
if (table->CurrentColumn != -1)
{
TableEndCell(table);
table->CurrentColumn = -1;
}
// Logging
if (g.LogEnabled)
@@ -1996,34 +2052,37 @@ void ImGui::TableEndRow(ImGuiTable* table)
// We need to do that in TableEndRow() instead of TableBeginRow() so the list clipper can mark end of row and
// get the new cursor position.
if (unfreeze_rows_request)
for (int column_n = 0; column_n < table->ColumnsCount; column_n++)
table->Columns[column_n].NavLayerCurrent = ImGuiNavLayer_Main;
if (unfreeze_rows_actual)
{
IM_ASSERT(table->IsUnfrozenRows == false);
const float y0 = ImMax(table->RowPosY2 + 1, window->InnerClipRect.Min.y);
table->IsUnfrozenRows = true;
for (int column_n = 0; column_n < table->ColumnsCount; column_n++)
table->Columns[column_n].NavLayerCurrent = table->NavLayer;
const float y0 = ImMax(table->RowPosY2 + 1, table->InnerClipRect.Min.y);
table_instance->LastFrozenHeight = y0 - table->OuterRect.Min.y;
// BgClipRect starts as table->InnerClipRect, reduce it now and make BgClipRectForDrawCmd == BgClipRect
table->BgClipRect.Min.y = table->Bg2ClipRectForDrawCmd.Min.y = ImMin(y0, window->InnerClipRect.Max.y);
table->BgClipRect.Max.y = table->Bg2ClipRectForDrawCmd.Max.y = window->InnerClipRect.Max.y;
table->Bg2DrawChannelCurrent = table->Bg2DrawChannelUnfrozen;
IM_ASSERT(table->Bg2ClipRectForDrawCmd.Min.y <= table->Bg2ClipRectForDrawCmd.Max.y);
float row_height = table->RowPosY2 - table->RowPosY1;
table->RowPosY2 = window->DC.CursorPos.y = table->WorkRect.Min.y + table->RowPosY2 - table->OuterRect.Min.y;
table->RowPosY1 = table->RowPosY2 - row_height;
for (int column_n = 0; column_n < table->ColumnsCount; column_n++)
if (unfreeze_rows_actual)
{
ImGuiTableColumn* column = &table->Columns[column_n];
column->DrawChannelCurrent = column->DrawChannelUnfrozen;
column->ClipRect.Min.y = table->Bg2ClipRectForDrawCmd.Min.y;
}
IM_ASSERT(table->IsUnfrozenRows == false);
table->IsUnfrozenRows = true;
// Update cliprect ahead of TableBeginCell() so clipper can access to new ClipRect->Min.y
SetWindowClipRectBeforeSetChannel(window, table->Columns[0].ClipRect);
table->DrawSplitter->SetCurrentChannel(window->DrawList, table->Columns[0].DrawChannelCurrent);
// BgClipRect starts as table->InnerClipRect, reduce it now and make BgClipRectForDrawCmd == BgClipRect
table->BgClipRect.Min.y = table->Bg2ClipRectForDrawCmd.Min.y = ImMin(y0, table->InnerClipRect.Max.y);
table->BgClipRect.Max.y = table->Bg2ClipRectForDrawCmd.Max.y = table->InnerClipRect.Max.y;
table->Bg2DrawChannelCurrent = table->Bg2DrawChannelUnfrozen;
IM_ASSERT(table->Bg2ClipRectForDrawCmd.Min.y <= table->Bg2ClipRectForDrawCmd.Max.y);
float row_height = table->RowPosY2 - table->RowPosY1;
table->RowPosY2 = window->DC.CursorPos.y = table->WorkRect.Min.y + table->RowPosY2 - table->OuterRect.Min.y;
table->RowPosY1 = table->RowPosY2 - row_height;
for (int column_n = 0; column_n < table->ColumnsCount; column_n++)
{
ImGuiTableColumn* column = &table->Columns[column_n];
column->DrawChannelCurrent = column->DrawChannelUnfrozen;
column->ClipRect.Min.y = table->Bg2ClipRectForDrawCmd.Min.y;
}
// Update cliprect ahead of TableBeginCell() so clipper can access to new ClipRect->Min.y
SetWindowClipRectBeforeSetChannel(window, table->Columns[0].ClipRect);
table->DrawSplitter->SetCurrentChannel(window->DrawList, table->Columns[0].DrawChannelCurrent);
}
}
if (!(table->RowFlags & ImGuiTableRowFlags_Headers))
@@ -2062,7 +2121,11 @@ bool ImGui::TableSetColumnIndex(int column_n)
{
if (table->CurrentColumn != -1)
TableEndCell(table);
IM_ASSERT(column_n >= 0 && table->ColumnsCount);
if ((column_n >= 0 && column_n < table->ColumnsCount) == false)
{
IM_ASSERT_USER_ERROR(column_n >= 0 && column_n < table->ColumnsCount, "TableSetColumnIndex() invalid column index!");
return false;
}
TableBeginCell(table, column_n);
}
@@ -2133,6 +2196,7 @@ void ImGui::TableBeginCell(ImGuiTable* table, int column_n)
g.LastItemData.StatusFlags = 0;
}
// Also see TablePushColumnChannel()
if (table->Flags & ImGuiTableFlags_NoClip)
{
// FIXME: if we end up drawing all borders/bg in EndTable, could remove this and just assert that channel hasn't changed.
@@ -2192,8 +2256,8 @@ void ImGui::TableEndCell(ImGuiTable* table)
// Note that actual columns widths are computed in TableUpdateLayout().
//-------------------------------------------------------------------------
// Maximum column content width given current layout. Use column->MinX so this value on a per-column basis.
float ImGui::TableGetMaxColumnWidth(const ImGuiTable* table, int column_n)
// Maximum column content width given current layout. Use column->MinX so this value differs on a per-column basis.
float ImGui::TableCalcMaxColumnWidth(const ImGuiTable* table, int column_n)
{
const ImGuiTableColumn* column = &table->Columns[column_n];
float max_width = FLT_MAX;
@@ -2255,7 +2319,7 @@ void ImGui::TableSetColumnWidth(int column_n, float width)
// Compare both requested and actual given width to avoid overwriting requested width when column is stuck (minimum size, bounded)
IM_ASSERT(table->MinColumnWidth > 0.0f);
const float min_width = table->MinColumnWidth;
const float max_width = ImMax(min_width, TableGetMaxColumnWidth(table, column_n));
const float max_width = ImMax(min_width, column_0->WidthMax); // Don't use TableCalcMaxColumnWidth() here as it would rely on MinX from last instance (#7933)
column_0_width = ImClamp(column_0_width, min_width, max_width);
if (column_0->WidthGiven == column_0_width || column_0->WidthRequest == column_0_width)
return;
@@ -2406,10 +2470,38 @@ void ImGui::TablePopBackgroundChannel()
ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow;
ImGuiTable* table = g.CurrentTable;
ImGuiTableColumn* column = &table->Columns[table->CurrentColumn];
// Optimization: avoid PopClipRect() + SetCurrentChannel()
SetWindowClipRectBeforeSetChannel(window, table->HostBackupInnerClipRect);
table->DrawSplitter->SetCurrentChannel(window->DrawList, table->Columns[table->CurrentColumn].DrawChannelCurrent);
}
// Also see TableBeginCell()
void ImGui::TablePushColumnChannel(int column_n)
{
ImGuiContext& g = *GImGui;
ImGuiTable* table = g.CurrentTable;
// Optimization: avoid SetCurrentChannel() + PushClipRect()
if (table->Flags & ImGuiTableFlags_NoClip)
return;
ImGuiWindow* window = g.CurrentWindow;
const ImGuiTableColumn* column = &table->Columns[column_n];
SetWindowClipRectBeforeSetChannel(window, column->ClipRect);
table->DrawSplitter->SetCurrentChannel(window->DrawList, column->DrawChannelCurrent);
}
void ImGui::TablePopColumnChannel()
{
ImGuiContext& g = *GImGui;
ImGuiTable* table = g.CurrentTable;
// Optimization: avoid PopClipRect() + SetCurrentChannel()
if ((table->Flags & ImGuiTableFlags_NoClip) || (table->CurrentColumn == -1)) // Calling TreePop() after TableNextRow() is supported.
return;
ImGuiWindow* window = g.CurrentWindow;
const ImGuiTableColumn* column = &table->Columns[table->CurrentColumn];
SetWindowClipRectBeforeSetChannel(window, column->ClipRect);
table->DrawSplitter->SetCurrentChannel(window->DrawList, column->DrawChannelCurrent);
}
@@ -2740,7 +2832,7 @@ void ImGui::TableDrawBorders(ImGuiTable* table)
const ImU32 outer_col = table->BorderColorStrong;
if ((table->Flags & ImGuiTableFlags_BordersOuter) == ImGuiTableFlags_BordersOuter)
{
inner_drawlist->AddRect(outer_border.Min, outer_border.Max + ImVec2(1, 1), outer_col, 0.0f, 0, border_size);
inner_drawlist->AddRect(outer_border.Min, outer_border.Max, outer_col, 0.0f, 0, border_size);
}
else if (table->Flags & ImGuiTableFlags_BordersOuterV)
{
@@ -3004,15 +3096,21 @@ float ImGui::TableGetHeaderAngledMaxLabelWidth()
// The intent is that advanced users willing to create customized headers would not need to use this helper
// and can create their own! For example: TableHeader() may be preceded by Checkbox() or other custom widgets.
// See 'Demo->Tables->Custom headers' for a demonstration of implementing a custom version of this.
// This code is constructed to not make much use of internal functions, as it is intended to be a template to copy.
// This code is intentionally written to not make much use of internal functions, to give you better direction
// if you need to write your own.
// FIXME-TABLE: TableOpenContextMenu() and TableGetHeaderRowHeight() are not public.
void ImGui::TableHeadersRow()
{
ImGuiContext& g = *GImGui;
ImGuiTable* table = g.CurrentTable;
IM_ASSERT(table != NULL && "Need to call TableHeadersRow() after BeginTable()!");
if (table == NULL)
{
IM_ASSERT_USER_ERROR(table != NULL, "Call should only be done while in BeginTable() scope!");
return;
}
// Layout if not already done (this is automatically done by TableNextRow, we do it here solely to facilitate stepping in debugger as it is frequent to step in TableUpdateLayout)
// Call layout if not already done. This is automatically done by TableNextRow: we do it here _only_ to make
// it easier to debug-step in TableUpdateLayout(). Your own version of this function doesn't need this.
if (!table->IsLayoutLocked)
TableUpdateLayout(table);
@@ -3029,8 +3127,7 @@ void ImGui::TableHeadersRow()
if (!TableSetColumnIndex(column_n))
continue;
// Push an id to allow unnamed labels (generally accidental, but let's behave nicely with them)
// In your own code you may omit the PushID/PopID all-together, provided you know they won't collide.
// Push an id to allow empty/unnamed headers. This is also idiomatic as it ensure there is a consistent ID path to access columns (for e.g. automation)
const char* name = (TableGetColumnFlags(column_n) & ImGuiTableColumnFlags_NoHeaderLabel) ? "" : TableGetColumnName(column_n);
PushID(column_n);
TableHeader(name);
@@ -3055,7 +3152,12 @@ void ImGui::TableHeader(const char* label)
return;
ImGuiTable* table = g.CurrentTable;
IM_ASSERT(table != NULL && "Need to call TableHeader() after BeginTable()!");
if (table == NULL)
{
IM_ASSERT_USER_ERROR(table != NULL, "Call should only be done while in BeginTable() scope!");
return;
}
IM_ASSERT(table->CurrentColumn != -1);
const int column_n = table->CurrentColumn;
ImGuiTableColumn* column = &table->Columns[column_n];
@@ -3121,7 +3223,7 @@ void ImGui::TableHeader(const char* label)
if ((table->RowFlags & ImGuiTableRowFlags_Headers) == 0)
TableSetBgColor(ImGuiTableBgTarget_CellBg, GetColorU32(ImGuiCol_TableHeaderBg), table->CurrentColumn);
}
RenderNavHighlight(bb, id, ImGuiNavHighlightFlags_Compact | ImGuiNavHighlightFlags_NoRounding);
RenderNavCursor(bb, id, ImGuiNavRenderCursorFlags_Compact | ImGuiNavRenderCursorFlags_NoRounding);
if (held)
table->HeldHeaderColumn = (ImGuiTableColumnIdx)column_n;
window->DC.CursorPos.y -= g.Style.ItemSpacing.y * 0.5f;
@@ -3176,7 +3278,7 @@ void ImGui::TableHeader(const char* label)
// Render clipped label. Clipping here ensure that in the majority of situations, all our header cells will
// be merged into a single draw call.
//window->DrawList->AddCircleFilled(ImVec2(ellipsis_max, label_pos.y), 40, IM_COL32_WHITE);
RenderTextEllipsis(window->DrawList, label_pos, ImVec2(ellipsis_max, label_pos.y + label_height + g.Style.FramePadding.y), ellipsis_max, ellipsis_max, label, label_end, &label_size);
RenderTextEllipsis(window->DrawList, label_pos, ImVec2(ellipsis_max, bb.Max.y), ellipsis_max, label, label_end, &label_size);
const bool text_clipped = label_size.x > (ellipsis_max - label_pos.x);
if (text_clipped && hovered && g.ActiveId == 0)
@@ -3230,7 +3332,11 @@ void ImGui::TableAngledHeadersRowEx(ImGuiID row_id, float angle, float max_label
ImGuiTable* table = g.CurrentTable;
ImGuiWindow* window = g.CurrentWindow;
ImDrawList* draw_list = window->DrawList;
IM_ASSERT(table != NULL && "Need to call TableHeadersRow() after BeginTable()!");
if (table == NULL)
{
IM_ASSERT_USER_ERROR(table != NULL, "Call should only be done while in BeginTable() scope!");
return;
}
IM_ASSERT(table->CurrentRow == -1 && "Must be first row");
if (max_label_width == 0.0f)
@@ -3269,13 +3375,13 @@ void ImGui::TableAngledHeadersRowEx(ImGuiID row_id, float angle, float max_label
ButtonBehavior(row_r, row_id, NULL, NULL);
KeepAliveID(row_id);
const float ascent_scaled = g.Font->Ascent * (g.FontSize / g.Font->FontSize); // FIXME: Standardize those scaling factors better
const float ascent_scaled = g.FontBaked->Ascent * g.FontBakedScale; // FIXME: Standardize those scaling factors better
const float line_off_for_ascent_x = (ImMax((g.FontSize - ascent_scaled) * 0.5f, 0.0f) / -sin_a) * (flip_label ? -1.0f : 1.0f);
const ImVec2 padding = g.Style.CellPadding; // We will always use swapped component
const ImVec2 align = g.Style.TableAngledHeadersTextAlign;
// Draw background and labels in first pass, then all borders.
float max_x = 0.0f;
float max_x = -FLT_MAX;
for (int pass = 0; pass < 2; pass++)
for (int order_n = 0; order_n < data_count; order_n++)
{
@@ -3324,7 +3430,7 @@ void ImGui::TableAngledHeadersRowEx(ImGuiID row_id, float angle, float max_label
ImRect clip_r(window->ClipRect.Min, window->ClipRect.Min + ImVec2(clip_width, clip_height));
int vtx_idx_begin = draw_list->_VtxCurrentIdx;
PushStyleColor(ImGuiCol_Text, request->TextColor);
RenderTextEllipsis(draw_list, clip_r.Min, clip_r.Max, clip_r.Max.x, clip_r.Max.x, label_name, label_name_eol, &label_size);
RenderTextEllipsis(draw_list, clip_r.Min, clip_r.Max, clip_r.Max.x, label_name, label_name_eol, &label_size);
PopStyleColor();
int vtx_idx_end = draw_list->_VtxCurrentIdx;
@@ -3471,7 +3577,7 @@ void ImGui::TableDrawDefaultContextMenu(ImGuiTable* table, ImGuiTableFlags flags
Separator();
want_separator = true;
PushItemFlag(ImGuiItemFlags_SelectableDontClosePopup, true);
PushItemFlag(ImGuiItemFlags_AutoClosePopups, false);
for (int other_column_n = 0; other_column_n < table->ColumnsCount; other_column_n++)
{
ImGuiTableColumn* other_column = &table->Columns[other_column_n];
@@ -3661,6 +3767,14 @@ void ImGui::TableLoadSettings(ImGuiTable* table)
table->SettingsLoadedFlags = settings->SaveFlags;
table->RefScale = settings->RefScale;
// Initialize default columns settings
for (int column_n = 0; column_n < table->ColumnsCount; column_n++)
{
ImGuiTableColumn* column = &table->Columns[column_n];
TableInitColumnDefaults(table, column, ~0);
column->AutoFitQueue = 0x00;
}
// Serialize ImGuiTableSettings/ImGuiTableColumnSettings into ImGuiTable/ImGuiTableColumn
ImGuiTableColumnSettings* column_settings = settings->GetColumnSettings();
ImU64 display_order_mask = 0;
@@ -3677,14 +3791,12 @@ void ImGui::TableLoadSettings(ImGuiTable* table)
column->StretchWeight = column_settings->WidthOrWeight;
else
column->WidthRequest = column_settings->WidthOrWeight;
column->AutoFitQueue = 0x00;
}
if (settings->SaveFlags & ImGuiTableFlags_Reorderable)
column->DisplayOrder = column_settings->DisplayOrder;
else
column->DisplayOrder = (ImGuiTableColumnIdx)column_n;
display_order_mask |= (ImU64)1 << column->DisplayOrder;
column->IsUserEnabled = column->IsUserEnabledNextFrame = column_settings->IsEnabled;
if ((settings->SaveFlags & ImGuiTableFlags_Hideable) && column_settings->IsEnabled != -1)
column->IsUserEnabled = column->IsUserEnabledNextFrame = column_settings->IsEnabled == 1;
column->SortOrder = column_settings->SortOrder;
column->SortDirection = column_settings->SortDirection;
}
@@ -3780,8 +3892,7 @@ static void TableSettingsHandler_WriteAll(ImGuiContext* ctx, ImGuiSettingsHandle
const bool save_visible = (settings->SaveFlags & ImGuiTableFlags_Hideable) != 0;
const bool save_order = (settings->SaveFlags & ImGuiTableFlags_Reorderable) != 0;
const bool save_sort = (settings->SaveFlags & ImGuiTableFlags_Sortable) != 0;
if (!save_size && !save_visible && !save_order && !save_sort)
continue;
// We need to save the [Table] entry even if all the bools are false, since this records a table with "default settings".
buf->reserve(buf->size() + 30 + settings->ColumnsCount * 50); // ballpark reserve
buf->appendf("[%s][0x%08X,%d]\n", handler->TypeName, settings->ID, settings->ColumnsCount);
@@ -4393,7 +4504,7 @@ void ImGui::EndColumns()
{
ButtonBehavior(column_hit_rect, column_id, &hovered, &held);
if (hovered || held)
g.MouseCursor = ImGuiMouseCursor_ResizeEW;
SetMouseCursor(ImGuiMouseCursor_ResizeEW);
if (held && !(column->Flags & ImGuiOldColumnFlags_NoResize))
dragging_column = n;
}
@@ -4425,12 +4536,12 @@ void ImGui::EndColumns()
NavUpdateCurrentWindowIsScrollPushableX();
}
void ImGui::Columns(int columns_count, const char* id, bool border)
void ImGui::Columns(int columns_count, const char* id, bool borders)
{
ImGuiWindow* window = GetCurrentWindow();
IM_ASSERT(columns_count >= 1);
ImGuiOldColumnFlags flags = (border ? 0 : ImGuiOldColumnFlags_NoBorder);
ImGuiOldColumnFlags flags = (borders ? 0 : ImGuiOldColumnFlags_NoBorder);
//flags |= ImGuiOldColumnFlags_NoPreserveWidths; // NB: Legacy behavior
ImGuiOldColumns* columns = window->DC.CurrentColumns;
if (columns != NULL && columns->Count == columns_count && columns->Flags == flags)
File diff suppressed because it is too large. Load diff
+96 -49
View File
@@ -3,6 +3,8 @@
// Those changes would need to be pushed into nothings/stb:
// - Fix in stb_textedit_discard_redo (see https://github.com/nothings/stb/issues/321)
// - Fix in stb_textedit_find_charpos to handle last line (see https://github.com/ocornut/imgui/issues/6000 + #6783)
// - Added name to struct or it may be forward declared in our code.
// - Added UTF-8 support (see https://github.com/nothings/stb/issues/188 + https://github.com/ocornut/imgui/pull/7925)
// Grep for [DEAR IMGUI] to find the changes.
// - Also renamed macros used or defined outside of IMSTB_TEXTEDIT_IMPLEMENTATION block from STB_TEXTEDIT_* to IMSTB_TEXTEDIT_*
@@ -139,6 +141,7 @@
// with previous char)
// STB_TEXTEDIT_KEYTOTEXT(k) maps a keyboard input to an insertable character
// (return type is int, -1 means not valid to insert)
// (not supported if you want to use UTF-8, see below)
// STB_TEXTEDIT_GETCHAR(obj,i) returns the i'th character of obj, 0-based
// STB_TEXTEDIT_NEWLINE the character returned by _GETCHAR() we recognize
// as manually wordwrapping for end-of-line positioning
@@ -176,6 +179,13 @@
// STB_TEXTEDIT_K_TEXTSTART2 secondary keyboard input to move cursor to start of text
// STB_TEXTEDIT_K_TEXTEND2 secondary keyboard input to move cursor to end of text
//
// To support UTF-8:
//
// STB_TEXTEDIT_GETPREVCHARINDEX returns index of previous character
// STB_TEXTEDIT_GETNEXTCHARINDEX returns index of next character
// Do NOT define STB_TEXTEDIT_KEYTOTEXT.
// Instead, call stb_textedit_text() directly for text contents.
//
// Keyboard input must be encoded as a single integer value; e.g. a character code
// and some bitflags that represent shift states. to simplify the interface, SHIFT must
// be a bitflag, so we can test the shifted state of cursor movements to allow selection,
@@ -209,6 +219,7 @@
// int stb_textedit_cut(STB_TEXTEDIT_STRING *str, STB_TexteditState *state)
// int stb_textedit_paste(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, STB_TEXTEDIT_CHARTYPE *text, int len)
// void stb_textedit_key(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, STB_TEXEDIT_KEYTYPE key)
// void stb_textedit_text(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, STB_TEXTEDIT_CHARTYPE *text, int text_len)
//
// Each of these functions potentially updates the string and updates the
// state.
@@ -243,7 +254,14 @@
// various definitions like STB_TEXTEDIT_K_LEFT have the is-key-event bit
// set, and make STB_TEXTEDIT_KEYTOCHAR check that the is-key-event bit is
// clear. STB_TEXTEDIT_KEYTYPE defaults to int, but you can #define it to
// anything other type you wante before including.
// anything other type you want before including.
// if the STB_TEXTEDIT_KEYTOTEXT function is defined, selected keys are
// transformed into text and stb_textedit_text() is automatically called.
//
// text: (added 2025)
// call this to directly send text input the textfield, which is required
// for UTF-8 support, because stb_textedit_key() + STB_TEXTEDIT_KEYTOTEXT()
// cannot infer text length.
//
//
// When rendering, you can read the cursor position and selection state from
@@ -318,7 +336,7 @@ typedef struct
int undo_char_point, redo_char_point;
} StbUndoState;
typedef struct
typedef struct STB_TexteditState
{
/////////////////////
//
@@ -392,6 +410,16 @@ typedef struct
#define IMSTB_TEXTEDIT_memmove memmove
#endif
// [DEAR IMGUI]
// Functions must be implemented for UTF8 support
// Code in this file that uses those functions is modified for [DEAR IMGUI] and deviates from the original stb_textedit.
// There is not necessarily a '[DEAR IMGUI]' at the usage sites.
#ifndef IMSTB_TEXTEDIT_GETPREVCHARINDEX
#define IMSTB_TEXTEDIT_GETPREVCHARINDEX(OBJ, IDX) ((IDX) - 1)
#endif
#ifndef IMSTB_TEXTEDIT_GETNEXTCHARINDEX
#define IMSTB_TEXTEDIT_GETNEXTCHARINDEX(OBJ, IDX) ((IDX) + 1)
#endif
/////////////////////////////////////////////////////////////////////////////
//
@@ -438,13 +466,13 @@ static int stb_text_locate_coord(IMSTB_TEXTEDIT_STRING *str, float x, float y)
if (x < r.x1) {
// search characters in row for one that straddles 'x'
prev_x = r.x0;
for (k=0; k < r.num_chars; ++k) {
for (k=0; k < r.num_chars; k = IMSTB_TEXTEDIT_GETNEXTCHARINDEX(str, i + k) - i) {
float w = STB_TEXTEDIT_GETWIDTH(str, i, k);
if (x < prev_x+w) {
if (x < prev_x+w/2)
return k+i;
else
return k+i+1;
return IMSTB_TEXTEDIT_GETNEXTCHARINDEX(str, i + k);
}
prev_x += w;
}
@@ -563,7 +591,7 @@ static void stb_textedit_find_charpos(StbFindState *find, IMSTB_TEXTEDIT_STRING
// now scan to find xpos
find->x = r.x0;
for (i=0; first+i < n; ++i)
for (i=0; first+i < n; i = IMSTB_TEXTEDIT_GETNEXTCHARINDEX(str, first + i) - first)
find->x += STB_TEXTEDIT_GETWIDTH(str, first, i);
}
@@ -649,9 +677,9 @@ static int is_word_boundary( IMSTB_TEXTEDIT_STRING *str, int idx )
#ifndef STB_TEXTEDIT_MOVEWORDLEFT
static int stb_textedit_move_to_word_previous( IMSTB_TEXTEDIT_STRING *str, int c )
{
--c; // always move at least one character
while( c >= 0 && !is_word_boundary( str, c ) )
--c;
c = IMSTB_TEXTEDIT_GETPREVCHARINDEX( str, c ); // always move at least one character
while (c >= 0 && !is_word_boundary(str, c))
c = IMSTB_TEXTEDIT_GETPREVCHARINDEX(str, c);
if( c < 0 )
c = 0;
@@ -665,9 +693,9 @@ static int stb_textedit_move_to_word_previous( IMSTB_TEXTEDIT_STRING *str, int c
static int stb_textedit_move_to_word_next( IMSTB_TEXTEDIT_STRING *str, int c )
{
const int len = STB_TEXTEDIT_STRINGLEN(str);
++c; // always move at least one character
c = IMSTB_TEXTEDIT_GETNEXTCHARINDEX(str, c); // always move at least one character
while( c < len && !is_word_boundary( str, c ) )
++c;
c = IMSTB_TEXTEDIT_GETNEXTCHARINDEX(str, c);
if( c > len )
c = len;
@@ -720,36 +748,45 @@ static int stb_textedit_paste_internal(IMSTB_TEXTEDIT_STRING *str, STB_TexteditS
#define STB_TEXTEDIT_KEYTYPE int
#endif
// API key: process text input
// [DEAR IMGUI] Added stb_textedit_text(), extracted out and called by stb_textedit_key() for backward compatibility.
static void stb_textedit_text(IMSTB_TEXTEDIT_STRING* str, STB_TexteditState* state, const IMSTB_TEXTEDIT_CHARTYPE* text, int text_len)
{
// can't add newline in single-line mode
if (text[0] == '\n' && state->single_line)
return;
if (state->insert_mode && !STB_TEXT_HAS_SELECTION(state) && state->cursor < STB_TEXTEDIT_STRINGLEN(str)) {
stb_text_makeundo_replace(str, state, state->cursor, 1, 1);
STB_TEXTEDIT_DELETECHARS(str, state->cursor, 1);
if (STB_TEXTEDIT_INSERTCHARS(str, state->cursor, text, text_len)) {
state->cursor += text_len;
state->has_preferred_x = 0;
}
} else {
stb_textedit_delete_selection(str, state); // implicitly clamps
if (STB_TEXTEDIT_INSERTCHARS(str, state->cursor, text, text_len)) {
stb_text_makeundo_insert(state, state->cursor, text_len);
state->cursor += text_len;
state->has_preferred_x = 0;
}
}
}
// API key: process a keyboard input
static void stb_textedit_key(IMSTB_TEXTEDIT_STRING *str, STB_TexteditState *state, STB_TEXTEDIT_KEYTYPE key)
{
retry:
switch (key) {
default: {
#ifdef STB_TEXTEDIT_KEYTOTEXT
// This is not suitable for UTF-8 support.
int c = STB_TEXTEDIT_KEYTOTEXT(key);
if (c > 0) {
IMSTB_TEXTEDIT_CHARTYPE ch = (IMSTB_TEXTEDIT_CHARTYPE) c;
// can't add newline in single-line mode
if (c == '\n' && state->single_line)
break;
if (state->insert_mode && !STB_TEXT_HAS_SELECTION(state) && state->cursor < STB_TEXTEDIT_STRINGLEN(str)) {
stb_text_makeundo_replace(str, state, state->cursor, 1, 1);
STB_TEXTEDIT_DELETECHARS(str, state->cursor, 1);
if (STB_TEXTEDIT_INSERTCHARS(str, state->cursor, &ch, 1)) {
++state->cursor;
state->has_preferred_x = 0;
}
} else {
stb_textedit_delete_selection(str,state); // implicitly clamps
if (STB_TEXTEDIT_INSERTCHARS(str, state->cursor, &ch, 1)) {
stb_text_makeundo_insert(state, state->cursor, 1);
++state->cursor;
state->has_preferred_x = 0;
}
}
IMSTB_TEXTEDIT_CHARTYPE ch = (IMSTB_TEXTEDIT_CHARTYPE)c;
stb_textedit_text(str, state, &ch, 1);
}
#endif
break;
}
@@ -775,7 +812,7 @@ retry:
stb_textedit_move_to_first(state);
else
if (state->cursor > 0)
--state->cursor;
state->cursor = IMSTB_TEXTEDIT_GETPREVCHARINDEX(str, state->cursor);
state->has_preferred_x = 0;
break;
@@ -784,7 +821,7 @@ retry:
if (STB_TEXT_HAS_SELECTION(state))
stb_textedit_move_to_last(str, state);
else
++state->cursor;
state->cursor = IMSTB_TEXTEDIT_GETNEXTCHARINDEX(str, state->cursor);
stb_textedit_clamp(str, state);
state->has_preferred_x = 0;
break;
@@ -794,7 +831,7 @@ retry:
stb_textedit_prep_selection_at_cursor(state);
// move selection left
if (state->select_end > 0)
--state->select_end;
state->select_end = IMSTB_TEXTEDIT_GETPREVCHARINDEX(str, state->select_end);
state->cursor = state->select_end;
state->has_preferred_x = 0;
break;
@@ -844,7 +881,7 @@ retry:
case STB_TEXTEDIT_K_RIGHT | STB_TEXTEDIT_K_SHIFT:
stb_textedit_prep_selection_at_cursor(state);
// move selection right
++state->select_end;
state->select_end = IMSTB_TEXTEDIT_GETNEXTCHARINDEX(str, state->select_end);
stb_textedit_clamp(str, state);
state->cursor = state->select_end;
state->has_preferred_x = 0;
@@ -891,8 +928,9 @@ retry:
state->cursor = start;
STB_TEXTEDIT_LAYOUTROW(&row, str, state->cursor);
x = row.x0;
for (i=0; i < row.num_chars; ++i) {
for (i=0; i < row.num_chars; ) {
float dx = STB_TEXTEDIT_GETWIDTH(str, start, i);
int next = IMSTB_TEXTEDIT_GETNEXTCHARINDEX(str, state->cursor);
#ifdef IMSTB_TEXTEDIT_GETWIDTH_NEWLINE
if (dx == IMSTB_TEXTEDIT_GETWIDTH_NEWLINE)
break;
@@ -900,7 +938,8 @@ retry:
x += dx;
if (x > goal_x)
break;
++state->cursor;
i += next - state->cursor;
state->cursor = next;
}
stb_textedit_clamp(str, state);
@@ -953,8 +992,9 @@ retry:
state->cursor = find.prev_first;
STB_TEXTEDIT_LAYOUTROW(&row, str, state->cursor);
x = row.x0;
for (i=0; i < row.num_chars; ++i) {
for (i=0; i < row.num_chars; ) {
float dx = STB_TEXTEDIT_GETWIDTH(str, find.prev_first, i);
int next = IMSTB_TEXTEDIT_GETNEXTCHARINDEX(str, state->cursor);
#ifdef IMSTB_TEXTEDIT_GETWIDTH_NEWLINE
if (dx == IMSTB_TEXTEDIT_GETWIDTH_NEWLINE)
break;
@@ -962,7 +1002,8 @@ retry:
x += dx;
if (x > goal_x)
break;
++state->cursor;
i += next - state->cursor;
state->cursor = next;
}
stb_textedit_clamp(str, state);
@@ -975,8 +1016,13 @@ retry:
// go to previous line
// (we need to scan previous line the hard way. maybe we could expose this as a new API function?)
prev_scan = find.prev_first > 0 ? find.prev_first - 1 : 0;
while (prev_scan > 0 && STB_TEXTEDIT_GETCHAR(str, prev_scan - 1) != STB_TEXTEDIT_NEWLINE)
--prev_scan;
while (prev_scan > 0)
{
int prev = IMSTB_TEXTEDIT_GETPREVCHARINDEX(str, prev_scan);
if (STB_TEXTEDIT_GETCHAR(str, prev) == STB_TEXTEDIT_NEWLINE)
break;
prev_scan = prev;
}
find.first_char = find.prev_first;
find.prev_first = prev_scan;
}
@@ -990,7 +1036,7 @@ retry:
else {
int n = STB_TEXTEDIT_STRINGLEN(str);
if (state->cursor < n)
stb_textedit_delete(str, state, state->cursor, 1);
stb_textedit_delete(str, state, state->cursor, IMSTB_TEXTEDIT_GETNEXTCHARINDEX(str, state->cursor) - state->cursor);
}
state->has_preferred_x = 0;
break;
@@ -1002,8 +1048,9 @@ retry:
else {
stb_textedit_clamp(str, state);
if (state->cursor > 0) {
stb_textedit_delete(str, state, state->cursor-1, 1);
--state->cursor;
int prev = IMSTB_TEXTEDIT_GETPREVCHARINDEX(str, state->cursor);
stb_textedit_delete(str, state, prev, state->cursor - prev);
state->cursor = prev;
}
}
state->has_preferred_x = 0;
@@ -1054,7 +1101,7 @@ retry:
if (state->single_line)
state->cursor = 0;
else while (state->cursor > 0 && STB_TEXTEDIT_GETCHAR(str, state->cursor-1) != STB_TEXTEDIT_NEWLINE)
--state->cursor;
state->cursor = IMSTB_TEXTEDIT_GETPREVCHARINDEX(str, state->cursor);
state->has_preferred_x = 0;
break;
@@ -1066,9 +1113,9 @@ retry:
stb_textedit_clamp(str, state);
stb_textedit_move_to_first(state);
if (state->single_line)
state->cursor = n;
state->cursor = n;
else while (state->cursor < n && STB_TEXTEDIT_GETCHAR(str, state->cursor) != STB_TEXTEDIT_NEWLINE)
++state->cursor;
state->cursor = IMSTB_TEXTEDIT_GETNEXTCHARINDEX(str, state->cursor);
state->has_preferred_x = 0;
break;
}
@@ -1082,7 +1129,7 @@ retry:
if (state->single_line)
state->cursor = 0;
else while (state->cursor > 0 && STB_TEXTEDIT_GETCHAR(str, state->cursor-1) != STB_TEXTEDIT_NEWLINE)
--state->cursor;
state->cursor = IMSTB_TEXTEDIT_GETPREVCHARINDEX(str, state->cursor);
state->select_end = state->cursor;
state->has_preferred_x = 0;
break;
@@ -1097,7 +1144,7 @@ retry:
if (state->single_line)
state->cursor = n;
else while (state->cursor < n && STB_TEXTEDIT_GETCHAR(str, state->cursor) != STB_TEXTEDIT_NEWLINE)
++state->cursor;
state->cursor = IMSTB_TEXTEDIT_GETNEXTCHARINDEX(str, state->cursor);
state->select_end = state->cursor;
state->has_preferred_x = 0;
break;
+2 -2
View File
@@ -4516,8 +4516,8 @@ static int stbtt__compute_crossings_x(float x, float y, int nverts, stbtt_vertex
q2[0] = (float)x2;
q2[1] = (float)y2;
if (equal(q0,q1) || equal(q1,q2)) {
x0 = (int)verts[i-1].x;
y0 = (int)verts[i-1].y;
x0 = (int)verts[i-1].x; //-V1048
y0 = (int)verts[i-1].y; //-V1048
x1 = (int)verts[i ].x;
y1 = (int)verts[i ].y;
if (y > STBTT_min(y0,y1) && y < STBTT_max(y0,y1) && x > STBTT_min(x0,x1)) {
Submodule core/deps/libjuice added at 77daa8befd.
+1 -1
View File
@@ -319,7 +319,7 @@ static void pppdump(uint8_t *buf, int len, int egress)
last_time_ms = PICO_TIME_MS();
}
uint32_t delta = (PICO_TIME_MS() - last_time_ms) / 100;
uint32_t delta = PICO_TIME_MS() / 100 - last_time_ms / 100;
if (delta < 256)
{
fputc(6, dumpfp); // Time step (short)
+18 -3
View File
@@ -1,6 +1,21 @@
===========
|Changelog|
===========
xBRZ 1.8 [2019-11-28]
---------------------
Consider ARGB outside area as transparent
Fixed ARGB scaling issue on image borders
xBRZ 1.7 [2019-07-04]
---------------------
Fixed asymmetric color distance
New parameter: "Center direction bias"
xBRZ 1.6 [2018-02-27]
---------------------
Added bilinear scaling
Option to skip color buffer creation
Updated license info
xBRZ 1.5 [2017-08-07]
---------------------
+439 -204
View File
@@ -1,24 +1,25 @@
// ****************************************************************************
// * This file is part of the HqMAME project. It is distributed under *
// * This file is part of the xBRZ project. It is distributed under *
// * GNU General Public License: https://www.gnu.org/licenses/gpl-3.0 *
// * Copyright (C) Zenju (zenju AT gmx DOT de) - All Rights Reserved *
// * *
// * Additionally and as a special exception, the author gives permission *
// * to link the code of this program with the MAME library (or with modified *
// * versions of MAME that use the same license as MAME), and distribute *
// * linked combinations including the two. You must obey the GNU General *
// * Public License in all respects for all of the code used other than MAME. *
// * to link the code of this program with the following libraries *
// * (or with modified versions that use the same licenses), and distribute *
// * linked combinations including the two: MAME, FreeFileSync, Snes9x, ePSXe *
// * You must obey the GNU General Public License in all respects for all of *
// * the code used other than MAME, FreeFileSync, Snes9x, ePSXe. *
// * If you modify this file, you may extend this exception to your version *
// * of the file, but you are not obligated to do so. If you do not wish to *
// * do so, delete this exception statement from your version. *
// ****************************************************************************
#include "xbrz.h"
#include "xbrz_tools.h"
#include <cassert>
#include <algorithm>
#include <vector>
#include <cmath>
#include <algorithm>
#include <cmath> //std::sqrt
#include "xbrz_tools.h"
using namespace xbrz;
@@ -26,9 +27,9 @@ using namespace xbrz;
namespace
{
template <unsigned int M, unsigned int N> inline
uint32_t gradientRGB(uint32_t pixFront, uint32_t pixBack) //blend front color with opacity M / N over opaque background: http://en.wikipedia.org/wiki/Alpha_compositing#Alpha_blending
uint32_t gradientRGB(uint32_t pixFront, uint32_t pixBack) //blend front color with opacity M / N over opaque background: https://en.wikipedia.org/wiki/Alpha_compositing#Alpha_blending
{
static_assert(0 < M && M < N && N <= 1000, "");
static_assert(0 < M && M < N && N <= 1000);
auto calcColor = [](unsigned char colFront, unsigned char colBack) -> unsigned char { return (colFront * M + colBack * (N - M)) / N; };
@@ -41,7 +42,7 @@ uint32_t gradientRGB(uint32_t pixFront, uint32_t pixBack) //blend front color wi
template <unsigned int M, unsigned int N> inline
uint32_t gradientARGB(uint32_t pixFront, uint32_t pixBack) //find intermediate color between two colors with alpha channels (=> NO alpha blending!!!)
{
static_assert(0 < M && M < N && N <= 1000, "");
static_assert(0 < M && M < N && N <= 1000);
const unsigned int weightFront = getAlpha(pixFront) * M;
const unsigned int weightBack = getAlpha(pixBack) * (N - M);
@@ -135,7 +136,7 @@ template <class T> inline
T square(T value) { return value * value; }
#if 0
inline
double distRGB(uint32_t pix1, uint32_t pix2)
{
@@ -146,12 +147,13 @@ double distRGB(uint32_t pix1, uint32_t pix2)
//euklidean RGB distance
return std::sqrt(square(r_diff) + square(g_diff) + square(b_diff));
}
#endif
inline
double distYCbCr(uint32_t pix1, uint32_t pix2, double lumaWeight)
{
//http://en.wikipedia.org/wiki/YCbCr#ITU-R_BT.601_conversion
//https://en.wikipedia.org/wiki/YCbCr#ITU-R_BT.601_conversion
//YCbCr conversion is a matrix multiplication => take advantage of linearity by subtracting first!
const int r_diff = static_cast<int>(getRed (pix1)) - getRed (pix2); //we may delay division by 255 to after matrix multiplication
const int g_diff = static_cast<int>(getGreen(pix1)) - getGreen(pix2); //
@@ -186,9 +188,9 @@ double distYCbCrBuffered(uint32_t pix1, uint32_t pix2)
for (uint32_t i = 0; i < 256 * 256 * 256; ++i) //startup time: 114 ms on Intel Core i5 (four cores)
{
const int r_diff = getByte<2>(i) * 2 - 0xFF;
const int g_diff = getByte<1>(i) * 2 - 0xFF;
const int b_diff = getByte<0>(i) * 2 - 0xFF;
const int r_diff = static_cast<signed char>(getByte<2>(i)) * 2;
const int g_diff = static_cast<signed char>(getByte<1>(i)) * 2;
const int b_diff = static_cast<signed char>(getByte<0>(i)) * 2;
const double k_b = 0.0593; //ITU-R BT.2020 conversion
const double k_r = 0.2627; //
@@ -210,24 +212,32 @@ double distYCbCrBuffered(uint32_t pix1, uint32_t pix2)
// return 0;
//if (pix1 < pix2)
// std::swap(pix1, pix2); -> 30% perf degradation!!!
#if 1
const int r_diff = static_cast<int>(getRed (pix1)) - getRed (pix2);
const int g_diff = static_cast<int>(getGreen(pix1)) - getGreen(pix2);
const int b_diff = static_cast<int>(getBlue (pix1)) - getBlue (pix2);
return diffToDist[(((r_diff + 0xFF) / 2) << 16) | //slightly reduce precision (division by 2) to squeeze value into single byte
(((g_diff + 0xFF) / 2) << 8) |
(( b_diff + 0xFF) / 2)];
#else //not noticeably faster:
const int r_diff_tmp = ((pix1 & 0xFF0000) + 0xFF0000 - (pix2 & 0xFF0000)) / 2;
const int g_diff_tmp = ((pix1 & 0x00FF00) + 0x00FF00 - (pix2 & 0x00FF00)) / 2; //slightly reduce precision (division by 2) to squeeze value into single byte
const int b_diff_tmp = ((pix1 & 0x0000FF) + 0x0000FF - (pix2 & 0x0000FF)) / 2;
const size_t index = (static_cast<unsigned char>(r_diff / 2) << 16) | //slightly reduce precision (division by 2) to squeeze value into single byte
(static_cast<unsigned char>(g_diff / 2) << 8) |
(static_cast<unsigned char>(b_diff / 2));
return diffToDist[(r_diff_tmp & 0xFF0000) | (g_diff_tmp & 0x00FF00) | (b_diff_tmp & 0x0000FF)];
#if 0 //attention: the following calculation creates an asymmetric color distance!!! (e.g. r_diff=46 will be unpacked as 45, but r_diff=-46 unpacks to -47
const size_t index = (((r_diff + 0xFF) / 2) << 16) | //slightly reduce precision (division by 2) to squeeze value into single byte
(((g_diff + 0xFF) / 2) << 8) |
(( b_diff + 0xFF) / 2);
#endif
return diffToDist[index];
}
#if defined _MSC_VER && !defined NDEBUG
const int debugPixelX = -1;
const int debugPixelY = 58;
thread_local bool breakIntoDebugger = false;
#endif
enum BlendType
{
BLEND_NONE = 0,
@@ -244,24 +254,32 @@ struct BlendResult
};
struct Kernel_3x3
{
uint32_t
a, b, c,
d, e, f,
g, h, i;
};
struct Kernel_4x4 //kernel for preprocessing step
{
uint32_t
/**/a, b, c, d,
/**/e, f, g, h,
/**/i, j, k, l,
/**/m, n, o, p;
a, b, c, //
e, f, g, // support reinterpret_cast from Kernel_4x4 => Kernel_3x3
i, j, k, //
m, n, o,
d, h, l, p;
};
/*
input kernel area naming convention:
/* input kernel area naming convention:
-----------------
| A | B | C | D |
----|---|---|---|
| E | F | G | H | //evaluate the four corners between F, G, J, K
----|---|---|---| //input pixel is at position F
|---|---|---|---|
| E | F | G | H | evaluate the four corners between F, G, J, K
|---|---|---|---| input pixel is at position F
| I | J | K | L |
----|---|---|---|
|---|---|---|---|
| M | N | O | P |
-----------------
*/
@@ -269,6 +287,11 @@ template <class ColorDistance>
FORCE_INLINE //detect blend direction
BlendResult preProcessCorners(const Kernel_4x4& ker, const xbrz::ScalerCfg& cfg) //result: F, G, J, K corners of "GradientType"
{
#if defined _MSC_VER && !defined NDEBUG
if (breakIntoDebugger)
__debugbreak(); //__asm int 3;
#endif
BlendResult result = {};
if ((ker.f == ker.g &&
@@ -279,9 +302,8 @@ BlendResult preProcessCorners(const Kernel_4x4& ker, const xbrz::ScalerCfg& cfg)
auto dist = [&](uint32_t pix1, uint32_t pix2) { return ColorDistance::dist(pix1, pix2, cfg.luminanceWeight); };
const int weight = 4;
double jg = dist(ker.i, ker.f) + dist(ker.f, ker.c) + dist(ker.n, ker.k) + dist(ker.k, ker.h) + weight * dist(ker.j, ker.g);
double fk = dist(ker.e, ker.j) + dist(ker.j, ker.o) + dist(ker.b, ker.g) + dist(ker.g, ker.l) + weight * dist(ker.f, ker.k);
double jg = dist(ker.i, ker.f) + dist(ker.f, ker.c) + dist(ker.n, ker.k) + dist(ker.k, ker.h) + cfg.centerDirectionBias * dist(ker.j, ker.g);
double fk = dist(ker.e, ker.j) + dist(ker.j, ker.o) + dist(ker.b, ker.g) + dist(ker.g, ker.l) + cfg.centerDirectionBias * dist(ker.f, ker.k);
if (jg < fk) //test sample: 70% of values max(jg, fk) / min(jg, fk) are between 1.1 and 3.7 with median being 1.8
{
@@ -304,14 +326,6 @@ BlendResult preProcessCorners(const Kernel_4x4& ker, const xbrz::ScalerCfg& cfg)
return result;
}
struct Kernel_3x3
{
uint32_t
/**/a, b, c,
/**/d, e, f,
/**/g, h, i;
};
#define DEF_GETTER(x) template <RotationDegree rotDeg> uint32_t inline get_##x(const Kernel_3x3& ker) { return ker.x; }
//we cannot and NEED NOT write "ker.##x" since ## concatenates preprocessor tokens but "." is not a token
DEF_GETTER(a) DEF_GETTER(b) DEF_GETTER(c)
@@ -339,17 +353,21 @@ DEF_GETTER(g, a) DEF_GETTER(h, d) DEF_GETTER(i, g)
//compress four blend types into a single byte
inline BlendType getTopL (unsigned char b) { return static_cast<BlendType>(0x3 & b); }
//inline BlendType getTopL (unsigned char b) { return static_cast<BlendType>(0x3 & b); }
inline BlendType getTopR (unsigned char b) { return static_cast<BlendType>(0x3 & (b >> 2)); }
inline BlendType getBottomR(unsigned char b) { return static_cast<BlendType>(0x3 & (b >> 4)); }
inline BlendType getBottomL(unsigned char b) { return static_cast<BlendType>(0x3 & (b >> 6)); }
inline void setTopL (unsigned char& b, BlendType bt) { b |= bt; } //buffer is assumed to be initialized before preprocessing!
inline void setTopR (unsigned char& b, BlendType bt) { b |= (bt << 2); }
inline void setBottomR(unsigned char& b, BlendType bt) { b |= (bt << 4); }
inline void setBottomL(unsigned char& b, BlendType bt) { b |= (bt << 6); }
inline void clearAddTopL(unsigned char& b, BlendType bt) { b = static_cast<unsigned char>(bt); }
inline void addTopR (unsigned char& b, BlendType bt) { b |= (bt << 2); } //buffer is assumed to be initialized before preprocessing!
inline void addBottomR (unsigned char& b, BlendType bt) { b |= (bt << 4); } //e.g. via clearAddTopL()
inline void addBottomL (unsigned char& b, BlendType bt) { b |= (bt << 6); } //
inline bool blendingNeeded(unsigned char b) { return b != 0; }
inline bool blendingNeeded(unsigned char b)
{
static_assert(BLEND_NONE == 0);
return b != 0;
}
template <RotationDegree rotDeg> inline
unsigned char rotateBlendInfo(unsigned char b) { return b; }
@@ -358,20 +376,12 @@ template <> inline unsigned char rotateBlendInfo<ROT_180>(unsigned char b) { ret
template <> inline unsigned char rotateBlendInfo<ROT_270>(unsigned char b) { return ((b << 6) | (b >> 2)) & 0xff; }
#if defined _MSC_VER && !defined NDEBUG
int debugPixelX = -1;
int debugPixelY = 12;
__declspec(thread) bool breakIntoDebugger = false;
#endif
/*
input kernel area naming convention:
/* input kernel area naming convention:
-------------
| A | B | C |
----|---|---|
| D | E | F | //input pixel is at position E
----|---|---|
|---|---|---|
| D | E | F | input pixel is at position E
|---|---|---|
| G | H | I |
-------------
*/
@@ -382,7 +392,7 @@ void blendPixel(const Kernel_3x3& ker,
unsigned char blendInfo, //result of preprocessing all four corners of pixel "e"
const xbrz::ScalerCfg& cfg)
{
#define a get_a<rotDeg>(ker)
//#define a get_a<rotDeg>(ker)
#define b get_b<rotDeg>(ker)
#define c get_c<rotDeg>(ker)
#define d get_d<rotDeg>(ker)
@@ -410,7 +420,7 @@ void blendPixel(const Kernel_3x3& ker,
return true;
//make sure there is no second blending in an adjacent rotation for this pixel: handles insular pixels, mario eyes
if (getTopR(blend) != BLEND_NONE && !eq(e, g)) //but support double-blending for 90� corners
if (getTopR(blend) != BLEND_NONE && !eq(e, g)) //but support double-blending for 90° corners
return false;
if (getBottomL(blend) != BLEND_NONE && !eq(e, c))
return false;
@@ -453,7 +463,7 @@ void blendPixel(const Kernel_3x3& ker,
Scaler::blendCorner(px, out);
}
#undef a
//#undef a
#undef b
#undef c
#undef d
@@ -465,7 +475,72 @@ void blendPixel(const Kernel_3x3& ker,
}
template <class Scaler, class ColorDistance> //scaler policy: see "Scaler2x" reference implementation
class OobReaderTransparent
{
public:
OobReaderTransparent(const uint32_t* src, int srcWidth, int srcHeight, int y) :
s_m1(0 <= y - 1 && y - 1 < srcHeight ? src + srcWidth * (y - 1) : nullptr),
s_0 (0 <= y && y < srcHeight ? src + srcWidth * y : nullptr),
s_p1(0 <= y + 1 && y + 1 < srcHeight ? src + srcWidth * (y + 1) : nullptr),
s_p2(0 <= y + 2 && y + 2 < srcHeight ? src + srcWidth * (y + 2) : nullptr),
srcWidth_(srcWidth) {}
void readDhlp(Kernel_4x4& ker, int x) const //(x, y) is at kernel position F
{
[[likely]] if (const int x_p2 = x + 2; 0 <= x_p2 && x_p2 < srcWidth_)
{
ker.d = s_m1 ? s_m1[x_p2] : 0;
ker.h = s_0 ? s_0 [x_p2] : 0;
ker.l = s_p1 ? s_p1[x_p2] : 0;
ker.p = s_p2 ? s_p2[x_p2] : 0;
}
else
{
ker.d = 0;
ker.h = 0;
ker.l = 0;
ker.p = 0;
}
}
private:
const uint32_t* const s_m1;
const uint32_t* const s_0;
const uint32_t* const s_p1;
const uint32_t* const s_p2;
const int srcWidth_;
};
class OobReaderDuplicate
{
public:
OobReaderDuplicate(const uint32_t* src, int srcWidth, int srcHeight, int y) :
s_m1(src + srcWidth * std::clamp(y - 1, 0, srcHeight - 1)),
s_0 (src + srcWidth * std::clamp(y, 0, srcHeight - 1)),
s_p1(src + srcWidth * std::clamp(y + 1, 0, srcHeight - 1)),
s_p2(src + srcWidth * std::clamp(y + 2, 0, srcHeight - 1)),
srcWidth_(srcWidth) {}
void readDhlp(Kernel_4x4& ker, int x) const //(x, y) is at kernel position F
{
const int x_p2 = std::clamp(x + 2, 0, srcWidth_ - 1);
ker.d = s_m1[x_p2];
ker.h = s_0 [x_p2];
ker.l = s_p1[x_p2];
ker.p = s_p2[x_p2];
}
private:
const uint32_t* const s_m1;
const uint32_t* const s_0;
const uint32_t* const s_p1;
const uint32_t* const s_p2;
const int srcWidth_;
};
template <class Scaler, class ColorDistance, class OobReader> //scaler policy: see "Scaler2x" reference implementation
void scaleImage(const uint32_t* src, uint32_t* trg, int srcWidth, int srcHeight, const xbrz::ScalerCfg& cfg, int yFirst, int yLast)
{
yFirst = std::max(yFirst, 0);
@@ -475,64 +550,72 @@ void scaleImage(const uint32_t* src, uint32_t* trg, int srcWidth, int srcHeight,
const int trgWidth = srcWidth * Scaler::scale;
//"use" space at the end of the image as temporary buffer for "on the fly preprocessing": we even could use larger area of
//"sizeof(uint32_t) * srcWidth * (yLast - yFirst)" bytes without risk of accidental overwriting before accessing
const int bufferSize = srcWidth;
unsigned char* preProcBuffer = reinterpret_cast<unsigned char*>(trg + yLast * Scaler::scale * trgWidth) - bufferSize;
std::fill(preProcBuffer, preProcBuffer + bufferSize, '\0');
static_assert(BLEND_NONE == 0, "");
//(ab)use space of "sizeof(uint32_t) * srcWidth * Scaler::scale" at the end of the image as temporary
//buffer for "on the fly preprocessing" without risk of accidental overwriting before accessing
unsigned char* const preProcBuf = reinterpret_cast<unsigned char*>(trg + yLast * Scaler::scale * trgWidth) - srcWidth;
//initialize preprocessing buffer for first row of current stripe: detect upper left and right corner blending
//this cannot be optimized for adjacent processing stripes; we must not allow for a memory race condition!
if (yFirst > 0)
{
const int y = yFirst - 1;
const OobReader oobReader(src, srcWidth, srcHeight, yFirst - 1);
const uint32_t* s_m1 = src + srcWidth * std::max(y - 1, 0);
const uint32_t* s_0 = src + srcWidth * y; //center line
const uint32_t* s_p1 = src + srcWidth * std::min(y + 1, srcHeight - 1);
const uint32_t* s_p2 = src + srcWidth * std::min(y + 2, srcHeight - 1);
//initialize at position x = -1
Kernel_4x4 ker4 = {};
oobReader.readDhlp(ker4, -4); //hack: read a, e, i, m at x = -1
ker4.a = ker4.d;
ker4.e = ker4.h;
ker4.i = ker4.l;
ker4.m = ker4.p;
oobReader.readDhlp(ker4, -3);
ker4.b = ker4.d;
ker4.f = ker4.h;
ker4.j = ker4.l;
ker4.n = ker4.p;
oobReader.readDhlp(ker4, -2);
ker4.c = ker4.d;
ker4.g = ker4.h;
ker4.k = ker4.l;
ker4.o = ker4.p;
oobReader.readDhlp(ker4, -1);
{
const BlendResult res = preProcessCorners<ColorDistance>(ker4, cfg);
clearAddTopL(preProcBuf[0], res.blend_k); //set 1st known corner for (0, yFirst)
}
for (int x = 0; x < srcWidth; ++x)
{
const int x_m1 = std::max(x - 1, 0);
const int x_p1 = std::min(x + 1, srcWidth - 1);
const int x_p2 = std::min(x + 2, srcWidth - 1);
ker4.a = ker4.b; //shift previous kernel to the left
ker4.e = ker4.f; // -----------------
ker4.i = ker4.j; // | A | B | C | D |
ker4.m = ker4.n; // |---|---|---|---|
/**/ // | E | F | G | H | (x, yFirst - 1) is at position F
ker4.b = ker4.c; // |---|---|---|---|
ker4.f = ker4.g; // | I | J | K | L |
ker4.j = ker4.k; // |---|---|---|---|
ker4.n = ker4.o; // | M | N | O | P |
/**/ // -----------------
ker4.c = ker4.d;
ker4.g = ker4.h;
ker4.k = ker4.l;
ker4.o = ker4.p;
Kernel_4x4 ker = {}; //perf: initialization is negligible
ker.a = s_m1[x_m1]; //read sequentially from memory as far as possible
ker.b = s_m1[x];
ker.c = s_m1[x_p1];
ker.d = s_m1[x_p2];
oobReader.readDhlp(ker4, x);
ker.e = s_0[x_m1];
ker.f = s_0[x];
ker.g = s_0[x_p1];
ker.h = s_0[x_p2];
/* preprocessing blend result:
---------
| F | G | evaluate corner between F, G, J, K
|---+---| current input pixel is at position F
| J | K |
--------- */
const BlendResult res = preProcessCorners<ColorDistance>(ker4, cfg);
addTopR(preProcBuf[x], res.blend_j); //set 2nd known corner for (x, yFirst)
ker.i = s_p1[x_m1];
ker.j = s_p1[x];
ker.k = s_p1[x_p1];
ker.l = s_p1[x_p2];
ker.m = s_p2[x_m1];
ker.n = s_p2[x];
ker.o = s_p2[x_p1];
ker.p = s_p2[x_p2];
const BlendResult res = preProcessCorners<ColorDistance>(ker, cfg);
/*
preprocessing blend result:
---------
| F | G | //evalute corner between F, G, J, K
----|---| //input pixel is at position F
| J | K |
---------
*/
setTopR(preProcBuffer[x], res.blend_j);
if (x + 1 < bufferSize)
setTopL(preProcBuffer[x + 1], res.blend_k);
if (x + 1 < srcWidth)
clearAddTopL(preProcBuf[x + 1], res.blend_k); //set 1st known corner for (x + 1, yFirst)
}
}
//------------------------------------------------------------------------------------
@@ -541,91 +624,92 @@ void scaleImage(const uint32_t* src, uint32_t* trg, int srcWidth, int srcHeight,
{
uint32_t* out = trg + Scaler::scale * y * trgWidth; //consider MT "striped" access
const uint32_t* s_m1 = src + srcWidth * std::max(y - 1, 0);
const uint32_t* s_0 = src + srcWidth * y; //center line
const uint32_t* s_p1 = src + srcWidth * std::min(y + 1, srcHeight - 1);
const uint32_t* s_p2 = src + srcWidth * std::min(y + 2, srcHeight - 1);
const OobReader oobReader(src, srcWidth, srcHeight, y);
//initialize at position x = -1
Kernel_4x4 ker4 = {};
oobReader.readDhlp(ker4, -4); //hack: read a, e, i, m at x = -1
ker4.a = ker4.d;
ker4.e = ker4.h;
ker4.i = ker4.l;
ker4.m = ker4.p;
oobReader.readDhlp(ker4, -3);
ker4.b = ker4.d;
ker4.f = ker4.h;
ker4.j = ker4.l;
ker4.n = ker4.p;
oobReader.readDhlp(ker4, -2);
ker4.c = ker4.d;
ker4.g = ker4.h;
ker4.k = ker4.l;
ker4.o = ker4.p;
oobReader.readDhlp(ker4, -1);
unsigned char blend_xy1 = 0; //corner blending for current (x, y + 1) position
{
const BlendResult res = preProcessCorners<ColorDistance>(ker4, cfg);
clearAddTopL(blend_xy1, res.blend_k); //set 1st known corner for (0, y + 1) and buffer for use on next column
addBottomL(preProcBuf[0], res.blend_g); //set 3rd known corner for (0, y)
}
for (int x = 0; x < srcWidth; ++x, out += Scaler::scale)
{
#if defined _MSC_VER && !defined NDEBUG
breakIntoDebugger = debugPixelX == x && debugPixelY == y;
#endif
//all those bounds checks have only insignificant impact on performance!
const int x_m1 = std::max(x - 1, 0); //perf: prefer array indexing to additional pointers!
const int x_p1 = std::min(x + 1, srcWidth - 1);
const int x_p2 = std::min(x + 2, srcWidth - 1);
ker4.a = ker4.b; //shift previous kernel to the left
ker4.e = ker4.f; // -----------------
ker4.i = ker4.j; // | A | B | C | D |
ker4.m = ker4.n; // |---|---|---|---|
/**/ // | E | F | G | H | (x, y) is at position F
ker4.b = ker4.c; // |---|---|---|---|
ker4.f = ker4.g; // | I | J | K | L |
ker4.j = ker4.k; // |---|---|---|---|
ker4.n = ker4.o; // | M | N | O | P |
/**/ // -----------------
ker4.c = ker4.d;
ker4.g = ker4.h;
ker4.k = ker4.l;
ker4.o = ker4.p;
Kernel_4x4 ker4 = {}; //perf: initialization is negligible
ker4.a = s_m1[x_m1]; //read sequentially from memory as far as possible
ker4.b = s_m1[x];
ker4.c = s_m1[x_p1];
ker4.d = s_m1[x_p2];
ker4.e = s_0[x_m1];
ker4.f = s_0[x];
ker4.g = s_0[x_p1];
ker4.h = s_0[x_p2];
ker4.i = s_p1[x_m1];
ker4.j = s_p1[x];
ker4.k = s_p1[x_p1];
ker4.l = s_p1[x_p2];
ker4.m = s_p2[x_m1];
ker4.n = s_p2[x];
ker4.o = s_p2[x_p1];
ker4.p = s_p2[x_p2];
oobReader.readDhlp(ker4, x);
//evaluate the four corners on bottom-right of current pixel
unsigned char blend_xy = 0; //for current (x, y) position
unsigned char blend_xy = preProcBuf[x]; //for current (x, y) position
{
/* preprocessing blend result:
---------
| F | G | evaluate corner between F, G, J, K
|---+---| current input pixel is at position F
| J | K |
--------- */
const BlendResult res = preProcessCorners<ColorDistance>(ker4, cfg);
/*
preprocessing blend result:
---------
| F | G | //evalute corner between F, G, J, K
----|---| //current input pixel is at position F
| J | K |
---------
*/
blend_xy = preProcBuffer[x];
setBottomR(blend_xy, res.blend_f); //all four corners of (x, y) have been determined at this point due to processing sequence!
addBottomR(blend_xy, res.blend_f); //all four corners of (x, y) have been determined at this point due to processing sequence!
setTopR(blend_xy1, res.blend_j); //set 2nd known corner for (x, y + 1)
preProcBuffer[x] = blend_xy1; //store on current buffer position for use on next row
addTopR(blend_xy1, res.blend_j); //set 2nd known corner for (x, y + 1)
preProcBuf[x] = blend_xy1; //store on current buffer position for use on next row
blend_xy1 = 0;
setTopL(blend_xy1, res.blend_k); //set 1st known corner for (x + 1, y + 1) and buffer for use on next column
[[likely]] if (x + 1 < srcWidth)
{
//blend_xy1 -> blend_x1y1
clearAddTopL(blend_xy1, res.blend_k); //set 1st known corner for (x + 1, y + 1) and buffer for use on next column
if (x + 1 < bufferSize) //set 3rd known corner for (x + 1, y)
setBottomL(preProcBuffer[x + 1], res.blend_g);
addBottomL(preProcBuf[x + 1], res.blend_g); //set 3rd known corner for (x + 1, y)
}
}
//fill block of size scale * scale with the given color
fillBlock(out, trgWidth * sizeof(uint32_t), ker4.f, Scaler::scale, Scaler::scale);
//place *after* preprocessing step, to not overwrite the results while processing the the last pixel!
//place *after* preprocessing step, to not overwrite the results while processing the last pixel!
//blend four corners of current pixel
if (blendingNeeded(blend_xy)) //good 5% perf-improvement
//blend all four corners of current pixel
if (blendingNeeded(blend_xy))
{
Kernel_3x3 ker3 = {}; //perf: initialization is negligible
ker3.a = ker4.a;
ker3.b = ker4.b;
ker3.c = ker4.c;
ker3.d = ker4.e;
ker3.e = ker4.f;
ker3.f = ker4.g;
ker3.g = ker4.i;
ker3.h = ker4.j;
ker3.i = ker4.k;
const auto& ker3 = reinterpret_cast<const Kernel_3x3&>(ker4); //"The Things We Do for Perf"
blendPixel<Scaler, ColorDistance, ROT_0 >(ker3, out, trgWidth, blend_xy, cfg);
blendPixel<Scaler, ColorDistance, ROT_90 >(ker3, out, trgWidth, blend_xy, cfg);
blendPixel<Scaler, ColorDistance, ROT_180>(ker3, out, trgWidth, blend_xy, cfg);
@@ -1037,6 +1121,22 @@ struct ColorDistanceARGB
};
struct ColorDistanceUnbufferedARGB
{
static double dist(uint32_t pix1, uint32_t pix2, double luminanceWeight)
{
const double a1 = getAlpha(pix1) / 255.0 ;
const double a2 = getAlpha(pix2) / 255.0 ;
const double d = distYCbCr(pix1, pix2, luminanceWeight);
if (a1 < a2)
return a1 * d + 255 * (a2 - a1);
else
return a2 * d + 255 * (a1 - a2);
}
};
struct ColorGradientRGB
{
template <unsigned int M, unsigned int N>
@@ -1059,37 +1159,60 @@ struct ColorGradientARGB
void xbrz::scale(size_t factor, const uint32_t* src, uint32_t* trg, int srcWidth, int srcHeight, ColorFormat colFmt, const xbrz::ScalerCfg& cfg, int yFirst, int yLast)
{
if (factor == 1)
{
std::copy(src + yFirst * srcWidth, src + yLast * srcWidth, trg);
return;
}
static_assert(SCALE_FACTOR_MAX == 6);
switch (colFmt)
{
case ColorFormat::ARGB:
switch (factor)
{
case 2:
return scaleImage<Scaler2x<ColorGradientARGB>, ColorDistanceARGB>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast);
case 3:
return scaleImage<Scaler3x<ColorGradientARGB>, ColorDistanceARGB>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast);
case 4:
return scaleImage<Scaler4x<ColorGradientARGB>, ColorDistanceARGB>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast);
case 5:
return scaleImage<Scaler5x<ColorGradientARGB>, ColorDistanceARGB>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast);
case 6:
return scaleImage<Scaler6x<ColorGradientARGB>, ColorDistanceARGB>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast);
}
break;
case ColorFormat::RGB:
switch (factor)
{
case 2:
return scaleImage<Scaler2x<ColorGradientRGB>, ColorDistanceRGB>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast);
return scaleImage<Scaler2x<ColorGradientRGB>, ColorDistanceRGB, OobReaderDuplicate>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast);
case 3:
return scaleImage<Scaler3x<ColorGradientRGB>, ColorDistanceRGB>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast);
return scaleImage<Scaler3x<ColorGradientRGB>, ColorDistanceRGB, OobReaderDuplicate>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast);
case 4:
return scaleImage<Scaler4x<ColorGradientRGB>, ColorDistanceRGB>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast);
return scaleImage<Scaler4x<ColorGradientRGB>, ColorDistanceRGB, OobReaderDuplicate>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast);
case 5:
return scaleImage<Scaler5x<ColorGradientRGB>, ColorDistanceRGB>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast);
return scaleImage<Scaler5x<ColorGradientRGB>, ColorDistanceRGB, OobReaderDuplicate>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast);
case 6:
return scaleImage<Scaler6x<ColorGradientRGB>, ColorDistanceRGB>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast);
return scaleImage<Scaler6x<ColorGradientRGB>, ColorDistanceRGB, OobReaderDuplicate>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast);
}
break;
case ColorFormat::ARGB:
switch (factor)
{
case 2:
return scaleImage<Scaler2x<ColorGradientARGB>, ColorDistanceARGB, OobReaderTransparent>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast);
case 3:
return scaleImage<Scaler3x<ColorGradientARGB>, ColorDistanceARGB, OobReaderTransparent>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast);
case 4:
return scaleImage<Scaler4x<ColorGradientARGB>, ColorDistanceARGB, OobReaderTransparent>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast);
case 5:
return scaleImage<Scaler5x<ColorGradientARGB>, ColorDistanceARGB, OobReaderTransparent>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast);
case 6:
return scaleImage<Scaler6x<ColorGradientARGB>, ColorDistanceARGB, OobReaderTransparent>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast);
}
break;
case ColorFormat::ARGB_UNBUFFERED:
switch (factor)
{
case 2:
return scaleImage<Scaler2x<ColorGradientARGB>, ColorDistanceUnbufferedARGB, OobReaderTransparent>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast);
case 3:
return scaleImage<Scaler3x<ColorGradientARGB>, ColorDistanceUnbufferedARGB, OobReaderTransparent>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast);
case 4:
return scaleImage<Scaler4x<ColorGradientARGB>, ColorDistanceUnbufferedARGB, OobReaderTransparent>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast);
case 5:
return scaleImage<Scaler5x<ColorGradientARGB>, ColorDistanceUnbufferedARGB, OobReaderTransparent>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast);
case 6:
return scaleImage<Scaler6x<ColorGradientARGB>, ColorDistanceUnbufferedARGB, OobReaderTransparent>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast);
}
break;
}
@@ -1101,21 +1224,133 @@ bool xbrz::equalColorTest(uint32_t col1, uint32_t col2, ColorFormat colFmt, doub
{
switch (colFmt)
{
case ColorFormat::ARGB:
return ColorDistanceARGB::dist(col1, col2, luminanceWeight) < equalColorTolerance;
case ColorFormat::RGB:
return ColorDistanceRGB::dist(col1, col2, luminanceWeight) < equalColorTolerance;
case ColorFormat::ARGB:
return ColorDistanceARGB::dist(col1, col2, luminanceWeight) < equalColorTolerance;
case ColorFormat::ARGB_UNBUFFERED:
return ColorDistanceUnbufferedARGB::dist(col1, col2, luminanceWeight) < equalColorTolerance;
}
assert(false);
return false;
}
void xbrz::bilinearScale(const uint32_t* src, int srcWidth, int srcHeight,
/**/ uint32_t* trg, int trgWidth, int trgHeight)
{
bilinearScale(src, srcWidth, srcHeight, srcWidth * sizeof(uint32_t),
trg, trgWidth, trgHeight, trgWidth * sizeof(uint32_t),
0, trgHeight, [](uint32_t pix) { return pix; });
}
void xbrz::nearestNeighborScale(const uint32_t* src, int srcWidth, int srcHeight,
uint32_t* trg, int trgWidth, int trgHeight)
/**/ uint32_t* trg, int trgWidth, int trgHeight)
{
nearestNeighborScale(src, srcWidth, srcHeight, srcWidth * sizeof(uint32_t),
trg, trgWidth, trgHeight, trgWidth * sizeof(uint32_t),
SliceType::TARGET, 0, trgHeight, [](uint32_t pix) { return pix; });
0, trgHeight, [](uint32_t pix) { return pix; });
}
#if 0
//#include <ppl.h>
void bilinearScaleCpu(const uint32_t* src, int srcWidth, int srcHeight,
/**/ uint32_t* trg, int trgWidth, int trgHeight)
{
const int TASK_GRANULARITY = 16;
concurrency::task_group tg;
for (int i = 0; i < trgHeight; i += TASK_GRANULARITY)
tg.run([=]
{
const int iLast = std::min(i + TASK_GRANULARITY, trgHeight);
xbrz::bilinearScale(src, srcWidth, srcHeight, srcWidth * sizeof(uint32_t),
trg, trgWidth, trgHeight, trgWidth * sizeof(uint32_t),
i, iLast, [](uint32_t pix) { return pix; });
});
tg.wait();
}
//Perf: AMP vs CPU: merely ~10% shorter runtime (scaling 1280x800 -> 1920x1080)
//#include <amp.h>
void bilinearScaleAmp(const uint32_t* src, int srcWidth, int srcHeight, //throw concurrency::runtime_exception
/**/ uint32_t* trg, int trgWidth, int trgHeight)
{
//C++ AMP reference: https://msdn.microsoft.com/en-us/library/hh289390.aspx
//introduction to C++ AMP: https://msdn.microsoft.com/en-us/magazine/hh882446.aspx
using namespace concurrency;
//TODO: pitch
if (srcHeight <= 0 || srcWidth <= 0) return;
const float scaleX = static_cast<float>(trgWidth ) / srcWidth;
const float scaleY = static_cast<float>(trgHeight) / srcHeight;
array_view<const uint32_t, 2> srcView(srcHeight, srcWidth, src);
array_view< uint32_t, 2> trgView(trgHeight, trgWidth, trg);
trgView.discard_data();
parallel_for_each(trgView.extent, [=](index<2> idx) restrict(amp) //throw ?
{
const int y = idx[0];
const int x = idx[1];
//Perf notes:
// -> float-based calculation is (almost) 2x as fas as double!
// -> no noticeable improvement via tiling: https://msdn.microsoft.com/en-us/magazine/hh882447.aspx
// -> no noticeable improvement with restrict(amp,cpu)
// -> iterating over y-axis only is significantly slower!
// -> pre-calculating x,y-dependent variables in a buffer + array_view<> is ~ 20 % slower!
const int y1 = srcHeight * y / trgHeight;
int y2 = y1 + 1;
if (y2 == srcHeight) --y2;
const float yy1 = y / scaleY - y1;
const float y2y = 1 - yy1;
//-------------------------------------
const int x1 = srcWidth * x / trgWidth;
int x2 = x1 + 1;
if (x2 == srcWidth) --x2;
const float xx1 = x / scaleX - x1;
const float x2x = 1 - xx1;
//-------------------------------------
const float x2xy2y = x2x * y2y;
const float xx1y2y = xx1 * y2y;
const float x2xyy1 = x2x * yy1;
const float xx1yy1 = xx1 * yy1;
auto interpolate = [=](int offset)
{
/*
https://en.wikipedia.org/wiki/Bilinear_interpolation
(c11(x2 - x) + c21(x - x1)) * (y2 - y ) +
(c12(x2 - x) + c22(x - x1)) * (y - y1)
*/
const auto c11 = (srcView(y1, x1) >> (8 * offset)) & 0xff;
const auto c21 = (srcView(y1, x2) >> (8 * offset)) & 0xff;
const auto c12 = (srcView(y2, x1) >> (8 * offset)) & 0xff;
const auto c22 = (srcView(y2, x2) >> (8 * offset)) & 0xff;
return c11 * x2xy2y + c21 * xx1y2y +
c12 * x2xyy1 + c22 * xx1yy1;
};
const float bi = interpolate(0);
const float gi = interpolate(1);
const float ri = interpolate(2);
const float ai = interpolate(3);
const auto b = static_cast<uint32_t>(bi + 0.5f);
const auto g = static_cast<uint32_t>(gi + 0.5f);
const auto r = static_cast<uint32_t>(ri + 0.5f);
const auto a = static_cast<uint32_t>(ai + 0.5f);
trgView(y, x) = (a << 24) | (r << 16) | (g << 8) | b;
});
trgView.synchronize(); //throw ?
}
#endif
+13 -11
View File
@@ -1,13 +1,14 @@
// ****************************************************************************
// * This file is part of the HqMAME project. It is distributed under *
// * This file is part of the xBRZ project. It is distributed under *
// * GNU General Public License: https://www.gnu.org/licenses/gpl-3.0 *
// * Copyright (C) Zenju (zenju AT gmx DOT de) - All Rights Reserved *
// * *
// * Additionally and as a special exception, the author gives permission *
// * to link the code of this program with the MAME library (or with modified *
// * versions of MAME that use the same license as MAME), and distribute *
// * linked combinations including the two. You must obey the GNU General *
// * Public License in all respects for all of the code used other than MAME. *
// * to link the code of this program with the following libraries *
// * (or with modified versions that use the same licenses), and distribute *
// * linked combinations including the two: MAME, FreeFileSync, Snes9x, ePSXe *
// * You must obey the GNU General Public License in all respects for all of *
// * the code used other than MAME, FreeFileSync, Snes9x, ePSXe. *
// * If you modify this file, you may extend this exception to your version *
// * of the file, but you are not obligated to do so. If you do not wish to *
// * do so, delete this exception statement from your version. *
@@ -21,10 +22,6 @@
#include <limits>
#include "xbrz_config.h"
// Guard against msvc stupidity
#ifdef max
#undef max
#endif
namespace xbrz
{
@@ -47,11 +44,13 @@ enum class ColorFormat //from high bits -> low bits, 8 bit per channel
{
RGB, //8 bit for each red, green, blue, upper 8 bits unused
ARGB, //including alpha channel, BGRA byte order on little-endian machines
ARGB_UNBUFFERED, //like ARGB, but without the one-time buffer creation overhead (ca. 100 - 300 ms) at the expense of a slightly slower scaling time
};
const int SCALE_FACTOR_MAX = 6;
/*
-> map source (srcWidth * srcHeight) to target (scale * width x scale * height) image, optionally processing a half-open slice of rows [yFirst, yLast) only
-> support for source/target pitch in bytes!
-> if your emulator changes only a few image slices during each cycle (e.g. DOSBox) then there's no need to run xBRZ on the complete image:
Just make sure you enlarge the source image slice by 2 rows on top and 2 on bottom (this is the additional range the xBRZ algorithm is using during analysis)
CAVEAT: If there are multiple changed slices, make sure they do not overlap after adding these additional rows in order to avoid a memory race condition
@@ -60,12 +59,15 @@ enum class ColorFormat //from high bits -> low bits, 8 bit per channel
THREAD-SAFETY: - parts of the same image may be scaled by multiple threads as long as the [yFirst, yLast) ranges do not overlap!
- there is a minor inefficiency for the first row of a slice, so avoid processing single rows only; suggestion: process at least 8-16 rows
*/
void scale(size_t factor, //valid range: 2 - 6
void scale(size_t factor, //valid range: 2 - SCALE_FACTOR_MAX
const uint32_t* src, uint32_t* trg, int srcWidth, int srcHeight,
ColorFormat colFmt,
const ScalerCfg& cfg = ScalerCfg(),
int yFirst = 0, int yLast = std::numeric_limits<int>::max()); //slice of source image
void bilinearScale(const uint32_t* src, int srcWidth, int srcHeight,
/**/ uint32_t* trg, int trgWidth, int trgHeight);
void nearestNeighborScale(const uint32_t* src, int srcWidth, int srcHeight,
/**/ uint32_t* trg, int trgWidth, int trgHeight);
+7 -5
View File
@@ -1,13 +1,14 @@
// ****************************************************************************
// * This file is part of the HqMAME project. It is distributed under *
// * This file is part of the xBRZ project. It is distributed under *
// * GNU General Public License: https://www.gnu.org/licenses/gpl-3.0 *
// * Copyright (C) Zenju (zenju AT gmx DOT de) - All Rights Reserved *
// * *
// * Additionally and as a special exception, the author gives permission *
// * to link the code of this program with the MAME library (or with modified *
// * versions of MAME that use the same license as MAME), and distribute *
// * linked combinations including the two. You must obey the GNU General *
// * Public License in all respects for all of the code used other than MAME. *
// * to link the code of this program with the following libraries *
// * (or with modified versions that use the same licenses), and distribute *
// * linked combinations including the two: MAME, FreeFileSync, Snes9x, ePSXe *
// * You must obey the GNU General Public License in all respects for all of *
// * the code used other than MAME, FreeFileSync, Snes9x, ePSXe. *
// * If you modify this file, you may extend this exception to your version *
// * of the file, but you are not obligated to do so. If you do not wish to *
// * do so, delete this exception statement from your version. *
@@ -24,6 +25,7 @@ struct ScalerCfg
{
double luminanceWeight = 1;
double equalColorTolerance = 30;
double centerDirectionBias = 4;
double dominantDirectionThreshold = 3.6;
double steepDirectionThreshold = 2.2;
double newTestAttribute = 0; //unused; test new parameters
+182 -71
View File
@@ -1,13 +1,14 @@
// ****************************************************************************
// * This file is part of the HqMAME project. It is distributed under *
// * This file is part of the xBRZ project. It is distributed under *
// * GNU General Public License: https://www.gnu.org/licenses/gpl-3.0 *
// * Copyright (C) Zenju (zenju AT gmx DOT de) - All Rights Reserved *
// * *
// * Additionally and as a special exception, the author gives permission *
// * to link the code of this program with the MAME library (or with modified *
// * versions of MAME that use the same license as MAME), and distribute *
// * linked combinations including the two. You must obey the GNU General *
// * Public License in all respects for all of the code used other than MAME. *
// * to link the code of this program with the following libraries *
// * (or with modified versions that use the same licenses), and distribute *
// * linked combinations including the two: MAME, FreeFileSync, Snes9x, ePSXe *
// * You must obey the GNU General Public License in all respects for all of *
// * the code used other than MAME, FreeFileSync, Snes9x, ePSXe. *
// * If you modify this file, you may extend this exception to your version *
// * of the file, but you are not obligated to do so. If you do not wish to *
// * do so, delete this exception statement from your version. *
@@ -25,14 +26,14 @@ namespace xbrz
{
template <uint32_t N> inline
unsigned char getByte(uint32_t val) { return static_cast<unsigned char>((val >> (8 * N)) & 0xff); }
// Note that we use RGBA, not ARGB
inline unsigned char getAlpha(uint32_t pix) { return getByte<3>(pix); }
inline unsigned char getRed (uint32_t pix) { return getByte<0>(pix); }
inline unsigned char getGreen(uint32_t pix) { return getByte<1>(pix); }
inline unsigned char getBlue (uint32_t pix) { return getByte<2>(pix); }
inline uint32_t makePixel(unsigned char a, unsigned char r, unsigned char g, unsigned char b) { return (a << 24) | (b << 16) | (g << 8) | r; }
inline uint32_t makePixel( unsigned char r, unsigned char g, unsigned char b) { return 0xFF000000 | (b << 16) | (g << 8) | r; }
inline unsigned char getAlpha(uint32_t pix) { return getByte<3>(pix); }
inline unsigned char getRed (uint32_t pix) { return getByte<2>(pix); }
inline unsigned char getGreen(uint32_t pix) { return getByte<1>(pix); }
inline unsigned char getBlue (uint32_t pix) { return getByte<0>(pix); }
inline uint32_t makePixel(unsigned char a, unsigned char r, unsigned char g, unsigned char b) { return (a << 24) | (r << 16) | (g << 8) | b; }
inline uint32_t makePixel( unsigned char r, unsigned char g, unsigned char b) { return (r << 16) | (g << 8) | b; }
inline uint32_t rgb555to888(uint16_t pix) { return ((pix & 0x7C00) << 9) | ((pix & 0x03E0) << 6) | ((pix & 0x001F) << 3); }
inline uint32_t rgb565to888(uint16_t pix) { return ((pix & 0xF800) << 8) | ((pix & 0x07E0) << 5) | ((pix & 0x001F) << 3); }
@@ -55,7 +56,7 @@ Pix* byteAdvance(Pix* ptr, int bytes)
//fill block with the given color
template <class Pix> inline
void fillBlock(Pix* trg, int pitch, Pix col, int blockWidth, int blockHeight)
void fillBlock(Pix* trg, int pitch /*[bytes]*/, Pix col, int blockWidth, int blockHeight)
{
//for (int y = 0; y < blockHeight; ++y, trg = byteAdvance(trg, pitch))
// std::fill(trg, trg + blockWidth, col);
@@ -66,16 +67,11 @@ void fillBlock(Pix* trg, int pitch, Pix col, int blockWidth, int blockHeight)
}
enum class SliceType
{
SOURCE,
TARGET,
};
//nearest-neighbor (going over target image - slow for upscaling, since source is read multiple times missing out on cache! Fast for similar image sizes!)
template <class PixSrc, class PixTrg, class PixConverter>
void nearestNeighborScale(const PixSrc* src, int srcWidth, int srcHeight, int srcPitch,
/**/ PixTrg* trg, int trgWidth, int trgHeight, int trgPitch,
SliceType st, int yFirst, int yLast, PixConverter pixCvrt /*convert PixSrc to PixTrg*/)
void nearestNeighborScale(const PixSrc* src, int srcWidth, int srcHeight, int srcPitch /*[bytes]*/,
/**/ PixTrg* trg, int trgWidth, int trgHeight, int trgPitch /*[bytes]*/,
int yFirst, int yLast, PixConverter pixCvrt /*convert PixSrc to PixTrg*/)
{
static_assert(std::is_integral<PixSrc>::value, "PixSrc* is expected to be cast-able to char*");
static_assert(std::is_integral<PixTrg>::value, "PixTrg* is expected to be cast-able to char*");
@@ -89,65 +85,180 @@ void nearestNeighborScale(const PixSrc* src, int srcWidth, int srcHeight, int sr
return;
}
switch (st)
yFirst = std::max(yFirst, 0);
yLast = std::min(yLast, trgHeight);
if (yFirst >= yLast || srcHeight <= 0 || srcWidth <= 0) return;
for (int y = yFirst; y < yLast; ++y)
{
case SliceType::SOURCE:
//nearest-neighbor (going over source image - fast for upscaling, since source is read only once
yFirst = std::max(yFirst, 0);
yLast = std::min(yLast, srcHeight);
if (yFirst >= yLast || trgWidth <= 0 || trgHeight <= 0) return;
const int ySrc = srcHeight * y / trgHeight;
const PixSrc* const srcLine = byteAdvance(src, ySrc * srcPitch);
PixTrg* const trgLine = byteAdvance(trg, y * trgPitch);
for (int y = yFirst; y < yLast; ++y)
for (int x = 0; x < trgWidth; ++x)
{
const int xSrc = srcWidth * x / trgWidth;
trgLine[x] = pixCvrt(srcLine[xSrc]);
}
}
}
//nearest-neighbor (going over source image - fast for upscaling, since source is read only once
template <class PixSrc, class PixTrg, class PixConverter>
void nearestNeighborScaleOverSource(const PixSrc* src, int srcWidth, int srcHeight, int srcPitch /*[bytes]*/,
/**/ PixTrg* trg, int trgWidth, int trgHeight, int trgPitch /*[bytes]*/,
int yFirst, int yLast, PixConverter pixCvrt /*convert PixSrc to PixTrg*/)
{
static_assert(std::is_integral<PixSrc>::value, "PixSrc* is expected to be cast-able to char*");
static_assert(std::is_integral<PixTrg>::value, "PixTrg* is expected to be cast-able to char*");
static_assert(std::is_same<decltype(pixCvrt(PixSrc())), PixTrg>::value, "PixConverter returning wrong pixel format");
if (srcPitch < srcWidth * static_cast<int>(sizeof(PixSrc)) ||
trgPitch < trgWidth * static_cast<int>(sizeof(PixTrg)))
{
assert(false);
return;
}
yFirst = std::max(yFirst, 0);
yLast = std::min(yLast, srcHeight);
if (yFirst >= yLast || trgWidth <= 0 || trgHeight <= 0) return;
for (int y = yFirst; y < yLast; ++y)
{
//mathematically: ySrc = floor(srcHeight * yTrg / trgHeight)
// => search for integers in: [ySrc, ySrc + 1) * trgHeight / srcHeight
//keep within for loop to support MT input slices!
const int yTrgFirst = ( y * trgHeight + srcHeight - 1) / srcHeight; //=ceil(y * trgHeight / srcHeight)
const int yTrgLast = ((y + 1) * trgHeight + srcHeight - 1) / srcHeight; //=ceil(((y + 1) * trgHeight) / srcHeight)
const int blockHeight = yTrgLast - yTrgFirst;
if (blockHeight > 0)
{
const PixSrc* srcLine = byteAdvance(src, y * srcPitch);
/**/ PixTrg* trgLine = byteAdvance(trg, yTrgFirst * trgPitch);
int xTrgFirst = 0;
for (int x = 0; x < srcWidth; ++x)
{
//mathematically: ySrc = floor(srcHeight * yTrg / trgHeight)
// => search for integers in: [ySrc, ySrc + 1) * trgHeight / srcHeight
//keep within for loop to support MT input slices!
const int yTrg_first = ( y * trgHeight + srcHeight - 1) / srcHeight; //=ceil(y * trgHeight / srcHeight)
const int yTrg_last = ((y + 1) * trgHeight + srcHeight - 1) / srcHeight; //=ceil(((y + 1) * trgHeight) / srcHeight)
const int blockHeight = yTrg_last - yTrg_first;
if (blockHeight > 0)
const int xTrgLast = ((x + 1) * trgWidth + srcWidth - 1) / srcWidth;
const int blockWidth = xTrgLast - xTrgFirst;
if (blockWidth > 0)
{
const PixSrc* srcLine = byteAdvance(src, y * srcPitch);
/**/ PixTrg* trgLine = byteAdvance(trg, yTrg_first * trgPitch);
int xTrg_first = 0;
xTrgFirst = xTrgLast;
for (int x = 0; x < srcWidth; ++x)
{
const int xTrg_last = ((x + 1) * trgWidth + srcWidth - 1) / srcWidth;
const int blockWidth = xTrg_last - xTrg_first;
if (blockWidth > 0)
{
xTrg_first = xTrg_last;
const auto trgPix = pixCvrt(srcLine[x]);
fillBlock(trgLine, trgPitch, trgPix, blockWidth, blockHeight);
trgLine += blockWidth;
}
}
const auto trgPix = pixCvrt(srcLine[x]);
fillBlock(trgLine, trgPitch, trgPix, blockWidth, blockHeight);
trgLine += blockWidth;
}
}
break;
}
}
}
case SliceType::TARGET:
//nearest-neighbor (going over target image - slow for upscaling, since source is read multiple times missing out on cache! Fast for similar image sizes!)
yFirst = std::max(yFirst, 0);
yLast = std::min(yLast, trgHeight);
if (yFirst >= yLast || srcHeight <= 0 || srcWidth <= 0) return;
for (int y = yFirst; y < yLast; ++y)
template <class PixTrg, class PixConverter>
void bilinearScale(const uint32_t* src, int srcWidth, int srcHeight, int srcPitch,
/**/ PixTrg* trg, int trgWidth, int trgHeight, int trgPitch,
int yFirst, int yLast, PixConverter pixCvrt /*convert uint32_t to PixTrg*/)
{
static_assert(std::is_integral<PixTrg>::value, "PixTrg* is expected to be cast-able to char*");
static_assert(std::is_same<decltype(pixCvrt(uint32_t())), PixTrg>::value, "PixConverter returning wrong pixel format");
if (srcPitch < srcWidth * static_cast<int>(sizeof(uint32_t)) ||
trgPitch < trgWidth * static_cast<int>(sizeof(PixTrg)))
{
assert(false);
return;
}
yFirst = std::max(yFirst, 0);
yLast = std::min(yLast, trgHeight);
if (yFirst >= yLast || srcHeight <= 0 || srcWidth <= 0) return;
const double scaleX = static_cast<double>(trgWidth ) / srcWidth;
const double scaleY = static_cast<double>(trgHeight) / srcHeight;
//perf notes:
// -> double-based calculation is (slightly) faster than float
// -> pre-calculation gives significant boost; std::vector<> memory allocation is negligible!
struct CoeffsX
{
int x1 = 0;
int x2 = 0;
double xx1 = 0;
double x2x = 0;
};
std::vector<CoeffsX> buf(trgWidth);
for (int x = 0; x < trgWidth; ++x)
{
const int x1 = srcWidth * x / trgWidth;
int x2 = x1 + 1;
if (x2 == srcWidth) --x2;
const double xx1 = x / scaleX - x1;
const double x2x = 1 - xx1;
buf[x] = { x1, x2, xx1, x2x };
}
for (int y = yFirst; y < yLast; ++y)
{
const int y1 = srcHeight * y / trgHeight;
int y2 = y1 + 1;
if (y2 == srcHeight) --y2;
const double yy1 = y / scaleY - y1;
const double y2y = 1 - yy1;
const uint32_t* const srcLine = byteAdvance(src, y1 * srcPitch);
const uint32_t* const srcLineNext = byteAdvance(src, y2 * srcPitch);
PixTrg* const trgLine = byteAdvance(trg, y * trgPitch);
for (int x = 0; x < trgWidth; ++x)
{
//perf: do NOT "simplify" the variable layout without measurement!
const int x1 = buf[x].x1;
const int x2 = buf[x].x2;
const double xx1 = buf[x].xx1;
const double x2x = buf[x].x2x;
const double x2xy2y = x2x * y2y;
const double xx1y2y = xx1 * y2y;
const double x2xyy1 = x2x * yy1;
const double xx1yy1 = xx1 * yy1;
auto interpolate = [=](int offset)
{
PixTrg* trgLine = byteAdvance(trg, y * trgPitch);
const int ySrc = srcHeight * y / trgHeight;
const PixSrc* srcLine = byteAdvance(src, ySrc * srcPitch);
for (int x = 0; x < trgWidth; ++x)
{
const int xSrc = srcWidth * x / trgWidth;
trgLine[x] = pixCvrt(srcLine[xSrc]);
}
}
break;
/* https://en.wikipedia.org/wiki/Bilinear_interpolation
(c11(x2 - x) + c21(x - x1)) * (y2 - y ) +
(c12(x2 - x) + c22(x - x1)) * (y - y1) */
const auto c11 = (srcLine [x1] >> (8 * offset)) & 0xff;
const auto c21 = (srcLine [x2] >> (8 * offset)) & 0xff;
const auto c12 = (srcLineNext[x1] >> (8 * offset)) & 0xff;
const auto c22 = (srcLineNext[x2] >> (8 * offset)) & 0xff;
return c11 * x2xy2y + c21 * xx1y2y +
c12 * x2xyy1 + c22 * xx1yy1;
};
const double bi = interpolate(0);
const double gi = interpolate(1);
const double ri = interpolate(2);
const double ai = interpolate(3);
const auto b = static_cast<uint32_t>(bi + 0.5);
const auto g = static_cast<uint32_t>(gi + 0.5);
const auto r = static_cast<uint32_t>(ri + 0.5);
const auto a = static_cast<uint32_t>(ai + 0.5);
const uint32_t trgPix = (a << 24) | (r << 16) | (g << 8) | b;
trgLine[x] = pixCvrt(trgPix);
}
}
}
}
+1
Submodule core/deps/xbyak added at 0d67fd1530.
-11
View File
@@ -1,11 +0,0 @@
name: test
on: [push]
jobs:
build:
name: test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- run: sudo apt install nasm yasm g++-multilib tcsh
- run: make test
-1
View File
@@ -1 +0,0 @@
/build* # cmake
-42
View File
@@ -1,42 +0,0 @@
cmake_minimum_required(VERSION 3.5...4.0.0)
project(xbyak CXX)
file(GLOB headers xbyak/*.h)
include(GNUInstallDirs)
add_library(${PROJECT_NAME} INTERFACE)
add_library(${PROJECT_NAME}::${PROJECT_NAME} ALIAS ${PROJECT_NAME})
target_include_directories(
${PROJECT_NAME} INTERFACE
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>"
"$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>"
)
install(
TARGETS ${PROJECT_NAME}
EXPORT ${PROJECT_NAME}-targets
)
configure_file(
cmake/config.cmake.in
${PROJECT_NAME}Config.cmake
@ONLY
)
install(
FILES ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}
)
install(
EXPORT ${PROJECT_NAME}-targets
NAMESPACE ${PROJECT_NAME}::
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}
)
install(
FILES ${headers}
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/xbyak
)
-47
View File
@@ -1,47 +0,0 @@
Copyright (c) 2007 MITSUNARI Shigeo
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
Neither the name of the copyright owner nor the names of its contributors may
be used to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
THE POSSIBILITY OF SUCH DAMAGE.
-----------------------------------------------------------------------------
ソースコード形式かバイナリ形式か、変更するかしないかを問わず、以下の条件を満た
す場合に限り、再頒布および使用が許可されます。
ソースコードを再頒布する場合、上記の著作権表示、本条件一覧、および下記免責条項
を含めること。
バイナリ形式で再頒布する場合、頒布物に付属のドキュメント等の資料に、上記の著作
権表示、本条件一覧、および下記免責条項を含めること。
書面による特別の許可なしに、本ソフトウェアから派生した製品の宣伝または販売促進
に、著作権者の名前またはコントリビューターの名前を使用してはならない。
本ソフトウェアは、著作権者およびコントリビューターによって「現状のまま」提供さ
れており、明示黙示を問わず、商業的な使用可能性、および特定の目的に対する適合性
に関する暗黙の保証も含め、またそれに限定されない、いかなる保証もありません。
著作権者もコントリビューターも、事由のいかんを問わず、 損害発生の原因いかんを
問わず、かつ責任の根拠が契約であるか厳格責任であるか(過失その他の)不法行為で
あるかを問わず、仮にそのような損害が発生する可能性を知らされていたとしても、
本ソフトウェアの使用によって発生した(代替品または代用サービスの調達、使用の
喪失、データの喪失、利益の喪失、業務の中断も含め、またそれに限定されない)直接
損害、間接損害、偶発的な損害、特別損害、懲罰的損害、または結果損害について、
一切責任を負わないものとします。
-24
View File
@@ -1,24 +0,0 @@
PREFIX?=/usr/local
INSTALL_DIR=$(PREFIX)/include/xbyak
all:
$(MAKE) -C sample
clean:
$(MAKE) -C sample clean
install:
mkdir -p $(INSTALL_DIR)
cp -pR xbyak/*.h $(INSTALL_DIR)
uninstall:
rm -i $(INSTALL_DIR)/*.h
rmdir $(INSTALL_DIR)
update:
$(MAKE) -C gen
test:
$(MAKE) -C test test
.PHONY: test update
-1
View File
@@ -1 +0,0 @@
include("${CMAKE_CURRENT_LIST_DIR}/@[email protected]")
-26
View File
@@ -1,26 +0,0 @@
TARGET=../xbyak/xbyak_mnemonic.h
BIN=sortline gen_code gen_avx512
CFLAGS=-I../ -O2 -DXBYAK_NO_OP_NAMES -Wall -Wextra -Wno-missing-field-initializers
all: $(TARGET)
sortline: sortline.cpp
$(CXX) $(CFLAGS) $< -o $@
gen_code: gen_code.cpp ../xbyak/xbyak.h avx_type.hpp
$(CXX) $(CFLAGS) $< -o $@
gen_avx512: gen_avx512.cpp ../xbyak/xbyak.h avx_type.hpp
$(CXX) $(CFLAGS) $< -o $@
$(TARGET): $(BIN)
./gen_code | ./sortline > $@
echo "#ifdef XBYAK_ENABLE_OMITTED_OPERAND" >> $@
./gen_code omit | ./sortline >> $@
echo "#endif" >>$@
./gen_code fixed >> $@
echo "#ifndef XBYAK_DISABLE_AVX512" >> $@
./gen_avx512 | ./sortline >> $@
echo "#ifdef XBYAK64" >> $@
./gen_avx512 64 | ./sortline >> $@
echo "#endif" >> $@
echo "#endif" >> $@
clean:
$(RM) $(BIN) $(TARGET)
-170
View File
@@ -1,170 +0,0 @@
#include <assert.h>
// copy CodeGenerator::AVXtype
enum AVXtype {
// low 3 bit
T_N1 = 1,
T_N2 = 2,
T_N4 = 3,
T_N8 = 4,
T_N16 = 5,
T_N32 = 6,
T_NX_MASK = 7,
//
T_N_VL = 1 << 3, // N * (1, 2, 4) for VL
T_DUP = 1 << 4, // N = (8, 32, 64)
T_66 = 1 << 5,
T_F3 = 1 << 6,
T_F2 = 1 << 7,
T_0F = 1 << 8,
T_0F38 = 1 << 9,
T_0F3A = 1 << 10,
T_L0 = 1 << 11,
T_L1 = 1 << 12,
T_W0 = 1 << 13,
T_W1 = 1 << 14,
T_EW0 = 1 << 15,
T_EW1 = 1 << 16,
T_YMM = 1 << 17, // support YMM, ZMM
T_EVEX = 1 << 18,
T_ER_X = 1 << 19, // xmm{er}
T_ER_Y = 1 << 20, // ymm{er}
T_ER_Z = 1 << 21, // zmm{er}
T_SAE_X = 1 << 22, // xmm{sae}
T_SAE_Y = 1 << 23, // ymm{sae}
T_SAE_Z = 1 << 24, // zmm{sae}
T_MUST_EVEX = 1 << 25, // contains T_EVEX
T_B32 = 1 << 26, // m32bcst
T_B64 = 1 << 27, // m64bcst
T_M_K = 1 << 28, // mem{k}
T_VSIB = 1 << 29,
T_MEM_EVEX = 1 << 30, // use evex if mem
T_XXX
};
const int NONE = 256; // same as Xbyak::CodeGenerator::NONE
std::string type2String(int type)
{
std::string str;
int low = type & T_NX_MASK;
if (0 < low) {
const char *tbl[8] = {
"T_N1", "T_N2", "T_N4", "T_N8", "T_N16", "T_N32"
};
assert(low < int(sizeof(tbl) / sizeof(tbl[0])));
str = tbl[low - 1];
}
if (type & T_N_VL) {
if (!str.empty()) str += " | ";
str += "T_N_VL";
}
if (type & T_DUP) {
if (!str.empty()) str += " | ";
str += "T_DUP";
}
if (type & T_66) {
if (!str.empty()) str += " | ";
str += "T_66";
}
if (type & T_F3) {
if (!str.empty()) str += " | ";
str += "T_F3";
}
if (type & T_F2) {
if (!str.empty()) str += " | ";
str += "T_F2";
}
if (type & T_0F) {
if (!str.empty()) str += " | ";
str += "T_0F";
}
if (type & T_0F38) {
if (!str.empty()) str += " | ";
str += "T_0F38";
}
if (type & T_0F3A) {
if (!str.empty()) str += " | ";
str += "T_0F3A";
}
if (type & T_L0) {
if (!str.empty()) str += " | ";
str += "VEZ_L0";
}
if (type & T_L1) {
if (!str.empty()) str += " | ";
str += "VEZ_L1";
}
if (type & T_W0) {
if (!str.empty()) str += " | ";
str += "T_W0";
}
if (type & T_W1) {
if (!str.empty()) str += " | ";
str += "T_W1";
}
if (type & T_EW0) {
if (!str.empty()) str += " | ";
str += "T_EW0";
}
if (type & T_EW1) {
if (!str.empty()) str += " | ";
str += "T_EW1";
}
if (type & T_YMM) {
if (!str.empty()) str += " | ";
str += "T_YMM";
}
if (type & T_EVEX) {
if (!str.empty()) str += " | ";
str += "T_EVEX";
}
if (type & T_ER_X) {
if (!str.empty()) str += " | ";
str += "T_ER_X";
}
if (type & T_ER_Y) {
if (!str.empty()) str += " | ";
str += "T_ER_Y";
}
if (type & T_ER_Z) {
if (!str.empty()) str += " | ";
str += "T_ER_Z";
}
if (type & T_SAE_X) {
if (!str.empty()) str += " | ";
str += "T_SAE_X";
}
if (type & T_SAE_Y) {
if (!str.empty()) str += " | ";
str += "T_SAE_Y";
}
if (type & T_SAE_Z) {
if (!str.empty()) str += " | ";
str += "T_SAE_Z";
}
if (type & T_MUST_EVEX) {
if (!str.empty()) str += " | ";
str += "T_MUST_EVEX";
}
if (type & T_B32) {
if (!str.empty()) str += " | ";
str += "T_B32";
}
if (type & T_B64) {
if (!str.empty()) str += " | ";
str += "T_B64";
}
if (type & T_M_K) {
if (!str.empty()) str += " | ";
str += "T_M_K";
}
if (type & T_VSIB) {
if (!str.empty()) str += " | ";
str += "T_VSIB";
}
if (type & T_MEM_EVEX) {
if (!str.empty()) str += " | ";
str += "T_MEM_EVEX";
}
return str;
}
-17
View File
@@ -1,17 +0,0 @@
#include <stdio.h>
int main()
{
puts("enum {");
for (int i = 0; i < 256; i++) {
printf(" B");
for (int j = 0; j < 8; j++) {
putchar(i & (1 << (7 - j)) ? '1' : '0');
}
printf("= %d", i);
if (i < 255) putchar(',');
putchar('\n');
}
puts("};");
return 0;
}
-750
View File
@@ -1,750 +0,0 @@
#define XBYAK_DONT_READ_LIST
#include <stdio.h>
#include <string.h>
#include "../xbyak/xbyak.h"
#define NUM_OF_ARRAY(x) (sizeof(x) / sizeof(x[0]))
using namespace Xbyak;
#ifdef _MSC_VER
#pragma warning(disable : 4996) // scanf
#define snprintf _snprintf_s
#endif
#include "avx_type.hpp"
void putOpmask(bool only64bit)
{
if (only64bit) {
puts("void kmovq(const Opmask& k, const Reg64& r) { opVex(k, 0, r, T_L0 | T_0F | T_F2 | T_W1, 0x92); }");
puts("void kmovq(const Reg64& r, const Opmask& k) { opVex(r, 0, k, T_L0 | T_0F | T_F2 | T_W1, 0x93); }");
return;
}
{
const struct Tbl {
const char *name;
uint8_t code;
} tbl[] = {
{ "kadd", 0x4A },
{ "kand", 0x41 },
{ "kandn", 0x42 },
{ "kor", 0x45 },
{ "kxnor", 0x46 },
{ "kxor", 0x47 },
};
for (size_t i = 0; i < NUM_OF_ARRAY(tbl); i++) {
const Tbl& p = tbl[i];
printf("void %sw(const Opmask& r1, const Opmask& r2, const Opmask& r3) { opVex(r1, &r2, r3, T_L1 | T_0F | T_W0, 0x%02X); }\n", p.name, p.code);
printf("void %sq(const Opmask& r1, const Opmask& r2, const Opmask& r3) { opVex(r1, &r2, r3, T_L1 | T_0F | T_W1, 0x%02X); }\n", p.name, p.code);
printf("void %sb(const Opmask& r1, const Opmask& r2, const Opmask& r3) { opVex(r1, &r2, r3, T_L1 | T_0F | T_66 | T_W0, 0x%02X); }\n", p.name, p.code);
printf("void %sd(const Opmask& r1, const Opmask& r2, const Opmask& r3) { opVex(r1, &r2, r3, T_L1 | T_0F | T_66 | T_W1, 0x%02X); }\n", p.name, p.code);
}
printf("void kunpckbw(const Opmask& r1, const Opmask& r2, const Opmask& r3) { opVex(r1, &r2, r3, T_L1 | T_0F | T_66 | T_W0, 0x4B); }\n");
printf("void kunpckwd(const Opmask& r1, const Opmask& r2, const Opmask& r3) { opVex(r1, &r2, r3, T_L1 | T_0F | T_W0, 0x4B); }\n");
printf("void kunpckdq(const Opmask& r1, const Opmask& r2, const Opmask& r3) { opVex(r1, &r2, r3, T_L1 | T_0F | T_W1, 0x4B); }\n");
}
{
const struct Tbl {
const char *name;
uint8_t code;
} tbl[] = {
{ "knot", 0x44 },
{ "kortest", 0x98 },
{ "ktest", 0x99 },
};
for (size_t i = 0; i < NUM_OF_ARRAY(tbl); i++) {
const Tbl& p = tbl[i];
printf("void %sw(const Opmask& r1, const Opmask& r2) { opVex(r1, 0, r2, T_0F | T_W0, 0x%02X); }\n", p.name, p.code);
printf("void %sq(const Opmask& r1, const Opmask& r2) { opVex(r1, 0, r2, T_0F | T_W1, 0x%02X); }\n", p.name, p.code);
printf("void %sb(const Opmask& r1, const Opmask& r2) { opVex(r1, 0, r2, T_0F | T_66 | T_W0, 0x%02X); }\n", p.name, p.code);
printf("void %sd(const Opmask& r1, const Opmask& r2) { opVex(r1, 0, r2, T_0F | T_66 | T_W1, 0x%02X); }\n", p.name, p.code);
}
}
{
const struct Tbl {
const char *name;
uint8_t code;
} tbl[] = {
{ "kshiftl", 0x32 },
{ "kshiftr", 0x30 },
};
for (size_t i = 0; i < NUM_OF_ARRAY(tbl); i++) {
const Tbl& p = tbl[i];
printf("void %sw(const Opmask& r1, const Opmask& r2, uint8_t imm) { opVex(r1, 0, r2, T_66 | T_0F3A | T_W1, 0x%02X, imm); }\n", p.name, p.code);
printf("void %sq(const Opmask& r1, const Opmask& r2, uint8_t imm) { opVex(r1, 0, r2, T_66 | T_0F3A | T_W1, 0x%02X, imm); }\n", p.name, p.code + 1);
printf("void %sb(const Opmask& r1, const Opmask& r2, uint8_t imm) { opVex(r1, 0, r2, T_66 | T_0F3A | T_W0, 0x%02X, imm); }\n", p.name, p.code);
printf("void %sd(const Opmask& r1, const Opmask& r2, uint8_t imm) { opVex(r1, 0, r2, T_66 | T_0F3A | T_W0, 0x%02X, imm); }\n", p.name, p.code + 1);
}
}
puts("void kmovw(const Opmask& k, const Operand& op) { if (!op.isMEM() && !op.isOPMASK()) XBYAK_THROW(ERR_BAD_COMBINATION) opVex(k, 0, op, T_L0 | T_0F | T_W0, 0x90); }");
puts("void kmovq(const Opmask& k, const Operand& op) { if (!op.isMEM() && !op.isOPMASK()) XBYAK_THROW(ERR_BAD_COMBINATION) opVex(k, 0, op, T_L0 | T_0F | T_W1, 0x90); }");
puts("void kmovb(const Opmask& k, const Operand& op) { if (!op.isMEM() && !op.isOPMASK()) XBYAK_THROW(ERR_BAD_COMBINATION) opVex(k, 0, op, T_L0 | T_0F | T_66 | T_W0, 0x90); }");
puts("void kmovd(const Opmask& k, const Operand& op) { if (!op.isMEM() && !op.isOPMASK()) XBYAK_THROW(ERR_BAD_COMBINATION) opVex(k, 0, op, T_L0 | T_0F | T_66 | T_W1, 0x90); }");
puts("void kmovw(const Address& addr, const Opmask& k) { opVex(k, 0, addr, T_L0 | T_0F | T_W0, 0x91); }");
puts("void kmovq(const Address& addr, const Opmask& k) { opVex(k, 0, addr, T_L0 | T_0F | T_W1, 0x91); }");
puts("void kmovb(const Address& addr, const Opmask& k) { opVex(k, 0, addr, T_L0 | T_0F | T_66 | T_W0, 0x91); }");
puts("void kmovd(const Address& addr, const Opmask& k) { opVex(k, 0, addr, T_L0 | T_0F | T_66 | T_W1, 0x91); }");
puts("void kmovw(const Opmask& k, const Reg32& r) { opVex(k, 0, r, T_L0 | T_0F | T_W0, 0x92); }");
puts("void kmovw(const Reg32& r, const Opmask& k) { opVex(r, 0, k, T_L0 | T_0F | T_W0, 0x93); }");
puts("void kmovb(const Opmask& k, const Reg32& r) { opVex(k, 0, r, T_L0 | T_0F | T_66 | T_W0, 0x92); }");
puts("void kmovb(const Reg32& r, const Opmask& k) { opVex(r, 0, k, T_L0 | T_0F | T_66 | T_W0, 0x93); }");
puts("void kmovd(const Opmask& k, const Reg32& r) { opVex(k, 0, r, T_L0 | T_0F | T_F2 | T_W0, 0x92); }");
puts("void kmovd(const Reg32& r, const Opmask& k) { opVex(r, 0, k, T_L0 | T_0F | T_F2 | T_W0, 0x93); }");
}
// vcmppd(k, x, op)
void putVcmp()
{
const struct Tbl {
uint8_t code;
const char *name;
int type;
bool hasIMM;
} tbl[] = {
{ 0xC2, "vcmppd", T_0F | T_MUST_EVEX | T_EW1 | T_SAE_Z | T_YMM | T_66 | T_B64, true },
{ 0xC2, "vcmpps", T_0F | T_MUST_EVEX | T_EW0 | T_SAE_Z | T_YMM | T_B32, true },
{ 0xC2, "vcmpsd", T_0F | T_MUST_EVEX | T_EW1 | T_SAE_Z | T_F2 | T_N8, true },
{ 0xC2, "vcmpss", T_0F | T_MUST_EVEX | T_EW0 | T_SAE_Z | T_F3 | T_N4, true },
{ 0x74, "vpcmpeqb", T_66 | T_0F | T_MUST_EVEX | T_YMM, false },
{ 0x75, "vpcmpeqw", T_66 | T_0F | T_MUST_EVEX | T_YMM, false },
{ 0x76, "vpcmpeqd", T_66 | T_0F | T_MUST_EVEX | T_YMM | T_B32, false },
{ 0x29, "vpcmpeqq", T_66 | T_0F38 | T_MUST_EVEX | T_YMM | T_EW1 | T_B64, false },
{ 0x64, "vpcmpgtb", T_66 | T_0F | T_MUST_EVEX | T_YMM, false },
{ 0x65, "vpcmpgtw", T_66 | T_0F | T_MUST_EVEX | T_YMM, false },
{ 0x66, "vpcmpgtd", T_66 | T_0F | T_MUST_EVEX | T_YMM | T_EW0 | T_B32, false },
{ 0x37, "vpcmpgtq", T_66 | T_0F38 | T_MUST_EVEX | T_YMM | T_EW1 | T_B64, false },
{ 0x3F, "vpcmpb", T_66 | T_0F3A | T_MUST_EVEX | T_YMM | T_EW0, true },
{ 0x3E, "vpcmpub", T_66 | T_0F3A | T_MUST_EVEX | T_YMM | T_EW0, true },
{ 0x3F, "vpcmpw", T_66 | T_0F3A | T_MUST_EVEX | T_YMM | T_EW1, true },
{ 0x3E, "vpcmpuw", T_66 | T_0F3A | T_MUST_EVEX | T_YMM | T_EW1, true },
{ 0x1F, "vpcmpd", T_66 | T_0F3A | T_MUST_EVEX | T_YMM | T_EW0 | T_B32, true },
{ 0x1E, "vpcmpud", T_66 | T_0F3A | T_MUST_EVEX | T_YMM | T_EW0 | T_B32, true },
{ 0x1F, "vpcmpq", T_66 | T_0F3A | T_MUST_EVEX | T_YMM | T_EW1 | T_B64, true },
{ 0x1E, "vpcmpuq", T_66 | T_0F3A | T_MUST_EVEX | T_YMM | T_EW1 | T_B64, true },
{ 0x26, "vptestmb", T_66 | T_0F38 | T_MUST_EVEX | T_YMM | T_EW0, false },
{ 0x26, "vptestmw", T_66 | T_0F38 | T_MUST_EVEX | T_YMM | T_EW1, false },
{ 0x27, "vptestmd", T_66 | T_0F38 | T_MUST_EVEX | T_YMM | T_EW0 | T_B32, false },
{ 0x27, "vptestmq", T_66 | T_0F38 | T_MUST_EVEX | T_YMM | T_EW1 | T_B64, false },
{ 0x26, "vptestnmb", T_F3 | T_0F38 | T_MUST_EVEX | T_YMM | T_EW0, false },
{ 0x26, "vptestnmw", T_F3 | T_0F38 | T_MUST_EVEX | T_YMM | T_EW1, false },
{ 0x27, "vptestnmd", T_F3 | T_0F38 | T_MUST_EVEX | T_YMM | T_EW0 | T_B32, false },
{ 0x27, "vptestnmq", T_F3 | T_0F38 | T_MUST_EVEX | T_YMM | T_EW1 | T_B64, false },
};
for (size_t i = 0; i < NUM_OF_ARRAY(tbl); i++) {
const Tbl *p = &tbl[i];
std::string type = type2String(p->type);
printf("void %s(const Opmask& k, const Xmm& x, const Operand& op%s) { opAVX_K_X_XM(k, x, op, %s, 0x%02X%s); }\n"
, p->name, p->hasIMM ? ", uint8_t imm" : "", type.c_str(), p->code, p->hasIMM ? ", imm" : "");
}
}
// XM_X
void putX_XM()
{
const struct Tbl {
uint8_t code;
const char *name;
int type;
} tbl[] = {
{ 0x6F, "vmovdqa32", T_66 | T_0F | T_MUST_EVEX | T_YMM | T_EW0 | T_ER_X | T_ER_Y | T_ER_Z },
{ 0x6F, "vmovdqa64", T_66 | T_0F | T_MUST_EVEX | T_YMM | T_EW1 | T_ER_X | T_ER_Y | T_ER_Z },
{ 0x6F, "vmovdqu8", T_F2 | T_0F | T_MUST_EVEX | T_YMM | T_EW0 | T_ER_X | T_ER_Y | T_ER_Z },
{ 0x6F, "vmovdqu16", T_F2 | T_0F | T_MUST_EVEX | T_YMM | T_EW1 | T_ER_X | T_ER_Y | T_ER_Z },
{ 0x6F, "vmovdqu32", T_F3 | T_0F | T_MUST_EVEX | T_YMM | T_EW0 | T_ER_X | T_ER_Y | T_ER_Z },
{ 0x6F, "vmovdqu64", T_F3 | T_0F | T_MUST_EVEX | T_YMM | T_EW1 | T_ER_X | T_ER_Y | T_ER_Z },
{ 0x7B, "vcvtpd2qq", T_66 | T_0F | T_MUST_EVEX | T_YMM | T_EW1 | T_B64 | T_ER_Z },
// putCvt
{ 0x79, "vcvtpd2uqq", T_66 | T_0F | T_MUST_EVEX | T_YMM | T_EW1 | T_B64 | T_ER_Z },
{ 0x79, "vcvtps2udq", T_0F | T_MUST_EVEX | T_YMM | T_EW0 | T_B32 | T_ER_Z },
{ 0xE6, "vcvtqq2pd", T_F3 | T_0F | T_MUST_EVEX | T_YMM | T_EW1 | T_B64 | T_ER_Z },
{ 0x7A, "vcvttpd2qq", T_66 | T_0F | T_MUST_EVEX | T_YMM | T_EW1 | T_B64 | T_SAE_Z },
{ 0x78, "vcvttpd2uqq", T_66 | T_0F | T_MUST_EVEX | T_YMM | T_EW1 | T_B64 | T_SAE_Z },
{ 0x78, "vcvttps2udq", T_0F | T_MUST_EVEX | T_YMM | T_EW0 | T_B32 | T_SAE_Z },
{ 0x7A, "vcvtudq2ps", T_F2 | T_0F | T_YMM | T_MUST_EVEX | T_EW0 | T_B32 | T_ER_Z },
{ 0x7A, "vcvtuqq2pd", T_F3 | T_0F | T_YMM | T_MUST_EVEX | T_EW1 | T_B64 | T_ER_Z },
{ 0x88, "vexpandpd", T_66 | T_0F38 | T_MUST_EVEX | T_YMM | T_EW1 | T_N8 },
{ 0x88, "vexpandps", T_66 | T_0F38 | T_MUST_EVEX | T_YMM | T_EW0 | T_N4 },
{ 0x89, "vpexpandd", T_66 | T_0F38 | T_MUST_EVEX | T_YMM | T_EW0 | T_N4 },
{ 0x89, "vpexpandq", T_66 | T_0F38 | T_MUST_EVEX | T_YMM | T_EW1 | T_N8 },
{ 0x42, "vgetexppd", T_66 | T_0F38 | T_MUST_EVEX | T_YMM | T_EW1 | T_B64 | T_SAE_Z },
{ 0x42, "vgetexpps", T_66 | T_0F38 | T_MUST_EVEX | T_YMM | T_EW0 | T_B32 | T_SAE_Z },
};
for (size_t i = 0; i < NUM_OF_ARRAY(tbl); i++) {
const Tbl *p = &tbl[i];
std::string type = type2String(p->type);
printf("void %s(const Xmm& x, const Operand& op) { opAVX_X_XM_IMM(x, op, %s, 0x%02X); }\n", p->name, type.c_str(), p->code);
}
puts("void vpabsq(const Xmm& x, const Operand& op) { opAVX_X_XM_IMM(x, op, T_66 | T_0F38 | T_MUST_EVEX | T_EW1 | T_B64 | T_YMM, 0x1F); }");
puts("void vexp2pd(const Zmm& z, const Operand& op) { opAVX_X_XM_IMM(z, op, T_66 | T_0F38 | T_MUST_EVEX | T_YMM | T_EW1 | T_B64 | T_SAE_Z, 0xC8); }");
puts("void vexp2ps(const Zmm& z, const Operand& op) { opAVX_X_XM_IMM(z, op, T_66 | T_0F38 | T_MUST_EVEX | T_YMM | T_EW0 | T_B32 | T_SAE_Z, 0xC8); }");
puts("void vrcp28pd(const Zmm& z, const Operand& op) { opAVX_X_XM_IMM(z, op, T_66 | T_0F38 | T_MUST_EVEX | T_YMM | T_EW1 | T_B64 | T_SAE_Z, 0xCA); }");
puts("void vrcp28ps(const Zmm& z, const Operand& op) { opAVX_X_XM_IMM(z, op, T_66 | T_0F38 | T_MUST_EVEX | T_YMM | T_EW0 | T_B32 | T_SAE_Z, 0xCA); }");
puts("void vrsqrt28pd(const Zmm& z, const Operand& op) { opAVX_X_XM_IMM(z, op, T_66 | T_0F38 | T_MUST_EVEX | T_YMM | T_EW1 | T_B64 | T_SAE_Z, 0xCC); }");
puts("void vrsqrt28ps(const Zmm& z, const Operand& op) { opAVX_X_XM_IMM(z, op, T_66 | T_0F38 | T_MUST_EVEX | T_YMM | T_EW0 | T_B32 | T_SAE_Z, 0xCC); }");
}
void putM_X()
{
const struct Tbl {
uint8_t code;
const char *name;
int type;
} tbl[] = {
{ 0x7F, "vmovdqa32", T_66 | T_0F | T_MUST_EVEX | T_YMM | T_EW0 | T_ER_X | T_ER_Y | T_ER_Z | T_M_K },
{ 0x7F, "vmovdqa64", T_66 | T_0F | T_MUST_EVEX | T_YMM | T_EW1 | T_ER_X | T_ER_Y | T_ER_Z | T_M_K },
{ 0x7F, "vmovdqu8", T_F2 | T_0F | T_MUST_EVEX | T_YMM | T_EW0 | T_ER_X | T_ER_Y | T_ER_Z | T_M_K },
{ 0x7F, "vmovdqu16", T_F2 | T_0F | T_MUST_EVEX | T_YMM | T_EW1 | T_ER_X | T_ER_Y | T_ER_Z | T_M_K },
{ 0x7F, "vmovdqu32", T_F3 | T_0F | T_MUST_EVEX | T_YMM | T_EW0 | T_ER_X | T_ER_Y | T_ER_Z | T_M_K },
{ 0x7F, "vmovdqu64", T_F3 | T_0F | T_MUST_EVEX | T_YMM | T_EW1 | T_ER_X | T_ER_Y | T_ER_Z | T_M_K },
};
for (size_t i = 0; i < NUM_OF_ARRAY(tbl); i++) {
const Tbl *p = &tbl[i];
std::string type = type2String(p->type);
printf("void %s(const Address& addr, const Xmm& x) { opAVX_X_XM_IMM(x, addr, %s, 0x%02X); }\n", p->name, type.c_str(), p->code);
}
}
void putXM_X()
{
const struct Tbl {
uint8_t code;
const char *name;
int type;
} tbl[] = {
{ 0x8A, "vcompresspd", T_66 | T_0F38 | T_MUST_EVEX | T_YMM | T_EW1 | T_N8 },
{ 0x8A, "vcompressps", T_66 | T_0F38 | T_MUST_EVEX | T_YMM | T_EW0 | T_N4 },
{ 0x8B, "vpcompressd", T_66 | T_0F38 | T_MUST_EVEX | T_YMM | T_EW0 | T_N4 },
{ 0x8B, "vpcompressq", T_66 | T_0F38 | T_MUST_EVEX | T_YMM | T_EW1 | T_N8 },
{ 0x63, "vcompressb", T_66 | T_0F38 | T_MUST_EVEX | T_YMM | T_EW0 | T_N1 },
{ 0x63, "vcompressw", T_66 | T_0F38 | T_MUST_EVEX | T_YMM | T_EW1 | T_N2 },
};
for (size_t i = 0; i < NUM_OF_ARRAY(tbl); i++) {
const Tbl *p = &tbl[i];
std::string type = type2String(p->type);
printf("void %s(const Operand& op, const Xmm& x) { opAVX_X_XM_IMM(x, op, %s, 0x%02X); }\n", p->name, type.c_str(), p->code);
}
}
void putX_X_XM_IMM()
{
const struct Tbl {
uint8_t code;
const char *name;
int type;
bool hasIMM;
} tbl[] = {
{ 0x03, "valignd", T_MUST_EVEX | T_66 | T_0F3A | T_EW0 | T_YMM, true },
{ 0x03, "valignq", T_MUST_EVEX | T_66 | T_0F3A | T_EW1 | T_YMM, true },
{ 0xDB, "vpandd", T_MUST_EVEX | T_YMM | T_66 | T_0F | T_EW0 | T_B32, false },
{ 0xDB, "vpandq", T_MUST_EVEX | T_YMM | T_66 | T_0F | T_EW1 | T_B64, false },
{ 0xDF, "vpandnd", T_MUST_EVEX | T_YMM | T_66 | T_0F | T_EW0 | T_B32, false },
{ 0xDF, "vpandnq", T_MUST_EVEX | T_YMM | T_66 | T_0F | T_EW1 | T_B64, false },
{ 0x3D, "vpmaxsq", T_66 | T_0F38 | T_MUST_EVEX | T_YMM | T_EW1 | T_B64, false },
{ 0x3F, "vpmaxuq", T_66 | T_0F38 | T_MUST_EVEX | T_YMM | T_EW1 | T_B64, false },
{ 0x39, "vpminsq", T_66 | T_0F38 | T_MUST_EVEX | T_YMM | T_EW1 | T_B64, false },
{ 0x3B, "vpminuq", T_66 | T_0F38 | T_MUST_EVEX | T_YMM | T_EW1 | T_B64, false },
{ 0xE2, "vpsraq", T_66 | T_0F | T_MUST_EVEX | T_YMM | T_EW1 | T_N16, false },
{ 0x46, "vpsravq", T_66 | T_0F38 | T_MUST_EVEX | T_YMM | T_EW1 | T_B64, false },
{ 0x11, "vpsravw", T_66 | T_0F38 | T_MUST_EVEX | T_YMM | T_EW1, false },
{ 0x12, "vpsllvw", T_66 | T_0F38 | T_MUST_EVEX | T_YMM | T_EW1, false },
{ 0x10, "vpsrlvw", T_66 | T_0F38 | T_MUST_EVEX | T_YMM | T_EW1, false },
{ 0xEB, "vpord", T_66 | T_0F | T_MUST_EVEX | T_YMM | T_EW0 | T_B32, false },
{ 0xEB, "vporq", T_66 | T_0F | T_MUST_EVEX | T_YMM | T_EW1 | T_B64, false },
{ 0xEF, "vpxord", T_66 | T_0F | T_MUST_EVEX | T_YMM | T_EW0 | T_B32, false },
{ 0xEF, "vpxorq", T_66 | T_0F | T_MUST_EVEX | T_YMM | T_EW1 | T_B64, false },
{ 0x40, "vpmullq", T_66 | T_0F38 | T_MUST_EVEX | T_YMM | T_EW1 | T_B64, false },
{ 0x8D, "vpermb", T_66 | T_0F38 | T_MUST_EVEX | T_YMM | T_EW0, false },
{ 0x8D, "vpermw", T_66 | T_0F38 | T_MUST_EVEX | T_YMM | T_EW1, false },
{ 0x65, "vblendmpd", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW1 | T_B64, false },
{ 0x65, "vblendmps", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW0 | T_B32, false },
{ 0x66, "vpblendmb", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW0, false },
{ 0x66, "vpblendmw", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW1, false },
{ 0x64, "vpblendmd", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW0 | T_B32, false },
{ 0x64, "vpblendmq", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW1 | T_B64, false },
{ 0x7D, "vpermt2b", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW0, false },
{ 0x7D, "vpermt2w", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW1, false },
{ 0x7E, "vpermt2d", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW0 | T_B32, false },
{ 0x7E, "vpermt2q", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW1 | T_B64, false },
{ 0x7F, "vpermt2ps", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW0 | T_B32, false },
{ 0x7F, "vpermt2pd", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW1 | T_B64, false },
{ 0x75, "vpermi2b", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW0, false },
{ 0x75, "vpermi2w", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW1, false },
{ 0x76, "vpermi2d", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW0 | T_B32, false },
{ 0x76, "vpermi2q", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW1 | T_B64, false },
{ 0x77, "vpermi2ps", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW0 | T_B32, false },
{ 0x77, "vpermi2pd", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW1 | T_B64, false },
{ 0x25, "vpternlogd", T_66 | T_0F3A | T_YMM | T_MUST_EVEX | T_EW0 | T_B32, true },
{ 0x25, "vpternlogq", T_66 | T_0F3A | T_YMM | T_MUST_EVEX | T_EW1 | T_B64, true },
{ 0x43, "vgetexpsd", T_66 | T_0F38 | T_MUST_EVEX | T_EW1 | T_SAE_X | T_N8, false },
{ 0x43, "vgetexpss", T_66 | T_0F38 | T_MUST_EVEX | T_EW0 | T_SAE_X | T_N4, false },
{ 0x27, "vgetmantsd", T_66 | T_0F3A | T_MUST_EVEX | T_EW1 | T_SAE_X | T_N8, true },
{ 0x27, "vgetmantss", T_66 | T_0F3A | T_MUST_EVEX | T_EW0 | T_SAE_X | T_N4, true },
{ 0x54, "vfixupimmpd", T_66 | T_0F3A | T_MUST_EVEX | T_YMM | T_EW1 | T_B64 | T_SAE_Z, true },
{ 0x54, "vfixupimmps", T_66 | T_0F3A | T_MUST_EVEX | T_YMM | T_EW0 | T_B32 | T_SAE_Z, true },
{ 0x55, "vfixupimmsd", T_66 | T_0F3A | T_MUST_EVEX | T_EW1 | T_SAE_Z | T_N8, true },
{ 0x55, "vfixupimmss", T_66 | T_0F3A | T_MUST_EVEX | T_EW0 | T_SAE_Z | T_N4, true },
{ 0x4D, "vrcp14sd", T_66 | T_0F38 | T_MUST_EVEX | T_EW1 | T_N8, false },
{ 0x4D, "vrcp14ss", T_66 | T_0F38 | T_MUST_EVEX | T_EW0 | T_N4, false },
{ 0x4F, "vrsqrt14sd", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW1 | T_N8, false },
{ 0x4F, "vrsqrt14ss", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW0 | T_N4, false },
{ 0x0B, "vrndscalesd", T_66 | T_0F3A | T_MUST_EVEX | T_EW1 | T_N8, true },
{ 0x0A, "vrndscaless", T_66 | T_0F3A | T_MUST_EVEX | T_EW0 | T_N4, true },
{ 0x2C, "vscalefpd", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW1 | T_B64 | T_ER_Z, false },
{ 0x2C, "vscalefps", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW0 | T_B32 | T_ER_Z, false },
{ 0x2D, "vscalefsd", T_66 | T_0F38 | T_MUST_EVEX | T_EW1 | T_ER_X | T_N8, false },
{ 0x2D, "vscalefss", T_66 | T_0F38 | T_MUST_EVEX | T_EW0 | T_ER_X | T_N4, false },
{ 0x42, "vdbpsadbw", T_66 | T_0F3A | T_YMM | T_MUST_EVEX | T_EW0, true },
{ 0x83, "vpmultishiftqb", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW1 | T_B64, false },
{ 0x15, "vprolvd", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW0 | T_B32, false },
{ 0x15, "vprolvq", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW1 | T_B64, false },
{ 0x14, "vprorvd", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW0 | T_B32, false },
{ 0x14, "vprorvq", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW1 | T_B64, false },
{ 0xCB, "vrcp28sd", T_66 | T_0F38 | T_MUST_EVEX | T_EW1 | T_N8 | T_SAE_X, false },
{ 0xCB, "vrcp28ss", T_66 | T_0F38 | T_MUST_EVEX | T_EW0 | T_N4 | T_SAE_X, false },
{ 0xCD, "vrsqrt28sd", T_66 | T_0F38 | T_MUST_EVEX | T_EW1 | T_N8 | T_SAE_X, false },
{ 0xCD, "vrsqrt28ss", T_66 | T_0F38 | T_MUST_EVEX | T_EW0 | T_N4 | T_SAE_X, false },
{ 0x50, "vrangepd", T_66 | T_0F3A | T_YMM | T_MUST_EVEX | T_EW1 | T_B64 | T_SAE_Z, true },
{ 0x50, "vrangeps", T_66 | T_0F3A | T_YMM | T_MUST_EVEX | T_EW0 | T_B32 | T_SAE_Z, true },
{ 0x51, "vrangesd", T_66 | T_0F3A | T_MUST_EVEX | T_EW1 | T_SAE_X | T_N8, true },
{ 0x51, "vrangess", T_66 | T_0F3A | T_MUST_EVEX | T_EW0 | T_SAE_X | T_N4, true },
{ 0x57, "vreducesd", T_66 | T_0F3A | T_MUST_EVEX | T_EW1 | T_SAE_X | T_N8, true },
{ 0x57, "vreducess", T_66 | T_0F3A | T_MUST_EVEX | T_EW0 | T_SAE_X | T_N4, true },
{ 0xB4, "vpmadd52luq", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW1 | T_B64, false },
{ 0xB5, "vpmadd52huq", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW1 | T_B64, false },
{ 0x70, "vpshldw", T_66 | T_0F3A | T_YMM | T_MUST_EVEX | T_EW1 | T_SAE_Z, true },
{ 0x71, "vpshldd", T_66 | T_0F3A | T_YMM | T_MUST_EVEX | T_EW0 | T_SAE_Z | T_B32, true },
{ 0x71, "vpshldq", T_66 | T_0F3A | T_YMM | T_MUST_EVEX | T_EW1 | T_SAE_Z | T_B64, true },
{ 0x70, "vpshldvw", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW1 | T_SAE_Z, false },
{ 0x71, "vpshldvd", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW0 | T_SAE_Z | T_B32, false },
{ 0x71, "vpshldvq", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW1 | T_SAE_Z | T_B64, false },
{ 0x72, "vpshrdw", T_66 | T_0F3A | T_YMM | T_MUST_EVEX | T_EW1 | T_SAE_Z, true },
{ 0x73, "vpshrdd", T_66 | T_0F3A | T_YMM | T_MUST_EVEX | T_EW0 | T_SAE_Z | T_B32, true },
{ 0x73, "vpshrdq", T_66 | T_0F3A | T_YMM | T_MUST_EVEX | T_EW1 | T_SAE_Z | T_B64, true },
{ 0x72, "vpshrdvw", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW1 | T_SAE_Z, false },
{ 0x73, "vpshrdvd", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW0 | T_SAE_Z | T_B32, false },
{ 0x73, "vpshrdvq", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW1 | T_SAE_Z | T_B64, false },
{ 0x72, "vcvtne2ps2bf16", T_F2 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW0 | T_SAE_Z | T_B32, false },
{ 0x52, "vdpbf16ps", T_F3 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW0 | T_SAE_Z | T_B32, false },
};
for (size_t i = 0; i < NUM_OF_ARRAY(tbl); i++) {
const Tbl *p = &tbl[i];
std::string type = type2String(p->type);
printf("void %s(const Xmm& x1, const Xmm& x2, const Operand& op%s) { opAVX_X_X_XM(x1, x2, op, %s, 0x%02X%s); }\n"
, p->name, p->hasIMM ? ", uint8_t imm" : "", type.c_str(), p->code, p->hasIMM ? ", imm" : "");
}
}
void putShift()
{
const struct Tbl {
const char *name;
uint8_t code;
int idx;
int type;
} tbl[] = {
{ "vpsraq", 0x72, 4, T_0F | T_66 | T_YMM | T_MUST_EVEX |T_EW1 | T_B64 },
{ "vprold", 0x72, 1, T_66 | T_0F | T_YMM | T_MUST_EVEX | T_EW0 | T_B32 },
{ "vprolq", 0x72, 1, T_66 | T_0F | T_YMM | T_MUST_EVEX | T_EW1 | T_B64 },
{ "vprord", 0x72, 0, T_66 | T_0F | T_YMM | T_MUST_EVEX | T_EW0 | T_B32 },
{ "vprorq", 0x72, 0, T_66 | T_0F | T_YMM | T_MUST_EVEX | T_EW1 | T_B64 },
};
for (size_t i = 0; i < NUM_OF_ARRAY(tbl); i++) {
const Tbl& p = tbl[i];
std::string type = type2String(p.type);
printf("void %s(const Xmm& x, const Operand& op, uint8_t imm) { opAVX_X_X_XM(Xmm(x.getKind(), %d), x, op, %s, 0x%02X, imm); }\n", p.name, p.idx, type.c_str(), p.code);
}
}
void putExtractInsert()
{
{
const struct Tbl {
const char *name;
uint8_t code;
int type;
bool isZMM;
} tbl[] = {
{ "vextractf32x4", 0x19, T_66 | T_0F3A | T_MUST_EVEX | T_EW0 | T_YMM | T_N16, false },
{ "vextractf64x2", 0x19, T_66 | T_0F3A | T_MUST_EVEX | T_EW1 | T_YMM | T_N16, false },
{ "vextractf32x8", 0x1B, T_66 | T_0F3A | T_MUST_EVEX | T_EW0 | T_YMM | T_N32, true },
{ "vextractf64x4", 0x1B, T_66 | T_0F3A | T_MUST_EVEX | T_EW1 | T_YMM | T_N32, true },
{ "vextracti32x4", 0x39, T_66 | T_0F3A | T_MUST_EVEX | T_EW0 | T_YMM | T_N16, false },
{ "vextracti64x2", 0x39, T_66 | T_0F3A | T_MUST_EVEX | T_EW1 | T_YMM | T_N16, false },
{ "vextracti32x8", 0x3B, T_66 | T_0F3A | T_MUST_EVEX | T_EW0 | T_YMM | T_N32, true },
{ "vextracti64x4", 0x3B, T_66 | T_0F3A | T_MUST_EVEX | T_EW1 | T_YMM | T_N32, true },
};
for (size_t i = 0; i < NUM_OF_ARRAY(tbl); i++) {
const Tbl& p = tbl[i];
std::string type = type2String(p.type);
const char *kind = p.isZMM ? "Operand::MEM | Operand::YMM" : "Operand::MEM | Operand::XMM";
printf("void %s(const Operand& op, const %s& r, uint8_t imm) { if (!op.is(%s)) XBYAK_THROW(ERR_BAD_COMBINATION) opVex(r, 0, op, %s, 0x%2X, imm); }\n", p.name, p.isZMM ? "Zmm" : "Ymm", kind, type.c_str(), p.code);
}
}
{
const struct Tbl {
const char *name;
uint8_t code;
int type;
bool isZMM;
} tbl[] = {
{ "vinsertf32x4", 0x18, T_66 | T_0F3A | T_MUST_EVEX | T_EW0 | T_YMM | T_N16, false },
{ "vinsertf64x2", 0x18, T_66 | T_0F3A | T_MUST_EVEX | T_EW1 | T_YMM | T_N16, false },
{ "vinsertf32x8", 0x1A, T_66 | T_0F3A | T_MUST_EVEX | T_EW0 | T_YMM | T_N32, true },
{ "vinsertf64x4", 0x1A, T_66 | T_0F3A | T_MUST_EVEX | T_EW1 | T_YMM | T_N32, true },
{ "vinserti32x4", 0x38, T_66 | T_0F3A | T_MUST_EVEX | T_EW0 | T_YMM | T_N16, false },
{ "vinserti64x2", 0x38, T_66 | T_0F3A | T_MUST_EVEX | T_EW1 | T_YMM | T_N16, false },
{ "vinserti32x8", 0x3A, T_66 | T_0F3A | T_MUST_EVEX | T_EW0 | T_YMM | T_N32, true },
{ "vinserti64x4", 0x3A, T_66 | T_0F3A | T_MUST_EVEX | T_EW1 | T_YMM | T_N32, true },
};
for (size_t i = 0; i < NUM_OF_ARRAY(tbl); i++) {
const Tbl& p = tbl[i];
std::string type = type2String(p.type);
const char *x = p.isZMM ? "Zmm" : "Ymm";
const char *cond = p.isZMM ? "op.is(Operand::MEM | Operand::YMM)" : "(r1.getKind() == r2.getKind() && op.is(Operand::MEM | Operand::XMM))";
printf("void %s(const %s& r1, const %s& r2, const Operand& op, uint8_t imm) {"
"if (!%s) XBYAK_THROW(ERR_BAD_COMBINATION) "
"opVex(r1, &r2, op, %s, 0x%2X, imm); }\n", p.name, x, x, cond, type.c_str(), p.code);
}
}
}
void putBroadcast(bool only64bit)
{
{
const struct Tbl {
uint8_t code;
const char *name;
int type;
int reg;
} tbl[] = {
{ 0x7A, "vpbroadcastb", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW0, 8 },
{ 0x7B, "vpbroadcastw", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW0, 16 },
{ 0x7C, "vpbroadcastd", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW0, 32 },
{ 0x7C, "vpbroadcastq", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW1, 64},
};
for (size_t i = 0; i < NUM_OF_ARRAY(tbl); i++) {
const Tbl& p = tbl[i];
std::string type = type2String(p.type);
if ((only64bit && p.reg == 64) || (!only64bit && p.reg != 64)) {
printf("void %s(const Xmm& x, const Reg%d& r) { opVex(x, 0, r, %s, 0x%02X); }\n", p.name, p.reg, type.c_str(), p.code);
}
}
}
if (only64bit) return;
puts("void vbroadcastf32x2(const Ymm& y, const Operand& op) { opAVX_X_XM_IMM(y, op, T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW0 | T_N8, 0x19); }");
puts("void vbroadcastf32x4(const Ymm& y, const Address& addr) { opAVX_X_XM_IMM(y, addr, T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW0 | T_N16, 0x1A); }");
puts("void vbroadcastf64x2(const Ymm& y, const Address& addr) { opAVX_X_XM_IMM(y, addr, T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW1 | T_N16, 0x1A); }");
puts("void vbroadcastf64x4(const Zmm& y, const Address& addr) { opAVX_X_XM_IMM(y, addr, T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW1 | T_N32, 0x1B); }");
puts("void vbroadcastf32x8(const Zmm& y, const Address& addr) { opAVX_X_XM_IMM(y, addr, T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW0 | T_N32, 0x1B); }");
puts("void vbroadcasti32x2(const Xmm& x, const Operand& op) { opAVX_X_XM_IMM(x, op, T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW0 | T_N8, 0x59); }");
puts("void vbroadcasti32x4(const Ymm& y, const Operand& op) { opAVX_X_XM_IMM(y, op, T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW0 | T_N16, 0x5A); }");
puts("void vbroadcasti64x2(const Ymm& y, const Operand& op) { opAVX_X_XM_IMM(y, op, T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW1 | T_N16, 0x5A); }");
puts("void vbroadcasti32x8(const Zmm& z, const Operand& op) { opAVX_X_XM_IMM(z, op, T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW0 | T_N32, 0x5B); }");
puts("void vbroadcasti64x4(const Zmm& z, const Operand& op) { opAVX_X_XM_IMM(z, op, T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW1 | T_N32, 0x5B); }");
}
void putCvt()
{
puts("void vcvtpd2udq(const Xmm& x, const Operand& op) { opCvt2(x, op, T_0F | T_YMM | T_MUST_EVEX | T_EW1 | T_B64 | T_ER_Z, 0x79); }");
puts("void vcvtps2qq(const Xmm& x, const Operand& op) { checkCvt1(x, op); opVex(x, 0, op, T_66 | T_0F | T_YMM | T_MUST_EVEX | T_EW0 | T_B32 | T_N8 | T_N_VL | T_ER_Y, 0x7B); }");
puts("void vcvtps2uqq(const Xmm& x, const Operand& op) { checkCvt1(x, op); opVex(x, 0, op, T_66 | T_0F | T_YMM | T_MUST_EVEX | T_EW0 | T_B32 | T_N8 | T_N_VL | T_ER_Y, 0x79); }");
puts("void vcvtqq2ps(const Xmm& x, const Operand& op) { opCvt2(x, op, T_0F | T_YMM | T_MUST_EVEX | T_EW1 | T_B64 | T_ER_Z, 0x5B); }");
puts("void vcvttpd2udq(const Xmm& x, const Operand& op) { opCvt2(x, op, T_0F | T_YMM | T_MUST_EVEX | T_EW1 | T_B64 | T_SAE_Z, 0x78); }");
puts("void vcvttps2qq(const Xmm& x, const Operand& op) { checkCvt1(x, op); opVex(x, 0, op, T_66 | T_0F | T_YMM | T_MUST_EVEX | T_EW0 | T_B32 | T_N8 | T_N_VL | T_SAE_Y, 0x7A); }");
puts("void vcvttps2uqq(const Xmm& x, const Operand& op) { checkCvt1(x, op); opVex(x, 0, op, T_66 | T_0F | T_YMM | T_MUST_EVEX | T_EW0 | T_B32 | T_N8 | T_N_VL | T_SAE_Y, 0x78); }");
puts("void vcvtudq2pd(const Xmm& x, const Operand& op) { checkCvt1(x, op); opVex(x, 0, op, T_F3 | T_0F | T_YMM | T_MUST_EVEX | T_EW0 | T_B32 | T_N8 | T_N_VL, 0x7A); }");
puts("void vcvtsd2usi(const Reg32e& r, const Operand& op) { int type = (T_F2 | T_0F | T_MUST_EVEX | T_N8 | T_ER_X) | (r.isREG(64) ? T_EW1 : T_EW0); opAVX_X_X_XM(Xmm(r.getIdx()), xm0, op, type, 0x79); }");
puts("void vcvtss2usi(const Reg32e& r, const Operand& op) { int type = (T_F3 | T_0F | T_MUST_EVEX | T_N4 | T_ER_X) | (r.isREG(64) ? T_EW1 : T_EW0); opAVX_X_X_XM(Xmm(r.getIdx()), xm0, op, type, 0x79); }");
puts("void vcvttsd2usi(const Reg32e& r, const Operand& op) { int type = (T_F2 | T_0F | T_MUST_EVEX | T_N8 | T_SAE_X) | (r.isREG(64) ? T_EW1 : T_EW0); opAVX_X_X_XM(Xmm(r.getIdx()), xm0, op, type, 0x78); }");
puts("void vcvttss2usi(const Reg32e& r, const Operand& op) { int type = (T_F3 | T_0F | T_MUST_EVEX | T_N4 | T_SAE_X) | (r.isREG(64) ? T_EW1 : T_EW0); opAVX_X_X_XM(Xmm(r.getIdx()), xm0, op, type, 0x78); }");
puts("void vcvtuqq2ps(const Xmm& x, const Operand& op) { opCvt2(x, op, T_F2 | T_0F | T_YMM | T_MUST_EVEX | T_EW1 | T_B64 | T_ER_Z, 0x7A); }");
puts("void vcvtusi2sd(const Xmm& x1, const Xmm& x2, const Operand& op) { opCvt3(x1, x2, op, T_F2 | T_0F | T_MUST_EVEX, T_W1 | T_EW1 | T_ER_X | T_N8, T_W0 | T_EW0 | T_N4, 0x7B); }");
puts("void vcvtusi2ss(const Xmm& x1, const Xmm& x2, const Operand& op) { opCvt3(x1, x2, op, T_F3 | T_0F | T_MUST_EVEX | T_ER_X, T_W1 | T_EW1 | T_N8, T_W0 | T_EW0 | T_N4, 0x7B); }");
}
enum { // same as xbyak.h
xx_yy_zz = 0,
xx_yx_zy = 1,
xx_xy_yz = 2,
};
void putGather()
{
const struct Tbl {
const char *name;
int type;
uint8_t code;
int mode;
} tbl[] = {
{ "vpgatherdd", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW0 | T_N4, 0x90, xx_yy_zz },
{ "vpgatherdq", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW1 | T_N8, 0x90, xx_yx_zy },
{ "vpgatherqd", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW0 | T_N4, 0x91, xx_xy_yz },
{ "vpgatherqq", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW1 | T_N8, 0x91, xx_yy_zz },
{ "vgatherdps", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW0 | T_N4, 0x92, xx_yy_zz },
{ "vgatherdpd", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW1 | T_N8, 0x92, xx_yx_zy },
{ "vgatherqps", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW0 | T_N4, 0x93, xx_xy_yz },
{ "vgatherqpd", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW1 | T_N8, 0x93, xx_yy_zz },
};
for (size_t i = 0; i < NUM_OF_ARRAY(tbl); i++) {
const Tbl& p = tbl[i];
std::string type = type2String(p.type | T_VSIB);
printf("void %s(const Xmm& x, const Address& addr) { opGather2(x, addr, %s, 0x%02X, %d); }\n", p.name, type.c_str(), p.code, p.mode);
}
}
void putScatter()
{
const struct Tbl {
const char *name;
int type;
uint8_t code;
int mode; // reverse of gather
} tbl[] = {
{ "vpscatterdd", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW0 | T_N4 | T_M_K, 0xA0, xx_yy_zz },
{ "vpscatterdq", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW1 | T_N8 | T_M_K, 0xA0, xx_yx_zy },
{ "vpscatterqd", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW0 | T_N4 | T_M_K, 0xA1, xx_xy_yz },
{ "vpscatterqq", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW1 | T_N8 | T_M_K, 0xA1, xx_yy_zz },
{ "vscatterdps", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW0 | T_N4 | T_M_K, 0xA2, xx_yy_zz },
{ "vscatterdpd", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW1 | T_N8 | T_M_K, 0xA2, xx_yx_zy },
{ "vscatterqps", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW0 | T_N4 | T_M_K, 0xA3, xx_xy_yz },
{ "vscatterqpd", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW1 | T_N8 | T_M_K, 0xA3, xx_yy_zz },
};
for (size_t i = 0; i < NUM_OF_ARRAY(tbl); i++) {
const Tbl& p = tbl[i];
std::string type = type2String(p.type | T_VSIB);
printf("void %s(const Address& addr, const Xmm& x) { opGather2(x, addr, %s, 0x%02X, %d); }\n", p.name, type.c_str(), p.code, p.mode);
}
}
void putShuff()
{
puts("void vshuff32x4(const Ymm& y1, const Ymm& y2, const Operand& op, uint8_t imm) { opAVX_X_X_XM(y1, y2, op, T_66 | T_0F3A | T_YMM | T_MUST_EVEX | T_EW0 | T_B32, 0x23, imm); }");
puts("void vshuff64x2(const Ymm& y1, const Ymm& y2, const Operand& op, uint8_t imm) { opAVX_X_X_XM(y1, y2, op, T_66 | T_0F3A | T_YMM | T_MUST_EVEX | T_EW1 | T_B64, 0x23, imm); }");
puts("void vshufi32x4(const Ymm& y1, const Ymm& y2, const Operand& op, uint8_t imm) { opAVX_X_X_XM(y1, y2, op, T_66 | T_0F3A | T_YMM | T_MUST_EVEX | T_EW0 | T_B32, 0x43, imm); }");
puts("void vshufi64x2(const Ymm& y1, const Ymm& y2, const Operand& op, uint8_t imm) { opAVX_X_X_XM(y1, y2, op, T_66 | T_0F3A | T_YMM | T_MUST_EVEX | T_EW1 | T_B64, 0x43, imm); }");
}
void putMov()
{
puts("void vpmovm2b(const Xmm& x, const Opmask& k) { opVex(x, 0, k, T_F3 | T_0F38 | T_MUST_EVEX | T_YMM | T_EW0, 0x28); }");
puts("void vpmovm2w(const Xmm& x, const Opmask& k) { opVex(x, 0, k, T_F3 | T_0F38 | T_MUST_EVEX | T_YMM | T_EW1, 0x28); }");
puts("void vpmovm2d(const Xmm& x, const Opmask& k) { opVex(x, 0, k, T_F3 | T_0F38 | T_MUST_EVEX | T_YMM | T_EW0, 0x38); }");
puts("void vpmovm2q(const Xmm& x, const Opmask& k) { opVex(x, 0, k, T_F3 | T_0F38 | T_MUST_EVEX | T_YMM | T_EW1, 0x38); }");
puts("void vpmovb2m(const Opmask& k, const Xmm& x) { opVex(k, 0, x, T_F3 | T_0F38 | T_MUST_EVEX | T_YMM | T_EW0, 0x29); }");
puts("void vpmovw2m(const Opmask& k, const Xmm& x) { opVex(k, 0, x, T_F3 | T_0F38 | T_MUST_EVEX | T_YMM | T_EW1, 0x29); }");
puts("void vpmovd2m(const Opmask& k, const Xmm& x) { opVex(k, 0, x, T_F3 | T_0F38 | T_MUST_EVEX | T_YMM | T_EW0, 0x39); }");
puts("void vpmovq2m(const Opmask& k, const Xmm& x) { opVex(k, 0, x, T_F3 | T_0F38 | T_MUST_EVEX | T_YMM | T_EW1, 0x39); }");
{
const struct Tbl {
uint8_t code;
const char *name;
int type;
int mode;
} tbl[] = {
{ 0x32, "vpmovqb", T_F3 | T_0F38 | T_MUST_EVEX | T_YMM | T_EW0 | T_N2 | T_N_VL, false },
{ 0x22, "vpmovsqb", T_F3 | T_0F38 | T_MUST_EVEX | T_YMM | T_EW0 | T_N2 | T_N_VL, false },
{ 0x12, "vpmovusqb", T_F3 | T_0F38 | T_MUST_EVEX | T_YMM | T_EW0 | T_N2 | T_N_VL, false },
{ 0x34, "vpmovqw", T_F3 | T_0F38 | T_MUST_EVEX | T_YMM | T_EW0 | T_N4 | T_N_VL, false },
{ 0x24, "vpmovsqw", T_F3 | T_0F38 | T_MUST_EVEX | T_YMM | T_EW0 | T_N4 | T_N_VL, false },
{ 0x14, "vpmovusqw", T_F3 | T_0F38 | T_MUST_EVEX | T_YMM | T_EW0 | T_N4 | T_N_VL, false },
{ 0x35, "vpmovqd", T_F3 | T_0F38 | T_MUST_EVEX | T_YMM | T_EW0 | T_N8 | T_N_VL, true },
{ 0x25, "vpmovsqd", T_F3 | T_0F38 | T_MUST_EVEX | T_YMM | T_EW0 | T_N8 | T_N_VL, true },
{ 0x15, "vpmovusqd", T_F3 | T_0F38 | T_MUST_EVEX | T_YMM | T_EW0 | T_N8 | T_N_VL, true },
{ 0x31, "vpmovdb", T_F3 | T_0F38 | T_MUST_EVEX | T_YMM | T_EW0 | T_N4 | T_N_VL, false },
{ 0x21, "vpmovsdb", T_F3 | T_0F38 | T_MUST_EVEX | T_YMM | T_EW0 | T_N4 | T_N_VL, false },
{ 0x11, "vpmovusdb", T_F3 | T_0F38 | T_MUST_EVEX | T_YMM | T_EW0 | T_N4 | T_N_VL, false },
{ 0x33, "vpmovdw", T_F3 | T_0F38 | T_MUST_EVEX | T_YMM | T_EW0 | T_N8 | T_N_VL, true },
{ 0x23, "vpmovsdw", T_F3 | T_0F38 | T_MUST_EVEX | T_YMM | T_EW0 | T_N8 | T_N_VL, true },
{ 0x13, "vpmovusdw", T_F3 | T_0F38 | T_MUST_EVEX | T_YMM | T_EW0 | T_N8 | T_N_VL, true },
{ 0x30, "vpmovwb", T_F3 | T_0F38 | T_MUST_EVEX | T_YMM | T_EW0 | T_N8 | T_N_VL, true },
{ 0x20, "vpmovswb", T_F3 | T_0F38 | T_MUST_EVEX | T_YMM | T_EW0 | T_N8 | T_N_VL, true },
{ 0x10, "vpmovuswb", T_F3 | T_0F38 | T_MUST_EVEX | T_YMM | T_EW0 | T_N8 | T_N_VL, true },
};
for (size_t i = 0; i < NUM_OF_ARRAY(tbl); i++) {
const Tbl& p = tbl[i];
std::string type = type2String(p.type);
printf("void %s(const Operand& op, const Xmm& x) { opVmov(op, x, %s, 0x%02X, %s); }\n", p.name, type.c_str(), p.code, p.mode ? "true" : "false");
}
}
}
void putX_XM_IMM()
{
const struct Tbl {
uint8_t code;
const char *name;
int type;
bool hasIMM;
} tbl[] = {
{ 0x26, "vgetmantpd", T_66 | T_0F3A | T_YMM | T_MUST_EVEX | T_EW1 | T_B64 | T_SAE_Z, true },
{ 0x26, "vgetmantps", T_66 | T_0F3A | T_YMM | T_MUST_EVEX | T_EW0 | T_B32 | T_SAE_Z, true },
{ 0x4C, "vrcp14pd", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW1 | T_B64, false },
{ 0x4C, "vrcp14ps", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW0 | T_B32, false },
{ 0x4E, "vrsqrt14pd", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW1 | T_B64, false },
{ 0x4E, "vrsqrt14ps", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW0 | T_B32, false },
{ 0x09, "vrndscalepd", T_66 | T_0F3A | T_YMM | T_MUST_EVEX | T_EW1 | T_B64, true },
{ 0x08, "vrndscaleps", T_66 | T_0F3A | T_YMM | T_MUST_EVEX | T_EW0 | T_B32, true },
{ 0xC4, "vpconflictd", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW0 | T_B32, false },
{ 0xC4, "vpconflictq", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW1 | T_B64, false },
{ 0x44, "vplzcntd", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW0 | T_B32, false },
{ 0x44, "vplzcntq", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW1 | T_B64, false },
{ 0x56, "vreducepd", T_66 | T_0F3A | T_YMM | T_MUST_EVEX | T_EW1 | T_B64 | T_SAE_Z, true },
{ 0x56, "vreduceps", T_66 | T_0F3A | T_YMM | T_MUST_EVEX | T_EW0 | T_B32 | T_SAE_Z, true },
{ 0x54, "vpopcntb", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW0 | T_SAE_Z, false },
{ 0x54, "vpopcntw", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW1 | T_SAE_Z, false },
{ 0x55, "vpopcntd", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW0 | T_SAE_Z | T_B32, false },
{ 0x55, "vpopcntq", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW1 | T_SAE_Z | T_B64, false },
{ 0x62, "vpexpandb", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW0 | T_SAE_Z | T_N1, false },
{ 0x62, "vpexpandw", T_66 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW1 | T_SAE_Z | T_N2, false },
};
for (size_t i = 0; i < NUM_OF_ARRAY(tbl); i++) {
const Tbl *p = &tbl[i];
std::string type = type2String(p->type);
printf("void %s(const Xmm& x, const Operand& op%s) { opAVX_X_XM_IMM(x, op, %s, 0x%02X%s); }\n"
, p->name, p->hasIMM ? ", uint8_t imm" : "", type.c_str(), p->code, p->hasIMM ? ", imm" : "");
}
}
void putMisc()
{
puts("void vpbroadcastmb2q(const Xmm& x, const Opmask& k) { opVex(x, 0, k, T_F3 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW1, 0x2A); }");
puts("void vpbroadcastmw2d(const Xmm& x, const Opmask& k) { opVex(x, 0, k, T_F3 | T_0F38 | T_YMM | T_MUST_EVEX | T_EW0, 0x3A); }");
{
const struct Tbl {
const char *name;
int zm;
int type;
uint8_t code;
bool isZmm;
} tbl[] = {
{ "vgatherpf0dps", 1, T_EW0 | T_N4, 0xC6, true },
{ "vgatherpf0qps", 1, T_EW0 | T_N4, 0xC7, true },
{ "vgatherpf0dpd", 1, T_EW1 | T_N8, 0xC6, false },
{ "vgatherpf0qpd", 1, T_EW1 | T_N8, 0xC7, true },
{ "vgatherpf1dps", 2, T_EW0 | T_N4, 0xC6, true },
{ "vgatherpf1qps", 2, T_EW0 | T_N4, 0xC7, true },
{ "vgatherpf1dpd", 2, T_EW1 | T_N8, 0xC6, false },
{ "vgatherpf1qpd", 2, T_EW1 | T_N8, 0xC7, true },
{ "vscatterpf0dps", 5, T_EW0 | T_N4, 0xC6, true },
{ "vscatterpf0qps", 5, T_EW0 | T_N4, 0xC7, true },
{ "vscatterpf0dpd", 5, T_EW1 | T_N8, 0xC6, false },
{ "vscatterpf0qpd", 5, T_EW1 | T_N8, 0xC7, true },
{ "vscatterpf1dps", 6, T_EW0 | T_N4, 0xC6, true },
{ "vscatterpf1qps", 6, T_EW0 | T_N4, 0xC7, true },
{ "vscatterpf1dpd", 6, T_EW1 | T_N8, 0xC6, false },
{ "vscatterpf1qpd", 6, T_EW1 | T_N8, 0xC7, true },
};
for (size_t i = 0; i < NUM_OF_ARRAY(tbl); i++) {
const Tbl& p = tbl[i];
std::string type = type2String(p.type | T_66 | T_0F38 | T_MUST_EVEX | T_M_K | T_VSIB);
printf("void %s(const Address& addr) { opGatherFetch(addr, zm%d, %s, 0x%2X, Operand::%s); }\n"
, p.name, p.zm, type.c_str(), p.code, p.isZmm ? "ZMM" : "YMM");
}
}
puts("void vfpclasspd(const Opmask& k, const Operand& op, uint8_t imm) { if (!op.isBit(128|256|512)) XBYAK_THROW(ERR_BAD_MEM_SIZE) opVex(k.changeBit(op.getBit()), 0, op, T_66 | T_0F3A | T_MUST_EVEX | T_YMM | T_EW1 | T_B64, 0x66, imm); }");
puts("void vfpclassps(const Opmask& k, const Operand& op, uint8_t imm) { if (!op.isBit(128|256|512)) XBYAK_THROW(ERR_BAD_MEM_SIZE) opVex(k.changeBit(op.getBit()), 0, op, T_66 | T_0F3A | T_MUST_EVEX | T_YMM | T_EW0 | T_B32, 0x66, imm); }");
puts("void vfpclasssd(const Opmask& k, const Operand& op, uint8_t imm) { if (!op.isXMEM()) XBYAK_THROW(ERR_BAD_MEM_SIZE) opVex(k, 0, op, T_66 | T_0F3A | T_MUST_EVEX | T_EW1 | T_N8, 0x67, imm); }");
puts("void vfpclassss(const Opmask& k, const Operand& op, uint8_t imm) { if (!op.isXMEM()) XBYAK_THROW(ERR_BAD_MEM_SIZE) opVex(k, 0, op, T_66 | T_0F3A | T_MUST_EVEX | T_EW0 | T_N4, 0x67, imm); }");
puts("void vpshufbitqmb(const Opmask& k, const Xmm& x, const Operand& op) { opVex(k, &x, op, T_66 | T_0F38 | T_EW0 | T_YMM | T_MUST_EVEX, 0x8F); }");
puts("void vcvtneps2bf16(const Xmm& x, const Operand& op) { opCvt2(x, op, T_F3 | T_0F38 | T_EW0 | T_YMM | T_SAE_Z | T_MUST_EVEX | T_B32, 0x72); }");
puts("void vp2intersectd(const Opmask& k, const Xmm& x, const Operand& op) { if (k.getOpmaskIdx() != 0) XBYAK_THROW(ERR_OPMASK_IS_ALREADY_SET) opAVX_K_X_XM(k, x, op, T_F2 | T_0F38 | T_YMM | T_EVEX | T_EW0 | T_B32, 0x68); }");
puts("void vp2intersectq(const Opmask& k, const Xmm& x, const Operand& op) { if (k.getOpmaskIdx() != 0) XBYAK_THROW(ERR_OPMASK_IS_ALREADY_SET) opAVX_K_X_XM(k, x, op, T_F2 | T_0F38 | T_YMM | T_EVEX | T_EW1 | T_B64, 0x68); }");
}
void putV4FMA()
{
puts("void v4fmaddps(const Zmm& z1, const Zmm& z2, const Address& addr) { opAVX_X_X_XM(z1, z2, addr, T_0F38 | T_F2 | T_EW0 | T_YMM | T_MUST_EVEX | T_N16, 0x9A); }");
puts("void v4fnmaddps(const Zmm& z1, const Zmm& z2, const Address& addr) { opAVX_X_X_XM(z1, z2, addr, T_0F38 | T_F2 | T_EW0 | T_YMM | T_MUST_EVEX | T_N16, 0xAA); }");
puts("void v4fmaddss(const Xmm& x1, const Xmm& x2, const Address& addr) { opAVX_X_X_XM(x1, x2, addr, T_0F38 | T_F2 | T_EW0 | T_MUST_EVEX | T_N16, 0x9B); }");
puts("void v4fnmaddss(const Xmm& x1, const Xmm& x2, const Address& addr) { opAVX_X_X_XM(x1, x2, addr, T_0F38 | T_F2 | T_EW0 | T_MUST_EVEX | T_N16, 0xAB); }");
puts("void vp4dpwssd(const Zmm& z1, const Zmm& z2, const Address& addr) { opAVX_X_X_XM(z1, z2, addr, T_0F38 | T_F2 | T_EW0 | T_YMM | T_MUST_EVEX | T_N16, 0x52); }");
puts("void vp4dpwssds(const Zmm& z1, const Zmm& z2, const Address& addr) { opAVX_X_X_XM(z1, z2, addr, T_0F38 | T_F2 | T_EW0 | T_YMM | T_MUST_EVEX | T_N16, 0x53); }");
}
int main(int argc, char *[])
{
bool only64bit = argc == 2;
putOpmask(only64bit);
putBroadcast(only64bit);
if (only64bit) {
return 0;
}
putVcmp();
putX_XM();
putM_X();
putXM_X();
putX_X_XM_IMM();
putShift();
putExtractInsert();
putCvt();
putGather();
putShuff();
putMov();
putX_XM_IMM();
putMisc();
putScatter();
putV4FMA();
}
File diff suppressed because it is too large. Load diff
-23
View File
@@ -1,23 +0,0 @@
#include <iostream>
#include <fstream>
#include <string>
#include <set>
typedef std::set<std::string> StrSet;
int main()
{
StrSet ss;
std::string line;
while (std::getline(std::cin, line)) {
if (!line.empty() && line[line.size() - 1] == '\n') {
line.resize(line.size() - 1);
}
if (!line.empty()) {
ss.insert(line);
}
}
for (StrSet::const_iterator i = ss.begin(), ie = ss.end(); i != ie; ++i) {
std::cout << *i << std::endl;
}
}
-17
View File
@@ -1,17 +0,0 @@
@echo off
set OPT=/EHsc -I../ /W4 -D_CRT_SECURE_NO_WARNINGS
set TARGET=..\\xbyak\\xbyak_mnemonic.h
set SORT=sortline
cl gen_code.cpp %OPT%
gen_code | %SORT% > %TARGET%
echo #ifdef XBYAK_ENABLE_OMITTED_OPERAND>> %TARGET%
gen_code omit | %SORT% >> %TARGET%
echo #endif>>%TARGET%
gen_code fixed >> %TARGET%
cl gen_avx512.cpp %OPT%
echo #ifndef XBYAK_DISABLE_AVX512>> %TARGET%
gen_avx512 | %SORT% >> %TARGET%
echo #ifdef XBYAK64>> %TARGET%
gen_avx512 64 | %SORT% >> %TARGET%
echo #endif>> %TARGET%
echo #endif>> %TARGET%
-617
View File
@@ -1,617 +0,0 @@
[![Build Status](https://github.com/herumi/xbyak/actions/workflows/main.yml/badge.svg)](https://github.com/herumi/xbyak/actions/workflows/main.yml)
# Xbyak 5.992 ; JIT assembler for x86(IA32), x64(AMD64, x86-64) by C++
## Abstract
Xbyak is a C++ header library that enables dynamically to assemble x86(IA32), x64(AMD64, x86-64) mnemonic.
The pronunciation of Xbyak is `kəi-bja-k`.
It is named from a Japanese word [開闢](https://translate.google.com/?hl=ja&sl=ja&tl=en&text=%E9%96%8B%E9%97%A2&op=translate), which means the beginning of the world.
## Feature
* header file only
* Intel/MASM like syntax
* fully support AVX-512
**Note**:
Use `and_()`, `or_()`, ... instead of `and()`, `or()`.
If you want to use them, then specify `-fno-operator-names` option to gcc/clang.
### News
- vnni instructions such as vpdpbusd supports vex encoding.
- (break backward compatibility) `push(byte, imm)` (resp. `push(word, imm)`) forces to cast `imm` to 8(resp. 16) bit.
- (Windows) `#include <winsock2.h>` has been removed from xbyak.h, so add it explicitly if you need it.
- support exception-less mode see. [Exception-less mode](#exception-less-mode)
- `XBYAK_USE_MMAP_ALLOCATOR` will be defined on Linux/macOS unless `XBYAK_DONT_USE_MMAP_ALLOCATOR` is defined.
### Supported OS
* Windows Xp, Vista, Windows 7, Windows 10(32bit, 64bit)
* Linux(32bit, 64bit)
* Intel macOS
### Supported Compilers
Almost C++03 or later compilers for x86/x64 such as Visual Studio, g++, clang++, Intel C++ compiler and g++ on mingw/cygwin.
## Install
The following files are necessary. Please add the path to your compile directory.
* xbyak.h
* xbyak_mnemonic.h
* xbyak_util.h
Linux:
```
make install
```
These files are copied into `/usr/local/include/xbyak`.
## How to use it
Inherit `Xbyak::CodeGenerator` class and make the class method.
```
#include <xbyak/xbyak.h>
struct Code : Xbyak::CodeGenerator {
Code(int x)
{
mov(eax, x);
ret();
}
};
```
Or you can pass the instance of CodeGenerator without inheriting.
```
void genCode(Xbyak::CodeGenerator& code, int x) {
using namespace Xbyak::util;
code.mov(eax, x);
code.ret();
}
```
Make an instance of the class and get the function
pointer by calling `getCode()` and call it.
```
Code c(5);
int (*f)() = c.getCode<int (*)()>();
printf("ret=%d\n", f()); // ret = 5
```
## Syntax
Similar to MASM/NASM syntax with parentheses.
```
NASM Xbyak
mov eax, ebx --> mov(eax, ebx);
inc ecx inc(ecx);
ret --> ret();
```
## Addressing
Use `qword`, `dword`, `word` and `byte` if it is necessary to specify the size of memory,
otherwise use `ptr`.
```
(ptr|qword|dword|word|byte) [base + index * (1|2|4|8) + displacement]
[rip + 32bit disp] ; x64 only
NASM Xbyak
mov eax, [ebx+ecx] --> mov(eax, ptr [ebx+ecx]);
mov al, [ebx+ecx] --> mov(al, ptr [ebx + ecx]);
test byte [esp], 4 --> test(byte [esp], 4);
inc qword [rax] --> inc(qword [rax]);
```
**Note**: `qword`, ... are member variables, then don't use `dword` as unsigned int type.
### How to use Selector (Segment Register)
```
mov eax, [fs:eax] --> putSeg(fs);
mov(eax, ptr [eax]);
mov ax, cs --> mov(ax, cs);
```
**Note**: Segment class is not derived from `Operand`.
## AVX
```
vaddps(xmm1, xmm2, xmm3); // xmm1 <- xmm2 + xmm3
vaddps(xmm2, xmm3, ptr [rax]); // use ptr to access memory
vgatherdpd(xmm1, ptr [ebp + 256 + xmm2*4], xmm3);
```
**Note**:
If `XBYAK_ENABLE_OMITTED_OPERAND` is defined, then you can use two operand version for backward compatibility.
But the newer version will not support it.
```
vaddps(xmm2, xmm3); // xmm2 <- xmm2 + xmm3
```
## AVX-512
```
vaddpd zmm2, zmm5, zmm30 --> vaddpd(zmm2, zmm5, zmm30);
vaddpd xmm30, xmm20, [rax] --> vaddpd(xmm30, xmm20, ptr [rax]);
vaddps xmm30, xmm20, [rax] --> vaddps(xmm30, xmm20, ptr [rax]);
vaddpd zmm2{k5}, zmm4, zmm2 --> vaddpd(zmm2 | k5, zmm4, zmm2);
vaddpd zmm2{k5}{z}, zmm4, zmm2 --> vaddpd(zmm2 | k5 | T_z, zmm4, zmm2);
vaddpd zmm2{k5}{z}, zmm4, zmm2,{rd-sae} --> vaddpd(zmm2 | k5 | T_z, zmm4, zmm2 | T_rd_sae);
vaddpd(zmm2 | k5 | T_z | T_rd_sae, zmm4, zmm2); // the position of `|` is arbitrary.
vcmppd k4{k3}, zmm1, zmm2, {sae}, 5 --> vcmppd(k4 | k3, zmm1, zmm2 | T_sae, 5);
vaddpd xmm1, xmm2, [rax+256] --> vaddpd(xmm1, xmm2, ptr [rax+256]);
vaddpd xmm1, xmm2, [rax+256]{1to2} --> vaddpd(xmm1, xmm2, ptr_b [rax+256]);
vaddpd ymm1, ymm2, [rax+256]{1to4} --> vaddpd(ymm1, ymm2, ptr_b [rax+256]);
vaddpd zmm1, zmm2, [rax+256]{1to8} --> vaddpd(zmm1, zmm2, ptr_b [rax+256]);
vaddps zmm1, zmm2, [rax+rcx*8+8]{1to16} --> vaddps(zmm1, zmm2, ptr_b [rax+rcx*8+8]);
vmovsd [rax]{k1}, xmm4 --> vmovsd(ptr [rax] | k1, xmm4);
vcvtpd2dq xmm16, oword [eax+33] --> vcvtpd2dq(xmm16, xword [eax+33]); // use xword for m128 instead of oword
vcvtpd2dq(xmm16, ptr [eax+33]); // default xword
vcvtpd2dq xmm21, [eax+32]{1to2} --> vcvtpd2dq(xmm21, ptr_b [eax+32]);
vcvtpd2dq xmm0, yword [eax+33] --> vcvtpd2dq(xmm0, yword [eax+33]); // use yword for m256
vcvtpd2dq xmm19, [eax+32]{1to4} --> vcvtpd2dq(xmm19, yword_b [eax+32]); // use yword_b to broadcast
vfpclassps k5{k3}, zword [rax+64], 5 --> vfpclassps(k5|k3, zword [rax+64], 5); // specify m512
vfpclasspd k5{k3}, [rax+64]{1to2}, 5 --> vfpclasspd(k5|k3, xword_b [rax+64], 5); // broadcast 64-bit to 128-bit
vfpclassps k5{k3}, [rax+64]{1to4}, 5 --> vfpclassps(k5|k3, yword_b [rax+64], 5); // broadcast 64-bit to 256-bit
vpdpbusd(xm0, xm1, xm2); // default encoding is EVEX
vpdpbusd(xm0, xm1, xm2, EvexEncoding); // same as the above
vpdpbusd(xm0, xm1, xm2, VexEncoding); // VEX encoding
```
### Remark
* `k1`, ..., `k7` are opmask registers.
- `k0` is dealt as no mask.
- e.g. `vmovaps(zmm0|k0, ptr[rax]);` and `vmovaps(zmm0|T_z, ptr[rax]);` are same to `vmovaps(zmm0, ptr[rax]);`.
* use `| T_z`, `| T_sae`, `| T_rn_sae`, `| T_rd_sae`, `| T_ru_sae`, `| T_rz_sae` instead of `,{z}`, `,{sae}`, `,{rn-sae}`, `,{rd-sae}`, `,{ru-sae}`, `,{rz-sae}` respectively.
* `k4 | k3` is different from `k3 | k4`.
* use `ptr_b` for broadcast `{1toX}`. X is automatically determined.
* specify `xword`/`yword`/`zword(_b)` for m128/m256/m512 if necessary.
## Label
Two kinds of Label are supported. (String literal and Label class).
### String literal
```
L("L1");
jmp("L1");
jmp("L2");
...
a few mnemonics (8-bit displacement jmp)
...
L("L2");
jmp("L3", T_NEAR);
...
a lot of mnemonics (32-bit displacement jmp)
...
L("L3");
```
* Call `hasUndefinedLabel()` to verify your code has no undefined label.
* you can use a label for immediate value of mov like as `mov(eax, "L2")`.
### Support `@@`, `@f`, `@b` like MASM
```
L("@@"); // <A>
jmp("@b"); // jmp to <A>
jmp("@f"); // jmp to <B>
L("@@"); // <B>
jmp("@b"); // jmp to <B>
mov(eax, "@b");
jmp(eax); // jmp to <B>
```
### Local label
Label symbols beginning with a period between `inLocalLabel()` and `outLocalLabel()`
are treated as a local label.
`inLocalLabel()` and `outLocalLabel()` can be nested.
```
void func1()
{
inLocalLabel();
L(".lp"); // <A> ; local label
...
jmp(".lp"); // jmp to <A>
L("aaa"); // global label <C>
outLocalLabel();
inLocalLabel();
L(".lp"); // <B> ; local label
func1();
jmp(".lp"); // jmp to <B>
inLocalLabel();
jmp("aaa"); // jmp to <C>
}
```
### short and long jump
Xbyak deals with jump mnemonics of an undefined label as short jump if no type is specified.
So if the size between jmp and label is larger than 127 byte, then xbyak will cause an error.
```
jmp("short-jmp"); // short jmp
// small code
L("short-jmp");
jmp("long-jmp");
// long code
L("long-jmp"); // throw exception
```
Then specify T_NEAR for jmp.
```
jmp("long-jmp", T_NEAR); // long jmp
// long code
L("long-jmp");
```
Or call `setDefaultJmpNEAR(true);` once, then the default type is set to T_NEAR.
```
jmp("long-jmp"); // long jmp
// long code
L("long-jmp");
```
### Label class
`L()` and `jxx()` support Label class.
```
Xbyak::Label label1, label2;
L(label1);
...
jmp(label1);
...
jmp(label2);
...
L(label2);
```
Use `putL` for jmp table
```
Label labelTbl, L0, L1, L2;
mov(rax, labelTbl);
// rdx is an index of jump table
jmp(ptr [rax + rdx * sizeof(void*)]);
L(labelTbl);
putL(L0);
putL(L1);
putL(L2);
L(L0);
....
L(L1);
....
```
`assignL(dstLabel, srcLabel)` binds dstLabel with srcLabel.
```
Label label2;
Label label1 = L(); // make label1 ; same to Label label1; L(label1);
...
jmp(label2); // label2 is not determined here
...
assignL(label2, label1); // label2 <- label1
```
The `jmp` in the above code jumps to label1 assigned by `assignL`.
**Note**:
* srcLabel must be used in `L()`.
* dstLabel must not be used in `L()`.
`Label::getAddress()` returns the address specified by the label instance and 0 if not specified.
```
// not AutoGrow mode
Label label;
assert(label.getAddress() == 0);
L(label);
assert(label.getAddress() == getCurr());
```
### Rip ; relative addressing
```
Label label;
mov(eax, ptr [rip + label]); // eax = 4
...
L(label);
dd(4);
```
```
int x;
...
mov(eax, ptr[rip + &x]); // throw exception if the difference between &x and current position is larger than 2GiB
```
## Code size
The default max code size is 4096 bytes.
Specify the size in constructor of `CodeGenerator()` if necessary.
```
class Quantize : public Xbyak::CodeGenerator {
public:
Quantize()
: CodeGenerator(8192)
{
}
...
};
```
## User allocated memory
You can make jit code on prepared memory.
Call `setProtectModeRE` yourself to change memory mode if using the prepared memory.
```
uint8_t alignas(4096) buf[8192]; // C++11 or later
struct Code : Xbyak::CodeGenerator {
Code() : Xbyak::CodeGenerator(sizeof(buf), buf)
{
mov(rax, 123);
ret();
}
};
int main()
{
Code c;
c.setProtectModeRE(); // set memory to Read/Exec
printf("%d\n", c.getCode<int(*)()>()());
}
```
**Note**: See [sample/test0.cpp](sample/test0.cpp).
### AutoGrow
The memory region for jit is automatically extended if necessary when `AutoGrow` is specified in a constructor of `CodeGenerator`.
Call `ready()` or `readyRE()` before calling `getCode()` to fix jump address.
```
struct Code : Xbyak::CodeGenerator {
Code()
: Xbyak::CodeGenerator(<default memory size>, Xbyak::AutoGrow)
{
...
}
};
Code c;
// generate code for jit
c.ready(); // mode = Read/Write/Exec
```
**Note**:
* Don't use the address returned by `getCurr()` before calling `ready()` because it may be invalid address.
### Read/Exec mode
Xbyak set Read/Write/Exec mode to memory to run jit code.
If you want to use Read/Exec mode for security, then specify `DontSetProtectRWE` for `CodeGenerator` and
call `setProtectModeRE()` after generating jit code.
```
struct Code : Xbyak::CodeGenerator {
Code()
: Xbyak::CodeGenerator(4096, Xbyak::DontSetProtectRWE)
{
mov(eax, 123);
ret();
}
};
Code c;
c.setProtectModeRE();
...
```
Call `readyRE()` instead of `ready()` when using `AutoGrow` mode.
See [protect-re.cpp](sample/protect-re.cpp).
## Exception-less mode
If `XBYAK_NO_EXCEPTION` is defined, then gcc/clang can compile xbyak with `-fno-exceptions`.
In stead of throwing an exception, `Xbyak::GetError()` returns non-zero value (e.g. `ERR_BAD_ADDRESSING`) if there is something wrong.
The status will not be changed automatically, then you should reset it by `Xbyak::ClearError()`.
`CodeGenerator::reset()` calls `ClearError()`.
## Macro
* **XBYAK32** is defined on 32bit.
* **XBYAK64** is defined on 64bit.
* **XBYAK64_WIN** is defined on 64bit Windows(VC).
* **XBYAK64_GCC** is defined on 64bit gcc, cygwin.
* define **XBYAK_USE_OP_NAMES** on gcc with `-fno-operator-names` if you want to use `and()`, ....
* define **XBYAK_ENABLE_OMITTED_OPERAND** if you use omitted destination such as `vaddps(xmm2, xmm3);`(deprecated in the future).
* define **XBYAK_UNDEF_JNL** if Bessel function jnl is defined as macro.
* define **XBYAK_NO_EXCEPTION** for a compiler option `-fno-exceptions`.
## Sample
* [test0.cpp](sample/test0.cpp) ; tiny sample (x86, x64)
* [quantize.cpp](sample/quantize.cpp) ; JIT optimized quantization by fast division (x86 only)
* [calc.cpp](sample/calc.cpp) ; assemble and estimate a given polynomial (x86, x64)
* [bf.cpp](sample/bf.cpp) ; JIT brainfuck (x86, x64)
## License
modified new BSD License
http://opensource.org/licenses/BSD-3-Clause
## History
* 2021/May/09 ver 5.992 support endbr32 and endbr64
* 2020/Nov/16 ver 5.991 disable constexpr for gcc-5 with -std=c++-14
* 2020/Oct/19 ver 5.99 support VNNI instructions(Thanks to akharito)
* 2020/Oct/17 ver 5.98 support the form of [scale * reg]
* 2020/Sep/08 ver 5.97 replace uint32 with uint32_t etc.
* 2020/Aug/28 ver 5.95 some constructors of register classes support constexpr if C++14 or later
* 2020/Aug/04 ver 5.941 `CodeGenerator::reset()` calls `ClearError()`.
* 2020/Jul/28 ver 5.94 remove #include <winsock2.h> (only windows)
* 2020/Jul/21 ver 5.93 support exception-less mode
* 2020/Jun/30 ver 5.92 support Intel AMX instruction set (Thanks to nshustrov)
* 2020/Jun/22 ver 5.913 fix mov(r64, imm64) on 32-bit env with XBYAK64
* 2020/Jun/19 ver 5.912 define MAP_JIT on macOS regardless of Xcode version (Thanks to rsdubtso)
* 2020/May/10 ver 5.911 XBYAK_USE_MMAP_ALLOCATOR is defined unless XBYAK_DONT_USE_MMAP_ALLOCATOR is defined.
* 2020/Apr/20 ver 5.91 accept mask register k0 (it means no mask)
* 2020/Apr/09 ver 5.90 kmov{b,d,w,q} throws exception for an unsupported register
* 2020/Feb/26 ver 5.891 fix typo of type
* 2020/Jan/03 ver 5.89 fix error of vfpclasspd
* 2019/Dec/20 ver 5.88 fix compile error on Windows
* 2019/Dec/19 ver 5.87 add setDefaultJmpNEAR(), which deals with `jmp` of an undefined label as T_NEAR if no type is specified.
* 2019/Dec/13 ver 5.86 [changed] revert to the behavior before v5.84 if -fno-operator-names is defined (and() is available)
* 2019/Dec/07 ver 5.85 append MAP_JIT flag to mmap for macOS mojave or later
* 2019/Nov/29 ver 5.84 [changed] XBYAK_NO_OP_NAMES is defined unless XBYAK_USE_OP_NAMES is defined
* 2019/Oct/12 ver 5.83 exit(1) was removed
* 2019/Sep/23 ver 5.82 support monitorx, mwaitx, clzero (thanks to @MagurosanTeam)
* 2019/Sep/14 ver 5.81 support some generic mnemonics.
* 2019/Aug/01 ver 5.802 fix detection of AVX512_BF16 (thanks to vpirogov)
* 2019/May/27 support vp2intersectd, vp2intersectq (not tested)
* 2019/May/26 ver 5.80 support vcvtne2ps2bf16, vcvtneps2bf16, vdpbf16ps
* 2019/Apr/27 ver 5.79 vcmppd/vcmpps supports ptr_b(thanks to jkopinsky)
* 2019/Apr/15 ver 5.78 rewrite Reg::changeBit() (thanks to MerryMage)
* 2019/Mar/06 ver 5.77 fix number of cores that share LLC cache by densamoilov
* 2019/Jan/17 ver 5.76 add Cpu::getNumCores() by shelleygoel
* 2018/Oct/31 ver 5.751 recover Xbyak::CastTo for compatibility
* 2018/Oct/29 ver 5.75 unlink LabelManager from Label when msg is destroyed
* 2018/Oct/21 ver 5.74 support RegRip +/- int. Xbyak::CastTo is removed
* 2018/Oct/15 util::AddressFrame uses push/pop instead of mov
* 2018/Sep/19 ver 5.73 fix evex encoding of vpslld, vpslldq, vpsllw, etc for (reg, mem, imm8)
* 2018/Sep/19 ver 5.72 fix the encoding of vinsertps for disp8N(Thanks to petercaday)
* 2018/Sep/04 ver 5.71 L() returns a new label instance
* 2018/Aug/27 ver 5.70 support setProtectMode() and DontUseProtect for read/exec setting
* 2018/Aug/24 ver 5.68 fix wrong VSIB encoding with vector index >= 16(thanks to petercaday)
* 2018/Aug/14 ver 5.67 remove mutable in Address ; fix setCacheHierarchy for cloud vm
* 2018/Jul/26 ver 5.661 support mingw64
* 2018/Jul/24 ver 5.66 add CodeArray::PROTECT_RE to mode of protect()
* 2018/Jun/26 ver 5.65 fix push(qword [mem])
* 2018/Mar/07 ver 5.64 fix zero division in Cpu() on some cpu
* 2018/Feb/14 ver 5.63 fix Cpu::setCacheHierarchy() and fix EvexModifierZero for clang<3.9(thanks to mgouicem)
* 2018/Feb/13 ver 5.62 Cpu::setCacheHierarchy() by mgouicem and rsdubtso
* 2018/Feb/07 ver 5.61 vmov* supports mem{k}{z}(I forgot it)
* 2018/Jan/24 ver 5.601 add xword, yword, etc. into Xbyak::util namespace
* 2018/Jan/05 ver 5.60 support AVX-512 for Ice lake(319433-030.pdf)
* 2017/Aug/22 ver 5.53 fix mpx encoding, add bnd() prefix
* 2017/Aug/18 ver 5.52 fix align (thanks to MerryMage)
* 2017/Aug/17 ver 5.51 add multi-byte nop and align() uses it(thanks to inolen)
* 2017/Aug/08 ver 5.50 add mpx(thanks to magurosan)
* 2017/Aug/08 ver 5.45 add sha(thanks to magurosan)
* 2017/Aug/08 ver 5.44 add prefetchw(thanks to rsdubtso)
* 2017/Jul/12 ver 5.432 reduce warnings of PVS studio
* 2017/Jul/09 ver 5.431 fix hasRex() (no affect) (thanks to drillsar)
* 2017/May/14 ver 5.43 fix CodeGenerator::resetSize() (thanks to gibbed)
* 2017/May/13 ver 5.42 add movs{b,w,d,q}
* 2017/Jan/26 ver 5.41 add prefetchwt1 and support for scale == 0(thanks to rsdubtso)
* 2016/Dec/14 ver 5.40 add Label::getAddress() method to get the pointer specified by the label
* 2016/Dec/09 ver 5.34 fix handling of negative offsets when encoding disp8N(thanks to rsdubtso)
* 2016/Dec/08 ver 5.33 fix encoding of vpbroadcast{b,w,d,q}, vpinsr{b,w}, vpextr{b,w} for disp8N
* 2016/Dec/01 ver 5.32 rename __xgetbv() to _xgetbv() to support clang for Visual Studio(thanks to freiro)
* 2016/Nov/27 ver 5.31 rename AVX512_4VNNI to AVX512_4VNNIW
* 2016/Nov/27 ver 5.30 add AVX512_4VNNI, AVX512_4FMAPS instructions(thanks to rsdubtso)
* 2016/Nov/26 ver 5.20 add detection of AVX512_4VNNI and AVX512_4FMAPS(thanks to rsdubtso)
* 2016/Nov/20 ver 5.11 lost vptest for ymm(thanks to gregory38)
* 2016/Nov/20 ver 5.10 add addressing [rip+&var]
* 2016/Sep/29 ver 5.03 fix detection ERR_INVALID_OPMASK_WITH_MEMORY(thanks to PVS-Studio)
* 2016/Aug/15 ver 5.02 xbyak does not include xbyak_bin2hex.h
* 2016/Aug/15 ver 5.011 fix detection of version of gcc 5.4
* 2016/Aug/03 ver 5.01 disable omitted operand
* 2016/Jun/24 ver 5.00 support avx-512 instruction set
* 2016/Jun/13 avx-512 add mask instructions
* 2016/May/05 ver 4.91 add detection of AVX-512 to Xbyak::util::Cpu
* 2016/Mar/14 ver 4.901 comment to ready() function(thanks to skmp)
* 2016/Feb/04 ver 4.90 add jcc(const void *addr);
* 2016/Jan/30 ver 4.89 vpblendvb supports ymm reg(thanks to John Funnell)
* 2016/Jan/24 ver 4.88 lea, cmov supports 16-bit register(thanks to whyisthisfieldhere)
* 2015/Oct/05 ver 4.87 support segment selectors
* 2015/Aug/18 ver 4.86 fix [rip + label] addressing with immediate value(thanks to whyisthisfieldhere)
* 2015/Aug/10 ver 4.85 Address::operator==() is not correct(thanks to inolen)
* 2015/Jun/22 ver 4.84 call() support variadic template if available(thanks to randomstuff)
* 2015/Jun/16 ver 4.83 support movbe(thanks to benvanik)
* 2015/May/24 ver 4.82 support detection of F16C
* 2015/Apr/25 ver 4.81 fix the condition to throw exception for setSize(thanks to whyisthisfieldhere)
* 2015/Apr/22 ver 4.80 rip supports label(thanks to whyisthisfieldhere)
* 2015/Jar/28 ver 4.71 support adcx, adox, cmpxchg, rdseed, stac
* 2014/Oct/14 ver 4.70 support MmapAllocator
* 2014/Jun/13 ver 4.62 disable warning of VC2014
* 2014/May/30 ver 4.61 support bt, bts, btr, btc
* 2014/May/28 ver 4.60 support vcvtph2ps, vcvtps2ph
* 2014/Apr/11 ver 4.52 add detection of rdrand
* 2014/Mar/25 ver 4.51 remove state information of unreferenced labels
* 2014/Mar/16 ver 4.50 support new Label
* 2014/Mar/05 ver 4.40 fix wrong detection of BMI/enhanced rep on VirtualBox
* 2013/Dec/03 ver 4.30 support Reg::cvt8(), cvt16(), cvt32(), cvt64()
* 2013/Oct/16 ver 4.21 label support std::string
* 2013/Jul/30 ver 4.20 [break backward compatibility] split Reg32e class into RegExp(base+index*scale+disp) and Reg32e(means Reg32 or Reg64)
* 2013/Jul/04 ver 4.10 [break backward compatibility] change the type of Xbyak::Error from enum to a class
* 2013/Jun/21 ver 4.02 add putL(LABEL) function to put the address of the label
* 2013/Jun/21 ver 4.01 vpsllw, vpslld, vpsllq, vpsraw, vpsrad, vpsrlw, vpsrld, vpsrlq support (ymm, ymm, xmm). support vpbroadcastb, vpbroadcastw, vpbroadcastd, vpbroadcastq(thanks to Gabest).
* 2013/May/30 ver 4.00 support AVX2, VEX-encoded GPR-instructions
* 2013/Mar/27 ver 3.80 support mov(reg, "label");
* 2013/Mar/13 ver 3.76 add cqo(), jcxz(), jecxz(), jrcxz()
* 2013/Jan/15 ver 3.75 add setSize() to modify generated code
* 2013/Jan/12 ver 3.74 add CodeGenerator::reset() ; add Allocator::useProtect()
* 2013/Jan/06 ver 3.73 use unordered_map if possible
* 2012/Dec/04 ver 3.72 eax, ebx, ... are member variables of CodeGenerator(revert), Xbyak::util::eax, ... are static const.
* 2012/Nov/17 ver 3.71 and_(), or_(), xor_(), not_() are available if XBYAK_NO_OP_NAMES is not defined.
* 2012/Nov/17 change eax, ebx, ptr and so on in CodeGenerator as static member and alias of them are defined in Xbyak::util.
* 2012/Nov/09 ver 3.70 XBYAK_NO_OP_NAMES macro is added to use and_() instead of and() (thanks to Mattias)
* 2012/Nov/01 ver 3.62 add fwait/fnwait/finit/fninit
* 2012/Nov/01 ver 3.61 add fldcw/fstcw
* 2012/May/03 ver 3.60 change interface of Allocator
* 2012/Mar/23 ver 3.51 fix userPtr mode
* 2012/Mar/19 ver 3.50 support AutoGrow mode
* 2011/Nov/09 ver 3.05 fix bit property of rip addresing / support movsxd
* 2011/Aug/15 ver 3.04 fix dealing with imm8 such as add(dword [ebp-8], 0xda); (thanks to lolcat)
* 2011/Jun/16 ver 3.03 fix __GNUC_PREREQ macro for Mac gcc(thanks to t_teruya)
* 2011/Apr/28 ver 3.02 do not use xgetbv on Mac gcc
* 2011/May/24 ver 3.01 fix typo of OSXSAVE
* 2011/May/23 ver 3.00 add vcmpeqps and so on
* 2011/Feb/16 ver 2.994 beta add vmovq for 32-bit mode(I forgot it)
* 2011/Feb/16 ver 2.993 beta remove cvtReg to avoid thread unsafe
* 2011/Feb/10 ver 2.992 beta support one argument syntax for fadd like nasm
* 2011/Feb/07 ver 2.991 beta fix pextrw reg, xmm, imm(Thanks to Gabest)
* 2011/Feb/04 ver 2.99 beta support AVX
* 2010/Dec/08 ver 2.31 fix ptr [rip + 32bit offset], support rdtscp
* 2010/Oct/19 ver 2.30 support pclmulqdq, aesdec, aesdeclast, aesenc, aesenclast, aesimc, aeskeygenassist
* 2010/Jun/07 ver 2.29 fix call(<label>)
* 2010/Jun/17 ver 2.28 move some member functions to public
* 2010/Jun/01 ver 2.27 support encoding of mov(reg64, imm) like yasm(not nasm)
* 2010/May/24 ver 2.26 fix sub(rsp, 1000)
* 2010/Apr/26 ver 2.25 add jc/jnc(I forgot to implement them...)
* 2010/Apr/16 ver 2.24 change the prototype of rewrite() method
* 2010/Apr/15 ver 2.23 fix align() and xbyak_util.h for Mac
* 2010/Feb/16 ver 2.22 fix inLocalLabel()/outLocalLabel()
* 2009/Dec/09 ver 2.21 support cygwin(gcc 4.3.2)
* 2009/Nov/28 support a part of FPU
* 2009/Jun/25 fix mov(qword[rax], imm); (thanks to Martin)
* 2009/Mar/10 fix redundant REX.W prefix on jmp/call reg64
* 2009/Feb/24 add movq reg64, mmx/xmm; movq mmx/xmm, reg64
* 2009/Feb/13 movd(xmm7, dword[eax]) drops 0x66 prefix (thanks to Gabest)
* 2008/Dec/30 fix call in short relative address(thanks to kato san)
* 2008/Sep/18 support @@, @f, @b and localization of label(thanks to nobu-q san)
* 2008/Sep/18 support (ptr[rip + 32bit offset]) (thanks to Dango-Chu san)
* 2008/Jun/03 fix align(). mov(ptr[eax],1) throws ERR_MEM_SIZE_IS_NOT_SPECIFIED.
* 2008/Jun/02 support memory interface allocated by user
* 2008/May/26 fix protect() to avoid invalid setting(thanks to shinichiro_h san)
* 2008/Apr/30 add cmpxchg16b, cdqe
* 2008/Apr/29 support x64
* 2008/Apr/14 code refactoring
* 2008/Mar/12 add bsr/bsf
* 2008/Feb/14 fix output of sub eax, 1234 (thanks to Robert)
* 2007/Nov/5 support lock, xadd, xchg
* 2007/Nov/2 support SSSE3/SSE4 (thanks to Dango-Chu san)
* 2007/Feb/4 fix the bug that exception doesn't occur under the condition which the offset of jmp mnemonic without T_NEAR is over 127.
* 2007/Jan/21 fix the bug to create address like [disp] select smaller representation for mov (eax|ax|al, [disp])
* 2007/Jan/4 first version
## Author
MITSUNARI Shigeo(herumi@nifty.com)
## Sponsors welcome
[GitHub Sponsor](https://github.com/sponsors/herumi)
-560
View File
@@ -1,560 +0,0 @@
C++用x86(IA-32), x64(AMD64, x86-64) JITアセンブラ Xbyak 5.992
-----------------------------------------------------------------------------
◎概要
これはx86, x64(AMD64, x86-64)のマシン語命令を生成するC++のクラスライブラリです。
プログラム実行時に動的にアセンブルすることが可能です。
-----------------------------------------------------------------------------
◎特徴
・ヘッダファイルオンリー
xbyak.hをインクルードするだけですぐ利用することができます。
C++の枠組み内で閉じているため、外部アセンブラは不要です。
32bit/64bit両対応です。
対応ニーモニック:特権命令除くx86, MMX/MMX2/SSE/SSE2/SSE3/SSSE3/SSE4/FPU(一部)/AVX/AVX2/FMA/VEX-encoded GPR
・Windows Xp(32bit, 64bit), Windows 7/Linux(32bit, 64bit)/Intel Mac対応
Windows Xp, Windows 7上ではVC2008, VC2010, VC2012
Linux (kernel 3.8)上ではgcc 4.7.3, clang 3.3
Intel Mac
などで動作確認をしています。
※ and, orなどの代わりにand_, or_を使用してください。
and, orなどを使いたい場合は-fno-operator-namesをgcc/clangに指定してください。
-----------------------------------------------------------------------------
◎準備
xbyak.h
xbyak_bin2hex.h
これらを同一のパスに入れてインクルードパスに追加してください。
Linuxではmake installで/usr/local/include/xbyakにコピーされます。
-----------------------------------------------------------------------------
◎下位互換性の破れ
* push byte, immまたはpush word, immが下位8bit, 16bitにキャストした値を使うように変更。
* (Windows) `<winsock2.h>`をincludeしなくなったので必要なら明示的にincludeしてください。
* XBYAK_USE_MMAP_ALLOCATORがデフォルトで有効になりました。従来の方式にする場合はXBYAK_DONT_USE_MMAP_ALLOCATORを定義してください。
* Xbyak::Errorの型をenumからclassに変更
** 従来のenumの値をとるにはintにキャストしてください。
* (古い)Reg32eクラスを(新しい)Reg32eとRegExpに分ける。
** (新しい)Reg32eはReg32かReg64
** (新しい)RegExpは'Reg32e + (Reg32e|Xmm|Ymm) * scale + disp'の型
-----------------------------------------------------------------------------
◎新機能
例外なしモード追加
XBYAK_NO_EXCEPTIONを定義してコンパイルするとgcc/clangで-fno-exceptionsオプションでコンパイルできます。
エラーは例外の代わりに`Xbyak::GetError()`で通達されます。
この値が0でなければ何か問題が発生しています。
この値は自動的に変更されないので`Xbyak::ClearError()`でリセットしてください。
`CodeGenerator::reset()`は`ClearError()`を呼びます。
MmapAllocator追加
これはUnix系OSでのみの仕様です。XBYAK_USE_MMAP_ALLOCATORを使うと利用できます。
デフォルトのAllocatorはメモリ確保時にposix_memalignを使います。
この領域に対するmprotectはmap countを減らします。
map countの最大値は/proc/sys/vm/max_map_countに書かれています。
デフォルトでは3万個ほどのXbyak::CodeGeneratorインスタンスを生成するとエラーになります。
test/mprotect_test.cppで確認できます。
これを避けるためにはmmapを使うMmapAllocatorを使ってください。
AutoGrowモード追加
これはメモリ伸長を動的に行うモードです。
今まではXbyak::CodeGenerator()に渡したメモリサイズを超えると例外が発生して
いましたが、このモードでは内部でメモリを再確保して伸長します。
ただし、getCode()を呼び出す前にジャンプ命令のアドレス解決をするためにready()
関数を呼ぶ必要があります。
次のように使います。
struct Code : Xbyak::CodeGenerator {
Code()
: Xbyak::CodeGenerator(<default memory size>, Xbyak::AutoGrow)
{
...
}
};
Code c;
c.ready(); // この呼び出しを忘れてはいけない
注意1. ready()を呼んで確定するまではgetCurr()で得たポインタは無効化されている
可能性があります。getSize()でoffsetを保持しておきready()のあとにgetCode()を
呼び出してからgetCode() + offsetで新しいポインタを取得してください。
注意2. AutoGrowモードでは64bitモードの相対アドレッシング[rip]は非サポートです。
-----------------------------------------------------------------------------
◎文法
Xbyak::CodeGeneratorクラスを継承し、そのクラスメソッド内でx86, x64アセンブラを
記述します。そのメソッドを呼び出した後、getCode()メソッドを呼び出し、その戻
り値を自分が使いたい関数ポインタに変換して利用します。アセンブルエラーは例外
により通知されます(cf. main.cpp)。
・基本的にnasmの命令で括弧をつければよいです。
mov eax, ebx --> mov(eax, ebx);
inc ecx inc(ecx);
ret --> ret();
・アドレッシング
(ptr|dword|word|byte) [base + index * (1|2|4|8) + displacement]
[rip + 32bit disp] ; x64 only
という形で指定します。サイズを指定する必要がない限りptrを使えばよいです。
セレクター(セグメントレジスタ)をサポートしました。
(注意)セグメントレジスタはOperandを継承していません。
mov eax, [fs:eax] --> putSeg(fs); mov(eax, ptr [eax]);
mov ax, cs --> mov(ax, cs);
mov eax, [ebx+ecx] --> mov (eax, ptr[ebx+ecx]);
test byte [esp], 4 --> test (byte [esp], 4);
(注意) dword, word, byteはメンバ変数です。従ってたとえばunsigned intの
つもりでdwordをtypedefしないでください。
・AVX
FMAについては簡略表記を導入するか検討中です(アイデア募集中)。
vaddps(xmm1, xmm2, xmm3); // xmm1 <- xmm2 + xmm3
vaddps(xmm2, xmm3, ptr [rax]); // メモリアクセスはptrで
vfmadd231pd(xmm1, xmm2, xmm3); // xmm1 <- (xmm2 * xmm3) + xmm1
*注意*
デスティネーションの省略形はサポートされなくなりました。
vaddps(xmm2, xmm3); // xmm2 <- xmm2 + xmm3
XBYAK_ENABLE_OMITTED_OPERANDを定義すると使えますが、将来はそれも非サポートになるでしょう。
・AVX-512
vaddpd zmm2, zmm5, zmm30 --> vaddpd(zmm2, zmm5, zmm30);
vaddpd xmm30, xmm20, [rax] --> vaddpd(xmm30, xmm20, ptr [rax]);
vaddps xmm30, xmm20, [rax] --> vaddps(xmm30, xmm20, ptr [rax]);
vaddpd zmm2{k5}, zmm4, zmm2 --> vaddpd(zmm2 | k5, zmm4, zmm2);
vaddpd zmm2{k5}{z}, zmm4, zmm2 --> vaddpd(zmm2 | k5 | T_z, zmm4, zmm2);
vaddpd zmm2{k5}{z}, zmm4, zmm2,{rd-sae} --> vaddpd(zmm2 | k5 | T_z, zmm4, zmm2 | T_rd_sae);
vaddpd(zmm2 | k5 | T_z | T_rd_sae, zmm4, zmm2); // the position of `|` is arbitrary.
vcmppd k4{k3}, zmm1, zmm2, {sae}, 5 --> vcmppd(k4 | k3, zmm1, zmm2 | T_sae, 5);
vaddpd xmm1, xmm2, [rax+256]{1to2} --> vaddpd(xmm1, xmm2, ptr_b [rax+256]);
vaddpd ymm1, ymm2, [rax+256]{1to4} --> vaddpd(ymm1, ymm2, ptr_b [rax+256]);
vaddpd zmm1, zmm2, [rax+256]{1to8} --> vaddpd(zmm1, zmm2, ptr_b [rax+256]);
vaddps zmm1, zmm2, [rax+rcx*8+8]{1to16} --> vaddps(zmm1, zmm2, ptr_b [rax+rcx*8+8]);
vmovsd [rax]{k1}, xmm4 --> vmovsd(ptr [rax] | k1, xmm4);
vcvtpd2dq xmm16, oword [eax+33] --> vcvtpd2dq(xmm16, xword [eax+33]); // use xword for m128 instead of oword
vcvtpd2dq(xmm16, ptr [eax+33]); // default xword
vcvtpd2dq xmm21, [eax+32]{1to2} --> vcvtpd2dq(xmm21, ptr_b [eax+32]);
vcvtpd2dq xmm0, yword [eax+33] --> vcvtpd2dq(xmm0, yword [eax+33]); // use yword for m256
vcvtpd2dq xmm19, [eax+32]{1to4} --> vcvtpd2dq(xmm19, yword_b [eax+32]); // use yword_b to broadcast
vfpclassps k5{k3}, zword [rax+64], 5 --> vfpclassps(k5|k3, zword [rax+64], 5); // specify m512
vfpclasspd k5{k3}, [rax+64]{1to2}, 5 --> vfpclasspd(k5|k3, xword_b [rax+64], 5); // broadcast 64-bit to 128-bit
vfpclassps k5{k3}, [rax+64]{1to4}, 5 --> vfpclassps(k5|k3, xword_b [rax+64], 5); // broadcast 64-bit to 256-bit
vpdpbusd(xm0, xm1, xm2); // default encoding is EVEX
vpdpbusd(xm0, xm1, xm2, EvexEncoding); // same as the above
vpdpbusd(xm0, xm1, xm2, VexEncoding); // VEX encoding
注意
* k1, ..., k7 は新しいopmaskレジスタです。
* z, sae, rn-sae, rd-sae, ru-sae, rz-saeの代わりにT_z, T_sae, T_rn_sae, T_rd_sae, T_ru_sae, T_rz_saeを使ってください。
* `k4 | k3`と`k3 | k4`は意味が異なります。
* {1toX}の代わりにptr_bを使ってください。Xは自動的に決まります。
* 一部の命令はメモリサイズを指定するためにxword/yword/zword(_b)を使ってください。
・ラベル
L(文字列);
で定義します。ジャンプするときはその文字列を指定します。後方参照も可能ですが、
相対アドレスが8ビットに収まらない場合はT_NEARをつけないと実行時に例外が発生
します。
mov(eax, "L2");の様にラベルが表すアドレスをmovの即値として使えます。
・hasUndefinedLabel()を呼び出して真ならジャンプ先が存在しないことを示します。
コードを見直してください。
L("L1");
jmp ("L1");
jmp ("L2");
...
少しの命令の場合。
...
L("L2");
jmp ("L3", T_NEAR);
...
沢山の命令がある場合
...
L("L3");
<応用編>
1. MASMライクな@@, @f, @bをサポート
L("@@"); // <A>
jmp("@b"); // jmp to <A>
jmp("@f"); // jmp to <B>
L("@@"); // <B>
jmp("@b"); // jmp to <B>
mov(eax, "@b");
jmp(eax); // jmp to <B>
2. ラベルの局所化
ピリオドで始まるラベルをinLocalLabel(), outLocalLabel()で挟むことで局所化できます。
inLocalLabel(), outLocalLabel()は入れ子にすることができます。
void func1()
{
inLocalLabel();
L(".lp"); // <A> ; ローカルラベル
...
jmp(".lp"); // jmpt to <A>
L("aaa"); // グローバルラベル
outLocalLabel();
}
void func2()
{
inLocalLabel();
L(".lp"); // <B> ; ローカルラベル
func1();
jmp(".lp"); // jmp to <B>
outLocalLabel();
}
上記サンプルではinLocalLabel(), outLocalLabel()が無いと、
".lp"ラベルの二重定義エラーになります。
3. 新しいLabelクラスによるジャンプ命令
ジャンプ先を文字列による指定だけでなくラベルクラスを使えるようになりました。
Label label1, label2;
L(label1);
...
jmp(label1);
...
jmp(label2);
...
L(label2);
更にラベルの割り当てを行うassignL(dstLabel, srcLabel)という命令も追加されました。
Label label2;
Label label1 = L(); // Label label1; L(label1);と同じ意味
...
jmp(label2);
...
assignL(label2, label1);
上記jmp命令はlabel1にジャンプします。
制限
* srcLabelはL()により飛び先が確定していないといけません。
* dstLabelはL()により飛び先が確定していてはいけません。
ラベルは`getAddress()`によりそのアドレスを取得できます。
未定義のときは0が返ります。
```
// not AutoGrow mode
Label label;
assert(label.getAddress(), 0);
L(label);
assert(label.getAddress(), getCurr());
```
・Xbyak::CodeGenerator()コンストラクタインタフェース
@param maxSize [in] コード生成最大サイズ(デフォルト4096byte)
@param userPtr [in] ユーザ指定メモリ
CodeGenerator(size_t maxSize = DEFAULT_MAX_CODE_SIZE, void *userPtr = 0);
デフォルトコードサイズは4096(=DEFAULT_MAX_CODE_SIZE)バイトです。
それより大きなコードを生成する場合はCodeGenerator()のコンストラクタに指定してください。
class Quantize : public Xbyak::CodeGenerator {
public:
Quantize()
: CodeGenerator(8192)
{
}
...
};
またユーザ指定メモリをコード生成最大サイズと共に指定すると、CodeGeneratorは
指定されたメモリ上にバイト列を生成します。
補助関数として指定されたアドレスの実行属性を変更するCodeArray::protect()と
与えられたポインタからアライメントされたポインタを取得するCodeArray::getAlignedAddress()
も用意しました。詳細はsample/test0.cppのuse memory allocated by userを参考に
してください。
/**
change exec permission of memory
@param addr [in] buffer address
@param size [in] buffer size
@param canExec [in] true(enable to exec), false(disable to exec)
@return true(success), false(failure)
*/
bool CodeArray::protect(const void *addr, size_t size, bool canExec);
/**
get aligned memory pointer
*/
uint8 *CodeArray::getAlignedAddress(uint8 *addr, size_t alignedSize = ALIGN_SIZE);
・read/execモード
デフォルトのCodeGeneratorはコンストラクト時にJIT用の領域をread/write/execモードに設定して利用します。
コード生成時はread/writeでコード実行時にはread/execにしたい場合、次のようにしてください。
struct Code : Xbyak::CodeGenerator {
Code()
: Xbyak::CodeGenerator(4096, Xbyak::DontUseProtect) // JIT領域をread/writeのままコード生成
{
mov(eax, 123);
ret();
}
};
Code c;
c.setProtectModeRE(); // read/execモードに変更
// JIT領域を実行
AutoGrowの場合はreadyの代わりにreadyRE()を読んでください。
struct Code : Xbyak::CodeGenerator {
Code()
: Xbyak::CodeGenerator(4096, Xbyak::AutoGrow) // JIT領域をread/writeのままコード生成
{
mov(eax, 123);
ret();
}
};
Code c;
c.readyRE(); // read/exeモードに変更
// JIT領域を実行
setProtectModeRW()を呼ぶと領域が元のread/execモードに戻ります。
その他詳細は各種サンプルを参照してください。
-----------------------------------------------------------------------------
◎マクロ
32bit環境上でコンパイルするとXBYAK32が、64bit環境上でコンパイルするとXBYAK64が
定義されます。さらに64bit環境上ではWindows(VC)ならXBYAK64_WIN、cygwin, gcc上では
XBYAK64_GCCが定義されます。
-----------------------------------------------------------------------------
◎使用例
test0.cpp ; 簡単な例(x86, x64)
quantize.cpp ; 割り算のJITアセンブルによる量子化の高速化(x86)
calc.cpp ; 与えられた多項式をアセンブルして実行(x86, x64)
boost(http://www.boost.org/)が必要
bf.cpp ; JIT Brainfuck(x86, x64)
-----------------------------------------------------------------------------
◎ライセンス
修正された新しいBSDライセンスに従います。
http://opensource.org/licenses/BSD-3-Clause
sample/{echo,hello}.bfは http://www.kmonos.net/alang/etc/brainfuck.php から
いただきました。
-----------------------------------------------------------------------------
◎履歴
2021/05/09 ver 5.992 endbr32とendbr64のサポート
2020/11/16 ver 5.991 g++-5のC++14でconstexpr機能の抑制
2020/10/19 ver 5.99 VNNI命令サポート(Thanks to akharito)
2020/10/17 ver 5.98 [scale * reg]のサポート
2020/09/08 ver 5.97 uint32などをuint32_tに置換
2020/08/28 ver 5.95 レジスタクラスのコンストラクタがconstexprに対応(C++14以降)
2020/08/04 ver 5.941 `CodeGenerator::reset()`が`ClearError()`を呼ぶように変更
2020/07/28 ver 5.94 #include <winsock2.h>の削除 (only windows)
2020/07/21 ver 5.93 例外なしモード追加
2020/06/30 ver 5.92 Intel AMX命令サポート (Thanks to nshustrov)
2020/06/19 ver 5.913 32ビット環境でXBYAK64を定義したときのmov(r64, imm64)を修正
2020/06/19 ver 5.912 macOSの古いXcodeでもMAP_JITを有効にする(Thanks to rsdubtso)
2020/05/10 ver 5.911 Linux/macOSでXBYAK_USE_MMAP_ALLOCATORがデフォルト有効になる
2020/04/20 ver 5.91 マスクレジスタk0を受け入れる(マスクをしない)
2020/04/09 ver 5.90 kmov{b,w,d,q}がサポートされないレジスタを受けると例外を投げる
2020/02/26 ver 5.891 zm0のtype修正
2020/01/03 ver 5.89 vfpclasspdの処理エラー修正
2019/12/20 ver 5.88 Windowsでのコンパイルエラー修正
2019/12/19 ver 5.87 未定義ラベルへのjmp命令のデフォルト挙動をT_NEARにするsetDefaultJmpNEAR()を追加
2019/12/13 ver 5.86 [変更] -fno-operator-namesが指定されたときは5.84以前の挙動に戻す
2019/12/07 ver 5.85 mmapにMAP_JITフラグを追加(macOS mojave以上)
2019/11/29 ver 5.84 [変更] XBYAK_USE_OP_NAMESが定義されていない限りXBYAK_NO_OP_NAMESが定義されるように変更
2019/10/12 ver 5.83 exit(1)の除去
2019/09/23 ver 5.82 monitorx, mwaitx, clzero対応 (thanks to MagurosanTeam)
2019/09/14 ver 5.81 いくつかの一般命令をサポート
2019/08/01 ver 5.802 AVX512_BF16判定修正 (thanks to vpirogov)
2019/05/27 support vp2intersectd, vp2intersectq (not tested)
2019/05/26 ver 5.80 support vcvtne2ps2bf16, vcvtneps2bf16, vdpbf16ps
2019/04/27 ver 5.79 vcmppd/vcmppsのptr_b対応忘れ(thanks to jkopinsky)
2019/04/15 ver 5.78 Reg::changeBit()のリファクタリング(thanks to MerryMage)
2019/03/06 ver 5.77 LLCキャッシュを共有数CPU数の修整(by densamoilov)
2019/01/17 ver 5.76 Cpu::getNumCores()追加(by shelleygoel)
2018/10/31 ver 5.751 互換性のためにXbyak::CastToの復元
2018/10/29 ver 5.75 LabelManagerのデストラクタでLabelから参照を切り離す
2018/10/21 ver 5.74 RegRip +/intの形をサポート Xbyak::CastToを削除
2018/10/15 util::StackFrameでmovの代わりにpush/popを使う
2018/09/19 ver 5.73 vpslld, vpslldq, vpsllwなどの(reg, mem, imm8)に対するevexエンコーディング修整
2018/09/19 ver 5.72 fix the encoding of vinsertps for disp8N(Thanks to petercaday)
2018/08/27 ver 5.71 新しいlabelインスタンスを返すL()を追加
2018/08/27 ver 5.70 read/exec設定のためのsetProtectMode()とDontUseProtectの追加
2018/08/24 ver 5.68 indexが16以上のVSIBエンコーディングのバグ修正(thanks to petercaday)
2018/08/14 ver 5.67 Addressクラス内のmutableを削除 ; fix setCacheHierarchy for cloud vm
2018/07/26 ver 5.661 mingw64対応
2018/07/24 ver 5.66 protect()のmodeにCodeArray::PROTECT_REを追加
2018/06/26 ver 5.65 fix push(qword [mem])
2018/03/07 ver 5.64 Cpu()の中でzero divisionが出ることがあるのを修正
2018/02/14 ver 5.63 Cpu::setCacheHierarchy()の修正とclang<3.9のためのEvexModifierZero修正(thanks to mgouicem)
2018/02/13 ver 5.62 Cpu::setCacheHierarchy() by mgouicem and rsdubtso
2018/02/07 ver 5.61 vmov*がmem{k}{z}形式対応(忘れてた)
2018/01/24 ver 5.601 xword, ywordなどをXbyak::util名前空間に追加
2018/01/05 ver 5.60 Ice lake系命令対応(319433-030.pdf)
2017/08/22 ver 5.53 mpxエンコーディングバグ修正, bnd()プレフィクス追加
2017/08/18 ver 5.52 align修正(thanks to MerryMage)
2017/08/17 ver 5.51 multi-byte nop追加 align()はそれを使用する(thanks to inolen)
2017/08/08 ver 5.50 mpx追加(thanks to magurosan)
2017/08/08 ver 5.45 sha追加(thanks to magurosan)
2017/08/08 ver 5.44 prefetchw追加(thanks to rsdubtso)
2017/07/12 ver 5.432 PVS-studioの警告を減らす
2017/07/09 ver 5.431 hasRex()修正 (影響なし) (thanks to drillsar)
2017/05/14 ver 5.43 CodeGenerator::resetSize()修正(thanks to gibbed)
2017/05/13 ver 5.42 movs{b,w,d,q}追加
2017/01/26 ver 5.41 prefetcwt1追加とscale == 0対応(thanks to rsdubtso)
2016/12/14 ver 5.40 Labelが示すアドレスを取得するLabel::getAddress()追加
2016/12/07 ver 5.34 disp8N時の負のオフセット処理の修正(thanks to rsdubtso)
2016/12/06 ver 5.33 disp8N時のvpbroadcast{b,w,d,q}, vpinsr{b,w}, vpextr{b,w}のバグ修正
2016/12/01 ver 5.32 clang for Visual Studioサポートのために__xgetbv()を_xgetbv()に変更(thanks to freiro)
2016/11/27 ver 5.31 AVX512_4VNNIをAVX512_4VNNIWに変更
2016/11/27 ver 5.30 AVX512_4VNNI, AVX512_4FMAPS命令の追加(thanks to rsdubtso)
2016/11/26 ver 5.20 AVX512_4VNNIとAVX512_4FMAPSの判定追加(thanks to rsdubtso)
2016/11/20 ver 5.11 何故か消えていたvptest for ymm追加(thanks to gregory38)
2016/11/20 ver 5.10 [rip+&var]の形のアドレッシング追加
2016/09/29 ver 5.03 ERR_INVALID_OPMASK_WITH_MEMORYの判定ミス修正(thanks to PVS-Studio)
2016/08/15 ver 5.02 xbyak_bin2hex.hをincludeしない
2016/08/15 ver 5.011 gcc 5.4のバージョン取得ミスの修正
2016/08/03 ver 5.01 AVXの省略表記非サポート
2016/07/24 ver 5.00 avx-512フルサポート
2016/06/13 avx-512 opmask命令サポート
2016/05/05 ver 4.91 AVX-512命令の検出サポート
2016/03/14 ver 4.901 ready()関数にコメント加筆(thanks to skmp)
2016/02/04 ver 4.90 条件分岐命令にjcc(const void *addr);のタイプを追加
2016/01/30 ver 4.89 vpblendvbがymmレジスタをサポートしていなかった(thanks to John Funnell)
2016/01/24 ver 4.88 lea, cmovの16bitレジスタ対応(thanks to whyisthisfieldhere)
2015/08/16 ver 4.87 セグメントセレクタに対応
2015/08/16 ver 4.86 [rip + label]アドレッシングで即値を使うと壊れる(thanks to whyisthisfieldhere)
2015/08/10 ver 4.85 Address::operator==()が間違っている(thanks to inolen)
2015/07/22 ver 4.84 call()がvariadic template対応
2015/05/24 ver 4.83 mobveサポート(thanks to benvanik)
2015/05/24 ver 4.82 F16Cが使えるかどうかの判定追加
2015/04/25 ver 4.81 setSizeが例外を投げる条件を修正(thanks to whyisthisfieldhere)
2015/04/22 ver 4.80 rip相対でLabelのサポート(thanks to whyisthisfieldhere)
2015/01/28 ver 4.71 adcx, adox, cmpxchg, rdseed, stacのサポート
2014/10/14 ver 4.70 MmapAllocatorのサポート
2014/06/13 ver 4.62 VC2014で警告抑制
2014/05/30 ver 4.61 bt, bts, btr, btcのサポート
2014/05/28 ver 4.60 vcvtph2ps, vcvtps2phのサポート
2014/04/11 ver 4.52 rdrandの判定追加
2014/03/25 ver 4.51 参照されなくなったラベルの状態を削除する
2014/03/16 ver 4.50 新しいラベルクラスのサポート
2014/03/05 ver 4.40 VirtualBox上でBMI/enhanced repのサポート判定を間違うことがあるのを修正
2013/12/03 ver 4.30 Reg::cvt8(), cvt16(), cvt32()のサポート
2013/10/16 ver 4.21 ラベルでstd::stringを受け付ける。
2013/07/30 ver 4.20 [break backward compatibility] 従来のReg32eクラスをアドレッシング用のRegExpとReg32, Reg64を表すReg32eに分離
2013/07/04 ver 4.10 [break backward compatibility] Xbyak::Errorの型をenumからclassに変更
2013/06/21 ver 4.02 LABELの指すアドレスを書き込むputL(LABEL)関数の追加。
2013/06/21 ver 4.01 vpsllw, vpslld, vpsllq, vpsraw, vpsrad, vpsrlw, vpsrld, vpsrlq support (ymm, ymm, xmm)
support vpbroadcastb, vpbroadcastw, vpbroadcastd, vpbroadcastq(thanks to Gabest)
2013/05/30 ver 4.00 AVX2, VEX-encoded GPR-instructionをサポート
2013/03/27 ver 3.80 mov(reg, "label");をサポート
2013/03/13 ver 3.76 cqo, jcxz, jecxz, jrcxz追加
2013/01/15 ver 3.75 生成されたコードを修正するためにsetSize()を追加
2013/01/12 ver 3.74 CodeGenerator::reset()とAllocator::useProtect()を追加
2013/01/06 ver 3.73 可能ならunordered_mapを使う
2012/12/04 ver 3.72 eaxなどをCodeGeneratorのメンバ変数に戻す. Xbyak::util::eaxはstatic const変数
2012/11/17 ver 3.71 and_(), or_(), xor_(), not_()をXBYAK_NO_OP_NAMESが定義されていないときでも使えるようにした
2012/11/17 CodeGeneratorのeax, ecx, ptrなどのメンバ変数をstaticにし、const参照をXbyak::utilにも定義
2012/11/09 ver 3.70 and()をand_()にするためのマクロXBYAK_NO_OP_NAMESを追加(thanks to Mattias)
2012/11/01 ver 3.62 add fwait/fnwait/finit/fninit
2012/11/01 ver 3.61 add fldcw/fstcw
2012/05/03 ver 3.60 Allocatorクラスのインタフェースを変更
2012/03/23 ver 3.51 userPtrモードがバグったのを修正
2012/03/19 ver 3.50 AutoGrowモードサポート
2011/11/09 ver 3.05 rip相対の64bitサイズ以外の扱いのバグ修正 / movsxdサポート
2011/08/15 ver 3.04 add(dword [ebp-8], 0xda);などにおけるimm8の扱いのバグ修正(thanks to lolcat)
2011/06/16 ver 3.03 Macのgcc上での__GNUC_PREREQがミスってたのを修正(thanks to t_teruya)
2011/04/28 ver 3.02 Macのgcc上ではxgetbvをdisable
2011/03/24 ver 3.01 fix typo of OSXSAVE
2011/03/23 ver 3.00 vcmpeqpsなどを追加
2011/02/16 ver 2.994 beta add vmovq for 32-bit mode(I forgot it)
2011/02/16 ver 2.993 beta remove cvtReg to avoid thread unsafe
2011/02/10 ver 2.992 beta support one argument syntax for fadd like nasm
2011/02/07 ver 2.991 beta fix pextrw reg, xmm, imm(Thanks to Gabest)
2011/02/04 ver 2.99 beta support AVX
2010/12/08 ver 2.31 fix ptr [rip + 32bit offset], support rtdscp
2010/10/19 ver 2.30 support pclmulqdq, aesdec, aesdeclast, aesenc, aesenclast, aesimc, aeskeygenassist
2010/07/07 ver 2.29 fix call(<label>)
2010/06/17 ver 2.28 move some member functions to public
2010/06/01 ver 2.27 support encoding of mov(reg64, imm) like yasm(not nasm)
2010/05/24 ver 2.26 fix sub(rsp, 1000)
2010/04/26 ver 2.25 add jc/jnc(I forgot to implement them...)
2010/04/16 ver 2.24 change the prototype of rewrite() method
2010/04/15 ver 2.23 fix align() and xbyak_util.h for Mac
2010/02/16 ver 2.22 fix inLocalLabel()/outLocalLabel()
2009/12/09 ver 2.21 support cygwin(gcc 4.3.2)
2009/11/28 ver 2.20 FPUの一部命令サポート
2009/06/25 ver 2.11 64bitモードでの mov(qword[rax], imm); 修正(thanks to Martinさん)
2009/03/10 ver 2.10 jmp/call reg64の冗長なREG.W削除
2009/02/24 ver 2.09 movq reg64, mmx/xmm; movq mmx/xmm, reg64追加
2009/02/13 ver 2.08 movd(xmm7, dword[eax])が0x66を落とすバグ修正(thanks to Gabestさん)
2008/12/30 ver 2.07 call()の相対アドレスが8bit以下のときのバグ修正(thanks to katoさん)
2008/09/18 ver 2.06 @@, @f, @bとラベルの局所化機能追加(thanks to nobu-qさん)
2008/09/18 ver 2.05 ptr [rip + 32bit offset]サポート(thanks to 団子厨(Dango-Chu)さん)
2008/06/03 ver 2.04 align()のポカミス修正。mov(ptr[eax],1);などをエラーに
2008/06/02 ver 2.03 ユーザ定義メモリインタフェースサポート
2008/05/26 ver 2.02 protect()(on Linux)で不正な設定になることがあるのを修正(thanks to sinichiro_hさん)
2008/04/30 ver 2.01 cmpxchg16b, cdqe追加
2008/04/29 ver 2.00 x86/x64-64版公開
2008/04/25 ver 1.90 x64版β公開
2008/04/18 ver 1.12 コード整理
2008/04/14 ver 1.11 コード整理
2008/03/12 ver 1.10 bsf/bsr追加(忘れていた)
2008/02/14 ver 1.09 sub eax, 1234が16bitモードで出力されていたのを修正(thanks to Robertさん)
2007/11/05 ver 1.08 lock, xadd, xchg追加
2007/11/02 ver 1.07 SSSE3/SSE4対応(thanks to 団子厨(Dango-Chu)さん)
2007/09/25 ver 1.06 call((int)関数ポインタ); jmp((int)関数ポインタ);のサポート
2007/08/04 ver 1.05 細かい修正
2007/02/04 後方へのジャンプでT_NEARをつけないときに8bit相対アドレスに入らない
場合に例外が発生しないバグの修正
2007/01/21 [disp]の形のアドレス生成のバグ修正
mov (eax|ax|al, [disp]); mov([disp], eax|ax|al);の短い表現選択
2007/01/17 webページ作成
2007/01/04 公開開始
-----------------------------------------------------------------------------
◎著作権者
光成滋生(MITSUNARI Shigeo, [email protected])
-123
View File
@@ -1,123 +0,0 @@
XBYAK_INC=../xbyak/xbyak.h
BOOST_EXIST=$(shell echo "\#include <boost/spirit/core.hpp>" | (gcc -E - 2>/dev/null) | grep "boost/spirit/core.hpp" >/dev/null && echo "1")
UNAME_M=$(shell uname -m)
ONLY_64BIT=0
ifeq ($(shell uname -s),Darwin)
ONLY_64BIT=1
OS=mac
ifeq ($(UNAME_M),x86_64)
BIT=64
endif
ifeq ($(UNAME_M),i386)
BIT=32
endif
ifeq ($(shell sw_vers -productVersion | cut -c1-4 | sed 's/\.//'),105)
ifeq ($(shell sysctl -n hw.cpu64bit_capable),1)
BIT=64
endif
endif
else
BIT=32
ifeq ($(UNAME_M),x86_64)
BIT=64
endif
ifeq ($(UNAME_M),amd64)
BIT=64
endif
endif
ifeq ($(BIT),64)
TARGET += test64 bf64 memfunc64 test_util64 jmp_table64
ifeq ($(BOOST_EXIST),1)
TARGET += calc64 #calc2_64
endif
endif
ifneq ($(OS),mac)
TARGET += static_buf64
endif
ifneq ($(ONLY_64BIT),1)
TARGET += test quantize bf toyvm test_util memfunc static_buf jmp_table
ifeq ($(BOOST_EXIST),1)
TARGET += calc #calc2
endif
endif
all: $(TARGET)
CFLAGS_WARN=-Wall -Wextra -Wformat=2 -Wcast-qual -Wcast-align -Wwrite-strings -Wfloat-equal -Wpointer-arith #-pedantic
CFLAGS=-g -O2 -fomit-frame-pointer -Wall -I../ $(CFLAGS_WARN)
test:
$(CXX) $(CFLAGS) test0.cpp -o $@ -m32
quantize:
$(CXX) $(CFLAGS) quantize.cpp -o $@ -m32
calc:
$(CXX) $(CFLAGS) calc.cpp -o $@ -m32
calc64:
$(CXX) $(CFLAGS) calc.cpp -o $@ -m64
calc2:
$(CXX) $(CFLAGS) calc2.cpp -o $@ -m32
calc2_64:
$(CXX) $(CFLAGS) calc2.cpp -o $@ -m64
bf:
$(CXX) $(CFLAGS) bf.cpp -o $@ -m32
bf64:
$(CXX) $(CFLAGS) bf.cpp -o $@ -m64
memfunc:
$(CXX) $(CFLAGS) memfunc.cpp -o $@ -m32
memfunc64:
$(CXX) $(CFLAGS) memfunc.cpp -o $@ -m64
toyvm:
$(CXX) $(CFLAGS) toyvm.cpp -o $@ -m32
test64:
$(CXX) $(CFLAGS) test0.cpp -o $@ -m64
test_util:
$(CXX) $(CFLAGS) test_util.cpp -o $@ -m32
test_util64:
$(CXX) $(CFLAGS) test_util.cpp -o $@ -m64
static_buf:
$(CXX) $(CFLAGS) static_buf.cpp -o $@ -m32
static_buf64:
$(CXX) $(CFLAGS) static_buf.cpp -o $@ -m64
jmp_table:
$(CXX) $(CFLAGS) jmp_table.cpp -o $@ -m32
jmp_table64:
$(CXX) $(CFLAGS) jmp_table.cpp -o $@ -m64
profiler: profiler.cpp ../xbyak/xbyak_util.h
$(CXX) $(CFLAGS) profiler.cpp -o $@
profiler-vtune: profiler.cpp ../xbyak/xbyak_util.h
$(CXX) $(CFLAGS) profiler.cpp -o $@ -DXBYAK_USE_VTUNE -I /opt/intel/vtune_amplifier/include/ -L /opt/intel/vtune_amplifier/lib64 -ljitprofiling -ldl
clean:
rm -rf *.o $(TARGET) *.exe profiler profiler-vtune
test : test0.cpp $(XBYAK_INC)
test64: test0.cpp $(XBYAK_INC)
quantize : quantize.cpp $(XBYAK_INC)
calc : calc.cpp $(XBYAK_INC)
calc64 : calc.cpp $(XBYAK_INC)
calc2 : calc2.cpp $(XBYAK_INC)
calc2_64 : calc2.cpp $(XBYAK_INC)
bf : bf.cpp $(XBYAK_INC)
bf64 : bf.cpp $(XBYAK_INC)
memfunc : memfunc.cpp $(XBYAK_INC)
memfunc64 : memfunc.cpp $(XBYAK_INC)
toyvm : toyvm.cpp $(XBYAK_INC)
static_buf: static_buf.cpp $(XBYAK_INC)
static_buf64: static_buf.cpp $(XBYAK_INC)
test_util : test_util.cpp $(XBYAK_INC) ../xbyak/xbyak_util.h
test_util2 : test_util.cpp $(XBYAK_INC) ../xbyak/xbyak_util.h
jmp_table: jmp_table.cpp $(XBYAK_INC)
jmp_table64: jmp_table.cpp $(XBYAK_INC)
-211
View File
@@ -1,211 +0,0 @@
#define XBYAK_NO_OP_NAMES
#include "xbyak/xbyak.h"
#include <stdio.h>
#include <stdlib.h>
#include <stack>
#include <fstream>
#ifdef _MSC_VER
#pragma warning(disable : 4996) // scanf
#define snprintf _snprintf_s
#endif
class Brainfuck : public Xbyak::CodeGenerator {
public:
int getContinuousChar(std::istream& is, char c)
{
int count = 1;
char p;
while (is >> p) {
if (p != c) break;
count++;
}
is.unget();
return count;
}
Brainfuck(std::istream& is) : CodeGenerator(100000)
{
// void (*)(void* putchar, void* getchar, int *stack)
using namespace Xbyak;
#ifdef XBYAK32
const Reg32& pPutchar(esi);
const Reg32& pGetchar(edi);
const Reg32& stack(ebp);
const Address cur = dword [stack];
push(ebp); // stack
push(esi);
push(edi);
const int P_ = 4 * 3;
mov(pPutchar, ptr[esp + P_ + 4]); // putchar
mov(pGetchar, ptr[esp + P_ + 8]); // getchar
mov(stack, ptr[esp + P_ + 12]); // stack
#elif defined(XBYAK64_WIN)
const Reg64& pPutchar(rsi);
const Reg64& pGetchar(rdi);
const Reg64& stack(rbp); // stack
const Address cur = dword [stack];
push(rsi);
push(rdi);
push(rbp);
mov(pPutchar, rcx); // putchar
mov(pGetchar, rdx); // getchar
mov(stack, r8); // stack
#else
const Reg64& pPutchar(rbx);
const Reg64& pGetchar(rbp);
const Reg64& stack(r12); // stack
const Address cur = dword [stack];
push(rbx);
push(rbp);
push(r12);
mov(pPutchar, rdi); // putchar
mov(pGetchar, rsi); // getchar
mov(stack, rdx); // stack
#endif
std::stack<Label> labelF, labelB;
char c;
while (is >> c) {
switch (c) {
case '+':
case '-':
{
int count = getContinuousChar(is, c);
if (count == 1) {
c == '+' ? inc(cur) : dec(cur);
} else {
add(cur, (c == '+' ? count : -count));
}
}
break;
case '>':
case '<':
{
int count = getContinuousChar(is, c);
add(stack, 4 * (c == '>' ? count : -count));
}
break;
case '.':
#ifdef XBYAK32
push(cur);
call(pPutchar);
pop(eax);
#elif defined(XBYAK64_WIN)
mov(ecx, cur);
sub(rsp, 32);
call(pPutchar);
add(rsp, 32);
#else
mov(edi, cur);
call(pPutchar);
#endif
break;
case ',':
#if defined(XBYAK32) || defined(XBYAK64_GCC)
call(pGetchar);
#elif defined(XBYAK64_WIN)
sub(rsp, 32);
call(pGetchar);
add(rsp, 32);
#endif
mov(cur, eax);
break;
case '[':
{
Label B = L();
labelB.push(B);
mov(eax, cur);
test(eax, eax);
Label F;
jz(F, T_NEAR);
labelF.push(F);
}
break;
case ']':
{
Label B = labelB.top(); labelB.pop();
jmp(B);
Label F = labelF.top(); labelF.pop();
L(F);
}
break;
default:
break;
}
}
#ifdef XBYAK32
pop(edi);
pop(esi);
pop(ebp);
#elif defined(XBYAK64_WIN)
pop(rbp);
pop(rdi);
pop(rsi);
#else
pop(r12);
pop(rbp);
pop(rbx);
#endif
ret();
}
};
void dump(const uint8_t *code, size_t size)
{
puts("#include <stdio.h>\nstatic int stack[128 * 1024];");
#ifdef _MSC_VER
printf("static __declspec(align(4096)) ");
#else
printf("static __attribute__((aligned(4096)))");
#endif
puts("const unsigned char code[] = {");
for (size_t i = 0; i < size; i++) {
printf("0x%02x,", code[i]); if ((i % 16) == 15) putchar('\n');
}
puts("\n};");
#ifdef _MSC_VER
puts("#include <windows.h>");
#else
puts("#include <unistd.h>");
puts("#include <sys/mman.h>");
#endif
puts("int main()\n{");
#ifdef _MSC_VER
puts("\tDWORD oldProtect;");
puts("\tVirtualProtect((void*)code, sizeof(code), PAGE_EXECUTE_READWRITE, &oldProtect);");
#else
puts("\tlong pageSize = sysconf(_SC_PAGESIZE) - 1;");
puts("\tmprotect((void*)code, (sizeof(code) + pageSize) & ~pageSize, PROT_READ | PROT_EXEC);");
#endif
puts(
"\t((void (*)(void*, void*, int *))code)((void*)putchar, (void*)getchar, stack);\n"
"}"
);
}
int main(int argc, char *argv[])
{
#ifdef XBYAK32
fprintf(stderr, "32bit mode\n");
#else
fprintf(stderr, "64bit mode\n");
#endif
if (argc == 1) {
fprintf(stderr, "bf filename.bf [0|1]\n");
return 1;
}
std::ifstream ifs(argv[1]);
int mode = argc == 3 ? atoi(argv[2]) : 0;
try {
Brainfuck bf(ifs);
if (mode == 0) {
static int stack[128 * 1024];
bf.getCode<void (*)(const void*, const void*, int *)>()(reinterpret_cast<const void*>(putchar), reinterpret_cast<const void*>(getchar), stack);
} else {
dump(bf.getCode(), bf.getSize());
}
} catch (std::exception& e) {
printf("ERR:%s\n", e.what());
} catch (...) {
printf("unknown error\n");
}
}
-228
View File
@@ -1,228 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{654BD79B-59D3-4B10-BBAA-158BAB272828}</ProjectGuid>
<WindowsTargetPlatformVersion>10.0.17763.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<PlatformToolset>v141</PlatformToolset>
<UseOfMfc>false</UseOfMfc>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<PlatformToolset>v141</PlatformToolset>
<UseOfMfc>false</UseOfMfc>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<PlatformToolset>v141</PlatformToolset>
<UseOfMfc>false</UseOfMfc>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<PlatformToolset>v141</PlatformToolset>
<UseOfMfc>false</UseOfMfc>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC60.props" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC60.props" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC60.props" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC60.props" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup>
<_ProjectFileVersion>15.0.27924.0</_ProjectFileVersion>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
<IntDir>$(ProjectName)\$(Configuration)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
<IntDir>$(ProjectName)\$(Configuration)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
<IntDir>$(ProjectName)\$(Platform)\$(Configuration)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
<IntDir>$(ProjectName)\$(Platform)\$(Configuration)\</IntDir>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Midl>
<TypeLibraryName>.\Release/bf.tlb</TypeLibraryName>
<HeaderFileName />
</Midl>
<ClCompile>
<Optimization>MaxSpeed</Optimization>
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
<AdditionalIncludeDirectories>../;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<StringPooling>true</StringPooling>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<FunctionLevelLinking>true</FunctionLevelLinking>
<PrecompiledHeaderOutputFile>.\Release/bf.pch</PrecompiledHeaderOutputFile>
<WarningLevel>Level4</WarningLevel>
<SuppressStartupBanner>true</SuppressStartupBanner>
</ClCompile>
<ResourceCompile>
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<Culture>0x0411</Culture>
</ResourceCompile>
<Link>
<SuppressStartupBanner>true</SuppressStartupBanner>
<SubSystem>Console</SubSystem>
<RandomizedBaseAddress>false</RandomizedBaseAddress>
<DataExecutionPrevention />
<TargetMachine>MachineX86</TargetMachine>
</Link>
<Bscmake>
<SuppressStartupBanner>true</SuppressStartupBanner>
</Bscmake>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Midl>
<TypeLibraryName>.\Debug/bf.tlb</TypeLibraryName>
<HeaderFileName />
</Midl>
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>../;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MinimalRebuild>true</MinimalRebuild>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<PrecompiledHeaderOutputFile>.\Debug/bf.pch</PrecompiledHeaderOutputFile>
<WarningLevel>Level4</WarningLevel>
<SuppressStartupBanner>true</SuppressStartupBanner>
</ClCompile>
<ResourceCompile>
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<Culture>0x0411</Culture>
</ResourceCompile>
<Link>
<SuppressStartupBanner>true</SuppressStartupBanner>
<GenerateDebugInformation>true</GenerateDebugInformation>
<ProgramDatabaseFile>.\Debug/bf.pdb</ProgramDatabaseFile>
<SubSystem>Console</SubSystem>
<RandomizedBaseAddress>false</RandomizedBaseAddress>
<DataExecutionPrevention />
<TargetMachine>MachineX86</TargetMachine>
</Link>
<Bscmake>
<SuppressStartupBanner>true</SuppressStartupBanner>
</Bscmake>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Midl>
<TargetEnvironment>X64</TargetEnvironment>
<TypeLibraryName>.\Release/bf.tlb</TypeLibraryName>
<HeaderFileName />
</Midl>
<ClCompile>
<Optimization>MaxSpeed</Optimization>
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
<AdditionalIncludeDirectories>../;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<StringPooling>true</StringPooling>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<FunctionLevelLinking>true</FunctionLevelLinking>
<PrecompiledHeaderOutputFile>.\Release/bf.pch</PrecompiledHeaderOutputFile>
<WarningLevel>Level4</WarningLevel>
<SuppressStartupBanner>true</SuppressStartupBanner>
</ClCompile>
<ResourceCompile>
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<Culture>0x0411</Culture>
</ResourceCompile>
<Link>
<SuppressStartupBanner>true</SuppressStartupBanner>
<SubSystem>Console</SubSystem>
<RandomizedBaseAddress>false</RandomizedBaseAddress>
<DataExecutionPrevention />
<TargetMachine>MachineX64</TargetMachine>
</Link>
<Bscmake>
<SuppressStartupBanner>true</SuppressStartupBanner>
</Bscmake>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Midl>
<TargetEnvironment>X64</TargetEnvironment>
<TypeLibraryName>.\Debug/bf.tlb</TypeLibraryName>
<HeaderFileName />
</Midl>
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>../;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MinimalRebuild>true</MinimalRebuild>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<PrecompiledHeaderOutputFile>.\Debug/bf.pch</PrecompiledHeaderOutputFile>
<WarningLevel>Level4</WarningLevel>
<SuppressStartupBanner>true</SuppressStartupBanner>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
</ClCompile>
<ResourceCompile>
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<Culture>0x0411</Culture>
</ResourceCompile>
<Link>
<SuppressStartupBanner>true</SuppressStartupBanner>
<GenerateDebugInformation>true</GenerateDebugInformation>
<ProgramDatabaseFile>.\Debug/bf.pdb</ProgramDatabaseFile>
<SubSystem>Console</SubSystem>
<RandomizedBaseAddress>false</RandomizedBaseAddress>
<DataExecutionPrevention />
<TargetMachine>MachineX64</TargetMachine>
</Link>
<Bscmake>
<SuppressStartupBanner>true</SuppressStartupBanner>
</Bscmake>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="bf.cpp" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
-229
View File
@@ -1,229 +0,0 @@
/*
@author herumi
tiny calculator
This program generates a function to calc the value of
polynomial given by user in run-time.
use boost::spirit::classic
see calc2.cpp for new version of boost::spirit
*/
#include <stdio.h>
#include <sstream>
#include <map>
#define XBYAK_NO_OP_NAMES
#include "xbyak/xbyak.h"
#ifdef _MSC_VER
#pragma warning(disable : 4127) // for boost(constant condition)
#pragma warning(disable : 4512) // for boost
#endif
#include <boost/spirit/include/classic_file_iterator.hpp>
#include <boost/spirit/include/classic_core.hpp>
#include <boost/bind.hpp>
enum Error {
UNDEFINED_VARIABLE = 1
};
/*
JIT assemble of given polynomial for VC or gcc
*/
class FuncGen : public Xbyak::CodeGenerator {
public:
typedef std::map<std::string, int> Map;
private:
enum {
MAX_CONST_NUM = 32
};
double constTbl_[MAX_CONST_NUM];
size_t constTblPos_;
int regIdx_;
Map varMap_; // map var name to index
#ifdef XBYAK32
const Xbyak::Reg32& valTbl_;
const Xbyak::Reg32& tbl_;
#else
const Xbyak::Reg64& valTbl_;
const Xbyak::Reg64& tbl_;
#endif
public:
/*
@param y [out] the value of f(var)
@param var [in] table of input variables
func(double *y, const double var[]);
@note func does not return double to avoid difference of compiler
*/
FuncGen(const std::vector<std::string>& varTbl)
: constTblPos_(0)
, regIdx_(-1)
#ifdef XBYAK32
, valTbl_(eax)
, tbl_(edx)
#elif defined(XBYAK64_WIN)
, valTbl_(rcx)
, tbl_(rdx)
#else
, valTbl_(rdi)
, tbl_(rsi)
#endif
{
#ifdef XBYAK32
mov(valTbl_, ptr[esp+8]); // eax == varTbl
mov(tbl_, (size_t)constTbl_);
#else
#ifdef XBYAK64_WIN
movaps(ptr [rsp + 8], xm6); // save xm6, xm7
movaps(ptr [rsp + 8 + 16], xm7);
#endif
mov(tbl_, (size_t)constTbl_);
#endif
for (int i = 0, n = static_cast<int>(varTbl.size()); i < n; i++) {
varMap_[varTbl[i]] = i;
}
}
// use edx
void genPush(double n)
{
if (constTblPos_ >= MAX_CONST_NUM) throw;
constTbl_[constTblPos_] = n;
if (regIdx_ == 7) throw;
movsd(Xbyak::Xmm(++regIdx_), ptr[tbl_ + (int)(constTblPos_ * sizeof(double))]);
constTblPos_++;
}
// use eax
void genVal(const char *begin, const char *end)
{
std::string var(begin, end);
if (varMap_.find(var) == varMap_.end()) throw UNDEFINED_VARIABLE;
if (regIdx_ == 7) throw;
movsd(Xbyak::Xmm(++regIdx_), ptr[valTbl_ + varMap_[var] * sizeof(double)]);
}
void genAdd(const char*, const char*)
{
addsd(Xbyak::Xmm(regIdx_ - 1), Xbyak::Xmm(regIdx_)); regIdx_--;
}
void genSub(const char*, const char*)
{
subsd(Xbyak::Xmm(regIdx_ - 1), Xbyak::Xmm(regIdx_)); regIdx_--;
}
void genMul(const char*, const char*)
{
mulsd(Xbyak::Xmm(regIdx_ - 1), Xbyak::Xmm(regIdx_)); regIdx_--;
}
void genDiv(const char*, const char*)
{
divsd(Xbyak::Xmm(regIdx_ - 1), Xbyak::Xmm(regIdx_)); regIdx_--;
}
void complete()
{
#ifdef XBYAK32
mov(eax, ptr [esp + 4]); // eax = valTbl
movsd(ptr [eax], xm0);
#else
#ifdef XBYAK64_WIN
movaps(xm6, ptr [rsp + 8]);
movaps(xm7, ptr [rsp + 8 + 16]);
#endif
#endif
ret();
}
};
struct Grammar : public boost::spirit::classic::grammar<Grammar> {
FuncGen& f_;
Grammar(FuncGen& f) : f_(f) { }
template<typename ScannerT>
struct definition {
boost::spirit::classic::rule<ScannerT> poly0, poly1, poly2, var;
definition(const Grammar& self)
{
using namespace boost;
using namespace boost::spirit::classic;
poly0 = poly1 >> *(('+' >> poly1)[bind(&FuncGen::genAdd, ref(self.f_), _1, _2)]
| ('-' >> poly1)[bind(&FuncGen::genSub, ref(self.f_), _1, _2)]);
poly1 = poly2 >> *(('*' >> poly2)[bind(&FuncGen::genMul, ref(self.f_), _1, _2)]
| ('/' >> poly2)[bind(&FuncGen::genDiv, ref(self.f_), _1, _2)]);
var = (+alpha_p)[bind(&FuncGen::genVal, ref(self.f_), _1, _2)];
poly2 = real_p[bind(&FuncGen::genPush, ref(self.f_), _1)]
| var
| '(' >> poly0 >> ')';
}
const boost::spirit::classic::rule<ScannerT>& start() const { return poly0; }
};
};
void put(const std::vector<double>& x)
{
for (size_t i = 0, n = x.size(); i < n; i++) {
if (i > 0) printf(", ");
printf("%f", x[i]);
}
}
int main(int argc, char *argv[])
{
if (argc <= 2) {
fprintf(stderr, "calc \"var1 var2 ...\" \"function of var\"\n");
fprintf(stderr, "eg. calc x \"x*x\"\n");
fprintf(stderr, "eg. calc \"x y z\" \"x*x + y - z\"\n");
return 1;
}
const char *poly = argv[2];
try {
std::vector<std::string> varTbl;
// get varTbl from argv[1]
{
std::istringstream is(argv[1]);
int i = 0;
printf("varTbl = { ");
while (is) {
std::string var;
is >> var;
if (var.empty()) break;
printf("%s:%d, ", var.c_str(), i);
varTbl.push_back(var);
i++;
}
printf("}\n");
}
FuncGen funcGen(varTbl);
Grammar calc(funcGen);
boost::spirit::classic::parse_info<> r = parse(poly, calc, boost::spirit::classic::space_p);
if (!r.full) {
printf("err poly=%s\n", poly);
return 1;
}
funcGen.complete();
std::vector<double> valTbl;
valTbl.resize(varTbl.size());
#ifdef XBYAK32
puts("32bit mode");
void (*func)(double *ret, const double *valTbl) = funcGen.getCode<void (*)(double *, const double*)>();
#else
puts("64bit mode");
double (*func)(const double *valTbl) = funcGen.getCode<double (*)(const double*)>();
#endif
for (int i = 0; i < 10; i++) {
for (size_t j = 0, n = valTbl.size(); j < n; j++) {
valTbl[j] = rand() % 7;
}
double y;
#ifdef XBYAK32
func(&y, &valTbl[0]);
#else
y = func(&valTbl[0]);
#endif
printf("f("); put(valTbl); printf(")=%f\n", y);
}
} catch (std::exception& e) {
printf("ERR:%s\n", e.what());
} catch (Error err) {
printf("ERR:%d\n", err);
} catch (...) {
printf("unknown error\n");
}
return 0;
}
-228
View File
@@ -1,228 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{5FDDFAA6-B947-491D-A17E-BBD863846579}</ProjectGuid>
<WindowsTargetPlatformVersion>10.0.17763.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<PlatformToolset>v141</PlatformToolset>
<UseOfMfc>false</UseOfMfc>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<PlatformToolset>v141</PlatformToolset>
<UseOfMfc>false</UseOfMfc>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<PlatformToolset>v141</PlatformToolset>
<UseOfMfc>false</UseOfMfc>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<PlatformToolset>v141</PlatformToolset>
<UseOfMfc>false</UseOfMfc>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC60.props" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC60.props" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC60.props" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC60.props" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup>
<_ProjectFileVersion>15.0.27924.0</_ProjectFileVersion>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
<IntDir>$(ProjectName)\$(Configuration)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
<IntDir>$(ProjectName)\$(Configuration)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
<IntDir>$(ProjectName)\$(Platform)\$(Configuration)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
<IntDir>$(ProjectName)\$(Platform)\$(Configuration)\</IntDir>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Midl>
<TypeLibraryName>.\Release/calc.tlb</TypeLibraryName>
<HeaderFileName />
</Midl>
<ClCompile>
<Optimization>MaxSpeed</Optimization>
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
<AdditionalIncludeDirectories>../;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<StringPooling>true</StringPooling>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<FunctionLevelLinking>true</FunctionLevelLinking>
<PrecompiledHeaderOutputFile>.\Release/calc.pch</PrecompiledHeaderOutputFile>
<WarningLevel>Level4</WarningLevel>
<SuppressStartupBanner>true</SuppressStartupBanner>
</ClCompile>
<ResourceCompile>
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<Culture>0x0411</Culture>
</ResourceCompile>
<Link>
<SuppressStartupBanner>true</SuppressStartupBanner>
<SubSystem>Console</SubSystem>
<RandomizedBaseAddress>false</RandomizedBaseAddress>
<DataExecutionPrevention />
<TargetMachine>MachineX86</TargetMachine>
</Link>
<Bscmake>
<SuppressStartupBanner>true</SuppressStartupBanner>
</Bscmake>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Midl>
<TypeLibraryName>.\Debug/calc.tlb</TypeLibraryName>
<HeaderFileName />
</Midl>
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>../;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MinimalRebuild>true</MinimalRebuild>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<PrecompiledHeaderOutputFile>.\Debug/calc.pch</PrecompiledHeaderOutputFile>
<WarningLevel>Level4</WarningLevel>
<SuppressStartupBanner>true</SuppressStartupBanner>
</ClCompile>
<ResourceCompile>
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<Culture>0x0411</Culture>
</ResourceCompile>
<Link>
<SuppressStartupBanner>true</SuppressStartupBanner>
<GenerateDebugInformation>true</GenerateDebugInformation>
<ProgramDatabaseFile>.\Debug/calc.pdb</ProgramDatabaseFile>
<SubSystem>Console</SubSystem>
<RandomizedBaseAddress>false</RandomizedBaseAddress>
<DataExecutionPrevention />
<TargetMachine>MachineX86</TargetMachine>
</Link>
<Bscmake>
<SuppressStartupBanner>true</SuppressStartupBanner>
</Bscmake>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Midl>
<TargetEnvironment>X64</TargetEnvironment>
<TypeLibraryName>.\Release/calc.tlb</TypeLibraryName>
<HeaderFileName />
</Midl>
<ClCompile>
<Optimization>MaxSpeed</Optimization>
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
<AdditionalIncludeDirectories>../;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<StringPooling>true</StringPooling>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<FunctionLevelLinking>true</FunctionLevelLinking>
<PrecompiledHeaderOutputFile>.\Release/calc.pch</PrecompiledHeaderOutputFile>
<WarningLevel>Level4</WarningLevel>
<SuppressStartupBanner>true</SuppressStartupBanner>
</ClCompile>
<ResourceCompile>
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<Culture>0x0411</Culture>
</ResourceCompile>
<Link>
<SuppressStartupBanner>true</SuppressStartupBanner>
<SubSystem>Console</SubSystem>
<RandomizedBaseAddress>false</RandomizedBaseAddress>
<DataExecutionPrevention />
<TargetMachine>MachineX64</TargetMachine>
</Link>
<Bscmake>
<SuppressStartupBanner>true</SuppressStartupBanner>
</Bscmake>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Midl>
<TargetEnvironment>X64</TargetEnvironment>
<TypeLibraryName>.\Debug/calc.tlb</TypeLibraryName>
<HeaderFileName />
</Midl>
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>../;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MinimalRebuild>true</MinimalRebuild>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<PrecompiledHeaderOutputFile>.\Debug/calc.pch</PrecompiledHeaderOutputFile>
<WarningLevel>Level4</WarningLevel>
<SuppressStartupBanner>true</SuppressStartupBanner>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
</ClCompile>
<ResourceCompile>
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<Culture>0x0411</Culture>
</ResourceCompile>
<Link>
<SuppressStartupBanner>true</SuppressStartupBanner>
<GenerateDebugInformation>true</GenerateDebugInformation>
<ProgramDatabaseFile>.\Debug/calc.pdb</ProgramDatabaseFile>
<SubSystem>Console</SubSystem>
<RandomizedBaseAddress>false</RandomizedBaseAddress>
<DataExecutionPrevention />
<TargetMachine>MachineX64</TargetMachine>
</Link>
<Bscmake>
<SuppressStartupBanner>true</SuppressStartupBanner>
</Bscmake>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="calc.cpp" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
-302
View File
@@ -1,302 +0,0 @@
/*
@author herumi
tiny calculator 2
This program generates a function to calc the value of
polynomial given by user in run-time.
use boost::spirit::qi
*/
#ifdef _WIN32
#pragma warning(disable : 4127) // for boost(constant condition)
#pragma warning(disable : 4512) // for boost
#pragma warning(disable : 4819)
#endif
#include <boost/config/warning_disable.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_container.hpp>
#include <boost/spirit/include/phoenix_bind.hpp>
#include <boost/timer.hpp>
#include <stdio.h>
#include <assert.h>
#include <string>
#include <vector>
#define XBYAK_NO_OP_NAMES
#include "xbyak/xbyak.h"
enum Operand {
OpAdd,
OpSub,
OpMul,
OpDiv,
OpNeg,
OpImm,
OpVarX
};
struct Code {
Operand op_;
double val_;
Code(Operand op)
: op_(op)
, val_(0)
{
}
Code(double val)
: op_(OpImm)
, val_(val)
{
}
};
typedef std::vector<Code> CodeSet;
struct Vm {
CodeSet code_;
double operator()(double x) const
{
const size_t maxStack = 16;
double stack[maxStack];
double *p = stack;
CodeSet::const_iterator pc = code_.begin();
while (pc != code_.end()) {
switch (pc->op_) {
case OpVarX:
*p++ = x;
break;
case OpImm:
*p++ = pc->val_;
break;
case OpNeg:
p[-1] = -p[-1];
break;
case OpAdd:
--p;
p[-1] += p[0];
break;
case OpSub:
--p;
p[-1] -= p[0];
break;
case OpMul:
--p;
p[-1] *= p[0];
break;
case OpDiv:
--p;
p[-1] /= p[0];
break;
}
++pc;
assert(p < stack + maxStack);
}
return p[-1];
}
};
class Jit : public Xbyak::CodeGenerator {
private:
enum {
MAX_CONST_NUM = 32
};
MIE_ALIGN(16) double constTbl_[MAX_CONST_NUM];
Xbyak::uint64_t negConst_;
size_t constTblPos_;
#ifdef XBYAK32
const Xbyak::Reg32& varTbl_;
const Xbyak::Reg32& tbl_;
#else
const Xbyak::Reg64& tbl_;
#endif
int regIdx_;
public:
/*
double jit(double x);
@note 32bit: x : [esp+4], return fp0
64bit: x [rcx](win), xmm0(gcc), return xmm0
*/
Jit()
: negConst_(Xbyak::uint64_t(1) << 63)
, constTblPos_(0)
#ifdef XBYAK32
, varTbl_(eax)
, tbl_(edx)
#elif defined(XBYAK64_WIN)
, tbl_(rcx)
#else
, tbl_(rdi)
#endif
, regIdx_(-1)
{
#ifdef XBYAK32
lea(varTbl_, ptr [esp+4]);
#else
#ifdef XBYAK64_WIN
movaps(ptr [rsp + 8], xm6); // save xm6, xm7
movaps(ptr [rsp + 8 + 16], xm7);
#endif
movaps(xm7, xm0); // save xm0
#endif
mov(tbl_, (size_t)constTbl_);
}
void genPush(double n)
{
if (constTblPos_ >= MAX_CONST_NUM) throw;
constTbl_[constTblPos_] = n;
if (regIdx_ == 7) throw;
movsd(Xbyak::Xmm(++regIdx_), ptr[tbl_ + constTblPos_ * sizeof(double)]);
constTblPos_++;
}
void genVarX()
{
#ifdef XBYAK32
if (regIdx_ == 7) throw;
movsd(Xbyak::Xmm(++regIdx_), ptr[varTbl_]);
#else
if (regIdx_ == 6) throw;
movsd(Xbyak::Xmm(++regIdx_), xm7);
#endif
}
void genAdd()
{
addsd(Xbyak::Xmm(regIdx_ - 1), Xbyak::Xmm(regIdx_)); regIdx_--;
}
void genSub()
{
subsd(Xbyak::Xmm(regIdx_ - 1), Xbyak::Xmm(regIdx_)); regIdx_--;
}
void genMul()
{
mulsd(Xbyak::Xmm(regIdx_ - 1), Xbyak::Xmm(regIdx_)); regIdx_--;
}
void genDiv()
{
divsd(Xbyak::Xmm(regIdx_ - 1), Xbyak::Xmm(regIdx_)); regIdx_--;
}
void genNeg()
{
xorpd(Xbyak::Xmm(regIdx_), ptr [tbl_ + MAX_CONST_NUM * sizeof(double)]);
}
void complete()
{
#ifdef XBYAK32
sub(esp, 8);
movsd(ptr [esp], xm0);
fld(qword [esp]);
add(esp, 8);
#else
#ifdef XBYAK64_WIN
movaps(xm6, ptr [rsp + 8]);
movaps(xm7, ptr [rsp + 8 + 16]);
#endif
#endif
ret();
}
};
template<typename Iterator>
struct Parser : boost::spirit::qi::grammar<Iterator, boost::spirit::ascii::space_type> {
boost::spirit::qi::rule<Iterator, boost::spirit::ascii::space_type> expression, term, factor;
CodeSet& code_;
Parser(CodeSet& code)
: Parser::base_type(expression)
, code_(code)
{
namespace qi = boost::spirit::qi;
using namespace qi::labels;
using boost::phoenix::ref;
using boost::phoenix::push_back;
expression = term >> *(('+' > term[push_back(ref(code_), OpAdd)])
| ('-' > term[push_back(ref(code_), OpSub)]));
term = factor >> *(('*' > factor[push_back(ref(code_), OpMul)])
| ('/' > factor[push_back(ref(code_), OpDiv)]));
factor = qi::double_[push_back(ref(code_), _1)]
| qi::lit('x')[push_back(ref(code_), OpVarX)]
| ('(' > expression > ')')
| ('-' > factor[push_back(ref(code_), OpNeg)])
| ('+' > factor);
}
};
template<typename Iterator>
struct ParserJit : boost::spirit::qi::grammar<Iterator, boost::spirit::ascii::space_type> {
boost::spirit::qi::rule<Iterator, boost::spirit::ascii::space_type> expression, term, factor;
Jit code_;
ParserJit()
: ParserJit::base_type(expression)
{
namespace qi = boost::spirit::qi;
using namespace qi::labels;
using boost::phoenix::ref;
using boost::phoenix::push_back;
using boost::phoenix::bind;
expression = term >> *(('+' > term[bind(&Jit::genAdd, ref(code_))])
| ('-' > term[bind(&Jit::genSub, ref(code_))]));
term = factor >> *(('*' > factor[bind(&Jit::genMul, ref(code_))])
| ('/' > factor[bind(&Jit::genDiv, ref(code_))]));
factor = qi::double_[bind(&Jit::genPush, ref(code_), _1)]
| qi::lit('x')[bind(&Jit::genVarX, ref(code_))]
| ('(' > expression > ')')
| ('-' > factor[bind(&Jit::genNeg, ref(code_))])
| ('+' > factor);
}
};
template<class Func>
void Test(const char *msg, const Func& f)
{
printf("%s:", msg);
boost::timer t;
double sum = 0;
for (double x = 0; x < 1000; x += 0.0001) {
sum += f(x);
}
printf("sum=%f, %fsec\n", sum, t.elapsed());
}
int main(int argc, char *argv[])
{
if (argc < 2) {
fprintf(stderr, "input formula\n");
return 1;
}
const std::string str(argv[1]);
try {
Vm vm;
Parser<std::string::const_iterator> parser(vm.code_);
ParserJit<std::string::const_iterator> parserJit;
const std::string::const_iterator end = str.end();
std::string::const_iterator i = str.begin();
if (!phrase_parse(i, end, parser, boost::spirit::ascii::space) || i != end) {
puts("err 1");
return 1;
}
printf("ret=%f\n", vm(2.3));
i = str.begin();
if (!phrase_parse(i, end, parserJit, boost::spirit::ascii::space) || i != end) {
puts("err 2");
return 1;
}
parserJit.code_.complete();
double (*jit)(double) = parserJit.code_.getCode<double (*)(double)>();
Test("VM ", vm);
Test("JIT", jit);
} catch (...) {
fprintf(stderr, "err\n");
}
}
-5
View File
@@ -1,5 +0,0 @@
>>++++++++[->++++++++<]>>>>+++++++++[->++++++++++<]>[<<,[->+<<+<<+>>>]<<<[
->>>+<<<]>>>>>[->+>>+<<<]>[<<[->+>>+<<<]>>>[-<<<+>>>]<<[[-]<->]>-]>>[-<<<+
>>>]<<<<<<<[-<+<<+>>>]<[>>[-<+<<+>>>]<<<[->>>+<<<]>>[[-]>-<]<-]<<[->>>+<<<
]>>>>><[[-]>++++++++++++++++++++++++++++++++>[[-]<------------------------
-------->]<<]>>[-]<.>>]
-19
View File
@@ -1,19 +0,0 @@
++++++[->++++>>+>+>-<<<<<]>
[<++++>>+++>++++>>+++>+++++>+++++>>>>>>++>>++<<<<<<<<<<<<<<-]
<++++>+++>-->+++>->>--->++>>>+++++[->++>++<<]<<<<<<<<<<
[->
-[>>>>>>>]>[<+++>.>.>>>>..>>>+<]<<<<<
-[>>>>]>[<+++++>.>.>..>>>+<]>>>>
+<-[<<<]<[
[-<<+>>]>>>+>+<<<<<<[->>+>+>-<<<<]<
]>>
[[-]<]>[
>>>[>.<<.<<<]<[.<<<<]>
]
>.<<<<<<<<<<<
]
-3
View File
@@ -1,3 +0,0 @@
>+++++++++[<++++++++>-]<.>+++++++[<++++>-]<+.+++++++..+++.[-]>++++++++[<++
++>-]<.>+++++++++++[<+++++>-]<.>++++++++[<+++>-]<.+++.------.--------.[-]>
++++++++[<++++>-]<+.[-]++++++++++.
-128
View File
@@ -1,128 +0,0 @@
/*
sample of move(reg, LABEL);, L(LABEL), putL(LABEL);
*/
#include <stdio.h>
#define XBYAK_NO_OP_NAMES
#include <xbyak/xbyak.h>
const int expectTbl[] = {
5, 9, 12
};
struct Code : Xbyak::CodeGenerator {
explicit Code(int mode, size_t size, void *p)
: Xbyak::CodeGenerator(size, p)
{
inLocalLabel();
#ifdef XBYAK64
const Xbyak::Reg64& a = rax;
const Xbyak::Reg64& c = rcx;
#ifdef XBYAK64_WIN
mov(rax, rcx);
#else
mov(rax, rdi);
#endif
#else
const Xbyak::Reg32& a = eax;
const Xbyak::Reg32& c = ecx;
mov(a, ptr [esp + 4]);
#endif
switch (mode) {
case 0:
mov(c, ".jmp_table");
lea(c, ptr [c + a * 8]);
jmp(c);
align(8);
L(".jmp_table");
mov(a, expectTbl[0]);
ret();
align(8);
mov(a, expectTbl[1]);
ret();
align(8);
mov(a, expectTbl[2]);
ret();
break;
case 1:
/*
the label for putL is defined when called
*/
mov(c, ".jmp_table");
jmp(ptr [c + a * (int)sizeof(size_t)]);
L(".label1");
mov(a, expectTbl[0]);
jmp(".end");
L(".label2");
mov(a, expectTbl[1]);
jmp(".end");
L(".label3");
mov(a, expectTbl[2]);
jmp(".end");
L(".end");
ret();
ud2();
align(8);
L(".jmp_table");
putL(".label1");
putL(".label2");
putL(".label3");
break;
case 2:
/*
the label for putL is not defined when called
*/
jmp(".in");
ud2();
align(8);
L(".jmp_table");
putL(".label1");
putL(".label2");
putL(".label3");
L(".in");
mov(c, ".jmp_table");
jmp(ptr [c + a * (int)sizeof(size_t)]);
L(".label1");
mov(a, expectTbl[0]);
jmp(".end");
L(".label2");
mov(a, expectTbl[1]);
jmp(".end");
L(".label3");
mov(a, expectTbl[2]);
jmp(".end");
L(".end");
ret();
break;
}
outLocalLabel();
}
};
int main()
try
{
for (int mode = 0; mode < 3; mode++) {
printf("mode=%d\n", mode);
for (int grow = 0; grow < 2; grow++) {
printf("auto grow=%s\n", grow ? "on" : "off");
Code c(mode, grow ? 30 : 4096, grow ? Xbyak::AutoGrow : 0);
int (*f)(int) = c.getCode<int (*)(int)>();
c.ready();
for (int i = 0; i < 3; i++) {
const int a = expectTbl[i];
const int b = f(i);
if (a != b) {
printf("ERR i=%d, a=%d, b=%d\n", i, a, b);
exit(1);
}
}
}
}
puts("ok");
} catch (std::exception& e) {
printf("ERR %s\n", e.what());
}
-111
View File
@@ -1,111 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#define XBYAK_NO_OP_NAMES
#include <xbyak/xbyak.h>
struct A {
int x_;
int y_;
A() : x_(3), y_(5) {}
int func(int a, int b, int c, int d, int e) const { return x_ + y_ + a + b + c + d + e; }
};
#ifdef _MSC_VER
#pragma warning(disable : 4510 4512 4610)
#endif
struct Code : public Xbyak::CodeGenerator {
Code()
{
using namespace Xbyak;
int RET_ADJ = 0;
#ifdef XBYAK32
#ifdef _WIN32
const int PARA_ADJ = 0;
RET_ADJ = 5 * 4;
#else
const int PARA_ADJ = 4;
mov(ecx, ptr [esp + 4]);
#endif
#endif
const struct {
#ifdef XBYAK32
const Reg32& self;
#else
const Reg64& self;
#endif
const Operand& a;
const Operand& b;
const Operand& c;
const Operand& d;
const Operand& e;
} para = {
#if defined(XBYAK64_WIN)
rcx,
edx,
r8d,
r9d,
ptr [rsp + 8 * 5],
ptr [rsp + 8 * 6],
#elif defined(XBYAK64_GCC)
rdi,
esi,
edx,
ecx,
r8d,
r9d,
#else
ecx,
ptr [esp + 4 + PARA_ADJ],
ptr [esp + 8 + PARA_ADJ],
ptr [esp + 12 + PARA_ADJ],
ptr [esp + 16 + PARA_ADJ],
ptr [esp + 20 + PARA_ADJ],
#endif
};
mov(eax, ptr [para.self]);
add(eax, ptr [para.self + 4]);
add(eax, para.a);
add(eax, para.b);
add(eax, para.c);
add(eax, para.d);
add(eax, para.e);
ret(RET_ADJ);
}
};
int main()
{
#ifdef XBYAK64
printf("64bit");
#else
printf("32bit");
#endif
#ifdef _WIN32
puts(" win");
#else
puts(" linux");
#endif
try {
Code code;
int (A::*p)(int, int, int, int, int) const = 0;
const void *addr = code.getCode<void*>();
memcpy(&p, &addr, sizeof(void*));
for (int i = 0; i < 10; i++) {
A a;
int t1, t2, t3, t4, t5, x, y;
a.x_ = rand(); a.y_ = rand();
t1 = rand(); t2 = rand(); t3 = rand();
t4 = rand(); t5 = rand();
x = a.func(t1, t2, t3, t4, t5);
y = (a.*p)(t1, t2, t3, t4, t5);
printf("%c %d, %d\n", x == y ? 'o' : 'x', x, y);
}
} catch (std::exception& e) {
printf("err=%s\n", e.what());
return 1;
}
}
-90
View File
@@ -1,90 +0,0 @@
/*
How to profile JIT-code with perf or VTune
sudo perf record ./profiler 1
amplxe-cl -collect hotspots -result-dir r001hs -quiet ./profiler-vtune 2
*/
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <xbyak/xbyak_util.h>
const int N = 3000000;
struct Code : public Xbyak::CodeGenerator {
Code()
{
mov(eax, N);
Xbyak::Label lp = L();
for (int i = 0; i < 10; i++) {
sub(eax, 1);
}
jg(lp);
mov(eax, 1);
ret();
}
};
struct Code2 : public Xbyak::CodeGenerator {
Code2()
{
mov(eax, N);
Xbyak::Label lp = L();
for (int i = 0; i < 10; i++) {
xorps(xm0, xm0);
}
sub(eax, 1);
jg(lp);
mov(eax, 1);
ret();
}
};
double s1(int n)
{
double r = 0;
for (int i = 0; i < n; i++) {
r += 1.0 / (i + 1);
}
return r;
}
double s2(int n)
{
double r = 0;
for (int i = 0; i < n; i++) {
r += 1.0 / (i * i + 1) + 2.0 / (i + 3);
}
return r;
}
int main(int argc, char *argv[])
{
int mode = argc == 1 ? 0 : atoi(argv[1]);
Code c;
Code2 c2;
int (*f)() = (int (*)())c.getCode();
int (*g)() = (int (*)())c2.getCode();
printf("f:%p, %d\n", (const void*)f, (int)c.getSize());
printf("g:%p, %d\n", (const void*)g, (int)c2.getSize());
Xbyak::util::Profiler prof;
printf("mode=%d\n", mode);
prof.init(mode);
prof.set("f", (const void*)f, c.getSize());
prof.set("g", (const void*)g, c2.getSize());
double sum = 0;
for (int i = 0; i < 20000; i++) {
sum += s1(i);
sum += s2(i);
}
printf("sum=%f\n", sum);
for (int i = 0; i < 2000; i++) {
sum += f();
}
printf("f=%f\n", sum);
for (int i = 0; i < 2000; i++) {
sum += g();
}
printf("g=%f\n", sum);
puts("end");
}
-70
View File
@@ -1,70 +0,0 @@
#define XBYAK_NO_OP_NAMES
#include <xbyak/xbyak.h>
struct Code1 : Xbyak::CodeGenerator {
Code1()
: Xbyak::CodeGenerator(4096, Xbyak::DontSetProtectRWE)
{
mov(eax, 123);
ret();
}
void update()
{
db(0);
}
};
void test1(bool updateCode)
{
Code1 c;
c.setProtectModeRE();
if (updateCode) c.update(); // segmentation fault
int (*f)() = c.getCode<int (*)()>();
printf("f=%d\n", f());
c.setProtectModeRW();
c.update();
puts("ok");
}
struct Code2 : Xbyak::CodeGenerator {
Code2()
: Xbyak::CodeGenerator(4096, Xbyak::AutoGrow)
{
mov(eax, 123);
ret();
}
void update()
{
db(0);
}
};
void test2(bool updateCode)
{
Code2 c;
c.readyRE();
if (updateCode) c.update(); // segmentation fault
int (*f)() = c.getCode<int (*)()>();
printf("f=%d\n", f());
c.setProtectModeRW();
c.update();
puts("ok");
}
int main(int argc, char *argv[])
{
if (argc < 2) {
fprintf(stderr, "%s <testNum> [update]\n", argv[0]);
return 0;
}
bool update = argc == 3;
int n = atoi(argv[1]);
printf("n=%d update=%d\n", n, update);
switch (n) {
case 1: test1(update); break;
case 2: test2(update); break;
default: fprintf(stderr, "no test %d\n", n); break;
}
}
-226
View File
@@ -1,226 +0,0 @@
/*
@author herumi
JPEG quantize sample
This program generates a quantization routine by using fast division algorithm in run-time.
time(sec)
quality 1(high) 10 50 100(low)
VC2005 8.0 8.0 8.0 8.0
Xbyak 1.6 0.8 0.5 0.5
; generated code at q = 1
push esi
push edi
mov edi,dword ptr [esp+0Ch]
mov esi,dword ptr [esp+10h]
mov eax,dword ptr [esi]
shr eax,4
mov dword ptr [edi],eax
mov eax,dword ptr [esi+4]
mov edx,0BA2E8BA3h
mul eax,edx
shr edx,3
...
; generated code at q = 100
push esi
push edi
mov edi,dword ptr [esp+0Ch]
mov esi,dword ptr [esp+10h]
mov eax,dword ptr [esi]
mov dword ptr [edi],eax
mov eax,dword ptr [esi+4]
mov dword ptr [edi+4],eax
mov eax,dword ptr [esi+8]
mov dword ptr [edi+8],eax
mov eax,dword ptr [esi+0Ch]
...
*/
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define XBYAK_NO_OP_NAMES
#include "xbyak/xbyak.h"
#ifdef _MSC_VER
#pragma warning(disable : 4996) // scanf
#endif
const int N = 64;
class Quantize : public Xbyak::CodeGenerator {
static int ilog2(int x)
{
int shift = 0;
while ((1 << shift) <= x) shift++;
return shift - 1;
}
public:
/*
input : esi
output : eax = [esi+offset] / dividend
destroy : edx
*/
void udiv(uint32_t dividend, int offset)
{
mov(eax, ptr[esi + offset]);
/* dividend = odd x 2^exponent */
int exponent = 0, odd = dividend;
while ((odd & 1) == 0) {
odd >>= 1; exponent++;
}
if (odd == 1) { // trivial case
if (exponent) {
shr(eax, exponent);
}
return;
}
uint64_t mLow, mHigh;
int len = ilog2(odd) + 1;
{
uint64_t roundUp = uint64_t(1) << (32 + len);
uint64_t k = roundUp / (0xFFFFFFFFL - (0xFFFFFFFFL % odd));
mLow = roundUp / odd;
mHigh = (roundUp + k) / odd;
}
while (((mLow >> 1) < (mHigh >> 1)) && (len > 0)) {
mLow >>= 1; mHigh >>= 1; len--;
}
uint64_t m; int a;
if ((mHigh >> 32) == 0) {
m = mHigh; a = 0;
} else {
len = ilog2(odd);
uint64_t roundDown = uint64_t(1) << (32 + len);
mLow = roundDown / odd;
int r = (int)(roundDown % odd);
m = (r <= (odd >> 1)) ? mLow : mLow + 1;
a = 1;
}
while ((m & 1) == 0) {
m >>= 1; len--;
}
len += exponent;
mov(edx, int(m));
mul(edx);
if (a) {
add(eax, int(m));
adc(edx, 0);
}
if (len) {
shr(edx, len);
}
mov(eax, edx);
}
/*
quantize(uint32_t dest[64], const uint32_t src[64]);
*/
Quantize(const uint32_t qTbl[64])
{
push(esi);
push(edi);
const int P_ = 4 * 2;
mov(edi, ptr [esp+P_+4]); // dest
mov(esi, ptr [esp+P_+8]); // src
for (int i = 0; i < N; i++) {
udiv(qTbl[i], i * 4);
mov(ptr[edi+i*4], eax);
}
pop(edi);
pop(esi);
ret();
}
};
void quantize(uint32_t dest[64], const uint32_t src[64], const uint32_t qTbl[64])
{
for (int i = 0; i < N; i++) {
dest[i] = src[i] / qTbl[i];
}
}
#ifdef XBYAK64
int main()
{
puts("not implemented for 64bit");
return 1;
}
#else
int main(int argc, char *argv[])
{
int q;
if (argc > 1) {
q = atoi(argv[1]);
} else {
printf("input quantize=");
if (scanf("%d", &q) != 1) {
fprintf(stderr, "bad number\n");
return 1;
}
}
printf("q=%d\n", q);
uint32_t qTbl[] = {
16, 11, 10, 16, 24, 40, 51, 61,
12, 12, 14, 19, 26, 58, 60, 55,
14, 13, 16, 24, 40, 57, 69, 56,
14, 17, 22, 29, 51, 87, 80, 62,
18, 22, 37, 56, 68, 109, 103, 77,
24, 35, 55, 64, 81, 104, 113, 92,
49, 64, 78, 87, 103, 121, 120, 101,
72, 92, 95, 98, 112, 100, 103, 99
};
for (int i = 0; i < N; i++) {
qTbl[i] /= q;
if (qTbl[i] == 0) qTbl[i] = 1;
}
try {
uint32_t src[N];
uint32_t dest[N];
uint32_t dest2[N];
for (int i = 0; i < N; i++) {
src[i] = rand() % 2048;
}
Quantize jit(qTbl);
//printf("jit size=%d, ptr=%p\n", jit.getSize(), jit.getCode());
void (*quantize2)(uint32_t*, const uint32_t*, const uint32_t *) = jit.getCode<void (*)(uint32_t*, const uint32_t*, const uint32_t *)>();
quantize(dest, src, qTbl);
quantize2(dest2, src, qTbl);
for (int i = 0; i < N; i++) {
if (dest[i] != dest2[i]) {
printf("err[%d] %d %d\n", i, dest[i], dest2[i]);
}
}
const int count = 10000000;
int begin;
begin = clock();
for (int i = 0; i < count; i++) {
quantize(dest, src, qTbl);
}
printf("time=%.1fsec\n", (clock() - begin) / double(CLOCKS_PER_SEC));
begin = clock();
for (int i = 0; i < count; i++) {
quantize2(dest, src, qTbl);
}
printf("time=%.1fsec\n", (clock() - begin) / double(CLOCKS_PER_SEC));
} catch (std::exception& e) {
printf("ERR:%s\n", e.what());
} catch (...) {
printf("unknown error\n");
}
}
#endif
-228
View File
@@ -1,228 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{D06753BF-E1F3-4578-9B18-08673327F77C}</ProjectGuid>
<WindowsTargetPlatformVersion>10.0.17763.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<PlatformToolset>v141</PlatformToolset>
<UseOfMfc>false</UseOfMfc>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<PlatformToolset>v141</PlatformToolset>
<UseOfMfc>false</UseOfMfc>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<PlatformToolset>v141</PlatformToolset>
<UseOfMfc>false</UseOfMfc>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<PlatformToolset>v141</PlatformToolset>
<UseOfMfc>false</UseOfMfc>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC60.props" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC60.props" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC60.props" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC60.props" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup>
<_ProjectFileVersion>15.0.27924.0</_ProjectFileVersion>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
<IntDir>$(ProjectName)\$(Configuration)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
<IntDir>$(ProjectName)\$(Configuration)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
<IntDir>$(ProjectName)\$(Platform)\$(Configuration)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
<IntDir>$(ProjectName)\$(Platform)\$(Configuration)\</IntDir>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Midl>
<TypeLibraryName>.\Debug/quantize.tlb</TypeLibraryName>
<HeaderFileName />
</Midl>
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>../;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MinimalRebuild>true</MinimalRebuild>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<PrecompiledHeaderOutputFile>.\Debug/quantize.pch</PrecompiledHeaderOutputFile>
<WarningLevel>Level4</WarningLevel>
<SuppressStartupBanner>true</SuppressStartupBanner>
</ClCompile>
<ResourceCompile>
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<Culture>0x0411</Culture>
</ResourceCompile>
<Link>
<SuppressStartupBanner>true</SuppressStartupBanner>
<GenerateDebugInformation>true</GenerateDebugInformation>
<ProgramDatabaseFile>.\Debug/quantize.pdb</ProgramDatabaseFile>
<SubSystem>Console</SubSystem>
<RandomizedBaseAddress>false</RandomizedBaseAddress>
<DataExecutionPrevention />
<TargetMachine>MachineX86</TargetMachine>
</Link>
<Bscmake>
<SuppressStartupBanner>true</SuppressStartupBanner>
</Bscmake>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Midl>
<TypeLibraryName>.\Release/quantize.tlb</TypeLibraryName>
<HeaderFileName />
</Midl>
<ClCompile>
<Optimization>MaxSpeed</Optimization>
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
<AdditionalIncludeDirectories>../;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<StringPooling>true</StringPooling>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<FunctionLevelLinking>true</FunctionLevelLinking>
<PrecompiledHeaderOutputFile>.\Release/quantize.pch</PrecompiledHeaderOutputFile>
<WarningLevel>Level4</WarningLevel>
<SuppressStartupBanner>true</SuppressStartupBanner>
</ClCompile>
<ResourceCompile>
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<Culture>0x0411</Culture>
</ResourceCompile>
<Link>
<SuppressStartupBanner>true</SuppressStartupBanner>
<SubSystem>Console</SubSystem>
<RandomizedBaseAddress>false</RandomizedBaseAddress>
<DataExecutionPrevention />
<TargetMachine>MachineX86</TargetMachine>
</Link>
<Bscmake>
<SuppressStartupBanner>true</SuppressStartupBanner>
</Bscmake>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Midl>
<TargetEnvironment>X64</TargetEnvironment>
<TypeLibraryName>.\Debug/quantize.tlb</TypeLibraryName>
<HeaderFileName />
</Midl>
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>../;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MinimalRebuild>true</MinimalRebuild>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<PrecompiledHeaderOutputFile>.\Debug/quantize.pch</PrecompiledHeaderOutputFile>
<WarningLevel>Level4</WarningLevel>
<SuppressStartupBanner>true</SuppressStartupBanner>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
</ClCompile>
<ResourceCompile>
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<Culture>0x0411</Culture>
</ResourceCompile>
<Link>
<SuppressStartupBanner>true</SuppressStartupBanner>
<GenerateDebugInformation>true</GenerateDebugInformation>
<ProgramDatabaseFile>.\Debug/quantize.pdb</ProgramDatabaseFile>
<SubSystem>Console</SubSystem>
<RandomizedBaseAddress>false</RandomizedBaseAddress>
<DataExecutionPrevention />
<TargetMachine>MachineX64</TargetMachine>
</Link>
<Bscmake>
<SuppressStartupBanner>true</SuppressStartupBanner>
</Bscmake>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Midl>
<TargetEnvironment>X64</TargetEnvironment>
<TypeLibraryName>.\Release/quantize.tlb</TypeLibraryName>
<HeaderFileName />
</Midl>
<ClCompile>
<Optimization>MaxSpeed</Optimization>
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
<AdditionalIncludeDirectories>../;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<StringPooling>true</StringPooling>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<FunctionLevelLinking>true</FunctionLevelLinking>
<PrecompiledHeaderOutputFile>.\Release/quantize.pch</PrecompiledHeaderOutputFile>
<WarningLevel>Level4</WarningLevel>
<SuppressStartupBanner>true</SuppressStartupBanner>
</ClCompile>
<ResourceCompile>
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<Culture>0x0411</Culture>
</ResourceCompile>
<Link>
<SuppressStartupBanner>true</SuppressStartupBanner>
<SubSystem>Console</SubSystem>
<RandomizedBaseAddress>false</RandomizedBaseAddress>
<DataExecutionPrevention />
<TargetMachine>MachineX64</TargetMachine>
</Link>
<Bscmake>
<SuppressStartupBanner>true</SuppressStartupBanner>
</Bscmake>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="quantize.cpp" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
-29
View File
@@ -1,29 +0,0 @@
#define XBYAK_NO_OP_NAMES
#include <xbyak/xbyak_util.h>
#ifdef XBYAK32
#error "this sample is for only 64-bit mode"
#endif
struct Code : public Xbyak::CodeGenerator {
Code()
{
// see xbyak/sample/sf_test.cpp for how to use other parameter
Xbyak::util::StackFrame sf(this, 3);
mov(rax, sf.p[0]);
add(rax, sf.p[1]);
add(rax, sf.p[2]);
}
};
int main()
{
Code c;
int (*f)(int, int, int) = c.getCode<int(*) (int, int, int)>();
int ret = f(3, 5, 2);
if (ret == 3 + 5 + 2) {
puts("ok");
} else {
puts("ng");
}
}
-45
View File
@@ -1,45 +0,0 @@
/*
sample to use static memory
*/
#include <stdio.h>
#define XBYAK_NO_OP_NAMES
#include "xbyak/xbyak.h"
MIE_ALIGN(4096) char buf[4096];
struct Code : Xbyak::CodeGenerator {
Code()
: Xbyak::CodeGenerator(sizeof(buf), buf)
{
puts("generate");
printf("ptr=%p, %p\n", getCode(), buf);
#ifdef XBYAK32
mov(eax, ptr [esp + 4]);
add(eax, ptr [esp + 8]);
#elif defined(XBYAK64_WIN)
lea(rax, ptr [rcx + rdx]);
#else
lea(rax, ptr [rdi + rsi]);
#endif
ret();
Xbyak::CodeArray::protect(buf, sizeof(buf), Xbyak::CodeArray::PROTECT_RE);
}
~Code()
{
Xbyak::CodeArray::protect(buf, sizeof(buf), Xbyak::CodeArray::PROTECT_RW);
}
} s_code;
inline int add(int a, int b)
{
return reinterpret_cast<int (*)(int, int)>(buf)(a, b);
}
int main()
{
int sum = 0;
for (int i = 0; i < 10; i++) {
sum += add(i, 5);
}
printf("sum=%d\n", sum);
}
-190
View File
@@ -1,190 +0,0 @@
#if defined(_MSC_VER) && (_MSC_VER <= 1200)
#pragma warning(disable:4514)
#pragma warning(disable:4786)
#endif
#if defined(_MSC_VER) && (_MSC_VER >= 1900)
#pragma warning(disable:4456)
#endif
#include <stdio.h>
#include <stdlib.h>
#define XBYAK_NO_OP_NAMES
#include "xbyak/xbyak.h"
class Sample : public Xbyak::CodeGenerator {
void operator=(const Sample&);
public:
Sample(void *userPtr = 0, size_t size = Xbyak::DEFAULT_MAX_CODE_SIZE) : Xbyak::CodeGenerator(size, userPtr)
{
inLocalLabel(); // use local label for multiple instance
#ifdef XBYAK32
mov(ecx, ptr [esp + 4]); // n
#elif defined(XBYAK64_GCC)
mov(ecx, edi); // n
#else
// n = ecx
#endif
xor_(eax, eax); // sum
test(ecx, ecx);
jz(".exit");
xor_(edx, edx); // i
L(".lp");
add(eax, edx);
inc(edx);
cmp(edx, ecx);
jbe(".lp"); // jmp to previous @@
L(".exit"); // <B>
ret();
outLocalLabel(); // end of local label
}
};
class AddFunc : public Xbyak::CodeGenerator {
void operator=(const AddFunc&);
public:
AddFunc(int y)
{
#ifdef XBYAK32
mov(eax, ptr [esp + 4]);
add(eax, y);
#elif defined(XBYAK64_WIN)
lea(rax, ptr [rcx + y]);
#else
lea(eax, ptr [edi + y]);
#endif
ret();
}
int (*get() const)(int) { return getCode<int(*)(int)>(); }
};
class CallAtoi : public Xbyak::CodeGenerator {
void operator=(const CallAtoi&);
public:
CallAtoi()
{
#ifdef XBYAK64
#ifdef XBYAK64_WIN
sub(rsp, 32); // return-address is destroied if 64bit debug mode
#endif
mov(rax, (size_t)atoi);
call(rax);
#ifdef XBYAK64_WIN
add(rsp, 32);
#endif
#else
mov(eax, ptr [esp + 4]);
push(eax);
#ifdef XBYAK_VARIADIC_TEMPLATE
call(atoi);
#else
call(reinterpret_cast<const void*>(atoi));
#endif
add(esp, 4);
#endif
ret();
}
int (*get() const)(const char *) { return getCode<int (*)(const char *)>(); }
};
class JmpAtoi : public Xbyak::CodeGenerator {
void operator=(const JmpAtoi&);
public:
JmpAtoi()
{
/* already pushed "456" */
#ifdef XBYAK64
mov(rax, (size_t)atoi);
jmp(rax);
#else
jmp(reinterpret_cast<const void*>(atoi));
#endif
}
int (*get() const)(const char *) { return getCode<int (*)(const char *)>(); }
};
struct Reset : public Xbyak::CodeGenerator {
void init(int n)
{
xor_(eax, eax);
mov(ecx, n);
test(ecx, ecx);
jnz("@f");
ret();
L("@@");
for (int i = 0; i < 10 - n; i++) {
add(eax, ecx);
}
sub(ecx, 1);
jnz("@b");
ret();
}
};
void testReset()
{
puts("testReset");
Reset code;
int (*f)(int) = code.getCode<int(*)(int)>();
for (int i = 0; i < 10; i++) {
code.init(i);
int v = f(i);
printf("%d %d\n", i, v);
code.reset();
}
}
int main()
{
try {
Sample s;
printf("Xbyak version=%s\n", s.getVersionString());
#ifdef XBYAK64_GCC
puts("64bit mode(gcc)");
#elif defined(XBYAK64_WIN)
puts("64bit mode(win)");
#else
puts("32bit");
#endif
int (*func)(int) = s.getCode<int (*)(int)>();
for (int i = 0; i <= 10; i++) {
printf("0 + ... + %d = %d\n", i, func(i));
}
for (int i = 0; i < 10; i++) {
AddFunc a(i);
int (*add)(int) = a.get();
int y = add(i);
printf("%d + %d = %d\n", i, i, y);
}
CallAtoi c;
printf("call atoi(\"123\") = %d\n", c.get()("123"));
JmpAtoi j;
printf("jmp atoi(\"456\") = %d\n", j.get()("456"));
{
// use memory allocated by user
using namespace Xbyak;
const size_t codeSize = 4096;
uint8_t buf[codeSize + 16];
uint8_t *p = CodeArray::getAlignedAddress(buf);
Sample s(p, codeSize);
if (!CodeArray::protect(p, codeSize, CodeArray::PROTECT_RWE)) {
fprintf(stderr, "can't protect\n");
return 1;
}
int (*func)(int) = s.getCode<int (*)(int)>();
const uint8_t *funcp = reinterpret_cast<const uint8_t*>(func);
if (funcp != p) {
fprintf(stderr, "internal error %p %p\n", p, funcp);
return 1;
}
printf("0 + ... + %d = %d\n", 100, func(100));
CodeArray::protect(p, codeSize, CodeArray::PROTECT_RW);
}
puts("OK");
testReset();
} catch (std::exception& e) {
printf("ERR:%s\n", e.what());
} catch (...) {
printf("unknown error\n");
}
}
-228
View File
@@ -1,228 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{1CDE4D2A-BE3A-4B9B-B28F-524A23084A8E}</ProjectGuid>
<WindowsTargetPlatformVersion>10.0.17763.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<PlatformToolset>v141</PlatformToolset>
<UseOfMfc>false</UseOfMfc>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<PlatformToolset>v141</PlatformToolset>
<UseOfMfc>false</UseOfMfc>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<PlatformToolset>v141</PlatformToolset>
<UseOfMfc>false</UseOfMfc>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<PlatformToolset>v141</PlatformToolset>
<UseOfMfc>false</UseOfMfc>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC60.props" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC60.props" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC60.props" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC60.props" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup>
<_ProjectFileVersion>15.0.27924.0</_ProjectFileVersion>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
<IntDir>$(ProjectName)\$(Configuration)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
<IntDir>$(ProjectName)\$(Configuration)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
<IntDir>$(ProjectName)\$(Platform)\$(Configuration)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
<IntDir>$(ProjectName)\$(Platform)\$(Configuration)\</IntDir>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Midl>
<TypeLibraryName>.\Debug/test0.tlb</TypeLibraryName>
<HeaderFileName />
</Midl>
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>../;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MinimalRebuild>true</MinimalRebuild>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<PrecompiledHeaderOutputFile>.\Debug/test0.pch</PrecompiledHeaderOutputFile>
<WarningLevel>Level4</WarningLevel>
<SuppressStartupBanner>true</SuppressStartupBanner>
</ClCompile>
<ResourceCompile>
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<Culture>0x0411</Culture>
</ResourceCompile>
<Link>
<SuppressStartupBanner>true</SuppressStartupBanner>
<GenerateDebugInformation>true</GenerateDebugInformation>
<ProgramDatabaseFile>.\Debug/test0.pdb</ProgramDatabaseFile>
<SubSystem>Console</SubSystem>
<RandomizedBaseAddress>false</RandomizedBaseAddress>
<DataExecutionPrevention />
<TargetMachine>MachineX86</TargetMachine>
</Link>
<Bscmake>
<SuppressStartupBanner>true</SuppressStartupBanner>
</Bscmake>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Midl>
<TypeLibraryName>.\Release/test0.tlb</TypeLibraryName>
<HeaderFileName />
</Midl>
<ClCompile>
<Optimization>MaxSpeed</Optimization>
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
<AdditionalIncludeDirectories>../;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<StringPooling>true</StringPooling>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<FunctionLevelLinking>true</FunctionLevelLinking>
<PrecompiledHeaderOutputFile>.\Release/test0.pch</PrecompiledHeaderOutputFile>
<WarningLevel>Level4</WarningLevel>
<SuppressStartupBanner>true</SuppressStartupBanner>
</ClCompile>
<ResourceCompile>
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<Culture>0x0411</Culture>
</ResourceCompile>
<Link>
<SuppressStartupBanner>true</SuppressStartupBanner>
<SubSystem>Console</SubSystem>
<RandomizedBaseAddress>false</RandomizedBaseAddress>
<DataExecutionPrevention />
<TargetMachine>MachineX86</TargetMachine>
</Link>
<Bscmake>
<SuppressStartupBanner>true</SuppressStartupBanner>
</Bscmake>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Midl>
<TargetEnvironment>X64</TargetEnvironment>
<TypeLibraryName>.\Debug/test0.tlb</TypeLibraryName>
<HeaderFileName />
</Midl>
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>../;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MinimalRebuild>true</MinimalRebuild>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<PrecompiledHeaderOutputFile>.\Debug/test0.pch</PrecompiledHeaderOutputFile>
<WarningLevel>Level4</WarningLevel>
<SuppressStartupBanner>true</SuppressStartupBanner>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
</ClCompile>
<ResourceCompile>
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<Culture>0x0411</Culture>
</ResourceCompile>
<Link>
<SuppressStartupBanner>true</SuppressStartupBanner>
<GenerateDebugInformation>true</GenerateDebugInformation>
<ProgramDatabaseFile>.\Debug/test0.pdb</ProgramDatabaseFile>
<SubSystem>Console</SubSystem>
<RandomizedBaseAddress>false</RandomizedBaseAddress>
<DataExecutionPrevention />
<TargetMachine>MachineX64</TargetMachine>
</Link>
<Bscmake>
<SuppressStartupBanner>true</SuppressStartupBanner>
</Bscmake>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Midl>
<TargetEnvironment>X64</TargetEnvironment>
<TypeLibraryName>.\Release/test0.tlb</TypeLibraryName>
<HeaderFileName />
</Midl>
<ClCompile>
<Optimization>MaxSpeed</Optimization>
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
<AdditionalIncludeDirectories>../;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<StringPooling>true</StringPooling>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<FunctionLevelLinking>true</FunctionLevelLinking>
<PrecompiledHeaderOutputFile>.\Release/test0.pch</PrecompiledHeaderOutputFile>
<WarningLevel>Level4</WarningLevel>
<SuppressStartupBanner>true</SuppressStartupBanner>
</ClCompile>
<ResourceCompile>
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<Culture>0x0411</Culture>
</ResourceCompile>
<Link>
<SuppressStartupBanner>true</SuppressStartupBanner>
<SubSystem>Console</SubSystem>
<RandomizedBaseAddress>false</RandomizedBaseAddress>
<DataExecutionPrevention />
<TargetMachine>MachineX64</TargetMachine>
</Link>
<Bscmake>
<SuppressStartupBanner>true</SuppressStartupBanner>
</Bscmake>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="test0.cpp" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
-134
View File
@@ -1,134 +0,0 @@
#include <stdio.h>
#include "xbyak/xbyak_util.h"
#define NUM_OF_ARRAY(x) (sizeof(x) / sizeof(x[0]))
struct PopCountTest : public Xbyak::CodeGenerator {
PopCountTest(int n)
: Xbyak::CodeGenerator(4096, Xbyak::DontSetProtectRWE)
{
ret();
mov(eax, n);
popcnt(eax, eax);
ret();
}
};
void putCPUinfo()
{
using namespace Xbyak::util;
Cpu cpu;
printf("vendor %s\n", cpu.has(Cpu::tINTEL) ? "intel" : "amd");
static const struct {
Cpu::Type type;
const char *str;
} tbl[] = {
{ Cpu::tMMX, "mmx" },
{ Cpu::tMMX2, "mmx2" },
{ Cpu::tCMOV, "cmov" },
{ Cpu::tSSE, "sse" },
{ Cpu::tSSE2, "sse2" },
{ Cpu::tSSE3, "sse3" },
{ Cpu::tSSSE3, "ssse3" },
{ Cpu::tSSE41, "sse41" },
{ Cpu::tSSE42, "sse42" },
{ Cpu::tPOPCNT, "popcnt" },
{ Cpu::t3DN, "3dn" },
{ Cpu::tE3DN, "e3dn" },
{ Cpu::tSSE4a, "sse4a" },
{ Cpu::tSSE5, "sse5" },
{ Cpu::tAESNI, "aesni" },
{ Cpu::tRDTSCP, "rdtscp" },
{ Cpu::tOSXSAVE, "osxsave(xgetvb)" },
{ Cpu::tPCLMULQDQ, "pclmulqdq" },
{ Cpu::tAVX, "avx" },
{ Cpu::tFMA, "fma" },
{ Cpu::tAVX2, "avx2" },
{ Cpu::tBMI1, "bmi1" },
{ Cpu::tBMI2, "bmi2" },
{ Cpu::tLZCNT, "lzcnt" },
{ Cpu::tPREFETCHW, "prefetchw" },
{ Cpu::tENHANCED_REP, "enh_rep" },
{ Cpu::tRDRAND, "rdrand" },
{ Cpu::tADX, "adx" },
{ Cpu::tRDSEED, "rdseed" },
{ Cpu::tSMAP, "smap" },
{ Cpu::tHLE, "hle" },
{ Cpu::tRTM, "rtm" },
{ Cpu::tMPX, "mpx" },
{ Cpu::tSHA, "sha" },
{ Cpu::tPREFETCHWT1, "prefetchwt1" },
{ Cpu::tF16C, "f16c" },
{ Cpu::tMOVBE, "movbe" },
{ Cpu::tAVX512F, "avx512f" },
{ Cpu::tAVX512DQ, "avx512dq" },
{ Cpu::tAVX512IFMA, "avx512_ifma" },
{ Cpu::tAVX512PF, "avx512pf" },
{ Cpu::tAVX512ER, "avx512er" },
{ Cpu::tAVX512CD, "avx512cd" },
{ Cpu::tAVX512BW, "avx512bw" },
{ Cpu::tAVX512VL, "avx512vl" },
{ Cpu::tAVX512VBMI, "avx512_vbmi" },
{ Cpu::tAVX512_4VNNIW, "avx512_4vnniw" },
{ Cpu::tAVX512_4FMAPS, "avx512_4fmaps" },
{ Cpu::tAVX512_VBMI2, "avx512_vbmi2" },
{ Cpu::tGFNI, "gfni" },
{ Cpu::tVAES, "vaes" },
{ Cpu::tVPCLMULQDQ, "vpclmulqdq" },
{ Cpu::tAVX512_VNNI, "avx512_vnni" },
{ Cpu::tAVX512_BITALG, "avx512_bitalg" },
{ Cpu::tAVX512_VPOPCNTDQ, "avx512_vpopcntdq" },
{ Cpu::tAVX512_BF16, "avx512_bf16" },
{ Cpu::tAVX512_VP2INTERSECT, "avx512_vp2intersect" },
{ Cpu::tAMX_TILE, "amx(tile)" },
{ Cpu::tAMX_INT8, "amx(int8)" },
{ Cpu::tAMX_BF16, "amx(bf16)" },
{ Cpu::tAVX_VNNI, "avx_vnni" },
};
for (size_t i = 0; i < NUM_OF_ARRAY(tbl); i++) {
if (cpu.has(tbl[i].type)) printf(" %s", tbl[i].str);
}
printf("\n");
if (cpu.has(Cpu::tPOPCNT)) {
const int n = 0x12345678; // bitcount = 13
const int ok = 13;
PopCountTest code(n);
code.setProtectModeRE();
int (*f)() = code.getCode<int (*)()>();
int r = f();
if (r == ok) {
puts("popcnt ok");
} else {
printf("popcnt ng %d %d\n", r, ok);
}
code.setProtectModeRW();
}
/*
displayFamily displayModel
Opteron 2376 10 4
Core2 Duo T7100 6 F
Core i3-2120T 6 2A
Core i7-2600 6 2A
Xeon X5650 6 2C
Core i7-3517 6 3A
Core i7-3930K 6 2D
*/
cpu.putFamily();
if (!cpu.has(Cpu::tINTEL)) return;
for (unsigned int i = 0; i < cpu.getDataCacheLevels(); i++) {
printf("cache level=%u data cache size=%u cores sharing data cache=%u\n", i, cpu.getDataCacheSize(i), cpu.getCoresSharingDataCache(i));
}
printf("SmtLevel =%u\n", cpu.getNumCores(Xbyak::util::SmtLevel));
printf("CoreLevel=%u\n", cpu.getNumCores(Xbyak::util::CoreLevel));
}
int main()
{
#ifdef XBYAK32
puts("32bit");
#else
puts("64bit");
#endif
putCPUinfo();
}
-228
View File
@@ -1,228 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{CFC9B272-FDA1-4C87-B4EF-CDCA9B57F4DD}</ProjectGuid>
<WindowsTargetPlatformVersion>10.0.17763.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<PlatformToolset>v141</PlatformToolset>
<UseOfMfc>false</UseOfMfc>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<PlatformToolset>v141</PlatformToolset>
<UseOfMfc>false</UseOfMfc>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<PlatformToolset>v141</PlatformToolset>
<UseOfMfc>false</UseOfMfc>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<PlatformToolset>v141</PlatformToolset>
<UseOfMfc>false</UseOfMfc>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC60.props" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC60.props" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC60.props" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC60.props" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup>
<_ProjectFileVersion>15.0.27924.0</_ProjectFileVersion>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
<IntDir>$(ProjectName)\$(Configuration)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
<IntDir>$(ProjectName)\$(Platform)\$(Configuration)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
<IntDir>$(ProjectName)\$(Configuration)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
<IntDir>$(ProjectName)\$(Platform)\$(Configuration)\</IntDir>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Midl>
<TypeLibraryName>.\Debug/test_util.tlb</TypeLibraryName>
<HeaderFileName />
</Midl>
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>../;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MinimalRebuild>true</MinimalRebuild>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<PrecompiledHeaderOutputFile>.\Debug/test_util.pch</PrecompiledHeaderOutputFile>
<WarningLevel>Level4</WarningLevel>
<SuppressStartupBanner>true</SuppressStartupBanner>
</ClCompile>
<ResourceCompile>
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<Culture>0x0411</Culture>
</ResourceCompile>
<Link>
<SuppressStartupBanner>true</SuppressStartupBanner>
<GenerateDebugInformation>true</GenerateDebugInformation>
<ProgramDatabaseFile>.\Debug/test_util.pdb</ProgramDatabaseFile>
<SubSystem>Console</SubSystem>
<RandomizedBaseAddress>false</RandomizedBaseAddress>
<DataExecutionPrevention />
<TargetMachine>MachineX86</TargetMachine>
</Link>
<Bscmake>
<SuppressStartupBanner>true</SuppressStartupBanner>
</Bscmake>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Midl>
<TargetEnvironment>X64</TargetEnvironment>
<TypeLibraryName>.\Debug/test_util.tlb</TypeLibraryName>
<HeaderFileName />
</Midl>
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>../;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MinimalRebuild>true</MinimalRebuild>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<PrecompiledHeaderOutputFile>.\Debug/test_util.pch</PrecompiledHeaderOutputFile>
<WarningLevel>Level4</WarningLevel>
<SuppressStartupBanner>true</SuppressStartupBanner>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
</ClCompile>
<ResourceCompile>
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<Culture>0x0411</Culture>
</ResourceCompile>
<Link>
<SuppressStartupBanner>true</SuppressStartupBanner>
<GenerateDebugInformation>true</GenerateDebugInformation>
<ProgramDatabaseFile>.\Debug/test_util.pdb</ProgramDatabaseFile>
<SubSystem>Console</SubSystem>
<RandomizedBaseAddress>false</RandomizedBaseAddress>
<DataExecutionPrevention />
<TargetMachine>MachineX64</TargetMachine>
</Link>
<Bscmake>
<SuppressStartupBanner>true</SuppressStartupBanner>
</Bscmake>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Midl>
<TypeLibraryName>.\Release/test_util.tlb</TypeLibraryName>
<HeaderFileName />
</Midl>
<ClCompile>
<Optimization>MaxSpeed</Optimization>
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
<AdditionalIncludeDirectories>../;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<StringPooling>true</StringPooling>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<FunctionLevelLinking>true</FunctionLevelLinking>
<PrecompiledHeaderOutputFile>.\Release/test_util.pch</PrecompiledHeaderOutputFile>
<WarningLevel>Level4</WarningLevel>
<SuppressStartupBanner>true</SuppressStartupBanner>
</ClCompile>
<ResourceCompile>
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<Culture>0x0411</Culture>
</ResourceCompile>
<Link>
<SuppressStartupBanner>true</SuppressStartupBanner>
<SubSystem>Console</SubSystem>
<RandomizedBaseAddress>false</RandomizedBaseAddress>
<DataExecutionPrevention />
<TargetMachine>MachineX86</TargetMachine>
</Link>
<Bscmake>
<SuppressStartupBanner>true</SuppressStartupBanner>
</Bscmake>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Midl>
<TargetEnvironment>X64</TargetEnvironment>
<TypeLibraryName>.\Release/test_util.tlb</TypeLibraryName>
<HeaderFileName />
</Midl>
<ClCompile>
<Optimization>MaxSpeed</Optimization>
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
<AdditionalIncludeDirectories>../;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<StringPooling>true</StringPooling>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<FunctionLevelLinking>true</FunctionLevelLinking>
<PrecompiledHeaderOutputFile>.\Release/test_util.pch</PrecompiledHeaderOutputFile>
<WarningLevel>Level4</WarningLevel>
<SuppressStartupBanner>true</SuppressStartupBanner>
</ClCompile>
<ResourceCompile>
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<Culture>0x0411</Culture>
</ResourceCompile>
<Link>
<SuppressStartupBanner>true</SuppressStartupBanner>
<SubSystem>Console</SubSystem>
<RandomizedBaseAddress>false</RandomizedBaseAddress>
<DataExecutionPrevention />
<TargetMachine>MachineX64</TargetMachine>
</Link>
<Bscmake>
<SuppressStartupBanner>true</SuppressStartupBanner>
</Bscmake>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="test_util.cpp" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
-380
View File
@@ -1,380 +0,0 @@
/*
toy vm
register A, B : 32bit
PC : program counter
mem_ 4byte x 65536
すべての命令は4byte固定
即値は全て16bit
R = A or B
vldiR, imm ; R = imm
vldR, idx ; R = mem_[idx]
vstR, idx ; mem_[idx] = R
vaddiR, imm ; R += imm
vsubiR, imm ; R -= imm
vaddR, idx ; R += mem_[idx]
vsubR, idx ; R -= mem_[idx]
vputR ; print R
vjnzR, offset; if (R != 0) then jmp(PC += offset(signed))
*/
#if defined(_MSC_VER) && (_MSC_VER <= 1200)
#pragma warning(disable:4514)
#pragma warning(disable:4786)
#endif
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include <vector>
#define XBYAK_NO_OP_NAMES
#include "xbyak/xbyak.h"
#include "xbyak/xbyak_util.h"
#define NUM_OF_ARRAY(x) (sizeof(x) / sizeof(x[0]))
#ifdef XBYAK64
#error "only 32bit"
#endif
using namespace Xbyak;
class ToyVm : public Xbyak::CodeGenerator {
typedef std::vector<uint32_t> Buffer;
public:
enum Reg {
A, B
};
enum Code {
LD, LDI, ST, ADD, ADDI, SUB, SUBI, PUT, JNZ,
END_OF_CODE
};
ToyVm()
: mark_(0)
{
::memset(mem_, 0, sizeof(mem_));
}
void vldi(Reg r, uint16_t imm) { encode(LDI, r, imm); }
void vld(Reg r, uint16_t idx) { encode(LD, r, idx); }
void vst(Reg r, uint16_t idx) { encode(ST, r, idx); }
void vadd(Reg r, uint16_t idx) { encode(ADD, r, idx); }
void vaddi(Reg r, uint16_t imm) { encode(ADDI, r, imm); }
void vsub(Reg r, uint16_t idx) { encode(SUB, r, idx); }
void vsubi(Reg r, uint16_t imm) { encode(SUBI, r, imm); }
void vjnz(Reg r, int offset) { encode(JNZ, r, static_cast<uint16_t>(offset)); }
void vput(Reg r) { encode(PUT, r); }
void setMark()
{
mark_ = (int)code_.size();
}
int getMarkOffset()
{
return mark_ - (int)code_.size() - 1;
}
void run()
{
bool debug = false;//true;
uint32_t reg[2] = { 0, 0 };
const size_t end = code_.size();
uint32_t pc = 0;
for (;;) {
uint32_t x = code_[pc];
uint32_t code, r, imm;
decode(code, r, imm, x);
if (debug) {
printf("---\n");
printf("A %08x B %08x\n", reg[0], reg[1]);
printf("mem_[] = %08x %08x %08x\n", mem_[0], mem_[1], mem_[2]);
printf("pc=%4d, code=%02x, r=%d, imm=%04x\n", pc, code, r, imm);
}
switch (code) {
case LDI:
reg[r] = imm;
break;
case LD:
reg[r] = mem_[imm];
break;
case ST:
mem_[imm] = reg[r];
break;
case ADD:
reg[r] += mem_[imm];
break;
case ADDI:
reg[r] += imm;
break;
case SUB:
reg[r] -= mem_[imm];
break;
case SUBI:
reg[r] -= imm;
break;
case PUT:
printf("%c %8d(0x%08x)\n", 'A' + r, reg[r], reg[r]);
break;
case JNZ:
if (reg[r] != 0) pc += static_cast<signed short>(imm);
break;
default:
assert(0);
break;
}
pc++;
if (pc >= end) break;
} // for (;;)
}
void recompile()
{
using namespace Xbyak;
/*
esi : A
edi : B
ebx : mem_
for speed up
mem_[0] : eax
mem_[1] : ecx
mem_[2] : edx
*/
push(ebx);
push(esi);
push(edi);
const Reg32 reg[2] = { esi, edi };
const Reg32 mem(ebx);
const Reg32 memTbl[] = { eax, ecx, edx };
const size_t memTblNum = NUM_OF_ARRAY(memTbl);
for (size_t i = 0; i < memTblNum; i++) xor_(memTbl[i], memTbl[i]);
xor_(esi, esi);
xor_(edi, edi);
mov(mem, (size_t)mem_);
const size_t end = code_.size();
uint32_t pc = 0;
uint32_t labelNum = 0;
for (;;) {
uint32_t x = code_[pc];
uint32_t code, r, imm;
decode(code, r, imm, x);
L(Label::toStr(labelNum++));
switch (code) {
case LDI:
mov(reg[r], imm);
break;
case LD:
if (imm < memTblNum) {
mov(reg[r], memTbl[imm]);
} else {
mov(reg[r], ptr[mem + imm * 4]);
}
break;
case ST:
if (imm < memTblNum) {
mov(memTbl[imm], reg[r]);
} else {
mov(ptr [mem + imm * 4], reg[r]);
}
break;
case ADD:
if (imm < memTblNum) {
add(reg[r], memTbl[imm]);
} else {
add(reg[r], ptr [mem + imm * 4]);
}
break;
case ADDI:
add(reg[r], imm);
break;
case SUB:
if (imm < memTblNum) {
sub(reg[r], memTbl[imm]);
} else {
sub(reg[r], ptr [mem + imm * 4]);
}
break;
case SUBI:
sub(reg[r], imm);
break;
case PUT:
{
static const char *str = "%c %8d(0x%08x)\n";
push(eax);
push(edx);
push(ecx);
push(reg[r]);
push(reg[r]);
push('A' + r);
push((int)str);
call(reinterpret_cast<const void*>(printf));
add(esp, 4 * 4);
pop(ecx);
pop(edx);
pop(eax);
}
break;
case JNZ:
test(reg[r], reg[r]);
jnz(Label::toStr(labelNum + static_cast<signed short>(imm)));
break;
default:
assert(0);
break;
}
pc++;
if (pc >= end) break;
} // for (;;)
pop(edi);
pop(esi);
pop(ebx);
ret();
}
private:
uint32_t mem_[65536];
Buffer code_;
int mark_;
void decode(uint32_t& code, uint32_t& r, uint32_t& imm, uint32_t x)
{
code = x >> 24;
r = (x >> 16) & 0xff;
imm = x & 0xffff;
}
void encode(Code code, Reg r, uint16_t imm = 0)
{
uint32_t x = (code << 24) | (r << 16) | imm;
code_.push_back(x);
}
};
class Fib : public ToyVm {
public:
Fib(int n)
{
if (n >= 65536) {
fprintf(stderr, "current version support only imm16\n");
return;
}
/*
A : c
B : temporary
mem_[0] : p
mem_[1] : t
mem_[2] : n
*/
vldi(A, 1); // c
vst(A, 0); // p(1)
vldi(B, static_cast<uint16_t>(n));
vst(B, 2); // n
// lp
setMark();
vst(A, 1); // t = c
vadd(A, 0); // c += p
vld(B, 1);
vst(B, 0); // p = t
// vput(A);
vld(B, 2);
vsubi(B, 1);
vst(B, 2); // n--
vjnz(B, getMarkOffset());
vput(A);
}
void runByJIT()
{
getCode<void (*)()>();
}
};
void fibC(uint32_t n)
{
uint32_t p, c, t;
p = 1;
c = 1;
lp:
t = c;
c += p;
p = t;
n--;
if (n != 0) goto lp;
printf("c=%d(0x%08x)\n", c, c);
}
int main()
{
try {
const int n = 10000;
Fib fib(n);
fib.recompile();
{
Xbyak::util::Clock clk;
clk.begin();
fib.run();
clk.end();
printf("vm %.2fKclk\n", clk.getClock() * 1e-3);
}
{
Xbyak::util::Clock clk;
clk.begin();
fib.runByJIT();
clk.end();
printf("jit %.2fKclk\n", clk.getClock() * 1e-3);
}
{
Xbyak::util::Clock clk;
clk.begin();
fibC(n);
clk.end();
printf("native C %.2fKclk\n", clk.getClock() * 1e-3);
}
} catch (std::exception& e) {
printf("ERR:%s\n", e.what());
} catch (...) {
printf("unknown error\n");
}
return 0;
}
/*
the code generated by Xbyak
push ebx
push esi
push edi
xor eax,eax
xor ecx,ecx
xor edx,edx
xor esi,esi
xor edi,edi
mov ebx,0EFF58h
mov esi,1
mov eax,esi
mov edi,2710h
mov edx,edi
.lp:
mov ecx,esi
add esi,eax
mov edi,ecx
mov eax,edi
mov edi,edx
sub edi,1
mov edx,edi
test edi,edi
jne .lp
push eax
push edx
push ecx
push esi
push esi
push 41h
push 42C434h
call printf (409342h)
add esp,10h
pop ecx
pop edx
pop eax
pop edi
pop esi
pop ebx
ret
*/
-228
View File
@@ -1,228 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{2E41C7AF-39FF-454C-B081-37445378DCB3}</ProjectGuid>
<WindowsTargetPlatformVersion>10.0.17763.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<PlatformToolset>v141</PlatformToolset>
<UseOfMfc>false</UseOfMfc>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<PlatformToolset>v141</PlatformToolset>
<UseOfMfc>false</UseOfMfc>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<PlatformToolset>v141</PlatformToolset>
<UseOfMfc>false</UseOfMfc>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<PlatformToolset>v141</PlatformToolset>
<UseOfMfc>false</UseOfMfc>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC60.props" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC60.props" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC60.props" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC60.props" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup>
<_ProjectFileVersion>15.0.27924.0</_ProjectFileVersion>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
<IntDir>$(ProjectName)\$(Configuration)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
<IntDir>$(ProjectName)\$(Configuration)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
<IntDir>$(ProjectName)\$(Platform)\$(Configuration)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
<IntDir>$(ProjectName)\$(Platform)\$(Configuration)\</IntDir>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Midl>
<TypeLibraryName>.\Debug/toyvm.tlb</TypeLibraryName>
<HeaderFileName />
</Midl>
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>../;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MinimalRebuild>true</MinimalRebuild>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<PrecompiledHeaderOutputFile>.\Debug/toyvm.pch</PrecompiledHeaderOutputFile>
<WarningLevel>Level4</WarningLevel>
<SuppressStartupBanner>true</SuppressStartupBanner>
</ClCompile>
<ResourceCompile>
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<Culture>0x0411</Culture>
</ResourceCompile>
<Link>
<SuppressStartupBanner>true</SuppressStartupBanner>
<GenerateDebugInformation>true</GenerateDebugInformation>
<ProgramDatabaseFile>.\Debug/toyvm.pdb</ProgramDatabaseFile>
<SubSystem>Console</SubSystem>
<RandomizedBaseAddress>false</RandomizedBaseAddress>
<DataExecutionPrevention />
<TargetMachine>MachineX86</TargetMachine>
</Link>
<Bscmake>
<SuppressStartupBanner>true</SuppressStartupBanner>
</Bscmake>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Midl>
<TypeLibraryName>.\Release/toyvm.tlb</TypeLibraryName>
<HeaderFileName />
</Midl>
<ClCompile>
<Optimization>MaxSpeed</Optimization>
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
<AdditionalIncludeDirectories>../;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<StringPooling>true</StringPooling>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<FunctionLevelLinking>true</FunctionLevelLinking>
<PrecompiledHeaderOutputFile>.\Release/toyvm.pch</PrecompiledHeaderOutputFile>
<WarningLevel>Level4</WarningLevel>
<SuppressStartupBanner>true</SuppressStartupBanner>
</ClCompile>
<ResourceCompile>
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<Culture>0x0411</Culture>
</ResourceCompile>
<Link>
<SuppressStartupBanner>true</SuppressStartupBanner>
<SubSystem>Console</SubSystem>
<RandomizedBaseAddress>false</RandomizedBaseAddress>
<DataExecutionPrevention />
<TargetMachine>MachineX86</TargetMachine>
</Link>
<Bscmake>
<SuppressStartupBanner>true</SuppressStartupBanner>
</Bscmake>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Midl>
<TargetEnvironment>X64</TargetEnvironment>
<TypeLibraryName>.\Debug/toyvm.tlb</TypeLibraryName>
<HeaderFileName />
</Midl>
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>../;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MinimalRebuild>true</MinimalRebuild>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<PrecompiledHeaderOutputFile>.\Debug/toyvm.pch</PrecompiledHeaderOutputFile>
<WarningLevel>Level4</WarningLevel>
<SuppressStartupBanner>true</SuppressStartupBanner>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
</ClCompile>
<ResourceCompile>
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<Culture>0x0411</Culture>
</ResourceCompile>
<Link>
<SuppressStartupBanner>true</SuppressStartupBanner>
<GenerateDebugInformation>true</GenerateDebugInformation>
<ProgramDatabaseFile>.\Debug/toyvm.pdb</ProgramDatabaseFile>
<SubSystem>Console</SubSystem>
<RandomizedBaseAddress>false</RandomizedBaseAddress>
<DataExecutionPrevention />
<TargetMachine>MachineX64</TargetMachine>
</Link>
<Bscmake>
<SuppressStartupBanner>true</SuppressStartupBanner>
</Bscmake>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Midl>
<TargetEnvironment>X64</TargetEnvironment>
<TypeLibraryName>.\Release/toyvm.tlb</TypeLibraryName>
<HeaderFileName />
</Midl>
<ClCompile>
<Optimization>MaxSpeed</Optimization>
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
<AdditionalIncludeDirectories>../;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<StringPooling>true</StringPooling>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<FunctionLevelLinking>true</FunctionLevelLinking>
<PrecompiledHeaderOutputFile>.\Release/toyvm.pch</PrecompiledHeaderOutputFile>
<WarningLevel>Level4</WarningLevel>
<SuppressStartupBanner>true</SuppressStartupBanner>
</ClCompile>
<ResourceCompile>
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<Culture>0x0411</Culture>
</ResourceCompile>
<Link>
<SuppressStartupBanner>true</SuppressStartupBanner>
<SubSystem>Console</SubSystem>
<RandomizedBaseAddress>false</RandomizedBaseAddress>
<DataExecutionPrevention />
<TargetMachine>MachineX64</TargetMachine>
</Link>
<Bscmake>
<SuppressStartupBanner>true</SuppressStartupBanner>
</Bscmake>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="toyvm.cpp" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
-104
View File
@@ -1,104 +0,0 @@
TARGET = make_nm normalize_prefix bad_address misc cvt_test cvt_test32 noexception
XBYAK_INC=../xbyak/xbyak.h
UNAME_S=$(shell uname -s)
BIT=32
ifeq ($(shell uname -m),x86_64)
BIT=64
endif
ONLY_64BIT=0
ifeq ($(UNAME_S),Darwin)
# 32-bit binary is not supported
ONLY_64BIT=1
endif
ifeq ($(ONLY_64BIT),0)
TARGET += jmp address
endif
ifeq ($(BIT),64)
TARGET += jmp64 address64
endif
all: $(TARGET)
CFLAGS_WARN=-Wall -Wextra -Wformat=2 -Wcast-qual -Wcast-align -Wwrite-strings -Wfloat-equal -Wpointer-arith
CFLAGS=-O2 -fomit-frame-pointer -Wall -fno-operator-names -I../ -I./ $(CFLAGS_WARN) #-std=c++0x
make_nm:
$(CXX) $(CFLAGS) make_nm.cpp -o $@
normalize_prefix: normalize_prefix.cpp ../xbyak/xbyak.h
$(CXX) $(CFLAGS) normalize_prefix.cpp -o $@
test_mmx: test_mmx.cpp ../xbyak/xbyak.h
$(CXX) $(CFLAGS) test_mmx.cpp -o $@ -lpthread
jmp: jmp.cpp ../xbyak/xbyak.h
$(CXX) $(CFLAGS) jmp.cpp -o $@ -m32
jmp64: jmp.cpp ../xbyak/xbyak.h
$(CXX) $(CFLAGS) jmp.cpp -o $@ -m64
address: address.cpp ../xbyak/xbyak.h
$(CXX) $(CFLAGS) address.cpp -o $@ -m32
address64: address.cpp ../xbyak/xbyak.h
$(CXX) $(CFLAGS) address.cpp -o $@ -m64
bad_address: bad_address.cpp ../xbyak/xbyak.h
$(CXX) $(CFLAGS) bad_address.cpp -o $@
misc: misc.cpp ../xbyak/xbyak.h
$(CXX) $(CFLAGS) misc.cpp -o $@
cvt_test: cvt_test.cpp ../xbyak/xbyak.h
$(CXX) $(CFLAGS) $< -o $@
cvt_test32: cvt_test.cpp ../xbyak/xbyak.h
$(CXX) $(CFLAGS) $< -o $@ -DXBYAK32
noexception: noexception.cpp ../xbyak/xbyak.h
$(CXX) $(CFLAGS) $< -o $@ -fno-exceptions
test_nm: normalize_prefix $(TARGET)
$(MAKE) -C ../gen
ifneq ($(ONLY_64BIT),1)
./test_nm.sh
./test_nm.sh noexcept
./noexception
./test_nm.sh Y
./test_nm.sh avx512
./test_address.sh
./jmp
./cvt_test32
endif
./bad_address
./misc
./cvt_test
ifeq ($(BIT),64)
./test_address.sh 64
./test_nm.sh 64
./test_nm.sh Y64
./jmp64
endif
test_avx: normalize_prefix
ifneq ($(ONLY_64BIT),0)
./test_avx.sh
./test_avx.sh Y
endif
ifeq ($(BIT),64)
./test_address.sh 64
./test_avx.sh 64
./test_avx.sh Y64
endif
test_avx512: normalize_prefix
ifneq ($(ONLY_64BIT),0)
./test_avx512.sh
endif
ifeq ($(BIT),64)
./test_avx512.sh 64
endif
test:
$(MAKE) test_nm
$(MAKE) test_avx
$(MAKE) test_avx512
clean:
rm -rf *.o $(TARGET) lib_run nm.cpp nm_frame make_512
lib_run: lib_test.cpp lib_run.cpp lib.h
$(CXX) $(CFLAGS) lib_run.cpp lib_test.cpp -o lib_run
make_nm: make_nm.cpp $(XBYAK_INC)
-14
View File
@@ -1,14 +0,0 @@
OPT=/EHsc -I../xbyak /W4 -D_CRT_SECURE_NO_WARNINGS
../xbyak/xbyak_mnemonic.h: ../gen/gen_code.exe ../gen/gen_avx512.exe
../gen/gen_code.exe > $@
../gen/gen_avx512.exe >> $@
../gen/gen_code.exe: ../gen/gen_code.cpp #../xbyak/xbyak.h
cl ../gen/gen_code.cpp $(OPT) /Fe:../gen/gen_code.exe
../gen/gen_avx512.exe: ../gen/gen_avx512.cpp #../xbyak/xbyak.h
cl ../gen/gen_avx512.cpp $(OPT) /Fe:../gen/gen_avx512.exe
SUB_HEADER=../xbyak/xbyak_mnemonic.h
all: $(SUB_HEADER)
-9
View File
@@ -1,9 +0,0 @@
@echo off
echo 32bit
rm -rf a.lst b.lst
echo nasm
nasm -l a.lst -f win32 -DWIN32 test.asm
cat a.lst
echo yasm
yasm -l b.lst -f win32 -DWIN32 test.asm
cat b.lst
-155
View File
@@ -1,155 +0,0 @@
#include <stdio.h>
#include <string.h>
#define NUM_OF_ARRAY(x) (sizeof(x) / sizeof(x[0]))
void genVsibSub(bool isJIT, const char *name, const char *tbl[], size_t tblSize)
{
for (size_t i = 0; i < tblSize; i++) {
if (isJIT) {
printf("%s (ymm7, ptr[", name);
} else {
printf("%s ymm7, [", name);
}
printf("%s", tbl[i]);
if (isJIT) {
printf("], ymm4); dump();\n");
} else {
printf("], ymm4\n");
}
}
}
void genVsib(bool isJIT)
{
if (isJIT) puts("void genVsib() {");
const char *vm32xTbl[] = {
"xmm0",
"xmm0 * 1",
"xmm0 + 4",
"xmm0 + eax",
"xmm0 * 4 + ecx",
"xmm3 * 8 + edi + 123",
"xmm2 * 2 + 5",
"eax + xmm0",
"esp + xmm4",
};
const char *vm32yTbl[] = {
"ymm0",
"ymm0 * 1",
"ymm0 + 4",
"ymm0 + eax",
"ymm0 * 4 + ecx",
"ymm3 * 8 + edi + 123",
"ymm2 * 2 + 5",
"eax + ymm0",
"esp + ymm4",
};
genVsibSub(isJIT, "vgatherdpd", vm32xTbl, NUM_OF_ARRAY(vm32xTbl));
genVsibSub(isJIT, "vgatherqpd", vm32yTbl, NUM_OF_ARRAY(vm32yTbl));
#ifdef XBYAK64
const char *vm32x64Tbl[] = {
"xmm0 + r11",
"r13 + xmm15",
"123 + rsi + xmm2 * 4",
};
genVsibSub(isJIT, "vgatherdpd", vm32x64Tbl, NUM_OF_ARRAY(vm32x64Tbl));
#endif
if (isJIT) puts("}");
}
void genAddress(bool isJIT, const char regTbl[][5], size_t regTblNum)
{
int count = 0;
int funcNum = 1;
if (isJIT) {
puts("void gen0(){");
}
for (size_t i = 0; i < regTblNum + 1; i++) {
const char *base = regTbl[i];
for (size_t j = 0; j < regTblNum + 1; j++) {
if (j == 4) continue; /* esp is not index register */
const char *index = regTbl[j];
static const int scaleTbl[] = { 0, 1, 2, 4, 8 };
for (size_t k = 0; k < NUM_OF_ARRAY(scaleTbl); k++) {
int scale = scaleTbl[k];
static const int dispTbl[] = { 0, 1, 1000, -1, -1000 };
for (size_t m = 0; m < NUM_OF_ARRAY(dispTbl); m++) {
int disp = dispTbl[m];
bool isFirst = true;
if (isJIT) {
printf("mov (ecx, ptr[");
} else {
printf("mov ecx, [");
}
if (i < regTblNum) {
printf("%s", base);
isFirst = false;
}
if (j < regTblNum) {
if (!isFirst) putchar('+');
printf("%s", index);
if (scale) printf("*%d", scale);
isFirst = false;
}
if (isFirst) {
if (isJIT) printf("(void*)");
printf("0x%08X", disp);
} else {
if (disp >= 0) {
putchar('+');
}
printf("%d", disp);
isFirst = false;
}
if (isJIT) {
printf("]); dump();\n");
} else {
printf("]\n");
}
if (isJIT) {
count++;
if ((count % 100) == 0) {
printf("}\n void gen%d(){\n", funcNum++);
}
}
}
}
}
}
if (isJIT) puts("}");
genVsib(isJIT);
if (isJIT) {
printf("void gen(){\n");
for (int i = 0; i < funcNum; i++) {
printf(" gen%d();\n", i);
}
puts("genVsib();");
printf("}\n");
}
}
int main(int argc, char *argv[])
{
argc--, argv++;
bool phase = argc > 0 && strcmp(*argv, "1") == 0;
bool isJIT = (argc > 1);
fprintf(stderr, "phase:%c %s\n", phase ? '1' : '2', isJIT ? "jit" : "asm");
if (phase) {
fprintf(stderr, "32bit reg\n");
static const char reg32Tbl[][5] = {
"eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi",
#ifdef XBYAK64
"r9d", "r10d", "r11d", "r12d", "r13d", "r14d", "r15d",
#endif
};
genAddress(isJIT, reg32Tbl, NUM_OF_ARRAY(reg32Tbl));
} else {
#ifdef XBYAK64
fprintf(stderr, "64bit reg\n");
static const char reg64Tbl[][5] = {
"rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
};
genAddress(isJIT, reg64Tbl, NUM_OF_ARRAY(reg64Tbl));
#endif
}
}
-28
View File
@@ -1,28 +0,0 @@
#include <xbyak/xbyak.h>
#include <cybozu/test.hpp>
struct Code : Xbyak::CodeGenerator {
Code()
{
CYBOZU_TEST_EXCEPTION(mov(eax, ptr [esp + esp]), std::exception);
CYBOZU_TEST_EXCEPTION(mov(eax, ptr [ax]), std::exception); // not support
CYBOZU_TEST_EXCEPTION(mov(eax, ptr [esp * 4]), std::exception);
CYBOZU_TEST_EXCEPTION(mov(eax, ptr [eax * 16]), std::exception);
CYBOZU_TEST_EXCEPTION(mov(eax, ptr [eax + eax + eax]), std::exception);
CYBOZU_TEST_EXCEPTION(mov(eax, ptr [eax * 2 + ecx * 4]), std::exception);
CYBOZU_TEST_EXCEPTION(mov(eax, ptr [eax * 2 + ecx * 4]), std::exception);
CYBOZU_TEST_EXCEPTION(mov(eax, ptr [xmm0]), std::exception);
CYBOZU_TEST_EXCEPTION(fld(dword [xmm0]), std::exception);
CYBOZU_TEST_EXCEPTION(vgatherdpd(xmm0, ptr [eax * 2], ymm3), std::exception);
CYBOZU_TEST_EXCEPTION(vgatherdpd(xmm0, ptr [xmm0 + xmm1], ymm3), std::exception);
#ifdef XBYAK64
CYBOZU_TEST_EXCEPTION(mov(eax, ptr [rax + eax]), std::exception);
CYBOZU_TEST_EXCEPTION(mov(eax, ptr [xmm0 + ymm0]), std::exception);
#endif
}
};
CYBOZU_TEST_AUTO(exception)
{
Code c;
}
-151
View File
@@ -1,151 +0,0 @@
#define XBYAK_NO_OP_NAMES
#include <xbyak/xbyak.h>
#include <cybozu/inttype.hpp>
#include <cybozu/test.hpp>
using namespace Xbyak;
using namespace Xbyak::util;
#ifdef XBYAK64
const struct Ptn {
const Reg8 *reg8;
Reg16 reg16;
Reg32 reg32;
Reg64 reg64;
} tbl[] = {
{ &al, ax, eax, rax },
{ &bl, bx, ebx, rbx },
{ &cl, cx, ecx, rcx },
{ &dl, dx, edx, rdx },
{ &sil, si, esi, rsi },
{ &dil, di, edi, rdi },
{ &bpl, bp, ebp, rbp },
{ &spl, sp, esp, rsp },
{ &r8b, r8w, r8d, r8 },
{ &r9b, r9w, r9d, r9 },
{ &r10b, r10w, r10d, r10 },
{ &r11b, r11w, r11d, r11 },
{ &r12b, r12w, r12d, r12 },
{ &r13b, r13w, r13d, r13 },
{ &r14b, r14w, r14d, r14 },
{ &r15b, r15w, r15d, r15 },
};
#else
const struct Ptn {
const Reg8 *reg8;
Reg16 reg16;
Reg32 reg32;
} tbl[] = {
{ &al, ax, eax },
{ &bl, bx, ebx },
{ &cl, cx, ecx },
{ &dl, dx, edx },
{ 0, si, esi },
{ 0, di, edi },
{ 0, bp, ebp },
{ 0, sp, esp },
};
#endif
CYBOZU_TEST_AUTO(cvt)
{
for (size_t i = 0; i < sizeof(tbl) / sizeof(tbl[0]); i++) {
if (tbl[i].reg8) {
CYBOZU_TEST_ASSERT(tbl[i].reg8->cvt8() == *tbl[i].reg8);
CYBOZU_TEST_ASSERT(tbl[i].reg8->cvt16() == tbl[i].reg16);
CYBOZU_TEST_ASSERT(tbl[i].reg8->cvt32() == tbl[i].reg32);
CYBOZU_TEST_ASSERT(tbl[i].reg16.cvt8() == *tbl[i].reg8);
CYBOZU_TEST_ASSERT(tbl[i].reg32.cvt8() == *tbl[i].reg8);
}
CYBOZU_TEST_ASSERT(tbl[i].reg16.cvt16() == tbl[i].reg16);
CYBOZU_TEST_ASSERT(tbl[i].reg16.cvt32() == tbl[i].reg32);
CYBOZU_TEST_ASSERT(tbl[i].reg32.cvt16() == tbl[i].reg16);
CYBOZU_TEST_ASSERT(tbl[i].reg32.cvt32() == tbl[i].reg32);
#ifdef XBYAK64
if (tbl[i].reg8) {
CYBOZU_TEST_ASSERT(tbl[i].reg64.cvt8() == *tbl[i].reg8);
CYBOZU_TEST_ASSERT(tbl[i].reg8->cvt64() == tbl[i].reg64);
}
CYBOZU_TEST_ASSERT(tbl[i].reg64.cvt16() == tbl[i].reg16);
CYBOZU_TEST_ASSERT(tbl[i].reg64.cvt32() == tbl[i].reg32);
CYBOZU_TEST_ASSERT(tbl[i].reg64.cvt64() == tbl[i].reg64);
CYBOZU_TEST_ASSERT(tbl[i].reg16.cvt64() == tbl[i].reg64);
CYBOZU_TEST_ASSERT(tbl[i].reg32.cvt64() == tbl[i].reg64);
#endif
}
{
const Reg8 errTbl[] = {
ah, bh, ch, dh
};
for (size_t i = 0; i < sizeof(errTbl) / sizeof(errTbl[0]); i++) {
CYBOZU_TEST_EXCEPTION(errTbl[i].cvt16(), std::exception);
}
}
#ifdef XBYAK32
{
const Reg16 errTbl[] = {
si, di, bp, sp
};
for (size_t i = 0; i < sizeof(errTbl) / sizeof(errTbl[0]); i++) {
CYBOZU_TEST_EXCEPTION(errTbl[i].cvt8(), std::exception);
}
}
#endif
}
CYBOZU_TEST_AUTO(changeBit)
{
using namespace Xbyak::util;
#ifdef XBYAK64
const size_t N = 7;
const Reg* tbl[][N] = {
{ &al, &ax, &eax, &rax, &xmm0, &ymm0, &zmm0 },
{ &cl, &cx, &ecx, &rcx, &xmm1, &ymm1, &zmm1 },
{ &dl, &dx, &edx, &rdx, &xmm2, &ymm2, &zmm2 },
{ &bl, &bx, &ebx, &rbx, &xmm3, &ymm3, &zmm3 },
{ &spl, &sp, &esp, &rsp, &xmm4, &ymm4, &zmm4 },
{ &bpl, &bp, &ebp, &rbp, &xmm5, &ymm5, &zmm5 },
{ &sil, &si, &esi, &rsi, &xmm6, &ymm6, &zmm6 },
{ &dil, &di, &edi, &rdi, &xmm7, &ymm7, &zmm7 },
{ &r8b, &r8w, &r8d, &r8, &xmm8, &ymm8, &zmm8 },
{ &r15b, &r15w, &r15d, &r15, &xmm15, &ymm15, &zmm15 },
{ 0, 0, 0, 0, &xmm16, &ymm16, &zmm16 },
{ 0, 0, 0, 0, &xmm31, &ymm31, &zmm31 },
};
const int bitTbl[N] = { 8, 16, 32, 64, 128, 256, 512 };
#else
const size_t N = 6;
const Reg* tbl[][N] = {
{ &al, &ax, &eax, &xmm0, &ymm0, &zmm0 },
{ &cl, &cx, &ecx, &xmm1, &ymm1, &zmm1 },
{ &dl, &dx, &edx, &xmm2, &ymm2, &zmm2 },
{ &bl, &bx, &ebx, &xmm3, &ymm3, &zmm3 },
{ 0, &sp, &esp, &xmm4, &ymm4, &zmm4 },
{ 0, &bp, &ebp, &xmm5, &ymm5, &zmm5 },
{ 0, &si, &esi, &xmm6, &ymm6, &zmm6 },
{ 0, &di, &edi, &xmm7, &ymm7, &zmm7 },
};
const int bitTbl[N] = { 8, 16, 32, 128, 256, 512 };
#endif
for (size_t i = 0; i < CYBOZU_NUM_OF_ARRAY(tbl); i++) {
for (size_t j = 0; j < N; j++) {
const Reg *r1 = tbl[i][j];
if (r1 == 0) continue;
for (size_t k = 0; k < N; k++) {
if (tbl[i][k]) {
CYBOZU_TEST_ASSERT(*tbl[i][k] == r1->changeBit(bitTbl[k]));
// printf("%s->changeBit(%d)=%s %s\n", r1->toString(), bitTbl[k], r1->changeBit(bitTbl[k]).toString(), tbl[i][k]->toString());
} else {
CYBOZU_TEST_EXCEPTION(r1->changeBit(bitTbl[k]), std::exception);
}
}
}
}
#ifdef XBYAK64
const Reg8 *special8bitTbl[] = { &ah, &bh, &ch, &dh };
for (size_t i = 0; i < CYBOZU_NUM_OF_ARRAY(special8bitTbl); i++) {
CYBOZU_TEST_EXCEPTION(special8bitTbl[i]->changeBit(16), std::exception);
}
#endif
}
-163
View File
@@ -1,163 +0,0 @@
#pragma once
/**
@file
@brief int type definition and macros
@author MITSUNARI Shigeo(@herumi)
*/
#if defined(_MSC_VER) && (MSC_VER <= 1500) && !defined(CYBOZU_DEFINED_INTXX)
#define CYBOZU_DEFINED_INTXX
typedef __int64 int64_t;
typedef unsigned __int64 uint64_t;
typedef unsigned int uint32_t;
typedef int int32_t;
typedef unsigned short uint16_t;
typedef short int16_t;
typedef unsigned char uint8_t;
typedef signed char int8_t;
#else
#include <stdint.h>
#endif
#ifdef _MSC_VER
#ifndef CYBOZU_DEFINED_SSIZE_T
#define CYBOZU_DEFINED_SSIZE_T
#ifdef _WIN64
typedef int64_t ssize_t;
#else
typedef int32_t ssize_t;
#endif
#endif
#else
#include <unistd.h> // for ssize_t
#endif
#ifndef CYBOZU_ALIGN
#ifdef _MSC_VER
#define CYBOZU_ALIGN(x) __declspec(align(x))
#else
#define CYBOZU_ALIGN(x) __attribute__((aligned(x)))
#endif
#endif
#ifndef CYBOZU_FORCE_INLINE
#ifdef _MSC_VER
#define CYBOZU_FORCE_INLINE __forceinline
#else
#define CYBOZU_FORCE_INLINE __attribute__((always_inline))
#endif
#endif
#ifndef CYBOZU_UNUSED
#ifdef __GNUC__
#define CYBOZU_UNUSED __attribute__((unused))
#else
#define CYBOZU_UNUSED
#endif
#endif
#ifndef CYBOZU_ALLOCA
#ifdef _MSC_VER
#include <malloc.h>
#define CYBOZU_ALLOCA(x) _malloca(x)
#else
#define CYBOZU_ALLOCA(x) __builtin_alloca(x)
#endif
#endif
#ifndef CYBOZU_NUM_OF_ARRAY
#define CYBOZU_NUM_OF_ARRAY(x) (sizeof(x) / sizeof(*x))
#endif
#ifndef CYBOZU_SNPRINTF
#if defined(_MSC_VER) && (_MSC_VER < 1900)
#define CYBOZU_SNPRINTF(x, len, ...) (void)_snprintf_s(x, len, len - 1, __VA_ARGS__)
#else
#define CYBOZU_SNPRINTF(x, len, ...) (void)snprintf(x, len, __VA_ARGS__)
#endif
#endif
#define CYBOZU_CPP_VERSION_CPP03 0
#define CYBOZU_CPP_VERSION_TR1 1
#define CYBOZU_CPP_VERSION_CPP11 2
#define CYBOZU_CPP_VERSION_CPP14 3
#define CYBOZU_CPP_VERSION_CPP17 4
#ifdef __GNUC__
#define CYBOZU_GNUC_PREREQ(major, minor) ((__GNUC__) * 100 + (__GNUC_MINOR__) >= (major) * 100 + (minor))
#else
#define CYBOZU_GNUC_PREREQ(major, minor) 0
#endif
#if (__cplusplus >= 201703)
#define CYBOZU_CPP_VERSION CYBOZU_CPP_VERSION_CPP17
#elif (__cplusplus >= 201402)
#define CYBOZU_CPP_VERSION CYBOZU_CPP_VERSION_CPP14
#elif (__cplusplus >= 201103) || (_MSC_VER >= 1500) || defined(__GXX_EXPERIMENTAL_CXX0X__)
#if defined(_MSC_VER) && (_MSC_VER <= 1600)
#define CYBOZU_CPP_VERSION CYBOZU_CPP_VERSION_TR1
#else
#define CYBOZU_CPP_VERSION CYBOZU_CPP_VERSION_CPP11
#endif
#elif CYBOZU_GNUC_PREREQ(4, 5) || (CYBOZU_GNUC_PREREQ(4, 2) && __GLIBCXX__ >= 20070719) || defined(__INTEL_COMPILER) || (__clang_major__ >= 3)
#define CYBOZU_CPP_VERSION CYBOZU_CPP_VERSION_TR1
#else
#define CYBOZU_CPP_VERSION CYBOZU_CPP_VERSION_CPP03
#endif
#ifdef CYBOZU_USE_BOOST
#define CYBOZU_NAMESPACE_STD boost
#define CYBOZU_NAMESPACE_TR1_BEGIN
#define CYBOZU_NAMESPACE_TR1_END
#elif (CYBOZU_CPP_VERSION == CYBOZU_CPP_VERSION_TR1) && !defined(__APPLE__)
#define CYBOZU_NAMESPACE_STD std::tr1
#define CYBOZU_NAMESPACE_TR1_BEGIN namespace tr1 {
#define CYBOZU_NAMESPACE_TR1_END }
#else
#define CYBOZU_NAMESPACE_STD std
#define CYBOZU_NAMESPACE_TR1_BEGIN
#define CYBOZU_NAMESPACE_TR1_END
#endif
#ifndef CYBOZU_OS_BIT
#if defined(_WIN64) || defined(__x86_64__) || defined(__AARCH64EL__) || defined(__EMSCRIPTEN__)
#define CYBOZU_OS_BIT 64
#else
#define CYBOZU_OS_BIT 32
#endif
#endif
#ifndef CYBOZU_HOST
#define CYBOZU_HOST_UNKNOWN 0
#define CYBOZU_HOST_INTEL 1
#define CYBOZU_HOST_ARM 2
#if defined(_M_IX86) || defined(_M_AMD64) || defined(__x86_64__) || defined(__i386__)
#define CYBOZU_HOST CYBOZU_HOST_INTEL
#elif defined(__arm__) || defined(__AARCH64EL__)
#define CYBOZU_HOST CYBOZU_HOST_ARM
#else
#define CYBOZU_HOST CYBOZU_HOST_UNKNOWN
#endif
#endif
#ifndef CYBOZU_ENDIAN
#define CYBOZU_ENDIAN_UNKNOWN 0
#define CYBOZU_ENDIAN_LITTLE 1
#define CYBOZU_ENDIAN_BIG 2
#if (CYBOZU_HOST == CYBOZU_HOST_INTEL)
#define CYBOZU_ENDIAN CYBOZU_ENDIAN_LITTLE
#elif (CYBOZU_HOST == CYBOZU_HOST_ARM) && (defined(__ARM_EABI__) || defined(__AARCH64EL__))
#define CYBOZU_ENDIAN CYBOZU_ENDIAN_LITTLE
#else
#define CYBOZU_ENDIAN CYBOZU_ENDIAN_UNKNOWN
#endif
#endif
#if CYBOZU_CPP_VERSION >= CYBOZU_CPP_VERSION_CPP11
#define CYBOZU_NOEXCEPT noexcept
#else
#define CYBOZU_NOEXCEPT throw()
#endif
namespace cybozu {
template<class T>
void disable_warning_unused_variable(const T&) { }
template<class T, class S>
T cast(const S* ptr) { return static_cast<T>(static_cast<const void*>(ptr)); }
template<class T, class S>
T cast(S* ptr) { return static_cast<T>(static_cast<void*>(ptr)); }
} // cybozu
-373
View File
@@ -1,373 +0,0 @@
#pragma once
/**
@file
@brief unit test class
@author MITSUNARI Shigeo(@herumi)
*/
#include <stdio.h>
#include <string.h>
#include <string>
#include <list>
#include <iostream>
#include <utility>
#if defined(_MSC_VER) && (MSC_VER <= 1500)
#include <cybozu/inttype.hpp>
#else
#include <stdint.h>
#endif
namespace cybozu { namespace test {
class AutoRun {
typedef void (*Func)();
typedef std::list<std::pair<const char*, Func> > UnitTestList;
public:
AutoRun()
: init_(0)
, term_(0)
, okCount_(0)
, ngCount_(0)
, exceptionCount_(0)
{
}
void setup(Func init, Func term)
{
init_ = init;
term_ = term;
}
void append(const char *name, Func func)
{
list_.push_back(std::make_pair(name, func));
}
void set(bool isOK)
{
if (isOK) {
okCount_++;
} else {
ngCount_++;
}
}
std::string getBaseName(const std::string& name) const
{
#ifdef _WIN32
const char sep = '\\';
#else
const char sep = '/';
#endif
size_t pos = name.find_last_of(sep);
std::string ret = name.substr(pos + 1);
pos = ret.find('.');
return ret.substr(0, pos);
}
int run(int, char *argv[])
{
std::string msg;
try {
if (init_) init_();
for (UnitTestList::const_iterator i = list_.begin(), ie = list_.end(); i != ie; ++i) {
std::cout << "ctest:module=" << i->first << std::endl;
try {
(i->second)();
} catch (std::exception& e) {
exceptionCount_++;
std::cout << "ctest: " << i->first << " is stopped by exception " << e.what() << std::endl;
} catch (...) {
exceptionCount_++;
std::cout << "ctest: " << i->first << " is stopped by unknown exception" << std::endl;
}
}
if (term_) term_();
} catch (std::exception& e) {
msg = std::string("ctest:err:") + e.what();
} catch (...) {
msg = "ctest:err: catch unknown exception";
}
fflush(stdout);
if (msg.empty()) {
int err = ngCount_ + exceptionCount_;
int total = okCount_ + err;
std::cout << "ctest:name=" << getBaseName(*argv)
<< ", module=" << list_.size()
<< ", total=" << total
<< ", ok=" << okCount_
<< ", ng=" << ngCount_
<< ", exception=" << exceptionCount_ << std::endl;
return err > 0 ? 1 : 0;
} else {
std::cout << msg << std::endl;
return 1;
}
}
static inline AutoRun& getInstance()
{
static AutoRun instance;
return instance;
}
private:
Func init_;
Func term_;
int okCount_;
int ngCount_;
int exceptionCount_;
UnitTestList list_;
};
static AutoRun& autoRun = AutoRun::getInstance();
inline void test(bool ret, const std::string& msg, const std::string& param, const char *file, int line)
{
autoRun.set(ret);
if (!ret) {
printf("%s(%d):ctest:%s(%s);\n", file, line, msg.c_str(), param.c_str());
}
}
template<typename T, typename U>
bool isEqual(const T& lhs, const U& rhs)
{
return lhs == rhs;
}
// avoid warning of comparision of integers of different signs
inline bool isEqual(size_t lhs, int rhs)
{
return lhs == size_t(rhs);
}
inline bool isEqual(int lhs, size_t rhs)
{
return size_t(lhs) == rhs;
}
inline bool isEqual(const char *lhs, const char *rhs)
{
return strcmp(lhs, rhs) == 0;
}
inline bool isEqual(char *lhs, const char *rhs)
{
return strcmp(lhs, rhs) == 0;
}
inline bool isEqual(const char *lhs, char *rhs)
{
return strcmp(lhs, rhs) == 0;
}
inline bool isEqual(char *lhs, char *rhs)
{
return strcmp(lhs, rhs) == 0;
}
// avoid to compare float directly
inline bool isEqual(float lhs, float rhs)
{
union fi {
float f;
uint32_t i;
} lfi, rfi;
lfi.f = lhs;
rfi.f = rhs;
return lfi.i == rfi.i;
}
// avoid to compare double directly
inline bool isEqual(double lhs, double rhs)
{
union di {
double d;
uint64_t i;
} ldi, rdi;
ldi.d = lhs;
rdi.d = rhs;
return ldi.i == rdi.i;
}
} } // cybozu::test
#ifndef CYBOZU_TEST_DISABLE_AUTO_RUN
int main(int argc, char *argv[])
{
return cybozu::test::autoRun.run(argc, argv);
}
#endif
/**
alert if !x
@param x [in]
*/
#define CYBOZU_TEST_ASSERT(x) cybozu::test::test(!!(x), "CYBOZU_TEST_ASSERT", #x, __FILE__, __LINE__)
/**
alert if x != y
@param x [in]
@param y [in]
*/
#define CYBOZU_TEST_EQUAL(x, y) { \
bool _cybozu_eq = cybozu::test::isEqual(x, y); \
cybozu::test::test(_cybozu_eq, "CYBOZU_TEST_EQUAL", #x ", " #y, __FILE__, __LINE__); \
if (!_cybozu_eq) { \
std::cout << "ctest: lhs=" << (x) << std::endl; \
std::cout << "ctest: rhs=" << (y) << std::endl; \
} \
}
/**
alert if fabs(x, y) >= eps
@param x [in]
@param y [in]
*/
#define CYBOZU_TEST_NEAR(x, y, eps) { \
bool _cybozu_isNear = fabs((x) - (y)) < eps; \
cybozu::test::test(_cybozu_isNear, "CYBOZU_TEST_NEAR", #x ", " #y, __FILE__, __LINE__); \
if (!_cybozu_isNear) { \
std::cout << "ctest: lhs=" << (x) << std::endl; \
std::cout << "ctest: rhs=" << (y) << std::endl; \
} \
}
#define CYBOZU_TEST_EQUAL_POINTER(x, y) { \
bool _cybozu_eq = x == y; \
cybozu::test::test(_cybozu_eq, "CYBOZU_TEST_EQUAL_POINTER", #x ", " #y, __FILE__, __LINE__); \
if (!_cybozu_eq) { \
std::cout << "ctest: lhs=" << static_cast<const void*>(x) << std::endl; \
std::cout << "ctest: rhs=" << static_cast<const void*>(y) << std::endl; \
} \
}
/**
alert if x[] != y[]
@param x [in]
@param y [in]
@param n [in]
*/
#define CYBOZU_TEST_EQUAL_ARRAY(x, y, n) { \
for (size_t _cybozu_test_i = 0, _cybozu_ie = (size_t)(n); _cybozu_test_i < _cybozu_ie; _cybozu_test_i++) { \
bool _cybozu_eq = cybozu::test::isEqual((x)[_cybozu_test_i], (y)[_cybozu_test_i]); \
cybozu::test::test(_cybozu_eq, "CYBOZU_TEST_EQUAL_ARRAY", #x ", " #y ", " #n, __FILE__, __LINE__); \
if (!_cybozu_eq) { \
std::cout << "ctest: i=" << _cybozu_test_i << std::endl; \
std::cout << "ctest: lhs=" << (x)[_cybozu_test_i] << std::endl; \
std::cout << "ctest: rhs=" << (y)[_cybozu_test_i] << std::endl; \
} \
} \
}
/**
always alert
@param msg [in]
*/
#define CYBOZU_TEST_FAIL(msg) cybozu::test::test(false, "CYBOZU_TEST_FAIL", msg, __FILE__, __LINE__)
/**
verify message in exception
*/
#define CYBOZU_TEST_EXCEPTION_MESSAGE(statement, Exception, msg) \
{ \
int _cybozu_ret = 0; \
std::string _cybozu_errMsg; \
try { \
statement; \
_cybozu_ret = 1; \
} catch (const Exception& _cybozu_e) { \
_cybozu_errMsg = _cybozu_e.what(); \
if (_cybozu_errMsg.find(msg) == std::string::npos) { \
_cybozu_ret = 2; \
} \
} catch (...) { \
_cybozu_ret = 3; \
} \
if (_cybozu_ret) { \
cybozu::test::test(false, "CYBOZU_TEST_EXCEPTION_MESSAGE", #statement ", " #Exception ", " #msg, __FILE__, __LINE__); \
if (_cybozu_ret == 1) { \
std::cout << "ctest: no exception" << std::endl; \
} else if (_cybozu_ret == 2) { \
std::cout << "ctest: bad exception msg:" << _cybozu_errMsg << std::endl; \
} else { \
std::cout << "ctest: unexpected exception" << std::endl; \
} \
} else { \
cybozu::test::autoRun.set(true); \
} \
}
#define CYBOZU_TEST_EXCEPTION(statement, Exception) \
{ \
int _cybozu_ret = 0; \
try { \
statement; \
_cybozu_ret = 1; \
} catch (const Exception&) { \
} catch (...) { \
_cybozu_ret = 2; \
} \
if (_cybozu_ret) { \
cybozu::test::test(false, "CYBOZU_TEST_EXCEPTION", #statement ", " #Exception, __FILE__, __LINE__); \
if (_cybozu_ret == 1) { \
std::cout << "ctest: no exception" << std::endl; \
} else { \
std::cout << "ctest: unexpected exception" << std::endl; \
} \
} else { \
cybozu::test::autoRun.set(true); \
} \
}
/**
verify statement does not throw
*/
#define CYBOZU_TEST_NO_EXCEPTION(statement) \
try { \
statement; \
cybozu::test::autoRun.set(true); \
} catch (...) { \
cybozu::test::test(false, "CYBOZU_TEST_NO_EXCEPTION", #statement, __FILE__, __LINE__); \
}
/**
append auto unit test
@param name [in] module name
*/
#define CYBOZU_TEST_AUTO(name) \
void cybozu_test_ ## name(); \
struct cybozu_test_local_ ## name { \
cybozu_test_local_ ## name() \
{ \
cybozu::test::autoRun.append(#name, cybozu_test_ ## name); \
} \
} cybozu_test_local_instance_ ## name; \
void cybozu_test_ ## name()
/**
append auto unit test with fixture
@param name [in] module name
*/
#define CYBOZU_TEST_AUTO_WITH_FIXTURE(name, Fixture) \
void cybozu_test_ ## name(); \
void cybozu_test_real_ ## name() \
{ \
Fixture f; \
cybozu_test_ ## name(); \
} \
struct cybozu_test_local_ ## name { \
cybozu_test_local_ ## name() \
{ \
cybozu::test::autoRun.append(#name, cybozu_test_real_ ## name); \
} \
} cybozu_test_local_instance_ ## name; \
void cybozu_test_ ## name()
/**
setup fixture
@param Fixture [in] class name of fixture
@note cstr of Fixture is called before test and dstr of Fixture is called after test
*/
#define CYBOZU_TEST_SETUP_FIXTURE(Fixture) \
Fixture *cybozu_test_local_fixture; \
void cybozu_test_local_init() \
{ \
cybozu_test_local_fixture = new Fixture(); \
} \
void cybozu_test_local_term() \
{ \
delete cybozu_test_local_fixture; \
} \
struct cybozu_test_local_fixture_setup_ { \
cybozu_test_local_fixture_setup_() \
{ \
cybozu::test::autoRun.setup(cybozu_test_local_init, cybozu_test_local_term); \
} \
} cybozu_test_local_fixture_setup_instance_;
File diff suppressed because it is too large. Load diff
-20
View File
@@ -1,20 +0,0 @@
þ½Ž¿
Microsoft Visual Studio Solution File, Format Version 10.00
# Visual C++ Express 2008
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "jmp", "jmp.vcproj", "{AC0B3317-E988-44F8-954A-BCBE4B3BB2BF}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
Release|Win32 = Release|Win32
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{AC0B3317-E988-44F8-954A-BCBE4B3BB2BF}.Debug|Win32.ActiveCfg = Debug|Win32
{AC0B3317-E988-44F8-954A-BCBE4B3BB2BF}.Debug|Win32.Build.0 = Debug|Win32
{AC0B3317-E988-44F8-954A-BCBE4B3BB2BF}.Release|Win32.ActiveCfg = Release|Win32
{AC0B3317-E988-44F8-954A-BCBE4B3BB2BF}.Release|Win32.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal
-195
View File
@@ -1,195 +0,0 @@
<?xml version="1.0" encoding="shift_jis"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="9.00"
Name="jmp"
ProjectGUID="{AC0B3317-E988-44F8-954A-BCBE4B3BB2BF}"
RootNamespace="jmp"
Keyword="Win32Proj"
TargetFrameworkVersion="196613"
>
<Platforms>
<Platform
Name="Win32"
/>
</Platforms>
<ToolFiles>
</ToolFiles>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="1"
CharacterSet="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="$(SolutionDir)/../"
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="3"
UsePrecompiledHeader="0"
WarningLevel="3"
DebugInformationFormat="4"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
LinkIncremental="2"
GenerateDebugInformation="true"
SubSystem="1"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="1"
CharacterSet="1"
WholeProgramOptimization="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="2"
EnableIntrinsicFunctions="true"
AdditionalIncludeDirectories="$(SolutionDir)/../"
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
RuntimeLibrary="2"
EnableFunctionLevelLinking="true"
UsePrecompiledHeader="0"
WarningLevel="3"
DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
LinkIncremental="1"
GenerateDebugInformation="true"
SubSystem="1"
OptimizeReferences="2"
EnableCOMDATFolding="2"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="ソース ファイル"
Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
>
<File
RelativePath=".\jmp.cpp"
>
</File>
</Filter>
<Filter
Name="ヘッダー ファイル"
Filter="h;hpp;hxx;hm;inl;inc;xsd"
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
>
</Filter>
<Filter
Name="リソース ファイル"
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
>
</Filter>
</Files>
<Globals>
</Globals>
</VisualStudioProject>
-63
View File
@@ -1,63 +0,0 @@
#pragma once
#include <stdio.h>
struct Reg {
int r_;
Reg(int r) : r_(r) {}
};
inline const Reg& getReg0() { static const Reg r(0); return r; }
inline const Reg& getReg1() { static const Reg r(1); return r; }
inline const Reg& getReg2() { static const Reg r(2); return r; }
static const Reg& r0 = getReg0();
static const Reg& r1 = getReg1();
static const Reg& r2 = getReg2();
inline void putReg()
{
puts("putReg");
printf("r0=%p, %d\n", &r0, r0.r_);
printf("r0=%p, %d\n", &r0, r1.r_);
printf("r0=%p, %d\n", &r0, r2.r_);
}
struct A {
int a;
A()
: a(5)
{
puts("A cstr");
}
~A()
{
puts("A dstr");
}
void put() const
{
printf("a=%d\n", a);
}
};
template<int dummy = 0>
struct XT {
static A a;
};
template<int dummy>
A XT<dummy>::a;
typedef XT<0> X;
void init();
struct Init {
Init()
{
puts("Init");
init();
putReg();
}
};
static Init s_init;
Loaded 100 of 353 files, more files were not shown because too many files have changed in this diff. Show more