Compare commits

..

73 Commits

Author SHA1 Message Date
GreemDev
b7dd718d6f use lambda-based config modifier insstead of manually setting a bool to true 2025-12-22 00:13:53 -06:00
GreemDev
6ee7957574 use a helper to get key path instead of checking mode & userpath existing every time 2025-12-19 23:15:23 -06:00
GreemDev
bf62531802 unused property 2025-12-19 23:15:23 -06:00
GreemDev
17be50ea80 Update title with page 2025-12-19 23:15:23 -06:00
GreemDev
ec50a1ec3e rename markup imported xml namespace to ext to match the rest of the codebase 2025-12-19 23:15:23 -06:00
GreemDev
5a20047e5e forgot to string.Format gamedir page desc 2025-12-19 23:15:23 -06:00
GreemDev
f9fed4cf4d make page desc smaller 2025-12-19 23:15:23 -06:00
GreemDev
2970dcd3c7 Localize all (I think...) previously hardcoded english strings in the setup wizard 2025-12-19 23:15:23 -06:00
GreemDev
4be6cb2fa1 oops 2025-12-19 23:15:23 -06:00
GreemDev
c90d2af9cd game dir setup
known bugs are a missing prod.keys popup after setup (how), as well as the dialog for autoload kinda cluttering up the screen after you hit next on the game dir page
2025-12-19 23:15:23 -06:00
GreemDev
13ff9cb162 Separate firmware avatar loading from the selector view model
This is going to be used for the setup wizard (probably)
2025-12-19 23:15:23 -06:00
GreemDev
b35ba58831 rewrite EmbeddedAvaloniaResources 2025-12-19 23:15:23 -06:00
GreemDev
e12a77d4a3 add a setup finished screen
added the ability to hide the help button (basically just for the finish screen, because it has a bigger discord button in the same place)
holding shift while opening the setup wizard now opens it in passive mode, aka it will install only what you need. this is mostly for testing and likely will be nuked before this code as a whole is made part of the official emulator, but it might not
2025-12-19 23:15:23 -06:00
GreemDev
804a4e0bcb reduce logo crunching 2025-12-19 23:15:23 -06:00
GreemDev
94870eafaa further simplify pagebuilding by embedding the desired title locale key in the context base type 2025-12-19 23:15:23 -06:00
GreemDev
7e6cc31866 cleanup usings 2025-12-19 23:15:23 -06:00
GreemDev
3b25c43abf reorganize RyujinxSetupWizard
additionally, the CreateHelpContent method is now no longer locked to returning an Avalonia `Control`.
the WithHelpContent method also has logic to handle it returning a string directly, and will wrap it in a textblock with h1 style and size 20 font. otherwise it's up to the ContentPresenter for the help content to choose how to display it if it's none of the above mentioned types.
2025-12-19 23:15:23 -06:00
GreemDev
1804dd031b oops
i left in my very professional logger debugging
2025-12-19 23:15:23 -06:00
GreemDev
211498e060 Overhaul setup wizard help pages
the context can now override a virtual method named `CreateHelpContent` which the setup wizard system will automatically try to use when you use the generic overload taking a generic context type. If the return is null, it skips setting entirely (the default impl is null)

additionally made the discord join link a button with code copied from the about window, and made it centered at the bottom.
2025-12-19 23:15:23 -06:00
GreemDev
4bdee89288 small cleanup 2025-12-19 23:15:23 -06:00
GreemDev
d8a6364cca rename NotificationHelper to RyujinxNotificationManager,
rename instance method names.
Additionally clarified what the math is in the notification manager margin parameter.
2025-12-19 23:15:23 -06:00
GreemDev
2f794794c6 use the margin to force it to show bottom center
(boy i sure do hope this doesnt have any adverse effects on anything but my specific resolution & scaling configuration!)
2025-12-19 23:15:23 -06:00
GreemDev
1d6c2426df OOPS broke the setup wizard :3 2025-12-19 23:15:23 -06:00
GreemDev
6cd03f15fa cleanup 2025-12-19 23:15:23 -06:00
GreemDev
3fe7600382 add "overwrite mode" for the setup wizard, basically this just ignores the precondition of having whatever the page configures before showing it.
i.e. if you had keys installed, previously it'd skip right to firmware.

additionally added more customization to the now instance-based NotificationHelper
2025-12-19 23:15:23 -06:00
GreemDev
dc2aa837b3 Setup Wizard restructuring
- Remove polymorphic base, this only existed because TKMM has a desktop/switch setup prodecure difference and has 2 implementations of the setup wizard. We only need one.
- Remove Systems/UI file split, they're all in Ryujinx.Ava.UI now
- made NotificationHelper instance-based to allow you to encapsulate notifications to a window that magically disappear when the window is closed, instead of switching to showing on the main window.
2025-12-19 23:15:22 -06:00
GreemDev
133ac41425 Bake setup step logic into the view models themselves instead of being in the setup wizard implementation
renamed view models to contexts (like TKMM), however the contexts here are actually of a unique base type; containing aforementioned setup step logic. if the return value is of an error state result, it will prompt a retry of the page.
2025-12-19 23:15:22 -06:00
GreemDev
fd2ecee479 fix "could not find part of path" error when installing firmware 2025-12-19 23:15:22 -06:00
GreemDev
8f529d17a8 combine SetupWizardPage and the builder type since the builder mutated an instance of the built type anyways 2025-12-19 23:15:22 -06:00
GreemDev
884d0f526c treat configuration load fail as first start (so you're prompted to set the game/autoload dirs, when that step is implemented) 2025-12-19 23:15:22 -06:00
GreemDev
c5b325bde2 add a setup wizard opener in the help dropdown in the menu bar, that also respects CanShowSetupWizard 2025-12-19 23:15:22 -06:00
GreemDev
8ab851ead8 move more of the setup wizard logic into the setup wizard itself instead of having some critical logic in a random lambda in MainWindow.axaml.cs 2025-12-19 23:15:22 -06:00
GreemDev
5a060cf451 fixup namespaces (again) 2025-12-19 23:15:22 -06:00
GreemDev
9b0fa3bf6d content & viewmodel object creation helper with out param, touch up firmware install step 2025-12-19 23:15:22 -06:00
GreemDev
325e13a490 fix: require valid key installations before moving onto firmware setup step 2025-12-19 23:15:22 -06:00
GreemDev
e202cccc6e firmware stage 2025-12-19 23:15:22 -06:00
GreemDev
e0ed8f56ea cleanup 2025-12-19 23:15:22 -06:00
GreemDev
46b2fb92d7 more namespace fixes 2025-12-19 23:15:22 -06:00
GreemDev
8563e7d4dc use a custom key install function with notifications instead of the normal one with dialogs 2025-12-19 23:15:22 -06:00
GreemDev
ee10cbf735 cleanup 2025-12-19 23:15:22 -06:00
GreemDev
b033adbde7 Initial work on a setup wizard
Setup wizard abstraction & architecture from TKMM
2025-12-19 23:15:22 -06:00
GreemDev
66f339d265 CI 2.0 (ryubing/ryujinx!237)
See merge request ryubing/ryujinx!237
2025-12-18 22:56:50 -06:00
GreemDev
6cdbdfd329 [ci skip] Pin GitLabCli to 1.4.1 in CI scripts so I can test v2.0 2025-12-18 03:27:43 -06:00
GreemDev
9f817d60d5 oops 2025-12-18 03:05:42 -06:00
GreemDev
5cffc95be6 Make all OSes build on Linux (7zip has a linux version) 2025-12-18 03:01:22 -06:00
LotP
2c0977f6b3 fix pre-action crash (ryubing/ryujinx!236)
See merge request ryubing/ryujinx!236
2025-12-12 14:28:54 -06:00
LotP
3a593b6084 Fix kaddressarbiter crash (ryubing/ryujinx!235)
See merge request ryubing/ryujinx!235
2025-12-06 20:16:43 -06:00
LotP
c3155fcadb Memory Changes 3.2 (ryubing/ryujinx!234)
See merge request ryubing/ryujinx!234
2025-12-06 17:19:19 -06:00
LotP
fd7554425a Update BiquadFilterEffectParameter2.cs (ryubing/ryujinx!233)
See merge request ryubing/ryujinx!233
2025-12-05 07:53:09 -06:00
Princess Piplup
52700f71dc Fix SaveCurrentScreenshot (ryubing/ryujinx!230)
See merge request ryubing/ryujinx!230
2025-12-04 17:35:17 -06:00
Alula
b018a44ff0 Disable coredumps by default on Linux + other minor fixes (ryubing/ryujinx!204)
See merge request ryubing/ryujinx!204
2025-12-04 17:32:26 -06:00
GreemDev
d522bfef62 fix: Force the key install helper to delete key files before copying (not sure why the overwrite boolean does nothing for File.Copy) 2025-12-02 21:23:06 -06:00
KeatonTheBot
39f55b2af3 cpu: Protect against stack overflow caused by deep recursion (ryubing/ryujinx!111)
See merge request ryubing/ryujinx!111
2025-11-19 20:50:23 -06:00
Goodfeat
6126e3dc1e fix: UI: Custom setting was reset to global when changed during gameplay. (ryubing/ryujinx!164)
See merge request ryubing/ryujinx!164
2025-11-19 20:33:35 -06:00
GreemDev
e1c829f91d We no longer offer a dedicated headless build. This script could have been deleted like a year ago lol 2025-11-17 22:47:23 -06:00
Babib3l
6c7dc7646b Translation updates (ryubing/ryujinx!221)
See merge request ryubing/ryujinx!221
2025-11-17 22:34:54 -06:00
GreemDev
862a686c5e UI: Improve "Show Changelog" button in the updater
Now it no longer causes the dialog to disappear (which then promptly re-appears so you can click yes/no to accept/deny the update)
2025-11-17 00:15:58 -06:00
GreemDev
e8751e1c40 more C# 14 partial properties 2025-11-16 19:14:26 -06:00
GreemDev
09748b140a Use the new C# 14 null propagation setter 2025-11-16 19:14:26 -06:00
Coxxs
456db46065 Stub IWriterForApplication: 0 (CreateContextRegistrar) (ryubing/ryujinx!183)
See merge request ryubing/ryujinx!183
2025-11-16 18:24:41 -06:00
GreemDev
7b39ff36c0 docs: compat: ZA LDN works and has for a while 2025-11-16 00:30:37 -06:00
Maki
10476771d3 fix: detect face button layout for gamepads (ryubing/ryujinx!219)
See merge request ryubing/ryujinx!219
2025-11-14 12:51:53 -06:00
Maki
c5082ac85a fix: make controller GUIDs match old SDL2 GUIDs (ryubing/ryujinx!218)
See merge request ryubing/ryujinx!218
2025-11-14 11:52:42 -06:00
GreemDev
5e86ad83cc feature: macOS Liquid Glass dynamic icon
No more squircle jail! Thanks @transistor.exe in the Ryubing discord for dropping the asset files for this to happen.
2025-11-13 20:47:05 -06:00
Coxxs
1baaa1c365 Preserve and rename the configuration file when it is deemed invalid (ryubing/ryujinx!216)
See merge request ryubing/ryujinx!216
2025-11-12 08:23:05 -06:00
LotP
e8225ce7aa Memory changes 3.1 (ryubing/ryujinx!212)
See merge request ryubing/ryujinx!212
2025-11-11 13:24:57 -06:00
GreemDev
6b814fb973 feature: .NET 10 (ryubing/ryujinx!214)
See merge request ryubing/ryujinx!214
2025-11-11 12:55:36 -06:00
GreemDev
49c70efdd5 UI: App Library: automatically remove nonexistent autoload/game dirs from the configuration upon load. 2025-11-10 19:14:29 -06:00
Babib3l
4677b749b1 fr_FR and es_ES small translation update (ryubing/ryujinx!172)
See merge request ryubing/ryujinx!172
2025-11-10 17:35:17 -06:00
GreemDev
ed32cd6999 fix nested project error when building 2025-11-10 13:32:40 -06:00
GreemDev
d7e2d4534a [ci skip] fix new SDL projects showing up in an src folder in the IDE (idk how I didn't see that before) 2025-11-10 00:12:39 -06:00
LotP
3c3e14c819 Update .gitattributes (ryubing/ryujinx!213)
See merge request ryubing/ryujinx!213
2025-11-09 19:03:01 -06:00
Godzilaa4
dd9ba05e36 Updated PT_BR translation (ryubing/ryujinx!208)
See merge request ryubing/ryujinx!208
2025-11-09 14:36:44 -06:00
309 changed files with 10398 additions and 8306 deletions

1
.gitattributes vendored
View File

@@ -2,3 +2,4 @@
# Set default behavior to automatically normalize line endings.
###############################################################################
* text=auto eol=lf
*.json text eol=lf

View File

@@ -1,4 +1,4 @@
name: Canary release job
name: Canary CI
on:
workflow_dispatch:
@@ -19,7 +19,6 @@ concurrency: release
env:
POWERSHELL_TELEMETRY_OPTOUT: 1
DOTNET_CLI_TELEMETRY_OPTOUT: 1
RYUJINX_BASE_VERSION: "1.3"
RYUJINX_TARGET_RELEASE_CHANNEL_NAME: "canary"
RELEASE: 1
@@ -30,8 +29,8 @@ jobs:
strategy:
matrix:
platform:
- { name: win-x64, os: windows-latest, zip_os_name: win_x64 }
#- { name: win-arm64, os: windows-latest, zip_os_name: win_arm64 }
- { name: win-x64, os: ubuntu-latest, zip_os_name: win_x64 }
#- { name: win-arm64, os: ubuntu-latest, zip_os_name: win_arm64 }
- { name: linux-x64, os: ubuntu-latest, zip_os_name: linux_x64 }
- { name: linux-arm64, os: ubuntu-latest, zip_os_name: linux_arm64 }
steps:
@@ -44,12 +43,27 @@ jobs:
- name: Overwrite csc problem matcher
run: echo "::add-matcher::.github/csc.json"
- name: Install 7zip
run: |
sudo apt install -y 7zip
- name: Install gli
run: |
mkdir -p $HOME/.bin
gh release download -R GreemDev/GLI -O gli -p 'gli-linux-x64'
chmod +x gli
mv gli $HOME/.bin/
echo "$HOME/.bin" >> $GITHUB_PATH
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Get version info
id: version_info
run: |
echo "build_version=${{ env.RYUJINX_BASE_VERSION }}.${{ github.run_number }}" >> $GITHUB_OUTPUT
echo "prev_build_version=${{ env.RYUJINX_BASE_VERSION }}.$((${{ github.run_number }} - 1))" >> $GITHUB_OUTPUT
echo "build_version=$(gli get-next-version -c Canary -R)" >> $GITHUB_OUTPUT
echo "prev_build_version=$(gli get-current-version -c Canary -R)" >> $GITHUB_OUTPUT
echo "git_short_hash=$(git rev-parse --short "${{ github.sha }}")" >> $GITHUB_OUTPUT
echo "commit_message=$(git log -1 --pretty=%B)" >> $GITHUB_OUTPUT
shell: bash
- name: Configure for release
@@ -69,33 +83,20 @@ jobs:
dotnet publish -c Release -r "${{ matrix.platform.name }}" -o ./publish -p:Version="${{ steps.version_info.outputs.build_version }}" -p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" -p:DebugType=embedded src/Ryujinx --self-contained
- name: Packing Windows builds
if: matrix.platform.os == 'windows-latest'
if: contains(matrix.platform.name, 'win')
run: |
pushd publish
rm libarmeilleure-jitsupport.dylib
7z a ../release_output/ryujinx-canary-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.zip ../publish
popd
gh release download -R GreemDev/GLI -O gli.exe -p 'GitLabCli-win_x64.exe'
./gli.exe --access-token=${{ secrets.GITLAB_TOKEN }} --project=ryubing/canary --command=UploadGenericPackage "Ryubing-Canary|${{ steps.version_info.outputs.build_version }}|release_output/ryujinx-canary-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.zip"
gli upload-generic-package -T ${{ secrets.GITLAB_TOKEN }} -P ryubing/canary -n Ryubing-Canary -v ${{ steps.version_info.outputs.build_version }} -p release_output/ryujinx-canary-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.zip
shell: bash
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Install GitLabCli
if: matrix.platform.os == 'ubuntu-latest'
run: |
mkdir -p $HOME/.bin
gh release download -R GreemDev/GLI -O gli -p 'GitLabCli-linux_x64'
chmod +x gli
mv gli $HOME/.bin/
echo "$HOME/.bin" >> $GITHUB_PATH
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Packing Linux builds
if: matrix.platform.os == 'ubuntu-latest'
if: contains(matrix.platform.name, 'linux')
run: |
pushd publish
rm libarmeilleure-jitsupport.dylib
@@ -103,11 +104,11 @@ jobs:
tar -czvf ../release_output/ryujinx-canary-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.tar.gz ../publish
popd
gli --access-token=${{ secrets.GITLAB_TOKEN }} --project=ryubing/canary --command=UploadGenericPackage "Ryubing-Canary|${{ steps.version_info.outputs.build_version }}|release_output/ryujinx-canary-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.tar.gz"
gli upload-generic-package -T ${{ secrets.GITLAB_TOKEN }} -P ryubing/canary -n Ryubing-Canary -v ${{ steps.version_info.outputs.build_version }} -p release_output/ryujinx-canary-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.tar.gz
shell: bash
- name: Build AppImage (Linux)
if: matrix.platform.os == 'ubuntu-latest'
if: contains(matrix.platform.name, 'linux')
run: |
BUILD_VERSION="${{ steps.version_info.outputs.build_version }}"
PLATFORM_NAME="${{ matrix.platform.name }}"
@@ -139,8 +140,8 @@ jobs:
pushd publish_appimage
mv Ryujinx.AppImage ../release_output/ryujinx-canary-$BUILD_VERSION-$ARCH_NAME.AppImage
popd
gli --access-token=${{ secrets.GITLAB_TOKEN }} --project=ryubing/canary --command=UploadGenericPackage "Ryubing-Canary|${{ steps.version_info.outputs.build_version }}|release_output/ryujinx-canary-$BUILD_VERSION-$ARCH_NAME.AppImage"
gli upload-generic-package -T ${{ secrets.GITLAB_TOKEN }} -P ryubing/canary -n Ryubing-Canary -v ${{ steps.version_info.outputs.build_version }} -p release_output/ryujinx-canary-$BUILD_VERSION-$ARCH_NAME.AppImage
shell: bash
macos_release:
@@ -159,10 +160,10 @@ jobs:
chmod +x llvm.sh
sudo ./llvm.sh 17
- name: Install GitLabCli
- name: Install gli
run: |
mkdir -p $HOME/.bin
gh release download -R GreemDev/GLI -O gli -p 'GitLabCli-linux_x64'
gh release download -R GreemDev/GLI -O gli -p 'gli-linux-x64'
chmod +x gli
mv gli $HOME/.bin/
echo "$HOME/.bin" >> $GITHUB_PATH
@@ -183,9 +184,10 @@ jobs:
- name: Get version info
id: version_info
run: |
echo "build_version=${{ env.RYUJINX_BASE_VERSION }}.${{ github.run_number }}" >> $GITHUB_OUTPUT
echo "prev_build_version=${{ env.RYUJINX_BASE_VERSION }}.$((${{ github.run_number }} - 1))" >> $GITHUB_OUTPUT
echo "build_version=$(gli get-next-version -c Canary -R)" >> $GITHUB_OUTPUT
echo "prev_build_version=$(gli get-current-version -c Canary -R)" >> $GITHUB_OUTPUT
echo "git_short_hash=$(git rev-parse --short "${{ github.sha }}")" >> $GITHUB_OUTPUT
shell: bash
- name: Configure for release
run: |
@@ -200,7 +202,7 @@ jobs:
- name: Publish macOS Ryujinx
run: |
./distribution/macos/create_macos_build_ava.sh . publish_tmp_ava publish_ava ./distribution/macos/entitlements.xml "${{ steps.version_info.outputs.build_version }}" "${{ steps.version_info.outputs.git_short_hash }}" Release 1
gli --access-token=${{ secrets.GITLAB_TOKEN }} --project=ryubing/canary --command=UploadGenericPackage "Ryubing-Canary|${{ steps.version_info.outputs.build_version }}|publish_ava/ryujinx-canary-${{ steps.version_info.outputs.build_version }}-macos_universal.app.tar.gz"
gli upload-generic-package -T ${{ secrets.GITLAB_TOKEN }} -P ryubing/canary -n Ryubing-Canary -v ${{ steps.version_info.outputs.build_version }} -p publish_ava/ryujinx-canary-${{ steps.version_info.outputs.build_version }}-macos_universal.app.tar.gz
create_gitlab_release:
name: Create GitLab Release
@@ -210,37 +212,42 @@ jobs:
- release
steps:
- uses: actions/checkout@v4
- name: Get version info
id: version_info
run: |
echo "build_version=${{ env.RYUJINX_BASE_VERSION }}.${{ github.run_number }}" >> $GITHUB_OUTPUT
echo "prev_build_version=${{ env.RYUJINX_BASE_VERSION }}.$((${{ github.run_number }} - 1))" >> $GITHUB_OUTPUT
echo "git_short_hash=$(git rev-parse --short "${{ github.sha }}")" >> $GITHUB_OUTPUT
shell: bash
- name: Install GitLabCli
- name: Install gli
run: |
mkdir -p $HOME/.bin
gh release download -R GreemDev/GLI -O gli -p 'GitLabCli-linux_x64'
gh release download -R GreemDev/GLI -O gli -p 'gli-linux-x64'
chmod +x gli
mv gli $HOME/.bin/
echo "$HOME/.bin" >> $GITHUB_PATH
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Get version info
id: version_info
run: |
echo "build_version=$(gli get-next-version -c Canary -R)" >> $GITHUB_OUTPUT
echo "prev_build_version=$(gli get-current-version -c Canary -R)" >> $GITHUB_OUTPUT
echo "git_short_hash=$(git rev-parse --short "${{ github.sha }}")" >> $GITHUB_OUTPUT
echo "commit_message=$(git log -1 --pretty=%B)" >> $GITHUB_OUTPUT
shell: bash
- name: Create tag
run: |
gli --access-token=${{ secrets.GITLAB_TOKEN }} --project=ryubing/ryujinx --command=CreateTag "Canary-${{ steps.version_info.outputs.build_version }}|${{ steps.version_info.outputs.git_short_hash }}"
gli create-tag -T ${{ secrets.GITLAB_TOKEN }} -P ryubing/ryujinx -n Canary-${{ steps.version_info.outputs.build_version }} -r ${{ steps.version_info.outputs.git_short_hash }} -c "${{ steps.version_info.outputs.commit_message }}"
- name: Create release
run: |
gli --access-token=${{ secrets.GITLAB_TOKEN }} --project=ryubing/canary --command=CreateReleaseFromGenericPackageFiles "Ryubing-Canary|${{ steps.version_info.outputs.build_version }}|main|Canary ${{ steps.version_info.outputs.build_version }}|**Full Changelog:** [${{ steps.version_info.outputs.prev_build_version }}...${{ steps.version_info.outputs.build_version }}](https://git.ryujinx.app/ryubing/ryujinx/-/compare/Canary-${{ steps.version_info.outputs.prev_build_version }}...Canary-${{ steps.version_info.outputs.build_version }})"
gli create-release-from-generic-package-files -T ${{ secrets.GITLAB_TOKEN }} -P ryubing/canary -n Ryubing-Canary -v ${{ steps.version_info.outputs.build_version }} -r main -t "Canary ${{ steps.version_info.outputs.build_version }}" -b "**Full Changelog:** [${{ steps.version_info.outputs.prev_build_version }}...${{ steps.version_info.outputs.build_version }}](https://git.ryujinx.app/ryubing/ryujinx/-/compare/Canary-${{ steps.version_info.outputs.prev_build_version }}...Canary-${{ steps.version_info.outputs.build_version }})"
- name: Send notification webhook
run: |
gli --access-token=${{ secrets.GITLAB_TOKEN }} --project=ryubing/canary --command=SendUpdateMessage "${{ steps.version_info.outputs.build_version }}|FF4500|${{ secrets.CANARY_DISCORD_WEBHOOK }}|https://avatars.githubusercontent.com/u/192939710?s=200&v=4|false"
gli send-update-message -T ${{ secrets.GITLAB_TOKEN }} -P ryubing/canary -t ${{ steps.version_info.outputs.build_version }} -c FF4500 -w ${{ secrets.CANARY_DISCORD_WEBHOOK }} -i https://avatars.githubusercontent.com/u/192939710?s=200&v=4
- name: Notify update server of new builds
run: |
curl 'https://update.ryujinx.app/api/v1/admin/refresh_cache?rc=canary' -X PATCH -H 'accept: */*' -H 'Authorization: ${{ secrets.UPDATE_SERVER_ADMIN_TOKEN }}'
gli refresh-version-cache -T ${{ secrets.UPDATE_SERVER_ADMIN_TOKEN }} -c Canary
- name: Advance to the next version
run: |
gli increment-version -T ${{ secrets.UPDATE_SERVER_ADMIN_TOKEN }} -c Canary

View File

@@ -1,224 +0,0 @@
name: Release job (Debug)
on:
workflow_dispatch:
inputs: {}
concurrency: release
env:
POWERSHELL_TELEMETRY_OPTOUT: 1
DOTNET_CLI_TELEMETRY_OPTOUT: 1
RYUJINX_BASE_VERSION: "1.3"
RYUJINX_TARGET_RELEASE_CHANNEL_NAME: "release"
RELEASE: 1
jobs:
release:
name: Release for ${{ matrix.platform.name }}
runs-on: ${{ matrix.platform.os }}
strategy:
matrix:
platform:
- { name: win-x64, os: windows-latest, zip_os_name: win_x64 }
#- { name: win-arm64, os: windows-latest, zip_os_name: win_arm64 }
- { name: linux-x64, os: ubuntu-latest, zip_os_name: linux_x64 }
- { name: linux-arm64, os: ubuntu-latest, zip_os_name: linux_arm64 }
steps:
- uses: actions/checkout@v4
- uses: actions/setup-dotnet@v4
with:
global-json-file: global.json
- name: Overwrite csc problem matcher
run: echo "::add-matcher::.github/csc.json"
- name: Get version info
id: version_info
run: |
echo "build_version=${{ env.RYUJINX_BASE_VERSION }}.$((${{ github.run_number }} + 10))" >> $GITHUB_OUTPUT
echo "prev_build_version=${{ env.RYUJINX_BASE_VERSION }}.$((${{ github.run_number }} - 1))" >> $GITHUB_OUTPUT
echo "git_short_hash=$(git rev-parse --short "${{ github.sha }}")" >> $GITHUB_OUTPUT
shell: bash
- name: Configure for release
run: |
sed -r --in-place 's/\%\%RYUJINX_BUILD_VERSION\%\%/${{ steps.version_info.outputs.build_version }}/g;' src/Ryujinx.Common/ReleaseInformation.cs
sed -r --in-place 's/\%\%RYUJINX_BUILD_GIT_HASH\%\%/${{ steps.version_info.outputs.git_short_hash }}/g;' src/Ryujinx.Common/ReleaseInformation.cs
sed -r --in-place 's/\%\%RYUJINX_TARGET_RELEASE_CHANNEL_NAME\%\%/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_NAME }}/g;' src/Ryujinx.Common/ReleaseInformation.cs
sed -r --in-place 's/\%\%RYUJINX_CONFIG_FILE_NAME\%\%/Config\.json/g;' src/Ryujinx.Common/ReleaseInformation.cs
shell: bash
- name: Create output dir
run: "mkdir release_output"
- name: Publish
run: |
dotnet publish -c Release -r "${{ matrix.platform.name }}" -o ./publish -p:Version="${{ steps.version_info.outputs.build_version }}" -p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" -p:DebugType=embedded src/Ryujinx --self-contained
- name: Packing Windows builds
if: matrix.platform.os == 'windows-latest'
run: |
pushd publish
rm libarmeilleure-jitsupport.dylib
7z a ../release_output/ryujinx-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.zip ../publish
popd
gh release download -R GreemDev/GLI -O gli.exe -p 'GitLabCli-win_x64.exe'
./gli.exe --access-token=${{ secrets.GITLAB_TOKEN }} --project=ryubing/ryujinx --command=UploadGenericPackage "Ryubing|${{ steps.version_info.outputs.build_version }}|release_output/ryujinx-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.zip"
shell: bash
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Install GitLabCli
if: matrix.platform.os == 'ubuntu-latest'
run: |
mkdir -p $HOME/.bin
gh release download -R GreemDev/GLI -O gli -p 'GitLabCli-linux_x64'
chmod +x gli
mv gli $HOME/.bin/
echo "$HOME/.bin" >> $GITHUB_PATH
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Packing Linux builds
if: matrix.platform.os == 'ubuntu-latest'
run: |
pushd publish
rm libarmeilleure-jitsupport.dylib
chmod +x Ryujinx.sh Ryujinx
tar -czvf ../release_output/ryujinx-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.tar.gz ../publish
popd
gli --access-token=${{ secrets.GITLAB_TOKEN }} --project=ryubing/ryujinx --command=UploadGenericPackage "Ryubing|${{ steps.version_info.outputs.build_version }}|release_output/ryujinx-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.tar.gz"
shell: bash
- name: Build AppImage (Linux)
if: matrix.platform.os == 'ubuntu-latest'
run: |
BUILD_VERSION="${{ steps.version_info.outputs.build_version }}"
PLATFORM_NAME="${{ matrix.platform.name }}"
sudo apt install -y zsync desktop-file-utils appstream
mkdir -p tools
export PATH="$PATH:$(readlink -f tools)"
# Setup appimagetool
wget -q -O tools/appimagetool "https://github.com/AppImage/appimagetool/releases/download/continuous/appimagetool-x86_64.AppImage"
chmod +x tools/appimagetool
chmod +x distribution/linux/appimage/build-appimage.sh
# Explicitly set $ARCH for appimagetool ($ARCH_NAME is for the file name)
if [ "$PLATFORM_NAME" = "linux-x64" ]; then
ARCH_NAME=x64
export ARCH=x86_64
elif [ "$PLATFORM_NAME" = "linux-arm64" ]; then
ARCH_NAME=arm64
export ARCH=aarch64
else
echo "Unexpected PLATFORM_NAME "$PLATFORM_NAME""
exit 1
fi
export UFLAG="gh-releases-zsync|${{ github.repository_owner }}|${{ github.event.repository.name }}|latest|*-$ARCH_NAME.AppImage.zsync"
BUILDDIR=publish OUTDIR=publish_appimage distribution/linux/appimage/build-appimage.sh
pushd publish_appimage
mv Ryujinx.AppImage ../release_output/ryujinx-$BUILD_VERSION-$ARCH_NAME.AppImage
mv Ryujinx.AppImage.zsync ../release_output/ryujinx-$BUILD_VERSION-$ARCH_NAME.AppImage.zsync
popd
gli --access-token=${{ secrets.GITLAB_TOKEN }} --project=ryubing/ryujinx --command=UploadGenericPackage "Ryubing|${{ steps.version_info.outputs.build_version }}|release_output/ryujinx-$BUILD_VERSION-$ARCH_NAME.AppImage"
gli --access-token=${{ secrets.GITLAB_TOKEN }} --project=ryubing/ryujinx --command=UploadGenericPackage "Ryubing|${{ steps.version_info.outputs.build_version }}|release_output/ryujinx-$BUILD_VERSION-$ARCH_NAME.AppImage.zsync"
shell: bash
macos_release:
name: Release MacOS universal
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4
- uses: actions/setup-dotnet@v4
with:
global-json-file: global.json
- name: Setup LLVM 17
run: |
wget https://apt.llvm.org/llvm.sh
chmod +x llvm.sh
sudo ./llvm.sh 17
- name: Install GitLabCli
run: |
mkdir -p $HOME/.bin
gh release download -R GreemDev/GLI -O gli -p 'GitLabCli-linux_x64'
chmod +x gli
mv gli $HOME/.bin/
echo "$HOME/.bin" >> $GITHUB_PATH
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Install rcodesign
run: |
mkdir -p $HOME/.bin
gh release download -R indygreg/apple-platform-rs -O apple-codesign.tar.gz -p 'apple-codesign-*-x86_64-unknown-linux-musl.tar.gz'
tar -xzvf apple-codesign.tar.gz --wildcards '*/rcodesign' --strip-components=1
rm apple-codesign.tar.gz
mv rcodesign $HOME/.bin/
echo "$HOME/.bin" >> $GITHUB_PATH
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Get version info
id: version_info
run: |
echo "build_version=${{ env.RYUJINX_BASE_VERSION }}.$((${{ github.run_number }} + 10))" >> $GITHUB_OUTPUT
echo "prev_build_version=${{ env.RYUJINX_BASE_VERSION }}.$((${{ github.run_number }} - 1))" >> $GITHUB_OUTPUT
echo "git_short_hash=$(git rev-parse --short "${{ github.sha }}")" >> $GITHUB_OUTPUT
- name: Configure for release
run: |
sed -r --in-place 's/\%\%RYUJINX_BUILD_VERSION\%\%/${{ steps.version_info.outputs.build_version }}/g;' src/Ryujinx.Common/ReleaseInformation.cs
sed -r --in-place 's/\%\%RYUJINX_BUILD_GIT_HASH\%\%/${{ steps.version_info.outputs.git_short_hash }}/g;' src/Ryujinx.Common/ReleaseInformation.cs
sed -r --in-place 's/\%\%RYUJINX_TARGET_RELEASE_CHANNEL_NAME\%\%/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_NAME }}/g;' src/Ryujinx.Common/ReleaseInformation.cs
sed -r --in-place 's/\%\%RYUJINX_CONFIG_FILE_NAME\%\%/Config\.json/g;' src/Ryujinx.Common/ReleaseInformation.cs
shell: bash
- name: Publish macOS Ryujinx
run: |
./distribution/macos/create_macos_build_ava.sh . publish_tmp_ava publish ./distribution/macos/entitlements.xml "${{ steps.version_info.outputs.build_version }}" "${{ steps.version_info.outputs.git_short_hash }}" Release 0
gli --access-token=${{ secrets.GITLAB_TOKEN }} --project=ryubing/ryujinx --command=UploadGenericPackage "Ryubing|${{ steps.version_info.outputs.build_version }}|publish/ryujinx-${{ steps.version_info.outputs.build_version }}-macos_universal.app.tar.gz"
create_gitlab_release:
name: Create GitLab Release
runs-on: ubuntu-24.04
needs:
- macos_release
- release
steps:
- uses: actions/checkout@v4
- name: Get version info
id: version_info
run: |
echo "build_version=${{ env.RYUJINX_BASE_VERSION }}.$((${{ github.run_number }} + 10))" >> $GITHUB_OUTPUT
echo "prev_build_version=${{ env.RYUJINX_BASE_VERSION }}.$((${{ github.run_number }} - 1))" >> $GITHUB_OUTPUT
echo "git_short_hash=$(git rev-parse --short "${{ github.sha }}")" >> $GITHUB_OUTPUT
shell: bash
- name: Install GitLabCli
run: |
mkdir -p $HOME/.bin
gh release download -R GreemDev/GLI -O gli -p 'GitLabCli-linux_x64'
chmod +x gli
mv gli $HOME/.bin/
echo "$HOME/.bin" >> $GITHUB_PATH
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Create release
run: |
gli --access-token=${{ secrets.GITLAB_TOKEN }} --project=ryubing/ryujinx --command=CreateReleaseFromGenericPackageFiles "Ryubing|${{ steps.version_info.outputs.build_version }}|${{ steps.version_info.outputs.git_short_hash }}|test|THIS IS NOT INTENDED FOR END USER USAGE"

View File

@@ -1,15 +1,18 @@
name: Release job
name: Stable CI
on:
workflow_dispatch:
inputs: {}
inputs:
is_bugfix_release:
description: "Bug fix release: If checked, this will increment the third number for only Stable, and leave the Major version alone for both Stable and Canary."
required: true
type: boolean
concurrency: release
env:
POWERSHELL_TELEMETRY_OPTOUT: 1
DOTNET_CLI_TELEMETRY_OPTOUT: 1
RYUJINX_BASE_VERSION: "1.3"
RYUJINX_TARGET_RELEASE_CHANNEL_NAME: "release"
RELEASE: 1
@@ -20,8 +23,8 @@ jobs:
strategy:
matrix:
platform:
- { name: win-x64, os: windows-latest, zip_os_name: win_x64 }
#- { name: win-arm64, os: windows-latest, zip_os_name: win_arm64 }
- { name: win-x64, os: ubuntu-latest, zip_os_name: win_x64 }
#- { name: win-arm64, os: ubuntu-latest, zip_os_name: win_arm64 }
- { name: linux-x64, os: ubuntu-latest, zip_os_name: linux_x64 }
- { name: linux-arm64, os: ubuntu-latest, zip_os_name: linux_arm64 }
steps:
@@ -33,12 +36,30 @@ jobs:
- name: Overwrite csc problem matcher
run: echo "::add-matcher::.github/csc.json"
- name: Install 7zip
run: |
sudo apt install -y 7zip
- name: Install gli
run: |
mkdir -p $HOME/.bin
gh release download -R GreemDev/GLI -O gli -p 'gli-linux-x64'
chmod +x gli
mv gli $HOME/.bin/
echo "$HOME/.bin" >> $GITHUB_PATH
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Get version info
id: version_info
run: |
echo "build_version=${{ env.RYUJINX_BASE_VERSION }}.${{ github.run_number }}" >> $GITHUB_OUTPUT
echo "prev_build_version=${{ env.RYUJINX_BASE_VERSION }}.$((${{ github.run_number }} - 1))" >> $GITHUB_OUTPUT
if [ '${{ inputs.is_bugfix_release }}' == 'false' ]; then
echo "build_version=$(gli get-next-version -m -c Stable -R)" >> $GITHUB_OUTPUT
else
echo "build_version=$(gli get-next-version -c Stable -R)" >> $GITHUB_OUTPUT
fi
echo "prev_build_version=$(gli get-current-version -c Stable -R)" >> $GITHUB_OUTPUT
echo "git_short_hash=$(git rev-parse --short "${{ github.sha }}")" >> $GITHUB_OUTPUT
shell: bash
@@ -58,47 +79,34 @@ jobs:
dotnet publish -c Release -r "${{ matrix.platform.name }}" -o ./publish -p:Version="${{ steps.version_info.outputs.build_version }}" -p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" -p:DebugType=embedded src/Ryujinx --self-contained
- name: Packing Windows builds
if: matrix.platform.os == 'windows-latest'
if: contains(matrix.platform.name, 'win')
run: |
pushd publish
rm libarmeilleure-jitsupport.dylib
7z a ../release_output/ryujinx-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.zip ../publish
popd
gh release download -R GreemDev/GLI -O gli.exe -p 'GitLabCli-win_x64.exe'
./gli.exe --access-token=${{ secrets.GITLAB_TOKEN }} --project=ryubing/ryujinx --command=UploadGenericPackage "Ryubing|${{ steps.version_info.outputs.build_version }}|release_output/ryujinx-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.zip"
gli upload-generic-package -T ${{ secrets.GITLAB_TOKEN }} -P ryubing/ryujinx -n Ryubing -v ${{ steps.version_info.outputs.build_version }} -p release_output/ryujinx-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.zip
shell: bash
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Install GitLabCli
if: matrix.platform.os == 'ubuntu-latest'
run: |
mkdir -p $HOME/.bin
gh release download -R GreemDev/GLI -O gli -p 'GitLabCli-linux_x64'
chmod +x gli
mv gli $HOME/.bin/
echo "$HOME/.bin" >> $GITHUB_PATH
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Packing Linux builds
if: matrix.platform.os == 'ubuntu-latest'
if: contains(matrix.platform.name, 'linux')
run: |
pushd publish
rm libarmeilleure-jitsupport.dylib
chmod +x Ryujinx.sh Ryujinx
tar -czvf ../release_output/ryujinx-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.tar.gz ../publish
popd
gli --access-token=${{ secrets.GITLAB_TOKEN }} --project=ryubing/ryujinx --command=UploadGenericPackage "Ryubing|${{ steps.version_info.outputs.build_version }}|release_output/ryujinx-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.tar.gz"
gli upload-generic-package -T ${{ secrets.GITLAB_TOKEN }} -P ryubing/ryujinx -n Ryubing -v ${{ steps.version_info.outputs.build_version }} -p release_output/ryujinx-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.tar.gz
shell: bash
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Build AppImage (Linux)
if: matrix.platform.os == 'ubuntu-latest'
if: contains(matrix.platform.name, 'linux')
run: |
BUILD_VERSION="${{ steps.version_info.outputs.build_version }}"
PLATFORM_NAME="${{ matrix.platform.name }}"
@@ -131,7 +139,7 @@ jobs:
mv Ryujinx.AppImage ../release_output/ryujinx-$BUILD_VERSION-$ARCH_NAME.AppImage
popd
gli --access-token=${{ secrets.GITLAB_TOKEN }} --project=ryubing/ryujinx --command=UploadGenericPackage "Ryubing|${{ steps.version_info.outputs.build_version }}|release_output/ryujinx-$BUILD_VERSION-$ARCH_NAME.AppImage"
gli upload-generic-package -T ${{ secrets.GITLAB_TOKEN }} -P ryubing/ryujinx -n Ryubing -v ${{ steps.version_info.outputs.build_version }} -p release_output/ryujinx-$BUILD_VERSION-$ARCH_NAME.AppImage
shell: bash
macos_release:
@@ -150,10 +158,10 @@ jobs:
chmod +x llvm.sh
sudo ./llvm.sh 17
- name: Install GitLabCli
- name: Install gli
run: |
mkdir -p $HOME/.bin
gh release download -R GreemDev/GLI -O gli -p 'GitLabCli-linux_x64'
gh release download -R GreemDev/GLI -O gli -p 'gli-linux-x64'
chmod +x gli
mv gli $HOME/.bin/
echo "$HOME/.bin" >> $GITHUB_PATH
@@ -174,9 +182,14 @@ jobs:
- name: Get version info
id: version_info
run: |
echo "build_version=${{ env.RYUJINX_BASE_VERSION }}.${{ github.run_number }}" >> $GITHUB_OUTPUT
echo "prev_build_version=${{ env.RYUJINX_BASE_VERSION }}.$((${{ github.run_number }} - 1))" >> $GITHUB_OUTPUT
if [ '${{ inputs.is_bugfix_release }}' == 'false' ]; then
echo "build_version=$(gli get-next-version -m -c Stable -R)" >> $GITHUB_OUTPUT
else
echo "build_version=$(gli get-next-version -c Stable -R)" >> $GITHUB_OUTPUT
fi
echo "prev_build_version=$(gli get-current-version -c Stable -R)" >> $GITHUB_OUTPUT
echo "git_short_hash=$(git rev-parse --short "${{ github.sha }}")" >> $GITHUB_OUTPUT
shell: bash
- name: Configure for release
run: |
@@ -189,7 +202,8 @@ jobs:
- name: Publish macOS Ryujinx
run: |
./distribution/macos/create_macos_build_ava.sh . publish_tmp_ava publish ./distribution/macos/entitlements.xml "${{ steps.version_info.outputs.build_version }}" "${{ steps.version_info.outputs.git_short_hash }}" Release 0
gli --access-token=${{ secrets.GITLAB_TOKEN }} --project=ryubing/ryujinx --command=UploadGenericPackage "Ryubing|${{ steps.version_info.outputs.build_version }}|publish/ryujinx-${{ steps.version_info.outputs.build_version }}-macos_universal.app.tar.gz"
gli upload-generic-package -T ${{ secrets.GITLAB_TOKEN }} -P ryubing/ryujinx -n Ryubing -v ${{ steps.version_info.outputs.build_version }} -p publish/ryujinx-${{ steps.version_info.outputs.build_version }}-macos_universal.app.tar.gz
create_gitlab_release:
name: Create GitLab Release
@@ -200,32 +214,45 @@ jobs:
steps:
- uses: actions/checkout@v4
- name: Get version info
id: version_info
run: |
echo "build_version=${{ env.RYUJINX_BASE_VERSION }}.${{ github.run_number }}" >> $GITHUB_OUTPUT
echo "prev_build_version=${{ env.RYUJINX_BASE_VERSION }}.$((${{ github.run_number }} - 1))" >> $GITHUB_OUTPUT
echo "git_short_hash=$(git rev-parse --short "${{ github.sha }}")" >> $GITHUB_OUTPUT
shell: bash
- name: Install GitLabCli
- name: Install gli
run: |
mkdir -p $HOME/.bin
gh release download -R GreemDev/GLI -O gli -p 'GitLabCli-linux_x64'
gh release download -R GreemDev/GLI -O gli -p 'gli-linux-x64'
chmod +x gli
mv gli $HOME/.bin/
echo "$HOME/.bin" >> $GITHUB_PATH
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Get version info
id: version_info
run: |
if [ '${{ inputs.is_bugfix_release }}' == 'false' ]; then
echo "build_version=$(gli get-next-version -m -c Stable -R)" >> $GITHUB_OUTPUT
else
echo "build_version=$(gli get-next-version -c Stable -R)" >> $GITHUB_OUTPUT
fi
echo "prev_build_version=$(gli get-current-version -c Stable -R)" >> $GITHUB_OUTPUT
echo "git_short_hash=$(git rev-parse --short "${{ github.sha }}")" >> $GITHUB_OUTPUT
echo "commit_message=$(git log -1 --pretty=%B)" >> $GITHUB_OUTPUT
shell: bash
- name: Create release
run: |
gli --access-token=${{ secrets.GITLAB_TOKEN }} --project=ryubing/ryujinx --command=CreateReleaseFromGenericPackageFiles "Ryubing|${{ steps.version_info.outputs.build_version }}|${{ steps.version_info.outputs.git_short_hash }}|${{ steps.version_info.outputs.build_version }}|msd:${{ steps.version_info.outputs.build_version }}"
gli create-release-from-generic-package-files -T ${{ secrets.GITLAB_TOKEN }} -P ryubing/ryujinx -n Ryubing -v ${{ steps.version_info.outputs.build_version }} -r ${{ steps.version_info.outputs.git_short_hash }} -t "${{ steps.version_info.outputs.build_version }}" -b "msd:${{ steps.version_info.outputs.build_version }}"
- name: Send notification webhook
run: |
gli --access-token=${{ secrets.GITLAB_TOKEN }} --project=ryubing/ryujinx --command=SendUpdateMessage "${{ steps.version_info.outputs.build_version }}|32cd32|${{ secrets.STABLE_DISCORD_WEBHOOK }}|https://avatars.githubusercontent.com/u/192939710?s=200&v=4|false"
gli send-update-message -T ${{ secrets.GITLAB_TOKEN }} -P ryubing/ryujinx -t ${{ steps.version_info.outputs.build_version }} -c 32cd32 -w ${{ secrets.STABLE_DISCORD_WEBHOOK }} -i https://avatars.githubusercontent.com/u/192939710?s=200&v=4
- name: Notify update server of new builds
run: |
curl 'https://update.ryujinx.app/api/v1/admin/refresh_cache?rc=stable' -X PATCH -H 'accept: */*' -H 'Authorization: ${{ secrets.UPDATE_SERVER_ADMIN_TOKEN }}'
gli refresh-version-cache -T ${{ secrets.UPDATE_SERVER_ADMIN_TOKEN }} -c Stable
- name: Advance to the next version
run: |
if [ '${{ inputs.is_bugfix_release }}' == 'false' ]; then
gli advance-version -T ${{ secrets.UPDATE_SERVER_ADMIN_TOKEN }}
else
gli increment-version -T ${{ secrets.UPDATE_SERVER_ADMIN_TOKEN }} -c Stable
fi

3
.gitignore vendored
View File

@@ -18,6 +18,8 @@ build/
[Oo]bj/
AppDir/
publish_appimage/
publish_ava/
publish_tmp_ava/
# Enable "build/" folder in the NuGet Packages folder since NuGet packages use it for MSBuild targets
!packages/*/build/
@@ -98,6 +100,7 @@ DocProject/Help/html
# Click-Once directory
publish/
RyubingMaintainerTools/
# Publish Web Output
*.Publish.xml

View File

@@ -5,7 +5,7 @@ If you wish to build the emulator yourself, follow these steps:
### Step 1
Install the [.NET 9.0 (or higher) SDK](https://dotnet.microsoft.com/download/dotnet/9.0).
Install the [.NET 10.0 (or higher) SDK](https://dotnet.microsoft.com/en-us/download/dotnet/10.0).
Make sure your SDK version is higher or equal to the required version specified in [global.json](global.json).
### Step 2

View File

@@ -1,6 +1,6 @@
<Project>
<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
<LangVersion>latest</LangVersion>
<TargetFramework>net10.0</TargetFramework>
<LangVersion>preview</LangVersion>
</PropertyGroup>
</Project>

View File

@@ -44,7 +44,7 @@
<PackageVersion Include="Ryujinx.LibHac" Version="0.21.0-alpha.126" />
<PackageVersion Include="Ryujinx.UpdateClient" Version="1.0.44" />
<PackageVersion Include="Ryujinx.Systems.Update.Common" Version="1.0.44" />
<PackageVersion Include="Gommon" Version="2.8.0.1" />
<PackageVersion Include="Gommon" Version="2.8.0.2" />
<PackageVersion Include="securifybv.ShellLink" Version="0.1.0" />
<PackageVersion Include="Sep" Version="0.11.1" />
<PackageVersion Include="shaderc.net" Version="0.1.0" />
@@ -59,4 +59,4 @@
<PackageVersion Include="System.Management" Version="9.0.2" />
<PackageVersion Include="UnicornEngine.Unicorn" Version="2.0.2-rc1-fb78016" />
</ItemGroup>
</Project>
</Project>

View File

@@ -45,12 +45,16 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Graphics.Vic", "src
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Graphics.Video", "src\Ryujinx.Graphics.Video\Ryujinx.Graphics.Video.csproj", "{FD4A2C14-8E3D-4957-ABBE-3C38897B3E2D}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Audio.Backends.SDL3", "src\Ryujinx.Audio.Backends.SDL3\Ryujinx.Audio.Backends.SDL3.csproj", "{988E6191-82E1-4E13-9DDB-CB9FA2FDAF29}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Audio.Backends.OpenAL", "src\Ryujinx.Audio.Backends.OpenAL\Ryujinx.Audio.Backends.OpenAL.csproj", "{0BE11899-DF2D-4BDE-B9EE-2489E8D35E7D}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Audio.Backends.SoundIo", "src\Ryujinx.Audio.Backends.SoundIo\Ryujinx.Audio.Backends.SoundIo.csproj", "{716364DE-B988-41A6-BAB4-327964266ECC}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Input", "src\Ryujinx.Input\Ryujinx.Input.csproj", "{C16F112F-38C3-40BC-9F5F-4791112063D6}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Input.SDL3", "src\Ryujinx.Input.SDL3\Ryujinx.Input.SDL3.csproj", "{D728444C-3D1F-4A0E-B4C9-5C9375D47EA3}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Graphics.Nvdec.FFmpeg", "src\Ryujinx.Graphics.Nvdec.FFmpeg\Ryujinx.Graphics.Nvdec.FFmpeg.csproj", "{BEE1C184-C9A4-410B-8DFC-FB74D5C93AEB}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx", "src\Ryujinx\Ryujinx.csproj", "{7C1B2721-13DA-4B62-B046-C626605ECCE6}"
@@ -73,24 +77,19 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.HLE.Generators", "s
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ryujinx.BuildValidationTasks", "src\Ryujinx.BuildValidationTasks\Ryujinx.BuildValidationTasks.csproj", "{4A89A234-4F19-497D-A576-DDE8CDFC5B22}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.SDL3.Common", "src\Ryujinx.SDL3.Common\Ryujinx.SDL3.Common.csproj", "{F6F9826A-BC58-4D78-A700-F358A66B2B06}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{36F870C1-3E5F-485F-B426-F0645AF78751}"
ProjectSection(SolutionItems) = preProject
.editorconfig = .editorconfig
.github\workflows\build.yml = .github\workflows\build.yml
.github\workflows\canary.yml = .github\workflows\canary.yml
Directory.Packages.props = Directory.Packages.props
Directory.Build.props = Directory.Build.props
.github\workflows\release.yml = .github\workflows\release.yml
nuget.config = nuget.config
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{827E0CD3-B72D-47B6-A68D-7590B98EB39B}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ryujinx.SDL3.Common", "src\Ryujinx.SDL3.Common\Ryujinx.SDL3.Common.csproj", "{F6F9826A-BC58-4D78-A700-F358A66B2B06}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ryujinx.Input.SDL3", "src\Ryujinx.Input.SDL3\Ryujinx.Input.SDL3.csproj", "{D728444C-3D1F-4A0E-B4C9-5C9375D47EA3}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ryujinx.Audio.Backends.SDL3", "src\Ryujinx.Audio.Backends.SDL3\Ryujinx.Audio.Backends.SDL3.csproj", "{988E6191-82E1-4E13-9DDB-CB9FA2FDAF29}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -560,11 +559,6 @@ Global
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{F6F9826A-BC58-4D78-A700-F358A66B2B06} = {827E0CD3-B72D-47B6-A68D-7590B98EB39B}
{D728444C-3D1F-4A0E-B4C9-5C9375D47EA3} = {827E0CD3-B72D-47B6-A68D-7590B98EB39B}
{988E6191-82E1-4E13-9DDB-CB9FA2FDAF29} = {827E0CD3-B72D-47B6-A68D-7590B98EB39B}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {110169B3-3328-4730-8AB0-BA05BEF75C1A}
EndGlobalSection

File diff suppressed because it is too large Load Diff

Binary file not shown.

View File

@@ -10,6 +10,8 @@
<string>Ryujinx</string>
<key>CFBundleIconFile</key>
<string>Ryujinx.icns</string>
<key>CFBundleIconName</key>
<string>Ryujinx</string>
<key>CFBundleDocumentTypes</key>
<array>
<dict>
@@ -40,7 +42,7 @@
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.2</string>
<string>1.3</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>

View File

@@ -25,6 +25,7 @@ cp "$PUBLISH_DIRECTORY"/*.dylib "$APP_BUNDLE_DIRECTORY/Contents/Frameworks"
cp Info.plist "$APP_BUNDLE_DIRECTORY/Contents"
cp Ryujinx.icns "$APP_BUNDLE_DIRECTORY/Contents/Resources/Ryujinx.icns"
cp updater.sh "$APP_BUNDLE_DIRECTORY/Contents/Resources/updater.sh"
cp Assets.car "$APP_BUNDLE_DIRECTORY/Contents/Resources/Assets.car"
cp -r "$PUBLISH_DIRECTORY/THIRDPARTY.md" "$APP_BUNDLE_DIRECTORY/Contents/Resources"
echo -n "APPL????" > "$APP_BUNDLE_DIRECTORY/Contents/PkgInfo"

View File

@@ -1,124 +0,0 @@
#!/bin/bash
set -e
if [ "$#" -lt 8 ]; then
echo "usage <BASE_DIR> <TEMP_DIRECTORY> <OUTPUT_DIRECTORY> <ENTITLEMENTS_FILE_PATH> <VERSION> <SOURCE_REVISION_ID> <CONFIGURATION> <CANARY>"
exit 1
fi
mkdir -p "$1"
mkdir -p "$2"
mkdir -p "$3"
BASE_DIR=$(readlink -f "$1")
TEMP_DIRECTORY=$(readlink -f "$2")
OUTPUT_DIRECTORY=$(readlink -f "$3")
ENTITLEMENTS_FILE_PATH=$(readlink -f "$4")
VERSION=$5
SOURCE_REVISION_ID=$6
CONFIGURATION=$7
CANARY=$8
if [[ "$(uname)" == "Darwin" ]]; then
echo "Clearing xattr on all dot undercsore files"
find "$BASE_DIR" -type f -name "._*" -exec sh -c '
for f; do
dir=$(dirname "$f")
base=$(basename "$f")
orig="$dir/${base#._}"
[ -f "$orig" ] && xattr -c "$orig" || true
done
' sh {} +
fi
if [ "$CANARY" == "1" ]; then
RELEASE_TAR_FILE_NAME=nogui-ryujinx-canary-$VERSION-macos_universal.tar
elif [ "$VERSION" == "1.1.0" ]; then
RELEASE_TAR_FILE_NAME=nogui-ryujinx-$CONFIGURATION-$VERSION+$SOURCE_REVISION_ID-macos_universal.tar
else
RELEASE_TAR_FILE_NAME=nogui-ryujinx-$VERSION-macos_universal.tar
fi
ARM64_OUTPUT="$TEMP_DIRECTORY/publish_arm64"
X64_OUTPUT="$TEMP_DIRECTORY/publish_x64"
UNIVERSAL_OUTPUT="$OUTPUT_DIRECTORY/publish"
EXECUTABLE_SUB_PATH=Ryujinx.Headless.SDL3
rm -rf "$TEMP_DIRECTORY"
mkdir -p "$TEMP_DIRECTORY"
DOTNET_COMMON_ARGS=(-p:DebugType=embedded -p:Version="$VERSION" -p:SourceRevisionId="$SOURCE_REVISION_ID" --self-contained true $EXTRA_ARGS)
dotnet restore
dotnet build -c "$CONFIGURATION" src/Ryujinx.Headless.SDL3
dotnet publish -c "$CONFIGURATION" -r osx-arm64 -o "$TEMP_DIRECTORY/publish_arm64" "${DOTNET_COMMON_ARGS[@]}" src/Ryujinx.Headless.SDL3
dotnet publish -c "$CONFIGURATION" -r osx-x64 -o "$TEMP_DIRECTORY/publish_x64" "${DOTNET_COMMON_ARGS[@]}" src/Ryujinx.Headless.SDL3
# Get rid of the support library for ARMeilleure for x64 (that's only for arm64)
rm -rf "$TEMP_DIRECTORY/publish_x64/libarmeilleure-jitsupport.dylib"
# Get rid of libsoundio from arm64 builds as we don't have a arm64 variant
# TODO: remove this once done
rm -rf "$TEMP_DIRECTORY/publish_arm64/libsoundio.dylib"
rm -rf "$OUTPUT_DIRECTORY"
mkdir -p "$OUTPUT_DIRECTORY"
# Let's copy one of the two different outputs and remove the executable
cp -R "$ARM64_OUTPUT/" "$UNIVERSAL_OUTPUT"
rm "$UNIVERSAL_OUTPUT/$EXECUTABLE_SUB_PATH"
# Make its libraries universal
python3 "$BASE_DIR/distribution/macos/construct_universal_dylib.py" "$ARM64_OUTPUT" "$X64_OUTPUT" "$UNIVERSAL_OUTPUT" "**/*.dylib"
if ! [ -x "$(command -v lipo)" ];
then
if ! [ -x "$(command -v llvm-lipo-17)" ];
then
LIPO=llvm-lipo
else
LIPO=llvm-lipo-17
fi
else
LIPO=lipo
fi
# Make the executable universal
$LIPO "$ARM64_OUTPUT/$EXECUTABLE_SUB_PATH" "$X64_OUTPUT/$EXECUTABLE_SUB_PATH" -output "$UNIVERSAL_OUTPUT/$EXECUTABLE_SUB_PATH" -create
# Now sign it
if ! [ -x "$(command -v codesign)" ];
then
if ! [ -x "$(command -v rcodesign)" ];
then
echo "Cannot find rcodesign on your system, please install rcodesign."
exit 1
fi
# NOTE: Currently require https://github.com/indygreg/apple-platform-rs/pull/44 to work on other OSes.
# cargo install --git "https://github.com/marysaka/apple-platform-rs" --branch "fix/adhoc-app-bundle" apple-codesign --bin "rcodesign"
echo "Using rcodesign for ad-hoc signing"
for FILE in "$UNIVERSAL_OUTPUT"/*; do
if [[ $(file "$FILE") == *"Mach-O"* ]]; then
rcodesign sign --entitlements-xml-path "$ENTITLEMENTS_FILE_PATH" "$FILE"
fi
done
else
echo "Using codesign for ad-hoc signing"
for FILE in "$UNIVERSAL_OUTPUT"/*; do
if [[ $(file "$FILE") == *"Mach-O"* ]]; then
codesign --entitlements "$ENTITLEMENTS_FILE_PATH" -f -s - "$FILE"
fi
done
fi
echo "Creating archive"
pushd "$OUTPUT_DIRECTORY"
tar --exclude "publish/Ryujinx.Headless.SDL3" -cvf "$RELEASE_TAR_FILE_NAME" publish 1> /dev/null
python3 "$BASE_DIR/distribution/misc/add_tar_exec.py" "$RELEASE_TAR_FILE_NAME" "publish/Ryujinx.Headless.SDL3" "publish/Ryujinx.Headless.SDL3"
gzip -9 < "$RELEASE_TAR_FILE_NAME" > "$RELEASE_TAR_FILE_NAME.gz"
rm "$RELEASE_TAR_FILE_NAME"
popd
echo "Done"

View File

@@ -2275,12 +2275,12 @@
010018E011D92000,"Pokémon™ Shining Pearl",gpu;ldn-works,ingame,2024-08-28 13:26:35
010015F008C54000,"Pokémon™ HOME",Needs Update;crash;services,menus,2020-12-06 06:01:51
01001F5010DFA000,"Pokémon™ Legends: Arceus",gpu;Needs Update;ldn-works,ingame,2024-09-19 10:02:02
0100F43008C44000,"Pokémon™ Legends: Z-A",gpu;crash;ldn-works,ingame,2025-11-16 00:30:00
01005D100807A000,"Pokémon™ Quest",,playable,2022-02-22 16:12:32
0100A3D008C5C000,"Pokémon™ Scarlet",gpu;nvdec;ldn-works;amd-vendor-bug,ingame,2023-12-14 13:18:29
01008F6008C5E000,"Pokémon™ Violet",gpu;nvdec;ldn-works;amd-vendor-bug;mac-bug,ingame,2024-07-30 02:51:48
0100187003A36000,"Pokémon™: Lets Go, Eevee!",crash;nvdec;online-broken;ldn-broken,ingame,2024-06-01 15:03:04
010003F003A34000,"Pokémon™: Lets Go, Pikachu!",crash;nvdec;online-broken;ldn-broken,ingame,2024-03-15 07:55:41
0100F43008C44000,"Pokémon Legends: Z-A",gpu;crash;ldn-broken,ingame,2025-10-16 19:13:00
0100B3F000BE2000,"Pokkén Tournament™ DX",nvdec;ldn-works;opengl-backend-bug;LAN;amd-vendor-bug;intel-vendor-bug,playable,2024-07-18 23:11:08
010030D005AE6000,"Pokkén Tournament™ DX Demo",demo;opengl-backend-bug,playable,2022-08-10 12:03:19
0100A3500B4EC000,"Polandball: Can Into Space",,playable,2020-06-25 15:13:26
1 title_id game_name labels status last_updated
2275 010018E011D92000 Pokémon™ Shining Pearl gpu;ldn-works ingame 2024-08-28 13:26:35
2276 010015F008C54000 Pokémon™ HOME Needs Update;crash;services menus 2020-12-06 06:01:51
2277 01001F5010DFA000 Pokémon™ Legends: Arceus gpu;Needs Update;ldn-works ingame 2024-09-19 10:02:02
2278 0100F43008C44000 Pokémon™ Legends: Z-A gpu;crash;ldn-works ingame 2025-11-16 00:30:00
2279 01005D100807A000 Pokémon™ Quest playable 2022-02-22 16:12:32
2280 0100A3D008C5C000 Pokémon™ Scarlet gpu;nvdec;ldn-works;amd-vendor-bug ingame 2023-12-14 13:18:29
2281 01008F6008C5E000 Pokémon™ Violet gpu;nvdec;ldn-works;amd-vendor-bug;mac-bug ingame 2024-07-30 02:51:48
2282 0100187003A36000 Pokémon™: Let’s Go, Eevee! crash;nvdec;online-broken;ldn-broken ingame 2024-06-01 15:03:04
2283 010003F003A34000 Pokémon™: Let’s Go, Pikachu! crash;nvdec;online-broken;ldn-broken ingame 2024-03-15 07:55:41
0100F43008C44000 Pokémon Legends: Z-A gpu;crash;ldn-broken ingame 2025-10-16 19:13:00
2284 0100B3F000BE2000 Pokkén Tournament™ DX nvdec;ldn-works;opengl-backend-bug;LAN;amd-vendor-bug;intel-vendor-bug playable 2024-07-18 23:11:08
2285 010030D005AE6000 Pokkén Tournament™ DX Demo demo;opengl-backend-bug playable 2022-08-10 12:03:19
2286 0100A3500B4EC000 Polandball: Can Into Space playable 2020-06-25 15:13:26

View File

@@ -1,6 +1,6 @@
{
"sdk": {
"version": "9.0.100",
"version": "10.0.100",
"rollForward": "latestFeature"
}
}

View File

@@ -25,9 +25,9 @@ namespace ARMeilleure.CodeGen.Arm64
static class ComparisonArm64Extensions
{
public static ArmCondition ToArmCondition(this Comparison comp)
extension(Comparison comparison)
{
return comp switch
public ArmCondition Arm => comparison switch
{
#pragma warning disable IDE0055 // Disable formatting
Comparison.Equal => ArmCondition.Eq,
@@ -42,7 +42,7 @@ namespace ARMeilleure.CodeGen.Arm64
Comparison.LessUI => ArmCondition.LtUn,
#pragma warning restore IDE0055
_ => throw new ArgumentException(null, nameof(comp)),
_ => throw new ArgumentException(null, nameof(comparison))
};
}
}

View File

@@ -181,10 +181,10 @@ namespace ARMeilleure.CodeGen.Arm64
public void Fmov(Operand rd, Operand rn, bool topHalf)
{
Debug.Assert(rd.Type.IsInteger() != rn.Type.IsInteger());
Debug.Assert(rd.Type.IsInteger != rn.Type.IsInteger);
Debug.Assert(rd.Type == OperandType.I64 || rn.Type == OperandType.I64 || !topHalf);
uint opcode = rd.Type.IsInteger() ? 0b110u : 0b111u;
uint opcode = rd.Type.IsInteger ? 0b110u : 0b111u;
uint rmode = topHalf ? 1u << 19 : 0u;
uint ftype = rd.Type == OperandType.FP64 || rn.Type == OperandType.FP64 ? 1u << 22 : 0u;
@@ -411,7 +411,7 @@ namespace ARMeilleure.CodeGen.Arm64
public void Mov(Operand rd, Operand rn)
{
if (rd.Type.IsInteger())
if (rd.Type.IsInteger)
{
Orr(rd, Factory.Register(ZrRegister, RegisterType.Integer, rd.Type), rn);
}
@@ -973,7 +973,7 @@ namespace ARMeilleure.CodeGen.Arm64
uint instruction;
int scale;
if (type.IsInteger())
if (type.IsInteger)
{
instruction = intInst;
@@ -1009,7 +1009,7 @@ namespace ARMeilleure.CodeGen.Arm64
{
uint instruction;
if (type.IsInteger())
if (type.IsInteger)
{
instruction = intInst;

View File

@@ -250,7 +250,7 @@ namespace ARMeilleure.CodeGen.Arm64
// ValidateBinOp(dest, src1, src2);
if (dest.Type.IsInteger())
if (dest.Type.IsInteger)
{
context.Assembler.Add(dest, src1, src2);
}
@@ -268,7 +268,7 @@ namespace ARMeilleure.CodeGen.Arm64
ValidateBinOp(dest, src1, src2);
Debug.Assert(dest.Type.IsInteger());
Debug.Assert(dest.Type.IsInteger);
context.Assembler.And(dest, src1, src2);
}
@@ -281,7 +281,7 @@ namespace ARMeilleure.CodeGen.Arm64
ValidateBinOp(dest, src1, src2);
if (dest.Type.IsInteger())
if (dest.Type.IsInteger)
{
context.Assembler.Eor(dest, src1, src2);
}
@@ -298,7 +298,7 @@ namespace ARMeilleure.CodeGen.Arm64
ValidateUnOp(dest, source);
Debug.Assert(dest.Type.IsInteger());
Debug.Assert(dest.Type.IsInteger);
context.Assembler.Mvn(dest, source);
}
@@ -311,7 +311,7 @@ namespace ARMeilleure.CodeGen.Arm64
ValidateBinOp(dest, src1, src2);
Debug.Assert(dest.Type.IsInteger());
Debug.Assert(dest.Type.IsInteger);
context.Assembler.Orr(dest, src1, src2);
}
@@ -322,7 +322,7 @@ namespace ARMeilleure.CodeGen.Arm64
Debug.Assert(comp.Kind == OperandKind.Constant);
ArmCondition cond = ((Comparison)comp.AsInt32()).ToArmCondition();
ArmCondition cond = ((Comparison)comp.AsInt32()).Arm;
GenerateCompareCommon(context, operation);
@@ -336,7 +336,7 @@ namespace ARMeilleure.CodeGen.Arm64
ValidateUnOp(dest, source);
Debug.Assert(dest.Type.IsInteger());
Debug.Assert(dest.Type.IsInteger);
context.Assembler.Rev(dest, source);
}
@@ -354,7 +354,7 @@ namespace ARMeilleure.CodeGen.Arm64
Debug.Assert(dest.Type == OperandType.I32);
Debug.Assert(comp.Kind == OperandKind.Constant);
ArmCondition cond = ((Comparison)comp.AsInt32()).ToArmCondition();
ArmCondition cond = ((Comparison)comp.AsInt32()).Arm;
GenerateCompareCommon(context, operation);
@@ -428,7 +428,7 @@ namespace ARMeilleure.CodeGen.Arm64
EnsureSameType(src1, src2);
Debug.Assert(src1.Type.IsInteger());
Debug.Assert(src1.Type.IsInteger);
context.Assembler.Cmp(src1, src2);
}
@@ -442,7 +442,7 @@ namespace ARMeilleure.CodeGen.Arm64
EnsureSameType(dest, src2, src3);
Debug.Assert(dest.Type.IsInteger());
Debug.Assert(dest.Type.IsInteger);
Debug.Assert(src1.Type == OperandType.I32);
context.Assembler.Cmp(src1, Const(src1.Type, 0));
@@ -468,7 +468,7 @@ namespace ARMeilleure.CodeGen.Arm64
Debug.Assert(dest.Type != source.Type);
Debug.Assert(source.Type != OperandType.V128);
if (source.Type.IsInteger())
if (source.Type.IsInteger)
{
context.Assembler.ScvtfScalar(dest, source);
}
@@ -485,7 +485,7 @@ namespace ARMeilleure.CodeGen.Arm64
Debug.Assert(dest.Type is OperandType.FP32 or OperandType.FP64);
Debug.Assert(dest.Type != source.Type);
Debug.Assert(source.Type.IsInteger());
Debug.Assert(source.Type.IsInteger);
context.Assembler.UcvtfScalar(dest, source);
}
@@ -497,7 +497,7 @@ namespace ARMeilleure.CodeGen.Arm64
EnsureSameType(dest, source);
Debug.Assert(dest.Type.IsInteger() || source.Kind != OperandKind.Constant);
Debug.Assert(dest.Type.IsInteger || source.Kind != OperandKind.Constant);
// Moves to the same register are useless.
if (dest.Kind == source.Kind && dest.Value == source.Value)
@@ -529,7 +529,7 @@ namespace ARMeilleure.CodeGen.Arm64
EnsureSameType(dest, source);
Debug.Assert(dest.Type.IsInteger());
Debug.Assert(dest.Type.IsInteger);
context.Assembler.Clz(dest, source);
}
@@ -542,7 +542,7 @@ namespace ARMeilleure.CodeGen.Arm64
ValidateBinOp(dest, dividend, divisor);
if (dest.Type.IsInteger())
if (dest.Type.IsInteger)
{
context.Assembler.Sdiv(dest, dividend, divisor);
}
@@ -576,7 +576,7 @@ namespace ARMeilleure.CodeGen.Arm64
Operand value = operation.Destination;
Operand address = operation.GetSource(0);
Debug.Assert(value.Type.IsInteger());
Debug.Assert(value.Type.IsInteger);
context.Assembler.LdrhRiUn(value, address, 0);
}
@@ -586,7 +586,7 @@ namespace ARMeilleure.CodeGen.Arm64
Operand value = operation.Destination;
Operand address = operation.GetSource(0);
Debug.Assert(value.Type.IsInteger());
Debug.Assert(value.Type.IsInteger);
context.Assembler.LdrbRiUn(value, address, 0);
}
@@ -604,7 +604,7 @@ namespace ARMeilleure.CodeGen.Arm64
EnsureSameType(dest, src1, src2);
if (dest.Type.IsInteger())
if (dest.Type.IsInteger)
{
context.Assembler.Mul(dest, src1, src2);
}
@@ -647,7 +647,7 @@ namespace ARMeilleure.CodeGen.Arm64
ValidateUnOp(dest, source);
if (dest.Type.IsInteger())
if (dest.Type.IsInteger)
{
context.Assembler.Neg(dest, source);
}
@@ -732,7 +732,7 @@ namespace ARMeilleure.CodeGen.Arm64
Operand dest = operation.Destination;
Operand source = operation.GetSource(0);
Debug.Assert(dest.Type.IsInteger() && source.Type.IsInteger());
Debug.Assert(dest.Type.IsInteger && source.Type.IsInteger);
context.Assembler.Sxth(dest, source);
}
@@ -742,7 +742,7 @@ namespace ARMeilleure.CodeGen.Arm64
Operand dest = operation.Destination;
Operand source = operation.GetSource(0);
Debug.Assert(dest.Type.IsInteger() && source.Type.IsInteger());
Debug.Assert(dest.Type.IsInteger && source.Type.IsInteger);
context.Assembler.Sxtw(dest, source);
}
@@ -752,7 +752,7 @@ namespace ARMeilleure.CodeGen.Arm64
Operand dest = operation.Destination;
Operand source = operation.GetSource(0);
Debug.Assert(dest.Type.IsInteger() && source.Type.IsInteger());
Debug.Assert(dest.Type.IsInteger && source.Type.IsInteger);
context.Assembler.Sxtb(dest, source);
}
@@ -823,7 +823,7 @@ namespace ARMeilleure.CodeGen.Arm64
Operand value = operation.GetSource(1);
Operand address = operation.GetSource(0);
Debug.Assert(value.Type.IsInteger());
Debug.Assert(value.Type.IsInteger);
context.Assembler.StrhRiUn(value, address, 0);
}
@@ -833,7 +833,7 @@ namespace ARMeilleure.CodeGen.Arm64
Operand value = operation.GetSource(1);
Operand address = operation.GetSource(0);
Debug.Assert(value.Type.IsInteger());
Debug.Assert(value.Type.IsInteger);
context.Assembler.StrbRiUn(value, address, 0);
}
@@ -858,7 +858,7 @@ namespace ARMeilleure.CodeGen.Arm64
// ValidateBinOp(dest, src1, src2);
if (dest.Type.IsInteger())
if (dest.Type.IsInteger)
{
context.Assembler.Sub(dest, src1, src2);
}
@@ -882,7 +882,7 @@ namespace ARMeilleure.CodeGen.Arm64
if (dest != default)
{
Debug.Assert(!dest.Type.IsInteger() && source.Type.IsInteger());
Debug.Assert(!dest.Type.IsInteger && source.Type.IsInteger);
OperandType destType = source.Type == OperandType.I64 ? OperandType.FP64 : OperandType.FP32;
@@ -901,9 +901,9 @@ namespace ARMeilleure.CodeGen.Arm64
byte index = src2.AsByte();
Debug.Assert(index < OperandType.V128.GetSizeInBytes() / dest.Type.GetSizeInBytes());
Debug.Assert(index < OperandType.V128.ByteSize / dest.Type.ByteSize);
if (dest.Type.IsInteger())
if (dest.Type.IsInteger)
{
context.Assembler.Umov(dest, src1, index, dest.Type == OperandType.I64 ? 3 : 2);
}
@@ -959,7 +959,7 @@ namespace ARMeilleure.CodeGen.Arm64
byte index = src3.AsByte();
if (src2.Type.IsInteger())
if (src2.Type.IsInteger)
{
context.Assembler.Ins(dest, src2, index, src2.Type == OperandType.I64 ? 3 : 2);
}
@@ -1007,7 +1007,7 @@ namespace ARMeilleure.CodeGen.Arm64
{
Operand dest = operation.Destination;
Debug.Assert(!dest.Type.IsInteger());
Debug.Assert(!dest.Type.IsInteger);
context.Assembler.CmeqVector(dest, dest, dest, 2);
}
@@ -1016,7 +1016,7 @@ namespace ARMeilleure.CodeGen.Arm64
{
Operand dest = operation.Destination;
Debug.Assert(!dest.Type.IsInteger());
Debug.Assert(!dest.Type.IsInteger);
context.Assembler.EorVector(dest, dest, dest);
}
@@ -1046,7 +1046,7 @@ namespace ARMeilleure.CodeGen.Arm64
Operand dest = operation.Destination;
Operand source = operation.GetSource(0);
Debug.Assert(dest.Type.IsInteger() && source.Type.IsInteger());
Debug.Assert(dest.Type.IsInteger && source.Type.IsInteger);
context.Assembler.Uxth(dest, source);
}
@@ -1056,7 +1056,7 @@ namespace ARMeilleure.CodeGen.Arm64
Operand dest = operation.Destination;
Operand source = operation.GetSource(0);
Debug.Assert(dest.Type.IsInteger() && source.Type.IsInteger());
Debug.Assert(dest.Type.IsInteger && source.Type.IsInteger);
// We can eliminate the move if source is already 32-bit and the registers are the same.
if (dest.Value == source.Value && source.Type == OperandType.I32)
@@ -1072,7 +1072,7 @@ namespace ARMeilleure.CodeGen.Arm64
Operand dest = operation.Destination;
Operand source = operation.GetSource(0);
Debug.Assert(dest.Type.IsInteger() && source.Type.IsInteger());
Debug.Assert(dest.Type.IsInteger && source.Type.IsInteger);
context.Assembler.Uxtb(dest, source);
}
@@ -1169,7 +1169,7 @@ namespace ARMeilleure.CodeGen.Arm64
context.Assembler.StrRiPre(Register(reg, type), Register(SpRegister), -calleeSaveRegionSize);
}
offset += type.GetSizeInBytes();
offset += type.ByteSize;
}
while (mask != 0)
@@ -1195,7 +1195,7 @@ namespace ARMeilleure.CodeGen.Arm64
context.Assembler.StpRiPre(Register(reg, type), Register(reg2, type), Register(SpRegister), -calleeSaveRegionSize);
}
offset += type.GetSizeInBytes() * 2;
offset += type.ByteSize * 2;
}
}
@@ -1273,7 +1273,7 @@ namespace ARMeilleure.CodeGen.Arm64
mask &= ~(1 << reg2);
offset -= type.GetSizeInBytes() * 2;
offset -= type.ByteSize * 2;
if (offset != 0)
{
@@ -1286,7 +1286,7 @@ namespace ARMeilleure.CodeGen.Arm64
}
else
{
offset -= type.GetSizeInBytes();
offset -= type.ByteSize;
if (offset != 0)
{
@@ -1435,12 +1435,12 @@ namespace ARMeilleure.CodeGen.Arm64
OperandType valueType = GetMemOpValueType(currentOp);
if (valueType != GetMemOpValueType(nextOp) || op1Offset + valueType.GetSizeInBytes() != op2Offset)
if (valueType != GetMemOpValueType(nextOp) || op1Offset + valueType.ByteSize != op2Offset)
{
return false;
}
if (!CodeGenCommon.ConstFitsOnSImm7(op1Offset, valueType.GetSizeInBytesLog2()))
if (!CodeGenCommon.ConstFitsOnSImm7(op1Offset, valueType.ByteSizeLog2))
{
return false;
}
@@ -1549,7 +1549,7 @@ namespace ARMeilleure.CodeGen.Arm64
// EnsureSameReg (dest, src1);
EnsureSameType(dest, src1);
Debug.Assert(dest.Type.IsInteger() && src2.Type == OperandType.I32);
Debug.Assert(dest.Type.IsInteger && src2.Type == OperandType.I32);
}
private static void EnsureSameReg(Operand op1, Operand op2)

View File

@@ -462,7 +462,7 @@ namespace ARMeilleure.CodeGen.Arm64
{
instruction |= (sz << 22);
if (rd.Type.IsInteger())
if (rd.Type.IsInteger)
{
context.Assembler.WriteInstructionAuto(instruction, rd, rn);
}
@@ -490,7 +490,7 @@ namespace ARMeilleure.CodeGen.Arm64
instruction |= (sz << 22);
instruction |= (64 - fBits) << 10;
if (rd.Type.IsInteger())
if (rd.Type.IsInteger)
{
Debug.Assert(rd.Type != OperandType.I32 || fBits <= 32);

View File

@@ -112,7 +112,7 @@ namespace ARMeilleure.CodeGen.Arm64
if (src1.Kind == OperandKind.Constant)
{
if (!src1.Type.IsInteger())
if (!src1.Type.IsInteger)
{
// Handle non-integer types (FP32, FP64 and V128).
// For instructions without an immediate operand, we do the following:
@@ -161,7 +161,7 @@ namespace ARMeilleure.CodeGen.Arm64
if (src2.Kind == OperandKind.Constant)
{
if (!src2.Type.IsInteger())
if (!src2.Type.IsInteger)
{
src2 = AddFloatConstantCopy(constants, nodes, node, src2);
@@ -191,7 +191,7 @@ namespace ARMeilleure.CodeGen.Arm64
if (src.Kind == OperandKind.Constant)
{
if (!src.Type.IsInteger())
if (!src.Type.IsInteger)
{
src = AddFloatConstantCopy(constants, nodes, node, src);
@@ -282,7 +282,7 @@ namespace ARMeilleure.CodeGen.Arm64
bool passOnReg;
if (source.Type.IsInteger())
if (source.Type.IsInteger)
{
passOnReg = intCount < intMax;
}
@@ -309,7 +309,7 @@ namespace ARMeilleure.CodeGen.Arm64
if (passOnReg)
{
Operand argReg = source.Type.IsInteger()
Operand argReg = source.Type.IsInteger
? Gpr(CallingConvention.GetIntArgumentRegister(intCount++), source.Type)
: Xmm(CallingConvention.GetVecArgumentRegister(vecCount++), source.Type);
@@ -327,7 +327,7 @@ namespace ARMeilleure.CodeGen.Arm64
InsertConstantRegCopies(constants, nodes, nodes.AddBefore(node, spillOp));
stackOffset += source.Type.GetSizeInBytes();
stackOffset += source.Type.ByteSize;
}
}
@@ -345,7 +345,7 @@ namespace ARMeilleure.CodeGen.Arm64
}
else
{
Operand retReg = dest.Type.IsInteger()
Operand retReg = dest.Type.IsInteger
? Gpr(CallingConvention.GetIntReturnRegister(), dest.Type)
: Xmm(CallingConvention.GetVecReturnRegister(), dest.Type);
@@ -385,7 +385,7 @@ namespace ARMeilleure.CodeGen.Arm64
bool passOnReg;
if (source.Type.IsInteger())
if (source.Type.IsInteger)
{
passOnReg = intCount + 1 < intMax;
}
@@ -408,7 +408,7 @@ namespace ARMeilleure.CodeGen.Arm64
if (passOnReg)
{
Operand argReg = source.Type.IsInteger()
Operand argReg = source.Type.IsInteger
? Gpr(CallingConvention.GetIntArgumentRegister(intCount++), source.Type)
: Xmm(CallingConvention.GetVecArgumentRegister(vecCount++), source.Type);
@@ -521,7 +521,7 @@ namespace ARMeilleure.CodeGen.Arm64
}
else
{
Operand retReg = source.Type.IsInteger()
Operand retReg = source.Type.IsInteger
? Gpr(CallingConvention.GetIntReturnRegister(), source.Type)
: Xmm(CallingConvention.GetVecReturnRegister(), source.Type);
@@ -551,7 +551,7 @@ namespace ARMeilleure.CodeGen.Arm64
{
OperandType argType = cctx.FuncArgTypes[cIndex];
if (argType.IsInteger())
if (argType.IsInteger)
{
intCount++;
}
@@ -567,7 +567,7 @@ namespace ARMeilleure.CodeGen.Arm64
bool passOnReg;
if (source.Type.IsInteger())
if (source.Type.IsInteger)
{
passOnReg = intCount < CallingConvention.GetArgumentsOnRegsCount();
}
@@ -606,7 +606,7 @@ namespace ARMeilleure.CodeGen.Arm64
{
Operand pArg = Local(dest.Type);
Operand argReg = dest.Type.IsInteger()
Operand argReg = dest.Type.IsInteger
? Gpr(CallingConvention.GetIntArgumentRegister(intCount), dest.Type)
: Xmm(CallingConvention.GetVecArgumentRegister(vecCount), dest.Type);

View File

@@ -51,7 +51,7 @@ namespace ARMeilleure.CodeGen.Optimizations
if (trueSucc == block.ListNext)
{
Comparison comp = (Comparison)branchOp.GetSource(2).AsInt32();
Comparison compInv = comp.Invert();
Comparison compInv = comp.Inverse;
branchOp.SetSource(2, Const((int)compInv));

View File

@@ -161,7 +161,7 @@ namespace ARMeilleure.CodeGen.Optimizations
}
else if (otherCompType == Comparison.Equal)
{
propCompType = compType.Invert();
propCompType = compType.Inverse;
}
else
{

View File

@@ -105,7 +105,7 @@ namespace ARMeilleure.CodeGen.Optimizations
Operand x = operation.GetSource(0);
Operand y = operation.GetSource(1);
if (x == y && x.Type.IsInteger())
if (x == y && x.Type.IsInteger)
{
operation.TurnIntoCopy(Const(x.Type, 0));
}
@@ -161,7 +161,7 @@ namespace ARMeilleure.CodeGen.Optimizations
private static bool IsConstEqual(Operand operand, ulong comparand)
{
if (operand.Kind != OperandKind.Constant || !operand.Type.IsInteger())
if (operand.Kind != OperandKind.Constant || !operand.Type.IsInteger)
{
return false;
}

View File

@@ -98,7 +98,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
{
OperandType type = types[copyDest];
type = type.IsInteger() ? OperandType.I64 : OperandType.V128;
type = type.IsInteger ? OperandType.I64 : OperandType.V128;
EmitXorSwap(sequence, GetRegister(copyDest, type), GetRegister(copySource, type));

View File

@@ -178,7 +178,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
}
else if (dest.Kind == OperandKind.Register)
{
if (dest.Type.IsInteger())
if (dest.Type.IsInteger)
{
intFixedRegisters |= 1 << dest.GetRegister().Index;
}
@@ -236,7 +236,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
{
Register reg = info.Register.GetRegister();
if (local.Type.IsInteger())
if (local.Type.IsInteger)
{
intLocalFreeRegisters |= 1 << reg.Index;
}
@@ -254,7 +254,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
if (temp == default || info.Sequence != sequence)
{
temp = local.Type.IsInteger()
temp = local.Type.IsInteger
? GetSpillTemp(local, intSpillTempRegisters, ref intLocalUse)
: GetSpillTemp(local, vecSpillTempRegisters, ref vecLocalUse);
@@ -335,7 +335,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
if (info.UsesAllocated == 0)
{
int mask = dest.Type.IsInteger()
int mask = dest.Type.IsInteger
? intLocalFreeRegisters
: vecLocalFreeRegisters;
@@ -343,9 +343,9 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
{
int selectedReg = BitOperations.TrailingZeroCount(mask);
info.Register = Register(selectedReg, info.Type.ToRegisterType(), info.Type);
info.Register = Register(selectedReg, info.Type.Register, info.Type);
if (dest.Type.IsInteger())
if (dest.Type.IsInteger)
{
intLocalFreeRegisters &= ~(1 << selectedReg);
intUsedRegisters |= 1 << selectedReg;
@@ -359,7 +359,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
else
{
info.Register = default;
info.SpillOffset = Const(stackAlloc.Allocate(dest.Type.GetSizeInBytes()));
info.SpillOffset = Const(stackAlloc.Allocate(dest.Type.ByteSize));
}
}
@@ -377,7 +377,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
if (temp == default || info.Sequence != sequence)
{
temp = dest.Type.IsInteger()
temp = dest.Type.IsInteger
? GetSpillTemp(dest, intSpillTempRegisters, ref intLocalAsg)
: GetSpillTemp(dest, vecSpillTempRegisters, ref vecLocalAsg);
@@ -443,7 +443,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
useMask |= 1 << selectedReg;
return Register(selectedReg, local.Type.ToRegisterType(), local.Type);
return Register(selectedReg, local.Type.Register, local.Type);
}
private static int UsesCount(Operand local)

View File

@@ -208,7 +208,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
private bool TryAllocateRegWithoutSpill(AllocationContext context, LiveInterval current, int cIndex, int registersCount)
{
RegisterType regType = current.Local.Type.ToRegisterType();
RegisterType regType = current.Local.Type.Register;
Span<int> freePositions = stackalloc int[registersCount];
@@ -318,7 +318,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
private void AllocateRegWithSpill(AllocationContext context, LiveInterval current, int cIndex, int registersCount)
{
RegisterType regType = current.Local.Type.ToRegisterType();
RegisterType regType = current.Local.Type.Register;
Span<int> usePositions = stackalloc int[registersCount];
Span<int> blockedPositions = stackalloc int[registersCount];

View File

@@ -10,7 +10,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
public int Allocate(OperandType type)
{
return Allocate(type.GetSizeInBytes());
return Allocate(type.ByteSize);
}
public int Allocate(int sizeInBytes)

View File

@@ -385,7 +385,7 @@ namespace ARMeilleure.CodeGen.X86
{
ref readonly InstructionInfo info = ref _instTable[(int)X86Instruction.Movd];
if (source.Type.IsInteger() || source.Kind == OperandKind.Memory)
if (source.Type.IsInteger || source.Kind == OperandKind.Memory)
{
WriteOpCode(dest, default, source, OperandType.None, info.Flags, info.OpRRM, rrm: true);
}
@@ -416,11 +416,11 @@ namespace ARMeilleure.CodeGen.X86
InstructionFlags flags = info.Flags | InstructionFlags.RexW;
if (source.Type.IsInteger() || source.Kind == OperandKind.Memory)
if (source.Type.IsInteger || source.Kind == OperandKind.Memory)
{
WriteOpCode(dest, default, source, OperandType.None, flags, info.OpRRM, rrm: true);
}
else if (dest.Type.IsInteger() || dest.Kind == OperandKind.Memory)
else if (dest.Type.IsInteger || dest.Kind == OperandKind.Memory)
{
WriteOpCode(dest, default, source, OperandType.None, flags, info.OpRMR);
}

View File

@@ -289,7 +289,7 @@ namespace ARMeilleure.CodeGen.X86
EnsureSameType(dest, source);
Debug.Assert(dest.Type.IsInteger());
Debug.Assert(dest.Type.IsInteger);
context.Assembler.Popcnt(dest, source, dest.Type);
@@ -303,7 +303,7 @@ namespace ARMeilleure.CodeGen.X86
EnsureSameType(dest, source);
Debug.Assert(!dest.Type.IsInteger());
Debug.Assert(!dest.Type.IsInteger);
context.Assembler.WriteInstruction(info.Inst, dest, source);
@@ -315,7 +315,7 @@ namespace ARMeilleure.CodeGen.X86
Operand dest = operation.Destination;
Operand source = operation.GetSource(0);
Debug.Assert(dest.Type.IsInteger() && !source.Type.IsInteger());
Debug.Assert(dest.Type.IsInteger && !source.Type.IsInteger);
if (operation.Intrinsic == Intrinsic.X86Cvtsi2si)
{
@@ -349,8 +349,8 @@ namespace ARMeilleure.CodeGen.X86
EnsureSameReg(dest, src1);
}
Debug.Assert(!dest.Type.IsInteger());
Debug.Assert(!src2.Type.IsInteger() || src2.Kind == OperandKind.Constant);
Debug.Assert(!dest.Type.IsInteger);
Debug.Assert(!src2.Type.IsInteger || src2.Kind == OperandKind.Constant);
context.Assembler.WriteInstruction(info.Inst, dest, src1, src2);
@@ -370,7 +370,7 @@ namespace ARMeilleure.CodeGen.X86
EnsureSameReg(dest, src1);
}
Debug.Assert(!dest.Type.IsInteger() && src2.Type.IsInteger());
Debug.Assert(!dest.Type.IsInteger && src2.Type.IsInteger);
context.Assembler.WriteInstruction(info.Inst, dest, src1, src2, src2.Type);
@@ -385,7 +385,7 @@ namespace ARMeilleure.CodeGen.X86
EnsureSameReg(dest, src1);
Debug.Assert(dest.Type.IsInteger() && src1.Type.IsInteger() && src2.Type.IsInteger());
Debug.Assert(dest.Type.IsInteger && src1.Type.IsInteger && src2.Type.IsInteger);
context.Assembler.WriteInstruction(info.Inst, dest, src2, dest.Type);
@@ -405,7 +405,7 @@ namespace ARMeilleure.CodeGen.X86
EnsureSameReg(dest, src1);
}
Debug.Assert(!dest.Type.IsInteger() && src2.Kind == OperandKind.Constant);
Debug.Assert(!dest.Type.IsInteger && src2.Kind == OperandKind.Constant);
context.Assembler.WriteInstruction(info.Inst, dest, src1, src2.AsByte());
@@ -421,7 +421,7 @@ namespace ARMeilleure.CodeGen.X86
EnsureSameType(dest, src1, src2, src3);
Debug.Assert(!dest.Type.IsInteger());
Debug.Assert(!dest.Type.IsInteger);
if (info.Inst == X86Instruction.Blendvpd && HardwareCapabilities.SupportsVexEncoding)
{
@@ -461,7 +461,7 @@ namespace ARMeilleure.CodeGen.X86
EnsureSameReg(dest, src1);
}
Debug.Assert(!dest.Type.IsInteger() && src3.Kind == OperandKind.Constant);
Debug.Assert(!dest.Type.IsInteger && src3.Kind == OperandKind.Constant);
context.Assembler.WriteInstruction(info.Inst, dest, src1, src2, src3.AsByte());
@@ -512,7 +512,7 @@ namespace ARMeilleure.CodeGen.X86
Operand src1 = operation.GetSource(0);
Operand src2 = operation.GetSource(1);
if (dest.Type.IsInteger())
if (dest.Type.IsInteger)
{
// If Destination and Source 1 Operands are the same, perform a standard add as there are no benefits to using LEA.
if (dest.Kind == src1.Kind && dest.Value == src1.Value)
@@ -567,7 +567,7 @@ namespace ARMeilleure.CodeGen.X86
ValidateBinOp(dest, src1, src2);
Debug.Assert(dest.Type.IsInteger());
Debug.Assert(dest.Type.IsInteger);
// Note: GenerateCompareCommon makes the assumption that BitwiseAnd will emit only a single `and`
// instruction.
@@ -582,7 +582,7 @@ namespace ARMeilleure.CodeGen.X86
ValidateBinOp(dest, src1, src2);
if (dest.Type.IsInteger())
if (dest.Type.IsInteger)
{
context.Assembler.Xor(dest, src2, dest.Type);
}
@@ -599,7 +599,7 @@ namespace ARMeilleure.CodeGen.X86
ValidateUnOp(dest, source);
Debug.Assert(dest.Type.IsInteger());
Debug.Assert(dest.Type.IsInteger);
context.Assembler.Not(dest);
}
@@ -612,7 +612,7 @@ namespace ARMeilleure.CodeGen.X86
ValidateBinOp(dest, src1, src2);
Debug.Assert(dest.Type.IsInteger());
Debug.Assert(dest.Type.IsInteger);
context.Assembler.Or(dest, src2, dest.Type);
}
@@ -623,7 +623,7 @@ namespace ARMeilleure.CodeGen.X86
Debug.Assert(comp.Kind == OperandKind.Constant);
X86Condition cond = ((Comparison)comp.AsInt32()).ToX86Condition();
X86Condition cond = ((Comparison)comp.AsInt32()).X86;
GenerateCompareCommon(context, operation);
@@ -637,7 +637,7 @@ namespace ARMeilleure.CodeGen.X86
ValidateUnOp(dest, source);
Debug.Assert(dest.Type.IsInteger());
Debug.Assert(dest.Type.IsInteger);
context.Assembler.Bswap(dest);
}
@@ -661,7 +661,7 @@ namespace ARMeilleure.CodeGen.X86
Debug.Assert(dest.Type == OperandType.I32);
Debug.Assert(comp.Kind == OperandKind.Constant);
X86Condition cond = ((Comparison)comp.AsInt32()).ToX86Condition();
X86Condition cond = ((Comparison)comp.AsInt32()).X86;
GenerateCompareCommon(context, operation);
@@ -676,7 +676,7 @@ namespace ARMeilleure.CodeGen.X86
EnsureSameType(src1, src2);
Debug.Assert(src1.Type.IsInteger());
Debug.Assert(src1.Type.IsInteger);
if (src2.Kind == OperandKind.Constant && src2.Value == 0)
{
@@ -766,7 +766,7 @@ namespace ARMeilleure.CodeGen.X86
EnsureSameReg(dest, src3);
EnsureSameType(dest, src2, src3);
Debug.Assert(dest.Type.IsInteger());
Debug.Assert(dest.Type.IsInteger);
Debug.Assert(src1.Type == OperandType.I32);
context.Assembler.Test(src1, src1, src1.Type);
@@ -792,9 +792,9 @@ namespace ARMeilleure.CodeGen.X86
if (dest.Type == OperandType.FP32)
{
Debug.Assert(source.Type.IsInteger() || source.Type == OperandType.FP64);
Debug.Assert(source.Type.IsInteger || source.Type == OperandType.FP64);
if (source.Type.IsInteger())
if (source.Type.IsInteger)
{
context.Assembler.Xorps(dest, dest, dest);
context.Assembler.Cvtsi2ss(dest, dest, source, source.Type);
@@ -808,9 +808,9 @@ namespace ARMeilleure.CodeGen.X86
}
else /* if (dest.Type == OperandType.FP64) */
{
Debug.Assert(source.Type.IsInteger() || source.Type == OperandType.FP32);
Debug.Assert(source.Type.IsInteger || source.Type == OperandType.FP32);
if (source.Type.IsInteger())
if (source.Type.IsInteger)
{
context.Assembler.Xorps(dest, dest, dest);
context.Assembler.Cvtsi2sd(dest, dest, source, source.Type);
@@ -831,7 +831,7 @@ namespace ARMeilleure.CodeGen.X86
EnsureSameType(dest, source);
Debug.Assert(dest.Type.IsInteger() || source.Kind != OperandKind.Constant);
Debug.Assert(dest.Type.IsInteger || source.Kind != OperandKind.Constant);
// Moves to the same register are useless.
if (dest.Kind == source.Kind && dest.Value == source.Value)
@@ -845,7 +845,7 @@ namespace ARMeilleure.CodeGen.X86
// Assemble "mov reg, 0" as "xor reg, reg" as the later is more efficient.
context.Assembler.Xor(dest, dest, OperandType.I32);
}
else if (dest.Type.IsInteger())
else if (dest.Type.IsInteger)
{
context.Assembler.Mov(dest, source, dest.Type);
}
@@ -862,7 +862,7 @@ namespace ARMeilleure.CodeGen.X86
EnsureSameType(dest, source);
Debug.Assert(dest.Type.IsInteger());
Debug.Assert(dest.Type.IsInteger);
context.Assembler.Bsr(dest, source, dest.Type);
@@ -894,12 +894,12 @@ namespace ARMeilleure.CodeGen.X86
Operand dividend = operation.GetSource(0);
Operand divisor = operation.GetSource(1);
if (!dest.Type.IsInteger())
if (!dest.Type.IsInteger)
{
ValidateBinOp(dest, dividend, divisor);
}
if (dest.Type.IsInteger())
if (dest.Type.IsInteger)
{
divisor = operation.GetSource(2);
@@ -932,7 +932,7 @@ namespace ARMeilleure.CodeGen.X86
Operand rdx = Register(X86Register.Rdx);
Debug.Assert(divisor.Type.IsInteger());
Debug.Assert(divisor.Type.IsInteger);
context.Assembler.Xor(rdx, rdx, OperandType.I32);
context.Assembler.Div(divisor);
@@ -967,7 +967,7 @@ namespace ARMeilleure.CodeGen.X86
Operand value = operation.Destination;
Operand address = Memory(operation.GetSource(0), value.Type);
Debug.Assert(value.Type.IsInteger());
Debug.Assert(value.Type.IsInteger);
context.Assembler.Movzx16(value, address, value.Type);
}
@@ -977,7 +977,7 @@ namespace ARMeilleure.CodeGen.X86
Operand value = operation.Destination;
Operand address = Memory(operation.GetSource(0), value.Type);
Debug.Assert(value.Type.IsInteger());
Debug.Assert(value.Type.IsInteger);
context.Assembler.Movzx8(value, address, value.Type);
}
@@ -1000,7 +1000,7 @@ namespace ARMeilleure.CodeGen.X86
EnsureSameType(dest, src1, src2);
if (dest.Type.IsInteger())
if (dest.Type.IsInteger)
{
if (src2.Kind == OperandKind.Constant)
{
@@ -1046,7 +1046,7 @@ namespace ARMeilleure.CodeGen.X86
ValidateUnOp(dest, source);
Debug.Assert(dest.Type.IsInteger());
Debug.Assert(dest.Type.IsInteger);
context.Assembler.Neg(dest);
}
@@ -1107,7 +1107,7 @@ namespace ARMeilleure.CodeGen.X86
Operand dest = operation.Destination;
Operand source = operation.GetSource(0);
Debug.Assert(dest.Type.IsInteger() && source.Type.IsInteger());
Debug.Assert(dest.Type.IsInteger && source.Type.IsInteger);
context.Assembler.Movsx16(dest, source, dest.Type);
}
@@ -1117,7 +1117,7 @@ namespace ARMeilleure.CodeGen.X86
Operand dest = operation.Destination;
Operand source = operation.GetSource(0);
Debug.Assert(dest.Type.IsInteger() && source.Type.IsInteger());
Debug.Assert(dest.Type.IsInteger && source.Type.IsInteger);
context.Assembler.Movsx32(dest, source, dest.Type);
}
@@ -1127,7 +1127,7 @@ namespace ARMeilleure.CodeGen.X86
Operand dest = operation.Destination;
Operand source = operation.GetSource(0);
Debug.Assert(dest.Type.IsInteger() && source.Type.IsInteger());
Debug.Assert(dest.Type.IsInteger && source.Type.IsInteger);
context.Assembler.Movsx8(dest, source, dest.Type);
}
@@ -1187,7 +1187,7 @@ namespace ARMeilleure.CodeGen.X86
Operand value = operation.GetSource(1);
Operand address = Memory(operation.GetSource(0), value.Type);
Debug.Assert(value.Type.IsInteger());
Debug.Assert(value.Type.IsInteger);
context.Assembler.Mov16(address, value);
}
@@ -1197,7 +1197,7 @@ namespace ARMeilleure.CodeGen.X86
Operand value = operation.GetSource(1);
Operand address = Memory(operation.GetSource(0), value.Type);
Debug.Assert(value.Type.IsInteger());
Debug.Assert(value.Type.IsInteger);
context.Assembler.Mov8(address, value);
}
@@ -1210,7 +1210,7 @@ namespace ARMeilleure.CodeGen.X86
ValidateBinOp(dest, src1, src2);
if (dest.Type.IsInteger())
if (dest.Type.IsInteger)
{
context.Assembler.Sub(dest, src2, dest.Type);
}
@@ -1236,7 +1236,7 @@ namespace ARMeilleure.CodeGen.X86
Operand dest = operation.Destination;
Operand source = operation.GetSource(0);
Debug.Assert(!dest.Type.IsInteger() && source.Type.IsInteger());
Debug.Assert(!dest.Type.IsInteger && source.Type.IsInteger);
if (source.Type == OperandType.I32)
{
@@ -1259,7 +1259,7 @@ namespace ARMeilleure.CodeGen.X86
byte index = src2.AsByte();
Debug.Assert(index < OperandType.V128.GetSizeInBytes() / dest.Type.GetSizeInBytes());
Debug.Assert(index < OperandType.V128.ByteSize / dest.Type.ByteSize);
if (dest.Type == OperandType.I32)
{
@@ -1541,7 +1541,7 @@ namespace ARMeilleure.CodeGen.X86
{
Operand dest = operation.Destination;
Debug.Assert(!dest.Type.IsInteger());
Debug.Assert(!dest.Type.IsInteger);
context.Assembler.Pcmpeqw(dest, dest, dest);
}
@@ -1550,7 +1550,7 @@ namespace ARMeilleure.CodeGen.X86
{
Operand dest = operation.Destination;
Debug.Assert(!dest.Type.IsInteger());
Debug.Assert(!dest.Type.IsInteger);
context.Assembler.Xorps(dest, dest, dest);
}
@@ -1580,7 +1580,7 @@ namespace ARMeilleure.CodeGen.X86
Operand dest = operation.Destination;
Operand source = operation.GetSource(0);
Debug.Assert(dest.Type.IsInteger() && source.Type.IsInteger());
Debug.Assert(dest.Type.IsInteger && source.Type.IsInteger);
context.Assembler.Movzx16(dest, source, OperandType.I32);
}
@@ -1590,7 +1590,7 @@ namespace ARMeilleure.CodeGen.X86
Operand dest = operation.Destination;
Operand source = operation.GetSource(0);
Debug.Assert(dest.Type.IsInteger() && source.Type.IsInteger());
Debug.Assert(dest.Type.IsInteger && source.Type.IsInteger);
// We can eliminate the move if source is already 32-bit and the registers are the same.
if (dest.Value == source.Value && source.Type == OperandType.I32)
@@ -1606,7 +1606,7 @@ namespace ARMeilleure.CodeGen.X86
Operand dest = operation.Destination;
Operand source = operation.GetSource(0);
Debug.Assert(dest.Type.IsInteger() && source.Type.IsInteger());
Debug.Assert(dest.Type.IsInteger && source.Type.IsInteger);
context.Assembler.Movzx8(dest, source, OperandType.I32);
}
@@ -1713,12 +1713,12 @@ namespace ARMeilleure.CodeGen.X86
EnsureSameReg(dest, src1);
EnsureSameType(dest, src1);
Debug.Assert(dest.Type.IsInteger() && src2.Type == OperandType.I32);
Debug.Assert(dest.Type.IsInteger && src2.Type == OperandType.I32);
}
private static void EnsureSameReg(Operand op1, Operand op2)
{
if (!op1.Type.IsInteger() && HardwareCapabilities.SupportsVexEncoding)
if (!op1.Type.IsInteger && HardwareCapabilities.SupportsVexEncoding)
{
return;
}

View File

@@ -86,7 +86,7 @@ namespace ARMeilleure.CodeGen.X86
break;
case Instruction.Negate:
if (!node.GetSource(0).Type.IsInteger())
if (!node.GetSource(0).Type.IsInteger)
{
GenerateNegate(block.Operations, node);
}
@@ -159,7 +159,7 @@ namespace ARMeilleure.CodeGen.X86
if (src1.Kind == OperandKind.Constant)
{
if (!src1.Type.IsInteger())
if (!src1.Type.IsInteger)
{
// Handle non-integer types (FP32, FP64 and V128).
// For instructions without an immediate operand, we do the following:
@@ -208,7 +208,7 @@ namespace ARMeilleure.CodeGen.X86
if (src2.Kind == OperandKind.Constant)
{
if (!src2.Type.IsInteger())
if (!src2.Type.IsInteger)
{
src2 = AddXmmCopy(nodes, node, src2);
@@ -298,7 +298,7 @@ namespace ARMeilleure.CodeGen.X86
// - The dividend is always in RDX:RAX.
// - The result is always in RAX.
// - Additionally it also writes the remainder in RDX.
if (dest.Type.IsInteger())
if (dest.Type.IsInteger)
{
Operand src1 = node.GetSource(0);
@@ -466,7 +466,7 @@ namespace ARMeilleure.CodeGen.X86
Operand dest = node.Destination;
Operand source = node.GetSource(0);
Debug.Assert(source.Type.IsInteger(), $"Invalid source type \"{source.Type}\".");
Debug.Assert(source.Type.IsInteger, $"Invalid source type \"{source.Type}\".");
Operation currentNode = node;
@@ -654,10 +654,10 @@ namespace ARMeilleure.CodeGen.X86
switch (operation.Instruction)
{
case Instruction.Add:
return !HardwareCapabilities.SupportsVexEncoding && !operation.Destination.Type.IsInteger();
return !HardwareCapabilities.SupportsVexEncoding && !operation.Destination.Type.IsInteger;
case Instruction.Multiply:
case Instruction.Subtract:
return !HardwareCapabilities.SupportsVexEncoding || operation.Destination.Type.IsInteger();
return !HardwareCapabilities.SupportsVexEncoding || operation.Destination.Type.IsInteger;
case Instruction.BitwiseAnd:
case Instruction.BitwiseExclusiveOr:
@@ -672,7 +672,7 @@ namespace ARMeilleure.CodeGen.X86
return true;
case Instruction.Divide:
return !HardwareCapabilities.SupportsVexEncoding && !operation.Destination.Type.IsInteger();
return !HardwareCapabilities.SupportsVexEncoding && !operation.Destination.Type.IsInteger;
case Instruction.VectorInsert:
case Instruction.VectorInsert16:

View File

@@ -35,7 +35,7 @@ namespace ARMeilleure.CodeGen.X86
bool passOnReg;
if (source.Type.IsInteger())
if (source.Type.IsInteger)
{
passOnReg = intCount < intMax;
}
@@ -62,7 +62,7 @@ namespace ARMeilleure.CodeGen.X86
if (passOnReg)
{
Operand argReg = source.Type.IsInteger()
Operand argReg = source.Type.IsInteger
? Gpr(CallingConvention.GetIntArgumentRegister(intCount++), source.Type)
: Xmm(CallingConvention.GetVecArgumentRegister(vecCount++), source.Type);
@@ -80,7 +80,7 @@ namespace ARMeilleure.CodeGen.X86
InsertConstantRegCopies(nodes, nodes.AddBefore(node, spillOp));
stackOffset += source.Type.GetSizeInBytes();
stackOffset += source.Type.ByteSize;
}
}
@@ -102,7 +102,7 @@ namespace ARMeilleure.CodeGen.X86
}
else
{
Operand retReg = dest.Type.IsInteger()
Operand retReg = dest.Type.IsInteger
? Gpr(CallingConvention.GetIntReturnRegister(), dest.Type)
: Xmm(CallingConvention.GetVecReturnRegister(), dest.Type);
@@ -137,7 +137,7 @@ namespace ARMeilleure.CodeGen.X86
bool passOnReg;
if (source.Type.IsInteger())
if (source.Type.IsInteger)
{
passOnReg = intCount + 1 < intMax;
}
@@ -160,7 +160,7 @@ namespace ARMeilleure.CodeGen.X86
if (passOnReg)
{
Operand argReg = source.Type.IsInteger()
Operand argReg = source.Type.IsInteger
? Gpr(CallingConvention.GetIntArgumentRegister(intCount++), source.Type)
: Xmm(CallingConvention.GetVecArgumentRegister(vecCount++), source.Type);
@@ -210,7 +210,7 @@ namespace ARMeilleure.CodeGen.X86
{
OperandType argType = cctx.FuncArgTypes[cIndex];
if (argType.IsInteger())
if (argType.IsInteger)
{
intCount++;
}
@@ -226,7 +226,7 @@ namespace ARMeilleure.CodeGen.X86
bool passOnReg;
if (source.Type.IsInteger())
if (source.Type.IsInteger)
{
passOnReg = intCount < CallingConvention.GetIntArgumentsOnRegsCount();
}
@@ -265,7 +265,7 @@ namespace ARMeilleure.CodeGen.X86
{
Operand pArg = Local(dest.Type);
Operand argReg = dest.Type.IsInteger()
Operand argReg = dest.Type.IsInteger
? Gpr(CallingConvention.GetIntArgumentRegister(intCount), dest.Type)
: Xmm(CallingConvention.GetVecArgumentRegister(vecCount), dest.Type);
@@ -320,7 +320,7 @@ namespace ARMeilleure.CodeGen.X86
}
else
{
Operand retReg = source.Type.IsInteger()
Operand retReg = source.Type.IsInteger
? Gpr(CallingConvention.GetIntReturnRegister(), source.Type)
: Xmm(CallingConvention.GetVecReturnRegister(), source.Type);

View File

@@ -40,7 +40,7 @@ namespace ARMeilleure.CodeGen.X86
if (dest != default && dest.Type == OperandType.V128)
{
int stackOffset = AllocateOnStack(dest.Type.GetSizeInBytes());
int stackOffset = AllocateOnStack(dest.Type.ByteSize);
arg0Reg = Gpr(CallingConvention.GetIntArgumentRegister(0), OperandType.I64);
@@ -76,7 +76,7 @@ namespace ARMeilleure.CodeGen.X86
{
Operand stackAddr = Local(OperandType.I64);
int stackOffset = AllocateOnStack(source.Type.GetSizeInBytes());
int stackOffset = AllocateOnStack(source.Type.ByteSize);
nodes.AddBefore(node, Operation(Instruction.StackAlloc, stackAddr, Const(stackOffset)));
@@ -96,7 +96,7 @@ namespace ARMeilleure.CodeGen.X86
int argIndex = index + retArgs;
if (source.Type.IsInteger())
if (source.Type.IsInteger)
{
argReg = Gpr(CallingConvention.GetIntArgumentRegister(argIndex), source.Type);
}
@@ -140,7 +140,7 @@ namespace ARMeilleure.CodeGen.X86
}
else
{
Operand retReg = dest.Type.IsInteger()
Operand retReg = dest.Type.IsInteger
? Gpr(CallingConvention.GetIntReturnRegister(), dest.Type)
: Xmm(CallingConvention.GetVecReturnRegister(), dest.Type);
@@ -171,7 +171,7 @@ namespace ARMeilleure.CodeGen.X86
for (int index = 0; index < argsCount; index++)
{
Operand source = node.GetSource(1 + index);
Operand argReg = source.Type.IsInteger()
Operand argReg = source.Type.IsInteger
? Gpr(CallingConvention.GetIntArgumentRegister(index), source.Type)
: Xmm(CallingConvention.GetVecArgumentRegister(index), source.Type);
@@ -219,7 +219,7 @@ namespace ARMeilleure.CodeGen.X86
{
Operand argReg, pArg;
if (dest.Type.IsInteger())
if (dest.Type.IsInteger)
{
argReg = Gpr(CallingConvention.GetIntArgumentRegister(index), dest.Type);
pArg = Local(dest.Type);
@@ -283,7 +283,7 @@ namespace ARMeilleure.CodeGen.X86
Operand source = node.GetSource(0);
Operand retReg;
if (source.Type.IsInteger())
if (source.Type.IsInteger)
{
retReg = Gpr(CallingConvention.GetIntReturnRegister(), source.Type);
}

View File

@@ -25,9 +25,9 @@ namespace ARMeilleure.CodeGen.X86
static class ComparisonX86Extensions
{
public static X86Condition ToX86Condition(this Comparison comp)
extension(Comparison comparison)
{
return comp switch
public X86Condition X86 => comparison switch
{
#pragma warning disable IDE0055 // Disable formatting
Comparison.Equal => X86Condition.Equal,
@@ -42,7 +42,7 @@ namespace ARMeilleure.CodeGen.X86
Comparison.LessUI => X86Condition.Below,
#pragma warning restore IDE0055
_ => throw new ArgumentException(null, nameof(comp)),
_ => throw new ArgumentException(null, nameof(comparison))
};
}
}

View File

@@ -22,11 +22,11 @@ namespace ARMeilleure.Decoders
static class ConditionExtensions
{
public static Condition Invert(this Condition cond)
extension(Condition condition)
{
// Bit 0 of all conditions is basically a negation bit, so
// inverting this bit has the effect of inverting the condition.
return (Condition)((int)cond ^ 1);
public Condition Inverse => (Condition)((int)condition ^ 1);
}
}
}

View File

@@ -19,7 +19,7 @@ namespace ARMeilleure.Instructions
context.LoadFromContext();
context.Return(Const(op.Address));
InstEmitFlowHelper.EmitReturn(context, Const(op.Address));
}
public static void Svc(ArmEmitterContext context)
@@ -49,7 +49,7 @@ namespace ARMeilleure.Instructions
context.LoadFromContext();
context.Return(Const(op.Address));
InstEmitFlowHelper.EmitReturn(context, Const(op.Address));
}
}
}

View File

@@ -33,7 +33,7 @@ namespace ARMeilleure.Instructions
context.LoadFromContext();
context.Return(Const(context.CurrOp.Address));
InstEmitFlowHelper.EmitReturn(context, Const(context.CurrOp.Address));
}
}
}

View File

@@ -66,7 +66,7 @@ namespace ARMeilleure.Instructions
{
OpCodeBReg op = (OpCodeBReg)context.CurrOp;
context.Return(GetIntOrZR(context, op.Rn));
EmitReturn(context, GetIntOrZR(context, op.Rn));
}
public static void Tbnz(ArmEmitterContext context) => EmitTb(context, onNotZero: true);

View File

@@ -13,6 +13,10 @@ namespace ARMeilleure.Instructions
{
static class InstEmitFlowHelper
{
// How many calls we can have in our call stack before we give up and return to the dispatcher.
// This prevents stack overflows caused by deep recursive calls.
private const int MaxCallDepth = 200;
public static void EmitCondBranch(ArmEmitterContext context, Operand target, Condition cond)
{
if (cond != Condition.Al)
@@ -182,12 +186,7 @@ namespace ARMeilleure.Instructions
{
if (isReturn || context.IsSingleStep)
{
if (target.Type == OperandType.I32)
{
target = context.ZeroExtend32(OperandType.I64, target);
}
context.Return(target);
EmitReturn(context, target);
}
else
{
@@ -195,6 +194,19 @@ namespace ARMeilleure.Instructions
}
}
public static void EmitReturn(ArmEmitterContext context, Operand target)
{
Operand nativeContext = context.LoadArgument(OperandType.I64, 0);
DecreaseCallDepth(context, nativeContext);
if (target.Type == OperandType.I32)
{
target = context.ZeroExtend32(OperandType.I64, target);
}
context.Return(target);
}
private static void EmitTableBranch(ArmEmitterContext context, Operand guestAddress, bool isJump)
{
context.StoreToContext();
@@ -257,6 +269,8 @@ namespace ARMeilleure.Instructions
if (isJump)
{
DecreaseCallDepth(context, nativeContext);
context.Tailcall(hostAddress, nativeContext);
}
else
@@ -278,8 +292,42 @@ namespace ARMeilleure.Instructions
Operand lblContinue = context.GetLabel(nextAddr.Value);
context.BranchIf(lblContinue, returnAddress, nextAddr, Comparison.Equal, BasicBlockFrequency.Cold);
DecreaseCallDepth(context, nativeContext);
context.Return(returnAddress);
}
}
public static void EmitCallDepthCheckAndIncrement(EmitterContext context, Operand guestAddress)
{
if (!Optimizations.EnableDeepCallRecursionProtection)
{
return;
}
Operand nativeContext = context.LoadArgument(OperandType.I64, 0);
Operand callDepthAddr = context.Add(nativeContext, Const((ulong)NativeContext.GetCallDepthOffset()));
Operand currentCallDepth = context.Load(OperandType.I32, callDepthAddr);
Operand lblDoCall = Label();
context.BranchIf(lblDoCall, currentCallDepth, Const(MaxCallDepth), Comparison.LessUI);
context.Store(callDepthAddr, context.Subtract(currentCallDepth, Const(1)));
context.Return(guestAddress);
context.MarkLabel(lblDoCall);
context.Store(callDepthAddr, context.Add(currentCallDepth, Const(1)));
}
private static void DecreaseCallDepth(EmitterContext context, Operand nativeContext)
{
if (!Optimizations.EnableDeepCallRecursionProtection)
{
return;
}
Operand callDepthAddr = context.Add(nativeContext, Const((ulong)NativeContext.GetCallDepthOffset()));
Operand currentCallDepth = context.Load(OperandType.I32, callDepthAddr);
context.Store(callDepthAddr, context.Subtract(currentCallDepth, Const(1)));
}
}
}

View File

@@ -16,7 +16,7 @@ namespace ARMeilleure.Instructions
public static Operand EmitCrc32(ArmEmitterContext context, Operand crc, Operand value, int size, bool castagnoli)
{
Debug.Assert(crc.Type.IsInteger() && value.Type.IsInteger());
Debug.Assert(crc.Type.IsInteger && value.Type.IsInteger);
Debug.Assert(size is >= 0 and < 4);
Debug.Assert((size < 3) || (value.Type == OperandType.I64));

View File

@@ -157,7 +157,7 @@ namespace ARMeilleure.Instructions
context.Copy(temp, value);
if (!context.Memory.Type.IsHostMappedOrTracked())
if (!context.Memory.Type.IsHostMappedOrTracked)
{
context.Branch(lblEnd);
@@ -198,7 +198,7 @@ namespace ARMeilleure.Instructions
SetInt(context, rt, value);
if (!context.Memory.Type.IsHostMappedOrTracked())
if (!context.Memory.Type.IsHostMappedOrTracked)
{
context.Branch(lblEnd);
@@ -265,7 +265,7 @@ namespace ARMeilleure.Instructions
context.Copy(GetVec(rt), value);
if (!context.Memory.Type.IsHostMappedOrTracked())
if (!context.Memory.Type.IsHostMappedOrTracked)
{
context.Branch(lblEnd);
@@ -312,7 +312,7 @@ namespace ARMeilleure.Instructions
break;
}
if (!context.Memory.Type.IsHostMappedOrTracked())
if (!context.Memory.Type.IsHostMappedOrTracked)
{
context.Branch(lblEnd);
@@ -385,7 +385,7 @@ namespace ARMeilleure.Instructions
break;
}
if (!context.Memory.Type.IsHostMappedOrTracked())
if (!context.Memory.Type.IsHostMappedOrTracked)
{
context.Branch(lblEnd);
@@ -399,11 +399,11 @@ namespace ARMeilleure.Instructions
public static Operand EmitPtPointerLoad(ArmEmitterContext context, Operand address, Operand lblSlowPath, bool write, int size)
{
if (context.Memory.Type.IsHostMapped())
if (context.Memory.Type.IsHostMapped)
{
return EmitHostMappedPointer(context, address);
}
else if (context.Memory.Type.IsHostTracked())
else if (context.Memory.Type.IsHostTracked)
{
if (address.Type == OperandType.I32)
{

View File

@@ -1,692 +0,0 @@
using ARMeilleure.State;
using System;
using System.Runtime.InteropServices;
namespace ARMeilleure.Instructions
{
static class SoftFallback
{
#region "ShrImm64"
[UnmanagedCallersOnly]
public static long SignedShrImm64(long value, long roundConst, int shift)
{
if (roundConst == 0L)
{
if (shift <= 63)
{
return value >> shift;
}
else /* if (shift == 64) */
{
if (value < 0L)
{
return -1L;
}
else /* if (value >= 0L) */
{
return 0L;
}
}
}
else /* if (roundConst == 1L << (shift - 1)) */
{
if (shift <= 63)
{
long add = value + roundConst;
if ((~value & (value ^ add)) < 0L)
{
return (long)((ulong)add >> shift);
}
else
{
return add >> shift;
}
}
else /* if (shift == 64) */
{
return 0L;
}
}
}
[UnmanagedCallersOnly]
public static ulong UnsignedShrImm64(ulong value, long roundConst, int shift)
{
if (roundConst == 0L)
{
if (shift <= 63)
{
return value >> shift;
}
else /* if (shift == 64) */
{
return 0UL;
}
}
else /* if (roundConst == 1L << (shift - 1)) */
{
ulong add = value + (ulong)roundConst;
if ((add < value) && (add < (ulong)roundConst))
{
if (shift <= 63)
{
return (add >> shift) | (0x8000000000000000UL >> (shift - 1));
}
else /* if (shift == 64) */
{
return 1UL;
}
}
else
{
if (shift <= 63)
{
return add >> shift;
}
else /* if (shift == 64) */
{
return 0UL;
}
}
}
}
#endregion
#region "Saturation"
[UnmanagedCallersOnly]
public static int SatF32ToS32(float value)
{
if (float.IsNaN(value))
{
return 0;
}
return value >= int.MaxValue ? int.MaxValue :
value <= int.MinValue ? int.MinValue : (int)value;
}
[UnmanagedCallersOnly]
public static long SatF32ToS64(float value)
{
if (float.IsNaN(value))
{
return 0;
}
return value >= long.MaxValue ? long.MaxValue :
value <= long.MinValue ? long.MinValue : (long)value;
}
[UnmanagedCallersOnly]
public static uint SatF32ToU32(float value)
{
if (float.IsNaN(value))
{
return 0;
}
return value >= uint.MaxValue ? uint.MaxValue :
value <= uint.MinValue ? uint.MinValue : (uint)value;
}
[UnmanagedCallersOnly]
public static ulong SatF32ToU64(float value)
{
if (float.IsNaN(value))
{
return 0;
}
return value >= ulong.MaxValue ? ulong.MaxValue :
value <= ulong.MinValue ? ulong.MinValue : (ulong)value;
}
[UnmanagedCallersOnly]
public static int SatF64ToS32(double value)
{
if (double.IsNaN(value))
{
return 0;
}
return value >= int.MaxValue ? int.MaxValue :
value <= int.MinValue ? int.MinValue : (int)value;
}
[UnmanagedCallersOnly]
public static long SatF64ToS64(double value)
{
if (double.IsNaN(value))
{
return 0;
}
return value >= long.MaxValue ? long.MaxValue :
value <= long.MinValue ? long.MinValue : (long)value;
}
[UnmanagedCallersOnly]
public static uint SatF64ToU32(double value)
{
if (double.IsNaN(value))
{
return 0;
}
return value >= uint.MaxValue ? uint.MaxValue :
value <= uint.MinValue ? uint.MinValue : (uint)value;
}
[UnmanagedCallersOnly]
public static ulong SatF64ToU64(double value)
{
if (double.IsNaN(value))
{
return 0;
}
return value >= ulong.MaxValue ? ulong.MaxValue :
value <= ulong.MinValue ? ulong.MinValue : (ulong)value;
}
#endregion
#region "Count"
[UnmanagedCallersOnly]
public static ulong CountLeadingSigns(ulong value, int size) // size is 8, 16, 32 or 64 (SIMD&FP or Base Inst.).
{
value ^= value >> 1;
int highBit = size - 2;
for (int bit = highBit; bit >= 0; bit--)
{
if (((int)(value >> bit) & 0b1) != 0)
{
return (ulong)(highBit - bit);
}
}
return (ulong)(size - 1);
}
private static ReadOnlySpan<byte> ClzNibbleTbl => [4, 3, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0];
[UnmanagedCallersOnly]
public static ulong CountLeadingZeros(ulong value, int size) // size is 8, 16, 32 or 64 (SIMD&FP or Base Inst.).
{
if (value == 0ul)
{
return (ulong)size;
}
int nibbleIdx = size;
int preCount, count = 0;
do
{
nibbleIdx -= 4;
preCount = ClzNibbleTbl[(int)(value >> nibbleIdx) & 0b1111];
count += preCount;
}
while (preCount == 4);
return (ulong)count;
}
#endregion
#region "Table"
[UnmanagedCallersOnly]
public static V128 Tbl1(V128 vector, int bytes, V128 tb0)
{
return TblOrTbx(default, vector, bytes, tb0);
}
[UnmanagedCallersOnly]
public static V128 Tbl2(V128 vector, int bytes, V128 tb0, V128 tb1)
{
return TblOrTbx(default, vector, bytes, tb0, tb1);
}
[UnmanagedCallersOnly]
public static V128 Tbl3(V128 vector, int bytes, V128 tb0, V128 tb1, V128 tb2)
{
return TblOrTbx(default, vector, bytes, tb0, tb1, tb2);
}
[UnmanagedCallersOnly]
public static V128 Tbl4(V128 vector, int bytes, V128 tb0, V128 tb1, V128 tb2, V128 tb3)
{
return TblOrTbx(default, vector, bytes, tb0, tb1, tb2, tb3);
}
[UnmanagedCallersOnly]
public static V128 Tbx1(V128 dest, V128 vector, int bytes, V128 tb0)
{
return TblOrTbx(dest, vector, bytes, tb0);
}
[UnmanagedCallersOnly]
public static V128 Tbx2(V128 dest, V128 vector, int bytes, V128 tb0, V128 tb1)
{
return TblOrTbx(dest, vector, bytes, tb0, tb1);
}
[UnmanagedCallersOnly]
public static V128 Tbx3(V128 dest, V128 vector, int bytes, V128 tb0, V128 tb1, V128 tb2)
{
return TblOrTbx(dest, vector, bytes, tb0, tb1, tb2);
}
[UnmanagedCallersOnly]
public static V128 Tbx4(V128 dest, V128 vector, int bytes, V128 tb0, V128 tb1, V128 tb2, V128 tb3)
{
return TblOrTbx(dest, vector, bytes, tb0, tb1, tb2, tb3);
}
private static V128 TblOrTbx(V128 dest, V128 vector, int bytes, params ReadOnlySpan<V128> tb)
{
byte[] res = new byte[16];
if (dest != default)
{
Buffer.BlockCopy(dest.ToArray(), 0, res, 0, bytes);
}
byte[] table = new byte[tb.Length * 16];
for (byte index = 0; index < tb.Length; index++)
{
Buffer.BlockCopy(tb[index].ToArray(), 0, table, index * 16, 16);
}
byte[] v = vector.ToArray();
for (byte index = 0; index < bytes; index++)
{
byte tblIndex = v[index];
if (tblIndex < table.Length)
{
res[index] = table[tblIndex];
}
}
return new V128(res);
}
#endregion
#region "Crc32"
private const uint Crc32RevPoly = 0xedb88320;
private const uint Crc32cRevPoly = 0x82f63b78;
[UnmanagedCallersOnly]
public static uint Crc32b(uint crc, byte value) => Crc32(crc, Crc32RevPoly, value);
[UnmanagedCallersOnly]
public static uint Crc32h(uint crc, ushort value) => Crc32h(crc, Crc32RevPoly, value);
[UnmanagedCallersOnly]
public static uint Crc32w(uint crc, uint value) => Crc32w(crc, Crc32RevPoly, value);
[UnmanagedCallersOnly]
public static uint Crc32x(uint crc, ulong value) => Crc32x(crc, Crc32RevPoly, value);
[UnmanagedCallersOnly]
public static uint Crc32cb(uint crc, byte value) => Crc32(crc, Crc32cRevPoly, value);
[UnmanagedCallersOnly]
public static uint Crc32ch(uint crc, ushort value) => Crc32h(crc, Crc32cRevPoly, value);
[UnmanagedCallersOnly]
public static uint Crc32cw(uint crc, uint value) => Crc32w(crc, Crc32cRevPoly, value);
[UnmanagedCallersOnly]
public static uint Crc32cx(uint crc, ulong value) => Crc32x(crc, Crc32cRevPoly, value);
private static uint Crc32h(uint crc, uint poly, ushort val)
{
crc = Crc32(crc, poly, (byte)(val >> 0));
crc = Crc32(crc, poly, (byte)(val >> 8));
return crc;
}
private static uint Crc32w(uint crc, uint poly, uint val)
{
crc = Crc32(crc, poly, (byte)(val >> 0));
crc = Crc32(crc, poly, (byte)(val >> 8));
crc = Crc32(crc, poly, (byte)(val >> 16));
crc = Crc32(crc, poly, (byte)(val >> 24));
return crc;
}
private static uint Crc32x(uint crc, uint poly, ulong val)
{
crc = Crc32(crc, poly, (byte)(val >> 0));
crc = Crc32(crc, poly, (byte)(val >> 8));
crc = Crc32(crc, poly, (byte)(val >> 16));
crc = Crc32(crc, poly, (byte)(val >> 24));
crc = Crc32(crc, poly, (byte)(val >> 32));
crc = Crc32(crc, poly, (byte)(val >> 40));
crc = Crc32(crc, poly, (byte)(val >> 48));
crc = Crc32(crc, poly, (byte)(val >> 56));
return crc;
}
private static uint Crc32(uint crc, uint poly, byte val)
{
crc ^= val;
for (int bit = 7; bit >= 0; bit--)
{
uint mask = (uint)(-(int)(crc & 1));
crc = (crc >> 1) ^ (poly & mask);
}
return crc;
}
#endregion
#region "Aes"
[UnmanagedCallersOnly]
public static V128 Decrypt(V128 value, V128 roundKey)
{
return CryptoHelper.AesInvSubBytes(CryptoHelper.AesInvShiftRows(value ^ roundKey));
}
[UnmanagedCallersOnly]
public static V128 Encrypt(V128 value, V128 roundKey)
{
return CryptoHelper.AesSubBytes(CryptoHelper.AesShiftRows(value ^ roundKey));
}
[UnmanagedCallersOnly]
public static V128 InverseMixColumns(V128 value)
{
return CryptoHelper.AesInvMixColumns(value);
}
[UnmanagedCallersOnly]
public static V128 MixColumns(V128 value)
{
return CryptoHelper.AesMixColumns(value);
}
#endregion
#region "Sha1"
[UnmanagedCallersOnly]
public static V128 HashChoose(V128 hash_abcd, uint hash_e, V128 wk)
{
for (int e = 0; e <= 3; e++)
{
uint t = ShaChoose(hash_abcd.Extract<uint>(1),
hash_abcd.Extract<uint>(2),
hash_abcd.Extract<uint>(3));
hash_e += Rol(hash_abcd.Extract<uint>(0), 5) + t + wk.Extract<uint>(e);
t = Rol(hash_abcd.Extract<uint>(1), 30);
hash_abcd.Insert(1, t);
Rol32_160(ref hash_e, ref hash_abcd);
}
return hash_abcd;
}
[UnmanagedCallersOnly]
public static uint FixedRotate(uint hash_e)
{
return hash_e.Rol(30);
}
[UnmanagedCallersOnly]
public static V128 HashMajority(V128 hash_abcd, uint hash_e, V128 wk)
{
for (int e = 0; e <= 3; e++)
{
uint t = ShaMajority(hash_abcd.Extract<uint>(1),
hash_abcd.Extract<uint>(2),
hash_abcd.Extract<uint>(3));
hash_e += Rol(hash_abcd.Extract<uint>(0), 5) + t + wk.Extract<uint>(e);
t = Rol(hash_abcd.Extract<uint>(1), 30);
hash_abcd.Insert(1, t);
Rol32_160(ref hash_e, ref hash_abcd);
}
return hash_abcd;
}
[UnmanagedCallersOnly]
public static V128 HashParity(V128 hash_abcd, uint hash_e, V128 wk)
{
for (int e = 0; e <= 3; e++)
{
uint t = ShaParity(hash_abcd.Extract<uint>(1),
hash_abcd.Extract<uint>(2),
hash_abcd.Extract<uint>(3));
hash_e += Rol(hash_abcd.Extract<uint>(0), 5) + t + wk.Extract<uint>(e);
t = Rol(hash_abcd.Extract<uint>(1), 30);
hash_abcd.Insert(1, t);
Rol32_160(ref hash_e, ref hash_abcd);
}
return hash_abcd;
}
[UnmanagedCallersOnly]
public static V128 Sha1SchedulePart1(V128 w0_3, V128 w4_7, V128 w8_11)
{
ulong t2 = w4_7.Extract<ulong>(0);
ulong t1 = w0_3.Extract<ulong>(1);
V128 result = new(t1, t2);
return result ^ (w0_3 ^ w8_11);
}
[UnmanagedCallersOnly]
public static V128 Sha1SchedulePart2(V128 tw0_3, V128 w12_15)
{
V128 t = tw0_3 ^ (w12_15 >> 32);
uint tE0 = t.Extract<uint>(0);
uint tE1 = t.Extract<uint>(1);
uint tE2 = t.Extract<uint>(2);
uint tE3 = t.Extract<uint>(3);
return new V128(tE0.Rol(1), tE1.Rol(1), tE2.Rol(1), tE3.Rol(1) ^ tE0.Rol(2));
}
private static void Rol32_160(ref uint y, ref V128 x)
{
uint xE3 = x.Extract<uint>(3);
x <<= 32;
x.Insert(0, y);
y = xE3;
}
private static uint ShaChoose(uint x, uint y, uint z)
{
return ((y ^ z) & x) ^ z;
}
private static uint ShaMajority(uint x, uint y, uint z)
{
return (x & y) | ((x | y) & z);
}
private static uint ShaParity(uint x, uint y, uint z)
{
return x ^ y ^ z;
}
private static uint Rol(this uint value, int count)
{
return (value << count) | (value >> (32 - count));
}
#endregion
#region "Sha256"
[UnmanagedCallersOnly]
public static V128 HashLower(V128 hash_abcd, V128 hash_efgh, V128 wk)
{
return Sha256Hash(hash_abcd, hash_efgh, wk, part1: true);
}
[UnmanagedCallersOnly]
public static V128 HashUpper(V128 hash_abcd, V128 hash_efgh, V128 wk)
{
return Sha256Hash(hash_abcd, hash_efgh, wk, part1: false);
}
[UnmanagedCallersOnly]
public static V128 Sha256SchedulePart1(V128 w0_3, V128 w4_7)
{
V128 result = new();
for (int e = 0; e <= 3; e++)
{
uint elt = (e <= 2 ? w0_3 : w4_7).Extract<uint>(e <= 2 ? e + 1 : 0);
elt = elt.Ror(7) ^ elt.Ror(18) ^ elt.Lsr(3);
elt += w0_3.Extract<uint>(e);
result.Insert(e, elt);
}
return result;
}
[UnmanagedCallersOnly]
public static V128 Sha256SchedulePart2(V128 w0_3, V128 w8_11, V128 w12_15)
{
V128 result = new();
ulong t1 = w12_15.Extract<ulong>(1);
for (int e = 0; e <= 1; e++)
{
uint elt = t1.ULongPart(e);
elt = elt.Ror(17) ^ elt.Ror(19) ^ elt.Lsr(10);
elt += w0_3.Extract<uint>(e) + w8_11.Extract<uint>(e + 1);
result.Insert(e, elt);
}
t1 = result.Extract<ulong>(0);
for (int e = 2; e <= 3; e++)
{
uint elt = t1.ULongPart(e - 2);
elt = elt.Ror(17) ^ elt.Ror(19) ^ elt.Lsr(10);
elt += w0_3.Extract<uint>(e) + (e == 2 ? w8_11 : w12_15).Extract<uint>(e == 2 ? 3 : 0);
result.Insert(e, elt);
}
return result;
}
private static V128 Sha256Hash(V128 x, V128 y, V128 w, bool part1)
{
for (int e = 0; e <= 3; e++)
{
uint chs = ShaChoose(y.Extract<uint>(0),
y.Extract<uint>(1),
y.Extract<uint>(2));
uint maj = ShaMajority(x.Extract<uint>(0),
x.Extract<uint>(1),
x.Extract<uint>(2));
uint t1 = y.Extract<uint>(3) + ShaHashSigma1(y.Extract<uint>(0)) + chs + w.Extract<uint>(e);
uint t2 = t1 + x.Extract<uint>(3);
x.Insert(3, t2);
t2 = t1 + ShaHashSigma0(x.Extract<uint>(0)) + maj;
y.Insert(3, t2);
Rol32_256(ref y, ref x);
}
return part1 ? x : y;
}
private static void Rol32_256(ref V128 y, ref V128 x)
{
uint yE3 = y.Extract<uint>(3);
uint xE3 = x.Extract<uint>(3);
y <<= 32;
x <<= 32;
y.Insert(0, xE3);
x.Insert(0, yE3);
}
private static uint ShaHashSigma0(uint x)
{
return x.Ror(2) ^ x.Ror(13) ^ x.Ror(22);
}
private static uint ShaHashSigma1(uint x)
{
return x.Ror(6) ^ x.Ror(11) ^ x.Ror(25);
}
private static uint Ror(this uint value, int count)
{
return (value >> count) | (value << (32 - count));
}
private static uint Lsr(this uint value, int count)
{
return value >> count;
}
private static uint ULongPart(this ulong value, int part)
{
return part == 0
? (uint)(value & 0xFFFFFFFFUL)
: (uint)(value >> 32);
}
#endregion
[UnmanagedCallersOnly]
public static V128 PolynomialMult64_128(ulong op1, ulong op2)
{
V128 result = V128.Zero;
V128 op2_128 = new(op2, 0);
for (int i = 0; i < 64; i++)
{
if (((op1 >> i) & 1) == 1)
{
result ^= op2_128 << i;
}
}
return result;
}
}
}

View File

@@ -0,0 +1,32 @@
using ARMeilleure.State;
using System.Runtime.InteropServices;
namespace ARMeilleure.Instructions
{
static partial class SoftFallback
{
[UnmanagedCallersOnly]
public static V128 Decrypt(V128 value, V128 roundKey)
{
return CryptoHelper.AesInvSubBytes(CryptoHelper.AesInvShiftRows(value ^ roundKey));
}
[UnmanagedCallersOnly]
public static V128 Encrypt(V128 value, V128 roundKey)
{
return CryptoHelper.AesSubBytes(CryptoHelper.AesShiftRows(value ^ roundKey));
}
[UnmanagedCallersOnly]
public static V128 InverseMixColumns(V128 value)
{
return CryptoHelper.AesInvMixColumns(value);
}
[UnmanagedCallersOnly]
public static V128 MixColumns(V128 value)
{
return CryptoHelper.AesMixColumns(value);
}
}
}

View File

@@ -0,0 +1,50 @@
using System;
using System.Runtime.InteropServices;
namespace ARMeilleure.Instructions
{
static partial class SoftFallback
{
[UnmanagedCallersOnly]
public static ulong CountLeadingSigns(ulong value, int size) // size is 8, 16, 32 or 64 (SIMD&FP or Base Inst.).
{
value ^= value >> 1;
int highBit = size - 2;
for (int bit = highBit; bit >= 0; bit--)
{
if (((int)(value >> bit) & 0b1) != 0)
{
return (ulong)(highBit - bit);
}
}
return (ulong)(size - 1);
}
private static ReadOnlySpan<byte> ClzNibbleTbl => [4, 3, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0];
[UnmanagedCallersOnly]
public static ulong CountLeadingZeros(ulong value, int size) // size is 8, 16, 32 or 64 (SIMD&FP or Base Inst.).
{
if (value == 0ul)
{
return (ulong)size;
}
int nibbleIdx = size;
int preCount, count = 0;
do
{
nibbleIdx -= 4;
preCount = ClzNibbleTbl[(int)(value >> nibbleIdx) & 0b1111];
count += preCount;
}
while (preCount == 4);
return (ulong)count;
}
}
}

View File

@@ -0,0 +1,74 @@
using System.Runtime.InteropServices;
namespace ARMeilleure.Instructions
{
static partial class SoftFallback
{
private const uint Crc32RevPoly = 0xedb88320;
private const uint Crc32cRevPoly = 0x82f63b78;
[UnmanagedCallersOnly]
public static uint Crc32b(uint crc, byte value) => Crc32(crc, Crc32RevPoly, value);
[UnmanagedCallersOnly]
public static uint Crc32h(uint crc, ushort value) => Crc32h(crc, Crc32RevPoly, value);
[UnmanagedCallersOnly]
public static uint Crc32w(uint crc, uint value) => Crc32w(crc, Crc32RevPoly, value);
[UnmanagedCallersOnly]
public static uint Crc32x(uint crc, ulong value) => Crc32x(crc, Crc32RevPoly, value);
[UnmanagedCallersOnly]
public static uint Crc32cb(uint crc, byte value) => Crc32(crc, Crc32cRevPoly, value);
[UnmanagedCallersOnly]
public static uint Crc32ch(uint crc, ushort value) => Crc32h(crc, Crc32cRevPoly, value);
[UnmanagedCallersOnly]
public static uint Crc32cw(uint crc, uint value) => Crc32w(crc, Crc32cRevPoly, value);
[UnmanagedCallersOnly]
public static uint Crc32cx(uint crc, ulong value) => Crc32x(crc, Crc32cRevPoly, value);
private static uint Crc32h(uint crc, uint poly, ushort val)
{
crc = Crc32(crc, poly, (byte)(val >> 0));
crc = Crc32(crc, poly, (byte)(val >> 8));
return crc;
}
private static uint Crc32w(uint crc, uint poly, uint val)
{
crc = Crc32(crc, poly, (byte)(val >> 0));
crc = Crc32(crc, poly, (byte)(val >> 8));
crc = Crc32(crc, poly, (byte)(val >> 16));
crc = Crc32(crc, poly, (byte)(val >> 24));
return crc;
}
private static uint Crc32x(uint crc, uint poly, ulong val)
{
crc = Crc32(crc, poly, (byte)(val >> 0));
crc = Crc32(crc, poly, (byte)(val >> 8));
crc = Crc32(crc, poly, (byte)(val >> 16));
crc = Crc32(crc, poly, (byte)(val >> 24));
crc = Crc32(crc, poly, (byte)(val >> 32));
crc = Crc32(crc, poly, (byte)(val >> 40));
crc = Crc32(crc, poly, (byte)(val >> 48));
crc = Crc32(crc, poly, (byte)(val >> 56));
return crc;
}
private static uint Crc32(uint crc, uint poly, byte val)
{
crc ^= val;
for (int bit = 7; bit >= 0; bit--)
{
uint mask = (uint)(-(int)(crc & 1));
crc = (crc >> 1) ^ (poly & mask);
}
return crc;
}
}
}

View File

@@ -0,0 +1,103 @@
using System.Runtime.InteropServices;
namespace ARMeilleure.Instructions
{
static partial class SoftFallback
{
[UnmanagedCallersOnly]
public static int SatF32ToS32(float value)
{
if (float.IsNaN(value))
{
return 0;
}
return value >= int.MaxValue ? int.MaxValue :
value <= int.MinValue ? int.MinValue : (int)value;
}
[UnmanagedCallersOnly]
public static long SatF32ToS64(float value)
{
if (float.IsNaN(value))
{
return 0;
}
return value >= long.MaxValue ? long.MaxValue :
value <= long.MinValue ? long.MinValue : (long)value;
}
[UnmanagedCallersOnly]
public static uint SatF32ToU32(float value)
{
if (float.IsNaN(value))
{
return 0;
}
return value >= uint.MaxValue ? uint.MaxValue :
value <= uint.MinValue ? uint.MinValue : (uint)value;
}
[UnmanagedCallersOnly]
public static ulong SatF32ToU64(float value)
{
if (float.IsNaN(value))
{
return 0;
}
return value >= ulong.MaxValue ? ulong.MaxValue :
value <= ulong.MinValue ? ulong.MinValue : (ulong)value;
}
[UnmanagedCallersOnly]
public static int SatF64ToS32(double value)
{
if (double.IsNaN(value))
{
return 0;
}
return value >= int.MaxValue ? int.MaxValue :
value <= int.MinValue ? int.MinValue : (int)value;
}
[UnmanagedCallersOnly]
public static long SatF64ToS64(double value)
{
if (double.IsNaN(value))
{
return 0;
}
return value >= long.MaxValue ? long.MaxValue :
value <= long.MinValue ? long.MinValue : (long)value;
}
[UnmanagedCallersOnly]
public static uint SatF64ToU32(double value)
{
if (double.IsNaN(value))
{
return 0;
}
return value >= uint.MaxValue ? uint.MaxValue :
value <= uint.MinValue ? uint.MinValue : (uint)value;
}
[UnmanagedCallersOnly]
public static ulong SatF64ToU64(double value)
{
if (double.IsNaN(value))
{
return 0;
}
return value >= ulong.MaxValue ? ulong.MaxValue :
value <= ulong.MinValue ? ulong.MinValue : (ulong)value;
}
}
}

View File

@@ -0,0 +1,131 @@
using ARMeilleure.State;
using System.Runtime.InteropServices;
namespace ARMeilleure.Instructions
{
static partial class SoftFallback
{
[UnmanagedCallersOnly]
public static V128 HashChoose(V128 hash_abcd, uint hash_e, V128 wk)
{
for (int e = 0; e <= 3; e++)
{
uint t = ShaChoose(hash_abcd.Extract<uint>(1),
hash_abcd.Extract<uint>(2),
hash_abcd.Extract<uint>(3));
hash_e += Rol(hash_abcd.Extract<uint>(0), 5) + t + wk.Extract<uint>(e);
t = Rol(hash_abcd.Extract<uint>(1), 30);
hash_abcd.Insert(1, t);
Rol32_160(ref hash_e, ref hash_abcd);
}
return hash_abcd;
}
[UnmanagedCallersOnly]
public static uint FixedRotate(uint hash_e)
{
return hash_e.Rol(30);
}
[UnmanagedCallersOnly]
public static V128 HashMajority(V128 hash_abcd, uint hash_e, V128 wk)
{
for (int e = 0; e <= 3; e++)
{
uint t = ShaMajority(hash_abcd.Extract<uint>(1),
hash_abcd.Extract<uint>(2),
hash_abcd.Extract<uint>(3));
hash_e += Rol(hash_abcd.Extract<uint>(0), 5) + t + wk.Extract<uint>(e);
t = Rol(hash_abcd.Extract<uint>(1), 30);
hash_abcd.Insert(1, t);
Rol32_160(ref hash_e, ref hash_abcd);
}
return hash_abcd;
}
[UnmanagedCallersOnly]
public static V128 HashParity(V128 hash_abcd, uint hash_e, V128 wk)
{
for (int e = 0; e <= 3; e++)
{
uint t = ShaParity(hash_abcd.Extract<uint>(1),
hash_abcd.Extract<uint>(2),
hash_abcd.Extract<uint>(3));
hash_e += Rol(hash_abcd.Extract<uint>(0), 5) + t + wk.Extract<uint>(e);
t = Rol(hash_abcd.Extract<uint>(1), 30);
hash_abcd.Insert(1, t);
Rol32_160(ref hash_e, ref hash_abcd);
}
return hash_abcd;
}
[UnmanagedCallersOnly]
public static V128 Sha1SchedulePart1(V128 w0_3, V128 w4_7, V128 w8_11)
{
ulong t2 = w4_7.Extract<ulong>(0);
ulong t1 = w0_3.Extract<ulong>(1);
V128 result = new(t1, t2);
return result ^ (w0_3 ^ w8_11);
}
[UnmanagedCallersOnly]
public static V128 Sha1SchedulePart2(V128 tw0_3, V128 w12_15)
{
V128 t = tw0_3 ^ (w12_15 >> 32);
uint tE0 = t.Extract<uint>(0);
uint tE1 = t.Extract<uint>(1);
uint tE2 = t.Extract<uint>(2);
uint tE3 = t.Extract<uint>(3);
return new V128(tE0.Rol(1), tE1.Rol(1), tE2.Rol(1), tE3.Rol(1) ^ tE0.Rol(2));
}
private static void Rol32_160(ref uint y, ref V128 x)
{
uint xE3 = x.Extract<uint>(3);
x <<= 32;
x.Insert(0, y);
y = xE3;
}
private static uint ShaChoose(uint x, uint y, uint z)
{
return ((y ^ z) & x) ^ z;
}
private static uint ShaMajority(uint x, uint y, uint z)
{
return (x & y) | ((x | y) & z);
}
private static uint ShaParity(uint x, uint y, uint z)
{
return x ^ y ^ z;
}
private static uint Rol(this uint value, int count)
{
return (value << count) | (value >> (32 - count));
}
}
}

View File

@@ -0,0 +1,140 @@
using ARMeilleure.State;
using System.Runtime.InteropServices;
namespace ARMeilleure.Instructions
{
static partial class SoftFallback
{
[UnmanagedCallersOnly]
public static V128 HashLower(V128 hash_abcd, V128 hash_efgh, V128 wk)
{
return Sha256Hash(hash_abcd, hash_efgh, wk, part1: true);
}
[UnmanagedCallersOnly]
public static V128 HashUpper(V128 hash_abcd, V128 hash_efgh, V128 wk)
{
return Sha256Hash(hash_abcd, hash_efgh, wk, part1: false);
}
[UnmanagedCallersOnly]
public static V128 Sha256SchedulePart1(V128 w0_3, V128 w4_7)
{
V128 result = new();
for (int e = 0; e <= 3; e++)
{
uint elt = (e <= 2 ? w0_3 : w4_7).Extract<uint>(e <= 2 ? e + 1 : 0);
elt = elt.Ror(7) ^ elt.Ror(18) ^ elt.Lsr(3);
elt += w0_3.Extract<uint>(e);
result.Insert(e, elt);
}
return result;
}
[UnmanagedCallersOnly]
public static V128 Sha256SchedulePart2(V128 w0_3, V128 w8_11, V128 w12_15)
{
V128 result = new();
ulong t1 = w12_15.Extract<ulong>(1);
for (int e = 0; e <= 1; e++)
{
uint elt = t1.ULongPart(e);
elt = elt.Ror(17) ^ elt.Ror(19) ^ elt.Lsr(10);
elt += w0_3.Extract<uint>(e) + w8_11.Extract<uint>(e + 1);
result.Insert(e, elt);
}
t1 = result.Extract<ulong>(0);
for (int e = 2; e <= 3; e++)
{
uint elt = t1.ULongPart(e - 2);
elt = elt.Ror(17) ^ elt.Ror(19) ^ elt.Lsr(10);
elt += w0_3.Extract<uint>(e) + (e == 2 ? w8_11 : w12_15).Extract<uint>(e == 2 ? 3 : 0);
result.Insert(e, elt);
}
return result;
}
private static V128 Sha256Hash(V128 x, V128 y, V128 w, bool part1)
{
for (int e = 0; e <= 3; e++)
{
uint chs = ShaChoose(y.Extract<uint>(0),
y.Extract<uint>(1),
y.Extract<uint>(2));
uint maj = ShaMajority(x.Extract<uint>(0),
x.Extract<uint>(1),
x.Extract<uint>(2));
uint t1 = y.Extract<uint>(3) + ShaHashSigma1(y.Extract<uint>(0)) + chs + w.Extract<uint>(e);
uint t2 = t1 + x.Extract<uint>(3);
x.Insert(3, t2);
t2 = t1 + ShaHashSigma0(x.Extract<uint>(0)) + maj;
y.Insert(3, t2);
Rol32_256(ref y, ref x);
}
return part1 ? x : y;
}
private static void Rol32_256(ref V128 y, ref V128 x)
{
uint yE3 = y.Extract<uint>(3);
uint xE3 = x.Extract<uint>(3);
y <<= 32;
x <<= 32;
y.Insert(0, xE3);
x.Insert(0, yE3);
}
private static uint ShaHashSigma0(uint x)
{
return x.Ror(2) ^ x.Ror(13) ^ x.Ror(22);
}
private static uint ShaHashSigma1(uint x)
{
return x.Ror(6) ^ x.Ror(11) ^ x.Ror(25);
}
private static uint Ror(this uint value, int count)
{
return (value >> count) | (value << (32 - count));
}
private static uint Lsr(this uint value, int count)
{
return value >> count;
}
private static uint ULongPart(this ulong value, int part)
{
return part == 0
? (uint)(value & 0xFFFFFFFFUL)
: (uint)(value >> 32);
}
}
}

View File

@@ -0,0 +1,93 @@
using System.Runtime.InteropServices;
namespace ARMeilleure.Instructions
{
static partial class SoftFallback
{
[UnmanagedCallersOnly]
public static long SignedShrImm64(long value, long roundConst, int shift)
{
if (roundConst == 0L)
{
if (shift <= 63)
{
return value >> shift;
}
else /* if (shift == 64) */
{
if (value < 0L)
{
return -1L;
}
else /* if (value >= 0L) */
{
return 0L;
}
}
}
else /* if (roundConst == 1L << (shift - 1)) */
{
if (shift <= 63)
{
long add = value + roundConst;
if ((~value & (value ^ add)) < 0L)
{
return (long)((ulong)add >> shift);
}
else
{
return add >> shift;
}
}
else /* if (shift == 64) */
{
return 0L;
}
}
}
[UnmanagedCallersOnly]
public static ulong UnsignedShrImm64(ulong value, long roundConst, int shift)
{
if (roundConst == 0L)
{
if (shift <= 63)
{
return value >> shift;
}
else /* if (shift == 64) */
{
return 0UL;
}
}
else /* if (roundConst == 1L << (shift - 1)) */
{
ulong add = value + (ulong)roundConst;
if ((add < value) && (add < (ulong)roundConst))
{
if (shift <= 63)
{
return (add >> shift) | (0x8000000000000000UL >> (shift - 1));
}
else /* if (shift == 64) */
{
return 1UL;
}
}
else
{
if (shift <= 63)
{
return add >> shift;
}
else /* if (shift == 64) */
{
return 0UL;
}
}
}
}
}
}

View File

@@ -0,0 +1,88 @@
using ARMeilleure.State;
using System;
using System.Runtime.InteropServices;
namespace ARMeilleure.Instructions
{
static partial class SoftFallback
{
[UnmanagedCallersOnly]
public static V128 Tbl1(V128 vector, int bytes, V128 tb0)
{
return TblOrTbx(default, vector, bytes, tb0);
}
[UnmanagedCallersOnly]
public static V128 Tbl2(V128 vector, int bytes, V128 tb0, V128 tb1)
{
return TblOrTbx(default, vector, bytes, tb0, tb1);
}
[UnmanagedCallersOnly]
public static V128 Tbl3(V128 vector, int bytes, V128 tb0, V128 tb1, V128 tb2)
{
return TblOrTbx(default, vector, bytes, tb0, tb1, tb2);
}
[UnmanagedCallersOnly]
public static V128 Tbl4(V128 vector, int bytes, V128 tb0, V128 tb1, V128 tb2, V128 tb3)
{
return TblOrTbx(default, vector, bytes, tb0, tb1, tb2, tb3);
}
[UnmanagedCallersOnly]
public static V128 Tbx1(V128 dest, V128 vector, int bytes, V128 tb0)
{
return TblOrTbx(dest, vector, bytes, tb0);
}
[UnmanagedCallersOnly]
public static V128 Tbx2(V128 dest, V128 vector, int bytes, V128 tb0, V128 tb1)
{
return TblOrTbx(dest, vector, bytes, tb0, tb1);
}
[UnmanagedCallersOnly]
public static V128 Tbx3(V128 dest, V128 vector, int bytes, V128 tb0, V128 tb1, V128 tb2)
{
return TblOrTbx(dest, vector, bytes, tb0, tb1, tb2);
}
[UnmanagedCallersOnly]
public static V128 Tbx4(V128 dest, V128 vector, int bytes, V128 tb0, V128 tb1, V128 tb2, V128 tb3)
{
return TblOrTbx(dest, vector, bytes, tb0, tb1, tb2, tb3);
}
private static V128 TblOrTbx(V128 dest, V128 vector, int bytes, params ReadOnlySpan<V128> tb)
{
byte[] res = new byte[16];
if (dest != default)
{
Buffer.BlockCopy(dest.ToArray(), 0, res, 0, bytes);
}
byte[] table = new byte[tb.Length * 16];
for (byte index = 0; index < tb.Length; index++)
{
Buffer.BlockCopy(tb[index].ToArray(), 0, table, index * 16, 16);
}
byte[] v = vector.ToArray();
for (byte index = 0; index < bytes; index++)
{
byte tblIndex = v[index];
if (tblIndex < table.Length)
{
res[index] = table[tblIndex];
}
}
return new V128(res);
}
}
}

View File

@@ -0,0 +1,26 @@
using ARMeilleure.State;
using System.Runtime.InteropServices;
namespace ARMeilleure.Instructions
{
static partial class SoftFallback
{
[UnmanagedCallersOnly]
public static V128 PolynomialMult64_128(ulong op1, ulong op2)
{
V128 result = V128.Zero;
V128 op2_128 = new(op2, 0);
for (int i = 0; i < 64; i++)
{
if (((op1 >> i) & 1) == 1)
{
result ^= op2_128 << i;
}
}
return result;
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,111 @@
using ARMeilleure.State;
using System;
using System.Diagnostics;
namespace ARMeilleure.Instructions
{
static class SoftFloat
{
static SoftFloat()
{
RecipEstimateTable = BuildRecipEstimateTable();
RecipSqrtEstimateTable = BuildRecipSqrtEstimateTable();
}
public static readonly byte[] RecipEstimateTable;
public static readonly byte[] RecipSqrtEstimateTable;
private static byte[] BuildRecipEstimateTable()
{
byte[] tbl = new byte[256];
for (int idx = 0; idx < 256; idx++)
{
uint src = (uint)idx + 256u;
Debug.Assert(src is >= 256u and < 512u);
src = (src << 1) + 1u;
uint aux = (1u << 19) / src;
uint dst = (aux + 1u) >> 1;
Debug.Assert(dst is >= 256u and < 512u);
tbl[idx] = (byte)(dst - 256u);
}
return tbl;
}
private static byte[] BuildRecipSqrtEstimateTable()
{
byte[] tbl = new byte[384];
for (int idx = 0; idx < 384; idx++)
{
uint src = (uint)idx + 128u;
Debug.Assert(src is >= 128u and < 512u);
if (src < 256u)
{
src = (src << 1) + 1u;
}
else
{
src = (src >> 1) << 1;
src = (src + 1u) << 1;
}
uint aux = 512u;
while (src * (aux + 1u) * (aux + 1u) < (1u << 28))
{
aux++;
}
uint dst = (aux + 1u) >> 1;
Debug.Assert(dst is >= 256u and < 512u);
tbl[idx] = (byte)(dst - 256u);
}
return tbl;
}
public static void FPProcessException(FPException exc, ExecutionContext context)
{
FPProcessException(exc, context, context.Fpcr);
}
public static void FPProcessException(FPException exc, ExecutionContext context, FPCR fpcr)
{
int enable = (int)exc + 8;
if ((fpcr & (FPCR)(1 << enable)) != 0)
{
throw new NotImplementedException("Floating-point trap handling.");
}
else
{
context.Fpsr |= (FPSR)(1 << (int)exc);
}
}
extension(FPCR fpcr)
{
public FPRoundingMode RoundingMode
{
get
{
const int RModeShift = 22;
return (FPRoundingMode)(((uint)fpcr >> RModeShift) & 3u);
}
}
}
}
}

View File

@@ -0,0 +1,212 @@
using ARMeilleure.State;
using System;
namespace ARMeilleure.Instructions
{
static class SoftFloat16
{
public static ushort FPDefaultNaN()
{
return (ushort)0x7E00u;
}
public static ushort FPInfinity(bool sign)
{
return sign ? (ushort)0xFC00u : (ushort)0x7C00u;
}
public static ushort FPZero(bool sign)
{
return sign ? (ushort)0x8000u : (ushort)0x0000u;
}
public static ushort FPMaxNormal(bool sign)
{
return sign ? (ushort)0xFBFFu : (ushort)0x7BFFu;
}
public static double FPUnpackCv(
this ushort valueBits,
out FPType type,
out bool sign,
ExecutionContext context)
{
sign = (~(uint)valueBits & 0x8000u) == 0u;
uint exp16 = ((uint)valueBits & 0x7C00u) >> 10;
uint frac16 = (uint)valueBits & 0x03FFu;
double real;
if (exp16 == 0u)
{
if (frac16 == 0u)
{
type = FPType.Zero;
real = 0d;
}
else
{
type = FPType.Nonzero; // Subnormal.
real = Math.Pow(2d, -14) * ((double)frac16 * Math.Pow(2d, -10));
}
}
else if (exp16 == 0x1Fu && (context.Fpcr & FPCR.Ahp) == 0)
{
if (frac16 == 0u)
{
type = FPType.Infinity;
real = Math.Pow(2d, 1000);
}
else
{
type = (~frac16 & 0x0200u) == 0u ? FPType.QNaN : FPType.SNaN;
real = 0d;
}
}
else
{
type = FPType.Nonzero; // Normal.
real = Math.Pow(2d, (int)exp16 - 15) * (1d + (double)frac16 * Math.Pow(2d, -10));
}
return sign ? -real : real;
}
public static ushort FPRoundCv(double real, ExecutionContext context)
{
const int MinimumExp = -14;
const int E = 5;
const int F = 10;
bool sign;
double mantissa;
if (real < 0d)
{
sign = true;
mantissa = -real;
}
else
{
sign = false;
mantissa = real;
}
int exponent = 0;
while (mantissa < 1d)
{
mantissa *= 2d;
exponent--;
}
while (mantissa >= 2d)
{
mantissa /= 2d;
exponent++;
}
uint biasedExp = (uint)Math.Max(exponent - MinimumExp + 1, 0);
if (biasedExp == 0u)
{
mantissa /= Math.Pow(2d, MinimumExp - exponent);
}
uint intMant = (uint)Math.Floor(mantissa * Math.Pow(2d, F));
double error = mantissa * Math.Pow(2d, F) - (double)intMant;
if (biasedExp == 0u && (error != 0d || (context.Fpcr & FPCR.Ufe) != 0))
{
SoftFloat.FPProcessException(FPException.Underflow, context);
}
bool overflowToInf;
bool roundUp;
switch (context.Fpcr.RoundingMode)
{
case FPRoundingMode.ToNearest:
roundUp = (error > 0.5d || (error == 0.5d && (intMant & 1u) == 1u));
overflowToInf = true;
break;
case FPRoundingMode.TowardsPlusInfinity:
roundUp = (error != 0d && !sign);
overflowToInf = !sign;
break;
case FPRoundingMode.TowardsMinusInfinity:
roundUp = (error != 0d && sign);
overflowToInf = sign;
break;
case FPRoundingMode.TowardsZero:
roundUp = false;
overflowToInf = false;
break;
default:
throw new ArgumentException($"Invalid rounding mode \"{context.Fpcr.RoundingMode}\".");
}
if (roundUp)
{
intMant++;
if (intMant == 1u << F)
{
biasedExp = 1u;
}
if (intMant == 1u << (F + 1))
{
biasedExp++;
intMant >>= 1;
}
}
ushort resultBits;
if ((context.Fpcr & FPCR.Ahp) == 0)
{
if (biasedExp >= (1u << E) - 1u)
{
resultBits = overflowToInf ? FPInfinity(sign) : FPMaxNormal(sign);
SoftFloat.FPProcessException(FPException.Overflow, context);
error = 1d;
}
else
{
resultBits = (ushort)((sign ? 1u : 0u) << 15 | (biasedExp & 0x1Fu) << 10 | (intMant & 0x03FFu));
}
}
else
{
if (biasedExp >= 1u << E)
{
resultBits = (ushort)((sign ? 1u : 0u) << 15 | 0x7FFFu);
SoftFloat.FPProcessException(FPException.InvalidOp, context);
error = 0d;
}
else
{
resultBits = (ushort)((sign ? 1u : 0u) << 15 | (biasedExp & 0x1Fu) << 10 | (intMant & 0x03FFu));
}
}
if (error != 0d)
{
SoftFloat.FPProcessException(FPException.Inexact, context);
}
return resultBits;
}
}
}

View File

@@ -0,0 +1,182 @@
using ARMeilleure.State;
using System;
using System.Runtime.InteropServices;
namespace ARMeilleure.Instructions
{
static class SoftFloat16_32
{
[UnmanagedCallersOnly]
public static float FPConvert(ushort valueBits)
{
ExecutionContext context = NativeInterface.GetContext();
double real = valueBits.FPUnpackCv(out FPType type, out bool sign, context);
float result;
if (type is FPType.SNaN or FPType.QNaN)
{
if ((context.Fpcr & FPCR.Dn) != 0)
{
result = SoftFloat32.FPDefaultNaN();
}
else
{
result = FPConvertNaN(valueBits);
}
if (type == FPType.SNaN)
{
SoftFloat.FPProcessException(FPException.InvalidOp, context);
}
}
else if (type == FPType.Infinity)
{
result = SoftFloat32.FPInfinity(sign);
}
else if (type == FPType.Zero)
{
result = SoftFloat32.FPZero(sign);
}
else
{
result = FPRoundCv(real, context);
}
return result;
}
private static float FPRoundCv(double real, ExecutionContext context)
{
const int MinimumExp = -126;
const int E = 8;
const int F = 23;
bool sign;
double mantissa;
if (real < 0d)
{
sign = true;
mantissa = -real;
}
else
{
sign = false;
mantissa = real;
}
int exponent = 0;
while (mantissa < 1d)
{
mantissa *= 2d;
exponent--;
}
while (mantissa >= 2d)
{
mantissa /= 2d;
exponent++;
}
if ((context.Fpcr & FPCR.Fz) != 0 && exponent < MinimumExp)
{
context.Fpsr |= FPSR.Ufc;
return SoftFloat32.FPZero(sign);
}
uint biasedExp = (uint)Math.Max(exponent - MinimumExp + 1, 0);
if (biasedExp == 0u)
{
mantissa /= Math.Pow(2d, MinimumExp - exponent);
}
uint intMant = (uint)Math.Floor(mantissa * Math.Pow(2d, F));
double error = mantissa * Math.Pow(2d, F) - (double)intMant;
if (biasedExp == 0u && (error != 0d || (context.Fpcr & FPCR.Ufe) != 0))
{
SoftFloat.FPProcessException(FPException.Underflow, context);
}
bool overflowToInf;
bool roundUp;
switch (context.Fpcr.RoundingMode)
{
case FPRoundingMode.ToNearest:
roundUp = (error > 0.5d || (error == 0.5d && (intMant & 1u) == 1u));
overflowToInf = true;
break;
case FPRoundingMode.TowardsPlusInfinity:
roundUp = (error != 0d && !sign);
overflowToInf = !sign;
break;
case FPRoundingMode.TowardsMinusInfinity:
roundUp = (error != 0d && sign);
overflowToInf = sign;
break;
case FPRoundingMode.TowardsZero:
roundUp = false;
overflowToInf = false;
break;
default:
throw new ArgumentException($"Invalid rounding mode \"{context.Fpcr.RoundingMode}\".");
}
if (roundUp)
{
intMant++;
if (intMant == 1u << F)
{
biasedExp = 1u;
}
if (intMant == 1u << (F + 1))
{
biasedExp++;
intMant >>= 1;
}
}
float result;
if (biasedExp >= (1u << E) - 1u)
{
result = overflowToInf ? SoftFloat32.FPInfinity(sign) : SoftFloat32.FPMaxNormal(sign);
SoftFloat.FPProcessException(FPException.Overflow, context);
error = 1d;
}
else
{
result = BitConverter.Int32BitsToSingle(
(int)((sign ? 1u : 0u) << 31 | (biasedExp & 0xFFu) << 23 | (intMant & 0x007FFFFFu)));
}
if (error != 0d)
{
SoftFloat.FPProcessException(FPException.Inexact, context);
}
return result;
}
private static float FPConvertNaN(ushort valueBits)
{
return BitConverter.Int32BitsToSingle(
(int)(((uint)valueBits & 0x8000u) << 16 | 0x7FC00000u | ((uint)valueBits & 0x01FFu) << 13));
}
}
}

View File

@@ -0,0 +1,182 @@
using ARMeilleure.State;
using System;
using System.Runtime.InteropServices;
namespace ARMeilleure.Instructions
{
static class SoftFloat16_64
{
[UnmanagedCallersOnly]
public static double FPConvert(ushort valueBits)
{
ExecutionContext context = NativeInterface.GetContext();
double real = valueBits.FPUnpackCv(out FPType type, out bool sign, context);
double result;
if (type is FPType.SNaN or FPType.QNaN)
{
if ((context.Fpcr & FPCR.Dn) != 0)
{
result = SoftFloat64.FPDefaultNaN();
}
else
{
result = FPConvertNaN(valueBits);
}
if (type == FPType.SNaN)
{
SoftFloat.FPProcessException(FPException.InvalidOp, context);
}
}
else if (type == FPType.Infinity)
{
result = SoftFloat64.FPInfinity(sign);
}
else if (type == FPType.Zero)
{
result = SoftFloat64.FPZero(sign);
}
else
{
result = FPRoundCv(real, context);
}
return result;
}
private static double FPRoundCv(double real, ExecutionContext context)
{
const int MinimumExp = -1022;
const int E = 11;
const int F = 52;
bool sign;
double mantissa;
if (real < 0d)
{
sign = true;
mantissa = -real;
}
else
{
sign = false;
mantissa = real;
}
int exponent = 0;
while (mantissa < 1d)
{
mantissa *= 2d;
exponent--;
}
while (mantissa >= 2d)
{
mantissa /= 2d;
exponent++;
}
if ((context.Fpcr & FPCR.Fz) != 0 && exponent < MinimumExp)
{
context.Fpsr |= FPSR.Ufc;
return SoftFloat64.FPZero(sign);
}
uint biasedExp = (uint)Math.Max(exponent - MinimumExp + 1, 0);
if (biasedExp == 0u)
{
mantissa /= Math.Pow(2d, MinimumExp - exponent);
}
ulong intMant = (ulong)Math.Floor(mantissa * Math.Pow(2d, F));
double error = mantissa * Math.Pow(2d, F) - (double)intMant;
if (biasedExp == 0u && (error != 0d || (context.Fpcr & FPCR.Ufe) != 0))
{
SoftFloat.FPProcessException(FPException.Underflow, context);
}
bool overflowToInf;
bool roundUp;
switch (context.Fpcr.RoundingMode)
{
case FPRoundingMode.ToNearest:
roundUp = (error > 0.5d || (error == 0.5d && (intMant & 1u) == 1u));
overflowToInf = true;
break;
case FPRoundingMode.TowardsPlusInfinity:
roundUp = (error != 0d && !sign);
overflowToInf = !sign;
break;
case FPRoundingMode.TowardsMinusInfinity:
roundUp = (error != 0d && sign);
overflowToInf = sign;
break;
case FPRoundingMode.TowardsZero:
roundUp = false;
overflowToInf = false;
break;
default:
throw new ArgumentException($"Invalid rounding mode \"{context.Fpcr.RoundingMode}\".");
}
if (roundUp)
{
intMant++;
if (intMant == 1ul << F)
{
biasedExp = 1u;
}
if (intMant == 1ul << (F + 1))
{
biasedExp++;
intMant >>= 1;
}
}
double result;
if (biasedExp >= (1u << E) - 1u)
{
result = overflowToInf ? SoftFloat64.FPInfinity(sign) : SoftFloat64.FPMaxNormal(sign);
SoftFloat.FPProcessException(FPException.Overflow, context);
error = 1d;
}
else
{
result = BitConverter.Int64BitsToDouble(
(long)((sign ? 1ul : 0ul) << 63 | (biasedExp & 0x7FFul) << 52 | (intMant & 0x000FFFFFFFFFFFFFul)));
}
if (error != 0d)
{
SoftFloat.FPProcessException(FPException.Inexact, context);
}
return result;
}
private static double FPConvertNaN(ushort valueBits)
{
return BitConverter.Int64BitsToDouble(
(long)(((ulong)valueBits & 0x8000ul) << 48 | 0x7FF8000000000000ul | ((ulong)valueBits & 0x01FFul) << 42));
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,126 @@
using ARMeilleure.State;
using System;
using System.Runtime.InteropServices;
namespace ARMeilleure.Instructions
{
static class SoftFloat32_16
{
[UnmanagedCallersOnly]
public static ushort FPConvert(float value)
{
ExecutionContext context = NativeInterface.GetContext();
double real = value.FPUnpackCv(out FPType type, out bool sign, out uint valueBits, context);
bool altHp = (context.Fpcr & FPCR.Ahp) != 0;
ushort resultBits;
if (type is FPType.SNaN or FPType.QNaN)
{
if (altHp)
{
resultBits = SoftFloat16.FPZero(sign);
}
else if ((context.Fpcr & FPCR.Dn) != 0)
{
resultBits = SoftFloat16.FPDefaultNaN();
}
else
{
resultBits = FPConvertNaN(valueBits);
}
if (type == FPType.SNaN || altHp)
{
SoftFloat.FPProcessException(FPException.InvalidOp, context);
}
}
else if (type == FPType.Infinity)
{
if (altHp)
{
resultBits = (ushort)((sign ? 1u : 0u) << 15 | 0x7FFFu);
SoftFloat.FPProcessException(FPException.InvalidOp, context);
}
else
{
resultBits = SoftFloat16.FPInfinity(sign);
}
}
else if (type == FPType.Zero)
{
resultBits = SoftFloat16.FPZero(sign);
}
else
{
resultBits = SoftFloat16.FPRoundCv(real, context);
}
return resultBits;
}
private static double FPUnpackCv(
this float value,
out FPType type,
out bool sign,
out uint valueBits,
ExecutionContext context)
{
valueBits = (uint)BitConverter.SingleToInt32Bits(value);
sign = (~valueBits & 0x80000000u) == 0u;
uint exp32 = (valueBits & 0x7F800000u) >> 23;
uint frac32 = valueBits & 0x007FFFFFu;
double real;
if (exp32 == 0u)
{
if (frac32 == 0u || (context.Fpcr & FPCR.Fz) != 0)
{
type = FPType.Zero;
real = 0d;
if (frac32 != 0u)
{
SoftFloat.FPProcessException(FPException.InputDenorm, context);
}
}
else
{
type = FPType.Nonzero; // Subnormal.
real = Math.Pow(2d, -126) * ((double)frac32 * Math.Pow(2d, -23));
}
}
else if (exp32 == 0xFFu)
{
if (frac32 == 0u)
{
type = FPType.Infinity;
real = Math.Pow(2d, 1000);
}
else
{
type = (~frac32 & 0x00400000u) == 0u ? FPType.QNaN : FPType.SNaN;
real = 0d;
}
}
else
{
type = FPType.Nonzero; // Normal.
real = Math.Pow(2d, (int)exp32 - 127) * (1d + (double)frac32 * Math.Pow(2d, -23));
}
return sign ? -real : real;
}
private static ushort FPConvertNaN(uint valueBits)
{
return (ushort)((valueBits & 0x80000000u) >> 16 | 0x7E00u | (valueBits & 0x003FE000u) >> 13);
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,127 @@
using ARMeilleure.State;
using System;
using System.Runtime.InteropServices;
namespace ARMeilleure.Instructions
{
static class SoftFloat64_16
{
[UnmanagedCallersOnly]
public static ushort FPConvert(double value)
{
ExecutionContext context = NativeInterface.GetContext();
double real = value.FPUnpackCv(out FPType type, out bool sign, out ulong valueBits, context);
bool altHp = (context.Fpcr & FPCR.Ahp) != 0;
ushort resultBits;
if (type is FPType.SNaN or FPType.QNaN)
{
if (altHp)
{
resultBits = SoftFloat16.FPZero(sign);
}
else if ((context.Fpcr & FPCR.Dn) != 0)
{
resultBits = SoftFloat16.FPDefaultNaN();
}
else
{
resultBits = FPConvertNaN(valueBits);
}
if (type == FPType.SNaN || altHp)
{
SoftFloat.FPProcessException(FPException.InvalidOp, context);
}
}
else if (type == FPType.Infinity)
{
if (altHp)
{
resultBits = (ushort)((sign ? 1u : 0u) << 15 | 0x7FFFu);
SoftFloat.FPProcessException(FPException.InvalidOp, context);
}
else
{
resultBits = SoftFloat16.FPInfinity(sign);
}
}
else if (type == FPType.Zero)
{
resultBits = SoftFloat16.FPZero(sign);
}
else
{
resultBits = SoftFloat16.FPRoundCv(real, context);
}
return resultBits;
}
private static double FPUnpackCv(
this double value,
out FPType type,
out bool sign,
out ulong valueBits,
ExecutionContext context)
{
valueBits = (ulong)BitConverter.DoubleToInt64Bits(value);
sign = (~valueBits & 0x8000000000000000ul) == 0u;
ulong exp64 = (valueBits & 0x7FF0000000000000ul) >> 52;
ulong frac64 = valueBits & 0x000FFFFFFFFFFFFFul;
double real;
if (exp64 == 0u)
{
if (frac64 == 0u || (context.Fpcr & FPCR.Fz) != 0)
{
type = FPType.Zero;
real = 0d;
if (frac64 != 0u)
{
SoftFloat.FPProcessException(FPException.InputDenorm, context);
}
}
else
{
type = FPType.Nonzero; // Subnormal.
real = Math.Pow(2d, -1022) * ((double)frac64 * Math.Pow(2d, -52));
}
}
else if (exp64 == 0x7FFul)
{
if (frac64 == 0u)
{
type = FPType.Infinity;
real = Math.Pow(2d, 1000000);
}
else
{
type = (~frac64 & 0x0008000000000000ul) == 0u ? FPType.QNaN : FPType.SNaN;
real = 0d;
}
}
else
{
type = FPType.Nonzero; // Normal.
real = Math.Pow(2d, (int)exp64 - 1023) * (1d + (double)frac64 * Math.Pow(2d, -52));
}
return sign ? -real : real;
}
private static ushort FPConvertNaN(ulong valueBits)
{
return (ushort)((valueBits & 0x8000000000000000ul) >> 48 | 0x7E00u |
(valueBits & 0x0007FC0000000000ul) >> 42);
}
}
}

View File

@@ -16,9 +16,9 @@ namespace ARMeilleure.IntermediateRepresentation
static class ComparisonExtensions
{
public static Comparison Invert(this Comparison comp)
extension(Comparison comparison)
{
return (Comparison)((int)comp ^ 1);
public Comparison Inverse => (Comparison)((int)comparison ^ 1);
}
}
}

View File

@@ -14,48 +14,38 @@ namespace ARMeilleure.IntermediateRepresentation
static class OperandTypeExtensions
{
public static bool IsInteger(this OperandType type)
extension(OperandType type)
{
return type is OperandType.I32 or
OperandType.I64;
}
public static RegisterType ToRegisterType(this OperandType type)
{
return type switch
public bool IsInteger => type is OperandType.I32 or OperandType.I64;
public RegisterType Register => type switch
{
OperandType.FP32 => RegisterType.Vector,
OperandType.FP64 => RegisterType.Vector,
OperandType.I32 => RegisterType.Integer,
OperandType.I64 => RegisterType.Integer,
OperandType.V128 => RegisterType.Vector,
_ => throw new InvalidOperationException($"Invalid operand type \"{type}\"."),
_ => throw new InvalidOperationException($"Invalid operand type \"{type}\".")
};
}
public static int GetSizeInBytes(this OperandType type)
{
return type switch
public int ByteSize => type switch
{
OperandType.FP32 => 4,
OperandType.FP64 => 8,
OperandType.I32 => 4,
OperandType.I64 => 8,
OperandType.V128 => 16,
_ => throw new InvalidOperationException($"Invalid operand type \"{type}\"."),
_ => throw new InvalidOperationException($"Invalid operand type \"{type}\".")
};
}
public static int GetSizeInBytesLog2(this OperandType type)
{
return type switch
public int ByteSizeLog2 => type switch
{
OperandType.FP32 => 2,
OperandType.FP64 => 3,
OperandType.I32 => 2,
OperandType.I64 => 3,
OperandType.V128 => 4,
_ => throw new InvalidOperationException($"Invalid operand type \"{type}\"."),
_ => throw new InvalidOperationException($"Invalid operand type \"{type}\".")
};
}
}

View File

@@ -45,19 +45,12 @@ namespace ARMeilleure.Memory
public static class MemoryManagerTypeExtensions
{
public static bool IsHostMapped(this MemoryManagerType type)
extension(MemoryManagerType type)
{
return type is MemoryManagerType.HostMapped or MemoryManagerType.HostMappedUnsafe;
}
public static bool IsHostTracked(this MemoryManagerType type)
{
return type is MemoryManagerType.HostTracked or MemoryManagerType.HostTrackedUnsafe;
}
public static bool IsHostMappedOrTracked(this MemoryManagerType type)
{
return type.IsHostMapped() || type.IsHostTracked();
public bool IsHostMapped => type is MemoryManagerType.HostMapped or MemoryManagerType.HostMappedUnsafe;
public bool IsHostTracked => type is MemoryManagerType.HostTracked or MemoryManagerType.HostTrackedUnsafe;
public bool IsHostMappedOrTracked => type.IsHostMapped || type.IsHostTracked;
}
}
}

View File

@@ -13,6 +13,7 @@ namespace ARMeilleure
public static bool AllowLcqInFunctionTable { get; set; } = true;
public static bool UseUnmanagedDispatchLoop { get; set; } = true;
public static bool EnableDebugging { get; set; } = false;
public static bool EnableDeepCallRecursionProtection { get; set; } = true;
public static bool UseAdvSimdIfAvailable { get; set; } = true;
public static bool UseArm64AesIfAvailable { get; set; } = true;

View File

@@ -134,6 +134,11 @@ namespace ARMeilleure.State
public bool GetFPstateFlag(FPState flag) => _nativeContext.GetFPStateFlag(flag);
public void SetFPstateFlag(FPState flag, bool value) => _nativeContext.SetFPStateFlag(flag, value);
internal void ResetCallDepth()
{
_nativeContext.ResetCallDepth();
}
internal void CheckInterrupt()
{
if (Interrupted)

View File

@@ -22,6 +22,7 @@ namespace ARMeilleure.State
public ulong ExclusiveValueHigh;
public int Running;
public long Tpidr2El0;
public int CallDepth;
/// <summary>
/// Precise PC value used for debugging.
@@ -199,6 +200,8 @@ namespace ARMeilleure.State
public bool GetRunning() => GetStorage().Running != 0;
public void SetRunning(bool value) => GetStorage().Running = value ? 1 : 0;
public void ResetCallDepth() => GetStorage().CallDepth = 0;
public unsafe static int GetRegisterOffset(Register reg)
{
if (reg.Type == RegisterType.Integer)
@@ -284,6 +287,11 @@ namespace ARMeilleure.State
return StorageOffset(ref _dummyStorage, ref _dummyStorage.DebugPrecisePc);
}
public static int GetCallDepthOffset()
{
return StorageOffset(ref _dummyStorage, ref _dummyStorage.CallDepth);
}
private static int StorageOffset<T>(ref NativeCtxStorage storage, ref T target)
{
return (int)Unsafe.ByteOffset(ref Unsafe.As<NativeCtxStorage, T>(ref storage), ref target);

View File

@@ -361,10 +361,7 @@ namespace ARMeilleure.Translation
IntervalTreeNode<TK, TV> tmp = LeftOf(replacementNode) ?? RightOf(replacementNode);
if (tmp != null)
{
tmp.Parent = ParentOf(replacementNode);
}
tmp?.Parent = ParentOf(replacementNode);
if (ParentOf(replacementNode) == null)
{
@@ -582,10 +579,7 @@ namespace ARMeilleure.Translation
{
IntervalTreeNode<TK, TV> right = RightOf(node);
node.Right = LeftOf(right);
if (node.Right != null)
{
node.Right.Parent = node;
}
node.Right?.Parent = node;
IntervalTreeNode<TK, TV> nodeParent = ParentOf(node);
right.Parent = nodeParent;
@@ -615,10 +609,7 @@ namespace ARMeilleure.Translation
{
IntervalTreeNode<TK, TV> left = LeftOf(node);
node.Left = RightOf(left);
if (node.Left != null)
{
node.Left.Parent = node;
}
node.Left?.Parent = node;
IntervalTreeNode<TK, TV> nodeParent = ParentOf(node);
left.Parent = nodeParent;
@@ -667,10 +658,7 @@ namespace ARMeilleure.Translation
/// <param name="color">Color (Boolean)</param>
private static void SetColor(IntervalTreeNode<TK, TV> node, bool color)
{
if (node != null)
{
node.Color = color;
}
node?.Color = color;
}
/// <summary>

View File

@@ -33,7 +33,7 @@ namespace ARMeilleure.Translation.PTC
private const string OuterHeaderMagicString = "PTCohd\0\0";
private const string InnerHeaderMagicString = "PTCihd\0\0";
private const uint InternalVersion = 7009; //! To be incremented manually for each change to the ARMeilleure project.
private const uint InternalVersion = 7010; //! To be incremented manually for each change to the ARMeilleure project.
private const string ActualDir = "0";
private const string BackupDir = "1";

View File

@@ -186,6 +186,7 @@ namespace ARMeilleure.Translation
Statistics.StartTimer();
context.ResetCallDepth();
ulong nextAddr = func.Execute(Stubs.ContextWrapper, context);
Statistics.StopTimer(address);
@@ -260,6 +261,7 @@ namespace ARMeilleure.Translation
Logger.StartPass(PassName.Translation);
InstEmitFlowHelper.EmitCallDepthCheckAndIncrement(context, Const(address));
EmitSynchronization(context);
if (blocks[0].Address != address)
@@ -412,7 +414,7 @@ namespace ARMeilleure.Translation
{
context.SyncQcFlag();
if (block.Branch != null && !block.Branch.Exit && block.Branch.Address <= block.Address)
if (block.Branch is { Exit: false } && block.Branch.Address <= block.Address)
{
EmitSynchronization(context);
}
@@ -429,14 +431,14 @@ namespace ARMeilleure.Translation
{
lblPredicateSkip = Label();
InstEmitFlowHelper.EmitCondBranch(context, lblPredicateSkip, context.CurrentIfThenBlockCond.Invert());
InstEmitFlowHelper.EmitCondBranch(context, lblPredicateSkip, context.CurrentIfThenBlockCond.Inverse);
}
if (opCode is OpCode32 op && op.Cond < Condition.Al)
if (opCode is OpCode32 { Cond: < Condition.Al } op)
{
lblPredicateSkip = Label();
InstEmitFlowHelper.EmitCondBranch(context, lblPredicateSkip, op.Cond.Invert());
InstEmitFlowHelper.EmitCondBranch(context, lblPredicateSkip, op.Cond.Inverse);
}
if (opCode.Instruction.Emitter != null)

View File

@@ -262,10 +262,18 @@ namespace ARMeilleure.Translation
Operand runningAddress = context.Add(nativeContext, Const((ulong)NativeContext.GetRunningOffset()));
Operand dispatchAddress = context.Add(nativeContext, Const((ulong)NativeContext.GetDispatchAddressOffset()));
Operand callDepthAddress = context.Add(nativeContext, Const((ulong)NativeContext.GetCallDepthOffset()));
EmitSyncFpContext(context, nativeContext, true);
context.MarkLabel(beginLbl);
if (Optimizations.EnableDeepCallRecursionProtection)
{
// Reset the call depth counter, since this is our first guest function call.
context.Store(callDepthAddress, Const(0));
}
context.Store(dispatchAddress, guestAddress);
context.Copy(guestAddress, context.Call(Const((ulong)DispatchStub), OperandType.I64, nativeContext));
context.BranchIfFalse(endLbl, guestAddress);

View File

@@ -58,16 +58,16 @@ namespace Ryujinx.Audio.Backends.CompatLayer
switch (realSampleFormat)
{
case SampleFormat.PcmInt8:
PcmHelper.ConvertSampleToPcm8(MemoryMarshal.Cast<byte, sbyte>(convertedSamples), samples);
PcmHelper.ConvertSampleToPcm8(MemoryMarshal.Cast<byte, sbyte>(new Span<byte>(convertedSamples)), samples);
break;
case SampleFormat.PcmInt24:
PcmHelper.ConvertSampleToPcm24(convertedSamples, samples);
break;
case SampleFormat.PcmInt32:
PcmHelper.ConvertSampleToPcm32(MemoryMarshal.Cast<byte, int>(convertedSamples), samples);
PcmHelper.ConvertSampleToPcm32(MemoryMarshal.Cast<byte, int>(new Span<byte>(convertedSamples)), samples);
break;
case SampleFormat.PcmFloat:
PcmHelper.ConvertSampleToPcmFloat(MemoryMarshal.Cast<byte, float>(convertedSamples), samples);
PcmHelper.ConvertSampleToPcmFloat(MemoryMarshal.Cast<byte, float>(new Span<byte>(convertedSamples)), samples);
break;
default:
throw new NotImplementedException($"Sample format conversion from {_userSampleFormat} to {realSampleFormat} not implemented.");

View File

@@ -27,7 +27,7 @@ namespace Ryujinx.Audio.Integration
public void AppendBuffer(ReadOnlySpan<short> data, uint channelCount)
{
data.CopyTo(MemoryMarshal.Cast<byte, short>(_buffer));
data.CopyTo(MemoryMarshal.Cast<byte, short>(new Span<byte>(_buffer)));
_session.QueueBuffer(new AudioBuffer
{

View File

@@ -92,6 +92,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
}
short[] outputBuffer = ArrayPool<short>.Shared.Rent((int)inputCount * SampleCount);
Array.Fill(outputBuffer, (short)0, 0, (int)inputCount * SampleCount);
for (int i = 0; i < bufferCount; i++)
{

View File

@@ -19,6 +19,11 @@ namespace Ryujinx.Audio.Renderer.Parameter.Effect
/// The output channel indices that will be used by the <see cref="Dsp.AudioProcessor"/>.
/// </summary>
public Array6<byte> Output;
/// <summary>
/// Reserved/unused.
/// </summary>
private readonly uint _padding;
/// <summary>
/// Biquad filter numerator (b0, b1, b2).

View File

@@ -91,7 +91,11 @@ namespace Ryujinx.Common
public void Dispose()
{
_queue.CompleteAdding();
try
{
_queue.CompleteAdding();
} catch (ObjectDisposedException) {}
_cts.Cancel();
_workerThread.Join();

View File

@@ -386,10 +386,7 @@ namespace Ryujinx.Common.Collections
IntervalTreeNode<TKey, TValue> tmp = LeftOf(replacementNode) ?? RightOf(replacementNode);
if (tmp != null)
{
tmp.Parent = ParentOf(replacementNode);
}
tmp?.Parent = ParentOf(replacementNode);
if (ParentOf(replacementNode) == null)
{

View File

@@ -235,10 +235,7 @@ namespace Ryujinx.Common.Collections
parent = ParentOf(element);
color = ColorOf(element);
if (child != null)
{
child.Parent = parent;
}
child?.Parent = parent;
if (parent == null)
{
@@ -258,8 +255,7 @@ namespace Ryujinx.Common.Collections
element.Right = old.Right;
element.Parent = old.Parent;
element.Predecessor = old.Predecessor;
if (element.Predecessor != null)
element.Predecessor.Successor = element;
element.Predecessor?.Successor = element;
if (ParentOf(old) == null)
{
@@ -292,10 +288,7 @@ namespace Ryujinx.Common.Collections
parent = ParentOf(nodeToDelete);
color = ColorOf(nodeToDelete);
if (child != null)
{
child.Parent = parent;
}
child?.Parent = parent;
if (parent == null)
{
@@ -314,11 +307,9 @@ namespace Ryujinx.Common.Collections
{
RestoreBalanceAfterRemoval(child);
}
if (old.Successor != null)
old.Successor.Predecessor = old.Predecessor;
if (old.Predecessor != null)
old.Predecessor.Successor = old.Successor;
old.Successor?.Predecessor = old.Predecessor;
old.Predecessor?.Successor = old.Successor;
return old;
}

View File

@@ -250,10 +250,7 @@ namespace Ryujinx.Common.Collections
{
T right = RightOf(node);
node.Right = LeftOf(right);
if (node.Right != null)
{
node.Right.Parent = node;
}
node.Right?.Parent = node;
T nodeParent = ParentOf(node);
right.Parent = nodeParent;
@@ -281,10 +278,7 @@ namespace Ryujinx.Common.Collections
{
T left = LeftOf(node);
node.Left = RightOf(left);
if (node.Left != null)
{
node.Left.Parent = node;
}
node.Left?.Parent = node;
T nodeParent = ParentOf(node);
left.Parent = nodeParent;
@@ -329,10 +323,7 @@ namespace Ryujinx.Common.Collections
/// <param name="color">Color (Boolean)</param>
protected static void SetColor(T node, bool color)
{
if (node != null)
{
node.Color = color;
}
node?.Color = color;
}
/// <summary>

View File

@@ -328,10 +328,7 @@ namespace Ryujinx.Common.Collections
Node<TKey, TValue> tmp = LeftOf(replacementNode) ?? RightOf(replacementNode);
if (tmp != null)
{
tmp.Parent = ParentOf(replacementNode);
}
tmp?.Parent = ParentOf(replacementNode);
if (ParentOf(replacementNode) == null)
{

View File

@@ -31,6 +31,11 @@ namespace Ryujinx.Common.Configuration
public static string KeysDirPath { get; private set; }
public static string KeysDirPathUser { get; }
public static string GetKeysDir() =>
Mode is LaunchMode.UserProfile && Directory.Exists(KeysDirPathUser)
? KeysDirPathUser
: KeysDirPath;
public static string LogsDirPath { get; private set; }
public const string DefaultNandDir = "bis";

View File

@@ -35,6 +35,7 @@ namespace Ryujinx.Common.Logging
ServiceBsd,
ServiceBtm,
ServiceCaps,
ServiceEctx,
ServiceFatal,
ServiceFriend,
ServiceFs,

View File

@@ -7,6 +7,9 @@ namespace Ryujinx.Common.Memory
{
private static readonly RecyclableMemoryStreamManager _shared = new();
private static readonly ObjectPool<RecyclableMemoryStream> _streamPool =
new(() => new RecyclableMemoryStream(_shared, Guid.NewGuid(), null, 0));
/// <summary>
/// We don't expose the <c>RecyclableMemoryStreamManager</c> directly because version 2.x
/// returns them as <c>MemoryStream</c>. This Shared class is here to a) offer only the GetStream() versions we use
@@ -19,7 +22,12 @@ namespace Ryujinx.Common.Memory
/// </summary>
/// <returns>A <c>RecyclableMemoryStream</c></returns>
public static RecyclableMemoryStream GetStream()
=> new(_shared);
{
RecyclableMemoryStream stream = _streamPool.Allocate();
stream.SetLength(0);
return stream;
}
/// <summary>
/// Retrieve a new <c>MemoryStream</c> object with the contents copied from the provided
@@ -55,7 +63,8 @@ namespace Ryujinx.Common.Memory
RecyclableMemoryStream stream = null;
try
{
stream = new RecyclableMemoryStream(_shared, id, tag, buffer.Length);
stream = _streamPool.Allocate();
stream.SetLength(0);
stream.Write(buffer);
stream.Position = 0;
return stream;
@@ -83,7 +92,8 @@ namespace Ryujinx.Common.Memory
RecyclableMemoryStream stream = null;
try
{
stream = new RecyclableMemoryStream(_shared, id, tag, count);
stream = _streamPool.Allocate();
stream.SetLength(0);
stream.Write(buffer, offset, count);
stream.Position = 0;
return stream;
@@ -94,6 +104,11 @@ namespace Ryujinx.Common.Memory
throw;
}
}
public static void ReleaseStream(RecyclableMemoryStream stream)
{
_streamPool.Release(stream);
}
}
}
}

View File

@@ -13,6 +13,15 @@ namespace Ryujinx.Common
public const string SetupGuideWikiUrl =
"https://git.ryujinx.app/ryubing/ryujinx/-/wikis/Setup-&-Configuration-Guide";
public const string DumpKeysWikiUrl =
"https://git.ryujinx.app/ryubing/ryujinx/-/wikis/Dumping/Keys";
public const string DumpFirmwareWikiUrl =
"https://git.ryujinx.app/ryubing/ryujinx/-/wikis/Dumping/Firmware";
public const string DumpContentWikiUrl =
"https://git.ryujinx.app/ryubing/ryujinx/-/wikis/Dumping/Games,-Updates-&-DLC";
public const string MultiplayerWikiUrl =
"https://git.ryujinx.app/ryubing/ryujinx/-/wikis/Multiplayer-(LDN-Local-Wireless)-Guide";
}

View File

@@ -20,5 +20,21 @@ namespace Ryujinx.Common.Utilities
Debug.Assert(res != -1);
}
}
// "dumpable" attribute of the calling process
private const int PR_SET_DUMPABLE = 4;
[DllImport("libc", SetLastError = true)]
private static extern int prctl(int option, int arg2);
public static void SetCoreDumpable(bool dumpable)
{
if (OperatingSystem.IsLinux())
{
int dumpableInt = dumpable ? 1 : 0;
int result = prctl(PR_SET_DUMPABLE, dumpableInt);
Debug.Assert(result == 0);
}
}
}
}

View File

@@ -17,7 +17,7 @@ namespace Ryujinx.Cpu.Jit
_functionTable = AddressTable<ulong>.CreateForArm(for64Bit, memory.Type);
_translator = new Translator(new JitMemoryAllocator(forJit: true), memory, _functionTable);
if (memory.Type.IsHostMappedOrTracked())
if (memory.Type.IsHostMappedOrTracked)
{
NativeSignalHandler.InitializeSignalHandler();
}

View File

@@ -26,7 +26,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm32
return;
}
if (_operand.Type.IsInteger())
if (_operand.Type.IsInteger)
{
_registerAllocator.FreeTempGprRegister(_operand.AsInt32());
}

View File

@@ -381,7 +381,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64
if (currentCond != ArmCondition.Al)
{
instructionPointer = context.CodeWriter.InstructionPointer;
context.Arm64Assembler.B(currentCond.Invert(), 0);
context.Arm64Assembler.B(currentCond.Inverse, 0);
}
}
}

View File

@@ -104,7 +104,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64
if (invert)
{
conditions[i++] = ((ArmCondition)firstCond).Invert();
conditions[i++] = ((ArmCondition)firstCond).Inverse;
}
else
{

View File

@@ -1129,7 +1129,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64
// We don't need to mask the address for the safe mode, since it is already naturally limited to 32-bit
// and can never reach out of the guest address space.
if (mmType.IsHostTracked())
if (mmType.IsHostTracked)
{
int tempRegister = regAlloc.AllocateTempGprRegister();
@@ -1141,7 +1141,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64
regAlloc.FreeTempGprRegister(tempRegister);
}
else if (mmType.IsHostMapped())
else if (mmType.IsHostMapped)
{
asm.Add(destination64, basePointer, guestAddress);
}

View File

@@ -132,7 +132,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm64
InstName lastInstructionName = Instructions[^1].Name;
return lastInstructionName.IsCall() || lastInstructionName.IsException();
return lastInstructionName.IsCall || lastInstructionName.IsException;
}
}
}

View File

@@ -1042,126 +1042,39 @@ namespace Ryujinx.Cpu.LightningJit.Arm64
static class InstNameExtensions
{
public static bool IsCall(this InstName name)
extension(InstName name)
{
return name is InstName.Bl or InstName.Blr;
}
public bool IsCall => name is InstName.Bl or InstName.Blr;
public static bool IsControlFlowOrException(this InstName name)
{
switch (name)
public bool IsControlFlowOrException => name is
InstName.BUncond or InstName.BCond or InstName.Bl or InstName.Blr or InstName.Br or InstName.Brk
or InstName.Cbnz or InstName.Cbz or InstName.Ret or InstName.Tbnz or InstName.Tbz or InstName.Svc
or InstName.UdfPermUndef;
public bool IsException => name is InstName.Brk or InstName.Svc or InstName.UdfPermUndef;
public bool IsSystem => name switch
{
case InstName.BUncond:
case InstName.BCond:
case InstName.Bl:
case InstName.Blr:
case InstName.Br:
case InstName.Brk:
case InstName.Cbnz:
case InstName.Cbz:
case InstName.Ret:
case InstName.Tbnz:
case InstName.Tbz:
case InstName.Svc:
case InstName.UdfPermUndef:
return true;
}
InstName.Mrs or InstName.MsrImm or InstName.MsrReg => true,
_ => name.IsException
};
return false;
}
public bool IsSystemOrCall => name.IsCall || name is
InstName.Svc or InstName.Mrs or InstName.MsrImm or InstName.MsrReg
or InstName.Sysl;
public static bool IsException(this InstName name)
{
switch (name)
{
case InstName.Brk:
case InstName.Svc:
case InstName.UdfPermUndef:
return true;
}
public bool IsPrivileged => name is
InstName.Dcps1 or InstName.Dcps2 or InstName.Dcps3 or InstName.Drps or InstName.Eret or InstName.Ereta
or InstName.Hvc or InstName.MsrImm or InstName.Smc;
return false;
}
public bool IsPartialRegisterUpdateMemory => name is
InstName.Ld1AdvsimdSnglAsNoPostIndex or InstName.Ld1AdvsimdSnglAsPostIndex
or InstName.Ld2AdvsimdSnglAsNoPostIndex or InstName.Ld2AdvsimdSnglAsPostIndex
or InstName.Ld3AdvsimdSnglAsNoPostIndex or InstName.Ld3AdvsimdSnglAsPostIndex
or InstName.Ld4AdvsimdSnglAsNoPostIndex or InstName.Ld4AdvsimdSnglAsPostIndex;
public static bool IsSystem(this InstName name)
{
switch (name)
{
case InstName.Mrs:
case InstName.MsrImm:
case InstName.MsrReg:
return true;
}
return name.IsException();
}
public static bool IsSystemOrCall(this InstName name)
{
switch (name)
{
case InstName.Bl:
case InstName.Blr:
case InstName.Svc:
case InstName.Mrs:
case InstName.MsrImm:
case InstName.MsrReg:
case InstName.Sysl:
return true;
}
return false;
}
public static bool IsPrivileged(this InstName name)
{
switch (name)
{
case InstName.Dcps1:
case InstName.Dcps2:
case InstName.Dcps3:
case InstName.Drps:
case InstName.Eret:
case InstName.Ereta:
case InstName.Hvc:
case InstName.MsrImm:
case InstName.Smc:
return true;
}
return false;
}
public static bool IsPartialRegisterUpdateMemory(this InstName name)
{
switch (name)
{
case InstName.Ld1AdvsimdSnglAsNoPostIndex:
case InstName.Ld1AdvsimdSnglAsPostIndex:
case InstName.Ld2AdvsimdSnglAsNoPostIndex:
case InstName.Ld2AdvsimdSnglAsPostIndex:
case InstName.Ld3AdvsimdSnglAsNoPostIndex:
case InstName.Ld3AdvsimdSnglAsPostIndex:
case InstName.Ld4AdvsimdSnglAsNoPostIndex:
case InstName.Ld4AdvsimdSnglAsPostIndex:
return true;
}
return false;
}
public static bool IsPrefetchMemory(this InstName name)
{
switch (name)
{
case InstName.PrfmImm:
case InstName.PrfmLit:
case InstName.PrfmReg:
case InstName.Prfum:
return true;
}
return false;
public bool IsPrefetchMemory => name is
InstName.PrfmImm or InstName.PrfmLit or InstName.PrfmReg or InstName.Prfum;
}
}
}

View File

@@ -150,7 +150,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm64
public static int CalculateMaxTemps(MemoryManagerType mmType)
{
return mmType.IsHostMapped() ? 1 : 2;
return mmType.IsHostMapped ? 1 : 2;
}
public static int CalculateMaxTempsInclFixed(MemoryManagerType mmType)

View File

@@ -247,7 +247,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm64
}
}
if (!flags.HasFlag(InstFlags.ReadRt) || name.IsPartialRegisterUpdateMemory())
if (!flags.HasFlag(InstFlags.ReadRt) || name.IsPartialRegisterUpdateMemory)
{
if (flags.HasFlag(InstFlags.Rt))
{
@@ -281,7 +281,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm64
gprMask |= MaskFromIndex(ExtractRd(flags, encoding));
}
if (!flags.HasFlag(InstFlags.ReadRt) || name.IsPartialRegisterUpdateMemory())
if (!flags.HasFlag(InstFlags.ReadRt) || name.IsPartialRegisterUpdateMemory)
{
if (flags.HasFlag(InstFlags.Rt))
{

View File

@@ -364,7 +364,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm64.Target.Arm64
{
InstEmitMemory.RewriteSysInstruction(memoryManager.AddressSpaceBits, memoryManager.Type, writer, regAlloc, encoding);
}
else if (instInfo.Name.IsSystem())
else if (instInfo.Name.IsSystem)
{
bool needsContextStoreLoad = InstEmitSystem.NeedsContextStoreLoad(instInfo.Name);
@@ -405,7 +405,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm64.Target.Arm64
lastInstructionEncoding = RegisterUtils.RemapRegisters(regAlloc, lastInstructionFlags, lastInstructionEncoding);
if (lastInstructionName.IsCall())
if (lastInstructionName.IsCall)
{
context.StoreToContextBeforeCall(blockIndex, pc + 4UL);

View File

@@ -257,7 +257,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm64.Target.Arm64
(name, flags, AddressForm addressForm) = InstTable.GetInstNameAndFlags(encoding, cpuPreset.Version, cpuPreset.Features);
if (name.IsPrivileged() || (name == InstName.Sys && IsPrivilegedSys(encoding)))
if (name.IsPrivileged || (name == InstName.Sys && IsPrivilegedSys(encoding)))
{
name = InstName.UdfPermUndef;
flags = InstFlags.None;
@@ -267,7 +267,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm64.Target.Arm64
(uint instGprReadMask, uint instFpSimdReadMask) = RegisterUtils.PopulateReadMasks(name, flags, encoding);
(uint instGprWriteMask, uint instFpSimdWriteMask) = RegisterUtils.PopulateWriteMasks(name, flags, encoding);
if (name.IsCall())
if (name.IsCall)
{
instGprWriteMask |= 1u << RegisterUtils.LrIndex;
}
@@ -310,12 +310,12 @@ namespace Ryujinx.Cpu.LightningJit.Arm64.Target.Arm64
fpSimdUseMask |= instFpSimdReadMask | instFpSimdWriteMask;
pStateUseMask |= instPStateReadMask | instPStateWriteMask;
if (name.IsSystemOrCall() && !hasHostCall)
if (name.IsSystemOrCall && !hasHostCall)
{
hasHostCall = name.IsCall() || InstEmitSystem.NeedsCall(encoding);
hasHostCall = name.IsCall || InstEmitSystem.NeedsCall(encoding);
}
isControlFlow = name.IsControlFlowOrException();
isControlFlow = name.IsControlFlowOrException;
RegisterUse registerUse = new(
instGprReadMask,
@@ -339,7 +339,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm64.Target.Arm64
useMask = new(gprUseMask, fpSimdUseMask, pStateUseMask);
return new(startAddress, address, insts, !isTruncated && !name.IsException(), isTruncated, isLoopEnd);
return new(startAddress, address, insts, !isTruncated && !name.IsException, isTruncated, isLoopEnd);
}
private static bool IsPrivilegedSys(uint encoding)

View File

@@ -55,7 +55,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm64.Target.Arm64
ulong pc,
uint encoding)
{
if (name.IsPrefetchMemory() && mmType == MemoryManagerType.HostTrackedUnsafe)
if (name.IsPrefetchMemory && mmType == MemoryManagerType.HostTrackedUnsafe)
{
// Prefetch to invalid addresses do not cause faults, so for memory manager
// types where we need to access the page table before doing the prefetch,
@@ -544,7 +544,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm64.Target.Arm64
{
Operand basePointer = new(regAlloc.FixedPageTableRegister, RegisterType.Integer, OperandType.I64);
if (mmType.IsHostTracked())
if (mmType.IsHostTracked)
{
int tempRegister = regAlloc.AllocateTempGprRegister();
@@ -562,7 +562,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm64.Target.Arm64
regAlloc.FreeTempGprRegister(tempRegister);
}
else if (mmType.IsHostMapped())
else if (mmType.IsHostMapped)
{
if (mmType == MemoryManagerType.HostMapped)
{

View File

@@ -22,9 +22,9 @@ namespace Ryujinx.Cpu.LightningJit.CodeGen.Arm64
static class ArmConditionExtensions
{
public static ArmCondition Invert(this ArmCondition condition)
extension(ArmCondition condition)
{
return (ArmCondition)((int)condition ^ 1);
public ArmCondition Inverse => (ArmCondition)((int)condition ^ 1);
}
}
}

View File

@@ -673,7 +673,7 @@ namespace Ryujinx.Cpu.LightningJit.CodeGen.Arm64
public readonly void Mov(Operand rd, Operand rn)
{
Debug.Assert(rd.Type.IsInteger());
Debug.Assert(rd.Type.IsInteger);
Orr(rd, new Operand(ZrRegister, RegisterType.Integer, rd.Type), rn);
}
@@ -4544,7 +4544,7 @@ namespace Ryujinx.Cpu.LightningJit.CodeGen.Arm64
uint instruction;
int scale;
if (type.IsInteger())
if (type.IsInteger)
{
instruction = intInst;
@@ -4580,7 +4580,7 @@ namespace Ryujinx.Cpu.LightningJit.CodeGen.Arm64
{
uint instruction;
if (type.IsInteger())
if (type.IsInteger)
{
instruction = intInst;
@@ -4610,7 +4610,7 @@ namespace Ryujinx.Cpu.LightningJit.CodeGen.Arm64
{
uint instruction;
if (type.IsInteger())
if (type.IsInteger)
{
instruction = intInst;

View File

@@ -34,7 +34,7 @@ namespace Ryujinx.Cpu.LightningJit.CodeGen.Arm64
int gprCalleeSavedRegsCount = BitOperations.PopCount(_gprMask);
int fpSimdCalleeSavedRegsCount = BitOperations.PopCount(_fpSimdMask);
return (_hasCall ? 16 : 0) + Align16(gprCalleeSavedRegsCount * 8 + fpSimdCalleeSavedRegsCount * _fpSimdType.GetSizeInBytes());
return (_hasCall ? 16 : 0) + Align16(gprCalleeSavedRegsCount * 8 + fpSimdCalleeSavedRegsCount * _fpSimdType.ByteSize);
}
public void WritePrologue(ref Assembler asm)
@@ -46,7 +46,7 @@ namespace Ryujinx.Cpu.LightningJit.CodeGen.Arm64
int fpSimdCalleeSavedRegsCount = BitOperations.PopCount(fpSimdMask);
int reservedStackSize = Align16(_reservedStackSize);
int calleeSaveRegionSize = Align16(gprCalleeSavedRegsCount * 8 + fpSimdCalleeSavedRegsCount * _fpSimdType.GetSizeInBytes()) + reservedStackSize;
int calleeSaveRegionSize = Align16(gprCalleeSavedRegsCount * 8 + fpSimdCalleeSavedRegsCount * _fpSimdType.ByteSize) + reservedStackSize;
int offset = 0;
WritePrologueCalleeSavesPreIndexed(ref asm, ref gprMask, ref offset, calleeSaveRegionSize, OperandType.I64);
@@ -103,7 +103,7 @@ namespace Ryujinx.Cpu.LightningJit.CodeGen.Arm64
asm.StrRiUn(Register(reg, type), Register(Assembler.SpRegister), 0);
}
offset += type.GetSizeInBytes();
offset += type.ByteSize;
}
while (mask != 0)
@@ -130,7 +130,7 @@ namespace Ryujinx.Cpu.LightningJit.CodeGen.Arm64
asm.StpRiUn(Register(reg, type), Register(reg2, type), Register(Assembler.SpRegister), 0);
}
offset += type.GetSizeInBytes() * 2;
offset += type.ByteSize * 2;
}
}
@@ -144,7 +144,7 @@ namespace Ryujinx.Cpu.LightningJit.CodeGen.Arm64
bool misalignedVector = _fpSimdType == OperandType.V128 && (gprCalleeSavedRegsCount & 1) != 0;
int offset = gprCalleeSavedRegsCount * 8 + fpSimdCalleeSavedRegsCount * _fpSimdType.GetSizeInBytes();
int offset = gprCalleeSavedRegsCount * 8 + fpSimdCalleeSavedRegsCount * _fpSimdType.ByteSize;
if (misalignedVector)
{
@@ -197,7 +197,7 @@ namespace Ryujinx.Cpu.LightningJit.CodeGen.Arm64
mask &= ~(1u << reg2);
offset -= type.GetSizeInBytes() * 2;
offset -= type.ByteSize * 2;
if (offset != 0)
{
@@ -215,7 +215,7 @@ namespace Ryujinx.Cpu.LightningJit.CodeGen.Arm64
}
else
{
offset -= type.GetSizeInBytes();
offset -= type.ByteSize;
if (offset != 0)
{

View File

@@ -14,14 +14,11 @@ namespace Ryujinx.Cpu.LightningJit.CodeGen
static class OperandTypeExtensions
{
public static bool IsInteger(this OperandType type)
extension(OperandType type)
{
return type is OperandType.I32 or OperandType.I64;
}
public bool IsInteger => type is OperandType.I32 or OperandType.I64;
public static int GetSizeInBytes(this OperandType type)
{
return type switch
public int ByteSize => type switch
{
OperandType.FP32 => 4,
OperandType.FP64 => 8,

Some files were not shown because too many files have changed in this diff Show More