Compare commits
157 Commits
Author | SHA1 | Date | |
---|---|---|---|
b8556530f2 | |||
4f3af839be | |||
155736c986 | |||
dba908dc78 | |||
ecee34a50c | |||
9b5a0c3889 | |||
80b4972139 | |||
5d85468302 | |||
9b1cc2cec6 | |||
e691622f0a | |||
f663a5cd38 | |||
f7c2e867f4 | |||
cedd200745 | |||
58207685c0 | |||
095ad923ad | |||
f07ae7d53f | |||
c308f09722 | |||
f1eef29409 | |||
1f8d66db7c | |||
c3a5716a95 | |||
1f1e2a7f03 | |||
e54f9dc4b4 | |||
edfd4d70c0 | |||
fc43aecbbd | |||
58d7a1fe97 | |||
7aa430f1a5 | |||
6bf460e104 | |||
efb135b74c | |||
a707842e14 | |||
a5a9b9bc8b | |||
17078ad929 | |||
32450d45de | |||
ed7a0474c6 | |||
fe9c49949a | |||
052b23c83c | |||
e4f68592c3 | |||
1dcd44b94f | |||
61b1ce252f | |||
5f38086f94 | |||
7bae440d3a | |||
f1943fd0b6 | |||
ec8d4f3af5 | |||
b3f0978869 | |||
f614d2c435 | |||
40c9416097 | |||
618c8edc79 | |||
99fc4fa61b | |||
f6d5499a16 | |||
26bf13a65d | |||
96cf242bcf | |||
59755818ef | |||
f8beeeb7d3 | |||
cb250162cb | |||
7528f94536 | |||
43081c16c4 | |||
780627e7b0 | |||
9044cb38d1 | |||
a53cfdab78 | |||
c7f9962dde | |||
296c4a3d01 | |||
e7cf4e6eaf | |||
a1a4771ac1 | |||
2fd819613f | |||
ad6ff6ce99 | |||
dc30d94852 | |||
4f293f8cbe | |||
32a1cd83fd | |||
e3d0ccf8d5 | |||
c14844d12c | |||
7fea26e97e | |||
7b7f62c776 | |||
423dbc8888 | |||
6adf15e479 | |||
2747f12591 | |||
a47824f961 | |||
8474d52778 | |||
dd7a924596 | |||
a76eaf9a9a | |||
009e6bcd1b | |||
eb2cc159fa | |||
bb89e36fd8 | |||
de3134adbe | |||
36d53819a4 | |||
ae4324032a | |||
f449895e6d | |||
410be95ab6 | |||
cff9046fc7 | |||
86fd0643c2 | |||
43a83a401e | |||
f0e27a23a5 | |||
e68650237d | |||
1faff14e73 | |||
784cf9d594 | |||
64263c5218 | |||
065c4e520d | |||
139a930407 | |||
719dc97bbd | |||
41bba5310a | |||
8071c8c8c0 | |||
b402b4e7f6 | |||
93df366b2c | |||
cd3a15aea5 | |||
070136b3f7 | |||
08ab47c6c0 | |||
85faa9d8fa | |||
dca5b14493 | |||
4d2c8e2a44 | |||
8fa248ceb4 | |||
30862b5ffd | |||
9f57747c57 | |||
fe29a2ff6e | |||
e9a173e00c | |||
a11784fcbf | |||
fd36c8deca | |||
70638340b3 | |||
4b495f3333 | |||
934b5a64e5 | |||
cee667b491 | |||
94a64f2aea | |||
2355c2af62 | |||
5e0f8e8738 | |||
d16288a2a8 | |||
600f86dc7b | |||
7210c17c5e | |||
a16854e55a | |||
3e455a90a1 | |||
e4413542b2 | |||
8c720783f5 | |||
8734ea9dd4 | |||
c586e6d2b7 | |||
3a4eeb77fe | |||
51b3953cfc | |||
610eecc1c1 | |||
492056abf6 | |||
ee6e682ab4 | |||
6f60e102a2 | |||
eeb2af9953 | |||
550747eac6 | |||
3ffceab1fb | |||
b9f2a96595 | |||
cbaa845f5d | |||
9e2681f2d7 | |||
81fae0d1a6 | |||
38519f3b9a | |||
7f27aabbd0 | |||
e876c43ce9 | |||
8639245533 | |||
d6b86a6629 | |||
8f2b7b5b8e | |||
fc4b7cba2c | |||
08831eecf7 | |||
c6a139a6e7 | |||
02714a1291 | |||
09c9686498 | |||
b6614c6ad5 | |||
b1d4b174a6 | |||
2b23463daa |
61
.gitattributes
vendored
61
.gitattributes
vendored
@ -1,63 +1,4 @@
|
||||
###############################################################################
|
||||
# Set default behavior to automatically normalize line endings.
|
||||
###############################################################################
|
||||
* text=auto
|
||||
|
||||
###############################################################################
|
||||
# Set default behavior for command prompt diff.
|
||||
#
|
||||
# This is need for earlier builds of msysgit that does not have it on by
|
||||
# default for csharp files.
|
||||
# Note: This is only used by command line
|
||||
###############################################################################
|
||||
#*.cs diff=csharp
|
||||
|
||||
###############################################################################
|
||||
# Set the merge driver for project and solution files
|
||||
#
|
||||
# Merging from the command prompt will add diff markers to the files if there
|
||||
# are conflicts (Merging from VS is not affected by the settings below, in VS
|
||||
# the diff markers are never inserted). Diff markers may cause the following
|
||||
# file extensions to fail to load in VS. An alternative would be to treat
|
||||
# these files as binary and thus will always conflict and require user
|
||||
# intervention with every merge. To do so, just uncomment the entries below
|
||||
###############################################################################
|
||||
#*.sln merge=binary
|
||||
#*.csproj merge=binary
|
||||
#*.vbproj merge=binary
|
||||
#*.vcxproj merge=binary
|
||||
#*.vcproj merge=binary
|
||||
#*.dbproj merge=binary
|
||||
#*.fsproj merge=binary
|
||||
#*.lsproj merge=binary
|
||||
#*.wixproj merge=binary
|
||||
#*.modelproj merge=binary
|
||||
#*.sqlproj merge=binary
|
||||
#*.wwaproj merge=binary
|
||||
|
||||
###############################################################################
|
||||
# behavior for image files
|
||||
#
|
||||
# image files are treated as binary by default.
|
||||
###############################################################################
|
||||
#*.jpg binary
|
||||
#*.png binary
|
||||
#*.gif binary
|
||||
|
||||
###############################################################################
|
||||
# diff behavior for common document formats
|
||||
#
|
||||
# Convert binary document formats to text before diffing them. This feature
|
||||
# is only available from the command line. Turn it on by uncommenting the
|
||||
# entries below.
|
||||
###############################################################################
|
||||
#*.doc diff=astextplain
|
||||
#*.DOC diff=astextplain
|
||||
#*.docx diff=astextplain
|
||||
#*.DOCX diff=astextplain
|
||||
#*.dot diff=astextplain
|
||||
#*.DOT diff=astextplain
|
||||
#*.pdf diff=astextplain
|
||||
#*.PDF diff=astextplain
|
||||
#*.rtf diff=astextplain
|
||||
#*.RTF diff=astextplain
|
||||
* text=auto eol=lf
|
||||
|
43
.github/ISSUE_TEMPLATE/bug_report.md
vendored
43
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@ -1,43 +0,0 @@
|
||||
---
|
||||
name: Bug Report
|
||||
about: Something doesn't work correctly in Ryujinx. Game-specific issues should be posted at https://github.com/Ryujinx/Ryujinx-Games-List instead, unless it is a provable regression.
|
||||
#assignees:
|
||||
---
|
||||
|
||||
## Bug Report
|
||||
|
||||
[ If any section does not apply, replace its contents with "N/A". ]</br>
|
||||
[ Lines between [ ] (square brackets) should be removed before posting. ]
|
||||
|
||||
### What's the issue you encountered?
|
||||
|
||||
[ Describe the issue in detail and what you were doing beforehand. ]</br>
|
||||
[ Did you make any changes related to Ryujinx itself? ]</br>
|
||||
[ If so, make sure to include details relating to what exactly you changed. ]
|
||||
|
||||
### How can the issue be reproduced?
|
||||
|
||||
[ Include a detailed step by step process for recreating your issue. ]
|
||||
|
||||
### Log file
|
||||
|
||||
[ Logs files can be found under ``Logs`` folder in Ryujinx program folder. ]</br>
|
||||
[ If you don't include a crash report in instances of crash related issues, we will ask you one to provide one. ]
|
||||
|
||||
### Environment?
|
||||
|
||||
- Ryujinx version: 1.0.X</br>
|
||||
[ Replace X's with the Ryujinx version at time of crash. ]
|
||||
- Game version: X.X.X</br>
|
||||
[ Replace X's with the game version at time of crash. ]
|
||||
- System Specs:
|
||||
- OS: *(e.g. Windows 10)*
|
||||
- CPU: *(e.g. i7-6700)*
|
||||
- GPU: *(e.g. NVIDIA RTX 2070)*
|
||||
- RAM: *(e.g. 16GiB)*
|
||||
- Applied Mods : [ Yes (Which ones) / No ]
|
||||
|
||||
### Additional context?
|
||||
|
||||
Additional info about your environment:</br>
|
||||
[ Any other information relevant to your issue. ]
|
86
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
Normal file
86
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
Normal file
@ -0,0 +1,86 @@
|
||||
name: Bug Report
|
||||
description: File a bug report
|
||||
title: "[Bug]"
|
||||
labels: bug
|
||||
body:
|
||||
- type: textarea
|
||||
id: issue
|
||||
attributes:
|
||||
label: Description of the issue
|
||||
description: What's the issue you encountered?
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: repro
|
||||
attributes:
|
||||
label: Reproduction steps
|
||||
description: How can the issue be reproduced?
|
||||
placeholder: Describe each step as precisely as possible
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: log
|
||||
attributes:
|
||||
label: Log file
|
||||
description: A log file will help our developers to better diagnose and fix the issue.
|
||||
placeholder: Logs files can be found under "Logs" folder in Ryujinx program folder. You can drag and drop the log on to the text area
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
id: os
|
||||
attributes:
|
||||
label: OS
|
||||
placeholder: "e.g. Windows 10"
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
id: ryujinx-version
|
||||
attributes:
|
||||
label: Ryujinx version
|
||||
placeholder: "e.g. 1.0.470"
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
id: game-version
|
||||
attributes:
|
||||
label: Game version
|
||||
placeholder: "e.g. 1.1.1"
|
||||
validations:
|
||||
required: false
|
||||
- type: input
|
||||
id: cpu
|
||||
attributes:
|
||||
label: CPU
|
||||
placeholder: "e.g. i7-6700"
|
||||
validations:
|
||||
required: false
|
||||
- type: input
|
||||
id: gpu
|
||||
attributes:
|
||||
label: GPU
|
||||
placeholder: "e.g. NVIDIA RTX 2070"
|
||||
validations:
|
||||
required: false
|
||||
- type: input
|
||||
id: ram
|
||||
attributes:
|
||||
label: RAM
|
||||
placeholder: "e.g. 16GB"
|
||||
validations:
|
||||
required: false
|
||||
- type: textarea
|
||||
id: mods
|
||||
attributes:
|
||||
label: List of applied mods
|
||||
placeholder: You can list applied mods here.
|
||||
validations:
|
||||
required: false
|
||||
- type: textarea
|
||||
id: additional-context
|
||||
attributes:
|
||||
label: Additional context?
|
||||
description: |
|
||||
- Additional info about your environment:
|
||||
- Any other information relevant to your issue.
|
||||
validations:
|
||||
required: false
|
34
.github/ISSUE_TEMPLATE/feature_request.md
vendored
34
.github/ISSUE_TEMPLATE/feature_request.md
vendored
@ -1,34 +0,0 @@
|
||||
---
|
||||
name: Feature Request
|
||||
about: Suggest a new feature for Ryujinx.
|
||||
#assignees:
|
||||
---
|
||||
|
||||
## Feature Request
|
||||
|
||||
[ If any section does not apply, replace its contents with "N/A". ]</br>
|
||||
[ If you do not have the information needed for a section, replace its contents with "Unknown". ]</br>
|
||||
[ Lines between [ ] (square brackets) are to be removed before posting. ]</br>
|
||||
|
||||
[ Please search for existing [feature requests](https://github.com/Ryujinx/Ryujinx/issues) before you make your own request. ]</br>
|
||||
[ Duplicate requests will be marked as such and you will be referred to the original request. ]
|
||||
|
||||
### What feature are you suggesting?
|
||||
#### Overview:
|
||||
- [ Include the basic, high-level concepts for this feature here. ]
|
||||
|
||||
#### Smaller Details:
|
||||
- [ These may include specific methods of implementation etc. ]
|
||||
|
||||
#### Nature of Request:
|
||||
[ Remove all that do not apply to your request. ]
|
||||
- Addition
|
||||
- [ Ex: Addition of certain original features or features from other community projects. ]
|
||||
- [ If you are suggesting porting features or including features from other projects, include what license they are distributed under and what, if any libraries those project use. ]
|
||||
- Change
|
||||
- Removal
|
||||
- [Ex: Removal of certain features or implementation due to a specific issue/bug or because of low quality code, etc.]
|
||||
|
||||
### Why would this feature be useful?
|
||||
[ If this is a feature for an end-user, how does it benefit the end-user? ]</br>
|
||||
[ If this feature is for developers, what does it add to Ryujinx that did not already exist? ]
|
30
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
Normal file
30
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
Normal file
@ -0,0 +1,30 @@
|
||||
name: Feature Request
|
||||
description: Suggest a new feature for Ryujinx.
|
||||
title: "[Feature Request]"
|
||||
body:
|
||||
- type: textarea
|
||||
id: overview
|
||||
attributes:
|
||||
label: Overview
|
||||
description: Include the basic, high-level concepts for this feature here.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: details
|
||||
attributes:
|
||||
label: Smaller details
|
||||
description: These may include specific methods of implementation etc.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: request
|
||||
attributes:
|
||||
label: Nature of request
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: feature
|
||||
attributes:
|
||||
label: Why would this feature be useful?
|
||||
validations:
|
||||
required: true
|
@ -1,34 +0,0 @@
|
||||
---
|
||||
name: Missing CPU Instruction
|
||||
about: CPU Instruction is missing in Ryujinx.
|
||||
#assignees:
|
||||
---
|
||||
|
||||
## Missing CPU Instruction
|
||||
|
||||
[ If any section does not apply, replace its contents with "N/A". ]</br>
|
||||
[ If you do not have the information needed for a section, replace its contents with "Unknown". ]</br>
|
||||
[ Lines between [ ] (square brackets) are to be removed before posting. ]
|
||||
|
||||
[ Please search for existing [missing CPU instruction](https://github.com/Ryujinx/Ryujinx/issues) before you make your own issue. ]</br>
|
||||
[ See the following [issue](https://github.com/Ryujinx/Ryujinx/issues/1405) as an example ]</br>
|
||||
[ Duplicate issue will be marked as such and you will be referred to the original request. ]
|
||||
|
||||
### What CPU instruction is missing?
|
||||
|
||||
Requires the *INSTRUCTION* instruction.</br>
|
||||
[ Replace *INSTRUCTION* by the instruction name, e.g. VADDL.U16 ]
|
||||
|
||||
```
|
||||
*
|
||||
```
|
||||
[ Add the undefined instruction error message in the above code block ]
|
||||
|
||||
### Instruction name
|
||||
```
|
||||
*
|
||||
```
|
||||
[ Include the name from [armconverter.com](https://armconverter.com/?disasm) or [shell-storm.org](http://shell-storm.org/online/Online-Assembler-and-Disassembler/?arch=arm64&endianness=big&dis_with_raw=True&dis_with_ins=True) in the above code block ]
|
||||
|
||||
### Required by:
|
||||
[ Add our (games list database)[https://github.com/Ryujinx/Ryujinx-Games-List/issues] links of games who require this instruction ]
|
26
.github/ISSUE_TEMPLATE/missing_cpu_instruction.yml
vendored
Normal file
26
.github/ISSUE_TEMPLATE/missing_cpu_instruction.yml
vendored
Normal file
@ -0,0 +1,26 @@
|
||||
name: Missing CPU Instruction
|
||||
description: CPU Instruction is missing in Ryujinx.
|
||||
title: "[CPU]"
|
||||
labels: [cpu, not-implemented]
|
||||
body:
|
||||
- type: textarea
|
||||
id: instruction
|
||||
attributes:
|
||||
label: CPU instruction
|
||||
description: What CPU instruction is missing?
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: name
|
||||
attributes:
|
||||
label: Instruction name
|
||||
description: Include the name from [armconverter.com](https://armconverter.com/?disasm) or [shell-storm.org](http://shell-storm.org/online/Online-Assembler-and-Disassembler/?arch=arm64&endianness=big&dis_with_raw=True&dis_with_ins=True) in the above code block
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: required
|
||||
attributes:
|
||||
label: Required by
|
||||
description: Add links to the [compatibility list page(s)](https://github.com/Ryujinx/Ryujinx-Games-List/issues) of the game(s) that require this instruction.
|
||||
validations:
|
||||
required: true
|
35
.github/ISSUE_TEMPLATE/missing_service_call.md
vendored
35
.github/ISSUE_TEMPLATE/missing_service_call.md
vendored
@ -1,35 +0,0 @@
|
||||
---
|
||||
name: Missing Service Call
|
||||
about: Service call is missing in Ryujinx.
|
||||
#assignees:
|
||||
---
|
||||
|
||||
## Missing Service Call
|
||||
|
||||
[ If any section does not apply, replace its contents with "N/A". ]</br>
|
||||
[ If you do not have the information needed for a section, replace its contents with "Unknown". ]</br>
|
||||
[ Lines between [ ] (square brackets) are to be removed before posting. ]
|
||||
|
||||
[ Please search for existing [missing service call](https://github.com/Ryujinx/Ryujinx/issues) before you make your own issue. ]</br>
|
||||
[ See the following [issue](https://github.com/Ryujinx/Ryujinx/issues/1431) as an example ]</br>
|
||||
[ Duplicate issue will be marked as such and you will be referred to the original request. ]
|
||||
|
||||
### What service call is missing?
|
||||
|
||||
*SERVICE* *INTERFACE*: *NUMBER* (*NAME*) is not implemented.</br>
|
||||
[ Replace *SERVICE* by the service name, e.g. appletAE ]</br>
|
||||
[ Replace *INTERFACE* by the interface name, e.g. IAllSystemAppletProxiesService ]</br>
|
||||
[ Replace *NUMBER* by the call number, e.g. 100 ]</br>
|
||||
[ Replace *NAME* by the call name, e.g. OpenSystemAppletProxy ]</br>
|
||||
[ e.g. appletAE IAllSystemAppletProxiesService: 100 (OpenSystemAppletProxy) ]
|
||||
|
||||
[ Add related links to the specific call from [Switchbrew](https://switchbrew.org/w/index.php?title=Services_API) and/or [SwIPC](https://reswitched.github.io/SwIPC/) ]
|
||||
|
||||
### Service description
|
||||
```
|
||||
*
|
||||
```
|
||||
[ Include the description/explanation from [Switchbrew](https://switchbrew.org/w/index.php?title=Services_API) and/or [SwIPC](https://reswitched.github.io/SwIPC/) in the above code block ]
|
||||
|
||||
### Required by:
|
||||
[ Add our (games list database)[https://github.com/Ryujinx/Ryujinx-Games-List/issues] links of games who require this call ]
|
25
.github/ISSUE_TEMPLATE/missing_service_call.yml
vendored
Normal file
25
.github/ISSUE_TEMPLATE/missing_service_call.yml
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
name: Missing Service Call
|
||||
description: Service call is missing in Ryujinx.
|
||||
labels: not-implemented
|
||||
body:
|
||||
- type: textarea
|
||||
id: instruction
|
||||
attributes:
|
||||
label: Service call
|
||||
description: What service call is missing?
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: name
|
||||
attributes:
|
||||
label: Service description
|
||||
description: Include the description/explanation from [Switchbrew](https://switchbrew.org/w/index.php?title=Services_API) and/or [SwIPC](https://reswitched.github.io/SwIPC/) in the above code block
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: required
|
||||
attributes:
|
||||
label: Required by
|
||||
description: Add links to the [compatibility list page(s)](https://github.com/Ryujinx/Ryujinx-Games-List/issues) of the game(s) that require this service.
|
||||
validations:
|
||||
required: true
|
28
.github/workflows/release.yml
vendored
28
.github/workflows/release.yml
vendored
@ -38,11 +38,11 @@ jobs:
|
||||
shell: bash
|
||||
- name: Configure for release
|
||||
run: |
|
||||
sed -r --in-place 's/\%\%RYUJINX_BUILD_VERSION\%\%/${{ steps.version_info.outputs.build_version }}/g;' Ryujinx.Common/ReleaseInformations.cs
|
||||
sed -r --in-place 's/\%\%RYUJINX_BUILD_GIT_HASH\%\%/${{ steps.version_info.outputs.git_short_hash }}/g;' Ryujinx.Common/ReleaseInformations.cs
|
||||
sed -r --in-place 's/\%\%RYUJINX_TARGET_RELEASE_CHANNEL_NAME\%\%/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_NAME }}/g;' Ryujinx.Common/ReleaseInformations.cs
|
||||
sed -r --in-place 's/\%\%RYUJINX_TARGET_RELEASE_CHANNEL_OWNER\%\%/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}/g;' Ryujinx.Common/ReleaseInformations.cs
|
||||
sed -r --in-place 's/\%\%RYUJINX_TARGET_RELEASE_CHANNEL_REPO\%\%/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }}/g;' Ryujinx.Common/ReleaseInformations.cs
|
||||
sed -r --in-place 's/\%\%RYUJINX_BUILD_VERSION\%\%/${{ steps.version_info.outputs.build_version }}/g;' Ryujinx.Common/ReleaseInformation.cs
|
||||
sed -r --in-place 's/\%\%RYUJINX_BUILD_GIT_HASH\%\%/${{ steps.version_info.outputs.git_short_hash }}/g;' Ryujinx.Common/ReleaseInformation.cs
|
||||
sed -r --in-place 's/\%\%RYUJINX_TARGET_RELEASE_CHANNEL_NAME\%\%/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_NAME }}/g;' Ryujinx.Common/ReleaseInformation.cs
|
||||
sed -r --in-place 's/\%\%RYUJINX_TARGET_RELEASE_CHANNEL_OWNER\%\%/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}/g;' Ryujinx.Common/ReleaseInformation.cs
|
||||
sed -r --in-place 's/\%\%RYUJINX_TARGET_RELEASE_CHANNEL_REPO\%\%/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }}/g;' Ryujinx.Common/ReleaseInformation.cs
|
||||
shell: bash
|
||||
- name: Create output dir
|
||||
run: "mkdir release_output"
|
||||
@ -75,15 +75,27 @@ jobs:
|
||||
- name: Packing Linux builds
|
||||
run: |
|
||||
pushd publish_linux
|
||||
tar -czvf ../release_output/ryujinx-${{ steps.version_info.outputs.build_version }}-linux_x64.tar.gz publish
|
||||
tar --exclude "publish/Ryujinx" --exclude "publish/Ryujinx.sh" -cvf ../release_output/ryujinx-${{ steps.version_info.outputs.build_version }}-linux_x64.tar publish
|
||||
python3 ../distribution/misc/add_tar_exec.py ../release_output/ryujinx-${{ steps.version_info.outputs.build_version }}-linux_x64.tar "publish/Ryujinx" "publish/Ryujinx"
|
||||
python3 ../distribution/misc/add_tar_exec.py ../release_output/ryujinx-${{ steps.version_info.outputs.build_version }}-linux_x64.tar "publish/Ryujinx.sh" "publish/Ryujinx.sh"
|
||||
gzip -9 < ../release_output/ryujinx-${{ steps.version_info.outputs.build_version }}-linux_x64.tar > ../release_output/ryujinx-${{ steps.version_info.outputs.build_version }}-linux_x64.tar.gz
|
||||
rm ../release_output/ryujinx-${{ steps.version_info.outputs.build_version }}-linux_x64.tar
|
||||
popd
|
||||
|
||||
pushd publish_linux_sdl2_headless
|
||||
tar -czvf ../release_output/sdl2-ryujinx-headless-${{ steps.version_info.outputs.build_version }}-linux_x64.tar.gz publish
|
||||
tar --exclude "publish/Ryujinx.Headless.SDL2" --exclude "publish/Ryujinx.sh" -cvf ../release_output/sdl2-ryujinx-headless-${{ steps.version_info.outputs.build_version }}-linux_x64.tar publish
|
||||
python3 ../distribution/misc/add_tar_exec.py ../release_output/sdl2-ryujinx-headless-${{ steps.version_info.outputs.build_version }}-linux_x64.tar "publish/Ryujinx.Headless.SDL2" "publish/Ryujinx.Headless.SDL2"
|
||||
python3 ../distribution/misc/add_tar_exec.py ../release_output/sdl2-ryujinx-headless-${{ steps.version_info.outputs.build_version }}-linux_x64.tar "publish/Ryujinx.sh" "publish/Ryujinx.sh"
|
||||
gzip -9 < ../release_output/sdl2-ryujinx-headless-${{ steps.version_info.outputs.build_version }}-linux_x64.tar > ../release_output/sdl2-ryujinx-headless-${{ steps.version_info.outputs.build_version }}-linux_x64.tar.gz
|
||||
rm ../release_output/sdl2-ryujinx-headless-${{ steps.version_info.outputs.build_version }}-linux_x64.tar
|
||||
popd
|
||||
|
||||
pushd publish_linux_ava
|
||||
tar -czvf ../release_output/test-ava-ryujinx-${{ steps.version_info.outputs.build_version }}-linux_x64.tar.gz publish
|
||||
tar --exclude "publish/Ryujinx.Ava" --exclude "publish/Ryujinx.sh" -cvf ../release_output/test-ava-ryujinx-${{ steps.version_info.outputs.build_version }}-linux_x64.tar publish
|
||||
python3 ../distribution/misc/add_tar_exec.py ../release_output/test-ava-ryujinx-${{ steps.version_info.outputs.build_version }}-linux_x64.tar "publish/Ryujinx.Ava" "publish/Ryujinx.Ava"
|
||||
python3 ../distribution/misc/add_tar_exec.py ../release_output/test-ava-ryujinx-${{ steps.version_info.outputs.build_version }}-linux_x64.tar "publish/Ryujinx.sh" "publish/Ryujinx.sh"
|
||||
gzip -9 < ../release_output/test-ava-ryujinx-${{ steps.version_info.outputs.build_version }}-linux_x64.tar > ../release_output/test-ava-ryujinx-${{ steps.version_info.outputs.build_version }}-linux_x64.tar.gz
|
||||
rm ../release_output/test-ava-ryujinx-${{ steps.version_info.outputs.build_version }}-linux_x64.tar
|
||||
popd
|
||||
shell: bash
|
||||
|
||||
|
3
.gitignore
vendored
3
.gitignore
vendored
@ -170,3 +170,6 @@ launchSettings.json
|
||||
|
||||
# NetCore Publishing Profiles
|
||||
PublishProfiles/
|
||||
|
||||
# Glade backup files
|
||||
*.glade~
|
||||
|
@ -9,4 +9,17 @@
|
||||
<ProjectReference Include="..\Ryujinx.Common\Ryujinx.Common.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ContentWithTargetPath Include="Native\libs\libarmeilleure-jitsupport.dylib" Condition="'$(RuntimeIdentifier)' == '' OR '$(RuntimeIdentifier)' == 'osx-arm64'">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
<TargetPath>libarmeilleure-jitsupport.dylib</TargetPath>
|
||||
</ContentWithTargetPath>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleTo">
|
||||
<_Parameter1>Ryujinx.Tests</_Parameter1>
|
||||
</AssemblyAttribute>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
270
ARMeilleure/CodeGen/Arm64/Arm64Optimizer.cs
Normal file
270
ARMeilleure/CodeGen/Arm64/Arm64Optimizer.cs
Normal file
@ -0,0 +1,270 @@
|
||||
using ARMeilleure.CodeGen.Optimizations;
|
||||
using ARMeilleure.IntermediateRepresentation;
|
||||
using ARMeilleure.Translation;
|
||||
using System.Collections.Generic;
|
||||
using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
|
||||
using static ARMeilleure.IntermediateRepresentation.Operation.Factory;
|
||||
|
||||
namespace ARMeilleure.CodeGen.Arm64
|
||||
{
|
||||
static class Arm64Optimizer
|
||||
{
|
||||
private const int MaxConstantUses = 10000;
|
||||
|
||||
public static void RunPass(ControlFlowGraph cfg)
|
||||
{
|
||||
var constants = new Dictionary<ulong, Operand>();
|
||||
|
||||
Operand GetConstantCopy(BasicBlock block, Operation operation, Operand source)
|
||||
{
|
||||
// If the constant has many uses, we also force a new constant mov to be added, in order
|
||||
// to avoid overflow of the counts field (that is limited to 16 bits).
|
||||
if (!constants.TryGetValue(source.Value, out var constant) || constant.UsesCount > MaxConstantUses)
|
||||
{
|
||||
constant = Local(source.Type);
|
||||
|
||||
Operation copyOp = Operation(Instruction.Copy, constant, source);
|
||||
|
||||
block.Operations.AddBefore(operation, copyOp);
|
||||
|
||||
constants[source.Value] = constant;
|
||||
}
|
||||
|
||||
return constant;
|
||||
}
|
||||
|
||||
for (BasicBlock block = cfg.Blocks.First; block != null; block = block.ListNext)
|
||||
{
|
||||
constants.Clear();
|
||||
|
||||
Operation nextNode;
|
||||
|
||||
for (Operation node = block.Operations.First; node != default; node = nextNode)
|
||||
{
|
||||
nextNode = node.ListNext;
|
||||
|
||||
// Insert copies for constants that can't fit on a 32-bit immediate.
|
||||
// Doing this early unblocks a few optimizations.
|
||||
if (node.Instruction == Instruction.Add)
|
||||
{
|
||||
Operand src1 = node.GetSource(0);
|
||||
Operand src2 = node.GetSource(1);
|
||||
|
||||
if (src1.Kind == OperandKind.Constant && (src1.Relocatable || ConstTooLong(src1, OperandType.I32)))
|
||||
{
|
||||
node.SetSource(0, GetConstantCopy(block, node, src1));
|
||||
}
|
||||
|
||||
if (src2.Kind == OperandKind.Constant && (src2.Relocatable || ConstTooLong(src2, OperandType.I32)))
|
||||
{
|
||||
node.SetSource(1, GetConstantCopy(block, node, src2));
|
||||
}
|
||||
}
|
||||
|
||||
// Try to fold something like:
|
||||
// lsl x1, x1, #2
|
||||
// add x0, x0, x1
|
||||
// ldr x0, [x0]
|
||||
// add x2, x2, #16
|
||||
// ldr x2, [x2]
|
||||
// Into:
|
||||
// ldr x0, [x0, x1, lsl #2]
|
||||
// ldr x2, [x2, #16]
|
||||
if (IsMemoryLoadOrStore(node.Instruction))
|
||||
{
|
||||
OperandType type;
|
||||
|
||||
if (node.Destination != default)
|
||||
{
|
||||
type = node.Destination.Type;
|
||||
}
|
||||
else
|
||||
{
|
||||
type = node.GetSource(1).Type;
|
||||
}
|
||||
|
||||
Operand memOp = GetMemoryOperandOrNull(node.GetSource(0), type);
|
||||
|
||||
if (memOp != default)
|
||||
{
|
||||
node.SetSource(0, memOp);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Optimizer.RemoveUnusedNodes(cfg);
|
||||
}
|
||||
|
||||
private static Operand GetMemoryOperandOrNull(Operand addr, OperandType type)
|
||||
{
|
||||
Operand baseOp = addr;
|
||||
|
||||
// First we check if the address is the result of a local X with immediate
|
||||
// addition. If that is the case, then the baseOp is X, and the memory operand immediate
|
||||
// becomes the addition immediate. Otherwise baseOp keeps being the address.
|
||||
int imm = GetConstOp(ref baseOp, type);
|
||||
if (imm != 0)
|
||||
{
|
||||
return MemoryOp(type, baseOp, default, Multiplier.x1, imm);
|
||||
}
|
||||
|
||||
// Now we check if the baseOp is the result of a local Y with a local Z addition.
|
||||
// If that is the case, we now set baseOp to Y and indexOp to Z. We further check
|
||||
// if Z is the result of a left shift of local W by a value == 0 or == Log2(AccessSize),
|
||||
// if that is the case, we set indexOp to W and adjust the scale value of the memory operand
|
||||
// to match that of the left shift.
|
||||
// There is one missed case, which is the address being a shift result, but this is
|
||||
// probably not worth optimizing as it should never happen.
|
||||
(Operand indexOp, Multiplier scale) = GetIndexOp(ref baseOp, type);
|
||||
|
||||
// If baseOp is still equal to address, then there's nothing that can be optimized.
|
||||
if (baseOp == addr)
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
return MemoryOp(type, baseOp, indexOp, scale, 0);
|
||||
}
|
||||
|
||||
private static int GetConstOp(ref Operand baseOp, OperandType accessType)
|
||||
{
|
||||
Operation operation = GetAsgOpWithInst(baseOp, Instruction.Add);
|
||||
|
||||
if (operation == default)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
Operand src1 = operation.GetSource(0);
|
||||
Operand src2 = operation.GetSource(1);
|
||||
|
||||
Operand constOp;
|
||||
Operand otherOp;
|
||||
|
||||
if (src1.Kind == OperandKind.Constant && src2.Kind == OperandKind.LocalVariable)
|
||||
{
|
||||
constOp = src1;
|
||||
otherOp = src2;
|
||||
}
|
||||
else if (src1.Kind == OperandKind.LocalVariable && src2.Kind == OperandKind.Constant)
|
||||
{
|
||||
constOp = src2;
|
||||
otherOp = src1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// If we have addition by a constant that we can't encode on the instruction,
|
||||
// then we can't optimize it further.
|
||||
if (ConstTooLong(constOp, accessType))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
baseOp = otherOp;
|
||||
|
||||
return constOp.AsInt32();
|
||||
}
|
||||
|
||||
private static (Operand, Multiplier) GetIndexOp(ref Operand baseOp, OperandType accessType)
|
||||
{
|
||||
Operand indexOp = default;
|
||||
|
||||
Multiplier scale = Multiplier.x1;
|
||||
|
||||
Operation addOp = GetAsgOpWithInst(baseOp, Instruction.Add);
|
||||
|
||||
if (addOp == default)
|
||||
{
|
||||
return (indexOp, scale);
|
||||
}
|
||||
|
||||
Operand src1 = addOp.GetSource(0);
|
||||
Operand src2 = addOp.GetSource(1);
|
||||
|
||||
if (src1.Kind != OperandKind.LocalVariable || src2.Kind != OperandKind.LocalVariable)
|
||||
{
|
||||
return (indexOp, scale);
|
||||
}
|
||||
|
||||
baseOp = src1;
|
||||
indexOp = src2;
|
||||
|
||||
Operation shlOp = GetAsgOpWithInst(src1, Instruction.ShiftLeft);
|
||||
|
||||
bool indexOnSrc2 = false;
|
||||
|
||||
if (shlOp == default)
|
||||
{
|
||||
shlOp = GetAsgOpWithInst(src2, Instruction.ShiftLeft);
|
||||
|
||||
indexOnSrc2 = true;
|
||||
}
|
||||
|
||||
if (shlOp != default)
|
||||
{
|
||||
Operand shSrc = shlOp.GetSource(0);
|
||||
Operand shift = shlOp.GetSource(1);
|
||||
|
||||
int maxShift = Assembler.GetScaleForType(accessType);
|
||||
|
||||
if (shSrc.Kind == OperandKind.LocalVariable &&
|
||||
shift.Kind == OperandKind.Constant &&
|
||||
(shift.Value == 0 || shift.Value == (ulong)maxShift))
|
||||
{
|
||||
scale = shift.Value switch
|
||||
{
|
||||
1 => Multiplier.x2,
|
||||
2 => Multiplier.x4,
|
||||
3 => Multiplier.x8,
|
||||
4 => Multiplier.x16,
|
||||
_ => Multiplier.x1
|
||||
};
|
||||
|
||||
baseOp = indexOnSrc2 ? src1 : src2;
|
||||
indexOp = shSrc;
|
||||
}
|
||||
}
|
||||
|
||||
return (indexOp, scale);
|
||||
}
|
||||
|
||||
private static Operation GetAsgOpWithInst(Operand op, Instruction inst)
|
||||
{
|
||||
// If we have multiple assignments, folding is not safe
|
||||
// as the value may be different depending on the
|
||||
// control flow path.
|
||||
if (op.AssignmentsCount != 1)
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
Operation asgOp = op.Assignments[0];
|
||||
|
||||
if (asgOp.Instruction != inst)
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
return asgOp;
|
||||
}
|
||||
|
||||
private static bool IsMemoryLoadOrStore(Instruction inst)
|
||||
{
|
||||
return inst == Instruction.Load || inst == Instruction.Store;
|
||||
}
|
||||
|
||||
private static bool ConstTooLong(Operand constOp, OperandType accessType)
|
||||
{
|
||||
if ((uint)constOp.Value != constOp.Value)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return !CodeGenCommon.ConstFitsOnUImm12(constOp.AsInt32(), accessType);
|
||||
}
|
||||
}
|
||||
}
|
47
ARMeilleure/CodeGen/Arm64/ArmCondition.cs
Normal file
47
ARMeilleure/CodeGen/Arm64/ArmCondition.cs
Normal file
@ -0,0 +1,47 @@
|
||||
using ARMeilleure.IntermediateRepresentation;
|
||||
using System;
|
||||
|
||||
namespace ARMeilleure.CodeGen.Arm64
|
||||
{
|
||||
enum ArmCondition
|
||||
{
|
||||
Eq = 0,
|
||||
Ne = 1,
|
||||
GeUn = 2,
|
||||
LtUn = 3,
|
||||
Mi = 4,
|
||||
Pl = 5,
|
||||
Vs = 6,
|
||||
Vc = 7,
|
||||
GtUn = 8,
|
||||
LeUn = 9,
|
||||
Ge = 10,
|
||||
Lt = 11,
|
||||
Gt = 12,
|
||||
Le = 13,
|
||||
Al = 14,
|
||||
Nv = 15
|
||||
}
|
||||
|
||||
static class ComparisonArm64Extensions
|
||||
{
|
||||
public static ArmCondition ToArmCondition(this Comparison comp)
|
||||
{
|
||||
return comp switch
|
||||
{
|
||||
Comparison.Equal => ArmCondition.Eq,
|
||||
Comparison.NotEqual => ArmCondition.Ne,
|
||||
Comparison.Greater => ArmCondition.Gt,
|
||||
Comparison.LessOrEqual => ArmCondition.Le,
|
||||
Comparison.GreaterUI => ArmCondition.GtUn,
|
||||
Comparison.LessOrEqualUI => ArmCondition.LeUn,
|
||||
Comparison.GreaterOrEqual => ArmCondition.Ge,
|
||||
Comparison.Less => ArmCondition.Lt,
|
||||
Comparison.GreaterOrEqualUI => ArmCondition.GeUn,
|
||||
Comparison.LessUI => ArmCondition.LtUn,
|
||||
|
||||
_ => throw new ArgumentException(null, nameof(comp))
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
14
ARMeilleure/CodeGen/Arm64/ArmExtensionType.cs
Normal file
14
ARMeilleure/CodeGen/Arm64/ArmExtensionType.cs
Normal file
@ -0,0 +1,14 @@
|
||||
namespace ARMeilleure.CodeGen.Arm64
|
||||
{
|
||||
enum ArmExtensionType
|
||||
{
|
||||
Uxtb = 0,
|
||||
Uxth = 1,
|
||||
Uxtw = 2,
|
||||
Uxtx = 3,
|
||||
Sxtb = 4,
|
||||
Sxth = 5,
|
||||
Sxtw = 6,
|
||||
Sxtx = 7
|
||||
}
|
||||
}
|
11
ARMeilleure/CodeGen/Arm64/ArmShiftType.cs
Normal file
11
ARMeilleure/CodeGen/Arm64/ArmShiftType.cs
Normal file
@ -0,0 +1,11 @@
|
||||
|
||||
namespace ARMeilleure.CodeGen.Arm64
|
||||
{
|
||||
enum ArmShiftType
|
||||
{
|
||||
Lsl = 0,
|
||||
Lsr = 1,
|
||||
Asr = 2,
|
||||
Ror = 3
|
||||
}
|
||||
}
|
1160
ARMeilleure/CodeGen/Arm64/Assembler.cs
Normal file
1160
ARMeilleure/CodeGen/Arm64/Assembler.cs
Normal file
File diff suppressed because it is too large
Load Diff
96
ARMeilleure/CodeGen/Arm64/CallingConvention.cs
Normal file
96
ARMeilleure/CodeGen/Arm64/CallingConvention.cs
Normal file
@ -0,0 +1,96 @@
|
||||
using System;
|
||||
|
||||
namespace ARMeilleure.CodeGen.Arm64
|
||||
{
|
||||
static class CallingConvention
|
||||
{
|
||||
private const int RegistersMask = unchecked((int)0xffffffff);
|
||||
|
||||
// Some of those register have specific roles and can't be used as general purpose registers.
|
||||
// X18 - Reserved for platform specific usage.
|
||||
// X29 - Frame pointer.
|
||||
// X30 - Return address.
|
||||
// X31 - Not an actual register, in some cases maps to SP, and in others to ZR.
|
||||
private const int ReservedRegsMask = (1 << CodeGenCommon.ReservedRegister) | (1 << 18) | (1 << 29) | (1 << 30) | (1 << 31);
|
||||
|
||||
public static int GetIntAvailableRegisters()
|
||||
{
|
||||
return RegistersMask & ~ReservedRegsMask;
|
||||
}
|
||||
|
||||
public static int GetVecAvailableRegisters()
|
||||
{
|
||||
return RegistersMask;
|
||||
}
|
||||
|
||||
public static int GetIntCallerSavedRegisters()
|
||||
{
|
||||
return (GetIntCalleeSavedRegisters() ^ RegistersMask) & ~ReservedRegsMask;
|
||||
}
|
||||
|
||||
public static int GetFpCallerSavedRegisters()
|
||||
{
|
||||
return GetFpCalleeSavedRegisters() ^ RegistersMask;
|
||||
}
|
||||
|
||||
public static int GetVecCallerSavedRegisters()
|
||||
{
|
||||
return GetVecCalleeSavedRegisters() ^ RegistersMask;
|
||||
}
|
||||
|
||||
public static int GetIntCalleeSavedRegisters()
|
||||
{
|
||||
return 0x1ff80000; // X19 to X28
|
||||
}
|
||||
|
||||
public static int GetFpCalleeSavedRegisters()
|
||||
{
|
||||
return 0xff00; // D8 to D15
|
||||
}
|
||||
|
||||
public static int GetVecCalleeSavedRegisters()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static int GetArgumentsOnRegsCount()
|
||||
{
|
||||
return 8;
|
||||
}
|
||||
|
||||
public static int GetIntArgumentRegister(int index)
|
||||
{
|
||||
if ((uint)index < (uint)GetArgumentsOnRegsCount())
|
||||
{
|
||||
return index;
|
||||
}
|
||||
|
||||
throw new ArgumentOutOfRangeException(nameof(index));
|
||||
}
|
||||
|
||||
public static int GetVecArgumentRegister(int index)
|
||||
{
|
||||
if ((uint)index < (uint)GetArgumentsOnRegsCount())
|
||||
{
|
||||
return index;
|
||||
}
|
||||
|
||||
throw new ArgumentOutOfRangeException(nameof(index));
|
||||
}
|
||||
|
||||
public static int GetIntReturnRegister()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static int GetIntReturnRegisterHigh()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
public static int GetVecReturnRegister()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
91
ARMeilleure/CodeGen/Arm64/CodeGenCommon.cs
Normal file
91
ARMeilleure/CodeGen/Arm64/CodeGenCommon.cs
Normal file
@ -0,0 +1,91 @@
|
||||
using ARMeilleure.IntermediateRepresentation;
|
||||
using System.Numerics;
|
||||
|
||||
namespace ARMeilleure.CodeGen.Arm64
|
||||
{
|
||||
static class CodeGenCommon
|
||||
{
|
||||
public const int TcAddressRegister = 8;
|
||||
public const int ReservedRegister = 17;
|
||||
|
||||
public static bool ConstFitsOnSImm7(int value, int scale)
|
||||
{
|
||||
return (((value >> scale) << 25) >> (25 - scale)) == value;
|
||||
}
|
||||
|
||||
public static bool ConstFitsOnSImm9(int value)
|
||||
{
|
||||
return ((value << 23) >> 23) == value;
|
||||
}
|
||||
|
||||
public static bool ConstFitsOnUImm12(int value)
|
||||
{
|
||||
return (value & 0xfff) == value;
|
||||
}
|
||||
|
||||
public static bool ConstFitsOnUImm12(int value, OperandType type)
|
||||
{
|
||||
int scale = Assembler.GetScaleForType(type);
|
||||
return (((value >> scale) & 0xfff) << scale) == value;
|
||||
}
|
||||
|
||||
public static bool TryEncodeBitMask(Operand operand, out int immN, out int immS, out int immR)
|
||||
{
|
||||
return TryEncodeBitMask(operand.Type, operand.Value, out immN, out immS, out immR);
|
||||
}
|
||||
|
||||
public static bool TryEncodeBitMask(OperandType type, ulong value, out int immN, out int immS, out int immR)
|
||||
{
|
||||
if (type == OperandType.I32)
|
||||
{
|
||||
value |= value << 32;
|
||||
}
|
||||
|
||||
return TryEncodeBitMask(value, out immN, out immS, out immR);
|
||||
}
|
||||
|
||||
public static bool TryEncodeBitMask(ulong value, out int immN, out int immS, out int immR)
|
||||
{
|
||||
// Some special values also can't be encoded:
|
||||
// 0 can't be encoded because we need to subtract 1 from onesCount (which would became negative if 0).
|
||||
// A value with all bits set can't be encoded because it is reserved according to the spec, because:
|
||||
// Any value AND all ones will be equal itself, so it's effectively a no-op.
|
||||
// Any value OR all ones will be equal all ones, so one can just use MOV.
|
||||
// Any value XOR all ones will be equal its inverse, so one can just use MVN.
|
||||
if (value == 0 || value == ulong.MaxValue)
|
||||
{
|
||||
immN = 0;
|
||||
immS = 0;
|
||||
immR = 0;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Normalize value, rotating it such that the LSB is 1: Ensures we get a complete element that has not
|
||||
// been cut-in-half across the word boundary.
|
||||
int rotation = BitOperations.TrailingZeroCount(value & (value + 1));
|
||||
ulong rotatedValue = ulong.RotateRight(value, rotation);
|
||||
|
||||
// Now that we have a complete element in the LSB with the LSB = 1, determine size and number of ones
|
||||
// in element.
|
||||
int elementSize = BitOperations.TrailingZeroCount(rotatedValue & (rotatedValue + 1));
|
||||
int onesInElement = BitOperations.TrailingZeroCount(~rotatedValue);
|
||||
|
||||
// Check the value is repeating; also ensures element size is a power of two.
|
||||
if (ulong.RotateRight(value, elementSize) != value)
|
||||
{
|
||||
immN = 0;
|
||||
immS = 0;
|
||||
immR = 0;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
immN = (elementSize >> 6) & 1;
|
||||
immS = (((~elementSize + 1) << 1) | (onesInElement - 1)) & 0x3f;
|
||||
immR = (elementSize - rotation) & (elementSize - 1);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
286
ARMeilleure/CodeGen/Arm64/CodeGenContext.cs
Normal file
286
ARMeilleure/CodeGen/Arm64/CodeGenContext.cs
Normal file
@ -0,0 +1,286 @@
|
||||
using ARMeilleure.CodeGen.Linking;
|
||||
using ARMeilleure.CodeGen.RegisterAllocators;
|
||||
using ARMeilleure.IntermediateRepresentation;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace ARMeilleure.CodeGen.Arm64
|
||||
{
|
||||
class CodeGenContext
|
||||
{
|
||||
private const int BccInstLength = 4;
|
||||
private const int CbnzInstLength = 4;
|
||||
private const int LdrLitInstLength = 4;
|
||||
|
||||
private Stream _stream;
|
||||
|
||||
public int StreamOffset => (int)_stream.Length;
|
||||
|
||||
public AllocationResult AllocResult { get; }
|
||||
|
||||
public Assembler Assembler { get; }
|
||||
|
||||
public BasicBlock CurrBlock { get; private set; }
|
||||
|
||||
public bool HasCall { get; }
|
||||
|
||||
public int CallArgsRegionSize { get; }
|
||||
public int FpLrSaveRegionSize { get; }
|
||||
|
||||
private readonly Dictionary<BasicBlock, long> _visitedBlocks;
|
||||
private readonly Dictionary<BasicBlock, List<(ArmCondition Condition, long BranchPos)>> _pendingBranches;
|
||||
|
||||
private struct ConstantPoolEntry
|
||||
{
|
||||
public readonly int Offset;
|
||||
public readonly Symbol Symbol;
|
||||
public readonly List<(Operand, int)> LdrOffsets;
|
||||
|
||||
public ConstantPoolEntry(int offset, Symbol symbol)
|
||||
{
|
||||
Offset = offset;
|
||||
Symbol = symbol;
|
||||
LdrOffsets = new List<(Operand, int)>();
|
||||
}
|
||||
}
|
||||
|
||||
private readonly Dictionary<ulong, ConstantPoolEntry> _constantPool;
|
||||
|
||||
private bool _constantPoolWritten;
|
||||
private long _constantPoolOffset;
|
||||
|
||||
private ArmCondition _jNearCondition;
|
||||
private Operand _jNearValue;
|
||||
|
||||
private long _jNearPosition;
|
||||
|
||||
private readonly bool _relocatable;
|
||||
|
||||
public CodeGenContext(AllocationResult allocResult, int maxCallArgs, int blocksCount, bool relocatable)
|
||||
{
|
||||
_stream = new MemoryStream();
|
||||
|
||||
AllocResult = allocResult;
|
||||
|
||||
Assembler = new Assembler(_stream);
|
||||
|
||||
bool hasCall = maxCallArgs >= 0;
|
||||
|
||||
HasCall = hasCall;
|
||||
|
||||
if (maxCallArgs < 0)
|
||||
{
|
||||
maxCallArgs = 0;
|
||||
}
|
||||
|
||||
CallArgsRegionSize = maxCallArgs * 16;
|
||||
FpLrSaveRegionSize = hasCall ? 16 : 0;
|
||||
|
||||
_visitedBlocks = new Dictionary<BasicBlock, long>();
|
||||
_pendingBranches = new Dictionary<BasicBlock, List<(ArmCondition, long)>>();
|
||||
_constantPool = new Dictionary<ulong, ConstantPoolEntry>();
|
||||
|
||||
_relocatable = relocatable;
|
||||
}
|
||||
|
||||
public void EnterBlock(BasicBlock block)
|
||||
{
|
||||
CurrBlock = block;
|
||||
|
||||
long target = _stream.Position;
|
||||
|
||||
if (_pendingBranches.TryGetValue(block, out var list))
|
||||
{
|
||||
foreach (var tuple in list)
|
||||
{
|
||||
_stream.Seek(tuple.BranchPos, SeekOrigin.Begin);
|
||||
WriteBranch(tuple.Condition, target);
|
||||
}
|
||||
|
||||
_stream.Seek(target, SeekOrigin.Begin);
|
||||
_pendingBranches.Remove(block);
|
||||
}
|
||||
|
||||
_visitedBlocks.Add(block, target);
|
||||
}
|
||||
|
||||
public void JumpTo(BasicBlock target)
|
||||
{
|
||||
JumpTo(ArmCondition.Al, target);
|
||||
}
|
||||
|
||||
public void JumpTo(ArmCondition condition, BasicBlock target)
|
||||
{
|
||||
if (_visitedBlocks.TryGetValue(target, out long offset))
|
||||
{
|
||||
WriteBranch(condition, offset);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!_pendingBranches.TryGetValue(target, out var list))
|
||||
{
|
||||
list = new List<(ArmCondition, long)>();
|
||||
_pendingBranches.Add(target, list);
|
||||
}
|
||||
|
||||
list.Add((condition, _stream.Position));
|
||||
|
||||
_stream.Seek(BccInstLength, SeekOrigin.Current);
|
||||
}
|
||||
}
|
||||
|
||||
private void WriteBranch(ArmCondition condition, long to)
|
||||
{
|
||||
int imm = checked((int)(to - _stream.Position));
|
||||
|
||||
if (condition != ArmCondition.Al)
|
||||
{
|
||||
Assembler.B(condition, imm);
|
||||
}
|
||||
else
|
||||
{
|
||||
Assembler.B(imm);
|
||||
}
|
||||
}
|
||||
|
||||
public void JumpToNear(ArmCondition condition)
|
||||
{
|
||||
_jNearCondition = condition;
|
||||
_jNearPosition = _stream.Position;
|
||||
|
||||
_stream.Seek(BccInstLength, SeekOrigin.Current);
|
||||
}
|
||||
|
||||
public void JumpToNearIfNotZero(Operand value)
|
||||
{
|
||||
_jNearValue = value;
|
||||
_jNearPosition = _stream.Position;
|
||||
|
||||
_stream.Seek(CbnzInstLength, SeekOrigin.Current);
|
||||
}
|
||||
|
||||
public void JumpHere()
|
||||
{
|
||||
long currentPosition = _stream.Position;
|
||||
long offset = currentPosition - _jNearPosition;
|
||||
|
||||
_stream.Seek(_jNearPosition, SeekOrigin.Begin);
|
||||
|
||||
if (_jNearValue != default)
|
||||
{
|
||||
Assembler.Cbnz(_jNearValue, checked((int)offset));
|
||||
_jNearValue = default;
|
||||
}
|
||||
else
|
||||
{
|
||||
Assembler.B(_jNearCondition, checked((int)offset));
|
||||
}
|
||||
|
||||
_stream.Seek(currentPosition, SeekOrigin.Begin);
|
||||
}
|
||||
|
||||
public void ReserveRelocatableConstant(Operand rt, Symbol symbol, ulong value)
|
||||
{
|
||||
if (!_constantPool.TryGetValue(value, out ConstantPoolEntry cpe))
|
||||
{
|
||||
cpe = new ConstantPoolEntry(_constantPool.Count * sizeof(ulong), symbol);
|
||||
_constantPool.Add(value, cpe);
|
||||
}
|
||||
|
||||
cpe.LdrOffsets.Add((rt, (int)_stream.Position));
|
||||
_stream.Seek(LdrLitInstLength, SeekOrigin.Current);
|
||||
}
|
||||
|
||||
private long WriteConstantPool()
|
||||
{
|
||||
if (_constantPoolWritten)
|
||||
{
|
||||
return _constantPoolOffset;
|
||||
}
|
||||
|
||||
long constantPoolBaseOffset = _stream.Position;
|
||||
|
||||
foreach (ulong value in _constantPool.Keys)
|
||||
{
|
||||
WriteUInt64(value);
|
||||
}
|
||||
|
||||
foreach (ConstantPoolEntry cpe in _constantPool.Values)
|
||||
{
|
||||
foreach ((Operand rt, int ldrOffset) in cpe.LdrOffsets)
|
||||
{
|
||||
_stream.Seek(ldrOffset, SeekOrigin.Begin);
|
||||
|
||||
int absoluteOffset = checked((int)(constantPoolBaseOffset + cpe.Offset));
|
||||
int pcRelativeOffset = absoluteOffset - ldrOffset;
|
||||
|
||||
Assembler.LdrLit(rt, pcRelativeOffset);
|
||||
}
|
||||
}
|
||||
|
||||
_stream.Seek(constantPoolBaseOffset + _constantPool.Count * sizeof(ulong), SeekOrigin.Begin);
|
||||
|
||||
_constantPoolOffset = constantPoolBaseOffset;
|
||||
_constantPoolWritten = true;
|
||||
|
||||
return constantPoolBaseOffset;
|
||||
}
|
||||
|
||||
public (byte[], RelocInfo) GetCode()
|
||||
{
|
||||
long constantPoolBaseOffset = WriteConstantPool();
|
||||
|
||||
byte[] code = new byte[_stream.Length];
|
||||
|
||||
long originalPosition = _stream.Position;
|
||||
|
||||
_stream.Seek(0, SeekOrigin.Begin);
|
||||
_stream.Read(code, 0, code.Length);
|
||||
_stream.Seek(originalPosition, SeekOrigin.Begin);
|
||||
|
||||
RelocInfo relocInfo;
|
||||
|
||||
if (_relocatable)
|
||||
{
|
||||
RelocEntry[] relocs = new RelocEntry[_constantPool.Count];
|
||||
|
||||
int index = 0;
|
||||
|
||||
foreach (ConstantPoolEntry cpe in _constantPool.Values)
|
||||
{
|
||||
if (cpe.Symbol.Type != SymbolType.None)
|
||||
{
|
||||
int absoluteOffset = checked((int)(constantPoolBaseOffset + cpe.Offset));
|
||||
relocs[index++] = new RelocEntry(absoluteOffset, cpe.Symbol);
|
||||
}
|
||||
}
|
||||
|
||||
if (index != relocs.Length)
|
||||
{
|
||||
Array.Resize(ref relocs, index);
|
||||
}
|
||||
|
||||
relocInfo = new RelocInfo(relocs);
|
||||
}
|
||||
else
|
||||
{
|
||||
relocInfo = new RelocInfo(new RelocEntry[0]);
|
||||
}
|
||||
|
||||
return (code, relocInfo);
|
||||
}
|
||||
|
||||
private void WriteUInt64(ulong value)
|
||||
{
|
||||
_stream.WriteByte((byte)(value >> 0));
|
||||
_stream.WriteByte((byte)(value >> 8));
|
||||
_stream.WriteByte((byte)(value >> 16));
|
||||
_stream.WriteByte((byte)(value >> 24));
|
||||
_stream.WriteByte((byte)(value >> 32));
|
||||
_stream.WriteByte((byte)(value >> 40));
|
||||
_stream.WriteByte((byte)(value >> 48));
|
||||
_stream.WriteByte((byte)(value >> 56));
|
||||
}
|
||||
}
|
||||
}
|
1580
ARMeilleure/CodeGen/Arm64/CodeGenerator.cs
Normal file
1580
ARMeilleure/CodeGen/Arm64/CodeGenerator.cs
Normal file
File diff suppressed because it is too large
Load Diff
662
ARMeilleure/CodeGen/Arm64/CodeGeneratorIntrinsic.cs
Normal file
662
ARMeilleure/CodeGen/Arm64/CodeGeneratorIntrinsic.cs
Normal file
@ -0,0 +1,662 @@
|
||||
using ARMeilleure.IntermediateRepresentation;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace ARMeilleure.CodeGen.Arm64
|
||||
{
|
||||
static class CodeGeneratorIntrinsic
|
||||
{
|
||||
public static void GenerateOperation(CodeGenContext context, Operation operation)
|
||||
{
|
||||
Intrinsic intrin = operation.Intrinsic;
|
||||
|
||||
IntrinsicInfo info = IntrinsicTable.GetInfo(intrin & ~(Intrinsic.Arm64VTypeMask | Intrinsic.Arm64VSizeMask));
|
||||
|
||||
switch (info.Type)
|
||||
{
|
||||
case IntrinsicType.ScalarUnary:
|
||||
GenerateVectorUnary(
|
||||
context,
|
||||
0,
|
||||
(uint)(intrin & Intrinsic.Arm64VSizeMask) >> (int)Intrinsic.Arm64VSizeShift,
|
||||
info.Inst,
|
||||
operation.Destination,
|
||||
operation.GetSource(0));
|
||||
break;
|
||||
case IntrinsicType.ScalarUnaryByElem:
|
||||
Debug.Assert(operation.GetSource(1).Kind == OperandKind.Constant);
|
||||
|
||||
GenerateVectorUnaryByElem(
|
||||
context,
|
||||
0,
|
||||
(uint)(intrin & Intrinsic.Arm64VSizeMask) >> (int)Intrinsic.Arm64VSizeShift,
|
||||
info.Inst,
|
||||
(uint)operation.GetSource(1).AsInt32(),
|
||||
operation.Destination,
|
||||
operation.GetSource(0));
|
||||
break;
|
||||
case IntrinsicType.ScalarBinary:
|
||||
GenerateVectorBinary(
|
||||
context,
|
||||
0,
|
||||
(uint)(intrin & Intrinsic.Arm64VSizeMask) >> (int)Intrinsic.Arm64VSizeShift,
|
||||
info.Inst,
|
||||
operation.Destination,
|
||||
operation.GetSource(0),
|
||||
operation.GetSource(1));
|
||||
break;
|
||||
case IntrinsicType.ScalarBinaryFPByElem:
|
||||
Debug.Assert(operation.GetSource(2).Kind == OperandKind.Constant);
|
||||
|
||||
GenerateVectorBinaryFPByElem(
|
||||
context,
|
||||
0,
|
||||
(uint)(intrin & Intrinsic.Arm64VSizeMask) >> (int)Intrinsic.Arm64VSizeShift,
|
||||
info.Inst,
|
||||
(uint)operation.GetSource(2).AsInt32(),
|
||||
operation.Destination,
|
||||
operation.GetSource(0),
|
||||
operation.GetSource(1));
|
||||
break;
|
||||
case IntrinsicType.ScalarBinaryRd:
|
||||
GenerateVectorUnary(
|
||||
context,
|
||||
0,
|
||||
(uint)(intrin & Intrinsic.Arm64VSizeMask) >> (int)Intrinsic.Arm64VSizeShift,
|
||||
info.Inst,
|
||||
operation.Destination,
|
||||
operation.GetSource(1));
|
||||
break;
|
||||
case IntrinsicType.ScalarBinaryShl:
|
||||
Debug.Assert(operation.GetSource(1).Kind == OperandKind.Constant);
|
||||
|
||||
GenerateVectorBinaryShlImm(
|
||||
context,
|
||||
0,
|
||||
(uint)(intrin & Intrinsic.Arm64VSizeMask) >> (int)Intrinsic.Arm64VSizeShift,
|
||||
info.Inst,
|
||||
operation.Destination,
|
||||
operation.GetSource(0),
|
||||
(uint)operation.GetSource(1).AsInt32());
|
||||
break;
|
||||
case IntrinsicType.ScalarBinaryShr:
|
||||
Debug.Assert(operation.GetSource(1).Kind == OperandKind.Constant);
|
||||
|
||||
GenerateVectorBinaryShrImm(
|
||||
context,
|
||||
0,
|
||||
(uint)(intrin & Intrinsic.Arm64VSizeMask) >> (int)Intrinsic.Arm64VSizeShift,
|
||||
info.Inst,
|
||||
operation.Destination,
|
||||
operation.GetSource(0),
|
||||
(uint)operation.GetSource(1).AsInt32());
|
||||
break;
|
||||
case IntrinsicType.ScalarFPCompare:
|
||||
GenerateScalarFPCompare(
|
||||
context,
|
||||
(uint)(intrin & Intrinsic.Arm64VSizeMask) >> (int)Intrinsic.Arm64VSizeShift,
|
||||
info.Inst,
|
||||
operation.Destination,
|
||||
operation.GetSource(0),
|
||||
operation.GetSource(1));
|
||||
break;
|
||||
case IntrinsicType.ScalarFPConvFixed:
|
||||
Debug.Assert(operation.GetSource(1).Kind == OperandKind.Constant);
|
||||
|
||||
GenerateVectorBinaryShrImm(
|
||||
context,
|
||||
0,
|
||||
((uint)(intrin & Intrinsic.Arm64VSizeMask) >> (int)Intrinsic.Arm64VSizeShift) + 2u,
|
||||
info.Inst,
|
||||
operation.Destination,
|
||||
operation.GetSource(0),
|
||||
(uint)operation.GetSource(1).AsInt32());
|
||||
break;
|
||||
case IntrinsicType.ScalarFPConvFixedGpr:
|
||||
Debug.Assert(operation.GetSource(1).Kind == OperandKind.Constant);
|
||||
|
||||
GenerateScalarFPConvGpr(
|
||||
context,
|
||||
(uint)(intrin & Intrinsic.Arm64VSizeMask) >> (int)Intrinsic.Arm64VSizeShift,
|
||||
info.Inst,
|
||||
operation.Destination,
|
||||
operation.GetSource(0),
|
||||
(uint)operation.GetSource(1).AsInt32());
|
||||
break;
|
||||
case IntrinsicType.ScalarFPConvGpr:
|
||||
GenerateScalarFPConvGpr(
|
||||
context,
|
||||
(uint)(intrin & Intrinsic.Arm64VSizeMask) >> (int)Intrinsic.Arm64VSizeShift,
|
||||
info.Inst,
|
||||
operation.Destination,
|
||||
operation.GetSource(0));
|
||||
break;
|
||||
case IntrinsicType.ScalarTernary:
|
||||
GenerateScalarTernary(
|
||||
context,
|
||||
(uint)(intrin & Intrinsic.Arm64VSizeMask) >> (int)Intrinsic.Arm64VSizeShift,
|
||||
info.Inst,
|
||||
operation.Destination,
|
||||
operation.GetSource(1),
|
||||
operation.GetSource(2),
|
||||
operation.GetSource(0));
|
||||
break;
|
||||
case IntrinsicType.ScalarTernaryFPRdByElem:
|
||||
Debug.Assert(operation.GetSource(3).Kind == OperandKind.Constant);
|
||||
|
||||
GenerateVectorBinaryFPByElem(
|
||||
context,
|
||||
0,
|
||||
(uint)(intrin & Intrinsic.Arm64VSizeMask) >> (int)Intrinsic.Arm64VSizeShift,
|
||||
info.Inst,
|
||||
(uint)operation.GetSource(3).AsInt32(),
|
||||
operation.Destination,
|
||||
operation.GetSource(1),
|
||||
operation.GetSource(2));
|
||||
break;
|
||||
case IntrinsicType.ScalarTernaryShlRd:
|
||||
Debug.Assert(operation.GetSource(2).Kind == OperandKind.Constant);
|
||||
|
||||
GenerateVectorBinaryShlImm(
|
||||
context,
|
||||
0,
|
||||
(uint)(intrin & Intrinsic.Arm64VSizeMask) >> (int)Intrinsic.Arm64VSizeShift,
|
||||
info.Inst,
|
||||
operation.Destination,
|
||||
operation.GetSource(1),
|
||||
(uint)operation.GetSource(2).AsInt32());
|
||||
break;
|
||||
case IntrinsicType.ScalarTernaryShrRd:
|
||||
Debug.Assert(operation.GetSource(2).Kind == OperandKind.Constant);
|
||||
|
||||
GenerateVectorBinaryShrImm(
|
||||
context,
|
||||
0,
|
||||
(uint)(intrin & Intrinsic.Arm64VSizeMask) >> (int)Intrinsic.Arm64VSizeShift,
|
||||
info.Inst,
|
||||
operation.Destination,
|
||||
operation.GetSource(1),
|
||||
(uint)operation.GetSource(2).AsInt32());
|
||||
break;
|
||||
|
||||
case IntrinsicType.VectorUnary:
|
||||
GenerateVectorUnary(
|
||||
context,
|
||||
(uint)(intrin & Intrinsic.Arm64VTypeMask) >> (int)Intrinsic.Arm64VTypeShift,
|
||||
(uint)(intrin & Intrinsic.Arm64VSizeMask) >> (int)Intrinsic.Arm64VSizeShift,
|
||||
info.Inst,
|
||||
operation.Destination,
|
||||
operation.GetSource(0));
|
||||
break;
|
||||
case IntrinsicType.VectorUnaryByElem:
|
||||
Debug.Assert(operation.GetSource(1).Kind == OperandKind.Constant);
|
||||
|
||||
GenerateVectorUnaryByElem(
|
||||
context,
|
||||
(uint)(intrin & Intrinsic.Arm64VTypeMask) >> (int)Intrinsic.Arm64VTypeShift,
|
||||
(uint)(intrin & Intrinsic.Arm64VSizeMask) >> (int)Intrinsic.Arm64VSizeShift,
|
||||
info.Inst,
|
||||
(uint)operation.GetSource(1).AsInt32(),
|
||||
operation.Destination,
|
||||
operation.GetSource(0));
|
||||
break;
|
||||
case IntrinsicType.VectorBinary:
|
||||
GenerateVectorBinary(
|
||||
context,
|
||||
(uint)(intrin & Intrinsic.Arm64VTypeMask) >> (int)Intrinsic.Arm64VTypeShift,
|
||||
(uint)(intrin & Intrinsic.Arm64VSizeMask) >> (int)Intrinsic.Arm64VSizeShift,
|
||||
info.Inst,
|
||||
operation.Destination,
|
||||
operation.GetSource(0),
|
||||
operation.GetSource(1));
|
||||
break;
|
||||
case IntrinsicType.VectorBinaryBitwise:
|
||||
GenerateVectorBinary(
|
||||
context,
|
||||
(uint)(intrin & Intrinsic.Arm64VTypeMask) >> (int)Intrinsic.Arm64VTypeShift,
|
||||
info.Inst,
|
||||
operation.Destination,
|
||||
operation.GetSource(0),
|
||||
operation.GetSource(1));
|
||||
break;
|
||||
case IntrinsicType.VectorBinaryByElem:
|
||||
Debug.Assert(operation.GetSource(2).Kind == OperandKind.Constant);
|
||||
|
||||
GenerateVectorBinaryByElem(
|
||||
context,
|
||||
(uint)(intrin & Intrinsic.Arm64VTypeMask) >> (int)Intrinsic.Arm64VTypeShift,
|
||||
(uint)(intrin & Intrinsic.Arm64VSizeMask) >> (int)Intrinsic.Arm64VSizeShift,
|
||||
info.Inst,
|
||||
(uint)operation.GetSource(2).AsInt32(),
|
||||
operation.Destination,
|
||||
operation.GetSource(0),
|
||||
operation.GetSource(1));
|
||||
break;
|
||||
case IntrinsicType.VectorBinaryFPByElem:
|
||||
Debug.Assert(operation.GetSource(2).Kind == OperandKind.Constant);
|
||||
|
||||
GenerateVectorBinaryFPByElem(
|
||||
context,
|
||||
(uint)(intrin & Intrinsic.Arm64VTypeMask) >> (int)Intrinsic.Arm64VTypeShift,
|
||||
(uint)(intrin & Intrinsic.Arm64VSizeMask) >> (int)Intrinsic.Arm64VSizeShift,
|
||||
info.Inst,
|
||||
(uint)operation.GetSource(2).AsInt32(),
|
||||
operation.Destination,
|
||||
operation.GetSource(0),
|
||||
operation.GetSource(1));
|
||||
break;
|
||||
case IntrinsicType.VectorBinaryRd:
|
||||
GenerateVectorUnary(
|
||||
context,
|
||||
(uint)(intrin & Intrinsic.Arm64VTypeMask) >> (int)Intrinsic.Arm64VTypeShift,
|
||||
(uint)(intrin & Intrinsic.Arm64VSizeMask) >> (int)Intrinsic.Arm64VSizeShift,
|
||||
info.Inst,
|
||||
operation.Destination,
|
||||
operation.GetSource(1));
|
||||
break;
|
||||
case IntrinsicType.VectorBinaryShl:
|
||||
Debug.Assert(operation.GetSource(1).Kind == OperandKind.Constant);
|
||||
|
||||
GenerateVectorBinaryShlImm(
|
||||
context,
|
||||
(uint)(intrin & Intrinsic.Arm64VTypeMask) >> (int)Intrinsic.Arm64VTypeShift,
|
||||
(uint)(intrin & Intrinsic.Arm64VSizeMask) >> (int)Intrinsic.Arm64VSizeShift,
|
||||
info.Inst,
|
||||
operation.Destination,
|
||||
operation.GetSource(0),
|
||||
(uint)operation.GetSource(1).AsInt32());
|
||||
break;
|
||||
case IntrinsicType.VectorBinaryShr:
|
||||
Debug.Assert(operation.GetSource(1).Kind == OperandKind.Constant);
|
||||
|
||||
GenerateVectorBinaryShrImm(
|
||||
context,
|
||||
(uint)(intrin & Intrinsic.Arm64VTypeMask) >> (int)Intrinsic.Arm64VTypeShift,
|
||||
(uint)(intrin & Intrinsic.Arm64VSizeMask) >> (int)Intrinsic.Arm64VSizeShift,
|
||||
info.Inst,
|
||||
operation.Destination,
|
||||
operation.GetSource(0),
|
||||
(uint)operation.GetSource(1).AsInt32());
|
||||
break;
|
||||
case IntrinsicType.VectorFPConvFixed:
|
||||
Debug.Assert(operation.GetSource(1).Kind == OperandKind.Constant);
|
||||
|
||||
GenerateVectorBinaryShrImm(
|
||||
context,
|
||||
(uint)(intrin & Intrinsic.Arm64VTypeMask) >> (int)Intrinsic.Arm64VTypeShift,
|
||||
((uint)(intrin & Intrinsic.Arm64VSizeMask) >> (int)Intrinsic.Arm64VSizeShift) + 2u,
|
||||
info.Inst,
|
||||
operation.Destination,
|
||||
operation.GetSource(0),
|
||||
(uint)operation.GetSource(1).AsInt32());
|
||||
break;
|
||||
case IntrinsicType.VectorInsertByElem:
|
||||
Debug.Assert(operation.GetSource(1).Kind == OperandKind.Constant);
|
||||
Debug.Assert(operation.GetSource(3).Kind == OperandKind.Constant);
|
||||
|
||||
GenerateVectorInsertByElem(
|
||||
context,
|
||||
(uint)(intrin & Intrinsic.Arm64VSizeMask) >> (int)Intrinsic.Arm64VSizeShift,
|
||||
info.Inst,
|
||||
(uint)operation.GetSource(3).AsInt32(),
|
||||
(uint)operation.GetSource(1).AsInt32(),
|
||||
operation.Destination,
|
||||
operation.GetSource(2));
|
||||
break;
|
||||
case IntrinsicType.VectorLookupTable:
|
||||
Debug.Assert((uint)(operation.SourcesCount - 2) <= 3);
|
||||
|
||||
for (int i = 1; i < operation.SourcesCount - 1; i++)
|
||||
{
|
||||
Register currReg = operation.GetSource(i).GetRegister();
|
||||
Register prevReg = operation.GetSource(i - 1).GetRegister();
|
||||
|
||||
Debug.Assert(prevReg.Index + 1 == currReg.Index && currReg.Type == RegisterType.Vector);
|
||||
}
|
||||
|
||||
GenerateVectorBinary(
|
||||
context,
|
||||
(uint)(intrin & Intrinsic.Arm64VTypeMask) >> (int)Intrinsic.Arm64VTypeShift,
|
||||
info.Inst | ((uint)(operation.SourcesCount - 2) << 13),
|
||||
operation.Destination,
|
||||
operation.GetSource(0),
|
||||
operation.GetSource(operation.SourcesCount - 1));
|
||||
break;
|
||||
case IntrinsicType.VectorTernaryFPRdByElem:
|
||||
Debug.Assert(operation.GetSource(3).Kind == OperandKind.Constant);
|
||||
|
||||
GenerateVectorBinaryFPByElem(
|
||||
context,
|
||||
(uint)(intrin & Intrinsic.Arm64VTypeMask) >> (int)Intrinsic.Arm64VTypeShift,
|
||||
(uint)(intrin & Intrinsic.Arm64VSizeMask) >> (int)Intrinsic.Arm64VSizeShift,
|
||||
info.Inst,
|
||||
(uint)operation.GetSource(3).AsInt32(),
|
||||
operation.Destination,
|
||||
operation.GetSource(1),
|
||||
operation.GetSource(2));
|
||||
break;
|
||||
case IntrinsicType.VectorTernaryRd:
|
||||
GenerateVectorBinary(
|
||||
context,
|
||||
(uint)(intrin & Intrinsic.Arm64VTypeMask) >> (int)Intrinsic.Arm64VTypeShift,
|
||||
(uint)(intrin & Intrinsic.Arm64VSizeMask) >> (int)Intrinsic.Arm64VSizeShift,
|
||||
info.Inst,
|
||||
operation.Destination,
|
||||
operation.GetSource(1),
|
||||
operation.GetSource(2));
|
||||
break;
|
||||
case IntrinsicType.VectorTernaryRdBitwise:
|
||||
GenerateVectorBinary(
|
||||
context,
|
||||
(uint)(intrin & Intrinsic.Arm64VTypeMask) >> (int)Intrinsic.Arm64VTypeShift,
|
||||
info.Inst,
|
||||
operation.Destination,
|
||||
operation.GetSource(1),
|
||||
operation.GetSource(2));
|
||||
break;
|
||||
case IntrinsicType.VectorTernaryRdByElem:
|
||||
Debug.Assert(operation.GetSource(3).Kind == OperandKind.Constant);
|
||||
|
||||
GenerateVectorBinaryByElem(
|
||||
context,
|
||||
(uint)(intrin & Intrinsic.Arm64VTypeMask) >> (int)Intrinsic.Arm64VTypeShift,
|
||||
(uint)(intrin & Intrinsic.Arm64VSizeMask) >> (int)Intrinsic.Arm64VSizeShift,
|
||||
info.Inst,
|
||||
(uint)operation.GetSource(3).AsInt32(),
|
||||
operation.Destination,
|
||||
operation.GetSource(1),
|
||||
operation.GetSource(2));
|
||||
break;
|
||||
case IntrinsicType.VectorTernaryShlRd:
|
||||
Debug.Assert(operation.GetSource(2).Kind == OperandKind.Constant);
|
||||
|
||||
GenerateVectorBinaryShlImm(
|
||||
context,
|
||||
(uint)(intrin & Intrinsic.Arm64VTypeMask) >> (int)Intrinsic.Arm64VTypeShift,
|
||||
(uint)(intrin & Intrinsic.Arm64VSizeMask) >> (int)Intrinsic.Arm64VSizeShift,
|
||||
info.Inst,
|
||||
operation.Destination,
|
||||
operation.GetSource(1),
|
||||
(uint)operation.GetSource(2).AsInt32());
|
||||
break;
|
||||
case IntrinsicType.VectorTernaryShrRd:
|
||||
Debug.Assert(operation.GetSource(2).Kind == OperandKind.Constant);
|
||||
|
||||
GenerateVectorBinaryShrImm(
|
||||
context,
|
||||
(uint)(intrin & Intrinsic.Arm64VTypeMask) >> (int)Intrinsic.Arm64VTypeShift,
|
||||
(uint)(intrin & Intrinsic.Arm64VSizeMask) >> (int)Intrinsic.Arm64VSizeShift,
|
||||
info.Inst,
|
||||
operation.Destination,
|
||||
operation.GetSource(1),
|
||||
(uint)operation.GetSource(2).AsInt32());
|
||||
break;
|
||||
|
||||
case IntrinsicType.GetRegister:
|
||||
context.Assembler.WriteInstruction(info.Inst, operation.Destination);
|
||||
break;
|
||||
case IntrinsicType.SetRegister:
|
||||
context.Assembler.WriteInstruction(info.Inst, operation.GetSource(0));
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new NotImplementedException(info.Type.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
private static void GenerateScalarFPCompare(
|
||||
CodeGenContext context,
|
||||
uint sz,
|
||||
uint instruction,
|
||||
Operand dest,
|
||||
Operand rn,
|
||||
Operand rm)
|
||||
{
|
||||
instruction |= (sz << 22);
|
||||
|
||||
if (rm.Kind == OperandKind.Constant && rm.Value == 0)
|
||||
{
|
||||
instruction |= 0b1000;
|
||||
rm = rn;
|
||||
}
|
||||
|
||||
context.Assembler.WriteInstructionRm16NoRet(instruction, rn, rm);
|
||||
context.Assembler.Mrs(dest, 1, 3, 4, 2, 0);
|
||||
}
|
||||
|
||||
private static void GenerateScalarFPConvGpr(
|
||||
CodeGenContext context,
|
||||
uint sz,
|
||||
uint instruction,
|
||||
Operand rd,
|
||||
Operand rn)
|
||||
{
|
||||
instruction |= (sz << 22);
|
||||
|
||||
if (rd.Type.IsInteger())
|
||||
{
|
||||
context.Assembler.WriteInstructionAuto(instruction, rd, rn);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (rn.Type == OperandType.I64)
|
||||
{
|
||||
instruction |= Assembler.SfFlag;
|
||||
}
|
||||
|
||||
context.Assembler.WriteInstruction(instruction, rd, rn);
|
||||
}
|
||||
}
|
||||
|
||||
private static void GenerateScalarFPConvGpr(
|
||||
CodeGenContext context,
|
||||
uint sz,
|
||||
uint instruction,
|
||||
Operand rd,
|
||||
Operand rn,
|
||||
uint fBits)
|
||||
{
|
||||
Debug.Assert(fBits <= 64);
|
||||
|
||||
instruction |= (sz << 22);
|
||||
instruction |= (64 - fBits) << 10;
|
||||
|
||||
if (rd.Type.IsInteger())
|
||||
{
|
||||
Debug.Assert(rd.Type != OperandType.I32 || fBits <= 32);
|
||||
|
||||
context.Assembler.WriteInstructionAuto(instruction, rd, rn);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (rn.Type == OperandType.I64)
|
||||
{
|
||||
instruction |= Assembler.SfFlag;
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.Assert(fBits <= 32);
|
||||
}
|
||||
|
||||
context.Assembler.WriteInstruction(instruction, rd, rn);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static void GenerateScalarTernary(
|
||||
CodeGenContext context,
|
||||
uint sz,
|
||||
uint instruction,
|
||||
Operand rd,
|
||||
Operand rn,
|
||||
Operand rm,
|
||||
Operand ra)
|
||||
{
|
||||
instruction |= (sz << 22);
|
||||
|
||||
context.Assembler.WriteInstruction(instruction, rd, rn, rm, ra);
|
||||
}
|
||||
|
||||
private static void GenerateVectorUnary(
|
||||
CodeGenContext context,
|
||||
uint q,
|
||||
uint sz,
|
||||
uint instruction,
|
||||
Operand rd,
|
||||
Operand rn)
|
||||
{
|
||||
instruction |= (q << 30) | (sz << 22);
|
||||
|
||||
context.Assembler.WriteInstruction(instruction, rd, rn);
|
||||
}
|
||||
|
||||
private static void GenerateVectorUnaryByElem(
|
||||
CodeGenContext context,
|
||||
uint q,
|
||||
uint sz,
|
||||
uint instruction,
|
||||
uint srcIndex,
|
||||
Operand rd,
|
||||
Operand rn)
|
||||
{
|
||||
uint imm5 = (srcIndex << ((int)sz + 1)) | (1u << (int)sz);
|
||||
|
||||
instruction |= (q << 30) | (imm5 << 16);
|
||||
|
||||
context.Assembler.WriteInstruction(instruction, rd, rn);
|
||||
}
|
||||
|
||||
private static void GenerateVectorBinary(
|
||||
CodeGenContext context,
|
||||
uint q,
|
||||
uint instruction,
|
||||
Operand rd,
|
||||
Operand rn,
|
||||
Operand rm)
|
||||
{
|
||||
instruction |= (q << 30);
|
||||
|
||||
context.Assembler.WriteInstructionRm16(instruction, rd, rn, rm);
|
||||
}
|
||||
|
||||
private static void GenerateVectorBinary(
|
||||
CodeGenContext context,
|
||||
uint q,
|
||||
uint sz,
|
||||
uint instruction,
|
||||
Operand rd,
|
||||
Operand rn,
|
||||
Operand rm)
|
||||
{
|
||||
instruction |= (q << 30) | (sz << 22);
|
||||
|
||||
context.Assembler.WriteInstructionRm16(instruction, rd, rn, rm);
|
||||
}
|
||||
|
||||
private static void GenerateVectorBinaryByElem(
|
||||
CodeGenContext context,
|
||||
uint q,
|
||||
uint size,
|
||||
uint instruction,
|
||||
uint srcIndex,
|
||||
Operand rd,
|
||||
Operand rn,
|
||||
Operand rm)
|
||||
{
|
||||
instruction |= (q << 30) | (size << 22);
|
||||
|
||||
if (size == 2)
|
||||
{
|
||||
instruction |= ((srcIndex & 1) << 21) | ((srcIndex & 2) << 10);
|
||||
}
|
||||
else
|
||||
{
|
||||
instruction |= ((srcIndex & 3) << 20) | ((srcIndex & 4) << 9);
|
||||
}
|
||||
|
||||
context.Assembler.WriteInstructionRm16(instruction, rd, rn, rm);
|
||||
}
|
||||
|
||||
private static void GenerateVectorBinaryFPByElem(
|
||||
CodeGenContext context,
|
||||
uint q,
|
||||
uint sz,
|
||||
uint instruction,
|
||||
uint srcIndex,
|
||||
Operand rd,
|
||||
Operand rn,
|
||||
Operand rm)
|
||||
{
|
||||
instruction |= (q << 30) | (sz << 22);
|
||||
|
||||
if (sz != 0)
|
||||
{
|
||||
instruction |= (srcIndex & 1) << 11;
|
||||
}
|
||||
else
|
||||
{
|
||||
instruction |= ((srcIndex & 1) << 21) | ((srcIndex & 2) << 10);
|
||||
}
|
||||
|
||||
context.Assembler.WriteInstructionRm16(instruction, rd, rn, rm);
|
||||
}
|
||||
|
||||
private static void GenerateVectorBinaryShlImm(
|
||||
CodeGenContext context,
|
||||
uint q,
|
||||
uint sz,
|
||||
uint instruction,
|
||||
Operand rd,
|
||||
Operand rn,
|
||||
uint shift)
|
||||
{
|
||||
instruction |= (q << 30);
|
||||
|
||||
Debug.Assert(shift >= 0 && shift < (8u << (int)sz));
|
||||
|
||||
uint imm = (8u << (int)sz) | (shift & (0x3fu >> (int)(3 - sz)));
|
||||
|
||||
instruction |= (imm << 16);
|
||||
|
||||
context.Assembler.WriteInstruction(instruction, rd, rn);
|
||||
}
|
||||
|
||||
private static void GenerateVectorBinaryShrImm(
|
||||
CodeGenContext context,
|
||||
uint q,
|
||||
uint sz,
|
||||
uint instruction,
|
||||
Operand rd,
|
||||
Operand rn,
|
||||
uint shift)
|
||||
{
|
||||
instruction |= (q << 30);
|
||||
|
||||
Debug.Assert(shift > 0 && shift <= (8u << (int)sz));
|
||||
|
||||
uint imm = (8u << (int)sz) | ((8u << (int)sz) - shift);
|
||||
|
||||
instruction |= (imm << 16);
|
||||
|
||||
context.Assembler.WriteInstruction(instruction, rd, rn);
|
||||
}
|
||||
|
||||
private static void GenerateVectorInsertByElem(
|
||||
CodeGenContext context,
|
||||
uint sz,
|
||||
uint instruction,
|
||||
uint srcIndex,
|
||||
uint dstIndex,
|
||||
Operand rd,
|
||||
Operand rn)
|
||||
{
|
||||
uint imm4 = srcIndex << (int)sz;
|
||||
uint imm5 = (dstIndex << ((int)sz + 1)) | (1u << (int)sz);
|
||||
|
||||
instruction |= imm4 << 11;
|
||||
instruction |= imm5 << 16;
|
||||
|
||||
context.Assembler.WriteInstruction(instruction, rd, rn);
|
||||
}
|
||||
}
|
||||
}
|
185
ARMeilleure/CodeGen/Arm64/HardwareCapabilities.cs
Normal file
185
ARMeilleure/CodeGen/Arm64/HardwareCapabilities.cs
Normal file
@ -0,0 +1,185 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.Intrinsics.Arm;
|
||||
using System.Runtime.Versioning;
|
||||
|
||||
namespace ARMeilleure.CodeGen.Arm64
|
||||
{
|
||||
static partial class HardwareCapabilities
|
||||
{
|
||||
static HardwareCapabilities()
|
||||
{
|
||||
if (!ArmBase.Arm64.IsSupported)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (OperatingSystem.IsLinux())
|
||||
{
|
||||
LinuxFeatureInfoHwCap = (LinuxFeatureFlagsHwCap)getauxval(AT_HWCAP);
|
||||
LinuxFeatureInfoHwCap2 = (LinuxFeatureFlagsHwCap2)getauxval(AT_HWCAP2);
|
||||
}
|
||||
|
||||
if (OperatingSystem.IsMacOS())
|
||||
{
|
||||
for (int i = 0; i < _sysctlNames.Length; i++)
|
||||
{
|
||||
if (CheckSysctlName(_sysctlNames[i]))
|
||||
{
|
||||
MacOsFeatureInfo |= (MacOsFeatureFlags)(1 << i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#region Linux
|
||||
|
||||
private const ulong AT_HWCAP = 16;
|
||||
private const ulong AT_HWCAP2 = 26;
|
||||
|
||||
[LibraryImport("libc", SetLastError = true)]
|
||||
private static partial ulong getauxval(ulong type);
|
||||
|
||||
[Flags]
|
||||
public enum LinuxFeatureFlagsHwCap : ulong
|
||||
{
|
||||
Fp = 1 << 0,
|
||||
Asimd = 1 << 1,
|
||||
Evtstrm = 1 << 2,
|
||||
Aes = 1 << 3,
|
||||
Pmull = 1 << 4,
|
||||
Sha1 = 1 << 5,
|
||||
Sha2 = 1 << 6,
|
||||
Crc32 = 1 << 7,
|
||||
Atomics = 1 << 8,
|
||||
FpHp = 1 << 9,
|
||||
AsimdHp = 1 << 10,
|
||||
CpuId = 1 << 11,
|
||||
AsimdRdm = 1 << 12,
|
||||
Jscvt = 1 << 13,
|
||||
Fcma = 1 << 14,
|
||||
Lrcpc = 1 << 15,
|
||||
DcpOp = 1 << 16,
|
||||
Sha3 = 1 << 17,
|
||||
Sm3 = 1 << 18,
|
||||
Sm4 = 1 << 19,
|
||||
AsimdDp = 1 << 20,
|
||||
Sha512 = 1 << 21,
|
||||
Sve = 1 << 22,
|
||||
AsimdFhm = 1 << 23,
|
||||
Dit = 1 << 24,
|
||||
Uscat = 1 << 25,
|
||||
Ilrcpc = 1 << 26,
|
||||
FlagM = 1 << 27,
|
||||
Ssbs = 1 << 28,
|
||||
Sb = 1 << 29,
|
||||
Paca = 1 << 30,
|
||||
Pacg = 1UL << 31
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum LinuxFeatureFlagsHwCap2 : ulong
|
||||
{
|
||||
Dcpodp = 1 << 0,
|
||||
Sve2 = 1 << 1,
|
||||
SveAes = 1 << 2,
|
||||
SvePmull = 1 << 3,
|
||||
SveBitperm = 1 << 4,
|
||||
SveSha3 = 1 << 5,
|
||||
SveSm4 = 1 << 6,
|
||||
FlagM2 = 1 << 7,
|
||||
Frint = 1 << 8,
|
||||
SveI8mm = 1 << 9,
|
||||
SveF32mm = 1 << 10,
|
||||
SveF64mm = 1 << 11,
|
||||
SveBf16 = 1 << 12,
|
||||
I8mm = 1 << 13,
|
||||
Bf16 = 1 << 14,
|
||||
Dgh = 1 << 15,
|
||||
Rng = 1 << 16,
|
||||
Bti = 1 << 17,
|
||||
Mte = 1 << 18,
|
||||
Ecv = 1 << 19,
|
||||
Afp = 1 << 20,
|
||||
Rpres = 1 << 21,
|
||||
Mte3 = 1 << 22,
|
||||
Sme = 1 << 23,
|
||||
Sme_i16i64 = 1 << 24,
|
||||
Sme_f64f64 = 1 << 25,
|
||||
Sme_i8i32 = 1 << 26,
|
||||
Sme_f16f32 = 1 << 27,
|
||||
Sme_b16f32 = 1 << 28,
|
||||
Sme_f32f32 = 1 << 29,
|
||||
Sme_fa64 = 1 << 30,
|
||||
Wfxt = 1UL << 31,
|
||||
Ebf16 = 1UL << 32,
|
||||
Sve_Ebf16 = 1UL << 33,
|
||||
Cssc = 1UL << 34,
|
||||
Rprfm = 1UL << 35,
|
||||
Sve2p1 = 1UL << 36
|
||||
}
|
||||
|
||||
public static LinuxFeatureFlagsHwCap LinuxFeatureInfoHwCap { get; } = 0;
|
||||
public static LinuxFeatureFlagsHwCap2 LinuxFeatureInfoHwCap2 { get; } = 0;
|
||||
|
||||
#endregion
|
||||
|
||||
#region macOS
|
||||
|
||||
[LibraryImport("libSystem.dylib", SetLastError = true)]
|
||||
private static unsafe partial int sysctlbyname([MarshalAs(UnmanagedType.LPStr)] string name, out int oldValue, ref ulong oldSize, IntPtr newValue, ulong newValueSize);
|
||||
|
||||
[SupportedOSPlatform("macos")]
|
||||
private static bool CheckSysctlName(string name)
|
||||
{
|
||||
ulong size = sizeof(int);
|
||||
if (sysctlbyname(name, out int val, ref size, IntPtr.Zero, 0) == 0 && size == sizeof(int))
|
||||
{
|
||||
return val != 0;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static string[] _sysctlNames = new string[]
|
||||
{
|
||||
"hw.optional.floatingpoint",
|
||||
"hw.optional.AdvSIMD",
|
||||
"hw.optional.arm.FEAT_FP16",
|
||||
"hw.optional.arm.FEAT_AES",
|
||||
"hw.optional.arm.FEAT_PMULL",
|
||||
"hw.optional.arm.FEAT_LSE",
|
||||
"hw.optional.armv8_crc32",
|
||||
"hw.optional.arm.FEAT_SHA1",
|
||||
"hw.optional.arm.FEAT_SHA256"
|
||||
};
|
||||
|
||||
[Flags]
|
||||
public enum MacOsFeatureFlags
|
||||
{
|
||||
Fp = 1 << 0,
|
||||
AdvSimd = 1 << 1,
|
||||
Fp16 = 1 << 2,
|
||||
Aes = 1 << 3,
|
||||
Pmull = 1 << 4,
|
||||
Lse = 1 << 5,
|
||||
Crc32 = 1 << 6,
|
||||
Sha1 = 1 << 7,
|
||||
Sha256 = 1 << 8
|
||||
}
|
||||
|
||||
public static MacOsFeatureFlags MacOsFeatureInfo { get; } = 0;
|
||||
|
||||
#endregion
|
||||
|
||||
public static bool SupportsAdvSimd => LinuxFeatureInfoHwCap.HasFlag(LinuxFeatureFlagsHwCap.Asimd) || MacOsFeatureInfo.HasFlag(MacOsFeatureFlags.AdvSimd);
|
||||
public static bool SupportsAes => LinuxFeatureInfoHwCap.HasFlag(LinuxFeatureFlagsHwCap.Aes) || MacOsFeatureInfo.HasFlag(MacOsFeatureFlags.Aes);
|
||||
public static bool SupportsPmull => LinuxFeatureInfoHwCap.HasFlag(LinuxFeatureFlagsHwCap.Pmull) || MacOsFeatureInfo.HasFlag(MacOsFeatureFlags.Pmull);
|
||||
public static bool SupportsLse => LinuxFeatureInfoHwCap.HasFlag(LinuxFeatureFlagsHwCap.Atomics) || MacOsFeatureInfo.HasFlag(MacOsFeatureFlags.Lse);
|
||||
public static bool SupportsCrc32 => LinuxFeatureInfoHwCap.HasFlag(LinuxFeatureFlagsHwCap.Crc32) || MacOsFeatureInfo.HasFlag(MacOsFeatureFlags.Crc32);
|
||||
public static bool SupportsSha1 => LinuxFeatureInfoHwCap.HasFlag(LinuxFeatureFlagsHwCap.Sha1) || MacOsFeatureInfo.HasFlag(MacOsFeatureFlags.Sha1);
|
||||
public static bool SupportsSha256 => LinuxFeatureInfoHwCap.HasFlag(LinuxFeatureFlagsHwCap.Sha2) || MacOsFeatureInfo.HasFlag(MacOsFeatureFlags.Sha256);
|
||||
}
|
||||
}
|
14
ARMeilleure/CodeGen/Arm64/IntrinsicInfo.cs
Normal file
14
ARMeilleure/CodeGen/Arm64/IntrinsicInfo.cs
Normal file
@ -0,0 +1,14 @@
|
||||
namespace ARMeilleure.CodeGen.Arm64
|
||||
{
|
||||
struct IntrinsicInfo
|
||||
{
|
||||
public uint Inst { get; }
|
||||
public IntrinsicType Type { get; }
|
||||
|
||||
public IntrinsicInfo(uint inst, IntrinsicType type)
|
||||
{
|
||||
Inst = inst;
|
||||
Type = type;
|
||||
}
|
||||
}
|
||||
}
|
461
ARMeilleure/CodeGen/Arm64/IntrinsicTable.cs
Normal file
461
ARMeilleure/CodeGen/Arm64/IntrinsicTable.cs
Normal file
@ -0,0 +1,461 @@
|
||||
using ARMeilleure.Common;
|
||||
using ARMeilleure.IntermediateRepresentation;
|
||||
|
||||
namespace ARMeilleure.CodeGen.Arm64
|
||||
{
|
||||
static class IntrinsicTable
|
||||
{
|
||||
private static IntrinsicInfo[] _intrinTable;
|
||||
|
||||
static IntrinsicTable()
|
||||
{
|
||||
_intrinTable = new IntrinsicInfo[EnumUtils.GetCount(typeof(Intrinsic))];
|
||||
|
||||
Add(Intrinsic.Arm64AbsS, new IntrinsicInfo(0x5e20b800u, IntrinsicType.ScalarUnary));
|
||||
Add(Intrinsic.Arm64AbsV, new IntrinsicInfo(0x0e20b800u, IntrinsicType.VectorUnary));
|
||||
Add(Intrinsic.Arm64AddhnV, new IntrinsicInfo(0x0e204000u, IntrinsicType.VectorTernaryRd));
|
||||
Add(Intrinsic.Arm64AddpS, new IntrinsicInfo(0x5e31b800u, IntrinsicType.ScalarUnary));
|
||||
Add(Intrinsic.Arm64AddpV, new IntrinsicInfo(0x0e20bc00u, IntrinsicType.VectorBinary));
|
||||
Add(Intrinsic.Arm64AddvV, new IntrinsicInfo(0x0e31b800u, IntrinsicType.VectorUnary));
|
||||
Add(Intrinsic.Arm64AddS, new IntrinsicInfo(0x5e208400u, IntrinsicType.ScalarBinary));
|
||||
Add(Intrinsic.Arm64AddV, new IntrinsicInfo(0x0e208400u, IntrinsicType.VectorBinary));
|
||||
Add(Intrinsic.Arm64AesdV, new IntrinsicInfo(0x4e285800u, IntrinsicType.Vector128Unary));
|
||||
Add(Intrinsic.Arm64AeseV, new IntrinsicInfo(0x4e284800u, IntrinsicType.Vector128Unary));
|
||||
Add(Intrinsic.Arm64AesimcV, new IntrinsicInfo(0x4e287800u, IntrinsicType.Vector128Unary));
|
||||
Add(Intrinsic.Arm64AesmcV, new IntrinsicInfo(0x4e286800u, IntrinsicType.Vector128Unary));
|
||||
Add(Intrinsic.Arm64AndV, new IntrinsicInfo(0x0e201c00u, IntrinsicType.VectorBinaryBitwise));
|
||||
Add(Intrinsic.Arm64BicVi, new IntrinsicInfo(0x2f001400u, IntrinsicType.VectorBinaryBitwiseImm));
|
||||
Add(Intrinsic.Arm64BicV, new IntrinsicInfo(0x0e601c00u, IntrinsicType.VectorBinaryBitwise));
|
||||
Add(Intrinsic.Arm64BifV, new IntrinsicInfo(0x2ee01c00u, IntrinsicType.VectorTernaryRdBitwise));
|
||||
Add(Intrinsic.Arm64BitV, new IntrinsicInfo(0x2ea01c00u, IntrinsicType.VectorTernaryRdBitwise));
|
||||
Add(Intrinsic.Arm64BslV, new IntrinsicInfo(0x2e601c00u, IntrinsicType.VectorTernaryRdBitwise));
|
||||
Add(Intrinsic.Arm64ClsV, new IntrinsicInfo(0x0e204800u, IntrinsicType.VectorUnary));
|
||||
Add(Intrinsic.Arm64ClzV, new IntrinsicInfo(0x2e204800u, IntrinsicType.VectorUnary));
|
||||
Add(Intrinsic.Arm64CmeqS, new IntrinsicInfo(0x7e208c00u, IntrinsicType.ScalarBinary));
|
||||
Add(Intrinsic.Arm64CmeqV, new IntrinsicInfo(0x2e208c00u, IntrinsicType.VectorBinary));
|
||||
Add(Intrinsic.Arm64CmeqSz, new IntrinsicInfo(0x5e209800u, IntrinsicType.ScalarUnary));
|
||||
Add(Intrinsic.Arm64CmeqVz, new IntrinsicInfo(0x0e209800u, IntrinsicType.VectorUnary));
|
||||
Add(Intrinsic.Arm64CmgeS, new IntrinsicInfo(0x5e203c00u, IntrinsicType.ScalarBinary));
|
||||
Add(Intrinsic.Arm64CmgeV, new IntrinsicInfo(0x0e203c00u, IntrinsicType.VectorBinary));
|
||||
Add(Intrinsic.Arm64CmgeSz, new IntrinsicInfo(0x7e208800u, IntrinsicType.ScalarUnary));
|
||||
Add(Intrinsic.Arm64CmgeVz, new IntrinsicInfo(0x2e208800u, IntrinsicType.VectorUnary));
|
||||
Add(Intrinsic.Arm64CmgtS, new IntrinsicInfo(0x5e203400u, IntrinsicType.ScalarBinary));
|
||||
Add(Intrinsic.Arm64CmgtV, new IntrinsicInfo(0x0e203400u, IntrinsicType.VectorBinary));
|
||||
Add(Intrinsic.Arm64CmgtSz, new IntrinsicInfo(0x5e208800u, IntrinsicType.ScalarUnary));
|
||||
Add(Intrinsic.Arm64CmgtVz, new IntrinsicInfo(0x0e208800u, IntrinsicType.VectorUnary));
|
||||
Add(Intrinsic.Arm64CmhiS, new IntrinsicInfo(0x7e203400u, IntrinsicType.ScalarBinary));
|
||||
Add(Intrinsic.Arm64CmhiV, new IntrinsicInfo(0x2e203400u, IntrinsicType.VectorBinary));
|
||||
Add(Intrinsic.Arm64CmhsS, new IntrinsicInfo(0x7e203c00u, IntrinsicType.ScalarBinary));
|
||||
Add(Intrinsic.Arm64CmhsV, new IntrinsicInfo(0x2e203c00u, IntrinsicType.VectorBinary));
|
||||
Add(Intrinsic.Arm64CmleSz, new IntrinsicInfo(0x7e209800u, IntrinsicType.ScalarUnary));
|
||||
Add(Intrinsic.Arm64CmleVz, new IntrinsicInfo(0x2e209800u, IntrinsicType.VectorUnary));
|
||||
Add(Intrinsic.Arm64CmltSz, new IntrinsicInfo(0x5e20a800u, IntrinsicType.ScalarUnary));
|
||||
Add(Intrinsic.Arm64CmltVz, new IntrinsicInfo(0x0e20a800u, IntrinsicType.VectorUnary));
|
||||
Add(Intrinsic.Arm64CmtstS, new IntrinsicInfo(0x5e208c00u, IntrinsicType.ScalarBinary));
|
||||
Add(Intrinsic.Arm64CmtstV, new IntrinsicInfo(0x0e208c00u, IntrinsicType.VectorBinary));
|
||||
Add(Intrinsic.Arm64CntV, new IntrinsicInfo(0x0e205800u, IntrinsicType.VectorUnary));
|
||||
Add(Intrinsic.Arm64DupSe, new IntrinsicInfo(0x5e000400u, IntrinsicType.ScalarUnaryByElem));
|
||||
Add(Intrinsic.Arm64DupVe, new IntrinsicInfo(0x0e000400u, IntrinsicType.VectorUnaryByElem));
|
||||
Add(Intrinsic.Arm64DupGp, new IntrinsicInfo(0x0e000c00u, IntrinsicType.VectorUnaryByElem));
|
||||
Add(Intrinsic.Arm64EorV, new IntrinsicInfo(0x2e201c00u, IntrinsicType.VectorBinaryBitwise));
|
||||
Add(Intrinsic.Arm64ExtV, new IntrinsicInfo(0x2e000000u, IntrinsicType.VectorExt));
|
||||
Add(Intrinsic.Arm64FabdS, new IntrinsicInfo(0x7ea0d400u, IntrinsicType.ScalarBinary));
|
||||
Add(Intrinsic.Arm64FabdV, new IntrinsicInfo(0x2ea0d400u, IntrinsicType.VectorBinary));
|
||||
Add(Intrinsic.Arm64FabsV, new IntrinsicInfo(0x0ea0f800u, IntrinsicType.VectorUnary));
|
||||
Add(Intrinsic.Arm64FabsS, new IntrinsicInfo(0x1e20c000u, IntrinsicType.ScalarUnary));
|
||||
Add(Intrinsic.Arm64FacgeS, new IntrinsicInfo(0x7e20ec00u, IntrinsicType.ScalarBinary));
|
||||
Add(Intrinsic.Arm64FacgeV, new IntrinsicInfo(0x2e20ec00u, IntrinsicType.VectorBinary));
|
||||
Add(Intrinsic.Arm64FacgtS, new IntrinsicInfo(0x7ea0ec00u, IntrinsicType.ScalarBinary));
|
||||
Add(Intrinsic.Arm64FacgtV, new IntrinsicInfo(0x2ea0ec00u, IntrinsicType.VectorBinary));
|
||||
Add(Intrinsic.Arm64FaddpS, new IntrinsicInfo(0x7e30d800u, IntrinsicType.ScalarUnary));
|
||||
Add(Intrinsic.Arm64FaddpV, new IntrinsicInfo(0x2e20d400u, IntrinsicType.VectorBinary));
|
||||
Add(Intrinsic.Arm64FaddV, new IntrinsicInfo(0x0e20d400u, IntrinsicType.VectorBinary));
|
||||
Add(Intrinsic.Arm64FaddS, new IntrinsicInfo(0x1e202800u, IntrinsicType.ScalarBinary));
|
||||
Add(Intrinsic.Arm64FccmpeS, new IntrinsicInfo(0x1e200410u, IntrinsicType.ScalarFPCompareCond));
|
||||
Add(Intrinsic.Arm64FccmpS, new IntrinsicInfo(0x1e200400u, IntrinsicType.ScalarFPCompareCond));
|
||||
Add(Intrinsic.Arm64FcmeqS, new IntrinsicInfo(0x5e20e400u, IntrinsicType.ScalarBinary));
|
||||
Add(Intrinsic.Arm64FcmeqV, new IntrinsicInfo(0x0e20e400u, IntrinsicType.VectorBinary));
|
||||
Add(Intrinsic.Arm64FcmeqSz, new IntrinsicInfo(0x5ea0d800u, IntrinsicType.ScalarUnary));
|
||||
Add(Intrinsic.Arm64FcmeqVz, new IntrinsicInfo(0x0ea0d800u, IntrinsicType.VectorUnary));
|
||||
Add(Intrinsic.Arm64FcmgeS, new IntrinsicInfo(0x7e20e400u, IntrinsicType.ScalarBinary));
|
||||
Add(Intrinsic.Arm64FcmgeV, new IntrinsicInfo(0x2e20e400u, IntrinsicType.VectorBinary));
|
||||
Add(Intrinsic.Arm64FcmgeSz, new IntrinsicInfo(0x7ea0c800u, IntrinsicType.ScalarUnary));
|
||||
Add(Intrinsic.Arm64FcmgeVz, new IntrinsicInfo(0x2ea0c800u, IntrinsicType.VectorUnary));
|
||||
Add(Intrinsic.Arm64FcmgtS, new IntrinsicInfo(0x7ea0e400u, IntrinsicType.ScalarBinary));
|
||||
Add(Intrinsic.Arm64FcmgtV, new IntrinsicInfo(0x2ea0e400u, IntrinsicType.VectorBinary));
|
||||
Add(Intrinsic.Arm64FcmgtSz, new IntrinsicInfo(0x5ea0c800u, IntrinsicType.ScalarUnary));
|
||||
Add(Intrinsic.Arm64FcmgtVz, new IntrinsicInfo(0x0ea0c800u, IntrinsicType.VectorUnary));
|
||||
Add(Intrinsic.Arm64FcmleSz, new IntrinsicInfo(0x7ea0d800u, IntrinsicType.ScalarUnary));
|
||||
Add(Intrinsic.Arm64FcmleVz, new IntrinsicInfo(0x2ea0d800u, IntrinsicType.VectorUnary));
|
||||
Add(Intrinsic.Arm64FcmltSz, new IntrinsicInfo(0x5ea0e800u, IntrinsicType.ScalarUnary));
|
||||
Add(Intrinsic.Arm64FcmltVz, new IntrinsicInfo(0x0ea0e800u, IntrinsicType.VectorUnary));
|
||||
Add(Intrinsic.Arm64FcmpeS, new IntrinsicInfo(0x1e202010u, IntrinsicType.ScalarFPCompare));
|
||||
Add(Intrinsic.Arm64FcmpS, new IntrinsicInfo(0x1e202000u, IntrinsicType.ScalarFPCompare));
|
||||
Add(Intrinsic.Arm64FcselS, new IntrinsicInfo(0x1e200c00u, IntrinsicType.ScalarFcsel));
|
||||
Add(Intrinsic.Arm64FcvtasS, new IntrinsicInfo(0x5e21c800u, IntrinsicType.ScalarUnary));
|
||||
Add(Intrinsic.Arm64FcvtasV, new IntrinsicInfo(0x0e21c800u, IntrinsicType.VectorUnary));
|
||||
Add(Intrinsic.Arm64FcvtasGp, new IntrinsicInfo(0x1e240000u, IntrinsicType.ScalarFPConvGpr));
|
||||
Add(Intrinsic.Arm64FcvtauS, new IntrinsicInfo(0x7e21c800u, IntrinsicType.ScalarUnary));
|
||||
Add(Intrinsic.Arm64FcvtauV, new IntrinsicInfo(0x2e21c800u, IntrinsicType.VectorUnary));
|
||||
Add(Intrinsic.Arm64FcvtauGp, new IntrinsicInfo(0x1e250000u, IntrinsicType.ScalarFPConvGpr));
|
||||
Add(Intrinsic.Arm64FcvtlV, new IntrinsicInfo(0x0e217800u, IntrinsicType.VectorUnary));
|
||||
Add(Intrinsic.Arm64FcvtmsS, new IntrinsicInfo(0x5e21b800u, IntrinsicType.ScalarUnary));
|
||||
Add(Intrinsic.Arm64FcvtmsV, new IntrinsicInfo(0x0e21b800u, IntrinsicType.VectorUnary));
|
||||
Add(Intrinsic.Arm64FcvtmsGp, new IntrinsicInfo(0x1e300000u, IntrinsicType.ScalarFPConvGpr));
|
||||
Add(Intrinsic.Arm64FcvtmuS, new IntrinsicInfo(0x7e21b800u, IntrinsicType.ScalarUnary));
|
||||
Add(Intrinsic.Arm64FcvtmuV, new IntrinsicInfo(0x2e21b800u, IntrinsicType.VectorUnary));
|
||||
Add(Intrinsic.Arm64FcvtmuGp, new IntrinsicInfo(0x1e310000u, IntrinsicType.ScalarFPConvGpr));
|
||||
Add(Intrinsic.Arm64FcvtnsS, new IntrinsicInfo(0x5e21a800u, IntrinsicType.ScalarUnary));
|
||||
Add(Intrinsic.Arm64FcvtnsV, new IntrinsicInfo(0x0e21a800u, IntrinsicType.VectorUnary));
|
||||
Add(Intrinsic.Arm64FcvtnsGp, new IntrinsicInfo(0x1e200000u, IntrinsicType.ScalarFPConvGpr));
|
||||
Add(Intrinsic.Arm64FcvtnuS, new IntrinsicInfo(0x7e21a800u, IntrinsicType.ScalarUnary));
|
||||
Add(Intrinsic.Arm64FcvtnuV, new IntrinsicInfo(0x2e21a800u, IntrinsicType.VectorUnary));
|
||||
Add(Intrinsic.Arm64FcvtnuGp, new IntrinsicInfo(0x1e210000u, IntrinsicType.ScalarFPConvGpr));
|
||||
Add(Intrinsic.Arm64FcvtnV, new IntrinsicInfo(0x0e216800u, IntrinsicType.VectorBinaryRd));
|
||||
Add(Intrinsic.Arm64FcvtpsS, new IntrinsicInfo(0x5ea1a800u, IntrinsicType.ScalarUnary));
|
||||
Add(Intrinsic.Arm64FcvtpsV, new IntrinsicInfo(0x0ea1a800u, IntrinsicType.VectorUnary));
|
||||
Add(Intrinsic.Arm64FcvtpsGp, new IntrinsicInfo(0x1e280000u, IntrinsicType.ScalarFPConvGpr));
|
||||
Add(Intrinsic.Arm64FcvtpuS, new IntrinsicInfo(0x7ea1a800u, IntrinsicType.ScalarUnary));
|
||||
Add(Intrinsic.Arm64FcvtpuV, new IntrinsicInfo(0x2ea1a800u, IntrinsicType.VectorUnary));
|
||||
Add(Intrinsic.Arm64FcvtpuGp, new IntrinsicInfo(0x1e290000u, IntrinsicType.ScalarFPConvGpr));
|
||||
Add(Intrinsic.Arm64FcvtxnS, new IntrinsicInfo(0x7e216800u, IntrinsicType.ScalarUnary));
|
||||
Add(Intrinsic.Arm64FcvtxnV, new IntrinsicInfo(0x2e216800u, IntrinsicType.VectorUnary));
|
||||
Add(Intrinsic.Arm64FcvtzsSFixed, new IntrinsicInfo(0x5f00fc00u, IntrinsicType.ScalarFPConvFixed));
|
||||
Add(Intrinsic.Arm64FcvtzsVFixed, new IntrinsicInfo(0x0f00fc00u, IntrinsicType.VectorFPConvFixed));
|
||||
Add(Intrinsic.Arm64FcvtzsS, new IntrinsicInfo(0x5ea1b800u, IntrinsicType.ScalarUnary));
|
||||
Add(Intrinsic.Arm64FcvtzsV, new IntrinsicInfo(0x0ea1b800u, IntrinsicType.VectorUnary));
|
||||
Add(Intrinsic.Arm64FcvtzsGpFixed, new IntrinsicInfo(0x1e180000u, IntrinsicType.ScalarFPConvFixedGpr));
|
||||
Add(Intrinsic.Arm64FcvtzsGp, new IntrinsicInfo(0x1e380000u, IntrinsicType.ScalarFPConvGpr));
|
||||
Add(Intrinsic.Arm64FcvtzuSFixed, new IntrinsicInfo(0x7f00fc00u, IntrinsicType.ScalarFPConvFixed));
|
||||
Add(Intrinsic.Arm64FcvtzuVFixed, new IntrinsicInfo(0x2f00fc00u, IntrinsicType.VectorFPConvFixed));
|
||||
Add(Intrinsic.Arm64FcvtzuS, new IntrinsicInfo(0x7ea1b800u, IntrinsicType.ScalarUnary));
|
||||
Add(Intrinsic.Arm64FcvtzuV, new IntrinsicInfo(0x2ea1b800u, IntrinsicType.VectorUnary));
|
||||
Add(Intrinsic.Arm64FcvtzuGpFixed, new IntrinsicInfo(0x1e190000u, IntrinsicType.ScalarFPConvFixedGpr));
|
||||
Add(Intrinsic.Arm64FcvtzuGp, new IntrinsicInfo(0x1e390000u, IntrinsicType.ScalarFPConvGpr));
|
||||
Add(Intrinsic.Arm64FcvtS, new IntrinsicInfo(0x1e224000u, IntrinsicType.ScalarFPConv));
|
||||
Add(Intrinsic.Arm64FdivV, new IntrinsicInfo(0x2e20fc00u, IntrinsicType.VectorBinary));
|
||||
Add(Intrinsic.Arm64FdivS, new IntrinsicInfo(0x1e201800u, IntrinsicType.ScalarBinary));
|
||||
Add(Intrinsic.Arm64FmaddS, new IntrinsicInfo(0x1f000000u, IntrinsicType.ScalarTernary));
|
||||
Add(Intrinsic.Arm64FmaxnmpS, new IntrinsicInfo(0x7e30c800u, IntrinsicType.ScalarUnary));
|
||||
Add(Intrinsic.Arm64FmaxnmpV, new IntrinsicInfo(0x2e20c400u, IntrinsicType.VectorBinary));
|
||||
Add(Intrinsic.Arm64FmaxnmvV, new IntrinsicInfo(0x2e30c800u, IntrinsicType.VectorUnary));
|
||||
Add(Intrinsic.Arm64FmaxnmV, new IntrinsicInfo(0x0e20c400u, IntrinsicType.VectorBinary));
|
||||
Add(Intrinsic.Arm64FmaxnmS, new IntrinsicInfo(0x1e206800u, IntrinsicType.ScalarBinary));
|
||||
Add(Intrinsic.Arm64FmaxpS, new IntrinsicInfo(0x7e30f800u, IntrinsicType.ScalarUnary));
|
||||
Add(Intrinsic.Arm64FmaxpV, new IntrinsicInfo(0x2e20f400u, IntrinsicType.VectorBinary));
|
||||
Add(Intrinsic.Arm64FmaxvV, new IntrinsicInfo(0x2e30f800u, IntrinsicType.VectorUnary));
|
||||
Add(Intrinsic.Arm64FmaxV, new IntrinsicInfo(0x0e20f400u, IntrinsicType.VectorBinary));
|
||||
Add(Intrinsic.Arm64FmaxS, new IntrinsicInfo(0x1e204800u, IntrinsicType.ScalarBinary));
|
||||
Add(Intrinsic.Arm64FminnmpS, new IntrinsicInfo(0x7eb0c800u, IntrinsicType.ScalarUnary));
|
||||
Add(Intrinsic.Arm64FminnmpV, new IntrinsicInfo(0x2ea0c400u, IntrinsicType.VectorBinary));
|
||||
Add(Intrinsic.Arm64FminnmvV, new IntrinsicInfo(0x2eb0c800u, IntrinsicType.VectorUnary));
|
||||
Add(Intrinsic.Arm64FminnmV, new IntrinsicInfo(0x0ea0c400u, IntrinsicType.VectorBinary));
|
||||
Add(Intrinsic.Arm64FminnmS, new IntrinsicInfo(0x1e207800u, IntrinsicType.ScalarBinary));
|
||||
Add(Intrinsic.Arm64FminpS, new IntrinsicInfo(0x7eb0f800u, IntrinsicType.ScalarUnary));
|
||||
Add(Intrinsic.Arm64FminpV, new IntrinsicInfo(0x2ea0f400u, IntrinsicType.VectorBinary));
|
||||
Add(Intrinsic.Arm64FminvV, new IntrinsicInfo(0x2eb0f800u, IntrinsicType.VectorUnary));
|
||||
Add(Intrinsic.Arm64FminV, new IntrinsicInfo(0x0ea0f400u, IntrinsicType.VectorBinary));
|
||||
Add(Intrinsic.Arm64FminS, new IntrinsicInfo(0x1e205800u, IntrinsicType.ScalarBinary));
|
||||
Add(Intrinsic.Arm64FmlaSe, new IntrinsicInfo(0x5f801000u, IntrinsicType.ScalarTernaryFPRdByElem));
|
||||
Add(Intrinsic.Arm64FmlaVe, new IntrinsicInfo(0x0f801000u, IntrinsicType.VectorTernaryFPRdByElem));
|
||||
Add(Intrinsic.Arm64FmlaV, new IntrinsicInfo(0x0e20cc00u, IntrinsicType.VectorTernaryRd));
|
||||
Add(Intrinsic.Arm64FmlsSe, new IntrinsicInfo(0x5f805000u, IntrinsicType.ScalarTernaryFPRdByElem));
|
||||
Add(Intrinsic.Arm64FmlsVe, new IntrinsicInfo(0x0f805000u, IntrinsicType.VectorTernaryFPRdByElem));
|
||||
Add(Intrinsic.Arm64FmlsV, new IntrinsicInfo(0x0ea0cc00u, IntrinsicType.VectorTernaryRd));
|
||||
Add(Intrinsic.Arm64FmovVi, new IntrinsicInfo(0x0f00f400u, IntrinsicType.VectorFmovi));
|
||||
Add(Intrinsic.Arm64FmovS, new IntrinsicInfo(0x1e204000u, IntrinsicType.ScalarUnary));
|
||||
Add(Intrinsic.Arm64FmovGp, new IntrinsicInfo(0x1e260000u, IntrinsicType.ScalarFPConvGpr));
|
||||
Add(Intrinsic.Arm64FmovSi, new IntrinsicInfo(0x1e201000u, IntrinsicType.ScalarFmovi));
|
||||
Add(Intrinsic.Arm64FmsubS, new IntrinsicInfo(0x1f008000u, IntrinsicType.ScalarTernary));
|
||||
Add(Intrinsic.Arm64FmulxSe, new IntrinsicInfo(0x7f809000u, IntrinsicType.ScalarBinaryFPByElem));
|
||||
Add(Intrinsic.Arm64FmulxVe, new IntrinsicInfo(0x2f809000u, IntrinsicType.VectorBinaryFPByElem));
|
||||
Add(Intrinsic.Arm64FmulxS, new IntrinsicInfo(0x5e20dc00u, IntrinsicType.ScalarBinary));
|
||||
Add(Intrinsic.Arm64FmulxV, new IntrinsicInfo(0x0e20dc00u, IntrinsicType.VectorBinary));
|
||||
Add(Intrinsic.Arm64FmulSe, new IntrinsicInfo(0x5f809000u, IntrinsicType.ScalarBinaryFPByElem));
|
||||
Add(Intrinsic.Arm64FmulVe, new IntrinsicInfo(0x0f809000u, IntrinsicType.VectorBinaryFPByElem));
|
||||
Add(Intrinsic.Arm64FmulV, new IntrinsicInfo(0x2e20dc00u, IntrinsicType.VectorBinary));
|
||||
Add(Intrinsic.Arm64FmulS, new IntrinsicInfo(0x1e200800u, IntrinsicType.ScalarBinary));
|
||||
Add(Intrinsic.Arm64FnegV, new IntrinsicInfo(0x2ea0f800u, IntrinsicType.VectorUnary));
|
||||
Add(Intrinsic.Arm64FnegS, new IntrinsicInfo(0x1e214000u, IntrinsicType.ScalarUnary));
|
||||
Add(Intrinsic.Arm64FnmaddS, new IntrinsicInfo(0x1f200000u, IntrinsicType.ScalarTernary));
|
||||
Add(Intrinsic.Arm64FnmsubS, new IntrinsicInfo(0x1f208000u, IntrinsicType.ScalarTernary));
|
||||
Add(Intrinsic.Arm64FnmulS, new IntrinsicInfo(0x1e208800u, IntrinsicType.ScalarBinary));
|
||||
Add(Intrinsic.Arm64FrecpeS, new IntrinsicInfo(0x5ea1d800u, IntrinsicType.ScalarUnary));
|
||||
Add(Intrinsic.Arm64FrecpeV, new IntrinsicInfo(0x0ea1d800u, IntrinsicType.VectorUnary));
|
||||
Add(Intrinsic.Arm64FrecpsS, new IntrinsicInfo(0x5e20fc00u, IntrinsicType.ScalarBinary));
|
||||
Add(Intrinsic.Arm64FrecpsV, new IntrinsicInfo(0x0e20fc00u, IntrinsicType.VectorBinary));
|
||||
Add(Intrinsic.Arm64FrecpxS, new IntrinsicInfo(0x5ea1f800u, IntrinsicType.ScalarUnary));
|
||||
Add(Intrinsic.Arm64FrintaV, new IntrinsicInfo(0x2e218800u, IntrinsicType.VectorUnary));
|
||||
Add(Intrinsic.Arm64FrintaS, new IntrinsicInfo(0x1e264000u, IntrinsicType.ScalarUnary));
|
||||
Add(Intrinsic.Arm64FrintiV, new IntrinsicInfo(0x2ea19800u, IntrinsicType.VectorUnary));
|
||||
Add(Intrinsic.Arm64FrintiS, new IntrinsicInfo(0x1e27c000u, IntrinsicType.ScalarUnary));
|
||||
Add(Intrinsic.Arm64FrintmV, new IntrinsicInfo(0x0e219800u, IntrinsicType.VectorUnary));
|
||||
Add(Intrinsic.Arm64FrintmS, new IntrinsicInfo(0x1e254000u, IntrinsicType.ScalarUnary));
|
||||
Add(Intrinsic.Arm64FrintnV, new IntrinsicInfo(0x0e218800u, IntrinsicType.VectorUnary));
|
||||
Add(Intrinsic.Arm64FrintnS, new IntrinsicInfo(0x1e244000u, IntrinsicType.ScalarUnary));
|
||||
Add(Intrinsic.Arm64FrintpV, new IntrinsicInfo(0x0ea18800u, IntrinsicType.VectorUnary));
|
||||
Add(Intrinsic.Arm64FrintpS, new IntrinsicInfo(0x1e24c000u, IntrinsicType.ScalarUnary));
|
||||
Add(Intrinsic.Arm64FrintxV, new IntrinsicInfo(0x2e219800u, IntrinsicType.VectorUnary));
|
||||
Add(Intrinsic.Arm64FrintxS, new IntrinsicInfo(0x1e274000u, IntrinsicType.ScalarUnary));
|
||||
Add(Intrinsic.Arm64FrintzV, new IntrinsicInfo(0x0ea19800u, IntrinsicType.VectorUnary));
|
||||
Add(Intrinsic.Arm64FrintzS, new IntrinsicInfo(0x1e25c000u, IntrinsicType.ScalarUnary));
|
||||
Add(Intrinsic.Arm64FrsqrteS, new IntrinsicInfo(0x7ea1d800u, IntrinsicType.ScalarUnary));
|
||||
Add(Intrinsic.Arm64FrsqrteV, new IntrinsicInfo(0x2ea1d800u, IntrinsicType.VectorUnary));
|
||||
Add(Intrinsic.Arm64FrsqrtsS, new IntrinsicInfo(0x5ea0fc00u, IntrinsicType.ScalarBinary));
|
||||
Add(Intrinsic.Arm64FrsqrtsV, new IntrinsicInfo(0x0ea0fc00u, IntrinsicType.VectorBinary));
|
||||
Add(Intrinsic.Arm64FsqrtV, new IntrinsicInfo(0x2ea1f800u, IntrinsicType.VectorUnary));
|
||||
Add(Intrinsic.Arm64FsqrtS, new IntrinsicInfo(0x1e21c000u, IntrinsicType.ScalarUnary));
|
||||
Add(Intrinsic.Arm64FsubV, new IntrinsicInfo(0x0ea0d400u, IntrinsicType.VectorBinary));
|
||||
Add(Intrinsic.Arm64FsubS, new IntrinsicInfo(0x1e203800u, IntrinsicType.ScalarBinary));
|
||||
Add(Intrinsic.Arm64InsVe, new IntrinsicInfo(0x6e000400u, IntrinsicType.VectorInsertByElem));
|
||||
Add(Intrinsic.Arm64InsGp, new IntrinsicInfo(0x4e001c00u, IntrinsicType.ScalarUnaryByElem));
|
||||
Add(Intrinsic.Arm64Ld1rV, new IntrinsicInfo(0x0d40c000u, IntrinsicType.VectorLdSt));
|
||||
Add(Intrinsic.Arm64Ld1Vms, new IntrinsicInfo(0x0c402000u, IntrinsicType.VectorLdSt));
|
||||
Add(Intrinsic.Arm64Ld1Vss, new IntrinsicInfo(0x0d400000u, IntrinsicType.VectorLdStSs));
|
||||
Add(Intrinsic.Arm64Ld2rV, new IntrinsicInfo(0x0d60c000u, IntrinsicType.VectorLdSt));
|
||||
Add(Intrinsic.Arm64Ld2Vms, new IntrinsicInfo(0x0c408000u, IntrinsicType.VectorLdSt));
|
||||
Add(Intrinsic.Arm64Ld2Vss, new IntrinsicInfo(0x0d600000u, IntrinsicType.VectorLdStSs));
|
||||
Add(Intrinsic.Arm64Ld3rV, new IntrinsicInfo(0x0d40e000u, IntrinsicType.VectorLdSt));
|
||||
Add(Intrinsic.Arm64Ld3Vms, new IntrinsicInfo(0x0c404000u, IntrinsicType.VectorLdSt));
|
||||
Add(Intrinsic.Arm64Ld3Vss, new IntrinsicInfo(0x0d402000u, IntrinsicType.VectorLdStSs));
|
||||
Add(Intrinsic.Arm64Ld4rV, new IntrinsicInfo(0x0d60e000u, IntrinsicType.VectorLdSt));
|
||||
Add(Intrinsic.Arm64Ld4Vms, new IntrinsicInfo(0x0c400000u, IntrinsicType.VectorLdSt));
|
||||
Add(Intrinsic.Arm64Ld4Vss, new IntrinsicInfo(0x0d602000u, IntrinsicType.VectorLdStSs));
|
||||
Add(Intrinsic.Arm64MlaVe, new IntrinsicInfo(0x2f000000u, IntrinsicType.VectorTernaryRdByElem));
|
||||
Add(Intrinsic.Arm64MlaV, new IntrinsicInfo(0x0e209400u, IntrinsicType.VectorTernaryRd));
|
||||
Add(Intrinsic.Arm64MlsVe, new IntrinsicInfo(0x2f004000u, IntrinsicType.VectorTernaryRdByElem));
|
||||
Add(Intrinsic.Arm64MlsV, new IntrinsicInfo(0x2e209400u, IntrinsicType.VectorTernaryRd));
|
||||
Add(Intrinsic.Arm64MoviV, new IntrinsicInfo(0x0f000400u, IntrinsicType.VectorMovi));
|
||||
Add(Intrinsic.Arm64MrsFpsr, new IntrinsicInfo(0xd53b4420u, IntrinsicType.GetRegister));
|
||||
Add(Intrinsic.Arm64MsrFpsr, new IntrinsicInfo(0xd51b4420u, IntrinsicType.SetRegister));
|
||||
Add(Intrinsic.Arm64MulVe, new IntrinsicInfo(0x0f008000u, IntrinsicType.VectorBinaryByElem));
|
||||
Add(Intrinsic.Arm64MulV, new IntrinsicInfo(0x0e209c00u, IntrinsicType.VectorBinary));
|
||||
Add(Intrinsic.Arm64MvniV, new IntrinsicInfo(0x2f000400u, IntrinsicType.VectorMvni));
|
||||
Add(Intrinsic.Arm64NegS, new IntrinsicInfo(0x7e20b800u, IntrinsicType.ScalarUnary));
|
||||
Add(Intrinsic.Arm64NegV, new IntrinsicInfo(0x2e20b800u, IntrinsicType.VectorUnary));
|
||||
Add(Intrinsic.Arm64NotV, new IntrinsicInfo(0x2e205800u, IntrinsicType.VectorUnaryBitwise));
|
||||
Add(Intrinsic.Arm64OrnV, new IntrinsicInfo(0x0ee01c00u, IntrinsicType.VectorBinaryBitwise));
|
||||
Add(Intrinsic.Arm64OrrVi, new IntrinsicInfo(0x0f001400u, IntrinsicType.VectorBinaryBitwiseImm));
|
||||
Add(Intrinsic.Arm64OrrV, new IntrinsicInfo(0x0ea01c00u, IntrinsicType.VectorBinaryBitwise));
|
||||
Add(Intrinsic.Arm64PmullV, new IntrinsicInfo(0x0e20e000u, IntrinsicType.VectorBinary));
|
||||
Add(Intrinsic.Arm64PmulV, new IntrinsicInfo(0x2e209c00u, IntrinsicType.VectorBinary));
|
||||
Add(Intrinsic.Arm64RaddhnV, new IntrinsicInfo(0x2e204000u, IntrinsicType.VectorTernaryRd));
|
||||
Add(Intrinsic.Arm64RbitV, new IntrinsicInfo(0x2e605800u, IntrinsicType.VectorUnaryBitwise));
|
||||
Add(Intrinsic.Arm64Rev16V, new IntrinsicInfo(0x0e201800u, IntrinsicType.VectorUnary));
|
||||
Add(Intrinsic.Arm64Rev32V, new IntrinsicInfo(0x2e200800u, IntrinsicType.VectorUnary));
|
||||
Add(Intrinsic.Arm64Rev64V, new IntrinsicInfo(0x0e200800u, IntrinsicType.VectorUnary));
|
||||
Add(Intrinsic.Arm64RshrnV, new IntrinsicInfo(0x0f008c00u, IntrinsicType.VectorTernaryShrRd));
|
||||
Add(Intrinsic.Arm64RsubhnV, new IntrinsicInfo(0x2e206000u, IntrinsicType.VectorTernaryRd));
|
||||
Add(Intrinsic.Arm64SabalV, new IntrinsicInfo(0x0e205000u, IntrinsicType.VectorTernaryRd));
|
||||
Add(Intrinsic.Arm64SabaV, new IntrinsicInfo(0x0e207c00u, IntrinsicType.VectorTernaryRd));
|
||||
Add(Intrinsic.Arm64SabdlV, new IntrinsicInfo(0x0e207000u, IntrinsicType.VectorBinary));
|
||||
Add(Intrinsic.Arm64SabdV, new IntrinsicInfo(0x0e207400u, IntrinsicType.VectorBinary));
|
||||
Add(Intrinsic.Arm64SadalpV, new IntrinsicInfo(0x0e206800u, IntrinsicType.VectorBinaryRd));
|
||||
Add(Intrinsic.Arm64SaddlpV, new IntrinsicInfo(0x0e202800u, IntrinsicType.VectorUnary));
|
||||
Add(Intrinsic.Arm64SaddlvV, new IntrinsicInfo(0x0e303800u, IntrinsicType.VectorUnary));
|
||||
Add(Intrinsic.Arm64SaddlV, new IntrinsicInfo(0x0e200000u, IntrinsicType.VectorBinary));
|
||||
Add(Intrinsic.Arm64SaddwV, new IntrinsicInfo(0x0e201000u, IntrinsicType.VectorBinary));
|
||||
Add(Intrinsic.Arm64ScvtfSFixed, new IntrinsicInfo(0x5f00e400u, IntrinsicType.ScalarFPConvFixed));
|
||||
Add(Intrinsic.Arm64ScvtfVFixed, new IntrinsicInfo(0x0f00e400u, IntrinsicType.VectorFPConvFixed));
|
||||
Add(Intrinsic.Arm64ScvtfS, new IntrinsicInfo(0x5e21d800u, IntrinsicType.ScalarUnary));
|
||||
Add(Intrinsic.Arm64ScvtfV, new IntrinsicInfo(0x0e21d800u, IntrinsicType.VectorUnary));
|
||||
Add(Intrinsic.Arm64ScvtfGpFixed, new IntrinsicInfo(0x1e020000u, IntrinsicType.ScalarFPConvFixedGpr));
|
||||
Add(Intrinsic.Arm64ScvtfGp, new IntrinsicInfo(0x1e220000u, IntrinsicType.ScalarFPConvGpr));
|
||||
Add(Intrinsic.Arm64Sha1cV, new IntrinsicInfo(0x5e000000u, IntrinsicType.Vector128Binary));
|
||||
Add(Intrinsic.Arm64Sha1hV, new IntrinsicInfo(0x5e280800u, IntrinsicType.Vector128Unary));
|
||||
Add(Intrinsic.Arm64Sha1mV, new IntrinsicInfo(0x5e002000u, IntrinsicType.Vector128Binary));
|
||||
Add(Intrinsic.Arm64Sha1pV, new IntrinsicInfo(0x5e001000u, IntrinsicType.Vector128Binary));
|
||||
Add(Intrinsic.Arm64Sha1su0V, new IntrinsicInfo(0x5e003000u, IntrinsicType.Vector128Binary));
|
||||
Add(Intrinsic.Arm64Sha1su1V, new IntrinsicInfo(0x5e281800u, IntrinsicType.Vector128Unary));
|
||||
Add(Intrinsic.Arm64Sha256h2V, new IntrinsicInfo(0x5e005000u, IntrinsicType.Vector128Binary));
|
||||
Add(Intrinsic.Arm64Sha256hV, new IntrinsicInfo(0x5e004000u, IntrinsicType.Vector128Binary));
|
||||
Add(Intrinsic.Arm64Sha256su0V, new IntrinsicInfo(0x5e282800u, IntrinsicType.Vector128Unary));
|
||||
Add(Intrinsic.Arm64Sha256su1V, new IntrinsicInfo(0x5e006000u, IntrinsicType.Vector128Binary));
|
||||
Add(Intrinsic.Arm64ShaddV, new IntrinsicInfo(0x0e200400u, IntrinsicType.VectorBinary));
|
||||
Add(Intrinsic.Arm64ShllV, new IntrinsicInfo(0x2e213800u, IntrinsicType.VectorUnary));
|
||||
Add(Intrinsic.Arm64ShlS, new IntrinsicInfo(0x5f005400u, IntrinsicType.ScalarBinaryShl));
|
||||
Add(Intrinsic.Arm64ShlV, new IntrinsicInfo(0x0f005400u, IntrinsicType.VectorBinaryShl));
|
||||
Add(Intrinsic.Arm64ShrnV, new IntrinsicInfo(0x0f008400u, IntrinsicType.VectorTernaryShrRd));
|
||||
Add(Intrinsic.Arm64ShsubV, new IntrinsicInfo(0x0e202400u, IntrinsicType.VectorBinary));
|
||||
Add(Intrinsic.Arm64SliS, new IntrinsicInfo(0x7f005400u, IntrinsicType.ScalarTernaryShlRd));
|
||||
Add(Intrinsic.Arm64SliV, new IntrinsicInfo(0x2f005400u, IntrinsicType.VectorTernaryShlRd));
|
||||
Add(Intrinsic.Arm64SmaxpV, new IntrinsicInfo(0x0e20a400u, IntrinsicType.VectorBinary));
|
||||
Add(Intrinsic.Arm64SmaxvV, new IntrinsicInfo(0x0e30a800u, IntrinsicType.VectorUnary));
|
||||
Add(Intrinsic.Arm64SmaxV, new IntrinsicInfo(0x0e206400u, IntrinsicType.VectorBinary));
|
||||
Add(Intrinsic.Arm64SminpV, new IntrinsicInfo(0x0e20ac00u, IntrinsicType.VectorBinary));
|
||||
Add(Intrinsic.Arm64SminvV, new IntrinsicInfo(0x0e31a800u, IntrinsicType.VectorUnary));
|
||||
Add(Intrinsic.Arm64SminV, new IntrinsicInfo(0x0e206c00u, IntrinsicType.VectorBinary));
|
||||
Add(Intrinsic.Arm64SmlalVe, new IntrinsicInfo(0x0f002000u, IntrinsicType.VectorTernaryRdByElem));
|
||||
Add(Intrinsic.Arm64SmlalV, new IntrinsicInfo(0x0e208000u, IntrinsicType.VectorTernaryRd));
|
||||
Add(Intrinsic.Arm64SmlslVe, new IntrinsicInfo(0x0f006000u, IntrinsicType.VectorTernaryRdByElem));
|
||||
Add(Intrinsic.Arm64SmlslV, new IntrinsicInfo(0x0e20a000u, IntrinsicType.VectorTernaryRd));
|
||||
Add(Intrinsic.Arm64SmovV, new IntrinsicInfo(0x0e002c00u, IntrinsicType.VectorUnaryByElem));
|
||||
Add(Intrinsic.Arm64SmullVe, new IntrinsicInfo(0x0f00a000u, IntrinsicType.VectorBinaryByElem));
|
||||
Add(Intrinsic.Arm64SmullV, new IntrinsicInfo(0x0e20c000u, IntrinsicType.VectorBinary));
|
||||
Add(Intrinsic.Arm64SqabsS, new IntrinsicInfo(0x5e207800u, IntrinsicType.ScalarUnary));
|
||||
Add(Intrinsic.Arm64SqabsV, new IntrinsicInfo(0x0e207800u, IntrinsicType.VectorUnary));
|
||||
Add(Intrinsic.Arm64SqaddS, new IntrinsicInfo(0x5e200c00u, IntrinsicType.ScalarBinary));
|
||||
Add(Intrinsic.Arm64SqaddV, new IntrinsicInfo(0x0e200c00u, IntrinsicType.VectorBinary));
|
||||
Add(Intrinsic.Arm64SqdmlalSe, new IntrinsicInfo(0x5f003000u, IntrinsicType.ScalarBinaryByElem));
|
||||
Add(Intrinsic.Arm64SqdmlalVe, new IntrinsicInfo(0x0f003000u, IntrinsicType.VectorBinaryByElem));
|
||||
Add(Intrinsic.Arm64SqdmlalS, new IntrinsicInfo(0x5e209000u, IntrinsicType.ScalarBinary));
|
||||
Add(Intrinsic.Arm64SqdmlalV, new IntrinsicInfo(0x0e209000u, IntrinsicType.VectorBinary));
|
||||
Add(Intrinsic.Arm64SqdmlslSe, new IntrinsicInfo(0x5f007000u, IntrinsicType.ScalarBinaryByElem));
|
||||
Add(Intrinsic.Arm64SqdmlslVe, new IntrinsicInfo(0x0f007000u, IntrinsicType.VectorBinaryByElem));
|
||||
Add(Intrinsic.Arm64SqdmlslS, new IntrinsicInfo(0x5e20b000u, IntrinsicType.ScalarBinary));
|
||||
Add(Intrinsic.Arm64SqdmlslV, new IntrinsicInfo(0x0e20b000u, IntrinsicType.VectorBinary));
|
||||
Add(Intrinsic.Arm64SqdmulhSe, new IntrinsicInfo(0x5f00c000u, IntrinsicType.ScalarBinaryByElem));
|
||||
Add(Intrinsic.Arm64SqdmulhVe, new IntrinsicInfo(0x0f00c000u, IntrinsicType.VectorBinaryByElem));
|
||||
Add(Intrinsic.Arm64SqdmulhS, new IntrinsicInfo(0x5e20b400u, IntrinsicType.ScalarBinary));
|
||||
Add(Intrinsic.Arm64SqdmulhV, new IntrinsicInfo(0x0e20b400u, IntrinsicType.VectorBinary));
|
||||
Add(Intrinsic.Arm64SqdmullSe, new IntrinsicInfo(0x5f00b000u, IntrinsicType.ScalarBinaryByElem));
|
||||
Add(Intrinsic.Arm64SqdmullVe, new IntrinsicInfo(0x0f00b000u, IntrinsicType.VectorBinaryByElem));
|
||||
Add(Intrinsic.Arm64SqdmullS, new IntrinsicInfo(0x5e20d000u, IntrinsicType.ScalarBinary));
|
||||
Add(Intrinsic.Arm64SqdmullV, new IntrinsicInfo(0x0e20d000u, IntrinsicType.VectorBinary));
|
||||
Add(Intrinsic.Arm64SqnegS, new IntrinsicInfo(0x7e207800u, IntrinsicType.ScalarUnary));
|
||||
Add(Intrinsic.Arm64SqnegV, new IntrinsicInfo(0x2e207800u, IntrinsicType.VectorUnary));
|
||||
Add(Intrinsic.Arm64SqrdmulhSe, new IntrinsicInfo(0x5f00d000u, IntrinsicType.ScalarBinaryByElem));
|
||||
Add(Intrinsic.Arm64SqrdmulhVe, new IntrinsicInfo(0x0f00d000u, IntrinsicType.VectorBinaryByElem));
|
||||
Add(Intrinsic.Arm64SqrdmulhS, new IntrinsicInfo(0x7e20b400u, IntrinsicType.ScalarBinary));
|
||||
Add(Intrinsic.Arm64SqrdmulhV, new IntrinsicInfo(0x2e20b400u, IntrinsicType.VectorBinary));
|
||||
Add(Intrinsic.Arm64SqrshlS, new IntrinsicInfo(0x5e205c00u, IntrinsicType.ScalarBinary));
|
||||
Add(Intrinsic.Arm64SqrshlV, new IntrinsicInfo(0x0e205c00u, IntrinsicType.VectorBinary));
|
||||
Add(Intrinsic.Arm64SqrshrnS, new IntrinsicInfo(0x5f009c00u, IntrinsicType.ScalarTernaryShrRd));
|
||||
Add(Intrinsic.Arm64SqrshrnV, new IntrinsicInfo(0x0f009c00u, IntrinsicType.VectorTernaryShrRd));
|
||||
Add(Intrinsic.Arm64SqrshrunS, new IntrinsicInfo(0x7f008c00u, IntrinsicType.ScalarTernaryShrRd));
|
||||
Add(Intrinsic.Arm64SqrshrunV, new IntrinsicInfo(0x2f008c00u, IntrinsicType.VectorTernaryShrRd));
|
||||
Add(Intrinsic.Arm64SqshluS, new IntrinsicInfo(0x7f006400u, IntrinsicType.ScalarBinaryShl));
|
||||
Add(Intrinsic.Arm64SqshluV, new IntrinsicInfo(0x2f006400u, IntrinsicType.VectorBinaryShl));
|
||||
Add(Intrinsic.Arm64SqshlSi, new IntrinsicInfo(0x5f007400u, IntrinsicType.ScalarBinaryShl));
|
||||
Add(Intrinsic.Arm64SqshlVi, new IntrinsicInfo(0x0f007400u, IntrinsicType.VectorBinaryShl));
|
||||
Add(Intrinsic.Arm64SqshlS, new IntrinsicInfo(0x5e204c00u, IntrinsicType.ScalarBinary));
|
||||
Add(Intrinsic.Arm64SqshlV, new IntrinsicInfo(0x0e204c00u, IntrinsicType.VectorBinary));
|
||||
Add(Intrinsic.Arm64SqshrnS, new IntrinsicInfo(0x5f009400u, IntrinsicType.ScalarTernaryShrRd));
|
||||
Add(Intrinsic.Arm64SqshrnV, new IntrinsicInfo(0x0f009400u, IntrinsicType.VectorTernaryShrRd));
|
||||
Add(Intrinsic.Arm64SqshrunS, new IntrinsicInfo(0x7f008400u, IntrinsicType.ScalarTernaryShrRd));
|
||||
Add(Intrinsic.Arm64SqshrunV, new IntrinsicInfo(0x2f008400u, IntrinsicType.VectorTernaryShrRd));
|
||||
Add(Intrinsic.Arm64SqsubS, new IntrinsicInfo(0x5e202c00u, IntrinsicType.ScalarBinary));
|
||||
Add(Intrinsic.Arm64SqsubV, new IntrinsicInfo(0x0e202c00u, IntrinsicType.VectorBinary));
|
||||
Add(Intrinsic.Arm64SqxtnS, new IntrinsicInfo(0x5e214800u, IntrinsicType.ScalarBinaryRd));
|
||||
Add(Intrinsic.Arm64SqxtnV, new IntrinsicInfo(0x0e214800u, IntrinsicType.VectorBinaryRd));
|
||||
Add(Intrinsic.Arm64SqxtunS, new IntrinsicInfo(0x7e212800u, IntrinsicType.ScalarBinaryRd));
|
||||
Add(Intrinsic.Arm64SqxtunV, new IntrinsicInfo(0x2e212800u, IntrinsicType.VectorBinaryRd));
|
||||
Add(Intrinsic.Arm64SrhaddV, new IntrinsicInfo(0x0e201400u, IntrinsicType.VectorBinary));
|
||||
Add(Intrinsic.Arm64SriS, new IntrinsicInfo(0x7f004400u, IntrinsicType.ScalarTernaryShrRd));
|
||||
Add(Intrinsic.Arm64SriV, new IntrinsicInfo(0x2f004400u, IntrinsicType.VectorTernaryShrRd));
|
||||
Add(Intrinsic.Arm64SrshlS, new IntrinsicInfo(0x5e205400u, IntrinsicType.ScalarBinary));
|
||||
Add(Intrinsic.Arm64SrshlV, new IntrinsicInfo(0x0e205400u, IntrinsicType.VectorBinary));
|
||||
Add(Intrinsic.Arm64SrshrS, new IntrinsicInfo(0x5f002400u, IntrinsicType.ScalarBinaryShr));
|
||||
Add(Intrinsic.Arm64SrshrV, new IntrinsicInfo(0x0f002400u, IntrinsicType.VectorBinaryShr));
|
||||
Add(Intrinsic.Arm64SrsraS, new IntrinsicInfo(0x5f003400u, IntrinsicType.ScalarTernaryShrRd));
|
||||
Add(Intrinsic.Arm64SrsraV, new IntrinsicInfo(0x0f003400u, IntrinsicType.VectorTernaryShrRd));
|
||||
Add(Intrinsic.Arm64SshllV, new IntrinsicInfo(0x0f00a400u, IntrinsicType.VectorBinaryShl));
|
||||
Add(Intrinsic.Arm64SshlS, new IntrinsicInfo(0x5e204400u, IntrinsicType.ScalarBinary));
|
||||
Add(Intrinsic.Arm64SshlV, new IntrinsicInfo(0x0e204400u, IntrinsicType.VectorBinary));
|
||||
Add(Intrinsic.Arm64SshrS, new IntrinsicInfo(0x5f000400u, IntrinsicType.ScalarBinaryShr));
|
||||
Add(Intrinsic.Arm64SshrV, new IntrinsicInfo(0x0f000400u, IntrinsicType.VectorBinaryShr));
|
||||
Add(Intrinsic.Arm64SsraS, new IntrinsicInfo(0x5f001400u, IntrinsicType.ScalarTernaryShrRd));
|
||||
Add(Intrinsic.Arm64SsraV, new IntrinsicInfo(0x0f001400u, IntrinsicType.VectorTernaryShrRd));
|
||||
Add(Intrinsic.Arm64SsublV, new IntrinsicInfo(0x0e202000u, IntrinsicType.VectorBinary));
|
||||
Add(Intrinsic.Arm64SsubwV, new IntrinsicInfo(0x0e203000u, IntrinsicType.VectorBinary));
|
||||
Add(Intrinsic.Arm64St1Vms, new IntrinsicInfo(0x0c002000u, IntrinsicType.VectorLdSt));
|
||||
Add(Intrinsic.Arm64St1Vss, new IntrinsicInfo(0x0d000000u, IntrinsicType.VectorLdStSs));
|
||||
Add(Intrinsic.Arm64St2Vms, new IntrinsicInfo(0x0c008000u, IntrinsicType.VectorLdSt));
|
||||
Add(Intrinsic.Arm64St2Vss, new IntrinsicInfo(0x0d200000u, IntrinsicType.VectorLdStSs));
|
||||
Add(Intrinsic.Arm64St3Vms, new IntrinsicInfo(0x0c004000u, IntrinsicType.VectorLdSt));
|
||||
Add(Intrinsic.Arm64St3Vss, new IntrinsicInfo(0x0d002000u, IntrinsicType.VectorLdStSs));
|
||||
Add(Intrinsic.Arm64St4Vms, new IntrinsicInfo(0x0c000000u, IntrinsicType.VectorLdSt));
|
||||
Add(Intrinsic.Arm64St4Vss, new IntrinsicInfo(0x0d202000u, IntrinsicType.VectorLdStSs));
|
||||
Add(Intrinsic.Arm64SubhnV, new IntrinsicInfo(0x0e206000u, IntrinsicType.VectorTernaryRd));
|
||||
Add(Intrinsic.Arm64SubS, new IntrinsicInfo(0x7e208400u, IntrinsicType.ScalarBinary));
|
||||
Add(Intrinsic.Arm64SubV, new IntrinsicInfo(0x2e208400u, IntrinsicType.VectorBinary));
|
||||
Add(Intrinsic.Arm64SuqaddS, new IntrinsicInfo(0x5e203800u, IntrinsicType.ScalarBinaryRd));
|
||||
Add(Intrinsic.Arm64SuqaddV, new IntrinsicInfo(0x0e203800u, IntrinsicType.VectorBinaryRd));
|
||||
Add(Intrinsic.Arm64TblV, new IntrinsicInfo(0x0e000000u, IntrinsicType.VectorLookupTable));
|
||||
Add(Intrinsic.Arm64TbxV, new IntrinsicInfo(0x0e001000u, IntrinsicType.VectorLookupTable));
|
||||
Add(Intrinsic.Arm64Trn1V, new IntrinsicInfo(0x0e002800u, IntrinsicType.VectorBinary));
|
||||
Add(Intrinsic.Arm64Trn2V, new IntrinsicInfo(0x0e006800u, IntrinsicType.VectorBinary));
|
||||
Add(Intrinsic.Arm64UabalV, new IntrinsicInfo(0x2e205000u, IntrinsicType.VectorTernaryRd));
|
||||
Add(Intrinsic.Arm64UabaV, new IntrinsicInfo(0x2e207c00u, IntrinsicType.VectorTernaryRd));
|
||||
Add(Intrinsic.Arm64UabdlV, new IntrinsicInfo(0x2e207000u, IntrinsicType.VectorBinary));
|
||||
Add(Intrinsic.Arm64UabdV, new IntrinsicInfo(0x2e207400u, IntrinsicType.VectorBinary));
|
||||
Add(Intrinsic.Arm64UadalpV, new IntrinsicInfo(0x2e206800u, IntrinsicType.VectorBinaryRd));
|
||||
Add(Intrinsic.Arm64UaddlpV, new IntrinsicInfo(0x2e202800u, IntrinsicType.VectorUnary));
|
||||
Add(Intrinsic.Arm64UaddlvV, new IntrinsicInfo(0x2e303800u, IntrinsicType.VectorUnary));
|
||||
Add(Intrinsic.Arm64UaddlV, new IntrinsicInfo(0x2e200000u, IntrinsicType.VectorBinary));
|
||||
Add(Intrinsic.Arm64UaddwV, new IntrinsicInfo(0x2e201000u, IntrinsicType.VectorBinary));
|
||||
Add(Intrinsic.Arm64UcvtfSFixed, new IntrinsicInfo(0x7f00e400u, IntrinsicType.ScalarFPConvFixed));
|
||||
Add(Intrinsic.Arm64UcvtfVFixed, new IntrinsicInfo(0x2f00e400u, IntrinsicType.VectorFPConvFixed));
|
||||
Add(Intrinsic.Arm64UcvtfS, new IntrinsicInfo(0x7e21d800u, IntrinsicType.ScalarUnary));
|
||||
Add(Intrinsic.Arm64UcvtfV, new IntrinsicInfo(0x2e21d800u, IntrinsicType.VectorUnary));
|
||||
Add(Intrinsic.Arm64UcvtfGpFixed, new IntrinsicInfo(0x1e030000u, IntrinsicType.ScalarFPConvFixedGpr));
|
||||
Add(Intrinsic.Arm64UcvtfGp, new IntrinsicInfo(0x1e230000u, IntrinsicType.ScalarFPConvGpr));
|
||||
Add(Intrinsic.Arm64UhaddV, new IntrinsicInfo(0x2e200400u, IntrinsicType.VectorBinary));
|
||||
Add(Intrinsic.Arm64UhsubV, new IntrinsicInfo(0x2e202400u, IntrinsicType.VectorBinary));
|
||||
Add(Intrinsic.Arm64UmaxpV, new IntrinsicInfo(0x2e20a400u, IntrinsicType.VectorBinary));
|
||||
Add(Intrinsic.Arm64UmaxvV, new IntrinsicInfo(0x2e30a800u, IntrinsicType.VectorUnary));
|
||||
Add(Intrinsic.Arm64UmaxV, new IntrinsicInfo(0x2e206400u, IntrinsicType.VectorBinary));
|
||||
Add(Intrinsic.Arm64UminpV, new IntrinsicInfo(0x2e20ac00u, IntrinsicType.VectorBinary));
|
||||
Add(Intrinsic.Arm64UminvV, new IntrinsicInfo(0x2e31a800u, IntrinsicType.VectorUnary));
|
||||
Add(Intrinsic.Arm64UminV, new IntrinsicInfo(0x2e206c00u, IntrinsicType.VectorBinary));
|
||||
Add(Intrinsic.Arm64UmlalVe, new IntrinsicInfo(0x2f002000u, IntrinsicType.VectorTernaryRdByElem));
|
||||
Add(Intrinsic.Arm64UmlalV, new IntrinsicInfo(0x2e208000u, IntrinsicType.VectorTernaryRd));
|
||||
Add(Intrinsic.Arm64UmlslVe, new IntrinsicInfo(0x2f006000u, IntrinsicType.VectorTernaryRdByElem));
|
||||
Add(Intrinsic.Arm64UmlslV, new IntrinsicInfo(0x2e20a000u, IntrinsicType.VectorTernaryRd));
|
||||
Add(Intrinsic.Arm64UmovV, new IntrinsicInfo(0x0e003c00u, IntrinsicType.VectorUnaryByElem));
|
||||
Add(Intrinsic.Arm64UmullVe, new IntrinsicInfo(0x2f00a000u, IntrinsicType.VectorBinaryByElem));
|
||||
Add(Intrinsic.Arm64UmullV, new IntrinsicInfo(0x2e20c000u, IntrinsicType.VectorBinary));
|
||||
Add(Intrinsic.Arm64UqaddS, new IntrinsicInfo(0x7e200c00u, IntrinsicType.ScalarBinary));
|
||||
Add(Intrinsic.Arm64UqaddV, new IntrinsicInfo(0x2e200c00u, IntrinsicType.VectorBinary));
|
||||
Add(Intrinsic.Arm64UqrshlS, new IntrinsicInfo(0x7e205c00u, IntrinsicType.ScalarBinary));
|
||||
Add(Intrinsic.Arm64UqrshlV, new IntrinsicInfo(0x2e205c00u, IntrinsicType.VectorBinary));
|
||||
Add(Intrinsic.Arm64UqrshrnS, new IntrinsicInfo(0x7f009c00u, IntrinsicType.ScalarTernaryShrRd));
|
||||
Add(Intrinsic.Arm64UqrshrnV, new IntrinsicInfo(0x2f009c00u, IntrinsicType.VectorTernaryShrRd));
|
||||
Add(Intrinsic.Arm64UqshlSi, new IntrinsicInfo(0x7f007400u, IntrinsicType.ScalarBinaryShl));
|
||||
Add(Intrinsic.Arm64UqshlVi, new IntrinsicInfo(0x2f007400u, IntrinsicType.VectorBinaryShl));
|
||||
Add(Intrinsic.Arm64UqshlS, new IntrinsicInfo(0x7e204c00u, IntrinsicType.ScalarBinary));
|
||||
Add(Intrinsic.Arm64UqshlV, new IntrinsicInfo(0x2e204c00u, IntrinsicType.VectorBinary));
|
||||
Add(Intrinsic.Arm64UqshrnS, new IntrinsicInfo(0x7f009400u, IntrinsicType.ScalarTernaryShrRd));
|
||||
Add(Intrinsic.Arm64UqshrnV, new IntrinsicInfo(0x2f009400u, IntrinsicType.VectorTernaryShrRd));
|
||||
Add(Intrinsic.Arm64UqsubS, new IntrinsicInfo(0x7e202c00u, IntrinsicType.ScalarBinary));
|
||||
Add(Intrinsic.Arm64UqsubV, new IntrinsicInfo(0x2e202c00u, IntrinsicType.VectorBinary));
|
||||
Add(Intrinsic.Arm64UqxtnS, new IntrinsicInfo(0x7e214800u, IntrinsicType.ScalarBinaryRd));
|
||||
Add(Intrinsic.Arm64UqxtnV, new IntrinsicInfo(0x2e214800u, IntrinsicType.VectorBinaryRd));
|
||||
Add(Intrinsic.Arm64UrecpeV, new IntrinsicInfo(0x0ea1c800u, IntrinsicType.VectorUnary));
|
||||
Add(Intrinsic.Arm64UrhaddV, new IntrinsicInfo(0x2e201400u, IntrinsicType.VectorBinary));
|
||||
Add(Intrinsic.Arm64UrshlS, new IntrinsicInfo(0x7e205400u, IntrinsicType.ScalarBinary));
|
||||
Add(Intrinsic.Arm64UrshlV, new IntrinsicInfo(0x2e205400u, IntrinsicType.VectorBinary));
|
||||
Add(Intrinsic.Arm64UrshrS, new IntrinsicInfo(0x7f002400u, IntrinsicType.ScalarBinaryShr));
|
||||
Add(Intrinsic.Arm64UrshrV, new IntrinsicInfo(0x2f002400u, IntrinsicType.VectorBinaryShr));
|
||||
Add(Intrinsic.Arm64UrsqrteV, new IntrinsicInfo(0x2ea1c800u, IntrinsicType.VectorUnary));
|
||||
Add(Intrinsic.Arm64UrsraS, new IntrinsicInfo(0x7f003400u, IntrinsicType.ScalarTernaryShrRd));
|
||||
Add(Intrinsic.Arm64UrsraV, new IntrinsicInfo(0x2f003400u, IntrinsicType.VectorTernaryShrRd));
|
||||
Add(Intrinsic.Arm64UshllV, new IntrinsicInfo(0x2f00a400u, IntrinsicType.VectorBinaryShl));
|
||||
Add(Intrinsic.Arm64UshlS, new IntrinsicInfo(0x7e204400u, IntrinsicType.ScalarBinary));
|
||||
Add(Intrinsic.Arm64UshlV, new IntrinsicInfo(0x2e204400u, IntrinsicType.VectorBinary));
|
||||
Add(Intrinsic.Arm64UshrS, new IntrinsicInfo(0x7f000400u, IntrinsicType.ScalarBinaryShr));
|
||||
Add(Intrinsic.Arm64UshrV, new IntrinsicInfo(0x2f000400u, IntrinsicType.VectorBinaryShr));
|
||||
Add(Intrinsic.Arm64UsqaddS, new IntrinsicInfo(0x7e203800u, IntrinsicType.ScalarBinaryRd));
|
||||
Add(Intrinsic.Arm64UsqaddV, new IntrinsicInfo(0x2e203800u, IntrinsicType.VectorBinaryRd));
|
||||
Add(Intrinsic.Arm64UsraS, new IntrinsicInfo(0x7f001400u, IntrinsicType.ScalarTernaryShrRd));
|
||||
Add(Intrinsic.Arm64UsraV, new IntrinsicInfo(0x2f001400u, IntrinsicType.VectorTernaryShrRd));
|
||||
Add(Intrinsic.Arm64UsublV, new IntrinsicInfo(0x2e202000u, IntrinsicType.VectorBinary));
|
||||
Add(Intrinsic.Arm64UsubwV, new IntrinsicInfo(0x2e203000u, IntrinsicType.VectorBinary));
|
||||
Add(Intrinsic.Arm64Uzp1V, new IntrinsicInfo(0x0e001800u, IntrinsicType.VectorBinary));
|
||||
Add(Intrinsic.Arm64Uzp2V, new IntrinsicInfo(0x0e005800u, IntrinsicType.VectorBinary));
|
||||
Add(Intrinsic.Arm64XtnV, new IntrinsicInfo(0x0e212800u, IntrinsicType.VectorUnary));
|
||||
Add(Intrinsic.Arm64Zip1V, new IntrinsicInfo(0x0e003800u, IntrinsicType.VectorBinary));
|
||||
Add(Intrinsic.Arm64Zip2V, new IntrinsicInfo(0x0e007800u, IntrinsicType.VectorBinary));
|
||||
}
|
||||
|
||||
private static void Add(Intrinsic intrin, IntrinsicInfo info)
|
||||
{
|
||||
_intrinTable[(int)intrin] = info;
|
||||
}
|
||||
|
||||
public static IntrinsicInfo GetInfo(Intrinsic intrin)
|
||||
{
|
||||
return _intrinTable[(int)intrin];
|
||||
}
|
||||
}
|
||||
}
|
59
ARMeilleure/CodeGen/Arm64/IntrinsicType.cs
Normal file
59
ARMeilleure/CodeGen/Arm64/IntrinsicType.cs
Normal file
@ -0,0 +1,59 @@
|
||||
namespace ARMeilleure.CodeGen.Arm64
|
||||
{
|
||||
enum IntrinsicType
|
||||
{
|
||||
ScalarUnary,
|
||||
ScalarUnaryByElem,
|
||||
ScalarBinary,
|
||||
ScalarBinaryByElem,
|
||||
ScalarBinaryFPByElem,
|
||||
ScalarBinaryRd,
|
||||
ScalarBinaryShl,
|
||||
ScalarBinaryShr,
|
||||
ScalarFcsel,
|
||||
ScalarFmovi,
|
||||
ScalarFPCompare,
|
||||
ScalarFPCompareCond,
|
||||
ScalarFPConv,
|
||||
ScalarFPConvFixed,
|
||||
ScalarFPConvFixedGpr,
|
||||
ScalarFPConvGpr,
|
||||
ScalarTernary,
|
||||
ScalarTernaryFPRdByElem,
|
||||
ScalarTernaryShlRd,
|
||||
ScalarTernaryShrRd,
|
||||
|
||||
VectorUnary,
|
||||
VectorUnaryBitwise,
|
||||
VectorUnaryByElem,
|
||||
VectorBinary,
|
||||
VectorBinaryBitwise,
|
||||
VectorBinaryBitwiseImm,
|
||||
VectorBinaryByElem,
|
||||
VectorBinaryFPByElem,
|
||||
VectorBinaryRd,
|
||||
VectorBinaryShl,
|
||||
VectorBinaryShr,
|
||||
VectorExt,
|
||||
VectorFmovi,
|
||||
VectorFPConvFixed,
|
||||
VectorInsertByElem,
|
||||
VectorLdSt,
|
||||
VectorLdStSs,
|
||||
VectorLookupTable,
|
||||
VectorMovi,
|
||||
VectorMvni,
|
||||
VectorTernaryFPRdByElem,
|
||||
VectorTernaryRd,
|
||||
VectorTernaryRdBitwise,
|
||||
VectorTernaryRdByElem,
|
||||
VectorTernaryShlRd,
|
||||
VectorTernaryShrRd,
|
||||
|
||||
Vector128Unary,
|
||||
Vector128Binary,
|
||||
|
||||
GetRegister,
|
||||
SetRegister
|
||||
}
|
||||
}
|
940
ARMeilleure/CodeGen/Arm64/PreAllocator.cs
Normal file
940
ARMeilleure/CodeGen/Arm64/PreAllocator.cs
Normal file
@ -0,0 +1,940 @@
|
||||
using ARMeilleure.CodeGen.RegisterAllocators;
|
||||
using ARMeilleure.IntermediateRepresentation;
|
||||
using ARMeilleure.Translation;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
|
||||
using static ARMeilleure.IntermediateRepresentation.Operation.Factory;
|
||||
|
||||
namespace ARMeilleure.CodeGen.Arm64
|
||||
{
|
||||
class PreAllocator
|
||||
{
|
||||
private class ConstantDict
|
||||
{
|
||||
private readonly Dictionary<(ulong, OperandType), Operand> _constants;
|
||||
|
||||
public ConstantDict()
|
||||
{
|
||||
_constants = new Dictionary<(ulong, OperandType), Operand>();
|
||||
}
|
||||
|
||||
public void Add(ulong value, OperandType type, Operand local)
|
||||
{
|
||||
_constants.Add((value, type), local);
|
||||
}
|
||||
|
||||
public bool TryGetValue(ulong value, OperandType type, out Operand local)
|
||||
{
|
||||
return _constants.TryGetValue((value, type), out local);
|
||||
}
|
||||
}
|
||||
|
||||
public static void RunPass(CompilerContext cctx, StackAllocator stackAlloc, out int maxCallArgs)
|
||||
{
|
||||
maxCallArgs = -1;
|
||||
|
||||
Span<Operation> buffer = default;
|
||||
|
||||
Operand[] preservedArgs = new Operand[CallingConvention.GetArgumentsOnRegsCount()];
|
||||
|
||||
for (BasicBlock block = cctx.Cfg.Blocks.First; block != null; block = block.ListNext)
|
||||
{
|
||||
ConstantDict constants = new ConstantDict();
|
||||
|
||||
Operation nextNode;
|
||||
|
||||
for (Operation node = block.Operations.First; node != default; node = nextNode)
|
||||
{
|
||||
nextNode = node.ListNext;
|
||||
|
||||
if (node.Instruction == Instruction.Phi)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
HandleConstantRegCopy(constants, block.Operations, node);
|
||||
HandleDestructiveRegCopy(block.Operations, node);
|
||||
|
||||
switch (node.Instruction)
|
||||
{
|
||||
case Instruction.Call:
|
||||
// Get the maximum number of arguments used on a call.
|
||||
// On windows, when a struct is returned from the call,
|
||||
// we also need to pass the pointer where the struct
|
||||
// should be written on the first argument.
|
||||
int argsCount = node.SourcesCount - 1;
|
||||
|
||||
if (node.Destination != default && node.Destination.Type == OperandType.V128)
|
||||
{
|
||||
argsCount++;
|
||||
}
|
||||
|
||||
if (maxCallArgs < argsCount)
|
||||
{
|
||||
maxCallArgs = argsCount;
|
||||
}
|
||||
|
||||
// Copy values to registers expected by the function
|
||||
// being called, as mandated by the ABI.
|
||||
HandleCall(constants, block.Operations, node);
|
||||
break;
|
||||
case Instruction.CompareAndSwap:
|
||||
case Instruction.CompareAndSwap16:
|
||||
case Instruction.CompareAndSwap8:
|
||||
nextNode = HandleCompareAndSwap(block.Operations, node);
|
||||
break;
|
||||
case Instruction.LoadArgument:
|
||||
nextNode = HandleLoadArgument(cctx, ref buffer, block.Operations, preservedArgs, node);
|
||||
break;
|
||||
case Instruction.Return:
|
||||
HandleReturn(block.Operations, node);
|
||||
break;
|
||||
case Instruction.Tailcall:
|
||||
HandleTailcall(constants, block.Operations, stackAlloc, node, node);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void HandleConstantRegCopy(ConstantDict constants, IntrusiveList<Operation> nodes, Operation node)
|
||||
{
|
||||
if (node.SourcesCount == 0 || IsIntrinsicWithConst(node))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Instruction inst = node.Instruction;
|
||||
|
||||
Operand src1 = node.GetSource(0);
|
||||
Operand src2;
|
||||
|
||||
if (src1.Kind == OperandKind.Constant)
|
||||
{
|
||||
if (!src1.Type.IsInteger())
|
||||
{
|
||||
// Handle non-integer types (FP32, FP64 and V128).
|
||||
// For instructions without an immediate operand, we do the following:
|
||||
// - Insert a copy with the constant value (as integer) to a GPR.
|
||||
// - Insert a copy from the GPR to a XMM register.
|
||||
// - Replace the constant use with the XMM register.
|
||||
src1 = AddFloatConstantCopy(constants, nodes, node, src1);
|
||||
|
||||
node.SetSource(0, src1);
|
||||
}
|
||||
else if (!HasConstSrc1(node, src1.Value))
|
||||
{
|
||||
// Handle integer types.
|
||||
// Most ALU instructions accepts a 32-bits immediate on the second operand.
|
||||
// We need to ensure the following:
|
||||
// - If the constant is on operand 1, we need to move it.
|
||||
// -- But first, we try to swap operand 1 and 2 if the instruction is commutative.
|
||||
// -- Doing so may allow us to encode the constant as operand 2 and avoid a copy.
|
||||
// - If the constant is on operand 2, we check if the instruction supports it,
|
||||
// if not, we also add a copy. 64-bits constants are usually not supported.
|
||||
if (IsCommutative(node))
|
||||
{
|
||||
src2 = node.GetSource(1);
|
||||
|
||||
Operand temp = src1;
|
||||
|
||||
src1 = src2;
|
||||
src2 = temp;
|
||||
|
||||
node.SetSource(0, src1);
|
||||
node.SetSource(1, src2);
|
||||
}
|
||||
|
||||
if (src1.Kind == OperandKind.Constant)
|
||||
{
|
||||
src1 = AddIntConstantCopy(constants, nodes, node, src1);
|
||||
|
||||
node.SetSource(0, src1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (node.SourcesCount < 2)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
src2 = node.GetSource(1);
|
||||
|
||||
if (src2.Kind == OperandKind.Constant)
|
||||
{
|
||||
if (!src2.Type.IsInteger())
|
||||
{
|
||||
src2 = AddFloatConstantCopy(constants, nodes, node, src2);
|
||||
|
||||
node.SetSource(1, src2);
|
||||
}
|
||||
else if (!HasConstSrc2(inst, src2))
|
||||
{
|
||||
src2 = AddIntConstantCopy(constants, nodes, node, src2);
|
||||
|
||||
node.SetSource(1, src2);
|
||||
}
|
||||
}
|
||||
|
||||
if (node.SourcesCount < 3 ||
|
||||
node.Instruction == Instruction.BranchIf ||
|
||||
node.Instruction == Instruction.Compare ||
|
||||
node.Instruction == Instruction.VectorInsert ||
|
||||
node.Instruction == Instruction.VectorInsert16 ||
|
||||
node.Instruction == Instruction.VectorInsert8)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (int srcIndex = 2; srcIndex < node.SourcesCount; srcIndex++)
|
||||
{
|
||||
Operand src = node.GetSource(srcIndex);
|
||||
|
||||
if (src.Kind == OperandKind.Constant)
|
||||
{
|
||||
if (!src.Type.IsInteger())
|
||||
{
|
||||
src = AddFloatConstantCopy(constants, nodes, node, src);
|
||||
|
||||
node.SetSource(srcIndex, src);
|
||||
}
|
||||
else
|
||||
{
|
||||
src = AddIntConstantCopy(constants, nodes, node, src);
|
||||
|
||||
node.SetSource(srcIndex, src);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void HandleDestructiveRegCopy(IntrusiveList<Operation> nodes, Operation node)
|
||||
{
|
||||
if (node.Destination == default || node.SourcesCount == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Operand dest = node.Destination;
|
||||
Operand src1 = node.GetSource(0);
|
||||
|
||||
if (IsSameOperandDestSrc1(node) && src1.Kind == OperandKind.LocalVariable)
|
||||
{
|
||||
bool useNewLocal = false;
|
||||
|
||||
for (int srcIndex = 1; srcIndex < node.SourcesCount; srcIndex++)
|
||||
{
|
||||
if (node.GetSource(srcIndex) == dest)
|
||||
{
|
||||
useNewLocal = true;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (useNewLocal)
|
||||
{
|
||||
// Dest is being used as some source already, we need to use a new
|
||||
// local to store the temporary value, otherwise the value on dest
|
||||
// local would be overwritten.
|
||||
Operand temp = Local(dest.Type);
|
||||
|
||||
nodes.AddBefore(node, Operation(Instruction.Copy, temp, src1));
|
||||
|
||||
node.SetSource(0, temp);
|
||||
|
||||
nodes.AddAfter(node, Operation(Instruction.Copy, dest, temp));
|
||||
|
||||
node.Destination = temp;
|
||||
}
|
||||
else
|
||||
{
|
||||
nodes.AddBefore(node, Operation(Instruction.Copy, dest, src1));
|
||||
|
||||
node.SetSource(0, dest);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void HandleCall(ConstantDict constants, IntrusiveList<Operation> nodes, Operation node)
|
||||
{
|
||||
Operation operation = node;
|
||||
|
||||
Operand dest = operation.Destination;
|
||||
|
||||
List<Operand> sources = new List<Operand>
|
||||
{
|
||||
operation.GetSource(0)
|
||||
};
|
||||
|
||||
int argsCount = operation.SourcesCount - 1;
|
||||
|
||||
int intMax = CallingConvention.GetArgumentsOnRegsCount();
|
||||
int vecMax = CallingConvention.GetArgumentsOnRegsCount();
|
||||
|
||||
int intCount = 0;
|
||||
int vecCount = 0;
|
||||
|
||||
int stackOffset = 0;
|
||||
|
||||
for (int index = 0; index < argsCount; index++)
|
||||
{
|
||||
Operand source = operation.GetSource(index + 1);
|
||||
|
||||
bool passOnReg;
|
||||
|
||||
if (source.Type.IsInteger())
|
||||
{
|
||||
passOnReg = intCount < intMax;
|
||||
}
|
||||
else if (source.Type == OperandType.V128)
|
||||
{
|
||||
passOnReg = intCount + 1 < intMax;
|
||||
}
|
||||
else
|
||||
{
|
||||
passOnReg = vecCount < vecMax;
|
||||
}
|
||||
|
||||
if (source.Type == OperandType.V128 && passOnReg)
|
||||
{
|
||||
// V128 is a struct, we pass each half on a GPR if possible.
|
||||
Operand argReg = Gpr(CallingConvention.GetIntArgumentRegister(intCount++), OperandType.I64);
|
||||
Operand argReg2 = Gpr(CallingConvention.GetIntArgumentRegister(intCount++), OperandType.I64);
|
||||
|
||||
nodes.AddBefore(node, Operation(Instruction.VectorExtract, argReg, source, Const(0)));
|
||||
nodes.AddBefore(node, Operation(Instruction.VectorExtract, argReg2, source, Const(1)));
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (passOnReg)
|
||||
{
|
||||
Operand argReg = source.Type.IsInteger()
|
||||
? Gpr(CallingConvention.GetIntArgumentRegister(intCount++), source.Type)
|
||||
: Xmm(CallingConvention.GetVecArgumentRegister(vecCount++), source.Type);
|
||||
|
||||
Operation copyOp = Operation(Instruction.Copy, argReg, source);
|
||||
|
||||
HandleConstantRegCopy(constants, nodes, nodes.AddBefore(node, copyOp));
|
||||
|
||||
sources.Add(argReg);
|
||||
}
|
||||
else
|
||||
{
|
||||
Operand offset = Const(stackOffset);
|
||||
|
||||
Operation spillOp = Operation(Instruction.SpillArg, default, offset, source);
|
||||
|
||||
HandleConstantRegCopy(constants, nodes, nodes.AddBefore(node, spillOp));
|
||||
|
||||
stackOffset += source.Type.GetSizeInBytes();
|
||||
}
|
||||
}
|
||||
|
||||
if (dest != default)
|
||||
{
|
||||
if (dest.Type == OperandType.V128)
|
||||
{
|
||||
Operand retLReg = Gpr(CallingConvention.GetIntReturnRegister(), OperandType.I64);
|
||||
Operand retHReg = Gpr(CallingConvention.GetIntReturnRegisterHigh(), OperandType.I64);
|
||||
|
||||
node = nodes.AddAfter(node, Operation(Instruction.VectorCreateScalar, dest, retLReg));
|
||||
nodes.AddAfter(node, Operation(Instruction.VectorInsert, dest, dest, retHReg, Const(1)));
|
||||
|
||||
operation.Destination = default;
|
||||
}
|
||||
else
|
||||
{
|
||||
Operand retReg = dest.Type.IsInteger()
|
||||
? Gpr(CallingConvention.GetIntReturnRegister(), dest.Type)
|
||||
: Xmm(CallingConvention.GetVecReturnRegister(), dest.Type);
|
||||
|
||||
Operation copyOp = Operation(Instruction.Copy, dest, retReg);
|
||||
|
||||
nodes.AddAfter(node, copyOp);
|
||||
|
||||
operation.Destination = retReg;
|
||||
}
|
||||
}
|
||||
|
||||
operation.SetSources(sources.ToArray());
|
||||
}
|
||||
|
||||
private static void HandleTailcall(
|
||||
ConstantDict constants,
|
||||
IntrusiveList<Operation> nodes,
|
||||
StackAllocator stackAlloc,
|
||||
Operation node,
|
||||
Operation operation)
|
||||
{
|
||||
List<Operand> sources = new List<Operand>
|
||||
{
|
||||
operation.GetSource(0)
|
||||
};
|
||||
|
||||
int argsCount = operation.SourcesCount - 1;
|
||||
|
||||
int intMax = CallingConvention.GetArgumentsOnRegsCount();
|
||||
int vecMax = CallingConvention.GetArgumentsOnRegsCount();
|
||||
|
||||
int intCount = 0;
|
||||
int vecCount = 0;
|
||||
|
||||
// Handle arguments passed on registers.
|
||||
for (int index = 0; index < argsCount; index++)
|
||||
{
|
||||
Operand source = operation.GetSource(1 + index);
|
||||
|
||||
bool passOnReg;
|
||||
|
||||
if (source.Type.IsInteger())
|
||||
{
|
||||
passOnReg = intCount + 1 < intMax;
|
||||
}
|
||||
else
|
||||
{
|
||||
passOnReg = vecCount < vecMax;
|
||||
}
|
||||
|
||||
if (source.Type == OperandType.V128 && passOnReg)
|
||||
{
|
||||
// V128 is a struct, we pass each half on a GPR if possible.
|
||||
Operand argReg = Gpr(CallingConvention.GetIntArgumentRegister(intCount++), OperandType.I64);
|
||||
Operand argReg2 = Gpr(CallingConvention.GetIntArgumentRegister(intCount++), OperandType.I64);
|
||||
|
||||
nodes.AddBefore(node, Operation(Instruction.VectorExtract, argReg, source, Const(0)));
|
||||
nodes.AddBefore(node, Operation(Instruction.VectorExtract, argReg2, source, Const(1)));
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (passOnReg)
|
||||
{
|
||||
Operand argReg = source.Type.IsInteger()
|
||||
? Gpr(CallingConvention.GetIntArgumentRegister(intCount++), source.Type)
|
||||
: Xmm(CallingConvention.GetVecArgumentRegister(vecCount++), source.Type);
|
||||
|
||||
Operation copyOp = Operation(Instruction.Copy, argReg, source);
|
||||
|
||||
HandleConstantRegCopy(constants, nodes, nodes.AddBefore(node, copyOp));
|
||||
|
||||
sources.Add(argReg);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new NotImplementedException("Spilling is not currently supported for tail calls. (too many arguments)");
|
||||
}
|
||||
}
|
||||
|
||||
// The target address must be on the return registers, since we
|
||||
// don't return anything and it is guaranteed to not be a
|
||||
// callee saved register (which would be trashed on the epilogue).
|
||||
Operand tcAddress = Gpr(CodeGenCommon.TcAddressRegister, OperandType.I64);
|
||||
|
||||
Operation addrCopyOp = Operation(Instruction.Copy, tcAddress, operation.GetSource(0));
|
||||
|
||||
nodes.AddBefore(node, addrCopyOp);
|
||||
|
||||
sources[0] = tcAddress;
|
||||
|
||||
operation.SetSources(sources.ToArray());
|
||||
}
|
||||
|
||||
private static Operation HandleCompareAndSwap(IntrusiveList<Operation> nodes, Operation node)
|
||||
{
|
||||
Operand expected = node.GetSource(1);
|
||||
|
||||
if (expected.Type == OperandType.V128)
|
||||
{
|
||||
Operand dest = node.Destination;
|
||||
Operand expectedLow = Local(OperandType.I64);
|
||||
Operand expectedHigh = Local(OperandType.I64);
|
||||
Operand desiredLow = Local(OperandType.I64);
|
||||
Operand desiredHigh = Local(OperandType.I64);
|
||||
Operand actualLow = Local(OperandType.I64);
|
||||
Operand actualHigh = Local(OperandType.I64);
|
||||
|
||||
Operand address = node.GetSource(0);
|
||||
Operand desired = node.GetSource(2);
|
||||
|
||||
void SplitOperand(Operand source, Operand low, Operand high)
|
||||
{
|
||||
nodes.AddBefore(node, Operation(Instruction.VectorExtract, low, source, Const(0)));
|
||||
nodes.AddBefore(node, Operation(Instruction.VectorExtract, high, source, Const(1)));
|
||||
}
|
||||
|
||||
SplitOperand(expected, expectedLow, expectedHigh);
|
||||
SplitOperand(desired, desiredLow, desiredHigh);
|
||||
|
||||
Operation operation = node;
|
||||
|
||||
// Update the sources and destinations with split 64-bit halfs of the whole 128-bit values.
|
||||
// We also need a additional registers that will be used to store temporary information.
|
||||
operation.SetDestinations(new[] { actualLow, actualHigh, Local(OperandType.I64), Local(OperandType.I64) });
|
||||
operation.SetSources(new[] { address, expectedLow, expectedHigh, desiredLow, desiredHigh });
|
||||
|
||||
// Add some dummy uses of the input operands, as the CAS operation will be a loop,
|
||||
// so they can't be used as destination operand.
|
||||
for (int i = 0; i < operation.SourcesCount; i++)
|
||||
{
|
||||
Operand src = operation.GetSource(i);
|
||||
node = nodes.AddAfter(node, Operation(Instruction.Copy, src, src));
|
||||
}
|
||||
|
||||
// Assemble the vector with the 64-bit values at the given memory location.
|
||||
node = nodes.AddAfter(node, Operation(Instruction.VectorCreateScalar, dest, actualLow));
|
||||
node = nodes.AddAfter(node, Operation(Instruction.VectorInsert, dest, dest, actualHigh, Const(1)));
|
||||
}
|
||||
else
|
||||
{
|
||||
// We need a additional register where the store result will be written to.
|
||||
node.SetDestinations(new[] { node.Destination, Local(OperandType.I32) });
|
||||
|
||||
// Add some dummy uses of the input operands, as the CAS operation will be a loop,
|
||||
// so they can't be used as destination operand.
|
||||
Operation operation = node;
|
||||
|
||||
for (int i = 0; i < operation.SourcesCount; i++)
|
||||
{
|
||||
Operand src = operation.GetSource(i);
|
||||
node = nodes.AddAfter(node, Operation(Instruction.Copy, src, src));
|
||||
}
|
||||
}
|
||||
|
||||
return node.ListNext;
|
||||
}
|
||||
|
||||
private static void HandleReturn(IntrusiveList<Operation> nodes, Operation node)
|
||||
{
|
||||
if (node.SourcesCount == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Operand source = node.GetSource(0);
|
||||
|
||||
if (source.Type == OperandType.V128)
|
||||
{
|
||||
Operand retLReg = Gpr(CallingConvention.GetIntReturnRegister(), OperandType.I64);
|
||||
Operand retHReg = Gpr(CallingConvention.GetIntReturnRegisterHigh(), OperandType.I64);
|
||||
|
||||
nodes.AddBefore(node, Operation(Instruction.VectorExtract, retLReg, source, Const(0)));
|
||||
nodes.AddBefore(node, Operation(Instruction.VectorExtract, retHReg, source, Const(1)));
|
||||
}
|
||||
else
|
||||
{
|
||||
Operand retReg = source.Type.IsInteger()
|
||||
? Gpr(CallingConvention.GetIntReturnRegister(), source.Type)
|
||||
: Xmm(CallingConvention.GetVecReturnRegister(), source.Type);
|
||||
|
||||
Operation retCopyOp = Operation(Instruction.Copy, retReg, source);
|
||||
|
||||
nodes.AddBefore(node, retCopyOp);
|
||||
}
|
||||
}
|
||||
|
||||
private static Operation HandleLoadArgument(
|
||||
CompilerContext cctx,
|
||||
ref Span<Operation> buffer,
|
||||
IntrusiveList<Operation> nodes,
|
||||
Operand[] preservedArgs,
|
||||
Operation node)
|
||||
{
|
||||
Operand source = node.GetSource(0);
|
||||
|
||||
Debug.Assert(source.Kind == OperandKind.Constant, "Non-constant LoadArgument source kind.");
|
||||
|
||||
int index = source.AsInt32();
|
||||
|
||||
int intCount = 0;
|
||||
int vecCount = 0;
|
||||
|
||||
for (int cIndex = 0; cIndex < index; cIndex++)
|
||||
{
|
||||
OperandType argType = cctx.FuncArgTypes[cIndex];
|
||||
|
||||
if (argType.IsInteger())
|
||||
{
|
||||
intCount++;
|
||||
}
|
||||
else if (argType == OperandType.V128)
|
||||
{
|
||||
intCount += 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
vecCount++;
|
||||
}
|
||||
}
|
||||
|
||||
bool passOnReg;
|
||||
|
||||
if (source.Type.IsInteger())
|
||||
{
|
||||
passOnReg = intCount < CallingConvention.GetArgumentsOnRegsCount();
|
||||
}
|
||||
else if (source.Type == OperandType.V128)
|
||||
{
|
||||
passOnReg = intCount + 1 < CallingConvention.GetArgumentsOnRegsCount();
|
||||
}
|
||||
else
|
||||
{
|
||||
passOnReg = vecCount < CallingConvention.GetArgumentsOnRegsCount();
|
||||
}
|
||||
|
||||
if (passOnReg)
|
||||
{
|
||||
Operand dest = node.Destination;
|
||||
|
||||
if (preservedArgs[index] == default)
|
||||
{
|
||||
if (dest.Type == OperandType.V128)
|
||||
{
|
||||
// V128 is a struct, we pass each half on a GPR if possible.
|
||||
Operand pArg = Local(OperandType.V128);
|
||||
|
||||
Operand argLReg = Gpr(CallingConvention.GetIntArgumentRegister(intCount), OperandType.I64);
|
||||
Operand argHReg = Gpr(CallingConvention.GetIntArgumentRegister(intCount + 1), OperandType.I64);
|
||||
|
||||
Operation copyL = Operation(Instruction.VectorCreateScalar, pArg, argLReg);
|
||||
Operation copyH = Operation(Instruction.VectorInsert, pArg, pArg, argHReg, Const(1));
|
||||
|
||||
cctx.Cfg.Entry.Operations.AddFirst(copyH);
|
||||
cctx.Cfg.Entry.Operations.AddFirst(copyL);
|
||||
|
||||
preservedArgs[index] = pArg;
|
||||
}
|
||||
else
|
||||
{
|
||||
Operand pArg = Local(dest.Type);
|
||||
|
||||
Operand argReg = dest.Type.IsInteger()
|
||||
? Gpr(CallingConvention.GetIntArgumentRegister(intCount), dest.Type)
|
||||
: Xmm(CallingConvention.GetVecArgumentRegister(vecCount), dest.Type);
|
||||
|
||||
Operation copyOp = Operation(Instruction.Copy, pArg, argReg);
|
||||
|
||||
cctx.Cfg.Entry.Operations.AddFirst(copyOp);
|
||||
|
||||
preservedArgs[index] = pArg;
|
||||
}
|
||||
}
|
||||
|
||||
Operation nextNode;
|
||||
|
||||
if (dest.AssignmentsCount == 1)
|
||||
{
|
||||
// Let's propagate the argument if we can to avoid copies.
|
||||
Propagate(ref buffer, dest, preservedArgs[index]);
|
||||
nextNode = node.ListNext;
|
||||
}
|
||||
else
|
||||
{
|
||||
Operation argCopyOp = Operation(Instruction.Copy, dest, preservedArgs[index]);
|
||||
nextNode = nodes.AddBefore(node, argCopyOp);
|
||||
}
|
||||
|
||||
Delete(nodes, node);
|
||||
return nextNode;
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: Pass on stack.
|
||||
return node;
|
||||
}
|
||||
}
|
||||
|
||||
private static void Propagate(ref Span<Operation> buffer, Operand dest, Operand value)
|
||||
{
|
||||
ReadOnlySpan<Operation> uses = dest.GetUses(ref buffer);
|
||||
|
||||
foreach (Operation use in uses)
|
||||
{
|
||||
for (int srcIndex = 0; srcIndex < use.SourcesCount; srcIndex++)
|
||||
{
|
||||
Operand useSrc = use.GetSource(srcIndex);
|
||||
|
||||
if (useSrc == dest)
|
||||
{
|
||||
use.SetSource(srcIndex, value);
|
||||
}
|
||||
else if (useSrc.Kind == OperandKind.Memory)
|
||||
{
|
||||
MemoryOperand memoryOp = useSrc.GetMemory();
|
||||
|
||||
Operand baseAddr = memoryOp.BaseAddress;
|
||||
Operand index = memoryOp.Index;
|
||||
bool changed = false;
|
||||
|
||||
if (baseAddr == dest)
|
||||
{
|
||||
baseAddr = value;
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if (index == dest)
|
||||
{
|
||||
index = value;
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if (changed)
|
||||
{
|
||||
use.SetSource(srcIndex, MemoryOp(
|
||||
useSrc.Type,
|
||||
baseAddr,
|
||||
index,
|
||||
memoryOp.Scale,
|
||||
memoryOp.Displacement));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static Operand AddFloatConstantCopy(
|
||||
ConstantDict constants,
|
||||
IntrusiveList<Operation> nodes,
|
||||
Operation node,
|
||||
Operand source)
|
||||
{
|
||||
Operand temp = Local(source.Type);
|
||||
|
||||
Operand intConst = AddIntConstantCopy(constants, nodes, node, GetIntConst(source));
|
||||
|
||||
Operation copyOp = Operation(Instruction.VectorCreateScalar, temp, intConst);
|
||||
|
||||
nodes.AddBefore(node, copyOp);
|
||||
|
||||
return temp;
|
||||
}
|
||||
|
||||
private static Operand AddIntConstantCopy(
|
||||
ConstantDict constants,
|
||||
IntrusiveList<Operation> nodes,
|
||||
Operation node,
|
||||
Operand source)
|
||||
{
|
||||
if (constants.TryGetValue(source.Value, source.Type, out Operand temp))
|
||||
{
|
||||
return temp;
|
||||
}
|
||||
|
||||
temp = Local(source.Type);
|
||||
|
||||
Operation copyOp = Operation(Instruction.Copy, temp, source);
|
||||
|
||||
nodes.AddBefore(node, copyOp);
|
||||
|
||||
constants.Add(source.Value, source.Type, temp);
|
||||
|
||||
return temp;
|
||||
}
|
||||
|
||||
private static Operand GetIntConst(Operand value)
|
||||
{
|
||||
if (value.Type == OperandType.FP32)
|
||||
{
|
||||
return Const(value.AsInt32());
|
||||
}
|
||||
else if (value.Type == OperandType.FP64)
|
||||
{
|
||||
return Const(value.AsInt64());
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
private static void Delete(IntrusiveList<Operation> nodes, Operation node)
|
||||
{
|
||||
node.Destination = default;
|
||||
|
||||
for (int index = 0; index < node.SourcesCount; index++)
|
||||
{
|
||||
node.SetSource(index, default);
|
||||
}
|
||||
|
||||
nodes.Remove(node);
|
||||
}
|
||||
|
||||
private static Operand Gpr(int register, OperandType type)
|
||||
{
|
||||
return Register(register, RegisterType.Integer, type);
|
||||
}
|
||||
|
||||
private static Operand Xmm(int register, OperandType type)
|
||||
{
|
||||
return Register(register, RegisterType.Vector, type);
|
||||
}
|
||||
|
||||
private static bool IsSameOperandDestSrc1(Operation operation)
|
||||
{
|
||||
switch (operation.Instruction)
|
||||
{
|
||||
case Instruction.Extended:
|
||||
return IsSameOperandDestSrc1(operation.Intrinsic);
|
||||
case Instruction.VectorInsert:
|
||||
case Instruction.VectorInsert16:
|
||||
case Instruction.VectorInsert8:
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static bool IsSameOperandDestSrc1(Intrinsic intrinsic)
|
||||
{
|
||||
IntrinsicInfo info = IntrinsicTable.GetInfo(intrinsic & ~(Intrinsic.Arm64VTypeMask | Intrinsic.Arm64VSizeMask));
|
||||
|
||||
return info.Type == IntrinsicType.ScalarBinaryRd ||
|
||||
info.Type == IntrinsicType.ScalarTernaryFPRdByElem ||
|
||||
info.Type == IntrinsicType.ScalarTernaryShlRd ||
|
||||
info.Type == IntrinsicType.ScalarTernaryShrRd ||
|
||||
info.Type == IntrinsicType.VectorBinaryRd ||
|
||||
info.Type == IntrinsicType.VectorInsertByElem ||
|
||||
info.Type == IntrinsicType.VectorTernaryRd ||
|
||||
info.Type == IntrinsicType.VectorTernaryRdBitwise ||
|
||||
info.Type == IntrinsicType.VectorTernaryFPRdByElem ||
|
||||
info.Type == IntrinsicType.VectorTernaryRdByElem ||
|
||||
info.Type == IntrinsicType.VectorTernaryShlRd ||
|
||||
info.Type == IntrinsicType.VectorTernaryShrRd;
|
||||
}
|
||||
|
||||
private static bool HasConstSrc1(Operation node, ulong value)
|
||||
{
|
||||
switch (node.Instruction)
|
||||
{
|
||||
case Instruction.Add:
|
||||
case Instruction.BranchIf:
|
||||
case Instruction.Compare:
|
||||
case Instruction.Subtract:
|
||||
// The immediate encoding of those instructions does not allow Rn to be
|
||||
// XZR (it will be SP instead), so we can't allow a Rn constant in this case.
|
||||
return value == 0 && NotConstOrConst0(node.GetSource(1));
|
||||
case Instruction.BitwiseAnd:
|
||||
case Instruction.BitwiseExclusiveOr:
|
||||
case Instruction.BitwiseNot:
|
||||
case Instruction.BitwiseOr:
|
||||
case Instruction.ByteSwap:
|
||||
case Instruction.CountLeadingZeros:
|
||||
case Instruction.Multiply:
|
||||
case Instruction.Negate:
|
||||
case Instruction.RotateRight:
|
||||
case Instruction.ShiftLeft:
|
||||
case Instruction.ShiftRightSI:
|
||||
case Instruction.ShiftRightUI:
|
||||
return value == 0;
|
||||
case Instruction.Copy:
|
||||
case Instruction.LoadArgument:
|
||||
case Instruction.Spill:
|
||||
case Instruction.SpillArg:
|
||||
return true;
|
||||
case Instruction.Extended:
|
||||
return value == 0;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static bool NotConstOrConst0(Operand operand)
|
||||
{
|
||||
return operand.Kind != OperandKind.Constant || operand.Value == 0;
|
||||
}
|
||||
|
||||
private static bool HasConstSrc2(Instruction inst, Operand operand)
|
||||
{
|
||||
ulong value = operand.Value;
|
||||
|
||||
switch (inst)
|
||||
{
|
||||
case Instruction.Add:
|
||||
case Instruction.BranchIf:
|
||||
case Instruction.Compare:
|
||||
case Instruction.Subtract:
|
||||
return ConstFitsOnUImm12Sh(value);
|
||||
case Instruction.BitwiseAnd:
|
||||
case Instruction.BitwiseExclusiveOr:
|
||||
case Instruction.BitwiseOr:
|
||||
return value == 0 || CodeGenCommon.TryEncodeBitMask(operand, out _, out _, out _);
|
||||
case Instruction.Multiply:
|
||||
case Instruction.Store:
|
||||
case Instruction.Store16:
|
||||
case Instruction.Store8:
|
||||
return value == 0;
|
||||
case Instruction.RotateRight:
|
||||
case Instruction.ShiftLeft:
|
||||
case Instruction.ShiftRightSI:
|
||||
case Instruction.ShiftRightUI:
|
||||
case Instruction.VectorExtract:
|
||||
case Instruction.VectorExtract16:
|
||||
case Instruction.VectorExtract8:
|
||||
return true;
|
||||
case Instruction.Extended:
|
||||
// TODO: Check if actual intrinsic is supposed to have consts here?
|
||||
// Right now we only hit this case for fixed-point int <-> FP conversion instructions.
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static bool IsCommutative(Operation operation)
|
||||
{
|
||||
switch (operation.Instruction)
|
||||
{
|
||||
case Instruction.Add:
|
||||
case Instruction.BitwiseAnd:
|
||||
case Instruction.BitwiseExclusiveOr:
|
||||
case Instruction.BitwiseOr:
|
||||
case Instruction.Multiply:
|
||||
return true;
|
||||
|
||||
case Instruction.BranchIf:
|
||||
case Instruction.Compare:
|
||||
{
|
||||
Operand comp = operation.GetSource(2);
|
||||
|
||||
Debug.Assert(comp.Kind == OperandKind.Constant);
|
||||
|
||||
var compType = (Comparison)comp.AsInt32();
|
||||
|
||||
return compType == Comparison.Equal || compType == Comparison.NotEqual;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static bool ConstFitsOnUImm12Sh(ulong value)
|
||||
{
|
||||
return (value & ~0xfffUL) == 0 || (value & ~0xfff000UL) == 0;
|
||||
}
|
||||
|
||||
private static bool IsIntrinsicWithConst(Operation operation)
|
||||
{
|
||||
bool isIntrinsic = IsIntrinsic(operation.Instruction);
|
||||
|
||||
if (isIntrinsic)
|
||||
{
|
||||
Intrinsic intrinsic = operation.Intrinsic;
|
||||
IntrinsicInfo info = IntrinsicTable.GetInfo(intrinsic & ~(Intrinsic.Arm64VTypeMask | Intrinsic.Arm64VSizeMask));
|
||||
|
||||
// Those have integer inputs that don't support consts.
|
||||
return info.Type != IntrinsicType.ScalarFPConvGpr &&
|
||||
info.Type != IntrinsicType.ScalarFPConvFixedGpr &&
|
||||
info.Type != IntrinsicType.SetRegister;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static bool IsIntrinsic(Instruction inst)
|
||||
{
|
||||
return inst == Instruction.Extended;
|
||||
}
|
||||
}
|
||||
}
|
@ -48,9 +48,21 @@ namespace ARMeilleure.CodeGen
|
||||
/// <returns>A delegate of type <typeparamref name="T"/> pointing to the mapped function</returns>
|
||||
public T Map<T>()
|
||||
{
|
||||
IntPtr codePtr = JitCache.Map(this);
|
||||
return MapWithPointer<T>(out _);
|
||||
}
|
||||
|
||||
return Marshal.GetDelegateForFunctionPointer<T>(codePtr);
|
||||
/// <summary>
|
||||
/// Maps the <see cref="CompiledFunction"/> onto the <see cref="JitCache"/> and returns a delegate of type
|
||||
/// <typeparamref name="T"/> pointing to the mapped function.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Type of delegate</typeparam>
|
||||
/// <param name="codePointer">Pointer to the function code in memory</param>
|
||||
/// <returns>A delegate of type <typeparamref name="T"/> pointing to the mapped function</returns>
|
||||
public T MapWithPointer<T>(out IntPtr codePointer)
|
||||
{
|
||||
codePointer = JitCache.Map(this);
|
||||
|
||||
return Marshal.GetDelegateForFunctionPointer<T>(codePointer);
|
||||
}
|
||||
}
|
||||
}
|
@ -90,6 +90,47 @@ namespace ARMeilleure.CodeGen.Optimizations
|
||||
}
|
||||
break;
|
||||
|
||||
case Instruction.Compare:
|
||||
if (type == OperandType.I32 &&
|
||||
operation.GetSource(0).Type == type &&
|
||||
operation.GetSource(1).Type == type)
|
||||
{
|
||||
switch ((Comparison)operation.GetSource(2).Value)
|
||||
{
|
||||
case Comparison.Equal:
|
||||
EvaluateBinaryI32(operation, (x, y) => x == y ? 1 : 0);
|
||||
break;
|
||||
case Comparison.NotEqual:
|
||||
EvaluateBinaryI32(operation, (x, y) => x != y ? 1 : 0);
|
||||
break;
|
||||
case Comparison.Greater:
|
||||
EvaluateBinaryI32(operation, (x, y) => x > y ? 1 : 0);
|
||||
break;
|
||||
case Comparison.LessOrEqual:
|
||||
EvaluateBinaryI32(operation, (x, y) => x <= y ? 1 : 0);
|
||||
break;
|
||||
case Comparison.GreaterUI:
|
||||
EvaluateBinaryI32(operation, (x, y) => (uint)x > (uint)y ? 1 : 0);
|
||||
break;
|
||||
case Comparison.LessOrEqualUI:
|
||||
EvaluateBinaryI32(operation, (x, y) => (uint)x <= (uint)y ? 1 : 0);
|
||||
break;
|
||||
case Comparison.GreaterOrEqual:
|
||||
EvaluateBinaryI32(operation, (x, y) => x >= y ? 1 : 0);
|
||||
break;
|
||||
case Comparison.Less:
|
||||
EvaluateBinaryI32(operation, (x, y) => x < y ? 1 : 0);
|
||||
break;
|
||||
case Comparison.GreaterOrEqualUI:
|
||||
EvaluateBinaryI32(operation, (x, y) => (uint)x >= (uint)y ? 1 : 0);
|
||||
break;
|
||||
case Comparison.LessUI:
|
||||
EvaluateBinaryI32(operation, (x, y) => (uint)x < (uint)y ? 1 : 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case Instruction.Copy:
|
||||
if (type == OperandType.I32)
|
||||
{
|
||||
|
@ -44,8 +44,8 @@ namespace ARMeilleure.CodeGen.Optimizations
|
||||
ConstantFolding.RunPass(node);
|
||||
Simplification.RunPass(node);
|
||||
|
||||
if (DestIsLocalVar(node))
|
||||
{
|
||||
if (DestIsSingleLocalVar(node))
|
||||
{
|
||||
if (IsPropagableCompare(node))
|
||||
{
|
||||
modified |= PropagateCompare(ref buffer, node);
|
||||
@ -99,20 +99,6 @@ namespace ARMeilleure.CodeGen.Optimizations
|
||||
while (modified);
|
||||
}
|
||||
|
||||
private static Span<Operation> GetUses(ref Span<Operation> buffer, Operand operand)
|
||||
{
|
||||
ReadOnlySpan<Operation> uses = operand.Uses;
|
||||
|
||||
if (buffer.Length < uses.Length)
|
||||
{
|
||||
buffer = Allocators.Default.AllocateSpan<Operation>((uint)uses.Length);
|
||||
}
|
||||
|
||||
uses.CopyTo(buffer);
|
||||
|
||||
return buffer.Slice(0, uses.Length);
|
||||
}
|
||||
|
||||
private static bool PropagateCompare(ref Span<Operation> buffer, Operation compOp)
|
||||
{
|
||||
// Try to propagate Compare operations into their BranchIf uses, when these BranchIf uses are in the form
|
||||
@ -160,7 +146,7 @@ namespace ARMeilleure.CodeGen.Optimizations
|
||||
|
||||
Comparison compType = (Comparison)comp.AsInt32();
|
||||
|
||||
Span<Operation> uses = GetUses(ref buffer, dest);
|
||||
Span<Operation> uses = dest.GetUses(ref buffer);
|
||||
|
||||
foreach (Operation use in uses)
|
||||
{
|
||||
@ -199,7 +185,7 @@ namespace ARMeilleure.CodeGen.Optimizations
|
||||
Operand dest = copyOp.Destination;
|
||||
Operand source = copyOp.GetSource(0);
|
||||
|
||||
Span<Operation> uses = GetUses(ref buffer, dest);
|
||||
Span<Operation> uses = dest.GetUses(ref buffer);
|
||||
|
||||
foreach (Operation use in uses)
|
||||
{
|
||||
@ -231,12 +217,12 @@ namespace ARMeilleure.CodeGen.Optimizations
|
||||
|
||||
private static bool IsUnused(Operation node)
|
||||
{
|
||||
return DestIsLocalVar(node) && node.Destination.UsesCount == 0 && !HasSideEffects(node);
|
||||
return DestIsSingleLocalVar(node) && node.Destination.UsesCount == 0 && !HasSideEffects(node);
|
||||
}
|
||||
|
||||
private static bool DestIsLocalVar(Operation node)
|
||||
private static bool DestIsSingleLocalVar(Operation node)
|
||||
{
|
||||
return node.Destination != default && node.Destination.Kind == OperandKind.LocalVariable;
|
||||
return node.DestinationsCount == 1 && node.Destination.Kind == OperandKind.LocalVariable;
|
||||
}
|
||||
|
||||
private static bool HasSideEffects(Operation node)
|
||||
|
@ -17,8 +17,6 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
|
||||
private const int InstructionGap = 2;
|
||||
private const int InstructionGapMask = InstructionGap - 1;
|
||||
|
||||
private const int RegistersCount = 16;
|
||||
|
||||
private HashSet<int> _blockEdges;
|
||||
private LiveRange[] _blockRanges;
|
||||
private BitMap[] _blockLiveIn;
|
||||
@ -59,7 +57,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
|
||||
|
||||
void PopulateFreePositions(RegisterType type, out int[] positions, out int count)
|
||||
{
|
||||
positions = new int[RegistersCount];
|
||||
positions = new int[masks.RegistersCount];
|
||||
count = BitOperations.PopCount((uint)masks.GetAvailableRegisters(type));
|
||||
|
||||
int mask = masks.GetAvailableRegisters(type);
|
||||
@ -115,7 +113,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
|
||||
StackAllocator stackAlloc,
|
||||
RegisterMasks regMasks)
|
||||
{
|
||||
NumberLocals(cfg);
|
||||
NumberLocals(cfg, regMasks.RegistersCount);
|
||||
|
||||
var context = new AllocationContext(stackAlloc, regMasks, _intervals.Count);
|
||||
|
||||
@ -134,22 +132,25 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
|
||||
{
|
||||
context.Active.Set(index);
|
||||
|
||||
if (current.Register.Type == RegisterType.Integer)
|
||||
if (current.IsFixedAndUsed)
|
||||
{
|
||||
context.IntUsedRegisters |= 1 << current.Register.Index;
|
||||
}
|
||||
else /* if (interval.Register.Type == RegisterType.Vector) */
|
||||
{
|
||||
context.VecUsedRegisters |= 1 << current.Register.Index;
|
||||
if (current.Register.Type == RegisterType.Integer)
|
||||
{
|
||||
context.IntUsedRegisters |= 1 << current.Register.Index;
|
||||
}
|
||||
else /* if (interval.Register.Type == RegisterType.Vector) */
|
||||
{
|
||||
context.VecUsedRegisters |= 1 << current.Register.Index;
|
||||
}
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
AllocateInterval(context, current, index);
|
||||
AllocateInterval(context, current, index, regMasks.RegistersCount);
|
||||
}
|
||||
|
||||
for (int index = RegistersCount * 2; index < _intervals.Count; index++)
|
||||
for (int index = regMasks.RegistersCount * 2; index < _intervals.Count; index++)
|
||||
{
|
||||
if (!_intervals[index].IsSpilled)
|
||||
{
|
||||
@ -163,7 +164,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
|
||||
return new AllocationResult(context.IntUsedRegisters, context.VecUsedRegisters, context.StackAlloc.TotalSize);
|
||||
}
|
||||
|
||||
private void AllocateInterval(AllocationContext context, LiveInterval current, int cIndex)
|
||||
private void AllocateInterval(AllocationContext context, LiveInterval current, int cIndex, int registersCount)
|
||||
{
|
||||
// Check active intervals that already ended.
|
||||
foreach (int iIndex in context.Active)
|
||||
@ -199,17 +200,17 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
|
||||
}
|
||||
}
|
||||
|
||||
if (!TryAllocateRegWithoutSpill(context, current, cIndex))
|
||||
if (!TryAllocateRegWithoutSpill(context, current, cIndex, registersCount))
|
||||
{
|
||||
AllocateRegWithSpill(context, current, cIndex);
|
||||
AllocateRegWithSpill(context, current, cIndex, registersCount);
|
||||
}
|
||||
}
|
||||
|
||||
private bool TryAllocateRegWithoutSpill(AllocationContext context, LiveInterval current, int cIndex)
|
||||
private bool TryAllocateRegWithoutSpill(AllocationContext context, LiveInterval current, int cIndex, int registersCount)
|
||||
{
|
||||
RegisterType regType = current.Local.Type.ToRegisterType();
|
||||
|
||||
Span<int> freePositions = stackalloc int[RegistersCount];
|
||||
Span<int> freePositions = stackalloc int[registersCount];
|
||||
|
||||
context.GetFreePositions(regType, freePositions, out int freePositionsCount);
|
||||
|
||||
@ -278,7 +279,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
|
||||
{
|
||||
Debug.Assert(splitChild.GetStart() > current.GetStart(), "Split interval has an invalid start position.");
|
||||
|
||||
InsertInterval(splitChild);
|
||||
InsertInterval(splitChild, registersCount);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -302,12 +303,12 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
|
||||
return true;
|
||||
}
|
||||
|
||||
private void AllocateRegWithSpill(AllocationContext context, LiveInterval current, int cIndex)
|
||||
private void AllocateRegWithSpill(AllocationContext context, LiveInterval current, int cIndex, int registersCount)
|
||||
{
|
||||
RegisterType regType = current.Local.Type.ToRegisterType();
|
||||
|
||||
Span<int> usePositions = stackalloc int[RegistersCount];
|
||||
Span<int> blockedPositions = stackalloc int[RegistersCount];
|
||||
Span<int> usePositions = stackalloc int[registersCount];
|
||||
Span<int> blockedPositions = stackalloc int[registersCount];
|
||||
|
||||
context.GetFreePositions(regType, usePositions, out _);
|
||||
context.GetFreePositions(regType, blockedPositions, out _);
|
||||
@ -386,7 +387,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
|
||||
|
||||
Debug.Assert(splitChild.GetStart() > current.GetStart(), "Split interval has an invalid start position.");
|
||||
|
||||
InsertInterval(splitChild);
|
||||
InsertInterval(splitChild, registersCount);
|
||||
|
||||
Spill(context, current);
|
||||
}
|
||||
@ -396,7 +397,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
|
||||
// so we only need to split the intervals using the selected register.
|
||||
current.Register = new Register(selectedReg, regType);
|
||||
|
||||
SplitAndSpillOverlappingIntervals(context, current);
|
||||
SplitAndSpillOverlappingIntervals(context, current, registersCount);
|
||||
|
||||
context.Active.Set(cIndex);
|
||||
}
|
||||
@ -417,14 +418,14 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
|
||||
{
|
||||
Debug.Assert(splitChild.GetStart() > current.GetStart(), "Split interval has an invalid start position.");
|
||||
|
||||
InsertInterval(splitChild);
|
||||
InsertInterval(splitChild, registersCount);
|
||||
}
|
||||
else
|
||||
{
|
||||
Spill(context, splitChild);
|
||||
}
|
||||
|
||||
SplitAndSpillOverlappingIntervals(context, current);
|
||||
SplitAndSpillOverlappingIntervals(context, current, registersCount);
|
||||
|
||||
context.Active.Set(cIndex);
|
||||
}
|
||||
@ -460,7 +461,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
|
||||
return selected;
|
||||
}
|
||||
|
||||
private void SplitAndSpillOverlappingIntervals(AllocationContext context, LiveInterval current)
|
||||
private void SplitAndSpillOverlappingIntervals(AllocationContext context, LiveInterval current, int registersCount)
|
||||
{
|
||||
foreach (int iIndex in context.Active)
|
||||
{
|
||||
@ -468,7 +469,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
|
||||
|
||||
if (!interval.IsFixed && interval.Register == current.Register)
|
||||
{
|
||||
SplitAndSpillOverlappingInterval(context, current, interval);
|
||||
SplitAndSpillOverlappingInterval(context, current, interval, registersCount);
|
||||
|
||||
context.Active.Clear(iIndex);
|
||||
}
|
||||
@ -480,7 +481,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
|
||||
|
||||
if (!interval.IsFixed && interval.Register == current.Register && interval.Overlaps(current))
|
||||
{
|
||||
SplitAndSpillOverlappingInterval(context, current, interval);
|
||||
SplitAndSpillOverlappingInterval(context, current, interval, registersCount);
|
||||
|
||||
context.Inactive.Clear(iIndex);
|
||||
}
|
||||
@ -490,7 +491,8 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
|
||||
private void SplitAndSpillOverlappingInterval(
|
||||
AllocationContext context,
|
||||
LiveInterval current,
|
||||
LiveInterval interval)
|
||||
LiveInterval interval,
|
||||
int registersCount)
|
||||
{
|
||||
// If there's a next use after the start of the current interval,
|
||||
// we need to split the spilled interval twice, and re-insert it
|
||||
@ -522,7 +524,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
|
||||
splitChild = right;
|
||||
}
|
||||
|
||||
InsertInterval(splitChild);
|
||||
InsertInterval(splitChild, registersCount);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -530,13 +532,13 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
|
||||
}
|
||||
}
|
||||
|
||||
private void InsertInterval(LiveInterval interval)
|
||||
private void InsertInterval(LiveInterval interval, int registersCount)
|
||||
{
|
||||
Debug.Assert(interval.UsesCount != 0, "Trying to insert a interval without uses.");
|
||||
Debug.Assert(!interval.IsEmpty, "Trying to insert a empty interval.");
|
||||
Debug.Assert(!interval.IsSpilled, "Trying to insert a spilled interval.");
|
||||
|
||||
int startIndex = RegistersCount * 2;
|
||||
int startIndex = registersCount * 2;
|
||||
|
||||
int insertIndex = _intervals.BinarySearch(startIndex, _intervals.Count - startIndex, interval, null);
|
||||
|
||||
@ -790,12 +792,12 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
|
||||
return _operationNodes[position / InstructionGap];
|
||||
}
|
||||
|
||||
private void NumberLocals(ControlFlowGraph cfg)
|
||||
private void NumberLocals(ControlFlowGraph cfg, int registersCount)
|
||||
{
|
||||
_operationNodes = new List<(IntrusiveList<Operation>, Operation)>();
|
||||
_intervals = new List<LiveInterval>();
|
||||
|
||||
for (int index = 0; index < RegistersCount; index++)
|
||||
for (int index = 0; index < registersCount; index++)
|
||||
{
|
||||
_intervals.Add(new LiveInterval(new Register(index, RegisterType.Integer)));
|
||||
_intervals.Add(new LiveInterval(new Register(index, RegisterType.Vector)));
|
||||
@ -1041,6 +1043,11 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
|
||||
{
|
||||
LiveInterval interval = _intervals[GetOperandId(dest)];
|
||||
|
||||
if (interval.IsFixed)
|
||||
{
|
||||
interval.IsFixedAndUsed = true;
|
||||
}
|
||||
|
||||
interval.SetStart(operationPos + 1);
|
||||
interval.AddUsePosition(operationPos + 1);
|
||||
}
|
||||
|
@ -27,6 +27,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
|
||||
public Register Register;
|
||||
|
||||
public bool IsFixed;
|
||||
public bool IsFixedAndUsed;
|
||||
}
|
||||
|
||||
private readonly Data* _data;
|
||||
@ -44,6 +45,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
|
||||
public ref int SpillOffset => ref _data->SpillOffset;
|
||||
|
||||
public bool IsFixed => _data->IsFixed;
|
||||
public ref bool IsFixedAndUsed => ref _data->IsFixedAndUsed;
|
||||
public bool IsEmpty => FirstRange == default;
|
||||
public bool IsSplit => Children.Count != 0;
|
||||
public bool IsSpilled => SpillOffset != -1;
|
||||
@ -114,7 +116,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
|
||||
}
|
||||
else
|
||||
{
|
||||
FirstRange = new LiveRange(position, position + 1);
|
||||
FirstRange = new LiveRange(position, position + 1);
|
||||
End = position + 1;
|
||||
}
|
||||
}
|
||||
|
@ -11,6 +11,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
|
||||
public int VecCallerSavedRegisters { get; }
|
||||
public int IntCalleeSavedRegisters { get; }
|
||||
public int VecCalleeSavedRegisters { get; }
|
||||
public int RegistersCount { get; }
|
||||
|
||||
public RegisterMasks(
|
||||
int intAvailableRegisters,
|
||||
@ -18,7 +19,8 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
|
||||
int intCallerSavedRegisters,
|
||||
int vecCallerSavedRegisters,
|
||||
int intCalleeSavedRegisters,
|
||||
int vecCalleeSavedRegisters)
|
||||
int vecCalleeSavedRegisters,
|
||||
int registersCount)
|
||||
{
|
||||
IntAvailableRegisters = intAvailableRegisters;
|
||||
VecAvailableRegisters = vecAvailableRegisters;
|
||||
@ -26,6 +28,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
|
||||
VecCallerSavedRegisters = vecCallerSavedRegisters;
|
||||
IntCalleeSavedRegisters = intCalleeSavedRegisters;
|
||||
VecCalleeSavedRegisters = vecCalleeSavedRegisters;
|
||||
RegistersCount = registersCount;
|
||||
}
|
||||
|
||||
public int GetAvailableRegisters(RegisterType type)
|
||||
|
@ -16,6 +16,7 @@ namespace ARMeilleure.CodeGen.X86
|
||||
{
|
||||
static class CodeGenerator
|
||||
{
|
||||
private const int RegistersCount = 16;
|
||||
private const int PageSize = 0x1000;
|
||||
private const int StackGuardSize = 0x2000;
|
||||
|
||||
@ -143,7 +144,8 @@ namespace ARMeilleure.CodeGen.X86
|
||||
CallingConvention.GetIntCallerSavedRegisters(),
|
||||
CallingConvention.GetVecCallerSavedRegisters(),
|
||||
CallingConvention.GetIntCalleeSavedRegisters(),
|
||||
CallingConvention.GetVecCalleeSavedRegisters());
|
||||
CallingConvention.GetVecCalleeSavedRegisters(),
|
||||
RegistersCount);
|
||||
|
||||
AllocationResult allocResult = regAlloc.RunPass(cfg, stackAlloc, regMasks);
|
||||
|
||||
|
@ -5,8 +5,6 @@ namespace ARMeilleure.CodeGen.X86
|
||||
{
|
||||
static class IntrinsicTable
|
||||
{
|
||||
private const int BadOp = 0;
|
||||
|
||||
private static IntrinsicInfo[] _intrinTable;
|
||||
|
||||
static IntrinsicTable()
|
||||
|
@ -1339,7 +1339,7 @@ namespace ARMeilleure.Decoders
|
||||
|
||||
private static void SetT32(string encoding, InstName name, InstEmitter emitter, MakeOp makeOp)
|
||||
{
|
||||
string reversedEncoding = encoding.Substring(16) + encoding.Substring(0, 16);
|
||||
string reversedEncoding = $"{encoding.AsSpan(16)}{encoding.AsSpan(0, 16)}";
|
||||
MakeOp reversedMakeOp =
|
||||
(inst, address, opCode)
|
||||
=> makeOp(inst, address, (int)BitOperations.RotateRight((uint)opCode, 16));
|
||||
@ -1353,7 +1353,7 @@ namespace ARMeilleure.Decoders
|
||||
string thumbEncoding = encoding;
|
||||
if (thumbEncoding.StartsWith("<<<<"))
|
||||
{
|
||||
thumbEncoding = "1110" + thumbEncoding.Substring(4);
|
||||
thumbEncoding = $"1110{thumbEncoding.AsSpan(4)}";
|
||||
}
|
||||
SetT32(thumbEncoding, name, emitter, makeOpT32);
|
||||
}
|
||||
@ -1365,19 +1365,19 @@ namespace ARMeilleure.Decoders
|
||||
string thumbEncoding = encoding;
|
||||
if (thumbEncoding.StartsWith("11110100"))
|
||||
{
|
||||
thumbEncoding = "11111001" + encoding.Substring(8);
|
||||
thumbEncoding = $"11111001{encoding.AsSpan(8)}";
|
||||
}
|
||||
else if (thumbEncoding.StartsWith("1111001x"))
|
||||
{
|
||||
thumbEncoding = "111x1111" + encoding.Substring(8);
|
||||
thumbEncoding = $"111x1111{encoding.AsSpan(8)}";
|
||||
}
|
||||
else if (thumbEncoding.StartsWith("11110010"))
|
||||
{
|
||||
thumbEncoding = "11101111" + encoding.Substring(8);
|
||||
thumbEncoding = $"11101111{encoding.AsSpan(8)}";
|
||||
}
|
||||
else if (thumbEncoding.StartsWith("11110011"))
|
||||
{
|
||||
thumbEncoding = "11111111" + encoding.Substring(8);
|
||||
thumbEncoding = $"11111111{encoding.AsSpan(8)}";
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1,9 +1,8 @@
|
||||
using ARMeilleure.Decoders;
|
||||
using ARMeilleure.IntermediateRepresentation;
|
||||
using ARMeilleure.Translation;
|
||||
|
||||
using static ARMeilleure.Instructions.InstEmitHelper;
|
||||
using static ARMeilleure.Instructions.InstEmitHashHelper;
|
||||
using static ARMeilleure.Instructions.InstEmitHelper;
|
||||
|
||||
namespace ARMeilleure.Instructions
|
||||
{
|
||||
|
@ -4,9 +4,8 @@ using ARMeilleure.IntermediateRepresentation;
|
||||
using ARMeilleure.Translation;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
|
||||
using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
|
||||
using static ARMeilleure.Instructions.InstEmitSimdHelper;
|
||||
using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
|
||||
|
||||
namespace ARMeilleure.Instructions
|
||||
{
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -2,6 +2,7 @@
|
||||
using ARMeilleure.IntermediateRepresentation;
|
||||
using ARMeilleure.Translation;
|
||||
using System;
|
||||
|
||||
using static ARMeilleure.Instructions.InstEmitFlowHelper;
|
||||
using static ARMeilleure.Instructions.InstEmitHelper;
|
||||
using static ARMeilleure.Instructions.InstEmitSimdHelper;
|
||||
@ -30,7 +31,11 @@ namespace ARMeilleure.Instructions
|
||||
{
|
||||
OpCode32SimdS op = (OpCode32SimdS)context.CurrOp;
|
||||
|
||||
if (Optimizations.FastFP && Optimizations.UseSse2)
|
||||
if (Optimizations.FastFP && Optimizations.UseAdvSimd)
|
||||
{
|
||||
InstEmitSimdHelper32Arm64.EmitScalarUnaryOpF32(context, Intrinsic.Arm64FabsS);
|
||||
}
|
||||
else if (Optimizations.FastFP && Optimizations.UseSse2)
|
||||
{
|
||||
EmitScalarUnaryOpSimd32(context, (m) =>
|
||||
{
|
||||
@ -49,7 +54,11 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
if (op.F)
|
||||
{
|
||||
if (Optimizations.FastFP && Optimizations.UseSse2)
|
||||
if (Optimizations.FastFP && Optimizations.UseAdvSimd)
|
||||
{
|
||||
InstEmitSimdHelper32Arm64.EmitVectorUnaryOpF32(context, Intrinsic.Arm64FabsV);
|
||||
}
|
||||
else if (Optimizations.FastFP && Optimizations.UseSse2)
|
||||
{
|
||||
EmitVectorUnaryOpSimd32(context, (m) =>
|
||||
{
|
||||
@ -76,7 +85,11 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
public static void Vadd_S(ArmEmitterContext context)
|
||||
{
|
||||
if (Optimizations.FastFP && Optimizations.UseSse2)
|
||||
if (Optimizations.FastFP && Optimizations.UseAdvSimd)
|
||||
{
|
||||
InstEmitSimdHelper32Arm64.EmitScalarBinaryOpF32(context, Intrinsic.Arm64FaddS);
|
||||
}
|
||||
else if (Optimizations.FastFP && Optimizations.UseSse2)
|
||||
{
|
||||
EmitScalarBinaryOpF32(context, Intrinsic.X86Addss, Intrinsic.X86Addsd);
|
||||
}
|
||||
@ -92,7 +105,11 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
public static void Vadd_V(ArmEmitterContext context)
|
||||
{
|
||||
if (Optimizations.FastFP && Optimizations.UseSse2)
|
||||
if (Optimizations.FastFP && Optimizations.UseAdvSimd)
|
||||
{
|
||||
InstEmitSimdHelper32Arm64.EmitVectorBinaryOpF32(context, Intrinsic.Arm64FaddV);
|
||||
}
|
||||
else if (Optimizations.FastFP && Optimizations.UseSse2)
|
||||
{
|
||||
EmitVectorBinaryOpF32(context, Intrinsic.X86Addps, Intrinsic.X86Addpd);
|
||||
}
|
||||
@ -280,7 +297,11 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
public static void Vfma_S(ArmEmitterContext context) // Fused.
|
||||
{
|
||||
if (Optimizations.FastFP && Optimizations.UseFma)
|
||||
if (Optimizations.FastFP && Optimizations.UseAdvSimd)
|
||||
{
|
||||
InstEmitSimdHelper32Arm64.EmitScalarTernaryOpF32(context, Intrinsic.Arm64FmaddS);
|
||||
}
|
||||
else if (Optimizations.FastFP && Optimizations.UseFma)
|
||||
{
|
||||
EmitScalarTernaryOpF32(context, Intrinsic.X86Vfmadd231ss, Intrinsic.X86Vfmadd231sd);
|
||||
}
|
||||
@ -299,7 +320,11 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
public static void Vfma_V(ArmEmitterContext context) // Fused.
|
||||
{
|
||||
if (Optimizations.FastFP && Optimizations.UseFma)
|
||||
if (Optimizations.FastFP && Optimizations.UseAdvSimd)
|
||||
{
|
||||
InstEmitSimdHelper32Arm64.EmitVectorTernaryOpF32(context, Intrinsic.Arm64FmlaV);
|
||||
}
|
||||
else if (Optimizations.FastFP && Optimizations.UseFma)
|
||||
{
|
||||
EmitVectorTernaryOpF32(context, Intrinsic.X86Vfmadd231ps);
|
||||
}
|
||||
@ -314,7 +339,11 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
public static void Vfms_S(ArmEmitterContext context) // Fused.
|
||||
{
|
||||
if (Optimizations.FastFP && Optimizations.UseFma)
|
||||
if (Optimizations.FastFP && Optimizations.UseAdvSimd)
|
||||
{
|
||||
InstEmitSimdHelper32Arm64.EmitScalarTernaryOpF32(context, Intrinsic.Arm64FmsubS);
|
||||
}
|
||||
else if (Optimizations.FastFP && Optimizations.UseFma)
|
||||
{
|
||||
EmitScalarTernaryOpF32(context, Intrinsic.X86Vfnmadd231ss, Intrinsic.X86Vfnmadd231sd);
|
||||
}
|
||||
@ -333,7 +362,11 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
public static void Vfms_V(ArmEmitterContext context) // Fused.
|
||||
{
|
||||
if (Optimizations.FastFP && Optimizations.UseFma)
|
||||
if (Optimizations.FastFP && Optimizations.UseAdvSimd)
|
||||
{
|
||||
InstEmitSimdHelper32Arm64.EmitVectorTernaryOpF32(context, Intrinsic.Arm64FmlsV);
|
||||
}
|
||||
else if (Optimizations.FastFP && Optimizations.UseFma)
|
||||
{
|
||||
EmitVectorTernaryOpF32(context, Intrinsic.X86Vfnmadd231ps);
|
||||
}
|
||||
@ -348,7 +381,11 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
public static void Vfnma_S(ArmEmitterContext context) // Fused.
|
||||
{
|
||||
if (Optimizations.FastFP && Optimizations.UseFma)
|
||||
if (Optimizations.FastFP && Optimizations.UseAdvSimd)
|
||||
{
|
||||
InstEmitSimdHelper32Arm64.EmitScalarTernaryOpF32(context, Intrinsic.Arm64FnmaddS);
|
||||
}
|
||||
else if (Optimizations.FastFP && Optimizations.UseFma)
|
||||
{
|
||||
EmitScalarTernaryOpF32(context, Intrinsic.X86Vfnmsub231ss, Intrinsic.X86Vfnmsub231sd);
|
||||
}
|
||||
@ -367,7 +404,11 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
public static void Vfnms_S(ArmEmitterContext context) // Fused.
|
||||
{
|
||||
if (Optimizations.FastFP && Optimizations.UseFma)
|
||||
if (Optimizations.FastFP && Optimizations.UseAdvSimd)
|
||||
{
|
||||
InstEmitSimdHelper32Arm64.EmitScalarTernaryOpF32(context, Intrinsic.Arm64FnmsubS);
|
||||
}
|
||||
else if (Optimizations.FastFP && Optimizations.UseFma)
|
||||
{
|
||||
EmitScalarTernaryOpF32(context, Intrinsic.X86Vfmsub231ss, Intrinsic.X86Vfmsub231sd);
|
||||
}
|
||||
@ -419,7 +460,11 @@ namespace ARMeilleure.Instructions
|
||||
{
|
||||
OpCode32SimdS op = (OpCode32SimdS)context.CurrOp;
|
||||
|
||||
if (Optimizations.UseSse2)
|
||||
if (Optimizations.FastFP && Optimizations.UseAdvSimd)
|
||||
{
|
||||
InstEmitSimdHelper32Arm64.EmitScalarUnaryOpF32(context, Intrinsic.Arm64FnegS);
|
||||
}
|
||||
else if (Optimizations.UseSse2)
|
||||
{
|
||||
EmitScalarUnaryOpSimd32(context, (m) =>
|
||||
{
|
||||
@ -445,7 +490,11 @@ namespace ARMeilleure.Instructions
|
||||
{
|
||||
OpCode32SimdRegS op = (OpCode32SimdRegS)context.CurrOp;
|
||||
|
||||
if (Optimizations.UseSse2)
|
||||
if (Optimizations.FastFP && Optimizations.UseAdvSimd)
|
||||
{
|
||||
InstEmitSimdHelper32Arm64.EmitScalarBinaryOpF32(context, Intrinsic.Arm64FnmulS);
|
||||
}
|
||||
else if (Optimizations.UseSse2)
|
||||
{
|
||||
EmitScalarBinaryOpSimd32(context, (n, m) =>
|
||||
{
|
||||
@ -473,7 +522,11 @@ namespace ARMeilleure.Instructions
|
||||
{
|
||||
OpCode32SimdRegS op = (OpCode32SimdRegS)context.CurrOp;
|
||||
|
||||
if (Optimizations.FastFP && Optimizations.UseSse2)
|
||||
if (Optimizations.FastFP && Optimizations.UseAdvSimd)
|
||||
{
|
||||
InstEmitSimdHelper32Arm64.EmitScalarTernaryOpF32(context, Intrinsic.Arm64FnmaddS);
|
||||
}
|
||||
else if (Optimizations.FastFP && Optimizations.UseSse2)
|
||||
{
|
||||
EmitScalarTernaryOpF32(context, Intrinsic.X86Mulss, Intrinsic.X86Mulsd, Intrinsic.X86Subss, Intrinsic.X86Subsd, isNegD: true);
|
||||
}
|
||||
@ -498,7 +551,11 @@ namespace ARMeilleure.Instructions
|
||||
{
|
||||
OpCode32SimdRegS op = (OpCode32SimdRegS)context.CurrOp;
|
||||
|
||||
if (Optimizations.FastFP && Optimizations.UseSse2)
|
||||
if (Optimizations.FastFP && Optimizations.UseAdvSimd)
|
||||
{
|
||||
InstEmitSimdHelper32Arm64.EmitScalarTernaryOpF32(context, Intrinsic.Arm64FnmsubS);
|
||||
}
|
||||
else if (Optimizations.FastFP && Optimizations.UseSse2)
|
||||
{
|
||||
EmitScalarTernaryOpF32(context, Intrinsic.X86Mulss, Intrinsic.X86Mulsd, Intrinsic.X86Addss, Intrinsic.X86Addsd, isNegD: true);
|
||||
}
|
||||
@ -525,7 +582,11 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
if (op.F)
|
||||
{
|
||||
if (Optimizations.FastFP && Optimizations.UseSse2)
|
||||
if (Optimizations.FastFP && Optimizations.UseAdvSimd)
|
||||
{
|
||||
InstEmitSimdHelper32Arm64.EmitVectorUnaryOpF32(context, Intrinsic.Arm64FnegV);
|
||||
}
|
||||
else if (Optimizations.FastFP && Optimizations.UseSse2)
|
||||
{
|
||||
EmitVectorUnaryOpSimd32(context, (m) =>
|
||||
{
|
||||
@ -554,7 +615,11 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
public static void Vdiv_S(ArmEmitterContext context)
|
||||
{
|
||||
if (Optimizations.FastFP && Optimizations.UseSse2)
|
||||
if (Optimizations.FastFP && Optimizations.UseAdvSimd)
|
||||
{
|
||||
InstEmitSimdHelper32Arm64.EmitScalarBinaryOpF32(context, Intrinsic.Arm64FdivS);
|
||||
}
|
||||
else if (Optimizations.FastFP && Optimizations.UseSse2)
|
||||
{
|
||||
EmitScalarBinaryOpF32(context, Intrinsic.X86Divss, Intrinsic.X86Divsd);
|
||||
}
|
||||
@ -573,7 +638,11 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
public static void Vmaxnm_S(ArmEmitterContext context)
|
||||
{
|
||||
if (Optimizations.FastFP && Optimizations.UseSse41)
|
||||
if (Optimizations.FastFP && Optimizations.UseAdvSimd)
|
||||
{
|
||||
InstEmitSimdHelper32Arm64.EmitScalarBinaryOpF32(context, Intrinsic.Arm64FmaxnmS);
|
||||
}
|
||||
else if (Optimizations.FastFP && Optimizations.UseSse41)
|
||||
{
|
||||
EmitSse41MaxMinNumOpF32(context, true, true);
|
||||
}
|
||||
@ -585,7 +654,11 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
public static void Vmaxnm_V(ArmEmitterContext context)
|
||||
{
|
||||
if (Optimizations.FastFP && Optimizations.UseSse41)
|
||||
if (Optimizations.FastFP && Optimizations.UseAdvSimd)
|
||||
{
|
||||
InstEmitSimdHelper32Arm64.EmitVectorBinaryOpF32(context, Intrinsic.Arm64FmaxnmV);
|
||||
}
|
||||
else if (Optimizations.FastFP && Optimizations.UseSse41)
|
||||
{
|
||||
EmitSse41MaxMinNumOpF32(context, true, false);
|
||||
}
|
||||
@ -597,7 +670,11 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
public static void Vminnm_S(ArmEmitterContext context)
|
||||
{
|
||||
if (Optimizations.FastFP && Optimizations.UseSse41)
|
||||
if (Optimizations.FastFP && Optimizations.UseAdvSimd)
|
||||
{
|
||||
InstEmitSimdHelper32Arm64.EmitScalarBinaryOpF32(context, Intrinsic.Arm64FminnmS);
|
||||
}
|
||||
else if (Optimizations.FastFP && Optimizations.UseSse41)
|
||||
{
|
||||
EmitSse41MaxMinNumOpF32(context, false, true);
|
||||
}
|
||||
@ -609,7 +686,11 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
public static void Vminnm_V(ArmEmitterContext context)
|
||||
{
|
||||
if (Optimizations.FastFP && Optimizations.UseSse41)
|
||||
if (Optimizations.FastFP && Optimizations.UseAdvSimd)
|
||||
{
|
||||
InstEmitSimdHelper32Arm64.EmitVectorBinaryOpF32(context, Intrinsic.Arm64FminnmV);
|
||||
}
|
||||
else if (Optimizations.FastFP && Optimizations.UseSse41)
|
||||
{
|
||||
EmitSse41MaxMinNumOpF32(context, false, false);
|
||||
}
|
||||
@ -621,7 +702,11 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
public static void Vmax_V(ArmEmitterContext context)
|
||||
{
|
||||
if (Optimizations.FastFP && Optimizations.UseSse2)
|
||||
if (Optimizations.FastFP && Optimizations.UseAdvSimd)
|
||||
{
|
||||
InstEmitSimdHelper32Arm64.EmitVectorBinaryOpF32(context, Intrinsic.Arm64FmaxV);
|
||||
}
|
||||
else if (Optimizations.FastFP && Optimizations.UseSse2)
|
||||
{
|
||||
EmitVectorBinaryOpF32(context, Intrinsic.X86Maxps, Intrinsic.X86Maxpd);
|
||||
}
|
||||
@ -664,7 +749,11 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
public static void Vmin_V(ArmEmitterContext context)
|
||||
{
|
||||
if (Optimizations.FastFP && Optimizations.UseSse2)
|
||||
if (Optimizations.FastFP && Optimizations.UseAdvSimd)
|
||||
{
|
||||
InstEmitSimdHelper32Arm64.EmitVectorBinaryOpF32(context, Intrinsic.Arm64FminV);
|
||||
}
|
||||
else if (Optimizations.FastFP && Optimizations.UseSse2)
|
||||
{
|
||||
EmitVectorBinaryOpF32(context, Intrinsic.X86Minps, Intrinsic.X86Minpd);
|
||||
}
|
||||
@ -707,7 +796,11 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
public static void Vmla_S(ArmEmitterContext context)
|
||||
{
|
||||
if (Optimizations.FastFP && Optimizations.UseSse2)
|
||||
if (Optimizations.FastFP && Optimizations.UseAdvSimd)
|
||||
{
|
||||
InstEmitSimdHelper32Arm64.EmitScalarTernaryOpF32(context, Intrinsic.Arm64FmaddS);
|
||||
}
|
||||
else if (Optimizations.FastFP && Optimizations.UseSse2)
|
||||
{
|
||||
EmitScalarTernaryOpF32(context, Intrinsic.X86Mulss, Intrinsic.X86Mulsd, Intrinsic.X86Addss, Intrinsic.X86Addsd);
|
||||
}
|
||||
@ -730,7 +823,11 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
public static void Vmla_V(ArmEmitterContext context)
|
||||
{
|
||||
if (Optimizations.FastFP && Optimizations.UseSse2)
|
||||
if (Optimizations.FastFP && Optimizations.UseAdvSimd)
|
||||
{
|
||||
InstEmitSimdHelper32Arm64.EmitVectorTernaryOpF32(context, Intrinsic.Arm64FmlaV);
|
||||
}
|
||||
else if (Optimizations.FastFP && Optimizations.UseSse2)
|
||||
{
|
||||
EmitVectorTernaryOpF32(context, Intrinsic.X86Mulps, Intrinsic.X86Mulpd, Intrinsic.X86Addps, Intrinsic.X86Addpd);
|
||||
}
|
||||
@ -786,7 +883,11 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
public static void Vmls_S(ArmEmitterContext context)
|
||||
{
|
||||
if (Optimizations.FastFP && Optimizations.UseSse2)
|
||||
if (Optimizations.FastFP && Optimizations.UseAdvSimd)
|
||||
{
|
||||
InstEmitSimdHelper32Arm64.EmitScalarTernaryOpF32(context, Intrinsic.Arm64FmlsV);
|
||||
}
|
||||
else if (Optimizations.FastFP && Optimizations.UseSse2)
|
||||
{
|
||||
EmitScalarTernaryOpF32(context, Intrinsic.X86Mulss, Intrinsic.X86Mulsd, Intrinsic.X86Subss, Intrinsic.X86Subsd);
|
||||
}
|
||||
@ -809,7 +910,11 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
public static void Vmls_V(ArmEmitterContext context)
|
||||
{
|
||||
if (Optimizations.FastFP && Optimizations.UseSse2)
|
||||
if (Optimizations.FastFP && Optimizations.UseAdvSimd)
|
||||
{
|
||||
InstEmitSimdHelper32Arm64.EmitVectorTernaryOpF32(context, Intrinsic.Arm64FmlsV);
|
||||
}
|
||||
else if (Optimizations.FastFP && Optimizations.UseSse2)
|
||||
{
|
||||
EmitVectorTernaryOpF32(context, Intrinsic.X86Mulps, Intrinsic.X86Mulpd, Intrinsic.X86Subps, Intrinsic.X86Subpd);
|
||||
}
|
||||
@ -865,7 +970,11 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
public static void Vmul_S(ArmEmitterContext context)
|
||||
{
|
||||
if (Optimizations.FastFP && Optimizations.UseSse2)
|
||||
if (Optimizations.FastFP && Optimizations.UseAdvSimd)
|
||||
{
|
||||
InstEmitSimdHelper32Arm64.EmitScalarBinaryOpF32(context, Intrinsic.Arm64FmulS);
|
||||
}
|
||||
else if (Optimizations.FastFP && Optimizations.UseSse2)
|
||||
{
|
||||
EmitScalarBinaryOpF32(context, Intrinsic.X86Mulss, Intrinsic.X86Mulsd);
|
||||
}
|
||||
@ -884,7 +993,11 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
public static void Vmul_V(ArmEmitterContext context)
|
||||
{
|
||||
if (Optimizations.FastFP && Optimizations.UseSse2)
|
||||
if (Optimizations.FastFP && Optimizations.UseAdvSimd)
|
||||
{
|
||||
InstEmitSimdHelper32Arm64.EmitVectorBinaryOpF32(context, Intrinsic.Arm64FmulV);
|
||||
}
|
||||
else if (Optimizations.FastFP && Optimizations.UseSse2)
|
||||
{
|
||||
EmitVectorBinaryOpF32(context, Intrinsic.X86Mulps, Intrinsic.X86Mulpd);
|
||||
}
|
||||
@ -975,7 +1088,11 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
public static void Vpadd_V(ArmEmitterContext context)
|
||||
{
|
||||
if (Optimizations.FastFP && Optimizations.UseSse2)
|
||||
if (Optimizations.FastFP && Optimizations.UseAdvSimd)
|
||||
{
|
||||
InstEmitSimdHelper32Arm64.EmitVectorPairwiseOpF32(context, Intrinsic.Arm64FaddpV);
|
||||
}
|
||||
else if (Optimizations.FastFP && Optimizations.UseSse2)
|
||||
{
|
||||
EmitSse2VectorPairwiseOpF32(context, Intrinsic.X86Addps);
|
||||
}
|
||||
@ -1008,7 +1125,11 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
public static void Vpmax_V(ArmEmitterContext context)
|
||||
{
|
||||
if (Optimizations.FastFP && Optimizations.UseSse2)
|
||||
if (Optimizations.FastFP && Optimizations.UseAdvSimd)
|
||||
{
|
||||
InstEmitSimdHelper32Arm64.EmitVectorPairwiseOpF32(context, Intrinsic.Arm64FmaxpV);
|
||||
}
|
||||
else if (Optimizations.FastFP && Optimizations.UseSse2)
|
||||
{
|
||||
EmitSse2VectorPairwiseOpF32(context, Intrinsic.X86Maxps);
|
||||
}
|
||||
@ -1038,7 +1159,11 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
public static void Vpmin_V(ArmEmitterContext context)
|
||||
{
|
||||
if (Optimizations.FastFP && Optimizations.UseSse2)
|
||||
if (Optimizations.FastFP && Optimizations.UseAdvSimd)
|
||||
{
|
||||
InstEmitSimdHelper32Arm64.EmitVectorPairwiseOpF32(context, Intrinsic.Arm64FminpV);
|
||||
}
|
||||
else if (Optimizations.FastFP && Optimizations.UseSse2)
|
||||
{
|
||||
EmitSse2VectorPairwiseOpF32(context, Intrinsic.X86Minps);
|
||||
}
|
||||
@ -1217,7 +1342,11 @@ namespace ARMeilleure.Instructions
|
||||
{
|
||||
int sizeF = op.Size & 1;
|
||||
|
||||
if (Optimizations.FastFP && Optimizations.UseSse2 && sizeF == 0)
|
||||
if (Optimizations.FastFP && Optimizations.UseAdvSimd)
|
||||
{
|
||||
InstEmitSimdHelper32Arm64.EmitVectorUnaryOpF32(context, Intrinsic.Arm64FrecpeV);
|
||||
}
|
||||
else if (Optimizations.FastFP && Optimizations.UseSse2 && sizeF == 0)
|
||||
{
|
||||
EmitVectorUnaryOpF32(context, Intrinsic.X86Rcpps, 0);
|
||||
}
|
||||
@ -1237,7 +1366,11 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
public static void Vrecps(ArmEmitterContext context)
|
||||
{
|
||||
if (Optimizations.FastFP && Optimizations.UseSse2)
|
||||
if (Optimizations.FastFP && Optimizations.UseAdvSimd)
|
||||
{
|
||||
InstEmitSimdHelper32Arm64.EmitVectorBinaryOpF32(context, Intrinsic.Arm64FrecpsV);
|
||||
}
|
||||
else if (Optimizations.FastFP && Optimizations.UseSse2)
|
||||
{
|
||||
OpCode32SimdReg op = (OpCode32SimdReg)context.CurrOp;
|
||||
bool single = (op.Size & 1) == 0;
|
||||
@ -1304,7 +1437,11 @@ namespace ARMeilleure.Instructions
|
||||
{
|
||||
int sizeF = op.Size & 1;
|
||||
|
||||
if (Optimizations.FastFP && Optimizations.UseSse2 && sizeF == 0)
|
||||
if (Optimizations.FastFP && Optimizations.UseAdvSimd)
|
||||
{
|
||||
InstEmitSimdHelper32Arm64.EmitVectorUnaryOpF32(context, Intrinsic.Arm64FrsqrteV);
|
||||
}
|
||||
else if (Optimizations.FastFP && Optimizations.UseSse2 && sizeF == 0)
|
||||
{
|
||||
EmitVectorUnaryOpF32(context, Intrinsic.X86Rsqrtps, 0);
|
||||
}
|
||||
@ -1324,7 +1461,11 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
public static void Vrsqrts(ArmEmitterContext context)
|
||||
{
|
||||
if (Optimizations.FastFP && Optimizations.UseSse2)
|
||||
if (Optimizations.FastFP && Optimizations.UseAdvSimd)
|
||||
{
|
||||
InstEmitSimdHelper32Arm64.EmitVectorBinaryOpF32(context, Intrinsic.Arm64FrsqrtsV);
|
||||
}
|
||||
else if (Optimizations.FastFP && Optimizations.UseSse2)
|
||||
{
|
||||
OpCode32SimdReg op = (OpCode32SimdReg)context.CurrOp;
|
||||
bool single = (op.Size & 1) == 0;
|
||||
@ -1393,7 +1534,11 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
public static void Vsqrt_S(ArmEmitterContext context)
|
||||
{
|
||||
if (Optimizations.FastFP && Optimizations.UseSse2)
|
||||
if (Optimizations.FastFP && Optimizations.UseAdvSimd)
|
||||
{
|
||||
InstEmitSimdHelper32Arm64.EmitScalarUnaryOpF32(context, Intrinsic.Arm64FsqrtS);
|
||||
}
|
||||
else if (Optimizations.FastFP && Optimizations.UseSse2)
|
||||
{
|
||||
EmitScalarUnaryOpF32(context, Intrinsic.X86Sqrtss, Intrinsic.X86Sqrtsd);
|
||||
}
|
||||
@ -1408,7 +1553,11 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
public static void Vsub_S(ArmEmitterContext context)
|
||||
{
|
||||
if (Optimizations.FastFP && Optimizations.UseSse2)
|
||||
if (Optimizations.FastFP && Optimizations.UseAdvSimd)
|
||||
{
|
||||
InstEmitSimdHelper32Arm64.EmitScalarBinaryOpF32(context, Intrinsic.Arm64FsubS);
|
||||
}
|
||||
else if (Optimizations.FastFP && Optimizations.UseSse2)
|
||||
{
|
||||
EmitScalarBinaryOpF32(context, Intrinsic.X86Subss, Intrinsic.X86Subsd);
|
||||
}
|
||||
@ -1420,7 +1569,11 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
public static void Vsub_V(ArmEmitterContext context)
|
||||
{
|
||||
if (Optimizations.FastFP && Optimizations.UseSse2)
|
||||
if (Optimizations.FastFP && Optimizations.UseAdvSimd)
|
||||
{
|
||||
InstEmitSimdHelper32Arm64.EmitVectorBinaryOpF32(context, Intrinsic.Arm64FsubV);
|
||||
}
|
||||
else if (Optimizations.FastFP && Optimizations.UseSse2)
|
||||
{
|
||||
EmitVectorBinaryOpF32(context, Intrinsic.X86Subps, Intrinsic.X86Subpd);
|
||||
}
|
||||
|
@ -466,12 +466,26 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
public static void Fcmp_S(ArmEmitterContext context)
|
||||
{
|
||||
EmitFcmpOrFcmpe(context, signalNaNs: false);
|
||||
if (Optimizations.UseAdvSimd)
|
||||
{
|
||||
InstEmitSimdHelperArm64.EmitFcmpOrFcmpe(context, signalNaNs: false);
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitFcmpOrFcmpe(context, signalNaNs: false);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Fcmpe_S(ArmEmitterContext context)
|
||||
{
|
||||
EmitFcmpOrFcmpe(context, signalNaNs: true);
|
||||
if (Optimizations.UseAdvSimd)
|
||||
{
|
||||
InstEmitSimdHelperArm64.EmitFcmpOrFcmpe(context, signalNaNs: true);
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitFcmpOrFcmpe(context, signalNaNs: true);
|
||||
}
|
||||
}
|
||||
|
||||
private static void EmitFccmpOrFccmpe(ArmEmitterContext context, bool signalNaNs)
|
||||
|
@ -17,7 +17,11 @@ namespace ARMeilleure.Instructions
|
||||
{
|
||||
public static void Vceq_V(ArmEmitterContext context)
|
||||
{
|
||||
if (Optimizations.FastFP && Optimizations.UseSse2)
|
||||
if (Optimizations.FastFP && Optimizations.UseAdvSimd)
|
||||
{
|
||||
InstEmitSimdHelper32Arm64.EmitCmpOpF32(context, CmpCondition.Equal, false);
|
||||
}
|
||||
else if (Optimizations.FastFP && Optimizations.UseSse2)
|
||||
{
|
||||
EmitSse2OrAvxCmpOpF32(context, CmpCondition.Equal, false);
|
||||
}
|
||||
@ -38,7 +42,11 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
if (op.F)
|
||||
{
|
||||
if (Optimizations.FastFP && Optimizations.UseSse2)
|
||||
if (Optimizations.FastFP && Optimizations.UseAdvSimd)
|
||||
{
|
||||
InstEmitSimdHelper32Arm64.EmitCmpOpF32(context, CmpCondition.Equal, true);
|
||||
}
|
||||
else if (Optimizations.FastFP && Optimizations.UseSse2)
|
||||
{
|
||||
EmitSse2OrAvxCmpOpF32(context, CmpCondition.Equal, true);
|
||||
}
|
||||
@ -55,7 +63,11 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
public static void Vcge_V(ArmEmitterContext context)
|
||||
{
|
||||
if (Optimizations.FastFP && Optimizations.UseAvx)
|
||||
if (Optimizations.FastFP && Optimizations.UseAdvSimd)
|
||||
{
|
||||
InstEmitSimdHelper32Arm64.EmitCmpOpF32(context, CmpCondition.GreaterThanOrEqual, false);
|
||||
}
|
||||
else if (Optimizations.FastFP && Optimizations.UseAvx)
|
||||
{
|
||||
EmitSse2OrAvxCmpOpF32(context, CmpCondition.GreaterThanOrEqual, false);
|
||||
}
|
||||
@ -78,7 +90,11 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
if (op.F)
|
||||
{
|
||||
if (Optimizations.FastFP && Optimizations.UseAvx)
|
||||
if (Optimizations.FastFP && Optimizations.UseAdvSimd)
|
||||
{
|
||||
InstEmitSimdHelper32Arm64.EmitCmpOpF32(context, CmpCondition.GreaterThanOrEqual, true);
|
||||
}
|
||||
else if (Optimizations.FastFP && Optimizations.UseAvx)
|
||||
{
|
||||
EmitSse2OrAvxCmpOpF32(context, CmpCondition.GreaterThanOrEqual, true);
|
||||
}
|
||||
@ -95,7 +111,11 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
public static void Vcgt_V(ArmEmitterContext context)
|
||||
{
|
||||
if (Optimizations.FastFP && Optimizations.UseAvx)
|
||||
if (Optimizations.FastFP && Optimizations.UseAdvSimd)
|
||||
{
|
||||
InstEmitSimdHelper32Arm64.EmitCmpOpF32(context, CmpCondition.GreaterThan, false);
|
||||
}
|
||||
else if (Optimizations.FastFP && Optimizations.UseAvx)
|
||||
{
|
||||
EmitSse2OrAvxCmpOpF32(context, CmpCondition.GreaterThan, false);
|
||||
}
|
||||
@ -118,7 +138,11 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
if (op.F)
|
||||
{
|
||||
if (Optimizations.FastFP && Optimizations.UseAvx)
|
||||
if (Optimizations.FastFP && Optimizations.UseAdvSimd)
|
||||
{
|
||||
InstEmitSimdHelper32Arm64.EmitCmpOpF32(context, CmpCondition.GreaterThan, true);
|
||||
}
|
||||
else if (Optimizations.FastFP && Optimizations.UseAvx)
|
||||
{
|
||||
EmitSse2OrAvxCmpOpF32(context, CmpCondition.GreaterThan, true);
|
||||
}
|
||||
@ -139,7 +163,11 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
if (op.F)
|
||||
{
|
||||
if (Optimizations.FastFP && Optimizations.UseSse2)
|
||||
if (Optimizations.FastFP && Optimizations.UseAdvSimd)
|
||||
{
|
||||
InstEmitSimdHelper32Arm64.EmitCmpOpF32(context, CmpCondition.LessThanOrEqual, true);
|
||||
}
|
||||
else if (Optimizations.FastFP && Optimizations.UseSse2)
|
||||
{
|
||||
EmitSse2OrAvxCmpOpF32(context, CmpCondition.LessThanOrEqual, true);
|
||||
}
|
||||
@ -160,7 +188,11 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
if (op.F)
|
||||
{
|
||||
if (Optimizations.FastFP && Optimizations.UseSse2)
|
||||
if (Optimizations.FastFP && Optimizations.UseAdvSimd)
|
||||
{
|
||||
InstEmitSimdHelper32Arm64.EmitCmpOpF32(context, CmpCondition.LessThan, true);
|
||||
}
|
||||
else if (Optimizations.FastFP && Optimizations.UseSse2)
|
||||
{
|
||||
EmitSse2OrAvxCmpOpF32(context, CmpCondition.LessThan, true);
|
||||
}
|
||||
@ -247,12 +279,26 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
public static void Vcmp(ArmEmitterContext context)
|
||||
{
|
||||
EmitVcmpOrVcmpe(context, false);
|
||||
if (Optimizations.UseAdvSimd)
|
||||
{
|
||||
InstEmitSimdHelper32Arm64.EmitVcmpOrVcmpe(context, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitVcmpOrVcmpe(context, false);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Vcmpe(ArmEmitterContext context)
|
||||
{
|
||||
EmitVcmpOrVcmpe(context, true);
|
||||
if (Optimizations.UseAdvSimd)
|
||||
{
|
||||
InstEmitSimdHelper32Arm64.EmitVcmpOrVcmpe(context, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitVcmpOrVcmpe(context, true);
|
||||
}
|
||||
}
|
||||
|
||||
private static void EmitVcmpOrVcmpe(ArmEmitterContext context, bool signalNaNs)
|
||||
|
@ -164,7 +164,11 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
public static void Fcvtas_Gp(ArmEmitterContext context)
|
||||
{
|
||||
if (Optimizations.UseSse41)
|
||||
if (Optimizations.UseAdvSimd)
|
||||
{
|
||||
InstEmitSimdHelperArm64.EmitScalarUnaryOpFToGp(context, Intrinsic.Arm64FcvtasGp);
|
||||
}
|
||||
else if (Optimizations.UseSse41)
|
||||
{
|
||||
EmitSse41Fcvts_Gp(context, FPRoundingMode.ToNearestAway, isFixed: false);
|
||||
}
|
||||
@ -176,7 +180,11 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
public static void Fcvtas_S(ArmEmitterContext context)
|
||||
{
|
||||
if (Optimizations.UseSse41)
|
||||
if (Optimizations.UseAdvSimd)
|
||||
{
|
||||
InstEmitSimdHelperArm64.EmitScalarUnaryOpF(context, Intrinsic.Arm64FcvtasS);
|
||||
}
|
||||
else if (Optimizations.UseSse41)
|
||||
{
|
||||
EmitSse41FcvtsOpF(context, FPRoundingMode.ToNearestAway, scalar: true);
|
||||
}
|
||||
@ -188,7 +196,11 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
public static void Fcvtas_V(ArmEmitterContext context)
|
||||
{
|
||||
if (Optimizations.UseSse41)
|
||||
if (Optimizations.UseAdvSimd)
|
||||
{
|
||||
InstEmitSimdHelperArm64.EmitVectorUnaryOpF(context, Intrinsic.Arm64FcvtasS);
|
||||
}
|
||||
else if (Optimizations.UseSse41)
|
||||
{
|
||||
EmitSse41FcvtsOpF(context, FPRoundingMode.ToNearestAway, scalar: false);
|
||||
}
|
||||
@ -200,7 +212,11 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
public static void Fcvtau_Gp(ArmEmitterContext context)
|
||||
{
|
||||
if (Optimizations.UseSse41)
|
||||
if (Optimizations.UseAdvSimd)
|
||||
{
|
||||
InstEmitSimdHelperArm64.EmitScalarUnaryOpFToGp(context, Intrinsic.Arm64FcvtauGp);
|
||||
}
|
||||
else if (Optimizations.UseSse41)
|
||||
{
|
||||
EmitSse41Fcvtu_Gp(context, FPRoundingMode.ToNearestAway, isFixed: false);
|
||||
}
|
||||
@ -212,7 +228,11 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
public static void Fcvtau_S(ArmEmitterContext context)
|
||||
{
|
||||
if (Optimizations.UseSse41)
|
||||
if (Optimizations.UseAdvSimd)
|
||||
{
|
||||
InstEmitSimdHelperArm64.EmitScalarUnaryOpF(context, Intrinsic.Arm64FcvtauS);
|
||||
}
|
||||
else if (Optimizations.UseSse41)
|
||||
{
|
||||
EmitSse41FcvtuOpF(context, FPRoundingMode.ToNearestAway, scalar: true);
|
||||
}
|
||||
@ -224,7 +244,11 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
public static void Fcvtau_V(ArmEmitterContext context)
|
||||
{
|
||||
if (Optimizations.UseSse41)
|
||||
if (Optimizations.UseAdvSimd)
|
||||
{
|
||||
InstEmitSimdHelperArm64.EmitVectorUnaryOpF(context, Intrinsic.Arm64FcvtauV);
|
||||
}
|
||||
else if (Optimizations.UseSse41)
|
||||
{
|
||||
EmitSse41FcvtuOpF(context, FPRoundingMode.ToNearestAway, scalar: false);
|
||||
}
|
||||
@ -240,7 +264,11 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
int sizeF = op.Size & 1;
|
||||
|
||||
if (Optimizations.UseSse2 && sizeF == 1)
|
||||
if (Optimizations.UseAdvSimd)
|
||||
{
|
||||
InstEmitSimdHelperArm64.EmitVectorUnaryOpF(context, Intrinsic.Arm64FcvtlV);
|
||||
}
|
||||
else if (Optimizations.UseSse2 && sizeF == 1)
|
||||
{
|
||||
Operand n = GetVec(op.Rn);
|
||||
|
||||
@ -296,7 +324,11 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
public static void Fcvtms_Gp(ArmEmitterContext context)
|
||||
{
|
||||
if (Optimizations.UseSse41)
|
||||
if (Optimizations.UseAdvSimd)
|
||||
{
|
||||
InstEmitSimdHelperArm64.EmitScalarUnaryOpFToGp(context, Intrinsic.Arm64FcvtmsGp);
|
||||
}
|
||||
else if (Optimizations.UseSse41)
|
||||
{
|
||||
EmitSse41Fcvts_Gp(context, FPRoundingMode.TowardsMinusInfinity, isFixed: false);
|
||||
}
|
||||
@ -308,7 +340,11 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
public static void Fcvtms_V(ArmEmitterContext context)
|
||||
{
|
||||
if (Optimizations.UseSse41)
|
||||
if (Optimizations.UseAdvSimd)
|
||||
{
|
||||
InstEmitSimdHelperArm64.EmitVectorUnaryOpF(context, Intrinsic.Arm64FcvtmsV);
|
||||
}
|
||||
else if (Optimizations.UseSse41)
|
||||
{
|
||||
EmitSse41FcvtsOpF(context, FPRoundingMode.TowardsMinusInfinity, scalar: false);
|
||||
}
|
||||
@ -320,7 +356,11 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
public static void Fcvtmu_Gp(ArmEmitterContext context)
|
||||
{
|
||||
if (Optimizations.UseSse41)
|
||||
if (Optimizations.UseAdvSimd)
|
||||
{
|
||||
InstEmitSimdHelperArm64.EmitScalarUnaryOpFToGp(context, Intrinsic.Arm64FcvtmuGp);
|
||||
}
|
||||
else if (Optimizations.UseSse41)
|
||||
{
|
||||
EmitSse41Fcvtu_Gp(context, FPRoundingMode.TowardsMinusInfinity, isFixed: false);
|
||||
}
|
||||
@ -336,7 +376,11 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
int sizeF = op.Size & 1;
|
||||
|
||||
if (Optimizations.UseSse2 && sizeF == 1)
|
||||
if (Optimizations.UseAdvSimd)
|
||||
{
|
||||
InstEmitSimdHelperArm64.EmitVectorBinaryOpFRd(context, Intrinsic.Arm64FcvtnV);
|
||||
}
|
||||
else if (Optimizations.UseSse2 && sizeF == 1)
|
||||
{
|
||||
Operand d = GetVec(op.Rd);
|
||||
|
||||
@ -405,7 +449,11 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
public static void Fcvtns_Gp(ArmEmitterContext context)
|
||||
{
|
||||
if (Optimizations.UseSse41)
|
||||
if (Optimizations.UseAdvSimd)
|
||||
{
|
||||
InstEmitSimdHelperArm64.EmitScalarUnaryOpFToGp(context, Intrinsic.Arm64FcvtnsGp);
|
||||
}
|
||||
else if (Optimizations.UseSse41)
|
||||
{
|
||||
EmitSse41Fcvts_Gp(context, FPRoundingMode.ToNearest, isFixed: false);
|
||||
}
|
||||
@ -417,7 +465,11 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
public static void Fcvtns_S(ArmEmitterContext context)
|
||||
{
|
||||
if (Optimizations.UseSse41)
|
||||
if (Optimizations.UseAdvSimd)
|
||||
{
|
||||
InstEmitSimdHelperArm64.EmitScalarUnaryOpF(context, Intrinsic.Arm64FcvtnsS);
|
||||
}
|
||||
else if (Optimizations.UseSse41)
|
||||
{
|
||||
EmitSse41FcvtsOpF(context, FPRoundingMode.ToNearest, scalar: true);
|
||||
}
|
||||
@ -429,7 +481,11 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
public static void Fcvtns_V(ArmEmitterContext context)
|
||||
{
|
||||
if (Optimizations.UseSse41)
|
||||
if (Optimizations.UseAdvSimd)
|
||||
{
|
||||
InstEmitSimdHelperArm64.EmitVectorUnaryOpF(context, Intrinsic.Arm64FcvtnsV);
|
||||
}
|
||||
else if (Optimizations.UseSse41)
|
||||
{
|
||||
EmitSse41FcvtsOpF(context, FPRoundingMode.ToNearest, scalar: false);
|
||||
}
|
||||
@ -441,7 +497,11 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
public static void Fcvtnu_S(ArmEmitterContext context)
|
||||
{
|
||||
if (Optimizations.UseSse41)
|
||||
if (Optimizations.UseAdvSimd)
|
||||
{
|
||||
InstEmitSimdHelperArm64.EmitScalarUnaryOpF(context, Intrinsic.Arm64FcvtnuS);
|
||||
}
|
||||
else if (Optimizations.UseSse41)
|
||||
{
|
||||
EmitSse41FcvtuOpF(context, FPRoundingMode.ToNearest, scalar: true);
|
||||
}
|
||||
@ -453,7 +513,11 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
public static void Fcvtnu_V(ArmEmitterContext context)
|
||||
{
|
||||
if (Optimizations.UseSse41)
|
||||
if (Optimizations.UseAdvSimd)
|
||||
{
|
||||
InstEmitSimdHelperArm64.EmitVectorUnaryOpF(context, Intrinsic.Arm64FcvtnuV);
|
||||
}
|
||||
else if (Optimizations.UseSse41)
|
||||
{
|
||||
EmitSse41FcvtuOpF(context, FPRoundingMode.ToNearest, scalar: false);
|
||||
}
|
||||
@ -465,7 +529,11 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
public static void Fcvtps_Gp(ArmEmitterContext context)
|
||||
{
|
||||
if (Optimizations.UseSse41)
|
||||
if (Optimizations.UseAdvSimd)
|
||||
{
|
||||
InstEmitSimdHelperArm64.EmitScalarUnaryOpFToGp(context, Intrinsic.Arm64FcvtpsGp);
|
||||
}
|
||||
else if (Optimizations.UseSse41)
|
||||
{
|
||||
EmitSse41Fcvts_Gp(context, FPRoundingMode.TowardsPlusInfinity, isFixed: false);
|
||||
}
|
||||
@ -477,7 +545,11 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
public static void Fcvtpu_Gp(ArmEmitterContext context)
|
||||
{
|
||||
if (Optimizations.UseSse41)
|
||||
if (Optimizations.UseAdvSimd)
|
||||
{
|
||||
InstEmitSimdHelperArm64.EmitScalarUnaryOpFToGp(context, Intrinsic.Arm64FcvtpuGp);
|
||||
}
|
||||
else if (Optimizations.UseSse41)
|
||||
{
|
||||
EmitSse41Fcvtu_Gp(context, FPRoundingMode.TowardsPlusInfinity, isFixed: false);
|
||||
}
|
||||
@ -489,7 +561,11 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
public static void Fcvtzs_Gp(ArmEmitterContext context)
|
||||
{
|
||||
if (Optimizations.UseSse41)
|
||||
if (Optimizations.UseAdvSimd)
|
||||
{
|
||||
InstEmitSimdHelperArm64.EmitScalarUnaryOpFToGp(context, Intrinsic.Arm64FcvtzsGp);
|
||||
}
|
||||
else if (Optimizations.UseSse41)
|
||||
{
|
||||
EmitSse41Fcvts_Gp(context, FPRoundingMode.TowardsZero, isFixed: false);
|
||||
}
|
||||
@ -501,7 +577,13 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
public static void Fcvtzs_Gp_Fixed(ArmEmitterContext context)
|
||||
{
|
||||
if (Optimizations.UseSse41)
|
||||
if (Optimizations.UseAdvSimd)
|
||||
{
|
||||
OpCodeSimdCvt op = (OpCodeSimdCvt)context.CurrOp;
|
||||
|
||||
InstEmitSimdHelperArm64.EmitScalarConvertBinaryOpFToGp(context, Intrinsic.Arm64FcvtzsGpFixed, op.FBits);
|
||||
}
|
||||
else if (Optimizations.UseSse41)
|
||||
{
|
||||
EmitSse41Fcvts_Gp(context, FPRoundingMode.TowardsZero, isFixed: true);
|
||||
}
|
||||
@ -513,7 +595,11 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
public static void Fcvtzs_S(ArmEmitterContext context)
|
||||
{
|
||||
if (Optimizations.UseSse41)
|
||||
if (Optimizations.UseAdvSimd)
|
||||
{
|
||||
InstEmitSimdHelperArm64.EmitScalarUnaryOpF(context, Intrinsic.Arm64FcvtzsS);
|
||||
}
|
||||
else if (Optimizations.UseSse41)
|
||||
{
|
||||
EmitSse41FcvtsOpF(context, FPRoundingMode.TowardsZero, scalar: true);
|
||||
}
|
||||
@ -525,7 +611,11 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
public static void Fcvtzs_V(ArmEmitterContext context)
|
||||
{
|
||||
if (Optimizations.UseSse41)
|
||||
if (Optimizations.UseAdvSimd)
|
||||
{
|
||||
InstEmitSimdHelperArm64.EmitVectorUnaryOpF(context, Intrinsic.Arm64FcvtzsV);
|
||||
}
|
||||
else if (Optimizations.UseSse41)
|
||||
{
|
||||
EmitSse41FcvtsOpF(context, FPRoundingMode.TowardsZero, scalar: false);
|
||||
}
|
||||
@ -537,7 +627,11 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
public static void Fcvtzs_V_Fixed(ArmEmitterContext context)
|
||||
{
|
||||
if (Optimizations.UseSse41)
|
||||
if (Optimizations.UseAdvSimd)
|
||||
{
|
||||
InstEmitSimdHelperArm64.EmitVectorConvertBinaryOpF(context, Intrinsic.Arm64FcvtzsVFixed, GetFBits(context));
|
||||
}
|
||||
else if (Optimizations.UseSse41)
|
||||
{
|
||||
EmitSse41FcvtsOpF(context, FPRoundingMode.TowardsZero, scalar: false);
|
||||
}
|
||||
@ -549,7 +643,11 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
public static void Fcvtzu_Gp(ArmEmitterContext context)
|
||||
{
|
||||
if (Optimizations.UseSse41)
|
||||
if (Optimizations.UseAdvSimd)
|
||||
{
|
||||
InstEmitSimdHelperArm64.EmitScalarUnaryOpFToGp(context, Intrinsic.Arm64FcvtzuGp);
|
||||
}
|
||||
else if (Optimizations.UseSse41)
|
||||
{
|
||||
EmitSse41Fcvtu_Gp(context, FPRoundingMode.TowardsZero, isFixed: false);
|
||||
}
|
||||
@ -561,7 +659,13 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
public static void Fcvtzu_Gp_Fixed(ArmEmitterContext context)
|
||||
{
|
||||
if (Optimizations.UseSse41)
|
||||
if (Optimizations.UseAdvSimd)
|
||||
{
|
||||
OpCodeSimdCvt op = (OpCodeSimdCvt)context.CurrOp;
|
||||
|
||||
InstEmitSimdHelperArm64.EmitScalarConvertBinaryOpFToGp(context, Intrinsic.Arm64FcvtzuGpFixed, op.FBits);
|
||||
}
|
||||
else if (Optimizations.UseSse41)
|
||||
{
|
||||
EmitSse41Fcvtu_Gp(context, FPRoundingMode.TowardsZero, isFixed: true);
|
||||
}
|
||||
@ -573,7 +677,11 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
public static void Fcvtzu_S(ArmEmitterContext context)
|
||||
{
|
||||
if (Optimizations.UseSse41)
|
||||
if (Optimizations.UseAdvSimd)
|
||||
{
|
||||
InstEmitSimdHelperArm64.EmitScalarUnaryOpF(context, Intrinsic.Arm64FcvtzuS);
|
||||
}
|
||||
else if (Optimizations.UseSse41)
|
||||
{
|
||||
EmitSse41FcvtuOpF(context, FPRoundingMode.TowardsZero, scalar: true);
|
||||
}
|
||||
@ -585,7 +693,11 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
public static void Fcvtzu_V(ArmEmitterContext context)
|
||||
{
|
||||
if (Optimizations.UseSse41)
|
||||
if (Optimizations.UseAdvSimd)
|
||||
{
|
||||
InstEmitSimdHelperArm64.EmitVectorUnaryOpF(context, Intrinsic.Arm64FcvtzuV);
|
||||
}
|
||||
else if (Optimizations.UseSse41)
|
||||
{
|
||||
EmitSse41FcvtuOpF(context, FPRoundingMode.TowardsZero, scalar: false);
|
||||
}
|
||||
@ -597,7 +709,11 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
public static void Fcvtzu_V_Fixed(ArmEmitterContext context)
|
||||
{
|
||||
if (Optimizations.UseSse41)
|
||||
if (Optimizations.UseAdvSimd)
|
||||
{
|
||||
InstEmitSimdHelperArm64.EmitVectorConvertBinaryOpF(context, Intrinsic.Arm64FcvtzuVFixed, GetFBits(context));
|
||||
}
|
||||
else if (Optimizations.UseSse41)
|
||||
{
|
||||
EmitSse41FcvtuOpF(context, FPRoundingMode.TowardsZero, scalar: false);
|
||||
}
|
||||
@ -609,41 +725,59 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
public static void Scvtf_Gp(ArmEmitterContext context)
|
||||
{
|
||||
OpCodeSimdCvt op = (OpCodeSimdCvt)context.CurrOp;
|
||||
|
||||
Operand res = GetIntOrZR(context, op.Rn);
|
||||
|
||||
if (op.RegisterSize == RegisterSize.Int32)
|
||||
if (Optimizations.UseAdvSimd)
|
||||
{
|
||||
res = context.SignExtend32(OperandType.I64, res);
|
||||
InstEmitSimdHelperArm64.EmitScalarUnaryOpFFromGp(context, Intrinsic.Arm64ScvtfGp);
|
||||
}
|
||||
else
|
||||
{
|
||||
OpCodeSimdCvt op = (OpCodeSimdCvt)context.CurrOp;
|
||||
|
||||
res = EmitFPConvert(context, res, op.Size, signed: true);
|
||||
Operand res = GetIntOrZR(context, op.Rn);
|
||||
|
||||
context.Copy(GetVec(op.Rd), context.VectorInsert(context.VectorZero(), res, 0));
|
||||
if (op.RegisterSize == RegisterSize.Int32)
|
||||
{
|
||||
res = context.SignExtend32(OperandType.I64, res);
|
||||
}
|
||||
|
||||
res = EmitFPConvert(context, res, op.Size, signed: true);
|
||||
|
||||
context.Copy(GetVec(op.Rd), context.VectorInsert(context.VectorZero(), res, 0));
|
||||
}
|
||||
}
|
||||
|
||||
public static void Scvtf_Gp_Fixed(ArmEmitterContext context)
|
||||
{
|
||||
OpCodeSimdCvt op = (OpCodeSimdCvt)context.CurrOp;
|
||||
|
||||
Operand res = GetIntOrZR(context, op.Rn);
|
||||
|
||||
if (op.RegisterSize == RegisterSize.Int32)
|
||||
if (Optimizations.UseAdvSimd)
|
||||
{
|
||||
res = context.SignExtend32(OperandType.I64, res);
|
||||
InstEmitSimdHelperArm64.EmitScalarConvertBinaryOpFFromGp(context, Intrinsic.Arm64ScvtfGpFixed, op.FBits);
|
||||
}
|
||||
else
|
||||
{
|
||||
Operand res = GetIntOrZR(context, op.Rn);
|
||||
|
||||
res = EmitFPConvert(context, res, op.Size, signed: true);
|
||||
if (op.RegisterSize == RegisterSize.Int32)
|
||||
{
|
||||
res = context.SignExtend32(OperandType.I64, res);
|
||||
}
|
||||
|
||||
res = EmitI2fFBitsMul(context, res, op.FBits);
|
||||
res = EmitFPConvert(context, res, op.Size, signed: true);
|
||||
|
||||
context.Copy(GetVec(op.Rd), context.VectorInsert(context.VectorZero(), res, 0));
|
||||
res = EmitI2fFBitsMul(context, res, op.FBits);
|
||||
|
||||
context.Copy(GetVec(op.Rd), context.VectorInsert(context.VectorZero(), res, 0));
|
||||
}
|
||||
}
|
||||
|
||||
public static void Scvtf_S(ArmEmitterContext context)
|
||||
{
|
||||
if (Optimizations.UseSse2)
|
||||
if (Optimizations.UseAdvSimd)
|
||||
{
|
||||
InstEmitSimdHelperArm64.EmitScalarUnaryOpF(context, Intrinsic.Arm64ScvtfS);
|
||||
}
|
||||
else if (Optimizations.UseSse2)
|
||||
{
|
||||
EmitSse2ScvtfOp(context, scalar: true);
|
||||
}
|
||||
@ -655,7 +789,11 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
public static void Scvtf_S_Fixed(ArmEmitterContext context)
|
||||
{
|
||||
if (Optimizations.UseSse2)
|
||||
if (Optimizations.UseAdvSimd)
|
||||
{
|
||||
InstEmitSimdHelperArm64.EmitScalarConvertBinaryOpF(context, Intrinsic.Arm64ScvtfSFixed, GetFBits(context));
|
||||
}
|
||||
else if (Optimizations.UseSse2)
|
||||
{
|
||||
EmitSse2ScvtfOp(context, scalar: true);
|
||||
}
|
||||
@ -667,7 +805,11 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
public static void Scvtf_V(ArmEmitterContext context)
|
||||
{
|
||||
if (Optimizations.UseSse2)
|
||||
if (Optimizations.UseAdvSimd)
|
||||
{
|
||||
InstEmitSimdHelperArm64.EmitVectorUnaryOpF(context, Intrinsic.Arm64ScvtfV);
|
||||
}
|
||||
else if (Optimizations.UseSse2)
|
||||
{
|
||||
EmitSse2ScvtfOp(context, scalar: false);
|
||||
}
|
||||
@ -679,7 +821,11 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
public static void Scvtf_V_Fixed(ArmEmitterContext context)
|
||||
{
|
||||
if (Optimizations.UseSse2)
|
||||
if (Optimizations.UseAdvSimd)
|
||||
{
|
||||
InstEmitSimdHelperArm64.EmitVectorConvertBinaryOpF(context, Intrinsic.Arm64ScvtfVFixed, GetFBits(context));
|
||||
}
|
||||
else if (Optimizations.UseSse2)
|
||||
{
|
||||
EmitSse2ScvtfOp(context, scalar: false);
|
||||
}
|
||||
@ -691,31 +837,49 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
public static void Ucvtf_Gp(ArmEmitterContext context)
|
||||
{
|
||||
OpCodeSimdCvt op = (OpCodeSimdCvt)context.CurrOp;
|
||||
if (Optimizations.UseAdvSimd)
|
||||
{
|
||||
InstEmitSimdHelperArm64.EmitScalarUnaryOpFFromGp(context, Intrinsic.Arm64UcvtfGp);
|
||||
}
|
||||
else
|
||||
{
|
||||
OpCodeSimdCvt op = (OpCodeSimdCvt)context.CurrOp;
|
||||
|
||||
Operand res = GetIntOrZR(context, op.Rn);
|
||||
Operand res = GetIntOrZR(context, op.Rn);
|
||||
|
||||
res = EmitFPConvert(context, res, op.Size, signed: false);
|
||||
res = EmitFPConvert(context, res, op.Size, signed: false);
|
||||
|
||||
context.Copy(GetVec(op.Rd), context.VectorInsert(context.VectorZero(), res, 0));
|
||||
context.Copy(GetVec(op.Rd), context.VectorInsert(context.VectorZero(), res, 0));
|
||||
}
|
||||
}
|
||||
|
||||
public static void Ucvtf_Gp_Fixed(ArmEmitterContext context)
|
||||
{
|
||||
OpCodeSimdCvt op = (OpCodeSimdCvt)context.CurrOp;
|
||||
|
||||
Operand res = GetIntOrZR(context, op.Rn);
|
||||
if (Optimizations.UseAdvSimd)
|
||||
{
|
||||
InstEmitSimdHelperArm64.EmitScalarConvertBinaryOpFFromGp(context, Intrinsic.Arm64UcvtfGpFixed, op.FBits);
|
||||
}
|
||||
else
|
||||
{
|
||||
Operand res = GetIntOrZR(context, op.Rn);
|
||||
|
||||
res = EmitFPConvert(context, res, op.Size, signed: false);
|
||||
res = EmitFPConvert(context, res, op.Size, signed: false);
|
||||
|
||||
res = EmitI2fFBitsMul(context, res, op.FBits);
|
||||
res = EmitI2fFBitsMul(context, res, op.FBits);
|
||||
|
||||
context.Copy(GetVec(op.Rd), context.VectorInsert(context.VectorZero(), res, 0));
|
||||
context.Copy(GetVec(op.Rd), context.VectorInsert(context.VectorZero(), res, 0));
|
||||
}
|
||||
}
|
||||
|
||||
public static void Ucvtf_S(ArmEmitterContext context)
|
||||
{
|
||||
if (Optimizations.UseSse2)
|
||||
if (Optimizations.UseAdvSimd)
|
||||
{
|
||||
InstEmitSimdHelperArm64.EmitScalarUnaryOpF(context, Intrinsic.Arm64UcvtfS);
|
||||
}
|
||||
else if (Optimizations.UseSse2)
|
||||
{
|
||||
EmitSse2UcvtfOp(context, scalar: true);
|
||||
}
|
||||
@ -727,7 +891,11 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
public static void Ucvtf_S_Fixed(ArmEmitterContext context)
|
||||
{
|
||||
if (Optimizations.UseSse2)
|
||||
if (Optimizations.UseAdvSimd)
|
||||
{
|
||||
InstEmitSimdHelperArm64.EmitScalarConvertBinaryOpF(context, Intrinsic.Arm64UcvtfSFixed, GetFBits(context));
|
||||
}
|
||||
else if (Optimizations.UseSse2)
|
||||
{
|
||||
EmitSse2UcvtfOp(context, scalar: true);
|
||||
}
|
||||
@ -739,7 +907,11 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
public static void Ucvtf_V(ArmEmitterContext context)
|
||||
{
|
||||
if (Optimizations.UseSse2)
|
||||
if (Optimizations.UseAdvSimd)
|
||||
{
|
||||
InstEmitSimdHelperArm64.EmitVectorUnaryOpF(context, Intrinsic.Arm64UcvtfV);
|
||||
}
|
||||
else if (Optimizations.UseSse2)
|
||||
{
|
||||
EmitSse2UcvtfOp(context, scalar: false);
|
||||
}
|
||||
@ -751,7 +923,11 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
public static void Ucvtf_V_Fixed(ArmEmitterContext context)
|
||||
{
|
||||
if (Optimizations.UseSse2)
|
||||
if (Optimizations.UseAdvSimd)
|
||||
{
|
||||
InstEmitSimdHelperArm64.EmitVectorConvertBinaryOpF(context, Intrinsic.Arm64UcvtfVFixed, GetFBits(context));
|
||||
}
|
||||
else if (Optimizations.UseSse2)
|
||||
{
|
||||
EmitSse2UcvtfOp(context, scalar: false);
|
||||
}
|
||||
|
@ -59,7 +59,11 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
if (toInteger)
|
||||
{
|
||||
if (Optimizations.UseSse41)
|
||||
if (Optimizations.UseAdvSimd)
|
||||
{
|
||||
InstEmitSimdHelper32Arm64.EmitVectorUnaryOpF32(context, unsigned ? Intrinsic.Arm64FcvtzuV : Intrinsic.Arm64FcvtzsV);
|
||||
}
|
||||
else if (Optimizations.UseSse41)
|
||||
{
|
||||
EmitSse41ConvertVector32(context, FPRoundingMode.TowardsZero, !unsigned);
|
||||
}
|
||||
@ -153,7 +157,28 @@ namespace ARMeilleure.Instructions
|
||||
bool unsigned = (op.Opc2 & 1) == 0;
|
||||
bool roundWithFpscr = op.Opc != 1;
|
||||
|
||||
if (!roundWithFpscr && Optimizations.UseSse41)
|
||||
if (!roundWithFpscr && Optimizations.UseAdvSimd)
|
||||
{
|
||||
bool doubleSize = floatSize == OperandType.FP64;
|
||||
|
||||
if (doubleSize)
|
||||
{
|
||||
Operand m = GetVecA32(op.Vm >> 1);
|
||||
|
||||
Operand toConvert = InstEmitSimdHelper32Arm64.EmitExtractScalar(context, m, op.Vm, doubleSize);
|
||||
|
||||
Intrinsic inst = (unsigned ? Intrinsic.Arm64FcvtzuGp : Intrinsic.Arm64FcvtzsGp) | Intrinsic.Arm64VDouble;
|
||||
|
||||
Operand asInteger = context.AddIntrinsicInt(inst, toConvert);
|
||||
|
||||
InsertScalar(context, op.Vd, asInteger);
|
||||
}
|
||||
else
|
||||
{
|
||||
InstEmitSimdHelper32Arm64.EmitScalarUnaryOpF32(context, unsigned ? Intrinsic.Arm64FcvtzuS : Intrinsic.Arm64FcvtzsS);
|
||||
}
|
||||
}
|
||||
else if (!roundWithFpscr && Optimizations.UseSse41)
|
||||
{
|
||||
EmitSse41ConvertInt32(context, FPRoundingMode.TowardsZero, !unsigned);
|
||||
}
|
||||
@ -231,7 +256,34 @@ namespace ARMeilleure.Instructions
|
||||
bool unsigned = op.Opc == 0;
|
||||
int rm = op.Opc2 & 3;
|
||||
|
||||
if (Optimizations.UseSse41)
|
||||
Intrinsic inst;
|
||||
|
||||
if (Optimizations.UseAdvSimd)
|
||||
{
|
||||
if (unsigned)
|
||||
{
|
||||
inst = rm switch {
|
||||
0b00 => Intrinsic.Arm64FcvtauS,
|
||||
0b01 => Intrinsic.Arm64FcvtnuS,
|
||||
0b10 => Intrinsic.Arm64FcvtpuS,
|
||||
0b11 => Intrinsic.Arm64FcvtmuS,
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(rm))
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
inst = rm switch {
|
||||
0b00 => Intrinsic.Arm64FcvtasS,
|
||||
0b01 => Intrinsic.Arm64FcvtnsS,
|
||||
0b10 => Intrinsic.Arm64FcvtpsS,
|
||||
0b11 => Intrinsic.Arm64FcvtmsS,
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(rm))
|
||||
};
|
||||
}
|
||||
|
||||
InstEmitSimdHelper32Arm64.EmitScalarUnaryOpF32(context, inst);
|
||||
}
|
||||
else if (Optimizations.UseSse41)
|
||||
{
|
||||
EmitSse41ConvertInt32(context, RMToRoundMode(rm), !unsigned);
|
||||
}
|
||||
@ -338,7 +390,19 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
int rm = op.Opc2 & 3;
|
||||
|
||||
if (Optimizations.UseSse41)
|
||||
if (Optimizations.UseAdvSimd)
|
||||
{
|
||||
Intrinsic inst = rm switch {
|
||||
0b00 => Intrinsic.Arm64FrintaS,
|
||||
0b01 => Intrinsic.Arm64FrintnS,
|
||||
0b10 => Intrinsic.Arm64FrintpS,
|
||||
0b11 => Intrinsic.Arm64FrintmS,
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(rm))
|
||||
};
|
||||
|
||||
InstEmitSimdHelper32Arm64.EmitScalarUnaryOpF32(context, inst);
|
||||
}
|
||||
else if (Optimizations.UseSse41)
|
||||
{
|
||||
EmitScalarUnaryOpSimd32(context, (m) =>
|
||||
{
|
||||
@ -382,12 +446,9 @@ namespace ARMeilleure.Instructions
|
||||
// VRINTA (vector).
|
||||
public static void Vrinta_V(ArmEmitterContext context)
|
||||
{
|
||||
if (Optimizations.UseSse41)
|
||||
if (Optimizations.UseAdvSimd)
|
||||
{
|
||||
EmitVectorUnaryOpSimd32(context, (m) =>
|
||||
{
|
||||
return EmitSse41RoundToNearestWithTiesToAwayOpF(context, m, scalar: false);
|
||||
});
|
||||
InstEmitSimdHelper32Arm64.EmitVectorUnaryOpF32(context, Intrinsic.Arm64FrintaS);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -398,7 +459,11 @@ namespace ARMeilleure.Instructions
|
||||
// VRINTM (vector).
|
||||
public static void Vrintm_V(ArmEmitterContext context)
|
||||
{
|
||||
if (Optimizations.UseSse2)
|
||||
if (Optimizations.UseAdvSimd)
|
||||
{
|
||||
InstEmitSimdHelper32Arm64.EmitVectorUnaryOpF32(context, Intrinsic.Arm64FrintmS);
|
||||
}
|
||||
else if (Optimizations.UseSse2)
|
||||
{
|
||||
EmitVectorUnaryOpSimd32(context, (m) =>
|
||||
{
|
||||
@ -414,7 +479,11 @@ namespace ARMeilleure.Instructions
|
||||
// VRINTN (vector).
|
||||
public static void Vrintn_V(ArmEmitterContext context)
|
||||
{
|
||||
if (Optimizations.UseSse2)
|
||||
if (Optimizations.UseAdvSimd)
|
||||
{
|
||||
InstEmitSimdHelper32Arm64.EmitVectorUnaryOpF32(context, Intrinsic.Arm64FrintnS);
|
||||
}
|
||||
else if (Optimizations.UseSse2)
|
||||
{
|
||||
EmitVectorUnaryOpSimd32(context, (m) =>
|
||||
{
|
||||
@ -430,7 +499,11 @@ namespace ARMeilleure.Instructions
|
||||
// VRINTP (vector).
|
||||
public static void Vrintp_V(ArmEmitterContext context)
|
||||
{
|
||||
if (Optimizations.UseSse2)
|
||||
if (Optimizations.UseAdvSimd)
|
||||
{
|
||||
InstEmitSimdHelper32Arm64.EmitVectorUnaryOpF32(context, Intrinsic.Arm64FrintpS);
|
||||
}
|
||||
else if (Optimizations.UseSse2)
|
||||
{
|
||||
EmitVectorUnaryOpSimd32(context, (m) =>
|
||||
{
|
||||
@ -448,7 +521,11 @@ namespace ARMeilleure.Instructions
|
||||
{
|
||||
OpCode32SimdS op = (OpCode32SimdS)context.CurrOp;
|
||||
|
||||
if (Optimizations.UseSse2)
|
||||
if (Optimizations.UseAdvSimd)
|
||||
{
|
||||
InstEmitSimdHelper32Arm64.EmitScalarUnaryOpF32(context, Intrinsic.Arm64FrintzS);
|
||||
}
|
||||
else if (Optimizations.UseSse2)
|
||||
{
|
||||
EmitScalarUnaryOpSimd32(context, (m) =>
|
||||
{
|
||||
|
366
ARMeilleure/Instructions/InstEmitSimdHelper32Arm64.cs
Normal file
366
ARMeilleure/Instructions/InstEmitSimdHelper32Arm64.cs
Normal file
@ -0,0 +1,366 @@
|
||||
|
||||
using ARMeilleure.Decoders;
|
||||
using ARMeilleure.IntermediateRepresentation;
|
||||
using ARMeilleure.State;
|
||||
using ARMeilleure.Translation;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
|
||||
using static ARMeilleure.Instructions.InstEmitHelper;
|
||||
using static ARMeilleure.Instructions.InstEmitSimdHelper;
|
||||
using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
|
||||
|
||||
namespace ARMeilleure.Instructions
|
||||
{
|
||||
using Func1I = Func<Operand, Operand>;
|
||||
using Func2I = Func<Operand, Operand, Operand>;
|
||||
using Func3I = Func<Operand, Operand, Operand, Operand>;
|
||||
|
||||
static class InstEmitSimdHelper32Arm64
|
||||
{
|
||||
// Intrinsic Helpers
|
||||
|
||||
public static Operand EmitMoveDoubleWordToSide(ArmEmitterContext context, Operand input, int originalV, int targetV)
|
||||
{
|
||||
Debug.Assert(input.Type == OperandType.V128);
|
||||
|
||||
int originalSide = originalV & 1;
|
||||
int targetSide = targetV & 1;
|
||||
|
||||
if (originalSide == targetSide)
|
||||
{
|
||||
return input;
|
||||
}
|
||||
|
||||
Intrinsic vType = Intrinsic.Arm64VDWord | Intrinsic.Arm64V128;
|
||||
|
||||
if (targetSide == 1)
|
||||
{
|
||||
return context.AddIntrinsic(Intrinsic.Arm64DupVe | vType, input, Const(OperandType.I32, 0)); // Low to high.
|
||||
}
|
||||
else
|
||||
{
|
||||
return context.AddIntrinsic(Intrinsic.Arm64DupVe | vType, input, Const(OperandType.I32, 1)); // High to low.
|
||||
}
|
||||
}
|
||||
|
||||
public static Operand EmitDoubleWordInsert(ArmEmitterContext context, Operand target, Operand value, int targetV)
|
||||
{
|
||||
Debug.Assert(target.Type == OperandType.V128 && value.Type == OperandType.V128);
|
||||
|
||||
int targetSide = targetV & 1;
|
||||
Operand idx = Const(targetSide);
|
||||
|
||||
return context.AddIntrinsic(Intrinsic.Arm64InsVe | Intrinsic.Arm64VDWord, target, idx, value, idx);
|
||||
}
|
||||
|
||||
public static Operand EmitScalarInsert(ArmEmitterContext context, Operand target, Operand value, int reg, bool doubleWidth)
|
||||
{
|
||||
Debug.Assert(target.Type == OperandType.V128 && value.Type == OperandType.V128);
|
||||
|
||||
// Insert from index 0 in value to index in target.
|
||||
int index = reg & (doubleWidth ? 1 : 3);
|
||||
|
||||
if (doubleWidth)
|
||||
{
|
||||
return context.AddIntrinsic(Intrinsic.Arm64InsVe | Intrinsic.Arm64VDWord, target, Const(index), value, Const(0));
|
||||
}
|
||||
else
|
||||
{
|
||||
return context.AddIntrinsic(Intrinsic.Arm64InsVe | Intrinsic.Arm64VWord, target, Const(index), value, Const(0));
|
||||
}
|
||||
}
|
||||
|
||||
public static Operand EmitExtractScalar(ArmEmitterContext context, Operand target, int reg, bool doubleWidth)
|
||||
{
|
||||
int index = reg & (doubleWidth ? 1 : 3);
|
||||
if (index == 0) return target; // Element is already at index 0, so just return the vector directly.
|
||||
|
||||
if (doubleWidth)
|
||||
{
|
||||
return context.AddIntrinsic(Intrinsic.Arm64DupSe | Intrinsic.Arm64VDWord, target, Const(1)); // Extract high (index 1).
|
||||
}
|
||||
else
|
||||
{
|
||||
return context.AddIntrinsic(Intrinsic.Arm64DupSe | Intrinsic.Arm64VWord, target, Const(index)); // Extract element at index.
|
||||
}
|
||||
}
|
||||
|
||||
// Vector Operand Templates
|
||||
|
||||
public static void EmitVectorUnaryOpSimd32(ArmEmitterContext context, Func1I vectorFunc)
|
||||
{
|
||||
OpCode32Simd op = (OpCode32Simd)context.CurrOp;
|
||||
|
||||
Operand m = GetVecA32(op.Qm);
|
||||
Operand d = GetVecA32(op.Qd);
|
||||
|
||||
if (!op.Q) // Register swap: move relevant doubleword to destination side.
|
||||
{
|
||||
m = EmitMoveDoubleWordToSide(context, m, op.Vm, op.Vd);
|
||||
}
|
||||
|
||||
Operand res = vectorFunc(m);
|
||||
|
||||
if (!op.Q) // Register insert.
|
||||
{
|
||||
res = EmitDoubleWordInsert(context, d, res, op.Vd);
|
||||
}
|
||||
|
||||
context.Copy(d, res);
|
||||
}
|
||||
|
||||
public static void EmitVectorUnaryOpF32(ArmEmitterContext context, Intrinsic inst)
|
||||
{
|
||||
OpCode32Simd op = (OpCode32Simd)context.CurrOp;
|
||||
|
||||
inst |= ((op.Size & 1) != 0 ? Intrinsic.Arm64VDouble : Intrinsic.Arm64VFloat) | Intrinsic.Arm64V128;
|
||||
EmitVectorUnaryOpSimd32(context, (m) => context.AddIntrinsic(inst, m));
|
||||
}
|
||||
|
||||
public static void EmitVectorBinaryOpSimd32(ArmEmitterContext context, Func2I vectorFunc, int side = -1)
|
||||
{
|
||||
OpCode32SimdReg op = (OpCode32SimdReg)context.CurrOp;
|
||||
|
||||
Operand n = GetVecA32(op.Qn);
|
||||
Operand m = GetVecA32(op.Qm);
|
||||
Operand d = GetVecA32(op.Qd);
|
||||
|
||||
if (side == -1)
|
||||
{
|
||||
side = op.Vd;
|
||||
}
|
||||
|
||||
if (!op.Q) // Register swap: move relevant doubleword to destination side.
|
||||
{
|
||||
n = EmitMoveDoubleWordToSide(context, n, op.Vn, side);
|
||||
m = EmitMoveDoubleWordToSide(context, m, op.Vm, side);
|
||||
}
|
||||
|
||||
Operand res = vectorFunc(n, m);
|
||||
|
||||
if (!op.Q) // Register insert.
|
||||
{
|
||||
if (side != op.Vd)
|
||||
{
|
||||
res = EmitMoveDoubleWordToSide(context, res, side, op.Vd);
|
||||
}
|
||||
res = EmitDoubleWordInsert(context, d, res, op.Vd);
|
||||
}
|
||||
|
||||
context.Copy(d, res);
|
||||
}
|
||||
|
||||
public static void EmitVectorBinaryOpF32(ArmEmitterContext context, Intrinsic inst)
|
||||
{
|
||||
OpCode32SimdReg op = (OpCode32SimdReg)context.CurrOp;
|
||||
|
||||
inst |= ((op.Size & 1) != 0 ? Intrinsic.Arm64VDouble : Intrinsic.Arm64VFloat) | Intrinsic.Arm64V128;
|
||||
EmitVectorBinaryOpSimd32(context, (n, m) => context.AddIntrinsic(inst, n, m));
|
||||
}
|
||||
|
||||
public static void EmitVectorTernaryOpSimd32(ArmEmitterContext context, Func3I vectorFunc)
|
||||
{
|
||||
OpCode32SimdReg op = (OpCode32SimdReg)context.CurrOp;
|
||||
|
||||
Operand n = GetVecA32(op.Qn);
|
||||
Operand m = GetVecA32(op.Qm);
|
||||
Operand d = GetVecA32(op.Qd);
|
||||
Operand initialD = d;
|
||||
|
||||
if (!op.Q) // Register swap: move relevant doubleword to destination side.
|
||||
{
|
||||
n = EmitMoveDoubleWordToSide(context, n, op.Vn, op.Vd);
|
||||
m = EmitMoveDoubleWordToSide(context, m, op.Vm, op.Vd);
|
||||
}
|
||||
|
||||
Operand res = vectorFunc(d, n, m);
|
||||
|
||||
if (!op.Q) // Register insert.
|
||||
{
|
||||
res = EmitDoubleWordInsert(context, initialD, res, op.Vd);
|
||||
}
|
||||
|
||||
context.Copy(initialD, res);
|
||||
}
|
||||
|
||||
public static void EmitVectorTernaryOpF32(ArmEmitterContext context, Intrinsic inst)
|
||||
{
|
||||
OpCode32SimdReg op = (OpCode32SimdReg)context.CurrOp;
|
||||
|
||||
inst |= ((op.Size & 1) != 0 ? Intrinsic.Arm64VDouble : Intrinsic.Arm64VFloat) | Intrinsic.Arm64V128;
|
||||
EmitVectorTernaryOpSimd32(context, (d, n, m) => context.AddIntrinsic(inst, d, n, m));
|
||||
}
|
||||
|
||||
public static void EmitScalarUnaryOpSimd32(ArmEmitterContext context, Func1I scalarFunc)
|
||||
{
|
||||
OpCode32SimdS op = (OpCode32SimdS)context.CurrOp;
|
||||
|
||||
bool doubleSize = (op.Size & 1) != 0;
|
||||
int shift = doubleSize ? 1 : 2;
|
||||
Operand m = GetVecA32(op.Vm >> shift);
|
||||
Operand d = GetVecA32(op.Vd >> shift);
|
||||
|
||||
m = EmitExtractScalar(context, m, op.Vm, doubleSize);
|
||||
|
||||
Operand res = scalarFunc(m);
|
||||
|
||||
// Insert scalar into vector.
|
||||
res = EmitScalarInsert(context, d, res, op.Vd, doubleSize);
|
||||
|
||||
context.Copy(d, res);
|
||||
}
|
||||
|
||||
public static void EmitScalarUnaryOpF32(ArmEmitterContext context, Intrinsic inst)
|
||||
{
|
||||
OpCode32SimdS op = (OpCode32SimdS)context.CurrOp;
|
||||
|
||||
inst |= ((op.Size & 1) != 0 ? Intrinsic.Arm64VDouble : Intrinsic.Arm64VFloat) | Intrinsic.Arm64V128;
|
||||
EmitScalarUnaryOpSimd32(context, (m) => (inst == 0) ? m : context.AddIntrinsic(inst, m));
|
||||
}
|
||||
|
||||
public static void EmitScalarBinaryOpSimd32(ArmEmitterContext context, Func2I scalarFunc)
|
||||
{
|
||||
OpCode32SimdRegS op = (OpCode32SimdRegS)context.CurrOp;
|
||||
|
||||
bool doubleSize = (op.Size & 1) != 0;
|
||||
int shift = doubleSize ? 1 : 2;
|
||||
Operand n = GetVecA32(op.Vn >> shift);
|
||||
Operand m = GetVecA32(op.Vm >> shift);
|
||||
Operand d = GetVecA32(op.Vd >> shift);
|
||||
|
||||
n = EmitExtractScalar(context, n, op.Vn, doubleSize);
|
||||
m = EmitExtractScalar(context, m, op.Vm, doubleSize);
|
||||
|
||||
Operand res = scalarFunc(n, m);
|
||||
|
||||
// Insert scalar into vector.
|
||||
res = EmitScalarInsert(context, d, res, op.Vd, doubleSize);
|
||||
|
||||
context.Copy(d, res);
|
||||
}
|
||||
|
||||
public static void EmitScalarBinaryOpF32(ArmEmitterContext context, Intrinsic inst)
|
||||
{
|
||||
OpCode32SimdRegS op = (OpCode32SimdRegS)context.CurrOp;
|
||||
|
||||
inst |= ((op.Size & 1) != 0 ? Intrinsic.Arm64VDouble : Intrinsic.Arm64VFloat) | Intrinsic.Arm64V128;
|
||||
EmitScalarBinaryOpSimd32(context, (n, m) => context.AddIntrinsic(inst, n, m));
|
||||
}
|
||||
|
||||
public static void EmitScalarTernaryOpSimd32(ArmEmitterContext context, Func3I scalarFunc)
|
||||
{
|
||||
OpCode32SimdRegS op = (OpCode32SimdRegS)context.CurrOp;
|
||||
|
||||
bool doubleSize = (op.Size & 1) != 0;
|
||||
int shift = doubleSize ? 1 : 2;
|
||||
Operand n = GetVecA32(op.Vn >> shift);
|
||||
Operand m = GetVecA32(op.Vm >> shift);
|
||||
Operand d = GetVecA32(op.Vd >> shift);
|
||||
Operand initialD = d;
|
||||
|
||||
n = EmitExtractScalar(context, n, op.Vn, doubleSize);
|
||||
m = EmitExtractScalar(context, m, op.Vm, doubleSize);
|
||||
d = EmitExtractScalar(context, d, op.Vd, doubleSize);
|
||||
|
||||
Operand res = scalarFunc(d, n, m);
|
||||
|
||||
// Insert scalar into vector.
|
||||
res = EmitScalarInsert(context, initialD, res, op.Vd, doubleSize);
|
||||
|
||||
context.Copy(initialD, res);
|
||||
}
|
||||
|
||||
public static void EmitScalarTernaryOpF32(ArmEmitterContext context, Intrinsic inst)
|
||||
{
|
||||
OpCode32SimdRegS op = (OpCode32SimdRegS)context.CurrOp;
|
||||
|
||||
inst |= ((op.Size & 1) != 0 ? Intrinsic.Arm64VDouble : Intrinsic.Arm64VFloat) | Intrinsic.Arm64V128;
|
||||
EmitScalarTernaryOpSimd32(context, (d, n, m) => context.AddIntrinsic(inst, d, n, m));
|
||||
}
|
||||
|
||||
// Pairwise
|
||||
|
||||
public static void EmitVectorPairwiseOpF32(ArmEmitterContext context, Intrinsic inst32)
|
||||
{
|
||||
OpCode32SimdReg op = (OpCode32SimdReg)context.CurrOp;
|
||||
|
||||
inst32 |= Intrinsic.Arm64V64 | Intrinsic.Arm64VFloat;
|
||||
EmitVectorBinaryOpSimd32(context, (n, m) => context.AddIntrinsic(inst32, n, m), 0);
|
||||
}
|
||||
|
||||
public static void EmitVcmpOrVcmpe(ArmEmitterContext context, bool signalNaNs)
|
||||
{
|
||||
OpCode32SimdS op = (OpCode32SimdS)context.CurrOp;
|
||||
|
||||
bool cmpWithZero = (op.Opc & 2) != 0;
|
||||
|
||||
Intrinsic inst = signalNaNs ? Intrinsic.Arm64FcmpeS : Intrinsic.Arm64FcmpS;
|
||||
inst |= ((op.Size & 1) != 0 ? Intrinsic.Arm64VDouble : Intrinsic.Arm64VFloat) | Intrinsic.Arm64V128;
|
||||
|
||||
bool doubleSize = (op.Size & 1) != 0;
|
||||
int shift = doubleSize ? 1 : 2;
|
||||
Operand n = GetVecA32(op.Vd >> shift);
|
||||
Operand m = GetVecA32(op.Vm >> shift);
|
||||
|
||||
n = EmitExtractScalar(context, n, op.Vd, doubleSize);
|
||||
m = cmpWithZero ? Const(0) : EmitExtractScalar(context, m, op.Vm, doubleSize);
|
||||
|
||||
Operand nzcv = context.AddIntrinsicInt(inst, n, m);
|
||||
|
||||
Operand one = Const(1);
|
||||
|
||||
SetFpFlag(context, FPState.VFlag, context.BitwiseAnd(context.ShiftRightUI(nzcv, Const(28)), one));
|
||||
SetFpFlag(context, FPState.CFlag, context.BitwiseAnd(context.ShiftRightUI(nzcv, Const(29)), one));
|
||||
SetFpFlag(context, FPState.ZFlag, context.BitwiseAnd(context.ShiftRightUI(nzcv, Const(30)), one));
|
||||
SetFpFlag(context, FPState.NFlag, context.BitwiseAnd(context.ShiftRightUI(nzcv, Const(31)), one));
|
||||
}
|
||||
|
||||
public static void EmitCmpOpF32(ArmEmitterContext context, CmpCondition cond, bool zero)
|
||||
{
|
||||
OpCode32Simd op = (OpCode32Simd)context.CurrOp;
|
||||
|
||||
int sizeF = op.Size & 1;
|
||||
|
||||
Intrinsic inst;
|
||||
if (zero)
|
||||
{
|
||||
inst = cond switch
|
||||
{
|
||||
CmpCondition.Equal => Intrinsic.Arm64FcmeqVz,
|
||||
CmpCondition.GreaterThan => Intrinsic.Arm64FcmgtVz,
|
||||
CmpCondition.GreaterThanOrEqual => Intrinsic.Arm64FcmgeVz,
|
||||
CmpCondition.LessThan => Intrinsic.Arm64FcmltVz,
|
||||
CmpCondition.LessThanOrEqual => Intrinsic.Arm64FcmleVz,
|
||||
_ => throw new InvalidOperationException()
|
||||
};
|
||||
}
|
||||
else {
|
||||
inst = cond switch
|
||||
{
|
||||
CmpCondition.Equal => Intrinsic.Arm64FcmeqV,
|
||||
CmpCondition.GreaterThan => Intrinsic.Arm64FcmgtV,
|
||||
CmpCondition.GreaterThanOrEqual => Intrinsic.Arm64FcmgeV,
|
||||
_ => throw new InvalidOperationException()
|
||||
};
|
||||
}
|
||||
|
||||
inst |= (sizeF != 0 ? Intrinsic.Arm64VDouble : Intrinsic.Arm64VFloat) | Intrinsic.Arm64V128;
|
||||
|
||||
if (zero)
|
||||
{
|
||||
EmitVectorUnaryOpSimd32(context, (m) =>
|
||||
{
|
||||
return context.AddIntrinsic(inst, m);
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitVectorBinaryOpSimd32(context, (n, m) =>
|
||||
{
|
||||
return context.AddIntrinsic(inst, n, m);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
720
ARMeilleure/Instructions/InstEmitSimdHelperArm64.cs
Normal file
720
ARMeilleure/Instructions/InstEmitSimdHelperArm64.cs
Normal file
@ -0,0 +1,720 @@
|
||||
using ARMeilleure.Decoders;
|
||||
using ARMeilleure.IntermediateRepresentation;
|
||||
using ARMeilleure.State;
|
||||
using ARMeilleure.Translation;
|
||||
|
||||
using static ARMeilleure.Instructions.InstEmitHelper;
|
||||
using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
|
||||
|
||||
namespace ARMeilleure.Instructions
|
||||
{
|
||||
static class InstEmitSimdHelperArm64
|
||||
{
|
||||
public static void EmitScalarUnaryOpF(ArmEmitterContext context, Intrinsic inst)
|
||||
{
|
||||
OpCodeSimd op = (OpCodeSimd)context.CurrOp;
|
||||
|
||||
Operand n = GetVec(op.Rn);
|
||||
|
||||
if ((op.Size & 1) != 0)
|
||||
{
|
||||
inst |= Intrinsic.Arm64VDouble;
|
||||
}
|
||||
|
||||
context.Copy(GetVec(op.Rd), context.AddIntrinsic(inst, n));
|
||||
}
|
||||
|
||||
public static void EmitScalarUnaryOpFFromGp(ArmEmitterContext context, Intrinsic inst)
|
||||
{
|
||||
OpCodeSimdCvt op = (OpCodeSimdCvt)context.CurrOp;
|
||||
|
||||
Operand n = GetIntOrZR(context, op.Rn);
|
||||
|
||||
if ((op.Size & 1) != 0)
|
||||
{
|
||||
inst |= Intrinsic.Arm64VDouble;
|
||||
}
|
||||
|
||||
context.Copy(GetVec(op.Rd), context.AddIntrinsic(inst, n));
|
||||
}
|
||||
|
||||
public static void EmitScalarUnaryOpFToGp(ArmEmitterContext context, Intrinsic inst)
|
||||
{
|
||||
OpCodeSimdCvt op = (OpCodeSimdCvt)context.CurrOp;
|
||||
|
||||
Operand n = GetVec(op.Rn);
|
||||
|
||||
if ((op.Size & 1) != 0)
|
||||
{
|
||||
inst |= Intrinsic.Arm64VDouble;
|
||||
}
|
||||
|
||||
SetIntOrZR(context, op.Rd, op.RegisterSize == RegisterSize.Int32
|
||||
? context.AddIntrinsicInt (inst, n)
|
||||
: context.AddIntrinsicLong(inst, n));
|
||||
}
|
||||
|
||||
public static void EmitScalarBinaryOpF(ArmEmitterContext context, Intrinsic inst)
|
||||
{
|
||||
OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp;
|
||||
|
||||
Operand n = GetVec(op.Rn);
|
||||
Operand m = GetVec(op.Rm);
|
||||
|
||||
if ((op.Size & 1) != 0)
|
||||
{
|
||||
inst |= Intrinsic.Arm64VDouble;
|
||||
}
|
||||
|
||||
context.Copy(GetVec(op.Rd), context.AddIntrinsic(inst, n, m));
|
||||
}
|
||||
|
||||
public static void EmitScalarBinaryOpFByElem(ArmEmitterContext context, Intrinsic inst)
|
||||
{
|
||||
OpCodeSimdRegElemF op = (OpCodeSimdRegElemF)context.CurrOp;
|
||||
|
||||
Operand n = GetVec(op.Rn);
|
||||
Operand m = GetVec(op.Rm);
|
||||
|
||||
if ((op.Size & 1) != 0)
|
||||
{
|
||||
inst |= Intrinsic.Arm64VDouble;
|
||||
}
|
||||
|
||||
context.Copy(GetVec(op.Rd), context.AddIntrinsic(inst, n, m, Const(op.Index)));
|
||||
}
|
||||
|
||||
public static void EmitScalarTernaryOpF(ArmEmitterContext context, Intrinsic inst)
|
||||
{
|
||||
OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp;
|
||||
|
||||
Operand n = GetVec(op.Rn);
|
||||
Operand m = GetVec(op.Rm);
|
||||
Operand a = GetVec(op.Ra);
|
||||
|
||||
if ((op.Size & 1) != 0)
|
||||
{
|
||||
inst |= Intrinsic.Arm64VDouble;
|
||||
}
|
||||
|
||||
context.Copy(GetVec(op.Rd), context.AddIntrinsic(inst, a, n, m));
|
||||
}
|
||||
|
||||
public static void EmitScalarTernaryOpFRdByElem(ArmEmitterContext context, Intrinsic inst)
|
||||
{
|
||||
OpCodeSimdRegElemF op = (OpCodeSimdRegElemF)context.CurrOp;
|
||||
|
||||
Operand d = GetVec(op.Rd);
|
||||
Operand n = GetVec(op.Rn);
|
||||
Operand m = GetVec(op.Rm);
|
||||
|
||||
if ((op.Size & 1) != 0)
|
||||
{
|
||||
inst |= Intrinsic.Arm64VDouble;
|
||||
}
|
||||
|
||||
context.Copy(d, context.AddIntrinsic(inst, d, n, m, Const(op.Index)));
|
||||
}
|
||||
|
||||
public static void EmitScalarUnaryOp(ArmEmitterContext context, Intrinsic inst)
|
||||
{
|
||||
OpCodeSimd op = (OpCodeSimd)context.CurrOp;
|
||||
|
||||
Operand n = GetVec(op.Rn);
|
||||
|
||||
inst |= (Intrinsic)(op.Size << (int)Intrinsic.Arm64VSizeShift);
|
||||
|
||||
context.Copy(GetVec(op.Rd), context.AddIntrinsic(inst, n));
|
||||
}
|
||||
|
||||
public static void EmitScalarBinaryOp(ArmEmitterContext context, Intrinsic inst)
|
||||
{
|
||||
OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp;
|
||||
|
||||
Operand n = GetVec(op.Rn);
|
||||
Operand m = GetVec(op.Rm);
|
||||
|
||||
inst |= (Intrinsic)(op.Size << (int)Intrinsic.Arm64VSizeShift);
|
||||
|
||||
context.Copy(GetVec(op.Rd), context.AddIntrinsic(inst, n, m));
|
||||
}
|
||||
|
||||
public static void EmitScalarBinaryOpRd(ArmEmitterContext context, Intrinsic inst)
|
||||
{
|
||||
OpCodeSimd op = (OpCodeSimd)context.CurrOp;
|
||||
|
||||
Operand d = GetVec(op.Rd);
|
||||
Operand n = GetVec(op.Rn);
|
||||
|
||||
inst |= (Intrinsic)(op.Size << (int)Intrinsic.Arm64VSizeShift);
|
||||
|
||||
context.Copy(GetVec(op.Rd), context.AddIntrinsic(inst, d, n));
|
||||
}
|
||||
|
||||
public static void EmitScalarTernaryOpRd(ArmEmitterContext context, Intrinsic inst)
|
||||
{
|
||||
OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp;
|
||||
|
||||
Operand d = GetVec(op.Rd);
|
||||
Operand n = GetVec(op.Rn);
|
||||
Operand m = GetVec(op.Rm);
|
||||
|
||||
inst |= (Intrinsic)(op.Size << (int)Intrinsic.Arm64VSizeShift);
|
||||
|
||||
context.Copy(d, context.AddIntrinsic(inst, d, n, m));
|
||||
}
|
||||
|
||||
public static void EmitScalarShiftBinaryOp(ArmEmitterContext context, Intrinsic inst, int shift)
|
||||
{
|
||||
OpCodeSimd op = (OpCodeSimd)context.CurrOp;
|
||||
|
||||
Operand n = GetVec(op.Rn);
|
||||
|
||||
inst |= (Intrinsic)(op.Size << (int)Intrinsic.Arm64VSizeShift);
|
||||
|
||||
context.Copy(GetVec(op.Rd), context.AddIntrinsic(inst, n, Const(shift)));
|
||||
}
|
||||
|
||||
public static void EmitScalarShiftTernaryOpRd(ArmEmitterContext context, Intrinsic inst, int shift)
|
||||
{
|
||||
OpCodeSimd op = (OpCodeSimd)context.CurrOp;
|
||||
|
||||
Operand d = GetVec(op.Rd);
|
||||
Operand n = GetVec(op.Rn);
|
||||
|
||||
inst |= (Intrinsic)(op.Size << (int)Intrinsic.Arm64VSizeShift);
|
||||
|
||||
context.Copy(GetVec(op.Rd), context.AddIntrinsic(inst, d, n, Const(shift)));
|
||||
}
|
||||
|
||||
public static void EmitScalarSaturatingShiftTernaryOpRd(ArmEmitterContext context, Intrinsic inst, int shift)
|
||||
{
|
||||
OpCodeSimd op = (OpCodeSimd)context.CurrOp;
|
||||
|
||||
Operand d = GetVec(op.Rd);
|
||||
Operand n = GetVec(op.Rn);
|
||||
|
||||
inst |= (Intrinsic)(op.Size << (int)Intrinsic.Arm64VSizeShift);
|
||||
|
||||
context.Copy(GetVec(op.Rd), context.AddIntrinsic(inst, d, n, Const(shift)));
|
||||
|
||||
context.SetPendingQcFlagSync();
|
||||
}
|
||||
|
||||
public static void EmitScalarSaturatingUnaryOp(ArmEmitterContext context, Intrinsic inst)
|
||||
{
|
||||
OpCodeSimd op = (OpCodeSimd)context.CurrOp;
|
||||
|
||||
Operand n = GetVec(op.Rn);
|
||||
|
||||
inst |= (Intrinsic)(op.Size << (int)Intrinsic.Arm64VSizeShift);
|
||||
|
||||
Operand result = context.AddIntrinsic(inst, n);
|
||||
|
||||
context.Copy(GetVec(op.Rd), result);
|
||||
|
||||
context.SetPendingQcFlagSync();
|
||||
}
|
||||
|
||||
public static void EmitScalarSaturatingBinaryOp(ArmEmitterContext context, Intrinsic inst)
|
||||
{
|
||||
OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp;
|
||||
|
||||
Operand n = GetVec(op.Rn);
|
||||
Operand m = GetVec(op.Rm);
|
||||
|
||||
inst |= (Intrinsic)(op.Size << (int)Intrinsic.Arm64VSizeShift);
|
||||
|
||||
Operand result = context.AddIntrinsic(inst, n, m);
|
||||
|
||||
context.Copy(GetVec(op.Rd), result);
|
||||
|
||||
context.SetPendingQcFlagSync();
|
||||
}
|
||||
|
||||
public static void EmitScalarSaturatingBinaryOpRd(ArmEmitterContext context, Intrinsic inst)
|
||||
{
|
||||
OpCodeSimd op = (OpCodeSimd)context.CurrOp;
|
||||
|
||||
Operand d = GetVec(op.Rd);
|
||||
Operand n = GetVec(op.Rn);
|
||||
|
||||
inst |= (Intrinsic)(op.Size << (int)Intrinsic.Arm64VSizeShift);
|
||||
|
||||
Operand result = context.AddIntrinsic(inst, d, n);
|
||||
|
||||
context.Copy(GetVec(op.Rd), result);
|
||||
|
||||
context.SetPendingQcFlagSync();
|
||||
}
|
||||
|
||||
public static void EmitScalarConvertBinaryOpF(ArmEmitterContext context, Intrinsic inst, int fBits)
|
||||
{
|
||||
OpCodeSimd op = (OpCodeSimd)context.CurrOp;
|
||||
|
||||
Operand n = GetVec(op.Rn);
|
||||
|
||||
if ((op.Size & 1) != 0)
|
||||
{
|
||||
inst |= Intrinsic.Arm64VDouble;
|
||||
}
|
||||
|
||||
context.Copy(GetVec(op.Rd), context.AddIntrinsic(inst, n, Const(fBits)));
|
||||
}
|
||||
|
||||
public static void EmitScalarConvertBinaryOpFFromGp(ArmEmitterContext context, Intrinsic inst, int fBits)
|
||||
{
|
||||
OpCodeSimd op = (OpCodeSimd)context.CurrOp;
|
||||
|
||||
Operand n = GetIntOrZR(context, op.Rn);
|
||||
|
||||
if ((op.Size & 1) != 0)
|
||||
{
|
||||
inst |= Intrinsic.Arm64VDouble;
|
||||
}
|
||||
|
||||
context.Copy(GetVec(op.Rd), context.AddIntrinsic(inst, n, Const(fBits)));
|
||||
}
|
||||
|
||||
public static void EmitScalarConvertBinaryOpFToGp(ArmEmitterContext context, Intrinsic inst, int fBits)
|
||||
{
|
||||
OpCodeSimd op = (OpCodeSimd)context.CurrOp;
|
||||
|
||||
Operand n = GetVec(op.Rn);
|
||||
|
||||
if ((op.Size & 1) != 0)
|
||||
{
|
||||
inst |= Intrinsic.Arm64VDouble;
|
||||
}
|
||||
|
||||
SetIntOrZR(context, op.Rd, op.RegisterSize == RegisterSize.Int32
|
||||
? context.AddIntrinsicInt (inst, n, Const(fBits))
|
||||
: context.AddIntrinsicLong(inst, n, Const(fBits)));
|
||||
}
|
||||
|
||||
public static void EmitVectorUnaryOpF(ArmEmitterContext context, Intrinsic inst)
|
||||
{
|
||||
OpCodeSimd op = (OpCodeSimd)context.CurrOp;
|
||||
|
||||
Operand n = GetVec(op.Rn);
|
||||
|
||||
if ((op.Size & 1) != 0)
|
||||
{
|
||||
inst |= Intrinsic.Arm64VDouble;
|
||||
}
|
||||
|
||||
if (op.RegisterSize == RegisterSize.Simd128)
|
||||
{
|
||||
inst |= Intrinsic.Arm64V128;
|
||||
}
|
||||
|
||||
context.Copy(GetVec(op.Rd), context.AddIntrinsic(inst, n));
|
||||
}
|
||||
|
||||
public static void EmitVectorBinaryOpF(ArmEmitterContext context, Intrinsic inst)
|
||||
{
|
||||
OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp;
|
||||
|
||||
Operand n = GetVec(op.Rn);
|
||||
Operand m = GetVec(op.Rm);
|
||||
|
||||
if ((op.Size & 1) != 0)
|
||||
{
|
||||
inst |= Intrinsic.Arm64VDouble;
|
||||
}
|
||||
|
||||
if (op.RegisterSize == RegisterSize.Simd128)
|
||||
{
|
||||
inst |= Intrinsic.Arm64V128;
|
||||
}
|
||||
|
||||
context.Copy(GetVec(op.Rd), context.AddIntrinsic(inst, n, m));
|
||||
}
|
||||
|
||||
public static void EmitVectorBinaryOpFRd(ArmEmitterContext context, Intrinsic inst)
|
||||
{
|
||||
OpCodeSimd op = (OpCodeSimd)context.CurrOp;
|
||||
|
||||
Operand d = GetVec(op.Rd);
|
||||
Operand n = GetVec(op.Rn);
|
||||
|
||||
if ((op.Size & 1) != 0)
|
||||
{
|
||||
inst |= Intrinsic.Arm64VDouble;
|
||||
}
|
||||
|
||||
if (op.RegisterSize == RegisterSize.Simd128)
|
||||
{
|
||||
inst |= Intrinsic.Arm64V128;
|
||||
}
|
||||
|
||||
context.Copy(GetVec(op.Rd), context.AddIntrinsic(inst, d, n));
|
||||
}
|
||||
|
||||
public static void EmitVectorBinaryOpFByElem(ArmEmitterContext context, Intrinsic inst)
|
||||
{
|
||||
OpCodeSimdRegElemF op = (OpCodeSimdRegElemF)context.CurrOp;
|
||||
|
||||
Operand n = GetVec(op.Rn);
|
||||
Operand m = GetVec(op.Rm);
|
||||
|
||||
if ((op.Size & 1) != 0)
|
||||
{
|
||||
inst |= Intrinsic.Arm64VDouble;
|
||||
}
|
||||
|
||||
if (op.RegisterSize == RegisterSize.Simd128)
|
||||
{
|
||||
inst |= Intrinsic.Arm64V128;
|
||||
}
|
||||
|
||||
context.Copy(GetVec(op.Rd), context.AddIntrinsic(inst, n, m, Const(op.Index)));
|
||||
}
|
||||
|
||||
public static void EmitVectorTernaryOpFRd(ArmEmitterContext context, Intrinsic inst)
|
||||
{
|
||||
OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp;
|
||||
|
||||
Operand d = GetVec(op.Rd);
|
||||
Operand n = GetVec(op.Rn);
|
||||
Operand m = GetVec(op.Rm);
|
||||
|
||||
if ((op.Size & 1) != 0)
|
||||
{
|
||||
inst |= Intrinsic.Arm64VDouble;
|
||||
}
|
||||
|
||||
if (op.RegisterSize == RegisterSize.Simd128)
|
||||
{
|
||||
inst |= Intrinsic.Arm64V128;
|
||||
}
|
||||
|
||||
context.Copy(d, context.AddIntrinsic(inst, d, n, m));
|
||||
}
|
||||
|
||||
public static void EmitVectorTernaryOpFRdByElem(ArmEmitterContext context, Intrinsic inst)
|
||||
{
|
||||
OpCodeSimdRegElemF op = (OpCodeSimdRegElemF)context.CurrOp;
|
||||
|
||||
Operand d = GetVec(op.Rd);
|
||||
Operand n = GetVec(op.Rn);
|
||||
Operand m = GetVec(op.Rm);
|
||||
|
||||
if ((op.Size & 1) != 0)
|
||||
{
|
||||
inst |= Intrinsic.Arm64VDouble;
|
||||
}
|
||||
|
||||
if (op.RegisterSize == RegisterSize.Simd128)
|
||||
{
|
||||
inst |= Intrinsic.Arm64V128;
|
||||
}
|
||||
|
||||
context.Copy(d, context.AddIntrinsic(inst, d, n, m, Const(op.Index)));
|
||||
}
|
||||
|
||||
public static void EmitVectorUnaryOp(ArmEmitterContext context, Intrinsic inst)
|
||||
{
|
||||
OpCodeSimd op = (OpCodeSimd)context.CurrOp;
|
||||
|
||||
Operand n = GetVec(op.Rn);
|
||||
|
||||
inst |= (Intrinsic)(op.Size << (int)Intrinsic.Arm64VSizeShift);
|
||||
|
||||
if (op.RegisterSize == RegisterSize.Simd128)
|
||||
{
|
||||
inst |= Intrinsic.Arm64V128;
|
||||
}
|
||||
|
||||
context.Copy(GetVec(op.Rd), context.AddIntrinsic(inst, n));
|
||||
}
|
||||
|
||||
public static void EmitVectorBinaryOp(ArmEmitterContext context, Intrinsic inst)
|
||||
{
|
||||
OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp;
|
||||
|
||||
Operand n = GetVec(op.Rn);
|
||||
Operand m = GetVec(op.Rm);
|
||||
|
||||
inst |= (Intrinsic)(op.Size << (int)Intrinsic.Arm64VSizeShift);
|
||||
|
||||
if (op.RegisterSize == RegisterSize.Simd128)
|
||||
{
|
||||
inst |= Intrinsic.Arm64V128;
|
||||
}
|
||||
|
||||
context.Copy(GetVec(op.Rd), context.AddIntrinsic(inst, n, m));
|
||||
}
|
||||
|
||||
public static void EmitVectorBinaryOpRd(ArmEmitterContext context, Intrinsic inst)
|
||||
{
|
||||
OpCodeSimd op = (OpCodeSimd)context.CurrOp;
|
||||
|
||||
Operand d = GetVec(op.Rd);
|
||||
Operand n = GetVec(op.Rn);
|
||||
|
||||
inst |= (Intrinsic)(op.Size << (int)Intrinsic.Arm64VSizeShift);
|
||||
|
||||
if (op.RegisterSize == RegisterSize.Simd128)
|
||||
{
|
||||
inst |= Intrinsic.Arm64V128;
|
||||
}
|
||||
|
||||
context.Copy(GetVec(op.Rd), context.AddIntrinsic(inst, d, n));
|
||||
}
|
||||
|
||||
public static void EmitVectorBinaryOpByElem(ArmEmitterContext context, Intrinsic inst)
|
||||
{
|
||||
OpCodeSimdRegElem op = (OpCodeSimdRegElem)context.CurrOp;
|
||||
|
||||
Operand n = GetVec(op.Rn);
|
||||
Operand m = GetVec(op.Rm);
|
||||
|
||||
inst |= (Intrinsic)(op.Size << (int)Intrinsic.Arm64VSizeShift);
|
||||
|
||||
if (op.RegisterSize == RegisterSize.Simd128)
|
||||
{
|
||||
inst |= Intrinsic.Arm64V128;
|
||||
}
|
||||
|
||||
context.Copy(GetVec(op.Rd), context.AddIntrinsic(inst, n, m, Const(op.Index)));
|
||||
}
|
||||
|
||||
public static void EmitVectorTernaryOpRd(ArmEmitterContext context, Intrinsic inst)
|
||||
{
|
||||
OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp;
|
||||
|
||||
Operand d = GetVec(op.Rd);
|
||||
Operand n = GetVec(op.Rn);
|
||||
Operand m = GetVec(op.Rm);
|
||||
|
||||
inst |= (Intrinsic)(op.Size << (int)Intrinsic.Arm64VSizeShift);
|
||||
|
||||
if (op.RegisterSize == RegisterSize.Simd128)
|
||||
{
|
||||
inst |= Intrinsic.Arm64V128;
|
||||
}
|
||||
|
||||
context.Copy(d, context.AddIntrinsic(inst, d, n, m));
|
||||
}
|
||||
|
||||
public static void EmitVectorTernaryOpRdByElem(ArmEmitterContext context, Intrinsic inst)
|
||||
{
|
||||
OpCodeSimdRegElem op = (OpCodeSimdRegElem)context.CurrOp;
|
||||
|
||||
Operand d = GetVec(op.Rd);
|
||||
Operand n = GetVec(op.Rn);
|
||||
Operand m = GetVec(op.Rm);
|
||||
|
||||
inst |= (Intrinsic)(op.Size << (int)Intrinsic.Arm64VSizeShift);
|
||||
|
||||
if (op.RegisterSize == RegisterSize.Simd128)
|
||||
{
|
||||
inst |= Intrinsic.Arm64V128;
|
||||
}
|
||||
|
||||
context.Copy(d, context.AddIntrinsic(inst, d, n, m, Const(op.Index)));
|
||||
}
|
||||
|
||||
public static void EmitVectorShiftBinaryOp(ArmEmitterContext context, Intrinsic inst, int shift)
|
||||
{
|
||||
OpCodeSimd op = (OpCodeSimd)context.CurrOp;
|
||||
|
||||
Operand n = GetVec(op.Rn);
|
||||
|
||||
inst |= (Intrinsic)(op.Size << (int)Intrinsic.Arm64VSizeShift);
|
||||
|
||||
if (op.RegisterSize == RegisterSize.Simd128)
|
||||
{
|
||||
inst |= Intrinsic.Arm64V128;
|
||||
}
|
||||
|
||||
context.Copy(GetVec(op.Rd), context.AddIntrinsic(inst, n, Const(shift)));
|
||||
}
|
||||
|
||||
public static void EmitVectorShiftTernaryOpRd(ArmEmitterContext context, Intrinsic inst, int shift)
|
||||
{
|
||||
OpCodeSimd op = (OpCodeSimd)context.CurrOp;
|
||||
|
||||
Operand d = GetVec(op.Rd);
|
||||
Operand n = GetVec(op.Rn);
|
||||
|
||||
inst |= (Intrinsic)(op.Size << (int)Intrinsic.Arm64VSizeShift);
|
||||
|
||||
if (op.RegisterSize == RegisterSize.Simd128)
|
||||
{
|
||||
inst |= Intrinsic.Arm64V128;
|
||||
}
|
||||
|
||||
context.Copy(GetVec(op.Rd), context.AddIntrinsic(inst, d, n, Const(shift)));
|
||||
}
|
||||
|
||||
public static void EmitVectorSaturatingShiftTernaryOpRd(ArmEmitterContext context, Intrinsic inst, int shift)
|
||||
{
|
||||
OpCodeSimd op = (OpCodeSimd)context.CurrOp;
|
||||
|
||||
Operand d = GetVec(op.Rd);
|
||||
Operand n = GetVec(op.Rn);
|
||||
|
||||
inst |= (Intrinsic)(op.Size << (int)Intrinsic.Arm64VSizeShift);
|
||||
|
||||
if (op.RegisterSize == RegisterSize.Simd128)
|
||||
{
|
||||
inst |= Intrinsic.Arm64V128;
|
||||
}
|
||||
|
||||
context.Copy(GetVec(op.Rd), context.AddIntrinsic(inst, d, n, Const(shift)));
|
||||
|
||||
context.SetPendingQcFlagSync();
|
||||
}
|
||||
|
||||
public static void EmitVectorSaturatingUnaryOp(ArmEmitterContext context, Intrinsic inst)
|
||||
{
|
||||
OpCodeSimd op = (OpCodeSimd)context.CurrOp;
|
||||
|
||||
Operand n = GetVec(op.Rn);
|
||||
|
||||
inst |= (Intrinsic)(op.Size << (int)Intrinsic.Arm64VSizeShift);
|
||||
|
||||
if (op.RegisterSize == RegisterSize.Simd128)
|
||||
{
|
||||
inst |= Intrinsic.Arm64V128;
|
||||
}
|
||||
|
||||
Operand result = context.AddIntrinsic(inst, n);
|
||||
|
||||
context.Copy(GetVec(op.Rd), result);
|
||||
|
||||
context.SetPendingQcFlagSync();
|
||||
}
|
||||
|
||||
public static void EmitVectorSaturatingBinaryOp(ArmEmitterContext context, Intrinsic inst)
|
||||
{
|
||||
OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp;
|
||||
|
||||
Operand n = GetVec(op.Rn);
|
||||
Operand m = GetVec(op.Rm);
|
||||
|
||||
inst |= (Intrinsic)(op.Size << (int)Intrinsic.Arm64VSizeShift);
|
||||
|
||||
if (op.RegisterSize == RegisterSize.Simd128)
|
||||
{
|
||||
inst |= Intrinsic.Arm64V128;
|
||||
}
|
||||
|
||||
Operand result = context.AddIntrinsic(inst, n, m);
|
||||
|
||||
context.Copy(GetVec(op.Rd), result);
|
||||
|
||||
context.SetPendingQcFlagSync();
|
||||
}
|
||||
|
||||
public static void EmitVectorSaturatingBinaryOpRd(ArmEmitterContext context, Intrinsic inst)
|
||||
{
|
||||
OpCodeSimd op = (OpCodeSimd)context.CurrOp;
|
||||
|
||||
Operand d = GetVec(op.Rd);
|
||||
Operand n = GetVec(op.Rn);
|
||||
|
||||
inst |= (Intrinsic)(op.Size << (int)Intrinsic.Arm64VSizeShift);
|
||||
|
||||
if (op.RegisterSize == RegisterSize.Simd128)
|
||||
{
|
||||
inst |= Intrinsic.Arm64V128;
|
||||
}
|
||||
|
||||
Operand result = context.AddIntrinsic(inst, d, n);
|
||||
|
||||
context.Copy(GetVec(op.Rd), result);
|
||||
|
||||
context.SetPendingQcFlagSync();
|
||||
}
|
||||
|
||||
public static void EmitVectorSaturatingBinaryOpByElem(ArmEmitterContext context, Intrinsic inst)
|
||||
{
|
||||
OpCodeSimdRegElem op = (OpCodeSimdRegElem)context.CurrOp;
|
||||
|
||||
Operand n = GetVec(op.Rn);
|
||||
Operand m = GetVec(op.Rm);
|
||||
|
||||
inst |= (Intrinsic)(op.Size << (int)Intrinsic.Arm64VSizeShift);
|
||||
|
||||
if (op.RegisterSize == RegisterSize.Simd128)
|
||||
{
|
||||
inst |= Intrinsic.Arm64V128;
|
||||
}
|
||||
|
||||
Operand result = context.AddIntrinsic(inst, n, m, Const(op.Index));
|
||||
|
||||
context.Copy(GetVec(op.Rd), result);
|
||||
|
||||
context.SetPendingQcFlagSync();
|
||||
}
|
||||
|
||||
public static void EmitVectorConvertBinaryOpF(ArmEmitterContext context, Intrinsic inst, int fBits)
|
||||
{
|
||||
OpCodeSimd op = (OpCodeSimd)context.CurrOp;
|
||||
|
||||
Operand n = GetVec(op.Rn);
|
||||
|
||||
if ((op.Size & 1) != 0)
|
||||
{
|
||||
inst |= Intrinsic.Arm64VDouble;
|
||||
}
|
||||
|
||||
if (op.RegisterSize == RegisterSize.Simd128)
|
||||
{
|
||||
inst |= Intrinsic.Arm64V128;
|
||||
}
|
||||
|
||||
context.Copy(GetVec(op.Rd), context.AddIntrinsic(inst, n, Const(fBits)));
|
||||
}
|
||||
|
||||
public static void EmitVectorLookupTable(ArmEmitterContext context, Intrinsic inst)
|
||||
{
|
||||
OpCodeSimdTbl op = (OpCodeSimdTbl)context.CurrOp;
|
||||
|
||||
Operand[] operands = new Operand[op.Size + 1];
|
||||
|
||||
operands[op.Size] = GetVec(op.Rm);
|
||||
|
||||
for (int index = 0; index < op.Size; index++)
|
||||
{
|
||||
operands[index] = GetVec((op.Rn + index) & 0x1F);
|
||||
}
|
||||
|
||||
if (op.RegisterSize == RegisterSize.Simd128)
|
||||
{
|
||||
inst |= Intrinsic.Arm64V128;
|
||||
}
|
||||
|
||||
context.Copy(GetVec(op.Rd), context.AddIntrinsic(inst, operands));
|
||||
}
|
||||
|
||||
public static void EmitFcmpOrFcmpe(ArmEmitterContext context, bool signalNaNs)
|
||||
{
|
||||
OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp;
|
||||
|
||||
bool cmpWithZero = !(op is OpCodeSimdFcond) ? op.Bit3 : false;
|
||||
|
||||
Intrinsic inst = signalNaNs ? Intrinsic.Arm64FcmpeS : Intrinsic.Arm64FcmpS;
|
||||
|
||||
if ((op.Size & 1) != 0)
|
||||
{
|
||||
inst |= Intrinsic.Arm64VDouble;
|
||||
}
|
||||
|
||||
Operand n = GetVec(op.Rn);
|
||||
Operand m = cmpWithZero ? Const(0) : GetVec(op.Rm);
|
||||
|
||||
Operand nzcv = context.AddIntrinsicInt(inst, n, m);
|
||||
|
||||
Operand one = Const(1);
|
||||
|
||||
SetFlag(context, PState.VFlag, context.BitwiseAnd(context.ShiftRightUI(nzcv, Const(28)), one));
|
||||
SetFlag(context, PState.CFlag, context.BitwiseAnd(context.ShiftRightUI(nzcv, Const(29)), one));
|
||||
SetFlag(context, PState.ZFlag, context.BitwiseAnd(context.ShiftRightUI(nzcv, Const(30)), one));
|
||||
SetFlag(context, PState.NFlag, context.BitwiseAnd(context.ShiftRightUI(nzcv, Const(31)), one));
|
||||
}
|
||||
}
|
||||
}
|
@ -14,7 +14,11 @@ namespace ARMeilleure.Instructions
|
||||
{
|
||||
public static void And_V(ArmEmitterContext context)
|
||||
{
|
||||
if (Optimizations.UseSse2)
|
||||
if (Optimizations.UseAdvSimd)
|
||||
{
|
||||
InstEmitSimdHelperArm64.EmitVectorBinaryOp(context, Intrinsic.Arm64AndV);
|
||||
}
|
||||
else if (Optimizations.UseSse2)
|
||||
{
|
||||
OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp;
|
||||
|
||||
@ -38,7 +42,11 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
public static void Bic_V(ArmEmitterContext context)
|
||||
{
|
||||
if (Optimizations.UseSse2)
|
||||
if (Optimizations.UseAdvSimd)
|
||||
{
|
||||
InstEmitSimdHelperArm64.EmitVectorBinaryOp(context, Intrinsic.Arm64BicV);
|
||||
}
|
||||
else if (Optimizations.UseSse2)
|
||||
{
|
||||
OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp;
|
||||
|
||||
@ -98,12 +106,26 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
public static void Bif_V(ArmEmitterContext context)
|
||||
{
|
||||
EmitBifBit(context, notRm: true);
|
||||
if (Optimizations.UseAdvSimd)
|
||||
{
|
||||
InstEmitSimdHelperArm64.EmitVectorTernaryOpRd(context, Intrinsic.Arm64BifV);
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitBifBit(context, notRm: true);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Bit_V(ArmEmitterContext context)
|
||||
{
|
||||
EmitBifBit(context, notRm: false);
|
||||
if (Optimizations.UseAdvSimd)
|
||||
{
|
||||
InstEmitSimdHelperArm64.EmitVectorTernaryOpRd(context, Intrinsic.Arm64BitV);
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitBifBit(context, notRm: false);
|
||||
}
|
||||
}
|
||||
|
||||
private static void EmitBifBit(ArmEmitterContext context, bool notRm)
|
||||
@ -167,7 +189,11 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
public static void Bsl_V(ArmEmitterContext context)
|
||||
{
|
||||
if (Optimizations.UseSse2)
|
||||
if (Optimizations.UseAdvSimd)
|
||||
{
|
||||
InstEmitSimdHelperArm64.EmitVectorTernaryOpRd(context, Intrinsic.Arm64BslV);
|
||||
}
|
||||
else if (Optimizations.UseSse2)
|
||||
{
|
||||
OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp;
|
||||
|
||||
@ -200,7 +226,11 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
public static void Eor_V(ArmEmitterContext context)
|
||||
{
|
||||
if (Optimizations.UseSse2)
|
||||
if (Optimizations.UseAdvSimd)
|
||||
{
|
||||
InstEmitSimdHelperArm64.EmitVectorBinaryOp(context, Intrinsic.Arm64EorV);
|
||||
}
|
||||
else if (Optimizations.UseSse2)
|
||||
{
|
||||
OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp;
|
||||
|
||||
@ -249,7 +279,11 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
public static void Orn_V(ArmEmitterContext context)
|
||||
{
|
||||
if (Optimizations.UseSse2)
|
||||
if (Optimizations.UseAdvSimd)
|
||||
{
|
||||
InstEmitSimdHelperArm64.EmitVectorBinaryOp(context, Intrinsic.Arm64OrnV);
|
||||
}
|
||||
else if (Optimizations.UseSse2)
|
||||
{
|
||||
OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp;
|
||||
|
||||
@ -280,7 +314,11 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
public static void Orr_V(ArmEmitterContext context)
|
||||
{
|
||||
if (Optimizations.UseSse2)
|
||||
if (Optimizations.UseAdvSimd)
|
||||
{
|
||||
InstEmitSimdHelperArm64.EmitVectorBinaryOp(context, Intrinsic.Arm64OrrV);
|
||||
}
|
||||
else if (Optimizations.UseSse2)
|
||||
{
|
||||
OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp;
|
||||
|
||||
|
@ -13,7 +13,11 @@ namespace ARMeilleure.Instructions
|
||||
{
|
||||
public static void Vand_I(ArmEmitterContext context)
|
||||
{
|
||||
if (Optimizations.UseSse2)
|
||||
if (Optimizations.UseAdvSimd)
|
||||
{
|
||||
InstEmitSimdHelper32Arm64.EmitVectorBinaryOpSimd32(context, (n, m) => context.AddIntrinsic(Intrinsic.Arm64AndV | Intrinsic.Arm64V128, n, m));
|
||||
}
|
||||
else if (Optimizations.UseSse2)
|
||||
{
|
||||
EmitVectorBinaryOpSimd32(context, (n, m) => context.AddIntrinsic(Intrinsic.X86Pand, n, m));
|
||||
}
|
||||
@ -25,7 +29,11 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
public static void Vbic_I(ArmEmitterContext context)
|
||||
{
|
||||
if (Optimizations.UseSse2)
|
||||
if (Optimizations.UseAdvSimd)
|
||||
{
|
||||
InstEmitSimdHelper32Arm64.EmitVectorBinaryOpSimd32(context, (n, m) => context.AddIntrinsic(Intrinsic.Arm64BicV | Intrinsic.Arm64V128, n, m));
|
||||
}
|
||||
else if (Optimizations.UseSse2)
|
||||
{
|
||||
EmitVectorBinaryOpSimd32(context, (n, m) => context.AddIntrinsic(Intrinsic.X86Pandn, m, n));
|
||||
}
|
||||
@ -73,17 +81,35 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
public static void Vbif(ArmEmitterContext context)
|
||||
{
|
||||
EmitBifBit(context, true);
|
||||
if (Optimizations.UseAdvSimd)
|
||||
{
|
||||
InstEmitSimdHelper32Arm64.EmitVectorTernaryOpSimd32(context, (d, n, m) => context.AddIntrinsic(Intrinsic.Arm64BifV | Intrinsic.Arm64V128, d, n, m));
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitBifBit(context, true);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Vbit(ArmEmitterContext context)
|
||||
{
|
||||
EmitBifBit(context, false);
|
||||
if (Optimizations.UseAdvSimd)
|
||||
{
|
||||
InstEmitSimdHelper32Arm64.EmitVectorTernaryOpSimd32(context, (d, n, m) => context.AddIntrinsic(Intrinsic.Arm64BitV | Intrinsic.Arm64V128, d, n, m));
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitBifBit(context, false);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Vbsl(ArmEmitterContext context)
|
||||
{
|
||||
if (Optimizations.UseSse2)
|
||||
if (Optimizations.UseAdvSimd)
|
||||
{
|
||||
InstEmitSimdHelper32Arm64.EmitVectorTernaryOpSimd32(context, (d, n, m) => context.AddIntrinsic(Intrinsic.Arm64BslV | Intrinsic.Arm64V128, d, n, m));
|
||||
}
|
||||
else if (Optimizations.UseSse2)
|
||||
{
|
||||
EmitVectorTernaryOpSimd32(context, (d, n, m) =>
|
||||
{
|
||||
@ -105,7 +131,11 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
public static void Veor_I(ArmEmitterContext context)
|
||||
{
|
||||
if (Optimizations.UseSse2)
|
||||
if (Optimizations.UseAdvSimd)
|
||||
{
|
||||
InstEmitSimdHelper32Arm64.EmitVectorBinaryOpSimd32(context, (n, m) => context.AddIntrinsic(Intrinsic.Arm64EorV | Intrinsic.Arm64V128, n, m));
|
||||
}
|
||||
else if (Optimizations.UseSse2)
|
||||
{
|
||||
EmitVectorBinaryOpSimd32(context, (n, m) => context.AddIntrinsic(Intrinsic.X86Pxor, n, m));
|
||||
}
|
||||
@ -117,7 +147,11 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
public static void Vorn_I(ArmEmitterContext context)
|
||||
{
|
||||
if (Optimizations.UseSse2)
|
||||
if (Optimizations.UseAdvSimd)
|
||||
{
|
||||
InstEmitSimdHelper32Arm64.EmitVectorBinaryOpSimd32(context, (n, m) => context.AddIntrinsic(Intrinsic.Arm64OrnV | Intrinsic.Arm64V128, n, m));
|
||||
}
|
||||
else if (Optimizations.UseSse2)
|
||||
{
|
||||
Operand mask = context.VectorOne();
|
||||
|
||||
@ -135,7 +169,11 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
public static void Vorr_I(ArmEmitterContext context)
|
||||
{
|
||||
if (Optimizations.UseSse2)
|
||||
if (Optimizations.UseAdvSimd)
|
||||
{
|
||||
InstEmitSimdHelper32Arm64.EmitVectorBinaryOpSimd32(context, (n, m) => context.AddIntrinsic(Intrinsic.Arm64OrrV | Intrinsic.Arm64V128, n, m));
|
||||
}
|
||||
else if (Optimizations.UseSse2)
|
||||
{
|
||||
EmitVectorBinaryOpSimd32(context, (n, m) => context.AddIntrinsic(Intrinsic.X86Por, n, m));
|
||||
}
|
||||
|
@ -392,7 +392,11 @@ namespace ARMeilleure.Instructions
|
||||
{
|
||||
OpCode32SimdCmpZ op = (OpCode32SimdCmpZ)context.CurrOp;
|
||||
|
||||
if (Optimizations.UseSse2)
|
||||
if (Optimizations.UseAdvSimd)
|
||||
{
|
||||
EmitVectorZipUzpOpSimd32(context, Intrinsic.Arm64Zip1V, Intrinsic.Arm64Zip2V);
|
||||
}
|
||||
else if (Optimizations.UseSse2)
|
||||
{
|
||||
EmitVectorShuffleOpSimd32(context, (m, d) =>
|
||||
{
|
||||
@ -461,7 +465,11 @@ namespace ARMeilleure.Instructions
|
||||
{
|
||||
OpCode32SimdCmpZ op = (OpCode32SimdCmpZ)context.CurrOp;
|
||||
|
||||
if (Optimizations.UseSsse3)
|
||||
if (Optimizations.UseAdvSimd)
|
||||
{
|
||||
EmitVectorZipUzpOpSimd32(context, Intrinsic.Arm64Uzp1V, Intrinsic.Arm64Uzp2V);
|
||||
}
|
||||
else if (Optimizations.UseSsse3)
|
||||
{
|
||||
EmitVectorShuffleOpSimd32(context, (m, d) =>
|
||||
{
|
||||
@ -559,6 +567,52 @@ namespace ARMeilleure.Instructions
|
||||
}
|
||||
}
|
||||
|
||||
private static void EmitVectorZipUzpOpSimd32(ArmEmitterContext context, Intrinsic inst1, Intrinsic inst2)
|
||||
{
|
||||
OpCode32SimdCmpZ op = (OpCode32SimdCmpZ)context.CurrOp;
|
||||
|
||||
bool overlap = op.Qm == op.Qd;
|
||||
|
||||
Operand d = GetVecA32(op.Qd);
|
||||
Operand m = GetVecA32(op.Qm);
|
||||
|
||||
Operand dPart = d;
|
||||
Operand mPart = m;
|
||||
|
||||
if (!op.Q) // Register swap: move relevant doubleword to destination side.
|
||||
{
|
||||
dPart = InstEmitSimdHelper32Arm64.EmitMoveDoubleWordToSide(context, d, op.Vd, 0);
|
||||
mPart = InstEmitSimdHelper32Arm64.EmitMoveDoubleWordToSide(context, m, op.Vm, 0);
|
||||
}
|
||||
|
||||
Intrinsic vSize = op.Q ? Intrinsic.Arm64V128 : Intrinsic.Arm64V64;
|
||||
|
||||
vSize |= (Intrinsic)(op.Size << (int)Intrinsic.Arm64VSizeShift);
|
||||
|
||||
Operand resD = context.AddIntrinsic(inst1 | vSize, dPart, mPart);
|
||||
Operand resM = context.AddIntrinsic(inst2 | vSize, dPart, mPart);
|
||||
|
||||
if (!op.Q) // Register insert.
|
||||
{
|
||||
resD = context.AddIntrinsic(Intrinsic.Arm64InsVe | Intrinsic.Arm64VDWord, d, Const(op.Vd & 1), resD, Const(0));
|
||||
|
||||
if (overlap)
|
||||
{
|
||||
resD = context.AddIntrinsic(Intrinsic.Arm64InsVe | Intrinsic.Arm64VDWord, resD, Const(op.Vm & 1), resM, Const(0));
|
||||
}
|
||||
else
|
||||
{
|
||||
resM = context.AddIntrinsic(Intrinsic.Arm64InsVe | Intrinsic.Arm64VDWord, m, Const(op.Vm & 1), resM, Const(0));
|
||||
}
|
||||
}
|
||||
|
||||
context.Copy(d, resD);
|
||||
if (!overlap)
|
||||
{
|
||||
context.Copy(m, resM);
|
||||
}
|
||||
}
|
||||
|
||||
private static void EmitVectorShuffleOpSimd32(ArmEmitterContext context, Func<Operand, Operand, (Operand, Operand)> shuffleFunc)
|
||||
{
|
||||
OpCode32Simd op = (OpCode32Simd)context.CurrOp;
|
||||
|
@ -26,7 +26,15 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
public static void Rshrn_V(ArmEmitterContext context)
|
||||
{
|
||||
if (Optimizations.UseSsse3)
|
||||
if (Optimizations.UseAdvSimd)
|
||||
{
|
||||
OpCodeSimdShImm op = (OpCodeSimdShImm)context.CurrOp;
|
||||
|
||||
int shift = GetImmShr(op);
|
||||
|
||||
InstEmitSimdHelperArm64.EmitVectorShiftTernaryOpRd(context, Intrinsic.Arm64RshrnV, shift);
|
||||
}
|
||||
else if (Optimizations.UseSsse3)
|
||||
{
|
||||
OpCodeSimdShImm op = (OpCodeSimdShImm)context.CurrOp;
|
||||
|
||||
@ -80,7 +88,14 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
int shift = GetImmShl(op);
|
||||
|
||||
EmitScalarUnaryOpZx(context, (op1) => context.ShiftLeft(op1, Const(shift)));
|
||||
if (Optimizations.UseAdvSimd)
|
||||
{
|
||||
InstEmitSimdHelperArm64.EmitScalarShiftBinaryOp(context, Intrinsic.Arm64ShlS, shift);
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitScalarUnaryOpZx(context, (op1) => context.ShiftLeft(op1, Const(shift)));
|
||||
}
|
||||
}
|
||||
|
||||
public static void Shl_V(ArmEmitterContext context)
|
||||
@ -90,7 +105,11 @@ namespace ARMeilleure.Instructions
|
||||
int shift = GetImmShl(op);
|
||||
int eSize = 8 << op.Size;
|
||||
|
||||
if (shift >= eSize)
|
||||
if (Optimizations.UseAdvSimd)
|
||||
{
|
||||
InstEmitSimdHelperArm64.EmitVectorShiftBinaryOp(context, Intrinsic.Arm64ShlV, shift);
|
||||
}
|
||||
else if (shift >= eSize)
|
||||
{
|
||||
if ((op.RegisterSize == RegisterSize.Simd64))
|
||||
{
|
||||
@ -143,7 +162,11 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
int shift = 8 << op.Size;
|
||||
|
||||
if (Optimizations.UseSse41)
|
||||
if (Optimizations.UseAdvSimd)
|
||||
{
|
||||
InstEmitSimdHelperArm64.EmitVectorUnaryOp(context, Intrinsic.Arm64ShllV);
|
||||
}
|
||||
else if (Optimizations.UseSse41)
|
||||
{
|
||||
Operand n = GetVec(op.Rn);
|
||||
|
||||
@ -170,7 +193,15 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
public static void Shrn_V(ArmEmitterContext context)
|
||||
{
|
||||
if (Optimizations.UseSsse3)
|
||||
if (Optimizations.UseAdvSimd)
|
||||
{
|
||||
OpCodeSimdShImm op = (OpCodeSimdShImm)context.CurrOp;
|
||||
|
||||
int shift = GetImmShr(op);
|
||||
|
||||
InstEmitSimdHelperArm64.EmitVectorShiftTernaryOpRd(context, Intrinsic.Arm64ShrnV, shift);
|
||||
}
|
||||
else if (Optimizations.UseSsse3)
|
||||
{
|
||||
OpCodeSimdShImm op = (OpCodeSimdShImm)context.CurrOp;
|
||||
|
||||
@ -205,89 +236,259 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
public static void Sli_S(ArmEmitterContext context)
|
||||
{
|
||||
EmitSli(context, scalar: true);
|
||||
if (Optimizations.UseAdvSimd)
|
||||
{
|
||||
OpCodeSimdShImm op = (OpCodeSimdShImm)context.CurrOp;
|
||||
|
||||
int shift = GetImmShl(op);
|
||||
|
||||
InstEmitSimdHelperArm64.EmitScalarShiftTernaryOpRd(context, Intrinsic.Arm64SliS, shift);
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitSli(context, scalar: true);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Sli_V(ArmEmitterContext context)
|
||||
{
|
||||
EmitSli(context, scalar: false);
|
||||
if (Optimizations.UseAdvSimd)
|
||||
{
|
||||
OpCodeSimdShImm op = (OpCodeSimdShImm)context.CurrOp;
|
||||
|
||||
int shift = GetImmShl(op);
|
||||
|
||||
InstEmitSimdHelperArm64.EmitVectorShiftTernaryOpRd(context, Intrinsic.Arm64SliV, shift);
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitSli(context, scalar: false);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Sqrshl_V(ArmEmitterContext context)
|
||||
{
|
||||
EmitShlRegOp(context, ShlRegFlags.Signed | ShlRegFlags.Round | ShlRegFlags.Saturating);
|
||||
if (Optimizations.UseAdvSimd)
|
||||
{
|
||||
InstEmitSimdHelperArm64.EmitVectorSaturatingBinaryOp(context, Intrinsic.Arm64SqrshlV);
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitShlRegOp(context, ShlRegFlags.Signed | ShlRegFlags.Round | ShlRegFlags.Saturating);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Sqrshrn_S(ArmEmitterContext context)
|
||||
{
|
||||
EmitRoundShrImmSaturatingNarrowOp(context, ShrImmSaturatingNarrowFlags.ScalarSxSx);
|
||||
if (Optimizations.UseAdvSimd)
|
||||
{
|
||||
OpCodeSimdShImm op = (OpCodeSimdShImm)context.CurrOp;
|
||||
|
||||
int shift = GetImmShr(op);
|
||||
|
||||
InstEmitSimdHelperArm64.EmitScalarSaturatingShiftTernaryOpRd(context, Intrinsic.Arm64SqrshrnS, shift);
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitRoundShrImmSaturatingNarrowOp(context, ShrImmSaturatingNarrowFlags.ScalarSxSx);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Sqrshrn_V(ArmEmitterContext context)
|
||||
{
|
||||
EmitRoundShrImmSaturatingNarrowOp(context, ShrImmSaturatingNarrowFlags.VectorSxSx);
|
||||
if (Optimizations.UseAdvSimd)
|
||||
{
|
||||
OpCodeSimdShImm op = (OpCodeSimdShImm)context.CurrOp;
|
||||
|
||||
int shift = GetImmShr(op);
|
||||
|
||||
InstEmitSimdHelperArm64.EmitVectorSaturatingShiftTernaryOpRd(context, Intrinsic.Arm64SqrshrnV, shift);
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitRoundShrImmSaturatingNarrowOp(context, ShrImmSaturatingNarrowFlags.VectorSxSx);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Sqrshrun_S(ArmEmitterContext context)
|
||||
{
|
||||
EmitRoundShrImmSaturatingNarrowOp(context, ShrImmSaturatingNarrowFlags.ScalarSxZx);
|
||||
if (Optimizations.UseAdvSimd)
|
||||
{
|
||||
OpCodeSimdShImm op = (OpCodeSimdShImm)context.CurrOp;
|
||||
|
||||
int shift = GetImmShr(op);
|
||||
|
||||
InstEmitSimdHelperArm64.EmitScalarSaturatingShiftTernaryOpRd(context, Intrinsic.Arm64SqrshrunS, shift);
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitRoundShrImmSaturatingNarrowOp(context, ShrImmSaturatingNarrowFlags.ScalarSxZx);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Sqrshrun_V(ArmEmitterContext context)
|
||||
{
|
||||
EmitRoundShrImmSaturatingNarrowOp(context, ShrImmSaturatingNarrowFlags.VectorSxZx);
|
||||
if (Optimizations.UseAdvSimd)
|
||||
{
|
||||
OpCodeSimdShImm op = (OpCodeSimdShImm)context.CurrOp;
|
||||
|
||||
int shift = GetImmShr(op);
|
||||
|
||||
InstEmitSimdHelperArm64.EmitVectorSaturatingShiftTernaryOpRd(context, Intrinsic.Arm64SqrshrunV, shift);
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitRoundShrImmSaturatingNarrowOp(context, ShrImmSaturatingNarrowFlags.VectorSxZx);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Sqshl_V(ArmEmitterContext context)
|
||||
{
|
||||
EmitShlRegOp(context, ShlRegFlags.Signed | ShlRegFlags.Saturating);
|
||||
if (Optimizations.UseAdvSimd)
|
||||
{
|
||||
InstEmitSimdHelperArm64.EmitVectorSaturatingBinaryOp(context, Intrinsic.Arm64SqshlV);
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitShlRegOp(context, ShlRegFlags.Signed | ShlRegFlags.Saturating);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Sqshrn_S(ArmEmitterContext context)
|
||||
{
|
||||
EmitShrImmSaturatingNarrowOp(context, ShrImmSaturatingNarrowFlags.ScalarSxSx);
|
||||
if (Optimizations.UseAdvSimd)
|
||||
{
|
||||
OpCodeSimdShImm op = (OpCodeSimdShImm)context.CurrOp;
|
||||
|
||||
int shift = GetImmShr(op);
|
||||
|
||||
InstEmitSimdHelperArm64.EmitScalarSaturatingShiftTernaryOpRd(context, Intrinsic.Arm64SqshrnS, shift);
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitShrImmSaturatingNarrowOp(context, ShrImmSaturatingNarrowFlags.ScalarSxSx);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Sqshrn_V(ArmEmitterContext context)
|
||||
{
|
||||
EmitShrImmSaturatingNarrowOp(context, ShrImmSaturatingNarrowFlags.VectorSxSx);
|
||||
if (Optimizations.UseAdvSimd)
|
||||
{
|
||||
OpCodeSimdShImm op = (OpCodeSimdShImm)context.CurrOp;
|
||||
|
||||
int shift = GetImmShr(op);
|
||||
|
||||
InstEmitSimdHelperArm64.EmitVectorSaturatingShiftTernaryOpRd(context, Intrinsic.Arm64SqshrnV, shift);
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitShrImmSaturatingNarrowOp(context, ShrImmSaturatingNarrowFlags.VectorSxSx);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Sqshrun_S(ArmEmitterContext context)
|
||||
{
|
||||
EmitShrImmSaturatingNarrowOp(context, ShrImmSaturatingNarrowFlags.ScalarSxZx);
|
||||
if (Optimizations.UseAdvSimd)
|
||||
{
|
||||
OpCodeSimdShImm op = (OpCodeSimdShImm)context.CurrOp;
|
||||
|
||||
int shift = GetImmShr(op);
|
||||
|
||||
InstEmitSimdHelperArm64.EmitScalarSaturatingShiftTernaryOpRd(context, Intrinsic.Arm64SqshrunS, shift);
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitShrImmSaturatingNarrowOp(context, ShrImmSaturatingNarrowFlags.ScalarSxZx);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Sqshrun_V(ArmEmitterContext context)
|
||||
{
|
||||
EmitShrImmSaturatingNarrowOp(context, ShrImmSaturatingNarrowFlags.VectorSxZx);
|
||||
if (Optimizations.UseAdvSimd)
|
||||
{
|
||||
OpCodeSimdShImm op = (OpCodeSimdShImm)context.CurrOp;
|
||||
|
||||
int shift = GetImmShr(op);
|
||||
|
||||
InstEmitSimdHelperArm64.EmitVectorSaturatingShiftTernaryOpRd(context, Intrinsic.Arm64SqshrunV, shift);
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitShrImmSaturatingNarrowOp(context, ShrImmSaturatingNarrowFlags.VectorSxZx);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Sri_S(ArmEmitterContext context)
|
||||
{
|
||||
EmitSri(context, scalar: true);
|
||||
if (Optimizations.UseAdvSimd)
|
||||
{
|
||||
OpCodeSimdShImm op = (OpCodeSimdShImm)context.CurrOp;
|
||||
|
||||
int shift = GetImmShr(op);
|
||||
|
||||
InstEmitSimdHelperArm64.EmitScalarShiftTernaryOpRd(context, Intrinsic.Arm64SriS, shift);
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitSri(context, scalar: true);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Sri_V(ArmEmitterContext context)
|
||||
{
|
||||
EmitSri(context, scalar: false);
|
||||
if (Optimizations.UseAdvSimd)
|
||||
{
|
||||
OpCodeSimdShImm op = (OpCodeSimdShImm)context.CurrOp;
|
||||
|
||||
int shift = GetImmShr(op);
|
||||
|
||||
InstEmitSimdHelperArm64.EmitVectorShiftTernaryOpRd(context, Intrinsic.Arm64SriV, shift);
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitSri(context, scalar: false);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Srshl_V(ArmEmitterContext context)
|
||||
{
|
||||
EmitShlRegOp(context, ShlRegFlags.Signed | ShlRegFlags.Round);
|
||||
if (Optimizations.UseAdvSimd)
|
||||
{
|
||||
InstEmitSimdHelperArm64.EmitVectorBinaryOp(context, Intrinsic.Arm64SrshlV);
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitShlRegOp(context, ShlRegFlags.Signed | ShlRegFlags.Round);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Srshr_S(ArmEmitterContext context)
|
||||
{
|
||||
EmitScalarShrImmOpSx(context, ShrImmFlags.Round);
|
||||
if (Optimizations.UseAdvSimd)
|
||||
{
|
||||
OpCodeSimdShImm op = (OpCodeSimdShImm)context.CurrOp;
|
||||
|
||||
int shift = GetImmShr(op);
|
||||
|
||||
InstEmitSimdHelperArm64.EmitScalarShiftBinaryOp(context, Intrinsic.Arm64SrshrS, shift);
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitScalarShrImmOpSx(context, ShrImmFlags.Round);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Srshr_V(ArmEmitterContext context)
|
||||
{
|
||||
OpCodeSimdShImm op = (OpCodeSimdShImm)context.CurrOp;
|
||||
|
||||
if (Optimizations.UseSse2 && op.Size > 0 && op.Size < 3)
|
||||
if (Optimizations.UseAdvSimd)
|
||||
{
|
||||
int shift = GetImmShr(op);
|
||||
|
||||
InstEmitSimdHelperArm64.EmitVectorShiftBinaryOp(context, Intrinsic.Arm64SrshrV, shift);
|
||||
}
|
||||
else if (Optimizations.UseSse2 && op.Size > 0 && op.Size < 3)
|
||||
{
|
||||
int shift = GetImmShr(op);
|
||||
int eSize = 8 << op.Size;
|
||||
@ -325,14 +526,31 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
public static void Srsra_S(ArmEmitterContext context)
|
||||
{
|
||||
EmitScalarShrImmOpSx(context, ShrImmFlags.Round | ShrImmFlags.Accumulate);
|
||||
if (Optimizations.UseAdvSimd)
|
||||
{
|
||||
OpCodeSimdShImm op = (OpCodeSimdShImm)context.CurrOp;
|
||||
|
||||
int shift = GetImmShr(op);
|
||||
|
||||
InstEmitSimdHelperArm64.EmitScalarShiftTernaryOpRd(context, Intrinsic.Arm64SrsraS, shift);
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitScalarShrImmOpSx(context, ShrImmFlags.Round | ShrImmFlags.Accumulate);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Srsra_V(ArmEmitterContext context)
|
||||
{
|
||||
OpCodeSimdShImm op = (OpCodeSimdShImm)context.CurrOp;
|
||||
|
||||
if (Optimizations.UseSse2 && op.Size > 0 && op.Size < 3)
|
||||
if (Optimizations.UseAdvSimd)
|
||||
{
|
||||
int shift = GetImmShr(op);
|
||||
|
||||
InstEmitSimdHelperArm64.EmitVectorShiftTernaryOpRd(context, Intrinsic.Arm64SrsraV, shift);
|
||||
}
|
||||
else if (Optimizations.UseSse2 && op.Size > 0 && op.Size < 3)
|
||||
{
|
||||
int shift = GetImmShr(op);
|
||||
int eSize = 8 << op.Size;
|
||||
@ -372,12 +590,26 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
public static void Sshl_S(ArmEmitterContext context)
|
||||
{
|
||||
EmitShlRegOp(context, ShlRegFlags.Scalar | ShlRegFlags.Signed);
|
||||
if (Optimizations.UseAdvSimd)
|
||||
{
|
||||
InstEmitSimdHelperArm64.EmitScalarBinaryOp(context, Intrinsic.Arm64SshlS);
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitShlRegOp(context, ShlRegFlags.Scalar | ShlRegFlags.Signed);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Sshl_V(ArmEmitterContext context)
|
||||
{
|
||||
EmitShlRegOp(context, ShlRegFlags.Signed);
|
||||
if (Optimizations.UseAdvSimd)
|
||||
{
|
||||
InstEmitSimdHelperArm64.EmitVectorBinaryOp(context, Intrinsic.Arm64SshlV);
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitShlRegOp(context, ShlRegFlags.Signed);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Sshll_V(ArmEmitterContext context)
|
||||
@ -386,7 +618,11 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
int shift = GetImmShl(op);
|
||||
|
||||
if (Optimizations.UseSse41)
|
||||
if (Optimizations.UseAdvSimd)
|
||||
{
|
||||
InstEmitSimdHelperArm64.EmitVectorShiftBinaryOp(context, Intrinsic.Arm64SshllV, shift);
|
||||
}
|
||||
else if (Optimizations.UseSse41)
|
||||
{
|
||||
Operand n = GetVec(op.Rn);
|
||||
|
||||
@ -416,7 +652,18 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
public static void Sshr_S(ArmEmitterContext context)
|
||||
{
|
||||
EmitShrImmOp(context, ShrImmFlags.ScalarSx);
|
||||
if (Optimizations.UseAdvSimd)
|
||||
{
|
||||
OpCodeSimdShImm op = (OpCodeSimdShImm)context.CurrOp;
|
||||
|
||||
int shift = GetImmShr(op);
|
||||
|
||||
InstEmitSimdHelperArm64.EmitScalarShiftBinaryOp(context, Intrinsic.Arm64SshrS, shift);
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitShrImmOp(context, ShrImmFlags.ScalarSx);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Sshr_V(ArmEmitterContext context)
|
||||
@ -425,7 +672,11 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
int shift = GetImmShr(op);
|
||||
|
||||
if (Optimizations.UseGfni && op.Size == 0)
|
||||
if (Optimizations.UseAdvSimd)
|
||||
{
|
||||
InstEmitSimdHelperArm64.EmitVectorShiftBinaryOp(context, Intrinsic.Arm64SshrV, shift);
|
||||
}
|
||||
else if (Optimizations.UseGfni && op.Size == 0)
|
||||
{
|
||||
Operand n = GetVec(op.Rn);
|
||||
|
||||
@ -478,14 +729,31 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
public static void Ssra_S(ArmEmitterContext context)
|
||||
{
|
||||
EmitScalarShrImmOpSx(context, ShrImmFlags.Accumulate);
|
||||
if (Optimizations.UseAdvSimd)
|
||||
{
|
||||
OpCodeSimdShImm op = (OpCodeSimdShImm)context.CurrOp;
|
||||
|
||||
int shift = GetImmShr(op);
|
||||
|
||||
InstEmitSimdHelperArm64.EmitScalarShiftTernaryOpRd(context, Intrinsic.Arm64SsraS, shift);
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitScalarShrImmOpSx(context, ShrImmFlags.Accumulate);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Ssra_V(ArmEmitterContext context)
|
||||
{
|
||||
OpCodeSimdShImm op = (OpCodeSimdShImm)context.CurrOp;
|
||||
|
||||
if (Optimizations.UseSse2 && op.Size > 0 && op.Size < 3)
|
||||
if (Optimizations.UseAdvSimd)
|
||||
{
|
||||
int shift = GetImmShr(op);
|
||||
|
||||
InstEmitSimdHelperArm64.EmitVectorShiftTernaryOpRd(context, Intrinsic.Arm64SsraV, shift);
|
||||
}
|
||||
else if (Optimizations.UseSse2 && op.Size > 0 && op.Size < 3)
|
||||
{
|
||||
int shift = GetImmShr(op);
|
||||
|
||||
@ -515,49 +783,131 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
public static void Uqrshl_V(ArmEmitterContext context)
|
||||
{
|
||||
EmitShlRegOp(context, ShlRegFlags.Round | ShlRegFlags.Saturating);
|
||||
if (Optimizations.UseAdvSimd)
|
||||
{
|
||||
InstEmitSimdHelperArm64.EmitVectorSaturatingBinaryOp(context, Intrinsic.Arm64UqrshlV);
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitShlRegOp(context, ShlRegFlags.Round | ShlRegFlags.Saturating);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Uqrshrn_S(ArmEmitterContext context)
|
||||
{
|
||||
EmitRoundShrImmSaturatingNarrowOp(context, ShrImmSaturatingNarrowFlags.ScalarZxZx);
|
||||
if (Optimizations.UseAdvSimd)
|
||||
{
|
||||
OpCodeSimdShImm op = (OpCodeSimdShImm)context.CurrOp;
|
||||
|
||||
int shift = GetImmShr(op);
|
||||
|
||||
InstEmitSimdHelperArm64.EmitScalarSaturatingShiftTernaryOpRd(context, Intrinsic.Arm64UqrshrnS, shift);
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitRoundShrImmSaturatingNarrowOp(context, ShrImmSaturatingNarrowFlags.ScalarZxZx);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Uqrshrn_V(ArmEmitterContext context)
|
||||
{
|
||||
EmitRoundShrImmSaturatingNarrowOp(context, ShrImmSaturatingNarrowFlags.VectorZxZx);
|
||||
if (Optimizations.UseAdvSimd)
|
||||
{
|
||||
OpCodeSimdShImm op = (OpCodeSimdShImm)context.CurrOp;
|
||||
|
||||
int shift = GetImmShr(op);
|
||||
|
||||
InstEmitSimdHelperArm64.EmitVectorSaturatingShiftTernaryOpRd(context, Intrinsic.Arm64UqrshrnV, shift);
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitRoundShrImmSaturatingNarrowOp(context, ShrImmSaturatingNarrowFlags.VectorZxZx);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Uqshl_V(ArmEmitterContext context)
|
||||
{
|
||||
EmitShlRegOp(context, ShlRegFlags.Saturating);
|
||||
if (Optimizations.UseAdvSimd)
|
||||
{
|
||||
InstEmitSimdHelperArm64.EmitVectorSaturatingBinaryOp(context, Intrinsic.Arm64UqshlV);
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitShlRegOp(context, ShlRegFlags.Saturating);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Uqshrn_S(ArmEmitterContext context)
|
||||
{
|
||||
EmitShrImmSaturatingNarrowOp(context, ShrImmSaturatingNarrowFlags.ScalarZxZx);
|
||||
if (Optimizations.UseAdvSimd)
|
||||
{
|
||||
OpCodeSimdShImm op = (OpCodeSimdShImm)context.CurrOp;
|
||||
|
||||
int shift = GetImmShr(op);
|
||||
|
||||
InstEmitSimdHelperArm64.EmitScalarSaturatingShiftTernaryOpRd(context, Intrinsic.Arm64UqshrnS, shift);
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitShrImmSaturatingNarrowOp(context, ShrImmSaturatingNarrowFlags.ScalarZxZx);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Uqshrn_V(ArmEmitterContext context)
|
||||
{
|
||||
EmitShrImmSaturatingNarrowOp(context, ShrImmSaturatingNarrowFlags.VectorZxZx);
|
||||
if (Optimizations.UseAdvSimd)
|
||||
{
|
||||
OpCodeSimdShImm op = (OpCodeSimdShImm)context.CurrOp;
|
||||
|
||||
int shift = GetImmShr(op);
|
||||
|
||||
InstEmitSimdHelperArm64.EmitVectorSaturatingShiftTernaryOpRd(context, Intrinsic.Arm64UqshrnV, shift);
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitShrImmSaturatingNarrowOp(context, ShrImmSaturatingNarrowFlags.VectorZxZx);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Urshl_V(ArmEmitterContext context)
|
||||
{
|
||||
EmitShlRegOp(context, ShlRegFlags.Round);
|
||||
if (Optimizations.UseAdvSimd)
|
||||
{
|
||||
InstEmitSimdHelperArm64.EmitVectorBinaryOp(context, Intrinsic.Arm64UrshlV);
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitShlRegOp(context, ShlRegFlags.Round);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Urshr_S(ArmEmitterContext context)
|
||||
{
|
||||
EmitScalarShrImmOpZx(context, ShrImmFlags.Round);
|
||||
if (Optimizations.UseAdvSimd)
|
||||
{
|
||||
OpCodeSimdShImm op = (OpCodeSimdShImm)context.CurrOp;
|
||||
|
||||
int shift = GetImmShr(op);
|
||||
|
||||
InstEmitSimdHelperArm64.EmitScalarShiftBinaryOp(context, Intrinsic.Arm64UrshrS, shift);
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitScalarShrImmOpZx(context, ShrImmFlags.Round);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Urshr_V(ArmEmitterContext context)
|
||||
{
|
||||
OpCodeSimdShImm op = (OpCodeSimdShImm)context.CurrOp;
|
||||
|
||||
if (Optimizations.UseSse2 && op.Size > 0)
|
||||
if (Optimizations.UseAdvSimd)
|
||||
{
|
||||
int shift = GetImmShr(op);
|
||||
|
||||
InstEmitSimdHelperArm64.EmitVectorShiftBinaryOp(context, Intrinsic.Arm64UrshrV, shift);
|
||||
}
|
||||
else if (Optimizations.UseSse2 && op.Size > 0)
|
||||
{
|
||||
int shift = GetImmShr(op);
|
||||
int eSize = 8 << op.Size;
|
||||
@ -593,14 +943,31 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
public static void Ursra_S(ArmEmitterContext context)
|
||||
{
|
||||
EmitScalarShrImmOpZx(context, ShrImmFlags.Round | ShrImmFlags.Accumulate);
|
||||
if (Optimizations.UseAdvSimd)
|
||||
{
|
||||
OpCodeSimdShImm op = (OpCodeSimdShImm)context.CurrOp;
|
||||
|
||||
int shift = GetImmShr(op);
|
||||
|
||||
InstEmitSimdHelperArm64.EmitScalarShiftTernaryOpRd(context, Intrinsic.Arm64UrsraS, shift);
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitScalarShrImmOpZx(context, ShrImmFlags.Round | ShrImmFlags.Accumulate);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Ursra_V(ArmEmitterContext context)
|
||||
{
|
||||
OpCodeSimdShImm op = (OpCodeSimdShImm)context.CurrOp;
|
||||
|
||||
if (Optimizations.UseSse2 && op.Size > 0)
|
||||
if (Optimizations.UseAdvSimd)
|
||||
{
|
||||
int shift = GetImmShr(op);
|
||||
|
||||
InstEmitSimdHelperArm64.EmitVectorShiftTernaryOpRd(context, Intrinsic.Arm64UrsraV, shift);
|
||||
}
|
||||
else if (Optimizations.UseSse2 && op.Size > 0)
|
||||
{
|
||||
int shift = GetImmShr(op);
|
||||
int eSize = 8 << op.Size;
|
||||
@ -638,12 +1005,26 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
public static void Ushl_S(ArmEmitterContext context)
|
||||
{
|
||||
EmitShlRegOp(context, ShlRegFlags.Scalar);
|
||||
if (Optimizations.UseAdvSimd)
|
||||
{
|
||||
InstEmitSimdHelperArm64.EmitScalarBinaryOp(context, Intrinsic.Arm64UshlS);
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitShlRegOp(context, ShlRegFlags.Scalar);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Ushl_V(ArmEmitterContext context)
|
||||
{
|
||||
EmitShlRegOp(context, ShlRegFlags.None);
|
||||
if (Optimizations.UseAdvSimd)
|
||||
{
|
||||
InstEmitSimdHelperArm64.EmitVectorBinaryOp(context, Intrinsic.Arm64UshlV);
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitShlRegOp(context, ShlRegFlags.None);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Ushll_V(ArmEmitterContext context)
|
||||
@ -652,7 +1033,11 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
int shift = GetImmShl(op);
|
||||
|
||||
if (Optimizations.UseSse41)
|
||||
if (Optimizations.UseAdvSimd)
|
||||
{
|
||||
InstEmitSimdHelperArm64.EmitVectorShiftBinaryOp(context, Intrinsic.Arm64UshllV, shift);
|
||||
}
|
||||
else if (Optimizations.UseSse41)
|
||||
{
|
||||
Operand n = GetVec(op.Rn);
|
||||
|
||||
@ -682,14 +1067,31 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
public static void Ushr_S(ArmEmitterContext context)
|
||||
{
|
||||
EmitShrImmOp(context, ShrImmFlags.ScalarZx);
|
||||
if (Optimizations.UseAdvSimd)
|
||||
{
|
||||
OpCodeSimdShImm op = (OpCodeSimdShImm)context.CurrOp;
|
||||
|
||||
int shift = GetImmShr(op);
|
||||
|
||||
InstEmitSimdHelperArm64.EmitScalarShiftBinaryOp(context, Intrinsic.Arm64UshrS, shift);
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitShrImmOp(context, ShrImmFlags.ScalarZx);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Ushr_V(ArmEmitterContext context)
|
||||
{
|
||||
OpCodeSimdShImm op = (OpCodeSimdShImm)context.CurrOp;
|
||||
|
||||
if (Optimizations.UseSse2 && op.Size > 0)
|
||||
if (Optimizations.UseAdvSimd)
|
||||
{
|
||||
int shift = GetImmShr(op);
|
||||
|
||||
InstEmitSimdHelperArm64.EmitVectorShiftBinaryOp(context, Intrinsic.Arm64UshrV, shift);
|
||||
}
|
||||
else if (Optimizations.UseSse2 && op.Size > 0)
|
||||
{
|
||||
int shift = GetImmShr(op);
|
||||
|
||||
@ -714,14 +1116,31 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
public static void Usra_S(ArmEmitterContext context)
|
||||
{
|
||||
EmitScalarShrImmOpZx(context, ShrImmFlags.Accumulate);
|
||||
if (Optimizations.UseAdvSimd)
|
||||
{
|
||||
OpCodeSimdShImm op = (OpCodeSimdShImm)context.CurrOp;
|
||||
|
||||
int shift = GetImmShr(op);
|
||||
|
||||
InstEmitSimdHelperArm64.EmitScalarShiftTernaryOpRd(context, Intrinsic.Arm64UsraS, shift);
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitScalarShrImmOpZx(context, ShrImmFlags.Accumulate);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Usra_V(ArmEmitterContext context)
|
||||
{
|
||||
OpCodeSimdShImm op = (OpCodeSimdShImm)context.CurrOp;
|
||||
|
||||
if (Optimizations.UseSse2 && op.Size > 0)
|
||||
if (Optimizations.UseAdvSimd)
|
||||
{
|
||||
int shift = GetImmShr(op);
|
||||
|
||||
InstEmitSimdHelperArm64.EmitVectorShiftTernaryOpRd(context, Intrinsic.Arm64UsraV, shift);
|
||||
}
|
||||
else if (Optimizations.UseSse2 && op.Size > 0)
|
||||
{
|
||||
int shift = GetImmShr(op);
|
||||
|
||||
|
@ -150,6 +150,8 @@ namespace ARMeilleure.Instructions
|
||||
{
|
||||
OpCodeSystem op = (OpCodeSystem)context.CurrOp;
|
||||
|
||||
context.SyncQcFlag();
|
||||
|
||||
Operand fpsr = Const(0);
|
||||
|
||||
for (int flag = 0; flag < RegisterConsts.FpFlagsCount; flag++)
|
||||
@ -196,6 +198,8 @@ namespace ARMeilleure.Instructions
|
||||
{
|
||||
OpCodeSystem op = (OpCodeSystem)context.CurrOp;
|
||||
|
||||
context.ClearQcFlagIfModified();
|
||||
|
||||
Operand fpsr = GetIntOrZR(context, op.Rt);
|
||||
fpsr = context.ConvertI64ToI32(fpsr);
|
||||
|
||||
|
@ -191,7 +191,7 @@ namespace ARMeilleure.Instructions
|
||||
{
|
||||
TranslatedFunction function = Context.Translator.GetOrTranslate(address, GetContext().ExecutionMode);
|
||||
|
||||
return (ulong)function.FuncPtr.ToInt64();
|
||||
return (ulong)function.FuncPointer.ToInt64();
|
||||
}
|
||||
|
||||
public static void InvalidateCacheLine(ulong address)
|
||||
|
@ -2,6 +2,8 @@ namespace ARMeilleure.IntermediateRepresentation
|
||||
{
|
||||
enum Intrinsic : ushort
|
||||
{
|
||||
// X86 (SSE and AVX)
|
||||
|
||||
X86Addpd,
|
||||
X86Addps,
|
||||
X86Addsd,
|
||||
@ -172,6 +174,458 @@ namespace ARMeilleure.IntermediateRepresentation
|
||||
X86Vfnmsub231sd,
|
||||
X86Vfnmsub231ss,
|
||||
X86Xorpd,
|
||||
X86Xorps
|
||||
X86Xorps,
|
||||
|
||||
// Arm64 (FP and Advanced SIMD)
|
||||
|
||||
Arm64AbsS,
|
||||
Arm64AbsV,
|
||||
Arm64AddhnV,
|
||||
Arm64AddpS,
|
||||
Arm64AddpV,
|
||||
Arm64AddvV,
|
||||
Arm64AddS,
|
||||
Arm64AddV,
|
||||
Arm64AesdV,
|
||||
Arm64AeseV,
|
||||
Arm64AesimcV,
|
||||
Arm64AesmcV,
|
||||
Arm64AndV,
|
||||
Arm64BicVi,
|
||||
Arm64BicV,
|
||||
Arm64BifV,
|
||||
Arm64BitV,
|
||||
Arm64BslV,
|
||||
Arm64ClsV,
|
||||
Arm64ClzV,
|
||||
Arm64CmeqS,
|
||||
Arm64CmeqV,
|
||||
Arm64CmeqSz,
|
||||
Arm64CmeqVz,
|
||||
Arm64CmgeS,
|
||||
Arm64CmgeV,
|
||||
Arm64CmgeSz,
|
||||
Arm64CmgeVz,
|
||||
Arm64CmgtS,
|
||||
Arm64CmgtV,
|
||||
Arm64CmgtSz,
|
||||
Arm64CmgtVz,
|
||||
Arm64CmhiS,
|
||||
Arm64CmhiV,
|
||||
Arm64CmhsS,
|
||||
Arm64CmhsV,
|
||||
Arm64CmleSz,
|
||||
Arm64CmleVz,
|
||||
Arm64CmltSz,
|
||||
Arm64CmltVz,
|
||||
Arm64CmtstS,
|
||||
Arm64CmtstV,
|
||||
Arm64CntV,
|
||||
Arm64DupSe,
|
||||
Arm64DupVe,
|
||||
Arm64DupGp,
|
||||
Arm64EorV,
|
||||
Arm64ExtV,
|
||||
Arm64FabdS,
|
||||
Arm64FabdV,
|
||||
Arm64FabsV,
|
||||
Arm64FabsS,
|
||||
Arm64FacgeS,
|
||||
Arm64FacgeV,
|
||||
Arm64FacgtS,
|
||||
Arm64FacgtV,
|
||||
Arm64FaddpS,
|
||||
Arm64FaddpV,
|
||||
Arm64FaddV,
|
||||
Arm64FaddS,
|
||||
Arm64FccmpeS,
|
||||
Arm64FccmpS,
|
||||
Arm64FcmeqS,
|
||||
Arm64FcmeqV,
|
||||
Arm64FcmeqSz,
|
||||
Arm64FcmeqVz,
|
||||
Arm64FcmgeS,
|
||||
Arm64FcmgeV,
|
||||
Arm64FcmgeSz,
|
||||
Arm64FcmgeVz,
|
||||
Arm64FcmgtS,
|
||||
Arm64FcmgtV,
|
||||
Arm64FcmgtSz,
|
||||
Arm64FcmgtVz,
|
||||
Arm64FcmleSz,
|
||||
Arm64FcmleVz,
|
||||
Arm64FcmltSz,
|
||||
Arm64FcmltVz,
|
||||
Arm64FcmpeS,
|
||||
Arm64FcmpS,
|
||||
Arm64FcselS,
|
||||
Arm64FcvtasS,
|
||||
Arm64FcvtasV,
|
||||
Arm64FcvtasGp,
|
||||
Arm64FcvtauS,
|
||||
Arm64FcvtauV,
|
||||
Arm64FcvtauGp,
|
||||
Arm64FcvtlV,
|
||||
Arm64FcvtmsS,
|
||||
Arm64FcvtmsV,
|
||||
Arm64FcvtmsGp,
|
||||
Arm64FcvtmuS,
|
||||
Arm64FcvtmuV,
|
||||
Arm64FcvtmuGp,
|
||||
Arm64FcvtnsS,
|
||||
Arm64FcvtnsV,
|
||||
Arm64FcvtnsGp,
|
||||
Arm64FcvtnuS,
|
||||
Arm64FcvtnuV,
|
||||
Arm64FcvtnuGp,
|
||||
Arm64FcvtnV,
|
||||
Arm64FcvtpsS,
|
||||
Arm64FcvtpsV,
|
||||
Arm64FcvtpsGp,
|
||||
Arm64FcvtpuS,
|
||||
Arm64FcvtpuV,
|
||||
Arm64FcvtpuGp,
|
||||
Arm64FcvtxnS,
|
||||
Arm64FcvtxnV,
|
||||
Arm64FcvtzsSFixed,
|
||||
Arm64FcvtzsVFixed,
|
||||
Arm64FcvtzsS,
|
||||
Arm64FcvtzsV,
|
||||
Arm64FcvtzsGpFixed,
|
||||
Arm64FcvtzsGp,
|
||||
Arm64FcvtzuSFixed,
|
||||
Arm64FcvtzuVFixed,
|
||||
Arm64FcvtzuS,
|
||||
Arm64FcvtzuV,
|
||||
Arm64FcvtzuGpFixed,
|
||||
Arm64FcvtzuGp,
|
||||
Arm64FcvtS,
|
||||
Arm64FdivV,
|
||||
Arm64FdivS,
|
||||
Arm64FmaddS,
|
||||
Arm64FmaxnmpS,
|
||||
Arm64FmaxnmpV,
|
||||
Arm64FmaxnmvV,
|
||||
Arm64FmaxnmV,
|
||||
Arm64FmaxnmS,
|
||||
Arm64FmaxpS,
|
||||
Arm64FmaxpV,
|
||||
Arm64FmaxvV,
|
||||
Arm64FmaxV,
|
||||
Arm64FmaxS,
|
||||
Arm64FminnmpS,
|
||||
Arm64FminnmpV,
|
||||
Arm64FminnmvV,
|
||||
Arm64FminnmV,
|
||||
Arm64FminnmS,
|
||||
Arm64FminpS,
|
||||
Arm64FminpV,
|
||||
Arm64FminvV,
|
||||
Arm64FminV,
|
||||
Arm64FminS,
|
||||
Arm64FmlaSe,
|
||||
Arm64FmlaVe,
|
||||
Arm64FmlaV,
|
||||
Arm64FmlsSe,
|
||||
Arm64FmlsVe,
|
||||
Arm64FmlsV,
|
||||
Arm64FmovVi,
|
||||
Arm64FmovS,
|
||||
Arm64FmovGp,
|
||||
Arm64FmovSi,
|
||||
Arm64FmsubS,
|
||||
Arm64FmulxSe,
|
||||
Arm64FmulxVe,
|
||||
Arm64FmulxS,
|
||||
Arm64FmulxV,
|
||||
Arm64FmulSe,
|
||||
Arm64FmulVe,
|
||||
Arm64FmulV,
|
||||
Arm64FmulS,
|
||||
Arm64FnegV,
|
||||
Arm64FnegS,
|
||||
Arm64FnmaddS,
|
||||
Arm64FnmsubS,
|
||||
Arm64FnmulS,
|
||||
Arm64FrecpeS,
|
||||
Arm64FrecpeV,
|
||||
Arm64FrecpsS,
|
||||
Arm64FrecpsV,
|
||||
Arm64FrecpxS,
|
||||
Arm64FrintaV,
|
||||
Arm64FrintaS,
|
||||
Arm64FrintiV,
|
||||
Arm64FrintiS,
|
||||
Arm64FrintmV,
|
||||
Arm64FrintmS,
|
||||
Arm64FrintnV,
|
||||
Arm64FrintnS,
|
||||
Arm64FrintpV,
|
||||
Arm64FrintpS,
|
||||
Arm64FrintxV,
|
||||
Arm64FrintxS,
|
||||
Arm64FrintzV,
|
||||
Arm64FrintzS,
|
||||
Arm64FrsqrteS,
|
||||
Arm64FrsqrteV,
|
||||
Arm64FrsqrtsS,
|
||||
Arm64FrsqrtsV,
|
||||
Arm64FsqrtV,
|
||||
Arm64FsqrtS,
|
||||
Arm64FsubV,
|
||||
Arm64FsubS,
|
||||
Arm64InsVe,
|
||||
Arm64InsGp,
|
||||
Arm64Ld1rV,
|
||||
Arm64Ld1Vms,
|
||||
Arm64Ld1Vss,
|
||||
Arm64Ld2rV,
|
||||
Arm64Ld2Vms,
|
||||
Arm64Ld2Vss,
|
||||
Arm64Ld3rV,
|
||||
Arm64Ld3Vms,
|
||||
Arm64Ld3Vss,
|
||||
Arm64Ld4rV,
|
||||
Arm64Ld4Vms,
|
||||
Arm64Ld4Vss,
|
||||
Arm64MlaVe,
|
||||
Arm64MlaV,
|
||||
Arm64MlsVe,
|
||||
Arm64MlsV,
|
||||
Arm64MoviV,
|
||||
Arm64MrsFpsr,
|
||||
Arm64MsrFpsr,
|
||||
Arm64MulVe,
|
||||
Arm64MulV,
|
||||
Arm64MvniV,
|
||||
Arm64NegS,
|
||||
Arm64NegV,
|
||||
Arm64NotV,
|
||||
Arm64OrnV,
|
||||
Arm64OrrVi,
|
||||
Arm64OrrV,
|
||||
Arm64PmullV,
|
||||
Arm64PmulV,
|
||||
Arm64RaddhnV,
|
||||
Arm64RbitV,
|
||||
Arm64Rev16V,
|
||||
Arm64Rev32V,
|
||||
Arm64Rev64V,
|
||||
Arm64RshrnV,
|
||||
Arm64RsubhnV,
|
||||
Arm64SabalV,
|
||||
Arm64SabaV,
|
||||
Arm64SabdlV,
|
||||
Arm64SabdV,
|
||||
Arm64SadalpV,
|
||||
Arm64SaddlpV,
|
||||
Arm64SaddlvV,
|
||||
Arm64SaddlV,
|
||||
Arm64SaddwV,
|
||||
Arm64ScvtfSFixed,
|
||||
Arm64ScvtfVFixed,
|
||||
Arm64ScvtfS,
|
||||
Arm64ScvtfV,
|
||||
Arm64ScvtfGpFixed,
|
||||
Arm64ScvtfGp,
|
||||
Arm64Sha1cV,
|
||||
Arm64Sha1hV,
|
||||
Arm64Sha1mV,
|
||||
Arm64Sha1pV,
|
||||
Arm64Sha1su0V,
|
||||
Arm64Sha1su1V,
|
||||
Arm64Sha256h2V,
|
||||
Arm64Sha256hV,
|
||||
Arm64Sha256su0V,
|
||||
Arm64Sha256su1V,
|
||||
Arm64ShaddV,
|
||||
Arm64ShllV,
|
||||
Arm64ShlS,
|
||||
Arm64ShlV,
|
||||
Arm64ShrnV,
|
||||
Arm64ShsubV,
|
||||
Arm64SliS,
|
||||
Arm64SliV,
|
||||
Arm64SmaxpV,
|
||||
Arm64SmaxvV,
|
||||
Arm64SmaxV,
|
||||
Arm64SminpV,
|
||||
Arm64SminvV,
|
||||
Arm64SminV,
|
||||
Arm64SmlalVe,
|
||||
Arm64SmlalV,
|
||||
Arm64SmlslVe,
|
||||
Arm64SmlslV,
|
||||
Arm64SmovV,
|
||||
Arm64SmullVe,
|
||||
Arm64SmullV,
|
||||
Arm64SqabsS,
|
||||
Arm64SqabsV,
|
||||
Arm64SqaddS,
|
||||
Arm64SqaddV,
|
||||
Arm64SqdmlalSe,
|
||||
Arm64SqdmlalVe,
|
||||
Arm64SqdmlalS,
|
||||
Arm64SqdmlalV,
|
||||
Arm64SqdmlslSe,
|
||||
Arm64SqdmlslVe,
|
||||
Arm64SqdmlslS,
|
||||
Arm64SqdmlslV,
|
||||
Arm64SqdmulhSe,
|
||||
Arm64SqdmulhVe,
|
||||
Arm64SqdmulhS,
|
||||
Arm64SqdmulhV,
|
||||
Arm64SqdmullSe,
|
||||
Arm64SqdmullVe,
|
||||
Arm64SqdmullS,
|
||||
Arm64SqdmullV,
|
||||
Arm64SqnegS,
|
||||
Arm64SqnegV,
|
||||
Arm64SqrdmulhSe,
|
||||
Arm64SqrdmulhVe,
|
||||
Arm64SqrdmulhS,
|
||||
Arm64SqrdmulhV,
|
||||
Arm64SqrshlS,
|
||||
Arm64SqrshlV,
|
||||
Arm64SqrshrnS,
|
||||
Arm64SqrshrnV,
|
||||
Arm64SqrshrunS,
|
||||
Arm64SqrshrunV,
|
||||
Arm64SqshluS,
|
||||
Arm64SqshluV,
|
||||
Arm64SqshlSi,
|
||||
Arm64SqshlVi,
|
||||
Arm64SqshlS,
|
||||
Arm64SqshlV,
|
||||
Arm64SqshrnS,
|
||||
Arm64SqshrnV,
|
||||
Arm64SqshrunS,
|
||||
Arm64SqshrunV,
|
||||
Arm64SqsubS,
|
||||
Arm64SqsubV,
|
||||
Arm64SqxtnS,
|
||||
Arm64SqxtnV,
|
||||
Arm64SqxtunS,
|
||||
Arm64SqxtunV,
|
||||
Arm64SrhaddV,
|
||||
Arm64SriS,
|
||||
Arm64SriV,
|
||||
Arm64SrshlS,
|
||||
Arm64SrshlV,
|
||||
Arm64SrshrS,
|
||||
Arm64SrshrV,
|
||||
Arm64SrsraS,
|
||||
Arm64SrsraV,
|
||||
Arm64SshllV,
|
||||
Arm64SshlS,
|
||||
Arm64SshlV,
|
||||
Arm64SshrS,
|
||||
Arm64SshrV,
|
||||
Arm64SsraS,
|
||||
Arm64SsraV,
|
||||
Arm64SsublV,
|
||||
Arm64SsubwV,
|
||||
Arm64St1Vms,
|
||||
Arm64St1Vss,
|
||||
Arm64St2Vms,
|
||||
Arm64St2Vss,
|
||||
Arm64St3Vms,
|
||||
Arm64St3Vss,
|
||||
Arm64St4Vms,
|
||||
Arm64St4Vss,
|
||||
Arm64SubhnV,
|
||||
Arm64SubS,
|
||||
Arm64SubV,
|
||||
Arm64SuqaddS,
|
||||
Arm64SuqaddV,
|
||||
Arm64TblV,
|
||||
Arm64TbxV,
|
||||
Arm64Trn1V,
|
||||
Arm64Trn2V,
|
||||
Arm64UabalV,
|
||||
Arm64UabaV,
|
||||
Arm64UabdlV,
|
||||
Arm64UabdV,
|
||||
Arm64UadalpV,
|
||||
Arm64UaddlpV,
|
||||
Arm64UaddlvV,
|
||||
Arm64UaddlV,
|
||||
Arm64UaddwV,
|
||||
Arm64UcvtfSFixed,
|
||||
Arm64UcvtfVFixed,
|
||||
Arm64UcvtfS,
|
||||
Arm64UcvtfV,
|
||||
Arm64UcvtfGpFixed,
|
||||
Arm64UcvtfGp,
|
||||
Arm64UhaddV,
|
||||
Arm64UhsubV,
|
||||
Arm64UmaxpV,
|
||||
Arm64UmaxvV,
|
||||
Arm64UmaxV,
|
||||
Arm64UminpV,
|
||||
Arm64UminvV,
|
||||
Arm64UminV,
|
||||
Arm64UmlalVe,
|
||||
Arm64UmlalV,
|
||||
Arm64UmlslVe,
|
||||
Arm64UmlslV,
|
||||
Arm64UmovV,
|
||||
Arm64UmullVe,
|
||||
Arm64UmullV,
|
||||
Arm64UqaddS,
|
||||
Arm64UqaddV,
|
||||
Arm64UqrshlS,
|
||||
Arm64UqrshlV,
|
||||
Arm64UqrshrnS,
|
||||
Arm64UqrshrnV,
|
||||
Arm64UqshlSi,
|
||||
Arm64UqshlVi,
|
||||
Arm64UqshlS,
|
||||
Arm64UqshlV,
|
||||
Arm64UqshrnS,
|
||||
Arm64UqshrnV,
|
||||
Arm64UqsubS,
|
||||
Arm64UqsubV,
|
||||
Arm64UqxtnS,
|
||||
Arm64UqxtnV,
|
||||
Arm64UrecpeV,
|
||||
Arm64UrhaddV,
|
||||
Arm64UrshlS,
|
||||
Arm64UrshlV,
|
||||
Arm64UrshrS,
|
||||
Arm64UrshrV,
|
||||
Arm64UrsqrteV,
|
||||
Arm64UrsraS,
|
||||
Arm64UrsraV,
|
||||
Arm64UshllV,
|
||||
Arm64UshlS,
|
||||
Arm64UshlV,
|
||||
Arm64UshrS,
|
||||
Arm64UshrV,
|
||||
Arm64UsqaddS,
|
||||
Arm64UsqaddV,
|
||||
Arm64UsraS,
|
||||
Arm64UsraV,
|
||||
Arm64UsublV,
|
||||
Arm64UsubwV,
|
||||
Arm64Uzp1V,
|
||||
Arm64Uzp2V,
|
||||
Arm64XtnV,
|
||||
Arm64Zip1V,
|
||||
Arm64Zip2V,
|
||||
|
||||
Arm64VTypeShift = 13,
|
||||
Arm64VTypeMask = 1 << Arm64VTypeShift,
|
||||
Arm64V64 = 0 << Arm64VTypeShift,
|
||||
Arm64V128 = 1 << Arm64VTypeShift,
|
||||
|
||||
Arm64VSizeShift = 14,
|
||||
Arm64VSizeMask = 3 << Arm64VSizeShift,
|
||||
Arm64VFloat = 0 << Arm64VSizeShift,
|
||||
Arm64VDouble = 1 << Arm64VSizeShift,
|
||||
Arm64VByte = 0 << Arm64VSizeShift,
|
||||
Arm64VHWord = 1 << Arm64VSizeShift,
|
||||
Arm64VWord = 2 << Arm64VSizeShift,
|
||||
Arm64VDWord = 3 << Arm64VSizeShift
|
||||
}
|
||||
}
|
@ -5,6 +5,7 @@ namespace ARMeilleure.IntermediateRepresentation
|
||||
x1 = 0,
|
||||
x2 = 1,
|
||||
x4 = 2,
|
||||
x8 = 3
|
||||
x8 = 3,
|
||||
x16 = 4
|
||||
}
|
||||
}
|
@ -259,6 +259,20 @@ namespace ARMeilleure.IntermediateRepresentation
|
||||
}
|
||||
}
|
||||
|
||||
public Span<Operation> GetUses(ref Span<Operation> buffer)
|
||||
{
|
||||
ReadOnlySpan<Operation> uses = Uses;
|
||||
|
||||
if (buffer.Length < uses.Length)
|
||||
{
|
||||
buffer = Allocators.Default.AllocateSpan<Operation>((uint)uses.Length);
|
||||
}
|
||||
|
||||
uses.CopyTo(buffer);
|
||||
|
||||
return buffer.Slice(0, uses.Length);
|
||||
}
|
||||
|
||||
private static void New<T>(ref T* data, ref ushort count, ref ushort capacity, ushort initialCapacity) where T : unmanaged
|
||||
{
|
||||
count = 0;
|
||||
|
@ -47,5 +47,19 @@ namespace ARMeilleure.IntermediateRepresentation
|
||||
|
||||
throw new InvalidOperationException($"Invalid operand type \"{type}\".");
|
||||
}
|
||||
|
||||
public static int GetSizeInBytesLog2(this OperandType type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case OperandType.FP32: return 2;
|
||||
case OperandType.FP64: return 3;
|
||||
case OperandType.I32: return 2;
|
||||
case OperandType.I64: return 3;
|
||||
case OperandType.V128: return 4;
|
||||
}
|
||||
|
||||
throw new InvalidOperationException($"Invalid operand type \"{type}\".");
|
||||
}
|
||||
}
|
||||
}
|
@ -4,5 +4,7 @@
|
||||
{
|
||||
IJitMemoryBlock Allocate(ulong size);
|
||||
IJitMemoryBlock Reserve(ulong size);
|
||||
|
||||
ulong GetPageSize();
|
||||
}
|
||||
}
|
||||
|
@ -71,6 +71,7 @@ namespace ARMeilleure.Memory
|
||||
/// <param name="size">Size of the region</param>
|
||||
/// <param name="write">True if the region was written, false if read</param>
|
||||
/// <param name="precise">True if the access is precise, false otherwise</param>
|
||||
void SignalMemoryTracking(ulong va, ulong size, bool write, bool precise = false);
|
||||
/// <param name="exemptId">Optional ID of the handles that should not be signalled</param>
|
||||
void SignalMemoryTracking(ulong va, ulong size, bool write, bool precise = false, int? exemptId = null);
|
||||
}
|
||||
}
|
@ -4,7 +4,7 @@ namespace ARMeilleure.Memory
|
||||
{
|
||||
class ReservedRegion
|
||||
{
|
||||
private const int DefaultGranularity = 65536; // Mapping granularity in Windows.
|
||||
public const int DefaultGranularity = 65536; // Mapping granularity in Windows.
|
||||
|
||||
public IJitMemoryBlock Block { get; }
|
||||
|
||||
|
13
ARMeilleure/Native/JitSupportDarwin.cs
Normal file
13
ARMeilleure/Native/JitSupportDarwin.cs
Normal file
@ -0,0 +1,13 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.Versioning;
|
||||
|
||||
namespace ARMeilleure.Native
|
||||
{
|
||||
[SupportedOSPlatform("macos")]
|
||||
public static partial class JitSupportDarwin
|
||||
{
|
||||
[LibraryImport("libarmeilleure-jitsupport", EntryPoint = "armeilleure_jit_memcpy")]
|
||||
public static partial void Copy(IntPtr dst, IntPtr src, ulong n);
|
||||
}
|
||||
}
|
BIN
ARMeilleure/Native/libs/libarmeilleure-jitsupport.dylib
Normal file
BIN
ARMeilleure/Native/libs/libarmeilleure-jitsupport.dylib
Normal file
Binary file not shown.
8
ARMeilleure/Native/macos_jit_support/Makefile
Normal file
8
ARMeilleure/Native/macos_jit_support/Makefile
Normal file
@ -0,0 +1,8 @@
|
||||
NAME = libarmeilleure-jitsupport.dylib
|
||||
|
||||
all: ${NAME}
|
||||
|
||||
${NAME}:
|
||||
clang -O3 -dynamiclib support.c -o ${NAME}
|
||||
clean:
|
||||
rm -f ${NAME}
|
14
ARMeilleure/Native/macos_jit_support/support.c
Normal file
14
ARMeilleure/Native/macos_jit_support/support.c
Normal file
@ -0,0 +1,14 @@
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#include <libkern/OSCacheControl.h>
|
||||
|
||||
void armeilleure_jit_memcpy(void *dst, const void *src, size_t n) {
|
||||
pthread_jit_write_protect_np(0);
|
||||
memcpy(dst, src, n);
|
||||
pthread_jit_write_protect_np(1);
|
||||
|
||||
// Ensure that the instruction cache for this range is invalidated.
|
||||
sys_icache_invalidate(dst, n);
|
||||
}
|
@ -1,7 +1,10 @@
|
||||
using ARMeilleure.CodeGen.X86;
|
||||
using System.Runtime.Intrinsics.Arm;
|
||||
|
||||
namespace ARMeilleure
|
||||
{
|
||||
using Arm64HardwareCapabilities = ARMeilleure.CodeGen.Arm64.HardwareCapabilities;
|
||||
using X86HardwareCapabilities = ARMeilleure.CodeGen.X86.HardwareCapabilities;
|
||||
|
||||
public static class Optimizations
|
||||
{
|
||||
public static bool FastFP { get; set; } = true;
|
||||
@ -9,6 +12,9 @@ namespace ARMeilleure
|
||||
public static bool AllowLcqInFunctionTable { get; set; } = true;
|
||||
public static bool UseUnmanagedDispatchLoop { get; set; } = true;
|
||||
|
||||
public static bool UseAdvSimdIfAvailable { get; set; } = true;
|
||||
public static bool UseArm64PmullIfAvailable { get; set; } = true;
|
||||
|
||||
public static bool UseSseIfAvailable { get; set; } = true;
|
||||
public static bool UseSse2IfAvailable { get; set; } = true;
|
||||
public static bool UseSse3IfAvailable { get; set; } = true;
|
||||
@ -26,23 +32,26 @@ namespace ARMeilleure
|
||||
|
||||
public static bool ForceLegacySse
|
||||
{
|
||||
get => HardwareCapabilities.ForceLegacySse;
|
||||
set => HardwareCapabilities.ForceLegacySse = value;
|
||||
get => X86HardwareCapabilities.ForceLegacySse;
|
||||
set => X86HardwareCapabilities.ForceLegacySse = value;
|
||||
}
|
||||
|
||||
internal static bool UseSse => UseSseIfAvailable && HardwareCapabilities.SupportsSse;
|
||||
internal static bool UseSse2 => UseSse2IfAvailable && HardwareCapabilities.SupportsSse2;
|
||||
internal static bool UseSse3 => UseSse3IfAvailable && HardwareCapabilities.SupportsSse3;
|
||||
internal static bool UseSsse3 => UseSsse3IfAvailable && HardwareCapabilities.SupportsSsse3;
|
||||
internal static bool UseSse41 => UseSse41IfAvailable && HardwareCapabilities.SupportsSse41;
|
||||
internal static bool UseSse42 => UseSse42IfAvailable && HardwareCapabilities.SupportsSse42;
|
||||
internal static bool UsePopCnt => UsePopCntIfAvailable && HardwareCapabilities.SupportsPopcnt;
|
||||
internal static bool UseAvx => UseAvxIfAvailable && HardwareCapabilities.SupportsAvx && !ForceLegacySse;
|
||||
internal static bool UseF16c => UseF16cIfAvailable && HardwareCapabilities.SupportsF16c;
|
||||
internal static bool UseFma => UseFmaIfAvailable && HardwareCapabilities.SupportsFma;
|
||||
internal static bool UseAesni => UseAesniIfAvailable && HardwareCapabilities.SupportsAesni;
|
||||
internal static bool UsePclmulqdq => UsePclmulqdqIfAvailable && HardwareCapabilities.SupportsPclmulqdq;
|
||||
internal static bool UseSha => UseShaIfAvailable && HardwareCapabilities.SupportsSha;
|
||||
internal static bool UseGfni => UseGfniIfAvailable && HardwareCapabilities.SupportsGfni;
|
||||
internal static bool UseAdvSimd => UseAdvSimdIfAvailable && Arm64HardwareCapabilities.SupportsAdvSimd;
|
||||
internal static bool UseArm64Pmull => UseArm64PmullIfAvailable && Arm64HardwareCapabilities.SupportsPmull;
|
||||
|
||||
internal static bool UseSse => UseSseIfAvailable && X86HardwareCapabilities.SupportsSse;
|
||||
internal static bool UseSse2 => UseSse2IfAvailable && X86HardwareCapabilities.SupportsSse2;
|
||||
internal static bool UseSse3 => UseSse3IfAvailable && X86HardwareCapabilities.SupportsSse3;
|
||||
internal static bool UseSsse3 => UseSsse3IfAvailable && X86HardwareCapabilities.SupportsSsse3;
|
||||
internal static bool UseSse41 => UseSse41IfAvailable && X86HardwareCapabilities.SupportsSse41;
|
||||
internal static bool UseSse42 => UseSse42IfAvailable && X86HardwareCapabilities.SupportsSse42;
|
||||
internal static bool UsePopCnt => UsePopCntIfAvailable && X86HardwareCapabilities.SupportsPopcnt;
|
||||
internal static bool UseAvx => UseAvxIfAvailable && X86HardwareCapabilities.SupportsAvx && !ForceLegacySse;
|
||||
internal static bool UseF16c => UseF16cIfAvailable && X86HardwareCapabilities.SupportsF16c;
|
||||
internal static bool UseFma => UseFmaIfAvailable && X86HardwareCapabilities.SupportsFma;
|
||||
internal static bool UseAesni => UseAesniIfAvailable && X86HardwareCapabilities.SupportsAesni;
|
||||
internal static bool UsePclmulqdq => UsePclmulqdqIfAvailable && X86HardwareCapabilities.SupportsPclmulqdq;
|
||||
internal static bool UseSha => UseShaIfAvailable && X86HardwareCapabilities.SupportsSha;
|
||||
internal static bool UseGfni => UseGfniIfAvailable && X86HardwareCapabilities.SupportsGfni;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,7 @@
|
||||
using ARMeilleure.IntermediateRepresentation;
|
||||
using ARMeilleure.Memory;
|
||||
using ARMeilleure.Translation;
|
||||
using ARMeilleure.Translation.Cache;
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
@ -69,8 +71,8 @@ namespace ARMeilleure.Signal
|
||||
|
||||
private const uint EXCEPTION_ACCESS_VIOLATION = 0xc0000005;
|
||||
|
||||
private const ulong PageSize = 0x1000;
|
||||
private const ulong PageMask = PageSize - 1;
|
||||
private static ulong _pageSize;
|
||||
private static ulong _pageMask;
|
||||
|
||||
private static IntPtr _handlerConfig;
|
||||
private static IntPtr _signalHandlerPtr;
|
||||
@ -87,7 +89,12 @@ namespace ARMeilleure.Signal
|
||||
config = new SignalHandlerConfig();
|
||||
}
|
||||
|
||||
public static void InitializeSignalHandler()
|
||||
public static void Initialize(IJitMemoryAllocator allocator)
|
||||
{
|
||||
JitCache.Initialize(allocator);
|
||||
}
|
||||
|
||||
public static void InitializeSignalHandler(ulong pageSize, Func<IntPtr, IntPtr, IntPtr> customSignalHandlerFactory = null)
|
||||
{
|
||||
if (_initialized) return;
|
||||
|
||||
@ -95,20 +102,22 @@ namespace ARMeilleure.Signal
|
||||
{
|
||||
if (_initialized) return;
|
||||
|
||||
bool unix = OperatingSystem.IsLinux() || OperatingSystem.IsMacOS();
|
||||
_pageSize = pageSize;
|
||||
_pageMask = pageSize - 1;
|
||||
|
||||
ref SignalHandlerConfig config = ref GetConfigRef();
|
||||
|
||||
if (unix)
|
||||
if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS())
|
||||
{
|
||||
// Unix siginfo struct locations.
|
||||
// NOTE: These are incredibly likely to be different between kernel version and architectures.
|
||||
|
||||
config.StructAddressOffset = OperatingSystem.IsMacOS() ? 24 : 16; // si_addr
|
||||
config.StructWriteOffset = 8; // si_code
|
||||
|
||||
_signalHandlerPtr = Marshal.GetFunctionPointerForDelegate(GenerateUnixSignalHandler(_handlerConfig));
|
||||
|
||||
SigAction old = UnixSignalHandlerRegistration.RegisterExceptionHandler(_signalHandlerPtr);
|
||||
if (customSignalHandlerFactory != null)
|
||||
{
|
||||
_signalHandlerPtr = customSignalHandlerFactory(UnixSignalHandlerRegistration.GetSegfaultExceptionHandler().sa_handler, _signalHandlerPtr);
|
||||
}
|
||||
|
||||
var old = UnixSignalHandlerRegistration.RegisterExceptionHandler(_signalHandlerPtr);
|
||||
|
||||
config.UnixOldSigaction = (nuint)(ulong)old.sa_handler;
|
||||
config.UnixOldSigaction3Arg = old.sa_flags & 4;
|
||||
}
|
||||
@ -119,6 +128,11 @@ namespace ARMeilleure.Signal
|
||||
|
||||
_signalHandlerPtr = Marshal.GetFunctionPointerForDelegate(GenerateWindowsSignalHandler(_handlerConfig));
|
||||
|
||||
if (customSignalHandlerFactory != null)
|
||||
{
|
||||
_signalHandlerPtr = customSignalHandlerFactory(IntPtr.Zero, _signalHandlerPtr);
|
||||
}
|
||||
|
||||
_signalHandlerHandle = WindowsSignalHandlerRegistration.RegisterExceptionHandler(_signalHandlerPtr);
|
||||
}
|
||||
|
||||
@ -197,7 +211,7 @@ namespace ARMeilleure.Signal
|
||||
// Only call tracking if in range.
|
||||
context.BranchIfFalse(nextLabel, inRange, BasicBlockFrequency.Cold);
|
||||
|
||||
Operand offset = context.BitwiseAnd(context.Subtract(faultAddress, rangeAddress), Const(~PageMask));
|
||||
Operand offset = context.BitwiseAnd(context.Subtract(faultAddress, rangeAddress), Const(~_pageMask));
|
||||
|
||||
// Call the tracking action, with the pointer's relative offset to the base address.
|
||||
Operand trackingActionPtr = context.Load(OperandType.I64, Const((ulong)signalStructPtr + rangeBaseOffset + 20));
|
||||
@ -208,7 +222,7 @@ namespace ARMeilleure.Signal
|
||||
|
||||
// Tracking action should be non-null to call it, otherwise assume false return.
|
||||
context.BranchIfFalse(skipActionLabel, trackingActionPtr);
|
||||
Operand result = context.Call(trackingActionPtr, OperandType.I32, offset, Const(PageSize), isWrite, Const(0));
|
||||
Operand result = context.Call(trackingActionPtr, OperandType.I32, offset, Const(_pageSize), isWrite);
|
||||
context.Copy(inRegionLocal, result);
|
||||
|
||||
context.MarkLabel(skipActionLabel);
|
||||
@ -231,18 +245,88 @@ namespace ARMeilleure.Signal
|
||||
return context.Copy(inRegionLocal);
|
||||
}
|
||||
|
||||
private static Operand GenerateUnixFaultAddress(EmitterContext context, Operand sigInfoPtr)
|
||||
{
|
||||
ulong structAddressOffset = OperatingSystem.IsMacOS() ? 24ul : 16ul; // si_addr
|
||||
return context.Load(OperandType.I64, context.Add(sigInfoPtr, Const(structAddressOffset)));
|
||||
}
|
||||
|
||||
private static Operand GenerateUnixWriteFlag(EmitterContext context, Operand ucontextPtr)
|
||||
{
|
||||
if (OperatingSystem.IsMacOS())
|
||||
{
|
||||
const ulong mcontextOffset = 48; // uc_mcontext
|
||||
Operand ctxPtr = context.Load(OperandType.I64, context.Add(ucontextPtr, Const(mcontextOffset)));
|
||||
|
||||
if (RuntimeInformation.ProcessArchitecture == Architecture.Arm64)
|
||||
{
|
||||
const ulong esrOffset = 8; // __es.__esr
|
||||
Operand esr = context.Load(OperandType.I64, context.Add(ctxPtr, Const(esrOffset)));
|
||||
return context.BitwiseAnd(esr, Const(0x40ul));
|
||||
}
|
||||
|
||||
if (RuntimeInformation.ProcessArchitecture == Architecture.X64)
|
||||
{
|
||||
const ulong errOffset = 4; // __es.__err
|
||||
Operand err = context.Load(OperandType.I64, context.Add(ctxPtr, Const(errOffset)));
|
||||
return context.BitwiseAnd(err, Const(2ul));
|
||||
}
|
||||
}
|
||||
else if (OperatingSystem.IsLinux())
|
||||
{
|
||||
if (RuntimeInformation.ProcessArchitecture == Architecture.Arm64)
|
||||
{
|
||||
Operand auxPtr = context.AllocateLocal(OperandType.I64);
|
||||
|
||||
Operand loopLabel = Label();
|
||||
Operand successLabel = Label();
|
||||
|
||||
const ulong auxOffset = 464; // uc_mcontext.__reserved
|
||||
const uint esrMagic = 0x45535201;
|
||||
|
||||
context.Copy(auxPtr, context.Add(ucontextPtr, Const(auxOffset)));
|
||||
|
||||
context.MarkLabel(loopLabel);
|
||||
|
||||
// _aarch64_ctx::magic
|
||||
Operand magic = context.Load(OperandType.I32, auxPtr);
|
||||
// _aarch64_ctx::size
|
||||
Operand size = context.Load(OperandType.I32, context.Add(auxPtr, Const(4ul)));
|
||||
|
||||
context.BranchIf(successLabel, magic, Const(esrMagic), Comparison.Equal);
|
||||
|
||||
context.Copy(auxPtr, context.Add(auxPtr, context.ZeroExtend32(OperandType.I64, size)));
|
||||
|
||||
context.Branch(loopLabel);
|
||||
|
||||
context.MarkLabel(successLabel);
|
||||
|
||||
// esr_context::esr
|
||||
Operand esr = context.Load(OperandType.I64, context.Add(auxPtr, Const(8ul)));
|
||||
return context.BitwiseAnd(esr, Const(0x40ul));
|
||||
}
|
||||
|
||||
if (RuntimeInformation.ProcessArchitecture == Architecture.X64)
|
||||
{
|
||||
const int errOffset = 192; // uc_mcontext.gregs[REG_ERR]
|
||||
Operand err = context.Load(OperandType.I64, context.Add(ucontextPtr, Const(errOffset)));
|
||||
return context.BitwiseAnd(err, Const(2ul));
|
||||
}
|
||||
}
|
||||
|
||||
throw new PlatformNotSupportedException();
|
||||
}
|
||||
|
||||
private static UnixExceptionHandler GenerateUnixSignalHandler(IntPtr signalStructPtr)
|
||||
{
|
||||
EmitterContext context = new EmitterContext();
|
||||
|
||||
// (int sig, SigInfo* sigInfo, void* ucontext)
|
||||
Operand sigInfoPtr = context.LoadArgument(OperandType.I64, 1);
|
||||
Operand ucontextPtr = context.LoadArgument(OperandType.I64, 2);
|
||||
|
||||
Operand structAddressOffset = context.Load(OperandType.I64, Const((ulong)signalStructPtr + StructAddressOffset));
|
||||
Operand structWriteOffset = context.Load(OperandType.I64, Const((ulong)signalStructPtr + StructWriteOffset));
|
||||
|
||||
Operand faultAddress = context.Load(OperandType.I64, context.Add(sigInfoPtr, context.ZeroExtend32(OperandType.I64, structAddressOffset)));
|
||||
Operand writeFlag = context.Load(OperandType.I64, context.Add(sigInfoPtr, context.ZeroExtend32(OperandType.I64, structWriteOffset)));
|
||||
Operand faultAddress = GenerateUnixFaultAddress(context, sigInfoPtr);
|
||||
Operand writeFlag = GenerateUnixWriteFlag(context, ucontextPtr);
|
||||
|
||||
Operand isWrite = context.ICompareNotEqual(writeFlag, Const(0L)); // Normalize to 0/1.
|
||||
|
||||
@ -278,7 +362,7 @@ namespace ARMeilleure.Signal
|
||||
|
||||
OperandType[] argTypes = new OperandType[] { OperandType.I32, OperandType.I64, OperandType.I64 };
|
||||
|
||||
return Compiler.Compile(cfg, argTypes, OperandType.None, CompilerOptions.HighCq).Map<UnixExceptionHandler>();
|
||||
return Compiler.Compile(cfg, argTypes, OperandType.None, CompilerOptions.HighCq, RuntimeInformation.ProcessArchitecture).Map<UnixExceptionHandler>();
|
||||
}
|
||||
|
||||
private static VectoredExceptionHandler GenerateWindowsSignalHandler(IntPtr signalStructPtr)
|
||||
@ -332,7 +416,7 @@ namespace ARMeilleure.Signal
|
||||
|
||||
OperandType[] argTypes = new OperandType[] { OperandType.I64 };
|
||||
|
||||
return Compiler.Compile(cfg, argTypes, OperandType.I32, CompilerOptions.HighCq).Map<VectoredExceptionHandler>();
|
||||
return Compiler.Compile(cfg, argTypes, OperandType.I32, CompilerOptions.HighCq, RuntimeInformation.ProcessArchitecture).Map<VectoredExceptionHandler>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
using ARMeilleure.IntermediateRepresentation;
|
||||
using ARMeilleure.Translation;
|
||||
using System;
|
||||
|
||||
using System.Runtime.InteropServices;
|
||||
using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
|
||||
|
||||
namespace ARMeilleure.Signal
|
||||
@ -32,7 +32,7 @@ namespace ARMeilleure.Signal
|
||||
|
||||
OperandType[] argTypes = new OperandType[] { OperandType.I64 };
|
||||
|
||||
return Compiler.Compile(cfg, argTypes, OperandType.I32, CompilerOptions.HighCq).Map<DebugPartialUnmap>();
|
||||
return Compiler.Compile(cfg, argTypes, OperandType.I32, CompilerOptions.HighCq, RuntimeInformation.ProcessArchitecture).Map<DebugPartialUnmap>();
|
||||
}
|
||||
|
||||
public static DebugThreadLocalMapGetOrReserve GenerateDebugThreadLocalMapGetOrReserve(IntPtr structPtr)
|
||||
@ -49,7 +49,7 @@ namespace ARMeilleure.Signal
|
||||
|
||||
OperandType[] argTypes = new OperandType[] { OperandType.I64 };
|
||||
|
||||
return Compiler.Compile(cfg, argTypes, OperandType.I32, CompilerOptions.HighCq).Map<DebugThreadLocalMapGetOrReserve>();
|
||||
return Compiler.Compile(cfg, argTypes, OperandType.I32, CompilerOptions.HighCq, RuntimeInformation.ProcessArchitecture).Map<DebugThreadLocalMapGetOrReserve>();
|
||||
}
|
||||
|
||||
public static DebugNativeWriteLoop GenerateDebugNativeWriteLoop()
|
||||
@ -78,7 +78,7 @@ namespace ARMeilleure.Signal
|
||||
|
||||
OperandType[] argTypes = new OperandType[] { OperandType.I64 };
|
||||
|
||||
return Compiler.Compile(cfg, argTypes, OperandType.None, CompilerOptions.HighCq).Map<DebugNativeWriteLoop>();
|
||||
return Compiler.Compile(cfg, argTypes, OperandType.None, CompilerOptions.HighCq, RuntimeInformation.ProcessArchitecture).Map<DebugNativeWriteLoop>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,23 +3,23 @@ using System.Runtime.InteropServices;
|
||||
|
||||
namespace ARMeilleure.Signal
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
unsafe struct SigSet
|
||||
{
|
||||
fixed long sa_mask[16];
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct SigAction
|
||||
{
|
||||
public IntPtr sa_handler;
|
||||
public SigSet sa_mask;
|
||||
public int sa_flags;
|
||||
public IntPtr sa_restorer;
|
||||
}
|
||||
|
||||
static partial class UnixSignalHandlerRegistration
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
public unsafe struct SigSet
|
||||
{
|
||||
fixed long sa_mask[16];
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
public struct SigAction
|
||||
{
|
||||
public IntPtr sa_handler;
|
||||
public SigSet sa_mask;
|
||||
public int sa_flags;
|
||||
public IntPtr sa_restorer;
|
||||
}
|
||||
|
||||
private const int SIGSEGV = 11;
|
||||
private const int SIGBUS = 10;
|
||||
private const int SA_SIGINFO = 0x00000004;
|
||||
@ -27,9 +27,24 @@ namespace ARMeilleure.Signal
|
||||
[LibraryImport("libc", SetLastError = true)]
|
||||
private static partial int sigaction(int signum, ref SigAction sigAction, out SigAction oldAction);
|
||||
|
||||
[LibraryImport("libc", SetLastError = true)]
|
||||
private static partial int sigaction(int signum, IntPtr sigAction, out SigAction oldAction);
|
||||
|
||||
[LibraryImport("libc", SetLastError = true)]
|
||||
private static partial int sigemptyset(ref SigSet set);
|
||||
|
||||
public static SigAction GetSegfaultExceptionHandler()
|
||||
{
|
||||
int result = sigaction(SIGSEGV, IntPtr.Zero, out SigAction old);
|
||||
|
||||
if (result != 0)
|
||||
{
|
||||
throw new InvalidOperationException($"Could not get SIGSEGV sigaction. Error: {result}");
|
||||
}
|
||||
|
||||
return old;
|
||||
}
|
||||
|
||||
public static SigAction RegisterExceptionHandler(IntPtr action)
|
||||
{
|
||||
SigAction sig = new SigAction
|
||||
@ -49,7 +64,7 @@ namespace ARMeilleure.Signal
|
||||
|
||||
if (OperatingSystem.IsMacOS())
|
||||
{
|
||||
result = sigaction(SIGBUS, ref sig, out SigAction oldb);
|
||||
result = sigaction(SIGBUS, ref sig, out _);
|
||||
|
||||
if (result != 0)
|
||||
{
|
||||
|
@ -6,7 +6,6 @@ using ARMeilleure.Instructions;
|
||||
using ARMeilleure.IntermediateRepresentation;
|
||||
using ARMeilleure.Memory;
|
||||
using ARMeilleure.State;
|
||||
using ARMeilleure.Translation.PTC;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
@ -40,18 +39,19 @@ namespace ARMeilleure.Translation
|
||||
}
|
||||
}
|
||||
|
||||
private bool _pendingQcFlagSync;
|
||||
|
||||
public OpCode CurrOp { get; set; }
|
||||
|
||||
public IMemoryManager Memory { get; }
|
||||
|
||||
public bool HasPtc { get; }
|
||||
|
||||
public EntryTable<uint> CountTable { get; }
|
||||
public AddressTable<ulong> FunctionTable { get; }
|
||||
public TranslatorStubs Stubs { get; }
|
||||
|
||||
public ulong EntryAddress { get; }
|
||||
public bool HighCq { get; }
|
||||
public bool HasPtc { get; }
|
||||
public Aarch32Mode Mode { get; }
|
||||
|
||||
private int _ifThenBlockStateIndex = 0;
|
||||
@ -66,15 +66,16 @@ namespace ARMeilleure.Translation
|
||||
TranslatorStubs stubs,
|
||||
ulong entryAddress,
|
||||
bool highCq,
|
||||
bool hasPtc,
|
||||
Aarch32Mode mode)
|
||||
{
|
||||
HasPtc = Ptc.State != PtcState.Disabled;
|
||||
Memory = memory;
|
||||
CountTable = countTable;
|
||||
FunctionTable = funcTable;
|
||||
Stubs = stubs;
|
||||
EntryAddress = entryAddress;
|
||||
HighCq = highCq;
|
||||
HasPtc = hasPtc;
|
||||
Mode = mode;
|
||||
|
||||
_labels = new Dictionary<ulong, Operand>();
|
||||
@ -82,6 +83,8 @@ namespace ARMeilleure.Translation
|
||||
|
||||
public override Operand Call(MethodInfo info, params Operand[] callArgs)
|
||||
{
|
||||
SyncQcFlag();
|
||||
|
||||
if (!HasPtc)
|
||||
{
|
||||
return base.Call(info, callArgs);
|
||||
@ -140,6 +143,51 @@ namespace ARMeilleure.Translation
|
||||
_optOpLastFlagSet = null;
|
||||
}
|
||||
|
||||
public void SetPendingQcFlagSync()
|
||||
{
|
||||
_pendingQcFlagSync = true;
|
||||
}
|
||||
|
||||
public void SyncQcFlag()
|
||||
{
|
||||
if (_pendingQcFlagSync)
|
||||
{
|
||||
if (Optimizations.UseAdvSimd)
|
||||
{
|
||||
Operand fpsr = AddIntrinsicInt(Intrinsic.Arm64MrsFpsr);
|
||||
|
||||
uint qcFlagMask = (uint)FPSR.Qc;
|
||||
|
||||
Operand qcClearLabel = Label();
|
||||
|
||||
BranchIfFalse(qcClearLabel, BitwiseAnd(fpsr, Const(qcFlagMask)));
|
||||
|
||||
AddIntrinsicNoRet(Intrinsic.Arm64MsrFpsr, Const(0));
|
||||
InstEmitHelper.SetFpFlag(this, FPState.QcFlag, Const(1));
|
||||
|
||||
MarkLabel(qcClearLabel);
|
||||
}
|
||||
|
||||
_pendingQcFlagSync = false;
|
||||
}
|
||||
}
|
||||
|
||||
public void ClearQcFlag()
|
||||
{
|
||||
if (Optimizations.UseAdvSimd)
|
||||
{
|
||||
AddIntrinsicNoRet(Intrinsic.Arm64MsrFpsr, Const(0));
|
||||
}
|
||||
}
|
||||
|
||||
public void ClearQcFlagIfModified()
|
||||
{
|
||||
if (_pendingQcFlagSync && Optimizations.UseAdvSimd)
|
||||
{
|
||||
AddIntrinsicNoRet(Intrinsic.Arm64MsrFpsr, Const(0));
|
||||
}
|
||||
}
|
||||
|
||||
public Operand TryGetComparisonResult(Condition condition)
|
||||
{
|
||||
if (_optOpLastCompare == null || _optOpLastCompare != _optOpLastFlagSet)
|
||||
|
@ -1,6 +1,7 @@
|
||||
using ARMeilleure.CodeGen;
|
||||
using ARMeilleure.CodeGen.Unwinding;
|
||||
using ARMeilleure.Memory;
|
||||
using ARMeilleure.Native;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
@ -17,6 +18,7 @@ namespace ARMeilleure.Translation.Cache
|
||||
private const int CacheSize = 2047 * 1024 * 1024;
|
||||
|
||||
private static ReservedRegion _jitRegion;
|
||||
private static JitCacheInvalidation _jitCacheInvalidator;
|
||||
|
||||
private static CacheMemoryAllocator _cacheAllocator;
|
||||
|
||||
@ -25,8 +27,6 @@ namespace ARMeilleure.Translation.Cache
|
||||
private static readonly object _lock = new object();
|
||||
private static bool _initialized;
|
||||
|
||||
public static IntPtr Base => _jitRegion.Pointer;
|
||||
|
||||
public static void Initialize(IJitMemoryAllocator allocator)
|
||||
{
|
||||
if (_initialized) return;
|
||||
@ -36,6 +36,7 @@ namespace ARMeilleure.Translation.Cache
|
||||
if (_initialized) return;
|
||||
|
||||
_jitRegion = new ReservedRegion(allocator, CacheSize);
|
||||
_jitCacheInvalidator = new JitCacheInvalidation(allocator);
|
||||
|
||||
_cacheAllocator = new CacheMemoryAllocator(CacheSize);
|
||||
|
||||
@ -60,11 +61,24 @@ namespace ARMeilleure.Translation.Cache
|
||||
|
||||
IntPtr funcPtr = _jitRegion.Pointer + funcOffset;
|
||||
|
||||
ReprotectAsWritable(funcOffset, code.Length);
|
||||
if (OperatingSystem.IsMacOS() && RuntimeInformation.ProcessArchitecture == Architecture.Arm64)
|
||||
{
|
||||
unsafe
|
||||
{
|
||||
fixed (byte *codePtr = code)
|
||||
{
|
||||
JitSupportDarwin.Copy(funcPtr, (IntPtr)codePtr, (ulong)code.Length);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ReprotectAsWritable(funcOffset, code.Length);
|
||||
Marshal.Copy(code, 0, funcPtr, code.Length);
|
||||
ReprotectAsExecutable(funcOffset, code.Length);
|
||||
|
||||
Marshal.Copy(code, 0, funcPtr, code.Length);
|
||||
|
||||
ReprotectAsExecutable(funcOffset, code.Length);
|
||||
_jitCacheInvalidator.Invalidate(funcPtr, (ulong)code.Length);
|
||||
}
|
||||
|
||||
Add(funcOffset, code.Length, func.UnwindInfo);
|
||||
|
||||
|
79
ARMeilleure/Translation/Cache/JitCacheInvalidation.cs
Normal file
79
ARMeilleure/Translation/Cache/JitCacheInvalidation.cs
Normal file
@ -0,0 +1,79 @@
|
||||
using ARMeilleure.Memory;
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace ARMeilleure.Translation.Cache
|
||||
{
|
||||
class JitCacheInvalidation
|
||||
{
|
||||
private static int[] _invalidationCode = new int[]
|
||||
{
|
||||
unchecked((int)0xd53b0022), // mrs x2, ctr_el0
|
||||
unchecked((int)0xd3504c44), // ubfx x4, x2, #16, #4
|
||||
unchecked((int)0x52800083), // mov w3, #0x4
|
||||
unchecked((int)0x12000c45), // and w5, w2, #0xf
|
||||
unchecked((int)0x1ac42064), // lsl w4, w3, w4
|
||||
unchecked((int)0x51000482), // sub w2, w4, #0x1
|
||||
unchecked((int)0x8a220002), // bic x2, x0, x2
|
||||
unchecked((int)0x1ac52063), // lsl w3, w3, w5
|
||||
unchecked((int)0xeb01005f), // cmp x2, x1
|
||||
unchecked((int)0x93407c84), // sxtw x4, w4
|
||||
unchecked((int)0x540000a2), // b.cs 3c <do_ic_clear>
|
||||
unchecked((int)0xd50b7b22), // dc cvau, x2
|
||||
unchecked((int)0x8b040042), // add x2, x2, x4
|
||||
unchecked((int)0xeb02003f), // cmp x1, x2
|
||||
unchecked((int)0x54ffffa8), // b.hi 2c <dc_clear_loop>
|
||||
unchecked((int)0xd5033b9f), // dsb ish
|
||||
unchecked((int)0x51000462), // sub w2, w3, #0x1
|
||||
unchecked((int)0x93407c63), // sxtw x3, w3
|
||||
unchecked((int)0x8a220000), // bic x0, x0, x2
|
||||
unchecked((int)0xeb00003f), // cmp x1, x0
|
||||
unchecked((int)0x540000a9), // b.ls 64 <exit>
|
||||
unchecked((int)0xd50b7520), // ic ivau, x0
|
||||
unchecked((int)0x8b030000), // add x0, x0, x3
|
||||
unchecked((int)0xeb00003f), // cmp x1, x0
|
||||
unchecked((int)0x54ffffa8), // b.hi 54 <ic_clear_loop>
|
||||
unchecked((int)0xd5033b9f), // dsb ish
|
||||
unchecked((int)0xd5033fdf), // isb
|
||||
unchecked((int)0xd65f03c0), // ret
|
||||
};
|
||||
|
||||
private delegate void InvalidateCache(ulong start, ulong end);
|
||||
|
||||
private InvalidateCache _invalidateCache;
|
||||
private ReservedRegion _invalidateCacheCodeRegion;
|
||||
|
||||
private readonly bool _needsInvalidation;
|
||||
|
||||
public JitCacheInvalidation(IJitMemoryAllocator allocator)
|
||||
{
|
||||
// On macOS, a different path is used to write to the JIT cache, which does the invalidation.
|
||||
if (!OperatingSystem.IsMacOS() && RuntimeInformation.ProcessArchitecture == Architecture.Arm64)
|
||||
{
|
||||
ulong size = (ulong)_invalidationCode.Length * sizeof(int);
|
||||
ulong mask = (ulong)ReservedRegion.DefaultGranularity - 1;
|
||||
|
||||
size = (size + mask) & ~mask;
|
||||
|
||||
_invalidateCacheCodeRegion = new ReservedRegion(allocator, size);
|
||||
_invalidateCacheCodeRegion.ExpandIfNeeded(size);
|
||||
|
||||
Marshal.Copy(_invalidationCode, 0, _invalidateCacheCodeRegion.Pointer, _invalidationCode.Length);
|
||||
|
||||
_invalidateCacheCodeRegion.Block.MapAsRx(0, size);
|
||||
|
||||
_invalidateCache = Marshal.GetDelegateForFunctionPointer<InvalidateCache>(_invalidateCacheCodeRegion.Pointer);
|
||||
|
||||
_needsInvalidation = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void Invalidate(IntPtr basePointer, ulong size)
|
||||
{
|
||||
if (_needsInvalidation)
|
||||
{
|
||||
_invalidateCache((ulong)basePointer, (ulong)basePointer + size);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,8 +1,9 @@
|
||||
using ARMeilleure.CodeGen;
|
||||
using ARMeilleure.CodeGen.Optimizations;
|
||||
using ARMeilleure.CodeGen.X86;
|
||||
using ARMeilleure.Diagnostics;
|
||||
using ARMeilleure.IntermediateRepresentation;
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace ARMeilleure.Translation
|
||||
{
|
||||
@ -12,7 +13,8 @@ namespace ARMeilleure.Translation
|
||||
ControlFlowGraph cfg,
|
||||
OperandType[] argTypes,
|
||||
OperandType retType,
|
||||
CompilerOptions options)
|
||||
CompilerOptions options,
|
||||
Architecture target)
|
||||
{
|
||||
CompilerContext cctx = new(cfg, argTypes, retType, options);
|
||||
|
||||
@ -49,7 +51,18 @@ namespace ARMeilleure.Translation
|
||||
Logger.EndPass(PassName.RegisterToLocal, cfg);
|
||||
}
|
||||
|
||||
return CodeGenerator.Generate(cctx);
|
||||
if (target == Architecture.X64)
|
||||
{
|
||||
return CodeGen.X86.CodeGenerator.Generate(cctx);
|
||||
}
|
||||
else if (target == Architecture.Arm64)
|
||||
{
|
||||
return CodeGen.Arm64.CodeGenerator.Generate(cctx);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new NotImplementedException(target.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
10
ARMeilleure/Translation/PTC/IPtcLoadState.cs
Normal file
10
ARMeilleure/Translation/PTC/IPtcLoadState.cs
Normal file
@ -0,0 +1,10 @@
|
||||
using System;
|
||||
|
||||
namespace ARMeilleure.Translation.PTC
|
||||
{
|
||||
public interface IPtcLoadState
|
||||
{
|
||||
event Action<PtcLoadingState, int, int> PtcStateChanged;
|
||||
void Continue();
|
||||
}
|
||||
}
|
@ -1,7 +1,6 @@
|
||||
using ARMeilleure.CodeGen;
|
||||
using ARMeilleure.CodeGen.Linking;
|
||||
using ARMeilleure.CodeGen.Unwinding;
|
||||
using ARMeilleure.CodeGen.X86;
|
||||
using ARMeilleure.Common;
|
||||
using ARMeilleure.Memory;
|
||||
using Ryujinx.Common;
|
||||
@ -22,12 +21,15 @@ using static ARMeilleure.Translation.PTC.PtcFormatter;
|
||||
|
||||
namespace ARMeilleure.Translation.PTC
|
||||
{
|
||||
public static class Ptc
|
||||
using Arm64HardwareCapabilities = ARMeilleure.CodeGen.Arm64.HardwareCapabilities;
|
||||
using X86HardwareCapabilities = ARMeilleure.CodeGen.X86.HardwareCapabilities;
|
||||
|
||||
class Ptc : IPtcLoadState
|
||||
{
|
||||
private const string OuterHeaderMagicString = "PTCohd\0\0";
|
||||
private const string InnerHeaderMagicString = "PTCihd\0\0";
|
||||
|
||||
private const uint InternalVersion = 4159; //! To be incremented manually for each change to the ARMeilleure project.
|
||||
private const uint InternalVersion = 4328; //! To be incremented manually for each change to the ARMeilleure project.
|
||||
|
||||
private const string ActualDir = "0";
|
||||
private const string BackupDir = "1";
|
||||
@ -35,45 +37,49 @@ namespace ARMeilleure.Translation.PTC
|
||||
private const string TitleIdTextDefault = "0000000000000000";
|
||||
private const string DisplayVersionDefault = "0";
|
||||
|
||||
internal static readonly Symbol PageTableSymbol = new(SymbolType.Special, 1);
|
||||
internal static readonly Symbol CountTableSymbol = new(SymbolType.Special, 2);
|
||||
internal static readonly Symbol DispatchStubSymbol = new(SymbolType.Special, 3);
|
||||
public static readonly Symbol PageTableSymbol = new(SymbolType.Special, 1);
|
||||
public static readonly Symbol CountTableSymbol = new(SymbolType.Special, 2);
|
||||
public static readonly Symbol DispatchStubSymbol = new(SymbolType.Special, 3);
|
||||
|
||||
private const byte FillingByte = 0x00;
|
||||
private const CompressionLevel SaveCompressionLevel = CompressionLevel.Fastest;
|
||||
|
||||
public PtcProfiler Profiler { get; }
|
||||
|
||||
// Carriers.
|
||||
private static MemoryStream _infosStream;
|
||||
private static List<byte[]> _codesList;
|
||||
private static MemoryStream _relocsStream;
|
||||
private static MemoryStream _unwindInfosStream;
|
||||
private MemoryStream _infosStream;
|
||||
private List<byte[]> _codesList;
|
||||
private MemoryStream _relocsStream;
|
||||
private MemoryStream _unwindInfosStream;
|
||||
|
||||
private static readonly ulong _outerHeaderMagic;
|
||||
private static readonly ulong _innerHeaderMagic;
|
||||
private readonly ulong _outerHeaderMagic;
|
||||
private readonly ulong _innerHeaderMagic;
|
||||
|
||||
private static readonly ManualResetEvent _waitEvent;
|
||||
private readonly ManualResetEvent _waitEvent;
|
||||
|
||||
private static readonly object _lock;
|
||||
private readonly object _lock;
|
||||
|
||||
private static bool _disposed;
|
||||
private bool _disposed;
|
||||
|
||||
internal static string TitleIdText { get; private set; }
|
||||
internal static string DisplayVersion { get; private set; }
|
||||
public string TitleIdText { get; private set; }
|
||||
public string DisplayVersion { get; private set; }
|
||||
|
||||
private static MemoryManagerMode _memoryMode;
|
||||
private MemoryManagerType _memoryMode;
|
||||
|
||||
internal static string CachePathActual { get; private set; }
|
||||
internal static string CachePathBackup { get; private set; }
|
||||
public string CachePathActual { get; private set; }
|
||||
public string CachePathBackup { get; private set; }
|
||||
|
||||
internal static PtcState State { get; private set; }
|
||||
public PtcState State { get; private set; }
|
||||
|
||||
// Progress reporting helpers.
|
||||
private static volatile int _translateCount;
|
||||
private static volatile int _translateTotalCount;
|
||||
public static event Action<PtcLoadingState, int, int> PtcStateChanged;
|
||||
private volatile int _translateCount;
|
||||
private volatile int _translateTotalCount;
|
||||
public event Action<PtcLoadingState, int, int> PtcStateChanged;
|
||||
|
||||
static Ptc()
|
||||
public Ptc()
|
||||
{
|
||||
Profiler = new PtcProfiler(this);
|
||||
|
||||
InitializeCarriers();
|
||||
|
||||
_outerHeaderMagic = BinaryPrimitives.ReadUInt64LittleEndian(EncodingCache.UTF8NoBOM.GetBytes(OuterHeaderMagicString).AsSpan());
|
||||
@ -94,12 +100,12 @@ namespace ARMeilleure.Translation.PTC
|
||||
Disable();
|
||||
}
|
||||
|
||||
public static void Initialize(string titleIdText, string displayVersion, bool enabled, MemoryManagerMode memoryMode)
|
||||
public void Initialize(string titleIdText, string displayVersion, bool enabled, MemoryManagerType memoryMode)
|
||||
{
|
||||
Wait();
|
||||
|
||||
PtcProfiler.Wait();
|
||||
PtcProfiler.ClearEntries();
|
||||
Profiler.Wait();
|
||||
Profiler.ClearEntries();
|
||||
|
||||
Logger.Info?.Print(LogClass.Ptc, $"Initializing Profiled Persistent Translation Cache (enabled: {enabled}).");
|
||||
|
||||
@ -137,12 +143,12 @@ namespace ARMeilleure.Translation.PTC
|
||||
CachePathBackup = Path.Combine(workPathBackup, DisplayVersion);
|
||||
|
||||
PreLoad();
|
||||
PtcProfiler.PreLoad();
|
||||
Profiler.PreLoad();
|
||||
|
||||
Enable();
|
||||
}
|
||||
|
||||
private static void InitializeCarriers()
|
||||
private void InitializeCarriers()
|
||||
{
|
||||
_infosStream = new MemoryStream();
|
||||
_codesList = new List<byte[]>();
|
||||
@ -150,7 +156,7 @@ namespace ARMeilleure.Translation.PTC
|
||||
_unwindInfosStream = new MemoryStream();
|
||||
}
|
||||
|
||||
private static void DisposeCarriers()
|
||||
private void DisposeCarriers()
|
||||
{
|
||||
_infosStream.Dispose();
|
||||
_codesList.Clear();
|
||||
@ -158,12 +164,12 @@ namespace ARMeilleure.Translation.PTC
|
||||
_unwindInfosStream.Dispose();
|
||||
}
|
||||
|
||||
private static bool AreCarriersEmpty()
|
||||
private bool AreCarriersEmpty()
|
||||
{
|
||||
return _infosStream.Length == 0L && _codesList.Count == 0 && _relocsStream.Length == 0L && _unwindInfosStream.Length == 0L;
|
||||
}
|
||||
|
||||
private static void ResetCarriersIfNeeded()
|
||||
private void ResetCarriersIfNeeded()
|
||||
{
|
||||
if (AreCarriersEmpty())
|
||||
{
|
||||
@ -175,10 +181,10 @@ namespace ARMeilleure.Translation.PTC
|
||||
InitializeCarriers();
|
||||
}
|
||||
|
||||
private static void PreLoad()
|
||||
private void PreLoad()
|
||||
{
|
||||
string fileNameActual = string.Concat(CachePathActual, ".cache");
|
||||
string fileNameBackup = string.Concat(CachePathBackup, ".cache");
|
||||
string fileNameActual = $"{CachePathActual}.cache";
|
||||
string fileNameBackup = $"{CachePathBackup}.cache";
|
||||
|
||||
FileInfo fileInfoActual = new FileInfo(fileNameActual);
|
||||
FileInfo fileInfoBackup = new FileInfo(fileNameBackup);
|
||||
@ -199,7 +205,7 @@ namespace ARMeilleure.Translation.PTC
|
||||
}
|
||||
}
|
||||
|
||||
private static unsafe bool Load(string fileName, bool isBackup)
|
||||
private unsafe bool Load(string fileName, bool isBackup)
|
||||
{
|
||||
using (FileStream compressedStream = new(fileName, FileMode.Open))
|
||||
using (DeflateStream deflateStream = new(compressedStream, CompressionMode.Decompress, true))
|
||||
@ -255,6 +261,13 @@ namespace ARMeilleure.Translation.PTC
|
||||
return false;
|
||||
}
|
||||
|
||||
if (outerHeader.Architecture != (uint)RuntimeInformation.ProcessArchitecture)
|
||||
{
|
||||
InvalidateCompressedStream(compressedStream);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
IntPtr intPtr = IntPtr.Zero;
|
||||
|
||||
try
|
||||
@ -376,19 +389,19 @@ namespace ARMeilleure.Translation.PTC
|
||||
return true;
|
||||
}
|
||||
|
||||
private static void InvalidateCompressedStream(FileStream compressedStream)
|
||||
private void InvalidateCompressedStream(FileStream compressedStream)
|
||||
{
|
||||
compressedStream.SetLength(0L);
|
||||
}
|
||||
|
||||
private static void PreSave()
|
||||
private void PreSave()
|
||||
{
|
||||
_waitEvent.Reset();
|
||||
|
||||
try
|
||||
{
|
||||
string fileNameActual = string.Concat(CachePathActual, ".cache");
|
||||
string fileNameBackup = string.Concat(CachePathBackup, ".cache");
|
||||
string fileNameActual = $"{CachePathActual}.cache";
|
||||
string fileNameBackup = $"{CachePathBackup}.cache";
|
||||
|
||||
FileInfo fileInfoActual = new FileInfo(fileNameActual);
|
||||
|
||||
@ -409,7 +422,7 @@ namespace ARMeilleure.Translation.PTC
|
||||
_waitEvent.Set();
|
||||
}
|
||||
|
||||
private static unsafe void Save(string fileName)
|
||||
private unsafe void Save(string fileName)
|
||||
{
|
||||
int translatedFuncsCount;
|
||||
|
||||
@ -431,6 +444,7 @@ namespace ARMeilleure.Translation.PTC
|
||||
outerHeader.FeatureInfo = GetFeatureInfo();
|
||||
outerHeader.MemoryManagerMode = GetMemoryManagerMode();
|
||||
outerHeader.OSPlatform = GetOSPlatform();
|
||||
outerHeader.Architecture = (uint)RuntimeInformation.ProcessArchitecture;
|
||||
|
||||
outerHeader.UncompressedStreamSize =
|
||||
(long)Unsafe.SizeOf<InnerHeader>() +
|
||||
@ -517,7 +531,7 @@ namespace ARMeilleure.Translation.PTC
|
||||
}
|
||||
}
|
||||
|
||||
internal static void LoadTranslations(Translator translator)
|
||||
public void LoadTranslations(Translator translator)
|
||||
{
|
||||
if (AreCarriersEmpty())
|
||||
{
|
||||
@ -550,7 +564,7 @@ namespace ARMeilleure.Translation.PTC
|
||||
|
||||
bool isEntryChanged = infoEntry.Hash != ComputeHash(translator.Memory, infoEntry.Address, infoEntry.GuestSize);
|
||||
|
||||
if (isEntryChanged || (!infoEntry.HighCq && PtcProfiler.ProfiledFuncs.TryGetValue(infoEntry.Address, out var value) && value.HighCq))
|
||||
if (isEntryChanged || (!infoEntry.HighCq && Profiler.ProfiledFuncs.TryGetValue(infoEntry.Address, out var value) && value.HighCq))
|
||||
{
|
||||
infoEntry.Stubbed = true;
|
||||
infoEntry.CodeLength = 0;
|
||||
@ -601,38 +615,38 @@ namespace ARMeilleure.Translation.PTC
|
||||
Logger.Info?.Print(LogClass.Ptc, $"{translator.Functions.Count} translated functions loaded");
|
||||
}
|
||||
|
||||
private static int GetEntriesCount()
|
||||
private int GetEntriesCount()
|
||||
{
|
||||
return _codesList.Count;
|
||||
}
|
||||
|
||||
[Conditional("DEBUG")]
|
||||
private static void SkipCode(int index, int codeLength)
|
||||
private void SkipCode(int index, int codeLength)
|
||||
{
|
||||
Debug.Assert(_codesList[index].Length == 0);
|
||||
Debug.Assert(codeLength == 0);
|
||||
}
|
||||
|
||||
private static void SkipReloc(int relocEntriesCount)
|
||||
private void SkipReloc(int relocEntriesCount)
|
||||
{
|
||||
_relocsStream.Seek(relocEntriesCount * RelocEntry.Stride, SeekOrigin.Current);
|
||||
}
|
||||
|
||||
private static void SkipUnwindInfo(BinaryReader unwindInfosReader)
|
||||
private void SkipUnwindInfo(BinaryReader unwindInfosReader)
|
||||
{
|
||||
int pushEntriesLength = unwindInfosReader.ReadInt32();
|
||||
|
||||
_unwindInfosStream.Seek(pushEntriesLength * UnwindPushEntry.Stride + UnwindInfo.Stride, SeekOrigin.Current);
|
||||
}
|
||||
|
||||
private static byte[] ReadCode(int index, int codeLength)
|
||||
private byte[] ReadCode(int index, int codeLength)
|
||||
{
|
||||
Debug.Assert(_codesList[index].Length == codeLength);
|
||||
|
||||
return _codesList[index];
|
||||
}
|
||||
|
||||
private static RelocEntry[] GetRelocEntries(BinaryReader relocsReader, int relocEntriesCount)
|
||||
private RelocEntry[] GetRelocEntries(BinaryReader relocsReader, int relocEntriesCount)
|
||||
{
|
||||
RelocEntry[] relocEntries = new RelocEntry[relocEntriesCount];
|
||||
|
||||
@ -648,7 +662,7 @@ namespace ARMeilleure.Translation.PTC
|
||||
return relocEntries;
|
||||
}
|
||||
|
||||
private static void PatchCode(Translator translator, Span<byte> code, RelocEntry[] relocEntries, out Counter<uint> callCounter)
|
||||
private void PatchCode(Translator translator, Span<byte> code, RelocEntry[] relocEntries, out Counter<uint> callCounter)
|
||||
{
|
||||
callCounter = null;
|
||||
|
||||
@ -702,7 +716,7 @@ namespace ARMeilleure.Translation.PTC
|
||||
}
|
||||
}
|
||||
|
||||
private static UnwindInfo ReadUnwindInfo(BinaryReader unwindInfosReader)
|
||||
private UnwindInfo ReadUnwindInfo(BinaryReader unwindInfosReader)
|
||||
{
|
||||
int pushEntriesLength = unwindInfosReader.ReadInt32();
|
||||
|
||||
@ -723,7 +737,7 @@ namespace ARMeilleure.Translation.PTC
|
||||
return new UnwindInfo(pushEntries, prologueSize);
|
||||
}
|
||||
|
||||
private static TranslatedFunction FastTranslate(
|
||||
private TranslatedFunction FastTranslate(
|
||||
byte[] code,
|
||||
Counter<uint> callCounter,
|
||||
ulong guestSize,
|
||||
@ -731,24 +745,24 @@ namespace ARMeilleure.Translation.PTC
|
||||
bool highCq)
|
||||
{
|
||||
var cFunc = new CompiledFunction(code, unwindInfo, RelocInfo.Empty);
|
||||
var gFunc = cFunc.Map<GuestFunction>();
|
||||
var gFunc = cFunc.MapWithPointer<GuestFunction>(out IntPtr gFuncPointer);
|
||||
|
||||
return new TranslatedFunction(gFunc, callCounter, guestSize, highCq);
|
||||
return new TranslatedFunction(gFunc, gFuncPointer, callCounter, guestSize, highCq);
|
||||
}
|
||||
|
||||
private static void UpdateInfo(InfoEntry infoEntry)
|
||||
private void UpdateInfo(InfoEntry infoEntry)
|
||||
{
|
||||
_infosStream.Seek(-Unsafe.SizeOf<InfoEntry>(), SeekOrigin.Current);
|
||||
|
||||
SerializeStructure(_infosStream, infoEntry);
|
||||
}
|
||||
|
||||
private static void StubCode(int index)
|
||||
private void StubCode(int index)
|
||||
{
|
||||
_codesList[index] = Array.Empty<byte>();
|
||||
}
|
||||
|
||||
private static void StubReloc(int relocEntriesCount)
|
||||
private void StubReloc(int relocEntriesCount)
|
||||
{
|
||||
for (int i = 0; i < relocEntriesCount * RelocEntry.Stride; i++)
|
||||
{
|
||||
@ -756,7 +770,7 @@ namespace ARMeilleure.Translation.PTC
|
||||
}
|
||||
}
|
||||
|
||||
private static void StubUnwindInfo(BinaryReader unwindInfosReader)
|
||||
private void StubUnwindInfo(BinaryReader unwindInfosReader)
|
||||
{
|
||||
int pushEntriesLength = unwindInfosReader.ReadInt32();
|
||||
|
||||
@ -766,9 +780,9 @@ namespace ARMeilleure.Translation.PTC
|
||||
}
|
||||
}
|
||||
|
||||
internal static void MakeAndSaveTranslations(Translator translator)
|
||||
public void MakeAndSaveTranslations(Translator translator)
|
||||
{
|
||||
var profiledFuncsToTranslate = PtcProfiler.GetProfiledFuncsToTranslate(translator.Functions);
|
||||
var profiledFuncsToTranslate = Profiler.GetProfiledFuncsToTranslate(translator.Functions);
|
||||
|
||||
_translateCount = 0;
|
||||
_translateTotalCount = profiledFuncsToTranslate.Count;
|
||||
@ -811,7 +825,7 @@ namespace ARMeilleure.Translation.PTC
|
||||
{
|
||||
ulong address = item.address;
|
||||
|
||||
Debug.Assert(PtcProfiler.IsAddressInStaticCodeRange(address));
|
||||
Debug.Assert(Profiler.IsAddressInStaticCodeRange(address));
|
||||
|
||||
TranslatedFunction func = translator.Translate(address, item.funcProfile.Mode, item.funcProfile.HighCq);
|
||||
|
||||
@ -861,7 +875,7 @@ namespace ARMeilleure.Translation.PTC
|
||||
preSaveThread.Start();
|
||||
}
|
||||
|
||||
private static void ReportProgress(object state)
|
||||
private void ReportProgress(object state)
|
||||
{
|
||||
const int refreshRate = 50; // ms.
|
||||
|
||||
@ -882,12 +896,12 @@ namespace ARMeilleure.Translation.PTC
|
||||
while (!endEvent.WaitOne(refreshRate));
|
||||
}
|
||||
|
||||
internal static Hash128 ComputeHash(IMemoryManager memory, ulong address, ulong guestSize)
|
||||
public static Hash128 ComputeHash(IMemoryManager memory, ulong address, ulong guestSize)
|
||||
{
|
||||
return XXHash128.ComputeHash(memory.GetSpan(address, checked((int)(guestSize))));
|
||||
}
|
||||
|
||||
internal static void WriteCompiledFunction(ulong address, ulong guestSize, Hash128 hash, bool highCq, CompiledFunction compiledFunc)
|
||||
public void WriteCompiledFunction(ulong address, ulong guestSize, Hash128 hash, bool highCq, CompiledFunction compiledFunc)
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
@ -936,26 +950,41 @@ namespace ARMeilleure.Translation.PTC
|
||||
}
|
||||
}
|
||||
|
||||
private static void WriteCode(ReadOnlySpan<byte> code)
|
||||
private void WriteCode(ReadOnlySpan<byte> code)
|
||||
{
|
||||
_codesList.Add(code.ToArray());
|
||||
}
|
||||
|
||||
internal static bool GetEndianness()
|
||||
public static bool GetEndianness()
|
||||
{
|
||||
return BitConverter.IsLittleEndian;
|
||||
}
|
||||
|
||||
private static FeatureInfo GetFeatureInfo()
|
||||
{
|
||||
return new FeatureInfo(
|
||||
(uint)HardwareCapabilities.FeatureInfo1Ecx,
|
||||
(uint)HardwareCapabilities.FeatureInfo1Edx,
|
||||
(uint)HardwareCapabilities.FeatureInfo7Ebx,
|
||||
(uint)HardwareCapabilities.FeatureInfo7Ecx);
|
||||
if (RuntimeInformation.ProcessArchitecture == Architecture.Arm64)
|
||||
{
|
||||
return new FeatureInfo(
|
||||
(ulong)Arm64HardwareCapabilities.LinuxFeatureInfoHwCap,
|
||||
(ulong)Arm64HardwareCapabilities.LinuxFeatureInfoHwCap2,
|
||||
(ulong)Arm64HardwareCapabilities.MacOsFeatureInfo,
|
||||
0);
|
||||
}
|
||||
else if (RuntimeInformation.ProcessArchitecture == Architecture.X64)
|
||||
{
|
||||
return new FeatureInfo(
|
||||
(ulong)X86HardwareCapabilities.FeatureInfo1Ecx,
|
||||
(ulong)X86HardwareCapabilities.FeatureInfo1Edx,
|
||||
(ulong)X86HardwareCapabilities.FeatureInfo7Ebx,
|
||||
(ulong)X86HardwareCapabilities.FeatureInfo7Ecx);
|
||||
}
|
||||
else
|
||||
{
|
||||
return new FeatureInfo(0, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
private static byte GetMemoryManagerMode()
|
||||
private byte GetMemoryManagerMode()
|
||||
{
|
||||
return (byte)_memoryMode;
|
||||
}
|
||||
@ -972,7 +1001,7 @@ namespace ARMeilleure.Translation.PTC
|
||||
return osPlatform;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1/*, Size = 58*/)]
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1/*, Size = 78*/)]
|
||||
private struct OuterHeader
|
||||
{
|
||||
public ulong Magic;
|
||||
@ -983,6 +1012,7 @@ namespace ARMeilleure.Translation.PTC
|
||||
public FeatureInfo FeatureInfo;
|
||||
public byte MemoryManagerMode;
|
||||
public uint OSPlatform;
|
||||
public uint Architecture;
|
||||
|
||||
public long UncompressedStreamSize;
|
||||
|
||||
@ -1003,8 +1033,8 @@ namespace ARMeilleure.Translation.PTC
|
||||
}
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1/*, Size = 16*/)]
|
||||
private record struct FeatureInfo(uint FeatureInfo0, uint FeatureInfo1, uint FeatureInfo2, uint FeatureInfo3);
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1/*, Size = 32*/)]
|
||||
private record struct FeatureInfo(ulong FeatureInfo0, ulong FeatureInfo1, ulong FeatureInfo2, ulong FeatureInfo3);
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1/*, Size = 128*/)]
|
||||
private struct InnerHeader
|
||||
@ -1050,12 +1080,12 @@ namespace ARMeilleure.Translation.PTC
|
||||
public int RelocEntriesCount;
|
||||
}
|
||||
|
||||
private static void Enable()
|
||||
private void Enable()
|
||||
{
|
||||
State = PtcState.Enabled;
|
||||
}
|
||||
|
||||
public static void Continue()
|
||||
public void Continue()
|
||||
{
|
||||
if (State == PtcState.Enabled)
|
||||
{
|
||||
@ -1063,7 +1093,7 @@ namespace ARMeilleure.Translation.PTC
|
||||
}
|
||||
}
|
||||
|
||||
public static void Close()
|
||||
public void Close()
|
||||
{
|
||||
if (State == PtcState.Enabled ||
|
||||
State == PtcState.Continuing)
|
||||
@ -1072,17 +1102,17 @@ namespace ARMeilleure.Translation.PTC
|
||||
}
|
||||
}
|
||||
|
||||
internal static void Disable()
|
||||
public void Disable()
|
||||
{
|
||||
State = PtcState.Disabled;
|
||||
}
|
||||
|
||||
private static void Wait()
|
||||
private void Wait()
|
||||
{
|
||||
_waitEvent.WaitOne();
|
||||
}
|
||||
|
||||
public static void Dispose()
|
||||
public void Dispose()
|
||||
{
|
||||
if (!_disposed)
|
||||
{
|
||||
|
@ -16,7 +16,7 @@ using static ARMeilleure.Translation.PTC.PtcFormatter;
|
||||
|
||||
namespace ARMeilleure.Translation.PTC
|
||||
{
|
||||
public static class PtcProfiler
|
||||
class PtcProfiler
|
||||
{
|
||||
private const string OuterHeaderMagicString = "Pohd\0\0\0\0";
|
||||
|
||||
@ -26,27 +26,31 @@ namespace ARMeilleure.Translation.PTC
|
||||
|
||||
private const CompressionLevel SaveCompressionLevel = CompressionLevel.Fastest;
|
||||
|
||||
private static readonly System.Timers.Timer _timer;
|
||||
private readonly Ptc _ptc;
|
||||
|
||||
private static readonly ulong _outerHeaderMagic;
|
||||
private readonly System.Timers.Timer _timer;
|
||||
|
||||
private static readonly ManualResetEvent _waitEvent;
|
||||
private readonly ulong _outerHeaderMagic;
|
||||
|
||||
private static readonly object _lock;
|
||||
private readonly ManualResetEvent _waitEvent;
|
||||
|
||||
private static bool _disposed;
|
||||
private readonly object _lock;
|
||||
|
||||
private static Hash128 _lastHash;
|
||||
private bool _disposed;
|
||||
|
||||
internal static Dictionary<ulong, FuncProfile> ProfiledFuncs { get; private set; }
|
||||
private Hash128 _lastHash;
|
||||
|
||||
internal static bool Enabled { get; private set; }
|
||||
public Dictionary<ulong, FuncProfile> ProfiledFuncs { get; private set; }
|
||||
|
||||
public static ulong StaticCodeStart { internal get; set; }
|
||||
public static ulong StaticCodeSize { internal get; set; }
|
||||
public bool Enabled { get; private set; }
|
||||
|
||||
static PtcProfiler()
|
||||
public ulong StaticCodeStart { get; set; }
|
||||
public ulong StaticCodeSize { get; set; }
|
||||
|
||||
public PtcProfiler(Ptc ptc)
|
||||
{
|
||||
_ptc = ptc;
|
||||
|
||||
_timer = new System.Timers.Timer((double)SaveInterval * 1000d);
|
||||
_timer.Elapsed += PreSave;
|
||||
|
||||
@ -63,7 +67,7 @@ namespace ARMeilleure.Translation.PTC
|
||||
Enabled = false;
|
||||
}
|
||||
|
||||
internal static void AddEntry(ulong address, ExecutionMode mode, bool highCq)
|
||||
public void AddEntry(ulong address, ExecutionMode mode, bool highCq)
|
||||
{
|
||||
if (IsAddressInStaticCodeRange(address))
|
||||
{
|
||||
@ -76,7 +80,7 @@ namespace ARMeilleure.Translation.PTC
|
||||
}
|
||||
}
|
||||
|
||||
internal static void UpdateEntry(ulong address, ExecutionMode mode, bool highCq)
|
||||
public void UpdateEntry(ulong address, ExecutionMode mode, bool highCq)
|
||||
{
|
||||
if (IsAddressInStaticCodeRange(address))
|
||||
{
|
||||
@ -91,12 +95,12 @@ namespace ARMeilleure.Translation.PTC
|
||||
}
|
||||
}
|
||||
|
||||
internal static bool IsAddressInStaticCodeRange(ulong address)
|
||||
public bool IsAddressInStaticCodeRange(ulong address)
|
||||
{
|
||||
return address >= StaticCodeStart && address < StaticCodeStart + StaticCodeSize;
|
||||
}
|
||||
|
||||
internal static ConcurrentQueue<(ulong address, FuncProfile funcProfile)> GetProfiledFuncsToTranslate(TranslatorCache<TranslatedFunction> funcs)
|
||||
public ConcurrentQueue<(ulong address, FuncProfile funcProfile)> GetProfiledFuncsToTranslate(TranslatorCache<TranslatedFunction> funcs)
|
||||
{
|
||||
var profiledFuncsToTranslate = new ConcurrentQueue<(ulong address, FuncProfile funcProfile)>();
|
||||
|
||||
@ -111,18 +115,18 @@ namespace ARMeilleure.Translation.PTC
|
||||
return profiledFuncsToTranslate;
|
||||
}
|
||||
|
||||
internal static void ClearEntries()
|
||||
public void ClearEntries()
|
||||
{
|
||||
ProfiledFuncs.Clear();
|
||||
ProfiledFuncs.TrimExcess();
|
||||
}
|
||||
|
||||
internal static void PreLoad()
|
||||
public void PreLoad()
|
||||
{
|
||||
_lastHash = default;
|
||||
|
||||
string fileNameActual = string.Concat(Ptc.CachePathActual, ".info");
|
||||
string fileNameBackup = string.Concat(Ptc.CachePathBackup, ".info");
|
||||
string fileNameActual = $"{_ptc.CachePathActual}.info";
|
||||
string fileNameBackup = $"{_ptc.CachePathBackup}.info";
|
||||
|
||||
FileInfo fileInfoActual = new FileInfo(fileNameActual);
|
||||
FileInfo fileInfoBackup = new FileInfo(fileNameBackup);
|
||||
@ -143,7 +147,7 @@ namespace ARMeilleure.Translation.PTC
|
||||
}
|
||||
}
|
||||
|
||||
private static bool Load(string fileName, bool isBackup)
|
||||
private bool Load(string fileName, bool isBackup)
|
||||
{
|
||||
using (FileStream compressedStream = new(fileName, FileMode.Open))
|
||||
using (DeflateStream deflateStream = new(compressedStream, CompressionMode.Decompress, true))
|
||||
@ -228,22 +232,22 @@ namespace ARMeilleure.Translation.PTC
|
||||
return DeserializeDictionary<ulong, FuncProfile>(stream, (stream) => DeserializeStructure<FuncProfile>(stream));
|
||||
}
|
||||
|
||||
private static ReadOnlySpan<byte> GetReadOnlySpan(MemoryStream memoryStream)
|
||||
private ReadOnlySpan<byte> GetReadOnlySpan(MemoryStream memoryStream)
|
||||
{
|
||||
return new(memoryStream.GetBuffer(), (int)memoryStream.Position, (int)memoryStream.Length - (int)memoryStream.Position);
|
||||
}
|
||||
|
||||
private static void InvalidateCompressedStream(FileStream compressedStream)
|
||||
private void InvalidateCompressedStream(FileStream compressedStream)
|
||||
{
|
||||
compressedStream.SetLength(0L);
|
||||
}
|
||||
|
||||
private static void PreSave(object source, System.Timers.ElapsedEventArgs e)
|
||||
private void PreSave(object source, System.Timers.ElapsedEventArgs e)
|
||||
{
|
||||
_waitEvent.Reset();
|
||||
|
||||
string fileNameActual = string.Concat(Ptc.CachePathActual, ".info");
|
||||
string fileNameBackup = string.Concat(Ptc.CachePathBackup, ".info");
|
||||
string fileNameActual = $"{_ptc.CachePathActual}.info";
|
||||
string fileNameBackup = $"{_ptc.CachePathBackup}.info";
|
||||
|
||||
FileInfo fileInfoActual = new FileInfo(fileNameActual);
|
||||
|
||||
@ -257,7 +261,7 @@ namespace ARMeilleure.Translation.PTC
|
||||
_waitEvent.Set();
|
||||
}
|
||||
|
||||
private static void Save(string fileName)
|
||||
private void Save(string fileName)
|
||||
{
|
||||
int profiledFuncsCount;
|
||||
|
||||
@ -329,7 +333,7 @@ namespace ARMeilleure.Translation.PTC
|
||||
}
|
||||
}
|
||||
|
||||
private static void Serialize(Stream stream, Dictionary<ulong, FuncProfile> profiledFuncs)
|
||||
private void Serialize(Stream stream, Dictionary<ulong, FuncProfile> profiledFuncs)
|
||||
{
|
||||
SerializeDictionary(stream, profiledFuncs, (stream, structure) => SerializeStructure(stream, structure));
|
||||
}
|
||||
@ -361,7 +365,7 @@ namespace ARMeilleure.Translation.PTC
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1/*, Size = 5*/)]
|
||||
internal struct FuncProfile
|
||||
public struct FuncProfile
|
||||
{
|
||||
public ExecutionMode Mode;
|
||||
public bool HighCq;
|
||||
@ -373,10 +377,10 @@ namespace ARMeilleure.Translation.PTC
|
||||
}
|
||||
}
|
||||
|
||||
internal static void Start()
|
||||
public void Start()
|
||||
{
|
||||
if (Ptc.State == PtcState.Enabled ||
|
||||
Ptc.State == PtcState.Continuing)
|
||||
if (_ptc.State == PtcState.Enabled ||
|
||||
_ptc.State == PtcState.Continuing)
|
||||
{
|
||||
Enabled = true;
|
||||
|
||||
@ -384,7 +388,7 @@ namespace ARMeilleure.Translation.PTC
|
||||
}
|
||||
}
|
||||
|
||||
public static void Stop()
|
||||
public void Stop()
|
||||
{
|
||||
Enabled = false;
|
||||
|
||||
@ -394,12 +398,12 @@ namespace ARMeilleure.Translation.PTC
|
||||
}
|
||||
}
|
||||
|
||||
internal static void Wait()
|
||||
public void Wait()
|
||||
{
|
||||
_waitEvent.WaitOne();
|
||||
}
|
||||
|
||||
public static void Dispose()
|
||||
public void Dispose()
|
||||
{
|
||||
if (!_disposed)
|
||||
{
|
||||
|
@ -1,6 +1,5 @@
|
||||
using ARMeilleure.Common;
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace ARMeilleure.Translation
|
||||
{
|
||||
@ -8,18 +7,18 @@ namespace ARMeilleure.Translation
|
||||
{
|
||||
private readonly GuestFunction _func; // Ensure that this delegate will not be garbage collected.
|
||||
|
||||
public IntPtr FuncPointer { get; }
|
||||
public Counter<uint> CallCounter { get; }
|
||||
public ulong GuestSize { get; }
|
||||
public bool HighCq { get; }
|
||||
public IntPtr FuncPtr { get; }
|
||||
|
||||
public TranslatedFunction(GuestFunction func, Counter<uint> callCounter, ulong guestSize, bool highCq)
|
||||
public TranslatedFunction(GuestFunction func, IntPtr funcPointer, Counter<uint> callCounter, ulong guestSize, bool highCq)
|
||||
{
|
||||
_func = func;
|
||||
FuncPointer = funcPointer;
|
||||
CallCounter = callCounter;
|
||||
GuestSize = guestSize;
|
||||
HighCq = highCq;
|
||||
FuncPtr = Marshal.GetFunctionPointerForDelegate(func);
|
||||
}
|
||||
|
||||
public ulong Execute(State.ExecutionContext context)
|
||||
|
@ -14,6 +14,7 @@ using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
|
||||
|
||||
@ -44,6 +45,8 @@ namespace ARMeilleure.Translation
|
||||
private readonly IJitMemoryAllocator _allocator;
|
||||
private readonly ConcurrentQueue<KeyValuePair<ulong, TranslatedFunction>> _oldFuncs;
|
||||
|
||||
private readonly Ptc _ptc;
|
||||
|
||||
internal TranslatorCache<TranslatedFunction> Functions { get; }
|
||||
internal AddressTable<ulong> FunctionTable { get; }
|
||||
internal EntryTable<uint> CountTable { get; }
|
||||
@ -63,6 +66,8 @@ namespace ARMeilleure.Translation
|
||||
|
||||
_oldFuncs = new ConcurrentQueue<KeyValuePair<ulong, TranslatedFunction>>();
|
||||
|
||||
_ptc = new Ptc();
|
||||
|
||||
Queue = new TranslatorQueue();
|
||||
|
||||
JitCache.Initialize(allocator);
|
||||
@ -76,7 +81,22 @@ namespace ARMeilleure.Translation
|
||||
|
||||
if (memory.Type.IsHostMapped())
|
||||
{
|
||||
NativeSignalHandler.InitializeSignalHandler();
|
||||
NativeSignalHandler.InitializeSignalHandler(allocator.GetPageSize());
|
||||
}
|
||||
}
|
||||
|
||||
public IPtcLoadState LoadDiskCache(string titleIdText, string displayVersion, bool enabled)
|
||||
{
|
||||
_ptc.Initialize(titleIdText, displayVersion, enabled, Memory.Type);
|
||||
return _ptc;
|
||||
}
|
||||
|
||||
public void PrepareCodeRange(ulong address, ulong size)
|
||||
{
|
||||
if (_ptc.Profiler.StaticCodeSize == 0)
|
||||
{
|
||||
_ptc.Profiler.StaticCodeStart = address;
|
||||
_ptc.Profiler.StaticCodeSize = size;
|
||||
}
|
||||
}
|
||||
|
||||
@ -86,16 +106,16 @@ namespace ARMeilleure.Translation
|
||||
{
|
||||
IsReadyForTranslation.WaitOne();
|
||||
|
||||
if (Ptc.State == PtcState.Enabled)
|
||||
if (_ptc.State == PtcState.Enabled)
|
||||
{
|
||||
Debug.Assert(Functions.Count == 0);
|
||||
Ptc.LoadTranslations(this);
|
||||
Ptc.MakeAndSaveTranslations(this);
|
||||
_ptc.LoadTranslations(this);
|
||||
_ptc.MakeAndSaveTranslations(this);
|
||||
}
|
||||
|
||||
PtcProfiler.Start();
|
||||
_ptc.Profiler.Start();
|
||||
|
||||
Ptc.Disable();
|
||||
_ptc.Disable();
|
||||
|
||||
// Simple heuristic, should be user configurable in future. (1 for 4 core/ht or less, 2 for 6 core + ht
|
||||
// etc). All threads are normal priority except from the last, which just fills as much of the last core
|
||||
@ -148,6 +168,12 @@ namespace ARMeilleure.Translation
|
||||
Stubs.Dispose();
|
||||
FunctionTable.Dispose();
|
||||
CountTable.Dispose();
|
||||
|
||||
_ptc.Close();
|
||||
_ptc.Profiler.Stop();
|
||||
|
||||
_ptc.Dispose();
|
||||
_ptc.Profiler.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
@ -185,13 +211,13 @@ namespace ARMeilleure.Translation
|
||||
|
||||
if (oldFunc != func)
|
||||
{
|
||||
JitCache.Unmap(func.FuncPtr);
|
||||
JitCache.Unmap(func.FuncPointer);
|
||||
func = oldFunc;
|
||||
}
|
||||
|
||||
if (PtcProfiler.Enabled)
|
||||
if (_ptc.Profiler.Enabled)
|
||||
{
|
||||
PtcProfiler.AddEntry(address, mode, highCq: false);
|
||||
_ptc.Profiler.AddEntry(address, mode, highCq: false);
|
||||
}
|
||||
|
||||
RegisterFunction(address, func);
|
||||
@ -204,7 +230,7 @@ namespace ARMeilleure.Translation
|
||||
{
|
||||
if (FunctionTable.IsValid(guestAddress) && (Optimizations.AllowLcqInFunctionTable || func.HighCq))
|
||||
{
|
||||
Volatile.Write(ref FunctionTable.GetValue(guestAddress), (ulong)func.FuncPtr);
|
||||
Volatile.Write(ref FunctionTable.GetValue(guestAddress), (ulong)func.FuncPointer);
|
||||
}
|
||||
}
|
||||
|
||||
@ -217,6 +243,7 @@ namespace ARMeilleure.Translation
|
||||
Stubs,
|
||||
address,
|
||||
highCq,
|
||||
_ptc.State != PtcState.Disabled,
|
||||
mode: Aarch32Mode.User);
|
||||
|
||||
Logger.StartPass(PassName.Decoding);
|
||||
@ -256,20 +283,20 @@ namespace ARMeilleure.Translation
|
||||
options |= CompilerOptions.Relocatable;
|
||||
}
|
||||
|
||||
CompiledFunction compiledFunc = Compiler.Compile(cfg, argTypes, retType, options);
|
||||
CompiledFunction compiledFunc = Compiler.Compile(cfg, argTypes, retType, options, RuntimeInformation.ProcessArchitecture);
|
||||
|
||||
if (context.HasPtc && !singleStep)
|
||||
{
|
||||
Hash128 hash = Ptc.ComputeHash(Memory, address, funcSize);
|
||||
|
||||
Ptc.WriteCompiledFunction(address, funcSize, hash, highCq, compiledFunc);
|
||||
_ptc.WriteCompiledFunction(address, funcSize, hash, highCq, compiledFunc);
|
||||
}
|
||||
|
||||
GuestFunction func = compiledFunc.Map<GuestFunction>();
|
||||
GuestFunction func = compiledFunc.MapWithPointer<GuestFunction>(out IntPtr funcPointer);
|
||||
|
||||
Allocators.ResetAll();
|
||||
|
||||
return new TranslatedFunction(func, counter, funcSize, highCq);
|
||||
return new TranslatedFunction(func, funcPointer, counter, funcSize, highCq);
|
||||
}
|
||||
|
||||
private void BackgroundTranslate()
|
||||
@ -284,9 +311,9 @@ namespace ARMeilleure.Translation
|
||||
return func;
|
||||
});
|
||||
|
||||
if (PtcProfiler.Enabled)
|
||||
if (_ptc.Profiler.Enabled)
|
||||
{
|
||||
PtcProfiler.UpdateEntry(request.Address, request.Mode, highCq: true);
|
||||
_ptc.Profiler.UpdateEntry(request.Address, request.Mode, highCq: true);
|
||||
}
|
||||
|
||||
RegisterFunction(request.Address, func);
|
||||
@ -333,9 +360,14 @@ namespace ARMeilleure.Translation
|
||||
}
|
||||
}
|
||||
|
||||
if (block.Address == context.EntryAddress && !context.HighCq)
|
||||
if (block.Address == context.EntryAddress)
|
||||
{
|
||||
EmitRejitCheck(context, out counter);
|
||||
if (!context.HighCq)
|
||||
{
|
||||
EmitRejitCheck(context, out counter);
|
||||
}
|
||||
|
||||
context.ClearQcFlag();
|
||||
}
|
||||
|
||||
context.CurrBlock = block;
|
||||
@ -360,9 +392,14 @@ namespace ARMeilleure.Translation
|
||||
|
||||
bool isLastOp = opcIndex == block.OpCodes.Count - 1;
|
||||
|
||||
if (isLastOp && block.Branch != null && !block.Branch.Exit && block.Branch.Address <= block.Address)
|
||||
if (isLastOp)
|
||||
{
|
||||
EmitSynchronization(context);
|
||||
context.SyncQcFlag();
|
||||
|
||||
if (block.Branch != null && !block.Branch.Exit && block.Branch.Address <= block.Address)
|
||||
{
|
||||
EmitSynchronization(context);
|
||||
}
|
||||
}
|
||||
|
||||
Operand lblPredicateSkip = default;
|
||||
@ -500,7 +537,7 @@ namespace ARMeilleure.Translation
|
||||
|
||||
foreach (var func in functions)
|
||||
{
|
||||
JitCache.Unmap(func.FuncPtr);
|
||||
JitCache.Unmap(func.FuncPointer);
|
||||
|
||||
func.CallCounter?.Dispose();
|
||||
}
|
||||
@ -509,7 +546,7 @@ namespace ARMeilleure.Translation
|
||||
|
||||
while (_oldFuncs.TryDequeue(out var kv))
|
||||
{
|
||||
JitCache.Unmap(kv.Value.FuncPtr);
|
||||
JitCache.Unmap(kv.Value.FuncPointer);
|
||||
|
||||
kv.Value.CallCounter?.Dispose();
|
||||
}
|
||||
|
@ -171,7 +171,7 @@ namespace ARMeilleure.Translation
|
||||
var retType = OperandType.I64;
|
||||
var argTypes = new[] { OperandType.I64 };
|
||||
|
||||
var func = Compiler.Compile(cfg, argTypes, retType, CompilerOptions.HighCq).Map<GuestFunction>();
|
||||
var func = Compiler.Compile(cfg, argTypes, retType, CompilerOptions.HighCq, RuntimeInformation.ProcessArchitecture).Map<GuestFunction>();
|
||||
|
||||
return Marshal.GetFunctionPointerForDelegate(func);
|
||||
}
|
||||
@ -197,7 +197,7 @@ namespace ARMeilleure.Translation
|
||||
var retType = OperandType.I64;
|
||||
var argTypes = new[] { OperandType.I64 };
|
||||
|
||||
var func = Compiler.Compile(cfg, argTypes, retType, CompilerOptions.HighCq).Map<GuestFunction>();
|
||||
var func = Compiler.Compile(cfg, argTypes, retType, CompilerOptions.HighCq, RuntimeInformation.ProcessArchitecture).Map<GuestFunction>();
|
||||
|
||||
return Marshal.GetFunctionPointerForDelegate(func);
|
||||
}
|
||||
@ -235,7 +235,7 @@ namespace ARMeilleure.Translation
|
||||
var retType = OperandType.None;
|
||||
var argTypes = new[] { OperandType.I64, OperandType.I64 };
|
||||
|
||||
return Compiler.Compile(cfg, argTypes, retType, CompilerOptions.HighCq).Map<DispatcherFunction>();
|
||||
return Compiler.Compile(cfg, argTypes, retType, CompilerOptions.HighCq, RuntimeInformation.ProcessArchitecture).Map<DispatcherFunction>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -19,24 +19,24 @@
|
||||
<PackageVersion Include="GtkSharp.Dependencies" Version="1.1.1" />
|
||||
<PackageVersion Include="GtkSharp.Dependencies.osx" Version="0.0.5" />
|
||||
<PackageVersion Include="jp2masa.Avalonia.Flexbox" Version="0.2.0" />
|
||||
<PackageVersion Include="LibHac" Version="0.17.0" />
|
||||
<PackageVersion Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.3" />
|
||||
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="4.4.0" />
|
||||
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.4.1" />
|
||||
<PackageVersion Include="LibHac" Version="0.18.0" />
|
||||
<PackageVersion Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.4" />
|
||||
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="4.5.0" />
|
||||
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.5.0" />
|
||||
<PackageVersion Include="MsgPack.Cli" Version="1.0.1" />
|
||||
<PackageVersion Include="NUnit" Version="3.13.3" />
|
||||
<PackageVersion Include="NUnit3TestAdapter" Version="3.17.0" />
|
||||
<PackageVersion Include="OpenTK.Core" Version="4.7.5" />
|
||||
<PackageVersion Include="OpenTK.Graphics" Version="4.7.5" />
|
||||
<PackageVersion Include="OpenTK.OpenAL" Version="4.7.5" />
|
||||
<PackageVersion Include="OpenTK.Windowing.GraphicsLibraryFramework" Version="4.7.5" />
|
||||
<PackageVersion Include="NUnit3TestAdapter" Version="4.1.0" />
|
||||
<PackageVersion Include="OpenTK.Core" Version="4.7.7" />
|
||||
<PackageVersion Include="OpenTK.Graphics" Version="4.7.7" />
|
||||
<PackageVersion Include="OpenTK.OpenAL" Version="4.7.7" />
|
||||
<PackageVersion Include="OpenTK.Windowing.GraphicsLibraryFramework" Version="4.7.7" />
|
||||
<PackageVersion Include="Ryujinx.Audio.OpenAL.Dependencies" Version="1.21.0.1" />
|
||||
<PackageVersion Include="Ryujinx.Graphics.Nvdec.Dependencies" Version="5.0.1-build13" />
|
||||
<PackageVersion Include="Ryujinx.Graphics.Vulkan.Dependencies.MoltenVK" Version="1.2.0" />
|
||||
<PackageVersion Include="Ryujinx.GtkSharp" Version="3.24.24.59-ryujinx" />
|
||||
<PackageVersion Include="Ryujinx.SDL2-CS" Version="2.24.2-build21" />
|
||||
<PackageVersion Include="Ryujinx.SDL2-CS" Version="2.26.1-build23" />
|
||||
<PackageVersion Include="shaderc.net" Version="0.1.0" />
|
||||
<PackageVersion Include="SharpZipLib" Version="1.4.1" />
|
||||
<PackageVersion Include="SharpZipLib" Version="1.4.2" />
|
||||
<PackageVersion Include="Silk.NET.Vulkan" Version="2.16.0" />
|
||||
<PackageVersion Include="Silk.NET.Vulkan.Extensions.EXT" Version="2.16.0" />
|
||||
<PackageVersion Include="Silk.NET.Vulkan.Extensions.KHR" Version="2.16.0" />
|
||||
@ -44,11 +44,12 @@
|
||||
<PackageVersion Include="SixLabors.ImageSharp.Drawing" Version="1.0.0-beta11" />
|
||||
<PackageVersion Include="SPB" Version="0.0.4-build28" />
|
||||
<PackageVersion Include="System.Drawing.Common" Version="7.0.0" />
|
||||
<PackageVersion Include="System.IdentityModel.Tokens.Jwt" Version="6.25.1" />
|
||||
<PackageVersion Include="System.IdentityModel.Tokens.Jwt" Version="6.27.0" />
|
||||
<PackageVersion Include="System.IO.FileSystem.Primitives" Version="4.3.0" />
|
||||
<PackageVersion Include="System.Management" Version="7.0.0" />
|
||||
<PackageVersion Include="System.Net.NameResolution" Version="4.3.0" />
|
||||
<PackageVersion Include="System.Threading.ThreadPool" Version="4.3.0" />
|
||||
<PackageVersion Include="UnicornEngine.Unicorn" Version="2.0.2-rc1-f7c841d" />
|
||||
<PackageVersion Include="XamlNameReferenceGenerator" Version="1.5.1" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
@ -96,7 +96,7 @@ Ryujinx system files are stored in the `Ryujinx` folder. This folder is located
|
||||
|
||||
- **GPU**
|
||||
|
||||
The GPU emulator emulates the Switch's Maxwell GPU using either the OpenGL (version 4.5 minimum), Vulkan, or Metal (via MoltenVK) APIs through a custom build of OpenTK or Silk.NET respectively. There are currently four graphics enhancements available to the end user in Ryujinx: Disk Shader Caching, Resolution Scaling, Aspect Ratio Adjustment, and Anisotropic Filtering. These enhancements can be adjusted or toggled as desired in the GUI.
|
||||
The GPU emulator emulates the Switch's Maxwell GPU using either the OpenGL (version 4.5 minimum), Vulkan, or Metal (via MoltenVK) APIs through a custom build of OpenTK or Silk.NET respectively. There are currently six graphics enhancements available to the end user in Ryujinx: Disk Shader Caching, Resolution Scaling, Anti-Aliasing, Scaling Filters (including FSR), Anisotropic Filtering and Aspect Ratio Adjustment. These enhancements can be adjusted or toggled as desired in the GUI.
|
||||
|
||||
- **Input**
|
||||
|
||||
|
@ -5,9 +5,8 @@ using Ryujinx.Memory;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Threading;
|
||||
|
||||
using static Ryujinx.Audio.Integration.IHardwareDeviceDriver;
|
||||
using static Ryujinx.Audio.Backends.SoundIo.Native.SoundIo;
|
||||
using static Ryujinx.Audio.Integration.IHardwareDeviceDriver;
|
||||
|
||||
namespace Ryujinx.Audio.Backends.SoundIo
|
||||
{
|
||||
|
@ -15,6 +15,8 @@ namespace Ryujinx.Audio.Backends.CompatLayer
|
||||
{
|
||||
private IHardwareDeviceDriver _realDriver;
|
||||
|
||||
public static bool IsSupported => true;
|
||||
|
||||
public CompatLayerHardwareDeviceDriver(IHardwareDeviceDriver realDevice)
|
||||
{
|
||||
_realDriver = realDevice;
|
||||
@ -73,9 +75,12 @@ namespace Ryujinx.Audio.Backends.CompatLayer
|
||||
return SampleFormat.PcmFloat;
|
||||
}
|
||||
|
||||
// TODO: Implement PCM24 conversion.
|
||||
if (_realDriver.SupportsSampleFormat(SampleFormat.PcmInt24))
|
||||
{
|
||||
return SampleFormat.PcmInt24;
|
||||
}
|
||||
|
||||
// If nothing is truly supported, attempt PCM8 at the cost of loosing quality.
|
||||
// If nothing is truly supported, attempt PCM8 at the cost of losing quality.
|
||||
if (_realDriver.SupportsSampleFormat(SampleFormat.PcmInt8))
|
||||
{
|
||||
return SampleFormat.PcmInt8;
|
||||
|
@ -58,10 +58,13 @@ namespace Ryujinx.Audio.Backends.CompatLayer
|
||||
switch (realSampleFormat)
|
||||
{
|
||||
case SampleFormat.PcmInt8:
|
||||
PcmHelper.Convert(MemoryMarshal.Cast<byte, sbyte>(convertedSamples), samples);
|
||||
PcmHelper.ConvertSampleToPcm8(MemoryMarshal.Cast<byte, sbyte>(convertedSamples), samples);
|
||||
break;
|
||||
case SampleFormat.PcmInt24:
|
||||
PcmHelper.ConvertSampleToPcm24(convertedSamples, samples);
|
||||
break;
|
||||
case SampleFormat.PcmInt32:
|
||||
PcmHelper.Convert(MemoryMarshal.Cast<byte, int>(convertedSamples), samples);
|
||||
PcmHelper.ConvertSampleToPcm32(MemoryMarshal.Cast<byte, int>(convertedSamples), samples);
|
||||
break;
|
||||
case SampleFormat.PcmFloat:
|
||||
PcmHelper.ConvertSampleToPcmFloat(MemoryMarshal.Cast<byte, float>(convertedSamples), samples);
|
||||
|
@ -12,6 +12,8 @@ namespace Ryujinx.Audio.Backends.Dummy
|
||||
private ManualResetEvent _updateRequiredEvent;
|
||||
private ManualResetEvent _pauseEvent;
|
||||
|
||||
public static bool IsSupported => true;
|
||||
|
||||
public DummyHardwareDeviceDriver()
|
||||
{
|
||||
_updateRequiredEvent = new ManualResetEvent(false);
|
||||
|
@ -26,6 +26,8 @@ namespace Ryujinx.Audio.Integration
|
||||
bool SupportsSampleFormat(SampleFormat sampleFormat);
|
||||
bool SupportsChannelCount(uint channelCount);
|
||||
|
||||
static abstract bool IsSupported { get; }
|
||||
|
||||
IHardwareDeviceDriver GetRealDeviceDriver()
|
||||
{
|
||||
return this;
|
||||
|
@ -1,8 +1,8 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using Ryujinx.Audio.Renderer.Dsp.Effect;
|
||||
using Ryujinx.Audio.Renderer.Dsp.Effect;
|
||||
using Ryujinx.Audio.Renderer.Dsp.State;
|
||||
using Ryujinx.Audio.Renderer.Parameter.Effect;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||
{
|
||||
|
@ -40,6 +40,12 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||
info.InputBufferIndices[i] = (ushort)(bufferOffset + inputBufferOffset[i]);
|
||||
}
|
||||
|
||||
if (info.BufferStates?.Length != (int)inputCount)
|
||||
{
|
||||
// Keep state if possible.
|
||||
info.BufferStates = new UpsamplerBufferState[(int)inputCount];
|
||||
}
|
||||
|
||||
UpsamplerInfo = info;
|
||||
}
|
||||
|
||||
@ -50,8 +56,6 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||
|
||||
public void Process(CommandList context)
|
||||
{
|
||||
float ratio = (float)InputSampleRate / Constants.TargetSampleRate;
|
||||
|
||||
uint bufferCount = Math.Min(BufferCount, UpsamplerInfo.SourceSampleCount);
|
||||
|
||||
for (int i = 0; i < bufferCount; i++)
|
||||
@ -59,9 +63,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||
Span<float> inputBuffer = context.GetBuffer(UpsamplerInfo.InputBufferIndices[i]);
|
||||
Span<float> outputBuffer = GetBuffer(UpsamplerInfo.InputBufferIndices[i], (int)UpsamplerInfo.SampleCount);
|
||||
|
||||
float fraction = 0.0f;
|
||||
|
||||
ResamplerHelper.ResampleForUpsampler(outputBuffer, inputBuffer, ratio, ref fraction, (int)(InputSampleCount / ratio));
|
||||
UpsamplerHelper.Upsample(outputBuffer, inputBuffer, (int)UpsamplerInfo.SampleCount, (int)InputSampleCount, ref UpsamplerInfo.BufferStates[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -37,19 +37,32 @@ namespace Ryujinx.Audio.Renderer.Dsp
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static TOutput ConvertSample<TInput, TOutput>(TInput value) where TInput: INumber<TInput>, IMinMaxValue<TInput> where TOutput : INumber<TOutput>, IMinMaxValue<TOutput>
|
||||
{
|
||||
TInput conversionRate = TInput.CreateSaturating(TOutput.MaxValue / TOutput.CreateSaturating(TInput.MaxValue));
|
||||
|
||||
return TOutput.CreateSaturating(value * conversionRate);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void Convert<TInput, TOutput>(Span<TOutput> output, ReadOnlySpan<TInput> input) where TInput : INumber<TInput>, IMinMaxValue<TInput> where TOutput : INumber<TOutput>, IMinMaxValue<TOutput>
|
||||
public static void ConvertSampleToPcm8(Span<sbyte> output, ReadOnlySpan<short> input)
|
||||
{
|
||||
for (int i = 0; i < input.Length; i++)
|
||||
{
|
||||
output[i] = ConvertSample<TInput, TOutput>(input[i]);
|
||||
// Output most significant byte
|
||||
output[i] = (sbyte)(input[i] >> 8);
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void ConvertSampleToPcm24(Span<byte> output, ReadOnlySpan<short> input)
|
||||
{
|
||||
for (int i = 0; i < input.Length; i++)
|
||||
{
|
||||
output[i * 3 + 2] = (byte)(input[i] >> 8);
|
||||
output[i * 3 + 1] = (byte)(input[i] & 0xff);
|
||||
output[i * 3 + 0] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void ConvertSampleToPcm32(Span<int> output, ReadOnlySpan<short> input)
|
||||
{
|
||||
for (int i = 0; i < input.Length; i++)
|
||||
{
|
||||
output[i] = ((int)input[i]) << 16;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.Intrinsics;
|
||||
using System.Runtime.Intrinsics.X86;
|
||||
@ -380,7 +381,6 @@ namespace Ryujinx.Audio.Renderer.Dsp
|
||||
return _normalCurveLut2F;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private unsafe static void ResampleDefaultQuality(Span<float> outputBuffer, ReadOnlySpan<short> inputBuffer, float ratio, ref float fraction, int sampleCount, bool needPitch)
|
||||
{
|
||||
ReadOnlySpan<float> parameters = GetDefaultParameter(ratio);
|
||||
@ -394,35 +394,33 @@ namespace Ryujinx.Audio.Renderer.Dsp
|
||||
if (ratio == 1f)
|
||||
{
|
||||
fixed (short* pInput = inputBuffer)
|
||||
fixed (float* pOutput = outputBuffer, pParameters = parameters)
|
||||
{
|
||||
fixed (float* pOutput = outputBuffer, pParameters = parameters)
|
||||
Vector128<float> parameter = Sse.LoadVector128(pParameters);
|
||||
|
||||
for (; i < (sampleCount & ~3); i += 4)
|
||||
{
|
||||
Vector128<float> parameter = Sse.LoadVector128(pParameters);
|
||||
Vector128<int> intInput0 = Sse41.ConvertToVector128Int32(pInput + (uint)i);
|
||||
Vector128<int> intInput1 = Sse41.ConvertToVector128Int32(pInput + (uint)i + 1);
|
||||
Vector128<int> intInput2 = Sse41.ConvertToVector128Int32(pInput + (uint)i + 2);
|
||||
Vector128<int> intInput3 = Sse41.ConvertToVector128Int32(pInput + (uint)i + 3);
|
||||
|
||||
for (; i < (sampleCount & ~3); i += 4)
|
||||
{
|
||||
Vector128<int> intInput0 = Sse41.ConvertToVector128Int32(pInput + (uint)i);
|
||||
Vector128<int> intInput1 = Sse41.ConvertToVector128Int32(pInput + (uint)i + 1);
|
||||
Vector128<int> intInput2 = Sse41.ConvertToVector128Int32(pInput + (uint)i + 2);
|
||||
Vector128<int> intInput3 = Sse41.ConvertToVector128Int32(pInput + (uint)i + 3);
|
||||
Vector128<float> input0 = Sse2.ConvertToVector128Single(intInput0);
|
||||
Vector128<float> input1 = Sse2.ConvertToVector128Single(intInput1);
|
||||
Vector128<float> input2 = Sse2.ConvertToVector128Single(intInput2);
|
||||
Vector128<float> input3 = Sse2.ConvertToVector128Single(intInput3);
|
||||
|
||||
Vector128<float> input0 = Sse2.ConvertToVector128Single(intInput0);
|
||||
Vector128<float> input1 = Sse2.ConvertToVector128Single(intInput1);
|
||||
Vector128<float> input2 = Sse2.ConvertToVector128Single(intInput2);
|
||||
Vector128<float> input3 = Sse2.ConvertToVector128Single(intInput3);
|
||||
Vector128<float> mix0 = Sse.Multiply(input0, parameter);
|
||||
Vector128<float> mix1 = Sse.Multiply(input1, parameter);
|
||||
Vector128<float> mix2 = Sse.Multiply(input2, parameter);
|
||||
Vector128<float> mix3 = Sse.Multiply(input3, parameter);
|
||||
|
||||
Vector128<float> mix0 = Sse.Multiply(input0, parameter);
|
||||
Vector128<float> mix1 = Sse.Multiply(input1, parameter);
|
||||
Vector128<float> mix2 = Sse.Multiply(input2, parameter);
|
||||
Vector128<float> mix3 = Sse.Multiply(input3, parameter);
|
||||
Vector128<float> mix01 = Sse3.HorizontalAdd(mix0, mix1);
|
||||
Vector128<float> mix23 = Sse3.HorizontalAdd(mix2, mix3);
|
||||
|
||||
Vector128<float> mix01 = Sse3.HorizontalAdd(mix0, mix1);
|
||||
Vector128<float> mix23 = Sse3.HorizontalAdd(mix2, mix3);
|
||||
Vector128<float> mix0123 = Sse3.HorizontalAdd(mix01, mix23);
|
||||
|
||||
Vector128<float> mix0123 = Sse3.HorizontalAdd(mix01, mix23);
|
||||
|
||||
Sse.Store(pOutput + (uint)i, Sse41.RoundToNearestInteger(mix0123));
|
||||
}
|
||||
Sse.Store(pOutput + (uint)i, Sse41.RoundToNearestInteger(mix0123));
|
||||
}
|
||||
}
|
||||
|
||||
@ -431,62 +429,60 @@ namespace Ryujinx.Audio.Renderer.Dsp
|
||||
else
|
||||
{
|
||||
fixed (short* pInput = inputBuffer)
|
||||
fixed (float* pOutput = outputBuffer, pParameters = parameters)
|
||||
{
|
||||
fixed (float* pOutput = outputBuffer, pParameters = parameters)
|
||||
for (; i < (sampleCount & ~3); i += 4)
|
||||
{
|
||||
for (; i < (sampleCount & ~3); i += 4)
|
||||
{
|
||||
uint baseIndex0 = (uint)(fraction * 128) * 4;
|
||||
uint inputIndex0 = (uint)inputBufferIndex;
|
||||
uint baseIndex0 = (uint)(fraction * 128) * 4;
|
||||
uint inputIndex0 = (uint)inputBufferIndex;
|
||||
|
||||
fraction += ratio;
|
||||
fraction += ratio;
|
||||
|
||||
uint baseIndex1 = ((uint)(fraction * 128) & 127) * 4;
|
||||
uint inputIndex1 = (uint)inputBufferIndex + (uint)fraction;
|
||||
uint baseIndex1 = ((uint)(fraction * 128) & 127) * 4;
|
||||
uint inputIndex1 = (uint)inputBufferIndex + (uint)fraction;
|
||||
|
||||
fraction += ratio;
|
||||
fraction += ratio;
|
||||
|
||||
uint baseIndex2 = ((uint)(fraction * 128) & 127) * 4;
|
||||
uint inputIndex2 = (uint)inputBufferIndex + (uint)fraction;
|
||||
uint baseIndex2 = ((uint)(fraction * 128) & 127) * 4;
|
||||
uint inputIndex2 = (uint)inputBufferIndex + (uint)fraction;
|
||||
|
||||
fraction += ratio;
|
||||
fraction += ratio;
|
||||
|
||||
uint baseIndex3 = ((uint)(fraction * 128) & 127) * 4;
|
||||
uint inputIndex3 = (uint)inputBufferIndex + (uint)fraction;
|
||||
uint baseIndex3 = ((uint)(fraction * 128) & 127) * 4;
|
||||
uint inputIndex3 = (uint)inputBufferIndex + (uint)fraction;
|
||||
|
||||
fraction += ratio;
|
||||
inputBufferIndex += (int)fraction;
|
||||
fraction += ratio;
|
||||
inputBufferIndex += (int)fraction;
|
||||
|
||||
// Only keep lower part (safe as fraction isn't supposed to be negative)
|
||||
fraction -= (int)fraction;
|
||||
// Only keep lower part (safe as fraction isn't supposed to be negative)
|
||||
fraction -= (int)fraction;
|
||||
|
||||
Vector128<float> parameter0 = Sse.LoadVector128(pParameters + baseIndex0);
|
||||
Vector128<float> parameter1 = Sse.LoadVector128(pParameters + baseIndex1);
|
||||
Vector128<float> parameter2 = Sse.LoadVector128(pParameters + baseIndex2);
|
||||
Vector128<float> parameter3 = Sse.LoadVector128(pParameters + baseIndex3);
|
||||
Vector128<float> parameter0 = Sse.LoadVector128(pParameters + baseIndex0);
|
||||
Vector128<float> parameter1 = Sse.LoadVector128(pParameters + baseIndex1);
|
||||
Vector128<float> parameter2 = Sse.LoadVector128(pParameters + baseIndex2);
|
||||
Vector128<float> parameter3 = Sse.LoadVector128(pParameters + baseIndex3);
|
||||
|
||||
Vector128<int> intInput0 = Sse41.ConvertToVector128Int32(pInput + inputIndex0);
|
||||
Vector128<int> intInput1 = Sse41.ConvertToVector128Int32(pInput + inputIndex1);
|
||||
Vector128<int> intInput2 = Sse41.ConvertToVector128Int32(pInput + inputIndex2);
|
||||
Vector128<int> intInput3 = Sse41.ConvertToVector128Int32(pInput + inputIndex3);
|
||||
Vector128<int> intInput0 = Sse41.ConvertToVector128Int32(pInput + inputIndex0);
|
||||
Vector128<int> intInput1 = Sse41.ConvertToVector128Int32(pInput + inputIndex1);
|
||||
Vector128<int> intInput2 = Sse41.ConvertToVector128Int32(pInput + inputIndex2);
|
||||
Vector128<int> intInput3 = Sse41.ConvertToVector128Int32(pInput + inputIndex3);
|
||||
|
||||
Vector128<float> input0 = Sse2.ConvertToVector128Single(intInput0);
|
||||
Vector128<float> input1 = Sse2.ConvertToVector128Single(intInput1);
|
||||
Vector128<float> input2 = Sse2.ConvertToVector128Single(intInput2);
|
||||
Vector128<float> input3 = Sse2.ConvertToVector128Single(intInput3);
|
||||
Vector128<float> input0 = Sse2.ConvertToVector128Single(intInput0);
|
||||
Vector128<float> input1 = Sse2.ConvertToVector128Single(intInput1);
|
||||
Vector128<float> input2 = Sse2.ConvertToVector128Single(intInput2);
|
||||
Vector128<float> input3 = Sse2.ConvertToVector128Single(intInput3);
|
||||
|
||||
Vector128<float> mix0 = Sse.Multiply(input0, parameter0);
|
||||
Vector128<float> mix1 = Sse.Multiply(input1, parameter1);
|
||||
Vector128<float> mix2 = Sse.Multiply(input2, parameter2);
|
||||
Vector128<float> mix3 = Sse.Multiply(input3, parameter3);
|
||||
Vector128<float> mix0 = Sse.Multiply(input0, parameter0);
|
||||
Vector128<float> mix1 = Sse.Multiply(input1, parameter1);
|
||||
Vector128<float> mix2 = Sse.Multiply(input2, parameter2);
|
||||
Vector128<float> mix3 = Sse.Multiply(input3, parameter3);
|
||||
|
||||
Vector128<float> mix01 = Sse3.HorizontalAdd(mix0, mix1);
|
||||
Vector128<float> mix23 = Sse3.HorizontalAdd(mix2, mix3);
|
||||
Vector128<float> mix01 = Sse3.HorizontalAdd(mix0, mix1);
|
||||
Vector128<float> mix23 = Sse3.HorizontalAdd(mix2, mix3);
|
||||
|
||||
Vector128<float> mix0123 = Sse3.HorizontalAdd(mix01, mix23);
|
||||
Vector128<float> mix0123 = Sse3.HorizontalAdd(mix01, mix23);
|
||||
|
||||
Sse.Store(pOutput + (uint)i, Sse41.RoundToNearestInteger(mix0123));
|
||||
}
|
||||
Sse.Store(pOutput + (uint)i, Sse41.RoundToNearestInteger(mix0123));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -526,34 +522,59 @@ namespace Ryujinx.Audio.Renderer.Dsp
|
||||
return _highCurveLut2F;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static void ResampleHighQuality(Span<float> outputBuffer, ReadOnlySpan<short> inputBuffer, float ratio, ref float fraction, int sampleCount)
|
||||
private static unsafe void ResampleHighQuality(Span<float> outputBuffer, ReadOnlySpan<short> inputBuffer, float ratio, ref float fraction, int sampleCount)
|
||||
{
|
||||
ReadOnlySpan<float> parameters = GetHighParameter(ratio);
|
||||
|
||||
int inputBufferIndex = 0;
|
||||
|
||||
// TODO: fast path
|
||||
|
||||
for (int i = 0; i < sampleCount; i++)
|
||||
if (Avx2.IsSupported)
|
||||
{
|
||||
int baseIndex = (int)(fraction * 128) * 8;
|
||||
ReadOnlySpan<float> parameter = parameters.Slice(baseIndex, 8);
|
||||
ReadOnlySpan<short> currentInput = inputBuffer.Slice(inputBufferIndex, 8);
|
||||
// Fast path; assumes 256-bit vectors for simplicity because the filter is 8 taps
|
||||
fixed (short* pInput = inputBuffer)
|
||||
fixed (float* pParameters = parameters)
|
||||
{
|
||||
for (int i = 0; i < sampleCount; i++)
|
||||
{
|
||||
int baseIndex = (int)(fraction * 128) * 8;
|
||||
|
||||
outputBuffer[i] = (float)Math.Round(currentInput[0] * parameter[0] +
|
||||
currentInput[1] * parameter[1] +
|
||||
currentInput[2] * parameter[2] +
|
||||
currentInput[3] * parameter[3] +
|
||||
currentInput[4] * parameter[4] +
|
||||
currentInput[5] * parameter[5] +
|
||||
currentInput[6] * parameter[6] +
|
||||
currentInput[7] * parameter[7]);
|
||||
Vector256<int> intInput = Avx2.ConvertToVector256Int32(pInput + inputBufferIndex);
|
||||
Vector256<float> floatInput = Avx.ConvertToVector256Single(intInput);
|
||||
Vector256<float> parameter = Avx.LoadVector256(pParameters + baseIndex);
|
||||
Vector256<float> dp = Avx.DotProduct(floatInput, parameter, control: 0xFF);
|
||||
|
||||
fraction += ratio;
|
||||
inputBufferIndex += (int)MathF.Truncate(fraction);
|
||||
// avx2 does an 8-element dot product piecewise so we have to sum up 2 intermediate results
|
||||
outputBuffer[i] = (float)Math.Round(dp[0] + dp[4]);
|
||||
|
||||
fraction -= (int)fraction;
|
||||
fraction += ratio;
|
||||
inputBufferIndex += (int)MathF.Truncate(fraction);
|
||||
|
||||
fraction -= (int)fraction;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < sampleCount; i++)
|
||||
{
|
||||
int baseIndex = (int)(fraction * 128) * 8;
|
||||
ReadOnlySpan<float> parameter = parameters.Slice(baseIndex, 8);
|
||||
ReadOnlySpan<short> currentInput = inputBuffer.Slice(inputBufferIndex, 8);
|
||||
|
||||
outputBuffer[i] = (float)Math.Round(currentInput[0] * parameter[0] +
|
||||
currentInput[1] * parameter[1] +
|
||||
currentInput[2] * parameter[2] +
|
||||
currentInput[3] * parameter[3] +
|
||||
currentInput[4] * parameter[4] +
|
||||
currentInput[5] * parameter[5] +
|
||||
currentInput[6] * parameter[6] +
|
||||
currentInput[7] * parameter[7]);
|
||||
|
||||
fraction += ratio;
|
||||
inputBufferIndex += (int)MathF.Truncate(fraction);
|
||||
|
||||
fraction -= (int)fraction;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -579,52 +600,5 @@ namespace Ryujinx.Audio.Renderer.Dsp
|
||||
fraction -= (int)fraction;
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void ResampleForUpsampler(Span<float> outputBuffer, ReadOnlySpan<float> inputBuffer, float ratio, ref float fraction, int sampleCount)
|
||||
{
|
||||
// Currently a simple cubic interpolation, assuming duplicated values at edges.
|
||||
// TODO: Discover and use algorithm that the switch uses.
|
||||
|
||||
int inputBufferIndex = 0;
|
||||
int maxIndex = inputBuffer.Length - 1;
|
||||
int cubicEnd = inputBuffer.Length - 3;
|
||||
|
||||
for (int i = 0; i < sampleCount; i++)
|
||||
{
|
||||
float s0, s1, s2, s3;
|
||||
|
||||
s1 = inputBuffer[inputBufferIndex];
|
||||
|
||||
if (inputBufferIndex == 0 || inputBufferIndex > cubicEnd)
|
||||
{
|
||||
// Clamp interplation values at the ends of the input buffer.
|
||||
s0 = inputBuffer[Math.Max(0, inputBufferIndex - 1)];
|
||||
s2 = inputBuffer[Math.Min(maxIndex, inputBufferIndex + 1)];
|
||||
s3 = inputBuffer[Math.Min(maxIndex, inputBufferIndex + 2)];
|
||||
}
|
||||
else
|
||||
{
|
||||
s0 = inputBuffer[inputBufferIndex - 1];
|
||||
s2 = inputBuffer[inputBufferIndex + 1];
|
||||
s3 = inputBuffer[inputBufferIndex + 2];
|
||||
}
|
||||
|
||||
float a = s3 - s2 - s0 + s1;
|
||||
float b = s0 - s1 - a;
|
||||
float c = s2 - s0;
|
||||
float d = s1;
|
||||
|
||||
float f2 = fraction * fraction;
|
||||
float f3 = f2 * fraction;
|
||||
|
||||
outputBuffer[i] = a * f3 + b * f2 + c * fraction + d;
|
||||
|
||||
fraction += ratio;
|
||||
inputBufferIndex += (int)MathF.Truncate(fraction);
|
||||
|
||||
fraction -= (int)fraction;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
192
Ryujinx.Audio/Renderer/Dsp/UpsamplerHelper.cs
Normal file
192
Ryujinx.Audio/Renderer/Dsp/UpsamplerHelper.cs
Normal file
@ -0,0 +1,192 @@
|
||||
using Ryujinx.Audio.Renderer.Server.Upsampler;
|
||||
using Ryujinx.Common.Memory;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Numerics;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Ryujinx.Audio.Renderer.Dsp
|
||||
{
|
||||
public class UpsamplerHelper
|
||||
{
|
||||
private const int HistoryLength = UpsamplerBufferState.HistoryLength;
|
||||
private const int FilterBankLength = 20;
|
||||
// Bank0 = [0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
|
||||
private const int Bank0CenterIndex = 9;
|
||||
private static readonly Array20<float> Bank1 = PrecomputeFilterBank(1.0f / 6.0f);
|
||||
private static readonly Array20<float> Bank2 = PrecomputeFilterBank(2.0f / 6.0f);
|
||||
private static readonly Array20<float> Bank3 = PrecomputeFilterBank(3.0f / 6.0f);
|
||||
private static readonly Array20<float> Bank4 = PrecomputeFilterBank(4.0f / 6.0f);
|
||||
private static readonly Array20<float> Bank5 = PrecomputeFilterBank(5.0f / 6.0f);
|
||||
|
||||
private static Array20<float> PrecomputeFilterBank(float offset)
|
||||
{
|
||||
float Sinc(float x)
|
||||
{
|
||||
if (x == 0)
|
||||
{
|
||||
return 1.0f;
|
||||
}
|
||||
return (MathF.Sin(MathF.PI * x) / (MathF.PI * x));
|
||||
}
|
||||
|
||||
float BlackmanWindow(float x)
|
||||
{
|
||||
const float a = 0.18f;
|
||||
const float a0 = 0.5f - 0.5f * a;
|
||||
const float a1 = -0.5f;
|
||||
const float a2 = 0.5f * a;
|
||||
return a0 + a1 * MathF.Cos(2 * MathF.PI * x) + a2 * MathF.Cos(4 * MathF.PI * x);
|
||||
}
|
||||
|
||||
Array20<float> result = new Array20<float>();
|
||||
|
||||
for (int i = 0; i < FilterBankLength; i++)
|
||||
{
|
||||
float x = (Bank0CenterIndex - i) + offset;
|
||||
result[i] = Sinc(x) * BlackmanWindow(x / FilterBankLength + 0.5f);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Polyphase upsampling algorithm
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void Upsample(Span<float> outputBuffer, ReadOnlySpan<float> inputBuffer, int outputSampleCount, int inputSampleCount, ref UpsamplerBufferState state)
|
||||
{
|
||||
if (!state.Initialized)
|
||||
{
|
||||
state.Scale = inputSampleCount switch
|
||||
{
|
||||
40 => 6.0f,
|
||||
80 => 3.0f,
|
||||
160 => 1.5f,
|
||||
_ => throw new ArgumentOutOfRangeException()
|
||||
};
|
||||
state.Initialized = true;
|
||||
}
|
||||
|
||||
if (outputSampleCount == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
float DoFilterBank(ref UpsamplerBufferState state, in Array20<float> bank)
|
||||
{
|
||||
float result = 0.0f;
|
||||
|
||||
Debug.Assert(state.History.Length == HistoryLength);
|
||||
Debug.Assert(bank.Length == FilterBankLength);
|
||||
|
||||
int curIdx = 0;
|
||||
if (Vector.IsHardwareAccelerated)
|
||||
{
|
||||
// Do SIMD-accelerated block operations where possible.
|
||||
// Only about a 2x speedup since filter bank length is short
|
||||
int stopIdx = FilterBankLength - (FilterBankLength % Vector<float>.Count);
|
||||
while (curIdx < stopIdx)
|
||||
{
|
||||
result += Vector.Dot(
|
||||
new Vector<float>(bank.AsSpan().Slice(curIdx, Vector<float>.Count)),
|
||||
new Vector<float>(state.History.AsSpan().Slice(curIdx, Vector<float>.Count)));
|
||||
curIdx += Vector<float>.Count;
|
||||
}
|
||||
}
|
||||
|
||||
while (curIdx < FilterBankLength)
|
||||
{
|
||||
result += bank[curIdx] * state.History[curIdx];
|
||||
curIdx++;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
void NextInput(ref UpsamplerBufferState state, float input)
|
||||
{
|
||||
state.History.AsSpan().Slice(1).CopyTo(state.History.AsSpan());
|
||||
state.History[HistoryLength - 1] = input;
|
||||
}
|
||||
|
||||
int inputBufferIndex = 0;
|
||||
|
||||
switch (state.Scale)
|
||||
{
|
||||
case 6.0f:
|
||||
for (int i = 0; i < outputSampleCount; i++)
|
||||
{
|
||||
switch (state.Phase)
|
||||
{
|
||||
case 0:
|
||||
NextInput(ref state, inputBuffer[inputBufferIndex++]);
|
||||
outputBuffer[i] = state.History[Bank0CenterIndex];
|
||||
break;
|
||||
case 1:
|
||||
outputBuffer[i] = DoFilterBank(ref state, Bank1);
|
||||
break;
|
||||
case 2:
|
||||
outputBuffer[i] = DoFilterBank(ref state, Bank2);
|
||||
break;
|
||||
case 3:
|
||||
outputBuffer[i] = DoFilterBank(ref state, Bank3);
|
||||
break;
|
||||
case 4:
|
||||
outputBuffer[i] = DoFilterBank(ref state, Bank4);
|
||||
break;
|
||||
case 5:
|
||||
outputBuffer[i] = DoFilterBank(ref state, Bank5);
|
||||
break;
|
||||
}
|
||||
|
||||
state.Phase = (state.Phase + 1) % 6;
|
||||
}
|
||||
break;
|
||||
case 3.0f:
|
||||
for (int i = 0; i < outputSampleCount; i++)
|
||||
{
|
||||
switch (state.Phase)
|
||||
{
|
||||
case 0:
|
||||
NextInput(ref state, inputBuffer[inputBufferIndex++]);
|
||||
outputBuffer[i] = state.History[Bank0CenterIndex];
|
||||
break;
|
||||
case 1:
|
||||
outputBuffer[i] = DoFilterBank(ref state, Bank2);
|
||||
break;
|
||||
case 2:
|
||||
outputBuffer[i] = DoFilterBank(ref state, Bank4);
|
||||
break;
|
||||
}
|
||||
|
||||
state.Phase = (state.Phase + 1) % 3;
|
||||
}
|
||||
break;
|
||||
case 1.5f:
|
||||
// Upsample by 3 then decimate by 2.
|
||||
for (int i = 0; i < outputSampleCount; i++)
|
||||
{
|
||||
switch (state.Phase)
|
||||
{
|
||||
case 0:
|
||||
NextInput(ref state, inputBuffer[inputBufferIndex++]);
|
||||
outputBuffer[i] = state.History[Bank0CenterIndex];
|
||||
break;
|
||||
case 1:
|
||||
outputBuffer[i] = DoFilterBank(ref state, Bank4);
|
||||
break;
|
||||
case 2:
|
||||
NextInput(ref state, inputBuffer[inputBufferIndex++]);
|
||||
outputBuffer[i] = DoFilterBank(ref state, Bank2);
|
||||
break;
|
||||
}
|
||||
|
||||
state.Phase = (state.Phase + 1) % 3;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
using Ryujinx.Audio.Renderer.Common;
|
||||
using Ryujinx.Audio.Renderer.Dsp.State;
|
||||
using Ryujinx.Audio.Renderer.Parameter.Effect;
|
||||
using Ryujinx.Audio.Renderer.Parameter;
|
||||
using Ryujinx.Audio.Renderer.Parameter.Effect;
|
||||
using Ryujinx.Audio.Renderer.Server.MemoryPool;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
|
@ -0,0 +1,14 @@
|
||||
using Ryujinx.Common.Memory;
|
||||
|
||||
namespace Ryujinx.Audio.Renderer.Server.Upsampler
|
||||
{
|
||||
public struct UpsamplerBufferState
|
||||
{
|
||||
public const int HistoryLength = 20;
|
||||
|
||||
public float Scale;
|
||||
public Array20<float> History;
|
||||
public bool Initialized;
|
||||
public int Phase;
|
||||
}
|
||||
}
|
@ -37,6 +37,11 @@ namespace Ryujinx.Audio.Renderer.Server.Upsampler
|
||||
/// </summary>
|
||||
public ushort[] InputBufferIndices;
|
||||
|
||||
/// <summary>
|
||||
/// State of each input buffer index kept across invocations of the upsampler.
|
||||
/// </summary>
|
||||
public UpsamplerBufferState[] BufferStates;
|
||||
|
||||
/// <summary>
|
||||
/// Create a new <see cref="UpsamplerState"/>.
|
||||
/// </summary>
|
||||
|
@ -59,11 +59,11 @@ namespace Ryujinx.Ava
|
||||
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
|
||||
{
|
||||
var result = await ContentDialogHelper.CreateConfirmationDialog(
|
||||
LocaleManager.Instance["DialogThemeRestartMessage"],
|
||||
LocaleManager.Instance["DialogThemeRestartSubMessage"],
|
||||
LocaleManager.Instance["InputDialogYes"],
|
||||
LocaleManager.Instance["InputDialogNo"],
|
||||
LocaleManager.Instance["DialogRestartRequiredMessage"]);
|
||||
LocaleManager.Instance[LocaleKeys.DialogThemeRestartMessage],
|
||||
LocaleManager.Instance[LocaleKeys.DialogThemeRestartSubMessage],
|
||||
LocaleManager.Instance[LocaleKeys.InputDialogYes],
|
||||
LocaleManager.Instance[LocaleKeys.InputDialogNo],
|
||||
LocaleManager.Instance[LocaleKeys.DialogRestartRequiredMessage]);
|
||||
|
||||
if (result == UserResult.Yes)
|
||||
{
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,4 +1,5 @@
|
||||
{
|
||||
"Language": "Deutsch",
|
||||
"MenuBarFileOpenApplet": "Applet öffnen",
|
||||
"MenuBarFileOpenAppletOpenMiiAppletToolTip": "Öffnet das Mii Editor Applet im Standalone Modus",
|
||||
"SettingsTabInputDirectMouseAccess": "Direkter Mauszugriff",
|
||||
@ -41,10 +42,10 @@
|
||||
"GameListHeaderPath": "Pfad",
|
||||
"GameListContextMenuOpenUserSaveDirectory": "Spielstand-Verzeichnis öffnen",
|
||||
"GameListContextMenuOpenUserSaveDirectoryToolTip": "Öffnet das Verzeichnis, welches den Benutzer-Spielstand beinhaltet",
|
||||
"GameListContextMenuOpenUserDeviceDirectory": "Benutzer-Geräte-Verzeichnis öffnen",
|
||||
"GameListContextMenuOpenUserDeviceDirectoryToolTip": "Öffnet das Verzeichnis, welches den Geräte-Spielstände beinhaltet",
|
||||
"GameListContextMenuOpenUserBcatDirectory": "Benutzer-BCAT-Vezeichnis öffnen",
|
||||
"GameListContextMenuOpenUserBcatDirectoryToolTip": "Öffnet das Verzeichnis, welches den BCAT Cache des Spiels beinhaltet",
|
||||
"GameListContextMenuOpenDeviceSaveDirectory": "Benutzer-Geräte-Verzeichnis öffnen",
|
||||
"GameListContextMenuOpenDeviceSaveDirectoryToolTip": "Öffnet das Verzeichnis, welches den Geräte-Spielstände beinhaltet",
|
||||
"GameListContextMenuOpenBcatSaveDirectory": "Benutzer-BCAT-Vezeichnis öffnen",
|
||||
"GameListContextMenuOpenBcatSaveDirectoryToolTip": "Öffnet das Verzeichnis, welches den BCAT Cache des Spiels beinhaltet",
|
||||
"GameListContextMenuManageTitleUpdates": "Verwalten von Spiel Updates",
|
||||
"GameListContextMenuManageTitleUpdatesToolTip": "Öffnet den Spiel-Update-Manager",
|
||||
"GameListContextMenuManageDlc": "Verwalten von DLC",
|
||||
@ -81,7 +82,7 @@
|
||||
"SettingsTabGeneralRemove": "Entfernen",
|
||||
"SettingsTabSystem": "System",
|
||||
"SettingsTabSystemCore": "Kern",
|
||||
"SettingsTabSystemSystemRegion": "System Region:",
|
||||
"SettingsTabSystemSystemRegion": "Systemregion:",
|
||||
"SettingsTabSystemSystemRegionJapan": "Japan",
|
||||
"SettingsTabSystemSystemRegionUSA": "USA",
|
||||
"SettingsTabSystemSystemRegionEurope": "Europa",
|
||||
@ -113,7 +114,7 @@
|
||||
"SettingsTabSystemEnablePptc": "PPTC Cache (Profiled Persistent Translation Cache)",
|
||||
"SettingsTabSystemEnableFsIntegrityChecks": "FS Integritätsprüfung",
|
||||
"SettingsTabSystemAudioBackend": "Audio-Backend:",
|
||||
"SettingsTabSystemAudioBackendDummy": "Dummy",
|
||||
"SettingsTabSystemAudioBackendDummy": "Ohne Funktion",
|
||||
"SettingsTabSystemAudioBackendOpenAL": "OpenAL",
|
||||
"SettingsTabSystemAudioBackendSoundIO": "SoundIO",
|
||||
"SettingsTabSystemAudioBackendSDL2": "SDL2",
|
||||
@ -157,6 +158,7 @@
|
||||
"SettingsTabLoggingEnableFsAccessLogs": "Aktiviere Fs Zugriff-Logs",
|
||||
"SettingsTabLoggingFsGlobalAccessLogMode": "Fs Globaler Zugriff-Log-Modus:",
|
||||
"SettingsTabLoggingDeveloperOptions": "Entwickleroptionen (WARNUNG: Beeinträchtigt die Leistung)",
|
||||
"SettingsTabLoggingGraphicsBackendLogLevel": "Graphics Backend Log Level:",
|
||||
"SettingsTabLoggingGraphicsBackendLogLevelNone": "Keine",
|
||||
"SettingsTabLoggingGraphicsBackendLogLevelError": "Fehler",
|
||||
"SettingsTabLoggingGraphicsBackendLogLevelPerformance": "Verlangsamungen",
|
||||
@ -190,7 +192,7 @@
|
||||
"ControllerSettingsControllerTypeJoyConLeft": "Joy-Con Links",
|
||||
"ControllerSettingsControllerTypeJoyConRight": "Joy-Con Rechts",
|
||||
"ControllerSettingsProfile": "Profil",
|
||||
"ControllerSettingsProfileDefault": "Default",
|
||||
"ControllerSettingsProfileDefault": "Standard",
|
||||
"ControllerSettingsLoad": "Laden",
|
||||
"ControllerSettingsAdd": "Hinzufügen",
|
||||
"ControllerSettingsRemove": "Entfernen",
|
||||
@ -230,7 +232,7 @@
|
||||
"ControllerSettingsTriggersRight": "Rechter Trigger",
|
||||
"ControllerSettingsTriggersButtonsLeft": "Linke Schultertaste",
|
||||
"ControllerSettingsTriggersButtonsRight": "Rechte Schultertaste",
|
||||
"ControllerSettingsTriggers": "Triggers",
|
||||
"ControllerSettingsTriggers": "Trigger",
|
||||
"ControllerSettingsTriggerL": "L",
|
||||
"ControllerSettingsTriggerR": "R",
|
||||
"ControllerSettingsTriggerZL": "ZL",
|
||||
@ -245,7 +247,7 @@
|
||||
"ControllerSettingsTriggerThreshold": "Empfindlichkeit:",
|
||||
"ControllerSettingsMotion": "Bewegung",
|
||||
"ControllerSettingsMotionUseCemuhookCompatibleMotion": "CemuHook kompatible Bewegungssteuerung",
|
||||
"ControllerSettingsMotionControllerSlot": "Controller Slot:",
|
||||
"ControllerSettingsMotionControllerSlot": "Kontroller Slot:",
|
||||
"ControllerSettingsMotionMirrorInput": "Spiegele Eingabe",
|
||||
"ControllerSettingsMotionRightJoyConSlot": "Rechter Joy-Con Slot:",
|
||||
"ControllerSettingsMotionServerHost": "Server Host:",
|
||||
@ -258,7 +260,7 @@
|
||||
"UserProfilesChangeProfileImage": "Profilbild ändern",
|
||||
"UserProfilesAvailableUserProfiles": "Verfügbare Profile:",
|
||||
"UserProfilesAddNewProfile": "Neues Profil",
|
||||
"UserProfilesDeleteSelectedProfile": "Profil löschen",
|
||||
"UserProfilesDelete": "Löschen",
|
||||
"UserProfilesClose": "Schließen",
|
||||
"ProfileImageSelectionTitle": "Auswahl des Profilbildes",
|
||||
"ProfileImageSelectionHeader": "Wähle ein Profilbild aus",
|
||||
@ -279,7 +281,7 @@
|
||||
"ControllerSettingsRemoveProfileToolTip": "Entfernt ein Profil",
|
||||
"ControllerSettingsSaveProfileToolTip": "Speichert ein Profil",
|
||||
"MenuBarFileToolsTakeScreenshot": "Screenshot aufnehmen",
|
||||
"MenuBarFileToolsHideUi": "Verstecke UI",
|
||||
"MenuBarFileToolsHideUi": "Hide UI",
|
||||
"GameListContextMenuToggleFavorite": "Als Favoriten hinzufügen/entfernen",
|
||||
"GameListContextMenuToggleFavoriteToolTip": "Aktiviert den Favoriten-Status des Spiels",
|
||||
"SettingsTabGeneralTheme": "Design",
|
||||
@ -314,8 +316,8 @@
|
||||
"DialogUpdaterConvertFailedMessage": "Die Konvertierung der aktuellen Ryujinx Version ist fehlgeschlagen.",
|
||||
"DialogUpdaterCancelUpdateMessage": "Download wird abgebrochen!",
|
||||
"DialogUpdaterAlreadyOnLatestVersionMessage": "Es wird bereits die aktuellste Version von Ryujinx benutzt",
|
||||
"DialogUpdaterFailedToGetVersionMessage": "Bei dem Versuch Versionsinformationen von AppVeyor zu erhalten, ist ein Fehler aufgetreten ",
|
||||
"DialogUpdaterConvertFailedAppveyorMessage": "Die von AppVeyor erhaltene Ryujinx Version konnte nicht konvertiert werden.",
|
||||
"DialogUpdaterFailedToGetVersionMessage": "An error has occurred when trying to get release information from GitHub Release. This can be caused if a new release is being compiled by GitHub Actions. Try again in a few minutes.",
|
||||
"DialogUpdaterConvertFailedGithubMessage": "Failed to convert the received Ryujinx version from Github Release.",
|
||||
"DialogUpdaterDownloadingMessage": "Update wird Heruntergeladen...",
|
||||
"DialogUpdaterExtractionMessage": "Update wird entpackt...",
|
||||
"DialogUpdaterRenamingMessage": "Update wird umbenannt...",
|
||||
@ -368,7 +370,7 @@
|
||||
"DialogUserProfileDeletionConfirmMessage": "Möchtest du das ausgewählte Profil löschen?",
|
||||
"DialogControllerSettingsModifiedConfirmMessage": "Die aktuellen Controller-Einstellungen wurden aktualisiert.",
|
||||
"DialogControllerSettingsModifiedConfirmSubMessage": "Controller-Einstellungen speichern?",
|
||||
"DialogDlcLoadNcaErrorMessage": "{0}. Fehlerhafte Datei: {1}",
|
||||
"DialogLoadNcaErrorMessage": "{0}. Fehlerhafte Datei: {1}",
|
||||
"DialogDlcNoDlcErrorMessage": "Die angegebene Datei enthält keinen DLC für den ausgewählten Titel!",
|
||||
"DialogPerformanceCheckLoggingEnabledMessage": "Es wurde die Debug Protokollierung aktiviert",
|
||||
"DialogPerformanceCheckLoggingEnabledConfirmMessage": "Um eine optimale Leistung zu erzielen, wird empfohlen, die Debug Protokollierung zu deaktivieren. Debug Protokollierung jetzt deaktivieren?",
|
||||
@ -411,6 +413,8 @@
|
||||
"DlcManagerTableHeadingContainerPathLabel": "Container-Pfad",
|
||||
"DlcManagerTableHeadingFullPathLabel": "Vollständiger-Pfad",
|
||||
"DlcManagerRemoveAllButton": "Entferne alle",
|
||||
"DlcManagerEnableAllButton": "Alle aktivieren",
|
||||
"DlcManagerDisableAllButton": "Alle deaktivieren",
|
||||
"MenuBarOptionsChangeLanguage": "Sprache ändern",
|
||||
"CommonSort": "Sortieren",
|
||||
"CommonShowNames": "Spiel-Namen anzeigen",
|
||||
@ -455,8 +459,8 @@
|
||||
"StubLogTooltip": "Ausgabe von Stub-Logs in der Konsole. Hat keinen Einfluss auf die Leistung.",
|
||||
"InfoLogTooltip": "Ausgabe von Info-Logs in der Konsole. Hat keinen Einfluss auf die Leistung.",
|
||||
"WarnLogTooltip": "Ausgabe von Warn-Logs in der Konsole. Hat keinen Einfluss auf die Leistung.",
|
||||
"TraceLogTooltip": "Ausgabe von Trace-Log in der Konsole. Hat keinen Einfluss auf die Leistung.",
|
||||
"ErrorLogTooltip": "Ausgabe von Fehler-Logs in der Konsole. Hat keinen Einfluss auf die Leistung.",
|
||||
"TraceLogTooltip": "Ausgabe von Trace-Log in der Konsole. Hat keinen Einfluss auf die Leistung.",
|
||||
"GuestLogTooltip": "Ausgabe von Gast-Logs in der Konsole. Hat keinen Einfluss auf die Leistung.",
|
||||
"FileAccessLogTooltip": "Ausgabe von FS-Zugriff-Logs in der Konsole.",
|
||||
"FSAccessLogModeTooltip": "Aktiviert die Ausgabe des FS-Zugriff-Logs in der Konsole. Mögliche Modi sind 0-3",
|
||||
@ -477,7 +481,7 @@
|
||||
"GridSizeTooltip": "Ändert die Größe der Rasterelemente",
|
||||
"SettingsTabSystemSystemLanguageBrazilianPortuguese": "Brasilianisches Portugiesisch",
|
||||
"AboutRyujinxContributorsButtonHeader": "Alle Mitwirkenden anzeigen",
|
||||
"SettingsTabSystemAudioVolume" : "Lautstärke: ",
|
||||
"SettingsTabSystemAudioVolume": "Lautstärke: ",
|
||||
"AudioVolumeTooltip": "Ändert die Lautstärke",
|
||||
"SettingsTabSystemEnableInternetAccess": "Gast-Internet-Zugang/LAN Modus",
|
||||
"EnableInternetAccessTooltip": "Erlaubt es der emulierten Anwendung sich mit dem Internet zu verbinden.\n\nSpiele die den LAN-Modus unterstützen, ermöglichen es Ryujinx sich sowohl mit anderen Ryujinx-Systemen, als auch mit offiziellen Nintendo Switch Konsolen zu verbinden. Allerdings nur, wenn diese Option aktiviert ist und die Systeme mit demselben lokalen Netzwerk verbunden sind.\n\nDies erlaubt KEINE Verbindung zu Nintendo-Servern. Kann bei bestimmten Spielen die versuchen sich mit dem Internet zu verbinden zum Absturz führen.\n\nIm Zweifelsfall AUS lassen",
|
||||
@ -554,8 +558,8 @@
|
||||
"SettingsTabHotkeysToggleMuteHotkey": "Stummschalten:",
|
||||
"ControllerMotionTitle": "Bewegungssteuerung - Einstellungen",
|
||||
"ControllerRumbleTitle": "Vibration - Einstellungen",
|
||||
"SettingsSelectThemeFileDialogTitle" : "Wähle ein Design für die Emulator-Benutzeroberfläche",
|
||||
"SettingsXamlThemeFile" : "Xaml Design-Datei",
|
||||
"SettingsSelectThemeFileDialogTitle": "Wähle ein Design für die Emulator-Benutzeroberfläche",
|
||||
"SettingsXamlThemeFile": "Xaml Design-Datei",
|
||||
"AvatarWindowTitle": "Profile verwalten - Avatar",
|
||||
"Amiibo": "Amiibo",
|
||||
"Unknown": "Unbekannt",
|
||||
@ -575,12 +579,12 @@
|
||||
"Discard": "Verwerfen",
|
||||
"UserProfilesSetProfileImage": "Profilbild einrichten",
|
||||
"UserProfileEmptyNameError": "Name ist erforderlich",
|
||||
"UserProfileNoImageError": "Bitte ein Profilbild auswählen",
|
||||
"UserProfileNoImageError": "Bitte ein Profilbild auswählen",
|
||||
"GameUpdateWindowHeading": "Update verfügbar für {0} [{1}]",
|
||||
"SettingsTabHotkeysResScaleUpHotkey": "Auflösung erhöhen:",
|
||||
"SettingsTabHotkeysResScaleDownHotkey": "Auflösung verringern:",
|
||||
"UserProfilesName": "Name:",
|
||||
"UserProfilesUserId" : "Benutzer Id:",
|
||||
"UserProfilesUserId": "Benutzer Id:",
|
||||
"SettingsTabGraphicsBackend": "Grafik-Backend:",
|
||||
"SettingsTabGraphicsBackendTooltip": "Verwendendetes Grafik-Backend",
|
||||
"SettingsEnableTextureRecompression": "Textur-Rekompression",
|
||||
@ -589,5 +593,22 @@
|
||||
"SettingsTabGraphicsPreferredGpuTooltip": "Wähle die Grafikkarte aus, die mit dem Vulkan Grafik-Backend verwendet werden soll.\n\nDies hat keinen Einfluss auf die GPU die OpenGL verwendet.\n\nIm Zweifelsfall die als \"dGPU\" gekennzeichnete GPU auswählen. Diese Einstellung unberührt lassen, wenn keine zur Auswahl steht.",
|
||||
"SettingsAppRequiredRestartMessage": "Ein Neustart von Ryujinx ist erforderlich",
|
||||
"SettingsGpuBackendRestartMessage": "Das Grafik-Backend oder die Grafikkarteneinstellungen wurden geändert. Ein Neustart ist erforderlich um diese Einstellungen anzuwenden.",
|
||||
"SettingsGpuBackendRestartSubMessage": "Ryujinx jetzt neu starten?"
|
||||
"SettingsGpuBackendRestartSubMessage": "Ryujinx jetzt neu starten?",
|
||||
"RyujinxUpdaterMessage": "Möchtest du Ryujinx auf die neueste Version aktualisieren?",
|
||||
"SettingsTabHotkeysVolumeUpHotkey": "Lautstärke erhöhen:",
|
||||
"SettingsTabHotkeysVolumeDownHotkey": "Lautstärke verringern:",
|
||||
"SettingsEnableMacroHLE": "HLE Makros aktivieren",
|
||||
"SettingsEnableMacroHLETooltip": "High-level emulation of GPU Macro code.\n\nImproves performance, but may cause graphical glitches in some games.\n\nLeave ON if unsure.",
|
||||
"VolumeShort": "Vol",
|
||||
"UserProfilesManageSaves": "Speicherstände verwalten",
|
||||
"DeleteUserSave": "Möchtest du den Spielerstand für dieses Spiel löschen?",
|
||||
"IrreversibleActionNote": "Diese Option kann nicht rückgängig gemacht werden.",
|
||||
"SaveManagerHeading": "Spielstände für {0} verwalten",
|
||||
"SaveManagerTitle": "Speicherdaten Manager",
|
||||
"Name": "Name",
|
||||
"Size": "Größe",
|
||||
"Search": "Suche",
|
||||
"UserProfilesRecoverLostAccounts": "Konto wiederherstellen",
|
||||
"Recover": "Wiederherstellen",
|
||||
"UserProfilesRecoverHeading": "Speicherstände wurden für die folgenden Konten gefunden"
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
{
|
||||
{
|
||||
"Language": "Ελληνικά",
|
||||
"MenuBarFileOpenApplet": "Άνοιγμα Applet",
|
||||
"MenuBarFileOpenAppletOpenMiiAppletToolTip": "Άνοιγμα του Mii Editor Applet σε Αυτόνομη λειτουργία",
|
||||
"SettingsTabInputDirectMouseAccess": "Άμεση Πρόσβαση Ποντικιού",
|
||||
@ -41,10 +42,10 @@
|
||||
"GameListHeaderPath": "Τοποθεσία",
|
||||
"GameListContextMenuOpenUserSaveDirectory": "Άνοιγμα Τοποθεσίας Αποθήκευσης Χρήστη",
|
||||
"GameListContextMenuOpenUserSaveDirectoryToolTip": "Ανοίγει την τοποθεσία που περιέχει την Αποθήκευση Χρήστη της εφαρμογής",
|
||||
"GameListContextMenuOpenUserDeviceDirectory": "Άνοιγμα Τοποθεσίας Συσκευής Χρήστη",
|
||||
"GameListContextMenuOpenUserDeviceDirectoryToolTip": "Ανοίγει την τοποθεσία που περιέχει την Αποθήκευση Συσκευής της εφαρμογής",
|
||||
"GameListContextMenuOpenUserBcatDirectory": "Άνοιγμα Τοποθεσίας BCAT",
|
||||
"GameListContextMenuOpenUserBcatDirectoryToolTip": "Ανοίγει την τοποθεσία που περιέχει την Αποθήκευση BCAT της εφαρμογής",
|
||||
"GameListContextMenuOpenDeviceSaveDirectory": "Άνοιγμα Τοποθεσίας Συσκευής Χρήστη",
|
||||
"GameListContextMenuOpenDeviceSaveDirectoryToolTip": "Ανοίγει την τοποθεσία που περιέχει την Αποθήκευση Συσκευής της εφαρμογής",
|
||||
"GameListContextMenuOpenBcatSaveDirectory": "Άνοιγμα Τοποθεσίας BCAT",
|
||||
"GameListContextMenuOpenBcatSaveDirectoryToolTip": "Ανοίγει την τοποθεσία που περιέχει την Αποθήκευση BCAT της εφαρμογής",
|
||||
"GameListContextMenuManageTitleUpdates": "Διαχείριση Ενημερώσεων Παιχνιδιού",
|
||||
"GameListContextMenuManageTitleUpdatesToolTip": "Ανοίγει το παράθυρο διαχείρισης Ενημερώσεων Παιχνιδιού",
|
||||
"GameListContextMenuManageDlc": "Διαχείριση DLC",
|
||||
@ -65,7 +66,7 @@
|
||||
"GameListContextMenuExtractDataExeFSToolTip": "Εξαγωγή της ενότητας ExeFS από την τρέχουσα διαμόρφωση της εφαρμογής (συμπεριλαμβανομένου ενημερώσεων)",
|
||||
"GameListContextMenuExtractDataRomFS": "RomFS",
|
||||
"GameListContextMenuExtractDataRomFSToolTip": "Εξαγωγή της ενότητας RomFS από την τρέχουσα διαμόρφωση της εφαρμογής (συμπεριλαμβανομένου ενημερώσεων)",
|
||||
"GameListContextMenuExtractDataLogo": "Logo",
|
||||
"GameListContextMenuExtractDataLogo": "Λογότυπο",
|
||||
"GameListContextMenuExtractDataLogoToolTip": "Εξαγωγή της ενότητας Logo από την τρέχουσα διαμόρφωση της εφαρμογής (συμπεριλαμβανομένου ενημερώσεων)",
|
||||
"StatusBarGamesLoaded": "{0}/{1} Φορτωμένα Παιχνίδια",
|
||||
"StatusBarSystemVersion": "Έκδοση Συστήματος: {0}",
|
||||
@ -157,6 +158,7 @@
|
||||
"SettingsTabLoggingEnableFsAccessLogs": "Ενεργοποίηση Καταγραφής Πρόσβασης FS",
|
||||
"SettingsTabLoggingFsGlobalAccessLogMode": "Λειτουργία Καταγραφής Καθολικής Πρόσβασης FS:",
|
||||
"SettingsTabLoggingDeveloperOptions": "Επιλογές Προγραμματιστή (ΠΡΟΕΙΔΟΠΟΙΗΣΗ: Η απόδοση Θα μειωθεί)",
|
||||
"SettingsTabLoggingGraphicsBackendLogLevel": "Επίπεδο Καταγραφής Διεπαφής Γραφικών:",
|
||||
"SettingsTabLoggingGraphicsBackendLogLevelNone": "Κανένα",
|
||||
"SettingsTabLoggingGraphicsBackendLogLevelError": "Σφάλμα",
|
||||
"SettingsTabLoggingGraphicsBackendLogLevelPerformance": "Επιβραδύνσεις",
|
||||
@ -167,7 +169,7 @@
|
||||
"SettingsTabInputDirectKeyboardAccess": "Άμεση Πρόσβαση στο Πληκτρολόγιο",
|
||||
"SettingsButtonSave": "Αποθήκευση",
|
||||
"SettingsButtonClose": "Κλείσιμο",
|
||||
"SettingsButtonOk": "OK",
|
||||
"SettingsButtonOk": "ΟΚ",
|
||||
"SettingsButtonCancel": "Ακύρωση",
|
||||
"SettingsButtonApply": "Εφαρμογή",
|
||||
"ControllerSettingsPlayer": "Παίχτης",
|
||||
@ -184,7 +186,7 @@
|
||||
"ControllerSettingsRefresh": "Ανανέωση",
|
||||
"ControllerSettingsDeviceDisabled": "Απενεργοποιημένο",
|
||||
"ControllerSettingsControllerType": "Τύπος Χειριστηρίου",
|
||||
"ControllerSettingsControllerTypeHandheld": "Handheld",
|
||||
"ControllerSettingsControllerTypeHandheld": "Φορητό",
|
||||
"ControllerSettingsControllerTypeProController": "Pro Controller",
|
||||
"ControllerSettingsControllerTypeJoyConPair": "Ζεύγος JoyCon",
|
||||
"ControllerSettingsControllerTypeJoyConLeft": "Αριστερό JoyCon",
|
||||
@ -195,7 +197,7 @@
|
||||
"ControllerSettingsAdd": "Προσθήκη",
|
||||
"ControllerSettingsRemove": "Αφαίρεση",
|
||||
"ControllerSettingsButtons": "Κουμπιά",
|
||||
"ControllerSettingsButtonA": "A",
|
||||
"ControllerSettingsButtonA": "Α",
|
||||
"ControllerSettingsButtonB": "B",
|
||||
"ControllerSettingsButtonX": "X",
|
||||
"ControllerSettingsButtonY": "Y",
|
||||
@ -212,7 +214,7 @@
|
||||
"ControllerSettingsLStickDown": "Κάτω",
|
||||
"ControllerSettingsLStickLeft": "Αριστερά",
|
||||
"ControllerSettingsLStickRight": "Δεξιά",
|
||||
"ControllerSettingsLStickStick": "Stick",
|
||||
"ControllerSettingsLStickStick": "Μοχλός",
|
||||
"ControllerSettingsLStickInvertXAxis": "Αντιστροφή Μοχλού X",
|
||||
"ControllerSettingsLStickInvertYAxis": "Αντιστροφή Μοχλού Y",
|
||||
"ControllerSettingsLStickDeadzone": "Νεκρή Ζώνη:",
|
||||
@ -222,7 +224,7 @@
|
||||
"ControllerSettingsRStickDown": "Κάτω",
|
||||
"ControllerSettingsRStickLeft": "Αριστερά",
|
||||
"ControllerSettingsRStickRight": "Δεξιά",
|
||||
"ControllerSettingsRStickStick": "Stick",
|
||||
"ControllerSettingsRStickStick": "Μοχλός",
|
||||
"ControllerSettingsRStickInvertXAxis": "Αντιστροφή Μοχλού X",
|
||||
"ControllerSettingsRStickInvertYAxis": "Αντιστροφή Μοχλού Y",
|
||||
"ControllerSettingsRStickDeadzone": "Νεκρή Ζώνη:",
|
||||
@ -258,7 +260,7 @@
|
||||
"UserProfilesChangeProfileImage": "Αλλαγή Εικόνας Προφίλ",
|
||||
"UserProfilesAvailableUserProfiles": "Διαθέσιμα Προφίλ Χρηστών:",
|
||||
"UserProfilesAddNewProfile": "Προσθήκη Νέου Προφίλ",
|
||||
"UserProfilesDeleteSelectedProfile": "Διαγραφή Επιλεγμένου Προφίλ",
|
||||
"UserProfilesDelete": "Διαγράφω",
|
||||
"UserProfilesClose": "Κλείσιμο",
|
||||
"ProfileImageSelectionTitle": "Επιλογή Εικόνας Προφίλ",
|
||||
"ProfileImageSelectionHeader": "Επιλέξτε μία Εικόνα Προφίλ",
|
||||
@ -266,7 +268,7 @@
|
||||
"ProfileImageSelectionImportImage": "Εισαγωγή Αρχείου Εικόνας",
|
||||
"ProfileImageSelectionSelectAvatar": "Επιλέξτε Avatar από Firmware",
|
||||
"InputDialogTitle": "Διάλογος Εισαγωγής",
|
||||
"InputDialogOk": "OK",
|
||||
"InputDialogOk": "ΟΚ",
|
||||
"InputDialogCancel": "Ακύρωση",
|
||||
"InputDialogAddNewProfileTitle": "Επιλογή Ονόματος Προφίλ",
|
||||
"InputDialogAddNewProfileHeader": "Εισαγωγή Ονόματος Προφίλ",
|
||||
@ -314,7 +316,7 @@
|
||||
"DialogUpdaterConvertFailedMessage": "Αποτυχία μετατροπής της τρέχουσας έκδοσης Ryujinx.",
|
||||
"DialogUpdaterCancelUpdateMessage": "Ακύρωση Ενημέρωσης!",
|
||||
"DialogUpdaterAlreadyOnLatestVersionMessage": "Χρησιμοποιείτε ήδη την πιο ενημερωμένη έκδοση του Ryujinx!",
|
||||
"DialogUpdaterFailedToGetVersionMessage": "Σφάλμα κατά την προσπάθεια λήψης έκδοσης από το GitHub Release. Αυτό μπορεί να προκληθεί εάν μία νέα έκδοση συντάσσεται από το GitHub Actions. Δοκιμάστε ξανά σε λίγα λεπτά.",
|
||||
"DialogUpdaterFailedToGetVersionMessage": "Προέκυψε ένα σφάλμα στη λήψη πληροφοριών έκδοσης από τα GitHub Releases. Αυτό δύναται να συμβεί αν μία έκδοση χτίζεται αυτή τη στιγμή στα GitHub Actions. Παρακαλούμε προσπαθήστε αργότερα.",
|
||||
"DialogUpdaterConvertFailedGithubMessage": "Αποτυχία μετατροπής της ληφθείσας έκδοσης Ryujinx από την έκδοση GitHub.",
|
||||
"DialogUpdaterDownloadingMessage": "Λήψη Ενημέρωσης...",
|
||||
"DialogUpdaterExtractionMessage": "Εξαγωγή Ενημέρωσης...",
|
||||
@ -368,7 +370,7 @@
|
||||
"DialogUserProfileDeletionConfirmMessage": "Θέλετε να διαγράψετε το επιλεγμένο προφίλ",
|
||||
"DialogControllerSettingsModifiedConfirmMessage": "Οι τρέχουσες ρυθμίσεις χειρισμού έχουν ενημερωθεί.",
|
||||
"DialogControllerSettingsModifiedConfirmSubMessage": "Θέλετε να αποθηκεύσετε;",
|
||||
"DialogDlcLoadNcaErrorMessage": "{0}. Σφάλμα Αρχείου: {1}",
|
||||
"DialogLoadNcaErrorMessage": "{0}. Σφάλμα Αρχείου: {1}",
|
||||
"DialogDlcNoDlcErrorMessage": "Το αρχείο δεν περιέχει DLC για τον επιλεγμένο τίτλο!",
|
||||
"DialogPerformanceCheckLoggingEnabledMessage": "Έχετε ενεργοποιημένη την καταγραφή εντοπισμού σφαλμάτων, η οποία έχει σχεδιαστεί για χρήση μόνο από προγραμματιστές.",
|
||||
"DialogPerformanceCheckLoggingEnabledConfirmMessage": "Για βέλτιστη απόδοση, συνιστάται η απενεργοποίηση καταγραφής εντοπισμού σφαλμάτων. Θέλετε να απενεργοποιήσετε την καταγραφή τώρα;",
|
||||
@ -411,6 +413,8 @@
|
||||
"DlcManagerTableHeadingContainerPathLabel": "Τοποθεσία DLC",
|
||||
"DlcManagerTableHeadingFullPathLabel": "Πλήρης τοποθεσία",
|
||||
"DlcManagerRemoveAllButton": "Αφαίρεση όλων",
|
||||
"DlcManagerEnableAllButton": "Ενεργοποίηση Όλων",
|
||||
"DlcManagerDisableAllButton": "Απενεργοποίηση Όλων",
|
||||
"MenuBarOptionsChangeLanguage": "Αλλαξε γλώσσα",
|
||||
"CommonSort": "Κατάταξη",
|
||||
"CommonShowNames": "Εμφάνιση ονομάτων",
|
||||
@ -492,6 +496,119 @@
|
||||
"SettingsTabNetworkConnection": "Σύνδεση δικτύου",
|
||||
"SettingsTabCpuCache": "Προσωρινή Μνήμη CPU",
|
||||
"SettingsTabCpuMemory": "Μνήμη CPU",
|
||||
"DialogUpdaterFlatpakNotSupportedMessage": "Παρακαλούμε ενημερώστε το Ryujinx μέσω FlatHub.",
|
||||
"UpdaterDisabledWarningTitle": "Ο Διαχειριστής Ενημερώσεων Είναι Απενεργοποιημένος!",
|
||||
"GameListContextMenuOpenSdModsDirectory": "Άνοιγμα Της Τοποθεσίας Των Atmosphere Mods",
|
||||
"GameListContextMenuOpenSdModsDirectoryToolTip": "Opens the alternative SD card Atmosphere directory which contains Application's Mods. Useful for mods that are packaged for real hardware.",
|
||||
"ControllerSettingsRotate90": "Rotate 90° Clockwise",
|
||||
"IconSize": "Icon Size",
|
||||
"IconSizeTooltip": "Change the size of game icons",
|
||||
"MenuBarOptionsShowConsole": "Show Console",
|
||||
"ShaderCachePurgeError": "Error purging shader cache at {0}: {1}",
|
||||
"UserErrorNoKeys": "Keys not found",
|
||||
"UserErrorNoFirmware": "Firmware not found",
|
||||
"UserErrorFirmwareParsingFailed": "Firmware parsing error",
|
||||
"UserErrorApplicationNotFound": "Application not found",
|
||||
"UserErrorUnknown": "Unknown error",
|
||||
"UserErrorUndefined": "Undefined error",
|
||||
"UserErrorNoKeysDescription": "Ryujinx was unable to find your 'prod.keys' file",
|
||||
"UserErrorNoFirmwareDescription": "Ryujinx was unable to find any firmwares installed",
|
||||
"UserErrorFirmwareParsingFailedDescription": "Ryujinx was unable to parse the provided firmware. This is usually caused by outdated keys.",
|
||||
"UserErrorApplicationNotFoundDescription": "Ryujinx couldn't find a valid application at the given path.",
|
||||
"UserErrorUnknownDescription": "An unknown error occured!",
|
||||
"UserErrorUndefinedDescription": "An undefined error occured! This shouldn't happen, please contact a dev!",
|
||||
"OpenSetupGuideMessage": "Open the Setup Guide",
|
||||
"NoUpdate": "No Update",
|
||||
"TitleUpdateVersionLabel": "Version {0} - {1}",
|
||||
"RyujinxInfo": "Ryujinx - Info",
|
||||
"RyujinxConfirm": "Ryujinx - Confirmation",
|
||||
"FileDialogAllTypes": "All types",
|
||||
"Never": "Never",
|
||||
"SwkbdMinCharacters": "Must be at least {0} characters long",
|
||||
"SwkbdMinRangeCharacters": "Must be {0}-{1} characters long",
|
||||
"SoftwareKeyboard": "Software Keyboard",
|
||||
"DialogControllerAppletMessagePlayerRange": "Application requests {0} player(s) with:\n\nTYPES: {1}\n\nPLAYERS: {2}\n\n{3}Please open Settings and reconfigure Input now or press Close.",
|
||||
"DialogControllerAppletMessage": "Application requests exactly {0} player(s) with:\n\nTYPES: {1}\n\nPLAYERS: {2}\n\n{3}Please open Settings and reconfigure Input now or press Close.",
|
||||
"DialogControllerAppletDockModeSet": "Docked mode set. Handheld is also invalid.\n\n",
|
||||
"UpdaterRenaming": "Renaming Old Files...",
|
||||
"UpdaterRenameFailed": "Updater was unable to rename file: {0}",
|
||||
"UpdaterAddingFiles": "Adding New Files...",
|
||||
"UpdaterExtracting": "Extracting Update...",
|
||||
"UpdaterDownloading": "Downloading Update...",
|
||||
"Game": "Game",
|
||||
"Docked": "Docked",
|
||||
"Handheld": "Handheld",
|
||||
"ConnectionError": "Connection Error.",
|
||||
"AboutPageDeveloperListMore": "{0} and more...",
|
||||
"ApiError": "API Error.",
|
||||
"LoadingHeading": "Loading {0}",
|
||||
"CompilingPPTC": "Compiling PTC",
|
||||
"CompilingShaders": "Compiling Shaders",
|
||||
"AllKeyboards": "All keyboards",
|
||||
"OpenFileDialogTitle": "Select a supported file to open",
|
||||
"OpenFolderDialogTitle": "Select a folder with an unpacked game",
|
||||
"AllSupportedFormats": "All Supported Formats",
|
||||
"RyujinxUpdater": "Ryujinx Updater",
|
||||
"SettingsTabHotkeys": "Keyboard Hotkeys",
|
||||
"SettingsTabHotkeysHotkeys": "Keyboard Hotkeys",
|
||||
"SettingsTabHotkeysToggleVsyncHotkey": "Toggle VSync:",
|
||||
"SettingsTabHotkeysScreenshotHotkey": "Screenshot:",
|
||||
"SettingsTabHotkeysShowUiHotkey": "Show UI:",
|
||||
"SettingsTabHotkeysPauseHotkey": "Pause:",
|
||||
"SettingsTabHotkeysToggleMuteHotkey": "Mute:",
|
||||
"ControllerMotionTitle": "Motion Control Settings",
|
||||
"ControllerRumbleTitle": "Rumble Settings"
|
||||
"ControllerRumbleTitle": "Rumble Settings",
|
||||
"SettingsSelectThemeFileDialogTitle": "Select Theme File",
|
||||
"SettingsXamlThemeFile": "Xaml Theme File",
|
||||
"AvatarWindowTitle": "Manage Accounts - Avatar",
|
||||
"Amiibo": "Amiibo",
|
||||
"Unknown": "Unknown",
|
||||
"Usage": "Usage",
|
||||
"Writable": "Writable",
|
||||
"SelectDlcDialogTitle": "Select DLC files",
|
||||
"SelectUpdateDialogTitle": "Select update files",
|
||||
"UserProfileWindowTitle": "User Profiles Manager",
|
||||
"CheatWindowTitle": "Cheats Manager",
|
||||
"DlcWindowTitle": "Downloadable Content Manager",
|
||||
"UpdateWindowTitle": "Title Update Manager",
|
||||
"CheatWindowHeading": "Cheats Available for {0} [{1}]",
|
||||
"DlcWindowHeading": "{0} Downloadable Content(s) available for {1} ({2})",
|
||||
"UserProfilesEditProfile": "Edit Selected",
|
||||
"Cancel": "Cancel",
|
||||
"Save": "Save",
|
||||
"Discard": "Discard",
|
||||
"UserProfilesSetProfileImage": "Set Profile Image",
|
||||
"UserProfileEmptyNameError": "Name is required",
|
||||
"UserProfileNoImageError": "Profile image must be set",
|
||||
"GameUpdateWindowHeading": "{0} Update(s) available for {1} ({2})",
|
||||
"SettingsTabHotkeysResScaleUpHotkey": "Increase resolution:",
|
||||
"SettingsTabHotkeysResScaleDownHotkey": "Decrease resolution:",
|
||||
"UserProfilesName": "Name:",
|
||||
"UserProfilesUserId": "User Id:",
|
||||
"SettingsTabGraphicsBackend": "Graphics Backend",
|
||||
"SettingsTabGraphicsBackendTooltip": "Graphics Backend to use",
|
||||
"SettingsEnableTextureRecompression": "Enable Texture Recompression",
|
||||
"SettingsEnableTextureRecompressionTooltip": "Compresses certain textures in order to reduce VRAM usage.\n\nRecommended for use with GPUs that have less than 4GiB VRAM.\n\nLeave OFF if unsure.",
|
||||
"SettingsTabGraphicsPreferredGpu": "Preferred GPU",
|
||||
"SettingsTabGraphicsPreferredGpuTooltip": "Select the graphics card that will be used with the Vulkan graphics backend.\n\nDoes not affect the GPU that OpenGL will use.\n\nSet to the GPU flagged as \"dGPU\" if unsure. If there isn't one, leave untouched.",
|
||||
"SettingsAppRequiredRestartMessage": "Ryujinx Restart Required",
|
||||
"SettingsGpuBackendRestartMessage": "Graphics Backend or GPU settings have been modified. This will require a restart to be applied",
|
||||
"SettingsGpuBackendRestartSubMessage": "Do you want to restart now?",
|
||||
"RyujinxUpdaterMessage": "Do you want to update Ryujinx to the latest version?",
|
||||
"SettingsTabHotkeysVolumeUpHotkey": "Increase Volume:",
|
||||
"SettingsTabHotkeysVolumeDownHotkey": "Decrease Volume:",
|
||||
"SettingsEnableMacroHLE": "Enable Macro HLE",
|
||||
"SettingsEnableMacroHLETooltip": "High-level emulation of GPU Macro code.\n\nImproves performance, but may cause graphical glitches in some games.\n\nLeave ON if unsure.",
|
||||
"VolumeShort": "Vol",
|
||||
"UserProfilesManageSaves": "Manage Saves",
|
||||
"DeleteUserSave": "Do you want to delete user save for this game?",
|
||||
"IrreversibleActionNote": "This action is not reversible.",
|
||||
"SaveManagerHeading": "Manage Saves for {0}",
|
||||
"SaveManagerTitle": "Save Manager",
|
||||
"Name": "Name",
|
||||
"Size": "Size",
|
||||
"Search": "Search",
|
||||
"UserProfilesRecoverLostAccounts": "Recover Lost Accounts",
|
||||
"Recover": "Recover",
|
||||
"UserProfilesRecoverHeading": "Saves were found for the following accounts"
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
{
|
||||
"Language": "English (US)",
|
||||
"MenuBarFileOpenApplet": "Open Applet",
|
||||
"MenuBarFileOpenAppletOpenMiiAppletToolTip": "Open Mii Editor Applet in Standalone mode",
|
||||
"SettingsTabInputDirectMouseAccess": "Direct Mouse Access",
|
||||
@ -6,6 +7,7 @@
|
||||
"SettingsTabSystemMemoryManagerModeSoftware": "Software",
|
||||
"SettingsTabSystemMemoryManagerModeHost": "Host (fast)",
|
||||
"SettingsTabSystemMemoryManagerModeHostUnchecked": "Host Unchecked (fastest, unsafe)",
|
||||
"SettingsTabSystemUseHypervisor": "Use Hypervisor",
|
||||
"MenuBarFile": "_File",
|
||||
"MenuBarFileOpenFromFile": "_Load Application From File",
|
||||
"MenuBarFileOpenUnpacked": "Load _Unpacked Game",
|
||||
@ -25,6 +27,9 @@
|
||||
"MenuBarToolsInstallFirmware": "Install Firmware",
|
||||
"MenuBarFileToolsInstallFirmwareFromFile": "Install a firmware from XCI or ZIP",
|
||||
"MenuBarFileToolsInstallFirmwareFromDirectory": "Install a firmware from a directory",
|
||||
"MenuBarToolsManageFileTypes": "Manage file types",
|
||||
"MenuBarToolsInstallFileTypes": "Install file types",
|
||||
"MenuBarToolsUninstallFileTypes": "Uninstall file types",
|
||||
"MenuBarHelp": "Help",
|
||||
"MenuBarHelpCheckForUpdates": "Check for Updates",
|
||||
"MenuBarHelpAbout": "About",
|
||||
@ -41,10 +46,10 @@
|
||||
"GameListHeaderPath": "Path",
|
||||
"GameListContextMenuOpenUserSaveDirectory": "Open User Save Directory",
|
||||
"GameListContextMenuOpenUserSaveDirectoryToolTip": "Opens the directory which contains Application's User Save",
|
||||
"GameListContextMenuOpenUserDeviceDirectory": "Open User Device Directory",
|
||||
"GameListContextMenuOpenUserDeviceDirectoryToolTip": "Opens the directory which contains Application's Device Save",
|
||||
"GameListContextMenuOpenUserBcatDirectory": "Open User BCAT Directory",
|
||||
"GameListContextMenuOpenUserBcatDirectoryToolTip": "Opens the directory which contains Application's BCAT Save",
|
||||
"GameListContextMenuOpenDeviceSaveDirectory": "Open Device Save Directory",
|
||||
"GameListContextMenuOpenDeviceSaveDirectoryToolTip": "Opens the directory which contains Application's Device Save",
|
||||
"GameListContextMenuOpenBcatSaveDirectory": "Open BCAT Save Directory",
|
||||
"GameListContextMenuOpenBcatSaveDirectoryToolTip": "Opens the directory which contains Application's BCAT Save",
|
||||
"GameListContextMenuManageTitleUpdates": "Manage Title Updates",
|
||||
"GameListContextMenuManageTitleUpdatesToolTip": "Opens the Title Update management window",
|
||||
"GameListContextMenuManageDlc": "Manage DLC",
|
||||
@ -118,7 +123,7 @@
|
||||
"SettingsTabSystemAudioBackendSoundIO": "SoundIO",
|
||||
"SettingsTabSystemAudioBackendSDL2": "SDL2",
|
||||
"SettingsTabSystemHacks": "Hacks",
|
||||
"SettingsTabSystemHacksNote": " (may cause instability)",
|
||||
"SettingsTabSystemHacksNote": "May cause instability",
|
||||
"SettingsTabSystemExpandDramSize": "Use alternative memory layout (Developers)",
|
||||
"SettingsTabSystemIgnoreMissingServices": "Ignore Missing Services",
|
||||
"SettingsTabGraphics": "Graphics",
|
||||
@ -156,7 +161,8 @@
|
||||
"SettingsTabLoggingEnableGuestLogs": "Enable Guest Logs",
|
||||
"SettingsTabLoggingEnableFsAccessLogs": "Enable Fs Access Logs",
|
||||
"SettingsTabLoggingFsGlobalAccessLogMode": "Fs Global Access Log Mode:",
|
||||
"SettingsTabLoggingDeveloperOptions": "Developer Options (WARNING: Will reduce performance)",
|
||||
"SettingsTabLoggingDeveloperOptions": "Developer Options",
|
||||
"SettingsTabLoggingDeveloperOptionsNote": "WARNING: Will reduce performance",
|
||||
"SettingsTabLoggingGraphicsBackendLogLevel": "Graphics Backend Log Level:",
|
||||
"SettingsTabLoggingGraphicsBackendLogLevelNone": "None",
|
||||
"SettingsTabLoggingGraphicsBackendLogLevelError": "Error",
|
||||
@ -259,8 +265,9 @@
|
||||
"UserProfilesChangeProfileImage": "Change Profile Image",
|
||||
"UserProfilesAvailableUserProfiles": "Available User Profiles:",
|
||||
"UserProfilesAddNewProfile": "Create Profile",
|
||||
"UserProfilesDeleteSelectedProfile": "Delete Selected",
|
||||
"UserProfilesDelete": "Delete",
|
||||
"UserProfilesClose": "Close",
|
||||
"ProfileNameSelectionWatermark": "Choose a nickname",
|
||||
"ProfileImageSelectionTitle": "Profile Image Selection",
|
||||
"ProfileImageSelectionHeader": "Choose a profile Image",
|
||||
"ProfileImageSelectionNote": "You may import a custom profile image, or select an avatar from system firmware",
|
||||
@ -272,7 +279,7 @@
|
||||
"InputDialogAddNewProfileTitle": "Choose the Profile Name",
|
||||
"InputDialogAddNewProfileHeader": "Please Enter a Profile Name",
|
||||
"InputDialogAddNewProfileSubtext": "(Max Length: {0})",
|
||||
"AvatarChoose": "Choose",
|
||||
"AvatarChoose": "Choose Avatar",
|
||||
"AvatarSetBackgroundColor": "Set Background Color",
|
||||
"AvatarClose": "Close",
|
||||
"ControllerSettingsLoadProfileToolTip": "Load Profile",
|
||||
@ -336,6 +343,10 @@
|
||||
"DialogFirmwareInstallEmbeddedSuccessMessage": "No installed firmware was found but Ryujinx was able to install firmware {0} from the provided game.\\nThe emulator will now start.",
|
||||
"DialogFirmwareNoFirmwareInstalledMessage": "No Firmware Installed",
|
||||
"DialogFirmwareInstalledMessage": "Firmware {0} was installed",
|
||||
"DialogInstallFileTypesSuccessMessage": "Successfully installed file types!",
|
||||
"DialogInstallFileTypesErrorMessage": "Failed to install file types.",
|
||||
"DialogUninstallFileTypesSuccessMessage": "Successfully uninstalled file types!",
|
||||
"DialogUninstallFileTypesErrorMessage": "Failed to uninstall file types.",
|
||||
"DialogOpenSettingsWindowLabel": "Open Settings Window",
|
||||
"DialogControllerAppletTitle": "Controller Applet",
|
||||
"DialogMessageDialogErrorExceptionMessage": "Error displaying Message Dialog: {0}",
|
||||
@ -367,9 +378,12 @@
|
||||
"DialogFirmwareInstallerFirmwareInstallSuccessMessage": "System version {0} successfully installed.",
|
||||
"DialogUserProfileDeletionWarningMessage": "There would be no other profiles to be opened if selected profile is deleted",
|
||||
"DialogUserProfileDeletionConfirmMessage": "Do you want to delete the selected profile",
|
||||
"DialogUserProfileUnsavedChangesTitle": "Warning - Unsaved Changes",
|
||||
"DialogUserProfileUnsavedChangesMessage": "You have made changes to this user profile that have not been saved.",
|
||||
"DialogUserProfileUnsavedChangesSubMessage": "Do you want to discard your changes?",
|
||||
"DialogControllerSettingsModifiedConfirmMessage": "The current controller settings has been updated.",
|
||||
"DialogControllerSettingsModifiedConfirmSubMessage": "Do you want to save?",
|
||||
"DialogDlcLoadNcaErrorMessage": "{0}. Errored File: {1}",
|
||||
"DialogLoadNcaErrorMessage": "{0}. Errored File: {1}",
|
||||
"DialogDlcNoDlcErrorMessage": "The specified file does not contain a DLC for the selected title!",
|
||||
"DialogPerformanceCheckLoggingEnabledMessage": "You have trace logging enabled, which is designed to be used by developers only.",
|
||||
"DialogPerformanceCheckLoggingEnabledConfirmMessage": "For optimal performance, it's recommended to disable trace logging. Would you like to disable trace logging now?",
|
||||
@ -444,6 +458,7 @@
|
||||
"MemoryManagerSoftwareTooltip": "Use a software page table for address translation. Highest accuracy but slowest performance.",
|
||||
"MemoryManagerHostTooltip": "Directly map memory in the host address space. Much faster JIT compilation and execution.",
|
||||
"MemoryManagerUnsafeTooltip": "Directly map memory, but do not mask the address within the guest address space before access. Faster, but at the cost of safety. The guest application can access memory from anywhere in Ryujinx, so only run programs you trust with this mode.",
|
||||
"UseHypervisorTooltip": "Use Hypervisor instead of JIT. Greatly improves performance when available, but can be unstable in its current state.",
|
||||
"DRamTooltip": "Utilizes an alternative MemoryMode layout to mimic a Switch development model.\n\nThis is only useful for higher-resolution texture packs or 4k resolution mods. Does NOT improve performance.\n\nLeave OFF if unsure.",
|
||||
"IgnoreMissingServicesTooltip": "Ignores unimplemented Horizon OS services. This may help in bypassing crashes when booting certain games.\n\nLeave OFF if unsure.",
|
||||
"GraphicsBackendThreadingTooltip": "Executes graphics backend commands on a second thread.\n\nSpeeds up shader compilation, reduces stuttering, and improves performance on GPU drivers without multithreading support of their own. Slightly better performance on drivers with multithreading.\n\nSet to AUTO if unsure.",
|
||||
@ -494,7 +509,7 @@
|
||||
"SettingsTabNetwork": "Network",
|
||||
"SettingsTabNetworkConnection": "Network Connection",
|
||||
"SettingsTabCpuCache": "CPU Cache",
|
||||
"SettingsTabCpuMemory": "CPU Memory",
|
||||
"SettingsTabCpuMemory": "CPU Mode",
|
||||
"DialogUpdaterFlatpakNotSupportedMessage": "Please update Ryujinx via FlatHub.",
|
||||
"UpdaterDisabledWarningTitle": "Updater Disabled!",
|
||||
"GameListContextMenuOpenSdModsDirectory": "Open Atmosphere Mods Directory",
|
||||
@ -518,7 +533,7 @@
|
||||
"UserErrorUndefinedDescription": "An undefined error occured! This shouldn't happen, please contact a dev!",
|
||||
"OpenSetupGuideMessage": "Open the Setup Guide",
|
||||
"NoUpdate": "No Update",
|
||||
"TitleUpdateVersionLabel": "Version {0} - {1}",
|
||||
"TitleUpdateVersionLabel": "Version {0}",
|
||||
"RyujinxInfo": "Ryujinx - Info",
|
||||
"RyujinxConfirm": "Ryujinx - Confirmation",
|
||||
"FileDialogAllTypes": "All types",
|
||||
@ -579,11 +594,11 @@
|
||||
"UserProfilesSetProfileImage": "Set Profile Image",
|
||||
"UserProfileEmptyNameError": "Name is required",
|
||||
"UserProfileNoImageError": "Profile image must be set",
|
||||
"GameUpdateWindowHeading": "{0} Update(s) available for {1} ({2})",
|
||||
"GameUpdateWindowHeading": "Manage Updates for {0} ({1})",
|
||||
"SettingsTabHotkeysResScaleUpHotkey": "Increase resolution:",
|
||||
"SettingsTabHotkeysResScaleDownHotkey": "Decrease resolution:",
|
||||
"UserProfilesName": "Name:",
|
||||
"UserProfilesUserId": "User Id:",
|
||||
"UserProfilesUserId": "User ID:",
|
||||
"SettingsTabGraphicsBackend": "Graphics Backend",
|
||||
"SettingsTabGraphicsBackendTooltip": "Graphics Backend to use",
|
||||
"SettingsEnableTextureRecompression": "Enable Texture Recompression",
|
||||
@ -602,12 +617,25 @@
|
||||
"UserProfilesManageSaves": "Manage Saves",
|
||||
"DeleteUserSave": "Do you want to delete user save for this game?",
|
||||
"IrreversibleActionNote": "This action is not reversible.",
|
||||
"SaveManagerHeading": "Manage Saves for {0}",
|
||||
"SaveManagerHeading": "Manage Saves for {0} ({1})",
|
||||
"SaveManagerTitle": "Save Manager",
|
||||
"Name": "Name",
|
||||
"Size": "Size",
|
||||
"Search": "Search",
|
||||
"UserProfilesRecoverLostAccounts": "Recover Lost Accounts",
|
||||
"Recover": "Recover",
|
||||
"UserProfilesRecoverHeading" : "Saves were found for the following accounts"
|
||||
"UserProfilesRecoverHeading" : "Saves were found for the following accounts",
|
||||
"UserProfilesRecoverEmptyList": "No profiles to recover",
|
||||
"GraphicsAATooltip": "Applies anti-aliasing to the game render",
|
||||
"GraphicsAALabel": "Anti-Aliasing:",
|
||||
"GraphicsScalingFilterLabel": "Scaling Filter:",
|
||||
"GraphicsScalingFilterTooltip": "Enables Framebuffer Scaling",
|
||||
"GraphicsScalingFilterLevelLabel": "Level",
|
||||
"GraphicsScalingFilterLevelTooltip": "Set Scaling Filter Level",
|
||||
"SmaaLow": "SMAA Low",
|
||||
"SmaaMedium": "SMAA Medium",
|
||||
"SmaaHigh": "SMAA High",
|
||||
"SmaaUltra": "SMAA Ultra",
|
||||
"UserEditorTitle" : "Edit User",
|
||||
"UserEditorTitleCreate" : "Create User"
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
{
|
||||
"Language": "Español (ES)",
|
||||
"MenuBarFileOpenApplet": "Abrir applet",
|
||||
"MenuBarFileOpenAppletOpenMiiAppletToolTip": "Abre el editor de Mii en modo autónomo",
|
||||
"SettingsTabInputDirectMouseAccess": "Acceso directo al ratón",
|
||||
@ -13,66 +14,66 @@
|
||||
"MenuBarFileOpenLogsFolder": "Abrir carpeta de registros",
|
||||
"MenuBarFileExit": "_Salir",
|
||||
"MenuBarOptions": "_Opciones",
|
||||
"MenuBarOptionsToggleFullscreen": "Alternar pantalla completa",
|
||||
"MenuBarOptionsToggleFullscreen": "Cambiar a pantalla completa.",
|
||||
"MenuBarOptionsStartGamesInFullscreen": "Iniciar juegos en pantalla completa",
|
||||
"MenuBarOptionsStopEmulation": "Detener emulación",
|
||||
"MenuBarOptionsSettings": "_Configuración",
|
||||
"MenuBarOptionsManageUserProfiles": "_Gestionar perfiles de usuario",
|
||||
"MenuBarActions": "Accio_nes",
|
||||
"MenuBarOptionsSimulateWakeUpMessage": "Simular mensaje de _reactivación",
|
||||
"MenuBarActionsScanAmiibo": "_Escanear Amiibo",
|
||||
"MenuBarActions": "_Acciones",
|
||||
"MenuBarOptionsSimulateWakeUpMessage": "Simular mensaje de reactivación",
|
||||
"MenuBarActionsScanAmiibo": "Escanear Amiibo",
|
||||
"MenuBarTools": "_Herramientas",
|
||||
"MenuBarToolsInstallFirmware": "Instalar firmware",
|
||||
"MenuBarFileToolsInstallFirmwareFromFile": "Instalar firmware desde un archivo XCI o ZIP",
|
||||
"MenuBarFileToolsInstallFirmwareFromDirectory": "Instalar firmware desde una carpeta",
|
||||
"MenuBarHelp": "A_yuda",
|
||||
"MenuBarHelp": "Ayuda",
|
||||
"MenuBarHelpCheckForUpdates": "Buscar actualizaciones",
|
||||
"MenuBarHelpAbout": "Acerca de",
|
||||
"MenuSearch": "Buscar...",
|
||||
"GameListHeaderFavorite": "Fav",
|
||||
"GameListHeaderFavorite": "Favoritos",
|
||||
"GameListHeaderIcon": "Icono",
|
||||
"GameListHeaderApplication": "Aplicación",
|
||||
"GameListHeaderApplication": "Nombre",
|
||||
"GameListHeaderDeveloper": "Desarrollador",
|
||||
"GameListHeaderVersion": "Versión",
|
||||
"GameListHeaderTimePlayed": "Tiempo jugado",
|
||||
"GameListHeaderLastPlayed": "Última vez",
|
||||
"GameListHeaderLastPlayed": "Jugado por última vez",
|
||||
"GameListHeaderFileExtension": "Extensión",
|
||||
"GameListHeaderFileSize": "Tamaño",
|
||||
"GameListHeaderFileSize": "Tamaño del archivo",
|
||||
"GameListHeaderPath": "Directorio",
|
||||
"GameListContextMenuOpenUserSaveDirectory": "Abrir carpeta de guardado de este usuario",
|
||||
"GameListContextMenuOpenUserSaveDirectoryToolTip": "Abre la carpeta que contiene la partida guardada del usuario para esta aplicación",
|
||||
"GameListContextMenuOpenUserDeviceDirectory": "Abrir carpeta de guardado del sistema para el usuario actual",
|
||||
"GameListContextMenuOpenUserDeviceDirectoryToolTip": "Abre la carpeta que contiene la partida guardada del sistema para esta aplicación",
|
||||
"GameListContextMenuOpenUserBcatDirectory": "Abrir carpeta de guardado BCAT del usuario",
|
||||
"GameListContextMenuOpenUserBcatDirectoryToolTip": "Abre la carpeta que contiene el guardado BCAT de esta aplicación",
|
||||
"GameListContextMenuOpenDeviceSaveDirectory": "Abrir carpeta de guardado del sistema para el usuario actual",
|
||||
"GameListContextMenuOpenDeviceSaveDirectoryToolTip": "Abre la carpeta que contiene la partida guardada del sistema para esta aplicación",
|
||||
"GameListContextMenuOpenBcatSaveDirectory": "Abrir carpeta de guardado BCAT del usuario",
|
||||
"GameListContextMenuOpenBcatSaveDirectoryToolTip": "Abrir la carpeta que contiene el guardado BCAT de esta aplicación",
|
||||
"GameListContextMenuManageTitleUpdates": "Gestionar actualizaciones del juego",
|
||||
"GameListContextMenuManageTitleUpdatesToolTip": "Abre la ventana de gestión de actualizaciones de esta aplicación",
|
||||
"GameListContextMenuManageTitleUpdatesToolTip": "Abrir la ventana de gestión de actualizaciones de esta aplicación",
|
||||
"GameListContextMenuManageDlc": "Gestionar DLC",
|
||||
"GameListContextMenuManageDlcToolTip": "Abre la ventana de gestión del contenido descargable",
|
||||
"GameListContextMenuManageDlcToolTip": "Abrir la ventana de gestión del DLC",
|
||||
"GameListContextMenuOpenModsDirectory": "Abrir carpeta de mods",
|
||||
"GameListContextMenuOpenModsDirectoryToolTip": "Abre la carpeta que contiene los mods (archivos modificantes) de esta aplicación",
|
||||
"GameListContextMenuCacheManagement": "Gestión de cachés",
|
||||
"GameListContextMenuCacheManagementPurgePptc": "Purgar caché de PPTC",
|
||||
"GameListContextMenuOpenModsDirectoryToolTip": "Abrir la carpeta que contiene los mods (archivos modificantes) de esta aplicación",
|
||||
"GameListContextMenuCacheManagement": "Gestión de caché ",
|
||||
"GameListContextMenuCacheManagementPurgePptc": "Reconstruir PPTC en cola",
|
||||
"GameListContextMenuCacheManagementPurgePptcToolTip": "Elimina la caché de PPTC de esta aplicación",
|
||||
"GameListContextMenuCacheManagementPurgeShaderCache": "Purgar caché de sombreadores",
|
||||
"GameListContextMenuCacheManagementPurgeShaderCacheToolTip": "Elimina la caché de sombreadores de esta aplicación",
|
||||
"GameListContextMenuCacheManagementPurgeShaderCache": "Limpiar caché de sombras",
|
||||
"GameListContextMenuCacheManagementPurgeShaderCacheToolTip": "Eliminar la caché de sombras de esta aplicación",
|
||||
"GameListContextMenuCacheManagementOpenPptcDirectory": "Abrir carpeta de PPTC",
|
||||
"GameListContextMenuCacheManagementOpenPptcDirectoryToolTip": "Abre la carpeta que contiene la caché de PPTC de esta aplicación",
|
||||
"GameListContextMenuCacheManagementOpenShaderCacheDirectory": "Abrir carpeta de caché de sombreadores",
|
||||
"GameListContextMenuCacheManagementOpenShaderCacheDirectoryToolTip": "Abre la carpeta que contiene la caché de sombreadores de esta aplicación",
|
||||
"GameListContextMenuCacheManagementOpenPptcDirectoryToolTip": "Abrir la carpeta que contiene la caché de PPTC de esta aplicación",
|
||||
"GameListContextMenuCacheManagementOpenShaderCacheDirectory": "Abrir carpeta de caché de sombras",
|
||||
"GameListContextMenuCacheManagementOpenShaderCacheDirectoryToolTip": "Abrir la carpeta que contiene la caché de sombras de esta aplicación",
|
||||
"GameListContextMenuExtractData": "Extraer datos",
|
||||
"GameListContextMenuExtractDataExeFS": "ExeFS",
|
||||
"GameListContextMenuExtractDataExeFSToolTip": "Extrae la sección ExeFS de la configuración actual de la aplicación (incluyendo actualizaciones)",
|
||||
"GameListContextMenuExtractDataExeFSToolTip": "Extraer la sección ExeFS de la configuración actual de la aplicación (incluyendo actualizaciones)",
|
||||
"GameListContextMenuExtractDataRomFS": "RomFS",
|
||||
"GameListContextMenuExtractDataRomFSToolTip": "Extrae la sección RomFS de la configuración actual de la aplicación (incluyendo actualizaciones)",
|
||||
"GameListContextMenuExtractDataLogo": "Logo",
|
||||
"GameListContextMenuExtractDataLogoToolTip": "Extrae la sección Logo de la configuración actual de la aplicación (incluyendo actualizaciones)",
|
||||
"GameListContextMenuExtractDataRomFSToolTip": "Extraer la sección RomFS de la configuración actual de la aplicación (incluyendo actualizaciones)",
|
||||
"GameListContextMenuExtractDataLogo": "Logotipo",
|
||||
"GameListContextMenuExtractDataLogoToolTip": "Extraer la sección Logo de la configuración actual de la aplicación (incluyendo actualizaciones)",
|
||||
"StatusBarGamesLoaded": "{0}/{1} juegos cargados",
|
||||
"StatusBarSystemVersion": "Versión del sistema: {0}",
|
||||
"Settings": "Configuración",
|
||||
"SettingsTabGeneral": "General",
|
||||
"SettingsTabGeneral": "Interfaz de usuario",
|
||||
"SettingsTabGeneralGeneral": "General",
|
||||
"SettingsTabGeneralEnableDiscordRichPresence": "Habilitar presencia enriquecida de Discord",
|
||||
"SettingsTabGeneralEnableDiscordRichPresence": "Habilitar estado en Discord",
|
||||
"SettingsTabGeneralCheckUpdatesOnLaunch": "Buscar actualizaciones al iniciar",
|
||||
"SettingsTabGeneralShowConfirmExitDialog": "Mostrar diálogo de confirmación al cerrar",
|
||||
"SettingsTabGeneralHideCursorOnIdle": "Ocultar cursor cuando esté inactivo",
|
||||
@ -80,7 +81,7 @@
|
||||
"SettingsTabGeneralAdd": "Agregar",
|
||||
"SettingsTabGeneralRemove": "Quitar",
|
||||
"SettingsTabSystem": "Sistema",
|
||||
"SettingsTabSystemCore": "Principal",
|
||||
"SettingsTabSystemCore": "Núcleo",
|
||||
"SettingsTabSystemSystemRegion": "Región del sistema:",
|
||||
"SettingsTabSystemSystemRegionJapan": "Japón",
|
||||
"SettingsTabSystemSystemRegionUSA": "EEUU",
|
||||
@ -110,22 +111,22 @@
|
||||
"SettingsTabSystemSystemTimeZone": "Zona horaria del sistema:",
|
||||
"SettingsTabSystemSystemTime": "Hora del sistema:",
|
||||
"SettingsTabSystemEnableVsync": "Sincronización vertical",
|
||||
"SettingsTabSystemEnablePptc": "PPTC (Profiled Persistent Translation Cache)",
|
||||
"SettingsTabSystemEnablePptc": "PPTC (Cache de Traducción de Perfil Persistente)",
|
||||
"SettingsTabSystemEnableFsIntegrityChecks": "Comprobar integridad de los archivos",
|
||||
"SettingsTabSystemAudioBackend": "Motor de audio:",
|
||||
"SettingsTabSystemAudioBackendDummy": "Dummy",
|
||||
"SettingsTabSystemAudioBackendDummy": "Vacio",
|
||||
"SettingsTabSystemAudioBackendOpenAL": "OpenAL",
|
||||
"SettingsTabSystemAudioBackendSoundIO": "SoundIO",
|
||||
"SettingsTabSystemAudioBackendSDL2": "SDL2",
|
||||
"SettingsTabSystemHacks": "Hacks",
|
||||
"SettingsTabSystemHacksNote": " (Pueden causar inestabilidad)",
|
||||
"SettingsTabSystemExpandDramSize": "Expandir DRAM a 6GiB",
|
||||
"SettingsTabSystemExpandDramSize": "Usar diseño alternativo de memoria (Desarrolladores)",
|
||||
"SettingsTabSystemIgnoreMissingServices": "Ignorar servicios no implementados",
|
||||
"SettingsTabGraphics": "Gráficos",
|
||||
"SettingsTabGraphicsAPI": "API de gráficos",
|
||||
"SettingsTabGraphicsEnableShaderCache": "Habilitar caché de sombreadores",
|
||||
"SettingsTabGraphicsEnableShaderCache": "Habilitar caché de sombras",
|
||||
"SettingsTabGraphicsAnisotropicFiltering": "Filtro anisotrópico:",
|
||||
"SettingsTabGraphicsAnisotropicFilteringAuto": "Auto",
|
||||
"SettingsTabGraphicsAnisotropicFilteringAuto": "Automático",
|
||||
"SettingsTabGraphicsAnisotropicFiltering2x": "x2",
|
||||
"SettingsTabGraphicsAnisotropicFiltering4x": "x4",
|
||||
"SettingsTabGraphicsAnisotropicFiltering8x": "x8",
|
||||
@ -144,10 +145,10 @@
|
||||
"SettingsTabGraphicsAspectRatio32x9": "32:9",
|
||||
"SettingsTabGraphicsAspectRatioStretch": "Estirar a la ventana",
|
||||
"SettingsTabGraphicsDeveloperOptions": "Opciones de desarrollador",
|
||||
"SettingsTabGraphicsShaderDumpPath": "Directorio de volcado de sombreadores:",
|
||||
"SettingsTabGraphicsShaderDumpPath": "Directorio de volcado de sombras:",
|
||||
"SettingsTabLogging": "Registros",
|
||||
"SettingsTabLoggingLogging": "Registros",
|
||||
"SettingsTabLoggingEnableLoggingToFile": "Escribir registros en archivo",
|
||||
"SettingsTabLoggingEnableLoggingToFile": "Habilitar registro a archivo",
|
||||
"SettingsTabLoggingEnableStubLogs": "Habilitar registros de Stub",
|
||||
"SettingsTabLoggingEnableInfoLogs": "Habilitar registros de Info",
|
||||
"SettingsTabLoggingEnableWarningLogs": "Habilitar registros de Advertencia",
|
||||
@ -157,6 +158,7 @@
|
||||
"SettingsTabLoggingEnableFsAccessLogs": "Habilitar registros de Fs Access",
|
||||
"SettingsTabLoggingFsGlobalAccessLogMode": "Modo de registros Fs Global Access:",
|
||||
"SettingsTabLoggingDeveloperOptions": "Opciones de desarrollador (ADVERTENCIA: empeorarán el rendimiento)",
|
||||
"SettingsTabLoggingGraphicsBackendLogLevel": "Nivel de registro de backend gráficos:",
|
||||
"SettingsTabLoggingGraphicsBackendLogLevelNone": "Nada",
|
||||
"SettingsTabLoggingGraphicsBackendLogLevelError": "Errores",
|
||||
"SettingsTabLoggingGraphicsBackendLogLevelPerformance": "Ralentizaciones",
|
||||
@ -167,7 +169,7 @@
|
||||
"SettingsTabInputDirectKeyboardAccess": "Acceso directo al teclado",
|
||||
"SettingsButtonSave": "Guardar",
|
||||
"SettingsButtonClose": "Cerrar",
|
||||
"SettingsButtonOk": "OK",
|
||||
"SettingsButtonOk": "Aceptar",
|
||||
"SettingsButtonCancel": "Cancelar",
|
||||
"SettingsButtonApply": "Aplicar",
|
||||
"ControllerSettingsPlayer": "Jugador",
|
||||
@ -258,7 +260,7 @@
|
||||
"UserProfilesChangeProfileImage": "Cambiar imagen de perfil",
|
||||
"UserProfilesAvailableUserProfiles": "Perfiles de usuario disponibles:",
|
||||
"UserProfilesAddNewProfile": "Añadir nuevo perfil",
|
||||
"UserProfilesDeleteSelectedProfile": "Eliminar perfil seleccionado",
|
||||
"UserProfilesDelete": "Eliminar",
|
||||
"UserProfilesClose": "Cerrar",
|
||||
"ProfileImageSelectionTitle": "Selección de imagen de perfil",
|
||||
"ProfileImageSelectionHeader": "Elige una imagen de perfil",
|
||||
@ -314,7 +316,7 @@
|
||||
"DialogUpdaterConvertFailedMessage": "No se pudo convertir la versión actual de Ryujinx.",
|
||||
"DialogUpdaterCancelUpdateMessage": "¡Cancelando actualización!",
|
||||
"DialogUpdaterAlreadyOnLatestVersionMessage": "¡Ya tienes la versión más reciente de Ryujinx!",
|
||||
"DialogUpdaterFailedToGetVersionMessage": "Ha ocurrido un error al intentar obtener información de versión desde GitHub Release. Esto puede ocurrir cuando una nueva versión está siendo compilada por GitHub Actions. Inténtalo de nuevo en unos minutos.",
|
||||
"DialogUpdaterFailedToGetVersionMessage": "Se ha producido un error al intentar obtener información de liberación de GitHub Release. Esto puede ser causado si una nueva versión está siendo compilada por GitHub Actions. Inténtalo de nuevo en unos minutos.",
|
||||
"DialogUpdaterConvertFailedGithubMessage": "No se pudo convertir la versión de Ryujinx recibida de GitHub Release.",
|
||||
"DialogUpdaterDownloadingMessage": "Descargando actualización...",
|
||||
"DialogUpdaterExtractionMessage": "Extrayendo actualización...",
|
||||
@ -368,12 +370,12 @@
|
||||
"DialogUserProfileDeletionConfirmMessage": "¿Quieres eliminar el perfil seleccionado?",
|
||||
"DialogControllerSettingsModifiedConfirmMessage": "Se ha actualizado la configuración del mando actual.",
|
||||
"DialogControllerSettingsModifiedConfirmSubMessage": "¿Guardar cambios?",
|
||||
"DialogDlcLoadNcaErrorMessage": "{0}. Archivo con error: {1}",
|
||||
"DialogLoadNcaErrorMessage": "{0}. Archivo con error: {1}",
|
||||
"DialogDlcNoDlcErrorMessage": "¡Ese archivo no contiene contenido descargable para el título seleccionado!",
|
||||
"DialogPerformanceCheckLoggingEnabledMessage": "Has habilitado los registros debug, diseñados solo para uso de los desarrolladores.",
|
||||
"DialogPerformanceCheckLoggingEnabledConfirmMessage": "Para un rendimiento óptimo, se recomienda deshabilitar los registros debug. ¿Quieres deshabilitarlos ahora?",
|
||||
"DialogPerformanceCheckShaderDumpEnabledMessage": "Has habilitado el volcado de sombreadores, diseñado solo para uso de los desarrolladores.",
|
||||
"DialogPerformanceCheckShaderDumpEnabledConfirmMessage": "Para un rendimiento óptimo, se recomienda deshabilitar el volcado de sombreadores. ¿Quieres deshabilitarlo ahora?",
|
||||
"DialogPerformanceCheckShaderDumpEnabledMessage": "Has habilitado el volcado de sombras, diseñado solo para uso de los desarrolladores.",
|
||||
"DialogPerformanceCheckShaderDumpEnabledConfirmMessage": "Para un rendimiento óptimo, se recomienda deshabilitar el volcado de sombraa. ¿Quieres deshabilitarlo ahora?",
|
||||
"DialogLoadAppGameAlreadyLoadedMessage": "Ya has cargado un juego",
|
||||
"DialogLoadAppGameAlreadyLoadedSubMessage": "Por favor, detén la emulación o cierra el emulador antes de iniciar otro juego.",
|
||||
"DialogUpdateAddUpdateErrorMessage": "¡Ese archivo no contiene una actualización para el título seleccionado!",
|
||||
@ -381,7 +383,7 @@
|
||||
"DialogSettingsBackendThreadingWarningMessage": "Ryujinx debe reiniciarse para aplicar este cambio. Dependiendo de tu plataforma, puede que tengas que desactivar manualmente la optimización enlazada de tus controladores gráficos para usar el multihilo de Ryujinx.",
|
||||
"SettingsTabGraphicsFeaturesOptions": "Funcionalidades",
|
||||
"SettingsTabGraphicsBackendMultithreading": "Multihilado del motor gráfico:",
|
||||
"CommonAuto": "Auto",
|
||||
"CommonAuto": "Automático",
|
||||
"CommonOff": "Desactivado",
|
||||
"CommonOn": "Activado",
|
||||
"InputDialogYes": "Sí",
|
||||
@ -400,7 +402,7 @@
|
||||
"AboutRyujinxAboutContent": "Ryujinx es un emulador para Nintendo Switch™.\nPor favor, apóyanos en Patreon.\nEncuentra las noticias más recientes en nuestro Twitter o Discord.\nDesarrolladores interesados en contribuir pueden encontrar más información en GitHub o Discord.",
|
||||
"AboutRyujinxMaintainersTitle": "Mantenido por:",
|
||||
"AboutRyujinxMaintainersContentTooltipMessage": "Haz clic para abrir la página de contribuidores en tu navegador predeterminado.",
|
||||
"AboutRyujinxSupprtersTitle": "Mecenas en Patreon:",
|
||||
"AboutRyujinxSupprtersTitle": "Apoyado en Patreon Por:",
|
||||
"AmiiboSeriesLabel": "Serie de Amiibo",
|
||||
"AmiiboCharacterLabel": "Personaje",
|
||||
"AmiiboScanButtonLabel": "Escanear",
|
||||
@ -411,13 +413,15 @@
|
||||
"DlcManagerTableHeadingContainerPathLabel": "Directorio del contenedor",
|
||||
"DlcManagerTableHeadingFullPathLabel": "Directorio completo",
|
||||
"DlcManagerRemoveAllButton": "Quitar todo",
|
||||
"DlcManagerEnableAllButton": "Activar todas",
|
||||
"DlcManagerDisableAllButton": "Desactivar todos",
|
||||
"MenuBarOptionsChangeLanguage": "Cambiar idioma",
|
||||
"CommonSort": "Orden",
|
||||
"CommonShowNames": "Mostrar nombres",
|
||||
"CommonFavorite": "Favorito",
|
||||
"OrderAscending": "Ascendente",
|
||||
"OrderDescending": "Descendente",
|
||||
"SettingsTabGraphicsFeatures": "Funcionalidades & Mejoras",
|
||||
"SettingsTabGraphicsFeatures": "Funcionalidades Y Mejoras",
|
||||
"ErrorWindowTitle": "Ventana de error",
|
||||
"ToggleDiscordTooltip": "Elige si muestras Ryujinx o no en tu actividad de Discord cuando lo estés usando",
|
||||
"AddGameDirBoxTooltip": "Elige un directorio de juegos para mostrar en la ventana principal",
|
||||
@ -476,7 +480,7 @@
|
||||
"GridSize": "Tamaño de cuadrícula",
|
||||
"GridSizeTooltip": "Cambia el tamaño de los objetos en la cuadrícula",
|
||||
"SettingsTabSystemSystemLanguageBrazilianPortuguese": "Portugués brasileño",
|
||||
"AboutRyujinxContributorsButtonHeader": "Ver todos los contribuidores",
|
||||
"AboutRyujinxContributorsButtonHeader": "Ver todos los contribuidores",
|
||||
"SettingsTabSystemAudioVolume": "Volumen: ",
|
||||
"AudioVolumeTooltip": "Ajusta el nivel de volumen",
|
||||
"SettingsTabSystemEnableInternetAccess": "Conectar guest a Internet/Modo LAN",
|
||||
@ -487,7 +491,7 @@
|
||||
"DialogStopEmulationTitle": "Ryujinx - Detener emulación",
|
||||
"DialogStopEmulationMessage": "¿Seguro que quieres detener la emulación actual?",
|
||||
"SettingsTabCpu": "CPU",
|
||||
"SettingsTabAudio": "Audio",
|
||||
"SettingsTabAudio": "Sonido",
|
||||
"SettingsTabNetwork": "Red",
|
||||
"SettingsTabNetworkConnection": "Conexión de red",
|
||||
"SettingsTabCpuCache": "Caché de CPU",
|
||||
@ -559,7 +563,7 @@
|
||||
"AvatarWindowTitle": "Administrar cuentas - Avatar",
|
||||
"Amiibo": "Amiibo",
|
||||
"Unknown": "Desconocido",
|
||||
"Usage": "Usage",
|
||||
"Usage": "Uso",
|
||||
"Writable": "Escribible",
|
||||
"SelectDlcDialogTitle": "Selecciona archivo(s) de DLC",
|
||||
"SelectUpdateDialogTitle": "Selecciona archivo(s) de actualización",
|
||||
@ -569,7 +573,42 @@
|
||||
"UpdateWindowTitle": "Administrar actualizaciones",
|
||||
"CheatWindowHeading": "Cheats disponibles para {0} [{1}]",
|
||||
"DlcWindowHeading": "Contenido descargable disponible para {0} [{1}]",
|
||||
"UserProfilesEditProfile": "Editar selección",
|
||||
"Cancel": "Cancelar",
|
||||
"Save": "Guardar",
|
||||
"Discard": "Descartar",
|
||||
"UserProfilesSetProfileImage": "Elegir Imagen de Perfil ",
|
||||
"UserProfileEmptyNameError": "El nombre es obligatorio",
|
||||
"UserProfileNoImageError": "Debe establecerse la imagen de perfil",
|
||||
"GameUpdateWindowHeading": "Actualizaciones disponibles para {0} [{1}]",
|
||||
"SettingsTabHotkeysResScaleUpHotkey": "Aumentar la resolución:",
|
||||
"SettingsTabHotkeysResScaleDownHotkey": "Disminuir la resolución:"
|
||||
"SettingsTabHotkeysResScaleDownHotkey": "Disminuir la resolución:",
|
||||
"UserProfilesName": "Nombre:",
|
||||
"UserProfilesUserId": "Id de Usuario:",
|
||||
"SettingsTabGraphicsBackend": "Fondo de gráficos",
|
||||
"SettingsTabGraphicsBackendTooltip": "Graphics Backend to use",
|
||||
"SettingsEnableTextureRecompression": "Enable Texture Recompression",
|
||||
"SettingsEnableTextureRecompressionTooltip": "Compresses certain textures in order to reduce VRAM usage.\n\nRecommended for use with GPUs that have less than 4GiB VRAM.\n\nLeave OFF if unsure.",
|
||||
"SettingsTabGraphicsPreferredGpu": "Preferred GPU",
|
||||
"SettingsTabGraphicsPreferredGpuTooltip": "Select the graphics card that will be used with the Vulkan graphics backend.\n\nDoes not affect the GPU that OpenGL will use.\n\nSet to the GPU flagged as \"dGPU\" if unsure. If there isn't one, leave untouched.",
|
||||
"SettingsAppRequiredRestartMessage": "Ryujinx Restart Required",
|
||||
"SettingsGpuBackendRestartMessage": "Graphics Backend or GPU settings have been modified. This will require a restart to be applied",
|
||||
"SettingsGpuBackendRestartSubMessage": "Do you want to restart now?",
|
||||
"RyujinxUpdaterMessage": "Do you want to update Ryujinx to the latest version?",
|
||||
"SettingsTabHotkeysVolumeUpHotkey": "Increase Volume:",
|
||||
"SettingsTabHotkeysVolumeDownHotkey": "Decrease Volume:",
|
||||
"SettingsEnableMacroHLE": "Enable Macro HLE",
|
||||
"SettingsEnableMacroHLETooltip": "High-level emulation of GPU Macro code.\n\nImproves performance, but may cause graphical glitches in some games.\n\nLeave ON if unsure.",
|
||||
"VolumeShort": "Vol",
|
||||
"UserProfilesManageSaves": "Manage Saves",
|
||||
"DeleteUserSave": "Do you want to delete user save for this game?",
|
||||
"IrreversibleActionNote": "This action is not reversible.",
|
||||
"SaveManagerHeading": "Manage Saves for {0}",
|
||||
"SaveManagerTitle": "Save Manager",
|
||||
"Name": "Name",
|
||||
"Size": "Size",
|
||||
"Search": "Search",
|
||||
"UserProfilesRecoverLostAccounts": "Recover Lost Accounts",
|
||||
"Recover": "Recover",
|
||||
"UserProfilesRecoverHeading": "Saves were found for the following accounts"
|
||||
}
|
||||
|
@ -1,9 +1,17 @@
|
||||
{
|
||||
"Language": "Français",
|
||||
"MenuBarFileOpenApplet": "Ouvrir Applet",
|
||||
"MenuBarFileOpenAppletOpenMiiAppletToolTip": "Ouvrir l'Applet Mii Editor en mode Standalone",
|
||||
"SettingsTabInputDirectMouseAccess": "Accès direct à la souris",
|
||||
"SettingsTabSystemMemoryManagerMode": "Mode de gestion mémoire :",
|
||||
"SettingsTabSystemMemoryManagerModeSoftware": "Logiciel",
|
||||
"SettingsTabSystemMemoryManagerModeHost": "Hôte (rapide)",
|
||||
"SettingsTabSystemMemoryManagerModeHostUnchecked": "Hôte non vérifié (plus rapide, non sécurisé)",
|
||||
"MenuBarFile": "_Fichier",
|
||||
"MenuBarFileOpenFromFile": "_Charger un jeu depuis un fichier",
|
||||
"MenuBarFileOpenUnpacked": "Charger un jeu _extrait",
|
||||
"MenuBarFileOpenEmuFolder": "Ouvrir le dossier Ryujinx",
|
||||
"MenuBarFileOpenLogsFolder": "Ouvrir le dossier de Logs",
|
||||
"MenuBarFileOpenLogsFolder": "Ouvrir le dossier des journaux",
|
||||
"MenuBarFileExit": "_Quitter",
|
||||
"MenuBarOptions": "Options",
|
||||
"MenuBarOptionsToggleFullscreen": "Basculer en plein écran",
|
||||
@ -34,10 +42,10 @@
|
||||
"GameListHeaderPath": "Chemin",
|
||||
"GameListContextMenuOpenUserSaveDirectory": "Ouvrir le dossier de sauvegarde utilisateur",
|
||||
"GameListContextMenuOpenUserSaveDirectoryToolTip": "Ouvre le dossier contenant la sauvegarde utilisateur du jeu",
|
||||
"GameListContextMenuOpenUserDeviceDirectory": "Ouvrir le dossier de sauvegarde console",
|
||||
"GameListContextMenuOpenUserDeviceDirectoryToolTip": "Ouvre le dossier contenant la sauvegarde console du jeu",
|
||||
"GameListContextMenuOpenUserBcatDirectory": "Ouvrir le dossier de sauvegarde BCAT",
|
||||
"GameListContextMenuOpenUserBcatDirectoryToolTip": "Ouvre le dossier contenant la sauvegarde BCAT du jeu",
|
||||
"GameListContextMenuOpenDeviceSaveDirectory": "Ouvrir le dossier de sauvegarde console",
|
||||
"GameListContextMenuOpenDeviceSaveDirectoryToolTip": "Ouvre le dossier contenant la sauvegarde console du jeu",
|
||||
"GameListContextMenuOpenBcatSaveDirectory": "Ouvrir le dossier de sauvegarde BCAT",
|
||||
"GameListContextMenuOpenBcatSaveDirectoryToolTip": "Ouvre le dossier contenant la sauvegarde BCAT du jeu",
|
||||
"GameListContextMenuManageTitleUpdates": "Gérer les mises à jour",
|
||||
"GameListContextMenuManageTitleUpdatesToolTip": "Ouvre la fenêtre de gestion des mises à jour",
|
||||
"GameListContextMenuManageDlc": "Gérer les DLC",
|
||||
@ -73,7 +81,7 @@
|
||||
"SettingsTabGeneralAdd": "Ajouter",
|
||||
"SettingsTabGeneralRemove": "Supprimer",
|
||||
"SettingsTabSystem": "Système",
|
||||
"SettingsTabSystemCore": "Core",
|
||||
"SettingsTabSystemCore": "Cœur",
|
||||
"SettingsTabSystemSystemRegion": "Région du système:",
|
||||
"SettingsTabSystemSystemRegionJapan": "Japon",
|
||||
"SettingsTabSystemSystemRegionUSA": "USA",
|
||||
@ -105,13 +113,13 @@
|
||||
"SettingsTabSystemEnableVsync": "Activer la VSync",
|
||||
"SettingsTabSystemEnablePptc": "Activer le PPTC (Profiled Persistent Translation Cache)",
|
||||
"SettingsTabSystemEnableFsIntegrityChecks": "Activer la vérification de l'intégrité du système de fichiers",
|
||||
"SettingsTabSystemAudioBackend": "Bibliothèque Audio:",
|
||||
"SettingsTabSystemAudioBackendDummy": "Dummy",
|
||||
"SettingsTabSystemAudioBackend": "Bibliothèque Audio :",
|
||||
"SettingsTabSystemAudioBackendDummy": "Factice",
|
||||
"SettingsTabSystemAudioBackendOpenAL": "OpenAL",
|
||||
"SettingsTabSystemAudioBackendSoundIO": "SoundIO",
|
||||
"SettingsTabSystemAudioBackendSDL2": "SDL2",
|
||||
"SettingsTabSystemHacks": "Hacks",
|
||||
"SettingsTabSystemHacksNote": " (Cela peut causer des instabilitées)",
|
||||
"SettingsTabSystemHacksNote": " (Cela peut causer des instabilités)",
|
||||
"SettingsTabSystemExpandDramSize": "Augmenter la taille de la DRAM à 6GiB",
|
||||
"SettingsTabSystemIgnoreMissingServices": "Ignorer les services manquant",
|
||||
"SettingsTabGraphics": "Graphique",
|
||||
@ -119,16 +127,16 @@
|
||||
"SettingsTabGraphicsEnableShaderCache": "Activer le cache des shaders",
|
||||
"SettingsTabGraphicsAnisotropicFiltering": "Filtrage anisotrope:",
|
||||
"SettingsTabGraphicsAnisotropicFilteringAuto": "Auto",
|
||||
"SettingsTabGraphicsAnisotropicFiltering2x": "2x",
|
||||
"SettingsTabGraphicsAnisotropicFiltering4x": "4x",
|
||||
"SettingsTabGraphicsAnisotropicFiltering8x": "8x",
|
||||
"SettingsTabGraphicsAnisotropicFiltering16x": "16x",
|
||||
"SettingsTabGraphicsAnisotropicFiltering2x": "x2",
|
||||
"SettingsTabGraphicsAnisotropicFiltering4x": "x4",
|
||||
"SettingsTabGraphicsAnisotropicFiltering8x": "x8",
|
||||
"SettingsTabGraphicsAnisotropicFiltering16x": "x16",
|
||||
"SettingsTabGraphicsResolutionScale": "Échelle de résolution:",
|
||||
"SettingsTabGraphicsResolutionScaleCustom": "Customisée (Non recommandée)",
|
||||
"SettingsTabGraphicsResolutionScaleNative": "Native (720p/1080p)",
|
||||
"SettingsTabGraphicsResolutionScale2x": "2x (1440p/2160p)",
|
||||
"SettingsTabGraphicsResolutionScale3x": "3x (2160p/3240p)",
|
||||
"SettingsTabGraphicsResolutionScale4x": "4x (2880p/4320p)",
|
||||
"SettingsTabGraphicsResolutionScaleNative": "Natif (720p/1080p)",
|
||||
"SettingsTabGraphicsResolutionScale2x": "x2 (1440p/2160p)",
|
||||
"SettingsTabGraphicsResolutionScale3x": "x3 (2160p/3240p)",
|
||||
"SettingsTabGraphicsResolutionScale4x": "x4 (2880p/4320p)",
|
||||
"SettingsTabGraphicsAspectRatio": "Format:",
|
||||
"SettingsTabGraphicsAspectRatio4x3": "4:3",
|
||||
"SettingsTabGraphicsAspectRatio16x9": "16:9",
|
||||
@ -138,7 +146,6 @@
|
||||
"SettingsTabGraphicsAspectRatioStretch": "Écran étiré",
|
||||
"SettingsTabGraphicsDeveloperOptions": "Options développeur",
|
||||
"SettingsTabGraphicsShaderDumpPath": "Chemin du dossier de dump des shaders:",
|
||||
"SettingsTabGraphicsFeatures": "Fonctionnalités & Améliorations",
|
||||
"SettingsTabLogging": "Journaux",
|
||||
"SettingsTabLoggingLogging": "Journaux",
|
||||
"SettingsTabLoggingEnableLoggingToFile": "Activer la sauvegarde des journaux vers un fichier",
|
||||
@ -146,10 +153,12 @@
|
||||
"SettingsTabLoggingEnableInfoLogs": "Activer les journaux d'informations",
|
||||
"SettingsTabLoggingEnableWarningLogs": "Activer les journaux d'avertissements",
|
||||
"SettingsTabLoggingEnableErrorLogs": "Activer les journaux d'erreurs",
|
||||
"SettingsTabLoggingEnableTraceLogs": "Activer journaux d'erreurs Trace",
|
||||
"SettingsTabLoggingEnableGuestLogs": "Activer les journaux du programme simulé",
|
||||
"SettingsTabLoggingEnableFsAccessLogs": "Activer les journaux des accès au système de fichiers",
|
||||
"SettingsTabLoggingFsGlobalAccessLogMode": "Niveau des journaux des accès au système de fichiers:",
|
||||
"SettingsTabLoggingDeveloperOptions": "Options développeur (ATTENTION: Cela peut réduire les performances)",
|
||||
"SettingsTabLoggingGraphicsBackendLogLevel": "Niveau du journal du backend graphique :",
|
||||
"SettingsTabLoggingGraphicsBackendLogLevelNone": "Aucun",
|
||||
"SettingsTabLoggingGraphicsBackendLogLevelError": "Erreur",
|
||||
"SettingsTabLoggingGraphicsBackendLogLevelPerformance": "Ralentissements",
|
||||
@ -219,11 +228,11 @@
|
||||
"ControllerSettingsRStickInvertXAxis": "Inverser l'axe X",
|
||||
"ControllerSettingsRStickInvertYAxis": "Inverser l'axe Y",
|
||||
"ControllerSettingsRStickDeadzone": "Zone morte:",
|
||||
"ControllerSettingsTriggers": "Gachettes",
|
||||
"ControllerSettingsTriggersLeft": "Gachettes Gauche",
|
||||
"ControllerSettingsTriggersRight": "Gachettes Droite",
|
||||
"ControllerSettingsTriggersButtonsLeft": "Boutons Gachettes Gauche",
|
||||
"ControllerSettingsTriggersButtonsRight": "Boutons Gachettes Droite",
|
||||
"ControllerSettingsTriggers": "Gachettes",
|
||||
"ControllerSettingsTriggerL": "L",
|
||||
"ControllerSettingsTriggerR": "R",
|
||||
"ControllerSettingsTriggerZL": "ZL",
|
||||
@ -237,7 +246,6 @@
|
||||
"ControllerSettingsMisc": "Divers",
|
||||
"ControllerSettingsTriggerThreshold": "Seuil de gachettes:",
|
||||
"ControllerSettingsMotion": "Mouvements",
|
||||
"ControllerSettingsConfigureGeneral": "Configurer",
|
||||
"ControllerSettingsMotionUseCemuhookCompatibleMotion": "Utiliser un capteur de mouvements CemuHook",
|
||||
"ControllerSettingsMotionControllerSlot": "Contrôleur ID:",
|
||||
"ControllerSettingsMotionMirrorInput": "Inverser les contrôles",
|
||||
@ -252,7 +260,7 @@
|
||||
"UserProfilesChangeProfileImage": "Changer l'image du profil",
|
||||
"UserProfilesAvailableUserProfiles": "Profils utilisateurs disponible:",
|
||||
"UserProfilesAddNewProfile": "Ajouter un nouveau profil",
|
||||
"UserProfilesDeleteSelectedProfile": "Supprimer le profil sélectionné",
|
||||
"UserProfilesDelete": "Supprimer",
|
||||
"UserProfilesClose": "Fermer",
|
||||
"ProfileImageSelectionTitle": "Sélection de l'image du profil",
|
||||
"ProfileImageSelectionHeader": "Choisir l'image du profil",
|
||||
@ -268,6 +276,339 @@
|
||||
"AvatarChoose": "Choisir",
|
||||
"AvatarSetBackgroundColor": "Choisir une couleur de fond",
|
||||
"AvatarClose": "Fermer",
|
||||
"ControllerMotionTitle": "Motion Control Settings",
|
||||
"ControllerRumbleTitle": "Rumble Settings"
|
||||
"ControllerSettingsLoadProfileToolTip": "Charger un profil",
|
||||
"ControllerSettingsAddProfileToolTip": "Ajouter un profil",
|
||||
"ControllerSettingsRemoveProfileToolTip": "Supprimer un profil",
|
||||
"ControllerSettingsSaveProfileToolTip": "Enregistrer un profil",
|
||||
"MenuBarFileToolsTakeScreenshot": "Prendre une Capture d'Écran",
|
||||
"MenuBarFileToolsHideUi": "Masquer l'interface utilisateur",
|
||||
"GameListContextMenuToggleFavorite": "Ajouter/Retirer des favoris",
|
||||
"GameListContextMenuToggleFavoriteToolTip": "Activer/désactiver le statut favori du jeu",
|
||||
"SettingsTabGeneralTheme": "Thème",
|
||||
"SettingsTabGeneralThemeCustomTheme": "Chemin du thème personnalisé",
|
||||
"SettingsTabGeneralThemeBaseStyle": "Style par défaut",
|
||||
"SettingsTabGeneralThemeBaseStyleDark": "Sombre",
|
||||
"SettingsTabGeneralThemeBaseStyleLight": "Lumière",
|
||||
"SettingsTabGeneralThemeEnableCustomTheme": "Activer un Thème Personnalisé",
|
||||
"ButtonBrowse": "Parcourir",
|
||||
"ControllerSettingsConfigureGeneral": "Configurer",
|
||||
"ControllerSettingsRumble": "Vibreur",
|
||||
"ControllerSettingsRumbleStrongMultiplier": "Multiplicateur de vibrations fortes",
|
||||
"ControllerSettingsRumbleWeakMultiplier": "Multiplicateur de vibrations faibles",
|
||||
"DialogMessageSaveNotAvailableMessage": "Il n'y a aucune sauvegarde pour {0} [{1:x16}]",
|
||||
"DialogMessageSaveNotAvailableCreateSaveMessage": "Voulez-vous créer une sauvegarde pour ce jeu ?",
|
||||
"DialogConfirmationTitle": "Ryujinx - Confirmation",
|
||||
"DialogUpdaterTitle": "Ryujinx - Mise à Jour",
|
||||
"DialogErrorTitle": "Ryujinx - Erreur",
|
||||
"DialogWarningTitle": "Ryujinx - Avertissement",
|
||||
"DialogExitTitle": "Ryujinx - Quitter",
|
||||
"DialogErrorMessage": "Ryujinx a rencontré une erreur",
|
||||
"DialogExitMessage": "Êtes-vous sûr de vouloir fermer Ryujinx ?",
|
||||
"DialogExitSubMessage": "Toute progression non sauvegardée sera perdue.",
|
||||
"DialogMessageCreateSaveErrorMessage": "Une erreur s'est produite lors de la création de la sauvegarde spécifiée : {0}",
|
||||
"DialogMessageFindSaveErrorMessage": "Une erreur s'est produite lors de la recherche de la sauvegarde spécifiée : {0}",
|
||||
"FolderDialogExtractTitle": "Choisissez le dossier dans lequel extraire",
|
||||
"DialogNcaExtractionMessage": "Extraction de la section {0} depuis {1}...",
|
||||
"DialogNcaExtractionTitle": "Ryujinx - Extracteur de la section NCA",
|
||||
"DialogNcaExtractionMainNcaNotFoundErrorMessage": "Échec de l'extraction. Le NCA principal n'était pas présent dans le fichier sélectionné.",
|
||||
"DialogNcaExtractionCheckLogErrorMessage": "Échec de l'extraction. Lisez le fichier journal pour plus d'informations.",
|
||||
"DialogNcaExtractionSuccessMessage": "Extraction terminée avec succès.",
|
||||
"DialogUpdaterConvertFailedMessage": "Échec de la conversion de la version actuelle de Ryujinx.",
|
||||
"DialogUpdaterCancelUpdateMessage": "Annuler la mise à jour!",
|
||||
"DialogUpdaterAlreadyOnLatestVersionMessage": "Vous utilisez déjà la version la plus mise à jour de Ryujinx!",
|
||||
"DialogUpdaterFailedToGetVersionMessage": "Une erreur s'est produite lors de la tentative d'obtention des informations de publication de la version GitHub. Cela peut survenir lorsqu'une nouvelle version est en cours de compilation par GitHub Actions. Réessayez dans quelques minutes.",
|
||||
"DialogUpdaterConvertFailedGithubMessage": "Impossible de convertir la version reçue de Ryujinx depuis Github Release.",
|
||||
"DialogUpdaterDownloadingMessage": "Téléchargement de la mise à jour...",
|
||||
"DialogUpdaterExtractionMessage": "Extraction de la mise à jour…",
|
||||
"DialogUpdaterRenamingMessage": "Renommage de la mise à jour...",
|
||||
"DialogUpdaterAddingFilesMessage": "Ajout d'une nouvelle mise à jour...",
|
||||
"DialogUpdaterCompleteMessage": "Mise à jour terminée !",
|
||||
"DialogUpdaterRestartMessage": "Voulez-vous redémarrer Ryujinx maintenant ?",
|
||||
"DialogUpdaterArchNotSupportedMessage": "Vous n'utilisez pas d'architecture système prise en charge !",
|
||||
"DialogUpdaterArchNotSupportedSubMessage": "(Seuls les systèmes x64 sont pris en charge !)",
|
||||
"DialogUpdaterNoInternetMessage": "Vous n'êtes pas connecté à Internet !",
|
||||
"DialogUpdaterNoInternetSubMessage": "Veuillez vérifier que vous avez une connexion Internet fonctionnelle!",
|
||||
"DialogUpdaterDirtyBuildMessage": "Vous ne pouvez pas mettre à jour une version Dirty de Ryujinx!",
|
||||
"DialogUpdaterDirtyBuildSubMessage": "Veuillez télécharger Ryujinx sur https://ryujinx.org/ si vous recherchez une version prise en charge.",
|
||||
"DialogRestartRequiredMessage": "Redémarrage Requis",
|
||||
"DialogThemeRestartMessage": "Le thème a été enregistré. Un redémarrage est requis pour appliquer le thème.",
|
||||
"DialogThemeRestartSubMessage": "Voulez-vous redémarrer",
|
||||
"DialogFirmwareInstallEmbeddedMessage": "Voulez-vous installer le firmware intégré dans ce jeu ? (Firmware {0})",
|
||||
"DialogFirmwareInstallEmbeddedSuccessMessage": "Aucun firmware installé n'a été trouvé mais Ryujinx a pu installer le firmware {0} à partir du jeu fourni.\\nL'émulateur va maintenant démarrer.",
|
||||
"DialogFirmwareNoFirmwareInstalledMessage": "Aucun Firmware installé",
|
||||
"DialogFirmwareInstalledMessage": "Le firmware {0} a été installé",
|
||||
"DialogOpenSettingsWindowLabel": "Ouvrir la fenêtre de configuration",
|
||||
"DialogControllerAppletTitle": "Controller Applet",
|
||||
"DialogMessageDialogErrorExceptionMessage": "Erreur lors de l'affichage de la boîte de dialogue : {0}",
|
||||
"DialogSoftwareKeyboardErrorExceptionMessage": "Erreur lors de l'affichage du clavier logiciel: {0}",
|
||||
"DialogErrorAppletErrorExceptionMessage": "Erreur lors de l'affichage de la boîte de dialogue ErrorApplet: {0}",
|
||||
"DialogUserErrorDialogMessage": "{0}: {1}",
|
||||
"DialogUserErrorDialogInfoMessage": "\nPour plus d'informations sur la manière de corriger cette erreur, suivez notre Guide d'Installation.",
|
||||
"DialogUserErrorDialogTitle": "Erreur Ryujinx ({0})",
|
||||
"DialogAmiiboApiTitle": "Amiibo API",
|
||||
"DialogAmiiboApiFailFetchMessage": "Une erreur est survenue lors de la récupération des informations de l'API.",
|
||||
"DialogAmiiboApiConnectErrorMessage": "Impossible de se connecter au serveur API Amiibo. Le service est peut-être hors service ou vous devriez peut-être vérifier que votre connexion internet est connectée.",
|
||||
"DialogProfileInvalidProfileErrorMessage": "Le profil {0} est incompatible avec le système de configuration de manette actuel.",
|
||||
"DialogProfileDefaultProfileOverwriteErrorMessage": "Le profil par défaut ne peut pas être écrasé",
|
||||
"DialogProfileDeleteProfileTitle": "Supprimer le profil",
|
||||
"DialogProfileDeleteProfileMessage": "Cette action est irréversible, êtes-vous sûr de vouloir continuer ?",
|
||||
"DialogWarning": "Avertissement",
|
||||
"DialogPPTCDeletionMessage": "Vous êtes sur le point de mettre en file d'attente une reconstruction PPTC au prochain démarrage de :\n\n{0}\n\nÊtes-vous sûr de vouloir continuer ?",
|
||||
"DialogPPTCDeletionErrorMessage": "Erreur lors de la purge du cache PPTC à {0}: {1}",
|
||||
"DialogShaderDeletionMessage": "Vous êtes sur le point de supprimer le cache du Shader pour :\n\n{0}\n\nÊtes-vous sûr de vouloir continuer ?",
|
||||
"DialogShaderDeletionErrorMessage": "Erreur lors de la purge du cache du Shader à {0}: {1}",
|
||||
"DialogRyujinxErrorMessage": "Ryujinx a rencontré une erreur",
|
||||
"DialogInvalidTitleIdErrorMessage": "Erreur d'UI : le jeu sélectionné n'a pas d'ID de titre valide",
|
||||
"DialogFirmwareInstallerFirmwareNotFoundErrorMessage": "Un firmware valide n'a pas été trouvé dans {0}.",
|
||||
"DialogFirmwareInstallerFirmwareInstallTitle": "Installer le Firmware {0}",
|
||||
"DialogFirmwareInstallerFirmwareInstallMessage": "La version {0} du système sera installée.",
|
||||
"DialogFirmwareInstallerFirmwareInstallSubMessage": "\n\nCela remplacera la version actuelle du système {0}.",
|
||||
"DialogFirmwareInstallerFirmwareInstallConfirmMessage": "\n\nVoulez-vous continuer ?",
|
||||
"DialogFirmwareInstallerFirmwareInstallWaitMessage": "Installation du firmware...",
|
||||
"DialogFirmwareInstallerFirmwareInstallSuccessMessage": "Version du système {0} installée avec succès.",
|
||||
"DialogUserProfileDeletionWarningMessage": "Il n'y aurait aucun autre profil à ouvrir si le profil sélectionné est supprimé",
|
||||
"DialogUserProfileDeletionConfirmMessage": "Voulez-vous supprimer le profil sélectionné ?",
|
||||
"DialogControllerSettingsModifiedConfirmMessage": "Les paramètres actuels du contrôleur ont été mis à jour.",
|
||||
"DialogControllerSettingsModifiedConfirmSubMessage": "Voulez-vous sauvegarder?",
|
||||
"DialogLoadNcaErrorMessage": "{0}. Fichier erroné : {1}",
|
||||
"DialogDlcNoDlcErrorMessage": "Le fichier spécifié ne contient pas de DLC pour le titre sélectionné !",
|
||||
"DialogPerformanceCheckLoggingEnabledMessage": "Vous avez activé la journalisation des traces, conçue pour être utilisée uniquement par les développeurs.",
|
||||
"DialogPerformanceCheckLoggingEnabledConfirmMessage": "Pour des performances optimales, il est recommandé de désactiver la journalisation des traces. Souhaitez-vous désactiver la journalisation des traces maintenant ?",
|
||||
"DialogPerformanceCheckShaderDumpEnabledMessage": "Vous avez activé l'extraction des shaders, qui est conçu pour être utilisé par les développeurs uniquement.",
|
||||
"DialogPerformanceCheckShaderDumpEnabledConfirmMessage": "Pour des performances optimales, il est recommandé de désactiver l'extraction des shaders. Souhaitez-vous désactiver l'extraction des shaders maintenant ?",
|
||||
"DialogLoadAppGameAlreadyLoadedMessage": "Un jeu a déjà été chargé",
|
||||
"DialogLoadAppGameAlreadyLoadedSubMessage": "Veuillez arrêter l'émulation ou fermer l'émulateur avant de lancer un autre jeu.",
|
||||
"DialogUpdateAddUpdateErrorMessage": "Le fichier spécifié ne contient pas de mise à jour pour le titre sélectionné !",
|
||||
"DialogSettingsBackendThreadingWarningTitle": "Avertissement - Backend Threading ",
|
||||
"DialogSettingsBackendThreadingWarningMessage": "Ryujinx doit être redémarré après avoir changé cette option pour qu'elle s'applique complètement. Selon votre plate-forme, vous devrez peut-être désactiver manuellement le multithreading de votre pilote lorsque vous utilisez Ryujinx.",
|
||||
"SettingsTabGraphicsFeaturesOptions": "Fonctionnalités",
|
||||
"SettingsTabGraphicsBackendMultithreading": "Interface graphique multithread",
|
||||
"CommonAuto": "Auto",
|
||||
"CommonOff": "Désactivé",
|
||||
"CommonOn": "Activé",
|
||||
"InputDialogYes": "Oui",
|
||||
"InputDialogNo": "Non",
|
||||
"DialogProfileInvalidProfileNameErrorMessage": "Le nom du fichier contient des caractères invalides. Veuillez réessayer.",
|
||||
"MenuBarOptionsPauseEmulation": "Suspendre",
|
||||
"MenuBarOptionsResumeEmulation": "Reprendre",
|
||||
"AboutUrlTooltipMessage": "Cliquez pour ouvrir le site de Ryujinx dans votre navigateur par défaut.",
|
||||
"AboutDisclaimerMessage": "Ryujinx n'est pas affilié à Nintendo™,\nou à aucun de ses partenaires, de quelque manière que ce soit.",
|
||||
"AboutAmiiboDisclaimerMessage": "AmiiboAPI (www.amiiboapi.com) est utilisé\ndans notre émulation Amiibo.",
|
||||
"AboutPatreonUrlTooltipMessage": "Cliquez pour ouvrir la page Patreon de Ryujinx dans votre navigateur par défaut.",
|
||||
"AboutGithubUrlTooltipMessage": "Cliquez pour ouvrir la page GitHub de Ryujinx dans votre navigateur par défaut.",
|
||||
"AboutDiscordUrlTooltipMessage": "Cliquez pour ouvrir une invitation au serveur Discord de Ryujinx dans votre navigateur par défaut.",
|
||||
"AboutTwitterUrlTooltipMessage": "Cliquez pour ouvrir la page Twitter de Ryujinx dans votre navigateur par défaut.",
|
||||
"AboutRyujinxAboutTitle": "Á propos:",
|
||||
"AboutRyujinxAboutContent": "Ryujinx est un émulateur pour la Nintendo Switch™.\nMerci de nous soutenir sur Patreon.\nObtenez toutes les dernières actualités sur notre Twitter ou notre Discord.\nLes développeurs intéressés à contribuer peuvent en savoir plus sur notre GitHub ou notre Discord.",
|
||||
"AboutRyujinxMaintainersTitle": "Maintenu par :",
|
||||
"AboutRyujinxMaintainersContentTooltipMessage": "Cliquez pour ouvrir la page Contributeurs dans votre navigateur par défaut.",
|
||||
"AboutRyujinxSupprtersTitle": "Supporté sur Patreon par :",
|
||||
"AmiiboSeriesLabel": "Séries Amiibo",
|
||||
"AmiiboCharacterLabel": "Personnage",
|
||||
"AmiiboScanButtonLabel": "Scanner",
|
||||
"AmiiboOptionsShowAllLabel": "Afficher tous les Amiibo",
|
||||
"AmiiboOptionsUsRandomTagLabel": "Hack : Utiliser un tag Uuid aléatoire",
|
||||
"DlcManagerTableHeadingEnabledLabel": "Activé",
|
||||
"DlcManagerTableHeadingTitleIdLabel": "ID du titre",
|
||||
"DlcManagerTableHeadingContainerPathLabel": "Chemin du conteneur",
|
||||
"DlcManagerTableHeadingFullPathLabel": "Chemin complet",
|
||||
"DlcManagerRemoveAllButton": "Tout supprimer",
|
||||
"DlcManagerEnableAllButton": "Activer Tout",
|
||||
"DlcManagerDisableAllButton": "Désactiver Tout",
|
||||
"MenuBarOptionsChangeLanguage": "Changer la Langue",
|
||||
"CommonSort": "Trier",
|
||||
"CommonShowNames": "Afficher les noms",
|
||||
"CommonFavorite": "Favoris",
|
||||
"OrderAscending": "Croissant",
|
||||
"OrderDescending": "Décroissant",
|
||||
"SettingsTabGraphicsFeatures": "Fonctionnalités & Améliorations",
|
||||
"ErrorWindowTitle": "Fenêtre d'erreur",
|
||||
"ToggleDiscordTooltip": "Choisissez d'afficher ou non Ryujinx sur votre activité « en cours de jeu » Discord",
|
||||
"AddGameDirBoxTooltip": "Entrez un répertoire de jeux à ajouter à la liste",
|
||||
"AddGameDirTooltip": "Ajouter un répertoire de jeux à la liste",
|
||||
"RemoveGameDirTooltip": "Supprimer le dossier sélectionné",
|
||||
"CustomThemeCheckTooltip": "Use a custom Avalonia theme for the GUI to change the appearance of the emulator menus",
|
||||
"CustomThemePathTooltip": "Chemin vers le thème personnalisé de l'interface utilisateur",
|
||||
"CustomThemeBrowseTooltip": "Parcourir vers un thème personnalisé pour l'interface utilisateur",
|
||||
"DockModeToggleTooltip": "Le mode station d'accueil permet à la console émulée de se comporter comme une Nintendo Switch en mode station d'accueil, ce qui améliore la fidélité graphique dans la plupart des jeux. Inversement, la désactivation de cette option rendra la console émulée comme une console Nintendo Switch portable, réduisant la qualité graphique.\n\nConfigurer les controles du joueur 1 si vous prévoyez d'utiliser le mode station d'accueil; configurez les commandes portable si vous prévoyez d'utiliser le mode portable.\n\nLaissez ACTIVER si vous n'êtes pas sûr.",
|
||||
"DirectKeyboardTooltip": "Direct keyboard access (HID) support. Provides games access to your keyboard as a text entry device.",
|
||||
"DirectMouseTooltip": "Direct mouse access (HID) support. Provides games access to your mouse as a pointing device.",
|
||||
"RegionTooltip": "Changer la région du système",
|
||||
"LanguageTooltip": "Changer la langue du système",
|
||||
"TimezoneTooltip": "Changer le fuseau horaire du système",
|
||||
"TimeTooltip": "Changer l'heure du système",
|
||||
"VSyncToggleTooltip": "Emulated console's Vertical Sync. Essentially a frame-limiter for the majority of games; disabling it may cause games to run at higher speed or make loading screens take longer or get stuck.\n\nCan be toggled in-game with a hotkey of your preference. We recommend doing this if you plan on disabling it.\n\nLeave ON if unsure.",
|
||||
"PptcToggleTooltip": "Saves translated JIT functions so that they do not need to be translated every time the game loads.\n\nReduces stuttering and significantly speeds up boot times after the first boot of a game.\n\nLeave ON if unsure.",
|
||||
"FsIntegrityToggleTooltip": "Checks for corrupt files when booting a game, and if corrupt files are detected, displays a hash error in the log.\n\nHas no impact on performance and is meant to help troubleshooting.\n\nLeave ON if unsure.",
|
||||
"AudioBackendTooltip": "Changes the backend used to render audio.\n\nSDL2 is the preferred one, while OpenAL and SoundIO are used as fallbacks. Dummy will have no sound.\n\nSet to SDL2 if unsure.",
|
||||
"MemoryManagerTooltip": "Change how guest memory is mapped and accessed. Greatly affects emulated CPU performance.\n\nSet to HOST UNCHECKED if unsure.",
|
||||
"MemoryManagerSoftwareTooltip": "Use a software page table for address translation. Highest accuracy but slowest performance.",
|
||||
"MemoryManagerHostTooltip": "Directly map memory in the host address space. Much faster JIT compilation and execution.",
|
||||
"MemoryManagerUnsafeTooltip": "Directly map memory, but do not mask the address within the guest address space before access. Faster, but at the cost of safety. The guest application can access memory from anywhere in Ryujinx, so only run programs you trust with this mode.",
|
||||
"DRamTooltip": "Utilizes an alternative MemoryMode layout to mimic a Switch development model.\n\nThis is only useful for higher-resolution texture packs or 4k resolution mods. Does NOT improve performance.\n\nLeave OFF if unsure.",
|
||||
"IgnoreMissingServicesTooltip": "Ignores unimplemented Horizon OS services. This may help in bypassing crashes when booting certain games.\n\nLeave OFF if unsure.",
|
||||
"GraphicsBackendThreadingTooltip": "Executes graphics backend commands on a second thread.\n\nSpeeds up shader compilation, reduces stuttering, and improves performance on GPU drivers without multithreading support of their own. Slightly better performance on drivers with multithreading.\n\nSet to AUTO if unsure.",
|
||||
"GalThreadingTooltip": "Executes graphics backend commands on a second thread.\n\nSpeeds up shader compilation, reduces stuttering, and improves performance on GPU drivers without multithreading support of their own. Slightly better performance on drivers with multithreading.\n\nSet to AUTO if unsure.",
|
||||
"ShaderCacheToggleTooltip": "Saves a disk shader cache which reduces stuttering in subsequent runs.\n\nLeave ON if unsure.",
|
||||
"ResolutionScaleTooltip": "Resolution Scale applied to applicable render targets",
|
||||
"ResolutionScaleEntryTooltip": "Floating point resolution scale, such as 1.5. Non-integral scales are more likely to cause issues or crash.",
|
||||
"AnisotropyTooltip": "Level of Anisotropic Filtering (set to Auto to use the value requested by the game)",
|
||||
"AspectRatioTooltip": "Ratio d'aspect appliqué à la fenêtre de rendu",
|
||||
"ShaderDumpPathTooltip": "Chemin de copie des Shaders Graphiques",
|
||||
"FileLogTooltip": "Sauver le journal de la console dans un fichier journal sur le disque. Cela n'affecte pas les performances.",
|
||||
"StubLogTooltip": "Prints stub log messages in the console. Does not affect performance.",
|
||||
"InfoLogTooltip": "Prints info log messages in the console. Does not affect performance.",
|
||||
"WarnLogTooltip": "Prints warning log messages in the console. Does not affect performance.",
|
||||
"ErrorLogTooltip": "Prints error log messages in the console. Does not affect performance.",
|
||||
"TraceLogTooltip": "Prints trace log messages in the console. Does not affect performance.",
|
||||
"GuestLogTooltip": "Prints guest log messages in the console. Does not affect performance.",
|
||||
"FileAccessLogTooltip": "Prints file access log messages in the console.",
|
||||
"FSAccessLogModeTooltip": "Enables FS access log output to the console. Possible modes are 0-3",
|
||||
"DeveloperOptionTooltip": "Utiliser avec précaution",
|
||||
"OpenGlLogLevel": "Nécessite l'activation des niveaux de journalisation appropriés",
|
||||
"DebugLogTooltip": "Prints debug log messages in the console.\n\nOnly use this if specifically instructed by a staff member, as it will make logs difficult to read and worsen emulator performance.",
|
||||
"LoadApplicationFileTooltip": "Ouvrir un explorateur de fichiers pour choisir un fichier compatible Switch à charger",
|
||||
"LoadApplicationFolderTooltip": "Ouvrir un explorateur de fichiers pour choisir une application Switch compatible et décompressée à charger",
|
||||
"OpenRyujinxFolderTooltip": "Ouvrir le dossier du système de fichiers Ryujinx",
|
||||
"OpenRyujinxLogsTooltip": "Ouvre le dossier dans lequel les journaux sont écrits",
|
||||
"ExitTooltip": "Quitter Ryujinx",
|
||||
"OpenSettingsTooltip": "Ouvrir la fenêtre de configuration",
|
||||
"OpenProfileManagerTooltip": "Ouvrir la fenêtre du gestionnaire de profils d'utilisateurs",
|
||||
"StopEmulationTooltip": "Arrêter l'émulation du jeu en cours et revenir à la sélection des jeux",
|
||||
"CheckUpdatesTooltip": "Vérifier les mises à jour de Ryujinx",
|
||||
"OpenAboutTooltip": "Ouvrir la fenêtre À Propos",
|
||||
"GridSize": "Taille de la grille",
|
||||
"GridSizeTooltip": "Modifier la taille des éléments de la grille",
|
||||
"SettingsTabSystemSystemLanguageBrazilianPortuguese": "Portugais brésilien",
|
||||
"AboutRyujinxContributorsButtonHeader": "Voir tous les contributeurs",
|
||||
"SettingsTabSystemAudioVolume": "Volume :",
|
||||
"AudioVolumeTooltip": "Modifier le volume audio",
|
||||
"SettingsTabSystemEnableInternetAccess": "Accès Internet Invité/Mode LAN",
|
||||
"EnableInternetAccessTooltip": "Permet à l'application émulée de se connecter à Internet.\n\nLes jeux avec un mode LAN peuvent se connecter les uns aux autres lorsque cette option est cochée et que les systèmes sont connectés au même point d'accès. Cela inclut également les vrais consoles.\n\nCette option n'autorise PAS la connexion aux serveurs Nintendo. Elle peut faire planter certains jeux qui essaient de se connecter à l'Internet.\n\nLaissez DÉSACTIVÉ si vous n'êtes pas sûr.",
|
||||
"GameListContextMenuManageCheatToolTip": "Gérer la triche",
|
||||
"GameListContextMenuManageCheat": "Gérer la triche",
|
||||
"ControllerSettingsStickRange": "Intervalle:",
|
||||
"DialogStopEmulationTitle": "Ryujinx - Arrêt de l'émulation",
|
||||
"DialogStopEmulationMessage": "Êtes-vous sûr de vouloir arrêter l'émulation ?",
|
||||
"SettingsTabCpu": "CPU",
|
||||
"SettingsTabAudio": "Audio",
|
||||
"SettingsTabNetwork": "Réseau",
|
||||
"SettingsTabNetworkConnection": "Connexion réseau",
|
||||
"SettingsTabCpuCache": "Cache CPU",
|
||||
"SettingsTabCpuMemory": "Mémoire CPU",
|
||||
"DialogUpdaterFlatpakNotSupportedMessage": "Merci de mettre à jour Ryujinx via FlatHub.",
|
||||
"UpdaterDisabledWarningTitle": "Mise à jour désactivée !",
|
||||
"GameListContextMenuOpenSdModsDirectory": "Ouvrir le dossier Mods d'Atmosphère",
|
||||
"GameListContextMenuOpenSdModsDirectoryToolTip": "Ouvre le répertoire alternatif de carte SD Atmosphère qui contient les Mods d'Application. Utile pour les mods qui sont conçu pour le vrai matériel.",
|
||||
"ControllerSettingsRotate90": "Rotation 90° horaire",
|
||||
"IconSize": "Taille d'icône",
|
||||
"IconSizeTooltip": "Changer la taille des icônes de jeu",
|
||||
"MenuBarOptionsShowConsole": "Afficher la console",
|
||||
"ShaderCachePurgeError": "Erreur lors de la purge du cache du Shader à {0}: {1}",
|
||||
"UserErrorNoKeys": "Clés introuvables",
|
||||
"UserErrorNoFirmware": "Firmware introuvable",
|
||||
"UserErrorFirmwareParsingFailed": "Erreur d'analyse du firmware",
|
||||
"UserErrorApplicationNotFound": " Application introuvable",
|
||||
"UserErrorUnknown": "Erreur inconnue",
|
||||
"UserErrorUndefined": "Erreur non définie",
|
||||
"UserErrorNoKeysDescription": "Ryujinx n'a pas trouvé votre fichier 'prod.keys'",
|
||||
"UserErrorNoFirmwareDescription": "Ryujinx n'a pas trouvé de firmwares installés",
|
||||
"UserErrorFirmwareParsingFailedDescription": "Ryujinx n'a pas pu analyser le firmware fourni. Cela est généralement dû à des clés obsolètes.",
|
||||
"UserErrorApplicationNotFoundDescription": "Ryujinx n'a pas pu trouver une application valide dans le chemin indiqué.",
|
||||
"UserErrorUnknownDescription": "Une erreur inconnue est survenue!",
|
||||
"UserErrorUndefinedDescription": "Une erreur inconnue est survenue ! Cela ne devrait pas se produire, merci de contacter un développeur !",
|
||||
"OpenSetupGuideMessage": "Ouvrir le guide d'installation",
|
||||
"NoUpdate": "Aucune mise à jour",
|
||||
"TitleUpdateVersionLabel": "Version {0} - {1}",
|
||||
"RyujinxInfo": "Ryujinx - Info",
|
||||
"RyujinxConfirm": "Ryujinx - Confirmation",
|
||||
"FileDialogAllTypes": "Tous les types",
|
||||
"Never": "Jamais",
|
||||
"SwkbdMinCharacters": "Doit comporter au moins {0} caractères",
|
||||
"SwkbdMinRangeCharacters": "Doit contenir {0}-{1} caractères en longueur",
|
||||
"SoftwareKeyboard": "Clavier logiciel",
|
||||
"DialogControllerAppletMessagePlayerRange": "L'application demande {0} joueur(s) avec :\n\nTYPES : {1}\n\nJOUEURS : {2}\n\n{3}Merci d'ouvrir les Paramètres et de reconfigurer les Périphériques maintenant ou appuyez sur Fermer.",
|
||||
"DialogControllerAppletMessage": "L'application demande exactement {0} joueur(s) avec :\n\nTYPES : {1}\n\nJOUEURS : {2}\n\n{3}Merci d'ouvrir les Paramètres et de reconfigurer les Périphériques maintenant ou appuyez sur Fermer.",
|
||||
"DialogControllerAppletDockModeSet": "Mode station d'accueil défini. Le portable est également invalide.\n\n",
|
||||
"UpdaterRenaming": "Renommage des anciens fichiers...",
|
||||
"UpdaterRenameFailed": "Impossible de renommer le fichier : {0}",
|
||||
"UpdaterAddingFiles": "Ajout des nouveaux fichiers...",
|
||||
"UpdaterExtracting": "Extraction de la mise à jour…",
|
||||
"UpdaterDownloading": "Téléchargement de la mise à jour...",
|
||||
"Game": "Jeu",
|
||||
"Docked": "Attaché",
|
||||
"Handheld": "Portable",
|
||||
"ConnectionError": "Erreur de connexion.",
|
||||
"AboutPageDeveloperListMore": "{0} et plus...",
|
||||
"ApiError": "Erreur API.",
|
||||
"LoadingHeading": "Chargement {0}",
|
||||
"CompilingPPTC": "Compilation PTC",
|
||||
"CompilingShaders": "Compilation des Shaders",
|
||||
"AllKeyboards": "Tous les claviers",
|
||||
"OpenFileDialogTitle": "Sélectionnez un fichier supporté à ouvrir",
|
||||
"OpenFolderDialogTitle": "Sélectionnez un dossier avec un jeu décompressé",
|
||||
"AllSupportedFormats": "Tous les formats supportés",
|
||||
"RyujinxUpdater": "Mise à jour de Ryujinx",
|
||||
"SettingsTabHotkeys": "Raccourcis clavier",
|
||||
"SettingsTabHotkeysHotkeys": "Raccourcis clavier",
|
||||
"SettingsTabHotkeysToggleVsyncHotkey": "Activer/désactiver la VSync :",
|
||||
"SettingsTabHotkeysScreenshotHotkey": "Captures d'écran :",
|
||||
"SettingsTabHotkeysShowUiHotkey": "Afficher UI :",
|
||||
"SettingsTabHotkeysPauseHotkey": "Suspendre :",
|
||||
"SettingsTabHotkeysToggleMuteHotkey": "Muet : ",
|
||||
"ControllerMotionTitle": "Réglages du contrôle par mouvement",
|
||||
"ControllerRumbleTitle": "Paramètres de Vibration",
|
||||
"SettingsSelectThemeFileDialogTitle": "Sélectionnez un Fichier de Thème",
|
||||
"SettingsXamlThemeFile": "Fichier thème Xaml",
|
||||
"AvatarWindowTitle": "Gérer les Comptes - Avatar",
|
||||
"Amiibo": "Amiibo",
|
||||
"Unknown": "Inconnu",
|
||||
"Usage": "Utilisation",
|
||||
"Writable": "Ecriture possible",
|
||||
"SelectDlcDialogTitle": "Sélectionner les fichiers DLC",
|
||||
"SelectUpdateDialogTitle": "Sélectionner les fichiers de mise à jour",
|
||||
"UserProfileWindowTitle": "Gestionnaire de profils utilisateur",
|
||||
"CheatWindowTitle": "Gestionnaire de triches",
|
||||
"DlcWindowTitle": "Gestionnaire de contenus téléchargeables",
|
||||
"UpdateWindowTitle": "Gestionnaire de mises à jour",
|
||||
"CheatWindowHeading": "Cheats disponibles pour {0} [{1}]",
|
||||
"DlcWindowHeading": "{0} Contenu(s) téléchargeable(s) disponible pour {1} ({2})",
|
||||
"UserProfilesEditProfile": "Éditer la sélection",
|
||||
"Cancel": "Annuler",
|
||||
"Save": "Enregistrer",
|
||||
"Discard": "Abandonner",
|
||||
"UserProfilesSetProfileImage": "Modifier l'image du profil",
|
||||
"UserProfileEmptyNameError": "Le nom est requis",
|
||||
"UserProfileNoImageError": "L'image du profil doit être définie",
|
||||
"GameUpdateWindowHeading": "{0} mise(s) à jour disponible pour {1} ({2})",
|
||||
"SettingsTabHotkeysResScaleUpHotkey": "Augmenter la résolution:",
|
||||
"SettingsTabHotkeysResScaleDownHotkey": "Diminuer la résolution :",
|
||||
"UserProfilesName": "Nom :",
|
||||
"UserProfilesUserId": "Identifiant de l'utilisateur :",
|
||||
"SettingsTabGraphicsBackend": "API de Rendu",
|
||||
"SettingsTabGraphicsBackendTooltip": "Interface Graphique à utiliser",
|
||||
"SettingsEnableTextureRecompression": "Activer la recompression des textures",
|
||||
"SettingsEnableTextureRecompressionTooltip": "Compresse certaines textures afin de réduire l'utilisation de la VRAM.\n\nRecommandé pour une utilisation avec des GPU qui ont moins de 4 Go de VRAM.\n\nLaissez DÉSACTIVÉ si vous n'êtes pas sûr.",
|
||||
"SettingsTabGraphicsPreferredGpu": "GPU préféré",
|
||||
"SettingsTabGraphicsPreferredGpuTooltip": "Sélectionnez la carte graphique qui sera utilisée avec l'interface graphique Vulkan.\n\nCela ne change pas le GPU qu'OpenGL utilisera.\n\nChoisissez le GPU noté \"dGPU\" si vous n'êtes pas sûr. S'il n'y en a pas, ne pas modifier.",
|
||||
"SettingsAppRequiredRestartMessage": "Redémarrage de Ryujinx requis",
|
||||
"SettingsGpuBackendRestartMessage": "Les paramètres de l'interface graphique ou du GPU ont été modifiés. Cela nécessitera un redémarrage pour être appliqué",
|
||||
"SettingsGpuBackendRestartSubMessage": "\n\nVoulez-vous redémarrer maintenant?",
|
||||
"RyujinxUpdaterMessage": "Voulez-vous mettre à jour Ryujinx vers la dernière version ?",
|
||||
"SettingsTabHotkeysVolumeUpHotkey": "Augmenter le volume :",
|
||||
"SettingsTabHotkeysVolumeDownHotkey": "Diminuer le volume :",
|
||||
"SettingsEnableMacroHLE": "Activer les macros HLE",
|
||||
"SettingsEnableMacroHLETooltip": "Émulation de haut niveau du code de Macro GPU.\n\nAméliore les performances, mais peut causer des bugs graphiques dans certains jeux.\n\nLaissez ACTIVER si vous n'êtes pas sûr.",
|
||||
"VolumeShort": "Vol",
|
||||
"UserProfilesManageSaves": "Gérer les sauvegardes",
|
||||
"DeleteUserSave": "Voulez-vous supprimer la sauvegarde de l'utilisateur pour ce jeu?",
|
||||
"IrreversibleActionNote": "Cette action n'est pas réversible.",
|
||||
"SaveManagerHeading": "Gérer les sauvegardes pour {0}",
|
||||
"SaveManagerTitle": "Gestionnaire de sauvegarde",
|
||||
"Name": "Nom ",
|
||||
"Size": "Taille",
|
||||
"Search": "Rechercher",
|
||||
"UserProfilesRecoverLostAccounts": "Récupérer les comptes perdus",
|
||||
"Recover": "Récupérer",
|
||||
"UserProfilesRecoverHeading": "Des sauvegardes ont été trouvées pour les comptes suivants"
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user