mirror of
https://git.ryujinx.app/projects/Kenji-NX.git
synced 2026-09-27 18:10:04 +02:00
Compare commits
325
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
280c427c55 | ||
|
|
25b4892981 | ||
|
|
d16d67f7c4 | ||
|
|
e7cb0632c5 | ||
|
|
4ea8c0b280 | ||
|
|
aef309800c | ||
|
|
a008cd20f1 | ||
|
|
ec6ce46357 | ||
|
|
a7a3a17b48 | ||
|
|
94cafdd1f9 | ||
|
|
1b57022694 | ||
|
|
2bb07a4364 | ||
|
|
5e67569a6e | ||
|
|
97f0336aa2 | ||
|
|
53d32a761e | ||
|
|
02d8eeb18f | ||
|
|
54e2f79c16 | ||
|
|
77277442a9 | ||
|
|
b707c73f83 | ||
|
|
235fb5f8c2 | ||
|
|
c2cbd53235 | ||
|
|
4f3c3a7b5d | ||
|
|
2dc1894e1e | ||
|
|
db4799e7ab | ||
|
|
06f049b874 | ||
|
|
58f9b6106f | ||
|
|
5422aa35b9 | ||
|
|
8ccf83d9a3 | ||
|
|
2eecc18dc7 | ||
|
|
3ceca9c381 | ||
|
|
a4412346a7 | ||
|
|
b0eb271b5b | ||
|
|
88cef7e853 | ||
|
|
69c088004a | ||
|
|
d3bd888885 | ||
|
|
b615f50701 | ||
|
|
d5524be27a | ||
|
|
43b4f3bf12 | ||
|
|
8d7d8f344c | ||
|
|
047dbf3db7 | ||
|
|
d0f0007421 | ||
|
|
60e553bffa | ||
|
|
a8a23b6b2c | ||
|
|
e0f6e207e8 | ||
|
|
30ab86cb72 | ||
|
|
2901f9b795 | ||
|
|
b08b9eabe6 | ||
|
|
83c65c2c06 | ||
|
|
3a6ce7cd1e | ||
|
|
94cfe6930c | ||
|
|
9a4bf8f94d | ||
|
|
d69d9c3b31 | ||
|
|
d9da38c10b | ||
|
|
ac699e430b | ||
|
|
89d7a5c45e | ||
|
|
93d1eea58d | ||
|
|
ad8ab179d2 | ||
|
|
18c6ec439b | ||
|
|
f2ac50360e | ||
|
|
8c42f306dd | ||
|
|
d765d6daa6 | ||
|
|
e7c720fd2c | ||
|
|
f3a87af51d | ||
|
|
1b9615983f | ||
|
|
d040492b7a | ||
|
|
05f7878699 | ||
|
|
0d8bd2653b | ||
|
|
b7ffcb3be8 | ||
|
|
46c55ee79d | ||
|
|
6c1c05dc5d | ||
|
|
637c8130a3 | ||
|
|
7781911baa | ||
|
|
bd3d4d0566 | ||
|
|
63c7d2a0ee | ||
|
|
5f40a22b0d | ||
|
|
72955d1aa4 | ||
|
|
ce2f2a14af | ||
|
|
b4d0f10568 | ||
|
|
c2dfc93fa6 | ||
|
|
29a828c4ef | ||
|
|
9995e26ec6 | ||
|
|
59c277bc6c | ||
|
|
491fb3ccfb | ||
|
|
e96823c9a0 | ||
|
|
ad0e2c0dea | ||
|
|
59b1989b97 | ||
|
|
40c32c7a20 | ||
|
|
bfe7973d90 | ||
|
|
14c432a416 | ||
|
|
e35ac3fed0 | ||
|
|
e3e46315f0 | ||
|
|
a6cb810a92 | ||
|
|
21b2b2bc03 | ||
|
|
d3a6d02ca1 | ||
|
|
1b2d471039 | ||
|
|
890d5a6e2c | ||
|
|
79ab37f282 | ||
|
|
487ef4c163 | ||
|
|
69908d7bf1 | ||
|
|
395081ae87 | ||
|
|
1a7be99263 | ||
|
|
d7770e2582 | ||
|
|
6a59302104 | ||
|
|
e49ef8d60e | ||
|
|
6840ae0c5c | ||
|
|
6f5b351fa0 | ||
|
|
6d36f471dd | ||
|
|
2c1b7bc667 | ||
|
|
dc4a51a462 | ||
|
|
ea7d680d11 | ||
|
|
fcf1ba6b9e | ||
|
|
99435c8708 | ||
|
|
74011bbb45 | ||
|
|
066afe9407 | ||
|
|
8aa08bc64b | ||
|
|
940d78a1ad | ||
|
|
d0e82aafb1 | ||
|
|
fe7b601826 | ||
|
|
9063b4b8db | ||
|
|
e036837211 | ||
|
|
c6deb3800f | ||
|
|
75220096e7 | ||
|
|
7f805f59fd | ||
|
|
ab571e81b3 | ||
|
|
f6adcd2f65 | ||
|
|
85e05bc7b2 | ||
|
|
bb0658bba9 | ||
|
|
50b00e3827 | ||
|
|
99c2e672c3 | ||
|
|
9ea27c3318 | ||
|
|
203ac3a175 | ||
|
|
bc0c483041 | ||
|
|
dbaf317f15 | ||
|
|
9357bb1524 | ||
|
|
734aecd711 | ||
|
|
1af7ebafc8 | ||
|
|
c8a6958ef3 | ||
|
|
377805579b | ||
|
|
35bced8527 | ||
|
|
c1e24961f9 | ||
|
|
2d720fea03 | ||
|
|
65c740ec4a | ||
|
|
0b8d1d5816 | ||
|
|
78db4c365f | ||
|
|
1bb1c7bba8 | ||
|
|
e1b6cb71f8 | ||
|
|
f34ab9f043 | ||
|
|
ebdc2a9e81 | ||
|
|
ebeb6e146c | ||
|
|
28b4f45645 | ||
|
|
f3931a789a | ||
|
|
42369a22a3 | ||
|
|
7b801bb9d3 | ||
|
|
457b7e77de | ||
|
|
169712a9e8 | ||
|
|
a187ec09d7 | ||
|
|
6d9e7fea75 | ||
|
|
ea89fc28da | ||
|
|
7242cb2449 | ||
|
|
4f101170f0 | ||
|
|
fc7932ad27 | ||
|
|
0c41346400 | ||
|
|
c6230fc02e | ||
|
|
1ef09717d2 | ||
|
|
41eb6f5dc4 | ||
|
|
f47be3342f | ||
|
|
4d1620c330 | ||
|
|
7a5b5dee6a | ||
|
|
fa5b5b127e | ||
|
|
327416c967 | ||
|
|
c42663115b | ||
|
|
09bc10b15d | ||
|
|
75058d850b | ||
|
|
ab6ccb3d0b | ||
|
|
07ae239130 | ||
|
|
548ec2c175 | ||
|
|
925ffc3976 | ||
|
|
cf12e5ab82 | ||
|
|
1f283b366b | ||
|
|
e4d2dea201 | ||
|
|
0cf2b1fbda | ||
|
|
8418025b82 | ||
|
|
316dc3a9b3 | ||
|
|
d73d82fbc0 | ||
|
|
7cc28d0242 | ||
|
|
92c3b72b17 | ||
|
|
8707fd5232 | ||
|
|
c125d08636 | ||
|
|
eee4a6272c | ||
|
|
be176fd367 | ||
|
|
48ba1cc9ed | ||
|
|
a6f3f0718d | ||
|
|
9cdd9f6dbf | ||
|
|
0928851966 | ||
|
|
d773bd60f4 | ||
|
|
dfb6164ba5 | ||
|
|
5a9bc0d703 | ||
|
|
2699bcf03e | ||
|
|
f45c1e6dcb | ||
|
|
fd75b35496 | ||
|
|
3e8d562182 | ||
|
|
65caa1e3f2 | ||
|
|
e3ef1e1fde | ||
|
|
3deddbd491 | ||
|
|
ff0daa9f35 | ||
|
|
faa8fb6642 | ||
|
|
6e7d013903 | ||
|
|
5db4793c7b | ||
|
|
db8b61106d | ||
|
|
55ea9046a2 | ||
|
|
a84dd77dc2 | ||
|
|
743eef7ff9 | ||
|
|
39066b846d | ||
|
|
307d048d25 | ||
|
|
7f89429b9f | ||
|
|
6b08ba47c4 | ||
|
|
f63cb962ad | ||
|
|
2c2b37678a | ||
|
|
6fed0795b9 | ||
|
|
c5540f9541 | ||
|
|
4c7a5a7261 | ||
|
|
925610723c | ||
|
|
bdc573ab17 | ||
|
|
f61e340a58 | ||
|
|
0149b71ac9 | ||
|
|
b4eaa5f262 | ||
|
|
2f7406aaca | ||
|
|
a9954c23cc | ||
|
|
9955191651 | ||
|
|
2e0bb4ec56 | ||
|
|
c417740beb | ||
|
|
0d51f4fcb5 | ||
|
|
4626aae70e | ||
|
|
d0abbc6da3 | ||
|
|
9b6b9146e2 | ||
|
|
4605c8bbd3 | ||
|
|
18743ed661 | ||
|
|
3487c4546e | ||
|
|
c457a2470f | ||
|
|
9fb338395a | ||
|
|
ab7e27a4e9 | ||
|
|
44b6f162c1 | ||
|
|
775c7b766c | ||
|
|
3faa22b85a | ||
|
|
05c3f2a250 | ||
|
|
8611e42a2e | ||
|
|
620666909f | ||
|
|
ef6f43825d | ||
|
|
d7b797bf02 | ||
|
|
0e4f71b2f1 | ||
|
|
1c23a55937 | ||
|
|
84d7f2d113 | ||
|
|
78b00e530c | ||
|
|
b22d771cce | ||
|
|
81aa3b769c | ||
|
|
fda90239bc | ||
|
|
3af88ad2e6 | ||
|
|
d73be3b927 | ||
|
|
cc0b704d8e | ||
|
|
cdd4557343 | ||
|
|
e172bdf2eb | ||
|
|
6e7808a65a | ||
|
|
5a86fb9826 | ||
|
|
45166424fc | ||
|
|
965c18225b | ||
|
|
2ea7d32b30 | ||
|
|
40cbd19bc3 | ||
|
|
0255c1f463 | ||
|
|
3657e55c70 | ||
|
|
af3aa8f786 | ||
|
|
81728f62bb | ||
|
|
a4856f1885 | ||
|
|
8fcf430ea8 | ||
|
|
fc2f1588d5 | ||
|
|
6f13e04a24 | ||
|
|
4e669ada26 | ||
|
|
575cc233c9 | ||
|
|
7a4017d164 | ||
|
|
e8e4c5aa61 | ||
|
|
df21f6019e | ||
|
|
232dc2653e | ||
|
|
98b4ff331c | ||
|
|
846b5b6e8a | ||
|
|
fc0528876f | ||
|
|
299b4cfe1d | ||
|
|
d640f50203 | ||
|
|
95ac0a7a51 | ||
|
|
0dc506317c | ||
|
|
3e3b7d22e6 | ||
|
|
e02463d779 | ||
|
|
cb37aea614 | ||
|
|
b40265e029 | ||
|
|
10c9e46fbe | ||
|
|
01f037ae83 | ||
|
|
bf618dc0b3 | ||
|
|
8b36e9fb39 | ||
|
|
0cf29113c0 | ||
|
|
e75d162dbd | ||
|
|
038f8352e0 | ||
|
|
2f48a5007a | ||
|
|
45db10220e | ||
|
|
ebe623bc07 | ||
|
|
4bcfae5905 | ||
|
|
eb6a7b9fea | ||
|
|
df322e6d57 | ||
|
|
d46a6bfed5 | ||
|
|
0e810e1e96 | ||
|
|
5da6c490b3 | ||
|
|
2ec9dda408 | ||
|
|
5b03721db6 | ||
|
|
3c644a712d | ||
|
|
19013d360a | ||
|
|
9bcb744a6a | ||
|
|
06ea0c32d3 | ||
|
|
feb3d9d31f | ||
|
|
198ee01437 | ||
|
|
58e3b5489b | ||
|
|
73b2eb6aeb | ||
|
|
6202526666 | ||
|
|
25bb6e8af7 | ||
|
|
191819488e | ||
|
|
85eb4761e8 | ||
|
|
90bf2ece82 | ||
|
|
772233d003 | ||
|
|
33955c1cb0 |
@@ -173,3 +173,6 @@ PublishProfiles/
|
|||||||
|
|
||||||
# Glade backup files
|
# Glade backup files
|
||||||
*.glade~
|
*.glade~
|
||||||
|
|
||||||
|
# Log files
|
||||||
|
/logs/
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
[submodule "src/KenjinxAndroid/app/src/main/cpp/libraries/adrenotools"]
|
||||||
|
path = src/KenjinxAndroid/app/src/main/cpp/libraries/adrenotools
|
||||||
|
url = https://git.ryujinx.app/kenji-nx/libadrenotools.git
|
||||||
|
[submodule "src/KenjinxAndroid/app/src/main/cpp/libraries/openal"]
|
||||||
|
path = src/KenjinxAndroid/app/src/main/cpp/libraries/openal
|
||||||
|
url = https://git.ryujinx.app/kenji-nx/openal-soft.git
|
||||||
|
[submodule "src/KenjinxAndroid/app/src/main/cpp/libraries/adrenotools/lib/linkernsbypass"]
|
||||||
|
path = src/KenjinxAndroid/app/src/main/cpp/libraries/adrenotools/lib/linkernsbypass
|
||||||
|
url = https://git.ryujinx.app/kenji-nx/liblinkernsbypass.git
|
||||||
+19
-33
@@ -1,6 +1,6 @@
|
|||||||
# Contribution to Ryujinx
|
# Contribution to Kenji-NX
|
||||||
|
|
||||||
You can contribute to Ryujinx with PRs, testing of PRs and issues. Contributing code and other implementations is greatly appreciated alongside simply filing issues for problems you encounter.
|
You can contribute to Kenji-NX with PRs, testing of PRs and issues. Contributing code and other implementations is greatly appreciated alongside simply filing issues for problems you encounter.
|
||||||
Please read the entire document before continuing as it can potentially save everyone involved a significant amount of time.
|
Please read the entire document before continuing as it can potentially save everyone involved a significant amount of time.
|
||||||
|
|
||||||
# Quick Links
|
# Quick Links
|
||||||
@@ -14,13 +14,13 @@ We always welcome bug reports, feature proposals and overall feedback. Here are
|
|||||||
|
|
||||||
### Finding Existing Issues
|
### Finding Existing Issues
|
||||||
|
|
||||||
Before filing a new issue, please search our [open issues](https://github.com/KeatonTheBot/Ryujinx/issues) to check if it already exists.
|
Before filing a new issue, please search our [open issues](https://git.ryujinx.app/kenji-nx/ryujinx/-/issues) to check if it already exists.
|
||||||
|
|
||||||
If you do find an existing issue, please include your own feedback in the discussion. Do consider upvoting (👍 reaction) the original post, as this helps us prioritize popular issues in our backlog.
|
If you do find an existing issue, please include your own feedback in the discussion. Do consider upvoting (👍 reaction) the original post, as this helps us prioritize popular issues in our backlog.
|
||||||
|
|
||||||
### Writing a Good Feature Request
|
### Writing a Good Feature Request
|
||||||
|
|
||||||
Please review any feature requests already opened to both check it has not already been suggested, and to familiarize yourself with the format. When ready to submit a proposal, please use the [Feature Request issue template](https://github.com/Ryujinx/Ryujinx/issues/new?assignees=&labels=&projects=&template=feature_request.yml&title=%5BFeature+Request%5D).
|
Please review any feature requests already opened to both check it has not already been suggested, and to familiarize yourself with the format. When ready to submit a proposal, please go [here](https://git.ryujinx.app/kenji-nx/ryujinx/-/issues).
|
||||||
|
|
||||||
### Writing a Good Bug Report
|
### Writing a Good Bug Report
|
||||||
|
|
||||||
@@ -34,13 +34,13 @@ Ideally, a bug report should contain the following information:
|
|||||||
* A Ryujinx log file of the run instance where the issue occurred. Log files can be found in `[Executable Folder]/Logs` and are named chronologically.
|
* A Ryujinx log file of the run instance where the issue occurred. Log files can be found in `[Executable Folder]/Logs` and are named chronologically.
|
||||||
* Additional information, e.g. is it a regression from previous versions? Are there any known workarounds?
|
* Additional information, e.g. is it a regression from previous versions? Are there any known workarounds?
|
||||||
|
|
||||||
When ready to submit a bug report, please use the [Bug Report issue template](https://github.com/KeatonTheBot/Ryujinx/issues/new?assignees=&labels=bug&projects=&template=bug_report.yml&title=%5BBug%5D).
|
When ready to submit a bug report, please go [here](https://git.ryujinx.app/kenji-nx/ryujinx/-/issues.
|
||||||
|
|
||||||
## Contributing Changes
|
## Contributing Changes
|
||||||
|
|
||||||
Project maintainers will merge changes that both improve the project and meet our standards for code quality.
|
Project maintainers will merge changes that both improve the project and meet our standards for code quality.
|
||||||
|
|
||||||
The [Pull Request Guide](docs/workflow/pr-guide.md) and [License](https://github.com/KeatonTheBot/Ryujinx/blob/master/LICENSE.txt) docs define additional guidance.
|
The [Pull Request Guide](docs/workflow/pr-guide.md) and [License](LICENSE.txt) docs define additional guidance.
|
||||||
|
|
||||||
### DOs and DON'Ts
|
### DOs and DON'Ts
|
||||||
|
|
||||||
@@ -67,30 +67,25 @@ Please do not:
|
|||||||
We use and recommend the following workflow:
|
We use and recommend the following workflow:
|
||||||
|
|
||||||
1. Create or find an issue for your work.
|
1. Create or find an issue for your work.
|
||||||
- You can skip this step for trivial changes.
|
- You can skip this step for trivial changes.
|
||||||
- Get agreement from the team and the community that your proposed change is a good one if it is of significant size or changes core functionality.
|
- Get agreement from the team and the community that your proposed change is a good one if it is of significant size or changes core functionality.
|
||||||
- Clearly state that you are going to take on implementing it, if that's the case. You can request that the issue be assigned to you. Note: The issue filer and the implementer don't have to be the same person.
|
- Clearly state that you are going to take on implementing it, if that's the case. You can request that the issue be assigned to you. Note: The issue filer and the implementer don't have to be the same person.
|
||||||
2. Create a personal fork of the repository on GitHub (if you don't already have one).
|
2. Create a personal fork of the repository on GitHub (if you don't already have one).
|
||||||
3. In your fork, create a branch off of main (`git checkout -b mybranch`).
|
3. In your fork, create a branch off of main (`git checkout -b mybranch`).
|
||||||
- Branches are useful since they isolate your changes from incoming changes from upstream. They also enable you to create multiple PRs from the same fork.
|
- Branches are useful since they isolate your changes from incoming changes from upstream. They also enable you to create multiple PRs from the same fork.
|
||||||
4. Make and commit your changes to your branch.
|
4. Make and commit your changes to your branch.
|
||||||
- [Build Instructions](https://github.com/KeatonTheBot/Ryujinx#building) explains how to build and test.
|
- [Build Instructions](https://git.ryujinx.app/kenji-nx/ryujinx#building) explains how to build and test.
|
||||||
- Commit messages should be clear statements of action and intent.
|
- Commit messages should be clear statements of action and intent.
|
||||||
6. Build the repository with your changes.
|
6. Build the repository with your changes.
|
||||||
- Make sure that the builds are clean.
|
- Make sure that the builds are clean.
|
||||||
- Make sure that `dotnet format` has been run and any corrections tested and committed.
|
- Make sure that `dotnet format` has been run and any corrections tested and committed.
|
||||||
7. Create a pull request (PR) against the Ryujinx/Ryujinx repository's **main** branch.
|
7. Create a pull request (PR) against the Ryujinx/Ryujinx repository's **main** branch.
|
||||||
- State in the description what issue or improvement your change is addressing.
|
- State in the description what issue or improvement your change is addressing.
|
||||||
- Check if all the Continuous Integration checks are passing. Refer to [Actions](https://github.com/KeatonTheBot/Ryujinx/actions) to check for outstanding errors.
|
|
||||||
8. Wait for feedback or approval of your changes from the core development team
|
8. Wait for feedback or approval of your changes from the core development team
|
||||||
- Details about the pull request [review procedure](docs/workflow/ci/pr-guide.md).
|
- Details about the pull request [review procedure](docs/workflow/ci/pr-guide.md).
|
||||||
9. When the team members have signed off, and all checks are green, your PR will be merged.
|
9. When the team members have signed off, and all checks are green, your PR will be merged.
|
||||||
- The next official build will automatically include your change.
|
- The next official build will automatically include your change.
|
||||||
- You can delete the branch you used for making the change.
|
- You can delete the branch you used for making the change.
|
||||||
|
|
||||||
### Good First Issues
|
|
||||||
|
|
||||||
The team marks the most straightforward issues as [good first issues](https://github.com/KeatonTheBot/Ryujinx/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22). This set of issues is the place to start if you are interested in contributing but new to the codebase.
|
|
||||||
|
|
||||||
### Commit Messages
|
### Commit Messages
|
||||||
|
|
||||||
@@ -111,15 +106,6 @@ Fix #42
|
|||||||
|
|
||||||
Also do your best to factor commits appropriately, not too large with unrelated things in the same commit, and not too small with the same small change applied N times in N different commits.
|
Also do your best to factor commits appropriately, not too large with unrelated things in the same commit, and not too small with the same small change applied N times in N different commits.
|
||||||
|
|
||||||
### PR - CI Process
|
|
||||||
|
|
||||||
The [Ryujinx continuous integration](https://github.com/KeatonTheBot/Ryujinx/actions) (CI) system will automatically perform the required builds and run tests (including the ones you are expected to run) for PRs. Builds and test runs must be clean or have bugs properly filed against flaky/unexpected failures that are unrelated to your change.
|
|
||||||
|
|
||||||
If the CI build fails for any reason, the PR actions tab should be consulted for further information on the failure. There are a few usual suspects for such a failure:
|
|
||||||
* `dotnet format` has not been run on the PR and has outstanding stylistic issues.
|
|
||||||
* There is an error within the PR that fails a test or errors the compiler.
|
|
||||||
* Random failure of the workflow can occasionally result in a CI failure. In this scenario a maintainer will manually restart the job.
|
|
||||||
|
|
||||||
### PR Feedback
|
### PR Feedback
|
||||||
|
|
||||||
Ryujinx team and community members will provide feedback on your change. Community feedback is highly valued. You may see the absence of team feedback if the community has already provided good review feedback.
|
Ryujinx team and community members will provide feedback on your change. Community feedback is highly valued. You may see the absence of team feedback if the community has already provided good review feedback.
|
||||||
@@ -134,5 +120,5 @@ Ryujinx uses some implementations and frameworks from other projects. The follow
|
|||||||
|
|
||||||
- The license of the file is [permissive](https://en.wikipedia.org/wiki/Permissive_free_software_licence).
|
- The license of the file is [permissive](https://en.wikipedia.org/wiki/Permissive_free_software_licence).
|
||||||
- The license of the file is left in-tact.
|
- The license of the file is left in-tact.
|
||||||
- The contribution is correctly attributed in the [3rd party notices](https://github.com/KeatonTheBot/Ryujinx/blob/master/distribution/legal/THIRDPARTY.md) file in the repository, as needed.
|
- The contribution is correctly attributed in the [3rd party notices](distribution/legal/THIRDPARTY.md) file in the repository, as needed.
|
||||||
|
|
||||||
|
|||||||
+36
-35
@@ -3,53 +3,54 @@
|
|||||||
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
|
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageVersion Include="Avalonia" Version="11.0.13" />
|
<PackageVersion Include="Avalonia" Version="11.3.13" />
|
||||||
<PackageVersion Include="Avalonia.Controls.DataGrid" Version="11.0.13" />
|
<PackageVersion Include="Avalonia.Controls.DataGrid" Version="11.3.13" />
|
||||||
<PackageVersion Include="Avalonia.Desktop" Version="11.0.13" />
|
<PackageVersion Include="Avalonia.Desktop" Version="11.3.13" />
|
||||||
<PackageVersion Include="Avalonia.Diagnostics" Version="11.0.13" />
|
<PackageVersion Include="Avalonia.Diagnostics" Version="11.3.13" />
|
||||||
<PackageVersion Include="Avalonia.Markup.Xaml.Loader" Version="11.0.13" />
|
<PackageVersion Include="Avalonia.Markup.Xaml.Loader" Version="11.3.13" />
|
||||||
<PackageVersion Include="Avalonia.Svg" Version="11.0.0.19" />
|
<PackageVersion Include="Svg.Controls.Avalonia" Version="11.3.9.5" />
|
||||||
<PackageVersion Include="Avalonia.Svg.Skia" Version="11.0.0.19" />
|
<PackageVersion Include="Svg.Controls.Skia.Avalonia" Version="11.3.9.5" />
|
||||||
<PackageVersion Include="CommandLineParser" Version="2.9.1" />
|
<PackageVersion Include="CommandLineParser" Version="2.9.1" />
|
||||||
<PackageVersion Include="Concentus" Version="2.2.2" />
|
<PackageVersion Include="Concentus" Version="2.2.2" />
|
||||||
<PackageVersion Include="DiscordRichPresence" Version="1.2.1.24" />
|
<PackageVersion Include="DiscordRichPresence" Version="1.6.1.70" />
|
||||||
<PackageVersion Include="DynamicData" Version="9.0.4" />
|
<PackageVersion Include="DynamicData" Version="9.4.31" />
|
||||||
<PackageVersion Include="FluentAvaloniaUI" Version="2.0.5" />
|
<PackageVersion Include="FluentAvaloniaUI" Version="2.4.1" />
|
||||||
<PackageVersion Include="Gommon" Version="2.7.1.1" />
|
<PackageVersion Include="Gommon" Version="2.8.1.1" />
|
||||||
<PackageVersion Include="GtkSharp.Dependencies" Version="1.1.1" />
|
<PackageVersion Include="Humanizer" Version="3.0.10" />
|
||||||
<PackageVersion Include="GtkSharp.Dependencies.osx" Version="0.0.5" />
|
|
||||||
<PackageVersion Include="Humanizer" Version="2.14.1" />
|
|
||||||
<PackageVersion Include="LibHac" Version="0.19.0" />
|
|
||||||
<PackageVersion Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.4" />
|
<PackageVersion Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.4" />
|
||||||
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="4.9.2" />
|
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="4.12.0" />
|
||||||
<PackageVersion Include="Microsoft.IdentityModel.JsonWebTokens" Version="8.6.1" />
|
<PackageVersion Include="Microsoft.IdentityModel.JsonWebTokens" Version="8.17.0" />
|
||||||
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.9.0" />
|
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="18.3.0" />
|
||||||
<PackageVersion Include="Microsoft.IO.RecyclableMemoryStream" Version="3.0.1" />
|
<PackageVersion Include="Microsoft.IO.RecyclableMemoryStream" Version="3.0.1" />
|
||||||
<PackageVersion Include="MsgPack.Cli" Version="1.0.1" />
|
<PackageVersion Include="MsgPack.Cli" Version="1.0.1" />
|
||||||
<PackageVersion Include="NetCoreServer" Version="8.0.7" />
|
<PackageVersion Include="NetCoreServer" Version="8.0.7" />
|
||||||
<PackageVersion Include="NUnit" Version="3.13.3" />
|
<PackageVersion Include="Newtonsoft.Json" Version="13.0.4" />
|
||||||
<PackageVersion Include="NUnit3TestAdapter" Version="4.1.0" />
|
<PackageVersion Include="NUnit" Version="4.5.1" />
|
||||||
<PackageVersion Include="OpenTK.Core" Version="4.8.2" />
|
<PackageVersion Include="NUnit3TestAdapter" Version="6.2.0" />
|
||||||
<PackageVersion Include="OpenTK.Graphics" Version="4.8.2" />
|
<PackageVersion Include="OpenTK.Core" Version="4.9.4" />
|
||||||
<PackageVersion Include="OpenTK.Audio.OpenAL" Version="4.8.2" />
|
<PackageVersion Include="OpenTK.Graphics" Version="4.9.4" />
|
||||||
<PackageVersion Include="OpenTK.Windowing.GraphicsLibraryFramework" Version="4.8.2" />
|
<PackageVersion Include="OpenTK.Audio.OpenAL" Version="4.9.4" />
|
||||||
|
<PackageVersion Include="OpenTK.Windowing.GraphicsLibraryFramework" Version="4.9.4" />
|
||||||
<PackageVersion Include="Open.NAT.Core" Version="2.1.0.5" />
|
<PackageVersion Include="Open.NAT.Core" Version="2.1.0.5" />
|
||||||
<PackageVersion Include="Ryujinx.Audio.OpenAL.Dependencies" Version="1.21.0.1" />
|
<PackageVersion Include="Ryujinx.Audio.OpenAL" Version="1.25.2" />
|
||||||
<PackageVersion Include="Ryujinx.Graphics.Nvdec.Dependencies.AllArch" Version="6.1.2-build3" />
|
<PackageVersion Include="Ryujinx.Graphics.Nvdec.Dependencies.Linux" Version="6.1.3-build5" />
|
||||||
|
<PackageVersion Include="Ryujinx.Graphics.Nvdec.Dependencies.macOS" Version="5.0.3-build14" />
|
||||||
|
<PackageVersion Include="Ryujinx.Graphics.Nvdec.Dependencies.Windows" Version="6.1.3-build5" />
|
||||||
<PackageVersion Include="Ryujinx.Graphics.Vulkan.Dependencies.MoltenVK" Version="1.2.0" />
|
<PackageVersion Include="Ryujinx.Graphics.Vulkan.Dependencies.MoltenVK" Version="1.2.0" />
|
||||||
<PackageVersion Include="Ryujinx.GtkSharp" Version="3.24.24.59-ryujinx" />
|
<PackageVersion Include="Ryujinx.LibHac" Version="0.21.0-alpha.128" />
|
||||||
<PackageVersion Include="Ryujinx.SDL2-CS" Version="2.30.0-build32" />
|
<PackageVersion Include="Ryujinx.SDL3-CS" Version="2026.707.0" />
|
||||||
<PackageVersion Include="securifybv.ShellLink" Version="0.1.0" />
|
<PackageVersion Include="securifybv.ShellLink" Version="0.1.0" />
|
||||||
<PackageVersion Include="shaderc.net" Version="0.1.0" />
|
|
||||||
<PackageVersion Include="SharpZipLib" Version="1.4.2" />
|
<PackageVersion Include="SharpZipLib" Version="1.4.2" />
|
||||||
<PackageVersion Include="Silk.NET.Vulkan" Version="2.22.0" />
|
<PackageVersion Include="Silk.NET.Shaderc" Version="2.23.0" />
|
||||||
<PackageVersion Include="Silk.NET.Vulkan.Extensions.EXT" Version="2.22.0" />
|
<PackageVersion Include="Silk.NET.Vulkan" Version="2.23.0" />
|
||||||
<PackageVersion Include="Silk.NET.Vulkan.Extensions.KHR" Version="2.22.0" />
|
<PackageVersion Include="Silk.NET.Vulkan.Extensions.EXT" Version="2.23.0" />
|
||||||
|
<PackageVersion Include="Silk.NET.Vulkan.Extensions.KHR" Version="2.23.0" />
|
||||||
<PackageVersion Include="SkiaSharp" Version="2.88.9" />
|
<PackageVersion Include="SkiaSharp" Version="2.88.9" />
|
||||||
<PackageVersion Include="SkiaSharp.NativeAssets.Linux" Version="2.88.9" />
|
<PackageVersion Include="SkiaSharp.NativeAssets.Linux" Version="2.88.9" />
|
||||||
<PackageVersion Include="SPB" Version="0.0.4-build32" />
|
<PackageVersion Include="SPB" Version="0.0.4-build32" />
|
||||||
<PackageVersion Include="System.IO.Hashing" Version="9.0.3" />
|
<PackageVersion Include="System.IO.Hashing" Version="9.0.12" />
|
||||||
<PackageVersion Include="System.Management" Version="9.0.3" />
|
<PackageVersion Include="System.Management" Version="9.0.12" />
|
||||||
<PackageVersion Include="UnicornEngine.Unicorn" Version="2.0.2-rc1-fb78016" />
|
<PackageVersion Include="UnicornEngine.Unicorn" Version="2.1.0" />
|
||||||
|
<PackageVersion Include="Rxmxnx.PInvoke.Extensions" Version="2.9.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -1,31 +1,26 @@
|
|||||||
<h1 align="center">
|
<h1 align="center">
|
||||||
<br>
|
<br>
|
||||||
<img src="distribution/misc/Logo.png" alt="Kenji-NX">
|
<img src="https://git.ryujinx.app/projects/Kenji-NX/raw/branch/master/distribution/misc/Logo.png" alt="Kenji-NX">
|
||||||
<br>
|
<br>
|
||||||
<b>Kenji-NX</b>
|
<b>Kenji-NX</b>
|
||||||
<br>
|
<br>
|
||||||
<a href="https://github.com/KeatonTheBot/Kenji-NX/releases/latest">
|
|
||||||
<img src="https://img.shields.io/github/v/release/KeatonTheBot/Kenji-NX"
|
[](https://git.ryujinx.app/projects/Kenji-NX/releases/latest)
|
||||||
alt="Latest Release">
|
[](https://git.ryujinx.app/Kenji-NX/android/releases/latest)
|
||||||
</a>
|
<br>
|
||||||
|
[](https://discord.gg/zBSAuZfKqe)
|
||||||
|
|
||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
<p>
|
Kenji-NX is an open-source Nintendo Switch emulator, originally created by gdkchan, written in C#.
|
||||||
Kenji-NX is an open-source Nintendo Switch emulator, originally created by gdkchan, written in C#.
|
This emulator aims at providing excellent accuracy and performance, a user-friendly interface and consistent builds.
|
||||||
This emulator aims at providing excellent accuracy and performance, a user-friendly interface and consistent builds.
|
It was written from scratch and development on the project began in September 2017.
|
||||||
It was written from scratch and development on the project began in September 2017.
|
Kenji-NX is available on GitHub under the [MIT license](LICENSE.txt).
|
||||||
Kenji-NX is available on GitHub under the <a href="https://github.com/KeatonTheBot/Kenji-NX/blob/master/LICENSE.txt" target="_blank">MIT license</a>.
|
|
||||||
<br><br>
|
|
||||||
On October 1st 2024, Ryujinx was discontinued as the creator was forced to abandon the project.
|
|
||||||
<br><br>
|
|
||||||
This fork is not a Ryujinx revival project; it aims to be a middle ground between GreemDev's <a href="https://git.ryujinx.app/ryubing/ryujinx">Ryujinx</a> fork and the more preservative <a href="https://git.ryujinx.app/archive/ryujinx-mirror">ryujinx-mirror</a> fork.
|
|
||||||
It brings over many of the front-facing features from the aforementioned forks with <i>additional</i> contributions from KeatonTheBot and others.
|
|
||||||
<br>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>
|
On October 1st 2024, Ryujinx was discontinued as the creator was forced to abandon the project.
|
||||||
<img src="docs/shell.png">
|
|
||||||
</p>
|
This fork is not a Ryujinx revival project; it aims to be a middle ground between GreemDev's [Ryujinx](https://git.ryujinx.app/projects/Ryubing) fork and the more preservative [ryujinx-mirror](https://git.ryujinx.app/archive/ryujinx-mirror) fork.
|
||||||
|
It brings over many of the front-facing features from the aforementioned forks with *additional* contributions from KeatonTheBot and others.
|
||||||
|
|
||||||
## Compatibility
|
## Compatibility
|
||||||
|
|
||||||
@@ -58,12 +53,12 @@ If you wish to build the emulator yourself, follow these steps:
|
|||||||
|
|
||||||
### Step 1
|
### Step 1
|
||||||
|
|
||||||
Install the [.NET 9.0 (or higher) SDK](https://dotnet.microsoft.com/download/dotnet/9.0).
|
Install the [.NET 10.0 (or higher) SDK](https://dotnet.microsoft.com/download/dotnet/10.0).
|
||||||
Make sure your SDK version is higher or equal to the required version specified in [global.json](global.json).
|
Make sure your SDK version is higher or equal to the required version specified in [global.json](global.json).
|
||||||
|
|
||||||
### Step 2
|
### Step 2
|
||||||
|
|
||||||
Either use `git clone https://github.com/KeatonTheBot/Kenji-NX` on the command line to clone the repository or use Code --> Download zip button to get the files.
|
Either use `git clone https://git.ryujinx.app/projects/Kenji-NX` on the command line to clone the repository or use Code --> Download zip button to get the files.
|
||||||
|
|
||||||
### Step 3
|
### Step 3
|
||||||
|
|
||||||
@@ -125,7 +120,7 @@ See [LICENSE.txt](LICENSE.txt) and [THIRDPARTY.md](distribution/legal/THIRDPARTY
|
|||||||
|
|
||||||
## Credits
|
## Credits
|
||||||
|
|
||||||
- [LibHac](https://github.com/Thealexbarney/LibHac) is used for our file-system.
|
- [LibHac](https://git.ryujinx.app/projects/LibHac) is used for our file-system.
|
||||||
- [AmiiboAPI](https://www.amiiboapi.com) is used in our Amiibo emulation.
|
- [AmiiboAPI](https://www.amiiboapi.com) is used in our Amiibo emulation.
|
||||||
- [ldn_mitm](https://github.com/spacemeowx2/ldn_mitm) is used for one of our available multiplayer modes.
|
- [ldn_mitm](https://github.com/spacemeowx2/ldn_mitm) is used for one of our available multiplayer modes.
|
||||||
- [ShellLink](https://github.com/securifybv/ShellLink) is used for Windows shortcut generation.
|
- [ShellLink](https://github.com/securifybv/ShellLink) is used for Windows shortcut generation.
|
||||||
|
|||||||
+8
-6
@@ -5,6 +5,8 @@ VisualStudioVersion = 17.1.32228.430
|
|||||||
MinimumVisualStudioVersion = 10.0.40219.1
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Tests", "src\Ryujinx.Tests\Ryujinx.Tests.csproj", "{EBB55AEA-C7D7-4DEB-BF96-FA1789E225E9}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Tests", "src\Ryujinx.Tests\Ryujinx.Tests.csproj", "{EBB55AEA-C7D7-4DEB-BF96-FA1789E225E9}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LibKenjinx", "src\LibKenjinx\LibKenjinx.csproj", "{AF58C1D5-DE16-429B-B155-7CE83B4E8FA6}"
|
||||||
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Tests.Unicorn", "src\Ryujinx.Tests.Unicorn\Ryujinx.Tests.Unicorn.csproj", "{D8F72938-78EF-4E8C-BAFE-531C9C3C8F15}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Tests.Unicorn", "src\Ryujinx.Tests.Unicorn\Ryujinx.Tests.Unicorn.csproj", "{D8F72938-78EF-4E8C-BAFE-531C9C3C8F15}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.HLE", "src\Ryujinx.HLE\Ryujinx.HLE.csproj", "{CB92CFF9-1D62-4D4F-9E88-8130EF61E351}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.HLE", "src\Ryujinx.HLE\Ryujinx.HLE.csproj", "{CB92CFF9-1D62-4D4F-9E88-8130EF61E351}"
|
||||||
@@ -32,7 +34,9 @@ EndProject
|
|||||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{36F870C1-3E5F-485F-B426-F0645AF78751}"
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{36F870C1-3E5F-485F-B426-F0645AF78751}"
|
||||||
ProjectSection(SolutionItems) = preProject
|
ProjectSection(SolutionItems) = preProject
|
||||||
.editorconfig = .editorconfig
|
.editorconfig = .editorconfig
|
||||||
|
Directory.Build.props = Directory.Build.props
|
||||||
Directory.Packages.props = Directory.Packages.props
|
Directory.Packages.props = Directory.Packages.props
|
||||||
|
nuget.config = nuget.config
|
||||||
EndProjectSection
|
EndProjectSection
|
||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Memory", "src\Ryujinx.Memory\Ryujinx.Memory.csproj", "{A5E6C691-9E22-4263-8F40-42F002CE66BE}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Memory", "src\Ryujinx.Memory\Ryujinx.Memory.csproj", "{A5E6C691-9E22-4263-8F40-42F002CE66BE}"
|
||||||
@@ -63,8 +67,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.SDL2.Common", "src\
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Audio.Backends.SDL2", "src\Ryujinx.Audio.Backends.SDL2\Ryujinx.Audio.Backends.SDL2.csproj", "{D99A395A-8569-4DB0-B336-900647890052}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Audio.Backends.SDL2", "src\Ryujinx.Audio.Backends.SDL2\Ryujinx.Audio.Backends.SDL2.csproj", "{D99A395A-8569-4DB0-B336-900647890052}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Headless.SDL2", "src\Ryujinx.Headless.SDL2\Ryujinx.Headless.SDL2.csproj", "{390DC343-5CB4-4C79-A5DD-E3ED235E4C49}"
|
|
||||||
EndProject
|
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Graphics.Nvdec.FFmpeg", "src\Ryujinx.Graphics.Nvdec.FFmpeg\Ryujinx.Graphics.Nvdec.FFmpeg.csproj", "{BEE1C184-C9A4-410B-8DFC-FB74D5C93AEB}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Graphics.Nvdec.FFmpeg", "src\Ryujinx.Graphics.Nvdec.FFmpeg\Ryujinx.Graphics.Nvdec.FFmpeg.csproj", "{BEE1C184-C9A4-410B-8DFC-FB74D5C93AEB}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx", "src\Ryujinx\Ryujinx.csproj", "{7C1B2721-13DA-4B62-B046-C626605ECCE6}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx", "src\Ryujinx\Ryujinx.csproj", "{7C1B2721-13DA-4B62-B046-C626605ECCE6}"
|
||||||
@@ -97,6 +99,10 @@ Global
|
|||||||
{EBB55AEA-C7D7-4DEB-BF96-FA1789E225E9}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{EBB55AEA-C7D7-4DEB-BF96-FA1789E225E9}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{EBB55AEA-C7D7-4DEB-BF96-FA1789E225E9}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{EBB55AEA-C7D7-4DEB-BF96-FA1789E225E9}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{EBB55AEA-C7D7-4DEB-BF96-FA1789E225E9}.Release|Any CPU.Build.0 = Release|Any CPU
|
{EBB55AEA-C7D7-4DEB-BF96-FA1789E225E9}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{AF58C1D5-DE16-429B-B155-7CE83B4E8FA6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{AF58C1D5-DE16-429B-B155-7CE83B4E8FA6}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{AF58C1D5-DE16-429B-B155-7CE83B4E8FA6}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{AF58C1D5-DE16-429B-B155-7CE83B4E8FA6}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
{D8F72938-78EF-4E8C-BAFE-531C9C3C8F15}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
{D8F72938-78EF-4E8C-BAFE-531C9C3C8F15}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
{D8F72938-78EF-4E8C-BAFE-531C9C3C8F15}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{D8F72938-78EF-4E8C-BAFE-531C9C3C8F15}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{D8F72938-78EF-4E8C-BAFE-531C9C3C8F15}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{D8F72938-78EF-4E8C-BAFE-531C9C3C8F15}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
@@ -201,10 +207,6 @@ Global
|
|||||||
{D99A395A-8569-4DB0-B336-900647890052}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{D99A395A-8569-4DB0-B336-900647890052}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{D99A395A-8569-4DB0-B336-900647890052}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{D99A395A-8569-4DB0-B336-900647890052}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{D99A395A-8569-4DB0-B336-900647890052}.Release|Any CPU.Build.0 = Release|Any CPU
|
{D99A395A-8569-4DB0-B336-900647890052}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
{390DC343-5CB4-4C79-A5DD-E3ED235E4C49}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{390DC343-5CB4-4C79-A5DD-E3ED235E4C49}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{390DC343-5CB4-4C79-A5DD-E3ED235E4C49}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{390DC343-5CB4-4C79-A5DD-E3ED235E4C49}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{BEE1C184-C9A4-410B-8DFC-FB74D5C93AEB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
{BEE1C184-C9A4-410B-8DFC-FB74D5C93AEB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
{BEE1C184-C9A4-410B-8DFC-FB74D5C93AEB}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{BEE1C184-C9A4-410B-8DFC-FB74D5C93AEB}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{BEE1C184-C9A4-410B-8DFC-FB74D5C93AEB}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{BEE1C184-C9A4-410B-8DFC-FB74D5C93AEB}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
|||||||
@@ -0,0 +1,47 @@
|
|||||||
|
<Solution>
|
||||||
|
<Folder Name="/Solution Items/">
|
||||||
|
<File Path=".editorconfig" />
|
||||||
|
<File Path="Directory.Build.props" />
|
||||||
|
<File Path="Directory.Packages.props" />
|
||||||
|
<File Path="nuget.config" />
|
||||||
|
</Folder>
|
||||||
|
<Project Path="src/ARMeilleure/ARMeilleure.csproj" />
|
||||||
|
<Project Path="src/LibKenjinx/LibKenjinx.csproj" />
|
||||||
|
<Project Path="src/Ryujinx.Audio.Backends.OpenAL/Ryujinx.Audio.Backends.OpenAL.csproj" />
|
||||||
|
<Project Path="src/Ryujinx.Audio.Backends.SDL3/Ryujinx.Audio.Backends.SDL3.csproj" />
|
||||||
|
<Project Path="src/Ryujinx.Audio.Backends.SoundIo/Ryujinx.Audio.Backends.SoundIo.csproj" />
|
||||||
|
<Project Path="src/Ryujinx.Audio/Ryujinx.Audio.csproj" />
|
||||||
|
<Project Path="src/Ryujinx.Common/Ryujinx.Common.csproj" />
|
||||||
|
<Project Path="src/Ryujinx.Cpu/Ryujinx.Cpu.csproj" />
|
||||||
|
<Project Path="src/Ryujinx.Graphics.Device/Ryujinx.Graphics.Device.csproj" />
|
||||||
|
<Project Path="src/Ryujinx.Graphics.GAL/Ryujinx.Graphics.GAL.csproj" />
|
||||||
|
<Project Path="src/Ryujinx.Graphics.Gpu/Ryujinx.Graphics.Gpu.csproj" />
|
||||||
|
<Project Path="src/Ryujinx.Graphics.Host1x/Ryujinx.Graphics.Host1x.csproj" />
|
||||||
|
<Project Path="src/Ryujinx.Graphics.Nvdec.FFmpeg/Ryujinx.Graphics.Nvdec.FFmpeg.csproj" />
|
||||||
|
<Project Path="src/Ryujinx.Graphics.Nvdec.Vp9/Ryujinx.Graphics.Nvdec.Vp9.csproj" />
|
||||||
|
<Project Path="src/Ryujinx.Graphics.Nvdec/Ryujinx.Graphics.Nvdec.csproj" />
|
||||||
|
<Project Path="src/Ryujinx.Graphics.OpenGL/Ryujinx.Graphics.OpenGL.csproj" />
|
||||||
|
<Project Path="src/Ryujinx.Graphics.Shader/Ryujinx.Graphics.Shader.csproj" />
|
||||||
|
<Project Path="src/Ryujinx.Graphics.Texture/Ryujinx.Graphics.Texture.csproj" />
|
||||||
|
<Project Path="src/Ryujinx.Graphics.Vic/Ryujinx.Graphics.Vic.csproj" />
|
||||||
|
<Project Path="src/Ryujinx.Graphics.Video/Ryujinx.Graphics.Video.csproj" />
|
||||||
|
<Project Path="src/Ryujinx.Graphics.Vulkan/Ryujinx.Graphics.Vulkan.csproj" />
|
||||||
|
<Project Path="src/Ryujinx.HLE.Generators/Ryujinx.HLE.Generators.csproj" />
|
||||||
|
<Project Path="src/Ryujinx.HLE/Ryujinx.HLE.csproj" />
|
||||||
|
<Project Path="src/Ryujinx.Horizon.Common/Ryujinx.Horizon.Common.csproj" />
|
||||||
|
<Project Path="src/Ryujinx.Horizon.Generators/Ryujinx.Horizon.Generators.csproj" />
|
||||||
|
<Project Path="src/Ryujinx.Horizon.Kernel.Generators/Ryujinx.Horizon.Kernel.Generators.csproj" />
|
||||||
|
<Project Path="src/Ryujinx.Horizon/Ryujinx.Horizon.csproj" />
|
||||||
|
<Project Path="src/Ryujinx.Input.SDL3/Ryujinx.Input.SDL3.csproj" />
|
||||||
|
<Project Path="src/Ryujinx.Input/Ryujinx.Input.csproj" />
|
||||||
|
<Project Path="src/Ryujinx.Memory/Ryujinx.Memory.csproj" />
|
||||||
|
<Project Path="src/Ryujinx.SDL3.Common/Ryujinx.SDL3.Common.csproj" />
|
||||||
|
<Project Path="src/Ryujinx.ShaderTools/Ryujinx.ShaderTools.csproj" />
|
||||||
|
<Project Path="src/Ryujinx.Tests.Memory/Ryujinx.Tests.Memory.csproj" />
|
||||||
|
<Project Path="src/Ryujinx.Tests.Unicorn/Ryujinx.Tests.Unicorn.csproj" />
|
||||||
|
<Project Path="src/Ryujinx.Tests/Ryujinx.Tests.csproj" />
|
||||||
|
<Project Path="src/Ryujinx.UI.Common/Ryujinx.UI.Common.csproj" />
|
||||||
|
<Project Path="src/Ryujinx.UI.LocaleGenerator/Ryujinx.UI.LocaleGenerator.csproj" />
|
||||||
|
<Project Path="src/Ryujinx/Ryujinx.csproj" />
|
||||||
|
<Project Path="src/Spv.Generator/Spv.Generator.csproj" />
|
||||||
|
</Solution>
|
||||||
+4
-4
@@ -1,14 +1,14 @@
|
|||||||
# Documents Index
|
# Documents Index
|
||||||
|
|
||||||
This repo includes several documents that explain both high-level and low-level concepts about Ryujinx and its functions. These are very useful for contributors, to get context that can be very difficult to acquire from just reading code.
|
This repo includes several documents that explain both high-level and low-level concepts about Kenji-NX and its functions. These are very useful for contributors, to get context that can be very difficult to acquire from just reading code.
|
||||||
|
|
||||||
Intro to Ryujinx
|
Intro to Kenji-NX
|
||||||
==================
|
==================
|
||||||
|
|
||||||
Ryujinx is an open-source Nintendo Switch emulator, created by gdkchan, written in C#.
|
Kenji-NX is an open-source Nintendo Switch emulator written in C#. It is based on Ryujinx, which was originally created by gdkchan.
|
||||||
* The CPU emulator, ARMeilleure, emulates an ARMv8 CPU and currently has support for most 64-bit ARMv8 and some of the ARMv7 (and older) instructions.
|
* The CPU emulator, ARMeilleure, emulates an ARMv8 CPU and currently has support for most 64-bit ARMv8 and some of the ARMv7 (and older) instructions.
|
||||||
* 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.
|
* 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.
|
||||||
* Audio output is entirely supported via C# wrappers for SDL2, with OpenAL & libsoundio as fallbacks.
|
* Audio output is entirely supported via C# wrappers for SDL3, with OpenAL & libsoundio as fallbacks.
|
||||||
|
|
||||||
Getting Started
|
Getting Started
|
||||||
===============
|
===============
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
## Contributing Rules
|
## Contributing Rules
|
||||||
|
|
||||||
All contributions to KeatonTheBot/Ryujinx repository are made via pull requests (PRs) rather than through direct commits. The pull requests are reviewed and merged by the maintainers after a review and at least two approvals from the core development team.
|
All contributions to Kenji-NX repository are made via pull requests (PRs) rather than through direct commits. The pull requests are reviewed and merged by the maintainers after a review and at least two approvals from the core development team.
|
||||||
|
|
||||||
To merge pull requests, you must have write permissions in the repository.
|
To merge pull requests, you must have write permissions in the repository.
|
||||||
|
|
||||||
@@ -18,17 +18,13 @@ To merge pull requests, you must have write permissions in the repository.
|
|||||||
|
|
||||||
## Pull Request Ownership
|
## Pull Request Ownership
|
||||||
|
|
||||||
Every pull request will have automatically have labels and reviewers assigned. The label not only indicates the code segment which the change touches but also the area reviewers to be assigned.
|
Every pull request will automatically have labels and reviewers assigned. The label not only indicates the code segment which the change touches but also the area reviewers to be assigned.
|
||||||
|
|
||||||
If during the code review process a merge conflict occurs, the PR author is responsible for its resolution. Help will be provided if necessary although GitHub makes this easier by allowing simple conflict resolution using the [conflict-editor](https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/resolving-a-merge-conflict-on-github).
|
If during the code review process a merge conflict occurs, the PR author is responsible for its resolution. Help will be provided if necessary although GitHub makes this easier by allowing simple conflict resolution using the [conflict-editor](https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/resolving-a-merge-conflict-on-github).
|
||||||
|
|
||||||
## Pull Request Builds
|
|
||||||
|
|
||||||
When submitting a PR to the `KeatonTheBot/Ryujinx` repository, various builds will run validating many areas to ensure we keep developer productivity and product quality high. These various workflows can be tracked in the [Actions](https://github.com/KeatonTheBot/Ryujinx/actions) tab of the repository. If the job continues to completion, the build artifacts will be uploaded and posted as a comment in the PR discussion.
|
|
||||||
|
|
||||||
## Review Turnaround Times
|
## Review Turnaround Times
|
||||||
|
|
||||||
Ryujinx is a project that is maintained by volunteers on a completely free-time basis. As such we cannot guarantee any particular timeframe for pull request review and approval. Weeks to months are common for larger (>500 line) PRs but there are some additional best practises to avoid review purgatory.
|
Kenji-NX is a project that is maintained by volunteers on a completely free-time basis. As such we cannot guarantee any particular timeframe for pull request review and approval. Weeks to months are common for larger (>500 line) PRs but there are some additional best practises to avoid review purgatory.
|
||||||
|
|
||||||
* Make the reviewers life easier wherever possible. Make use of descriptive commit names, code comments and XML docs where applicable.
|
* Make the reviewers life easier wherever possible. Make use of descriptive commit names, code comments and XML docs where applicable.
|
||||||
* If there is disagreement on feedback then always lean on the side of the development team and community over any personal opinion.
|
* If there is disagreement on feedback then always lean on the side of the development team and community over any personal opinion.
|
||||||
@@ -41,8 +37,7 @@ To re-iterate, make the review as easy for us as possible, respond promptly and
|
|||||||
Anyone with write access can merge a pull request manually when the following conditions have been met:
|
Anyone with write access can merge a pull request manually when the following conditions have been met:
|
||||||
|
|
||||||
* The PR has been approved by two reviewers and any other objections are addressed.
|
* The PR has been approved by two reviewers and any other objections are addressed.
|
||||||
* You can request follow up reviews from the original reviewers if they requested changes.
|
* You can request follow-up reviews from the original reviewers if they requested changes.
|
||||||
* The PR successfully builds and passes all tests in the Continuous Integration (CI) system. In case of failures, refer to the [Actions](https://github.com/KeatonTheBot/Ryujinx/actions) tab of your PR.
|
|
||||||
|
|
||||||
Typically, PRs are merged as one commit (squash merges). It creates a simpler history than a Merge Commit. "Special circumstances" are rare, and typically mean that there are a series of cleanly separated changes that will be too hard to understand if squashed together, or for some reason we want to preserve the ability to dissect them.
|
Typically, PRs are merged as one commit (squash merges). It creates a simpler history than a Merge Commit. "Special circumstances" are rare, and typically mean that there are a series of cleanly separated changes that will be too hard to understand if squashed together, or for some reason we want to preserve the ability to dissect them.
|
||||||
|
|
||||||
|
|||||||
+20
-4
@@ -1,7 +1,23 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<configuration>
|
<configuration>
|
||||||
<packageSources>
|
<packageSources>
|
||||||
<clear />
|
<clear />
|
||||||
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" />
|
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" />
|
||||||
</packageSources>
|
<!-- Only needed when using pre-release versions of Ryujinx.LibHac. -->
|
||||||
|
<add key="LibHacAlpha" value="https://git.ryujinx.app/api/packages/projects/nuget/index.json" />
|
||||||
|
<!--<add key="Silk.NET" value="https://gitlab.com/api/v4/projects/51457475/packages/nuget/index.json" />-->
|
||||||
|
</packageSources>
|
||||||
|
<packageSourceMapping>
|
||||||
|
<!-- key value for <packageSource> should match key values from <packageSources> element -->
|
||||||
|
<!-- These are defined and .NET still yells about multiple package sources with no mappings. Not sure what to do, this is in the docs lol -->
|
||||||
|
<packageSource key="nuget.org">
|
||||||
|
<package pattern="*" />
|
||||||
|
</packageSource>
|
||||||
|
<packageSource key="LibHacAlpha">
|
||||||
|
<package pattern="Ryujinx.LibHac" />
|
||||||
|
</packageSource>
|
||||||
|
<!--<packageSource key="Silk.NET">
|
||||||
|
<package pattern="Silk.*" />
|
||||||
|
</packageSource>-->
|
||||||
|
</packageSourceMapping>
|
||||||
</configuration>
|
</configuration>
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
|
<RuntimeIdentifiers>osx-arm64</RuntimeIdentifiers>
|
||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
<DefaultItemExcludes>$(DefaultItemExcludes);._*</DefaultItemExcludes>
|
<DefaultItemExcludes>$(DefaultItemExcludes);._*</DefaultItemExcludes>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\Ryujinx.Common\Ryujinx.Common.csproj" />
|
|
||||||
<ProjectReference Include="..\Ryujinx.Memory\Ryujinx.Memory.csproj" />
|
<ProjectReference Include="..\Ryujinx.Memory\Ryujinx.Memory.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
|||||||
@@ -13,13 +13,13 @@ namespace ARMeilleure.CodeGen.Arm64
|
|||||||
|
|
||||||
public static void RunPass(ControlFlowGraph cfg)
|
public static void RunPass(ControlFlowGraph cfg)
|
||||||
{
|
{
|
||||||
var constants = new Dictionary<ulong, Operand>();
|
Dictionary<ulong, Operand> constants = new();
|
||||||
|
|
||||||
Operand GetConstantCopy(BasicBlock block, Operation operation, Operand source)
|
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
|
// 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).
|
// to avoid overflow of the counts field (that is limited to 16 bits).
|
||||||
if (!constants.TryGetValue(source.Value, out var constant) || constant.UsesCount > MaxConstantUses)
|
if (!constants.TryGetValue(source.Value, out Operand constant) || constant.UsesCount > MaxConstantUses)
|
||||||
{
|
{
|
||||||
constant = Local(source.Type);
|
constant = Local(source.Type);
|
||||||
|
|
||||||
@@ -254,7 +254,7 @@ namespace ARMeilleure.CodeGen.Arm64
|
|||||||
|
|
||||||
private static bool IsMemoryLoadOrStore(Instruction inst)
|
private static bool IsMemoryLoadOrStore(Instruction inst)
|
||||||
{
|
{
|
||||||
return inst == Instruction.Load || inst == Instruction.Store;
|
return inst is Instruction.Load or Instruction.Store;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool ConstTooLong(Operand constOp, OperandType accessType)
|
private static bool ConstTooLong(Operand constOp, OperandType accessType)
|
||||||
|
|||||||
@@ -123,7 +123,7 @@ namespace ARMeilleure.CodeGen.Arm64
|
|||||||
|
|
||||||
public void Cset(Operand rd, ArmCondition condition)
|
public void Cset(Operand rd, ArmCondition condition)
|
||||||
{
|
{
|
||||||
var zr = Factory.Register(ZrRegister, RegisterType.Integer, rd.Type);
|
Operand zr = Factory.Register(ZrRegister, RegisterType.Integer, rd.Type);
|
||||||
Csinc(rd, zr, zr, (ArmCondition)((int)condition ^ 1));
|
Csinc(rd, zr, zr, (ArmCondition)((int)condition ^ 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ namespace ARMeilleure.CodeGen.Arm64
|
|||||||
// Any value AND all ones will be equal itself, so it's effectively a no-op.
|
// 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 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.
|
// Any value XOR all ones will be equal its inverse, so one can just use MVN.
|
||||||
if (value == 0 || value == ulong.MaxValue)
|
if (value is 0 or ulong.MaxValue)
|
||||||
{
|
{
|
||||||
immN = 0;
|
immN = 0;
|
||||||
immS = 0;
|
immS = 0;
|
||||||
|
|||||||
@@ -91,7 +91,7 @@ namespace ARMeilleure.CodeGen.Arm64
|
|||||||
|
|
||||||
long target = _stream.Position;
|
long target = _stream.Position;
|
||||||
|
|
||||||
if (_pendingBranches.TryGetValue(block, out var list))
|
if (_pendingBranches.TryGetValue(block, out List<(ArmCondition Condition, long BranchPos)> list))
|
||||||
{
|
{
|
||||||
foreach ((ArmCondition condition, long branchPos) in list)
|
foreach ((ArmCondition condition, long branchPos) in list)
|
||||||
{
|
{
|
||||||
@@ -119,7 +119,7 @@ namespace ARMeilleure.CodeGen.Arm64
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (!_pendingBranches.TryGetValue(target, out var list))
|
if (!_pendingBranches.TryGetValue(target, out List<(ArmCondition Condition, long BranchPos)> list))
|
||||||
{
|
{
|
||||||
list = new List<(ArmCondition, long)>();
|
list = new List<(ArmCondition, long)>();
|
||||||
_pendingBranches.Add(target, list);
|
_pendingBranches.Add(target, list);
|
||||||
|
|||||||
@@ -189,8 +189,7 @@ namespace ARMeilleure.CodeGen.Arm64
|
|||||||
// The only blocks which can have 0 successors are exit blocks.
|
// The only blocks which can have 0 successors are exit blocks.
|
||||||
Operation last = block.Operations.Last;
|
Operation last = block.Operations.Last;
|
||||||
|
|
||||||
Debug.Assert(last.Instruction == Instruction.Tailcall ||
|
Debug.Assert(last.Instruction is Instruction.Tailcall or Instruction.Return);
|
||||||
last.Instruction == Instruction.Return);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -322,7 +321,7 @@ namespace ARMeilleure.CodeGen.Arm64
|
|||||||
|
|
||||||
Debug.Assert(comp.Kind == OperandKind.Constant);
|
Debug.Assert(comp.Kind == OperandKind.Constant);
|
||||||
|
|
||||||
var cond = ((Comparison)comp.AsInt32()).ToArmCondition();
|
ArmCondition cond = ((Comparison)comp.AsInt32()).ToArmCondition();
|
||||||
|
|
||||||
GenerateCompareCommon(context, operation);
|
GenerateCompareCommon(context, operation);
|
||||||
|
|
||||||
@@ -354,7 +353,7 @@ namespace ARMeilleure.CodeGen.Arm64
|
|||||||
Debug.Assert(dest.Type == OperandType.I32);
|
Debug.Assert(dest.Type == OperandType.I32);
|
||||||
Debug.Assert(comp.Kind == OperandKind.Constant);
|
Debug.Assert(comp.Kind == OperandKind.Constant);
|
||||||
|
|
||||||
var cond = ((Comparison)comp.AsInt32()).ToArmCondition();
|
ArmCondition cond = ((Comparison)comp.AsInt32()).ToArmCondition();
|
||||||
|
|
||||||
GenerateCompareCommon(context, operation);
|
GenerateCompareCommon(context, operation);
|
||||||
|
|
||||||
@@ -464,7 +463,7 @@ namespace ARMeilleure.CodeGen.Arm64
|
|||||||
Operand dest = operation.Destination;
|
Operand dest = operation.Destination;
|
||||||
Operand source = operation.GetSource(0);
|
Operand source = operation.GetSource(0);
|
||||||
|
|
||||||
Debug.Assert(dest.Type == OperandType.FP32 || dest.Type == OperandType.FP64);
|
Debug.Assert(dest.Type is OperandType.FP32 or OperandType.FP64);
|
||||||
Debug.Assert(dest.Type != source.Type);
|
Debug.Assert(dest.Type != source.Type);
|
||||||
Debug.Assert(source.Type != OperandType.V128);
|
Debug.Assert(source.Type != OperandType.V128);
|
||||||
|
|
||||||
@@ -483,7 +482,7 @@ namespace ARMeilleure.CodeGen.Arm64
|
|||||||
Operand dest = operation.Destination;
|
Operand dest = operation.Destination;
|
||||||
Operand source = operation.GetSource(0);
|
Operand source = operation.GetSource(0);
|
||||||
|
|
||||||
Debug.Assert(dest.Type == OperandType.FP32 || dest.Type == OperandType.FP64);
|
Debug.Assert(dest.Type is OperandType.FP32 or OperandType.FP64);
|
||||||
Debug.Assert(dest.Type != source.Type);
|
Debug.Assert(dest.Type != source.Type);
|
||||||
Debug.Assert(source.Type.IsInteger());
|
Debug.Assert(source.Type.IsInteger());
|
||||||
|
|
||||||
@@ -1463,7 +1462,7 @@ namespace ARMeilleure.CodeGen.Arm64
|
|||||||
|
|
||||||
private static bool IsLoadOrStore(Operation operation)
|
private static bool IsLoadOrStore(Operation operation)
|
||||||
{
|
{
|
||||||
return operation.Instruction == Instruction.Load || operation.Instruction == Instruction.Store;
|
return operation.Instruction is Instruction.Load or Instruction.Store;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static OperandType GetMemOpValueType(Operation operation)
|
private static OperandType GetMemOpValueType(Operation operation)
|
||||||
@@ -1553,7 +1552,7 @@ namespace ARMeilleure.CodeGen.Arm64
|
|||||||
|
|
||||||
private static void EnsureSameReg(Operand op1, Operand op2)
|
private static void EnsureSameReg(Operand op1, Operand op2)
|
||||||
{
|
{
|
||||||
Debug.Assert(op1.Kind == OperandKind.Register || op1.Kind == OperandKind.Memory);
|
Debug.Assert(op1.Kind is OperandKind.Register or OperandKind.Memory);
|
||||||
Debug.Assert(op1.Kind == op2.Kind);
|
Debug.Assert(op1.Kind == op2.Kind);
|
||||||
Debug.Assert(op1.Value == op2.Value);
|
Debug.Assert(op1.Value == op2.Value);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -127,13 +127,13 @@ namespace ARMeilleure.CodeGen.Arm64
|
|||||||
#region macOS
|
#region macOS
|
||||||
|
|
||||||
[LibraryImport("libSystem.dylib", SetLastError = true)]
|
[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);
|
private static unsafe partial int sysctlbyname([MarshalAs(UnmanagedType.LPStr)] string name, out int oldValue, ref ulong oldSize, nint newValue, ulong newValueSize);
|
||||||
|
|
||||||
[SupportedOSPlatform("macos")]
|
[SupportedOSPlatform("macos")]
|
||||||
private static bool CheckSysctlName(string name)
|
private static bool CheckSysctlName(string name)
|
||||||
{
|
{
|
||||||
ulong size = sizeof(int);
|
ulong size = sizeof(int);
|
||||||
if (sysctlbyname(name, out int val, ref size, IntPtr.Zero, 0) == 0 && size == sizeof(int))
|
if (sysctlbyname(name, out int val, ref size, nint.Zero, 0) == 0 && size == sizeof(int))
|
||||||
{
|
{
|
||||||
return val != 0;
|
return val != 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -736,19 +736,19 @@ namespace ARMeilleure.CodeGen.Arm64
|
|||||||
{
|
{
|
||||||
IntrinsicInfo info = IntrinsicTable.GetInfo(intrinsic & ~(Intrinsic.Arm64VTypeMask | Intrinsic.Arm64VSizeMask));
|
IntrinsicInfo info = IntrinsicTable.GetInfo(intrinsic & ~(Intrinsic.Arm64VTypeMask | Intrinsic.Arm64VSizeMask));
|
||||||
|
|
||||||
return info.Type == IntrinsicType.ScalarBinaryRd ||
|
return info.Type is IntrinsicType.ScalarBinaryRd
|
||||||
info.Type == IntrinsicType.ScalarTernaryFPRdByElem ||
|
or IntrinsicType.ScalarTernaryFPRdByElem
|
||||||
info.Type == IntrinsicType.ScalarTernaryShlRd ||
|
or IntrinsicType.ScalarTernaryShlRd
|
||||||
info.Type == IntrinsicType.ScalarTernaryShrRd ||
|
or IntrinsicType.ScalarTernaryShrRd
|
||||||
info.Type == IntrinsicType.Vector128BinaryRd ||
|
or IntrinsicType.Vector128BinaryRd
|
||||||
info.Type == IntrinsicType.VectorBinaryRd ||
|
or IntrinsicType.VectorBinaryRd
|
||||||
info.Type == IntrinsicType.VectorInsertByElem ||
|
or IntrinsicType.VectorInsertByElem
|
||||||
info.Type == IntrinsicType.VectorTernaryRd ||
|
or IntrinsicType.VectorTernaryRd
|
||||||
info.Type == IntrinsicType.VectorTernaryRdBitwise ||
|
or IntrinsicType.VectorTernaryRdBitwise
|
||||||
info.Type == IntrinsicType.VectorTernaryFPRdByElem ||
|
or IntrinsicType.VectorTernaryFPRdByElem
|
||||||
info.Type == IntrinsicType.VectorTernaryRdByElem ||
|
or IntrinsicType.VectorTernaryRdByElem
|
||||||
info.Type == IntrinsicType.VectorTernaryShlRd ||
|
or IntrinsicType.VectorTernaryShlRd
|
||||||
info.Type == IntrinsicType.VectorTernaryShrRd;
|
or IntrinsicType.VectorTernaryShrRd;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool HasConstSrc1(Operation node, ulong value)
|
private static bool HasConstSrc1(Operation node, ulong value)
|
||||||
@@ -847,9 +847,9 @@ namespace ARMeilleure.CodeGen.Arm64
|
|||||||
|
|
||||||
Debug.Assert(comp.Kind == OperandKind.Constant);
|
Debug.Assert(comp.Kind == OperandKind.Constant);
|
||||||
|
|
||||||
var compType = (Comparison)comp.AsInt32();
|
Comparison compType = (Comparison)comp.AsInt32();
|
||||||
|
|
||||||
return compType == Comparison.Equal || compType == Comparison.NotEqual;
|
return compType is Comparison.Equal or Comparison.NotEqual;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
using ARMeilleure.CodeGen.Linking;
|
using ARMeilleure.CodeGen.Linking;
|
||||||
using ARMeilleure.CodeGen.Unwinding;
|
using ARMeilleure.CodeGen.Unwinding;
|
||||||
using ARMeilleure.Translation.Cache;
|
using ARMeilleure.Translation.Cache;
|
||||||
using System;
|
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace ARMeilleure.CodeGen
|
namespace ARMeilleure.CodeGen
|
||||||
@@ -58,7 +57,7 @@ namespace ARMeilleure.CodeGen
|
|||||||
/// <typeparam name="T">Type of delegate</typeparam>
|
/// <typeparam name="T">Type of delegate</typeparam>
|
||||||
/// <param name="codePointer">Pointer to the function code in memory</param>
|
/// <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>
|
/// <returns>A delegate of type <typeparamref name="T"/> pointing to the mapped function</returns>
|
||||||
public T MapWithPointer<T>(out IntPtr codePointer)
|
public T MapWithPointer<T>(out nint codePointer)
|
||||||
{
|
{
|
||||||
codePointer = JitCache.Map(this);
|
codePointer = JitCache.Map(this);
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ namespace ARMeilleure.CodeGen.Linking
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets an empty <see cref="RelocInfo"/>.
|
/// Gets an empty <see cref="RelocInfo"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static RelocInfo Empty { get; } = new RelocInfo(null);
|
public static RelocInfo Empty { get; } = new(null);
|
||||||
|
|
||||||
private readonly RelocEntry[] _entries;
|
private readonly RelocEntry[] _entries;
|
||||||
|
|
||||||
|
|||||||
@@ -227,11 +227,11 @@ namespace ARMeilleure.CodeGen.Optimizations
|
|||||||
|
|
||||||
private static bool HasSideEffects(Operation node)
|
private static bool HasSideEffects(Operation node)
|
||||||
{
|
{
|
||||||
return node.Instruction == Instruction.Call
|
return node.Instruction is Instruction.Call
|
||||||
|| node.Instruction == Instruction.Tailcall
|
or Instruction.Tailcall
|
||||||
|| node.Instruction == Instruction.CompareAndSwap
|
or Instruction.CompareAndSwap
|
||||||
|| node.Instruction == Instruction.CompareAndSwap16
|
or Instruction.CompareAndSwap16
|
||||||
|| node.Instruction == Instruction.CompareAndSwap8;
|
or Instruction.CompareAndSwap8;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool IsPropagableCompare(Operation operation)
|
private static bool IsPropagableCompare(Operation operation)
|
||||||
|
|||||||
@@ -115,7 +115,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
|
|||||||
{
|
{
|
||||||
NumberLocals(cfg, regMasks.RegistersCount);
|
NumberLocals(cfg, regMasks.RegistersCount);
|
||||||
|
|
||||||
var context = new AllocationContext(stackAlloc, regMasks, _intervals.Count);
|
AllocationContext context = new(stackAlloc, regMasks, _intervals.Count);
|
||||||
|
|
||||||
BuildIntervals(cfg, context);
|
BuildIntervals(cfg, context);
|
||||||
|
|
||||||
@@ -839,7 +839,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
|
|||||||
{
|
{
|
||||||
dest.NumberLocal(_intervals.Count);
|
dest.NumberLocal(_intervals.Count);
|
||||||
|
|
||||||
LiveInterval interval = new LiveInterval(dest);
|
LiveInterval interval = new(dest);
|
||||||
_intervals.Add(interval);
|
_intervals.Add(interval);
|
||||||
|
|
||||||
SetVisited(dest);
|
SetVisited(dest);
|
||||||
@@ -847,7 +847,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
|
|||||||
// If this is a copy (or copy-like operation), set the copy source interval as well.
|
// If this is a copy (or copy-like operation), set the copy source interval as well.
|
||||||
// This is used for register preferencing later on, which allows the copy to be eliminated
|
// This is used for register preferencing later on, which allows the copy to be eliminated
|
||||||
// in some cases.
|
// in some cases.
|
||||||
if (node.Instruction == Instruction.Copy || node.Instruction == Instruction.ZeroExtend32)
|
if (node.Instruction is Instruction.Copy or Instruction.ZeroExtend32)
|
||||||
{
|
{
|
||||||
Operand source = node.GetSource(0);
|
Operand source = node.GetSource(0);
|
||||||
|
|
||||||
@@ -1120,8 +1120,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
|
|||||||
|
|
||||||
private static bool IsLocalOrRegister(OperandKind kind)
|
private static bool IsLocalOrRegister(OperandKind kind)
|
||||||
{
|
{
|
||||||
return kind == OperandKind.LocalVariable ||
|
return kind is OperandKind.LocalVariable or OperandKind.Register;
|
||||||
kind == OperandKind.Register;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -387,7 +387,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
|
|||||||
|
|
||||||
public override int GetHashCode()
|
public override int GetHashCode()
|
||||||
{
|
{
|
||||||
return HashCode.Combine((IntPtr)_data);
|
return HashCode.Combine((nint)_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
|
|||||||
@@ -15,12 +15,12 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
|
|||||||
{
|
{
|
||||||
if (_count + 1 > _capacity)
|
if (_count + 1 > _capacity)
|
||||||
{
|
{
|
||||||
var oldSpan = Span;
|
Span<LiveInterval> oldSpan = Span;
|
||||||
|
|
||||||
_capacity = Math.Max(4, _capacity * 2);
|
_capacity = Math.Max(4, _capacity * 2);
|
||||||
_items = Allocators.References.Allocate<LiveInterval>((uint)_capacity);
|
_items = Allocators.References.Allocate<LiveInterval>((uint)_capacity);
|
||||||
|
|
||||||
var newSpan = Span;
|
Span<LiveInterval> newSpan = Span;
|
||||||
|
|
||||||
oldSpan.CopyTo(newSpan);
|
oldSpan.CopyTo(newSpan);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
|
|||||||
|
|
||||||
public override int GetHashCode()
|
public override int GetHashCode()
|
||||||
{
|
{
|
||||||
return HashCode.Combine((IntPtr)_data);
|
return HashCode.Combine((nint)_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
|
|||||||
@@ -16,12 +16,12 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
|
|||||||
{
|
{
|
||||||
if (Count + 1 > _capacity)
|
if (Count + 1 > _capacity)
|
||||||
{
|
{
|
||||||
var oldSpan = Span;
|
Span<int> oldSpan = Span;
|
||||||
|
|
||||||
_capacity = Math.Max(4, _capacity * 2);
|
_capacity = Math.Max(4, _capacity * 2);
|
||||||
_items = Allocators.Default.Allocate<int>((uint)_capacity);
|
_items = Allocators.Default.Allocate<int>((uint)_capacity);
|
||||||
|
|
||||||
var newSpan = Span;
|
Span<int> newSpan = Span;
|
||||||
|
|
||||||
oldSpan.CopyTo(newSpan);
|
oldSpan.CopyTo(newSpan);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using ARMeilleure.CodeGen.Linking;
|
using ARMeilleure.CodeGen.Linking;
|
||||||
using ARMeilleure.IntermediateRepresentation;
|
using ARMeilleure.IntermediateRepresentation;
|
||||||
|
using Microsoft.IO;
|
||||||
using Ryujinx.Common.Memory;
|
using Ryujinx.Common.Memory;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
@@ -1106,17 +1107,17 @@ namespace ARMeilleure.CodeGen.X86
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (flags.HasFlag(InstructionFlags.Prefix66))
|
if ((flags & InstructionFlags.Prefix66) != 0)
|
||||||
{
|
{
|
||||||
WriteByte(0x66);
|
WriteByte(0x66);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (flags.HasFlag(InstructionFlags.PrefixF2))
|
if ((flags & InstructionFlags.PrefixF2) != 0f)
|
||||||
{
|
{
|
||||||
WriteByte(0xf2);
|
WriteByte(0xf2);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (flags.HasFlag(InstructionFlags.PrefixF3))
|
if ((flags & InstructionFlags.PrefixF3) != 0f)
|
||||||
{
|
{
|
||||||
WriteByte(0xf3);
|
WriteByte(0xf3);
|
||||||
}
|
}
|
||||||
@@ -1324,8 +1325,8 @@ namespace ARMeilleure.CodeGen.X86
|
|||||||
|
|
||||||
public (byte[], RelocInfo) GetCode()
|
public (byte[], RelocInfo) GetCode()
|
||||||
{
|
{
|
||||||
var jumps = CollectionsMarshal.AsSpan(_jumps);
|
Span<Jump> jumps = CollectionsMarshal.AsSpan(_jumps);
|
||||||
var relocs = CollectionsMarshal.AsSpan(_relocs);
|
Span<Reloc> relocs = CollectionsMarshal.AsSpan(_relocs);
|
||||||
|
|
||||||
// Write jump relative offsets.
|
// Write jump relative offsets.
|
||||||
bool modified;
|
bool modified;
|
||||||
@@ -1410,13 +1411,13 @@ namespace ARMeilleure.CodeGen.X86
|
|||||||
// Write the code, ignoring the dummy bytes after jumps, into a new stream.
|
// Write the code, ignoring the dummy bytes after jumps, into a new stream.
|
||||||
_stream.Seek(0, SeekOrigin.Begin);
|
_stream.Seek(0, SeekOrigin.Begin);
|
||||||
|
|
||||||
using var codeStream = MemoryStreamManager.Shared.GetStream();
|
using RecyclableMemoryStream codeStream = MemoryStreamManager.Shared.GetStream();
|
||||||
var assembler = new Assembler(codeStream, HasRelocs);
|
Assembler assembler = new(codeStream, HasRelocs);
|
||||||
|
|
||||||
bool hasRelocs = HasRelocs;
|
bool hasRelocs = HasRelocs;
|
||||||
int relocIndex = 0;
|
int relocIndex = 0;
|
||||||
int relocOffset = 0;
|
int relocOffset = 0;
|
||||||
var relocEntries = hasRelocs
|
RelocEntry[] relocEntries = hasRelocs
|
||||||
? new RelocEntry[relocs.Length]
|
? new RelocEntry[relocs.Length]
|
||||||
: Array.Empty<RelocEntry>();
|
: Array.Empty<RelocEntry>();
|
||||||
|
|
||||||
@@ -1469,15 +1470,15 @@ namespace ARMeilleure.CodeGen.X86
|
|||||||
|
|
||||||
_stream.CopyTo(codeStream);
|
_stream.CopyTo(codeStream);
|
||||||
|
|
||||||
var code = codeStream.ToArray();
|
byte[] code = codeStream.ToArray();
|
||||||
var relocInfo = new RelocInfo(relocEntries);
|
RelocInfo relocInfo = new(relocEntries);
|
||||||
|
|
||||||
return (code, relocInfo);
|
return (code, relocInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool Is64Bits(OperandType type)
|
private static bool Is64Bits(OperandType type)
|
||||||
{
|
{
|
||||||
return type == OperandType.I64 || type == OperandType.FP64;
|
return type is OperandType.I64 or OperandType.FP64;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool IsImm8(ulong immediate, OperandType type)
|
private static bool IsImm8(ulong immediate, OperandType type)
|
||||||
|
|||||||
@@ -175,8 +175,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||||||
// The only blocks which can have 0 successors are exit blocks.
|
// The only blocks which can have 0 successors are exit blocks.
|
||||||
Operation last = block.Operations.Last;
|
Operation last = block.Operations.Last;
|
||||||
|
|
||||||
Debug.Assert(last.Instruction == Instruction.Tailcall ||
|
Debug.Assert(last.Instruction is Instruction.Tailcall or Instruction.Return);
|
||||||
last.Instruction == Instruction.Return);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -478,7 +477,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||||||
Debug.Assert(HardwareCapabilities.SupportsVexEncoding);
|
Debug.Assert(HardwareCapabilities.SupportsVexEncoding);
|
||||||
|
|
||||||
Debug.Assert(dest.Kind == OperandKind.Register && src1.Kind == OperandKind.Register && src2.Kind == OperandKind.Register);
|
Debug.Assert(dest.Kind == OperandKind.Register && src1.Kind == OperandKind.Register && src2.Kind == OperandKind.Register);
|
||||||
Debug.Assert(src3.Kind == OperandKind.Register || src3.Kind == OperandKind.Memory);
|
Debug.Assert(src3.Kind is OperandKind.Register or OperandKind.Memory);
|
||||||
|
|
||||||
EnsureSameType(dest, src1, src2, src3);
|
EnsureSameType(dest, src1, src2, src3);
|
||||||
Debug.Assert(dest.Type == OperandType.V128);
|
Debug.Assert(dest.Type == OperandType.V128);
|
||||||
@@ -623,7 +622,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||||||
|
|
||||||
Debug.Assert(comp.Kind == OperandKind.Constant);
|
Debug.Assert(comp.Kind == OperandKind.Constant);
|
||||||
|
|
||||||
var cond = ((Comparison)comp.AsInt32()).ToX86Condition();
|
X86Condition cond = ((Comparison)comp.AsInt32()).ToX86Condition();
|
||||||
|
|
||||||
GenerateCompareCommon(context, operation);
|
GenerateCompareCommon(context, operation);
|
||||||
|
|
||||||
@@ -661,7 +660,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||||||
Debug.Assert(dest.Type == OperandType.I32);
|
Debug.Assert(dest.Type == OperandType.I32);
|
||||||
Debug.Assert(comp.Kind == OperandKind.Constant);
|
Debug.Assert(comp.Kind == OperandKind.Constant);
|
||||||
|
|
||||||
var cond = ((Comparison)comp.AsInt32()).ToX86Condition();
|
X86Condition cond = ((Comparison)comp.AsInt32()).ToX86Condition();
|
||||||
|
|
||||||
GenerateCompareCommon(context, operation);
|
GenerateCompareCommon(context, operation);
|
||||||
|
|
||||||
@@ -788,7 +787,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||||||
Operand dest = operation.Destination;
|
Operand dest = operation.Destination;
|
||||||
Operand source = operation.GetSource(0);
|
Operand source = operation.GetSource(0);
|
||||||
|
|
||||||
Debug.Assert(dest.Type == OperandType.FP32 || dest.Type == OperandType.FP64);
|
Debug.Assert(dest.Type is OperandType.FP32 or OperandType.FP64);
|
||||||
|
|
||||||
if (dest.Type == OperandType.FP32)
|
if (dest.Type == OperandType.FP32)
|
||||||
{
|
{
|
||||||
@@ -1723,7 +1722,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Debug.Assert(op1.Kind == OperandKind.Register || op1.Kind == OperandKind.Memory);
|
Debug.Assert(op1.Kind is OperandKind.Register or OperandKind.Memory);
|
||||||
Debug.Assert(op1.Kind == op2.Kind);
|
Debug.Assert(op1.Kind == op2.Kind);
|
||||||
Debug.Assert(op1.Value == op2.Value);
|
Debug.Assert(op1.Value == op2.Value);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||||||
|
|
||||||
memGetXcr0.Reprotect(0, (ulong)asmGetXcr0.Length, MemoryPermission.ReadAndExecute);
|
memGetXcr0.Reprotect(0, (ulong)asmGetXcr0.Length, MemoryPermission.ReadAndExecute);
|
||||||
|
|
||||||
var fGetXcr0 = Marshal.GetDelegateForFunctionPointer<GetXcr0>(memGetXcr0.Pointer);
|
GetXcr0 fGetXcr0 = Marshal.GetDelegateForFunctionPointer<GetXcr0>(memGetXcr0.Pointer);
|
||||||
|
|
||||||
return fGetXcr0();
|
return fGetXcr0();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -312,9 +312,9 @@ namespace ARMeilleure.CodeGen.X86
|
|||||||
|
|
||||||
case Instruction.Extended:
|
case Instruction.Extended:
|
||||||
{
|
{
|
||||||
bool isBlend = node.Intrinsic == Intrinsic.X86Blendvpd ||
|
bool isBlend = node.Intrinsic is Intrinsic.X86Blendvpd
|
||||||
node.Intrinsic == Intrinsic.X86Blendvps ||
|
or Intrinsic.X86Blendvps
|
||||||
node.Intrinsic == Intrinsic.X86Pblendvb;
|
or Intrinsic.X86Pblendvb;
|
||||||
|
|
||||||
// BLENDVPD, BLENDVPS, PBLENDVB last operand is always implied to be XMM0 when VEX is not supported.
|
// BLENDVPD, BLENDVPS, PBLENDVB last operand is always implied to be XMM0 when VEX is not supported.
|
||||||
// SHA256RNDS2 always has an implied XMM0 as a last operand.
|
// SHA256RNDS2 always has an implied XMM0 as a last operand.
|
||||||
@@ -513,8 +513,8 @@ namespace ARMeilleure.CodeGen.X86
|
|||||||
Operand dest = node.Destination;
|
Operand dest = node.Destination;
|
||||||
Operand source = node.GetSource(0);
|
Operand source = node.GetSource(0);
|
||||||
|
|
||||||
Debug.Assert(dest.Type == OperandType.FP32 ||
|
Debug.Assert(dest.Type is OperandType.FP32 or OperandType.FP64,
|
||||||
dest.Type == OperandType.FP64, $"Invalid destination type \"{dest.Type}\".");
|
$"Invalid destination type \"{dest.Type}\".");
|
||||||
|
|
||||||
Operation currentNode = node;
|
Operation currentNode = node;
|
||||||
|
|
||||||
@@ -759,9 +759,9 @@ namespace ARMeilleure.CodeGen.X86
|
|||||||
|
|
||||||
Debug.Assert(comp.Kind == OperandKind.Constant);
|
Debug.Assert(comp.Kind == OperandKind.Constant);
|
||||||
|
|
||||||
var compType = (Comparison)comp.AsInt32();
|
Comparison compType = (Comparison)comp.AsInt32();
|
||||||
|
|
||||||
return compType == Comparison.Equal || compType == Comparison.NotEqual;
|
return compType is Comparison.Equal or Comparison.NotEqual;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,13 +13,13 @@ namespace ARMeilleure.CodeGen.X86
|
|||||||
|
|
||||||
public static void RunPass(ControlFlowGraph cfg)
|
public static void RunPass(ControlFlowGraph cfg)
|
||||||
{
|
{
|
||||||
var constants = new Dictionary<ulong, Operand>();
|
Dictionary<ulong, Operand> constants = new();
|
||||||
|
|
||||||
Operand GetConstantCopy(BasicBlock block, Operation operation, Operand source)
|
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
|
// 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).
|
// to avoid overflow of the counts field (that is limited to 16 bits).
|
||||||
if (!constants.TryGetValue(source.Value, out var constant) || constant.UsesCount > MaxConstantUses)
|
if (!constants.TryGetValue(source.Value, out Operand constant) || constant.UsesCount > MaxConstantUses)
|
||||||
{
|
{
|
||||||
constant = Local(source.Type);
|
constant = Local(source.Type);
|
||||||
|
|
||||||
@@ -248,12 +248,12 @@ namespace ARMeilleure.CodeGen.X86
|
|||||||
|
|
||||||
private static bool IsMemoryLoadOrStore(Instruction inst)
|
private static bool IsMemoryLoadOrStore(Instruction inst)
|
||||||
{
|
{
|
||||||
return inst == Instruction.Load ||
|
return inst is Instruction.Load
|
||||||
inst == Instruction.Load16 ||
|
or Instruction.Load16
|
||||||
inst == Instruction.Load8 ||
|
or Instruction.Load8
|
||||||
inst == Instruction.Store ||
|
or Instruction.Store
|
||||||
inst == Instruction.Store16 ||
|
or Instruction.Store16
|
||||||
inst == Instruction.Store8;
|
or Instruction.Store8;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ namespace ARMeilleure.Common
|
|||||||
private List<PageInfo> _pages;
|
private List<PageInfo> _pages;
|
||||||
private readonly ulong _pageSize;
|
private readonly ulong _pageSize;
|
||||||
private readonly uint _pageCount;
|
private readonly uint _pageCount;
|
||||||
private readonly List<IntPtr> _extras;
|
private readonly List<nint> _extras;
|
||||||
|
|
||||||
public ArenaAllocator(uint pageSize, uint pageCount)
|
public ArenaAllocator(uint pageSize, uint pageCount)
|
||||||
{
|
{
|
||||||
@@ -64,7 +64,7 @@ namespace ARMeilleure.Common
|
|||||||
{
|
{
|
||||||
void* extra = NativeAllocator.Instance.Allocate(size);
|
void* extra = NativeAllocator.Instance.Allocate(size);
|
||||||
|
|
||||||
_extras.Add((IntPtr)extra);
|
_extras.Add((nint)extra);
|
||||||
|
|
||||||
return extra;
|
return extra;
|
||||||
}
|
}
|
||||||
@@ -114,7 +114,7 @@ namespace ARMeilleure.Common
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Free extra blocks that are not page-sized
|
// Free extra blocks that are not page-sized
|
||||||
foreach (IntPtr ptr in _extras)
|
foreach (nint ptr in _extras)
|
||||||
{
|
{
|
||||||
NativeAllocator.Instance.Free((void*)ptr);
|
NativeAllocator.Instance.Free((void*)ptr);
|
||||||
}
|
}
|
||||||
@@ -173,7 +173,7 @@ namespace ARMeilleure.Common
|
|||||||
NativeAllocator.Instance.Free(info.Pointer);
|
NativeAllocator.Instance.Free(info.Pointer);
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (IntPtr ptr in _extras)
|
foreach (nint ptr in _extras)
|
||||||
{
|
{
|
||||||
NativeAllocator.Instance.Free((void*)ptr);
|
NativeAllocator.Instance.Free((void*)ptr);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -129,13 +129,13 @@ namespace ARMeilleure.Common
|
|||||||
|
|
||||||
if (count > _count)
|
if (count > _count)
|
||||||
{
|
{
|
||||||
var oldMask = _masks;
|
long* oldMask = _masks;
|
||||||
var oldSpan = new Span<long>(_masks, _count);
|
Span<long> oldSpan = new(_masks, _count);
|
||||||
|
|
||||||
_masks = _allocator.Allocate<long>((uint)count);
|
_masks = _allocator.Allocate<long>((uint)count);
|
||||||
_count = count;
|
_count = count;
|
||||||
|
|
||||||
var newSpan = new Span<long>(_masks, _count);
|
Span<long> newSpan = new(_masks, _count);
|
||||||
|
|
||||||
oldSpan.CopyTo(newSpan);
|
oldSpan.CopyTo(newSpan);
|
||||||
newSpan[oldSpan.Length..].Clear();
|
newSpan[oldSpan.Length..].Clear();
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ namespace ARMeilleure.Common
|
|||||||
private int _freeHint;
|
private int _freeHint;
|
||||||
private readonly int _pageCapacity; // Number of entries per page.
|
private readonly int _pageCapacity; // Number of entries per page.
|
||||||
private readonly int _pageLogCapacity;
|
private readonly int _pageLogCapacity;
|
||||||
private readonly Dictionary<int, IntPtr> _pages;
|
private readonly Dictionary<int, nint> _pages;
|
||||||
private readonly BitMap _allocated;
|
private readonly BitMap _allocated;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -41,7 +41,7 @@ namespace ARMeilleure.Common
|
|||||||
}
|
}
|
||||||
|
|
||||||
_allocated = new BitMap(NativeAllocator.Instance);
|
_allocated = new BitMap(NativeAllocator.Instance);
|
||||||
_pages = new Dictionary<int, IntPtr>();
|
_pages = new Dictionary<int, nint>();
|
||||||
_pageLogCapacity = BitOperations.Log2((uint)(pageSize / sizeof(TEntry)));
|
_pageLogCapacity = BitOperations.Log2((uint)(pageSize / sizeof(TEntry)));
|
||||||
_pageCapacity = 1 << _pageLogCapacity;
|
_pageCapacity = 1 << _pageLogCapacity;
|
||||||
}
|
}
|
||||||
@@ -63,7 +63,7 @@ namespace ARMeilleure.Common
|
|||||||
}
|
}
|
||||||
|
|
||||||
int index = _freeHint++;
|
int index = _freeHint++;
|
||||||
var page = GetPage(index);
|
Span<TEntry> page = GetPage(index);
|
||||||
|
|
||||||
_allocated.Set(index);
|
_allocated.Set(index);
|
||||||
|
|
||||||
@@ -111,7 +111,7 @@ namespace ARMeilleure.Common
|
|||||||
throw new ArgumentException("Entry at the specified index was not allocated", nameof(index));
|
throw new ArgumentException("Entry at the specified index was not allocated", nameof(index));
|
||||||
}
|
}
|
||||||
|
|
||||||
var page = GetPage(index);
|
Span<TEntry> page = GetPage(index);
|
||||||
|
|
||||||
return ref GetValue(page, index);
|
return ref GetValue(page, index);
|
||||||
}
|
}
|
||||||
@@ -136,11 +136,11 @@ namespace ARMeilleure.Common
|
|||||||
/// <returns>Page for the specified <see cref="index"/></returns>
|
/// <returns>Page for the specified <see cref="index"/></returns>
|
||||||
private unsafe Span<TEntry> GetPage(int index)
|
private unsafe Span<TEntry> GetPage(int index)
|
||||||
{
|
{
|
||||||
var pageIndex = (int)((uint)(index & ~(_pageCapacity - 1)) >> _pageLogCapacity);
|
int pageIndex = (int)((uint)(index & ~(_pageCapacity - 1)) >> _pageLogCapacity);
|
||||||
|
|
||||||
if (!_pages.TryGetValue(pageIndex, out IntPtr page))
|
if (!_pages.TryGetValue(pageIndex, out nint page))
|
||||||
{
|
{
|
||||||
page = (IntPtr)NativeAllocator.Instance.Allocate((uint)sizeof(TEntry) * (uint)_pageCapacity);
|
page = (nint)NativeAllocator.Instance.Allocate((uint)sizeof(TEntry) * (uint)_pageCapacity);
|
||||||
|
|
||||||
_pages.Add(pageIndex, page);
|
_pages.Add(pageIndex, page);
|
||||||
}
|
}
|
||||||
@@ -168,7 +168,7 @@ namespace ARMeilleure.Common
|
|||||||
{
|
{
|
||||||
_allocated.Dispose();
|
_allocated.Dispose();
|
||||||
|
|
||||||
foreach (var page in _pages.Values)
|
foreach (IntPtr page in _pages.Values)
|
||||||
{
|
{
|
||||||
NativeAllocator.Instance.Free((void*)page);
|
NativeAllocator.Instance.Free((void*)page);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ namespace ARMeilleure.Common
|
|||||||
|
|
||||||
public override void* Allocate(ulong size)
|
public override void* Allocate(ulong size)
|
||||||
{
|
{
|
||||||
void* result = (void*)Marshal.AllocHGlobal((IntPtr)size);
|
void* result = (void*)Marshal.AllocHGlobal((nint)size);
|
||||||
|
|
||||||
if (result == null)
|
if (result == null)
|
||||||
{
|
{
|
||||||
@@ -21,7 +21,7 @@ namespace ARMeilleure.Common
|
|||||||
|
|
||||||
public override void Free(void* block)
|
public override void Free(void* block)
|
||||||
{
|
{
|
||||||
Marshal.FreeHGlobal((IntPtr)block);
|
Marshal.FreeHGlobal((nint)block);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -254,8 +254,7 @@ namespace ARMeilleure.Decoders
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Compare and branch instructions are always conditional.
|
// Compare and branch instructions are always conditional.
|
||||||
if (opCode.Instruction.Name == InstName.Cbz ||
|
if (opCode.Instruction.Name is InstName.Cbz or InstName.Cbnz)
|
||||||
opCode.Instruction.Name == InstName.Cbnz)
|
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -284,7 +283,7 @@ namespace ARMeilleure.Decoders
|
|||||||
// register (Rt == 15 or (mask & (1 << 15)) != 0), and cases where there is
|
// register (Rt == 15 or (mask & (1 << 15)) != 0), and cases where there is
|
||||||
// a write back to PC (wback == true && Rn == 15), however the later may
|
// a write back to PC (wback == true && Rn == 15), however the later may
|
||||||
// be "undefined" depending on the CPU, so compilers should not produce that.
|
// be "undefined" depending on the CPU, so compilers should not produce that.
|
||||||
if (opCode is IOpCode32Mem || opCode is IOpCode32MemMult)
|
if (opCode is IOpCode32Mem or IOpCode32MemMult)
|
||||||
{
|
{
|
||||||
int rt, rn;
|
int rt, rn;
|
||||||
|
|
||||||
@@ -326,15 +325,12 @@ namespace ARMeilleure.Decoders
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Explicit branch instructions.
|
// Explicit branch instructions.
|
||||||
return opCode is IOpCode32BImm ||
|
return opCode is IOpCode32BImm or IOpCode32BReg;
|
||||||
opCode is IOpCode32BReg;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool IsCall(OpCode opCode)
|
private static bool IsCall(OpCode opCode)
|
||||||
{
|
{
|
||||||
return opCode.Instruction.Name == InstName.Bl ||
|
return opCode.Instruction.Name is InstName.Bl or InstName.Blr or InstName.Blx;
|
||||||
opCode.Instruction.Name == InstName.Blr ||
|
|
||||||
opCode.Instruction.Name == InstName.Blx;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool IsException(OpCode opCode)
|
private static bool IsException(OpCode opCode)
|
||||||
@@ -344,9 +340,7 @@ namespace ARMeilleure.Decoders
|
|||||||
|
|
||||||
private static bool IsTrap(OpCode opCode)
|
private static bool IsTrap(OpCode opCode)
|
||||||
{
|
{
|
||||||
return opCode.Instruction.Name == InstName.Brk ||
|
return opCode.Instruction.Name is InstName.Brk or InstName.Trap or InstName.Und;
|
||||||
opCode.Instruction.Name == InstName.Trap ||
|
|
||||||
opCode.Instruction.Name == InstName.Und;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static OpCode DecodeOpCode(IMemoryManager memory, ulong address, ExecutionMode mode)
|
public static OpCode DecodeOpCode(IMemoryManager memory, ulong address, ExecutionMode mode)
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ namespace ARMeilleure.Decoders
|
|||||||
|
|
||||||
public OpCode32SimdDupElem(InstDescriptor inst, ulong address, int opCode, bool isThumb) : base(inst, address, opCode, isThumb)
|
public OpCode32SimdDupElem(InstDescriptor inst, ulong address, int opCode, bool isThumb) : base(inst, address, opCode, isThumb)
|
||||||
{
|
{
|
||||||
var opc = (opCode >> 16) & 0xf;
|
int opc = (opCode >> 16) & 0xf;
|
||||||
|
|
||||||
if ((opc & 0b1) == 1)
|
if ((opc & 0b1) == 1)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ namespace ARMeilleure.Decoders
|
|||||||
Op = (opCode >> 20) & 0x1;
|
Op = (opCode >> 20) & 0x1;
|
||||||
U = ((opCode >> 23) & 1) != 0;
|
U = ((opCode >> 23) & 1) != 0;
|
||||||
|
|
||||||
var opc = (((opCode >> 23) & 1) << 4) | (((opCode >> 21) & 0x3) << 2) | ((opCode >> 5) & 0x3);
|
int opc = (((opCode >> 23) & 1) << 4) | (((opCode >> 21) & 0x3) << 2) | ((opCode >> 5) & 0x3);
|
||||||
|
|
||||||
if ((opc & 0b01000) == 0b01000)
|
if ((opc & 0b01000) == 0b01000)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ namespace ARMeilleure.Decoders
|
|||||||
}
|
}
|
||||||
else if (DataOp == DataOp.Logical)
|
else if (DataOp == DataOp.Logical)
|
||||||
{
|
{
|
||||||
var bm = DecoderHelper.DecodeBitMask(opCode, true);
|
DecoderHelper.BitMask bm = DecoderHelper.DecodeBitMask(opCode, true);
|
||||||
|
|
||||||
if (bm.IsUndefined)
|
if (bm.IsUndefined)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ namespace ARMeilleure.Decoders
|
|||||||
|
|
||||||
public OpCodeBfm(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
public OpCodeBfm(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
||||||
{
|
{
|
||||||
var bm = DecoderHelper.DecodeBitMask(opCode, false);
|
DecoderHelper.BitMask bm = DecoderHelper.DecodeBitMask(opCode, false);
|
||||||
|
|
||||||
if (bm.IsUndefined)
|
if (bm.IsUndefined)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -28,8 +28,7 @@ namespace ARMeilleure.Decoders
|
|||||||
MemOp type = WBack ? (MemOp)((opCode >> 10) & 3) : MemOp.Unsigned;
|
MemOp type = WBack ? (MemOp)((opCode >> 10) & 3) : MemOp.Unsigned;
|
||||||
|
|
||||||
PostIdx = type == MemOp.PostIndexed;
|
PostIdx = type == MemOp.PostIndexed;
|
||||||
Unscaled = type == MemOp.Unscaled ||
|
Unscaled = type is MemOp.Unscaled or MemOp.Unprivileged;
|
||||||
type == MemOp.Unprivileged;
|
|
||||||
|
|
||||||
// Unscaled and Unprivileged doesn't write back,
|
// Unscaled and Unprivileged doesn't write back,
|
||||||
// but they do use the 9-bits Signed Immediate.
|
// but they do use the 9-bits Signed Immediate.
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ namespace ARMeilleure.Decoders.Optimizations
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var newBlocks = new List<Block>(blocks.Count);
|
List<Block> newBlocks = new(blocks.Count);
|
||||||
|
|
||||||
// Finally, rebuild decoded block list, ignoring blocks outside the contiguous range.
|
// Finally, rebuild decoded block list, ignoring blocks outside the contiguous range.
|
||||||
for (int i = 0; i < blocks.Count; i++)
|
for (int i = 0; i < blocks.Count; i++)
|
||||||
|
|||||||
@@ -141,7 +141,7 @@ namespace ARMeilleure.Diagnostics
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case OperandKind.Memory:
|
case OperandKind.Memory:
|
||||||
var memOp = operand.GetMemory();
|
MemoryOperand memOp = operand.GetMemory();
|
||||||
|
|
||||||
_builder.Append('[');
|
_builder.Append('[');
|
||||||
|
|
||||||
@@ -235,8 +235,7 @@ namespace ARMeilleure.Diagnostics
|
|||||||
{
|
{
|
||||||
_builder.Append('.').Append(operation.Intrinsic);
|
_builder.Append('.').Append(operation.Intrinsic);
|
||||||
}
|
}
|
||||||
else if (operation.Instruction == Instruction.BranchIf ||
|
else if (operation.Instruction is Instruction.BranchIf or Instruction.Compare)
|
||||||
operation.Instruction == Instruction.Compare)
|
|
||||||
{
|
{
|
||||||
comparison = true;
|
comparison = true;
|
||||||
}
|
}
|
||||||
@@ -285,7 +284,7 @@ namespace ARMeilleure.Diagnostics
|
|||||||
|
|
||||||
public static string GetDump(ControlFlowGraph cfg)
|
public static string GetDump(ControlFlowGraph cfg)
|
||||||
{
|
{
|
||||||
var dumper = new IRDumper(1);
|
IRDumper dumper = new(1);
|
||||||
|
|
||||||
for (BasicBlock block = cfg.Blocks.First; block != null; block = block.ListNext)
|
for (BasicBlock block = cfg.Blocks.First; block != null; block = block.ListNext)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -415,7 +415,7 @@ namespace ARMeilleure.Instructions
|
|||||||
{
|
{
|
||||||
IOpCode32AluBf op = (IOpCode32AluBf)context.CurrOp;
|
IOpCode32AluBf op = (IOpCode32AluBf)context.CurrOp;
|
||||||
|
|
||||||
var msb = op.Lsb + op.Msb; // For this instruction, the msb is actually a width.
|
int msb = op.Lsb + op.Msb; // For this instruction, the msb is actually a width.
|
||||||
|
|
||||||
Operand n = GetIntA32(context, op.Rn);
|
Operand n = GetIntA32(context, op.Rn);
|
||||||
Operand res = context.ShiftRightSI(context.ShiftLeft(n, Const(31 - msb)), Const(31 - op.Msb));
|
Operand res = context.ShiftRightSI(context.ShiftLeft(n, Const(31 - msb)), Const(31 - op.Msb));
|
||||||
@@ -547,7 +547,7 @@ namespace ARMeilleure.Instructions
|
|||||||
{
|
{
|
||||||
IOpCode32AluBf op = (IOpCode32AluBf)context.CurrOp;
|
IOpCode32AluBf op = (IOpCode32AluBf)context.CurrOp;
|
||||||
|
|
||||||
var msb = op.Lsb + op.Msb; // For this instruction, the msb is actually a width.
|
int msb = op.Lsb + op.Msb; // For this instruction, the msb is actually a width.
|
||||||
|
|
||||||
Operand n = GetIntA32(context, op.Rn);
|
Operand n = GetIntA32(context, op.Rn);
|
||||||
Operand res = context.ShiftRightUI(context.ShiftLeft(n, Const(31 - msb)), Const(31 - op.Msb));
|
Operand res = context.ShiftRightUI(context.ShiftLeft(n, Const(31 - msb)), Const(31 - op.Msb));
|
||||||
|
|||||||
@@ -283,8 +283,6 @@ namespace ARMeilleure.Instructions
|
|||||||
switch (op.ShiftType)
|
switch (op.ShiftType)
|
||||||
{
|
{
|
||||||
case ShiftType.Lsr:
|
case ShiftType.Lsr:
|
||||||
shift = 32;
|
|
||||||
break;
|
|
||||||
case ShiftType.Asr:
|
case ShiftType.Asr:
|
||||||
shift = 32;
|
shift = 32;
|
||||||
break;
|
break;
|
||||||
@@ -332,8 +330,6 @@ namespace ARMeilleure.Instructions
|
|||||||
switch (shiftType)
|
switch (shiftType)
|
||||||
{
|
{
|
||||||
case ShiftType.Lsr:
|
case ShiftType.Lsr:
|
||||||
shift = 32;
|
|
||||||
break;
|
|
||||||
case ShiftType.Asr:
|
case ShiftType.Asr:
|
||||||
shift = 32;
|
shift = 32;
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
context.LoadFromContext();
|
context.LoadFromContext();
|
||||||
|
|
||||||
context.Return(Const(op.Address));
|
InstEmitFlowHelper.EmitReturn(context, Const(op.Address));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Svc(ArmEmitterContext context)
|
public static void Svc(ArmEmitterContext context)
|
||||||
@@ -49,7 +49,7 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
context.LoadFromContext();
|
context.LoadFromContext();
|
||||||
|
|
||||||
context.Return(Const(op.Address));
|
InstEmitFlowHelper.EmitReturn(context, Const(op.Address));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
context.LoadFromContext();
|
context.LoadFromContext();
|
||||||
|
|
||||||
context.Return(Const(context.CurrOp.Address));
|
InstEmitFlowHelper.EmitReturn(context, Const(context.CurrOp.Address));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ namespace ARMeilleure.Instructions
|
|||||||
{
|
{
|
||||||
OpCodeBReg op = (OpCodeBReg)context.CurrOp;
|
OpCodeBReg op = (OpCodeBReg)context.CurrOp;
|
||||||
|
|
||||||
context.Return(GetIntOrZR(context, op.Rn));
|
EmitReturn(context, GetIntOrZR(context, op.Rn));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Tbnz(ArmEmitterContext context) => EmitTb(context, onNotZero: true);
|
public static void Tbnz(ArmEmitterContext context) => EmitTb(context, onNotZero: true);
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using ARMeilleure.CodeGen.Linking;
|
using ARMeilleure.CodeGen.Linking;
|
||||||
|
using ARMeilleure.Common;
|
||||||
using ARMeilleure.Decoders;
|
using ARMeilleure.Decoders;
|
||||||
using ARMeilleure.IntermediateRepresentation;
|
using ARMeilleure.IntermediateRepresentation;
|
||||||
using ARMeilleure.State;
|
using ARMeilleure.State;
|
||||||
@@ -12,6 +13,10 @@ namespace ARMeilleure.Instructions
|
|||||||
{
|
{
|
||||||
static class InstEmitFlowHelper
|
static class InstEmitFlowHelper
|
||||||
{
|
{
|
||||||
|
// How many calls we can have in our call stack before we give up and return to the dispatcher.
|
||||||
|
// This prevents stack overflows caused by deep recursive calls.
|
||||||
|
private const int MaxCallDepth = 200;
|
||||||
|
|
||||||
public static void EmitCondBranch(ArmEmitterContext context, Operand target, Condition cond)
|
public static void EmitCondBranch(ArmEmitterContext context, Operand target, Condition cond)
|
||||||
{
|
{
|
||||||
if (cond != Condition.Al)
|
if (cond != Condition.Al)
|
||||||
@@ -163,12 +168,7 @@ namespace ARMeilleure.Instructions
|
|||||||
{
|
{
|
||||||
if (isReturn)
|
if (isReturn)
|
||||||
{
|
{
|
||||||
if (target.Type == OperandType.I32)
|
EmitReturn(context, target);
|
||||||
{
|
|
||||||
target = context.ZeroExtend32(OperandType.I64, target);
|
|
||||||
}
|
|
||||||
|
|
||||||
context.Return(target);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -176,6 +176,19 @@ namespace ARMeilleure.Instructions
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void EmitReturn(ArmEmitterContext context, Operand target)
|
||||||
|
{
|
||||||
|
Operand nativeContext = context.LoadArgument(OperandType.I64, 0);
|
||||||
|
DecreaseCallDepth(context, nativeContext);
|
||||||
|
|
||||||
|
if (target.Type == OperandType.I32)
|
||||||
|
{
|
||||||
|
target = context.ZeroExtend32(OperandType.I64, target);
|
||||||
|
}
|
||||||
|
|
||||||
|
context.Return(target);
|
||||||
|
}
|
||||||
|
|
||||||
private static void EmitTableBranch(ArmEmitterContext context, Operand guestAddress, bool isJump)
|
private static void EmitTableBranch(ArmEmitterContext context, Operand guestAddress, bool isJump)
|
||||||
{
|
{
|
||||||
context.StoreToContext();
|
context.StoreToContext();
|
||||||
@@ -193,7 +206,7 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
Operand hostAddress;
|
Operand hostAddress;
|
||||||
|
|
||||||
var table = context.FunctionTable;
|
IAddressTable<ulong> table = context.FunctionTable;
|
||||||
|
|
||||||
// If address is mapped onto the function table, we can skip the table walk. Otherwise we fallback
|
// If address is mapped onto the function table, we can skip the table walk. Otherwise we fallback
|
||||||
// onto the dispatch stub.
|
// onto the dispatch stub.
|
||||||
@@ -218,7 +231,7 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
for (int i = 0; i < table.Levels.Length; i++)
|
for (int i = 0; i < table.Levels.Length; i++)
|
||||||
{
|
{
|
||||||
var level = table.Levels[i];
|
AddressTableLevel level = table.Levels[i];
|
||||||
int clearBits = 64 - (level.Index + level.Length);
|
int clearBits = 64 - (level.Index + level.Length);
|
||||||
|
|
||||||
Operand index = context.ShiftLeft(
|
Operand index = context.ShiftLeft(
|
||||||
@@ -238,6 +251,8 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
if (isJump)
|
if (isJump)
|
||||||
{
|
{
|
||||||
|
DecreaseCallDepth(context, nativeContext);
|
||||||
|
|
||||||
context.Tailcall(hostAddress, nativeContext);
|
context.Tailcall(hostAddress, nativeContext);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -259,8 +274,42 @@ namespace ARMeilleure.Instructions
|
|||||||
Operand lblContinue = context.GetLabel(nextAddr.Value);
|
Operand lblContinue = context.GetLabel(nextAddr.Value);
|
||||||
context.BranchIf(lblContinue, returnAddress, nextAddr, Comparison.Equal, BasicBlockFrequency.Cold);
|
context.BranchIf(lblContinue, returnAddress, nextAddr, Comparison.Equal, BasicBlockFrequency.Cold);
|
||||||
|
|
||||||
|
DecreaseCallDepth(context, nativeContext);
|
||||||
|
|
||||||
context.Return(returnAddress);
|
context.Return(returnAddress);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void EmitCallDepthCheckAndIncrement(EmitterContext context, Operand guestAddress)
|
||||||
|
{
|
||||||
|
if (!Optimizations.EnableDeepCallRecursionProtection)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Operand nativeContext = context.LoadArgument(OperandType.I64, 0);
|
||||||
|
Operand callDepthAddr = context.Add(nativeContext, Const((ulong)NativeContext.GetCallDepthOffset()));
|
||||||
|
Operand currentCallDepth = context.Load(OperandType.I32, callDepthAddr);
|
||||||
|
Operand lblDoCall = Label();
|
||||||
|
|
||||||
|
context.BranchIf(lblDoCall, currentCallDepth, Const(MaxCallDepth), Comparison.LessUI);
|
||||||
|
context.Store(callDepthAddr, context.Subtract(currentCallDepth, Const(1)));
|
||||||
|
context.Return(guestAddress);
|
||||||
|
|
||||||
|
context.MarkLabel(lblDoCall);
|
||||||
|
context.Store(callDepthAddr, context.Add(currentCallDepth, Const(1)));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void DecreaseCallDepth(EmitterContext context, Operand nativeContext)
|
||||||
|
{
|
||||||
|
if (!Optimizations.EnableDeepCallRecursionProtection)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Operand callDepthAddr = context.Add(nativeContext, Const((ulong)NativeContext.GetCallDepthOffset()));
|
||||||
|
Operand currentCallDepth = context.Load(OperandType.I32, callDepthAddr);
|
||||||
|
context.Store(callDepthAddr, context.Subtract(currentCallDepth, Const(1)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -140,7 +140,7 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
if (pair)
|
if (pair)
|
||||||
{
|
{
|
||||||
Debug.Assert(op.Size == 2 || op.Size == 3, "Invalid size for pairwise store.");
|
Debug.Assert(op.Size is 2 or 3, "Invalid size for pairwise store.");
|
||||||
|
|
||||||
Operand t2 = GetIntOrZR(context, op.Rt2);
|
Operand t2 = GetIntOrZR(context, op.Rt2);
|
||||||
|
|
||||||
|
|||||||
@@ -143,8 +143,8 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
Operand address = context.Copy(GetIntA32(context, op.Rn));
|
Operand address = context.Copy(GetIntA32(context, op.Rn));
|
||||||
|
|
||||||
var exclusive = (accType & AccessType.Exclusive) != 0;
|
bool exclusive = (accType & AccessType.Exclusive) != 0;
|
||||||
var ordered = (accType & AccessType.Ordered) != 0;
|
bool ordered = (accType & AccessType.Ordered) != 0;
|
||||||
|
|
||||||
if ((accType & AccessType.Load) != 0)
|
if ((accType & AccessType.Load) != 0)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ namespace ARMeilleure.Instructions
|
|||||||
{
|
{
|
||||||
Operand value = GetInt(context, rt);
|
Operand value = GetInt(context, rt);
|
||||||
|
|
||||||
if (ext == Extension.Sx32 || ext == Extension.Sx64)
|
if (ext is Extension.Sx32 or Extension.Sx64)
|
||||||
{
|
{
|
||||||
OperandType destType = ext == Extension.Sx64 ? OperandType.I64 : OperandType.I32;
|
OperandType destType = ext == Extension.Sx64 ? OperandType.I64 : OperandType.I32;
|
||||||
|
|
||||||
@@ -124,8 +124,7 @@ namespace ARMeilleure.Instructions
|
|||||||
private static bool IsSimd(ArmEmitterContext context)
|
private static bool IsSimd(ArmEmitterContext context)
|
||||||
{
|
{
|
||||||
return context.CurrOp is IOpCodeSimd &&
|
return context.CurrOp is IOpCodeSimd &&
|
||||||
!(context.CurrOp is OpCodeSimdMemMs ||
|
!(context.CurrOp is OpCodeSimdMemMs or OpCodeSimdMemSs);
|
||||||
context.CurrOp is OpCodeSimdMemSs);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Operand EmitReadInt(ArmEmitterContext context, Operand address, int size)
|
public static Operand EmitReadInt(ArmEmitterContext context, Operand address, int size)
|
||||||
@@ -305,8 +304,6 @@ namespace ARMeilleure.Instructions
|
|||||||
context.Store16(physAddr, value);
|
context.Store16(physAddr, value);
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
context.Store(physAddr, value);
|
|
||||||
break;
|
|
||||||
case 3:
|
case 3:
|
||||||
context.Store(physAddr, value);
|
context.Store(physAddr, value);
|
||||||
break;
|
break;
|
||||||
@@ -591,8 +588,6 @@ namespace ARMeilleure.Instructions
|
|||||||
value = context.VectorInsert16(vector, value, elem);
|
value = context.VectorInsert16(vector, value, elem);
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
value = context.VectorInsert(vector, value, elem);
|
|
||||||
break;
|
|
||||||
case 3:
|
case 3:
|
||||||
value = context.VectorInsert(vector, value, elem);
|
value = context.VectorInsert(vector, value, elem);
|
||||||
break;
|
break;
|
||||||
@@ -733,8 +728,6 @@ namespace ARMeilleure.Instructions
|
|||||||
switch (op.ShiftType)
|
switch (op.ShiftType)
|
||||||
{
|
{
|
||||||
case ShiftType.Lsr:
|
case ShiftType.Lsr:
|
||||||
shift = 32;
|
|
||||||
break;
|
|
||||||
case ShiftType.Asr:
|
case ShiftType.Asr:
|
||||||
shift = 32;
|
shift = 32;
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -229,7 +229,7 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
private static Operand ZerosOrOnes(ArmEmitterContext context, Operand fromBool, OperandType baseType)
|
private static Operand ZerosOrOnes(ArmEmitterContext context, Operand fromBool, OperandType baseType)
|
||||||
{
|
{
|
||||||
var ones = (baseType == OperandType.I64) ? Const(-1L) : Const(-1);
|
Operand ones = (baseType == OperandType.I64) ? Const(-1L) : Const(-1);
|
||||||
|
|
||||||
return context.ConditionalSelect(fromBool, ones, Const(baseType, 0L));
|
return context.ConditionalSelect(fromBool, ones, Const(baseType, 0L));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1119,7 +1119,7 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
private static Operand EmitFPConvert(ArmEmitterContext context, Operand value, int size, bool signed)
|
private static Operand EmitFPConvert(ArmEmitterContext context, Operand value, int size, bool signed)
|
||||||
{
|
{
|
||||||
Debug.Assert(value.Type == OperandType.I32 || value.Type == OperandType.I64);
|
Debug.Assert(value.Type is OperandType.I32 or OperandType.I64);
|
||||||
Debug.Assert((uint)size < 2);
|
Debug.Assert((uint)size < 2);
|
||||||
|
|
||||||
OperandType type = size == 0 ? OperandType.FP32 : OperandType.FP64;
|
OperandType type = size == 0 ? OperandType.FP32 : OperandType.FP64;
|
||||||
@@ -1136,7 +1136,7 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
private static Operand EmitScalarFcvts(ArmEmitterContext context, Operand value, int fBits)
|
private static Operand EmitScalarFcvts(ArmEmitterContext context, Operand value, int fBits)
|
||||||
{
|
{
|
||||||
Debug.Assert(value.Type == OperandType.FP32 || value.Type == OperandType.FP64);
|
Debug.Assert(value.Type is OperandType.FP32 or OperandType.FP64);
|
||||||
|
|
||||||
value = EmitF2iFBitsMul(context, value, fBits);
|
value = EmitF2iFBitsMul(context, value, fBits);
|
||||||
|
|
||||||
@@ -1160,7 +1160,7 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
private static Operand EmitScalarFcvtu(ArmEmitterContext context, Operand value, int fBits)
|
private static Operand EmitScalarFcvtu(ArmEmitterContext context, Operand value, int fBits)
|
||||||
{
|
{
|
||||||
Debug.Assert(value.Type == OperandType.FP32 || value.Type == OperandType.FP64);
|
Debug.Assert(value.Type is OperandType.FP32 or OperandType.FP64);
|
||||||
|
|
||||||
value = EmitF2iFBitsMul(context, value, fBits);
|
value = EmitF2iFBitsMul(context, value, fBits);
|
||||||
|
|
||||||
@@ -1184,7 +1184,7 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
private static Operand EmitF2iFBitsMul(ArmEmitterContext context, Operand value, int fBits)
|
private static Operand EmitF2iFBitsMul(ArmEmitterContext context, Operand value, int fBits)
|
||||||
{
|
{
|
||||||
Debug.Assert(value.Type == OperandType.FP32 || value.Type == OperandType.FP64);
|
Debug.Assert(value.Type is OperandType.FP32 or OperandType.FP64);
|
||||||
|
|
||||||
if (fBits == 0)
|
if (fBits == 0)
|
||||||
{
|
{
|
||||||
@@ -1203,7 +1203,7 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
private static Operand EmitI2fFBitsMul(ArmEmitterContext context, Operand value, int fBits)
|
private static Operand EmitI2fFBitsMul(ArmEmitterContext context, Operand value, int fBits)
|
||||||
{
|
{
|
||||||
Debug.Assert(value.Type == OperandType.FP32 || value.Type == OperandType.FP64);
|
Debug.Assert(value.Type is OperandType.FP32 or OperandType.FP64);
|
||||||
|
|
||||||
if (fBits == 0)
|
if (fBits == 0)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -118,15 +118,15 @@ namespace ARMeilleure.Instructions
|
|||||||
{
|
{
|
||||||
OpCode32SimdCvtFFixed op = (OpCode32SimdCvtFFixed)context.CurrOp;
|
OpCode32SimdCvtFFixed op = (OpCode32SimdCvtFFixed)context.CurrOp;
|
||||||
|
|
||||||
var toFixed = op.Opc == 1;
|
bool toFixed = op.Opc == 1;
|
||||||
int fracBits = op.Fbits;
|
int fracBits = op.Fbits;
|
||||||
var unsigned = op.U;
|
bool unsigned = op.U;
|
||||||
|
|
||||||
if (toFixed) // F32 to S32 or U32 (fixed)
|
if (toFixed) // F32 to S32 or U32 (fixed)
|
||||||
{
|
{
|
||||||
EmitVectorUnaryOpF32(context, (op1) =>
|
EmitVectorUnaryOpF32(context, (op1) =>
|
||||||
{
|
{
|
||||||
var scaledValue = context.Multiply(op1, ConstF(MathF.Pow(2f, fracBits)));
|
Operand scaledValue = context.Multiply(op1, ConstF(MathF.Pow(2f, fracBits)));
|
||||||
MethodInfo info = unsigned ? typeof(SoftFallback).GetMethod(nameof(SoftFallback.SatF32ToU32)) : typeof(SoftFallback).GetMethod(nameof(SoftFallback.SatF32ToS32));
|
MethodInfo info = unsigned ? typeof(SoftFallback).GetMethod(nameof(SoftFallback.SatF32ToU32)) : typeof(SoftFallback).GetMethod(nameof(SoftFallback.SatF32ToS32));
|
||||||
|
|
||||||
return context.Call(info, scaledValue);
|
return context.Call(info, scaledValue);
|
||||||
@@ -136,7 +136,7 @@ namespace ARMeilleure.Instructions
|
|||||||
{
|
{
|
||||||
EmitVectorUnaryOpI32(context, (op1) =>
|
EmitVectorUnaryOpI32(context, (op1) =>
|
||||||
{
|
{
|
||||||
var floatValue = unsigned ? context.ConvertToFPUI(OperandType.FP32, op1) : context.ConvertToFP(OperandType.FP32, op1);
|
Operand floatValue = unsigned ? context.ConvertToFPUI(OperandType.FP32, op1) : context.ConvertToFP(OperandType.FP32, op1);
|
||||||
|
|
||||||
return context.Multiply(floatValue, ConstF(1f / MathF.Pow(2f, fracBits)));
|
return context.Multiply(floatValue, ConstF(1f / MathF.Pow(2f, fracBits)));
|
||||||
}, !unsigned);
|
}, !unsigned);
|
||||||
@@ -635,7 +635,7 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
private static Operand EmitFPConvert(ArmEmitterContext context, Operand value, OperandType type, bool signed)
|
private static Operand EmitFPConvert(ArmEmitterContext context, Operand value, OperandType type, bool signed)
|
||||||
{
|
{
|
||||||
Debug.Assert(value.Type == OperandType.I32 || value.Type == OperandType.I64);
|
Debug.Assert(value.Type is OperandType.I32 or OperandType.I64);
|
||||||
|
|
||||||
if (signed)
|
if (signed)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -363,7 +363,7 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
public static Operand EmitCountSetBits8(ArmEmitterContext context, Operand op) // "size" is 8 (SIMD&FP Inst.).
|
public static Operand EmitCountSetBits8(ArmEmitterContext context, Operand op) // "size" is 8 (SIMD&FP Inst.).
|
||||||
{
|
{
|
||||||
Debug.Assert(op.Type == OperandType.I32 || op.Type == OperandType.I64);
|
Debug.Assert(op.Type is OperandType.I32 or OperandType.I64);
|
||||||
|
|
||||||
Operand op0 = context.Subtract(op, context.BitwiseAnd(context.ShiftRightUI(op, Const(1)), Const(op.Type, 0x55L)));
|
Operand op0 = context.Subtract(op, context.BitwiseAnd(context.ShiftRightUI(op, Const(1)), Const(op.Type, 0x55L)));
|
||||||
|
|
||||||
@@ -489,7 +489,7 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
public static Operand EmitRoundByRMode(ArmEmitterContext context, Operand op)
|
public static Operand EmitRoundByRMode(ArmEmitterContext context, Operand op)
|
||||||
{
|
{
|
||||||
Debug.Assert(op.Type == OperandType.FP32 || op.Type == OperandType.FP64);
|
Debug.Assert(op.Type is OperandType.FP32 or OperandType.FP64);
|
||||||
|
|
||||||
Operand lbl1 = Label();
|
Operand lbl1 = Label();
|
||||||
Operand lbl2 = Label();
|
Operand lbl2 = Label();
|
||||||
@@ -1676,7 +1676,7 @@ namespace ARMeilleure.Instructions
|
|||||||
int eSize = 8 << size;
|
int eSize = 8 << size;
|
||||||
|
|
||||||
Debug.Assert(op.Type == OperandType.I64);
|
Debug.Assert(op.Type == OperandType.I64);
|
||||||
Debug.Assert(eSize == 8 || eSize == 16 || eSize == 32 || eSize == 64);
|
Debug.Assert(eSize is 8 or 16 or 32 or 64);
|
||||||
|
|
||||||
Operand lbl1 = Label();
|
Operand lbl1 = Label();
|
||||||
Operand lblEnd = Label();
|
Operand lblEnd = Label();
|
||||||
@@ -1709,7 +1709,7 @@ namespace ARMeilleure.Instructions
|
|||||||
int eSize = 8 << size;
|
int eSize = 8 << size;
|
||||||
|
|
||||||
Debug.Assert(op.Type == OperandType.I64);
|
Debug.Assert(op.Type == OperandType.I64);
|
||||||
Debug.Assert(eSize == 8 || eSize == 16 || eSize == 32 || eSize == 64);
|
Debug.Assert(eSize is 8 or 16 or 32 or 64);
|
||||||
|
|
||||||
Operand lblEnd = Label();
|
Operand lblEnd = Label();
|
||||||
|
|
||||||
@@ -1735,7 +1735,7 @@ namespace ARMeilleure.Instructions
|
|||||||
int eSizeDst = 8 << sizeDst;
|
int eSizeDst = 8 << sizeDst;
|
||||||
|
|
||||||
Debug.Assert(op.Type == OperandType.I64);
|
Debug.Assert(op.Type == OperandType.I64);
|
||||||
Debug.Assert(eSizeDst == 8 || eSizeDst == 16 || eSizeDst == 32);
|
Debug.Assert(eSizeDst is 8 or 16 or 32);
|
||||||
|
|
||||||
Operand lbl1 = Label();
|
Operand lbl1 = Label();
|
||||||
Operand lblEnd = Label();
|
Operand lblEnd = Label();
|
||||||
@@ -1768,7 +1768,7 @@ namespace ARMeilleure.Instructions
|
|||||||
int eSizeDst = 8 << sizeDst;
|
int eSizeDst = 8 << sizeDst;
|
||||||
|
|
||||||
Debug.Assert(op.Type == OperandType.I64);
|
Debug.Assert(op.Type == OperandType.I64);
|
||||||
Debug.Assert(eSizeDst == 8 || eSizeDst == 16 || eSizeDst == 32);
|
Debug.Assert(eSizeDst is 8 or 16 or 32);
|
||||||
|
|
||||||
Operand lblEnd = Label();
|
Operand lblEnd = Label();
|
||||||
|
|
||||||
@@ -2082,8 +2082,6 @@ namespace ARMeilleure.Instructions
|
|||||||
vector = context.VectorInsert16(vector, value, index);
|
vector = context.VectorInsert16(vector, value, index);
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
vector = context.VectorInsert(vector, value, index);
|
|
||||||
break;
|
|
||||||
case 3:
|
case 3:
|
||||||
vector = context.VectorInsert(vector, value, index);
|
vector = context.VectorInsert(vector, value, index);
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ namespace ARMeilleure.Instructions
|
|||||||
{
|
{
|
||||||
Debug.Assert(type != OperandType.V128);
|
Debug.Assert(type != OperandType.V128);
|
||||||
|
|
||||||
if (type == OperandType.FP64 || type == OperandType.I64)
|
if (type is OperandType.FP64 or OperandType.I64)
|
||||||
{
|
{
|
||||||
// From dreg.
|
// From dreg.
|
||||||
return context.VectorExtract(type, GetVecA32(reg >> 1), reg & 1);
|
return context.VectorExtract(type, GetVecA32(reg >> 1), reg & 1);
|
||||||
@@ -48,7 +48,7 @@ namespace ARMeilleure.Instructions
|
|||||||
Debug.Assert(value.Type != OperandType.V128);
|
Debug.Assert(value.Type != OperandType.V128);
|
||||||
|
|
||||||
Operand vec, insert;
|
Operand vec, insert;
|
||||||
if (value.Type == OperandType.FP64 || value.Type == OperandType.I64)
|
if (value.Type is OperandType.FP64 or OperandType.I64)
|
||||||
{
|
{
|
||||||
// From dreg.
|
// From dreg.
|
||||||
vec = GetVecA32(reg >> 1);
|
vec = GetVecA32(reg >> 1);
|
||||||
@@ -71,7 +71,7 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
public static void InsertScalar16(ArmEmitterContext context, int reg, bool top, Operand value)
|
public static void InsertScalar16(ArmEmitterContext context, int reg, bool top, Operand value)
|
||||||
{
|
{
|
||||||
Debug.Assert(value.Type == OperandType.FP32 || value.Type == OperandType.I32);
|
Debug.Assert(value.Type is OperandType.FP32 or OperandType.I32);
|
||||||
|
|
||||||
Operand vec, insert;
|
Operand vec, insert;
|
||||||
vec = GetVecA32(reg >> 2);
|
vec = GetVecA32(reg >> 2);
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ namespace ARMeilleure.Instructions
|
|||||||
{
|
{
|
||||||
if (op.Replicate)
|
if (op.Replicate)
|
||||||
{
|
{
|
||||||
var regs = (count > 1) ? 1 : op.Increment;
|
int regs = (count > 1) ? 1 : op.Increment;
|
||||||
for (int reg = 0; reg < regs; reg++)
|
for (int reg = 0; reg < regs; reg++)
|
||||||
{
|
{
|
||||||
int dreg = reg + d;
|
int dreg = reg + d;
|
||||||
|
|||||||
@@ -1634,7 +1634,7 @@ namespace ARMeilleure.Instructions
|
|||||||
int eSize = 8 << size;
|
int eSize = 8 << size;
|
||||||
|
|
||||||
Debug.Assert(op.Type == OperandType.I64);
|
Debug.Assert(op.Type == OperandType.I64);
|
||||||
Debug.Assert(eSize == 8 || eSize == 16 || eSize == 32 || eSize == 64);
|
Debug.Assert(eSize is 8 or 16 or 32 or 64);
|
||||||
|
|
||||||
Operand res = context.AllocateLocal(OperandType.I64);
|
Operand res = context.AllocateLocal(OperandType.I64);
|
||||||
|
|
||||||
@@ -1657,7 +1657,7 @@ namespace ARMeilleure.Instructions
|
|||||||
int eSize = 8 << size;
|
int eSize = 8 << size;
|
||||||
|
|
||||||
Debug.Assert(op.Type == OperandType.I64);
|
Debug.Assert(op.Type == OperandType.I64);
|
||||||
Debug.Assert(eSize == 8 || eSize == 16 || eSize == 32 || eSize == 64);
|
Debug.Assert(eSize is 8 or 16 or 32 or 64);
|
||||||
|
|
||||||
Operand lblEnd = Label();
|
Operand lblEnd = Label();
|
||||||
|
|
||||||
@@ -1732,7 +1732,7 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
Debug.Assert(op.Type == OperandType.I64);
|
Debug.Assert(op.Type == OperandType.I64);
|
||||||
Debug.Assert(shiftLsB.Type == OperandType.I32);
|
Debug.Assert(shiftLsB.Type == OperandType.I32);
|
||||||
Debug.Assert(eSize == 8 || eSize == 16 || eSize == 32 || eSize == 64);
|
Debug.Assert(eSize is 8 or 16 or 32 or 64);
|
||||||
|
|
||||||
Operand lbl1 = Label();
|
Operand lbl1 = Label();
|
||||||
Operand lblEnd = Label();
|
Operand lblEnd = Label();
|
||||||
@@ -1769,7 +1769,7 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
Debug.Assert(op.Type == OperandType.I64);
|
Debug.Assert(op.Type == OperandType.I64);
|
||||||
Debug.Assert(shiftLsB.Type == OperandType.I32);
|
Debug.Assert(shiftLsB.Type == OperandType.I32);
|
||||||
Debug.Assert(eSize == 8 || eSize == 16 || eSize == 32 || eSize == 64);
|
Debug.Assert(eSize is 8 or 16 or 32 or 64);
|
||||||
|
|
||||||
Operand lbl1 = Label();
|
Operand lbl1 = Label();
|
||||||
Operand lbl2 = Label();
|
Operand lbl2 = Label();
|
||||||
|
|||||||
@@ -1,39 +1,59 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
#if ANDROID
|
||||||
using System.Linq;
|
using System.Runtime.CompilerServices;
|
||||||
|
#else
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Text;
|
#endif
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace ARMeilleure.Instructions
|
namespace ARMeilleure.Instructions
|
||||||
{
|
{
|
||||||
static class MathHelper
|
static class MathHelper
|
||||||
{
|
{
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static double Abs(double value)
|
public static double Abs(double value)
|
||||||
{
|
{
|
||||||
return Math.Abs(value);
|
return Math.Abs(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static double Ceiling(double value)
|
public static double Ceiling(double value)
|
||||||
{
|
{
|
||||||
return Math.Ceiling(value);
|
return Math.Ceiling(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static double Floor(double value)
|
public static double Floor(double value)
|
||||||
{
|
{
|
||||||
return Math.Floor(value);
|
return Math.Floor(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static double Round(double value, int mode)
|
public static double Round(double value, int mode)
|
||||||
{
|
{
|
||||||
return Math.Round(value, (MidpointRounding)mode);
|
return Math.Round(value, (MidpointRounding)mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static double Truncate(double value)
|
public static double Truncate(double value)
|
||||||
{
|
{
|
||||||
return Math.Truncate(value);
|
return Math.Truncate(value);
|
||||||
@@ -42,31 +62,51 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
static class MathHelperF
|
static class MathHelperF
|
||||||
{
|
{
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static float Abs(float value)
|
public static float Abs(float value)
|
||||||
{
|
{
|
||||||
return MathF.Abs(value);
|
return MathF.Abs(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static float Ceiling(float value)
|
public static float Ceiling(float value)
|
||||||
{
|
{
|
||||||
return MathF.Ceiling(value);
|
return MathF.Ceiling(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static float Floor(float value)
|
public static float Floor(float value)
|
||||||
{
|
{
|
||||||
return MathF.Floor(value);
|
return MathF.Floor(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static float Round(float value, int mode)
|
public static float Round(float value, int mode)
|
||||||
{
|
{
|
||||||
return MathF.Round(value, (MidpointRounding)mode);
|
return MathF.Round(value, (MidpointRounding)mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static float Truncate(float value)
|
public static float Truncate(float value)
|
||||||
{
|
{
|
||||||
return MathF.Truncate(value);
|
return MathF.Truncate(value);
|
||||||
|
|||||||
@@ -2,7 +2,11 @@ using ARMeilleure.Memory;
|
|||||||
using ARMeilleure.State;
|
using ARMeilleure.State;
|
||||||
using ARMeilleure.Translation;
|
using ARMeilleure.Translation;
|
||||||
using System;
|
using System;
|
||||||
|
#if ANDROID
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
#else
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace ARMeilleure.Instructions
|
namespace ARMeilleure.Instructions
|
||||||
{
|
{
|
||||||
@@ -35,7 +39,11 @@ namespace ARMeilleure.Instructions
|
|||||||
Context = null;
|
Context = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static void Break(ulong address, int imm)
|
public static void Break(ulong address, int imm)
|
||||||
{
|
{
|
||||||
Statistics.PauseTimer();
|
Statistics.PauseTimer();
|
||||||
@@ -45,7 +53,11 @@ namespace ARMeilleure.Instructions
|
|||||||
Statistics.ResumeTimer();
|
Statistics.ResumeTimer();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static void SupervisorCall(ulong address, int imm)
|
public static void SupervisorCall(ulong address, int imm)
|
||||||
{
|
{
|
||||||
Statistics.PauseTimer();
|
Statistics.PauseTimer();
|
||||||
@@ -55,7 +67,11 @@ namespace ARMeilleure.Instructions
|
|||||||
Statistics.ResumeTimer();
|
Statistics.ResumeTimer();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static void Undefined(ulong address, int opCode)
|
public static void Undefined(ulong address, int opCode)
|
||||||
{
|
{
|
||||||
Statistics.PauseTimer();
|
Statistics.PauseTimer();
|
||||||
@@ -66,31 +82,51 @@ namespace ARMeilleure.Instructions
|
|||||||
}
|
}
|
||||||
|
|
||||||
#region "System registers"
|
#region "System registers"
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static ulong GetCtrEl0()
|
public static ulong GetCtrEl0()
|
||||||
{
|
{
|
||||||
return GetContext().CtrEl0;
|
return GetContext().CtrEl0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static ulong GetDczidEl0()
|
public static ulong GetDczidEl0()
|
||||||
{
|
{
|
||||||
return GetContext().DczidEl0;
|
return GetContext().DczidEl0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static ulong GetCntfrqEl0()
|
public static ulong GetCntfrqEl0()
|
||||||
{
|
{
|
||||||
return GetContext().CntfrqEl0;
|
return GetContext().CntfrqEl0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static ulong GetCntpctEl0()
|
public static ulong GetCntpctEl0()
|
||||||
{
|
{
|
||||||
return GetContext().CntpctEl0;
|
return GetContext().CntpctEl0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static ulong GetCntvctEl0()
|
public static ulong GetCntvctEl0()
|
||||||
{
|
{
|
||||||
return GetContext().CntvctEl0;
|
return GetContext().CntvctEl0;
|
||||||
@@ -98,31 +134,51 @@ namespace ARMeilleure.Instructions
|
|||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region "Read"
|
#region "Read"
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static byte ReadByte(ulong address)
|
public static byte ReadByte(ulong address)
|
||||||
{
|
{
|
||||||
return GetMemoryManager().ReadGuest<byte>(address);
|
return GetMemoryManager().ReadGuest<byte>(address);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static ushort ReadUInt16(ulong address)
|
public static ushort ReadUInt16(ulong address)
|
||||||
{
|
{
|
||||||
return GetMemoryManager().ReadGuest<ushort>(address);
|
return GetMemoryManager().ReadGuest<ushort>(address);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static uint ReadUInt32(ulong address)
|
public static uint ReadUInt32(ulong address)
|
||||||
{
|
{
|
||||||
return GetMemoryManager().ReadGuest<uint>(address);
|
return GetMemoryManager().ReadGuest<uint>(address);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static ulong ReadUInt64(ulong address)
|
public static ulong ReadUInt64(ulong address)
|
||||||
{
|
{
|
||||||
return GetMemoryManager().ReadGuest<ulong>(address);
|
return GetMemoryManager().ReadGuest<ulong>(address);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static V128 ReadVector128(ulong address)
|
public static V128 ReadVector128(ulong address)
|
||||||
{
|
{
|
||||||
return GetMemoryManager().ReadGuest<V128>(address);
|
return GetMemoryManager().ReadGuest<V128>(address);
|
||||||
@@ -130,56 +186,92 @@ namespace ARMeilleure.Instructions
|
|||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region "Write"
|
#region "Write"
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static void WriteByte(ulong address, byte value)
|
public static void WriteByte(ulong address, byte value)
|
||||||
{
|
{
|
||||||
GetMemoryManager().WriteGuest(address, value);
|
GetMemoryManager().WriteGuest(address, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static void WriteUInt16(ulong address, ushort value)
|
public static void WriteUInt16(ulong address, ushort value)
|
||||||
{
|
{
|
||||||
GetMemoryManager().WriteGuest(address, value);
|
GetMemoryManager().WriteGuest(address, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static void WriteUInt32(ulong address, uint value)
|
public static void WriteUInt32(ulong address, uint value)
|
||||||
{
|
{
|
||||||
GetMemoryManager().WriteGuest(address, value);
|
GetMemoryManager().WriteGuest(address, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static void WriteUInt64(ulong address, ulong value)
|
public static void WriteUInt64(ulong address, ulong value)
|
||||||
{
|
{
|
||||||
GetMemoryManager().WriteGuest(address, value);
|
GetMemoryManager().WriteGuest(address, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static void WriteVector128(ulong address, V128 value)
|
public static void WriteVector128(ulong address, V128 value)
|
||||||
{
|
{
|
||||||
GetMemoryManager().WriteGuest(address, value);
|
GetMemoryManager().WriteGuest(address, value);
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static void EnqueueForRejit(ulong address)
|
public static void EnqueueForRejit(ulong address)
|
||||||
{
|
{
|
||||||
Context.Translator.EnqueueForRejit(address, GetContext().ExecutionMode);
|
Context.Translator.EnqueueForRejit(address, GetContext().ExecutionMode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static void SignalMemoryTracking(ulong address, ulong size, byte write)
|
public static void SignalMemoryTracking(ulong address, ulong size, byte write)
|
||||||
{
|
{
|
||||||
GetMemoryManager().SignalMemoryTracking(address, size, write == 1);
|
GetMemoryManager().SignalMemoryTracking(address, size, write == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static void ThrowInvalidMemoryAccess(ulong address)
|
public static void ThrowInvalidMemoryAccess(ulong address)
|
||||||
{
|
{
|
||||||
throw new InvalidAccessException(address);
|
throw new InvalidAccessException(address);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static ulong GetFunctionAddress(ulong address)
|
public static ulong GetFunctionAddress(ulong address)
|
||||||
{
|
{
|
||||||
TranslatedFunction function = Context.Translator.GetOrTranslate(address, GetContext().ExecutionMode);
|
TranslatedFunction function = Context.Translator.GetOrTranslate(address, GetContext().ExecutionMode);
|
||||||
@@ -187,13 +279,21 @@ namespace ARMeilleure.Instructions
|
|||||||
return (ulong)function.FuncPointer.ToInt64();
|
return (ulong)function.FuncPointer.ToInt64();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static void InvalidateCacheLine(ulong address)
|
public static void InvalidateCacheLine(ulong address)
|
||||||
{
|
{
|
||||||
Context.Translator.InvalidateJitCacheRegion(address, InstEmit.DczSizeInBytes);
|
Context.Translator.InvalidateJitCacheRegion(address, InstEmit.DczSizeInBytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static byte CheckSynchronization()
|
public static byte CheckSynchronization()
|
||||||
{
|
{
|
||||||
Statistics.PauseTimer();
|
Statistics.PauseTimer();
|
||||||
|
|||||||
@@ -1,13 +1,21 @@
|
|||||||
using ARMeilleure.State;
|
using ARMeilleure.State;
|
||||||
using System;
|
using System;
|
||||||
|
#if ANDROID
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
#else
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace ARMeilleure.Instructions
|
namespace ARMeilleure.Instructions
|
||||||
{
|
{
|
||||||
static class SoftFallback
|
static class SoftFallback
|
||||||
{
|
{
|
||||||
#region "ShrImm64"
|
#region "ShrImm64"
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static long SignedShrImm64(long value, long roundConst, int shift)
|
public static long SignedShrImm64(long value, long roundConst, int shift)
|
||||||
{
|
{
|
||||||
if (roundConst == 0L)
|
if (roundConst == 0L)
|
||||||
@@ -50,7 +58,11 @@ namespace ARMeilleure.Instructions
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static ulong UnsignedShrImm64(ulong value, long roundConst, int shift)
|
public static ulong UnsignedShrImm64(ulong value, long roundConst, int shift)
|
||||||
{
|
{
|
||||||
if (roundConst == 0L)
|
if (roundConst == 0L)
|
||||||
@@ -95,7 +107,11 @@ namespace ARMeilleure.Instructions
|
|||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region "Saturation"
|
#region "Saturation"
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static int SatF32ToS32(float value)
|
public static int SatF32ToS32(float value)
|
||||||
{
|
{
|
||||||
if (float.IsNaN(value))
|
if (float.IsNaN(value))
|
||||||
@@ -107,7 +123,11 @@ namespace ARMeilleure.Instructions
|
|||||||
value <= int.MinValue ? int.MinValue : (int)value;
|
value <= int.MinValue ? int.MinValue : (int)value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static long SatF32ToS64(float value)
|
public static long SatF32ToS64(float value)
|
||||||
{
|
{
|
||||||
if (float.IsNaN(value))
|
if (float.IsNaN(value))
|
||||||
@@ -119,7 +139,11 @@ namespace ARMeilleure.Instructions
|
|||||||
value <= long.MinValue ? long.MinValue : (long)value;
|
value <= long.MinValue ? long.MinValue : (long)value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static uint SatF32ToU32(float value)
|
public static uint SatF32ToU32(float value)
|
||||||
{
|
{
|
||||||
if (float.IsNaN(value))
|
if (float.IsNaN(value))
|
||||||
@@ -131,7 +155,11 @@ namespace ARMeilleure.Instructions
|
|||||||
value <= uint.MinValue ? uint.MinValue : (uint)value;
|
value <= uint.MinValue ? uint.MinValue : (uint)value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static ulong SatF32ToU64(float value)
|
public static ulong SatF32ToU64(float value)
|
||||||
{
|
{
|
||||||
if (float.IsNaN(value))
|
if (float.IsNaN(value))
|
||||||
@@ -143,7 +171,11 @@ namespace ARMeilleure.Instructions
|
|||||||
value <= ulong.MinValue ? ulong.MinValue : (ulong)value;
|
value <= ulong.MinValue ? ulong.MinValue : (ulong)value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static int SatF64ToS32(double value)
|
public static int SatF64ToS32(double value)
|
||||||
{
|
{
|
||||||
if (double.IsNaN(value))
|
if (double.IsNaN(value))
|
||||||
@@ -155,7 +187,11 @@ namespace ARMeilleure.Instructions
|
|||||||
value <= int.MinValue ? int.MinValue : (int)value;
|
value <= int.MinValue ? int.MinValue : (int)value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static long SatF64ToS64(double value)
|
public static long SatF64ToS64(double value)
|
||||||
{
|
{
|
||||||
if (double.IsNaN(value))
|
if (double.IsNaN(value))
|
||||||
@@ -167,7 +203,11 @@ namespace ARMeilleure.Instructions
|
|||||||
value <= long.MinValue ? long.MinValue : (long)value;
|
value <= long.MinValue ? long.MinValue : (long)value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static uint SatF64ToU32(double value)
|
public static uint SatF64ToU32(double value)
|
||||||
{
|
{
|
||||||
if (double.IsNaN(value))
|
if (double.IsNaN(value))
|
||||||
@@ -179,7 +219,11 @@ namespace ARMeilleure.Instructions
|
|||||||
value <= uint.MinValue ? uint.MinValue : (uint)value;
|
value <= uint.MinValue ? uint.MinValue : (uint)value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static ulong SatF64ToU64(double value)
|
public static ulong SatF64ToU64(double value)
|
||||||
{
|
{
|
||||||
if (double.IsNaN(value))
|
if (double.IsNaN(value))
|
||||||
@@ -193,7 +237,11 @@ namespace ARMeilleure.Instructions
|
|||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region "Count"
|
#region "Count"
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static ulong CountLeadingSigns(ulong value, int size) // size is 8, 16, 32 or 64 (SIMD&FP or Base Inst.).
|
public static ulong CountLeadingSigns(ulong value, int size) // size is 8, 16, 32 or 64 (SIMD&FP or Base Inst.).
|
||||||
{
|
{
|
||||||
value ^= value >> 1;
|
value ^= value >> 1;
|
||||||
@@ -213,7 +261,11 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
private static ReadOnlySpan<byte> ClzNibbleTbl => [4, 3, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0];
|
private static ReadOnlySpan<byte> ClzNibbleTbl => [4, 3, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0];
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static ulong CountLeadingZeros(ulong value, int size) // size is 8, 16, 32 or 64 (SIMD&FP or Base Inst.).
|
public static ulong CountLeadingZeros(ulong value, int size) // size is 8, 16, 32 or 64 (SIMD&FP or Base Inst.).
|
||||||
{
|
{
|
||||||
if (value == 0ul)
|
if (value == 0ul)
|
||||||
@@ -237,49 +289,81 @@ namespace ARMeilleure.Instructions
|
|||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region "Table"
|
#region "Table"
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static V128 Tbl1(V128 vector, int bytes, V128 tb0)
|
public static V128 Tbl1(V128 vector, int bytes, V128 tb0)
|
||||||
{
|
{
|
||||||
return TblOrTbx(default, vector, bytes, tb0);
|
return TblOrTbx(default, vector, bytes, tb0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static V128 Tbl2(V128 vector, int bytes, V128 tb0, V128 tb1)
|
public static V128 Tbl2(V128 vector, int bytes, V128 tb0, V128 tb1)
|
||||||
{
|
{
|
||||||
return TblOrTbx(default, vector, bytes, tb0, tb1);
|
return TblOrTbx(default, vector, bytes, tb0, tb1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static V128 Tbl3(V128 vector, int bytes, V128 tb0, V128 tb1, V128 tb2)
|
public static V128 Tbl3(V128 vector, int bytes, V128 tb0, V128 tb1, V128 tb2)
|
||||||
{
|
{
|
||||||
return TblOrTbx(default, vector, bytes, tb0, tb1, tb2);
|
return TblOrTbx(default, vector, bytes, tb0, tb1, tb2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static V128 Tbl4(V128 vector, int bytes, V128 tb0, V128 tb1, V128 tb2, V128 tb3)
|
public static V128 Tbl4(V128 vector, int bytes, V128 tb0, V128 tb1, V128 tb2, V128 tb3)
|
||||||
{
|
{
|
||||||
return TblOrTbx(default, vector, bytes, tb0, tb1, tb2, tb3);
|
return TblOrTbx(default, vector, bytes, tb0, tb1, tb2, tb3);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static V128 Tbx1(V128 dest, V128 vector, int bytes, V128 tb0)
|
public static V128 Tbx1(V128 dest, V128 vector, int bytes, V128 tb0)
|
||||||
{
|
{
|
||||||
return TblOrTbx(dest, vector, bytes, tb0);
|
return TblOrTbx(dest, vector, bytes, tb0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static V128 Tbx2(V128 dest, V128 vector, int bytes, V128 tb0, V128 tb1)
|
public static V128 Tbx2(V128 dest, V128 vector, int bytes, V128 tb0, V128 tb1)
|
||||||
{
|
{
|
||||||
return TblOrTbx(dest, vector, bytes, tb0, tb1);
|
return TblOrTbx(dest, vector, bytes, tb0, tb1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static V128 Tbx3(V128 dest, V128 vector, int bytes, V128 tb0, V128 tb1, V128 tb2)
|
public static V128 Tbx3(V128 dest, V128 vector, int bytes, V128 tb0, V128 tb1, V128 tb2)
|
||||||
{
|
{
|
||||||
return TblOrTbx(dest, vector, bytes, tb0, tb1, tb2);
|
return TblOrTbx(dest, vector, bytes, tb0, tb1, tb2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static V128 Tbx4(V128 dest, V128 vector, int bytes, V128 tb0, V128 tb1, V128 tb2, V128 tb3)
|
public static V128 Tbx4(V128 dest, V128 vector, int bytes, V128 tb0, V128 tb1, V128 tb2, V128 tb3)
|
||||||
{
|
{
|
||||||
return TblOrTbx(dest, vector, bytes, tb0, tb1, tb2, tb3);
|
return TblOrTbx(dest, vector, bytes, tb0, tb1, tb2, tb3);
|
||||||
@@ -321,22 +405,54 @@ namespace ARMeilleure.Instructions
|
|||||||
private const uint Crc32RevPoly = 0xedb88320;
|
private const uint Crc32RevPoly = 0xedb88320;
|
||||||
private const uint Crc32cRevPoly = 0x82f63b78;
|
private const uint Crc32cRevPoly = 0x82f63b78;
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static uint Crc32b(uint crc, byte value) => Crc32(crc, Crc32RevPoly, value);
|
public static uint Crc32b(uint crc, byte value) => Crc32(crc, Crc32RevPoly, value);
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static uint Crc32h(uint crc, ushort value) => Crc32h(crc, Crc32RevPoly, value);
|
public static uint Crc32h(uint crc, ushort value) => Crc32h(crc, Crc32RevPoly, value);
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static uint Crc32w(uint crc, uint value) => Crc32w(crc, Crc32RevPoly, value);
|
public static uint Crc32w(uint crc, uint value) => Crc32w(crc, Crc32RevPoly, value);
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static uint Crc32x(uint crc, ulong value) => Crc32x(crc, Crc32RevPoly, value);
|
public static uint Crc32x(uint crc, ulong value) => Crc32x(crc, Crc32RevPoly, value);
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static uint Crc32cb(uint crc, byte value) => Crc32(crc, Crc32cRevPoly, value);
|
public static uint Crc32cb(uint crc, byte value) => Crc32(crc, Crc32cRevPoly, value);
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static uint Crc32ch(uint crc, ushort value) => Crc32h(crc, Crc32cRevPoly, value);
|
public static uint Crc32ch(uint crc, ushort value) => Crc32h(crc, Crc32cRevPoly, value);
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static uint Crc32cw(uint crc, uint value) => Crc32w(crc, Crc32cRevPoly, value);
|
public static uint Crc32cw(uint crc, uint value) => Crc32w(crc, Crc32cRevPoly, value);
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static uint Crc32cx(uint crc, ulong value) => Crc32x(crc, Crc32cRevPoly, value);
|
public static uint Crc32cx(uint crc, ulong value) => Crc32x(crc, Crc32cRevPoly, value);
|
||||||
|
|
||||||
private static uint Crc32h(uint crc, uint poly, ushort val)
|
private static uint Crc32h(uint crc, uint poly, ushort val)
|
||||||
@@ -387,25 +503,41 @@ namespace ARMeilleure.Instructions
|
|||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region "Aes"
|
#region "Aes"
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static V128 Decrypt(V128 value, V128 roundKey)
|
public static V128 Decrypt(V128 value, V128 roundKey)
|
||||||
{
|
{
|
||||||
return CryptoHelper.AesInvSubBytes(CryptoHelper.AesInvShiftRows(value ^ roundKey));
|
return CryptoHelper.AesInvSubBytes(CryptoHelper.AesInvShiftRows(value ^ roundKey));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static V128 Encrypt(V128 value, V128 roundKey)
|
public static V128 Encrypt(V128 value, V128 roundKey)
|
||||||
{
|
{
|
||||||
return CryptoHelper.AesSubBytes(CryptoHelper.AesShiftRows(value ^ roundKey));
|
return CryptoHelper.AesSubBytes(CryptoHelper.AesShiftRows(value ^ roundKey));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static V128 InverseMixColumns(V128 value)
|
public static V128 InverseMixColumns(V128 value)
|
||||||
{
|
{
|
||||||
return CryptoHelper.AesInvMixColumns(value);
|
return CryptoHelper.AesInvMixColumns(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static V128 MixColumns(V128 value)
|
public static V128 MixColumns(V128 value)
|
||||||
{
|
{
|
||||||
return CryptoHelper.AesMixColumns(value);
|
return CryptoHelper.AesMixColumns(value);
|
||||||
@@ -413,7 +545,11 @@ namespace ARMeilleure.Instructions
|
|||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region "Sha1"
|
#region "Sha1"
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static V128 HashChoose(V128 hash_abcd, uint hash_e, V128 wk)
|
public static V128 HashChoose(V128 hash_abcd, uint hash_e, V128 wk)
|
||||||
{
|
{
|
||||||
for (int e = 0; e <= 3; e++)
|
for (int e = 0; e <= 3; e++)
|
||||||
@@ -434,13 +570,21 @@ namespace ARMeilleure.Instructions
|
|||||||
return hash_abcd;
|
return hash_abcd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static uint FixedRotate(uint hash_e)
|
public static uint FixedRotate(uint hash_e)
|
||||||
{
|
{
|
||||||
return hash_e.Rol(30);
|
return hash_e.Rol(30);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static V128 HashMajority(V128 hash_abcd, uint hash_e, V128 wk)
|
public static V128 HashMajority(V128 hash_abcd, uint hash_e, V128 wk)
|
||||||
{
|
{
|
||||||
for (int e = 0; e <= 3; e++)
|
for (int e = 0; e <= 3; e++)
|
||||||
@@ -461,7 +605,11 @@ namespace ARMeilleure.Instructions
|
|||||||
return hash_abcd;
|
return hash_abcd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static V128 HashParity(V128 hash_abcd, uint hash_e, V128 wk)
|
public static V128 HashParity(V128 hash_abcd, uint hash_e, V128 wk)
|
||||||
{
|
{
|
||||||
for (int e = 0; e <= 3; e++)
|
for (int e = 0; e <= 3; e++)
|
||||||
@@ -482,7 +630,11 @@ namespace ARMeilleure.Instructions
|
|||||||
return hash_abcd;
|
return hash_abcd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static V128 Sha1SchedulePart1(V128 w0_3, V128 w4_7, V128 w8_11)
|
public static V128 Sha1SchedulePart1(V128 w0_3, V128 w4_7, V128 w8_11)
|
||||||
{
|
{
|
||||||
ulong t2 = w4_7.Extract<ulong>(0);
|
ulong t2 = w4_7.Extract<ulong>(0);
|
||||||
@@ -493,7 +645,11 @@ namespace ARMeilleure.Instructions
|
|||||||
return result ^ (w0_3 ^ w8_11);
|
return result ^ (w0_3 ^ w8_11);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static V128 Sha1SchedulePart2(V128 tw0_3, V128 w12_15)
|
public static V128 Sha1SchedulePart2(V128 tw0_3, V128 w12_15)
|
||||||
{
|
{
|
||||||
V128 t = tw0_3 ^ (w12_15 >> 32);
|
V128 t = tw0_3 ^ (w12_15 >> 32);
|
||||||
@@ -538,19 +694,31 @@ namespace ARMeilleure.Instructions
|
|||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region "Sha256"
|
#region "Sha256"
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static V128 HashLower(V128 hash_abcd, V128 hash_efgh, V128 wk)
|
public static V128 HashLower(V128 hash_abcd, V128 hash_efgh, V128 wk)
|
||||||
{
|
{
|
||||||
return Sha256Hash(hash_abcd, hash_efgh, wk, part1: true);
|
return Sha256Hash(hash_abcd, hash_efgh, wk, part1: true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static V128 HashUpper(V128 hash_abcd, V128 hash_efgh, V128 wk)
|
public static V128 HashUpper(V128 hash_abcd, V128 hash_efgh, V128 wk)
|
||||||
{
|
{
|
||||||
return Sha256Hash(hash_abcd, hash_efgh, wk, part1: false);
|
return Sha256Hash(hash_abcd, hash_efgh, wk, part1: false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static V128 Sha256SchedulePart1(V128 w0_3, V128 w4_7)
|
public static V128 Sha256SchedulePart1(V128 w0_3, V128 w4_7)
|
||||||
{
|
{
|
||||||
V128 result = new();
|
V128 result = new();
|
||||||
@@ -569,7 +737,11 @@ namespace ARMeilleure.Instructions
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static V128 Sha256SchedulePart2(V128 w0_3, V128 w8_11, V128 w12_15)
|
public static V128 Sha256SchedulePart2(V128 w0_3, V128 w8_11, V128 w12_15)
|
||||||
{
|
{
|
||||||
V128 result = new();
|
V128 result = new();
|
||||||
@@ -671,7 +843,11 @@ namespace ARMeilleure.Instructions
|
|||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static V128 PolynomialMult64_128(ulong op1, ulong op2)
|
public static V128 PolynomialMult64_128(ulong op1, ulong op2)
|
||||||
{
|
{
|
||||||
V128 result = V128.Zero;
|
V128 result = V128.Zero;
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -32,7 +32,7 @@ namespace ARMeilleure.IntermediateRepresentation
|
|||||||
/// <exception cref="ArgumentException"><typeparamref name="T"/> is not pointer sized.</exception>
|
/// <exception cref="ArgumentException"><typeparamref name="T"/> is not pointer sized.</exception>
|
||||||
public IntrusiveList()
|
public IntrusiveList()
|
||||||
{
|
{
|
||||||
if (Unsafe.SizeOf<T>() != IntPtr.Size)
|
if (Unsafe.SizeOf<T>() != nint.Size)
|
||||||
{
|
{
|
||||||
throw new ArgumentException("T must be a reference type or a pointer sized struct.");
|
throw new ArgumentException("T must be a reference type or a pointer sized struct.");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
using System;
|
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
@@ -24,7 +23,7 @@ namespace ARMeilleure.IntermediateRepresentation
|
|||||||
{
|
{
|
||||||
Debug.Assert(operand.Kind == OperandKind.Memory);
|
Debug.Assert(operand.Kind == OperandKind.Memory);
|
||||||
|
|
||||||
_data = (Data*)Unsafe.As<Operand, IntPtr>(ref operand);
|
_data = (Data*)Unsafe.As<Operand, nint>(ref operand);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Operand BaseAddress
|
public Operand BaseAddress
|
||||||
|
|||||||
@@ -304,7 +304,7 @@ namespace ARMeilleure.IntermediateRepresentation
|
|||||||
ushort newCount = checked((ushort)(count + 1));
|
ushort newCount = checked((ushort)(count + 1));
|
||||||
ushort newCapacity = (ushort)Math.Min(capacity * 2, ushort.MaxValue);
|
ushort newCapacity = (ushort)Math.Min(capacity * 2, ushort.MaxValue);
|
||||||
|
|
||||||
var oldSpan = new Span<T>(data, count);
|
Span<T> oldSpan = new(data, count);
|
||||||
|
|
||||||
capacity = newCapacity;
|
capacity = newCapacity;
|
||||||
data = Allocators.References.Allocate<T>(capacity);
|
data = Allocators.References.Allocate<T>(capacity);
|
||||||
@@ -338,7 +338,7 @@ namespace ARMeilleure.IntermediateRepresentation
|
|||||||
throw new OverflowException();
|
throw new OverflowException();
|
||||||
}
|
}
|
||||||
|
|
||||||
var oldSpan = new Span<T>(data, (int)count);
|
Span<T> oldSpan = new(data, (int)count);
|
||||||
|
|
||||||
capacity = newCapacity;
|
capacity = newCapacity;
|
||||||
data = Allocators.References.Allocate<T>(capacity);
|
data = Allocators.References.Allocate<T>(capacity);
|
||||||
@@ -352,7 +352,7 @@ namespace ARMeilleure.IntermediateRepresentation
|
|||||||
|
|
||||||
private static void Remove<T>(in T item, ref T* data, ref ushort count) where T : unmanaged
|
private static void Remove<T>(in T item, ref T* data, ref ushort count) where T : unmanaged
|
||||||
{
|
{
|
||||||
var span = new Span<T>(data, count);
|
Span<T> span = new(data, count);
|
||||||
|
|
||||||
for (int i = 0; i < span.Length; i++)
|
for (int i = 0; i < span.Length; i++)
|
||||||
{
|
{
|
||||||
@@ -372,7 +372,7 @@ namespace ARMeilleure.IntermediateRepresentation
|
|||||||
|
|
||||||
private static void Remove<T>(in T item, ref T* data, ref uint count) where T : unmanaged
|
private static void Remove<T>(in T item, ref T* data, ref uint count) where T : unmanaged
|
||||||
{
|
{
|
||||||
var span = new Span<T>(data, (int)count);
|
Span<T> span = new(data, (int)count);
|
||||||
|
|
||||||
for (int i = 0; i < span.Length; i++)
|
for (int i = 0; i < span.Length; i++)
|
||||||
{
|
{
|
||||||
@@ -446,7 +446,7 @@ namespace ARMeilleure.IntermediateRepresentation
|
|||||||
Data* data = null;
|
Data* data = null;
|
||||||
|
|
||||||
// If constant or register, then try to look up in the intern table before allocating.
|
// If constant or register, then try to look up in the intern table before allocating.
|
||||||
if (kind == OperandKind.Constant || kind == OperandKind.Register)
|
if (kind is OperandKind.Constant or OperandKind.Register)
|
||||||
{
|
{
|
||||||
uint hash = (uint)HashCode.Combine(kind, type, value);
|
uint hash = (uint)HashCode.Combine(kind, type, value);
|
||||||
|
|
||||||
|
|||||||
@@ -16,8 +16,7 @@ namespace ARMeilleure.IntermediateRepresentation
|
|||||||
{
|
{
|
||||||
public static bool IsInteger(this OperandType type)
|
public static bool IsInteger(this OperandType type)
|
||||||
{
|
{
|
||||||
return type == OperandType.I32 ||
|
return type is OperandType.I32 or OperandType.I64;
|
||||||
type == OperandType.I64;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static RegisterType ToRegisterType(this OperandType type)
|
public static RegisterType ToRegisterType(this OperandType type)
|
||||||
|
|||||||
@@ -228,7 +228,7 @@ namespace ARMeilleure.IntermediateRepresentation
|
|||||||
|
|
||||||
public readonly override int GetHashCode()
|
public readonly override int GetHashCode()
|
||||||
{
|
{
|
||||||
return HashCode.Combine((IntPtr)_data);
|
return HashCode.Combine((nint)_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool operator ==(Operation a, Operation b)
|
public static bool operator ==(Operation a, Operation b)
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ namespace ARMeilleure.Memory
|
|||||||
{
|
{
|
||||||
public interface IJitMemoryBlock : IDisposable
|
public interface IJitMemoryBlock : IDisposable
|
||||||
{
|
{
|
||||||
IntPtr Pointer { get; }
|
nint Pointer { get; }
|
||||||
|
|
||||||
void Commit(ulong offset, ulong size);
|
void Commit(ulong offset, ulong size);
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ namespace ARMeilleure.Memory
|
|||||||
{
|
{
|
||||||
int AddressSpaceBits { get; }
|
int AddressSpaceBits { get; }
|
||||||
|
|
||||||
IntPtr PageTablePointer { get; }
|
nint PageTablePointer { get; }
|
||||||
|
|
||||||
MemoryManagerType Type { get; }
|
MemoryManagerType Type { get; }
|
||||||
|
|
||||||
|
|||||||
@@ -47,12 +47,12 @@ namespace ARMeilleure.Memory
|
|||||||
{
|
{
|
||||||
public static bool IsHostMapped(this MemoryManagerType type)
|
public static bool IsHostMapped(this MemoryManagerType type)
|
||||||
{
|
{
|
||||||
return type == MemoryManagerType.HostMapped || type == MemoryManagerType.HostMappedUnsafe;
|
return type is MemoryManagerType.HostMapped or MemoryManagerType.HostMappedUnsafe;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool IsHostTracked(this MemoryManagerType type)
|
public static bool IsHostTracked(this MemoryManagerType type)
|
||||||
{
|
{
|
||||||
return type == MemoryManagerType.HostTracked || type == MemoryManagerType.HostTrackedUnsafe;
|
return type is MemoryManagerType.HostTracked or MemoryManagerType.HostTrackedUnsafe;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool IsHostMappedOrTracked(this MemoryManagerType type)
|
public static bool IsHostMappedOrTracked(this MemoryManagerType type)
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ namespace ARMeilleure.Memory
|
|||||||
public IJitMemoryBlock Block { get; }
|
public IJitMemoryBlock Block { get; }
|
||||||
public IJitMemoryAllocator Allocator { get; }
|
public IJitMemoryAllocator Allocator { get; }
|
||||||
|
|
||||||
public IntPtr Pointer => Block.Pointer;
|
public nint Pointer => Block.Pointer;
|
||||||
|
|
||||||
private readonly ulong _maxSize;
|
private readonly ulong _maxSize;
|
||||||
private readonly ulong _sizeGranularity;
|
private readonly ulong _sizeGranularity;
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
using System;
|
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Runtime.Versioning;
|
using System.Runtime.Versioning;
|
||||||
|
|
||||||
@@ -8,6 +7,6 @@ namespace ARMeilleure.Native
|
|||||||
static partial class JitSupportDarwin
|
static partial class JitSupportDarwin
|
||||||
{
|
{
|
||||||
[LibraryImport("libarmeilleure-jitsupport", EntryPoint = "armeilleure_jit_memcpy")]
|
[LibraryImport("libarmeilleure-jitsupport", EntryPoint = "armeilleure_jit_memcpy")]
|
||||||
public static partial void Copy(IntPtr dst, IntPtr src, ulong n);
|
public static partial void Copy(nint dst, nint src, ulong n);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,17 +1,21 @@
|
|||||||
namespace ARMeilleure
|
namespace ARMeilleure
|
||||||
{
|
{
|
||||||
using Arm64HardwareCapabilities = ARMeilleure.CodeGen.Arm64.HardwareCapabilities;
|
using Arm64HardwareCapabilities = CodeGen.Arm64.HardwareCapabilities;
|
||||||
using X86HardwareCapabilities = ARMeilleure.CodeGen.X86.HardwareCapabilities;
|
using X86HardwareCapabilities = CodeGen.X86.HardwareCapabilities;
|
||||||
|
|
||||||
public static class Optimizations
|
public static class Optimizations
|
||||||
{
|
{
|
||||||
// low-core count PPTC
|
// low-core count PPTC
|
||||||
public static bool EcoFriendly { get; set; } = false;
|
public static bool EcoFriendly { get; set; } = false;
|
||||||
|
|
||||||
|
// Jit cache eviction
|
||||||
|
public static bool CacheEviction { get; set; } = false;
|
||||||
|
|
||||||
public static bool FastFP { get; set; } = true;
|
public static bool FastFP { get; set; } = true;
|
||||||
|
|
||||||
public static bool AllowLcqInFunctionTable { get; set; } = true;
|
public static bool AllowLcqInFunctionTable { get; set; } = true;
|
||||||
public static bool UseUnmanagedDispatchLoop { get; set; } = true;
|
public static bool UseUnmanagedDispatchLoop { get; set; } = true;
|
||||||
|
public static bool EnableDeepCallRecursionProtection { get; set; } = true;
|
||||||
|
|
||||||
public static bool UseAdvSimdIfAvailable { get; set; } = true;
|
public static bool UseAdvSimdIfAvailable { get; set; } = true;
|
||||||
public static bool UseArm64AesIfAvailable { get; set; } = true;
|
public static bool UseArm64AesIfAvailable { get; set; } = true;
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ namespace ARMeilleure.Signal
|
|||||||
{
|
{
|
||||||
public static class NativeSignalHandlerGenerator
|
public static class NativeSignalHandlerGenerator
|
||||||
{
|
{
|
||||||
public const int MaxTrackedRanges = 16;
|
public const int MaxTrackedRanges = 8;
|
||||||
|
|
||||||
private const int StructAddressOffset = 0;
|
private const int StructAddressOffset = 0;
|
||||||
private const int StructWriteOffset = 4;
|
private const int StructWriteOffset = 4;
|
||||||
@@ -21,7 +21,7 @@ namespace ARMeilleure.Signal
|
|||||||
|
|
||||||
private const uint EXCEPTION_ACCESS_VIOLATION = 0xc0000005;
|
private const uint EXCEPTION_ACCESS_VIOLATION = 0xc0000005;
|
||||||
|
|
||||||
private static Operand EmitGenericRegionCheck(EmitterContext context, IntPtr signalStructPtr, Operand faultAddress, Operand isWrite, int rangeStructSize)
|
private static Operand EmitGenericRegionCheck(EmitterContext context, nint signalStructPtr, Operand faultAddress, Operand isWrite, int rangeStructSize)
|
||||||
{
|
{
|
||||||
Operand inRegionLocal = context.AllocateLocal(OperandType.I32);
|
Operand inRegionLocal = context.AllocateLocal(OperandType.I32);
|
||||||
context.Copy(inRegionLocal, Const(0));
|
context.Copy(inRegionLocal, Const(0));
|
||||||
@@ -155,7 +155,7 @@ namespace ARMeilleure.Signal
|
|||||||
throw new PlatformNotSupportedException();
|
throw new PlatformNotSupportedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static byte[] GenerateUnixSignalHandler(IntPtr signalStructPtr, int rangeStructSize)
|
public static byte[] GenerateUnixSignalHandler(nint signalStructPtr, int rangeStructSize)
|
||||||
{
|
{
|
||||||
EmitterContext context = new();
|
EmitterContext context = new();
|
||||||
|
|
||||||
@@ -203,7 +203,7 @@ namespace ARMeilleure.Signal
|
|||||||
return Compiler.Compile(cfg, argTypes, OperandType.None, CompilerOptions.HighCq, RuntimeInformation.ProcessArchitecture).Code;
|
return Compiler.Compile(cfg, argTypes, OperandType.None, CompilerOptions.HighCq, RuntimeInformation.ProcessArchitecture).Code;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static byte[] GenerateWindowsSignalHandler(IntPtr signalStructPtr, int rangeStructSize)
|
public static byte[] GenerateWindowsSignalHandler(nint signalStructPtr, int rangeStructSize)
|
||||||
{
|
{
|
||||||
EmitterContext context = new();
|
EmitterContext context = new();
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
using ARMeilleure.IntermediateRepresentation;
|
using ARMeilleure.IntermediateRepresentation;
|
||||||
using ARMeilleure.Translation;
|
using ARMeilleure.Translation;
|
||||||
using System;
|
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
|
using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
|
||||||
|
|
||||||
@@ -16,13 +15,13 @@ namespace ARMeilleure.Signal
|
|||||||
{
|
{
|
||||||
public delegate bool DebugPartialUnmap();
|
public delegate bool DebugPartialUnmap();
|
||||||
public delegate int DebugThreadLocalMapGetOrReserve(int threadId, int initialState);
|
public delegate int DebugThreadLocalMapGetOrReserve(int threadId, int initialState);
|
||||||
public delegate void DebugNativeWriteLoop(IntPtr nativeWriteLoopPtr, IntPtr writePtr);
|
public delegate void DebugNativeWriteLoop(nint nativeWriteLoopPtr, nint writePtr);
|
||||||
|
|
||||||
public static DebugPartialUnmap GenerateDebugPartialUnmap()
|
public static DebugPartialUnmap GenerateDebugPartialUnmap()
|
||||||
{
|
{
|
||||||
EmitterContext context = new();
|
EmitterContext context = new();
|
||||||
|
|
||||||
var result = WindowsPartialUnmapHandler.EmitRetryFromAccessViolation(context);
|
Operand result = WindowsPartialUnmapHandler.EmitRetryFromAccessViolation(context);
|
||||||
|
|
||||||
context.Return(result);
|
context.Return(result);
|
||||||
|
|
||||||
@@ -35,11 +34,11 @@ namespace ARMeilleure.Signal
|
|||||||
return Compiler.Compile(cfg, argTypes, OperandType.I32, CompilerOptions.HighCq, RuntimeInformation.ProcessArchitecture).Map<DebugPartialUnmap>();
|
return Compiler.Compile(cfg, argTypes, OperandType.I32, CompilerOptions.HighCq, RuntimeInformation.ProcessArchitecture).Map<DebugPartialUnmap>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static DebugThreadLocalMapGetOrReserve GenerateDebugThreadLocalMapGetOrReserve(IntPtr structPtr)
|
public static DebugThreadLocalMapGetOrReserve GenerateDebugThreadLocalMapGetOrReserve(nint structPtr)
|
||||||
{
|
{
|
||||||
EmitterContext context = new();
|
EmitterContext context = new();
|
||||||
|
|
||||||
var result = WindowsPartialUnmapHandler.EmitThreadLocalMapIntGetOrReserve(context, structPtr, context.LoadArgument(OperandType.I32, 0), context.LoadArgument(OperandType.I32, 1));
|
Operand result = WindowsPartialUnmapHandler.EmitThreadLocalMapIntGetOrReserve(context, structPtr, context.LoadArgument(OperandType.I32, 0), context.LoadArgument(OperandType.I32, 1));
|
||||||
|
|
||||||
context.Return(result);
|
context.Return(result);
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
using ARMeilleure.IntermediateRepresentation;
|
using ARMeilleure.IntermediateRepresentation;
|
||||||
using ARMeilleure.Translation;
|
using ARMeilleure.Translation;
|
||||||
using Ryujinx.Common.Memory.PartialUnmaps;
|
using Ryujinx.Common.Memory.PartialUnmaps;
|
||||||
using System;
|
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
|
using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
|
||||||
|
|
||||||
@@ -13,18 +12,18 @@ namespace ARMeilleure.Signal
|
|||||||
internal static partial class WindowsPartialUnmapHandler
|
internal static partial class WindowsPartialUnmapHandler
|
||||||
{
|
{
|
||||||
[LibraryImport("kernel32.dll", SetLastError = true, EntryPoint = "LoadLibraryA")]
|
[LibraryImport("kernel32.dll", SetLastError = true, EntryPoint = "LoadLibraryA")]
|
||||||
private static partial IntPtr LoadLibrary([MarshalAs(UnmanagedType.LPStr)] string lpFileName);
|
private static partial nint LoadLibrary([MarshalAs(UnmanagedType.LPStr)] string lpFileName);
|
||||||
|
|
||||||
[LibraryImport("kernel32.dll", SetLastError = true)]
|
[LibraryImport("kernel32.dll", SetLastError = true)]
|
||||||
private static partial IntPtr GetProcAddress(IntPtr hModule, [MarshalAs(UnmanagedType.LPStr)] string procName);
|
private static partial nint GetProcAddress(nint hModule, [MarshalAs(UnmanagedType.LPStr)] string procName);
|
||||||
|
|
||||||
private static IntPtr _getCurrentThreadIdPtr;
|
private static nint _getCurrentThreadIdPtr;
|
||||||
|
|
||||||
public static IntPtr GetCurrentThreadIdFunc()
|
public static nint GetCurrentThreadIdFunc()
|
||||||
{
|
{
|
||||||
if (_getCurrentThreadIdPtr == IntPtr.Zero)
|
if (_getCurrentThreadIdPtr == nint.Zero)
|
||||||
{
|
{
|
||||||
IntPtr handle = LoadLibrary("kernel32.dll");
|
nint handle = LoadLibrary("kernel32.dll");
|
||||||
|
|
||||||
_getCurrentThreadIdPtr = GetProcAddress(handle, "GetCurrentThreadId");
|
_getCurrentThreadIdPtr = GetProcAddress(handle, "GetCurrentThreadId");
|
||||||
}
|
}
|
||||||
@@ -34,13 +33,13 @@ namespace ARMeilleure.Signal
|
|||||||
|
|
||||||
public static Operand EmitRetryFromAccessViolation(EmitterContext context)
|
public static Operand EmitRetryFromAccessViolation(EmitterContext context)
|
||||||
{
|
{
|
||||||
IntPtr partialRemapStatePtr = PartialUnmapState.GlobalState;
|
nint partialRemapStatePtr = PartialUnmapState.GlobalState;
|
||||||
IntPtr localCountsPtr = IntPtr.Add(partialRemapStatePtr, PartialUnmapState.LocalCountsOffset);
|
nint localCountsPtr = nint.Add(partialRemapStatePtr, PartialUnmapState.LocalCountsOffset);
|
||||||
|
|
||||||
// Get the lock first.
|
// Get the lock first.
|
||||||
EmitNativeReaderLockAcquire(context, IntPtr.Add(partialRemapStatePtr, PartialUnmapState.PartialUnmapLockOffset));
|
EmitNativeReaderLockAcquire(context, nint.Add(partialRemapStatePtr, PartialUnmapState.PartialUnmapLockOffset));
|
||||||
|
|
||||||
IntPtr getCurrentThreadId = GetCurrentThreadIdFunc();
|
nint getCurrentThreadId = GetCurrentThreadIdFunc();
|
||||||
Operand threadId = context.Call(Const((ulong)getCurrentThreadId), OperandType.I32);
|
Operand threadId = context.Call(Const((ulong)getCurrentThreadId), OperandType.I32);
|
||||||
Operand threadIndex = EmitThreadLocalMapIntGetOrReserve(context, localCountsPtr, threadId, Const(0));
|
Operand threadIndex = EmitThreadLocalMapIntGetOrReserve(context, localCountsPtr, threadId, Const(0));
|
||||||
|
|
||||||
@@ -58,7 +57,7 @@ namespace ARMeilleure.Signal
|
|||||||
|
|
||||||
Operand threadLocalPartialUnmapsPtr = EmitThreadLocalMapIntGetValuePtr(context, localCountsPtr, threadIndex);
|
Operand threadLocalPartialUnmapsPtr = EmitThreadLocalMapIntGetValuePtr(context, localCountsPtr, threadIndex);
|
||||||
Operand threadLocalPartialUnmaps = context.Load(OperandType.I32, threadLocalPartialUnmapsPtr);
|
Operand threadLocalPartialUnmaps = context.Load(OperandType.I32, threadLocalPartialUnmapsPtr);
|
||||||
Operand partialUnmapsCount = context.Load(OperandType.I32, Const((ulong)IntPtr.Add(partialRemapStatePtr, PartialUnmapState.PartialUnmapsCountOffset)));
|
Operand partialUnmapsCount = context.Load(OperandType.I32, Const((ulong)nint.Add(partialRemapStatePtr, PartialUnmapState.PartialUnmapsCountOffset)));
|
||||||
|
|
||||||
context.Copy(retry, context.ICompareNotEqual(threadLocalPartialUnmaps, partialUnmapsCount));
|
context.Copy(retry, context.ICompareNotEqual(threadLocalPartialUnmaps, partialUnmapsCount));
|
||||||
|
|
||||||
@@ -79,14 +78,14 @@ namespace ARMeilleure.Signal
|
|||||||
context.MarkLabel(endLabel);
|
context.MarkLabel(endLabel);
|
||||||
|
|
||||||
// Finally, release the lock and return the retry value.
|
// Finally, release the lock and return the retry value.
|
||||||
EmitNativeReaderLockRelease(context, IntPtr.Add(partialRemapStatePtr, PartialUnmapState.PartialUnmapLockOffset));
|
EmitNativeReaderLockRelease(context, nint.Add(partialRemapStatePtr, PartialUnmapState.PartialUnmapLockOffset));
|
||||||
|
|
||||||
return retry;
|
return retry;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Operand EmitThreadLocalMapIntGetOrReserve(EmitterContext context, IntPtr threadLocalMapPtr, Operand threadId, Operand initialState)
|
public static Operand EmitThreadLocalMapIntGetOrReserve(EmitterContext context, nint threadLocalMapPtr, Operand threadId, Operand initialState)
|
||||||
{
|
{
|
||||||
Operand idsPtr = Const((ulong)IntPtr.Add(threadLocalMapPtr, ThreadLocalMap<int>.ThreadIdsOffset));
|
Operand idsPtr = Const((ulong)nint.Add(threadLocalMapPtr, ThreadLocalMap<int>.ThreadIdsOffset));
|
||||||
|
|
||||||
Operand i = context.AllocateLocal(OperandType.I32);
|
Operand i = context.AllocateLocal(OperandType.I32);
|
||||||
|
|
||||||
@@ -130,7 +129,7 @@ namespace ARMeilleure.Signal
|
|||||||
// If it was 0, then we need to initialize the struct entry and return i.
|
// If it was 0, then we need to initialize the struct entry and return i.
|
||||||
context.BranchIfFalse(idNot0Label, context.ICompareEqual(existingId2, Const(0)));
|
context.BranchIfFalse(idNot0Label, context.ICompareEqual(existingId2, Const(0)));
|
||||||
|
|
||||||
Operand structsPtr = Const((ulong)IntPtr.Add(threadLocalMapPtr, ThreadLocalMap<int>.StructsOffset));
|
Operand structsPtr = Const((ulong)nint.Add(threadLocalMapPtr, ThreadLocalMap<int>.StructsOffset));
|
||||||
Operand structPtr = context.Add(structsPtr, context.SignExtend32(OperandType.I64, offset2));
|
Operand structPtr = context.Add(structsPtr, context.SignExtend32(OperandType.I64, offset2));
|
||||||
context.Store(structPtr, initialState);
|
context.Store(structPtr, initialState);
|
||||||
|
|
||||||
@@ -149,10 +148,10 @@ namespace ARMeilleure.Signal
|
|||||||
return context.Copy(i);
|
return context.Copy(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Operand EmitThreadLocalMapIntGetValuePtr(EmitterContext context, IntPtr threadLocalMapPtr, Operand index)
|
private static Operand EmitThreadLocalMapIntGetValuePtr(EmitterContext context, nint threadLocalMapPtr, Operand index)
|
||||||
{
|
{
|
||||||
Operand offset = context.Multiply(index, Const(sizeof(int)));
|
Operand offset = context.Multiply(index, Const(sizeof(int)));
|
||||||
Operand structsPtr = Const((ulong)IntPtr.Add(threadLocalMapPtr, ThreadLocalMap<int>.StructsOffset));
|
Operand structsPtr = Const((ulong)nint.Add(threadLocalMapPtr, ThreadLocalMap<int>.StructsOffset));
|
||||||
|
|
||||||
return context.Add(structsPtr, context.SignExtend32(OperandType.I64, offset));
|
return context.Add(structsPtr, context.SignExtend32(OperandType.I64, offset));
|
||||||
}
|
}
|
||||||
@@ -170,9 +169,9 @@ namespace ARMeilleure.Signal
|
|||||||
context.BranchIfFalse(loop, context.ICompareEqual(initial, replaced));
|
context.BranchIfFalse(loop, context.ICompareEqual(initial, replaced));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void EmitNativeReaderLockAcquire(EmitterContext context, IntPtr nativeReaderLockPtr)
|
private static void EmitNativeReaderLockAcquire(EmitterContext context, nint nativeReaderLockPtr)
|
||||||
{
|
{
|
||||||
Operand writeLockPtr = Const((ulong)IntPtr.Add(nativeReaderLockPtr, NativeReaderWriterLock.WriteLockOffset));
|
Operand writeLockPtr = Const((ulong)nint.Add(nativeReaderLockPtr, NativeReaderWriterLock.WriteLockOffset));
|
||||||
|
|
||||||
// Spin until we can acquire the write lock.
|
// Spin until we can acquire the write lock.
|
||||||
Operand spinLabel = Label();
|
Operand spinLabel = Label();
|
||||||
@@ -182,16 +181,16 @@ namespace ARMeilleure.Signal
|
|||||||
context.BranchIfTrue(spinLabel, context.CompareAndSwap(writeLockPtr, Const(0), Const(1)));
|
context.BranchIfTrue(spinLabel, context.CompareAndSwap(writeLockPtr, Const(0), Const(1)));
|
||||||
|
|
||||||
// Increment reader count.
|
// Increment reader count.
|
||||||
EmitAtomicAddI32(context, Const((ulong)IntPtr.Add(nativeReaderLockPtr, NativeReaderWriterLock.ReaderCountOffset)), Const(1));
|
EmitAtomicAddI32(context, Const((ulong)nint.Add(nativeReaderLockPtr, NativeReaderWriterLock.ReaderCountOffset)), Const(1));
|
||||||
|
|
||||||
// Release write lock.
|
// Release write lock.
|
||||||
context.CompareAndSwap(writeLockPtr, Const(1), Const(0));
|
context.CompareAndSwap(writeLockPtr, Const(1), Const(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void EmitNativeReaderLockRelease(EmitterContext context, IntPtr nativeReaderLockPtr)
|
private static void EmitNativeReaderLockRelease(EmitterContext context, nint nativeReaderLockPtr)
|
||||||
{
|
{
|
||||||
// Decrement reader count.
|
// Decrement reader count.
|
||||||
EmitAtomicAddI32(context, Const((ulong)IntPtr.Add(nativeReaderLockPtr, NativeReaderWriterLock.ReaderCountOffset)), Const(-1));
|
EmitAtomicAddI32(context, Const((ulong)nint.Add(nativeReaderLockPtr, NativeReaderWriterLock.ReaderCountOffset)), Const(-1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
using ARMeilleure.Memory;
|
using ARMeilleure.Memory;
|
||||||
using System;
|
|
||||||
|
|
||||||
namespace ARMeilleure.State
|
namespace ARMeilleure.State
|
||||||
{
|
{
|
||||||
@@ -9,7 +8,7 @@ namespace ARMeilleure.State
|
|||||||
|
|
||||||
private readonly NativeContext _nativeContext;
|
private readonly NativeContext _nativeContext;
|
||||||
|
|
||||||
internal IntPtr NativeContextPtr => _nativeContext.BasePtr;
|
internal nint NativeContextPtr => _nativeContext.BasePtr;
|
||||||
|
|
||||||
private bool _interrupted;
|
private bool _interrupted;
|
||||||
|
|
||||||
@@ -128,6 +127,11 @@ namespace ARMeilleure.State
|
|||||||
public bool GetFPstateFlag(FPState flag) => _nativeContext.GetFPStateFlag(flag);
|
public bool GetFPstateFlag(FPState flag) => _nativeContext.GetFPStateFlag(flag);
|
||||||
public void SetFPstateFlag(FPState flag, bool value) => _nativeContext.SetFPStateFlag(flag, value);
|
public void SetFPstateFlag(FPState flag, bool value) => _nativeContext.SetFPStateFlag(flag, value);
|
||||||
|
|
||||||
|
internal void ResetCallDepth()
|
||||||
|
{
|
||||||
|
_nativeContext.ResetCallDepth();
|
||||||
|
}
|
||||||
|
|
||||||
internal void CheckInterrupt()
|
internal void CheckInterrupt()
|
||||||
{
|
{
|
||||||
if (_interrupted)
|
if (_interrupted)
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ namespace ARMeilleure.State
|
|||||||
public ulong ExclusiveValueLow;
|
public ulong ExclusiveValueLow;
|
||||||
public ulong ExclusiveValueHigh;
|
public ulong ExclusiveValueHigh;
|
||||||
public int Running;
|
public int Running;
|
||||||
|
public int CallDepth;
|
||||||
public long Tpidr2El0;
|
public long Tpidr2El0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -28,7 +29,7 @@ namespace ARMeilleure.State
|
|||||||
|
|
||||||
private readonly IJitMemoryBlock _block;
|
private readonly IJitMemoryBlock _block;
|
||||||
|
|
||||||
public IntPtr BasePtr => _block.Pointer;
|
public nint BasePtr => _block.Pointer;
|
||||||
|
|
||||||
public NativeContext(IJitMemoryAllocator allocator)
|
public NativeContext(IJitMemoryAllocator allocator)
|
||||||
{
|
{
|
||||||
@@ -186,6 +187,8 @@ namespace ARMeilleure.State
|
|||||||
public bool GetRunning() => GetStorage().Running != 0;
|
public bool GetRunning() => GetStorage().Running != 0;
|
||||||
public void SetRunning(bool value) => GetStorage().Running = value ? 1 : 0;
|
public void SetRunning(bool value) => GetStorage().Running = value ? 1 : 0;
|
||||||
|
|
||||||
|
public void ResetCallDepth() => GetStorage().CallDepth = 0;
|
||||||
|
|
||||||
public unsafe static int GetRegisterOffset(Register reg)
|
public unsafe static int GetRegisterOffset(Register reg)
|
||||||
{
|
{
|
||||||
if (reg.Type == RegisterType.Integer)
|
if (reg.Type == RegisterType.Integer)
|
||||||
@@ -266,6 +269,11 @@ namespace ARMeilleure.State
|
|||||||
return StorageOffset(ref _dummyStorage, ref _dummyStorage.Running);
|
return StorageOffset(ref _dummyStorage, ref _dummyStorage.Running);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static int GetCallDepthOffset()
|
||||||
|
{
|
||||||
|
return StorageOffset(ref _dummyStorage, ref _dummyStorage.CallDepth);
|
||||||
|
}
|
||||||
|
|
||||||
private static int StorageOffset<T>(ref NativeCtxStorage storage, ref T target)
|
private static int StorageOffset<T>(ref NativeCtxStorage storage, ref T target)
|
||||||
{
|
{
|
||||||
return (int)Unsafe.ByteOffset(ref Unsafe.As<NativeCtxStorage, T>(ref storage), ref target);
|
return (int)Unsafe.ByteOffset(ref Unsafe.As<NativeCtxStorage, T>(ref storage), ref target);
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ using ARMeilleure.Instructions;
|
|||||||
using ARMeilleure.IntermediateRepresentation;
|
using ARMeilleure.IntermediateRepresentation;
|
||||||
using ARMeilleure.Memory;
|
using ARMeilleure.Memory;
|
||||||
using ARMeilleure.State;
|
using ARMeilleure.State;
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
|
using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
|
||||||
@@ -92,7 +91,7 @@ namespace ARMeilleure.Translation
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
int index = Delegates.GetDelegateIndex(info);
|
int index = Delegates.GetDelegateIndex(info);
|
||||||
IntPtr funcPtr = Delegates.GetDelegateFuncPtrByIndex(index);
|
nint funcPtr = Delegates.GetDelegateFuncPtrByIndex(index);
|
||||||
|
|
||||||
OperandType returnType = GetOperandType(info.ReturnType);
|
OperandType returnType = GetOperandType(info.ReturnType);
|
||||||
|
|
||||||
|
|||||||
@@ -2,12 +2,12 @@ using ARMeilleure.CodeGen;
|
|||||||
using ARMeilleure.CodeGen.Unwinding;
|
using ARMeilleure.CodeGen.Unwinding;
|
||||||
using ARMeilleure.Memory;
|
using ARMeilleure.Memory;
|
||||||
using ARMeilleure.Native;
|
using ARMeilleure.Native;
|
||||||
using Humanizer;
|
|
||||||
using Ryujinx.Common.Logging;
|
using Ryujinx.Common.Logging;
|
||||||
using Ryujinx.Memory;
|
using Ryujinx.Memory;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
using System.Linq;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Runtime.Versioning;
|
using System.Runtime.Versioning;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
@@ -19,83 +19,123 @@ namespace ARMeilleure.Translation.Cache
|
|||||||
private static readonly int _pageSize = (int)MemoryBlock.GetPageSize();
|
private static readonly int _pageSize = (int)MemoryBlock.GetPageSize();
|
||||||
private static readonly int _pageMask = _pageSize - 1;
|
private static readonly int _pageMask = _pageSize - 1;
|
||||||
|
|
||||||
private const int CodeAlignment = 4; // Bytes.
|
private const int CodeAlignment = 4;
|
||||||
private const int CacheSize = 256 * 1024 * 1024;
|
private const int FullCacheSize = 2047 * 1024 * 1024;
|
||||||
|
private const int ReducedCacheSize = FullCacheSize / 8;
|
||||||
|
|
||||||
|
private const float EvictionTargetPercentage = 0.20f;
|
||||||
|
private const int MaxEntriesToEvictAtOnce = 100;
|
||||||
|
|
||||||
|
// Simple logging configuration
|
||||||
|
private const int LogInterval = 5000; // Log every 5000 allocations
|
||||||
|
|
||||||
|
private static ReservedRegion _jitRegion;
|
||||||
private static JitCacheInvalidation _jitCacheInvalidator;
|
private static JitCacheInvalidation _jitCacheInvalidator;
|
||||||
|
|
||||||
private static List<CacheMemoryAllocator> _cacheAllocators = [];
|
private static CacheMemoryAllocator _cacheAllocator;
|
||||||
|
|
||||||
private static readonly List<CacheEntry> _cacheEntries = [];
|
private static readonly List<CacheEntry> _cacheEntries = [];
|
||||||
|
private static readonly Dictionary<int, EntryUsageStats> _entryUsageStats = [];
|
||||||
|
|
||||||
private static readonly Lock _lock = new();
|
private static readonly Lock _lock = new();
|
||||||
private static bool _initialized;
|
private static bool _initialized;
|
||||||
|
private static int _cacheSize;
|
||||||
|
|
||||||
private static readonly List<ReservedRegion> _jitRegions = [];
|
// Basic statistics
|
||||||
private static int _activeRegionIndex = 0;
|
private static int _totalAllocations = 0;
|
||||||
|
private static int _totalEvictions = 0;
|
||||||
|
|
||||||
|
private class EntryUsageStats
|
||||||
|
{
|
||||||
|
public long LastAccessTime { get; private set; }
|
||||||
|
public int UsageCount { get; private set; }
|
||||||
|
|
||||||
|
public EntryUsageStats()
|
||||||
|
{
|
||||||
|
LastAccessTime = DateTime.UtcNow.Ticks;
|
||||||
|
UsageCount = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UpdateUsage()
|
||||||
|
{
|
||||||
|
LastAccessTime = DateTime.UtcNow.Ticks;
|
||||||
|
UsageCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[SupportedOSPlatform("windows")]
|
[SupportedOSPlatform("windows")]
|
||||||
[LibraryImport("kernel32.dll", SetLastError = true)]
|
[LibraryImport("kernel32.dll", SetLastError = true)]
|
||||||
public static partial IntPtr FlushInstructionCache(IntPtr hProcess, IntPtr lpAddress, UIntPtr dwSize);
|
public static partial nint FlushInstructionCache(nint hProcess, nint lpAddress, nuint dwSize);
|
||||||
|
|
||||||
public static void Initialize(IJitMemoryAllocator allocator)
|
public static void Initialize(IJitMemoryAllocator allocator)
|
||||||
{
|
{
|
||||||
|
if (_initialized)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
lock (_lock)
|
lock (_lock)
|
||||||
{
|
{
|
||||||
if (_initialized)
|
if (_initialized)
|
||||||
{
|
{
|
||||||
if (OperatingSystem.IsWindows())
|
return;
|
||||||
{
|
|
||||||
JitUnwindWindows.RemoveFunctionTableHandler(
|
|
||||||
_jitRegions[0].Pointer);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < _jitRegions.Count; i++)
|
|
||||||
{
|
|
||||||
_jitRegions[i].Dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
_jitRegions.Clear();
|
|
||||||
_cacheAllocators.Clear();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_initialized = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_activeRegionIndex = 0;
|
_cacheSize = Optimizations.CacheEviction ? ReducedCacheSize : FullCacheSize;
|
||||||
|
_jitRegion = new ReservedRegion(allocator, (ulong)_cacheSize);
|
||||||
var firstRegion = new ReservedRegion(allocator, CacheSize);
|
|
||||||
_jitRegions.Add(firstRegion);
|
|
||||||
|
|
||||||
CacheMemoryAllocator firstCacheAllocator = new(CacheSize);
|
|
||||||
_cacheAllocators.Add(firstCacheAllocator);
|
|
||||||
|
|
||||||
if (!OperatingSystem.IsWindows() && !OperatingSystem.IsMacOS())
|
if (!OperatingSystem.IsWindows() && !OperatingSystem.IsMacOS())
|
||||||
{
|
{
|
||||||
_jitCacheInvalidator = new JitCacheInvalidation(allocator);
|
_jitCacheInvalidator = new JitCacheInvalidation(allocator);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_cacheAllocator = new CacheMemoryAllocator(_cacheSize);
|
||||||
|
|
||||||
if (OperatingSystem.IsWindows())
|
if (OperatingSystem.IsWindows())
|
||||||
{
|
{
|
||||||
JitUnwindWindows.InstallFunctionTableHandler(
|
JitUnwindWindows.InstallFunctionTableHandler(_jitRegion.Pointer, (uint)_cacheSize, _jitRegion.Pointer + Allocate(_pageSize));
|
||||||
firstRegion.Pointer, CacheSize, firstRegion.Pointer + Allocate(_pageSize)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Logger.Info?.Print(LogClass.Cpu, $"JIT Cache initialized: Size={_cacheSize / (1024 * 1024)} MB, Eviction={Optimizations.CacheEviction}");
|
||||||
|
_initialized = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IntPtr Map(CompiledFunction func)
|
public static nint Map(CompiledFunction func)
|
||||||
{
|
{
|
||||||
byte[] code = func.Code;
|
byte[] code = func.Code;
|
||||||
|
|
||||||
lock (_lock)
|
lock (_lock)
|
||||||
{
|
{
|
||||||
Debug.Assert(_initialized);
|
Debug.Assert(_initialized);
|
||||||
|
_totalAllocations++;
|
||||||
|
|
||||||
int funcOffset = Allocate(code.Length);
|
int funcOffset;
|
||||||
ReservedRegion targetRegion = _jitRegions[_activeRegionIndex];
|
|
||||||
IntPtr funcPtr = targetRegion.Pointer + funcOffset;
|
if (Optimizations.CacheEviction)
|
||||||
|
{
|
||||||
|
int codeSize = AlignCodeSize(code.Length);
|
||||||
|
funcOffset = _cacheAllocator.Allocate(codeSize);
|
||||||
|
|
||||||
|
if (funcOffset < 0)
|
||||||
|
{
|
||||||
|
EvictEntries(codeSize);
|
||||||
|
funcOffset = _cacheAllocator.Allocate(codeSize);
|
||||||
|
|
||||||
|
if (funcOffset < 0)
|
||||||
|
{
|
||||||
|
throw new OutOfMemoryException("JIT Cache exhausted even after eviction.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_jitRegion.ExpandIfNeeded((ulong)funcOffset + (ulong)codeSize);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
funcOffset = Allocate(code.Length);
|
||||||
|
}
|
||||||
|
|
||||||
|
nint funcPtr = _jitRegion.Pointer + funcOffset;
|
||||||
|
|
||||||
if (OperatingSystem.IsMacOS() && RuntimeInformation.ProcessArchitecture == Architecture.Arm64)
|
if (OperatingSystem.IsMacOS() && RuntimeInformation.ProcessArchitecture == Architecture.Arm64)
|
||||||
{
|
{
|
||||||
@@ -103,19 +143,19 @@ namespace ARMeilleure.Translation.Cache
|
|||||||
{
|
{
|
||||||
fixed (byte* codePtr = code)
|
fixed (byte* codePtr = code)
|
||||||
{
|
{
|
||||||
JitSupportDarwin.Copy(funcPtr, (IntPtr)codePtr, (ulong)code.Length);
|
JitSupportDarwin.Copy(funcPtr, (nint)codePtr, (ulong)code.Length);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ReprotectAsWritable(targetRegion, funcOffset, code.Length);
|
ReprotectAsWritable(funcOffset, code.Length);
|
||||||
Marshal.Copy(code, 0, funcPtr, code.Length);
|
Marshal.Copy(code, 0, funcPtr, code.Length);
|
||||||
ReprotectAsExecutable(targetRegion, funcOffset, code.Length);
|
ReprotectAsExecutable(funcOffset, code.Length);
|
||||||
|
|
||||||
if (OperatingSystem.IsWindows() && RuntimeInformation.ProcessArchitecture == Architecture.Arm64)
|
if (OperatingSystem.IsWindows() && RuntimeInformation.ProcessArchitecture == Architecture.Arm64)
|
||||||
{
|
{
|
||||||
FlushInstructionCache(Process.GetCurrentProcess().Handle, funcPtr, (UIntPtr)code.Length);
|
FlushInstructionCache(Process.GetCurrentProcess().Handle, funcPtr, (nuint)code.Length);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -125,84 +165,71 @@ namespace ARMeilleure.Translation.Cache
|
|||||||
|
|
||||||
Add(funcOffset, code.Length, func.UnwindInfo);
|
Add(funcOffset, code.Length, func.UnwindInfo);
|
||||||
|
|
||||||
|
// Simple periodic logging
|
||||||
|
if (_totalAllocations % LogInterval == 0)
|
||||||
|
{
|
||||||
|
LogCacheStatus();
|
||||||
|
}
|
||||||
|
|
||||||
return funcPtr;
|
return funcPtr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Unmap(IntPtr pointer)
|
public static void Unmap(nint pointer)
|
||||||
{
|
{
|
||||||
lock (_lock)
|
lock (_lock)
|
||||||
{
|
{
|
||||||
Debug.Assert(_initialized);
|
Debug.Assert(_initialized);
|
||||||
|
|
||||||
foreach (var region in _jitRegions)
|
int funcOffset = (int)(pointer.ToInt64() - _jitRegion.Pointer.ToInt64());
|
||||||
|
|
||||||
|
if (TryFind(funcOffset, out CacheEntry entry, out int entryIndex) && entry.Offset == funcOffset)
|
||||||
{
|
{
|
||||||
if (pointer.ToInt64() < region.Pointer.ToInt64() ||
|
_cacheAllocator.Free(funcOffset, AlignCodeSize(entry.Size));
|
||||||
pointer.ToInt64() >= (region.Pointer + CacheSize).ToInt64())
|
_cacheEntries.RemoveAt(entryIndex);
|
||||||
|
|
||||||
|
if (Optimizations.CacheEviction)
|
||||||
{
|
{
|
||||||
continue;
|
_entryUsageStats.Remove(funcOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
int funcOffset = (int)(pointer.ToInt64() - region.Pointer.ToInt64());
|
|
||||||
|
|
||||||
if (TryFind(funcOffset, out CacheEntry entry, out int entryIndex) && entry.Offset == funcOffset)
|
|
||||||
{
|
|
||||||
_cacheAllocators[_activeRegionIndex].Free(funcOffset, AlignCodeSize(entry.Size));
|
|
||||||
_cacheEntries.RemoveAt(entryIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void ReprotectAsWritable(ReservedRegion region, int offset, int size)
|
private static void ReprotectAsWritable(int offset, int size)
|
||||||
{
|
{
|
||||||
int endOffs = offset + size;
|
int endOffs = offset + size;
|
||||||
|
|
||||||
int regionStart = offset & ~_pageMask;
|
int regionStart = offset & ~_pageMask;
|
||||||
int regionEnd = (endOffs + _pageMask) & ~_pageMask;
|
int regionEnd = (endOffs + _pageMask) & ~_pageMask;
|
||||||
|
|
||||||
region.Block.MapAsRwx((ulong)regionStart, (ulong)(regionEnd - regionStart));
|
_jitRegion.Block.MapAsRwx((ulong)regionStart, (ulong)(regionEnd - regionStart));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void ReprotectAsExecutable(ReservedRegion region, int offset, int size)
|
private static void ReprotectAsExecutable(int offset, int size)
|
||||||
{
|
{
|
||||||
int endOffs = offset + size;
|
int endOffs = offset + size;
|
||||||
|
|
||||||
int regionStart = offset & ~_pageMask;
|
int regionStart = offset & ~_pageMask;
|
||||||
int regionEnd = (endOffs + _pageMask) & ~_pageMask;
|
int regionEnd = (endOffs + _pageMask) & ~_pageMask;
|
||||||
|
|
||||||
region.Block.MapAsRx((ulong)regionStart, (ulong)(regionEnd - regionStart));
|
_jitRegion.Block.MapAsRx((ulong)regionStart, (ulong)(regionEnd - regionStart));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int Allocate(int codeSize)
|
private static int Allocate(int codeSize)
|
||||||
{
|
{
|
||||||
codeSize = AlignCodeSize(codeSize);
|
codeSize = AlignCodeSize(codeSize);
|
||||||
|
|
||||||
int allocOffset = _cacheAllocators[_activeRegionIndex].Allocate(codeSize);
|
int allocOffset = _cacheAllocator.Allocate(codeSize);
|
||||||
|
|
||||||
if (allocOffset >= 0)
|
if (allocOffset < 0)
|
||||||
{
|
{
|
||||||
_jitRegions[_activeRegionIndex].ExpandIfNeeded((ulong)allocOffset + (ulong)codeSize);
|
throw new OutOfMemoryException("JIT Cache exhausted.");
|
||||||
return allocOffset;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int exhaustedRegion = _activeRegionIndex;
|
_jitRegion.ExpandIfNeeded((ulong)allocOffset + (ulong)codeSize);
|
||||||
var newRegion = new ReservedRegion(_jitRegions[0].Allocator, CacheSize);
|
|
||||||
_jitRegions.Add(newRegion);
|
|
||||||
_activeRegionIndex = _jitRegions.Count - 1;
|
|
||||||
|
|
||||||
Logger.Warning?.Print(LogClass.Cpu, $"JIT Cache Region {exhaustedRegion} exhausted, creating new Cache Region {_activeRegionIndex} ({((long)(_activeRegionIndex + 1) * CacheSize).Bytes()} Total Allocation).");
|
return allocOffset;
|
||||||
|
|
||||||
_cacheAllocators.Add(new CacheMemoryAllocator(CacheSize));
|
|
||||||
|
|
||||||
int allocOffsetNew = _cacheAllocators[_activeRegionIndex].Allocate(codeSize);
|
|
||||||
if (allocOffsetNew < 0)
|
|
||||||
{
|
|
||||||
throw new OutOfMemoryException("Failed to allocate in new Cache Region!");
|
|
||||||
}
|
|
||||||
|
|
||||||
newRegion.ExpandIfNeeded((ulong)allocOffsetNew + (ulong)codeSize);
|
|
||||||
return allocOffsetNew;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int AlignCodeSize(int codeSize)
|
private static int AlignCodeSize(int codeSize)
|
||||||
@@ -222,27 +249,35 @@ namespace ARMeilleure.Translation.Cache
|
|||||||
}
|
}
|
||||||
|
|
||||||
_cacheEntries.Insert(index, entry);
|
_cacheEntries.Insert(index, entry);
|
||||||
|
|
||||||
|
if (Optimizations.CacheEviction)
|
||||||
|
{
|
||||||
|
_entryUsageStats[offset] = new EntryUsageStats();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool TryFind(int offset, out CacheEntry entry, out int entryIndex)
|
public static bool TryFind(int offset, out CacheEntry entry, out int entryIndex)
|
||||||
{
|
{
|
||||||
lock (_lock)
|
lock (_lock)
|
||||||
{
|
{
|
||||||
foreach (var region in _jitRegions)
|
int index = _cacheEntries.BinarySearch(new CacheEntry(offset, 0, default));
|
||||||
|
|
||||||
|
if (index < 0)
|
||||||
{
|
{
|
||||||
int index = _cacheEntries.BinarySearch(new CacheEntry(offset, 0, default));
|
index = ~index - 1;
|
||||||
|
}
|
||||||
|
|
||||||
if (index < 0)
|
if (index >= 0)
|
||||||
|
{
|
||||||
|
entry = _cacheEntries[index];
|
||||||
|
|
||||||
|
if (Optimizations.CacheEviction && _entryUsageStats.TryGetValue(offset, out EntryUsageStats stats))
|
||||||
{
|
{
|
||||||
index = ~index - 1;
|
stats.UpdateUsage();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (index >= 0)
|
entryIndex = index;
|
||||||
{
|
return true;
|
||||||
entry = _cacheEntries[index];
|
|
||||||
entryIndex = index;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -250,5 +285,83 @@ namespace ARMeilleure.Translation.Cache
|
|||||||
entryIndex = 0;
|
entryIndex = 0;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void EvictEntries(int requiredSize)
|
||||||
|
{
|
||||||
|
if (!Optimizations.CacheEviction)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
lock (_lock)
|
||||||
|
{
|
||||||
|
int targetSpace = Math.Max(requiredSize, (int)(_cacheSize * EvictionTargetPercentage));
|
||||||
|
int freedSpace = 0;
|
||||||
|
int evictedCount = 0;
|
||||||
|
|
||||||
|
var entriesWithStats = _cacheEntries
|
||||||
|
.Where(e => _entryUsageStats.ContainsKey(e.Offset))
|
||||||
|
.Select(e => new {
|
||||||
|
Entry = e,
|
||||||
|
Stats = _entryUsageStats[e.Offset],
|
||||||
|
Score = CalculateEvictionScore(_entryUsageStats[e.Offset])
|
||||||
|
})
|
||||||
|
.OrderBy(x => x.Score)
|
||||||
|
.Take(MaxEntriesToEvictAtOnce)
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
foreach (var item in entriesWithStats)
|
||||||
|
{
|
||||||
|
int entrySize = AlignCodeSize(item.Entry.Size);
|
||||||
|
|
||||||
|
int entryIndex = _cacheEntries.BinarySearch(item.Entry);
|
||||||
|
if (entryIndex >= 0)
|
||||||
|
{
|
||||||
|
_cacheAllocator.Free(item.Entry.Offset, entrySize);
|
||||||
|
_cacheEntries.RemoveAt(entryIndex);
|
||||||
|
_entryUsageStats.Remove(item.Entry.Offset);
|
||||||
|
|
||||||
|
freedSpace += entrySize;
|
||||||
|
evictedCount++;
|
||||||
|
|
||||||
|
if (freedSpace >= targetSpace)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_totalEvictions += evictedCount;
|
||||||
|
|
||||||
|
Logger.Info?.Print(LogClass.Cpu, $"JIT Cache: Evicted {evictedCount} entries, freed {freedSpace / (1024 * 1024.0):F2} MB");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static double CalculateEvictionScore(EntryUsageStats stats)
|
||||||
|
{
|
||||||
|
long currentTime = DateTime.UtcNow.Ticks;
|
||||||
|
long ageInTicks = currentTime - stats.LastAccessTime;
|
||||||
|
|
||||||
|
double ageInSeconds = ageInTicks / 10_000_000.0;
|
||||||
|
|
||||||
|
const double usageWeight = 1.0;
|
||||||
|
const double ageWeight = 2.0;
|
||||||
|
|
||||||
|
double usageScore = Math.Log10(stats.UsageCount + 1) * usageWeight;
|
||||||
|
double ageScore = (10.0 / (ageInSeconds + 1.0)) * ageWeight;
|
||||||
|
|
||||||
|
return usageScore + ageScore;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void LogCacheStatus()
|
||||||
|
{
|
||||||
|
int estimatedUsedSize = _cacheEntries.Sum(e => AlignCodeSize(e.Size));
|
||||||
|
double usagePercentage = 100.0 * estimatedUsedSize / _cacheSize;
|
||||||
|
|
||||||
|
Logger.Info?.Print(LogClass.Cpu,
|
||||||
|
$"JIT Cache status: entries={_cacheEntries.Count}, " +
|
||||||
|
$"est. used={estimatedUsedSize / (1024 * 1024.0):F2} MB ({usagePercentage:F1}%), " +
|
||||||
|
$"evictions={_totalEvictions}, allocations={_totalAllocations}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
using ARMeilleure.Memory;
|
using ARMeilleure.Memory;
|
||||||
using System;
|
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace ARMeilleure.Translation.Cache
|
namespace ARMeilleure.Translation.Cache
|
||||||
@@ -68,7 +67,7 @@ namespace ARMeilleure.Translation.Cache
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Invalidate(IntPtr basePointer, ulong size)
|
public void Invalidate(nint basePointer, ulong size)
|
||||||
{
|
{
|
||||||
if (_needsInvalidation)
|
if (_needsInvalidation)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ namespace ARMeilleure.Translation.Cache
|
|||||||
PushMachframe = 10,
|
PushMachframe = 10,
|
||||||
}
|
}
|
||||||
|
|
||||||
private unsafe delegate RuntimeFunction* GetRuntimeFunctionCallback(ulong controlPc, IntPtr context);
|
private unsafe delegate RuntimeFunction* GetRuntimeFunctionCallback(ulong controlPc, nint context);
|
||||||
|
|
||||||
[LibraryImport("kernel32.dll")]
|
[LibraryImport("kernel32.dll")]
|
||||||
[return: MarshalAs(UnmanagedType.Bool)]
|
[return: MarshalAs(UnmanagedType.Bool)]
|
||||||
@@ -49,7 +49,7 @@ namespace ARMeilleure.Translation.Cache
|
|||||||
ulong baseAddress,
|
ulong baseAddress,
|
||||||
uint length,
|
uint length,
|
||||||
GetRuntimeFunctionCallback callback,
|
GetRuntimeFunctionCallback callback,
|
||||||
IntPtr context,
|
nint context,
|
||||||
[MarshalAs(UnmanagedType.LPWStr)] string outOfProcessCallbackDll);
|
[MarshalAs(UnmanagedType.LPWStr)] string outOfProcessCallbackDll);
|
||||||
|
|
||||||
[LibraryImport("kernel32.dll")]
|
[LibraryImport("kernel32.dll")]
|
||||||
@@ -65,7 +65,7 @@ namespace ARMeilleure.Translation.Cache
|
|||||||
|
|
||||||
private unsafe static UnwindInfo* _unwindInfo;
|
private unsafe static UnwindInfo* _unwindInfo;
|
||||||
|
|
||||||
public static void InstallFunctionTableHandler(IntPtr codeCachePointer, uint codeCacheLength, IntPtr workBufferPtr)
|
public static void InstallFunctionTableHandler(nint codeCachePointer, uint codeCacheLength, nint workBufferPtr)
|
||||||
{
|
{
|
||||||
ulong codeCachePtr = (ulong)codeCachePointer.ToInt64();
|
ulong codeCachePtr = (ulong)codeCachePointer.ToInt64();
|
||||||
|
|
||||||
@@ -96,7 +96,7 @@ namespace ARMeilleure.Translation.Cache
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void RemoveFunctionTableHandler(IntPtr codeCachePointer)
|
public static void RemoveFunctionTableHandler(nint codeCachePointer)
|
||||||
{
|
{
|
||||||
ulong codeCachePtr = (ulong)codeCachePointer.ToInt64();
|
ulong codeCachePtr = (ulong)codeCachePointer.ToInt64();
|
||||||
|
|
||||||
@@ -113,7 +113,7 @@ namespace ARMeilleure.Translation.Cache
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static unsafe RuntimeFunction* FunctionTableHandler(ulong controlPc, IntPtr context)
|
private static unsafe RuntimeFunction* FunctionTableHandler(ulong controlPc, nint context)
|
||||||
{
|
{
|
||||||
int offset = (int)((long)controlPc - context.ToInt64());
|
int offset = (int)((long)controlPc - context.ToInt64());
|
||||||
|
|
||||||
@@ -122,13 +122,13 @@ namespace ARMeilleure.Translation.Cache
|
|||||||
return null; // Not found.
|
return null; // Not found.
|
||||||
}
|
}
|
||||||
|
|
||||||
var unwindInfo = funcEntry.UnwindInfo;
|
CodeGen.Unwinding.UnwindInfo unwindInfo = funcEntry.UnwindInfo;
|
||||||
|
|
||||||
int codeIndex = 0;
|
int codeIndex = 0;
|
||||||
|
|
||||||
for (int index = unwindInfo.PushEntries.Length - 1; index >= 0; index--)
|
for (int index = unwindInfo.PushEntries.Length - 1; index >= 0; index--)
|
||||||
{
|
{
|
||||||
var entry = unwindInfo.PushEntries[index];
|
UnwindPushEntry entry = unwindInfo.PushEntries[index];
|
||||||
|
|
||||||
switch (entry.PseudoOp)
|
switch (entry.PseudoOp)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -47,8 +47,8 @@ namespace ARMeilleure.Translation
|
|||||||
{
|
{
|
||||||
RemoveUnreachableBlocks(Blocks);
|
RemoveUnreachableBlocks(Blocks);
|
||||||
|
|
||||||
var visited = new HashSet<BasicBlock>();
|
HashSet<BasicBlock> visited = new();
|
||||||
var blockStack = new Stack<BasicBlock>();
|
Stack<BasicBlock> blockStack = new();
|
||||||
|
|
||||||
Array.Resize(ref _postOrderBlocks, Blocks.Count);
|
Array.Resize(ref _postOrderBlocks, Blocks.Count);
|
||||||
Array.Resize(ref _postOrderMap, Blocks.Count);
|
Array.Resize(ref _postOrderMap, Blocks.Count);
|
||||||
@@ -88,8 +88,8 @@ namespace ARMeilleure.Translation
|
|||||||
|
|
||||||
private void RemoveUnreachableBlocks(IntrusiveList<BasicBlock> blocks)
|
private void RemoveUnreachableBlocks(IntrusiveList<BasicBlock> blocks)
|
||||||
{
|
{
|
||||||
var visited = new HashSet<BasicBlock>();
|
HashSet<BasicBlock> visited = new();
|
||||||
var workQueue = new Queue<BasicBlock>();
|
Queue<BasicBlock> workQueue = new();
|
||||||
|
|
||||||
visited.Add(Entry);
|
visited.Add(Entry);
|
||||||
workQueue.Enqueue(Entry);
|
workQueue.Enqueue(Entry);
|
||||||
|
|||||||
@@ -1,12 +1,10 @@
|
|||||||
using System;
|
|
||||||
|
|
||||||
namespace ARMeilleure.Translation
|
namespace ARMeilleure.Translation
|
||||||
{
|
{
|
||||||
class DelegateInfo
|
public class DelegateInfo
|
||||||
{
|
{
|
||||||
public IntPtr FuncPtr { get; }
|
public nint FuncPtr { get; }
|
||||||
|
|
||||||
public DelegateInfo(IntPtr funcPtr)
|
public DelegateInfo(nint funcPtr)
|
||||||
{
|
{
|
||||||
FuncPtr = funcPtr;
|
FuncPtr = funcPtr;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,12 +2,359 @@ using ARMeilleure.Instructions;
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
#if ANDROID
|
||||||
|
using ARMeilleure.State;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace ARMeilleure.Translation
|
namespace ARMeilleure.Translation
|
||||||
{
|
{
|
||||||
static class Delegates
|
static class Delegates
|
||||||
{
|
{
|
||||||
public static bool TryGetDelegateFuncPtrByIndex(int index, out IntPtr funcPtr)
|
#if ANDROID
|
||||||
|
// MathHelper delegates
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate double MathHelperAbsDelegate(double value);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate double MathHelperCeilingDelegate(double value);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate double MathHelperFloorDelegate(double value);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate double MathHelperRoundDelegate(double value, int mode);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate double MathHelperTruncateDelegate(double value);
|
||||||
|
|
||||||
|
// MathHelperF delegates
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate float MathHelperFAbsDelegate(float value);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate float MathHelperFCeilingDelegate(float value);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate float MathHelperFFloorDelegate(float value);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate float MathHelperFRoundDelegate(float value, int mode);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate float MathHelperFTruncateDelegate(float value);
|
||||||
|
|
||||||
|
// NativeInterface delegates
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate void NativeInterfaceBreakDelegate(ulong address, int imm);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate byte NativeInterfaceCheckSynchronizationDelegate();
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate void NativeInterfaceEnqueueForRejitDelegate(ulong address);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate ulong NativeInterfaceGetCntfrqEl0Delegate();
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate ulong NativeInterfaceGetCntpctEl0Delegate();
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate ulong NativeInterfaceGetCntvctEl0Delegate();
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate ulong NativeInterfaceGetCtrEl0Delegate();
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate ulong NativeInterfaceGetDczidEl0Delegate();
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate ulong NativeInterfaceGetFunctionAddressDelegate(ulong address);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate void NativeInterfaceInvalidateCacheLineDelegate(ulong address);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate byte NativeInterfaceReadByteDelegate(ulong address);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate ushort NativeInterfaceReadUInt16Delegate(ulong address);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate uint NativeInterfaceReadUInt32Delegate(ulong address);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate ulong NativeInterfaceReadUInt64Delegate(ulong address);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate V128 NativeInterfaceReadVector128Delegate(ulong address);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate void NativeInterfaceSignalMemoryTrackingDelegate(ulong address, ulong size, byte write);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate void NativeInterfaceSupervisorCallDelegate(ulong address, int imm);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate void NativeInterfaceThrowInvalidMemoryAccessDelegate(ulong address);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate void NativeInterfaceUndefinedDelegate(ulong address, int opCode);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate void NativeInterfaceWriteByteDelegate(ulong address, byte value);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate void NativeInterfaceWriteUInt16Delegate(ulong address, ushort value);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate void NativeInterfaceWriteUInt32Delegate(ulong address, uint value);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate void NativeInterfaceWriteUInt64Delegate(ulong address, ulong value);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate void NativeInterfaceWriteVector128Delegate(ulong address, V128 value);
|
||||||
|
|
||||||
|
// SoftFallback delegates
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate ulong SoftFallbackCountLeadingSignsDelegate(ulong value, int size);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate ulong SoftFallbackCountLeadingZerosDelegate(ulong value, int size);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate uint SoftFallbackCrc32bDelegate(uint crc, byte val);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate uint SoftFallbackCrc32cbDelegate(uint crc, byte val);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate uint SoftFallbackCrc32chDelegate(uint crc, ushort val);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate uint SoftFallbackCrc32cwDelegate(uint crc, uint val);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate uint SoftFallbackCrc32cxDelegate(uint crc, ulong val);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate uint SoftFallbackCrc32hDelegate(uint crc, ushort val);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate uint SoftFallbackCrc32wDelegate(uint crc, uint val);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate uint SoftFallbackCrc32xDelegate(uint crc, ulong val);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate V128 SoftFallbackDecryptDelegate(V128 value, V128 roundKey);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate V128 SoftFallbackEncryptDelegate(V128 value, V128 roundKey);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate uint SoftFallbackFixedRotateDelegate(uint hash_e);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate V128 SoftFallbackHashChooseDelegate(V128 hash_abcd, uint hash_e, V128 wk);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate V128 SoftFallbackHashLowerDelegate(V128 hash_abcd, V128 hash_efgh, V128 wk);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate V128 SoftFallbackHashMajorityDelegate(V128 hash_abcd, uint hash_e, V128 wk);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate V128 SoftFallbackHashParityDelegate(V128 hash_abcd, uint hash_e, V128 wk);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate V128 SoftFallbackHashUpperDelegate(V128 hash_abcd, V128 hash_efgh, V128 wk);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate V128 SoftFallbackInverseMixColumnsDelegate(V128 value);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate V128 SoftFallbackMixColumnsDelegate(V128 value);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate V128 SoftFallbackPolynomialMult64_128Delegate(ulong op1, ulong op2);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate int SoftFallbackSatF32ToS32Delegate(float value);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate long SoftFallbackSatF32ToS64Delegate(float value);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate uint SoftFallbackSatF32ToU32Delegate(float value);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate ulong SoftFallbackSatF32ToU64Delegate(float value);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate int SoftFallbackSatF64ToS32Delegate(double value);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate long SoftFallbackSatF64ToS64Delegate(double value);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate uint SoftFallbackSatF64ToU32Delegate(double value);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate ulong SoftFallbackSatF64ToU64Delegate(double value);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate V128 SoftFallbackSha1SchedulePart1Delegate(V128 w0_3, V128 w4_7, V128 w8_11);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate V128 SoftFallbackSha1SchedulePart2Delegate(V128 tw0_3, V128 w12_15);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate V128 SoftFallbackSha256SchedulePart1Delegate(V128 w0_3, V128 w4_7);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate V128 SoftFallbackSha256SchedulePart2Delegate(V128 w0_3, V128 w8_11, V128 w12_15);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate long SoftFallbackSignedShrImm64Delegate(long value, long roundConst, int shift);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate V128 SoftFallbackTbl1Delegate(V128 vector, int bytes, V128 table);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate V128 SoftFallbackTbl2Delegate(V128 vector, int bytes, V128 table0, V128 table1);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate V128 SoftFallbackTbl3Delegate(V128 vector, int bytes, V128 table0, V128 table1, V128 table2);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate V128 SoftFallbackTbl4Delegate(V128 vector, int bytes, V128 table0, V128 table1, V128 table2, V128 table3);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate V128 SoftFallbackTbx1Delegate(V128 dest, V128 vector, int bytes, V128 table);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate V128 SoftFallbackTbx2Delegate(V128 dest, V128 vector, int bytes, V128 table0, V128 table1);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate V128 SoftFallbackTbx3Delegate(V128 dest, V128 vector, int bytes, V128 table0, V128 table1, V128 table2);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate V128 SoftFallbackTbx4Delegate(V128 dest, V128 vector, int bytes, V128 table0, V128 table1, V128 table2, V128 table3);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate ulong SoftFallbackUnsignedShrImm64Delegate(ulong value, long roundConst, int shift);
|
||||||
|
|
||||||
|
// SoftFloat delegates
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate float SoftFloat16_32FPConvertDelegate(ushort value);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate double SoftFloat16_64FPConvertDelegate(ushort value);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate float SoftFloat32FPAddDelegate(float a, float b);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate float SoftFloat32FPAddFpscrDelegate(float a, float b, byte standardFpscr);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate int SoftFloat32FPCompareDelegate(float a, float b, byte signalNaNs);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate float SoftFloat32FPCompareEQDelegate(float a, float b);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate float SoftFloat32FPCompareEQFpscrDelegate(float a, float b, byte standardFpscr);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate float SoftFloat32FPCompareGEDelegate(float a, float b);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate float SoftFloat32FPCompareGEFpscrDelegate(float a, float b, byte standardFpscr);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate float SoftFloat32FPCompareGTDelegate(float a, float b);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate float SoftFloat32FPCompareGTFpscrDelegate(float a, float b, byte standardFpscr);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate float SoftFloat32FPCompareLEDelegate(float a, float b);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate float SoftFloat32FPCompareLEFpscrDelegate(float a, float b, byte standardFpscr);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate float SoftFloat32FPCompareLTDelegate(float a, float b);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate float SoftFloat32FPCompareLTFpscrDelegate(float a, float b, byte standardFpscr);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate float SoftFloat32FPDivDelegate(float a, float b);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate float SoftFloat32FPMaxDelegate(float a, float b);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate float SoftFloat32FPMaxFpscrDelegate(float a, float b, byte standardFpscr);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate float SoftFloat32FPMaxNumDelegate(float a, float b);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate float SoftFloat32FPMaxNumFpscrDelegate(float a, float b, byte standardFpscr);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate float SoftFloat32FPMinDelegate(float a, float b);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate float SoftFloat32FPMinFpscrDelegate(float a, float b, byte standardFpscr);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate float SoftFloat32FPMinNumDelegate(float a, float b);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate float SoftFloat32FPMinNumFpscrDelegate(float a, float b, byte standardFpscr);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate float SoftFloat32FPMulDelegate(float a, float b);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate float SoftFloat32FPMulFpscrDelegate(float a, float b, byte standardFpscr);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate float SoftFloat32FPMulAddDelegate(float a, float b, float c);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate float SoftFloat32FPMulAddFpscrDelegate(float a, float b, float c, byte standardFpscr);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate float SoftFloat32FPMulSubDelegate(float a, float b, float c);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate float SoftFloat32FPMulSubFpscrDelegate(float a, float b, float c, byte standardFpscr);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate float SoftFloat32FPMulXDelegate(float a, float b);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate float SoftFloat32FPNegMulAddDelegate(float a, float b, float c);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate float SoftFloat32FPNegMulSubDelegate(float a, float b, float c);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate float SoftFloat32FPRecipEstimateDelegate(float a);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate float SoftFloat32FPRecipEstimateFpscrDelegate(float a, byte standardFpscr);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate float SoftFloat32FPRecipStepDelegate(float a, float b);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate float SoftFloat32FPRecipStepFusedDelegate(float a, float b);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate float SoftFloat32FPRecpXDelegate(float a);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate float SoftFloat32FPRSqrtEstimateDelegate(float a);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate float SoftFloat32FPRSqrtEstimateFpscrDelegate(float a, byte standardFpscr);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate float SoftFloat32FPRSqrtStepDelegate(float a, float b);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate float SoftFloat32FPRSqrtStepFusedDelegate(float a, float b);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate float SoftFloat32FPSqrtDelegate(float a);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate float SoftFloat32FPSubDelegate(float a, float b);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate ushort SoftFloat32_16FPConvertDelegate(float value);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate double SoftFloat64FPAddDelegate(double a, double b);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate double SoftFloat64FPAddFpscrDelegate(double a, double b, byte standardFpscr);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate int SoftFloat64FPCompareDelegate(double a, double b, byte signalNaNs);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate double SoftFloat64FPCompareEQDelegate(double a, double b);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate double SoftFloat64FPCompareEQFpscrDelegate(double a, double b, byte standardFpscr);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate double SoftFloat64FPCompareGEDelegate(double a, double b);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate double SoftFloat64FPCompareGEFpscrDelegate(double a, double b, byte standardFpscr);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate double SoftFloat64FPCompareGTDelegate(double a, double b);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate double SoftFloat64FPCompareGTFpscrDelegate(double a, double b, byte standardFpscr);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate double SoftFloat64FPCompareLEDelegate(double a, double b);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate double SoftFloat64FPCompareLEFpscrDelegate(double a, double b, byte standardFpscr);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate double SoftFloat64FPCompareLTDelegate(double a, double b);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate double SoftFloat64FPCompareLTFpscrDelegate(double a, double b, byte standardFpscr);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate double SoftFloat64FPDivDelegate(double a, double b);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate double SoftFloat64FPMaxDelegate(double a, double b);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate double SoftFloat64FPMaxFpscrDelegate(double a, double b, byte standardFpscr);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate double SoftFloat64FPMaxNumDelegate(double a, double b);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate double SoftFloat64FPMaxNumFpscrDelegate(double a, double b, byte standardFpscr);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate double SoftFloat64FPMinDelegate(double a, double b);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate double SoftFloat64FPMinFpscrDelegate(double a, double b, byte standardFpscr);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate double SoftFloat64FPMinNumDelegate(double a, double b);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate double SoftFloat64FPMinNumFpscrDelegate(double a, double b, byte standardFpscr);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate double SoftFloat64FPMulDelegate(double a, double b);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate double SoftFloat64FPMulFpscrDelegate(double a, double b, byte standardFpscr);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate double SoftFloat64FPMulAddDelegate(double a, double b, double c);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate double SoftFloat64FPMulAddFpscrDelegate(double a, double b, double c, byte standardFpscr);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate double SoftFloat64FPMulSubDelegate(double a, double b, double c);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate double SoftFloat64FPMulSubFpscrDelegate(double a, double b, double c, byte standardFpscr);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate double SoftFloat64FPMulXDelegate(double a, double b);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate double SoftFloat64FPNegMulAddDelegate(double a, double b, double c);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate double SoftFloat64FPNegMulSubDelegate(double a, double b, double c);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate double SoftFloat64FPRecipEstimateDelegate(double a);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate double SoftFloat64FPRecipEstimateFpscrDelegate(double a, byte standardFpscr);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate double SoftFloat64FPRecipStepDelegate(double a, double b);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate double SoftFloat64FPRecipStepFusedDelegate(double a, double b);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate double SoftFloat64FPRecpXDelegate(double a);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate double SoftFloat64FPRSqrtEstimateDelegate(double a);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate double SoftFloat64FPRSqrtEstimateFpscrDelegate(double a, byte standardFpscr);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate double SoftFloat64FPRSqrtStepDelegate(double a, double b);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate double SoftFloat64FPRSqrtStepFusedDelegate(double a, double b);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate double SoftFloat64FPSqrtDelegate(double a);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate double SoftFloat64FPSubDelegate(double a, double b);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate ushort SoftFloat64_16FPConvertDelegate(double value);
|
||||||
|
|
||||||
|
private static readonly Dictionary<string, Delegate> _androidDelegates;
|
||||||
|
#endif
|
||||||
|
public static bool TryGetDelegateFuncPtrByIndex(int index, out nint funcPtr)
|
||||||
{
|
{
|
||||||
if (index >= 0 && index < _delegates.Count)
|
if (index >= 0 && index < _delegates.Count)
|
||||||
{
|
{
|
||||||
@@ -23,7 +370,7 @@ namespace ARMeilleure.Translation
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IntPtr GetDelegateFuncPtrByIndex(int index)
|
public static nint GetDelegateFuncPtrByIndex(int index)
|
||||||
{
|
{
|
||||||
if (index < 0 || index >= _delegates.Count)
|
if (index < 0 || index >= _delegates.Count)
|
||||||
{
|
{
|
||||||
@@ -53,12 +400,37 @@ namespace ARMeilleure.Translation
|
|||||||
{
|
{
|
||||||
string key = GetKey(method);
|
string key = GetKey(method);
|
||||||
|
|
||||||
_delegates.Add(key, new DelegateInfo(method.MethodHandle.GetFunctionPointer())); // ArgumentException (key).
|
#if ANDROID
|
||||||
|
if (_androidDelegates.TryGetValue(key, out Delegate del))
|
||||||
|
{
|
||||||
|
nint funcPtr = Marshal.GetFunctionPointerForDelegate(del);
|
||||||
|
_delegates.Add(key, new DelegateInfo(funcPtr));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_delegates.Add(key, new DelegateInfo(method.MethodHandle.GetFunctionPointer()));
|
||||||
|
}
|
||||||
|
catch (NotSupportedException) when (IsRunningOnAndroid())
|
||||||
|
{
|
||||||
|
throw new PlatformNotSupportedException($"Cannot obtain function pointer {key}: it must be registered.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool IsRunningOnAndroid()
|
||||||
|
{
|
||||||
|
#if ANDROID
|
||||||
|
return true;
|
||||||
|
#else
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string GetKey(MethodInfo info)
|
private static string GetKey(MethodInfo info)
|
||||||
{
|
{
|
||||||
return $"{info.DeclaringType.Name}.{info.Name}";
|
return $"{info.DeclaringType?.Name}.{info.Name}";
|
||||||
}
|
}
|
||||||
|
|
||||||
private static readonly SortedList<string, DelegateInfo> _delegates;
|
private static readonly SortedList<string, DelegateInfo> _delegates;
|
||||||
@@ -67,6 +439,190 @@ namespace ARMeilleure.Translation
|
|||||||
{
|
{
|
||||||
_delegates = new SortedList<string, DelegateInfo>();
|
_delegates = new SortedList<string, DelegateInfo>();
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
_androidDelegates = new Dictionary<string, Delegate>
|
||||||
|
{
|
||||||
|
// MathHelper delegates
|
||||||
|
{ "MathHelper.Abs", new MathHelperAbsDelegate(Math.Abs) },
|
||||||
|
{ "MathHelper.Ceiling", new MathHelperCeilingDelegate(Math.Ceiling) },
|
||||||
|
{ "MathHelper.Floor", new MathHelperFloorDelegate(Math.Floor) },
|
||||||
|
{ "MathHelper.Round", new MathHelperRoundDelegate((value, mode) => Math.Round(value, (MidpointRounding)mode)) },
|
||||||
|
{ "MathHelper.Truncate", new MathHelperTruncateDelegate(Math.Truncate) },
|
||||||
|
|
||||||
|
// MathHelperF delegates
|
||||||
|
{ "MathHelperF.Abs", new MathHelperFAbsDelegate(MathF.Abs) },
|
||||||
|
{ "MathHelperF.Ceiling", new MathHelperFCeilingDelegate(MathF.Ceiling) },
|
||||||
|
{ "MathHelperF.Floor", new MathHelperFFloorDelegate(MathF.Floor) },
|
||||||
|
{ "MathHelperF.Round", new MathHelperFRoundDelegate((value, mode) => MathF.Round(value, (MidpointRounding)mode)) },
|
||||||
|
{ "MathHelperF.Truncate", new MathHelperFTruncateDelegate(MathF.Truncate) },
|
||||||
|
|
||||||
|
// NativeInterface delegates
|
||||||
|
{ "NativeInterface.Break", new NativeInterfaceBreakDelegate(NativeInterface.Break) },
|
||||||
|
{ "NativeInterface.CheckSynchronization", new NativeInterfaceCheckSynchronizationDelegate(NativeInterface.CheckSynchronization) },
|
||||||
|
{ "NativeInterface.EnqueueForRejit", new NativeInterfaceEnqueueForRejitDelegate(NativeInterface.EnqueueForRejit) },
|
||||||
|
{ "NativeInterface.GetCntfrqEl0", new NativeInterfaceGetCntfrqEl0Delegate(NativeInterface.GetCntfrqEl0) },
|
||||||
|
{ "NativeInterface.GetCntpctEl0", new NativeInterfaceGetCntpctEl0Delegate(NativeInterface.GetCntpctEl0) },
|
||||||
|
{ "NativeInterface.GetCntvctEl0", new NativeInterfaceGetCntvctEl0Delegate(NativeInterface.GetCntvctEl0) },
|
||||||
|
{ "NativeInterface.GetCtrEl0", new NativeInterfaceGetCtrEl0Delegate(NativeInterface.GetCtrEl0) },
|
||||||
|
{ "NativeInterface.GetDczidEl0", new NativeInterfaceGetDczidEl0Delegate(NativeInterface.GetDczidEl0) },
|
||||||
|
{ "NativeInterface.GetFunctionAddress", new NativeInterfaceGetFunctionAddressDelegate(NativeInterface.GetFunctionAddress) },
|
||||||
|
{ "NativeInterface.InvalidateCacheLine", new NativeInterfaceInvalidateCacheLineDelegate(NativeInterface.InvalidateCacheLine) },
|
||||||
|
{ "NativeInterface.ReadByte", new NativeInterfaceReadByteDelegate(NativeInterface.ReadByte) },
|
||||||
|
{ "NativeInterface.ReadUInt16", new NativeInterfaceReadUInt16Delegate(NativeInterface.ReadUInt16) },
|
||||||
|
{ "NativeInterface.ReadUInt32", new NativeInterfaceReadUInt32Delegate(NativeInterface.ReadUInt32) },
|
||||||
|
{ "NativeInterface.ReadUInt64", new NativeInterfaceReadUInt64Delegate(NativeInterface.ReadUInt64) },
|
||||||
|
{ "NativeInterface.ReadVector128", new NativeInterfaceReadVector128Delegate(NativeInterface.ReadVector128) },
|
||||||
|
{ "NativeInterface.SignalMemoryTracking", new NativeInterfaceSignalMemoryTrackingDelegate(NativeInterface.SignalMemoryTracking) },
|
||||||
|
{ "NativeInterface.SupervisorCall", new NativeInterfaceSupervisorCallDelegate(NativeInterface.SupervisorCall) },
|
||||||
|
{ "NativeInterface.ThrowInvalidMemoryAccess", new NativeInterfaceThrowInvalidMemoryAccessDelegate(NativeInterface.ThrowInvalidMemoryAccess) },
|
||||||
|
{ "NativeInterface.Undefined", new NativeInterfaceUndefinedDelegate(NativeInterface.Undefined) },
|
||||||
|
{ "NativeInterface.WriteByte", new NativeInterfaceWriteByteDelegate(NativeInterface.WriteByte) },
|
||||||
|
{ "NativeInterface.WriteUInt16", new NativeInterfaceWriteUInt16Delegate(NativeInterface.WriteUInt16) },
|
||||||
|
{ "NativeInterface.WriteUInt32", new NativeInterfaceWriteUInt32Delegate(NativeInterface.WriteUInt32) },
|
||||||
|
{ "NativeInterface.WriteUInt64", new NativeInterfaceWriteUInt64Delegate(NativeInterface.WriteUInt64) },
|
||||||
|
{ "NativeInterface.WriteVector128", new NativeInterfaceWriteVector128Delegate(NativeInterface.WriteVector128) },
|
||||||
|
|
||||||
|
// SoftFallback delegates
|
||||||
|
{ "SoftFallback.CountLeadingSigns", new SoftFallbackCountLeadingSignsDelegate(SoftFallback.CountLeadingSigns) },
|
||||||
|
{ "SoftFallback.CountLeadingZeros", new SoftFallbackCountLeadingZerosDelegate(SoftFallback.CountLeadingZeros) },
|
||||||
|
{ "SoftFallback.Crc32b", new SoftFallbackCrc32bDelegate(SoftFallback.Crc32b) },
|
||||||
|
{ "SoftFallback.Crc32cb", new SoftFallbackCrc32cbDelegate(SoftFallback.Crc32cb) },
|
||||||
|
{ "SoftFallback.Crc32ch", new SoftFallbackCrc32chDelegate(SoftFallback.Crc32ch) },
|
||||||
|
{ "SoftFallback.Crc32cw", new SoftFallbackCrc32cwDelegate(SoftFallback.Crc32cw) },
|
||||||
|
{ "SoftFallback.Crc32cx", new SoftFallbackCrc32cxDelegate(SoftFallback.Crc32cx) },
|
||||||
|
{ "SoftFallback.Crc32h", new SoftFallbackCrc32hDelegate(SoftFallback.Crc32h) },
|
||||||
|
{ "SoftFallback.Crc32w", new SoftFallbackCrc32wDelegate(SoftFallback.Crc32w) },
|
||||||
|
{ "SoftFallback.Crc32x", new SoftFallbackCrc32xDelegate(SoftFallback.Crc32x) },
|
||||||
|
{ "SoftFallback.Decrypt", new SoftFallbackDecryptDelegate(SoftFallback.Decrypt) },
|
||||||
|
{ "SoftFallback.Encrypt", new SoftFallbackEncryptDelegate(SoftFallback.Encrypt) },
|
||||||
|
{ "SoftFallback.FixedRotate", new SoftFallbackFixedRotateDelegate(SoftFallback.FixedRotate) },
|
||||||
|
{ "SoftFallback.HashChoose", new SoftFallbackHashChooseDelegate(SoftFallback.HashChoose) },
|
||||||
|
{ "SoftFallback.HashLower", new SoftFallbackHashLowerDelegate(SoftFallback.HashLower) },
|
||||||
|
{ "SoftFallback.HashMajority", new SoftFallbackHashMajorityDelegate(SoftFallback.HashMajority) },
|
||||||
|
{ "SoftFallback.HashParity", new SoftFallbackHashParityDelegate(SoftFallback.HashParity) },
|
||||||
|
{ "SoftFallback.HashUpper", new SoftFallbackHashUpperDelegate(SoftFallback.HashUpper) },
|
||||||
|
{ "SoftFallback.InverseMixColumns", new SoftFallbackInverseMixColumnsDelegate(SoftFallback.InverseMixColumns) },
|
||||||
|
{ "SoftFallback.MixColumns", new SoftFallbackMixColumnsDelegate(SoftFallback.MixColumns) },
|
||||||
|
{ "SoftFallback.PolynomialMult64_128", new SoftFallbackPolynomialMult64_128Delegate(SoftFallback.PolynomialMult64_128) },
|
||||||
|
{ "SoftFallback.SatF32ToS32", new SoftFallbackSatF32ToS32Delegate(SoftFallback.SatF32ToS32) },
|
||||||
|
{ "SoftFallback.SatF32ToS64", new SoftFallbackSatF32ToS64Delegate(SoftFallback.SatF32ToS64) },
|
||||||
|
{ "SoftFallback.SatF32ToU32", new SoftFallbackSatF32ToU32Delegate(SoftFallback.SatF32ToU32) },
|
||||||
|
{ "SoftFallback.SatF32ToU64", new SoftFallbackSatF32ToU64Delegate(SoftFallback.SatF32ToU64) },
|
||||||
|
{ "SoftFallback.SatF64ToS32", new SoftFallbackSatF64ToS32Delegate(SoftFallback.SatF64ToS32) },
|
||||||
|
{ "SoftFallback.SatF64ToS64", new SoftFallbackSatF64ToS64Delegate(SoftFallback.SatF64ToS64) },
|
||||||
|
{ "SoftFallback.SatF64ToU32", new SoftFallbackSatF64ToU32Delegate(SoftFallback.SatF64ToU32) },
|
||||||
|
{ "SoftFallback.SatF64ToU64", new SoftFallbackSatF64ToU64Delegate(SoftFallback.SatF64ToU64) },
|
||||||
|
{ "SoftFallback.Sha1SchedulePart1", new SoftFallbackSha1SchedulePart1Delegate(SoftFallback.Sha1SchedulePart1) },
|
||||||
|
{ "SoftFallback.Sha1SchedulePart2", new SoftFallbackSha1SchedulePart2Delegate(SoftFallback.Sha1SchedulePart2) },
|
||||||
|
{ "SoftFallback.Sha256SchedulePart1", new SoftFallbackSha256SchedulePart1Delegate(SoftFallback.Sha256SchedulePart1) },
|
||||||
|
{ "SoftFallback.Sha256SchedulePart2", new SoftFallbackSha256SchedulePart2Delegate(SoftFallback.Sha256SchedulePart2) },
|
||||||
|
{ "SoftFallback.SignedShrImm64", new SoftFallbackSignedShrImm64Delegate(SoftFallback.SignedShrImm64) },
|
||||||
|
{ "SoftFallback.Tbl1", new SoftFallbackTbl1Delegate(SoftFallback.Tbl1) },
|
||||||
|
{ "SoftFallback.Tbl2", new SoftFallbackTbl2Delegate(SoftFallback.Tbl2) },
|
||||||
|
{ "SoftFallback.Tbl3", new SoftFallbackTbl3Delegate(SoftFallback.Tbl3) },
|
||||||
|
{ "SoftFallback.Tbl4", new SoftFallbackTbl4Delegate(SoftFallback.Tbl4) },
|
||||||
|
{ "SoftFallback.Tbx1", new SoftFallbackTbx1Delegate(SoftFallback.Tbx1) },
|
||||||
|
{ "SoftFallback.Tbx2", new SoftFallbackTbx2Delegate(SoftFallback.Tbx2) },
|
||||||
|
{ "SoftFallback.Tbx3", new SoftFallbackTbx3Delegate(SoftFallback.Tbx3) },
|
||||||
|
{ "SoftFallback.Tbx4", new SoftFallbackTbx4Delegate(SoftFallback.Tbx4) },
|
||||||
|
{ "SoftFallback.UnsignedShrImm64", new SoftFallbackUnsignedShrImm64Delegate(SoftFallback.UnsignedShrImm64) },
|
||||||
|
|
||||||
|
// SoftFloat delegates
|
||||||
|
{ "SoftFloat16_32.FPConvert", new SoftFloat16_32FPConvertDelegate(SoftFloat16_32.FPConvert) },
|
||||||
|
{ "SoftFloat16_64.FPConvert", new SoftFloat16_64FPConvertDelegate(SoftFloat16_64.FPConvert) },
|
||||||
|
|
||||||
|
{ "SoftFloat32.FPAdd", new SoftFloat32FPAddDelegate(SoftFloat32.FPAdd) },
|
||||||
|
{ "SoftFloat32.FPAddFpscr", new SoftFloat32FPAddFpscrDelegate(SoftFloat32.FPAddFpscr) },
|
||||||
|
{ "SoftFloat32.FPCompare", new SoftFloat32FPCompareDelegate(SoftFloat32.FPCompare) },
|
||||||
|
{ "SoftFloat32.FPCompareEQ", new SoftFloat32FPCompareEQDelegate(SoftFloat32.FPCompareEQ) },
|
||||||
|
{ "SoftFloat32.FPCompareEQFpscr", new SoftFloat32FPCompareEQFpscrDelegate(SoftFloat32.FPCompareEQFpscr) },
|
||||||
|
{ "SoftFloat32.FPCompareGE", new SoftFloat32FPCompareGEDelegate(SoftFloat32.FPCompareGE) },
|
||||||
|
{ "SoftFloat32.FPCompareGEFpscr", new SoftFloat32FPCompareGEFpscrDelegate(SoftFloat32.FPCompareGEFpscr) },
|
||||||
|
{ "SoftFloat32.FPCompareGT", new SoftFloat32FPCompareGTDelegate(SoftFloat32.FPCompareGT) },
|
||||||
|
{ "SoftFloat32.FPCompareGTFpscr", new SoftFloat32FPCompareGTFpscrDelegate(SoftFloat32.FPCompareGTFpscr) },
|
||||||
|
{ "SoftFloat32.FPCompareLE", new SoftFloat32FPCompareLEDelegate(SoftFloat32.FPCompareLE) },
|
||||||
|
{ "SoftFloat32.FPCompareLEFpscr", new SoftFloat32FPCompareLEFpscrDelegate(SoftFloat32.FPCompareLEFpscr) },
|
||||||
|
{ "SoftFloat32.FPCompareLT", new SoftFloat32FPCompareLTDelegate(SoftFloat32.FPCompareLT) },
|
||||||
|
{ "SoftFloat32.FPCompareLTFpscr", new SoftFloat32FPCompareLTFpscrDelegate(SoftFloat32.FPCompareLTFpscr) },
|
||||||
|
{ "SoftFloat32.FPDiv", new SoftFloat32FPDivDelegate(SoftFloat32.FPDiv) },
|
||||||
|
{ "SoftFloat32.FPMax", new SoftFloat32FPMaxDelegate(SoftFloat32.FPMax) },
|
||||||
|
{ "SoftFloat32.FPMaxFpscr", new SoftFloat32FPMaxFpscrDelegate(SoftFloat32.FPMaxFpscr) },
|
||||||
|
{ "SoftFloat32.FPMaxNum", new SoftFloat32FPMaxNumDelegate(SoftFloat32.FPMaxNum) },
|
||||||
|
{ "SoftFloat32.FPMaxNumFpscr", new SoftFloat32FPMaxNumFpscrDelegate(SoftFloat32.FPMaxNumFpscr) },
|
||||||
|
{ "SoftFloat32.FPMin", new SoftFloat32FPMinDelegate(SoftFloat32.FPMin) },
|
||||||
|
{ "SoftFloat32.FPMinFpscr", new SoftFloat32FPMinFpscrDelegate(SoftFloat32.FPMinFpscr) },
|
||||||
|
{ "SoftFloat32.FPMinNum", new SoftFloat32FPMinNumDelegate(SoftFloat32.FPMinNum) },
|
||||||
|
{ "SoftFloat32.FPMinNumFpscr", new SoftFloat32FPMinNumFpscrDelegate(SoftFloat32.FPMinNumFpscr) },
|
||||||
|
{ "SoftFloat32.FPMul", new SoftFloat32FPMulDelegate(SoftFloat32.FPMul) },
|
||||||
|
{ "SoftFloat32.FPMulFpscr", new SoftFloat32FPMulFpscrDelegate(SoftFloat32.FPMulFpscr) },
|
||||||
|
{ "SoftFloat32.FPMulAdd", new SoftFloat32FPMulAddDelegate(SoftFloat32.FPMulAdd) },
|
||||||
|
{ "SoftFloat32.FPMulAddFpscr", new SoftFloat32FPMulAddFpscrDelegate(SoftFloat32.FPMulAddFpscr) },
|
||||||
|
{ "SoftFloat32.FPMulSub", new SoftFloat32FPMulSubDelegate(SoftFloat32.FPMulSub) },
|
||||||
|
{ "SoftFloat32.FPMulSubFpscr", new SoftFloat32FPMulSubFpscrDelegate(SoftFloat32.FPMulSubFpscr) },
|
||||||
|
{ "SoftFloat32.FPMulX", new SoftFloat32FPMulXDelegate(SoftFloat32.FPMulX) },
|
||||||
|
{ "SoftFloat32.FPNegMulAdd", new SoftFloat32FPNegMulAddDelegate(SoftFloat32.FPNegMulAdd) },
|
||||||
|
{ "SoftFloat32.FPNegMulSub", new SoftFloat32FPNegMulSubDelegate(SoftFloat32.FPNegMulSub) },
|
||||||
|
{ "SoftFloat32.FPRecipEstimate", new SoftFloat32FPRecipEstimateDelegate(SoftFloat32.FPRecipEstimate) },
|
||||||
|
{ "SoftFloat32.FPRecipEstimateFpscr", new SoftFloat32FPRecipEstimateFpscrDelegate(SoftFloat32.FPRecipEstimateFpscr) },
|
||||||
|
{ "SoftFloat32.FPRecipStep", new SoftFloat32FPRecipStepDelegate(SoftFloat32.FPRecipStep) },
|
||||||
|
{ "SoftFloat32.FPRecipStepFused", new SoftFloat32FPRecipStepFusedDelegate(SoftFloat32.FPRecipStepFused) },
|
||||||
|
{ "SoftFloat32.FPRecpX", new SoftFloat32FPRecpXDelegate(SoftFloat32.FPRecpX) },
|
||||||
|
{ "SoftFloat32.FPRSqrtEstimate", new SoftFloat32FPRSqrtEstimateDelegate(SoftFloat32.FPRSqrtEstimate) },
|
||||||
|
{ "SoftFloat32.FPRSqrtEstimateFpscr", new SoftFloat32FPRSqrtEstimateFpscrDelegate(SoftFloat32.FPRSqrtEstimateFpscr) },
|
||||||
|
{ "SoftFloat32.FPRSqrtStep", new SoftFloat32FPRSqrtStepDelegate(SoftFloat32.FPRSqrtStep) },
|
||||||
|
{ "SoftFloat32.FPRSqrtStepFused", new SoftFloat32FPRSqrtStepFusedDelegate(SoftFloat32.FPRSqrtStepFused) },
|
||||||
|
{ "SoftFloat32.FPSqrt", new SoftFloat32FPSqrtDelegate(SoftFloat32.FPSqrt) },
|
||||||
|
{ "SoftFloat32.FPSub", new SoftFloat32FPSubDelegate(SoftFloat32.FPSub) },
|
||||||
|
|
||||||
|
{ "SoftFloat32_16.FPConvert", new SoftFloat32_16FPConvertDelegate(SoftFloat32_16.FPConvert) },
|
||||||
|
|
||||||
|
{ "SoftFloat64.FPAdd", new SoftFloat64FPAddDelegate(SoftFloat64.FPAdd) },
|
||||||
|
{ "SoftFloat64.FPAddFpscr", new SoftFloat64FPAddFpscrDelegate(SoftFloat64.FPAddFpscr) },
|
||||||
|
{ "SoftFloat64.FPCompare", new SoftFloat64FPCompareDelegate(SoftFloat64.FPCompare) },
|
||||||
|
{ "SoftFloat64.FPCompareEQ", new SoftFloat64FPCompareEQDelegate(SoftFloat64.FPCompareEQ) },
|
||||||
|
{ "SoftFloat64.FPCompareEQFpscr", new SoftFloat64FPCompareEQFpscrDelegate(SoftFloat64.FPCompareEQFpscr) },
|
||||||
|
{ "SoftFloat64.FPCompareGE", new SoftFloat64FPCompareGEDelegate(SoftFloat64.FPCompareGE) },
|
||||||
|
{ "SoftFloat64.FPCompareGEFpscr", new SoftFloat64FPCompareGEFpscrDelegate(SoftFloat64.FPCompareGEFpscr) },
|
||||||
|
{ "SoftFloat64.FPCompareGT", new SoftFloat64FPCompareGTDelegate(SoftFloat64.FPCompareGT) },
|
||||||
|
{ "SoftFloat64.FPCompareGTFpscr", new SoftFloat64FPCompareGTFpscrDelegate(SoftFloat64.FPCompareGTFpscr) },
|
||||||
|
{ "SoftFloat64.FPCompareLE", new SoftFloat64FPCompareLEDelegate(SoftFloat64.FPCompareLE) },
|
||||||
|
{ "SoftFloat64.FPCompareLEFpscr", new SoftFloat64FPCompareLEFpscrDelegate(SoftFloat64.FPCompareLEFpscr) },
|
||||||
|
{ "SoftFloat64.FPCompareLT", new SoftFloat64FPCompareLTDelegate(SoftFloat64.FPCompareLT) },
|
||||||
|
{ "SoftFloat64.FPCompareLTFpscr", new SoftFloat64FPCompareLTFpscrDelegate(SoftFloat64.FPCompareLTFpscr) },
|
||||||
|
{ "SoftFloat64.FPDiv", new SoftFloat64FPDivDelegate(SoftFloat64.FPDiv) },
|
||||||
|
{ "SoftFloat64.FPMax", new SoftFloat64FPMaxDelegate(SoftFloat64.FPMax) },
|
||||||
|
{ "SoftFloat64.FPMaxFpscr", new SoftFloat64FPMaxFpscrDelegate(SoftFloat64.FPMaxFpscr) },
|
||||||
|
{ "SoftFloat64.FPMaxNum", new SoftFloat64FPMaxNumDelegate(SoftFloat64.FPMaxNum) },
|
||||||
|
{ "SoftFloat64.FPMaxNumFpscr", new SoftFloat64FPMaxNumFpscrDelegate(SoftFloat64.FPMaxNumFpscr) },
|
||||||
|
{ "SoftFloat64.FPMin", new SoftFloat64FPMinDelegate(SoftFloat64.FPMin) },
|
||||||
|
{ "SoftFloat64.FPMinFpscr", new SoftFloat64FPMinFpscrDelegate(SoftFloat64.FPMinFpscr) },
|
||||||
|
{ "SoftFloat64.FPMinNum", new SoftFloat64FPMinNumDelegate(SoftFloat64.FPMinNum) },
|
||||||
|
{ "SoftFloat64.FPMinNumFpscr", new SoftFloat64FPMinNumFpscrDelegate(SoftFloat64.FPMinNumFpscr) },
|
||||||
|
{ "SoftFloat64.FPMul", new SoftFloat64FPMulDelegate(SoftFloat64.FPMul) },
|
||||||
|
{ "SoftFloat64.FPMulFpscr", new SoftFloat64FPMulFpscrDelegate(SoftFloat64.FPMulFpscr) },
|
||||||
|
{ "SoftFloat64.FPMulAdd", new SoftFloat64FPMulAddDelegate(SoftFloat64.FPMulAdd) },
|
||||||
|
{ "SoftFloat64.FPMulAddFpscr", new SoftFloat64FPMulAddFpscrDelegate(SoftFloat64.FPMulAddFpscr) },
|
||||||
|
{ "SoftFloat64.FPMulSub", new SoftFloat64FPMulSubDelegate(SoftFloat64.FPMulSub) },
|
||||||
|
{ "SoftFloat64.FPMulSubFpscr", new SoftFloat64FPMulSubFpscrDelegate(SoftFloat64.FPMulSubFpscr) },
|
||||||
|
{ "SoftFloat64.FPMulX", new SoftFloat64FPMulXDelegate(SoftFloat64.FPMulX) },
|
||||||
|
{ "SoftFloat64.FPNegMulAdd", new SoftFloat64FPNegMulAddDelegate(SoftFloat64.FPNegMulAdd) },
|
||||||
|
{ "SoftFloat64.FPNegMulSub", new SoftFloat64FPNegMulSubDelegate(SoftFloat64.FPNegMulSub) },
|
||||||
|
{ "SoftFloat64.FPRecipEstimate", new SoftFloat64FPRecipEstimateDelegate(SoftFloat64.FPRecipEstimate) },
|
||||||
|
{ "SoftFloat64.FPRecipEstimateFpscr", new SoftFloat64FPRecipEstimateFpscrDelegate(SoftFloat64.FPRecipEstimateFpscr) },
|
||||||
|
{ "SoftFloat64.FPRecipStep", new SoftFloat64FPRecipStepDelegate(SoftFloat64.FPRecipStep) },
|
||||||
|
{ "SoftFloat64.FPRecipStepFused", new SoftFloat64FPRecipStepFusedDelegate(SoftFloat64.FPRecipStepFused) },
|
||||||
|
{ "SoftFloat64.FPRecpX", new SoftFloat64FPRecpXDelegate(SoftFloat64.FPRecpX) },
|
||||||
|
{ "SoftFloat64.FPRSqrtEstimate", new SoftFloat64FPRSqrtEstimateDelegate(SoftFloat64.FPRSqrtEstimate) },
|
||||||
|
{ "SoftFloat64.FPRSqrtEstimateFpscr", new SoftFloat64FPRSqrtEstimateFpscrDelegate(SoftFloat64.FPRSqrtEstimateFpscr) },
|
||||||
|
{ "SoftFloat64.FPRSqrtStep", new SoftFloat64FPRSqrtStepDelegate(SoftFloat64.FPRSqrtStep) },
|
||||||
|
{ "SoftFloat64.FPRSqrtStepFused", new SoftFloat64FPRSqrtStepFusedDelegate(SoftFloat64.FPRSqrtStepFused) },
|
||||||
|
{ "SoftFloat64.FPSqrt", new SoftFloat64FPSqrtDelegate(SoftFloat64.FPSqrt) },
|
||||||
|
{ "SoftFloat64.FPSub", new SoftFloat64FPSubDelegate(SoftFloat64.FPSub) },
|
||||||
|
|
||||||
|
{ "SoftFloat64_16.FPConvert", new SoftFloat64_16FPConvertDelegate(SoftFloat64_16.FPConvert) }
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
SetDelegateInfo(typeof(MathHelper).GetMethod(nameof(MathHelper.Abs)));
|
SetDelegateInfo(typeof(MathHelper).GetMethod(nameof(MathHelper.Abs)));
|
||||||
SetDelegateInfo(typeof(MathHelper).GetMethod(nameof(MathHelper.Ceiling)));
|
SetDelegateInfo(typeof(MathHelper).GetMethod(nameof(MathHelper.Ceiling)));
|
||||||
SetDelegateInfo(typeof(MathHelper).GetMethod(nameof(MathHelper.Floor)));
|
SetDelegateInfo(typeof(MathHelper).GetMethod(nameof(MathHelper.Floor)));
|
||||||
@@ -152,44 +708,44 @@ namespace ARMeilleure.Translation
|
|||||||
SetDelegateInfo(typeof(SoftFloat16_64).GetMethod(nameof(SoftFloat16_64.FPConvert)));
|
SetDelegateInfo(typeof(SoftFloat16_64).GetMethod(nameof(SoftFloat16_64.FPConvert)));
|
||||||
|
|
||||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPAdd)));
|
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPAdd)));
|
||||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPAddFpscr))); // A32 only.
|
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPAddFpscr)));
|
||||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompare)));
|
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompare)));
|
||||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareEQ)));
|
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareEQ)));
|
||||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareEQFpscr))); // A32 only.
|
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareEQFpscr)));
|
||||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareGE)));
|
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareGE)));
|
||||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareGEFpscr))); // A32 only.
|
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareGEFpscr)));
|
||||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareGT)));
|
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareGT)));
|
||||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareGTFpscr))); // A32 only.
|
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareGTFpscr)));
|
||||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareLE)));
|
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareLE)));
|
||||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareLEFpscr))); // A32 only.
|
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareLEFpscr)));
|
||||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareLT)));
|
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareLT)));
|
||||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareLTFpscr))); // A32 only.
|
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareLTFpscr)));
|
||||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPDiv)));
|
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPDiv)));
|
||||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMax)));
|
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMax)));
|
||||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMaxFpscr))); // A32 only.
|
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMaxFpscr)));
|
||||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMaxNum)));
|
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMaxNum)));
|
||||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMaxNumFpscr))); // A32 only.
|
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMaxNumFpscr)));
|
||||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMin)));
|
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMin)));
|
||||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMinFpscr))); // A32 only.
|
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMinFpscr)));
|
||||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMinNum)));
|
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMinNum)));
|
||||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMinNumFpscr))); // A32 only.
|
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMinNumFpscr)));
|
||||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMul)));
|
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMul)));
|
||||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMulFpscr))); // A32 only.
|
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMulFpscr)));
|
||||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMulAdd)));
|
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMulAdd)));
|
||||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMulAddFpscr))); // A32 only.
|
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMulAddFpscr)));
|
||||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMulSub)));
|
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMulSub)));
|
||||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMulSubFpscr))); // A32 only.
|
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMulSubFpscr)));
|
||||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMulX)));
|
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMulX)));
|
||||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPNegMulAdd)));
|
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPNegMulAdd)));
|
||||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPNegMulSub)));
|
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPNegMulSub)));
|
||||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRecipEstimate)));
|
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRecipEstimate)));
|
||||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRecipEstimateFpscr))); // A32 only.
|
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRecipEstimateFpscr)));
|
||||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRecipStep))); // A32 only.
|
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRecipStep)));
|
||||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRecipStepFused)));
|
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRecipStepFused)));
|
||||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRecpX)));
|
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRecpX)));
|
||||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRSqrtEstimate)));
|
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRSqrtEstimate)));
|
||||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRSqrtEstimateFpscr))); // A32 only.
|
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRSqrtEstimateFpscr)));
|
||||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRSqrtStep))); // A32 only.
|
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRSqrtStep)));
|
||||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRSqrtStepFused)));
|
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRSqrtStepFused)));
|
||||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPSqrt)));
|
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPSqrt)));
|
||||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPSub)));
|
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPSub)));
|
||||||
@@ -197,44 +753,44 @@ namespace ARMeilleure.Translation
|
|||||||
SetDelegateInfo(typeof(SoftFloat32_16).GetMethod(nameof(SoftFloat32_16.FPConvert)));
|
SetDelegateInfo(typeof(SoftFloat32_16).GetMethod(nameof(SoftFloat32_16.FPConvert)));
|
||||||
|
|
||||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPAdd)));
|
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPAdd)));
|
||||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPAddFpscr))); // A32 only.
|
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPAddFpscr)));
|
||||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompare)));
|
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompare)));
|
||||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareEQ)));
|
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareEQ)));
|
||||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareEQFpscr))); // A32 only.
|
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareEQFpscr)));
|
||||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareGE)));
|
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareGE)));
|
||||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareGEFpscr))); // A32 only.
|
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareGEFpscr)));
|
||||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareGT)));
|
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareGT)));
|
||||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareGTFpscr))); // A32 only.
|
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareGTFpscr)));
|
||||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareLE)));
|
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareLE)));
|
||||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareLEFpscr))); // A32 only.
|
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareLEFpscr)));
|
||||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareLT)));
|
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareLT)));
|
||||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareLTFpscr))); // A32 only.
|
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareLTFpscr)));
|
||||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPDiv)));
|
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPDiv)));
|
||||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMax)));
|
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMax)));
|
||||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMaxFpscr))); // A32 only.
|
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMaxFpscr)));
|
||||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMaxNum)));
|
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMaxNum)));
|
||||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMaxNumFpscr))); // A32 only.
|
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMaxNumFpscr)));
|
||||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMin)));
|
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMin)));
|
||||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMinFpscr))); // A32 only.
|
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMinFpscr)));
|
||||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMinNum)));
|
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMinNum)));
|
||||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMinNumFpscr))); // A32 only.
|
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMinNumFpscr)));
|
||||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMul)));
|
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMul)));
|
||||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMulFpscr))); // A32 only.
|
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMulFpscr)));
|
||||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMulAdd)));
|
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMulAdd)));
|
||||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMulAddFpscr))); // A32 only.
|
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMulAddFpscr)));
|
||||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMulSub)));
|
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMulSub)));
|
||||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMulSubFpscr))); // A32 only.
|
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMulSubFpscr)));
|
||||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMulX)));
|
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMulX)));
|
||||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPNegMulAdd)));
|
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPNegMulAdd)));
|
||||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPNegMulSub)));
|
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPNegMulSub)));
|
||||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRecipEstimate)));
|
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRecipEstimate)));
|
||||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRecipEstimateFpscr))); // A32 only.
|
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRecipEstimateFpscr)));
|
||||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRecipStep))); // A32 only.
|
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRecipStep)));
|
||||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRecipStepFused)));
|
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRecipStepFused)));
|
||||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRecpX)));
|
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRecpX)));
|
||||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRSqrtEstimate)));
|
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRSqrtEstimate)));
|
||||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRSqrtEstimateFpscr))); // A32 only.
|
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRSqrtEstimateFpscr)));
|
||||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRSqrtStep))); // A32 only.
|
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRSqrtStep)));
|
||||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRSqrtStepFused)));
|
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRSqrtStepFused)));
|
||||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPSqrt)));
|
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPSqrt)));
|
||||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPSub)));
|
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPSub)));
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
using System;
|
|
||||||
|
|
||||||
namespace ARMeilleure.Translation
|
namespace ARMeilleure.Translation
|
||||||
{
|
{
|
||||||
delegate void DispatcherFunction(IntPtr nativeContext, ulong startAddress);
|
delegate void DispatcherFunction(nint nativeContext, ulong startAddress);
|
||||||
delegate ulong WrapperFunction(IntPtr nativeContext, ulong startAddress);
|
delegate ulong WrapperFunction(nint nativeContext, ulong startAddress);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -97,7 +97,14 @@ namespace ARMeilleure.Translation
|
|||||||
|
|
||||||
public virtual Operand Call(MethodInfo info, params Operand[] callArgs)
|
public virtual Operand Call(MethodInfo info, params Operand[] callArgs)
|
||||||
{
|
{
|
||||||
IntPtr funcPtr = info.MethodHandle.GetFunctionPointer();
|
#if ANDROID
|
||||||
|
// For Android, use the Delegates class to get the function pointer
|
||||||
|
int index = Delegates.GetDelegateIndex(info);
|
||||||
|
nint funcPtr = Delegates.GetDelegateFuncPtrByIndex(index);
|
||||||
|
#else
|
||||||
|
// For other platforms, use direct method handle approach
|
||||||
|
nint funcPtr = info.MethodHandle.GetFunctionPointer();
|
||||||
|
#endif
|
||||||
|
|
||||||
OperandType returnType = GetOperandType(info.ReturnType);
|
OperandType returnType = GetOperandType(info.ReturnType);
|
||||||
|
|
||||||
@@ -668,8 +675,7 @@ namespace ARMeilleure.Translation
|
|||||||
Operation last = block.Operations.Last;
|
Operation last = block.Operations.Last;
|
||||||
|
|
||||||
return last != default &&
|
return last != default &&
|
||||||
(last.Instruction == Instruction.Return ||
|
last.Instruction is Instruction.Return or Instruction.Tailcall;
|
||||||
last.Instruction == Instruction.Tailcall);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public ControlFlowGraph GetControlFlowGraph()
|
public ControlFlowGraph GetControlFlowGraph()
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
using System;
|
|
||||||
|
|
||||||
namespace ARMeilleure.Translation
|
namespace ARMeilleure.Translation
|
||||||
{
|
{
|
||||||
delegate ulong GuestFunction(IntPtr nativeContextPtr);
|
delegate ulong GuestFunction(nint nativeContextPtr);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -316,7 +316,7 @@ namespace ARMeilleure.Translation
|
|||||||
{
|
{
|
||||||
_root = newNode;
|
_root = newNode;
|
||||||
}
|
}
|
||||||
else if (start.CompareTo(parent.Start) < 0)
|
else if (start.CompareTo(parent!.Start) < 0)
|
||||||
{
|
{
|
||||||
parent.Left = newNode;
|
parent.Left = newNode;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ using Ryujinx.Common.Logging;
|
|||||||
using Ryujinx.Common.Memory;
|
using Ryujinx.Common.Memory;
|
||||||
using System;
|
using System;
|
||||||
using System.Buffers.Binary;
|
using System.Buffers.Binary;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
@@ -30,14 +31,11 @@ namespace ARMeilleure.Translation.PTC
|
|||||||
private const string OuterHeaderMagicString = "PTCohd\0\0";
|
private const string OuterHeaderMagicString = "PTCohd\0\0";
|
||||||
private const string InnerHeaderMagicString = "PTCihd\0\0";
|
private const string InnerHeaderMagicString = "PTCihd\0\0";
|
||||||
|
|
||||||
private const uint InternalVersion = 6998; //! To be incremented manually for each change to the ARMeilleure project.
|
private const uint InternalVersion = 7031; //! To be incremented manually for each change to the ARMeilleure project.
|
||||||
|
|
||||||
private const string ActualDir = "0";
|
private const string ActualDir = "0";
|
||||||
private const string BackupDir = "1";
|
private const string BackupDir = "1";
|
||||||
|
|
||||||
private const string TitleIdTextDefault = "0000000000000000";
|
|
||||||
private const string DisplayVersionDefault = "0";
|
|
||||||
|
|
||||||
public static readonly Symbol PageTableSymbol = new(SymbolType.Special, 1);
|
public static readonly Symbol PageTableSymbol = new(SymbolType.Special, 1);
|
||||||
public static readonly Symbol CountTableSymbol = new(SymbolType.Special, 2);
|
public static readonly Symbol CountTableSymbol = new(SymbolType.Special, 2);
|
||||||
public static readonly Symbol DispatchStubSymbol = new(SymbolType.Special, 3);
|
public static readonly Symbol DispatchStubSymbol = new(SymbolType.Special, 3);
|
||||||
@@ -63,8 +61,7 @@ namespace ARMeilleure.Translation.PTC
|
|||||||
|
|
||||||
private bool _disposed;
|
private bool _disposed;
|
||||||
|
|
||||||
public string TitleIdText { get; private set; }
|
public PtcCacheInfo CacheInfo { get; private set; }
|
||||||
public string DisplayVersion { get; private set; }
|
|
||||||
|
|
||||||
private MemoryManagerType _memoryMode;
|
private MemoryManagerType _memoryMode;
|
||||||
|
|
||||||
@@ -91,8 +88,7 @@ namespace ARMeilleure.Translation.PTC
|
|||||||
|
|
||||||
_disposed = false;
|
_disposed = false;
|
||||||
|
|
||||||
TitleIdText = TitleIdTextDefault;
|
CacheInfo = new PtcCacheInfo(0, null, null, 0, null, "Unknown", "default");
|
||||||
DisplayVersion = DisplayVersionDefault;
|
|
||||||
|
|
||||||
CachePathActual = string.Empty;
|
CachePathActual = string.Empty;
|
||||||
CachePathBackup = string.Empty;
|
CachePathBackup = string.Empty;
|
||||||
@@ -100,20 +96,24 @@ namespace ARMeilleure.Translation.PTC
|
|||||||
Disable();
|
Disable();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Initialize(string titleIdText, string displayVersion, bool enabled, MemoryManagerType memoryMode, string cacheSelector)
|
public void Initialize(PtcCacheInfo cacheInfo, bool enabled, MemoryManagerType memoryMode)
|
||||||
{
|
{
|
||||||
Wait();
|
Wait();
|
||||||
|
|
||||||
Profiler.Wait();
|
Profiler.Wait();
|
||||||
Profiler.ClearEntries();
|
Profiler.ClearEntries();
|
||||||
|
|
||||||
Logger.Info?.Print(LogClass.Ptc, $"Initializing Profiled Persistent Translation Cache (enabled: {enabled}).");
|
CacheInfo = cacheInfo;
|
||||||
|
|
||||||
if (!enabled || string.IsNullOrEmpty(titleIdText) || titleIdText == TitleIdTextDefault)
|
Logger.Info?.Print(
|
||||||
|
LogClass.Ptc,
|
||||||
|
$"Initializing Profiled Persistent Translation Cache v{InternalVersion}\n\t\t " +
|
||||||
|
$"(pid: {cacheInfo.ProcessId}, title: {cacheInfo.TitleIdText}, application: {cacheInfo.ApplicationIdText}, " +
|
||||||
|
$"programIndex: {cacheInfo.ProgramIndex}, version: '{cacheInfo.DisplayVersion}', kind: {cacheInfo.ProcessKind}, " +
|
||||||
|
$"selector: '{cacheInfo.CacheSelector}', key: '{cacheInfo.CacheKey}', enabled: {enabled}).");
|
||||||
|
|
||||||
|
if (!enabled || cacheInfo.TitleIdText == PtcCacheInfo.TitleIdTextDefault)
|
||||||
{
|
{
|
||||||
TitleIdText = TitleIdTextDefault;
|
|
||||||
DisplayVersion = DisplayVersionDefault;
|
|
||||||
|
|
||||||
CachePathActual = string.Empty;
|
CachePathActual = string.Empty;
|
||||||
CachePathBackup = string.Empty;
|
CachePathBackup = string.Empty;
|
||||||
|
|
||||||
@@ -122,14 +122,10 @@ namespace ARMeilleure.Translation.PTC
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
TitleIdText = titleIdText;
|
|
||||||
DisplayVersion = !string.IsNullOrEmpty(displayVersion) ? displayVersion : DisplayVersionDefault;
|
|
||||||
_memoryMode = memoryMode;
|
_memoryMode = memoryMode;
|
||||||
|
|
||||||
Logger.Info?.Print(LogClass.Ptc, $"PPTC (v{InternalVersion}) Profile: {DisplayVersion}-{cacheSelector}");
|
string workPathActual = Path.Combine(AppDataManager.GamesDirPath, CacheInfo.TitleIdText, "cache", "cpu", ActualDir);
|
||||||
|
string workPathBackup = Path.Combine(AppDataManager.GamesDirPath, CacheInfo.TitleIdText, "cache", "cpu", BackupDir);
|
||||||
string workPathActual = Path.Combine(AppDataManager.GamesDirPath, TitleIdText, "cache", "cpu", ActualDir);
|
|
||||||
string workPathBackup = Path.Combine(AppDataManager.GamesDirPath, TitleIdText, "cache", "cpu", BackupDir);
|
|
||||||
|
|
||||||
if (!Directory.Exists(workPathActual))
|
if (!Directory.Exists(workPathActual))
|
||||||
{
|
{
|
||||||
@@ -141,8 +137,14 @@ namespace ARMeilleure.Translation.PTC
|
|||||||
Directory.CreateDirectory(workPathBackup);
|
Directory.CreateDirectory(workPathBackup);
|
||||||
}
|
}
|
||||||
|
|
||||||
CachePathActual = Path.Combine(workPathActual, DisplayVersion) + "-" + cacheSelector;
|
CachePathActual = Path.Combine(workPathActual, CacheInfo.DisplayVersion) + "-" + CacheInfo.CacheSelector;
|
||||||
CachePathBackup = Path.Combine(workPathBackup, DisplayVersion) + "-" + cacheSelector;
|
CachePathBackup = Path.Combine(workPathBackup, CacheInfo.DisplayVersion) + "-" + CacheInfo.CacheSelector;
|
||||||
|
|
||||||
|
Logger.Info?.Print(
|
||||||
|
LogClass.Ptc,
|
||||||
|
$"PPTC cache owner selected (pid: {CacheInfo.ProcessId}, title: {CacheInfo.TitleIdText}, application: {CacheInfo.ApplicationIdText}, " +
|
||||||
|
$"version: '{CacheInfo.DisplayVersion}', kind: {CacheInfo.ProcessKind}, selector: '{CacheInfo.CacheSelector}', " +
|
||||||
|
$"key: '{CacheInfo.CacheKey}', path: '{CachePathActual}').");
|
||||||
|
|
||||||
PreLoad();
|
PreLoad();
|
||||||
Profiler.PreLoad();
|
Profiler.PreLoad();
|
||||||
@@ -190,7 +192,7 @@ namespace ARMeilleure.Translation.PTC
|
|||||||
_infosStream.Seek(0L, SeekOrigin.Begin);
|
_infosStream.Seek(0L, SeekOrigin.Begin);
|
||||||
bool foundBadFunction = false;
|
bool foundBadFunction = false;
|
||||||
|
|
||||||
for (int index = 0; index < GetEntriesCount(); index++)
|
for (int index = 0; index < _infosStream.Length / Unsafe.SizeOf<InfoEntry>(); index++)
|
||||||
{
|
{
|
||||||
InfoEntry infoEntry = DeserializeStructure<InfoEntry>(_infosStream);
|
InfoEntry infoEntry = DeserializeStructure<InfoEntry>(_infosStream);
|
||||||
foreach (ulong address in blacklist)
|
foreach (ulong address in blacklist)
|
||||||
@@ -244,67 +246,25 @@ namespace ARMeilleure.Translation.PTC
|
|||||||
{
|
{
|
||||||
OuterHeader outerHeader = DeserializeStructure<OuterHeader>(compressedStream);
|
OuterHeader outerHeader = DeserializeStructure<OuterHeader>(compressedStream);
|
||||||
|
|
||||||
if (!outerHeader.IsHeaderValid())
|
if (!outerHeader.IsHeaderValid() ||
|
||||||
|
outerHeader.Magic != _outerHeaderMagic ||
|
||||||
|
outerHeader.CacheFileVersion != InternalVersion ||
|
||||||
|
outerHeader.Endianness != GetEndianness() ||
|
||||||
|
outerHeader.FeatureInfo != GetFeatureInfo() ||
|
||||||
|
outerHeader.MemoryManagerMode != GetMemoryManagerMode() ||
|
||||||
|
outerHeader.OSPlatform != GetOSPlatform() ||
|
||||||
|
outerHeader.Architecture != (uint)RuntimeInformation.ProcessArchitecture)
|
||||||
{
|
{
|
||||||
InvalidateCompressedStream(compressedStream);
|
InvalidateCompressedStream(compressedStream);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (outerHeader.Magic != _outerHeaderMagic)
|
nint intPtr = nint.Zero;
|
||||||
{
|
|
||||||
InvalidateCompressedStream(compressedStream);
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (outerHeader.CacheFileVersion != InternalVersion)
|
|
||||||
{
|
|
||||||
InvalidateCompressedStream(compressedStream);
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (outerHeader.Endianness != GetEndianness())
|
|
||||||
{
|
|
||||||
InvalidateCompressedStream(compressedStream);
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (outerHeader.FeatureInfo != GetFeatureInfo())
|
|
||||||
{
|
|
||||||
InvalidateCompressedStream(compressedStream);
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (outerHeader.MemoryManagerMode != GetMemoryManagerMode())
|
|
||||||
{
|
|
||||||
InvalidateCompressedStream(compressedStream);
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (outerHeader.OSPlatform != GetOSPlatform())
|
|
||||||
{
|
|
||||||
InvalidateCompressedStream(compressedStream);
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (outerHeader.Architecture != (uint)RuntimeInformation.ProcessArchitecture)
|
|
||||||
{
|
|
||||||
InvalidateCompressedStream(compressedStream);
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
IntPtr intPtr = IntPtr.Zero;
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
intPtr = Marshal.AllocHGlobal(new IntPtr(outerHeader.UncompressedStreamSize));
|
intPtr = Marshal.AllocHGlobal(new nint(outerHeader.UncompressedStreamSize));
|
||||||
|
|
||||||
using UnmanagedMemoryStream stream = new((byte*)intPtr.ToPointer(), outerHeader.UncompressedStreamSize, outerHeader.UncompressedStreamSize, FileAccess.ReadWrite);
|
using UnmanagedMemoryStream stream = new((byte*)intPtr.ToPointer(), outerHeader.UncompressedStreamSize, outerHeader.UncompressedStreamSize, FileAccess.ReadWrite);
|
||||||
try
|
try
|
||||||
@@ -324,14 +284,7 @@ namespace ARMeilleure.Translation.PTC
|
|||||||
|
|
||||||
InnerHeader innerHeader = DeserializeStructure<InnerHeader>(stream);
|
InnerHeader innerHeader = DeserializeStructure<InnerHeader>(stream);
|
||||||
|
|
||||||
if (!innerHeader.IsHeaderValid())
|
if (!innerHeader.IsHeaderValid() || innerHeader.Magic != _innerHeaderMagic)
|
||||||
{
|
|
||||||
InvalidateCompressedStream(compressedStream);
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (innerHeader.Magic != _innerHeaderMagic)
|
|
||||||
{
|
{
|
||||||
InvalidateCompressedStream(compressedStream);
|
InvalidateCompressedStream(compressedStream);
|
||||||
|
|
||||||
@@ -405,7 +358,7 @@ namespace ARMeilleure.Translation.PTC
|
|||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
if (intPtr != IntPtr.Zero)
|
if (intPtr != nint.Zero)
|
||||||
{
|
{
|
||||||
Marshal.FreeHGlobal(intPtr);
|
Marshal.FreeHGlobal(intPtr);
|
||||||
}
|
}
|
||||||
@@ -414,7 +367,12 @@ namespace ARMeilleure.Translation.PTC
|
|||||||
|
|
||||||
long fileSize = new FileInfo(fileName).Length;
|
long fileSize = new FileInfo(fileName).Length;
|
||||||
|
|
||||||
Logger.Info?.Print(LogClass.Ptc, $"{(isBackup ? "Loaded Backup Translation Cache" : "Loaded Translation Cache")} (size: {fileSize} bytes, translated functions: {GetEntriesCount()}).");
|
Logger.Info?.Print(
|
||||||
|
LogClass.Ptc,
|
||||||
|
$"{(isBackup ? "Loaded Backup Translation Cache" : "Loaded Translation Cache")} " +
|
||||||
|
$"(pid: {CacheInfo.ProcessId}, title: {CacheInfo.TitleIdText}, version: '{CacheInfo.DisplayVersion}', kind: {CacheInfo.ProcessKind}, " +
|
||||||
|
$"selector: '{CacheInfo.CacheSelector}', key: '{CacheInfo.CacheKey}', path: '{fileName}', " +
|
||||||
|
$"size: {fileSize} bytes, translated functions: {GetEntriesCount()}).");
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -487,11 +445,11 @@ namespace ARMeilleure.Translation.PTC
|
|||||||
|
|
||||||
outerHeader.SetHeaderHash();
|
outerHeader.SetHeaderHash();
|
||||||
|
|
||||||
IntPtr intPtr = IntPtr.Zero;
|
nint intPtr = nint.Zero;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
intPtr = Marshal.AllocHGlobal(new IntPtr(outerHeader.UncompressedStreamSize));
|
intPtr = Marshal.AllocHGlobal(new nint(outerHeader.UncompressedStreamSize));
|
||||||
|
|
||||||
using UnmanagedMemoryStream stream = new((byte*)intPtr.ToPointer(), outerHeader.UncompressedStreamSize, outerHeader.UncompressedStreamSize, FileAccess.ReadWrite);
|
using UnmanagedMemoryStream stream = new((byte*)intPtr.ToPointer(), outerHeader.UncompressedStreamSize, outerHeader.UncompressedStreamSize, FileAccess.ReadWrite);
|
||||||
stream.Seek((long)Unsafe.SizeOf<InnerHeader>(), SeekOrigin.Begin);
|
stream.Seek((long)Unsafe.SizeOf<InnerHeader>(), SeekOrigin.Begin);
|
||||||
@@ -545,7 +503,7 @@ namespace ARMeilleure.Translation.PTC
|
|||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
if (intPtr != IntPtr.Zero)
|
if (intPtr != nint.Zero)
|
||||||
{
|
{
|
||||||
Marshal.FreeHGlobal(intPtr);
|
Marshal.FreeHGlobal(intPtr);
|
||||||
}
|
}
|
||||||
@@ -563,6 +521,7 @@ namespace ARMeilleure.Translation.PTC
|
|||||||
{
|
{
|
||||||
if (AreCarriersEmpty() || ContainsBlacklistedFunctions())
|
if (AreCarriersEmpty() || ContainsBlacklistedFunctions())
|
||||||
{
|
{
|
||||||
|
ResetCarriersIfNeeded();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -592,7 +551,7 @@ namespace ARMeilleure.Translation.PTC
|
|||||||
|
|
||||||
bool isEntryChanged = infoEntry.Hash != ComputeHash(translator.Memory, infoEntry.Address, infoEntry.GuestSize);
|
bool isEntryChanged = infoEntry.Hash != ComputeHash(translator.Memory, infoEntry.Address, infoEntry.GuestSize);
|
||||||
|
|
||||||
if (isEntryChanged || (!infoEntry.HighCq && Profiler.ProfiledFuncs.TryGetValue(infoEntry.Address, out var value) && value.HighCq))
|
if (isEntryChanged || (!infoEntry.HighCq && Profiler.ProfiledFuncs.TryGetValue(infoEntry.Address, out PtcProfiler.FuncProfile value) && value.HighCq))
|
||||||
{
|
{
|
||||||
infoEntry.Stubbed = true;
|
infoEntry.Stubbed = true;
|
||||||
infoEntry.CodeLength = 0;
|
infoEntry.CodeLength = 0;
|
||||||
@@ -696,7 +655,7 @@ namespace ARMeilleure.Translation.PTC
|
|||||||
|
|
||||||
foreach (RelocEntry relocEntry in relocEntries)
|
foreach (RelocEntry relocEntry in relocEntries)
|
||||||
{
|
{
|
||||||
IntPtr? imm = null;
|
nint? imm = null;
|
||||||
Symbol symbol = relocEntry.Symbol;
|
Symbol symbol = relocEntry.Symbol;
|
||||||
|
|
||||||
if (symbol.Type == SymbolType.FunctionTable)
|
if (symbol.Type == SymbolType.FunctionTable)
|
||||||
@@ -707,7 +666,7 @@ namespace ARMeilleure.Translation.PTC
|
|||||||
{
|
{
|
||||||
unsafe
|
unsafe
|
||||||
{
|
{
|
||||||
imm = (IntPtr)Unsafe.AsPointer(ref translator.FunctionTable.GetValue(guestAddress));
|
imm = (nint)Unsafe.AsPointer(ref translator.FunctionTable.GetValue(guestAddress));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -715,7 +674,7 @@ namespace ARMeilleure.Translation.PTC
|
|||||||
{
|
{
|
||||||
int index = (int)symbol.Value;
|
int index = (int)symbol.Value;
|
||||||
|
|
||||||
if (Delegates.TryGetDelegateFuncPtrByIndex(index, out IntPtr funcPtr))
|
if (Delegates.TryGetDelegateFuncPtrByIndex(index, out nint funcPtr))
|
||||||
{
|
{
|
||||||
imm = funcPtr;
|
imm = funcPtr;
|
||||||
}
|
}
|
||||||
@@ -730,7 +689,7 @@ namespace ARMeilleure.Translation.PTC
|
|||||||
|
|
||||||
unsafe
|
unsafe
|
||||||
{
|
{
|
||||||
imm = (IntPtr)Unsafe.AsPointer(ref callCounter.Value);
|
imm = (nint)Unsafe.AsPointer(ref callCounter.Value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (symbol == DispatchStubSymbol)
|
else if (symbol == DispatchStubSymbol)
|
||||||
@@ -779,8 +738,8 @@ namespace ARMeilleure.Translation.PTC
|
|||||||
UnwindInfo unwindInfo,
|
UnwindInfo unwindInfo,
|
||||||
bool highCq)
|
bool highCq)
|
||||||
{
|
{
|
||||||
var cFunc = new CompiledFunction(code, unwindInfo, RelocInfo.Empty);
|
CompiledFunction cFunc = new(code, unwindInfo, RelocInfo.Empty);
|
||||||
var gFunc = cFunc.MapWithPointer<GuestFunction>(out IntPtr gFuncPointer);
|
GuestFunction gFunc = cFunc.MapWithPointer<GuestFunction>(out nint gFuncPointer);
|
||||||
|
|
||||||
return new TranslatedFunction(gFunc, gFuncPointer, callCounter, guestSize, highCq);
|
return new TranslatedFunction(gFunc, gFuncPointer, callCounter, guestSize, highCq);
|
||||||
}
|
}
|
||||||
@@ -817,7 +776,7 @@ namespace ARMeilleure.Translation.PTC
|
|||||||
|
|
||||||
public void MakeAndSaveTranslations(Translator translator)
|
public void MakeAndSaveTranslations(Translator translator)
|
||||||
{
|
{
|
||||||
var profiledFuncsToTranslate = Profiler.GetProfiledFuncsToTranslate(translator.Functions);
|
ConcurrentQueue<(ulong address, PtcProfiler.FuncProfile funcProfile)> profiledFuncsToTranslate = Profiler.GetProfiledFuncsToTranslate(translator.Functions);
|
||||||
|
|
||||||
_translateCount = 0;
|
_translateCount = 0;
|
||||||
_translateTotalCount = profiledFuncsToTranslate.Count;
|
_translateTotalCount = profiledFuncsToTranslate.Count;
|
||||||
@@ -861,7 +820,7 @@ namespace ARMeilleure.Translation.PTC
|
|||||||
|
|
||||||
void TranslateFuncs()
|
void TranslateFuncs()
|
||||||
{
|
{
|
||||||
while (profiledFuncsToTranslate.TryDequeue(out var item))
|
while (profiledFuncsToTranslate.TryDequeue(out (ulong address, PtcProfiler.FuncProfile funcProfile) item))
|
||||||
{
|
{
|
||||||
ulong address = item.address;
|
ulong address = item.address;
|
||||||
ExecutionMode executionMode = item.funcProfile.Mode;
|
ExecutionMode executionMode = item.funcProfile.Mode;
|
||||||
@@ -869,7 +828,7 @@ namespace ARMeilleure.Translation.PTC
|
|||||||
|
|
||||||
Debug.Assert(Profiler.IsAddressInStaticCodeRange(address));
|
Debug.Assert(Profiler.IsAddressInStaticCodeRange(address));
|
||||||
|
|
||||||
TranslatedFunction func = translator.Translate(address, executionMode, highCq);
|
TranslatedFunction func = translator.Translate(address, executionMode, highCq, pptcTranslation: true);
|
||||||
|
|
||||||
if (func == null)
|
if (func == null)
|
||||||
{
|
{
|
||||||
@@ -906,11 +865,11 @@ namespace ARMeilleure.Translation.PTC
|
|||||||
|
|
||||||
Stopwatch sw = Stopwatch.StartNew();
|
Stopwatch sw = Stopwatch.StartNew();
|
||||||
|
|
||||||
foreach (var thread in threads)
|
foreach (Thread thread in threads)
|
||||||
{
|
{
|
||||||
thread.Start();
|
thread.Start();
|
||||||
}
|
}
|
||||||
foreach (var thread in threads)
|
foreach (Thread thread in threads)
|
||||||
{
|
{
|
||||||
thread.Join();
|
thread.Join();
|
||||||
}
|
}
|
||||||
@@ -990,7 +949,7 @@ namespace ARMeilleure.Translation.PTC
|
|||||||
WriteCode(code.AsSpan());
|
WriteCode(code.AsSpan());
|
||||||
|
|
||||||
// WriteReloc.
|
// WriteReloc.
|
||||||
using var relocInfoWriter = new BinaryWriter(_relocsStream, EncodingCache.UTF8NoBOM, true);
|
using BinaryWriter relocInfoWriter = new(_relocsStream, EncodingCache.UTF8NoBOM, true);
|
||||||
|
|
||||||
foreach (RelocEntry entry in relocInfo.Entries)
|
foreach (RelocEntry entry in relocInfo.Entries)
|
||||||
{
|
{
|
||||||
@@ -1000,7 +959,7 @@ namespace ARMeilleure.Translation.PTC
|
|||||||
}
|
}
|
||||||
|
|
||||||
// WriteUnwindInfo.
|
// WriteUnwindInfo.
|
||||||
using var unwindInfoWriter = new BinaryWriter(_unwindInfosStream, EncodingCache.UTF8NoBOM, true);
|
using BinaryWriter unwindInfoWriter = new(_unwindInfosStream, EncodingCache.UTF8NoBOM, true);
|
||||||
|
|
||||||
unwindInfoWriter.Write(unwindInfo.PushEntries.Length);
|
unwindInfoWriter.Write(unwindInfo.PushEntries.Length);
|
||||||
|
|
||||||
@@ -1165,8 +1124,7 @@ namespace ARMeilleure.Translation.PTC
|
|||||||
|
|
||||||
public void Close()
|
public void Close()
|
||||||
{
|
{
|
||||||
if (State == PtcState.Enabled ||
|
if (State is PtcState.Enabled or PtcState.Continuing)
|
||||||
State == PtcState.Continuing)
|
|
||||||
{
|
{
|
||||||
State = PtcState.Closing;
|
State = PtcState.Closing;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,37 @@
|
|||||||
|
namespace ARMeilleure.Translation.PTC
|
||||||
|
{
|
||||||
|
public readonly struct PtcCacheInfo
|
||||||
|
{
|
||||||
|
public const string TitleIdTextDefault = "0000000000000000";
|
||||||
|
public const string ApplicationIdTextDefault = "0000000000000000";
|
||||||
|
public const string DisplayVersionDefault = "0";
|
||||||
|
|
||||||
|
public ulong ProcessId { get; }
|
||||||
|
public string TitleIdText { get; }
|
||||||
|
public string ApplicationIdText { get; }
|
||||||
|
public byte ProgramIndex { get; }
|
||||||
|
public string DisplayVersion { get; }
|
||||||
|
public string ProcessKind { get; }
|
||||||
|
public string CacheSelector { get; }
|
||||||
|
|
||||||
|
public string CacheKey => $"{DisplayVersion}-{CacheSelector}";
|
||||||
|
|
||||||
|
public PtcCacheInfo(
|
||||||
|
ulong processId,
|
||||||
|
string titleIdText,
|
||||||
|
string applicationIdText,
|
||||||
|
byte programIndex,
|
||||||
|
string displayVersion,
|
||||||
|
string processKind,
|
||||||
|
string cacheSelector)
|
||||||
|
{
|
||||||
|
ProcessId = processId;
|
||||||
|
TitleIdText = !string.IsNullOrEmpty(titleIdText) ? titleIdText : TitleIdTextDefault;
|
||||||
|
ApplicationIdText = !string.IsNullOrEmpty(applicationIdText) ? applicationIdText : ApplicationIdTextDefault;
|
||||||
|
ProgramIndex = programIndex;
|
||||||
|
DisplayVersion = !string.IsNullOrEmpty(displayVersion) ? displayVersion : DisplayVersionDefault;
|
||||||
|
ProcessKind = processKind ?? string.Empty;
|
||||||
|
CacheSelector = string.IsNullOrEmpty(cacheSelector) ? "default" : cacheSelector;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -9,13 +9,13 @@ using System.Collections.Generic;
|
|||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.IO.Compression;
|
using System.IO.Compression;
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Timers;
|
using System.Timers;
|
||||||
using static ARMeilleure.Translation.PTC.PtcFormatter;
|
using static ARMeilleure.Translation.PTC.PtcFormatter;
|
||||||
using Timer = System.Timers.Timer;
|
using Timer = System.Timers.Timer;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
namespace ARMeilleure.Translation.PTC
|
namespace ARMeilleure.Translation.PTC
|
||||||
{
|
{
|
||||||
@@ -23,7 +23,7 @@ namespace ARMeilleure.Translation.PTC
|
|||||||
{
|
{
|
||||||
private const string OuterHeaderMagicString = "Pohd\0\0\0\0";
|
private const string OuterHeaderMagicString = "Pohd\0\0\0\0";
|
||||||
|
|
||||||
private const uint InternalVersion = 6698; //! Not to be incremented manually for each change to the ARMeilleure project.
|
private const uint InternalVersion = 7031; //! Not to be incremented manually for each change to the ARMeilleure project.
|
||||||
|
|
||||||
private static readonly uint[] _migrateInternalVersions =
|
private static readonly uint[] _migrateInternalVersions =
|
||||||
[
|
[
|
||||||
@@ -119,9 +119,9 @@ namespace ARMeilleure.Translation.PTC
|
|||||||
|
|
||||||
public 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)>();
|
ConcurrentQueue<(ulong address, FuncProfile funcProfile)> profiledFuncsToTranslate = new();
|
||||||
|
|
||||||
foreach (var profiledFunc in ProfiledFuncs)
|
foreach (KeyValuePair<ulong, FuncProfile> profiledFunc in ProfiledFuncs)
|
||||||
{
|
{
|
||||||
if (!funcs.ContainsKey(profiledFunc.Key) && !profiledFunc.Value.Blacklist)
|
if (!funcs.ContainsKey(profiledFunc.Key) && !profiledFunc.Value.Blacklist)
|
||||||
{
|
{
|
||||||
@@ -142,7 +142,7 @@ namespace ARMeilleure.Translation.PTC
|
|||||||
{
|
{
|
||||||
List<ulong> funcs = [];
|
List<ulong> funcs = [];
|
||||||
|
|
||||||
foreach (var profiledFunc in ProfiledFuncs)
|
foreach (KeyValuePair<ulong, FuncProfile> profiledFunc in ProfiledFuncs)
|
||||||
{
|
{
|
||||||
if (profiledFunc.Value.Blacklist)
|
if (profiledFunc.Value.Blacklist)
|
||||||
{
|
{
|
||||||
@@ -189,28 +189,10 @@ namespace ARMeilleure.Translation.PTC
|
|||||||
{
|
{
|
||||||
OuterHeader outerHeader = DeserializeStructure<OuterHeader>(compressedStream);
|
OuterHeader outerHeader = DeserializeStructure<OuterHeader>(compressedStream);
|
||||||
|
|
||||||
if (!outerHeader.IsHeaderValid())
|
if (!outerHeader.IsHeaderValid() ||
|
||||||
{
|
outerHeader.Magic != _outerHeaderMagic ||
|
||||||
InvalidateCompressedStream(compressedStream);
|
outerHeader.InfoFileVersion != InternalVersion && !_migrateInternalVersions.Contains(outerHeader.InfoFileVersion) ||
|
||||||
|
outerHeader.Endianness != Ptc.GetEndianness())
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (outerHeader.Magic != _outerHeaderMagic)
|
|
||||||
{
|
|
||||||
InvalidateCompressedStream(compressedStream);
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (outerHeader.InfoFileVersion != InternalVersion && !_migrateInternalVersions.Contains(outerHeader.InfoFileVersion))
|
|
||||||
{
|
|
||||||
InvalidateCompressedStream(compressedStream);
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (outerHeader.Endianness != Ptc.GetEndianness())
|
|
||||||
{
|
{
|
||||||
InvalidateCompressedStream(compressedStream);
|
InvalidateCompressedStream(compressedStream);
|
||||||
|
|
||||||
@@ -272,7 +254,12 @@ namespace ARMeilleure.Translation.PTC
|
|||||||
|
|
||||||
long fileSize = new FileInfo(fileName).Length;
|
long fileSize = new FileInfo(fileName).Length;
|
||||||
|
|
||||||
Logger.Info?.Print(LogClass.Ptc, $"{(isBackup ? "Loaded Backup Profiling Info" : "Loaded Profiling Info")} (size: {fileSize} bytes, profiled functions: {ProfiledFuncs.Count}).");
|
Logger.Info?.Print(
|
||||||
|
LogClass.Ptc,
|
||||||
|
$"{(isBackup ? "Loaded Backup Profiling Info" : "Loaded Profiling Info")} " +
|
||||||
|
$"(pid: {_ptc.CacheInfo.ProcessId}, title: {_ptc.CacheInfo.TitleIdText}, version: '{_ptc.CacheInfo.DisplayVersion}', " +
|
||||||
|
$"kind: {_ptc.CacheInfo.ProcessKind}, selector: '{_ptc.CacheInfo.CacheSelector}', key: '{_ptc.CacheInfo.CacheKey}', " +
|
||||||
|
$"path: '{fileName}', size: {fileSize} bytes, profiled functions: {ProfiledFuncs.Count}).");
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -393,7 +380,11 @@ namespace ARMeilleure.Translation.PTC
|
|||||||
|
|
||||||
if (fileSize != 0L)
|
if (fileSize != 0L)
|
||||||
{
|
{
|
||||||
Logger.Info?.Print(LogClass.Ptc, $"Saved Profiling Info (size: {fileSize} bytes, profiled functions: {profiledFuncsCount}).");
|
Logger.Info?.Print(
|
||||||
|
LogClass.Ptc,
|
||||||
|
$"Saved Profiling Info (pid: {_ptc.CacheInfo.ProcessId}, title: {_ptc.CacheInfo.TitleIdText}, version: '{_ptc.CacheInfo.DisplayVersion}', " +
|
||||||
|
$"kind: {_ptc.CacheInfo.ProcessKind}, selector: '{_ptc.CacheInfo.CacheSelector}', key: '{_ptc.CacheInfo.CacheKey}', " +
|
||||||
|
$"path: '{fileName}', size: {fileSize} bytes, profiled functions: {profiledFuncsCount}).");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -465,8 +456,7 @@ namespace ARMeilleure.Translation.PTC
|
|||||||
|
|
||||||
public void Start()
|
public void Start()
|
||||||
{
|
{
|
||||||
if (_ptc.State == PtcState.Enabled ||
|
if (_ptc.State is PtcState.Enabled or PtcState.Continuing)
|
||||||
_ptc.State == PtcState.Continuing)
|
|
||||||
{
|
{
|
||||||
Enabled = true;
|
Enabled = true;
|
||||||
|
|
||||||
|
|||||||
@@ -95,7 +95,7 @@ namespace ARMeilleure.Translation
|
|||||||
// This is required because we have a implicit context load at the start of the function,
|
// This is required because we have a implicit context load at the start of the function,
|
||||||
// but if there is a jump to the start of the function, the context load would trash the modified values.
|
// but if there is a jump to the start of the function, the context load would trash the modified values.
|
||||||
// Here we insert a new entry block that will jump to the existing entry block.
|
// Here we insert a new entry block that will jump to the existing entry block.
|
||||||
BasicBlock newEntry = new BasicBlock(cfg.Blocks.Count);
|
BasicBlock newEntry = new(cfg.Blocks.Count);
|
||||||
|
|
||||||
cfg.UpdateEntry(newEntry);
|
cfg.UpdateEntry(newEntry);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,10 +44,10 @@ namespace ARMeilleure.Translation
|
|||||||
|
|
||||||
public static void Construct(ControlFlowGraph cfg)
|
public static void Construct(ControlFlowGraph cfg)
|
||||||
{
|
{
|
||||||
var globalDefs = new DefMap[cfg.Blocks.Count];
|
DefMap[] globalDefs = new DefMap[cfg.Blocks.Count];
|
||||||
var localDefs = new Operand[cfg.LocalsCount + RegisterConsts.TotalCount];
|
Operand[] localDefs = new Operand[cfg.LocalsCount + RegisterConsts.TotalCount];
|
||||||
|
|
||||||
var dfPhiBlocks = new Queue<BasicBlock>();
|
Queue<BasicBlock> dfPhiBlocks = new();
|
||||||
|
|
||||||
for (BasicBlock block = cfg.Blocks.First; block != null; block = block.ListNext)
|
for (BasicBlock block = cfg.Blocks.First; block != null; block = block.ListNext)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
using ARMeilleure.Common;
|
using ARMeilleure.Common;
|
||||||
using System;
|
|
||||||
|
|
||||||
namespace ARMeilleure.Translation
|
namespace ARMeilleure.Translation
|
||||||
{
|
{
|
||||||
@@ -7,12 +6,12 @@ namespace ARMeilleure.Translation
|
|||||||
{
|
{
|
||||||
private readonly GuestFunction _func; // Ensure that this delegate will not be garbage collected.
|
private readonly GuestFunction _func; // Ensure that this delegate will not be garbage collected.
|
||||||
|
|
||||||
public IntPtr FuncPointer { get; }
|
public nint FuncPointer { get; }
|
||||||
public Counter<uint> CallCounter { get; }
|
public Counter<uint> CallCounter { get; }
|
||||||
public ulong GuestSize { get; }
|
public ulong GuestSize { get; }
|
||||||
public bool HighCq { get; }
|
public bool HighCq { get; }
|
||||||
|
|
||||||
public TranslatedFunction(GuestFunction func, IntPtr funcPointer, Counter<uint> callCounter, ulong guestSize, bool highCq)
|
public TranslatedFunction(GuestFunction func, nint funcPointer, Counter<uint> callCounter, ulong guestSize, bool highCq)
|
||||||
{
|
{
|
||||||
_func = func;
|
_func = func;
|
||||||
FuncPointer = funcPointer;
|
FuncPointer = funcPointer;
|
||||||
|
|||||||
@@ -57,9 +57,9 @@ namespace ARMeilleure.Translation
|
|||||||
FunctionTable.Fill = (ulong)Stubs.SlowDispatchStub;
|
FunctionTable.Fill = (ulong)Stubs.SlowDispatchStub;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IPtcLoadState LoadDiskCache(string titleIdText, string displayVersion, bool enabled, string cacheSelector)
|
public IPtcLoadState LoadDiskCache(PtcCacheInfo cacheInfo, bool enabled)
|
||||||
{
|
{
|
||||||
_ptc.Initialize(titleIdText, displayVersion, enabled, Memory.Type, cacheSelector);
|
_ptc.Initialize(cacheInfo, enabled, Memory.Type);
|
||||||
return _ptc;
|
return _ptc;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -168,6 +168,7 @@ namespace ARMeilleure.Translation
|
|||||||
|
|
||||||
Statistics.StartTimer();
|
Statistics.StartTimer();
|
||||||
|
|
||||||
|
context.ResetCallDepth();
|
||||||
ulong nextAddr = func.Execute(Stubs.ContextWrapper, context);
|
ulong nextAddr = func.Execute(Stubs.ContextWrapper, context);
|
||||||
|
|
||||||
Statistics.StopTimer(address);
|
Statistics.StopTimer(address);
|
||||||
@@ -219,9 +220,9 @@ namespace ARMeilleure.Translation
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal TranslatedFunction Translate(ulong address, ExecutionMode mode, bool highCq, bool singleStep = false)
|
internal TranslatedFunction Translate(ulong address, ExecutionMode mode, bool highCq, bool singleStep = false, bool pptcTranslation = false)
|
||||||
{
|
{
|
||||||
var context = new ArmEmitterContext(
|
ArmEmitterContext context = new(
|
||||||
Memory,
|
Memory,
|
||||||
CountTable,
|
CountTable,
|
||||||
FunctionTable,
|
FunctionTable,
|
||||||
@@ -239,6 +240,7 @@ namespace ARMeilleure.Translation
|
|||||||
|
|
||||||
Logger.StartPass(PassName.Translation);
|
Logger.StartPass(PassName.Translation);
|
||||||
|
|
||||||
|
InstEmitFlowHelper.EmitCallDepthCheckAndIncrement(context, Const(address));
|
||||||
EmitSynchronization(context);
|
EmitSynchronization(context);
|
||||||
|
|
||||||
if (blocks[0].Address != address)
|
if (blocks[0].Address != address)
|
||||||
@@ -246,7 +248,7 @@ namespace ARMeilleure.Translation
|
|||||||
context.Branch(context.GetLabel(address));
|
context.Branch(context.GetLabel(address));
|
||||||
}
|
}
|
||||||
|
|
||||||
ControlFlowGraph cfg = EmitAndGetCFG(context, blocks, out Range funcRange, out Counter<uint> counter);
|
ControlFlowGraph cfg = EmitAndGetCFG(context, blocks, out Range funcRange, out Counter<uint> counter, pptcTranslation);
|
||||||
|
|
||||||
if (cfg == null)
|
if (cfg == null)
|
||||||
{
|
{
|
||||||
@@ -263,10 +265,10 @@ namespace ARMeilleure.Translation
|
|||||||
|
|
||||||
Logger.EndPass(PassName.RegisterUsage);
|
Logger.EndPass(PassName.RegisterUsage);
|
||||||
|
|
||||||
var retType = OperandType.I64;
|
OperandType retType = OperandType.I64;
|
||||||
var argTypes = new OperandType[] { OperandType.I64 };
|
OperandType[] argTypes = new OperandType[] { OperandType.I64 };
|
||||||
|
|
||||||
var options = highCq ? CompilerOptions.HighCq : CompilerOptions.None;
|
CompilerOptions options = highCq ? CompilerOptions.HighCq : CompilerOptions.None;
|
||||||
|
|
||||||
if (context.HasPtc && !singleStep)
|
if (context.HasPtc && !singleStep)
|
||||||
{
|
{
|
||||||
@@ -282,7 +284,7 @@ namespace ARMeilleure.Translation
|
|||||||
_ptc.WriteCompiledFunction(address, funcSize, hash, highCq, compiledFunc);
|
_ptc.WriteCompiledFunction(address, funcSize, hash, highCq, compiledFunc);
|
||||||
}
|
}
|
||||||
|
|
||||||
GuestFunction func = compiledFunc.MapWithPointer<GuestFunction>(out IntPtr funcPointer);
|
GuestFunction func = compiledFunc.MapWithPointer<GuestFunction>(out nint funcPointer);
|
||||||
|
|
||||||
Allocators.ResetAll();
|
Allocators.ResetAll();
|
||||||
|
|
||||||
@@ -326,7 +328,8 @@ namespace ARMeilleure.Translation
|
|||||||
ArmEmitterContext context,
|
ArmEmitterContext context,
|
||||||
Block[] blocks,
|
Block[] blocks,
|
||||||
out Range range,
|
out Range range,
|
||||||
out Counter<uint> counter)
|
out Counter<uint> counter,
|
||||||
|
bool pptcTranslation)
|
||||||
{
|
{
|
||||||
counter = null;
|
counter = null;
|
||||||
|
|
||||||
@@ -411,7 +414,10 @@ namespace ARMeilleure.Translation
|
|||||||
if (opCode.Instruction.Emitter != null)
|
if (opCode.Instruction.Emitter != null)
|
||||||
{
|
{
|
||||||
opCode.Instruction.Emitter(context);
|
opCode.Instruction.Emitter(context);
|
||||||
if (opCode.Instruction.Name == InstName.Und && blkIndex == 0)
|
// if we're pre-compiling PPTC functions, and we hit an Undefined instruction as the first
|
||||||
|
// instruction in the block, mark the function as blacklisted
|
||||||
|
// this way, we don't pre-compile Exlaunch hooks, which allows ExeFS mods to run with PPTC
|
||||||
|
if (pptcTranslation && opCode.Instruction.Name == InstName.Und && blkIndex == 0)
|
||||||
{
|
{
|
||||||
range = new Range(rangeStart, rangeEnd);
|
range = new Range(rangeStart, rangeEnd);
|
||||||
return null;
|
return null;
|
||||||
@@ -530,7 +536,7 @@ namespace ARMeilleure.Translation
|
|||||||
|
|
||||||
List<TranslatedFunction> functions = Functions.AsList();
|
List<TranslatedFunction> functions = Functions.AsList();
|
||||||
|
|
||||||
foreach (var func in functions)
|
foreach (TranslatedFunction func in functions)
|
||||||
{
|
{
|
||||||
JitCache.Unmap(func.FuncPointer);
|
JitCache.Unmap(func.FuncPointer);
|
||||||
|
|
||||||
@@ -539,7 +545,7 @@ namespace ARMeilleure.Translation
|
|||||||
|
|
||||||
Functions.Clear();
|
Functions.Clear();
|
||||||
|
|
||||||
while (_oldFuncs.TryDequeue(out var kv))
|
while (_oldFuncs.TryDequeue(out KeyValuePair<ulong, TranslatedFunction> kv))
|
||||||
{
|
{
|
||||||
JitCache.Unmap(kv.Value.FuncPointer);
|
JitCache.Unmap(kv.Value.FuncPointer);
|
||||||
|
|
||||||
@@ -560,7 +566,7 @@ namespace ARMeilleure.Translation
|
|||||||
{
|
{
|
||||||
while (Queue.Count > 0 && Queue.TryDequeue(out RejitRequest request))
|
while (Queue.Count > 0 && Queue.TryDequeue(out RejitRequest request))
|
||||||
{
|
{
|
||||||
if (Functions.TryGetValue(request.Address, out var func) && func.CallCounter != null)
|
if (Functions.TryGetValue(request.Address, out TranslatedFunction func) && func.CallCounter != null)
|
||||||
{
|
{
|
||||||
Volatile.Write(ref func.CallCounter.Value, 0);
|
Volatile.Write(ref func.CallCounter.Value, 0);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ namespace ARMeilleure.Translation
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
class TranslatorStubs : IDisposable
|
class TranslatorStubs : IDisposable
|
||||||
{
|
{
|
||||||
private readonly Lazy<IntPtr> _slowDispatchStub;
|
private readonly Lazy<nint> _slowDispatchStub;
|
||||||
|
|
||||||
private bool _disposed;
|
private bool _disposed;
|
||||||
|
|
||||||
@@ -27,7 +27,7 @@ namespace ARMeilleure.Translation
|
|||||||
/// Gets the dispatch stub.
|
/// Gets the dispatch stub.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <exception cref="ObjectDisposedException"><see cref="TranslatorStubs"/> instance was disposed</exception>
|
/// <exception cref="ObjectDisposedException"><see cref="TranslatorStubs"/> instance was disposed</exception>
|
||||||
public IntPtr DispatchStub
|
public nint DispatchStub
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
@@ -41,7 +41,7 @@ namespace ARMeilleure.Translation
|
|||||||
/// Gets the slow dispatch stub.
|
/// Gets the slow dispatch stub.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <exception cref="ObjectDisposedException"><see cref="TranslatorStubs"/> instance was disposed</exception>
|
/// <exception cref="ObjectDisposedException"><see cref="TranslatorStubs"/> instance was disposed</exception>
|
||||||
public IntPtr SlowDispatchStub
|
public nint SlowDispatchStub
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
@@ -139,9 +139,9 @@ namespace ARMeilleure.Translation
|
|||||||
/// Generates a <see cref="DispatchStub"/>.
|
/// Generates a <see cref="DispatchStub"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>Generated <see cref="DispatchStub"/></returns>
|
/// <returns>Generated <see cref="DispatchStub"/></returns>
|
||||||
private IntPtr GenerateDispatchStub()
|
private nint GenerateDispatchStub()
|
||||||
{
|
{
|
||||||
var context = new EmitterContext();
|
EmitterContext context = new();
|
||||||
|
|
||||||
Operand lblFallback = Label();
|
Operand lblFallback = Label();
|
||||||
Operand lblEnd = Label();
|
Operand lblEnd = Label();
|
||||||
@@ -160,7 +160,7 @@ namespace ARMeilleure.Translation
|
|||||||
|
|
||||||
for (int i = 0; i < _functionTable.Levels.Length; i++)
|
for (int i = 0; i < _functionTable.Levels.Length; i++)
|
||||||
{
|
{
|
||||||
ref var level = ref _functionTable.Levels[i];
|
ref AddressTableLevel level = ref _functionTable.Levels[i];
|
||||||
|
|
||||||
// level.Mask is not used directly because it is more often bigger than 32-bits, so it will not
|
// level.Mask is not used directly because it is more often bigger than 32-bits, so it will not
|
||||||
// be encoded as an immediate on x86's bitwise and operation.
|
// be encoded as an immediate on x86's bitwise and operation.
|
||||||
@@ -184,11 +184,11 @@ namespace ARMeilleure.Translation
|
|||||||
hostAddress = context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFunctionAddress)), guestAddress);
|
hostAddress = context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFunctionAddress)), guestAddress);
|
||||||
context.Tailcall(hostAddress, nativeContext);
|
context.Tailcall(hostAddress, nativeContext);
|
||||||
|
|
||||||
var cfg = context.GetControlFlowGraph();
|
ControlFlowGraph cfg = context.GetControlFlowGraph();
|
||||||
var retType = OperandType.I64;
|
OperandType retType = OperandType.I64;
|
||||||
var argTypes = new[] { OperandType.I64 };
|
OperandType[] argTypes = new[] { OperandType.I64 };
|
||||||
|
|
||||||
var func = Compiler.Compile(cfg, argTypes, retType, CompilerOptions.HighCq, RuntimeInformation.ProcessArchitecture).Map<GuestFunction>();
|
GuestFunction func = Compiler.Compile(cfg, argTypes, retType, CompilerOptions.HighCq, RuntimeInformation.ProcessArchitecture).Map<GuestFunction>();
|
||||||
|
|
||||||
return Marshal.GetFunctionPointerForDelegate(func);
|
return Marshal.GetFunctionPointerForDelegate(func);
|
||||||
}
|
}
|
||||||
@@ -197,9 +197,9 @@ namespace ARMeilleure.Translation
|
|||||||
/// Generates a <see cref="SlowDispatchStub"/>.
|
/// Generates a <see cref="SlowDispatchStub"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>Generated <see cref="SlowDispatchStub"/></returns>
|
/// <returns>Generated <see cref="SlowDispatchStub"/></returns>
|
||||||
private IntPtr GenerateSlowDispatchStub()
|
private nint GenerateSlowDispatchStub()
|
||||||
{
|
{
|
||||||
var context = new EmitterContext();
|
EmitterContext context = new();
|
||||||
|
|
||||||
// Load the target guest address from the native context.
|
// Load the target guest address from the native context.
|
||||||
Operand nativeContext = context.LoadArgument(OperandType.I64, 0);
|
Operand nativeContext = context.LoadArgument(OperandType.I64, 0);
|
||||||
@@ -209,11 +209,11 @@ namespace ARMeilleure.Translation
|
|||||||
Operand hostAddress = context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFunctionAddress)), guestAddress);
|
Operand hostAddress = context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFunctionAddress)), guestAddress);
|
||||||
context.Tailcall(hostAddress, nativeContext);
|
context.Tailcall(hostAddress, nativeContext);
|
||||||
|
|
||||||
var cfg = context.GetControlFlowGraph();
|
ControlFlowGraph cfg = context.GetControlFlowGraph();
|
||||||
var retType = OperandType.I64;
|
OperandType retType = OperandType.I64;
|
||||||
var argTypes = new[] { OperandType.I64 };
|
OperandType[] argTypes = new[] { OperandType.I64 };
|
||||||
|
|
||||||
var func = Compiler.Compile(cfg, argTypes, retType, CompilerOptions.HighCq, RuntimeInformation.ProcessArchitecture).Map<GuestFunction>();
|
GuestFunction func = Compiler.Compile(cfg, argTypes, retType, CompilerOptions.HighCq, RuntimeInformation.ProcessArchitecture).Map<GuestFunction>();
|
||||||
|
|
||||||
return Marshal.GetFunctionPointerForDelegate(func);
|
return Marshal.GetFunctionPointerForDelegate(func);
|
||||||
}
|
}
|
||||||
@@ -250,7 +250,7 @@ namespace ARMeilleure.Translation
|
|||||||
/// <returns><see cref="DispatchLoop"/> function</returns>
|
/// <returns><see cref="DispatchLoop"/> function</returns>
|
||||||
private DispatcherFunction GenerateDispatchLoop()
|
private DispatcherFunction GenerateDispatchLoop()
|
||||||
{
|
{
|
||||||
var context = new EmitterContext();
|
EmitterContext context = new();
|
||||||
|
|
||||||
Operand beginLbl = Label();
|
Operand beginLbl = Label();
|
||||||
Operand endLbl = Label();
|
Operand endLbl = Label();
|
||||||
@@ -262,10 +262,18 @@ namespace ARMeilleure.Translation
|
|||||||
|
|
||||||
Operand runningAddress = context.Add(nativeContext, Const((ulong)NativeContext.GetRunningOffset()));
|
Operand runningAddress = context.Add(nativeContext, Const((ulong)NativeContext.GetRunningOffset()));
|
||||||
Operand dispatchAddress = context.Add(nativeContext, Const((ulong)NativeContext.GetDispatchAddressOffset()));
|
Operand dispatchAddress = context.Add(nativeContext, Const((ulong)NativeContext.GetDispatchAddressOffset()));
|
||||||
|
Operand callDepthAddress = context.Add(nativeContext, Const((ulong)NativeContext.GetCallDepthOffset()));
|
||||||
|
|
||||||
EmitSyncFpContext(context, nativeContext, true);
|
EmitSyncFpContext(context, nativeContext, true);
|
||||||
|
|
||||||
context.MarkLabel(beginLbl);
|
context.MarkLabel(beginLbl);
|
||||||
|
|
||||||
|
if (Optimizations.EnableDeepCallRecursionProtection)
|
||||||
|
{
|
||||||
|
// Reset the call depth counter, since this is our first guest function call.
|
||||||
|
context.Store(callDepthAddress, Const(0));
|
||||||
|
}
|
||||||
|
|
||||||
context.Store(dispatchAddress, guestAddress);
|
context.Store(dispatchAddress, guestAddress);
|
||||||
context.Copy(guestAddress, context.Call(Const((ulong)DispatchStub), OperandType.I64, nativeContext));
|
context.Copy(guestAddress, context.Call(Const((ulong)DispatchStub), OperandType.I64, nativeContext));
|
||||||
context.BranchIfFalse(endLbl, guestAddress);
|
context.BranchIfFalse(endLbl, guestAddress);
|
||||||
@@ -278,9 +286,9 @@ namespace ARMeilleure.Translation
|
|||||||
|
|
||||||
context.Return();
|
context.Return();
|
||||||
|
|
||||||
var cfg = context.GetControlFlowGraph();
|
ControlFlowGraph cfg = context.GetControlFlowGraph();
|
||||||
var retType = OperandType.None;
|
OperandType retType = OperandType.None;
|
||||||
var argTypes = new[] { OperandType.I64, OperandType.I64 };
|
OperandType[] argTypes = new[] { OperandType.I64, OperandType.I64 };
|
||||||
|
|
||||||
return Compiler.Compile(cfg, argTypes, retType, CompilerOptions.HighCq, RuntimeInformation.ProcessArchitecture).Map<DispatcherFunction>();
|
return Compiler.Compile(cfg, argTypes, retType, CompilerOptions.HighCq, RuntimeInformation.ProcessArchitecture).Map<DispatcherFunction>();
|
||||||
}
|
}
|
||||||
@@ -291,7 +299,7 @@ namespace ARMeilleure.Translation
|
|||||||
/// <returns><see cref="ContextWrapper"/> function</returns>
|
/// <returns><see cref="ContextWrapper"/> function</returns>
|
||||||
private WrapperFunction GenerateContextWrapper()
|
private WrapperFunction GenerateContextWrapper()
|
||||||
{
|
{
|
||||||
var context = new EmitterContext();
|
EmitterContext context = new();
|
||||||
|
|
||||||
Operand nativeContext = context.LoadArgument(OperandType.I64, 0);
|
Operand nativeContext = context.LoadArgument(OperandType.I64, 0);
|
||||||
Operand guestMethod = context.LoadArgument(OperandType.I64, 1);
|
Operand guestMethod = context.LoadArgument(OperandType.I64, 1);
|
||||||
@@ -302,9 +310,9 @@ namespace ARMeilleure.Translation
|
|||||||
|
|
||||||
context.Return(returnValue);
|
context.Return(returnValue);
|
||||||
|
|
||||||
var cfg = context.GetControlFlowGraph();
|
ControlFlowGraph cfg = context.GetControlFlowGraph();
|
||||||
var retType = OperandType.I64;
|
OperandType retType = OperandType.I64;
|
||||||
var argTypes = new[] { OperandType.I64, OperandType.I64 };
|
OperandType[] argTypes = new[] { OperandType.I64, OperandType.I64 };
|
||||||
|
|
||||||
return Compiler.Compile(cfg, argTypes, retType, CompilerOptions.HighCq, RuntimeInformation.ProcessArchitecture).Map<WrapperFunction>();
|
return Compiler.Compile(cfg, argTypes, retType, CompilerOptions.HighCq, RuntimeInformation.ProcessArchitecture).Map<WrapperFunction>();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ namespace ARMeilleure.Translation
|
|||||||
{
|
{
|
||||||
public static class TranslatorTestMethods
|
public static class TranslatorTestMethods
|
||||||
{
|
{
|
||||||
public delegate int FpFlagsPInvokeTest(IntPtr managedMethod);
|
public delegate int FpFlagsPInvokeTest(nint managedMethod);
|
||||||
|
|
||||||
private static bool SetPlatformFtz(EmitterContext context, bool ftz)
|
private static bool SetPlatformFtz(EmitterContext context, bool ftz)
|
||||||
{
|
{
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user