mirror of
https://git.ryujinx.app/ryubing/ryujinx.git
synced 2025-09-13 05:25:06 +00:00
Compare commits
76 Commits
Canary-1.3
...
update/dot
Author | SHA1 | Date | |
---|---|---|---|
|
0e26e35ec0 | ||
|
a5a13271d5 | ||
|
de49d1779e | ||
|
9cd1e9be68 | ||
|
9def11f7d2 | ||
|
2fa5905f1e | ||
|
04427f3a1a | ||
|
e152dbe254 | ||
|
bda52e97ad | ||
|
4a64b23ca3 | ||
|
5fcf70be77 | ||
|
7a115764e8 | ||
|
e78bc68dc5 | ||
|
34a36fb3ff | ||
|
ef86ae59cb | ||
|
df29d51250 | ||
|
aaa0bd98ec | ||
|
bbf30a107c | ||
|
df40a69872 | ||
|
b000f91dad | ||
|
a60b2a0ba3 | ||
|
4c9b48b754 | ||
|
3bd7d5904e | ||
|
23eb9a3043 | ||
|
931ec44406 | ||
|
d68efa98ba | ||
|
ded76801d1 | ||
|
6084df7473 | ||
|
f3953c6039 | ||
|
91f5247e7f | ||
|
5658402c6b | ||
|
1b2c93e188 | ||
|
9e599ff325 | ||
|
7a5f430b59 | ||
|
1e340ce2f3 | ||
|
dbb4e63e1e | ||
|
d00ab52fa2 | ||
|
959af3613d | ||
|
3309fb2351 | ||
|
e1e8628a6f | ||
|
3969191605 | ||
|
07c7b39053 | ||
|
053efaa414 | ||
|
56e6339553 | ||
|
042362ee2b | ||
|
7347ee2212 | ||
|
01a9b636af | ||
|
6e47d8548c | ||
|
da340f5615 | ||
|
be249f7bdc | ||
|
462c93e1ff | ||
|
573a6f32fe | ||
|
7846f58cad | ||
|
0203065fed | ||
|
7319a2dafc | ||
|
f992735656 | ||
|
48b9f2ab93 | ||
|
50ab108ee1 | ||
|
d499449f57 | ||
|
cd3c614021 | ||
|
5fa82bb1f5 | ||
|
234cb99325 | ||
|
ab7914f235 | ||
|
3df6b7c0f5 | ||
|
37e81481c4 | ||
|
4d8b799763 | ||
|
cb786b7147 | ||
|
2a308f50c0 | ||
|
b51c5cead6 | ||
|
461c1f5342 | ||
|
cfea61b3a0 | ||
|
ae2e9a73ab | ||
|
c6f22318a7 | ||
|
dd5e1b99b1 | ||
|
c863ffd353 | ||
|
d6d089b81b |
78
.github/workflows/canary.yml
vendored
78
.github/workflows/canary.yml
vendored
@@ -106,47 +106,45 @@ jobs:
|
|||||||
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 --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"
|
||||||
shell: bash
|
shell: bash
|
||||||
|
|
||||||
# If anyone wants to look into why appimagetool randomly errors with exit code 8, that would be cool
|
- name: Build AppImage (Linux)
|
||||||
|
if: matrix.platform.os == 'ubuntu-latest'
|
||||||
|
run: |
|
||||||
|
BUILD_VERSION="${{ steps.version_info.outputs.build_version }}"
|
||||||
|
PLATFORM_NAME="${{ matrix.platform.name }}"
|
||||||
|
|
||||||
# - name: Build AppImage (Linux)
|
sudo apt install -y zsync desktop-file-utils appstream
|
||||||
# if: matrix.platform.os == 'ubuntu-latest'
|
|
||||||
# run: |
|
mkdir -p tools
|
||||||
# BUILD_VERSION="${{ steps.version_info.outputs.build_version }}"
|
export PATH="$PATH:$(readlink -f tools)"
|
||||||
# PLATFORM_NAME="${{ matrix.platform.name }}"
|
|
||||||
#
|
# Setup appimagetool
|
||||||
# sudo apt install -y zsync desktop-file-utils appstream
|
wget -q -O tools/appimagetool "https://github.com/AppImage/appimagetool/releases/download/continuous/appimagetool-x86_64.AppImage"
|
||||||
#
|
chmod +x tools/appimagetool
|
||||||
# mkdir -p tools
|
chmod +x distribution/linux/appimage/build-appimage.sh
|
||||||
# export PATH="$PATH:$(readlink -f tools)"
|
|
||||||
#
|
# Explicitly set $ARCH for appimagetool ($ARCH_NAME is for the file name)
|
||||||
# # Setup appimagetool
|
if [ "$PLATFORM_NAME" = "linux-x64" ]; then
|
||||||
# wget -q -O tools/appimagetool "https://github.com/AppImage/appimagetool/releases/download/continuous/appimagetool-x86_64.AppImage"
|
ARCH_NAME=x64
|
||||||
# chmod +x tools/appimagetool
|
export ARCH=x86_64
|
||||||
# chmod +x distribution/linux/appimage/build-appimage.sh
|
elif [ "$PLATFORM_NAME" = "linux-arm64" ]; then
|
||||||
#
|
ARCH_NAME=arm64
|
||||||
# # Explicitly set $ARCH for appimagetool ($ARCH_NAME is for the file name)
|
export ARCH=aarch64
|
||||||
# if [ "$PLATFORM_NAME" = "linux-x64" ]; then
|
else
|
||||||
# ARCH_NAME=x64
|
echo "Unexpected PLATFORM_NAME "$PLATFORM_NAME""
|
||||||
# export ARCH=x86_64
|
exit 1
|
||||||
# elif [ "$PLATFORM_NAME" = "linux-arm64" ]; then
|
fi
|
||||||
# ARCH_NAME=arm64
|
|
||||||
# export ARCH=aarch64
|
export UFLAG="gh-releases-zsync|${{ secrets.RC_OWNER }}${{ secrets.RC_CANARY_NAME }}|latest|*-$ARCH_NAME.AppImage.zsync"
|
||||||
# else
|
BUILDDIR=publish OUTDIR=publish_appimage distribution/linux/appimage/build-appimage.sh
|
||||||
# echo "Unexpected PLATFORM_NAME "$PLATFORM_NAME""
|
|
||||||
# exit 1
|
pushd publish_appimage
|
||||||
# fi
|
mv Ryujinx.AppImage ../release_output/ryujinx-canary-$BUILD_VERSION-$ARCH_NAME.AppImage
|
||||||
#
|
mv Ryujinx.AppImage.zsync ../release_output/ryujinx-canary-$BUILD_VERSION-$ARCH_NAME.AppImage.zsync
|
||||||
# export UFLAG="gh-releases-zsync|${{ secrets.RC_OWNER }}${{ secrets.RC_CANARY_NAME }}|latest|*-$ARCH_NAME.AppImage.zsync"
|
popd
|
||||||
# BUILDDIR=publish OUTDIR=publish_appimage distribution/linux/appimage/build-appimage.sh
|
|
||||||
#
|
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"
|
||||||
# pushd publish_appimage
|
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.zsync"
|
||||||
# mv Ryujinx.AppImage ../release_output/ryujinx-canary-$BUILD_VERSION-$ARCH_NAME.AppImage
|
shell: bash
|
||||||
# mv Ryujinx.AppImage.zsync ../release_output/ryujinx-canary-$BUILD_VERSION-$ARCH_NAME.AppImage.zsync
|
|
||||||
# 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 --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.zsync"
|
|
||||||
# shell: bash
|
|
||||||
|
|
||||||
macos_release:
|
macos_release:
|
||||||
name: Release MacOS universal
|
name: Release MacOS universal
|
||||||
|
78
.github/workflows/release.yml
vendored
78
.github/workflows/release.yml
vendored
@@ -97,47 +97,45 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
# If anyone wants to look into why appimagetool randomly errors with exit code 8, that would be cool
|
- name: Build AppImage (Linux)
|
||||||
|
if: matrix.platform.os == 'ubuntu-latest'
|
||||||
|
run: |
|
||||||
|
BUILD_VERSION="${{ steps.version_info.outputs.build_version }}"
|
||||||
|
PLATFORM_NAME="${{ matrix.platform.name }}"
|
||||||
|
|
||||||
# - name: Build AppImage (Linux)
|
sudo apt install -y zsync desktop-file-utils appstream
|
||||||
# if: matrix.platform.os == 'ubuntu-latest'
|
|
||||||
# run: |
|
mkdir -p tools
|
||||||
# BUILD_VERSION="${{ steps.version_info.outputs.build_version }}"
|
export PATH="$PATH:$(readlink -f tools)"
|
||||||
# PLATFORM_NAME="${{ matrix.platform.name }}"
|
|
||||||
#
|
# Setup appimagetool
|
||||||
# sudo apt install -y zsync desktop-file-utils appstream
|
wget -q -O tools/appimagetool "https://github.com/AppImage/appimagetool/releases/download/continuous/appimagetool-x86_64.AppImage"
|
||||||
#
|
chmod +x tools/appimagetool
|
||||||
# mkdir -p tools
|
chmod +x distribution/linux/appimage/build-appimage.sh
|
||||||
# export PATH="$PATH:$(readlink -f tools)"
|
|
||||||
#
|
# Explicitly set $ARCH for appimagetool ($ARCH_NAME is for the file name)
|
||||||
# # Setup appimagetool
|
if [ "$PLATFORM_NAME" = "linux-x64" ]; then
|
||||||
# wget -q -O tools/appimagetool "https://github.com/AppImage/appimagetool/releases/download/continuous/appimagetool-x86_64.AppImage"
|
ARCH_NAME=x64
|
||||||
# chmod +x tools/appimagetool
|
export ARCH=x86_64
|
||||||
# chmod +x distribution/linux/appimage/build-appimage.sh
|
elif [ "$PLATFORM_NAME" = "linux-arm64" ]; then
|
||||||
#
|
ARCH_NAME=arm64
|
||||||
# # Explicitly set $ARCH for appimagetool ($ARCH_NAME is for the file name)
|
export ARCH=aarch64
|
||||||
# if [ "$PLATFORM_NAME" = "linux-x64" ]; then
|
else
|
||||||
# ARCH_NAME=x64
|
echo "Unexpected PLATFORM_NAME "$PLATFORM_NAME""
|
||||||
# export ARCH=x86_64
|
exit 1
|
||||||
# elif [ "$PLATFORM_NAME" = "linux-arm64" ]; then
|
fi
|
||||||
# ARCH_NAME=arm64
|
|
||||||
# export ARCH=aarch64
|
export UFLAG="gh-releases-zsync|${{ github.repository_owner }}|${{ github.event.repository.name }}|latest|*-$ARCH_NAME.AppImage.zsync"
|
||||||
# else
|
BUILDDIR=publish OUTDIR=publish_appimage distribution/linux/appimage/build-appimage.sh
|
||||||
# echo "Unexpected PLATFORM_NAME "$PLATFORM_NAME""
|
|
||||||
# exit 1
|
pushd publish_appimage
|
||||||
# fi
|
mv Ryujinx.AppImage ../release_output/ryujinx-$BUILD_VERSION-$ARCH_NAME.AppImage
|
||||||
#
|
mv Ryujinx.AppImage.zsync ../release_output/ryujinx-$BUILD_VERSION-$ARCH_NAME.AppImage.zsync
|
||||||
# export UFLAG="gh-releases-zsync|${{ github.repository_owner }}|${{ github.event.repository.name }}|latest|*-$ARCH_NAME.AppImage.zsync"
|
popd
|
||||||
# BUILDDIR=publish OUTDIR=publish_appimage distribution/linux/appimage/build-appimage.sh
|
|
||||||
#
|
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"
|
||||||
# pushd publish_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"
|
||||||
# mv Ryujinx.AppImage ../release_output/ryujinx-$BUILD_VERSION-$ARCH_NAME.AppImage
|
shell: bash
|
||||||
# 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:
|
macos_release:
|
||||||
name: Release MacOS universal
|
name: Release MacOS universal
|
||||||
|
@@ -1,18 +0,0 @@
|
|||||||
function pub {
|
|
||||||
dotnet publish -c release
|
|
||||||
}
|
|
||||||
|
|
||||||
function package {
|
|
||||||
cd src/$1
|
|
||||||
pub
|
|
||||||
mv bin/Release/$1.1.0.0.nupkg ../../pkgs/$1.1.0.0.nupkg
|
|
||||||
cd ../../
|
|
||||||
}
|
|
||||||
|
|
||||||
rm -rf pkgs
|
|
||||||
mkdir pkgs
|
|
||||||
|
|
||||||
package ARMeilleure
|
|
||||||
package Ryujinx.Memory
|
|
||||||
|
|
||||||
dotnet nuget push pkgs/*.nupkg --source RyubingPkgs
|
|
40
CHANGELOG.md
40
CHANGELOG.md
@@ -21,8 +21,8 @@ Additionally, 1.2.74 & 75 were fixes for uploading Windows build artifacts.
|
|||||||
|
|
||||||
1.2.76 fixes a rare crash on startup.
|
1.2.76 fixes a rare crash on startup.
|
||||||
|
|
||||||
## [1.2.72](<https://github.com/GreemDev/Ryujinx/releases/tag/1.2.72>) - 2024-11-03
|
## [1.2.72](<https://git.ryujinx.app/ryubing/ryujinx/-/tags/1.2.72>) - 2024-11-03
|
||||||
PRs [#163](<https://github.com/GreemDev/Ryujinx/pull/163>), [#164](<https://github.com/GreemDev/Ryujinx/pull/164>), [#139](<https://github.com/GreemDev/Ryujinx/pull/139>)
|
PRs [#163](<https://web.archive.org/web/20241123015123/https://github.com/GreemDev/Ryujinx/pull/163>), [#164](<https://web.archive.org/web/20250307192526/https://github.com/Ryubing/Ryujinx/pull/164>), [#139](<https://web.archive.org/web/20250306123457/https://github.com/Ryubing/Ryujinx/pull/139>)
|
||||||
### HLE:
|
### HLE:
|
||||||
- Add DebugMouse HID device.
|
- Add DebugMouse HID device.
|
||||||
- Fixes "Clock Tower Rewind" crashing while loading.
|
- Fixes "Clock Tower Rewind" crashing while loading.
|
||||||
@@ -32,7 +32,7 @@ PRs [#163](<https://github.com/GreemDev/Ryujinx/pull/163>), [#164](<https://gith
|
|||||||
### misc:
|
### misc:
|
||||||
- Update macOS distribution .icns.
|
- Update macOS distribution .icns.
|
||||||
|
|
||||||
## [1.2.69](<https://github.com/GreemDev/Ryujinx/releases/tag/1.2.69>) - 2024-11-01
|
## [1.2.69](<https://git.ryujinx.app/ryubing/ryujinx/-/tags/1.2.69>) - 2024-11-01
|
||||||
### Infra:
|
### Infra:
|
||||||
- Compile the native libraries into the Ryujinx executable.
|
- Compile the native libraries into the Ryujinx executable.
|
||||||
- Remove `libarmeilleure-jitsupport.dylib` from Windows & Linux releases (dylibs are macOS-only)
|
- Remove `libarmeilleure-jitsupport.dylib` from Windows & Linux releases (dylibs are macOS-only)
|
||||||
@@ -42,8 +42,8 @@ PRs [#163](<https://github.com/GreemDev/Ryujinx/pull/163>), [#164](<https://gith
|
|||||||
- Replace "" with `string.Empty`.
|
- Replace "" with `string.Empty`.
|
||||||
- Code cleanups & simplifications.
|
- Code cleanups & simplifications.
|
||||||
|
|
||||||
## [1.2.67](<https://github.com/GreemDev/Ryujinx/releases/tag/1.2.67>) - 2024-11-01
|
## [1.2.67](<https://git.ryujinx.app/ryubing/ryujinx/-/tags/1.2.67>) - 2024-11-01
|
||||||
PRs [#36](<https://github.com/GreemDev/Ryujinx/pull/36>), [#135](<https://github.com/GreemDev/Ryujinx/pull/135>)
|
PRs [#36](<https://web.archive.org/web/20250306215917/https://github.com/Ryubing/Ryujinx/pull/36>), [#135](<https://web.archive.org/web/20241122135125/https://github.com/GreemDev/Ryujinx/pull/135>)
|
||||||
|
|
||||||
### GUI:
|
### GUI:
|
||||||
- Set UseFloatingWatermark to false when watermark is empty
|
- Set UseFloatingWatermark to false when watermark is empty
|
||||||
@@ -54,8 +54,8 @@ PRs [#36](<https://github.com/GreemDev/Ryujinx/pull/36>), [#135](<https://github
|
|||||||
- Fix homebrew loading.
|
- Fix homebrew loading.
|
||||||
|
|
||||||
|
|
||||||
## [1.2.64](https://github.com/GreemDev/Ryujinx/releases/tag/1.2.64) - 2024-10-30
|
## [1.2.64](https://git.ryujinx.app/ryubing/ryujinx/-/tags/1.2.64) - 2024-10-30
|
||||||
PRs [#92](https://github.com/GreemDev/Ryujinx/pull/92), [#96](https://github.com/GreemDev/Ryujinx/pull/96), [#97](https://github.com/GreemDev/Ryujinx/pull/97), [#101](https://github.com/GreemDev/Ryujinx/pull/101), [#103](https://github.com/GreemDev/Ryujinx/pull/103)
|
PRs [#92](https://web.archive.org/web/20241118052724/https://github.com/GreemDev/Ryujinx/pull/92), ~~[#96](https://github.com/GreemDev/Ryujinx/pull/96)~~, ~~[#97](https://github.com/GreemDev/Ryujinx/pull/97)~~, [#101](https://web.archive.org/web/20250306223605/https://github.com/Ryubing/Ryujinx/pull/101), ~~[#103](https://github.com/GreemDev/Ryujinx/pull/103)~~
|
||||||
### GUI:
|
### GUI:
|
||||||
- Option to show classic-style title bar. Requires restart of emulator to take effect.
|
- Option to show classic-style title bar. Requires restart of emulator to take effect.
|
||||||
- This is only relevant on Windows. Other Operating Systems default to this being on and not being changeable, because the custom (current) title bar only works on Windows in the first place.
|
- This is only relevant on Windows. Other Operating Systems default to this being on and not being changeable, because the custom (current) title bar only works on Windows in the first place.
|
||||||
@@ -71,14 +71,14 @@ PRs [#92](https://github.com/GreemDev/Ryujinx/pull/92), [#96](https://github.com
|
|||||||
|
|
||||||
## 1.2.59 - 2024-10-27
|
## 1.2.59 - 2024-10-27
|
||||||
|
|
||||||
PRs [#88](https://github.com/GreemDev/Ryujinx/pull/88), [#87](https://github.com/GreemDev/Ryujinx/pull/87)
|
PRs ~~[#88](https://github.com/GreemDev/Ryujinx/pull/88), [#87](https://github.com/GreemDev/Ryujinx/pull/87)~~
|
||||||
### i18n:
|
### i18n:
|
||||||
- fr_FR:
|
- fr_FR:
|
||||||
- Add missing translations for new features & fix a couple wrong ones.
|
- Add missing translations for new features & fix a couple wrong ones.
|
||||||
- Fix Ignore Missing Services / Ignore Applet tooltip.
|
- Fix Ignore Missing Services / Ignore Applet tooltip.
|
||||||
|
|
||||||
## 1.2.57 - 2024-10-27
|
## 1.2.57 - 2024-10-27
|
||||||
PRs [#60](https://github.com/GreemDev/Ryujinx/pull/60), [#42](https://github.com/GreemDev/Ryujinx/pull/42)
|
PRs ~~[#60](https://github.com/GreemDev/Ryujinx/pull/60)~~, [#42](https://web.archive.org/web/20241126203614/https://github.com/GreemDev/Ryujinx/pull/42)
|
||||||
### GUI:
|
### GUI:
|
||||||
- Automatically remove invalid DLC & updates as part of autoload.
|
- Automatically remove invalid DLC & updates as part of autoload.
|
||||||
- Added Thai translation for Ignore Applet hover tooltip.
|
- Added Thai translation for Ignore Applet hover tooltip.
|
||||||
@@ -104,7 +104,7 @@ PRs [#60](https://github.com/GreemDev/Ryujinx/pull/60), [#42](https://github.com
|
|||||||
- Code cleanup.
|
- Code cleanup.
|
||||||
|
|
||||||
## 1.2.44 - 2024-10-25
|
## 1.2.44 - 2024-10-25
|
||||||
PR [#59](https://github.com/GreemDev/Ryujinx/pull/59)
|
PR [#59](https://web.archive.org/web/20241125060420/https://github.com/GreemDev/Ryujinx/pull/59)
|
||||||
### GUI:
|
### GUI:
|
||||||
- Add descriptions for "ignoring applet" translated into other languages.
|
- Add descriptions for "ignoring applet" translated into other languages.
|
||||||
|
|
||||||
@@ -117,9 +117,9 @@ NOTE: The translation isn't referenced in the code yet, it will be in the next u
|
|||||||
## 1.2.42 - 2024-10-24
|
## 1.2.42 - 2024-10-24
|
||||||
Sources:
|
Sources:
|
||||||
|
|
||||||
Init function: https://github.com/MutantAura/Ryujinx/commit/9cef4ceba40d66492ff775af793ff70e6e7551a9
|
Init function: [archive of github.com/MutantAura/Ryujinx/commit/9cef4ceba40d66492ff775af793ff70e6e7551a9](https://web.archive.org/web/20241122193401/https://github.com/MutantAura/Ryujinx/commit/9cef4ceba40d66492ff775af793ff70e6e7551a9)
|
||||||
|
|
||||||
Shader counter: https://github.com/MutantAura/Ryujinx/commit/67b873645fd593e83d042a77bf7ab12e5ec97357
|
Shader counter: ~~https://github.com/MutantAura/Ryujinx/commit/67b873645fd593e83d042a77bf7ab12e5ec97357~~ Original commit has been lost
|
||||||
|
|
||||||
Thanks MutantAura :D
|
Thanks MutantAura :D
|
||||||
### GUI:
|
### GUI:
|
||||||
@@ -127,14 +127,14 @@ Thanks MutantAura :D
|
|||||||
- Remove graphics backend / GPU name event logic in favor of a single init function.
|
- Remove graphics backend / GPU name event logic in favor of a single init function.
|
||||||
|
|
||||||
## 1.2.41 - 2024-10-24
|
## 1.2.41 - 2024-10-24
|
||||||
PR [#54](https://github.com/GreemDev/Ryujinx/pull/54)
|
PR ~~[#54](https://github.com/GreemDev/Ryujinx/pull/54)~~
|
||||||
|
|
||||||
Thanks Whitescatz!
|
Thanks Whitescatz!
|
||||||
### i18n:
|
### i18n:
|
||||||
- th_TH (Thai): Added missing translations, reduce transliterated words, fix grammar.
|
- th_TH (Thai): Added missing translations, reduce transliterated words, fix grammar.
|
||||||
|
|
||||||
## 1.2.40 - 2024-10-23
|
## 1.2.40 - 2024-10-23
|
||||||
PR [#40](https://github.com/GreemDev/Ryujinx/pull/40)
|
PR ~~[#40](https://github.com/GreemDev/Ryujinx/pull/40)~~
|
||||||
|
|
||||||
Thanks Вова С!
|
Thanks Вова С!
|
||||||
### GUI:
|
### GUI:
|
||||||
@@ -148,30 +148,30 @@ Thanks Вова С!
|
|||||||
- Should prevent crashing on config loads in some circumstances.
|
- Should prevent crashing on config loads in some circumstances.
|
||||||
|
|
||||||
## 1.2.38 - 2024-10-23
|
## 1.2.38 - 2024-10-23
|
||||||
PR [#51](https://github.com/GreemDev/Ryujinx/pull/51)
|
PR [#51](https://web.archive.org/web/20241127022413/https://github.com/GreemDev/Ryujinx/pull/51)
|
||||||
### i18n:
|
### i18n:
|
||||||
- zh_CH (Simplified Chinese): Add some missing translations.
|
- zh_CH (Simplified Chinese): Add some missing translations.
|
||||||
|
|
||||||
## 1.2.37 - 2024-10-23
|
## 1.2.37 - 2024-10-23
|
||||||
PR [#37](https://github.com/GreemDev/Ryujinx/pull/37)
|
PR [#37](https://web.archive.org/web/20241123010103/https://github.com/GreemDev/Ryujinx/pull/37)
|
||||||
|
|
||||||
Thanks Last Breath!
|
Thanks Last Breath!
|
||||||
### GUI:
|
### GUI:
|
||||||
- Set the default controller to the Pro Controller.
|
- Set the default controller to the Pro Controller.
|
||||||
|
|
||||||
## 1.2.36 - 2024-10-21
|
## 1.2.36 - 2024-10-21
|
||||||
PR [#30](https://github.com/GreemDev/Ryujinx/pull/30)
|
PR ~~[#30](https://github.com/GreemDev/Ryujinx/pull/30)~~
|
||||||
### GUI:
|
### GUI:
|
||||||
- Fix repeated dialog popup notifying you of new updates when there aren't any, while having a bundled update inside an XCI and an external update file.
|
- Fix repeated dialog popup notifying you of new updates when there aren't any, while having a bundled update inside an XCI and an external update file.
|
||||||
|
|
||||||
## 1.2.35 - 2024-10-21
|
## 1.2.35 - 2024-10-21
|
||||||
PR [#32](https://github.com/GreemDev/Ryujinx/pull/32)
|
PR [#32](https://web.archive.org/web/20241127010942/https://github.com/GreemDev/Ryujinx/pull/32)
|
||||||
### GUI:
|
### GUI:
|
||||||
- Replace "expand DRAM" option with a DRAM size dropdown.
|
- Replace "expand DRAM" option with a DRAM size dropdown.
|
||||||
- Allows for using mods which require a ridiculous amount of memory to allocate from.
|
- Allows for using mods which require a ridiculous amount of memory to allocate from.
|
||||||
|
|
||||||
## 1.2.34 - 2024-10-21
|
## 1.2.34 - 2024-10-21
|
||||||
PR [#29](https://github.com/GreemDev/Ryujinx/pull/29)
|
PR [#29](https://web.archive.org/web/20241125093029/https://github.com/GreemDev/Ryujinx/pull/29)
|
||||||
### GUI:
|
### GUI:
|
||||||
- Fix duplicate controller names when 2 controllers of the same type are connected.
|
- Fix duplicate controller names when 2 controllers of the same type are connected.
|
||||||
### INPUT:
|
### INPUT:
|
||||||
@@ -248,7 +248,7 @@ Added Low-power PPTC mode strings to the translation files.
|
|||||||
## 1.2.1-1.2.19 - 2024-10-08 - 2024-10-11
|
## 1.2.1-1.2.19 - 2024-10-08 - 2024-10-11
|
||||||
### GUI/INFRA/MISC:
|
### GUI/INFRA/MISC:
|
||||||
- Remove GTK UI.
|
- Remove GTK UI.
|
||||||
- Autoload DLC/Updates from dir ([#12](https://github.com/GreemDev/Ryujinx/pull/12)).
|
- Autoload DLC/Updates from dir ([#12](https://web.archive.org/web/20241127004005/https://github.com/GreemDev/Ryujinx/pull/12)).
|
||||||
- Changed executable icon to rainbow logo.
|
- Changed executable icon to rainbow logo.
|
||||||
- Extract Data > Logo now also extracts the square thumbnail you see for the game in the UI.
|
- Extract Data > Logo now also extracts the square thumbnail you see for the game in the UI.
|
||||||
- The "use random UUID hack" checkbox in the Amiibo screen now remembers its last state when you reopen the window in a given session.
|
- The "use random UUID hack" checkbox in the Amiibo screen now remembers its last state when you reopen the window in a given session.
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
<Project>
|
<Project>
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net9.0</TargetFramework>
|
<TargetFramework>net10.0</TargetFramework>
|
||||||
<LangVersion>latest</LangVersion>
|
<LangVersion>preview</LangVersion>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
@@ -19,8 +19,8 @@
|
|||||||
<PackageVersion Include="CommandLineParser" Version="2.9.1" />
|
<PackageVersion Include="CommandLineParser" Version="2.9.1" />
|
||||||
<PackageVersion Include="CommunityToolkit.Mvvm" Version="8.4.0"/>
|
<PackageVersion Include="CommunityToolkit.Mvvm" Version="8.4.0"/>
|
||||||
<PackageVersion Include="Concentus" Version="2.2.2" />
|
<PackageVersion Include="Concentus" Version="2.2.2" />
|
||||||
<PackageVersion Include="DiscordRichPresence" Version="1.2.1.24" />
|
<PackageVersion Include="DiscordRichPresence" Version="1.6.1.70" />
|
||||||
<PackageVersion Include="DynamicData" Version="9.0.4" />
|
<PackageVersion Include="DynamicData" Version="9.4.1" />
|
||||||
<PackageVersion Include="FluentAvaloniaUI" Version="2.0.5" />
|
<PackageVersion Include="FluentAvaloniaUI" Version="2.0.5" />
|
||||||
<PackageVersion Include="Humanizer" Version="2.14.1" />
|
<PackageVersion Include="Humanizer" Version="2.14.1" />
|
||||||
<PackageVersion Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.4" />
|
<PackageVersion Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.4" />
|
||||||
@@ -42,11 +42,11 @@
|
|||||||
<PackageVersion Include="Ryujinx.Graphics.Vulkan.Dependencies.MoltenVK" Version="1.2.0" />
|
<PackageVersion Include="Ryujinx.Graphics.Vulkan.Dependencies.MoltenVK" Version="1.2.0" />
|
||||||
<PackageVersion Include="Ryujinx.LibHac" Version="0.21.0-alpha.116" />
|
<PackageVersion Include="Ryujinx.LibHac" Version="0.21.0-alpha.116" />
|
||||||
<PackageVersion Include="Ryujinx.SDL2-CS" Version="2.30.0-build32" />
|
<PackageVersion Include="Ryujinx.SDL2-CS" Version="2.30.0-build32" />
|
||||||
<PackageVersion Include="Ryujinx.UpdateClient" Version="1.0.29" />
|
<PackageVersion Include="Ryujinx.UpdateClient" Version="1.0.44" />
|
||||||
<PackageVersion Include="Ryujinx.Systems.Update.Common" Version="1.0.29" />
|
<PackageVersion Include="Ryujinx.Systems.Update.Common" Version="1.0.44" />
|
||||||
<PackageVersion Include="Gommon" Version="2.7.1.1" />
|
<PackageVersion Include="Gommon" Version="2.7.2.1" />
|
||||||
<PackageVersion Include="securifybv.ShellLink" Version="0.1.0" />
|
<PackageVersion Include="securifybv.ShellLink" Version="0.1.0" />
|
||||||
<PackageVersion Include="Sep" Version="0.6.0" />
|
<PackageVersion Include="Sep" Version="0.11.1" />
|
||||||
<PackageVersion Include="shaderc.net" Version="0.1.0" />
|
<PackageVersion Include="shaderc.net" Version="0.1.0" />
|
||||||
<PackageVersion Include="SharpZipLib" Version="1.4.2" />
|
<PackageVersion Include="SharpZipLib" Version="1.4.2" />
|
||||||
<PackageVersion Include="Silk.NET.Vulkan" Version="2.22.0" />
|
<PackageVersion Include="Silk.NET.Vulkan" Version="2.22.0" />
|
||||||
|
@@ -85,6 +85,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
|
|||||||
.github\workflows\build.yml = .github\workflows\build.yml
|
.github\workflows\build.yml = .github\workflows\build.yml
|
||||||
.github\workflows\canary.yml = .github\workflows\canary.yml
|
.github\workflows\canary.yml = .github\workflows\canary.yml
|
||||||
Directory.Packages.props = Directory.Packages.props
|
Directory.Packages.props = Directory.Packages.props
|
||||||
|
Directory.Build.props = Directory.Build.props
|
||||||
.github\workflows\release.yml = .github\workflows\release.yml
|
.github\workflows\release.yml = .github\workflows\release.yml
|
||||||
nuget.config = nuget.config
|
nuget.config = nuget.config
|
||||||
EndProjectSection
|
EndProjectSection
|
||||||
|
3660
assets/locales.json
3660
assets/locales.json
File diff suppressed because it is too large
Load Diff
@@ -23,7 +23,7 @@ chmod +x AppDir/AppRun AppDir/usr/bin/Ryujinx*
|
|||||||
|
|
||||||
mkdir -p "$OUTDIR"
|
mkdir -p "$OUTDIR"
|
||||||
|
|
||||||
appimagetool --comp zstd --mksquashfs-opt -Xcompression-level --mksquashfs-opt 21 \
|
appimagetool -n --comp zstd --mksquashfs-opt -Xcompression-level --mksquashfs-opt 21 \
|
||||||
-u "$UFLAG" \
|
-u "$UFLAG" \
|
||||||
AppDir "$OUTDIR"/Ryujinx.AppImage
|
AppDir "$OUTDIR"/Ryujinx.AppImage
|
||||||
|
|
||||||
|
@@ -978,7 +978,7 @@
|
|||||||
0100416004C00000,"DOOM",gpu;slow;nvdec;online-broken,ingame,2024-09-23 15:40:07
|
0100416004C00000,"DOOM",gpu;slow;nvdec;online-broken,ingame,2024-09-23 15:40:07
|
||||||
010018900DD00000,"DOOM (1993)",nvdec;online-broken,menus,2022-09-06 13:32:19
|
010018900DD00000,"DOOM (1993)",nvdec;online-broken,menus,2022-09-06 13:32:19
|
||||||
01008CB01E52E000,"DOOM + DOOM II",opengl;ldn-untested;LAN,playable,2024-09-12 07:06:01
|
01008CB01E52E000,"DOOM + DOOM II",opengl;ldn-untested;LAN,playable,2024-09-12 07:06:01
|
||||||
010029D00E740000,"DOOM 3",crash,menus,2024-08-03 05:25:47
|
010029D00E740000,"DOOM 3",crash;slow,menus,2024-08-03 05:25:47
|
||||||
01005D700E742000,"DOOM 64",nvdec;vulkan,playable,2020-10-13 23:47:28
|
01005D700E742000,"DOOM 64",nvdec;vulkan,playable,2020-10-13 23:47:28
|
||||||
0100D4F00DD02000,"DOOM II (Classic)",nvdec;online,playable,2021-06-03 20:10:01
|
0100D4F00DD02000,"DOOM II (Classic)",nvdec;online,playable,2021-06-03 20:10:01
|
||||||
0100B1A00D8CE000,"DOOM® Eternal",gpu;slow;nvdec;online-broken,ingame,2024-08-28 15:57:17
|
0100B1A00D8CE000,"DOOM® Eternal",gpu;slow;nvdec;online-broken,ingame,2024-08-28 15:57:17
|
||||||
@@ -1097,7 +1097,7 @@
|
|||||||
0100F9600E746000,"ESP Ra.De. Psi",audio;slow,ingame,2024-03-07 15:05:08
|
0100F9600E746000,"ESP Ra.De. Psi",audio;slow,ingame,2024-03-07 15:05:08
|
||||||
010073000FE18000,"Esports powerful pro yakyuu 2020",gpu;crash;Needs More Attention,ingame,2024-04-29 05:34:14
|
010073000FE18000,"Esports powerful pro yakyuu 2020",gpu;crash;Needs More Attention,ingame,2024-04-29 05:34:14
|
||||||
01004F9012FD8000,"Estranged: The Departure",nvdec;UE4,playable,2022-10-24 10:37:58
|
01004F9012FD8000,"Estranged: The Departure",nvdec;UE4,playable,2022-10-24 10:37:58
|
||||||
010018f01e0a0000,"Eternights",,playable,2025-07-30 12:10:24
|
010018F01E0A0000,"Eternights",,playable,2025-07-30 12:10:24
|
||||||
0100CB900B498000,"Eternum Ex",,playable,2021-01-13 20:28:32
|
0100CB900B498000,"Eternum Ex",,playable,2021-01-13 20:28:32
|
||||||
010092501EB2C000,"Europa (Demo)",gpu;crash;UE4,ingame,2024-04-23 10:47:12
|
010092501EB2C000,"Europa (Demo)",gpu;crash;UE4,ingame,2024-04-23 10:47:12
|
||||||
01007BE0160D6000,"EVE ghost enemies",gpu,ingame,2023-01-14 03:13:30
|
01007BE0160D6000,"EVE ghost enemies",gpu,ingame,2023-01-14 03:13:30
|
||||||
@@ -1243,7 +1243,7 @@
|
|||||||
010003F00BD48000,"Friday the 13th: Killer Puzzle",,playable,2021-01-28 01:33:38
|
010003F00BD48000,"Friday the 13th: Killer Puzzle",,playable,2021-01-28 01:33:38
|
||||||
010092A00C4B6000,"Friday the 13th: The Game Ultimate Slasher Edition",nvdec;online-broken;UE4,playable,2022-09-06 17:33:27
|
010092A00C4B6000,"Friday the 13th: The Game Ultimate Slasher Edition",nvdec;online-broken;UE4,playable,2022-09-06 17:33:27
|
||||||
0100F200178F4000,"FRONT MISSION 1st: Remake",,playable,2023-06-09 07:44:24
|
0100F200178F4000,"FRONT MISSION 1st: Remake",,playable,2023-06-09 07:44:24
|
||||||
0100c4e018a24000,"FRONT MISSION 2: Remake",,playable,2025-07-30 12:11:23
|
0100C4E018A24000,"FRONT MISSION 2: Remake",,playable,2025-07-30 12:11:23
|
||||||
01007E6019872000,"FRONT MISSION 3: Remake",,playable,2025-07-30 12:12:02
|
01007E6019872000,"FRONT MISSION 3: Remake",,playable,2025-07-30 12:12:02
|
||||||
0100861012474000,"Frontline Zed",,playable,2020-10-03 12:55:59
|
0100861012474000,"Frontline Zed",,playable,2020-10-03 12:55:59
|
||||||
0100B5300B49A000,"Frost",,playable,2022-07-27 12:00:36
|
0100B5300B49A000,"Frost",,playable,2022-07-27 12:00:36
|
||||||
@@ -1440,6 +1440,7 @@
|
|||||||
0100C2700E338000,"Heroland",,playable,2020-08-05 15:35:39
|
0100C2700E338000,"Heroland",,playable,2020-08-05 15:35:39
|
||||||
01007AC00E012000,"HexaGravity",,playable,2021-05-28 13:47:48
|
01007AC00E012000,"HexaGravity",,playable,2021-05-28 13:47:48
|
||||||
01004E800F03C000,"Hidden",slow,ingame,2022-10-05 10:56:53
|
01004E800F03C000,"Hidden",slow,ingame,2022-10-05 10:56:53
|
||||||
|
0100C1101EE5A000,"High on Life",,menus,2025-08-26 19:11:00
|
||||||
0100F6A00A684000,"Higurashi no Naku Koro ni Hō",audio,ingame,2021-09-18 14:40:28
|
0100F6A00A684000,"Higurashi no Naku Koro ni Hō",audio,ingame,2021-09-18 14:40:28
|
||||||
0100F8D0129F4000,"Himehibi 1 gakki - Princess Days",crash,nothing,2021-11-03 08:34:19
|
0100F8D0129F4000,"Himehibi 1 gakki - Princess Days",crash,nothing,2021-11-03 08:34:19
|
||||||
0100F3D008436000,"Hiragana Pixel Party",,playable,2021-01-14 08:36:50
|
0100F3D008436000,"Hiragana Pixel Party",,playable,2021-01-14 08:36:50
|
||||||
@@ -1449,6 +1450,7 @@
|
|||||||
0100F7300ED2C000,"Hoggy2",,playable,2022-10-10 13:53:35
|
0100F7300ED2C000,"Hoggy2",,playable,2022-10-10 13:53:35
|
||||||
0100F7E00C70E000,"Hogwarts Legacy",UE4;slow,ingame,2024-09-03 19:53:58
|
0100F7E00C70E000,"Hogwarts Legacy",UE4;slow,ingame,2024-09-03 19:53:58
|
||||||
0100633007D48000,"Hollow Knight",nvdec,playable,2023-01-16 15:44:56
|
0100633007D48000,"Hollow Knight",nvdec,playable,2023-01-16 15:44:56
|
||||||
|
010013C00E930000,"Hollow Knight: Silksong",,playable,2025-09-04 17:23:22
|
||||||
0100F2100061E800,"Hollow0",UE4;gpu,ingame,2021-03-03 23:42:56
|
0100F2100061E800,"Hollow0",UE4;gpu,ingame,2021-03-03 23:42:56
|
||||||
0100342009E16000,"Holy Potatoes! What The Hell?!",,playable,2020-07-03 10:48:56
|
0100342009E16000,"Holy Potatoes! What The Hell?!",,playable,2020-07-03 10:48:56
|
||||||
010071B00C904000,"HoPiKo",,playable,2021-01-13 20:12:38
|
010071B00C904000,"HoPiKo",,playable,2021-01-13 20:12:38
|
||||||
@@ -1887,7 +1889,7 @@
|
|||||||
010097800EA20000,"Monster Energy Supercross - The Official Videogame 3",UE4;audout;nvdec;online,playable,2021-06-14 12:37:54
|
010097800EA20000,"Monster Energy Supercross - The Official Videogame 3",UE4;audout;nvdec;online,playable,2021-06-14 12:37:54
|
||||||
0100E9900ED74000,"Monster Farm",32-bit;nvdec,playable,2021-05-05 19:29:13
|
0100E9900ED74000,"Monster Farm",32-bit;nvdec,playable,2021-05-05 19:29:13
|
||||||
0100770008DD8000,"Monster Hunter Generations Ultimate™",32-bit;online-broken;ldn-works,playable,2024-03-18 14:35:36
|
0100770008DD8000,"Monster Hunter Generations Ultimate™",32-bit;online-broken;ldn-works,playable,2024-03-18 14:35:36
|
||||||
0100B04011742000,"Monster Hunter Rise",gpu;slow;crash;nvdec;online-broken;Needs Update;ldn-works,ingame,2024-08-24 11:04:59
|
0100B04011742000,"MONSTER HUNTER RISE",gpu;slow;crash;nvdec;online-broken;Needs Update;ldn-works,ingame,2024-08-24 11:04:59
|
||||||
010093A01305C000,"Monster Hunter Rise Demo",online-broken;ldn-works;demo,playable,2022-10-18 23:04:17
|
010093A01305C000,"Monster Hunter Rise Demo",online-broken;ldn-works;demo,playable,2022-10-18 23:04:17
|
||||||
0100E21011446000,"Monster Hunter Stories 2: Wings of Ruin",services,ingame,2022-07-10 19:27:30
|
0100E21011446000,"Monster Hunter Stories 2: Wings of Ruin",services,ingame,2022-07-10 19:27:30
|
||||||
010042501329E000,"MONSTER HUNTER STORIES 2: WINGS OF RUIN Trial Version",demo,playable,2022-11-13 22:20:26
|
010042501329E000,"MONSTER HUNTER STORIES 2: WINGS OF RUIN Trial Version",demo,playable,2022-11-13 22:20:26
|
||||||
@@ -2312,7 +2314,7 @@
|
|||||||
010077B00BDD8000,"Professional Farmer: Nintendo Switch™ Edition",slow,playable,2020-12-16 13:38:19
|
010077B00BDD8000,"Professional Farmer: Nintendo Switch™ Edition",slow,playable,2020-12-16 13:38:19
|
||||||
010018300C83A000,"Professor Lupo and his Horrible Pets",,playable,2020-06-12 00:08:45
|
010018300C83A000,"Professor Lupo and his Horrible Pets",,playable,2020-06-12 00:08:45
|
||||||
0100D1F0132F6000,"Professor Lupo: Ocean",,playable,2021-04-14 16:33:33
|
0100D1F0132F6000,"Professor Lupo: Ocean",,playable,2021-04-14 16:33:33
|
||||||
0100c3a017834000,"Prodeus",,playable,2025-07-30 12:07:52
|
0100C3A017834000,"Prodeus",,playable,2025-07-30 12:07:52
|
||||||
0100BBD00976C000,"Project Highrise: Architect's Edition",,playable,2022-08-10 17:19:12
|
0100BBD00976C000,"Project Highrise: Architect's Edition",,playable,2022-08-10 17:19:12
|
||||||
0100ACE00DAB6000,"Project Nimbus: Complete Edition",nvdec;UE4;vulkan-backend-bug,playable,2022-08-10 17:35:43
|
0100ACE00DAB6000,"Project Nimbus: Complete Edition",nvdec;UE4;vulkan-backend-bug,playable,2022-08-10 17:35:43
|
||||||
01002980140F6000,"Project TRIANGLE STRATEGY™ Debut Demo",UE4;demo,playable,2022-10-24 21:40:27
|
01002980140F6000,"Project TRIANGLE STRATEGY™ Debut Demo",UE4;demo,playable,2022-10-24 21:40:27
|
||||||
@@ -2578,6 +2580,7 @@
|
|||||||
0100C610154CA000,"Shadowrun: Hong Kong - Extended Edition",gpu;Needs Update,ingame,2022-10-04 20:53:09
|
0100C610154CA000,"Shadowrun: Hong Kong - Extended Edition",gpu;Needs Update,ingame,2022-10-04 20:53:09
|
||||||
010000000EEF0000,"Shadows 2: Perfidia",,playable,2020-08-07 12:43:46
|
010000000EEF0000,"Shadows 2: Perfidia",,playable,2020-08-07 12:43:46
|
||||||
0100AD700CBBE000,"Shadows of Adam",,playable,2021-01-11 13:35:58
|
0100AD700CBBE000,"Shadows of Adam",,playable,2021-01-11 13:35:58
|
||||||
|
010037A01F96C000,"Shadows of the Damned: Hella Remastered",,playable,2025-09-05 11:34:32
|
||||||
01002A800C064000,"Shadowverse Champions Battle",,playable,2022-10-02 22:59:29
|
01002A800C064000,"Shadowverse Champions Battle",,playable,2022-10-02 22:59:29
|
||||||
01003B90136DA000,"Shadowverse: Champion's Battle",crash,nothing,2023-03-06 00:31:50
|
01003B90136DA000,"Shadowverse: Champion's Battle",crash,nothing,2023-03-06 00:31:50
|
||||||
0100820013612000,"Shady Part of Me",,playable,2022-10-20 11:31:55
|
0100820013612000,"Shady Part of Me",,playable,2022-10-20 11:31:55
|
||||||
@@ -2976,6 +2979,7 @@
|
|||||||
0100EBA01548E000,"The Cruel King and the Great Hero",gpu;services,ingame,2022-12-02 07:02:08
|
0100EBA01548E000,"The Cruel King and the Great Hero",gpu;services,ingame,2022-12-02 07:02:08
|
||||||
010051800E922000,"The Dark Crystal: Age of Resistance Tactics",,playable,2020-08-11 13:43:41
|
010051800E922000,"The Dark Crystal: Age of Resistance Tactics",,playable,2020-08-11 13:43:41
|
||||||
01003DE00918E000,"The Darkside Detective",,playable,2020-06-03 22:16:18
|
01003DE00918E000,"The Darkside Detective",,playable,2020-06-03 22:16:18
|
||||||
|
010032B015D66000,"The DioField Chronicle",,playable,2025-09-05 11:35:50
|
||||||
01000A10041EA000,"The Elder Scrolls V: Skyrim",gpu;crash,ingame,2024-07-14 03:21:31
|
01000A10041EA000,"The Elder Scrolls V: Skyrim",gpu;crash,ingame,2024-07-14 03:21:31
|
||||||
01004A9006B84000,"The End Is Nigh",,playable,2020-06-01 11:26:45
|
01004A9006B84000,"The End Is Nigh",,playable,2020-06-01 11:26:45
|
||||||
0100CA100489C000,"The Escapists 2",nvdec,playable,2020-09-24 12:31:31
|
0100CA100489C000,"The Escapists 2",nvdec,playable,2020-09-24 12:31:31
|
||||||
|
|
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"sdk": {
|
"sdk": {
|
||||||
"version": "9.0.100",
|
"version": "10.0.100",
|
||||||
"rollForward": "latestFeature"
|
"rollForward": "latestFeature"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -25,9 +25,9 @@ namespace ARMeilleure.CodeGen.Arm64
|
|||||||
|
|
||||||
static class ComparisonArm64Extensions
|
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
|
#pragma warning disable IDE0055 // Disable formatting
|
||||||
Comparison.Equal => ArmCondition.Eq,
|
Comparison.Equal => ArmCondition.Eq,
|
||||||
@@ -42,7 +42,7 @@ namespace ARMeilleure.CodeGen.Arm64
|
|||||||
Comparison.LessUI => ArmCondition.LtUn,
|
Comparison.LessUI => ArmCondition.LtUn,
|
||||||
#pragma warning restore IDE0055
|
#pragma warning restore IDE0055
|
||||||
|
|
||||||
_ => throw new ArgumentException(null, nameof(comp)),
|
_ => throw new ArgumentException(null, nameof(comparison))
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -181,10 +181,10 @@ namespace ARMeilleure.CodeGen.Arm64
|
|||||||
|
|
||||||
public void Fmov(Operand rd, Operand rn, bool topHalf)
|
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);
|
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 rmode = topHalf ? 1u << 19 : 0u;
|
||||||
uint ftype = rd.Type == OperandType.FP64 || rn.Type == OperandType.FP64 ? 1u << 22 : 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)
|
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);
|
Orr(rd, Factory.Register(ZrRegister, RegisterType.Integer, rd.Type), rn);
|
||||||
}
|
}
|
||||||
@@ -973,7 +973,7 @@ namespace ARMeilleure.CodeGen.Arm64
|
|||||||
uint instruction;
|
uint instruction;
|
||||||
int scale;
|
int scale;
|
||||||
|
|
||||||
if (type.IsInteger())
|
if (type.IsInteger)
|
||||||
{
|
{
|
||||||
instruction = intInst;
|
instruction = intInst;
|
||||||
|
|
||||||
@@ -1009,7 +1009,7 @@ namespace ARMeilleure.CodeGen.Arm64
|
|||||||
{
|
{
|
||||||
uint instruction;
|
uint instruction;
|
||||||
|
|
||||||
if (type.IsInteger())
|
if (type.IsInteger)
|
||||||
{
|
{
|
||||||
instruction = intInst;
|
instruction = intInst;
|
||||||
|
|
||||||
|
@@ -250,7 +250,7 @@ namespace ARMeilleure.CodeGen.Arm64
|
|||||||
|
|
||||||
// ValidateBinOp(dest, src1, src2);
|
// ValidateBinOp(dest, src1, src2);
|
||||||
|
|
||||||
if (dest.Type.IsInteger())
|
if (dest.Type.IsInteger)
|
||||||
{
|
{
|
||||||
context.Assembler.Add(dest, src1, src2);
|
context.Assembler.Add(dest, src1, src2);
|
||||||
}
|
}
|
||||||
@@ -268,7 +268,7 @@ namespace ARMeilleure.CodeGen.Arm64
|
|||||||
|
|
||||||
ValidateBinOp(dest, src1, src2);
|
ValidateBinOp(dest, src1, src2);
|
||||||
|
|
||||||
Debug.Assert(dest.Type.IsInteger());
|
Debug.Assert(dest.Type.IsInteger);
|
||||||
|
|
||||||
context.Assembler.And(dest, src1, src2);
|
context.Assembler.And(dest, src1, src2);
|
||||||
}
|
}
|
||||||
@@ -281,7 +281,7 @@ namespace ARMeilleure.CodeGen.Arm64
|
|||||||
|
|
||||||
ValidateBinOp(dest, src1, src2);
|
ValidateBinOp(dest, src1, src2);
|
||||||
|
|
||||||
if (dest.Type.IsInteger())
|
if (dest.Type.IsInteger)
|
||||||
{
|
{
|
||||||
context.Assembler.Eor(dest, src1, src2);
|
context.Assembler.Eor(dest, src1, src2);
|
||||||
}
|
}
|
||||||
@@ -298,7 +298,7 @@ namespace ARMeilleure.CodeGen.Arm64
|
|||||||
|
|
||||||
ValidateUnOp(dest, source);
|
ValidateUnOp(dest, source);
|
||||||
|
|
||||||
Debug.Assert(dest.Type.IsInteger());
|
Debug.Assert(dest.Type.IsInteger);
|
||||||
|
|
||||||
context.Assembler.Mvn(dest, source);
|
context.Assembler.Mvn(dest, source);
|
||||||
}
|
}
|
||||||
@@ -311,7 +311,7 @@ namespace ARMeilleure.CodeGen.Arm64
|
|||||||
|
|
||||||
ValidateBinOp(dest, src1, src2);
|
ValidateBinOp(dest, src1, src2);
|
||||||
|
|
||||||
Debug.Assert(dest.Type.IsInteger());
|
Debug.Assert(dest.Type.IsInteger);
|
||||||
|
|
||||||
context.Assembler.Orr(dest, src1, src2);
|
context.Assembler.Orr(dest, src1, src2);
|
||||||
}
|
}
|
||||||
@@ -322,7 +322,7 @@ namespace ARMeilleure.CodeGen.Arm64
|
|||||||
|
|
||||||
Debug.Assert(comp.Kind == OperandKind.Constant);
|
Debug.Assert(comp.Kind == OperandKind.Constant);
|
||||||
|
|
||||||
ArmCondition cond = ((Comparison)comp.AsInt32()).ToArmCondition();
|
ArmCondition cond = ((Comparison)comp.AsInt32()).Arm;
|
||||||
|
|
||||||
GenerateCompareCommon(context, operation);
|
GenerateCompareCommon(context, operation);
|
||||||
|
|
||||||
@@ -336,7 +336,7 @@ namespace ARMeilleure.CodeGen.Arm64
|
|||||||
|
|
||||||
ValidateUnOp(dest, source);
|
ValidateUnOp(dest, source);
|
||||||
|
|
||||||
Debug.Assert(dest.Type.IsInteger());
|
Debug.Assert(dest.Type.IsInteger);
|
||||||
|
|
||||||
context.Assembler.Rev(dest, source);
|
context.Assembler.Rev(dest, source);
|
||||||
}
|
}
|
||||||
@@ -354,7 +354,7 @@ namespace ARMeilleure.CodeGen.Arm64
|
|||||||
Debug.Assert(dest.Type == OperandType.I32);
|
Debug.Assert(dest.Type == OperandType.I32);
|
||||||
Debug.Assert(comp.Kind == OperandKind.Constant);
|
Debug.Assert(comp.Kind == OperandKind.Constant);
|
||||||
|
|
||||||
ArmCondition cond = ((Comparison)comp.AsInt32()).ToArmCondition();
|
ArmCondition cond = ((Comparison)comp.AsInt32()).Arm;
|
||||||
|
|
||||||
GenerateCompareCommon(context, operation);
|
GenerateCompareCommon(context, operation);
|
||||||
|
|
||||||
@@ -428,7 +428,7 @@ namespace ARMeilleure.CodeGen.Arm64
|
|||||||
|
|
||||||
EnsureSameType(src1, src2);
|
EnsureSameType(src1, src2);
|
||||||
|
|
||||||
Debug.Assert(src1.Type.IsInteger());
|
Debug.Assert(src1.Type.IsInteger);
|
||||||
|
|
||||||
context.Assembler.Cmp(src1, src2);
|
context.Assembler.Cmp(src1, src2);
|
||||||
}
|
}
|
||||||
@@ -442,7 +442,7 @@ namespace ARMeilleure.CodeGen.Arm64
|
|||||||
|
|
||||||
EnsureSameType(dest, src2, src3);
|
EnsureSameType(dest, src2, src3);
|
||||||
|
|
||||||
Debug.Assert(dest.Type.IsInteger());
|
Debug.Assert(dest.Type.IsInteger);
|
||||||
Debug.Assert(src1.Type == OperandType.I32);
|
Debug.Assert(src1.Type == OperandType.I32);
|
||||||
|
|
||||||
context.Assembler.Cmp(src1, Const(src1.Type, 0));
|
context.Assembler.Cmp(src1, Const(src1.Type, 0));
|
||||||
@@ -468,7 +468,7 @@ namespace ARMeilleure.CodeGen.Arm64
|
|||||||
Debug.Assert(dest.Type != source.Type);
|
Debug.Assert(dest.Type != source.Type);
|
||||||
Debug.Assert(source.Type != OperandType.V128);
|
Debug.Assert(source.Type != OperandType.V128);
|
||||||
|
|
||||||
if (source.Type.IsInteger())
|
if (source.Type.IsInteger)
|
||||||
{
|
{
|
||||||
context.Assembler.ScvtfScalar(dest, source);
|
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 is OperandType.FP32 or OperandType.FP64);
|
||||||
Debug.Assert(dest.Type != source.Type);
|
Debug.Assert(dest.Type != source.Type);
|
||||||
Debug.Assert(source.Type.IsInteger());
|
Debug.Assert(source.Type.IsInteger);
|
||||||
|
|
||||||
context.Assembler.UcvtfScalar(dest, source);
|
context.Assembler.UcvtfScalar(dest, source);
|
||||||
}
|
}
|
||||||
@@ -497,7 +497,7 @@ namespace ARMeilleure.CodeGen.Arm64
|
|||||||
|
|
||||||
EnsureSameType(dest, source);
|
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.
|
// Moves to the same register are useless.
|
||||||
if (dest.Kind == source.Kind && dest.Value == source.Value)
|
if (dest.Kind == source.Kind && dest.Value == source.Value)
|
||||||
@@ -529,7 +529,7 @@ namespace ARMeilleure.CodeGen.Arm64
|
|||||||
|
|
||||||
EnsureSameType(dest, source);
|
EnsureSameType(dest, source);
|
||||||
|
|
||||||
Debug.Assert(dest.Type.IsInteger());
|
Debug.Assert(dest.Type.IsInteger);
|
||||||
|
|
||||||
context.Assembler.Clz(dest, source);
|
context.Assembler.Clz(dest, source);
|
||||||
}
|
}
|
||||||
@@ -542,7 +542,7 @@ namespace ARMeilleure.CodeGen.Arm64
|
|||||||
|
|
||||||
ValidateBinOp(dest, dividend, divisor);
|
ValidateBinOp(dest, dividend, divisor);
|
||||||
|
|
||||||
if (dest.Type.IsInteger())
|
if (dest.Type.IsInteger)
|
||||||
{
|
{
|
||||||
context.Assembler.Sdiv(dest, dividend, divisor);
|
context.Assembler.Sdiv(dest, dividend, divisor);
|
||||||
}
|
}
|
||||||
@@ -576,7 +576,7 @@ namespace ARMeilleure.CodeGen.Arm64
|
|||||||
Operand value = operation.Destination;
|
Operand value = operation.Destination;
|
||||||
Operand address = operation.GetSource(0);
|
Operand address = operation.GetSource(0);
|
||||||
|
|
||||||
Debug.Assert(value.Type.IsInteger());
|
Debug.Assert(value.Type.IsInteger);
|
||||||
|
|
||||||
context.Assembler.LdrhRiUn(value, address, 0);
|
context.Assembler.LdrhRiUn(value, address, 0);
|
||||||
}
|
}
|
||||||
@@ -586,7 +586,7 @@ namespace ARMeilleure.CodeGen.Arm64
|
|||||||
Operand value = operation.Destination;
|
Operand value = operation.Destination;
|
||||||
Operand address = operation.GetSource(0);
|
Operand address = operation.GetSource(0);
|
||||||
|
|
||||||
Debug.Assert(value.Type.IsInteger());
|
Debug.Assert(value.Type.IsInteger);
|
||||||
|
|
||||||
context.Assembler.LdrbRiUn(value, address, 0);
|
context.Assembler.LdrbRiUn(value, address, 0);
|
||||||
}
|
}
|
||||||
@@ -604,7 +604,7 @@ namespace ARMeilleure.CodeGen.Arm64
|
|||||||
|
|
||||||
EnsureSameType(dest, src1, src2);
|
EnsureSameType(dest, src1, src2);
|
||||||
|
|
||||||
if (dest.Type.IsInteger())
|
if (dest.Type.IsInteger)
|
||||||
{
|
{
|
||||||
context.Assembler.Mul(dest, src1, src2);
|
context.Assembler.Mul(dest, src1, src2);
|
||||||
}
|
}
|
||||||
@@ -647,7 +647,7 @@ namespace ARMeilleure.CodeGen.Arm64
|
|||||||
|
|
||||||
ValidateUnOp(dest, source);
|
ValidateUnOp(dest, source);
|
||||||
|
|
||||||
if (dest.Type.IsInteger())
|
if (dest.Type.IsInteger)
|
||||||
{
|
{
|
||||||
context.Assembler.Neg(dest, source);
|
context.Assembler.Neg(dest, source);
|
||||||
}
|
}
|
||||||
@@ -732,7 +732,7 @@ namespace ARMeilleure.CodeGen.Arm64
|
|||||||
Operand dest = operation.Destination;
|
Operand dest = operation.Destination;
|
||||||
Operand source = operation.GetSource(0);
|
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);
|
context.Assembler.Sxth(dest, source);
|
||||||
}
|
}
|
||||||
@@ -742,7 +742,7 @@ namespace ARMeilleure.CodeGen.Arm64
|
|||||||
Operand dest = operation.Destination;
|
Operand dest = operation.Destination;
|
||||||
Operand source = operation.GetSource(0);
|
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);
|
context.Assembler.Sxtw(dest, source);
|
||||||
}
|
}
|
||||||
@@ -752,7 +752,7 @@ namespace ARMeilleure.CodeGen.Arm64
|
|||||||
Operand dest = operation.Destination;
|
Operand dest = operation.Destination;
|
||||||
Operand source = operation.GetSource(0);
|
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);
|
context.Assembler.Sxtb(dest, source);
|
||||||
}
|
}
|
||||||
@@ -823,7 +823,7 @@ namespace ARMeilleure.CodeGen.Arm64
|
|||||||
Operand value = operation.GetSource(1);
|
Operand value = operation.GetSource(1);
|
||||||
Operand address = operation.GetSource(0);
|
Operand address = operation.GetSource(0);
|
||||||
|
|
||||||
Debug.Assert(value.Type.IsInteger());
|
Debug.Assert(value.Type.IsInteger);
|
||||||
|
|
||||||
context.Assembler.StrhRiUn(value, address, 0);
|
context.Assembler.StrhRiUn(value, address, 0);
|
||||||
}
|
}
|
||||||
@@ -833,7 +833,7 @@ namespace ARMeilleure.CodeGen.Arm64
|
|||||||
Operand value = operation.GetSource(1);
|
Operand value = operation.GetSource(1);
|
||||||
Operand address = operation.GetSource(0);
|
Operand address = operation.GetSource(0);
|
||||||
|
|
||||||
Debug.Assert(value.Type.IsInteger());
|
Debug.Assert(value.Type.IsInteger);
|
||||||
|
|
||||||
context.Assembler.StrbRiUn(value, address, 0);
|
context.Assembler.StrbRiUn(value, address, 0);
|
||||||
}
|
}
|
||||||
@@ -858,7 +858,7 @@ namespace ARMeilleure.CodeGen.Arm64
|
|||||||
|
|
||||||
// ValidateBinOp(dest, src1, src2);
|
// ValidateBinOp(dest, src1, src2);
|
||||||
|
|
||||||
if (dest.Type.IsInteger())
|
if (dest.Type.IsInteger)
|
||||||
{
|
{
|
||||||
context.Assembler.Sub(dest, src1, src2);
|
context.Assembler.Sub(dest, src1, src2);
|
||||||
}
|
}
|
||||||
@@ -882,7 +882,7 @@ namespace ARMeilleure.CodeGen.Arm64
|
|||||||
|
|
||||||
if (dest != default)
|
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;
|
OperandType destType = source.Type == OperandType.I64 ? OperandType.FP64 : OperandType.FP32;
|
||||||
|
|
||||||
@@ -901,9 +901,9 @@ namespace ARMeilleure.CodeGen.Arm64
|
|||||||
|
|
||||||
byte index = src2.AsByte();
|
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);
|
context.Assembler.Umov(dest, src1, index, dest.Type == OperandType.I64 ? 3 : 2);
|
||||||
}
|
}
|
||||||
@@ -959,7 +959,7 @@ namespace ARMeilleure.CodeGen.Arm64
|
|||||||
|
|
||||||
byte index = src3.AsByte();
|
byte index = src3.AsByte();
|
||||||
|
|
||||||
if (src2.Type.IsInteger())
|
if (src2.Type.IsInteger)
|
||||||
{
|
{
|
||||||
context.Assembler.Ins(dest, src2, index, src2.Type == OperandType.I64 ? 3 : 2);
|
context.Assembler.Ins(dest, src2, index, src2.Type == OperandType.I64 ? 3 : 2);
|
||||||
}
|
}
|
||||||
@@ -1007,7 +1007,7 @@ namespace ARMeilleure.CodeGen.Arm64
|
|||||||
{
|
{
|
||||||
Operand dest = operation.Destination;
|
Operand dest = operation.Destination;
|
||||||
|
|
||||||
Debug.Assert(!dest.Type.IsInteger());
|
Debug.Assert(!dest.Type.IsInteger);
|
||||||
|
|
||||||
context.Assembler.CmeqVector(dest, dest, dest, 2);
|
context.Assembler.CmeqVector(dest, dest, dest, 2);
|
||||||
}
|
}
|
||||||
@@ -1016,7 +1016,7 @@ namespace ARMeilleure.CodeGen.Arm64
|
|||||||
{
|
{
|
||||||
Operand dest = operation.Destination;
|
Operand dest = operation.Destination;
|
||||||
|
|
||||||
Debug.Assert(!dest.Type.IsInteger());
|
Debug.Assert(!dest.Type.IsInteger);
|
||||||
|
|
||||||
context.Assembler.EorVector(dest, dest, dest);
|
context.Assembler.EorVector(dest, dest, dest);
|
||||||
}
|
}
|
||||||
@@ -1046,7 +1046,7 @@ namespace ARMeilleure.CodeGen.Arm64
|
|||||||
Operand dest = operation.Destination;
|
Operand dest = operation.Destination;
|
||||||
Operand source = operation.GetSource(0);
|
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);
|
context.Assembler.Uxth(dest, source);
|
||||||
}
|
}
|
||||||
@@ -1056,7 +1056,7 @@ namespace ARMeilleure.CodeGen.Arm64
|
|||||||
Operand dest = operation.Destination;
|
Operand dest = operation.Destination;
|
||||||
Operand source = operation.GetSource(0);
|
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.
|
// 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)
|
if (dest.Value == source.Value && source.Type == OperandType.I32)
|
||||||
@@ -1072,7 +1072,7 @@ namespace ARMeilleure.CodeGen.Arm64
|
|||||||
Operand dest = operation.Destination;
|
Operand dest = operation.Destination;
|
||||||
Operand source = operation.GetSource(0);
|
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);
|
context.Assembler.Uxtb(dest, source);
|
||||||
}
|
}
|
||||||
@@ -1169,7 +1169,7 @@ namespace ARMeilleure.CodeGen.Arm64
|
|||||||
context.Assembler.StrRiPre(Register(reg, type), Register(SpRegister), -calleeSaveRegionSize);
|
context.Assembler.StrRiPre(Register(reg, type), Register(SpRegister), -calleeSaveRegionSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
offset += type.GetSizeInBytes();
|
offset += type.ByteSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (mask != 0)
|
while (mask != 0)
|
||||||
@@ -1195,7 +1195,7 @@ namespace ARMeilleure.CodeGen.Arm64
|
|||||||
context.Assembler.StpRiPre(Register(reg, type), Register(reg2, type), Register(SpRegister), -calleeSaveRegionSize);
|
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);
|
mask &= ~(1 << reg2);
|
||||||
|
|
||||||
offset -= type.GetSizeInBytes() * 2;
|
offset -= type.ByteSize * 2;
|
||||||
|
|
||||||
if (offset != 0)
|
if (offset != 0)
|
||||||
{
|
{
|
||||||
@@ -1286,7 +1286,7 @@ namespace ARMeilleure.CodeGen.Arm64
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
offset -= type.GetSizeInBytes();
|
offset -= type.ByteSize;
|
||||||
|
|
||||||
if (offset != 0)
|
if (offset != 0)
|
||||||
{
|
{
|
||||||
@@ -1435,12 +1435,12 @@ namespace ARMeilleure.CodeGen.Arm64
|
|||||||
|
|
||||||
OperandType valueType = GetMemOpValueType(currentOp);
|
OperandType valueType = GetMemOpValueType(currentOp);
|
||||||
|
|
||||||
if (valueType != GetMemOpValueType(nextOp) || op1Offset + valueType.GetSizeInBytes() != op2Offset)
|
if (valueType != GetMemOpValueType(nextOp) || op1Offset + valueType.ByteSize != op2Offset)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!CodeGenCommon.ConstFitsOnSImm7(op1Offset, valueType.GetSizeInBytesLog2()))
|
if (!CodeGenCommon.ConstFitsOnSImm7(op1Offset, valueType.ByteSizeLog2))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -1549,7 +1549,7 @@ namespace ARMeilleure.CodeGen.Arm64
|
|||||||
// EnsureSameReg (dest, src1);
|
// EnsureSameReg (dest, src1);
|
||||||
EnsureSameType(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)
|
private static void EnsureSameReg(Operand op1, Operand op2)
|
||||||
|
@@ -462,7 +462,7 @@ namespace ARMeilleure.CodeGen.Arm64
|
|||||||
{
|
{
|
||||||
instruction |= (sz << 22);
|
instruction |= (sz << 22);
|
||||||
|
|
||||||
if (rd.Type.IsInteger())
|
if (rd.Type.IsInteger)
|
||||||
{
|
{
|
||||||
context.Assembler.WriteInstructionAuto(instruction, rd, rn);
|
context.Assembler.WriteInstructionAuto(instruction, rd, rn);
|
||||||
}
|
}
|
||||||
@@ -490,7 +490,7 @@ namespace ARMeilleure.CodeGen.Arm64
|
|||||||
instruction |= (sz << 22);
|
instruction |= (sz << 22);
|
||||||
instruction |= (64 - fBits) << 10;
|
instruction |= (64 - fBits) << 10;
|
||||||
|
|
||||||
if (rd.Type.IsInteger())
|
if (rd.Type.IsInteger)
|
||||||
{
|
{
|
||||||
Debug.Assert(rd.Type != OperandType.I32 || fBits <= 32);
|
Debug.Assert(rd.Type != OperandType.I32 || fBits <= 32);
|
||||||
|
|
||||||
|
@@ -112,7 +112,7 @@ namespace ARMeilleure.CodeGen.Arm64
|
|||||||
|
|
||||||
if (src1.Kind == OperandKind.Constant)
|
if (src1.Kind == OperandKind.Constant)
|
||||||
{
|
{
|
||||||
if (!src1.Type.IsInteger())
|
if (!src1.Type.IsInteger)
|
||||||
{
|
{
|
||||||
// Handle non-integer types (FP32, FP64 and V128).
|
// Handle non-integer types (FP32, FP64 and V128).
|
||||||
// For instructions without an immediate operand, we do the following:
|
// 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.Kind == OperandKind.Constant)
|
||||||
{
|
{
|
||||||
if (!src2.Type.IsInteger())
|
if (!src2.Type.IsInteger)
|
||||||
{
|
{
|
||||||
src2 = AddFloatConstantCopy(constants, nodes, node, src2);
|
src2 = AddFloatConstantCopy(constants, nodes, node, src2);
|
||||||
|
|
||||||
@@ -191,7 +191,7 @@ namespace ARMeilleure.CodeGen.Arm64
|
|||||||
|
|
||||||
if (src.Kind == OperandKind.Constant)
|
if (src.Kind == OperandKind.Constant)
|
||||||
{
|
{
|
||||||
if (!src.Type.IsInteger())
|
if (!src.Type.IsInteger)
|
||||||
{
|
{
|
||||||
src = AddFloatConstantCopy(constants, nodes, node, src);
|
src = AddFloatConstantCopy(constants, nodes, node, src);
|
||||||
|
|
||||||
@@ -282,7 +282,7 @@ namespace ARMeilleure.CodeGen.Arm64
|
|||||||
|
|
||||||
bool passOnReg;
|
bool passOnReg;
|
||||||
|
|
||||||
if (source.Type.IsInteger())
|
if (source.Type.IsInteger)
|
||||||
{
|
{
|
||||||
passOnReg = intCount < intMax;
|
passOnReg = intCount < intMax;
|
||||||
}
|
}
|
||||||
@@ -309,7 +309,7 @@ namespace ARMeilleure.CodeGen.Arm64
|
|||||||
|
|
||||||
if (passOnReg)
|
if (passOnReg)
|
||||||
{
|
{
|
||||||
Operand argReg = source.Type.IsInteger()
|
Operand argReg = source.Type.IsInteger
|
||||||
? Gpr(CallingConvention.GetIntArgumentRegister(intCount++), source.Type)
|
? Gpr(CallingConvention.GetIntArgumentRegister(intCount++), source.Type)
|
||||||
: Xmm(CallingConvention.GetVecArgumentRegister(vecCount++), source.Type);
|
: Xmm(CallingConvention.GetVecArgumentRegister(vecCount++), source.Type);
|
||||||
|
|
||||||
@@ -327,7 +327,7 @@ namespace ARMeilleure.CodeGen.Arm64
|
|||||||
|
|
||||||
InsertConstantRegCopies(constants, nodes, nodes.AddBefore(node, spillOp));
|
InsertConstantRegCopies(constants, nodes, nodes.AddBefore(node, spillOp));
|
||||||
|
|
||||||
stackOffset += source.Type.GetSizeInBytes();
|
stackOffset += source.Type.ByteSize;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -345,7 +345,7 @@ namespace ARMeilleure.CodeGen.Arm64
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Operand retReg = dest.Type.IsInteger()
|
Operand retReg = dest.Type.IsInteger
|
||||||
? Gpr(CallingConvention.GetIntReturnRegister(), dest.Type)
|
? Gpr(CallingConvention.GetIntReturnRegister(), dest.Type)
|
||||||
: Xmm(CallingConvention.GetVecReturnRegister(), dest.Type);
|
: Xmm(CallingConvention.GetVecReturnRegister(), dest.Type);
|
||||||
|
|
||||||
@@ -385,7 +385,7 @@ namespace ARMeilleure.CodeGen.Arm64
|
|||||||
|
|
||||||
bool passOnReg;
|
bool passOnReg;
|
||||||
|
|
||||||
if (source.Type.IsInteger())
|
if (source.Type.IsInteger)
|
||||||
{
|
{
|
||||||
passOnReg = intCount + 1 < intMax;
|
passOnReg = intCount + 1 < intMax;
|
||||||
}
|
}
|
||||||
@@ -408,7 +408,7 @@ namespace ARMeilleure.CodeGen.Arm64
|
|||||||
|
|
||||||
if (passOnReg)
|
if (passOnReg)
|
||||||
{
|
{
|
||||||
Operand argReg = source.Type.IsInteger()
|
Operand argReg = source.Type.IsInteger
|
||||||
? Gpr(CallingConvention.GetIntArgumentRegister(intCount++), source.Type)
|
? Gpr(CallingConvention.GetIntArgumentRegister(intCount++), source.Type)
|
||||||
: Xmm(CallingConvention.GetVecArgumentRegister(vecCount++), source.Type);
|
: Xmm(CallingConvention.GetVecArgumentRegister(vecCount++), source.Type);
|
||||||
|
|
||||||
@@ -521,7 +521,7 @@ namespace ARMeilleure.CodeGen.Arm64
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Operand retReg = source.Type.IsInteger()
|
Operand retReg = source.Type.IsInteger
|
||||||
? Gpr(CallingConvention.GetIntReturnRegister(), source.Type)
|
? Gpr(CallingConvention.GetIntReturnRegister(), source.Type)
|
||||||
: Xmm(CallingConvention.GetVecReturnRegister(), source.Type);
|
: Xmm(CallingConvention.GetVecReturnRegister(), source.Type);
|
||||||
|
|
||||||
@@ -551,7 +551,7 @@ namespace ARMeilleure.CodeGen.Arm64
|
|||||||
{
|
{
|
||||||
OperandType argType = cctx.FuncArgTypes[cIndex];
|
OperandType argType = cctx.FuncArgTypes[cIndex];
|
||||||
|
|
||||||
if (argType.IsInteger())
|
if (argType.IsInteger)
|
||||||
{
|
{
|
||||||
intCount++;
|
intCount++;
|
||||||
}
|
}
|
||||||
@@ -567,7 +567,7 @@ namespace ARMeilleure.CodeGen.Arm64
|
|||||||
|
|
||||||
bool passOnReg;
|
bool passOnReg;
|
||||||
|
|
||||||
if (source.Type.IsInteger())
|
if (source.Type.IsInteger)
|
||||||
{
|
{
|
||||||
passOnReg = intCount < CallingConvention.GetArgumentsOnRegsCount();
|
passOnReg = intCount < CallingConvention.GetArgumentsOnRegsCount();
|
||||||
}
|
}
|
||||||
@@ -606,7 +606,7 @@ namespace ARMeilleure.CodeGen.Arm64
|
|||||||
{
|
{
|
||||||
Operand pArg = Local(dest.Type);
|
Operand pArg = Local(dest.Type);
|
||||||
|
|
||||||
Operand argReg = dest.Type.IsInteger()
|
Operand argReg = dest.Type.IsInteger
|
||||||
? Gpr(CallingConvention.GetIntArgumentRegister(intCount), dest.Type)
|
? Gpr(CallingConvention.GetIntArgumentRegister(intCount), dest.Type)
|
||||||
: Xmm(CallingConvention.GetVecArgumentRegister(vecCount), dest.Type);
|
: Xmm(CallingConvention.GetVecArgumentRegister(vecCount), dest.Type);
|
||||||
|
|
||||||
|
@@ -51,7 +51,7 @@ namespace ARMeilleure.CodeGen.Optimizations
|
|||||||
if (trueSucc == block.ListNext)
|
if (trueSucc == block.ListNext)
|
||||||
{
|
{
|
||||||
Comparison comp = (Comparison)branchOp.GetSource(2).AsInt32();
|
Comparison comp = (Comparison)branchOp.GetSource(2).AsInt32();
|
||||||
Comparison compInv = comp.Invert();
|
Comparison compInv = comp.Inverse;
|
||||||
|
|
||||||
branchOp.SetSource(2, Const((int)compInv));
|
branchOp.SetSource(2, Const((int)compInv));
|
||||||
|
|
||||||
|
@@ -161,7 +161,7 @@ namespace ARMeilleure.CodeGen.Optimizations
|
|||||||
}
|
}
|
||||||
else if (otherCompType == Comparison.Equal)
|
else if (otherCompType == Comparison.Equal)
|
||||||
{
|
{
|
||||||
propCompType = compType.Invert();
|
propCompType = compType.Inverse;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@@ -105,7 +105,7 @@ namespace ARMeilleure.CodeGen.Optimizations
|
|||||||
Operand x = operation.GetSource(0);
|
Operand x = operation.GetSource(0);
|
||||||
Operand y = operation.GetSource(1);
|
Operand y = operation.GetSource(1);
|
||||||
|
|
||||||
if (x == y && x.Type.IsInteger())
|
if (x == y && x.Type.IsInteger)
|
||||||
{
|
{
|
||||||
operation.TurnIntoCopy(Const(x.Type, 0));
|
operation.TurnIntoCopy(Const(x.Type, 0));
|
||||||
}
|
}
|
||||||
@@ -161,7 +161,7 @@ namespace ARMeilleure.CodeGen.Optimizations
|
|||||||
|
|
||||||
private static bool IsConstEqual(Operand operand, ulong comparand)
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
@@ -98,7 +98,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
|
|||||||
{
|
{
|
||||||
OperandType type = types[copyDest];
|
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));
|
EmitXorSwap(sequence, GetRegister(copyDest, type), GetRegister(copySource, type));
|
||||||
|
|
||||||
|
@@ -178,7 +178,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
|
|||||||
}
|
}
|
||||||
else if (dest.Kind == OperandKind.Register)
|
else if (dest.Kind == OperandKind.Register)
|
||||||
{
|
{
|
||||||
if (dest.Type.IsInteger())
|
if (dest.Type.IsInteger)
|
||||||
{
|
{
|
||||||
intFixedRegisters |= 1 << dest.GetRegister().Index;
|
intFixedRegisters |= 1 << dest.GetRegister().Index;
|
||||||
}
|
}
|
||||||
@@ -236,7 +236,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
|
|||||||
{
|
{
|
||||||
Register reg = info.Register.GetRegister();
|
Register reg = info.Register.GetRegister();
|
||||||
|
|
||||||
if (local.Type.IsInteger())
|
if (local.Type.IsInteger)
|
||||||
{
|
{
|
||||||
intLocalFreeRegisters |= 1 << reg.Index;
|
intLocalFreeRegisters |= 1 << reg.Index;
|
||||||
}
|
}
|
||||||
@@ -254,7 +254,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
|
|||||||
|
|
||||||
if (temp == default || info.Sequence != sequence)
|
if (temp == default || info.Sequence != sequence)
|
||||||
{
|
{
|
||||||
temp = local.Type.IsInteger()
|
temp = local.Type.IsInteger
|
||||||
? GetSpillTemp(local, intSpillTempRegisters, ref intLocalUse)
|
? GetSpillTemp(local, intSpillTempRegisters, ref intLocalUse)
|
||||||
: GetSpillTemp(local, vecSpillTempRegisters, ref vecLocalUse);
|
: GetSpillTemp(local, vecSpillTempRegisters, ref vecLocalUse);
|
||||||
|
|
||||||
@@ -335,7 +335,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
|
|||||||
|
|
||||||
if (info.UsesAllocated == 0)
|
if (info.UsesAllocated == 0)
|
||||||
{
|
{
|
||||||
int mask = dest.Type.IsInteger()
|
int mask = dest.Type.IsInteger
|
||||||
? intLocalFreeRegisters
|
? intLocalFreeRegisters
|
||||||
: vecLocalFreeRegisters;
|
: vecLocalFreeRegisters;
|
||||||
|
|
||||||
@@ -343,9 +343,9 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
|
|||||||
{
|
{
|
||||||
int selectedReg = BitOperations.TrailingZeroCount(mask);
|
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);
|
intLocalFreeRegisters &= ~(1 << selectedReg);
|
||||||
intUsedRegisters |= 1 << selectedReg;
|
intUsedRegisters |= 1 << selectedReg;
|
||||||
@@ -359,7 +359,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
info.Register = default;
|
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)
|
if (temp == default || info.Sequence != sequence)
|
||||||
{
|
{
|
||||||
temp = dest.Type.IsInteger()
|
temp = dest.Type.IsInteger
|
||||||
? GetSpillTemp(dest, intSpillTempRegisters, ref intLocalAsg)
|
? GetSpillTemp(dest, intSpillTempRegisters, ref intLocalAsg)
|
||||||
: GetSpillTemp(dest, vecSpillTempRegisters, ref vecLocalAsg);
|
: GetSpillTemp(dest, vecSpillTempRegisters, ref vecLocalAsg);
|
||||||
|
|
||||||
@@ -443,7 +443,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
|
|||||||
|
|
||||||
useMask |= 1 << selectedReg;
|
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)
|
private static int UsesCount(Operand local)
|
||||||
|
@@ -208,7 +208,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
|
|||||||
|
|
||||||
private bool TryAllocateRegWithoutSpill(AllocationContext context, LiveInterval current, int cIndex, int registersCount)
|
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];
|
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)
|
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> usePositions = stackalloc int[registersCount];
|
||||||
Span<int> blockedPositions = stackalloc int[registersCount];
|
Span<int> blockedPositions = stackalloc int[registersCount];
|
||||||
|
@@ -10,7 +10,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
|
|||||||
|
|
||||||
public int Allocate(OperandType type)
|
public int Allocate(OperandType type)
|
||||||
{
|
{
|
||||||
return Allocate(type.GetSizeInBytes());
|
return Allocate(type.ByteSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int Allocate(int sizeInBytes)
|
public int Allocate(int sizeInBytes)
|
||||||
|
@@ -385,7 +385,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||||||
{
|
{
|
||||||
ref readonly InstructionInfo info = ref _instTable[(int)X86Instruction.Movd];
|
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);
|
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;
|
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);
|
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);
|
WriteOpCode(dest, default, source, OperandType.None, flags, info.OpRMR);
|
||||||
}
|
}
|
||||||
|
@@ -289,7 +289,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||||||
|
|
||||||
EnsureSameType(dest, source);
|
EnsureSameType(dest, source);
|
||||||
|
|
||||||
Debug.Assert(dest.Type.IsInteger());
|
Debug.Assert(dest.Type.IsInteger);
|
||||||
|
|
||||||
context.Assembler.Popcnt(dest, source, dest.Type);
|
context.Assembler.Popcnt(dest, source, dest.Type);
|
||||||
|
|
||||||
@@ -303,7 +303,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||||||
|
|
||||||
EnsureSameType(dest, source);
|
EnsureSameType(dest, source);
|
||||||
|
|
||||||
Debug.Assert(!dest.Type.IsInteger());
|
Debug.Assert(!dest.Type.IsInteger);
|
||||||
|
|
||||||
context.Assembler.WriteInstruction(info.Inst, dest, source);
|
context.Assembler.WriteInstruction(info.Inst, dest, source);
|
||||||
|
|
||||||
@@ -315,7 +315,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||||||
Operand dest = operation.Destination;
|
Operand dest = operation.Destination;
|
||||||
Operand source = operation.GetSource(0);
|
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)
|
if (operation.Intrinsic == Intrinsic.X86Cvtsi2si)
|
||||||
{
|
{
|
||||||
@@ -349,8 +349,8 @@ namespace ARMeilleure.CodeGen.X86
|
|||||||
EnsureSameReg(dest, src1);
|
EnsureSameReg(dest, src1);
|
||||||
}
|
}
|
||||||
|
|
||||||
Debug.Assert(!dest.Type.IsInteger());
|
Debug.Assert(!dest.Type.IsInteger);
|
||||||
Debug.Assert(!src2.Type.IsInteger() || src2.Kind == OperandKind.Constant);
|
Debug.Assert(!src2.Type.IsInteger || src2.Kind == OperandKind.Constant);
|
||||||
|
|
||||||
context.Assembler.WriteInstruction(info.Inst, dest, src1, src2);
|
context.Assembler.WriteInstruction(info.Inst, dest, src1, src2);
|
||||||
|
|
||||||
@@ -370,7 +370,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||||||
EnsureSameReg(dest, src1);
|
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);
|
context.Assembler.WriteInstruction(info.Inst, dest, src1, src2, src2.Type);
|
||||||
|
|
||||||
@@ -385,7 +385,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||||||
|
|
||||||
EnsureSameReg(dest, src1);
|
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);
|
context.Assembler.WriteInstruction(info.Inst, dest, src2, dest.Type);
|
||||||
|
|
||||||
@@ -405,7 +405,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||||||
EnsureSameReg(dest, src1);
|
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());
|
context.Assembler.WriteInstruction(info.Inst, dest, src1, src2.AsByte());
|
||||||
|
|
||||||
@@ -421,7 +421,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||||||
|
|
||||||
EnsureSameType(dest, src1, src2, src3);
|
EnsureSameType(dest, src1, src2, src3);
|
||||||
|
|
||||||
Debug.Assert(!dest.Type.IsInteger());
|
Debug.Assert(!dest.Type.IsInteger);
|
||||||
|
|
||||||
if (info.Inst == X86Instruction.Blendvpd && HardwareCapabilities.SupportsVexEncoding)
|
if (info.Inst == X86Instruction.Blendvpd && HardwareCapabilities.SupportsVexEncoding)
|
||||||
{
|
{
|
||||||
@@ -461,7 +461,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||||||
EnsureSameReg(dest, src1);
|
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());
|
context.Assembler.WriteInstruction(info.Inst, dest, src1, src2, src3.AsByte());
|
||||||
|
|
||||||
@@ -512,7 +512,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||||||
Operand src1 = operation.GetSource(0);
|
Operand src1 = operation.GetSource(0);
|
||||||
Operand src2 = operation.GetSource(1);
|
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 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)
|
if (dest.Kind == src1.Kind && dest.Value == src1.Value)
|
||||||
@@ -567,7 +567,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||||||
|
|
||||||
ValidateBinOp(dest, src1, src2);
|
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`
|
// Note: GenerateCompareCommon makes the assumption that BitwiseAnd will emit only a single `and`
|
||||||
// instruction.
|
// instruction.
|
||||||
@@ -582,7 +582,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||||||
|
|
||||||
ValidateBinOp(dest, src1, src2);
|
ValidateBinOp(dest, src1, src2);
|
||||||
|
|
||||||
if (dest.Type.IsInteger())
|
if (dest.Type.IsInteger)
|
||||||
{
|
{
|
||||||
context.Assembler.Xor(dest, src2, dest.Type);
|
context.Assembler.Xor(dest, src2, dest.Type);
|
||||||
}
|
}
|
||||||
@@ -599,7 +599,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||||||
|
|
||||||
ValidateUnOp(dest, source);
|
ValidateUnOp(dest, source);
|
||||||
|
|
||||||
Debug.Assert(dest.Type.IsInteger());
|
Debug.Assert(dest.Type.IsInteger);
|
||||||
|
|
||||||
context.Assembler.Not(dest);
|
context.Assembler.Not(dest);
|
||||||
}
|
}
|
||||||
@@ -612,7 +612,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||||||
|
|
||||||
ValidateBinOp(dest, src1, src2);
|
ValidateBinOp(dest, src1, src2);
|
||||||
|
|
||||||
Debug.Assert(dest.Type.IsInteger());
|
Debug.Assert(dest.Type.IsInteger);
|
||||||
|
|
||||||
context.Assembler.Or(dest, src2, dest.Type);
|
context.Assembler.Or(dest, src2, dest.Type);
|
||||||
}
|
}
|
||||||
@@ -623,7 +623,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||||||
|
|
||||||
Debug.Assert(comp.Kind == OperandKind.Constant);
|
Debug.Assert(comp.Kind == OperandKind.Constant);
|
||||||
|
|
||||||
X86Condition cond = ((Comparison)comp.AsInt32()).ToX86Condition();
|
X86Condition cond = ((Comparison)comp.AsInt32()).X86;
|
||||||
|
|
||||||
GenerateCompareCommon(context, operation);
|
GenerateCompareCommon(context, operation);
|
||||||
|
|
||||||
@@ -637,7 +637,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||||||
|
|
||||||
ValidateUnOp(dest, source);
|
ValidateUnOp(dest, source);
|
||||||
|
|
||||||
Debug.Assert(dest.Type.IsInteger());
|
Debug.Assert(dest.Type.IsInteger);
|
||||||
|
|
||||||
context.Assembler.Bswap(dest);
|
context.Assembler.Bswap(dest);
|
||||||
}
|
}
|
||||||
@@ -661,7 +661,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||||||
Debug.Assert(dest.Type == OperandType.I32);
|
Debug.Assert(dest.Type == OperandType.I32);
|
||||||
Debug.Assert(comp.Kind == OperandKind.Constant);
|
Debug.Assert(comp.Kind == OperandKind.Constant);
|
||||||
|
|
||||||
X86Condition cond = ((Comparison)comp.AsInt32()).ToX86Condition();
|
X86Condition cond = ((Comparison)comp.AsInt32()).X86;
|
||||||
|
|
||||||
GenerateCompareCommon(context, operation);
|
GenerateCompareCommon(context, operation);
|
||||||
|
|
||||||
@@ -676,7 +676,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||||||
|
|
||||||
EnsureSameType(src1, src2);
|
EnsureSameType(src1, src2);
|
||||||
|
|
||||||
Debug.Assert(src1.Type.IsInteger());
|
Debug.Assert(src1.Type.IsInteger);
|
||||||
|
|
||||||
if (src2.Kind == OperandKind.Constant && src2.Value == 0)
|
if (src2.Kind == OperandKind.Constant && src2.Value == 0)
|
||||||
{
|
{
|
||||||
@@ -766,7 +766,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||||||
EnsureSameReg(dest, src3);
|
EnsureSameReg(dest, src3);
|
||||||
EnsureSameType(dest, src2, src3);
|
EnsureSameType(dest, src2, src3);
|
||||||
|
|
||||||
Debug.Assert(dest.Type.IsInteger());
|
Debug.Assert(dest.Type.IsInteger);
|
||||||
Debug.Assert(src1.Type == OperandType.I32);
|
Debug.Assert(src1.Type == OperandType.I32);
|
||||||
|
|
||||||
context.Assembler.Test(src1, src1, src1.Type);
|
context.Assembler.Test(src1, src1, src1.Type);
|
||||||
@@ -792,9 +792,9 @@ namespace ARMeilleure.CodeGen.X86
|
|||||||
|
|
||||||
if (dest.Type == OperandType.FP32)
|
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.Xorps(dest, dest, dest);
|
||||||
context.Assembler.Cvtsi2ss(dest, dest, source, source.Type);
|
context.Assembler.Cvtsi2ss(dest, dest, source, source.Type);
|
||||||
@@ -808,9 +808,9 @@ namespace ARMeilleure.CodeGen.X86
|
|||||||
}
|
}
|
||||||
else /* if (dest.Type == OperandType.FP64) */
|
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.Xorps(dest, dest, dest);
|
||||||
context.Assembler.Cvtsi2sd(dest, dest, source, source.Type);
|
context.Assembler.Cvtsi2sd(dest, dest, source, source.Type);
|
||||||
@@ -831,7 +831,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||||||
|
|
||||||
EnsureSameType(dest, source);
|
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.
|
// Moves to the same register are useless.
|
||||||
if (dest.Kind == source.Kind && dest.Value == source.Value)
|
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.
|
// Assemble "mov reg, 0" as "xor reg, reg" as the later is more efficient.
|
||||||
context.Assembler.Xor(dest, dest, OperandType.I32);
|
context.Assembler.Xor(dest, dest, OperandType.I32);
|
||||||
}
|
}
|
||||||
else if (dest.Type.IsInteger())
|
else if (dest.Type.IsInteger)
|
||||||
{
|
{
|
||||||
context.Assembler.Mov(dest, source, dest.Type);
|
context.Assembler.Mov(dest, source, dest.Type);
|
||||||
}
|
}
|
||||||
@@ -862,7 +862,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||||||
|
|
||||||
EnsureSameType(dest, source);
|
EnsureSameType(dest, source);
|
||||||
|
|
||||||
Debug.Assert(dest.Type.IsInteger());
|
Debug.Assert(dest.Type.IsInteger);
|
||||||
|
|
||||||
context.Assembler.Bsr(dest, source, dest.Type);
|
context.Assembler.Bsr(dest, source, dest.Type);
|
||||||
|
|
||||||
@@ -894,12 +894,12 @@ namespace ARMeilleure.CodeGen.X86
|
|||||||
Operand dividend = operation.GetSource(0);
|
Operand dividend = operation.GetSource(0);
|
||||||
Operand divisor = operation.GetSource(1);
|
Operand divisor = operation.GetSource(1);
|
||||||
|
|
||||||
if (!dest.Type.IsInteger())
|
if (!dest.Type.IsInteger)
|
||||||
{
|
{
|
||||||
ValidateBinOp(dest, dividend, divisor);
|
ValidateBinOp(dest, dividend, divisor);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dest.Type.IsInteger())
|
if (dest.Type.IsInteger)
|
||||||
{
|
{
|
||||||
divisor = operation.GetSource(2);
|
divisor = operation.GetSource(2);
|
||||||
|
|
||||||
@@ -932,7 +932,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||||||
|
|
||||||
Operand rdx = Register(X86Register.Rdx);
|
Operand rdx = Register(X86Register.Rdx);
|
||||||
|
|
||||||
Debug.Assert(divisor.Type.IsInteger());
|
Debug.Assert(divisor.Type.IsInteger);
|
||||||
|
|
||||||
context.Assembler.Xor(rdx, rdx, OperandType.I32);
|
context.Assembler.Xor(rdx, rdx, OperandType.I32);
|
||||||
context.Assembler.Div(divisor);
|
context.Assembler.Div(divisor);
|
||||||
@@ -967,7 +967,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||||||
Operand value = operation.Destination;
|
Operand value = operation.Destination;
|
||||||
Operand address = Memory(operation.GetSource(0), value.Type);
|
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);
|
context.Assembler.Movzx16(value, address, value.Type);
|
||||||
}
|
}
|
||||||
@@ -977,7 +977,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||||||
Operand value = operation.Destination;
|
Operand value = operation.Destination;
|
||||||
Operand address = Memory(operation.GetSource(0), value.Type);
|
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);
|
context.Assembler.Movzx8(value, address, value.Type);
|
||||||
}
|
}
|
||||||
@@ -1000,7 +1000,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||||||
|
|
||||||
EnsureSameType(dest, src1, src2);
|
EnsureSameType(dest, src1, src2);
|
||||||
|
|
||||||
if (dest.Type.IsInteger())
|
if (dest.Type.IsInteger)
|
||||||
{
|
{
|
||||||
if (src2.Kind == OperandKind.Constant)
|
if (src2.Kind == OperandKind.Constant)
|
||||||
{
|
{
|
||||||
@@ -1046,7 +1046,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||||||
|
|
||||||
ValidateUnOp(dest, source);
|
ValidateUnOp(dest, source);
|
||||||
|
|
||||||
Debug.Assert(dest.Type.IsInteger());
|
Debug.Assert(dest.Type.IsInteger);
|
||||||
|
|
||||||
context.Assembler.Neg(dest);
|
context.Assembler.Neg(dest);
|
||||||
}
|
}
|
||||||
@@ -1107,7 +1107,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||||||
Operand dest = operation.Destination;
|
Operand dest = operation.Destination;
|
||||||
Operand source = operation.GetSource(0);
|
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);
|
context.Assembler.Movsx16(dest, source, dest.Type);
|
||||||
}
|
}
|
||||||
@@ -1117,7 +1117,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||||||
Operand dest = operation.Destination;
|
Operand dest = operation.Destination;
|
||||||
Operand source = operation.GetSource(0);
|
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);
|
context.Assembler.Movsx32(dest, source, dest.Type);
|
||||||
}
|
}
|
||||||
@@ -1127,7 +1127,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||||||
Operand dest = operation.Destination;
|
Operand dest = operation.Destination;
|
||||||
Operand source = operation.GetSource(0);
|
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);
|
context.Assembler.Movsx8(dest, source, dest.Type);
|
||||||
}
|
}
|
||||||
@@ -1187,7 +1187,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||||||
Operand value = operation.GetSource(1);
|
Operand value = operation.GetSource(1);
|
||||||
Operand address = Memory(operation.GetSource(0), value.Type);
|
Operand address = Memory(operation.GetSource(0), value.Type);
|
||||||
|
|
||||||
Debug.Assert(value.Type.IsInteger());
|
Debug.Assert(value.Type.IsInteger);
|
||||||
|
|
||||||
context.Assembler.Mov16(address, value);
|
context.Assembler.Mov16(address, value);
|
||||||
}
|
}
|
||||||
@@ -1197,7 +1197,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||||||
Operand value = operation.GetSource(1);
|
Operand value = operation.GetSource(1);
|
||||||
Operand address = Memory(operation.GetSource(0), value.Type);
|
Operand address = Memory(operation.GetSource(0), value.Type);
|
||||||
|
|
||||||
Debug.Assert(value.Type.IsInteger());
|
Debug.Assert(value.Type.IsInteger);
|
||||||
|
|
||||||
context.Assembler.Mov8(address, value);
|
context.Assembler.Mov8(address, value);
|
||||||
}
|
}
|
||||||
@@ -1210,7 +1210,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||||||
|
|
||||||
ValidateBinOp(dest, src1, src2);
|
ValidateBinOp(dest, src1, src2);
|
||||||
|
|
||||||
if (dest.Type.IsInteger())
|
if (dest.Type.IsInteger)
|
||||||
{
|
{
|
||||||
context.Assembler.Sub(dest, src2, dest.Type);
|
context.Assembler.Sub(dest, src2, dest.Type);
|
||||||
}
|
}
|
||||||
@@ -1236,7 +1236,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||||||
Operand dest = operation.Destination;
|
Operand dest = operation.Destination;
|
||||||
Operand source = operation.GetSource(0);
|
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)
|
if (source.Type == OperandType.I32)
|
||||||
{
|
{
|
||||||
@@ -1259,7 +1259,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||||||
|
|
||||||
byte index = src2.AsByte();
|
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)
|
if (dest.Type == OperandType.I32)
|
||||||
{
|
{
|
||||||
@@ -1541,7 +1541,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||||||
{
|
{
|
||||||
Operand dest = operation.Destination;
|
Operand dest = operation.Destination;
|
||||||
|
|
||||||
Debug.Assert(!dest.Type.IsInteger());
|
Debug.Assert(!dest.Type.IsInteger);
|
||||||
|
|
||||||
context.Assembler.Pcmpeqw(dest, dest, dest);
|
context.Assembler.Pcmpeqw(dest, dest, dest);
|
||||||
}
|
}
|
||||||
@@ -1550,7 +1550,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||||||
{
|
{
|
||||||
Operand dest = operation.Destination;
|
Operand dest = operation.Destination;
|
||||||
|
|
||||||
Debug.Assert(!dest.Type.IsInteger());
|
Debug.Assert(!dest.Type.IsInteger);
|
||||||
|
|
||||||
context.Assembler.Xorps(dest, dest, dest);
|
context.Assembler.Xorps(dest, dest, dest);
|
||||||
}
|
}
|
||||||
@@ -1580,7 +1580,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||||||
Operand dest = operation.Destination;
|
Operand dest = operation.Destination;
|
||||||
Operand source = operation.GetSource(0);
|
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);
|
context.Assembler.Movzx16(dest, source, OperandType.I32);
|
||||||
}
|
}
|
||||||
@@ -1590,7 +1590,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||||||
Operand dest = operation.Destination;
|
Operand dest = operation.Destination;
|
||||||
Operand source = operation.GetSource(0);
|
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.
|
// 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)
|
if (dest.Value == source.Value && source.Type == OperandType.I32)
|
||||||
@@ -1606,7 +1606,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||||||
Operand dest = operation.Destination;
|
Operand dest = operation.Destination;
|
||||||
Operand source = operation.GetSource(0);
|
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);
|
context.Assembler.Movzx8(dest, source, OperandType.I32);
|
||||||
}
|
}
|
||||||
@@ -1713,12 +1713,12 @@ namespace ARMeilleure.CodeGen.X86
|
|||||||
EnsureSameReg(dest, src1);
|
EnsureSameReg(dest, src1);
|
||||||
EnsureSameType(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)
|
private static void EnsureSameReg(Operand op1, Operand op2)
|
||||||
{
|
{
|
||||||
if (!op1.Type.IsInteger() && HardwareCapabilities.SupportsVexEncoding)
|
if (!op1.Type.IsInteger && HardwareCapabilities.SupportsVexEncoding)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@@ -86,7 +86,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case Instruction.Negate:
|
case Instruction.Negate:
|
||||||
if (!node.GetSource(0).Type.IsInteger())
|
if (!node.GetSource(0).Type.IsInteger)
|
||||||
{
|
{
|
||||||
GenerateNegate(block.Operations, node);
|
GenerateNegate(block.Operations, node);
|
||||||
}
|
}
|
||||||
@@ -159,7 +159,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||||||
|
|
||||||
if (src1.Kind == OperandKind.Constant)
|
if (src1.Kind == OperandKind.Constant)
|
||||||
{
|
{
|
||||||
if (!src1.Type.IsInteger())
|
if (!src1.Type.IsInteger)
|
||||||
{
|
{
|
||||||
// Handle non-integer types (FP32, FP64 and V128).
|
// Handle non-integer types (FP32, FP64 and V128).
|
||||||
// For instructions without an immediate operand, we do the following:
|
// 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.Kind == OperandKind.Constant)
|
||||||
{
|
{
|
||||||
if (!src2.Type.IsInteger())
|
if (!src2.Type.IsInteger)
|
||||||
{
|
{
|
||||||
src2 = AddXmmCopy(nodes, node, src2);
|
src2 = AddXmmCopy(nodes, node, src2);
|
||||||
|
|
||||||
@@ -298,7 +298,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||||||
// - The dividend is always in RDX:RAX.
|
// - The dividend is always in RDX:RAX.
|
||||||
// - The result is always in RAX.
|
// - The result is always in RAX.
|
||||||
// - Additionally it also writes the remainder in RDX.
|
// - Additionally it also writes the remainder in RDX.
|
||||||
if (dest.Type.IsInteger())
|
if (dest.Type.IsInteger)
|
||||||
{
|
{
|
||||||
Operand src1 = node.GetSource(0);
|
Operand src1 = node.GetSource(0);
|
||||||
|
|
||||||
@@ -466,7 +466,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||||||
Operand dest = node.Destination;
|
Operand dest = node.Destination;
|
||||||
Operand source = node.GetSource(0);
|
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;
|
Operation currentNode = node;
|
||||||
|
|
||||||
@@ -654,10 +654,10 @@ namespace ARMeilleure.CodeGen.X86
|
|||||||
switch (operation.Instruction)
|
switch (operation.Instruction)
|
||||||
{
|
{
|
||||||
case Instruction.Add:
|
case Instruction.Add:
|
||||||
return !HardwareCapabilities.SupportsVexEncoding && !operation.Destination.Type.IsInteger();
|
return !HardwareCapabilities.SupportsVexEncoding && !operation.Destination.Type.IsInteger;
|
||||||
case Instruction.Multiply:
|
case Instruction.Multiply:
|
||||||
case Instruction.Subtract:
|
case Instruction.Subtract:
|
||||||
return !HardwareCapabilities.SupportsVexEncoding || operation.Destination.Type.IsInteger();
|
return !HardwareCapabilities.SupportsVexEncoding || operation.Destination.Type.IsInteger;
|
||||||
|
|
||||||
case Instruction.BitwiseAnd:
|
case Instruction.BitwiseAnd:
|
||||||
case Instruction.BitwiseExclusiveOr:
|
case Instruction.BitwiseExclusiveOr:
|
||||||
@@ -672,7 +672,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||||||
return true;
|
return true;
|
||||||
|
|
||||||
case Instruction.Divide:
|
case Instruction.Divide:
|
||||||
return !HardwareCapabilities.SupportsVexEncoding && !operation.Destination.Type.IsInteger();
|
return !HardwareCapabilities.SupportsVexEncoding && !operation.Destination.Type.IsInteger;
|
||||||
|
|
||||||
case Instruction.VectorInsert:
|
case Instruction.VectorInsert:
|
||||||
case Instruction.VectorInsert16:
|
case Instruction.VectorInsert16:
|
||||||
|
@@ -35,7 +35,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||||||
|
|
||||||
bool passOnReg;
|
bool passOnReg;
|
||||||
|
|
||||||
if (source.Type.IsInteger())
|
if (source.Type.IsInteger)
|
||||||
{
|
{
|
||||||
passOnReg = intCount < intMax;
|
passOnReg = intCount < intMax;
|
||||||
}
|
}
|
||||||
@@ -62,7 +62,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||||||
|
|
||||||
if (passOnReg)
|
if (passOnReg)
|
||||||
{
|
{
|
||||||
Operand argReg = source.Type.IsInteger()
|
Operand argReg = source.Type.IsInteger
|
||||||
? Gpr(CallingConvention.GetIntArgumentRegister(intCount++), source.Type)
|
? Gpr(CallingConvention.GetIntArgumentRegister(intCount++), source.Type)
|
||||||
: Xmm(CallingConvention.GetVecArgumentRegister(vecCount++), source.Type);
|
: Xmm(CallingConvention.GetVecArgumentRegister(vecCount++), source.Type);
|
||||||
|
|
||||||
@@ -80,7 +80,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||||||
|
|
||||||
InsertConstantRegCopies(nodes, nodes.AddBefore(node, spillOp));
|
InsertConstantRegCopies(nodes, nodes.AddBefore(node, spillOp));
|
||||||
|
|
||||||
stackOffset += source.Type.GetSizeInBytes();
|
stackOffset += source.Type.ByteSize;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -102,7 +102,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Operand retReg = dest.Type.IsInteger()
|
Operand retReg = dest.Type.IsInteger
|
||||||
? Gpr(CallingConvention.GetIntReturnRegister(), dest.Type)
|
? Gpr(CallingConvention.GetIntReturnRegister(), dest.Type)
|
||||||
: Xmm(CallingConvention.GetVecReturnRegister(), dest.Type);
|
: Xmm(CallingConvention.GetVecReturnRegister(), dest.Type);
|
||||||
|
|
||||||
@@ -137,7 +137,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||||||
|
|
||||||
bool passOnReg;
|
bool passOnReg;
|
||||||
|
|
||||||
if (source.Type.IsInteger())
|
if (source.Type.IsInteger)
|
||||||
{
|
{
|
||||||
passOnReg = intCount + 1 < intMax;
|
passOnReg = intCount + 1 < intMax;
|
||||||
}
|
}
|
||||||
@@ -160,7 +160,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||||||
|
|
||||||
if (passOnReg)
|
if (passOnReg)
|
||||||
{
|
{
|
||||||
Operand argReg = source.Type.IsInteger()
|
Operand argReg = source.Type.IsInteger
|
||||||
? Gpr(CallingConvention.GetIntArgumentRegister(intCount++), source.Type)
|
? Gpr(CallingConvention.GetIntArgumentRegister(intCount++), source.Type)
|
||||||
: Xmm(CallingConvention.GetVecArgumentRegister(vecCount++), source.Type);
|
: Xmm(CallingConvention.GetVecArgumentRegister(vecCount++), source.Type);
|
||||||
|
|
||||||
@@ -210,7 +210,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||||||
{
|
{
|
||||||
OperandType argType = cctx.FuncArgTypes[cIndex];
|
OperandType argType = cctx.FuncArgTypes[cIndex];
|
||||||
|
|
||||||
if (argType.IsInteger())
|
if (argType.IsInteger)
|
||||||
{
|
{
|
||||||
intCount++;
|
intCount++;
|
||||||
}
|
}
|
||||||
@@ -226,7 +226,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||||||
|
|
||||||
bool passOnReg;
|
bool passOnReg;
|
||||||
|
|
||||||
if (source.Type.IsInteger())
|
if (source.Type.IsInteger)
|
||||||
{
|
{
|
||||||
passOnReg = intCount < CallingConvention.GetIntArgumentsOnRegsCount();
|
passOnReg = intCount < CallingConvention.GetIntArgumentsOnRegsCount();
|
||||||
}
|
}
|
||||||
@@ -265,7 +265,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||||||
{
|
{
|
||||||
Operand pArg = Local(dest.Type);
|
Operand pArg = Local(dest.Type);
|
||||||
|
|
||||||
Operand argReg = dest.Type.IsInteger()
|
Operand argReg = dest.Type.IsInteger
|
||||||
? Gpr(CallingConvention.GetIntArgumentRegister(intCount), dest.Type)
|
? Gpr(CallingConvention.GetIntArgumentRegister(intCount), dest.Type)
|
||||||
: Xmm(CallingConvention.GetVecArgumentRegister(vecCount), dest.Type);
|
: Xmm(CallingConvention.GetVecArgumentRegister(vecCount), dest.Type);
|
||||||
|
|
||||||
@@ -320,7 +320,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Operand retReg = source.Type.IsInteger()
|
Operand retReg = source.Type.IsInteger
|
||||||
? Gpr(CallingConvention.GetIntReturnRegister(), source.Type)
|
? Gpr(CallingConvention.GetIntReturnRegister(), source.Type)
|
||||||
: Xmm(CallingConvention.GetVecReturnRegister(), source.Type);
|
: Xmm(CallingConvention.GetVecReturnRegister(), source.Type);
|
||||||
|
|
||||||
|
@@ -40,7 +40,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||||||
|
|
||||||
if (dest != default && dest.Type == OperandType.V128)
|
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);
|
arg0Reg = Gpr(CallingConvention.GetIntArgumentRegister(0), OperandType.I64);
|
||||||
|
|
||||||
@@ -76,7 +76,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||||||
{
|
{
|
||||||
Operand stackAddr = Local(OperandType.I64);
|
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)));
|
nodes.AddBefore(node, Operation(Instruction.StackAlloc, stackAddr, Const(stackOffset)));
|
||||||
|
|
||||||
@@ -96,7 +96,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||||||
|
|
||||||
int argIndex = index + retArgs;
|
int argIndex = index + retArgs;
|
||||||
|
|
||||||
if (source.Type.IsInteger())
|
if (source.Type.IsInteger)
|
||||||
{
|
{
|
||||||
argReg = Gpr(CallingConvention.GetIntArgumentRegister(argIndex), source.Type);
|
argReg = Gpr(CallingConvention.GetIntArgumentRegister(argIndex), source.Type);
|
||||||
}
|
}
|
||||||
@@ -140,7 +140,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Operand retReg = dest.Type.IsInteger()
|
Operand retReg = dest.Type.IsInteger
|
||||||
? Gpr(CallingConvention.GetIntReturnRegister(), dest.Type)
|
? Gpr(CallingConvention.GetIntReturnRegister(), dest.Type)
|
||||||
: Xmm(CallingConvention.GetVecReturnRegister(), dest.Type);
|
: Xmm(CallingConvention.GetVecReturnRegister(), dest.Type);
|
||||||
|
|
||||||
@@ -171,7 +171,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||||||
for (int index = 0; index < argsCount; index++)
|
for (int index = 0; index < argsCount; index++)
|
||||||
{
|
{
|
||||||
Operand source = node.GetSource(1 + index);
|
Operand source = node.GetSource(1 + index);
|
||||||
Operand argReg = source.Type.IsInteger()
|
Operand argReg = source.Type.IsInteger
|
||||||
? Gpr(CallingConvention.GetIntArgumentRegister(index), source.Type)
|
? Gpr(CallingConvention.GetIntArgumentRegister(index), source.Type)
|
||||||
: Xmm(CallingConvention.GetVecArgumentRegister(index), source.Type);
|
: Xmm(CallingConvention.GetVecArgumentRegister(index), source.Type);
|
||||||
|
|
||||||
@@ -219,7 +219,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||||||
{
|
{
|
||||||
Operand argReg, pArg;
|
Operand argReg, pArg;
|
||||||
|
|
||||||
if (dest.Type.IsInteger())
|
if (dest.Type.IsInteger)
|
||||||
{
|
{
|
||||||
argReg = Gpr(CallingConvention.GetIntArgumentRegister(index), dest.Type);
|
argReg = Gpr(CallingConvention.GetIntArgumentRegister(index), dest.Type);
|
||||||
pArg = Local(dest.Type);
|
pArg = Local(dest.Type);
|
||||||
@@ -283,7 +283,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||||||
Operand source = node.GetSource(0);
|
Operand source = node.GetSource(0);
|
||||||
Operand retReg;
|
Operand retReg;
|
||||||
|
|
||||||
if (source.Type.IsInteger())
|
if (source.Type.IsInteger)
|
||||||
{
|
{
|
||||||
retReg = Gpr(CallingConvention.GetIntReturnRegister(), source.Type);
|
retReg = Gpr(CallingConvention.GetIntReturnRegister(), source.Type);
|
||||||
}
|
}
|
||||||
|
@@ -25,9 +25,9 @@ namespace ARMeilleure.CodeGen.X86
|
|||||||
|
|
||||||
static class ComparisonX86Extensions
|
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
|
#pragma warning disable IDE0055 // Disable formatting
|
||||||
Comparison.Equal => X86Condition.Equal,
|
Comparison.Equal => X86Condition.Equal,
|
||||||
@@ -42,7 +42,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||||||
Comparison.LessUI => X86Condition.Below,
|
Comparison.LessUI => X86Condition.Below,
|
||||||
#pragma warning restore IDE0055
|
#pragma warning restore IDE0055
|
||||||
|
|
||||||
_ => throw new ArgumentException(null, nameof(comp)),
|
_ => throw new ArgumentException(null, nameof(comparison))
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -22,11 +22,11 @@ namespace ARMeilleure.Decoders
|
|||||||
|
|
||||||
static class ConditionExtensions
|
static class ConditionExtensions
|
||||||
{
|
{
|
||||||
public static Condition Invert(this Condition cond)
|
extension(Condition condition)
|
||||||
{
|
{
|
||||||
// Bit 0 of all conditions is basically a negation bit, so
|
// Bit 0 of all conditions is basically a negation bit, so
|
||||||
// inverting this bit has the effect of inverting the condition.
|
// inverting this bit has the effect of inverting the condition.
|
||||||
return (Condition)((int)cond ^ 1);
|
public Condition Inverse => (Condition)((int)condition ^ 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -16,7 +16,7 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
public static Operand EmitCrc32(ArmEmitterContext context, Operand crc, Operand value, int size, bool castagnoli)
|
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 is >= 0 and < 4);
|
||||||
Debug.Assert((size < 3) || (value.Type == OperandType.I64));
|
Debug.Assert((size < 3) || (value.Type == OperandType.I64));
|
||||||
|
|
||||||
|
@@ -157,7 +157,7 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
context.Copy(temp, value);
|
context.Copy(temp, value);
|
||||||
|
|
||||||
if (!context.Memory.Type.IsHostMappedOrTracked())
|
if (!context.Memory.Type.IsHostMappedOrTracked)
|
||||||
{
|
{
|
||||||
context.Branch(lblEnd);
|
context.Branch(lblEnd);
|
||||||
|
|
||||||
@@ -198,7 +198,7 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
SetInt(context, rt, value);
|
SetInt(context, rt, value);
|
||||||
|
|
||||||
if (!context.Memory.Type.IsHostMappedOrTracked())
|
if (!context.Memory.Type.IsHostMappedOrTracked)
|
||||||
{
|
{
|
||||||
context.Branch(lblEnd);
|
context.Branch(lblEnd);
|
||||||
|
|
||||||
@@ -265,7 +265,7 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
context.Copy(GetVec(rt), value);
|
context.Copy(GetVec(rt), value);
|
||||||
|
|
||||||
if (!context.Memory.Type.IsHostMappedOrTracked())
|
if (!context.Memory.Type.IsHostMappedOrTracked)
|
||||||
{
|
{
|
||||||
context.Branch(lblEnd);
|
context.Branch(lblEnd);
|
||||||
|
|
||||||
@@ -312,7 +312,7 @@ namespace ARMeilleure.Instructions
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!context.Memory.Type.IsHostMappedOrTracked())
|
if (!context.Memory.Type.IsHostMappedOrTracked)
|
||||||
{
|
{
|
||||||
context.Branch(lblEnd);
|
context.Branch(lblEnd);
|
||||||
|
|
||||||
@@ -385,7 +385,7 @@ namespace ARMeilleure.Instructions
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!context.Memory.Type.IsHostMappedOrTracked())
|
if (!context.Memory.Type.IsHostMappedOrTracked)
|
||||||
{
|
{
|
||||||
context.Branch(lblEnd);
|
context.Branch(lblEnd);
|
||||||
|
|
||||||
@@ -399,11 +399,11 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
public static Operand EmitPtPointerLoad(ArmEmitterContext context, Operand address, Operand lblSlowPath, bool write, int size)
|
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);
|
return EmitHostMappedPointer(context, address);
|
||||||
}
|
}
|
||||||
else if (context.Memory.Type.IsHostTracked())
|
else if (context.Memory.Type.IsHostTracked)
|
||||||
{
|
{
|
||||||
if (address.Type == OperandType.I32)
|
if (address.Type == OperandType.I32)
|
||||||
{
|
{
|
||||||
|
@@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
131
src/ARMeilleure/Instructions/SoftFallback/SoftFallback.Sha1.cs
Normal file
131
src/ARMeilleure/Instructions/SoftFallback/SoftFallback.Sha1.cs
Normal 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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
140
src/ARMeilleure/Instructions/SoftFallback/SoftFallback.Sha256.cs
Normal file
140
src/ARMeilleure/Instructions/SoftFallback/SoftFallback.Sha256.cs
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
26
src/ARMeilleure/Instructions/SoftFallback/SoftFallback.cs
Normal file
26
src/ARMeilleure/Instructions/SoftFallback/SoftFallback.cs
Normal 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
111
src/ARMeilleure/Instructions/SoftFloat/SoftFloat.cs
Normal file
111
src/ARMeilleure/Instructions/SoftFloat/SoftFloat.cs
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
212
src/ARMeilleure/Instructions/SoftFloat/SoftFloat16.cs
Normal file
212
src/ARMeilleure/Instructions/SoftFloat/SoftFloat16.cs
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
182
src/ARMeilleure/Instructions/SoftFloat/SoftFloat16_32.cs
Normal file
182
src/ARMeilleure/Instructions/SoftFloat/SoftFloat16_32.cs
Normal 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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
182
src/ARMeilleure/Instructions/SoftFloat/SoftFloat16_64.cs
Normal file
182
src/ARMeilleure/Instructions/SoftFloat/SoftFloat16_64.cs
Normal 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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
1421
src/ARMeilleure/Instructions/SoftFloat/SoftFloat32.cs
Normal file
1421
src/ARMeilleure/Instructions/SoftFloat/SoftFloat32.cs
Normal file
File diff suppressed because it is too large
Load Diff
126
src/ARMeilleure/Instructions/SoftFloat/SoftFloat32_16.cs
Normal file
126
src/ARMeilleure/Instructions/SoftFloat/SoftFloat32_16.cs
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
1421
src/ARMeilleure/Instructions/SoftFloat/SoftFloat64.cs
Normal file
1421
src/ARMeilleure/Instructions/SoftFloat/SoftFloat64.cs
Normal file
File diff suppressed because it is too large
Load Diff
127
src/ARMeilleure/Instructions/SoftFloat/SoftFloat64_16.cs
Normal file
127
src/ARMeilleure/Instructions/SoftFloat/SoftFloat64_16.cs
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -16,9 +16,9 @@ namespace ARMeilleure.IntermediateRepresentation
|
|||||||
|
|
||||||
static class ComparisonExtensions
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -14,48 +14,38 @@ namespace ARMeilleure.IntermediateRepresentation
|
|||||||
|
|
||||||
static class OperandTypeExtensions
|
static class OperandTypeExtensions
|
||||||
{
|
{
|
||||||
public static bool IsInteger(this OperandType type)
|
extension(OperandType type)
|
||||||
{
|
{
|
||||||
return type is OperandType.I32 or
|
public bool IsInteger => type is OperandType.I32 or OperandType.I64;
|
||||||
OperandType.I64;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static RegisterType ToRegisterType(this OperandType type)
|
public RegisterType Register => type switch
|
||||||
{
|
|
||||||
return type switch
|
|
||||||
{
|
{
|
||||||
OperandType.FP32 => RegisterType.Vector,
|
OperandType.FP32 => RegisterType.Vector,
|
||||||
OperandType.FP64 => RegisterType.Vector,
|
OperandType.FP64 => RegisterType.Vector,
|
||||||
OperandType.I32 => RegisterType.Integer,
|
OperandType.I32 => RegisterType.Integer,
|
||||||
OperandType.I64 => RegisterType.Integer,
|
OperandType.I64 => RegisterType.Integer,
|
||||||
OperandType.V128 => RegisterType.Vector,
|
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)
|
public int ByteSize => type switch
|
||||||
{
|
|
||||||
return type switch
|
|
||||||
{
|
{
|
||||||
OperandType.FP32 => 4,
|
OperandType.FP32 => 4,
|
||||||
OperandType.FP64 => 8,
|
OperandType.FP64 => 8,
|
||||||
OperandType.I32 => 4,
|
OperandType.I32 => 4,
|
||||||
OperandType.I64 => 8,
|
OperandType.I64 => 8,
|
||||||
OperandType.V128 => 16,
|
OperandType.V128 => 16,
|
||||||
_ => throw new InvalidOperationException($"Invalid operand type \"{type}\"."),
|
_ => throw new InvalidOperationException($"Invalid operand type \"{type}\".")
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
public static int GetSizeInBytesLog2(this OperandType type)
|
public int ByteSizeLog2 => type switch
|
||||||
{
|
|
||||||
return type switch
|
|
||||||
{
|
{
|
||||||
OperandType.FP32 => 2,
|
OperandType.FP32 => 2,
|
||||||
OperandType.FP64 => 3,
|
OperandType.FP64 => 3,
|
||||||
OperandType.I32 => 2,
|
OperandType.I32 => 2,
|
||||||
OperandType.I64 => 3,
|
OperandType.I64 => 3,
|
||||||
OperandType.V128 => 4,
|
OperandType.V128 => 4,
|
||||||
_ => throw new InvalidOperationException($"Invalid operand type \"{type}\"."),
|
_ => throw new InvalidOperationException($"Invalid operand type \"{type}\".")
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -45,19 +45,12 @@ namespace ARMeilleure.Memory
|
|||||||
|
|
||||||
public static class MemoryManagerTypeExtensions
|
public static class MemoryManagerTypeExtensions
|
||||||
{
|
{
|
||||||
public static bool IsHostMapped(this MemoryManagerType type)
|
extension(MemoryManagerType type)
|
||||||
{
|
{
|
||||||
return type is MemoryManagerType.HostMapped or MemoryManagerType.HostMappedUnsafe;
|
public bool IsHostMapped => type is MemoryManagerType.HostMapped or MemoryManagerType.HostMappedUnsafe;
|
||||||
}
|
public bool IsHostTracked => type is MemoryManagerType.HostTracked or MemoryManagerType.HostTrackedUnsafe;
|
||||||
|
|
||||||
public static bool IsHostTracked(this MemoryManagerType type)
|
public bool IsHostMappedOrTracked => type.IsHostMapped || type.IsHostTracked;
|
||||||
{
|
|
||||||
return type is MemoryManagerType.HostTracked or MemoryManagerType.HostTrackedUnsafe;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool IsHostMappedOrTracked(this MemoryManagerType type)
|
|
||||||
{
|
|
||||||
return type.IsHostMapped() || type.IsHostTracked();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -412,7 +412,7 @@ namespace ARMeilleure.Translation
|
|||||||
{
|
{
|
||||||
context.SyncQcFlag();
|
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);
|
EmitSynchronization(context);
|
||||||
}
|
}
|
||||||
@@ -429,14 +429,14 @@ namespace ARMeilleure.Translation
|
|||||||
{
|
{
|
||||||
lblPredicateSkip = Label();
|
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();
|
lblPredicateSkip = Label();
|
||||||
|
|
||||||
InstEmitFlowHelper.EmitCondBranch(context, lblPredicateSkip, op.Cond.Invert());
|
InstEmitFlowHelper.EmitCondBranch(context, lblPredicateSkip, op.Cond.Inverse);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (opCode.Instruction.Emitter != null)
|
if (opCode.Instruction.Emitter != null)
|
||||||
|
@@ -58,16 +58,16 @@ namespace Ryujinx.Audio.Backends.CompatLayer
|
|||||||
switch (realSampleFormat)
|
switch (realSampleFormat)
|
||||||
{
|
{
|
||||||
case SampleFormat.PcmInt8:
|
case SampleFormat.PcmInt8:
|
||||||
PcmHelper.ConvertSampleToPcm8(MemoryMarshal.Cast<byte, sbyte>(convertedSamples), samples);
|
PcmHelper.ConvertSampleToPcm8(MemoryMarshal.Cast<byte, sbyte>(new Span<byte>(convertedSamples)), samples);
|
||||||
break;
|
break;
|
||||||
case SampleFormat.PcmInt24:
|
case SampleFormat.PcmInt24:
|
||||||
PcmHelper.ConvertSampleToPcm24(convertedSamples, samples);
|
PcmHelper.ConvertSampleToPcm24(convertedSamples, samples);
|
||||||
break;
|
break;
|
||||||
case SampleFormat.PcmInt32:
|
case SampleFormat.PcmInt32:
|
||||||
PcmHelper.ConvertSampleToPcm32(MemoryMarshal.Cast<byte, int>(convertedSamples), samples);
|
PcmHelper.ConvertSampleToPcm32(MemoryMarshal.Cast<byte, int>(new Span<byte>(convertedSamples)), samples);
|
||||||
break;
|
break;
|
||||||
case SampleFormat.PcmFloat:
|
case SampleFormat.PcmFloat:
|
||||||
PcmHelper.ConvertSampleToPcmFloat(MemoryMarshal.Cast<byte, float>(convertedSamples), samples);
|
PcmHelper.ConvertSampleToPcmFloat(MemoryMarshal.Cast<byte, float>(new Span<byte>(convertedSamples)), samples);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new NotImplementedException($"Sample format conversion from {_userSampleFormat} to {realSampleFormat} not implemented.");
|
throw new NotImplementedException($"Sample format conversion from {_userSampleFormat} to {realSampleFormat} not implemented.");
|
||||||
|
@@ -27,7 +27,7 @@ namespace Ryujinx.Audio.Integration
|
|||||||
|
|
||||||
public void AppendBuffer(ReadOnlySpan<short> data, uint channelCount)
|
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
|
_session.QueueBuffer(new AudioBuffer
|
||||||
{
|
{
|
||||||
|
@@ -26,12 +26,15 @@ namespace Ryujinx.Audio.Renderer.Dsp
|
|||||||
ReadOnlySpan<float> inputBuffer,
|
ReadOnlySpan<float> inputBuffer,
|
||||||
uint sampleCount)
|
uint sampleCount)
|
||||||
{
|
{
|
||||||
float a0 = FixedPointHelper.ToFloat(parameter.Numerator[0], FixedPointPrecisionForParameter);
|
Span<short> numeratorSpan = parameter.Numerator.AsSpan();
|
||||||
float a1 = FixedPointHelper.ToFloat(parameter.Numerator[1], FixedPointPrecisionForParameter);
|
Span<short> denominatorSpan = parameter.Denominator.AsSpan();
|
||||||
float a2 = FixedPointHelper.ToFloat(parameter.Numerator[2], FixedPointPrecisionForParameter);
|
|
||||||
|
|
||||||
float b1 = FixedPointHelper.ToFloat(parameter.Denominator[0], FixedPointPrecisionForParameter);
|
float a0 = FixedPointHelper.ToFloat(numeratorSpan[0], FixedPointPrecisionForParameter);
|
||||||
float b2 = FixedPointHelper.ToFloat(parameter.Denominator[1], FixedPointPrecisionForParameter);
|
float a1 = FixedPointHelper.ToFloat(numeratorSpan[1], FixedPointPrecisionForParameter);
|
||||||
|
float a2 = FixedPointHelper.ToFloat(numeratorSpan[2], FixedPointPrecisionForParameter);
|
||||||
|
|
||||||
|
float b1 = FixedPointHelper.ToFloat(denominatorSpan[0], FixedPointPrecisionForParameter);
|
||||||
|
float b2 = FixedPointHelper.ToFloat(denominatorSpan[1], FixedPointPrecisionForParameter);
|
||||||
|
|
||||||
for (int i = 0; i < sampleCount; i++)
|
for (int i = 0; i < sampleCount; i++)
|
||||||
{
|
{
|
||||||
@@ -64,12 +67,15 @@ namespace Ryujinx.Audio.Renderer.Dsp
|
|||||||
uint sampleCount,
|
uint sampleCount,
|
||||||
float volume)
|
float volume)
|
||||||
{
|
{
|
||||||
float a0 = FixedPointHelper.ToFloat(parameter.Numerator[0], FixedPointPrecisionForParameter);
|
Span<short> numeratorSpan = parameter.Numerator.AsSpan();
|
||||||
float a1 = FixedPointHelper.ToFloat(parameter.Numerator[1], FixedPointPrecisionForParameter);
|
Span<short> denominatorSpan = parameter.Denominator.AsSpan();
|
||||||
float a2 = FixedPointHelper.ToFloat(parameter.Numerator[2], FixedPointPrecisionForParameter);
|
|
||||||
|
|
||||||
float b1 = FixedPointHelper.ToFloat(parameter.Denominator[0], FixedPointPrecisionForParameter);
|
float a0 = FixedPointHelper.ToFloat(numeratorSpan[0], FixedPointPrecisionForParameter);
|
||||||
float b2 = FixedPointHelper.ToFloat(parameter.Denominator[1], FixedPointPrecisionForParameter);
|
float a1 = FixedPointHelper.ToFloat(numeratorSpan[1], FixedPointPrecisionForParameter);
|
||||||
|
float a2 = FixedPointHelper.ToFloat(numeratorSpan[2], FixedPointPrecisionForParameter);
|
||||||
|
|
||||||
|
float b1 = FixedPointHelper.ToFloat(denominatorSpan[0], FixedPointPrecisionForParameter);
|
||||||
|
float b2 = FixedPointHelper.ToFloat(denominatorSpan[1], FixedPointPrecisionForParameter);
|
||||||
|
|
||||||
for (int i = 0; i < sampleCount; i++)
|
for (int i = 0; i < sampleCount; i++)
|
||||||
{
|
{
|
||||||
@@ -107,12 +113,15 @@ namespace Ryujinx.Audio.Renderer.Dsp
|
|||||||
float volume,
|
float volume,
|
||||||
float ramp)
|
float ramp)
|
||||||
{
|
{
|
||||||
float a0 = FixedPointHelper.ToFloat(parameter.Numerator[0], FixedPointPrecisionForParameter);
|
Span<short> numeratorSpan = parameter.Numerator.AsSpan();
|
||||||
float a1 = FixedPointHelper.ToFloat(parameter.Numerator[1], FixedPointPrecisionForParameter);
|
Span<short> denominatorSpan = parameter.Denominator.AsSpan();
|
||||||
float a2 = FixedPointHelper.ToFloat(parameter.Numerator[2], FixedPointPrecisionForParameter);
|
|
||||||
|
|
||||||
float b1 = FixedPointHelper.ToFloat(parameter.Denominator[0], FixedPointPrecisionForParameter);
|
float a0 = FixedPointHelper.ToFloat(numeratorSpan[0], FixedPointPrecisionForParameter);
|
||||||
float b2 = FixedPointHelper.ToFloat(parameter.Denominator[1], FixedPointPrecisionForParameter);
|
float a1 = FixedPointHelper.ToFloat(numeratorSpan[1], FixedPointPrecisionForParameter);
|
||||||
|
float a2 = FixedPointHelper.ToFloat(numeratorSpan[2], FixedPointPrecisionForParameter);
|
||||||
|
|
||||||
|
float b1 = FixedPointHelper.ToFloat(denominatorSpan[0], FixedPointPrecisionForParameter);
|
||||||
|
float b2 = FixedPointHelper.ToFloat(denominatorSpan[1], FixedPointPrecisionForParameter);
|
||||||
|
|
||||||
float mixState = 0f;
|
float mixState = 0f;
|
||||||
|
|
||||||
@@ -158,12 +167,15 @@ namespace Ryujinx.Audio.Renderer.Dsp
|
|||||||
|
|
||||||
ref BiquadFilterState state = ref states[stageIndex];
|
ref BiquadFilterState state = ref states[stageIndex];
|
||||||
|
|
||||||
float a0 = FixedPointHelper.ToFloat(parameter.Numerator[0], FixedPointPrecisionForParameter);
|
Span<short> numeratorSpan = parameter.Numerator.AsSpan();
|
||||||
float a1 = FixedPointHelper.ToFloat(parameter.Numerator[1], FixedPointPrecisionForParameter);
|
Span<short> denominatorSpan = parameter.Denominator.AsSpan();
|
||||||
float a2 = FixedPointHelper.ToFloat(parameter.Numerator[2], FixedPointPrecisionForParameter);
|
|
||||||
|
|
||||||
float b1 = FixedPointHelper.ToFloat(parameter.Denominator[0], FixedPointPrecisionForParameter);
|
float a0 = FixedPointHelper.ToFloat(numeratorSpan[0], FixedPointPrecisionForParameter);
|
||||||
float b2 = FixedPointHelper.ToFloat(parameter.Denominator[1], FixedPointPrecisionForParameter);
|
float a1 = FixedPointHelper.ToFloat(numeratorSpan[1], FixedPointPrecisionForParameter);
|
||||||
|
float a2 = FixedPointHelper.ToFloat(numeratorSpan[2], FixedPointPrecisionForParameter);
|
||||||
|
|
||||||
|
float b1 = FixedPointHelper.ToFloat(denominatorSpan[0], FixedPointPrecisionForParameter);
|
||||||
|
float b2 = FixedPointHelper.ToFloat(denominatorSpan[1], FixedPointPrecisionForParameter);
|
||||||
|
|
||||||
for (int i = 0; i < sampleCount; i++)
|
for (int i = 0; i < sampleCount; i++)
|
||||||
{
|
{
|
||||||
@@ -201,19 +213,25 @@ namespace Ryujinx.Audio.Renderer.Dsp
|
|||||||
uint sampleCount,
|
uint sampleCount,
|
||||||
float volume)
|
float volume)
|
||||||
{
|
{
|
||||||
float a00 = FixedPointHelper.ToFloat(parameter0.Numerator[0], FixedPointPrecisionForParameter);
|
Span<short> numerator0Span = parameter0.Numerator.AsSpan();
|
||||||
float a10 = FixedPointHelper.ToFloat(parameter0.Numerator[1], FixedPointPrecisionForParameter);
|
Span<short> numerator1Span = parameter1.Numerator.AsSpan();
|
||||||
float a20 = FixedPointHelper.ToFloat(parameter0.Numerator[2], FixedPointPrecisionForParameter);
|
Span<short> denominator0Span = parameter0.Denominator.AsSpan();
|
||||||
|
Span<short> denominator1Span = parameter1.Denominator.AsSpan();
|
||||||
|
|
||||||
float b10 = FixedPointHelper.ToFloat(parameter0.Denominator[0], FixedPointPrecisionForParameter);
|
|
||||||
float b20 = FixedPointHelper.ToFloat(parameter0.Denominator[1], FixedPointPrecisionForParameter);
|
|
||||||
|
|
||||||
float a01 = FixedPointHelper.ToFloat(parameter1.Numerator[0], FixedPointPrecisionForParameter);
|
float a00 = FixedPointHelper.ToFloat(numerator0Span[0], FixedPointPrecisionForParameter);
|
||||||
float a11 = FixedPointHelper.ToFloat(parameter1.Numerator[1], FixedPointPrecisionForParameter);
|
float a10 = FixedPointHelper.ToFloat(numerator0Span[1], FixedPointPrecisionForParameter);
|
||||||
float a21 = FixedPointHelper.ToFloat(parameter1.Numerator[2], FixedPointPrecisionForParameter);
|
float a20 = FixedPointHelper.ToFloat(numerator0Span[2], FixedPointPrecisionForParameter);
|
||||||
|
|
||||||
float b11 = FixedPointHelper.ToFloat(parameter1.Denominator[0], FixedPointPrecisionForParameter);
|
float b10 = FixedPointHelper.ToFloat(denominator0Span[0], FixedPointPrecisionForParameter);
|
||||||
float b21 = FixedPointHelper.ToFloat(parameter1.Denominator[1], FixedPointPrecisionForParameter);
|
float b20 = FixedPointHelper.ToFloat(denominator0Span[1], FixedPointPrecisionForParameter);
|
||||||
|
|
||||||
|
float a01 = FixedPointHelper.ToFloat(numerator1Span[0], FixedPointPrecisionForParameter);
|
||||||
|
float a11 = FixedPointHelper.ToFloat(numerator1Span[1], FixedPointPrecisionForParameter);
|
||||||
|
float a21 = FixedPointHelper.ToFloat(numerator1Span[2], FixedPointPrecisionForParameter);
|
||||||
|
|
||||||
|
float b11 = FixedPointHelper.ToFloat(denominator1Span[0], FixedPointPrecisionForParameter);
|
||||||
|
float b21 = FixedPointHelper.ToFloat(denominator1Span[1], FixedPointPrecisionForParameter);
|
||||||
|
|
||||||
for (int i = 0; i < sampleCount; i++)
|
for (int i = 0; i < sampleCount; i++)
|
||||||
{
|
{
|
||||||
@@ -261,19 +279,24 @@ namespace Ryujinx.Audio.Renderer.Dsp
|
|||||||
float volume,
|
float volume,
|
||||||
float ramp)
|
float ramp)
|
||||||
{
|
{
|
||||||
float a00 = FixedPointHelper.ToFloat(parameter0.Numerator[0], FixedPointPrecisionForParameter);
|
Span<short> numerator0Span = parameter0.Numerator.AsSpan();
|
||||||
float a10 = FixedPointHelper.ToFloat(parameter0.Numerator[1], FixedPointPrecisionForParameter);
|
Span<short> numerator1Span = parameter1.Numerator.AsSpan();
|
||||||
float a20 = FixedPointHelper.ToFloat(parameter0.Numerator[2], FixedPointPrecisionForParameter);
|
Span<short> denominator0Span = parameter0.Denominator.AsSpan();
|
||||||
|
Span<short> denominator1Span = parameter1.Denominator.AsSpan();
|
||||||
|
|
||||||
float b10 = FixedPointHelper.ToFloat(parameter0.Denominator[0], FixedPointPrecisionForParameter);
|
float a00 = FixedPointHelper.ToFloat(numerator0Span[0], FixedPointPrecisionForParameter);
|
||||||
float b20 = FixedPointHelper.ToFloat(parameter0.Denominator[1], FixedPointPrecisionForParameter);
|
float a10 = FixedPointHelper.ToFloat(numerator0Span[1], FixedPointPrecisionForParameter);
|
||||||
|
float a20 = FixedPointHelper.ToFloat(numerator0Span[2], FixedPointPrecisionForParameter);
|
||||||
|
|
||||||
float a01 = FixedPointHelper.ToFloat(parameter1.Numerator[0], FixedPointPrecisionForParameter);
|
float b10 = FixedPointHelper.ToFloat(denominator0Span[0], FixedPointPrecisionForParameter);
|
||||||
float a11 = FixedPointHelper.ToFloat(parameter1.Numerator[1], FixedPointPrecisionForParameter);
|
float b20 = FixedPointHelper.ToFloat(denominator0Span[1], FixedPointPrecisionForParameter);
|
||||||
float a21 = FixedPointHelper.ToFloat(parameter1.Numerator[2], FixedPointPrecisionForParameter);
|
|
||||||
|
|
||||||
float b11 = FixedPointHelper.ToFloat(parameter1.Denominator[0], FixedPointPrecisionForParameter);
|
float a01 = FixedPointHelper.ToFloat(numerator1Span[0], FixedPointPrecisionForParameter);
|
||||||
float b21 = FixedPointHelper.ToFloat(parameter1.Denominator[1], FixedPointPrecisionForParameter);
|
float a11 = FixedPointHelper.ToFloat(numerator1Span[1], FixedPointPrecisionForParameter);
|
||||||
|
float a21 = FixedPointHelper.ToFloat(numerator1Span[2], FixedPointPrecisionForParameter);
|
||||||
|
|
||||||
|
float b11 = FixedPointHelper.ToFloat(denominator1Span[0], FixedPointPrecisionForParameter);
|
||||||
|
float b21 = FixedPointHelper.ToFloat(denominator1Span[1], FixedPointPrecisionForParameter);
|
||||||
|
|
||||||
float mixState = 0f;
|
float mixState = 0f;
|
||||||
|
|
||||||
|
@@ -40,11 +40,13 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
|||||||
SampleRate = serverState.SampleRate;
|
SampleRate = serverState.SampleRate;
|
||||||
Pitch = serverState.Pitch;
|
Pitch = serverState.Pitch;
|
||||||
|
|
||||||
|
Span<Server.Voice.WaveBuffer> waveBufferSpan = serverState.WaveBuffers.AsSpan();
|
||||||
|
|
||||||
WaveBuffers = new WaveBuffer[Constants.VoiceWaveBufferCount];
|
WaveBuffers = new WaveBuffer[Constants.VoiceWaveBufferCount];
|
||||||
|
|
||||||
for (int i = 0; i < WaveBuffers.Length; i++)
|
for (int i = 0; i < WaveBuffers.Length; i++)
|
||||||
{
|
{
|
||||||
ref Server.Voice.WaveBuffer voiceWaveBuffer = ref serverState.WaveBuffers[i];
|
ref Server.Voice.WaveBuffer voiceWaveBuffer = ref waveBufferSpan[i];
|
||||||
|
|
||||||
WaveBuffers[i] = voiceWaveBuffer.ToCommon(1);
|
WaveBuffers[i] = voiceWaveBuffer.ToCommon(1);
|
||||||
}
|
}
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
using Ryujinx.Audio.Renderer.Parameter.Sink;
|
using Ryujinx.Audio.Renderer.Parameter.Sink;
|
||||||
using Ryujinx.Audio.Renderer.Server.MemoryPool;
|
using Ryujinx.Audio.Renderer.Server.MemoryPool;
|
||||||
|
using System;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
|
||||||
namespace Ryujinx.Audio.Renderer.Dsp.Command
|
namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||||
@@ -29,9 +30,11 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
|||||||
Input = new ushort[Constants.ChannelCountMax];
|
Input = new ushort[Constants.ChannelCountMax];
|
||||||
InputCount = parameter.InputCount;
|
InputCount = parameter.InputCount;
|
||||||
|
|
||||||
|
Span<byte> inputSpan = parameter.Input.AsSpan();
|
||||||
|
|
||||||
for (int i = 0; i < InputCount; i++)
|
for (int i = 0; i < InputCount; i++)
|
||||||
{
|
{
|
||||||
Input[i] = (ushort)(bufferOffset + parameter.Input[i]);
|
Input[i] = (ushort)(bufferOffset + inputSpan[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
CircularBuffer = circularBufferAddressInfo.GetReference(true);
|
CircularBuffer = circularBufferAddressInfo.GetReference(true);
|
||||||
|
@@ -43,10 +43,13 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
|||||||
InputBufferIndices = new ushort[Constants.VoiceChannelCountMax];
|
InputBufferIndices = new ushort[Constants.VoiceChannelCountMax];
|
||||||
OutputBufferIndices = new ushort[Constants.VoiceChannelCountMax];
|
OutputBufferIndices = new ushort[Constants.VoiceChannelCountMax];
|
||||||
|
|
||||||
|
Span<byte> inputSpan = _parameter.Input.AsSpan();
|
||||||
|
Span<byte> outputSpan = _parameter.Output.AsSpan();
|
||||||
|
|
||||||
for (int i = 0; i < _parameter.ChannelCount; i++)
|
for (int i = 0; i < _parameter.ChannelCount; i++)
|
||||||
{
|
{
|
||||||
InputBufferIndices[i] = (ushort)(bufferOffset + _parameter.Input[i]);
|
InputBufferIndices[i] = (ushort)(bufferOffset + inputSpan[i]);
|
||||||
OutputBufferIndices[i] = (ushort)(bufferOffset + _parameter.Output[i]);
|
OutputBufferIndices[i] = (ushort)(bufferOffset + outputSpan[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -172,9 +175,11 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
|||||||
statistics.MinimumGain = MathF.Min(statistics.MinimumGain, compressionGain * state.OutputGain);
|
statistics.MinimumGain = MathF.Min(statistics.MinimumGain, compressionGain * state.OutputGain);
|
||||||
statistics.MaximumMean = MathF.Max(statistics.MaximumMean, mean);
|
statistics.MaximumMean = MathF.Max(statistics.MaximumMean, mean);
|
||||||
|
|
||||||
|
Span<float> lastSamplesSpan = statistics.LastSamples.AsSpan();
|
||||||
|
|
||||||
for (int channelIndex = 0; channelIndex < _parameter.ChannelCount; channelIndex++)
|
for (int channelIndex = 0; channelIndex < _parameter.ChannelCount; channelIndex++)
|
||||||
{
|
{
|
||||||
statistics.LastSamples[channelIndex] = MathF.Abs(channelInput[channelIndex] * (1f / 32768f));
|
lastSamplesSpan[channelIndex] = MathF.Abs(channelInput[channelIndex] * (1f / 32768f));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -53,11 +53,13 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
|||||||
SampleRate = serverState.SampleRate;
|
SampleRate = serverState.SampleRate;
|
||||||
Pitch = serverState.Pitch;
|
Pitch = serverState.Pitch;
|
||||||
|
|
||||||
|
Span<Server.Voice.WaveBuffer> waveBufferSpan = serverState.WaveBuffers.AsSpan();
|
||||||
|
|
||||||
WaveBuffers = new WaveBuffer[Constants.VoiceWaveBufferCount];
|
WaveBuffers = new WaveBuffer[Constants.VoiceWaveBufferCount];
|
||||||
|
|
||||||
for (int i = 0; i < WaveBuffers.Length; i++)
|
for (int i = 0; i < WaveBuffers.Length; i++)
|
||||||
{
|
{
|
||||||
ref Server.Voice.WaveBuffer voiceWaveBuffer = ref serverState.WaveBuffers[i];
|
ref Server.Voice.WaveBuffer voiceWaveBuffer = ref waveBufferSpan[i];
|
||||||
|
|
||||||
WaveBuffers[i] = voiceWaveBuffer.ToCommon(2);
|
WaveBuffers[i] = voiceWaveBuffer.ToCommon(2);
|
||||||
}
|
}
|
||||||
|
@@ -43,10 +43,13 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
|||||||
InputBufferIndices = new ushort[Constants.VoiceChannelCountMax];
|
InputBufferIndices = new ushort[Constants.VoiceChannelCountMax];
|
||||||
OutputBufferIndices = new ushort[Constants.VoiceChannelCountMax];
|
OutputBufferIndices = new ushort[Constants.VoiceChannelCountMax];
|
||||||
|
|
||||||
|
Span<byte> inputSpan = Parameter.Input.AsSpan();
|
||||||
|
Span<byte> outputSpan = Parameter.Output.AsSpan();
|
||||||
|
|
||||||
for (int i = 0; i < Parameter.ChannelCount; i++)
|
for (int i = 0; i < Parameter.ChannelCount; i++)
|
||||||
{
|
{
|
||||||
InputBufferIndices[i] = (ushort)(bufferOffset + Parameter.Input[i]);
|
InputBufferIndices[i] = (ushort)(bufferOffset + inputSpan[i]);
|
||||||
OutputBufferIndices[i] = (ushort)(bufferOffset + Parameter.Output[i]);
|
OutputBufferIndices[i] = (ushort)(bufferOffset + outputSpan[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
DataSourceHelper.RemapLegacyChannelEffectMappingToChannelResourceMapping(newEffectChannelMappingSupported, InputBufferIndices, Parameter.ChannelCount);
|
DataSourceHelper.RemapLegacyChannelEffectMappingToChannelResourceMapping(newEffectChannelMappingSupported, InputBufferIndices, Parameter.ChannelCount);
|
||||||
|
@@ -42,14 +42,15 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
|||||||
ref VoiceUpdateState state = ref State.Span[0];
|
ref VoiceUpdateState state = ref State.Span[0];
|
||||||
|
|
||||||
Span<float> depopBuffer = DepopBuffer.Span;
|
Span<float> depopBuffer = DepopBuffer.Span;
|
||||||
|
Span<float> lastSamplesSpan = state.LastSamples.AsSpan();
|
||||||
|
|
||||||
for (int i = 0; i < MixBufferCount; i++)
|
for (int i = 0; i < MixBufferCount; i++)
|
||||||
{
|
{
|
||||||
if (state.LastSamples[i] != 0)
|
if (lastSamplesSpan[i] != 0)
|
||||||
{
|
{
|
||||||
depopBuffer[OutputBufferIndices[i]] += state.LastSamples[i];
|
depopBuffer[OutputBufferIndices[i]] += lastSamplesSpan[i];
|
||||||
|
|
||||||
state.LastSamples[i] = 0;
|
lastSamplesSpan[i] = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -35,9 +35,11 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
|||||||
InputCount = sink.Parameter.InputCount;
|
InputCount = sink.Parameter.InputCount;
|
||||||
InputBufferIndices = new ushort[InputCount];
|
InputBufferIndices = new ushort[InputCount];
|
||||||
|
|
||||||
|
Span<byte> inputSpan = sink.Parameter.Input.AsSpan();
|
||||||
|
|
||||||
for (int i = 0; i < Math.Min(InputCount, Constants.ChannelCountMax); i++)
|
for (int i = 0; i < Math.Min(InputCount, Constants.ChannelCountMax); i++)
|
||||||
{
|
{
|
||||||
InputBufferIndices[i] = (ushort)(bufferOffset + sink.Parameter.Input[i]);
|
InputBufferIndices[i] = (ushort)(bufferOffset + inputSpan[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sink.UpsamplerState != null)
|
if (sink.UpsamplerState != null)
|
||||||
|
@@ -38,10 +38,13 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
|||||||
InputBufferIndices = new ushort[Constants.VoiceChannelCountMax];
|
InputBufferIndices = new ushort[Constants.VoiceChannelCountMax];
|
||||||
OutputBufferIndices = new ushort[Constants.VoiceChannelCountMax];
|
OutputBufferIndices = new ushort[Constants.VoiceChannelCountMax];
|
||||||
|
|
||||||
|
Span<byte> inputSpan = _parameter.Input.AsSpan();
|
||||||
|
Span<byte> outputSpan = _parameter.Output.AsSpan();
|
||||||
|
|
||||||
for (int i = 0; i < _parameter.ChannelCount; i++)
|
for (int i = 0; i < _parameter.ChannelCount; i++)
|
||||||
{
|
{
|
||||||
InputBufferIndices[i] = (ushort)(bufferOffset + _parameter.Input[i]);
|
InputBufferIndices[i] = (ushort)(bufferOffset + inputSpan[i]);
|
||||||
OutputBufferIndices[i] = (ushort)(bufferOffset + _parameter.Output[i]);
|
OutputBufferIndices[i] = (ushort)(bufferOffset + outputSpan[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -49,10 +49,13 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
|||||||
InputBufferIndices = new ushort[Constants.VoiceChannelCountMax];
|
InputBufferIndices = new ushort[Constants.VoiceChannelCountMax];
|
||||||
OutputBufferIndices = new ushort[Constants.VoiceChannelCountMax];
|
OutputBufferIndices = new ushort[Constants.VoiceChannelCountMax];
|
||||||
|
|
||||||
|
Span<byte> inputSpan = _parameter.Input.AsSpan();
|
||||||
|
Span<byte> outputSpan = _parameter.Output.AsSpan();
|
||||||
|
|
||||||
for (int i = 0; i < _parameter.ChannelCount; i++)
|
for (int i = 0; i < _parameter.ChannelCount; i++)
|
||||||
{
|
{
|
||||||
InputBufferIndices[i] = (ushort)(bufferOffset + _parameter.Input[i]);
|
InputBufferIndices[i] = (ushort)(bufferOffset + inputSpan[i]);
|
||||||
OutputBufferIndices[i] = (ushort)(bufferOffset + _parameter.Output[i]);
|
OutputBufferIndices[i] = (ushort)(bufferOffset + outputSpan[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -150,8 +153,11 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
|||||||
{
|
{
|
||||||
ref LimiterStatistics statistics = ref MemoryMarshal.Cast<byte, LimiterStatistics>(ResultState.Span[0].SpecificData)[0];
|
ref LimiterStatistics statistics = ref MemoryMarshal.Cast<byte, LimiterStatistics>(ResultState.Span[0].SpecificData)[0];
|
||||||
|
|
||||||
statistics.InputMax[channelIndex] = Math.Max(statistics.InputMax[channelIndex], sampleInputMax);
|
Span<float> inputMaxSpan = statistics.InputMax.AsSpan();
|
||||||
statistics.CompressionGainMin[channelIndex] = Math.Min(statistics.CompressionGainMin[channelIndex], compressionGain);
|
Span<float> compressionGainMinSpan = statistics.CompressionGainMin.AsSpan();
|
||||||
|
|
||||||
|
inputMaxSpan[channelIndex] = Math.Max(inputMaxSpan[channelIndex], sampleInputMax);
|
||||||
|
compressionGainMinSpan[channelIndex] = Math.Min(compressionGainMinSpan[channelIndex], compressionGain);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -79,6 +79,10 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
|||||||
|
|
||||||
public void Process(CommandList context)
|
public void Process(CommandList context)
|
||||||
{
|
{
|
||||||
|
ref VoiceUpdateState state = ref State.Span[0];
|
||||||
|
|
||||||
|
Span<float> lastSamplesSpan = state.LastSamples.AsSpan();
|
||||||
|
|
||||||
for (int i = 0; i < MixBufferCount; i++)
|
for (int i = 0; i < MixBufferCount; i++)
|
||||||
{
|
{
|
||||||
ReadOnlySpan<float> inputBuffer = context.GetBuffer(InputBufferIndices[i]);
|
ReadOnlySpan<float> inputBuffer = context.GetBuffer(InputBufferIndices[i]);
|
||||||
@@ -87,15 +91,13 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
|||||||
float volume0 = Volume0[i];
|
float volume0 = Volume0[i];
|
||||||
float volume1 = Volume1[i];
|
float volume1 = Volume1[i];
|
||||||
|
|
||||||
ref VoiceUpdateState state = ref State.Span[0];
|
|
||||||
|
|
||||||
if (volume0 != 0 || volume1 != 0)
|
if (volume0 != 0 || volume1 != 0)
|
||||||
{
|
{
|
||||||
state.LastSamples[i] = ProcessMixRampGrouped(outputBuffer, inputBuffer, volume0, volume1, (int)context.SampleCount);
|
lastSamplesSpan[i] = ProcessMixRampGrouped(outputBuffer, inputBuffer, volume0, volume1, (int)context.SampleCount);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
state.LastSamples[i] = 0;
|
lastSamplesSpan[i] = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -43,9 +43,11 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
|||||||
|
|
||||||
WaveBuffers = new WaveBuffer[Constants.VoiceWaveBufferCount];
|
WaveBuffers = new WaveBuffer[Constants.VoiceWaveBufferCount];
|
||||||
|
|
||||||
|
Span<Server.Voice.WaveBuffer> waveBufferSpan = serverState.WaveBuffers.AsSpan();
|
||||||
|
|
||||||
for (int i = 0; i < WaveBuffers.Length; i++)
|
for (int i = 0; i < WaveBuffers.Length; i++)
|
||||||
{
|
{
|
||||||
ref Server.Voice.WaveBuffer voiceWaveBuffer = ref serverState.WaveBuffers[i];
|
ref Server.Voice.WaveBuffer voiceWaveBuffer = ref waveBufferSpan[i];
|
||||||
|
|
||||||
WaveBuffers[i] = voiceWaveBuffer.ToCommon(1);
|
WaveBuffers[i] = voiceWaveBuffer.ToCommon(1);
|
||||||
}
|
}
|
||||||
|
@@ -43,9 +43,11 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
|||||||
|
|
||||||
WaveBuffers = new WaveBuffer[Constants.VoiceWaveBufferCount];
|
WaveBuffers = new WaveBuffer[Constants.VoiceWaveBufferCount];
|
||||||
|
|
||||||
|
Span<Server.Voice.WaveBuffer> waveBufferSpan = serverState.WaveBuffers.AsSpan();
|
||||||
|
|
||||||
for (int i = 0; i < WaveBuffers.Length; i++)
|
for (int i = 0; i < WaveBuffers.Length; i++)
|
||||||
{
|
{
|
||||||
ref Server.Voice.WaveBuffer voiceWaveBuffer = ref serverState.WaveBuffers[i];
|
ref Server.Voice.WaveBuffer voiceWaveBuffer = ref waveBufferSpan[i];
|
||||||
|
|
||||||
WaveBuffers[i] = voiceWaveBuffer.ToCommon(1);
|
WaveBuffers[i] = voiceWaveBuffer.ToCommon(1);
|
||||||
}
|
}
|
||||||
|
@@ -66,10 +66,13 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
|||||||
InputBufferIndices = new ushort[Constants.VoiceChannelCountMax];
|
InputBufferIndices = new ushort[Constants.VoiceChannelCountMax];
|
||||||
OutputBufferIndices = new ushort[Constants.VoiceChannelCountMax];
|
OutputBufferIndices = new ushort[Constants.VoiceChannelCountMax];
|
||||||
|
|
||||||
|
Span<byte> inputSpan = Parameter.Input.AsSpan();
|
||||||
|
Span<byte> outputSpan = Parameter.Output.AsSpan();
|
||||||
|
|
||||||
for (int i = 0; i < Parameter.ChannelCount; i++)
|
for (int i = 0; i < Parameter.ChannelCount; i++)
|
||||||
{
|
{
|
||||||
InputBufferIndices[i] = (ushort)(bufferOffset + Parameter.Input[i]);
|
InputBufferIndices[i] = (ushort)(bufferOffset + inputSpan[i]);
|
||||||
OutputBufferIndices[i] = (ushort)(bufferOffset + Parameter.Output[i]);
|
OutputBufferIndices[i] = (ushort)(bufferOffset + outputSpan[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: We do the opposite as Nintendo here for now to restore previous behaviour
|
// NOTE: We do the opposite as Nintendo here for now to restore previous behaviour
|
||||||
|
@@ -64,10 +64,13 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
|||||||
InputBufferIndices = new ushort[Constants.VoiceChannelCountMax];
|
InputBufferIndices = new ushort[Constants.VoiceChannelCountMax];
|
||||||
OutputBufferIndices = new ushort[Constants.VoiceChannelCountMax];
|
OutputBufferIndices = new ushort[Constants.VoiceChannelCountMax];
|
||||||
|
|
||||||
|
Span<byte> inputSpan = Parameter.Input.AsSpan();
|
||||||
|
Span<byte> outputSpan = Parameter.Output.AsSpan();
|
||||||
|
|
||||||
for (int i = 0; i < Parameter.ChannelCount; i++)
|
for (int i = 0; i < Parameter.ChannelCount; i++)
|
||||||
{
|
{
|
||||||
InputBufferIndices[i] = (ushort)(bufferOffset + Parameter.Input[i]);
|
InputBufferIndices[i] = (ushort)(bufferOffset + inputSpan[i]);
|
||||||
OutputBufferIndices[i] = (ushort)(bufferOffset + Parameter.Output[i]);
|
OutputBufferIndices[i] = (ushort)(bufferOffset + outputSpan[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
IsLongSizePreDelaySupported = isLongSizePreDelaySupported;
|
IsLongSizePreDelaySupported = isLongSizePreDelaySupported;
|
||||||
|
@@ -74,7 +74,7 @@ namespace Ryujinx.Audio.Renderer.Dsp
|
|||||||
{
|
{
|
||||||
int tempBufferIndex = 0;
|
int tempBufferIndex = 0;
|
||||||
|
|
||||||
if (!info.DecodingBehaviour.HasFlag(DecodingBehaviour.SkipPitchAndSampleRateConversion))
|
if ((info.DecodingBehaviour & DecodingBehaviour.SkipPitchAndSampleRateConversion) != DecodingBehaviour.SkipPitchAndSampleRateConversion)
|
||||||
{
|
{
|
||||||
voiceState.Pitch.AsSpan()[..pitchMaxLength].CopyTo(tempBuffer);
|
voiceState.Pitch.AsSpan()[..pitchMaxLength].CopyTo(tempBuffer);
|
||||||
tempBufferIndex += pitchMaxLength;
|
tempBufferIndex += pitchMaxLength;
|
||||||
@@ -208,7 +208,7 @@ namespace Ryujinx.Audio.Renderer.Dsp
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (info.DecodingBehaviour.HasFlag(DecodingBehaviour.PlayedSampleCountResetWhenLooping))
|
if ((info.DecodingBehaviour & DecodingBehaviour.PlayedSampleCountResetWhenLooping) == DecodingBehaviour.PlayedSampleCountResetWhenLooping)
|
||||||
{
|
{
|
||||||
playedSampleCount = 0;
|
playedSampleCount = 0;
|
||||||
}
|
}
|
||||||
@@ -222,7 +222,7 @@ namespace Ryujinx.Audio.Renderer.Dsp
|
|||||||
|
|
||||||
Span<int> outputSpanInt = MemoryMarshal.Cast<float, int>(outputBuffer[i..]);
|
Span<int> outputSpanInt = MemoryMarshal.Cast<float, int>(outputBuffer[i..]);
|
||||||
|
|
||||||
if (info.DecodingBehaviour.HasFlag(DecodingBehaviour.SkipPitchAndSampleRateConversion))
|
if ((info.DecodingBehaviour & DecodingBehaviour.SkipPitchAndSampleRateConversion) == DecodingBehaviour.SkipPitchAndSampleRateConversion)
|
||||||
{
|
{
|
||||||
for (int j = 0; j < y; j++)
|
for (int j = 0; j < y; j++)
|
||||||
{
|
{
|
||||||
|
@@ -41,11 +41,12 @@ namespace Ryujinx.Audio.Renderer.Dsp
|
|||||||
}
|
}
|
||||||
|
|
||||||
Array20<float> result = new();
|
Array20<float> result = new();
|
||||||
|
Span<float> resultSpan = result.AsSpan();
|
||||||
|
|
||||||
for (int i = 0; i < FilterBankLength; i++)
|
for (int i = 0; i < FilterBankLength; i++)
|
||||||
{
|
{
|
||||||
float x = (Bank0CenterIndex - i) + offset;
|
float x = (Bank0CenterIndex - i) + offset;
|
||||||
result[i] = Sinc(x) * BlackmanWindow(x / FilterBankLength + 0.5f);
|
resultSpan[i] = Sinc(x) * BlackmanWindow(x / FilterBankLength + 0.5f);
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
@@ -79,6 +80,9 @@ namespace Ryujinx.Audio.Renderer.Dsp
|
|||||||
Debug.Assert(state.History.Length == HistoryLength);
|
Debug.Assert(state.History.Length == HistoryLength);
|
||||||
Debug.Assert(bank.Length == FilterBankLength);
|
Debug.Assert(bank.Length == FilterBankLength);
|
||||||
|
|
||||||
|
Span<float> bankSpan = bank.AsSpan();
|
||||||
|
Span<float> historySpan = state.History.AsSpan();
|
||||||
|
|
||||||
int curIdx = 0;
|
int curIdx = 0;
|
||||||
if (Vector.IsHardwareAccelerated)
|
if (Vector.IsHardwareAccelerated)
|
||||||
{
|
{
|
||||||
@@ -88,15 +92,15 @@ namespace Ryujinx.Audio.Renderer.Dsp
|
|||||||
while (curIdx < stopIdx)
|
while (curIdx < stopIdx)
|
||||||
{
|
{
|
||||||
result += Vector.Dot(
|
result += Vector.Dot(
|
||||||
new Vector<float>(bank.AsSpan().Slice(curIdx, Vector<float>.Count)),
|
new Vector<float>(bankSpan[curIdx..(curIdx + Vector<float>.Count)]),
|
||||||
new Vector<float>(state.History.AsSpan().Slice(curIdx, Vector<float>.Count)));
|
new Vector<float>(historySpan[curIdx..(curIdx + Vector<float>.Count)]));
|
||||||
curIdx += Vector<float>.Count;
|
curIdx += Vector<float>.Count;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
while (curIdx < FilterBankLength)
|
while (curIdx < FilterBankLength)
|
||||||
{
|
{
|
||||||
result += bank[curIdx] * state.History[curIdx];
|
result += bankSpan[curIdx] * historySpan[curIdx];
|
||||||
curIdx++;
|
curIdx++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -141,18 +141,20 @@ namespace Ryujinx.Audio.Renderer.Server
|
|||||||
{
|
{
|
||||||
bool supportsOptimizedPath = _rendererContext.BehaviourContext.UseMultiTapBiquadFilterProcessing();
|
bool supportsOptimizedPath = _rendererContext.BehaviourContext.UseMultiTapBiquadFilterProcessing();
|
||||||
|
|
||||||
if (supportsOptimizedPath && voiceState.BiquadFilters[0].Enable && voiceState.BiquadFilters[1].Enable)
|
Span<BiquadFilterParameter> biquadFiltersSpan = voiceState.BiquadFilters.AsSpan();
|
||||||
|
|
||||||
|
if (supportsOptimizedPath && biquadFiltersSpan[0].Enable && biquadFiltersSpan[1].Enable)
|
||||||
{
|
{
|
||||||
Memory<byte> biquadStateRawMemory = SpanMemoryManager<byte>.Cast(state)[..(Unsafe.SizeOf<BiquadFilterState>() * Constants.VoiceBiquadFilterCount)];
|
Memory<byte> biquadStateRawMemory = SpanMemoryManager<byte>.Cast(state)[..(Unsafe.SizeOf<BiquadFilterState>() * Constants.VoiceBiquadFilterCount)];
|
||||||
Memory<BiquadFilterState> stateMemory = SpanMemoryManager<BiquadFilterState>.Cast(biquadStateRawMemory);
|
Memory<BiquadFilterState> stateMemory = SpanMemoryManager<BiquadFilterState>.Cast(biquadStateRawMemory);
|
||||||
|
|
||||||
_commandBuffer.GenerateMultiTapBiquadFilter(baseIndex, voiceState.BiquadFilters.AsSpan(), stateMemory, bufferOffset, bufferOffset, voiceState.BiquadFilterNeedInitialization, nodeId);
|
_commandBuffer.GenerateMultiTapBiquadFilter(baseIndex, biquadFiltersSpan, stateMemory, bufferOffset, bufferOffset, voiceState.BiquadFilterNeedInitialization, nodeId);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
for (int i = 0; i < voiceState.BiquadFilters.Length; i++)
|
for (int i = 0; i < biquadFiltersSpan.Length; i++)
|
||||||
{
|
{
|
||||||
ref BiquadFilterParameter filter = ref voiceState.BiquadFilters[i];
|
ref BiquadFilterParameter filter = ref biquadFiltersSpan[i];
|
||||||
|
|
||||||
if (filter.Enable)
|
if (filter.Enable)
|
||||||
{
|
{
|
||||||
@@ -312,11 +314,14 @@ namespace Ryujinx.Audio.Renderer.Server
|
|||||||
int nodeId = voiceState.NodeId;
|
int nodeId = voiceState.NodeId;
|
||||||
uint channelsCount = voiceState.ChannelsCount;
|
uint channelsCount = voiceState.ChannelsCount;
|
||||||
|
|
||||||
|
Span<int> channelResourceIdsSpan = voiceState.ChannelResourceIds.AsSpan();
|
||||||
|
Span<BiquadFilterParameter> biquadFiltersSpan = voiceState.BiquadFilters.AsSpan();
|
||||||
|
|
||||||
for (int channelIndex = 0; channelIndex < channelsCount; channelIndex++)
|
for (int channelIndex = 0; channelIndex < channelsCount; channelIndex++)
|
||||||
{
|
{
|
||||||
Memory<VoiceUpdateState> dspStateMemory = _voiceContext.GetUpdateStateForDsp(voiceState.ChannelResourceIds[channelIndex]);
|
Memory<VoiceUpdateState> dspStateMemory = _voiceContext.GetUpdateStateForDsp(channelResourceIdsSpan[channelIndex]);
|
||||||
|
|
||||||
ref VoiceChannelResource channelResource = ref _voiceContext.GetChannelResource(voiceState.ChannelResourceIds[channelIndex]);
|
ref VoiceChannelResource channelResource = ref _voiceContext.GetChannelResource(channelResourceIdsSpan[channelIndex]);
|
||||||
|
|
||||||
PerformanceDetailType dataSourceDetailType = PerformanceDetailType.Adpcm;
|
PerformanceDetailType dataSourceDetailType = PerformanceDetailType.Adpcm;
|
||||||
|
|
||||||
@@ -476,7 +481,7 @@ namespace Ryujinx.Audio.Renderer.Server
|
|||||||
|
|
||||||
for (int i = 0; i < voiceState.BiquadFilterNeedInitialization.Length; i++)
|
for (int i = 0; i < voiceState.BiquadFilterNeedInitialization.Length; i++)
|
||||||
{
|
{
|
||||||
voiceState.BiquadFilterNeedInitialization[i] = voiceState.BiquadFilters[i].Enable;
|
voiceState.BiquadFilterNeedInitialization[i] = biquadFiltersSpan[i].Enable;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -526,15 +531,19 @@ namespace Ryujinx.Audio.Renderer.Server
|
|||||||
|
|
||||||
if (effect.IsEnabled)
|
if (effect.IsEnabled)
|
||||||
{
|
{
|
||||||
|
Span<float> volumesSpan = effect.Parameter.Volumes.AsSpan();
|
||||||
|
Span<byte> inputSpan = effect.Parameter.Input.AsSpan();
|
||||||
|
Span<byte> outputSpan = effect.Parameter.Output.AsSpan();
|
||||||
|
|
||||||
for (int i = 0; i < effect.Parameter.MixesCount; i++)
|
for (int i = 0; i < effect.Parameter.MixesCount; i++)
|
||||||
{
|
{
|
||||||
if (effect.Parameter.Volumes[i] != 0.0f)
|
if (volumesSpan[i] != 0.0f)
|
||||||
{
|
{
|
||||||
_commandBuffer.GenerateMix(
|
_commandBuffer.GenerateMix(
|
||||||
(uint)bufferOffset + effect.Parameter.Input[i],
|
(uint)bufferOffset + inputSpan[i],
|
||||||
(uint)bufferOffset + effect.Parameter.Output[i],
|
(uint)bufferOffset + outputSpan[i],
|
||||||
nodeId,
|
nodeId,
|
||||||
effect.Parameter.Volumes[i]);
|
volumesSpan[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -554,6 +563,10 @@ namespace Ryujinx.Audio.Renderer.Server
|
|||||||
{
|
{
|
||||||
int i = 0;
|
int i = 0;
|
||||||
uint writeOffset = 0;
|
uint writeOffset = 0;
|
||||||
|
|
||||||
|
Span<byte> inputSpan = effect.Parameter.Input.AsSpan();
|
||||||
|
Span<byte> outputSpan = effect.Parameter.Output.AsSpan();
|
||||||
|
|
||||||
for (uint channelIndex = effect.Parameter.ChannelCount; channelIndex != 0; channelIndex--)
|
for (uint channelIndex = effect.Parameter.ChannelCount; channelIndex != 0; channelIndex--)
|
||||||
{
|
{
|
||||||
uint newUpdateCount = writeOffset + _commandBuffer.CommandList.SampleCount;
|
uint newUpdateCount = writeOffset + _commandBuffer.CommandList.SampleCount;
|
||||||
@@ -571,8 +584,8 @@ namespace Ryujinx.Audio.Renderer.Server
|
|||||||
|
|
||||||
_commandBuffer.GenerateAuxEffect(
|
_commandBuffer.GenerateAuxEffect(
|
||||||
bufferOffset,
|
bufferOffset,
|
||||||
effect.Parameter.Input[i],
|
inputSpan[i],
|
||||||
effect.Parameter.Output[i],
|
outputSpan[i],
|
||||||
ref effect.State,
|
ref effect.State,
|
||||||
effect.IsEnabled,
|
effect.IsEnabled,
|
||||||
effect.Parameter.BufferStorageSize,
|
effect.Parameter.BufferStorageSize,
|
||||||
@@ -620,6 +633,9 @@ namespace Ryujinx.Audio.Renderer.Server
|
|||||||
{
|
{
|
||||||
Debug.Assert(effect.Type == EffectType.BiquadFilter);
|
Debug.Assert(effect.Type == EffectType.BiquadFilter);
|
||||||
|
|
||||||
|
Span<byte> inputSpan = effect.Parameter.Input.AsSpan();
|
||||||
|
Span<byte> outputSpan = effect.Parameter.Output.AsSpan();
|
||||||
|
|
||||||
if (effect.IsEnabled)
|
if (effect.IsEnabled)
|
||||||
{
|
{
|
||||||
bool needInitialization = effect.Parameter.Status == UsageState.Invalid ||
|
bool needInitialization = effect.Parameter.Status == UsageState.Invalid ||
|
||||||
@@ -639,8 +655,8 @@ namespace Ryujinx.Audio.Renderer.Server
|
|||||||
(int)bufferOffset,
|
(int)bufferOffset,
|
||||||
ref parameter,
|
ref parameter,
|
||||||
effect.State.Slice(i, 1),
|
effect.State.Slice(i, 1),
|
||||||
effect.Parameter.Input[i],
|
inputSpan[i],
|
||||||
effect.Parameter.Output[i],
|
outputSpan[i],
|
||||||
needInitialization,
|
needInitialization,
|
||||||
nodeId);
|
nodeId);
|
||||||
}
|
}
|
||||||
@@ -649,8 +665,8 @@ namespace Ryujinx.Audio.Renderer.Server
|
|||||||
{
|
{
|
||||||
for (int i = 0; i < effect.Parameter.ChannelCount; i++)
|
for (int i = 0; i < effect.Parameter.ChannelCount; i++)
|
||||||
{
|
{
|
||||||
uint inputBufferIndex = bufferOffset + effect.Parameter.Input[i];
|
uint inputBufferIndex = bufferOffset + inputSpan[i];
|
||||||
uint outputBufferIndex = bufferOffset + effect.Parameter.Output[i];
|
uint outputBufferIndex = bufferOffset + outputSpan[i];
|
||||||
|
|
||||||
// If the input and output isn't the same, generate a command.
|
// If the input and output isn't the same, generate a command.
|
||||||
if (inputBufferIndex != outputBufferIndex)
|
if (inputBufferIndex != outputBufferIndex)
|
||||||
@@ -702,6 +718,8 @@ namespace Ryujinx.Audio.Renderer.Server
|
|||||||
int i = 0;
|
int i = 0;
|
||||||
uint writeOffset = 0;
|
uint writeOffset = 0;
|
||||||
|
|
||||||
|
Span<byte> inputSpan = effect.Parameter.Input.AsSpan();
|
||||||
|
|
||||||
for (uint channelIndex = effect.Parameter.ChannelCount; channelIndex != 0; channelIndex--)
|
for (uint channelIndex = effect.Parameter.ChannelCount; channelIndex != 0; channelIndex--)
|
||||||
{
|
{
|
||||||
uint newUpdateCount = writeOffset + _commandBuffer.CommandList.SampleCount;
|
uint newUpdateCount = writeOffset + _commandBuffer.CommandList.SampleCount;
|
||||||
@@ -719,7 +737,7 @@ namespace Ryujinx.Audio.Renderer.Server
|
|||||||
|
|
||||||
_commandBuffer.GenerateCaptureEffect(
|
_commandBuffer.GenerateCaptureEffect(
|
||||||
bufferOffset,
|
bufferOffset,
|
||||||
effect.Parameter.Input[i],
|
inputSpan[i],
|
||||||
effect.State.SendBufferInfo,
|
effect.State.SendBufferInfo,
|
||||||
effect.IsEnabled,
|
effect.IsEnabled,
|
||||||
effect.Parameter.BufferStorageSize,
|
effect.Parameter.BufferStorageSize,
|
||||||
|
@@ -218,7 +218,8 @@ namespace Ryujinx.Audio.Renderer.Server.Splitter
|
|||||||
/// <returns>True if any biquad filter is enabled.</returns>
|
/// <returns>True if any biquad filter is enabled.</returns>
|
||||||
public bool IsBiquadFilterEnabled()
|
public bool IsBiquadFilterEnabled()
|
||||||
{
|
{
|
||||||
return _biquadFilters[0].Enable || _biquadFilters[1].Enable;
|
Span<BiquadFilterParameter> biquadFiltersSpan = _biquadFilters.AsSpan();
|
||||||
|
return biquadFiltersSpan[0].Enable || biquadFiltersSpan[1].Enable;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@@ -162,9 +162,11 @@ namespace Ryujinx.Audio.Renderer.Server
|
|||||||
{
|
{
|
||||||
ref VoiceState currentVoiceState = ref context.GetState(i);
|
ref VoiceState currentVoiceState = ref context.GetState(i);
|
||||||
|
|
||||||
|
Span<int> channelResourceIdsSpan = parameter.ChannelResourceIds.AsSpan();
|
||||||
|
|
||||||
for (int channelResourceIndex = 0; channelResourceIndex < parameter.ChannelCount; channelResourceIndex++)
|
for (int channelResourceIndex = 0; channelResourceIndex < parameter.ChannelCount; channelResourceIndex++)
|
||||||
{
|
{
|
||||||
int channelId = parameter.ChannelResourceIds[channelResourceIndex];
|
int channelId = channelResourceIdsSpan[channelResourceIndex];
|
||||||
|
|
||||||
Debug.Assert(channelId >= 0 && channelId < context.GetCount());
|
Debug.Assert(channelId >= 0 && channelId < context.GetCount());
|
||||||
|
|
||||||
|
@@ -126,9 +126,9 @@ namespace Ryujinx.Audio.Renderer.Server.Voice
|
|||||||
_sortedVoices.Span[i] = i;
|
_sortedVoices.Span[i] = i;
|
||||||
}
|
}
|
||||||
|
|
||||||
int[] sortedVoicesTemp = _sortedVoices[..(int)GetCount()].ToArray();
|
Span<int> sortedVoicesTemp = _sortedVoices[..(int)_voiceCount].Span;
|
||||||
|
|
||||||
Array.Sort(sortedVoicesTemp, (a, b) =>
|
sortedVoicesTemp.Sort((a, b) =>
|
||||||
{
|
{
|
||||||
ref VoiceState aState = ref GetState(a);
|
ref VoiceState aState = ref GetState(a);
|
||||||
ref VoiceState bState = ref GetState(b);
|
ref VoiceState bState = ref GetState(b);
|
||||||
@@ -143,7 +143,7 @@ namespace Ryujinx.Audio.Renderer.Server.Voice
|
|||||||
return result;
|
return result;
|
||||||
});
|
});
|
||||||
|
|
||||||
sortedVoicesTemp.AsSpan().CopyTo(_sortedVoices.Span);
|
// sortedVoicesTemp.CopyTo(_sortedVoices.Span);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -219,15 +219,17 @@ namespace Ryujinx.Audio.Renderer.Server.Voice
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private void InitializeWaveBuffers()
|
private void InitializeWaveBuffers()
|
||||||
{
|
{
|
||||||
for (int i = 0; i < WaveBuffers.Length; i++)
|
Span<WaveBuffer> waveBuffersSpan = WaveBuffers.AsSpan();
|
||||||
|
|
||||||
|
for (int i = 0; i < waveBuffersSpan.Length; i++)
|
||||||
{
|
{
|
||||||
WaveBuffers[i].StartSampleOffset = 0;
|
waveBuffersSpan[i].StartSampleOffset = 0;
|
||||||
WaveBuffers[i].EndSampleOffset = 0;
|
waveBuffersSpan[i].EndSampleOffset = 0;
|
||||||
WaveBuffers[i].ShouldLoop = false;
|
waveBuffersSpan[i].ShouldLoop = false;
|
||||||
WaveBuffers[i].IsEndOfStream = false;
|
waveBuffersSpan[i].IsEndOfStream = false;
|
||||||
WaveBuffers[i].BufferAddressInfo.Setup(0, 0);
|
waveBuffersSpan[i].BufferAddressInfo.Setup(0, 0);
|
||||||
WaveBuffers[i].ContextAddressInfo.Setup(0, 0);
|
waveBuffersSpan[i].ContextAddressInfo.Setup(0, 0);
|
||||||
WaveBuffers[i].IsSendToAudioProcessor = true;
|
waveBuffersSpan[i].IsSendToAudioProcessor = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -447,9 +449,12 @@ namespace Ryujinx.Audio.Renderer.Server.Voice
|
|||||||
|
|
||||||
ref VoiceUpdateState voiceUpdateState = ref voiceUpdateStates[0].Span[0];
|
ref VoiceUpdateState voiceUpdateState = ref voiceUpdateStates[0].Span[0];
|
||||||
|
|
||||||
|
Span<WaveBuffer> waveBuffersSpan = WaveBuffers.AsSpan();
|
||||||
|
Span<WaveBufferInternal> pWaveBuffersSpan = parameter.WaveBuffers.AsSpan();
|
||||||
|
|
||||||
for (int i = 0; i < Constants.VoiceWaveBufferCount; i++)
|
for (int i = 0; i < Constants.VoiceWaveBufferCount; i++)
|
||||||
{
|
{
|
||||||
UpdateWaveBuffer(errorInfos.AsSpan(i * 2, 2), ref WaveBuffers[i], ref parameter.WaveBuffers[i], parameter.SampleFormat, voiceUpdateState.IsWaveBufferValid[i], mapper, ref behaviourContext);
|
UpdateWaveBuffer(errorInfos.AsSpan(i * 2, 2), ref waveBuffersSpan[i], ref pWaveBuffersSpan[i], parameter.SampleFormat, voiceUpdateState.IsWaveBufferValid[i], mapper, ref behaviourContext);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -534,9 +539,11 @@ namespace Ryujinx.Audio.Renderer.Server.Voice
|
|||||||
/// <param name="context">The voice context.</param>
|
/// <param name="context">The voice context.</param>
|
||||||
private void ResetResources(VoiceContext context)
|
private void ResetResources(VoiceContext context)
|
||||||
{
|
{
|
||||||
|
Span<int> channelResourceIdsSpan = ChannelResourceIds.AsSpan();
|
||||||
|
|
||||||
for (int i = 0; i < ChannelsCount; i++)
|
for (int i = 0; i < ChannelsCount; i++)
|
||||||
{
|
{
|
||||||
int channelResourceId = ChannelResourceIds[i];
|
int channelResourceId = channelResourceIdsSpan[i];
|
||||||
|
|
||||||
ref VoiceChannelResource voiceChannelResource = ref context.GetChannelResource(channelResourceId);
|
ref VoiceChannelResource voiceChannelResource = ref context.GetChannelResource(channelResourceId);
|
||||||
|
|
||||||
@@ -560,9 +567,11 @@ namespace Ryujinx.Audio.Renderer.Server.Voice
|
|||||||
{
|
{
|
||||||
uint waveBufferIndex = WaveBuffersIndex;
|
uint waveBufferIndex = WaveBuffersIndex;
|
||||||
|
|
||||||
|
Span<WaveBuffer> waveBuffersSpan = WaveBuffers.AsSpan();
|
||||||
|
|
||||||
for (int i = 0; i < waveBufferCount; i++)
|
for (int i = 0; i < waveBufferCount; i++)
|
||||||
{
|
{
|
||||||
WaveBuffers[(int)waveBufferIndex].IsSendToAudioProcessor = true;
|
waveBuffersSpan[(int)waveBufferIndex].IsSendToAudioProcessor = true;
|
||||||
|
|
||||||
for (int j = 0; j < channelCount; j++)
|
for (int j = 0; j < channelCount; j++)
|
||||||
{
|
{
|
||||||
@@ -591,14 +600,18 @@ namespace Ryujinx.Audio.Renderer.Server.Voice
|
|||||||
FlushWaveBufferCount = 0;
|
FlushWaveBufferCount = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Span<WaveBuffer> waveBuffersSpan;
|
||||||
|
|
||||||
switch (PlayState)
|
switch (PlayState)
|
||||||
{
|
{
|
||||||
case PlayState.Started:
|
case PlayState.Started:
|
||||||
for (int i = 0; i < WaveBuffers.Length; i++)
|
waveBuffersSpan = WaveBuffers.AsSpan();
|
||||||
{
|
|
||||||
ref WaveBuffer wavebuffer = ref WaveBuffers[i];
|
|
||||||
|
|
||||||
if (!wavebuffer.IsSendToAudioProcessor)
|
for (int i = 0; i < waveBuffersSpan.Length; i++)
|
||||||
|
{
|
||||||
|
ref WaveBuffer waveBuffer = ref waveBuffersSpan[i];
|
||||||
|
|
||||||
|
if (!waveBuffer.IsSendToAudioProcessor)
|
||||||
{
|
{
|
||||||
for (int y = 0; y < ChannelsCount; y++)
|
for (int y = 0; y < ChannelsCount; y++)
|
||||||
{
|
{
|
||||||
@@ -607,7 +620,7 @@ namespace Ryujinx.Audio.Renderer.Server.Voice
|
|||||||
voiceUpdateStates[y].Span[0].IsWaveBufferValid[i] = true;
|
voiceUpdateStates[y].Span[0].IsWaveBufferValid[i] = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
wavebuffer.IsSendToAudioProcessor = true;
|
waveBuffer.IsSendToAudioProcessor = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -626,11 +639,13 @@ namespace Ryujinx.Audio.Renderer.Server.Voice
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
case PlayState.Stopping:
|
case PlayState.Stopping:
|
||||||
for (int i = 0; i < WaveBuffers.Length; i++)
|
waveBuffersSpan = WaveBuffers.AsSpan();
|
||||||
{
|
|
||||||
ref WaveBuffer wavebuffer = ref WaveBuffers[i];
|
|
||||||
|
|
||||||
wavebuffer.IsSendToAudioProcessor = true;
|
for (int i = 0; i < waveBuffersSpan.Length; i++)
|
||||||
|
{
|
||||||
|
ref WaveBuffer waveBuffer = ref waveBuffersSpan[i];
|
||||||
|
|
||||||
|
waveBuffer.IsSendToAudioProcessor = true;
|
||||||
|
|
||||||
for (int j = 0; j < ChannelsCount; j++)
|
for (int j = 0; j < ChannelsCount; j++)
|
||||||
{
|
{
|
||||||
@@ -702,9 +717,11 @@ namespace Ryujinx.Audio.Renderer.Server.Voice
|
|||||||
|
|
||||||
Memory<VoiceUpdateState>[] voiceUpdateStates = new Memory<VoiceUpdateState>[Constants.VoiceChannelCountMax];
|
Memory<VoiceUpdateState>[] voiceUpdateStates = new Memory<VoiceUpdateState>[Constants.VoiceChannelCountMax];
|
||||||
|
|
||||||
|
Span<int> channelResourceIdsSpan = ChannelResourceIds.AsSpan();
|
||||||
|
|
||||||
for (int i = 0; i < ChannelsCount; i++)
|
for (int i = 0; i < ChannelsCount; i++)
|
||||||
{
|
{
|
||||||
voiceUpdateStates[i] = context.GetUpdateStateForDsp(ChannelResourceIds[i]);
|
voiceUpdateStates[i] = context.GetUpdateStateForDsp(channelResourceIdsSpan[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return UpdateParametersForCommandGeneration(voiceUpdateStates);
|
return UpdateParametersForCommandGeneration(voiceUpdateStates);
|
||||||
|
@@ -131,7 +131,6 @@ namespace Ryujinx.Common.Collections
|
|||||||
if (parent.Predecessor != null)
|
if (parent.Predecessor != null)
|
||||||
{
|
{
|
||||||
newNode.Predecessor = parent.Predecessor;
|
newNode.Predecessor = parent.Predecessor;
|
||||||
parent.Predecessor = newNode;
|
|
||||||
newNode.Predecessor.Successor = newNode;
|
newNode.Predecessor.Successor = newNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,3 +1,5 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
namespace Ryujinx.Common.Memory
|
namespace Ryujinx.Common.Memory
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -17,5 +19,10 @@ namespace Ryujinx.Common.Memory
|
|||||||
/// Number of elements on the array.
|
/// Number of elements on the array.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
int Length { get; }
|
int Length { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Number of elements on the array.
|
||||||
|
/// </summary>
|
||||||
|
public Span<T> AsSpan();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
#nullable enable
|
#nullable enable
|
||||||
using System;
|
using System;
|
||||||
using System.Buffers;
|
using System.Buffers;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
@@ -10,11 +11,126 @@ namespace Ryujinx.Common.Memory
|
|||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// An <see cref="IMemoryOwner{T}"/> implementation with an embedded length and fast <see cref="Span{T}"/>
|
/// An <see cref="IMemoryOwner{T}"/> implementation with an embedded length and fast <see cref="Span{T}"/>
|
||||||
/// accessor, with memory allocated from <seealso cref="ArrayPool{T}.Shared"/>.
|
/// accessor, with memory allocated from <see cref="ArrayPooling"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="T">The type of item to store.</typeparam>
|
/// <typeparam name="T">The type of item to store.</typeparam>
|
||||||
public sealed class MemoryOwner<T> : IMemoryOwner<T>
|
public sealed class MemoryOwner<T> : IMemoryOwner<T>
|
||||||
{
|
{
|
||||||
|
private static class ArrayPooling
|
||||||
|
{
|
||||||
|
public class Holder(T[]? array = null) : IComparable<Holder>, IComparable<int>
|
||||||
|
{
|
||||||
|
public int SkipCount;
|
||||||
|
public readonly T[]? Array = array;
|
||||||
|
|
||||||
|
public int CompareTo(Holder? other)
|
||||||
|
{
|
||||||
|
return Array!.Length.CompareTo(other!.Array!.Length);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int CompareTo(int other)
|
||||||
|
{
|
||||||
|
int self = Array!.Length;
|
||||||
|
|
||||||
|
if (self < other)
|
||||||
|
{
|
||||||
|
SkipCount++;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (self > other * 4)
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReSharper disable once StaticMemberInGenericType
|
||||||
|
private static int _maxCacheCount = 50;
|
||||||
|
|
||||||
|
private const int MaxSkipCount = 50;
|
||||||
|
|
||||||
|
static readonly List<Holder> _pool = new();
|
||||||
|
|
||||||
|
// ReSharper disable once StaticMemberInGenericType
|
||||||
|
static readonly Lock _lock = new();
|
||||||
|
|
||||||
|
private static int BinarySearch(List<Holder> list, int size)
|
||||||
|
{
|
||||||
|
int min = 0;
|
||||||
|
int max = list.Count-1;
|
||||||
|
|
||||||
|
while (min <= max)
|
||||||
|
{
|
||||||
|
int mid = (min + max) / 2;
|
||||||
|
int comparison = list[mid].CompareTo(size);
|
||||||
|
if (comparison == 0)
|
||||||
|
{
|
||||||
|
return mid;
|
||||||
|
}
|
||||||
|
if (comparison < 0)
|
||||||
|
{
|
||||||
|
min = mid+1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
max = mid-1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ~min;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static T[] Get(int minimumSize)
|
||||||
|
{
|
||||||
|
lock (_lock)
|
||||||
|
{
|
||||||
|
int index = BinarySearch(_pool, minimumSize);
|
||||||
|
|
||||||
|
if (index >= 0)
|
||||||
|
{
|
||||||
|
Holder holder = _pool[index];
|
||||||
|
|
||||||
|
_pool.Remove(holder);
|
||||||
|
return holder.Array!;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new T[minimumSize];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Return(T[] array)
|
||||||
|
{
|
||||||
|
|
||||||
|
lock (_lock)
|
||||||
|
{
|
||||||
|
Holder holder = new(array);
|
||||||
|
int i = _pool.BinarySearch(holder);
|
||||||
|
if (i < 0)
|
||||||
|
{
|
||||||
|
_pool.Insert(~i, holder);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_pool.Count >= _maxCacheCount)
|
||||||
|
{
|
||||||
|
for (int index = 0; index < _pool.Count; index++)
|
||||||
|
{
|
||||||
|
Holder h = _pool[index];
|
||||||
|
|
||||||
|
if (h.SkipCount >= MaxSkipCount)
|
||||||
|
{
|
||||||
|
_pool.Remove(h);
|
||||||
|
index--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_maxCacheCount = _pool.Count * 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private readonly int _length;
|
private readonly int _length;
|
||||||
private T[]? _array;
|
private T[]? _array;
|
||||||
|
|
||||||
@@ -25,7 +141,7 @@ namespace Ryujinx.Common.Memory
|
|||||||
private MemoryOwner(int length)
|
private MemoryOwner(int length)
|
||||||
{
|
{
|
||||||
_length = length;
|
_length = length;
|
||||||
_array = ArrayPool<T>.Shared.Rent(length);
|
_array = ArrayPooling.Get(length);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -124,7 +240,7 @@ namespace Ryujinx.Common.Memory
|
|||||||
|
|
||||||
if (array is not null)
|
if (array is not null)
|
||||||
{
|
{
|
||||||
ArrayPool<T>.Shared.Return(array, RuntimeHelpers.IsReferenceOrContainsReferences<T>());
|
ArrayPooling.Return(array);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,3 +1,4 @@
|
|||||||
|
using System;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using static Ryujinx.Common.Memory.PartialUnmaps.PartialUnmapHelpers;
|
using static Ryujinx.Common.Memory.PartialUnmaps.PartialUnmapHelpers;
|
||||||
@@ -43,9 +44,12 @@ namespace Ryujinx.Common.Memory.PartialUnmaps
|
|||||||
{
|
{
|
||||||
// Try get a match first.
|
// Try get a match first.
|
||||||
|
|
||||||
|
Span<int> threadIdsSpan = ThreadIds.AsSpan();
|
||||||
|
Span<T> structsSpan = Structs.AsSpan();
|
||||||
|
|
||||||
for (int i = 0; i < MapSize; i++)
|
for (int i = 0; i < MapSize; i++)
|
||||||
{
|
{
|
||||||
int compare = Interlocked.CompareExchange(ref ThreadIds[i], threadId, threadId);
|
int compare = Interlocked.CompareExchange(ref threadIdsSpan[i], threadId, threadId);
|
||||||
|
|
||||||
if (compare == threadId)
|
if (compare == threadId)
|
||||||
{
|
{
|
||||||
@@ -57,11 +61,11 @@ namespace Ryujinx.Common.Memory.PartialUnmaps
|
|||||||
|
|
||||||
for (int i = 0; i < MapSize; i++)
|
for (int i = 0; i < MapSize; i++)
|
||||||
{
|
{
|
||||||
int compare = Interlocked.CompareExchange(ref ThreadIds[i], threadId, 0);
|
int compare = Interlocked.CompareExchange(ref threadIdsSpan[i], threadId, 0);
|
||||||
|
|
||||||
if (compare == 0)
|
if (compare == 0)
|
||||||
{
|
{
|
||||||
Structs[i] = initial;
|
structsSpan[i] = initial;
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -2,8 +2,18 @@ namespace Ryujinx.Common
|
|||||||
{
|
{
|
||||||
public static class SharedConstants
|
public static class SharedConstants
|
||||||
{
|
{
|
||||||
public const string DefaultLanPlayHost = "ryuldn.vudjun.com";
|
public const string DefaultLanPlayHost = "ldn.ryujinx.app";
|
||||||
public const short LanPlayPort = 30456;
|
public const short LanPlayPort = 30456;
|
||||||
public const string DefaultLanPlayWebHost = "ryuldnweb.vudjun.com";
|
public const string DefaultLanPlayWebHost = DefaultLanPlayHost;
|
||||||
|
|
||||||
|
public const string AmiiboTagsUrl = "https://raw.githubusercontent.com/Ryubing/Nfc/refs/heads/main/tags.json";
|
||||||
|
|
||||||
|
public const string FaqWikiUrl = "https://git.ryujinx.app/ryubing/ryujinx/-/wikis/FAQ-&-Troubleshooting";
|
||||||
|
|
||||||
|
public const string SetupGuideWikiUrl =
|
||||||
|
"https://git.ryujinx.app/ryubing/ryujinx/-/wikis/Setup-&-Configuration-Guide";
|
||||||
|
|
||||||
|
public const string MultiplayerWikiUrl =
|
||||||
|
"https://git.ryujinx.app/ryubing/ryujinx/-/wikis/Multiplayer-(LDN-Local-Wireless)-Guide";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -182,6 +182,7 @@ namespace Ryujinx.Common
|
|||||||
"01001cc01b2d4000", // Goat Simulator 3
|
"01001cc01b2d4000", // Goat Simulator 3
|
||||||
"01003620068ea000", // Hand of Fate 2
|
"01003620068ea000", // Hand of Fate 2
|
||||||
"0100f7e00c70e000", // Hogwarts Legacy
|
"0100f7e00c70e000", // Hogwarts Legacy
|
||||||
|
"010013c00e930000", // Hollow Knight: Silksong
|
||||||
"010085500130a000", // Lego City: Undercover
|
"010085500130a000", // Lego City: Undercover
|
||||||
"010073c01af34000", // LEGO Horizon Adventures
|
"010073c01af34000", // LEGO Horizon Adventures
|
||||||
"0100d71004694000", // Minecraft
|
"0100d71004694000", // Minecraft
|
||||||
|
@@ -17,7 +17,7 @@ namespace Ryujinx.Cpu.Jit
|
|||||||
_functionTable = AddressTable<ulong>.CreateForArm(for64Bit, memory.Type);
|
_functionTable = AddressTable<ulong>.CreateForArm(for64Bit, memory.Type);
|
||||||
_translator = new Translator(new JitMemoryAllocator(forJit: true), memory, _functionTable);
|
_translator = new Translator(new JitMemoryAllocator(forJit: true), memory, _functionTable);
|
||||||
|
|
||||||
if (memory.Type.IsHostMappedOrTracked())
|
if (memory.Type.IsHostMappedOrTracked)
|
||||||
{
|
{
|
||||||
NativeSignalHandler.InitializeSignalHandler();
|
NativeSignalHandler.InitializeSignalHandler();
|
||||||
}
|
}
|
||||||
|
@@ -26,7 +26,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm32
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_operand.Type.IsInteger())
|
if (_operand.Type.IsInteger)
|
||||||
{
|
{
|
||||||
_registerAllocator.FreeTempGprRegister(_operand.AsInt32());
|
_registerAllocator.FreeTempGprRegister(_operand.AsInt32());
|
||||||
}
|
}
|
||||||
|
@@ -381,7 +381,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64
|
|||||||
if (currentCond != ArmCondition.Al)
|
if (currentCond != ArmCondition.Al)
|
||||||
{
|
{
|
||||||
instructionPointer = context.CodeWriter.InstructionPointer;
|
instructionPointer = context.CodeWriter.InstructionPointer;
|
||||||
context.Arm64Assembler.B(currentCond.Invert(), 0);
|
context.Arm64Assembler.B(currentCond.Inverse, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -104,7 +104,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64
|
|||||||
|
|
||||||
if (invert)
|
if (invert)
|
||||||
{
|
{
|
||||||
conditions[i++] = ((ArmCondition)firstCond).Invert();
|
conditions[i++] = ((ArmCondition)firstCond).Inverse;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@@ -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
|
// 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.
|
// and can never reach out of the guest address space.
|
||||||
|
|
||||||
if (mmType.IsHostTracked())
|
if (mmType.IsHostTracked)
|
||||||
{
|
{
|
||||||
int tempRegister = regAlloc.AllocateTempGprRegister();
|
int tempRegister = regAlloc.AllocateTempGprRegister();
|
||||||
|
|
||||||
@@ -1141,7 +1141,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64
|
|||||||
|
|
||||||
regAlloc.FreeTempGprRegister(tempRegister);
|
regAlloc.FreeTempGprRegister(tempRegister);
|
||||||
}
|
}
|
||||||
else if (mmType.IsHostMapped())
|
else if (mmType.IsHostMapped)
|
||||||
{
|
{
|
||||||
asm.Add(destination64, basePointer, guestAddress);
|
asm.Add(destination64, basePointer, guestAddress);
|
||||||
}
|
}
|
||||||
|
@@ -132,7 +132,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm64
|
|||||||
|
|
||||||
InstName lastInstructionName = Instructions[^1].Name;
|
InstName lastInstructionName = Instructions[^1].Name;
|
||||||
|
|
||||||
return lastInstructionName.IsCall() || lastInstructionName.IsException();
|
return lastInstructionName.IsCall || lastInstructionName.IsException;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1042,126 +1042,39 @@ namespace Ryujinx.Cpu.LightningJit.Arm64
|
|||||||
|
|
||||||
static class InstNameExtensions
|
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)
|
public bool IsControlFlowOrException => name is
|
||||||
{
|
InstName.BUncond or InstName.BCond or InstName.Bl or InstName.Blr or InstName.Br or InstName.Brk
|
||||||
switch (name)
|
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:
|
InstName.Mrs or InstName.MsrImm or InstName.MsrReg => true,
|
||||||
case InstName.BCond:
|
_ => name.IsException
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
public bool IsPrivileged => name is
|
||||||
{
|
InstName.Dcps1 or InstName.Dcps2 or InstName.Dcps3 or InstName.Drps or InstName.Eret or InstName.Ereta
|
||||||
switch (name)
|
or InstName.Hvc or InstName.MsrImm or InstName.Smc;
|
||||||
{
|
|
||||||
case InstName.Brk:
|
|
||||||
case InstName.Svc:
|
|
||||||
case InstName.UdfPermUndef:
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
public bool IsPrefetchMemory => name is
|
||||||
{
|
InstName.PrfmImm or InstName.PrfmLit or InstName.PrfmReg or InstName.Prfum;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -150,7 +150,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm64
|
|||||||
|
|
||||||
public static int CalculateMaxTemps(MemoryManagerType mmType)
|
public static int CalculateMaxTemps(MemoryManagerType mmType)
|
||||||
{
|
{
|
||||||
return mmType.IsHostMapped() ? 1 : 2;
|
return mmType.IsHostMapped ? 1 : 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int CalculateMaxTempsInclFixed(MemoryManagerType mmType)
|
public static int CalculateMaxTempsInclFixed(MemoryManagerType mmType)
|
||||||
|
@@ -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))
|
if (flags.HasFlag(InstFlags.Rt))
|
||||||
{
|
{
|
||||||
@@ -281,7 +281,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm64
|
|||||||
gprMask |= MaskFromIndex(ExtractRd(flags, encoding));
|
gprMask |= MaskFromIndex(ExtractRd(flags, encoding));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!flags.HasFlag(InstFlags.ReadRt) || name.IsPartialRegisterUpdateMemory())
|
if (!flags.HasFlag(InstFlags.ReadRt) || name.IsPartialRegisterUpdateMemory)
|
||||||
{
|
{
|
||||||
if (flags.HasFlag(InstFlags.Rt))
|
if (flags.HasFlag(InstFlags.Rt))
|
||||||
{
|
{
|
||||||
|
@@ -364,7 +364,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm64.Target.Arm64
|
|||||||
{
|
{
|
||||||
InstEmitMemory.RewriteSysInstruction(memoryManager.AddressSpaceBits, memoryManager.Type, writer, regAlloc, encoding);
|
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);
|
bool needsContextStoreLoad = InstEmitSystem.NeedsContextStoreLoad(instInfo.Name);
|
||||||
|
|
||||||
@@ -405,7 +405,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm64.Target.Arm64
|
|||||||
|
|
||||||
lastInstructionEncoding = RegisterUtils.RemapRegisters(regAlloc, lastInstructionFlags, lastInstructionEncoding);
|
lastInstructionEncoding = RegisterUtils.RemapRegisters(regAlloc, lastInstructionFlags, lastInstructionEncoding);
|
||||||
|
|
||||||
if (lastInstructionName.IsCall())
|
if (lastInstructionName.IsCall)
|
||||||
{
|
{
|
||||||
context.StoreToContextBeforeCall(blockIndex, pc + 4UL);
|
context.StoreToContextBeforeCall(blockIndex, pc + 4UL);
|
||||||
|
|
||||||
|
@@ -257,7 +257,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm64.Target.Arm64
|
|||||||
|
|
||||||
(name, flags, AddressForm addressForm) = InstTable.GetInstNameAndFlags(encoding, cpuPreset.Version, cpuPreset.Features);
|
(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;
|
name = InstName.UdfPermUndef;
|
||||||
flags = InstFlags.None;
|
flags = InstFlags.None;
|
||||||
@@ -267,7 +267,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm64.Target.Arm64
|
|||||||
(uint instGprReadMask, uint instFpSimdReadMask) = RegisterUtils.PopulateReadMasks(name, flags, encoding);
|
(uint instGprReadMask, uint instFpSimdReadMask) = RegisterUtils.PopulateReadMasks(name, flags, encoding);
|
||||||
(uint instGprWriteMask, uint instFpSimdWriteMask) = RegisterUtils.PopulateWriteMasks(name, flags, encoding);
|
(uint instGprWriteMask, uint instFpSimdWriteMask) = RegisterUtils.PopulateWriteMasks(name, flags, encoding);
|
||||||
|
|
||||||
if (name.IsCall())
|
if (name.IsCall)
|
||||||
{
|
{
|
||||||
instGprWriteMask |= 1u << RegisterUtils.LrIndex;
|
instGprWriteMask |= 1u << RegisterUtils.LrIndex;
|
||||||
}
|
}
|
||||||
@@ -310,12 +310,12 @@ namespace Ryujinx.Cpu.LightningJit.Arm64.Target.Arm64
|
|||||||
fpSimdUseMask |= instFpSimdReadMask | instFpSimdWriteMask;
|
fpSimdUseMask |= instFpSimdReadMask | instFpSimdWriteMask;
|
||||||
pStateUseMask |= instPStateReadMask | instPStateWriteMask;
|
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(
|
RegisterUse registerUse = new(
|
||||||
instGprReadMask,
|
instGprReadMask,
|
||||||
@@ -339,7 +339,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm64.Target.Arm64
|
|||||||
|
|
||||||
useMask = new(gprUseMask, fpSimdUseMask, pStateUseMask);
|
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)
|
private static bool IsPrivilegedSys(uint encoding)
|
||||||
|
@@ -55,7 +55,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm64.Target.Arm64
|
|||||||
ulong pc,
|
ulong pc,
|
||||||
uint encoding)
|
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
|
// 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,
|
// 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);
|
Operand basePointer = new(regAlloc.FixedPageTableRegister, RegisterType.Integer, OperandType.I64);
|
||||||
|
|
||||||
if (mmType.IsHostTracked())
|
if (mmType.IsHostTracked)
|
||||||
{
|
{
|
||||||
int tempRegister = regAlloc.AllocateTempGprRegister();
|
int tempRegister = regAlloc.AllocateTempGprRegister();
|
||||||
|
|
||||||
@@ -562,7 +562,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm64.Target.Arm64
|
|||||||
|
|
||||||
regAlloc.FreeTempGprRegister(tempRegister);
|
regAlloc.FreeTempGprRegister(tempRegister);
|
||||||
}
|
}
|
||||||
else if (mmType.IsHostMapped())
|
else if (mmType.IsHostMapped)
|
||||||
{
|
{
|
||||||
if (mmType == MemoryManagerType.HostMapped)
|
if (mmType == MemoryManagerType.HostMapped)
|
||||||
{
|
{
|
||||||
|
@@ -22,9 +22,9 @@ namespace Ryujinx.Cpu.LightningJit.CodeGen.Arm64
|
|||||||
|
|
||||||
static class ArmConditionExtensions
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -673,7 +673,7 @@ namespace Ryujinx.Cpu.LightningJit.CodeGen.Arm64
|
|||||||
|
|
||||||
public readonly void Mov(Operand rd, Operand rn)
|
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);
|
Orr(rd, new Operand(ZrRegister, RegisterType.Integer, rd.Type), rn);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4544,7 +4544,7 @@ namespace Ryujinx.Cpu.LightningJit.CodeGen.Arm64
|
|||||||
uint instruction;
|
uint instruction;
|
||||||
int scale;
|
int scale;
|
||||||
|
|
||||||
if (type.IsInteger())
|
if (type.IsInteger)
|
||||||
{
|
{
|
||||||
instruction = intInst;
|
instruction = intInst;
|
||||||
|
|
||||||
@@ -4580,7 +4580,7 @@ namespace Ryujinx.Cpu.LightningJit.CodeGen.Arm64
|
|||||||
{
|
{
|
||||||
uint instruction;
|
uint instruction;
|
||||||
|
|
||||||
if (type.IsInteger())
|
if (type.IsInteger)
|
||||||
{
|
{
|
||||||
instruction = intInst;
|
instruction = intInst;
|
||||||
|
|
||||||
@@ -4610,7 +4610,7 @@ namespace Ryujinx.Cpu.LightningJit.CodeGen.Arm64
|
|||||||
{
|
{
|
||||||
uint instruction;
|
uint instruction;
|
||||||
|
|
||||||
if (type.IsInteger())
|
if (type.IsInteger)
|
||||||
{
|
{
|
||||||
instruction = intInst;
|
instruction = intInst;
|
||||||
|
|
||||||
|
@@ -34,7 +34,7 @@ namespace Ryujinx.Cpu.LightningJit.CodeGen.Arm64
|
|||||||
int gprCalleeSavedRegsCount = BitOperations.PopCount(_gprMask);
|
int gprCalleeSavedRegsCount = BitOperations.PopCount(_gprMask);
|
||||||
int fpSimdCalleeSavedRegsCount = BitOperations.PopCount(_fpSimdMask);
|
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)
|
public void WritePrologue(ref Assembler asm)
|
||||||
@@ -46,7 +46,7 @@ namespace Ryujinx.Cpu.LightningJit.CodeGen.Arm64
|
|||||||
int fpSimdCalleeSavedRegsCount = BitOperations.PopCount(fpSimdMask);
|
int fpSimdCalleeSavedRegsCount = BitOperations.PopCount(fpSimdMask);
|
||||||
|
|
||||||
int reservedStackSize = Align16(_reservedStackSize);
|
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;
|
int offset = 0;
|
||||||
|
|
||||||
WritePrologueCalleeSavesPreIndexed(ref asm, ref gprMask, ref offset, calleeSaveRegionSize, OperandType.I64);
|
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);
|
asm.StrRiUn(Register(reg, type), Register(Assembler.SpRegister), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
offset += type.GetSizeInBytes();
|
offset += type.ByteSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (mask != 0)
|
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);
|
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;
|
bool misalignedVector = _fpSimdType == OperandType.V128 && (gprCalleeSavedRegsCount & 1) != 0;
|
||||||
|
|
||||||
int offset = gprCalleeSavedRegsCount * 8 + fpSimdCalleeSavedRegsCount * _fpSimdType.GetSizeInBytes();
|
int offset = gprCalleeSavedRegsCount * 8 + fpSimdCalleeSavedRegsCount * _fpSimdType.ByteSize;
|
||||||
|
|
||||||
if (misalignedVector)
|
if (misalignedVector)
|
||||||
{
|
{
|
||||||
@@ -197,7 +197,7 @@ namespace Ryujinx.Cpu.LightningJit.CodeGen.Arm64
|
|||||||
|
|
||||||
mask &= ~(1u << reg2);
|
mask &= ~(1u << reg2);
|
||||||
|
|
||||||
offset -= type.GetSizeInBytes() * 2;
|
offset -= type.ByteSize * 2;
|
||||||
|
|
||||||
if (offset != 0)
|
if (offset != 0)
|
||||||
{
|
{
|
||||||
@@ -215,7 +215,7 @@ namespace Ryujinx.Cpu.LightningJit.CodeGen.Arm64
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
offset -= type.GetSizeInBytes();
|
offset -= type.ByteSize;
|
||||||
|
|
||||||
if (offset != 0)
|
if (offset != 0)
|
||||||
{
|
{
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user