Compare commits

...

284 Commits

Author SHA1 Message Date
gdkchan
f95b7c5877 Fix incorrect fragment origin when YNegate is enabled (#4673)
* Fix incorrect fragment origin when YNegate is enabled

* Shader cache version bump

* Do not update support buffer if shader does not read gl_FragCoord

* Pass unscaled viewport size to the support buffer
2023-07-29 18:47:03 -03:00
TSRBerry
eb528ae0f0 Add workflow to automatically check code style issues for PRs (#4670)
* Add workflow to perform automated checks for PRs

* Downgrade Microsoft.CodeAnalysis to 4.4.0

This is a workaround to fix issues with dotnet-format.
See:
- https://github.com/dotnet/format/issues/1805
- https://github.com/dotnet/format/issues/1800

* Adjust editorconfig to be more compatible with Ryujinx code-style

* Adjust .editorconfig line endings to match .gitattributes

* Disable 'prefer switch expression' rule

* Remove naming styles

These are the default rules, so we don't need to override them.

* Silence IDE0060 in .editorconfig

* Slightly adjust .editorconfig

* Add lost workflow changes

* Move .editorconfig comment to the top

* .editorconfig: private static readonly fields should be _lowerCamelCase

* .editorconfig: Remove alignment for declarations as well

* editorconfig: Add rule for local constants

* Disable CA1822 for HLE services

* Disable CA1822 for ViewModels

Bindings won't work with static members, but this issue is silently ignored.

* Run dotnet format for the whole solution

* Check result code of SDL_GetDisplayBounds

* Fix dotnet format style issues

* Add missing trailing commas

* Update Microsoft.CodeAnalysis.CSharp to 4.6.0

Skipping 4.5.0 since it breaks dotnet format

* Restore old default naming rules for dotnet format

* Add naming rule exception for CPU tests

* checks: Include all files before excluding paths

* Fix dotnet format issues

* Check dotnet format version

* checks: Run dotnet format with severity info again

* checks: Disable naming style rules until they won't crash the process anymore

* Remove unread private member

* checks: Attempt to run analyzers 3 times before giving up

* checks: Enable naming style rules again with the new retry logic
2023-07-24 18:35:04 +02:00
Mary
487261592e ava: Fix regression on title updater and dlc manager window caused by precious commit 2023-07-21 22:50:10 +02:00
MutantAura
9e04e6cba1 Ava UI: Remove IsActive checks from dialog methods (#5456)
* Remove `IsActive` checks from dialog methods

* Remove old windows bandaid

* Remove null dialog code path entirely and return nothing.
2023-07-21 12:24:13 +01:00
TSRBerry
4cf2419e6c HLE: Fix corrupted Mii structs (#5468)
* StructArrayHelpers: Add PureAttribute to all AsSpan() methods

* Fix broken Mii structs
2023-07-19 22:02:31 -03:00
Mary
440abac9f8 chore: Update Ryujinx.SDL2-CS to 2.28.1 (#5453) 2023-07-18 16:08:48 +02:00
TSRBerry
732714349e [Hotfix] sockets: Resolve empty port requests to 0 again (#5459) 2023-07-17 20:47:47 +02:00
TSRBerry
016262514d cpu: Hotfix missing ToNearest rounding mode cases 2023-07-16 20:39:08 +01:00
TSRBerry
326749498b [Ryujinx.HLE] Address dotnet-format issues (#5380)
* dotnet format style --severity info

Some changes were manually reverted.

* dotnet format analyzers --serverity info

Some changes have been minimally adapted.

* Restore a few unused methods and variables

* Silence dotnet format IDE0060 warnings

* Silence dotnet format IDE0052 warnings

* Address or silence dotnet format IDE1006 warnings

* Address dotnet format CA1816 warnings

* Address or silence dotnet format CA2208 warnings

* Address or silence dotnet format CA1806 and a few CA1854 warnings

* Address dotnet format CA2211 warnings

* Address dotnet format CA1822 warnings

* Address or silence dotnet format CA1069 warnings

* Make dotnet format succeed in style mode

* Address or silence dotnet format CA2211 warnings

* Address review comments

* Address dotnet format CA2208 warnings properly

* Make ProcessResult readonly

* Address most dotnet format whitespace warnings

* Apply dotnet format whitespace formatting

A few of them have been manually reverted and the corresponding warning was silenced

* Add previously silenced warnings back

I have no clue how these disappeared

* Revert formatting changes for while and for-loops

* Format if-blocks correctly

* Run dotnet format style after rebase

* Run dotnet format whitespace after rebase

* Run dotnet format style after rebase

* Run dotnet format analyzers after rebase

* Run dotnet format after rebase and remove unused usings

- analyzers
- style
- whitespace

* Disable 'prefer switch expression' rule

* Add comments to disabled warnings

* Fix a few disabled warnings

* Fix naming rule violation, Convert shader properties to auto-property and convert values to const

* Simplify properties and array initialization, Use const when possible, Remove trailing commas

* Start working on disabled warnings

* Fix and silence a few dotnet-format warnings again

* Run dotnet format after rebase

* Use using declaration instead of block syntax

* Address IDE0251 warnings

* Address a few disabled IDE0060 warnings

* Silence IDE0060 in .editorconfig

* Revert "Simplify properties and array initialization, Use const when possible, Remove trailing commas"

This reverts commit 9462e4136c0a2100dc28b20cf9542e06790aa67e.

* dotnet format whitespace after rebase

* First dotnet format pass

* Fix naming rule violations

* Fix typo

* Add trailing commas, use targeted new and use array initializer

* Fix build issues

* Fix remaining build issues

* Remove SuppressMessage for CA1069 where possible

* Address dotnet format issues

* Address formatting issues

Co-authored-by: Ac_K <acoustik666@gmail.com>

* Add GetHashCode implementation for RenderingSurfaceInfo

* Explicitly silence CA1822 for every affected method in Syscall

* Address formatting issues in Demangler.cs

* Address review feedback

Co-authored-by: Ac_K <acoustik666@gmail.com>

* Revert marking service methods as static

* Next dotnet format pass

* Address review feedback

---------

Co-authored-by: Ac_K <acoustik666@gmail.com>
2023-07-16 19:31:14 +02:00
Mary
fec8291c17 infra: do not assign developers team for now
Hopefully fix PR triage for real...
2023-07-14 11:32:14 +02:00
gdkchan
c5d9e67cb2 Fix some Vulkan validation errors (#5452)
* Fix some validation errors and silence the annoying pipeline barrier error

* Remove bogus decref/incref on index buffer state

* Make unsafe blit opt-in rather than opt-out

* Remove Vulkan debugger messages blacklist

* Adjust GetImageUsage to not set the storage bit for multisample textures if not supported
2023-07-14 09:08:52 +02:00
Mary
e5261228d7 infra: Fix team name in reviewer.yml 2023-07-12 19:22:09 +02:00
Mary
e61c09bc85 infra: Fix PR triage once and for all (#5442)
Switch to a custom made python script that query GitHub API to grab latest state of the PR after label assign.
2023-07-12 18:31:08 +02:00
ealekseychik
ac2444f908 Move ShaderBinaries into individual .spv files (#5280)
* Move ShaderBinaries into individual spv files

* Rename binaries directory, remove variables and add helper method instead

* Update .csproj file

* Move ShaderBinaries into individual spv files

* Rename binaries directory, remove variables and add helper method instead

* Split shader binaries into folders, use string.Join to create filepath

* Move files back to general binaries folder

* Remove ShaderSource suffix from file names

---------

Co-authored-by: Egor Alekseychik <e.alekseychik@syberry.com>
Co-authored-by: Gabriel A <gab.dark.100@gmail.com>
2023-07-11 14:41:18 -03:00
gdkchan
9c6071a645 Move support buffer update out of the backends (#5411)
* Move support buffer update out of the backends

* Fix render scale init and remove redundant state from SupportBufferUpdater

* Stop passing texture scale to the backends

* XML docs for SupportBufferUpdater
2023-07-11 14:07:41 -03:00
gleng
fa32ef9275 MacOS: Allow barriers inside a render pass for non-Apple GPUs and don't treat as TBDR (#5440)
* MoltenVK: Allow barriers inside a render pass on non-Apple GPUs

* Don't treat all non-Apple GPUs using MoltenVK as TBDR
2023-07-11 03:10:23 +02:00
gleng
7805d27e67 MacOS: Fix rendering on AMD GPUs (#5446)
* MacOS: Fix rendering on AMD GPUs

* Only disable MultiViewPort on MoltenVK for AMD GPUs
2023-07-11 03:00:19 +02:00
TSRBerry
6c515e1822 [Ryujinx.Ava] Address dotnet-format issues (#5361)
* dotnet format style --severity info

Some changes were manually reverted.

* dotnet format analyzers --serverity info

Some changes have been minimally adapted.

* Restore a few unused methods and variables

* Silence dotnet format IDE0060 warnings

* Silence dotnet format IDE0052 warnings

* Silence dotnet format IDE0059 warnings

* Address or silence dotnet format IDE1006 warnings

* Address dotnet format CA1816 warnings

* Address dotnet format CA1822 warnings

* Address or silence dotnet format CA1069 warnings

* Make dotnet format succeed in style mode

* Address dotnet format CA1401 warnings

* Address remaining dotnet format analyzer warnings

* Address review comments

* dotnet-format fixes after rebase

* Address most dotnet format whitespace warnings

* Apply dotnet format whitespace formatting

A few of them have been manually reverted and the corresponding warning was silenced

* Format if-blocks correctly

* Another rebase, another dotnet format run

* Run dotnet format whitespace after rebase

* Run dotnet format style after rebase

* Run dotnet format after rebase and remove unused usings

- analyzers
- style
- whitespace

* Add comments to disabled warnings

* Remove a few unused parameters

* Simplify properties and array initialization, Use const when possible, Remove trailing commas

* Start working on disabled warnings

* Fix and silence a few dotnet-format warnings again

* Address IDE0260 warnings

* Address a few disabled IDE0060 warnings

* Silence IDE0060 in .editorconfig

* Revert "Simplify properties and array initialization, Use const when possible, Remove trailing commas"

This reverts commit 9462e4136c0a2100dc28b20cf9542e06790aa67e.

* dotnet format whitespace after rebase

* dotnet format pass with new editorconfig

* Fix naming style issues

* Apply suggestions from code review

Co-authored-by: Ac_K <Acoustik666@gmail.com>

* Revert one suggestion

* Second dotnet format pass and fix build issues

* Final pass of dotnet format

* Add trailing commas

* Fix formatting issues

* Keep unnecessary assignment in IconColorPicker.cs

* Use using declarations and extend resource lifetimes

* Fix rebase issues

* Adjust comment spacing

* Fix typo

* Fix naming issues

* Apply suggestions from code review

Co-authored-by: Ac_K <Acoustik666@gmail.com>

* Revert unintentional change

* Remove unused file

* Remove static keyword from ViewModels

Binding of static members doesn't work and is silently ignored.

---------

Co-authored-by: Ac_K <Acoustik666@gmail.com>
2023-07-07 23:03:27 +02:00
Mary
8a363b5df2 Revert "sdl: set SDL_HINT_GAMECONTROLLER_USE_BUTTON_LABELS to 0 (#5433)" (#5439)
This reverts commit 2b5abac809.
2023-07-06 18:08:14 +02:00
SuperSamus
2b5abac809 sdl: set SDL_HINT_GAMECONTROLLER_USE_BUTTON_LABELS to 0 (#5433)
Nintendo controllers notoriously have the A/B and X/Y buttons swapped, compared to the standard.
In order to combat this, when setting the default controller layout, Ryujinx checks whether the controller name contains "Nintendo", and swaps the mapping accordingly.
However, the reason the mapping is inverted in the first place is because SDL has `SDL_HINT_GAMECONTROLLER_USE_BUTTON_LABELS` set to 1 by default. By setting it to 0, the mapping will be based on the buttons' position instead.
So, by doing it (and removing the `isNintendoStyle` variable), we get the following advantages:
- The mapping will be the same on all controllers, removing the need to adjust custom mappings depending on what controller is used
- Users who already set `SDL_HINT_GAMECONTROLLER_USE_BUTTON_LABELS` to 0 globally for other games/applications (like me) won't have a wrong default mapping
- Checking whether the controller name contains "Nintendo" is ugly

Disadvantages:
- Breaks the controller configuration for existing users who are using a Nintendo controller
2023-07-06 17:11:26 +02:00
Theun de Bruijn
c19c8bbade Headless: Add support for fullscreen option (#5339)
* Headless: Added support for fullscreen option

* Headless: cleanup of fullscreen support

* Headless: fullscreen support : implemented proposed changes

* Headless: fullscreen support: cleanup

* Headless: fullscreen support: fix for OpenGL scaling

* Headless: fullscreen support: cleanup

* Headless: fullscreen support: cleanup

* Headless: fullscreen support: add. macOS fullscreen fix

* Headless: fullscreen support: cleanup

* Headless: fullscreen support: cleanup

* Headless: fullscreen support: cleanup
2023-07-06 12:10:15 +02:00
gdkchan
1c7a90ef35 Stop identifying shader textures with handle and cbuf, use binding instead (#5266)
* Stop identifying shader textures with handle and cbuf, use binding instead

* Remove now unused code

* Consider image operations as having accurate type information too

I don't know why that was not the case before

* Fix missing unscale on InsertCoordNormalization, stop calling SetUsageFlagsForTextureQuery when not needed

* Shader cache version bump

* Change get texture methods to return descriptors created from ResourceManager state

 This is required to ensure that reserved textures and images will not be bound as a guest texture/image

* Fix BindlessElimination.SetHandle inserting coords at the wrong place
2023-07-03 14:29:27 -03:00
TSRBerry
3b46bb73f7 [Ryujinx.Graphics.Gpu] Address dotnet-format issues (#5367)
* dotnet format style --severity info

Some changes were manually reverted.

* dotnet format analyzers --serverity info

Some changes have been minimally adapted.

* Restore a few unused methods and variables

* Silence dotnet format IDE0060 warnings

* Silence dotnet format IDE0052 warnings

* Address dotnet format CA1816 warnings

* Address or silence dotnet format CA1069 warnings

* Address or silence dotnet format CA2211 warnings

* Address remaining dotnet format analyzer warnings

* Address review comments

* Address most dotnet format whitespace warnings

* Apply dotnet format whitespace formatting

A few of them have been manually reverted and the corresponding warning was silenced

* Format if-blocks correctly

* Run dotnet format whitespace after rebase

* Run dotnet format style after rebase

* Another rebase, another dotnet format run

* Run dotnet format style after rebase

* Run dotnet format after rebase and remove unused usings

- analyzers
- style
- whitespace

* Disable 'prefer switch expression' rule

* Add comments to disabled warnings

* Remove a few unused parameters

* Replace MmeShadowScratch with Array256<uint>

* Simplify properties and array initialization, Use const when possible, Remove trailing commas

* Start working on disabled warnings

* Fix and silence a few dotnet-format warnings again

* Run dotnet format after rebase

* Address IDE0251 warnings

* Silence IDE0060 in .editorconfig

* Revert "Simplify properties and array initialization, Use const when possible, Remove trailing commas"

This reverts commit 9462e4136c0a2100dc28b20cf9542e06790aa67e.

* dotnet format whitespace after rebase

* First pass of dotnet format

* Add unsafe dotnet format changes

* Fix typos

* Add trailing commas

* Disable formatting for FormatTable

* Address review feedback
2023-07-02 02:47:54 +02:00
TSRBerry
2457cfc911 Fix naming issue in ControllerWindow (#5424) 2023-07-02 02:26:32 +02:00
TSRBerry
515fc32b21 [Ryujinx.Audio] Address dotnet-format issues (#5362)
* dotnet format style --severity info

Some changes were manually reverted.

* dotnet format analyzers --serverity info

Some changes have been minimally adapted.

* Restore a few unused methods and variables

* Silence dotnet format IDE0060 warnings

* Silence dotnet format IDE0052 warnings

* Address dotnet format CA1816 warnings

* Address or silence dotnet format CA2208 warnings

* Address or silence dotnet format CA2211 warnings

* Address review comments

* Address most dotnet format whitespace warnings

* Apply dotnet format whitespace formatting

A few of them have been manually reverted and the corresponding warning was silenced

* Format if-blocks correctly

* Run dotnet format whitespace after rebase

* Run dotnet format after rebase and remove unused usings

- analyzers
- style
- whitespace

* Add comments to disabled warnings

* Remove a few unused parameters

* Simplify properties and array initialization, Use const when possible, Remove trailing commas

* Start working on disabled warnings

* Fix and silence a few dotnet-format warnings again

* Address IDE0251 warnings

* Silence IDE0060 in .editorconfig

* Revert "Simplify properties and array initialization, Use const when possible, Remove trailing commas"

This reverts commit 9462e4136c0a2100dc28b20cf9542e06790aa67e.

* dotnet format whitespace after rebase

* Fix naming rule violations, remove redundant code and fix build issues

* Apply suggestions from code review

Co-authored-by: Ac_K <Acoustik666@gmail.com>

* Add trailing commas

* Apply suggestions from code review

Co-authored-by: Ac_K <Acoustik666@gmail.com>

* Address review feedback

---------

Co-authored-by: Ac_K <Acoustik666@gmail.com>
2023-07-02 01:27:18 +02:00
TSRBerry
0684b00b3c [Ryujinx] Address dotnet-format issues (#5395)
* dotnet format style --severity info

Some changes were manually reverted.

* dotnet format analyzers --serverity info

Some changes have been minimally adapted.

* Restore a few unused methods and variables

* Address dotnet format CA1816 warnings

* Address or silence dotnet format CA2208 warnings

* Address or silence dotnet format CA1806 and a few CA1854 warnings

* Address dotnet format CA1822 warnings

* Make dotnet format succeed in style mode

* Address dotnet format CA2208 warnings properly

* Address most dotnet format whitespace warnings

* Apply dotnet format whitespace formatting

A few of them have been manually reverted and the corresponding warning was silenced

* Format if-blocks correctly

* Another rebase, another dotnet format run

* Run dotnet format whitespace after rebase

* Run dotnet format after rebase and remove unused usings

- analyzers
- style
- whitespace

* Add comments to disabled warnings

* Simplify properties and array initialization, Use const when possible, Remove trailing commas

* Revert "Simplify properties and array initialization, Use const when possible, Remove trailing commas"

This reverts commit 9462e4136c0a2100dc28b20cf9542e06790aa67e.

* dotnet format whitespace after rebase

* First dotnet format pass

* Fix build issues

* Apply suggestions from code review

Co-authored-by: Ac_K <Acoustik666@gmail.com>

* Second dotnet format pass

* Update src/Ryujinx/Modules/Updater/Updater.cs

Co-authored-by: Ac_K <Acoustik666@gmail.com>

* Add trailing commas and improve formatting

* Fix formatting and naming issues

* Rename nvStutterWorkaround to nvidiaStutterWorkaround

* Use using declarations and extend resource lifetimes

* Fix GTK issues

* Add formatting for generated files

* Add trailing commas

---------

Co-authored-by: Ac_K <Acoustik666@gmail.com>
2023-07-02 00:25:07 +02:00
TSRBerry
02b5c7ea89 [Ryujinx.Horizon] Address dotnet-format issues (#5381)
* dotnet format style --severity info

Some changes were manually reverted.

* dotnet format analyzers --serverity info

Some changes have been minimally adapted.

* Restore a few unused methods and variables

* Silence dotnet format IDE0060 warnings

* Silence dotnet format IDE0052 warnings

* Address dotnet format CA1822 warnings

* Address most dotnet format whitespace warnings

* Apply dotnet format whitespace formatting

A few of them have been manually reverted and the corresponding warning was silenced

* Revert formatting changes for while and for-loops

* Run dotnet format whitespace after rebase

* Run dotnet format style after rebase

* Run dotnet format after rebase and remove unused usings

- analyzers
- style
- whitespace

* Add comments to disabled warnings

* Remove a few unused parameters

* Simplify properties and array initialization, Use const when possible, Remove trailing commas

* Address IDE0251 warnings

* Silence IDE0060 in .editorconfig

* Revert "Simplify properties and array initialization, Use const when possible, Remove trailing commas"

This reverts commit 9462e4136c0a2100dc28b20cf9542e06790aa67e.

* dotnet format whitespace after rebase

* First dotnet format pass

* Add trailing commas and fix formatting issues

* Convert if-else chain to switch block

* Address review feedback
2023-07-01 12:42:10 +02:00
TSRBerry
801b71a128 [Ryujinx.Graphics.Vulkan] Address dotnet-format issues (#5378)
* dotnet format style --severity info

Some changes were manually reverted.

* dotnet format analyzers --serverity info

Some changes have been minimally adapted.

* Restore a few unused methods and variables

* Silence dotnet format IDE0060 warnings

* Silence dotnet format IDE0059 warnings

* Address dotnet format CA1816 warnings

* Fix new dotnet-format issues after rebase

* Address most dotnet format whitespace warnings

* Apply dotnet format whitespace formatting

A few of them have been manually reverted and the corresponding warning was silenced

* Format if-blocks correctly

* Another rebase, another dotnet format run

* Run dotnet format whitespace after rebase

* Run dotnet format style after rebase

* Run dotnet format analyzers after rebase

* Run dotnet format style after rebase

* Run dotnet format after rebase and remove unused usings

- analyzers
- style
- whitespace

* Disable 'prefer switch expression' rule

* Add comments to disabled warnings

* Simplify properties and array initialization, Use const when possible, Remove trailing commas

* Run dotnet format after rebase

* Address IDE0251 warnings

* Address a few disabled IDE0060 warnings

* Silence IDE0060 in .editorconfig

* Revert "Simplify properties and array initialization, Use const when possible, Remove trailing commas"

This reverts commit 9462e4136c0a2100dc28b20cf9542e06790aa67e.

* dotnet format whitespace after rebase

* First dotnet format pass

* Fix naming rule violations

* Remove redundant code

* Rename generics

* Address review feedback

* Remove SetOrigin
2023-07-01 12:31:42 +02:00
Marco Carvalho
12c5f6ee89 Indexing at 0 should be used instead of the "Enumerable" extension method "First" (#5354) 2023-07-01 06:29:37 +00:00
TSRBerry
79a1314ee4 [Ryujinx.Cpu] Address dotnet-format issues (#5365)
* dotnet format style --severity info

Some changes were manually reverted.

* dotnet format analyzers --serverity info

Some changes have been minimally adapted.

* Restore a few unused methods and variables

* Silence dotnet format IDE0060 warnings

* Silence dotnet format IDE0052 warnings

* Silence dotnet format IDE0059 warnings

* Address or silence dotnet format IDE1006 warnings

* Address dotnet format CA1816 warnings

* Address most dotnet format whitespace warnings

* Run dotnet format after rebase and remove unused usings

- analyzers
- style
- whitespace

* Add comments to disabled warnings

* Remove a few unused parameters

* Adjust namespaces

* Simplify properties and array initialization, Use const when possible, Remove trailing commas

* Start working on disabled warnings

* Fix and silence a few dotnet-format warnings again

* Address a few disabled IDE0060 warnings

* Silence IDE0060 in .editorconfig

* Revert "Simplify properties and array initialization, Use const when possible, Remove trailing commas"

This reverts commit 9462e4136c0a2100dc28b20cf9542e06790aa67e.

* dotnet format whitespace after rebase

* Address review feedback

* Remove redundant unsafe modifiers

* Fix build issues

* Add GC.SuppressFinalize() call

* Add trailing commas and fix naming rule violations

* Remove unused members and assignments
2023-07-01 02:18:52 +00:00
TSRBerry
e9848339dd [Ryujinx.Tests] Address dotnet-format issues (#5389)
* dotnet format style --severity info

Some changes were manually reverted.

* dotnet format analyzers --serverity info

Some changes have been minimally adapted.

* Restore a few unused methods and variables

* Fix new dotnet-format issues after rebase

* Address review comments

* Address most dotnet format whitespace warnings

* Apply dotnet format whitespace formatting

A few of them have been manually reverted and the corresponding warning was silenced

* Format if-blocks correctly

* Run dotnet format after rebase and remove unused usings

- analyzers
- style
- whitespace

* Add comments to disabled warnings

* Simplify properties and array initialization, Use const when possible, Remove trailing commas

* cpu tests: Disable CA2211 for CodeBaseAddress and DataBaseAddress

* Revert "Simplify properties and array initialization, Use const when possible, Remove trailing commas"

This reverts commit 9462e4136c0a2100dc28b20cf9542e06790aa67e.

* dotnet format whitespace after rebase

* Apply suggestions from code review

Co-authored-by: Ac_K <Acoustik666@gmail.com>

* First dotnet format pass

* Fix naming rule violations

* Remove naming rule violation exceptions

* Fix comment style

* Use targeted new

* Remove redundant code

* Remove comment alignment

* Remove naming rule exceptions

* Add trailing commas

* Use nameof expression

* Reformat to add remaining trailing commas

---------

Co-authored-by: Ac_K <Acoustik666@gmail.com>
2023-07-01 02:14:34 +00:00
TSRBerry
6e28a4dd13 [Ryujinx.Ui.Common] Address dotnet-format issues (#5392)
* dotnet format style --severity info

Some changes were manually reverted.

* dotnet format analyzers --serverity info

Some changes have been minimally adapted.

* Silence dotnet format IDE0060 warnings

* Address dotnet format CA1401 warnings

* dotnet-format fixes after rebase

* Address most dotnet format whitespace warnings

* Apply dotnet format whitespace formatting

A few of them have been manually reverted and the corresponding warning was silenced

* Another rebase, another dotnet format run

* Run dotnet format style after rebase

* Add comments to disabled warnings

* Remove a few unused parameters

* Simplify properties and array initialization, Use const when possible, Remove trailing commas

* Address IDE0251 warnings

* Revert "Simplify properties and array initialization, Use const when possible, Remove trailing commas"

This reverts commit 9462e4136c0a2100dc28b20cf9542e06790aa67e.

* dotnet format whitespace after rebase

* Small optimizations

* Remove alignment

* Apply formatting

* Fix build issues

* Final pass for dotnet format

* Add trailing commas

Co-authored-by: Ac_K <Acoustik666@gmail.com>

* Add trailing commas

---------

Co-authored-by: Ac_K <Acoustik666@gmail.com>
2023-06-29 02:39:22 +02:00
TSRBerry
7c989f88bd [Ryujinx.Graphics.GAL] Address dotnet-format issues (#5366)
* dotnet format style --severity info

Some changes were manually reverted.

* dotnet format analyzers --serverity info

Some changes have been minimally adapted.

* Restore a few unused methods and variables

* Silence dotnet format IDE0052 warnings

* Address dotnet format CA1816 warnings

* Address or silence dotnet format CA1069 warnings

* Address remaining dotnet format analyzer warnings

* Address review comments

* Address most dotnet format whitespace warnings

* Apply dotnet format whitespace formatting

A few of them have been manually reverted and the corresponding warning was silenced

* Revert formatting changes for while and for-loops

* Another rebase, another dotnet format run

* Run dotnet format whitespace after rebase

* Run dotnet format style after rebase

* Run dotnet format analyzers after rebase

* Run dotnet format after rebase and remove unused usings

- analyzers
- style
- whitespace

* Disable 'prefer switch expression' rule

* Add comments to disabled warnings

* Simplify properties and array initialization, Use const when possible, Remove trailing commas

* Start working on disabled warnings

* Address IDE0251 warnings

* Revert "Simplify properties and array initialization, Use const when possible, Remove trailing commas"

This reverts commit 9462e4136c0a2100dc28b20cf9542e06790aa67e.

* dotnet format whitespace after rebase

* First dotnet format pass

* Address review feedback

* Add trailing commas

* Remove SuppressMessage for IDE0066

* Make explicit Equals implementation implicit
2023-06-28 20:20:10 +02:00
Ac_K
16fa983704 macOS: Fix warning in some shell scripts (#5398)
* macOS: Fix warning in some shell scripts

In a way to continue the cleaning of the project, there are some warnings which can be easily fixed.

* Try to fix CI

* Fix APP_ARGUMENTS

* Addresses feedback
2023-06-28 19:09:48 +02:00
TSRBerry
40daca5684 [Ryujinx.Headless.SDL2] Address dotnet-format issues (#5379)
* dotnet format style --severity info

Some changes were manually reverted.

* dotnet format analyzers --serverity info

Some changes have been minimally adapted.

* Restore a few unused methods and variables

* Address or silence dotnet format CA1806 and a few CA1854 warnings

* Address most dotnet format whitespace warnings

* Apply dotnet format whitespace formatting

A few of them have been manually reverted and the corresponding warning was silenced

* Simplify properties and array initialization, Use const when possible, Remove trailing commas

* Revert "Simplify properties and array initialization, Use const when possible, Remove trailing commas"

This reverts commit 9462e4136c0a2100dc28b20cf9542e06790aa67e.

* dotnet format whitespace after rebase

* First dotnet format pass

* Add trailing commas

* Fix naming and formatting issues
2023-06-28 19:03:27 +02:00
TSRBerry
981e0c082d [Spv.Generator] Address dotnet-format issues (#5394)
* dotnet format style --severity info

Some changes were manually reverted.

* Restore a few unused methods and variables

* Silence dotnet format IDE0052 warnings

* Address or silence dotnet format IDE1006 warnings

* Address or silence dotnet format CA1069 warnings

* Address review comments

* Address most dotnet format whitespace warnings

* Run dotnet format after rebase and remove unused usings

- analyzers
- style
- whitespace

* Add comments to disabled warnings

* Simplify properties and array initialization, Use const when possible, Remove trailing commas

* Address IDE0251 warnings

* Revert "Simplify properties and array initialization, Use const when possible, Remove trailing commas"

This reverts commit 9462e4136c0a2100dc28b20cf9542e06790aa67e.

* dotnet format whitespace after rebase

* Rename Operand.cs to IOperand.cs

* Update src/Spv.Generator/Module.cs

Co-authored-by: Ac_K <Acoustik666@gmail.com>

* Remove NotNullWhen attribute and use conditional access to avoid NRE

* Fix duplicated enum values

* Remove unread member

---------

Co-authored-by: Ac_K <Acoustik666@gmail.com>
2023-06-28 18:54:20 +02:00
TSRBerry
cebfa54467 [Ryujinx.Graphics.Texture] Address dotnet-format issues (#5375)
* dotnet format style --severity info

Some changes were manually reverted.

* Restore a few unused methods and variables

* Silence dotnet format IDE0060 warnings

* Silence dotnet format IDE0059 warnings

* Address or silence dotnet format CA2208 warnings

* Address most dotnet format whitespace warnings

* Apply dotnet format whitespace formatting

A few of them have been manually reverted and the corresponding warning was silenced

* Format if-blocks correctly

* Add comments to disabled warnings

* Simplify properties and array initialization, Use const when possible, Remove trailing commas

* Address IDE0251 warnings

* Silence IDE0060 in .editorconfig

* Revert "Simplify properties and array initialization, Use const when possible, Remove trailing commas"

This reverts commit 9462e4136c0a2100dc28b20cf9542e06790aa67e.

* dotnet format whitespace after rebase

* First dotnet format pass

* Apply suggestions from code review

Co-authored-by: Ac_K <Acoustik666@gmail.com>

* Address review feedback

* Update src/Ryujinx.Graphics.Texture/Astc/AstcDecoder.cs

Co-authored-by: Ac_K <Acoustik666@gmail.com>

---------

Co-authored-by: Ac_K <Acoustik666@gmail.com>
2023-06-28 18:46:18 +02:00
TSRBerry
fc20d9b925 [Ryujinx.Common] Address dotnet-format issues (#5358)
* dotnet format style --severity info

Some changes were manually reverted.

* dotnet format analyzers --serverity info

Some changes have been minimally adapted.

* Restore a few unused methods and variables

* Silence dotnet format IDE0060 warnings

* Silence dotnet format IDE0059 warnings

* Address or silence dotnet format IDE1006 warnings

* Address dotnet format CA1816 warnings

* Address or silence dotnet format CA2211 warnings

* Silence CA1806 and CA1834 issues

* Fix formatting for switch expressions

* Address most dotnet format whitespace warnings

* Apply dotnet format whitespace formatting

A few of them have been manually reverted and the corresponding warning was silenced

* Revert formatting changes for while and for-loops

* Format if-blocks correctly

* Run dotnet format whitespace after rebase

* Run dotnet format style after rebase

* Run dotnet format analyzers after rebase

* Run dotnet format after rebase and remove unused usings

- analyzers
- style
- whitespace

* Add comments to disabled warnings

* Remove a few unused parameters

* Replace MmeShadowScratch with Array256<uint>

* Simplify properties and array initialization, Use const when possible, Remove trailing commas

* Run dotnet format after rebase

* Address IDE0251 warnings

* Revert "Simplify properties and array initialization, Use const when possible, Remove trailing commas"

This reverts commit 9462e4136c0a2100dc28b20cf9542e06790aa67e.

* dotnet format whitespace after rebase

* First dotnet format pass

* Second dotnet format pass

* Fix build issues

* Fix StructArrayHelpers.cs

* Apply suggestions from code review

Co-authored-by: Ac_K <Acoustik666@gmail.com>

* Fix return statements

* Fix naming rule violations

* Update src/Ryujinx.Common/Utilities/StreamUtils.cs

Co-authored-by: Ac_K <Acoustik666@gmail.com>

* Add trailing commas

* Address review feedback

* Address review feedback

* Rename remaining type parameters to TKey and TValue

* Fix manual formatting for logging levels

* Fix spacing before comments

---------

Co-authored-by: Ac_K <Acoustik666@gmail.com>
2023-06-28 18:41:38 +02:00
TSRBerry
0a75b73fa4 [Ryujinx.Memory] Address dotnet-format issues (#5386)
* dotnet format style --severity info

Some changes were manually reverted.

* dotnet format analyzers --serverity info

Some changes have been minimally adapted.

* Silence dotnet format IDE0059 warnings

* Address or silence dotnet format IDE1006 warnings

* Address dotnet format CA1816 warnings

* Address or silence dotnet format CA1069 warnings

* Address remaining dotnet format analyzer warnings

* Address review comments

* Address most dotnet format whitespace warnings

* Apply dotnet format whitespace formatting

A few of them have been manually reverted and the corresponding warning was silenced

* Format if-blocks correctly

* Another rebase, another dotnet format run

* Run dotnet format after rebase and remove unused usings

- analyzers
- style
- whitespace

* Add comments to disabled warnings

* Simplify properties and array initialization, Use const when possible, Remove trailing commas

* Revert "Simplify properties and array initialization, Use const when possible, Remove trailing commas"

This reverts commit 9462e4136c0a2100dc28b20cf9542e06790aa67e.

* dotnet format whitespace after rebase

* Address review feedback

* Assign Decommit to ReplacePlaceholder

* Run final dotnet format pass

* Organize imports again

* Add trailing commas

* Add missing newline
2023-06-28 18:34:00 +02:00
TSRBerry
46b7c905f5 [Ryujinx.Input] Address dotnet-format issues (#5384)
* dotnet format style --severity info

Some changes were manually reverted.

* dotnet format analyzers --serverity info

Some changes have been minimally adapted.

* Restore a few unused methods and variables

* Address dotnet format CA1816 warnings

* Address or silence dotnet format CA1806 and a few CA1854 warnings

* Address most dotnet format whitespace warnings

* Apply dotnet format whitespace formatting

A few of them have been manually reverted and the corresponding warning was silenced

* Add comments to disabled warnings

* Simplify properties and array initialization, Use const when possible, Remove trailing commas

* Revert "Simplify properties and array initialization, Use const when possible, Remove trailing commas"

This reverts commit 9462e4136c0a2100dc28b20cf9542e06790aa67e.

* dotnet format whitespace after rebase

* Remove redundant code, convert to auto-properties and fix naming rule violations

* Remove bogus change

* Address review feedback
2023-06-28 18:23:00 +02:00
TSRBerry
40f2bd37e3 [Ryujinx.Graphics.OpenGL] Address dotnet-format issues (#5372)
* dotnet format style --severity info

Some changes were manually reverted.

* dotnet format analyzers --serverity info

Some changes have been minimally adapted.

* Restore a few unused methods and variables

* Silence dotnet format IDE0060 warnings

* Address or silence dotnet format IDE1006 warnings

* Fix IDE0090 after rebase

* Address most dotnet format whitespace warnings

* Apply dotnet format whitespace formatting

A few of them have been manually reverted and the corresponding warning was silenced

* Format if-blocks correctly

* Another rebase, another dotnet format run

* Run dotnet format after rebase and remove unused usings

- analyzers
- style
- whitespace

* Add comments to disabled warnings

* Simplify properties and array initialization, Use const when possible, Remove trailing commas

* Start working on disabled warnings

* Address a few disabled IDE0060 warnings

* Silence IDE0060 in .editorconfig

* Revert "Simplify properties and array initialization, Use const when possible, Remove trailing commas"

This reverts commit 9462e4136c0a2100dc28b20cf9542e06790aa67e.

* dotnet format whitespace after rebase

* First dotnet format pass

* Address review feedback
2023-06-28 18:10:55 +02:00
Ac_K
9288ffd26d Cpu: Implement VCVT (between floating-point and fixed-point) instruction (#5343)
* cpu: Implement VCVT (between floating-point and fixed-point) instruction

Rebase, fix and superseed of https://github.com/Ryujinx/Ryujinx/pull/2915

(Since I only have little CPU knowledge, I hope I have done everything good)

* Update Ptc.cs

* Fix wrong cast

* Rename tests

* Addresses feedback

Co-Authored-By: gdkchan <5624669+gdkchan@users.noreply.github.com>

* Remove extra empty line

---------

Co-authored-by: gdkchan <5624669+gdkchan@users.noreply.github.com>
2023-06-28 17:36:30 +02:00
dependabot[bot]
2cdc82cb91 nuget: bump Microsoft.NET.Test.Sdk from 17.6.2 to 17.6.3 (#5406)
Bumps [Microsoft.NET.Test.Sdk](https://github.com/microsoft/vstest) from 17.6.2 to 17.6.3.
- [Release notes](https://github.com/microsoft/vstest/releases)
- [Changelog](https://github.com/microsoft/vstest/blob/main/docs/releases.md)
- [Commits](https://github.com/microsoft/vstest/compare/v17.6.2...v17.6.3)

---
updated-dependencies:
- dependency-name: Microsoft.NET.Test.Sdk
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-06-28 09:36:22 +02:00
TSRBerry
6aa8d71588 [Ryujinx.Graphics.Nvdec.Vp9] Address dotnet-format issues (#5371)
* dotnet format style --severity info

Some changes were manually reverted.

* dotnet format analyzers --serverity info

Some changes have been minimally adapted.

* Restore a few unused methods and variables

* Silence dotnet format IDE0060 warnings

* Address or silence dotnet format IDE1006 warnings

* Address most dotnet format whitespace warnings

* Apply dotnet format whitespace formatting

A few of them have been manually reverted and the corresponding warning was silenced

* Add comments to disabled warnings

* Simplify properties and array initialization, Use const when possible, Remove trailing commas

* Address IDE0251 warnings

* Address a few disabled IDE0060 warnings

* Silence IDE0060 in .editorconfig

* Revert "Simplify properties and array initialization, Use const when possible, Remove trailing commas"

This reverts commit 9462e4136c0a2100dc28b20cf9542e06790aa67e.

* dotnet format whitespace after rebase

* Fix empty lines before return

Co-authored-by: Ac_K <Acoustik666@gmail.com>

* Add trailing commas, remove redundant code and remove static modifier from Surface.HighBd

* Fix naming rule violations

* Fix naming rule violations

* Fix empty line before return

* Fix comment style

Co-authored-by: Ac_K <Acoustik666@gmail.com>

* Remove comment alignment

* Address review feedback

* Separate comments by 2 spaces and fix other formatting issues

* Make HighBd an auto-property

* Replace if-chain with if-else-chain

* Fix new naming rule violations

---------

Co-authored-by: Ac_K <Acoustik666@gmail.com>
2023-06-28 09:26:39 +02:00
TSRBerry
9becbd7d72 [Ryujinx.Graphics.Shader] Address dotnet-format issues (#5373)
* dotnet format style --severity info

Some changes were manually reverted.

* Restore a few unused methods and variables

* Silence dotnet format IDE0060 warnings

* Silence dotnet format IDE0052 warnings

* Silence dotnet format IDE0059 warnings

* Address or silence dotnet format CA1069 warnings

* Address or silence dotnet format CA2211 warnings

* Address review comments

* Fix formatting for switch expressions

* Address most dotnet format whitespace warnings

* Apply dotnet format whitespace formatting

A few of them have been manually reverted and the corresponding warning was silenced

* Format if-blocks correctly

* Run dotnet format whitespace after rebase

* Run dotnet format style after rebase

* Run dotnet format whitespace after rebase

* Run dotnet format style after rebase

* Run dotnet format after rebase and remove unused usings

- analyzers
- style
- whitespace

* Disable 'prefer switch expression' rule

* Add comments to disabled warnings

* Fix naming rule violation, Convert shader properties to auto-property and convert values to const

* Simplify properties and array initialization, Use const when possible, Remove trailing commas

* Run dotnet format after rebase

* Address IDE0251 warnings

* Address a few disabled IDE0060 warnings

* Silence IDE0060 in .editorconfig

* Run dotnet format after rebase

* Revert "Simplify properties and array initialization, Use const when possible, Remove trailing commas"

This reverts commit 9462e4136c0a2100dc28b20cf9542e06790aa67e.

* dotnet format whitespace after rebase

* First dotnet format pass

* Fix naming rule violations

* Add trailing commas

* Remove unused members and most unnecessary value assignments

* Remove more unnecessary assignments

* Remove NRE suppressor
2023-06-28 08:59:13 +02:00
TSRBerry
e055217292 [Ryujinx.Horizon.Kernel.Generators] Address dotnet-format issues (#5376)
* Address most dotnet format whitespace warnings

* Apply dotnet format whitespace formatting

A few of them have been manually reverted and the corresponding warning was silenced

* Simplify properties and array initialization, Use const when possible, Remove trailing commas

* Revert "Simplify properties and array initialization, Use const when possible, Remove trailing commas"

This reverts commit 9462e4136c0a2100dc28b20cf9542e06790aa67e.

* dotnet format whitespace after rebase

* Run dotnet format pass

* Remove left-over files and adjust namespaces

* Fix alignment
2023-06-27 23:27:48 +00:00
TSRBerry
fbaf62c230 Apply new naming rule to all projects except Vp9 (#5407) 2023-06-28 01:18:19 +02:00
TSRBerry
b186ec9fc5 [Ryujinx.Graphics.Video] Address dotnet-format issues (#5377)
* Address most dotnet format whitespace warnings

* dotnet format whitespace after rebase
2023-06-27 16:45:33 +02:00
TSRBerry
0191e2396a [Ryujinx.Graphics.Host1x] Address dotnet-format issues (#5368)
* dotnet format style --severity info

Some changes were manually reverted.

* Address most dotnet format whitespace warnings

* Add comments to disabled warnings

* dotnet format whitespace after rebase
2023-06-27 16:35:48 +02:00
TSRBerry
e96299eef5 [Ryujinx.Horizon.Generators] Address dotnet-format issues (#5383)
* dotnet format style --severity info

Some changes were manually reverted.

* Address most dotnet format whitespace warnings

* Apply dotnet format whitespace formatting

A few of them have been manually reverted and the corresponding warning was silenced

* dotnet format whitespace after rebase
2023-06-26 07:35:19 +02:00
TSRBerry
ff53dcf560 [ARMeilleure] Address dotnet-format issues (#5357)
* dotnet format style --severity info

Some changes were manually reverted.

* dotnet format analyzers --serverity info

Some changes have been minimally adapted.

* Restore a few unused methods and variables

* Silence dotnet format IDE0060 warnings

* Silence dotnet format IDE0052 warnings

* Address or silence dotnet format IDE1006 warnings

* Address or silence dotnet format CA2208 warnings

* Address dotnet format CA1822 warnings

* Address or silence dotnet format CA1069 warnings

* Silence CA1806 and CA1834 issues

* Address dotnet format CA1401 warnings

* Fix new dotnet-format issues after rebase

* Address review comments

* Address dotnet format CA2208 warnings properly

* Fix formatting for switch expressions

* Address most dotnet format whitespace warnings

* Apply dotnet format whitespace formatting

A few of them have been manually reverted and the corresponding warning was silenced

* Add previously silenced warnings back

I have no clue how these disappeared

* Revert formatting changes for OpCodeTable.cs

* Enable formatting for a few cases again

* Format if-blocks correctly

* Enable formatting for a few more cases again

* Fix inline comment alignment

* Run dotnet format after rebase and remove unused usings

- analyzers
- style
- whitespace

* Disable 'prefer switch expression' rule

* Add comments to disabled warnings

* Remove a few unused parameters

* Adjust namespaces

* Simplify properties and array initialization, Use const when possible, Remove trailing commas

* Start working on disabled warnings

* Fix and silence a few dotnet-format warnings again

* Address IDE0251 warnings

* Address a few disabled IDE0060 warnings

* Silence IDE0060 in .editorconfig

* Revert "Simplify properties and array initialization, Use const when possible, Remove trailing commas"

This reverts commit 9462e4136c0a2100dc28b20cf9542e06790aa67e.

* dotnet format whitespace after rebase

* First dotnet format pass

* Remove unnecessary formatting exclusion

* Add unsafe dotnet format changes

* Change visibility of JitSupportDarwin to internal
2023-06-26 07:25:06 +02:00
TSRBerry
2de78a2d55 [Ryujinx.Input.SDL2] Address dotnet-format issues (#5385)
* dotnet format style --severity info

Some changes were manually reverted.

* dotnet format analyzers --serverity info

Some changes have been minimally adapted.

* Restore a few unused methods and variables

* Silence dotnet format IDE0052 warnings

* Address dotnet format CA1816 warnings

* Address or silence dotnet format CA1806 and a few CA1854 warnings

* Address most dotnet format whitespace warnings

* Add comments to disabled warnings

* Simplify properties and array initialization, Use const when possible, Remove trailing commas

* Revert "Simplify properties and array initialization, Use const when possible, Remove trailing commas"

This reverts commit 9462e4136c0a2100dc28b20cf9542e06790aa67e.

* dotnet format whitespace after rebase

* Add trailing commas, log errors instead of throwing and remove redundant code
2023-06-26 01:55:25 +00:00
TSRBerry
b29ded1d60 [Ryujinx.SDL2.Common] Address dotnet-format issues (#5387)
* dotnet format style --severity info

Some changes were manually reverted.

* Address dotnet format CA1816 warnings

* Address or silence dotnet format CA1806 and a few CA1854 warnings

* Address most dotnet format whitespace warnings

* dotnet format whitespace after rebase
2023-06-26 01:51:16 +00:00
Mary
9860bfb2cd misc: memory: Migrate from OutOfMemoryException to SystemException entirely (#5399)
Fix a regression with address space allocation while providing more
information about the context of the exception.
2023-06-26 01:37:12 +00:00
TSRBerry
f6ada8d169 [Ryujinx.Graphics.Device] Address dotnet-format issues (#5363)
* dotnet format analyzers --serverity info

Some changes have been minimally adapted.

* Address most dotnet format whitespace warnings

* dotnet format whitespace after rebase
2023-06-25 23:58:44 +02:00
TSRBerry
42d31f646d [Ryujinx.Audio.Backends.SDL2] Address dotnet-format issues (#5364)
* dotnet format style --severity info

Some changes were manually reverted.

* dotnet format analyzers --serverity info

Some changes have been minimally adapted.

* Address dotnet format CA1816 warnings

* Address most dotnet format whitespace warnings

* Run dotnet format style after rebase

* Run dotnet format analyzers after rebase

* Simplify properties and array initialization, Use const when possible, Remove trailing commas

* Revert "Simplify properties and array initialization, Use const when possible, Remove trailing commas"

This reverts commit 9462e4136c0a2100dc28b20cf9542e06790aa67e.

* dotnet format whitespace after rebase

* Update src/Ryujinx.Audio.Backends.SDL2/SDL2HardwareDeviceDriver.cs

Co-authored-by: Ac_K <Acoustik666@gmail.com>

---------

Co-authored-by: Ac_K <Acoustik666@gmail.com>
2023-06-25 22:50:59 +02:00
TSRBerry
07fc3ded68 [Ryujinx.Graphics.Nvdec] Address dotnet-format issues (#5369)
* dotnet format style --severity info

Some changes were manually reverted.

* Restore a few unused methods and variables

* Address most dotnet format whitespace warnings

* Apply dotnet format whitespace formatting

A few of them have been manually reverted and the corresponding warning was silenced

* Add previously silenced warnings back

I have no clue how these disappeared

* Add comments to disabled warnings

* Simplify properties and array initialization, Use const when possible, Remove trailing commas

* Address IDE0251 warnings

* Revert "Simplify properties and array initialization, Use const when possible, Remove trailing commas"

This reverts commit 9462e4136c0a2100dc28b20cf9542e06790aa67e.

* dotnet format whitespace after rebase

* First dotnet format pass
2023-06-25 21:44:42 +02:00
TSRBerry
fd01259d2b [Ryujinx.ShaderTools] Address dotnet-format issues (#5388)
* dotnet format style --severity info

Some changes were manually reverted.

* dotnet format whitespace after rebase
2023-06-25 21:37:33 +02:00
TSRBerry
7ffe7f8442 [Ryujinx.Graphics.Nvdec.FFmpeg] Address dotnet-format issues (#5370)
* dotnet format style --severity info

Some changes were manually reverted.

* Address or silence dotnet format CA1806 and a few CA1854 warnings

* Address most dotnet format whitespace warnings

* Apply dotnet format whitespace formatting

A few of them have been manually reverted and the corresponding warning was silenced

* Add comments to disabled warnings

* Simplify properties and array initialization, Use const when possible, Remove trailing commas

* Address IDE0251 warnings

* Revert "Simplify properties and array initialization, Use const when possible, Remove trailing commas"

This reverts commit 9462e4136c0a2100dc28b20cf9542e06790aa67e.

* dotnet format whitespace after rebase

* First dotnet format pass
2023-06-25 19:03:48 +02:00
TSRBerry
2b2ce68f07 [Ryujinx.Tests.Memory] Address dotnet-format issues (#5390)
* dotnet format style --severity info

Some changes were manually reverted.

* dotnet format analyzers --serverity info

Some changes have been minimally adapted.

* Restore a few unused methods and variables

* Silence dotnet format IDE0060 warnings

* Address dotnet format CA1822 warnings

* Address most dotnet format whitespace warnings

* Apply dotnet format whitespace formatting

A few of them have been manually reverted and the corresponding warning was silenced

* Add comments to disabled warnings

* Simplify properties and array initialization, Use const when possible, Remove trailing commas

* Silence IDE0060 in .editorconfig

* Revert "Simplify properties and array initialization, Use const when possible, Remove trailing commas"

This reverts commit 9462e4136c0a2100dc28b20cf9542e06790aa67e.

* dotnet format whitespace after rebase

* Final dotnet format pass and fix naming rule violations

* Apply suggestions from code review

Co-authored-by: Ac_K <Acoustik666@gmail.com>

* Remove unused constant

---------

Co-authored-by: Ac_K <Acoustik666@gmail.com>
2023-06-25 18:37:53 +02:00
TSRBerry
bc53d00463 [Ryujinx.Graphics.Vic] Address dotnet-format issues (#5374)
* dotnet format style --severity info

Some changes were manually reverted.

* Restore a few unused methods and variables

* Address review comments

* Address most dotnet format whitespace warnings

* Add comments to disabled warnings

* Address IDE0251 warnings

* dotnet format whitespace after rebase

* Remove SuppressMessage attribute for removed rule
2023-06-25 18:37:09 +02:00
TSRBerry
bddb2a1483 [Ryujinx.Tests.Unicorn] Address dotnet-format issues (#5391)
* dotnet format style --severity info

Some changes were manually reverted.

* Restore a few unused methods and variables

* Address most dotnet format whitespace warnings

* Apply dotnet format whitespace formatting

A few of them have been manually reverted and the corresponding warning was silenced

* Add comments to disabled warnings

* Simplify properties and array initialization, Use const when possible, Remove trailing commas

* Revert "Simplify properties and array initialization, Use const when possible, Remove trailing commas"

This reverts commit 9462e4136c0a2100dc28b20cf9542e06790aa67e.

* dotnet format whitespace after rebase

* Final dotnet format pass and fix naming rule violations
2023-06-25 18:03:08 +02:00
Shihta Kuan
e3bacfa774 Set COMPlus_DefaultStackSize to 2M in macOS (#5349)
* Set COMPlus_DefaultStackSize to 2M in macOS

* Remove the custom thread stack size on Ryujinx.Ava
2023-06-25 14:49:53 +02:00
TSRBerry
7c2f07d124 [Ryujinx.Horizon.Common] Address dotnet-format issues (#5382)
* dotnet format style --severity info

Some changes were manually reverted.

* Address most dotnet format whitespace warnings

* Address IDE0251 warnings

* dotnet format whitespace after rebase
2023-06-25 13:40:37 +02:00
TSRBerry
ede5b3c324 [Ryujinx.Audio.Backends.SoundIo] Address dotnet-format issues (#5360)
* dotnet format style --severity info

Some changes were manually reverted.

* Address dotnet format CA1816 warnings

* Address dotnet format CA1401 warnings

* Address most dotnet format whitespace warnings

* Run dotnet format after rebase and remove unused usings

- analyzers
- style
- whitespace

* Simplify properties and array initialization, Use const when possible, Remove trailing commas

* Revert "Simplify properties and array initialization, Use const when possible, Remove trailing commas"

This reverts commit 9462e4136c0a2100dc28b20cf9542e06790aa67e.

* dotnet format whitespace after rebase

* Address review feedback
2023-06-25 02:15:56 +02:00
TSRBerry
df5be5812f [Ryujinx.Audio.Backends.OpenAL] Address dotnet-format issues (#5359)
* dotnet format style --severity info

Some changes were manually reverted.

* Restore a few unused methods and variables

* Address dotnet format CA1816 warnings

* Address most dotnet format whitespace warnings

* Simplify properties and array initialization, Use const when possible, Remove trailing commas

* Revert "Simplify properties and array initialization, Use const when possible, Remove trailing commas"

This reverts commit 9462e4136c0a2100dc28b20cf9542e06790aa67e.

* dotnet format whitespace after rebase
2023-06-25 01:29:40 +02:00
Marco Carvalho
bc392e55df Empty "case" clauses that fall through to the "default" should be omitted (#5353)
* Empty "case" clauses that fall through to the "default" should be omitted

* default throw exception

* format
2023-06-24 12:06:58 +00:00
Marco Carvalho
fffc3ed193 Mutable fields should not be "public static" (#5352) 2023-06-24 12:01:59 +00:00
TSRBerry
7d160e98fd MemoryManagement: Change return types for Commit/Decommit to void (#5325)
* Replace return type with void for Commit/Decommit

* Small cleanup
2023-06-24 02:46:04 +02:00
Marco Carvalho
bf96bc84a8 "Where" should be used before "OrderBy" (#5346) 2023-06-23 00:51:44 +00:00
Marco Carvalho
91e4caaa69 "StartsWith" and "EndsWith" overloads that take a "char" should be used instead of the ones that take a "string" (#5347) 2023-06-23 02:15:14 +02:00
Marco Carvalho
efbd29463d "Find" method should be used instead of the "FirstOrDefault" extension (#5344) 2023-06-23 01:42:23 +02:00
Marco Carvalho
7608cb37ab "Exists" method should be used instead of the "Any" extension (#5345) 2023-06-23 01:37:25 +02:00
Kurochi51
d604e98227 Fix regression introduced by 1.1.1733 on Intel GPUs (#5311)
* Fix regression introduced by 1.1733 on Intel iGPUs

* Should have actually figured the variable, oops.

* maybe something goes wrong here? honestly lost

* Shader cache bump
2023-06-22 21:35:06 +02:00
Marco Carvalho
58907e2c29 GetHashCode should not reference mutable fields (#5331) 2023-06-22 18:36:07 +02:00
Mary
649d372f7d misc: Implement address space size workarounds (#5191)
* misc: Implement address space size workarounds

This adds code to support userland with less than 39 bits of address
space available by testing reserving multiple sizes and reducing
guess address space when needed.

This is required for ARM64 support when the kernel is
configured to use 63..39 bits for kernel space.(meaning only 38 bits is available to userland)

* Address comments

* Fix 32 bits address space support and address more comments
2023-06-20 17:33:54 +02:00
gdkchan
f9a538bb0f Ensure shader local and shared memory sizes are not zero (#5321) 2023-06-17 16:28:27 -03:00
gdkchan
f92921a6d1 Implement Load/Store Local/Shared and Atomic shared using new instructions (#5241)
* Implement Load/Store Local/Shared and Atomic shared using new instructions

* Remove now unused code

* Fix base offset register overwrite

* Fix missing storage buffer set index when generating GLSL for Vulkan

* Shader cache version bump

* Remove more unused code

* Some PR feedback
2023-06-15 17:31:53 -03:00
Marco Carvalho
32d21ddf17 Inheritance list should not be redundant (#5230) 2023-06-15 03:54:27 +00:00
Marco Carvalho
82f90704a0 Blocks should be synchronized on read-only fields (#5212)
* Blocks should be synchronized on read-only fields

* more readonlys

* fix alignment

* more

* Update ISelfController.cs

* simplify new

* simplify new
2023-06-15 00:34:55 +00:00
dependabot[bot]
f978d3726a nuget: bump System.Management from 7.0.1 to 7.0.2 (#5302)
Bumps [System.Management](https://github.com/dotnet/runtime) from 7.0.1 to 7.0.2.
- [Release notes](https://github.com/dotnet/runtime/releases)
- [Commits](https://github.com/dotnet/runtime/compare/v7.0.1...v7.0.2)

---
updated-dependencies:
- dependency-name: System.Management
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-06-14 18:21:17 +02:00
Mary
6f28c4abad test: Make tests runnable on system without 4KiB page size (#5184)
* ARMeilleure: Do not hardcode 4KiB page size in JitCache

* test: Do not hardcode page size to 4KiB for Ryujinx.Tests.Memory.Tests

Fix running tests on Asahi Linux with 16KiB pages.

* test: Do not hardcode page size to 4KiB for Ryujinx.Tests.Cpu

Fix running tests on Asahi Linux.

Test runner still crash when trying to run all test suite.

* test: Do not hardcode page size to 4KiB for Ryujinx.Tests.Cpu

Fix somecrashes on Asahi Linux.

* test: Ignore Vshl test on ARM64 due to unicorn crashes

* test: Workaround hardcoded size on some tests

Change mapping of code and data in case of non 4KiB configuration.

* test: Make CpuTestT32Flow depends on code address

Fix failure with different page size.

* test: Disable CpuTestThumb.TestRandomTestCases when page size isn't 4KiB

The test data needs to be reevaluated to take different page size into account.

* Address gdkchan's comments
2023-06-14 18:02:41 +02:00
gdkchan
105c9712c1 Fix Arm32 double to int/uint conversion on Arm64 (#5292)
* Fix Arm32 double to int/uint conversion on Arm64

* PPTC version bump
2023-06-14 00:57:02 -03:00
Kurochi51
4d804ed45e Mod Loader: Stop loading mods from folders that don't exactly match titleId (#5298)
* Stop loading mods from folders that don't exactly match titleId

* What the worst that can happen?
2023-06-13 20:47:33 +02:00
Mary
4a27d29412 infra: Sync paths-ignore with release job and attempt to fix review assign 2023-06-13 11:51:22 +02:00
mmdurrant
5bd2c58ad6 UI: Correctly set 'shell/open/command; registry key for file associations (#5244)
* Correctly set 'shell/open/command; registry key for file associations

* File association fixes
* 'using' statements instead of blocks
* Idempotent unregistration
* Single "hey shell, we changed file associations" notification at the
  end instead of 1 for every operation, speeds things up greatly.

* Adapt and fix Linux specific function as well

---------

Co-authored-by: TSR Berry <20988865+TSRBerry@users.noreply.github.com>
2023-06-13 00:36:40 +00:00
gdkchan
cf4c78b9c8 Make LM skip instead of crashing for invalid messages (#5290) 2023-06-13 00:12:06 +00:00
TSRBerry
52aa4b6c22 Fix action version (#5299) 2023-06-12 21:57:07 +02:00
TSRBerry
5a02433080 infra: Fix PR triage workflow glob patterns (#5297)
* Use glob patterns to match file paths

* Update ignored paths for releases

* Adjust build.yml as well

* Add names to auto-assign steps

* Fix developer team name

* Allow build workflows to run if workflows changed
2023-06-12 18:42:27 +00:00
Steveice10
915a0f7173 hle: Stub IHidbusServer.GetBusHandle (#5284) 2023-06-12 17:33:13 +02:00
Mary
0cc266ff19 infra: Add PR triage action (#5293)
This is a bare minimal triage action that handle big categories.

In the future we could also label all services correctly but
I didn't felt this was required for a first iteration.
2023-06-12 12:29:41 +02:00
TSRBerry
9a1b74799d Ava: Fix OpenGL on Linux again (#5216)
* ava: Fix OpenGL on Linux again

This shouldn't be working like that, but for some reason it does.

* Apply the correct fix

* gtk: Add warning messages for caught exceptions

* ava: Handle disposing the same way as GTK does

* Address review feedback
2023-06-11 18:31:22 +02:00
Patrick Hovsepian
638f3761f3 Show/Hide UI Hotkey fix on Avalonia (#5133)
* fix show/hide ui for ava

* revert style

* unbound by default

* revert
2023-06-11 15:34:56 +02:00
gdkchan
193ca3c9a2 Implement fast path for AES crypto instructions on Arm64 (#5281)
* Implement fast path for AES crypto instructions on Arm64

* PPTC version bump

* Use AES HW feature check
2023-06-11 00:51:35 +00:00
gdkchan
eb0bb36bbf Implement transform feedback emulation for hardware without native support (#5080)
* Implement transform feedback emulation for hardware without native support

* Stop doing some useless buffer updates and account for non-zero base instance

* Reduce redundant updates even more

* Update descriptor init logic to account for ResourceLayout

* Fix transform feedback and storage buffers not being updated in some cases

* Shader cache version bump

* PR feedback

* SetInstancedDrawVertexCount must be always called after UpdateState

* Minor typo
2023-06-10 18:31:38 -03:00
Marco Carvalho
0e95a8271a Non-flags enums should not be used in bitwise operations (#5214) 2023-06-09 19:44:22 +02:00
Marco Carvalho
76b474e97b Update ShaderConfig.cs (#5226) 2023-06-09 14:53:20 +00:00
siegmund-heiss-ich
27ee86f33b Exclude macOS from checking for changed files (#5270) 2023-06-09 15:35:24 +02:00
siegmund-heiss-ich
f7ec310231 Check if existing oldConfigPath is a Symlink (#5271) 2023-06-09 15:31:19 +02:00
Marco Carvalho
e94d24f508 Prefer a 'TryGetValue' call over a Dictionary indexer access guarded by a 'ContainsKey' (#5231)
* Prefer a 'TryGetValue' call over a Dictionary indexer access guarded by a 'ContainsKey' check to avoid double lookup

* fix
2023-06-09 13:05:32 +02:00
Isaac Marovitz
2bf4555591 Swkbd Applet Fixes (#5236)
* Swkbd Applet Fixes

* Forgot a full stop

* Update src/Ryujinx.Ava/UI/Applet/SwkbdAppletDialog.axaml.cs

Co-authored-by: Ac_K <Acoustik666@gmail.com>

* Update src/Ryujinx/Ui/Applet/SwkbdAppletDialog.cs

Co-authored-by: Ac_K <Acoustik666@gmail.com>

---------

Co-authored-by: Ac_K <Acoustik666@gmail.com>
2023-06-09 12:11:53 +02:00
Marco Carvalho
86de288142 Removing shift by 0 (#5249)
* Integral numbers should not be shifted by zero or more than their number of bits-1

* more
2023-06-09 11:23:44 +02:00
dependabot[bot]
f35aa8e9d6 nuget: bump Microsoft.NET.Test.Sdk from 17.6.1 to 17.6.2 (#5250)
Bumps [Microsoft.NET.Test.Sdk](https://github.com/microsoft/vstest) from 17.6.1 to 17.6.2.
- [Release notes](https://github.com/microsoft/vstest/releases)
- [Changelog](https://github.com/microsoft/vstest/blob/main/docs/releases.md)
- [Commits](https://github.com/microsoft/vstest/compare/v17.6.1...v17.6.2)

---
updated-dependencies:
- dependency-name: Microsoft.NET.Test.Sdk
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-06-09 11:02:56 +02:00
dependabot[bot]
0e8e735a6d nuget: bump System.IdentityModel.Tokens.Jwt from 6.30.1 to 6.31.0 (#5265)
Bumps [System.IdentityModel.Tokens.Jwt](https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet) from 6.30.1 to 6.31.0.
- [Release notes](https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/releases)
- [Changelog](https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/blob/dev/CHANGELOG.md)
- [Commits](https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/compare/6.30.1...6.31.0)

---
updated-dependencies:
- dependency-name: System.IdentityModel.Tokens.Jwt
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-06-09 10:40:25 +02:00
riperiperi
0003a7c118 Vulkan: Use aspect flags for identity views for bindings (#5267) 2023-06-08 20:23:36 -03:00
gdkchan
2cdcfe46d8 Remove barrier on Intel if control flow is potentially divergent (#5044)
* Remove barrier on Intel if control flow is potentially divergent

* Shader cache version bump
2023-06-08 17:43:16 -03:00
gdkchan
fe30c03cac Implement soft float64 conversion on shaders when host has no support (#5159)
* Implement soft float64 conversion on shaders when host has no support

* Shader cache version bump

* Fix rebase error
2023-06-08 17:09:14 -03:00
Kurochi51
5813b2e354 Updater: Ignore files introduced by the user in base directory (#5092)
* Updater: Ignore files introduced by the user in base directory

* Replicate logic in Avalonia version.

* Address requested changes

* Updater: Ignore files introduced by the user in base directory

* Replicate logic in Avalonia version.

* Address requested changes

* Address requested changes

* Address requested changes

* Comment cleanup

* Address feedback

* Forgot comment, tehe
2023-06-05 14:19:17 +02:00
gdkchan
af1906ea04 Fix wrong unaligned SB state when fetching compute shaders (#5223) 2023-06-05 14:01:33 +02:00
riperiperi
68848000f7 Texture: Fix 3D texture size when totalBlocksOfGobsInZ > 1 (#5228)
* Texture: Fix 3D texture size when totalBlocksOfGobsInZ > 0

When there is a remainder when dividing depth by gobs in z, it is used to remove the unused part of the 3D texture's size. This was done to calculate correct sizes for single slice views of 3D textures.

However, this case can also apply to 3D textures with many slices, and more than one total block of gobs in z. In this case it's meant to trim off the end of the level size. Most textures won't encounter this as their size will be aligned, but UE4 games tend to use 3D textures with funny unaligned sizes.

The size offset should have been applied to the level size instead of the slice size, and it should only affect the slice size if it ends up larger.

Hopefully should fix issues with UE4 games without breaking other stuff, I don't have much time to test.

* Whoops
2023-06-05 13:33:09 +02:00
Théo Arrouye
d98da47a0f Better application grid flex (#5218) 2023-06-05 00:48:11 +00:00
Isaac Marovitz
306f7e93a0 Dont Error on Invalid Enum Values (#5169)
* Dont Error on Invalid Enum

* Use TryParse

* Log warning
2023-06-05 01:19:46 +02:00
Marco Carvalho
8954ff3af2 Replacing ZbcColorArray with Array4<uint> (#5210)
* Related "if/else if" statements should not have the same condition

* replacing ZbcColorArray with Array4<uint>

* fix alignment
2023-06-04 20:30:04 +00:00
riperiperi
d2f3adbf69 Texture: Fix layout conversion when gobs in z is used with depth = 1 (#5220)
* Texture: Fix layout conversion when gobs in z is used with depth = 1

The size calculator methods deliberately reduce the gob size of textures if they are deemed too small for it. This is required to get correct sizes when iterating mip levels of a texture.

Rendering to a slice of a 3D texture can produce a 3D texture with depth 1, but a gob size matching a much larger texture. We _can't_ "correct" this gob size, as it is intended as a slice of a larger 3D texture. Ignoring it causes layout conversion to break on read and flush.

This caused an issue in Tears of the Kingdom where the compressed 3D texture used for the gloom would always break on OpenGL, and seemingly randomly break on Vulkan. In the first case, the data is forcibly flushed to decompress the BC4 texture on the CPU to upload it as 3D, which was broken due to the incorrect layout. In the second, the data may be randomly flushed if it falls out of the cache, but it will appear correct if it's able to form copy dependencies.

This change only allows gob sizes to be reduced once per mip level. For the purpose of aligned size, it can still be reduced infinitely as our texture cache isn't properly able to handle a view being _misaligned_.

The SizeCalculator has also been changed to reduce the size of rendered depth slices to only include the exact range a single depth slice will cover. (before, the size was way too small with gobs in z reduced to 1, and too large when using the correct value)

Gobs in Y logic remains untouched, we don't support Y slices of textures so it's fine as is.

This is probably worth testing in a few games as it also affects texture size and view logic.

* Improve wording

* Maybe a bit better
2023-06-04 20:25:57 +00:00
WilliamWsyHK
d511c845b7 Check KeyboardMode in GUI (#4343)
* Update SoftwareKeyboard to send KeyboardMode to UI

* Update GTK UI to check text against KeyboardMode

* Update Ava UI to check text against KeyboardMode

* Restructure input validation

* true when text is not empty

* Add English validation text for SoftwareKeyboardMode

* Add Chinese validation text for SoftwareKeyboardMode

* Update base on feedback

---------

Co-authored-by: TSR Berry <20988865+TSRBerry@users.noreply.github.com>
2023-06-04 05:30:24 +02:00
gdkchan
21c9ac6240 Implement shader storage buffer operations using new Load/Store instructions (#4993)
* Implement storage buffer operations using new Load/Store instruction

* Extend GenerateMultiTargetStorageOp to also match access with constant offset, and log and comments

* Remove now unused code

* Catch more complex cases of global memory usage

* Shader cache version bump

* Extend global access elimination to work with more shared memory cases

* Change alignment requirement from 16 bytes to 8 bytes, handle cases where we need more than 16 storage buffers

* Tweak preferencing to catch more cases

* Enable CB0 elimination even when host storage buffer alignment is > 16 (for Intel)

* Fix storage buffer bindings

* Simplify some code

* Shader cache version bump

* Fix typo

* Extend global memory elimination to handle shared memory with multiple possible offsets and local memory
2023-06-03 20:12:18 -03:00
Ac_K
81c9052847 ava: Fix Input Touch (#5204) 2023-06-03 16:03:42 +01:00
Ac_K
9367e3c35d ava: Fix Open Applet menu enabled (#5206)
Currently, the `Open Applet` menu is still enabled when a guest is running, which is wrong. This is not fixed by refreshing the property binding on `IsEnabled`.
2023-06-03 11:03:34 +02:00
Mary
52cf141874 Armeilleure: Fix support for Windows on ARM64 (#5202)
* Armeilleure: Fix support for Windows on ARM64

Tested on Windows DevKit 2023.

* Address gdkchan's comments
2023-06-03 10:23:51 +02:00
gdkchan
8a352df3c6 Allow BGRA images on Vulkan (#5203) 2023-06-03 03:43:00 +00:00
Ac_K
c545c59851 ava: Fix exit dialog while guest is running. (#5207)
* ava: Fix exit dialog while guest is running.

There is currently an issue while a game runs, the content dialog creation method check if `IsGameRunning` is true to show the popup.
But the condition here is wrong (`window` is null) so it throw a NullException silently in `Dispatcher.UIThread`.
This is now fixed by using the right casting.

* improve condition

* Fix spacing
2023-06-03 03:37:00 +00:00
dependabot[bot]
96ea4e8c8e nuget: bump Microsoft.NET.Test.Sdk from 17.6.0 to 17.6.1 (#5192)
Bumps [Microsoft.NET.Test.Sdk](https://github.com/microsoft/vstest) from 17.6.0 to 17.6.1.
- [Release notes](https://github.com/microsoft/vstest/releases)
- [Changelog](https://github.com/microsoft/vstest/blob/main/docs/releases.md)
- [Commits](https://github.com/microsoft/vstest/compare/v17.6.0...v17.6.1)

---
updated-dependencies:
- dependency-name: Microsoft.NET.Test.Sdk
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-06-01 21:03:00 +02:00
Ac_K
b8f48bcf64 UI: Fix empty homebrew icon (#5189)
* UI: Fix empty homebrew icon

We currently don't check the icon size when we read it from the homebrew data. That could cause issues at UI side since the buffer isn't null but empty. Extra check have been added UI side too.
(I cleaned up some files during my research too)

Fixes #5188

* Remove additional check

* Remove unused using
2023-06-01 18:24:00 +02:00
Théo Arrouye
6966211e07 Give Library header DockPanel explicit height (#5160) 2023-06-01 17:40:44 +02:00
ExE Boss
57524a4c8a Add issue template for missing shader instructions (#5048)
* Add issue template for missing shader instructions

* fixup! Add issue template for missing shader instructions

* Update .github/ISSUE_TEMPLATE/missing_shader_instruction.yml

---------

Co-authored-by: Ac_K <Acoustik666@gmail.com>
2023-06-01 17:32:38 +02:00
TSRBerry
f4539c49d8 [Logger] Add print with stacktrace method (#5129)
* Add print with stacktrace method

* Adjust logging namespaces

* Add static keyword to DynamicObjectFormatter
2023-06-01 13:47:53 +00:00
dependabot[bot]
12c62fdbc2 nuget: bump DynamicData from 7.13.8 to 7.14.2 (#5148)
Bumps [DynamicData](https://github.com/reactiveui/DynamicData) from 7.13.8 to 7.14.2.
- [Release notes](https://github.com/reactiveui/DynamicData/releases)
- [Changelog](https://github.com/reactivemarbles/DynamicData/blob/main/ReleaseNotes.md)
- [Commits](https://github.com/reactiveui/DynamicData/compare/7.13.8...7.14.2)

---
updated-dependencies:
- dependency-name: DynamicData
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-06-01 13:35:04 +00:00
TSRBerry
e3c6be5e29 Only run one workflow for a PR at a time (#5137) 2023-06-01 09:42:49 +02:00
riperiperi
4741a05df9 Vulkan: Include DepthMode in ProgramPipelineState (#5185) 2023-06-01 09:05:39 +02:00
riperiperi
c6676007bf GPU: Dispose Renderer after running deferred actions (#5144)
* GAL: Dispose Renderer after running deferred actions

Deferred actions from disposing physical memory instances always dispose the resources in their caches. The renderer can't be disposed before these resources get disposed, otherwise the dispose actions will not actually run, and the ThreadedRenderer may get stuck trying to enqueue too many commands when there is nothing consuming them.

This should fix most instances of the emulator freezing on close.

* Wait for main render commands to finish, but keep RenderThread alive til dispose

* Address some feedback.

* No parameterize needed

* Set thread name as part of constructor

* Port to Ava and SDL2
2023-05-31 21:43:20 +00:00
yell0wsuit
92b0b7d753 Avalonia UI: Fix letter "x" in Ryujinx logo being cut off (#5176)
Also make the pronunciation center-aligned
2023-05-31 21:03:11 +00:00
gdkchan
232237bf28 Skip draws with zero vertex count (#5149) 2023-05-31 17:51:11 -03:00
gdkchan
c27e453fd3 Share ResourceManager vertex vertex A and B shaders (#5181) 2023-05-31 17:17:50 -03:00
Isaac Marovitz
0e037d0213 macOS Headless Fixes (#5167)
* Default hypervisor to disabled

* Include MVK on macOS

* Properly sign headless builds on macOS

* Force Vulkan on macOS

* Suggestions
2023-05-31 09:08:50 +02:00
Patrick Hovsepian
0dca1fbe12 Add Context Menu Option to Run Application (#5154) 2023-05-30 19:51:03 +01:00
TSRBerry
35d91a0e58 Linux: Automatically increase vm.max_map_count if it's too low (#4702)
* memory: Check results of pinvoke calls

* Increase vm.max_map_count when running Ryujinx

* Add SupportedOSPlatform attribute for WindowsApiException

* Revert increasing vm.max_map_count via script

* Add LinuxHelper to detect and increase vm.max_map_count

With GUI dialogs, this should be a bit more user-friendly.

* Supply arguments as a list to RunPkExec

* Add error logging in case RunPkExec() fails

* Prevent Gtk from crashing
2023-05-30 01:48:37 +02:00
dependabot[bot]
a73a5d7e85 nuget: bump Microsoft.NET.Test.Sdk from 17.5.0 to 17.6.0 (#4986)
Bumps [Microsoft.NET.Test.Sdk](https://github.com/microsoft/vstest) from 17.5.0 to 17.6.0.
- [Release notes](https://github.com/microsoft/vstest/releases)
- [Changelog](https://github.com/microsoft/vstest/blob/main/docs/releases.md)
- [Commits](https://github.com/microsoft/vstest/compare/v17.5.0...v17.6.0)

---
updated-dependencies:
- dependency-name: Microsoft.NET.Test.Sdk
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-05-29 01:14:07 +02:00
gdkchan
832a5e8852 Make sure blend is disabled if render target has integer format (#5122)
* Make sure blend is disabled if render target has integer format

* Change approach to avoid permanently mutating state
2023-05-29 00:38:04 +02:00
gdkchan
96d1f0da2d Workaround for MoltenVK barrier issues (#5118) 2023-05-29 00:24:35 +02:00
gdkchan
597388ecda Fix incorrect vertex attribute format change (#5112)
* Fix incorrect vertex attribute format change

* Only change vertex format if the host supports the new format
2023-05-29 00:17:07 +02:00
Simon Wegendt
1cf6d7b7bb Fix #5108: Allow surround sound for SDL2 in more scenarios (#5131) 2023-05-29 00:07:27 +02:00
subanz
7bc9d0cdad Linux: Use gamemode if it is available when using Ryujinx.sh. (#4938)
* Linux: Detect if gamemode is installed and start it when launching Ryujinx.

When using the Ryujinx.sh script to start the emulator check if gamemoderun exists and use it if it does.

Gamemode mode on Linux changes some system settings to make performance during gaming more consistent mainly by changing the CPU governor to performance.

https://github.com/FeralInteractive/gamemode

* Removed if statement.

* Fix due to wrong assumption about the output of which.

Checks if the which output contains a no match response, otherwise use gamemoderun.

Using a case statement because it makes substring matching possible in sh and also it turns out that adding an empty string after env throws an error because env attempts to parse it as a paramater.

* Missed a couple semicolons.

* Different approach for checking if gamemode is available.

Should hopefully work across all implementations of which.

* Remove unneeded which command.

* Change code to keep launch command to a single line.
2023-05-28 23:54:22 +02:00
cstamford
dc0dbc50ab Add support for VK_EXT_depth_clip_control. (#5027)
* Add support for VK_EXT_depth_clip_control.

* Code review feedback

Minor formatting

Co-authored-by: gdkchan <gab.dark.100@gmail.com>

* Check .DepthClipControl to make sure the host actually supports the feature.

* Review feedback: remove Vulkan platform switch, relying on QueryHostSupportsDepthClipControl to drive the behaviour - OpenGL returns true, and any future platforms that don't support the [-1, 1] depth mode can return false for the transformation.

---------

Co-authored-by: gdkchan <gab.dark.100@gmail.com>
2023-05-28 23:31:56 +02:00
Mary
994f4dc77d chore: Update Avalonia to 0.10.21 (#5124) 2023-05-28 23:25:55 +02:00
yell0wsuit
c9e297b74c About window: Add changelog link under ver. number (#5095) 2023-05-28 23:13:40 +02:00
Théo Arrouye
dd514a115c Update LastPlayed date on emulation end. (#5056) 2023-05-28 23:03:27 +02:00
siegmund-heiss-ich
7e0b4bd538 Improve macOS updater (#5064)
* Fix macOS Updater (once again)

* Also fix my brain's issues

* Move set -e that lsof doesn't trigger exit 1

* Resolve yesterdays brain malfunction 2

* Revert "Move set -e that lsof doesn't trigger exit 1"

This reverts commit 589a630610.

* Also check if PID exists

* Remove lsof and instead check for running processes

* Remove empty lines

* Increase max iterations

* Address feedback

* Remove obsolete check for child processes

* Update comments

* Update comments

* I swear this is the last commit

* lsof + ps check
2023-05-28 22:54:30 +02:00
Daniel Shala
378080eb87 Added Custom Path case when saving screenshots (#5086) 2023-05-28 22:44:46 +02:00
Mary
e8f5e97fa4 actions: revert timeout-minutes changes for PR workflow
Varibales aren't exposed to PRs...
2023-05-28 11:34:57 +02:00
Mary
f3873620a3 actions: Workaround YAML limitation for timeout-minutes
Because Github Actions wants an int, we use fromJSON to hack around
this.
2023-05-28 08:10:43 +02:00
TSRBerry
986ac9ff83 Use variables to configure job timeouts (#5123) 2023-05-28 08:02:30 +02:00
jhorv
42b9c1e8fe Ryujinx.Ava: fixes for random hangs on exit (#4827)
* Attempt at fixing hang on exit by ending the WindowNotificationManager notification loop, so that the Thread running it can exit.

* explicitly apply the NotificationManager template to allow the notification loop to begin

* NotificationHelper - remove explicity call to ApplyTemplate(). Change to ManualResetEventSlim so we can cancel the Wait on it.

* add a timeout to AudioRenderSystem.Stop()'s waiting for the termination signal, log a warning if this timeout occurs, and continue execution

* NotifiationHelper - cancel first, the CompleteAdding()

* Remove AudioRenderSystem._terminationEvent, redundant

* NotificationHelper - use host.Closing event to trigger cancellation instead of _notifationManager.DetachedFromLogicalTree

* Change NotificationHelper to use an explicit Thread for background work.  Wait on the cancellationToken's WaitHandle so the Thread doesn't have to deal with async. Wrap foreach in try/catch (OperationCanceledException) to swallow the escaping exception from the GetConsumingEnumerable().

* adjust formatting of AsyncWorkQueue constructor to use object initializers consistently

* use AsyncWorkQueue to do everything I added in SetNotificationManager()

* Revert "use AsyncWorkQueue to do everything I added in SetNotificationManager()"

This reverts commit f0e78366b8776ec8e2fef8ab023c0db1833155d3.

* use AsyncWorkQueue to handle the Thread-related changes previously made to NotificationHelper.SetNotificationHelper(). Wrap it in Lazy<T> and force instantiation in the TemplateApplied event handler to accomodate for the fact that AsyncWorkQueue starts immediately, and the notification dispatch loop was being delayed by _templateAppliedEvent.

* impl changes suggested by AcK77

* impl changes suggested by AcK77 (more)
2023-05-26 23:57:43 +02:00
gdkchan
3b375525fb Force reciprocal operation with value biased by constant to be precise on macOS (#5110)
* Force operations to be precise in some cases on SPIR-V

* Make it a bit more strict, add comments

* Shader cache version bump
2023-05-26 15:19:37 -03:00
gdkchan
e6658c133c Fix resolution scaling of image operation coordinates (#5102)
* Fix resolution scaling of image operation coordinates

* Shader cache version bump
2023-05-25 23:42:49 -03:00
TSRBerry
5b42a4d2c4 Fix mod names (#5088) 2023-05-25 23:41:03 +02:00
gdkchan
8f0c89ffd6 Generate scaling helper functions on IR (#4714)
* Generate scaling helper functions on IR

* Delete unused code

* Split RewriteTextureSample and move gather bias add to an earlier pass

* Remove using

* Shader cache version bump
2023-05-25 17:46:58 -03:00
gdkchan
2c9715acf6 Truncate vertex attribute format if it exceeds stride on MoltenVK (#5094)
* Truncate vertex attribute format if it exceeds stride on MoltenVK

* Fix BGR format

* Move vertex attribute check to pipeline creation to avoid costs

* No need for this to be public
2023-05-25 17:03:51 -03:00
Isaac Marovitz
274af65f69 Update release.yml (#5058) 2023-05-25 16:17:37 +02:00
gdkchan
4ca78eded5 Vulkan: Do not set storage flag for multisample textures if not supported (#5060) 2023-05-23 10:41:37 +02:00
makigumo
6cb6b15612 Implement p2rc, p2ri, p2rr and r2p.cc shaders (#5031)
* implement P2rC, P2rI, P2rR shaders

* implement R2p.CC shader

* bump CodeGenVersion

* address feedback
2023-05-22 17:32:15 -03:00
gdkchan
2725e40838 Revert "Bump MVK Version (#5057)" (#5061)
This reverts commit c2e4c8f98e.
2023-05-22 17:12:11 -03:00
Isaac Marovitz
c2e4c8f98e Bump MVK Version (#5057) 2023-05-22 14:41:08 -03:00
Isaac Marovitz
b53e7ffd46 Ava UI: Input Menu Redesign (#4990)
* Cleanup

* Remove redundant locales

* Start SVG Fixes…

Better +/- buttons

Fix the grips

Bumpers

Better directional pad

More SVG stuff

Grip adjustments

Final stuff

* Make image bigger

* Border radius

* More cleanup

* Restructure

* Restructure Rumble View

* Use compiled bindings where possible

* Round those pesky corners

* Ack Suggestions

* More suggestions

* Update src/Ryujinx.Ava/UI/Views/Input/RumbleInputView.axaml.cs

Co-authored-by: Ac_K <Acoustik666@gmail.com>

---------

Co-authored-by: Ac_K <Acoustik666@gmail.com>
2023-05-22 01:16:20 +02:00
jhorv
ac66643346 Fix crash in SettingsViewModel when Vulkan isn't available (#4985)
* fix crash when Vulkan isn't available

* add VulkanRenderer.GetPhysicalDevices() overload that provides its own Vk API object and logs on failure

* adjustments per AcK77
2023-05-21 21:39:06 +02:00
jhorv
21e88f17f6 ServerBase thread safety (#4577)
* Add guard against ServerBase.Dispose() being called multiple times. Add reset event to avoid Dispose() being called while the ServerLoop is still running.

* remove unused usings

* rework ServerBase to use one collection each for sessions and ports, and make all accesses thread-safe.

* fix Logger call

* use GetSessionObj(int) instead of using _sessions directly

* move _threadStopped check inside "dispose once" test

* - Replace _threadStopped event with attempt to Join() the ending thread (if that isn't the current thread) instead.

- Use the instance-local _selfProcess and (new) _selfThread variables to avoid suggesting that the current KProcess and KThread could change. Per gdkchan, they can't currently, and this old IPC system will be removed before that changes.

- Re-order Dispose() so that the Interlocked _isDisposed check is the last check before disposing, to increase the likelihood that multiple callers will result in one of them succeeding.

* code style suggestions per AcK77

* add infinite wait for thread termination
2023-05-21 21:28:51 +02:00
gdkchan
5626f2ca1c Replace ShaderBindings with new ResourceLayout structure for Vulkan (#5025)
* Introduce ResourceLayout

* Part 1: Use new ResourceSegments array on UpdateAndBind

* Part 2: Use ResourceLayout to build PipelineLayout

* Delete old code

* XML docs

* Fix shader cache load NRE

* Fix typo
2023-05-21 14:04:21 -03:00
gdkchan
402f05b8ef Replace constant buffer access on shader with new Load instruction (#4646) 2023-05-20 16:19:26 -03:00
gdkchan
fb27042e01 Limit compute storage buffer size (#5028) 2023-05-20 16:15:07 +00:00
riperiperi
69a9de33d3 SPIR-V: Only allow implicit LOD sampling on fragment (#5026) 2023-05-20 15:52:26 +02:00
Isaac Marovitz
bba51c2eeb Fix macOS Update Script (#5014)
* Update updater.sh

* Better script

* Revert "Better script"

This reverts commit 9bf6be863892e5e10c2f2dba45f1d0a60daca688.
2023-05-19 21:20:01 +02:00
gdkchan
fc26189fe1 Eliminate redundant multiplications by gl_FragCoord.w on the shader (#4578)
* Eliminate redundant multiplications by gl_FragCoord.w on the shader

* Shader cache version bump
2023-05-19 11:52:31 -03:00
dependabot[bot]
a40c90e7dd nuget: bump DynamicData from 7.13.5 to 7.13.8 (#5001)
Bumps [DynamicData](https://github.com/reactiveui/DynamicData) from 7.13.5 to 7.13.8.
- [Release notes](https://github.com/reactiveui/DynamicData/releases)
- [Changelog](https://github.com/reactivemarbles/DynamicData/blob/main/ReleaseNotes.md)
- [Commits](https://github.com/reactiveui/DynamicData/compare/7.13.5...7.13.8)

---
updated-dependencies:
- dependency-name: DynamicData
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-05-19 06:52:44 +02:00
gdkchan
f864a49014 Fix Vulkan blit-like operations swizzle (#5003) 2023-05-18 18:16:03 -03:00
riperiperi
ecbf303266 GPU: Avoid using garbage size for non-cb0 storage buffers (#4999)
* GPU: Avoid using garbage size for non-cb0 storage buffers

In the depths area, Tears of the Kingdom uses a global memory access with address on constant buffer slot 6. This isn't standard and thus doesn't actually have a size 8 bytes after it, so we were reading back a garbage size that ended up very large (at least in version 1.1.0), and would synchronize a lot of data per frame.

This PR makes storage buffers created from addresses outside constant buffer slot 0 get their size as the number of bytes remaining in the GPU mapping starting at the given virtual address. This should bound the buffer to a reasonable size, and ideally stop it crossing into other memory.

* Limit max size

* Add TODO

* Feedback
2023-05-18 08:56:34 +02:00
Mary
b3bf05356b ava: Fix crash when extracting sections from NCA with no data section (#5002)
Tested against Omega Strickers.
2023-05-17 19:27:49 +00:00
OpaqueReptile
cb4b58052f Start GPU performance counter at 0 instead of host GPU value (#4992)
* Start performance counter at 0 instead of host perf counter value

* whitespace

* init _firstTimestamp in constructer per feedback

* change comment

* punctuation

* address feedback

* revise comment
2023-05-17 15:38:59 -03:00
Mary
f8cdd5f484 macos: Fix relaunch with updater when no arguments were provided to the emulator (#4987)
The updater still seems to be erroring when replacing installed folder under normal operations.
2023-05-17 19:02:15 +02:00
TSRBerry
22202be394 [GUI] Fix always hide cursor mode not hiding the cursor until it was moved (#4927)
* gtk: Add missing isMouseInClient check for hide-cursor

* ava: Add missing events and default isCursorInRenderer to true

This is necessary because we don't receive a initial PointerEnter event for some reason.
2023-05-14 16:34:31 +02:00
riperiperi
17ba217940 Vulkan: Device map buffers written more than flushed (#4911) 2023-05-13 15:15:05 +02:00
TSRBerry
aae4595bdb Add timeout of 35 minutes to workflow jobs (#4928) 2023-05-13 13:24:43 +02:00
Mary
880fd3cfcb audio: sdl2: Do not report 5.1 if the device doesn't support it (#4908)
* amadeus: adjust VirtualDevice channel configuration reporting with HardwareDevice

* audio: sdl2: Do not report 5.1 if device doesn't support it

SDL2 5.1 to Stereo conversion is terrible and make everything sound
quiet.

Let's not expose 5.1 if not truly supported by the device.
2023-05-13 07:15:16 +00:00
gdkchan
f679f25e08 Set OpenGL PixelPackBuffer to 0 when done (#4921) 2023-05-13 00:59:46 +00:00
Isaac Marovitz
c2709b3bdd macOS CI Adjustments (#4910)
* Fix macOS build name in CI

Fixes updater

* Update build.yml

Don't publish x86 Mac builds

* Naming nitpick

* Berry changes

* Use the same prefix for PR and release build archives

---------

Co-authored-by: TSR Berry <20988865+TSRBerry@users.noreply.github.com>
2023-05-13 00:53:52 +02:00
Ac_K
2b6e81deea Ava: Fix wrong MouseButton (#4900) 2023-05-12 21:39:42 +02:00
Mary
7271f1b18e Bump shader cache codegen version
That was missing from #4892
2023-05-12 18:53:14 +02:00
riperiperi
5fda543f84 Vulkan: Partially workaround MoltenVK InvalidResource error (#4880)
* Add MVK stage flags workaround

* Actually do the workaround

* Remove GS on VS stuff

* Address feedback
2023-05-11 22:06:15 -03:00
riperiperi
95c06de4c1 GPU: Remove swizzle undefined matching and rework depth aliasing (#4896)
* GPU: Remove swizzle undefined matching and rework depth aliasing

@gdkchan pointed out that UI textures in TOTK seemed to be setting their texture swizzle incorrectly (texture was RGB but was sampling A, swizzle for A was wrong), so I determined that SwizzleComponentMatches was the problem and set on eliminating it. This PR combines existing work to select the most recently modified texture (now used when selecting which aliased texture to use) with some additional changes to remove the swizzle check and support aliased view creation.

The original observation (#1538) was that we wanted to match depth textures for the purposes of aliasing with color textures, but they often had different swizzle from what was sampled (as it's generally the identity swizzle once rendered). At the time, I decided to allow swizzles to match if only the defined components matched, which fixed the issue in all known cases but could easily be broken by a game _expecting_ a given swizzle, such as a 1/0 value on a component.

This error case could also occur in textures that don't even depth alias, such as R11G11B10, as the rule was created to generally apply to all cases.

The solution is now to fail this exact match test, and allow the search for an R32 texture to create a swizzled view of a D32 texture (and other such cases). This allows the creation of a view that mismatches the requested format, which wasn't present before and was the reason for the swizzle matching approach.

The exact match and view creation rules now follow the same rules over what textures to select when there are multiple options (such as a "perfect" match and an "aliased" match at the same time). It now selects the most recently modified texture, which is done with a new sequence number in the GpuContext (because we don't have enough of these).

Reportedly fixes UI having weird coloured backgrounds in TOTK. This also fixes an issue in MK8D where returning from a race resulted in the character selection cubemaps being broken. May work around issues introduced by the "short texture cache" PR due to modification ordering, though they won't be truly fixed.

Should allow (#4365) to avoid copies in more cases. Need to test that.

I tested a bunch of games #1538 originally affected and they seem to be fine. This change affects all games so it would be good to get some wide testing on it.

* Address feedback 1, fix an issue

* Workaround: Do not allow copies for format alias.

These should be removed when D32<->R32 copy dependencies become legal
2023-05-11 21:30:47 -03:00
John
49c63ea077 Fix the restart after an update. (#4869)
* Fix the restart after an update.

* Fix the updater for the Ava UI too.

* Fixing up the code after some change requests.
Removed a line of code that was accidentally left in.

* Fix restarting on Linux Avalonia.

* Fix issues with escaped arguments.
2023-05-12 02:14:29 +02:00
SamusAranX
531da8a1c0 Changed LastPlayed field from string to nullable DateTime (#4861)
* Changed LastPlayed field from string to nullable DateTime

Added ApplicationData.LastPlayedString property
Added NullableDateTimeConverter for the DateTime->string conversion in Avalonia

* Added migration from string-based last_played to DateTime-based last_played_utc

* Updated comment style

* Added MarkupExtension to NullableDateTimeConverter and changed its usage

Cleaned up leftover usings

* Missed one comment
2023-05-12 01:56:37 +02:00
Mary
5cbdfbc7a4 amadeus: Allow 5.1 sink output (#4894)
* amadeus: Allow 5.1 sink output

Also add a simple Stereo to 5.1 change for device sink.

Tested against NES - Nintendo Switch Online that output stereo on the
audio renderer.

* Remove outdated comment
2023-05-12 00:19:19 +02:00
Nico
e0544dd9c7 UI: Adjust input mapping view (#4866)
* refactor: clean up controller settings ui

- Remove inconsistencies between left and right side
- Use style to set ToggleButton properties (since they are all the same)
- Move topmost controller settings from one line to 2x2 grid for improved clarity
- Properly adjust borders, text widths, etc. to neighboring elements to eliminate misaligned visual lines

* fix: merge issues

* fix: prevent sliders from jumping by giving text block fixed width

* refactor: add more separators and increase margin

* refactor: center deadzone and range descriptions

* refactor: move rumble border top margin to -1 and prevent double border

* refactor: remove margins & double borders + switch profile & input selection

* style: apply suggestions from code review

Co-authored-by: Ac_K <Acoustik666@gmail.com>

---------

Co-authored-by: Ac_K <Acoustik666@gmail.com>
2023-05-11 21:10:57 +00:00
dependabot[bot]
aa784c3e5e nuget: bump System.IdentityModel.Tokens.Jwt from 6.30.0 to 6.30.1 (#4886)
Bumps [System.IdentityModel.Tokens.Jwt](https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet) from 6.30.0 to 6.30.1.
- [Release notes](https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/releases)
- [Changelog](https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/blob/dev/CHANGELOG.md)
- [Commits](https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/compare/6.30.0...6.30.1)

---
updated-dependencies:
- dependency-name: System.IdentityModel.Tokens.Jwt
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-05-11 21:42:46 +02:00
gdkchan
9205077590 Enable explicit LOD for array textures with depth compare on SPIR-V (#4892) 2023-05-11 21:35:36 +02:00
gdkchan
0ed40c7175 Fix incorrect ASTC endpoint color when using LuminanceDelta mode (#4890) 2023-05-11 20:47:55 +02:00
Mary
40d47b7aa2 amadeus: Fix wrong channel mapping check and an old typo (#4888)
* amadeus: Fix wrong channel mapping check

This was always going to happens, as a result quadratic would break and
move index after the channel count point, effectively breaking
input/output indices.

* amadeus: Fix reverb 3d early delay wrong output index
2023-05-11 20:14:02 +02:00
John
ec0bb74968 Stop SDL from inhibiting sleep. (#4842) 2023-05-11 20:13:01 +02:00
2435043xia
42f7f98666 Fix the issue of unequal check for amiibo file date due to the lack o… (#4832)
* Fix the issue of unequal check for amiibo file date due to the lack of sub-second units in the header, causing slow opening of the amiibo interface.

* Supplement the unrepaired.
2023-05-11 19:10:24 +02:00
riperiperi
95bad6995c GPU: Fix shader cache assuming past shader data was mapped (#4885)
This fixes a potential issue where a shader lookup could match the address of a previous _different_ shader, but that shader is now partially unmapped. This would just crash with an invalid region exception.

To compare a shader in the address cache with one in memory, we get the memory at the location with the previous shader's size. However, it's possible it has been unmapped and then remapped with a smaller size. In this case, we should just get back the mapped portion of the shader, which will then fail the comparison immediately and get to compile/lookup for the new one.

This might fix a random crash in TOTK that was reported by Piplup. I don't know if it does, because I don't have the game yet.
2023-05-11 18:41:34 +02:00
Mary
3d42995822 Attempt to fix release.yml after merge 2023-05-11 17:42:33 +02:00
TSRBerry
9095941fd1 Update release workflow & Add jobs for macOS (#4837)
* Add build config and extra args to create_macos_build.sh

* Use matrix strategy for releases

* Add macOS jobs

Co-authored-by: Mary <thog@protonmail.com>

* Fix wrong version argument

* Fix check for the correct amount of args

* Install latest rcodesign release

Co-authored-by: Mary <thog@protonmail.com>

* Set executable bits for PR builds on linux

---------

Co-authored-by: Mary <thog@protonmail.com>
2023-05-11 17:36:53 +02:00
gdkchan
ba71141bdc Ensure background translation threads exited before disposing JIT (#4874) 2023-05-10 21:46:38 -03:00
gdkchan
0a0675a7f6 Fix missing domain service object dispose (#4879) 2023-05-11 00:29:17 +00:00
Aaron O'Mullan
a7c6e6a8cf fix(mvk): resumeLostDevice (#4800)
Command buffer errors currently trigger an exception "DeviceLost" crashing the process.

Looking at [MKV's code](53a4eb26f2/MoltenVK/MoltenVK/GPUObjects/MVKQueue.mm (L392-L408)) we observe that:
- It hard fails if error is:
  ```
   MTLCommandBufferErrorBlacklisted || MTLCommandBufferErrorNotPermitted || MTLCommandBufferErrorDeviceRemoved
   ```
- Otherwise fails conditionally if `config.resumeLostDevice == false` (current default)

For Ryujinx's use-case it's more graceful to resume on those errors rather than crashing the app, the error isn't totally silenced since `mvk` still logs it

Fixes #4704, #4575
2023-05-10 03:31:52 +02:00
Emmanuel Hansen
0bc8151c7e IPC - Refactor Bcat service to use new ipc - Revisit (#4803)
* bcat ipc

* fix hipc buffer flags

* add buffer fixed size flag on generator
2023-05-09 21:46:23 +00:00
gdkchan
40c17673f5 Replace DelegateHelper with pre-generated delegates (#4867) 2023-05-09 09:02:39 +00:00
Mary
a8950d6ac4 vulkan: Pass Vk instance to VulkanRenderer (#4859)
This will allow possible multiple driver selection without any need of
LD preload. (useful when testing custom version of mesa for example)
2023-05-08 13:05:37 +02:00
Mary
162798b026 vulkan: Avoid hardcoding features in CreateDevice (#4858)
Those shouldn't have been hardcoded.
2023-05-08 10:48:16 +00:00
riperiperi
1b28ecd63e Vulkan: Simplify MultiFenceHolder and managing them (#4845)
* Vulkan: Simplify waitable add/remove

Removal of unnecessary hashset and dictionary

* Thread safety for GetBufferData in PersistentFlushBuffer

* Fix WaitForFencesImpl thread safety

* Proper methods for risky reference increments

* Wrong type of CB.

* Address feedback
2023-05-08 12:45:12 +02:00
riperiperi
895d9b53bc Vulkan: Batch vertex buffer updates (#4843)
* Vulkan: Batch vertex buffer updates

Some games can bind a large number of vertex buffers for draws. This PR allows for vertex buffers to be updated with one call rather than one per buffer.

This mostly affects the AMD Mesa driver, the testing platform was Steam Deck with Super Mario Odyssey. It was taking about 12% before, should be greatly reduced now.

A small optimization has been added to avoid looking up the same buffer multiple times, as a common pattern is for the same buffer to be bound many times in a row with different ranges.

* Only rebind vertex buffers if they have changed

* Address feedback
2023-05-08 10:59:26 +02:00
Mary
0e06aace45 misc: Avoid copy of ApplicationControlProperty (#4849)
Avoid more giant copy when passing it around.
2023-05-08 01:50:07 +02:00
Ac_K
adf4ebcd60 Ava: Fix SystemTimeOffset calculation (#4848)
* Ava: Fix SystemTimeOffset calculation

During testing of #4822, Mary pointed out the way we calculate time offset is wrong in our Avalonia UI. This PR fixed that.
The axaml file is autoformatted too.

* DateTime.Now in local var
2023-05-08 00:31:08 +02:00
Mary
470a8031a4 time: Update for 15.0.0 changes and fixes long standing issues (#4822)
* time: Update for 15.0.0 changes

Last time we did an upgrade on the time service was during 9.x era, it was about time to take back that reverse again!

15.0.0 added a new structure on the shared memory to get steady clock raw timepoints with a granularity in nanoseconds.

This commit implements this new part.

I plan to write a follow up with a bit of refactoring of this ancient part of the emulator.

As always, reverse and work done by your truly.

PS: As a reminder, if this change is reused anywhere else, work should be credited as Ryujinx and not my person.

* time: Do not set setup value to posix time

This should fix local and network clock returning 0 under usage with
shared memory.

This probably fix #2430.

* Address gdkchan's comment

* Fix internal offset not working since changes and ensure that user clock have a valid clock id

* time: Report auto correcting clock and hardcode steady clock unique id

Fix Pokemon Sword Pokejobs for real.

* Address gdkchan's comment
2023-05-08 00:15:58 +02:00
Mary
5440d4ad5c misc: Switch ProcessResult to a class (#4846)
This avoid giant copies being performed when being returned or passed.
2023-05-07 20:50:45 +00:00
gnisman
dde208b480 UI: Expose games build ID for cheat management (#4340)
* Ava UI: Expose games build ID for cheat management

* Fix bad merge

* Change integrity check level to error on invalid

* Add support for GDK

* Remove whitespace

* Add BID identifier

* PR Comments fix

* Restore title id in cheats GTK window

* use halign center instead of margin_left

* Merge

* fix after merge

* PR comments fix - design AVA

* PR fix - Move GetApplicationBuildId to ApplicationData class

* PR comment fix - Add empty line before method

* Align with PR #4755

* PR comments fix

* Change BuildId label to support translation

* Comments fix

* Remove unused BuildIdLabel property
2023-05-07 14:36:44 +00:00
Nico
4c3d2d5d75 UI: Add progress bar for re-packaging shaders (#4805)
* feat: introduce new shader loading state for progress tracking when writing shaders to disk

* fix: move translation to bottom of locale file

* fix: change back to foreach and add requested spacing between lines

* style: fix formatting

Co-authored-by: gdkchan <gab.dark.100@gmail.com>

---------

Co-authored-by: gdkchan <gab.dark.100@gmail.com>
2023-05-06 15:35:46 +02:00
Ac_K
fab11ba3f1 AM: Stub some service calls (#4825)
* AM: Stub some service call

Some IPC I have stubbed during private testing and I don't want to deal with them anymore. Nothing more.

* ICommonStateGetter disposable
2023-05-06 03:33:50 +02:00
riperiperi
332891b5ff Use correct offset for storage constant buffer elimination (#4821) 2023-05-05 23:59:36 +02:00
riperiperi
7df4fcada7 GPU: Remove CPU region handle containers (#4817)
* GPU: Remove CPU region handle containers.

Another one for the "I don't know why I didn't do this earlier" pile.

This removes the "Cpu" prefixed region handle classes, which each mirror a region handle type from Ryujinx.Memory.

Originally, not all projects had a reference to Ryujinx.Memory, so these classes were introduced to bridge the gap. Someone else crossed that bridge since, so these classes don't have much of a purpose anymore.

This PR replaces all uses of CpuRegionHandle etc to their direct Ryujinx.Memory versions.

RegionHandle methods (specifically QueryModified) are about the hottest path there is in the entire emulator, so there is a nice boost from doing this.

* Add docs
2023-05-05 23:40:46 +02:00
Ac_K
d6698680be UI: Fix sections extraction (#4820)
* UI: Fix sections extraction

There is currently an issue when the update NCA doesn't contains the section we want to extract, this is fixed by adding a check.
I have fixed the inverted handler of ExeFs/Logo introduced in #4755.

Fixes #4521

* Addresses feedback
2023-05-05 21:24:35 +00:00
ashuk
e5c9838b0b Correct tooltips for add,remove,removeall buttons (#4819) 2023-05-05 22:38:57 +02:00
Ikko Eltociear Ashimine
f8ec878796 Fix typo in TextureBindingsManager.cs (#4798)
accomodate -> accommodate
2023-05-05 22:17:36 +02:00
Skyth (Asilkan)
9ff21f9ab6 Use ToLowerInvariant when detecting GPU vendor. (#4815) 2023-05-05 16:35:59 +00:00
gdkchan
aa021085cf Allow any shader SSBO constant buffer slot and offset (#2237)
* Allow any shader SSBO constant buffer slot and offset

* Fix slot value passed to SetUsedStorageBuffer on fallback case

* Shader cache version

* Ensure that the storage buffer source constant buffer offset is word aligned

* Fix FirstBinding on GetUniformBufferDescriptors
2023-05-05 14:20:20 +00:00
riperiperi
1f5d881860 GPU: Allow granular buffer updates from the constant buffer updater (#4749)
* GPU: Allow granular buffer updates from the constant buffer updater

Sometimes, constant buffer updates can't be avoided, either due to a cb0 access that cannot be eliminated, or the game updating a buffer between draws to the detriment of everyone.

To avoid uploading the full 4096 bytes each time, this PR remembers the offset and size containing all constant buffer updates since the last sync. It will then upload that range after sync.

* Allow clearing the dirty range

* Always use precise

Might want to not do this if distance between the existing range and new one is too high.

* Use old force dirty mechanism when distance between regions is too great

* Update src/Ryujinx.Graphics.Gpu/Memory/Buffer.cs

Co-authored-by: gdkchan <gab.dark.100@gmail.com>

* Fix inheritance of _dirtyStart and _dirtyEnd

---------

Co-authored-by: gdkchan <gab.dark.100@gmail.com>
2023-05-05 13:47:15 +00:00
TSRBerry
1f664100bd ModLoader: Fix case sensitivy issues without breaking cheats (#4783)
* Fix case sensitivity for mod subdirectories

* Small refactoring of ModLoader

* Don't share instruction list between all cheats

Co-authored-by: riperiperi <rhy3756547@hotmail.com>

---------

Co-authored-by: riperiperi <rhy3756547@hotmail.com>
2023-05-05 09:39:08 +02:00
Horizon
1f5e1ffa80 fix: linux launcher breaks when there are spaces in the directory path (#4795)
* fix: linux launcher breaks when there are spaces in the directory path

* Add quotes around $0 as well

---------

Co-authored-by: TSRBerry <20988865+TSRBerry@users.noreply.github.com>
2023-05-05 09:06:15 +02:00
gdkchan
264438ff19 Revert "bcat ipc (#4446)" (#4801)
This reverts commit 4250732353.
2023-05-04 18:16:51 +02:00
Ac_K
3b8ac1641a UI: Move ApplicationContextMenu in a separated class (#4755)
* UI: Move ApplicationContextMenu in a separated class

This PR remove duplicated code related to the context menu on the Application list/grid by create a control for the menu which include related handler.

I've renamed "GameList/GameGrid" by "Application" for consistencies. And I've removed all uneeded field from the project file too.

While I cleaned up things, I've found an issue about purging Ptc/Shader cache, both methods list files even if the user say "No", shader cache is purged even if the user say "No". It's fixed.

* Adresses feedbacks
2023-05-04 14:41:06 +00:00
Emmanuel Hansen
4250732353 bcat ipc (#4446) 2023-05-04 16:26:10 +02:00
gdkchan
4d1579acbf Fix some invalid blits involving depth textures (#4723) 2023-05-03 21:20:12 -03:00
Erdem Keskin
6279f5e430 Update SettingsWindow.cs (#4785)
fix saving if directory path directly pasted in to the text field instead of using FileChooser.
2023-05-03 16:04:40 +02:00
Mary
b7d2bff6aa Revert "ModLoader: Fix case sensitivy issues (#4720)" (#4781)
This reverts commit cc1a933a2f.
2023-05-03 11:20:05 +02:00
riperiperi
7c327fecb3 Vulkan: Record modifications after changing the framebuffer (#4775)
Our Vulkan backend inserts image barriers when a texture is sampled after it is rendered. This is done via a "modification flag" which is set when a render target is unbound (presuming that a texture has finished drawing to it).

Imagine the following scenario:
- Game sets render target to texture A
- Game renders to texture A
- (render pass ends)
- Game binds texture A to a sampler
- Game sets render target to texture B
- Renders to texture B using texture A (barrier required)

Because of the previous behaviour, the check to add a barrier for sampling a texture actually happens before it is registered as modified, meaning no barrier was added at all. This isn't always the case, but it was definitely causing issues in Xenoblade 2.

This doesn't fix any more complicated issues where a texture is repeatedly sampled while it is currently being rendered.

Fixes visual glitches at lower resolutions in Xenoblade 2. May fix other cases.
2023-05-03 10:42:21 +02:00
TSRBerry
cc1a933a2f ModLoader: Fix case sensitivy issues (#4720)
* Fix case sensitivity for mod subdirectories

* Small refactoring of ModLoader
2023-05-03 02:07:16 +02:00
TSRBerry
dd574146fb Add hide-cursor command line argument & always hide cursor option (#4613)
* Add hide-cursor command line argument

* gtk: Adjust SettingsWindow for hide cursor options

* ava: Adjust SettingsWindow for hide cursor options

* ava: Add override check for HideCursor arg

* Remove copy&paste sins

* ava: Leave a little more room between the options

* gtk: Fix hide cursor issues

* ava: Only hide cursor if it's within the embedded window
2023-05-02 03:29:47 +02:00
riperiperi
2c94ac455e GPU: Keep rendered textures without any pool references alive (#4662)
* GPU: Keep sampled textures without any pool references alive

Occasionally games are very wasteful and clear/write to a texture without ever sampling it. As rendered textures in NVN games seem to all have overlapping memory ranges, the texture will eventually get overwritten.

Normally, this would trigger a removal from the auto delete cache, but a pool entry would keep the texture alive. However, with these textures that are never used, they will get deleted immediately and recreated on the next frame.

This change makes it so the ShortTextureCache can keep textures that have naver had a pool reference alive for a few frames, so they're not constantly being created and deleted.

This improves performance in Zelda BOTW a little.

* Cleanup
2023-05-01 16:27:51 -03:00
riperiperi
e18d258fa0 GPU: Pre-emptively flush textures that are flushed often (to imported memory when available) (#4711)
* WIP texture pre-flush

Improve performance of TextureView GetData to buffer

Fix copy/sync ordering

Fix minor bug

Make this actually work

WIP host mapping stuff

* Fix usage flags

* message

* Cleanup 1

* Fix rebase

* Fix

* Improve pre-flush rules

* Fix pre-flush

* A lot of cleanup

* Use the host memory bits

* Select the correct memory type

* Cleanup TextureGroupHandle

* Missing comment

* Remove debugging logs

* Revert BufferHandle _value access modifier

* One interrupt action at a time.

* Support D32S8 to D24S8 conversion, safeguards

* Interrupt cannot happen in sync handle's lock

Waitable needs to be checked twice now, but this should stop it from deadlocking.

* Remove unused using

* Address some feedback

* Address feedback

* Address more feedback

* Address more feedback

* Improve sync rules

Should allow for faster sync in some cases.
2023-05-01 16:05:12 -03:00
riperiperi
36f10df775 GPU: Fix errors handling texture remapping (#4745)
* GPU: Fix errors handling texture remapping

- Fixes an error where a pool entry and memory mapping changing at the same time could cause a texture to rebind its data from the wrong GPU VA (data swaps)
- Fixes an error where the texture pool could act on a mapping change before the mapping has actually been changed ("Unmapped" event happens before change, we need to signal it changed _after_ it completes)

TODO: remove textures from partially mapped list... if they aren't.

* Add Remap actions for handling post-mapping behaviours

* Remove unused code.

* Address feedback

* Nit
2023-05-01 15:32:32 -03:00
al81-ru
680e548022 Uneven frame pacing with vsync (#4744)
fixes issue #3906
2023-04-29 21:54:41 +01:00
MutantAura
21c4176157 Allow window to remember its size, position and state (GTK + Avalonia) (#4657)
* Update ConfigurationState.cs

* Update ConfigurationFileFormat.cs

* Update MainWindow.cs

* Update ConfigurationFileFormat.cs

* Update ConfigurationState.cs

* Update MainWindow.cs

* Update MainWindow.cs

* Update Ryujinx.Ui.Common/Configuration/ConfigurationState.cs

Co-authored-by: gdkchan <gab.dark.100@gmail.com>

* Update MainWindow.cs

* Update Ryujinx/Ui/MainWindow.cs

Co-authored-by: gdkchan <gab.dark.100@gmail.com>

* Initial properties

* Viewmodel adjustments and additions

* abstract and monitor dimension changes

* Remove position from ViewModel and simplify methods

* Remove unused dep

* Update configuration and fix typo from AA

* review changes

* Review changes

* Screensize checks - Ava

* Review changes 2

* basic review changes

* Standardise GTK/Ava functions

* Actually call function

---------

Co-authored-by: HaizenTrist <123991082+HaizenTrist@users.noreply.github.com>
Co-authored-by: gdkchan <gab.dark.100@gmail.com>
2023-04-28 22:59:53 +02:00
dependabot[bot]
3b4ff2d6d9 nuget: bump System.IdentityModel.Tokens.Jwt from 6.29.0 to 6.30.0 (#4736)
Bumps [System.IdentityModel.Tokens.Jwt](https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet) from 6.29.0 to 6.30.0.
- [Release notes](https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/releases)
- [Changelog](https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/blob/dev/CHANGELOG.md)
- [Commits](https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/compare/6.29.0...6.30.0)

---
updated-dependencies:
- dependency-name: System.IdentityModel.Tokens.Jwt
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-04-28 11:54:19 +02:00
TSRBerry
12504f280c Fix paths and typos for macOS scripts (#4738)
* Fix paths and typos for macOS scripts

* Update outdated comments about rcodesign

---------

Co-authored-by: Mary <thog@protonmail.com>
2023-04-28 08:14:44 +00:00
TSR Berry
250fc51374 Adjust github workflows for new src directory 2023-04-27 23:51:14 +02:00
TSR Berry
206e0882c2 Adjust Ryujinx.Tests.Memory namespace 2023-04-27 23:51:14 +02:00
TSR Berry
609abc8b9b Rename Ryujinx.Memory.Tests to Ryujinx.Tests.Memory 2023-04-27 23:51:14 +02:00
TSR Berry
cee7121058 Move solution and projects to src 2023-04-27 23:51:14 +02:00
gdkchan
cd124bda58 Fix geometry shader layer passthrough regression (#4735)
* Fix geometry shader layer passthrough regression

* Shader cache version bump
2023-04-27 11:09:49 -03:00
gdkchan
9f12e50a54 Refactor attribute handling on the shader generator (#4565)
* Refactor attribute handling on the shader generator

* Implement gl_ViewportMask[]

* Add back the Intel FrontFacing bug workaround

* Fix GLSL transform feedback outputs mistmatch with fragment stage

* Shader cache version bump

* Fix geometry shader recognition

* PR feedback

* Delete GetOperandDef and GetOperandUse

* Remove replacements that are no longer needed on GLSL compilation on Vulkan

* Fix incorrect load for per-patch outputs

* Fix build
2023-04-25 19:51:07 -03:00
gdkchan
097562bc6c Add missing check for thread termination on ArbitrateLock (#4722)
* Add missing check for thread termination on ArbitrateLock

* Use TerminationRequested in all places where it can be used
2023-04-25 19:33:14 -03:00
gdkchan
db4242c5dc Implement DMA texture copy component shuffle (#4717)
* Implement DMA texture copy component shuffle

* Set UInt24 alignment to 1
2023-04-24 15:28:03 +02:00
gdkchan
4dd77316f7 Use vector transform feedback outputs with fragment shaders (#4708)
* Use vector transform feedback outputs with fragment shaders

* Shader cache version bump

* Fix missing outputs when vector transform feedback outputs are used
2023-04-24 08:34:38 +02:00
TSRBerry
3f98369a17 Set the console title for GTK again (#4706)
Fixes a regression from #3707 where I accidentally removed that line.
2023-04-24 08:15:19 +02:00
TSRBerry
c26aeefe03 Fix amiibo timeout issues & log errors/exceptions (#4712) 2023-04-24 02:08:31 +00:00
jhorv
666e05f5cb Reducing Memory Allocations 202303 (#4624)
* use ArrayPool, avoid 6000-7000 allocs/sec of runtime

* use ArrayPool, avoid ~7k allocs/second during game execution

* use ArrayPool, avoid ~3000 allocs/sec during game execution

* use MemoryPool, reduce 0.5 MB/sec of new allocations during game execution

* avoid over-allocation by setting List<> Capacity when known

* remove LINQ in KTimeManager.UnscheduleFutureInvocation

* KTimeManager - avoid spinning one more time when the time has arrived

* KTimeManager - let SpinWait decide when to Thread.Yield(), and don't SpinOnce() immediately after Thread.Yield()

* use MemoryPool, reduce ~175k bytes/sec allocation during game execution

* IpcService - call commands via dynamic methods instead of reflection .Invoke(). Faster to call and with fewer allocations because parameters can be passed directly instead of as an array

* Make ButtonMappingEntry a record struct to avoid allocations. Set the List<ButtonMappingEntry> capacity according to use.

* add MemoryBuffer type for working with MemoryPool<byte>

* update changes to use MemoryBuffer

* make parameter ReadOnlySpan instead of Span

* whitespace fix

* Revert "IpcService - call commands via dynamic methods instead of reflection .Invoke(). Faster to call and with fewer allocations because parameters can be passed directly instead of as an array"

This reverts commit f2c698bdf65f049e8481c9f2ec7138d9b9a8261d.

* tweak KTimeManager spin behavior

* replace MemoryBuffer with ByteMemoryPool modeled after System.Buffers.ArrayMemoryPool<T>

* make ByteMemoryPoolBuffer responsible for renting memory
2023-04-24 02:06:23 +00:00
riperiperi
8d9d508dc7 Shader: Bias textureGather instructions on AMD/Intel (#4703)
* Experimental (GLSL, forced)

* SPIR-V attempt

* Add capability

* Fix pCount == 1 on glsl

* Fix typo
2023-04-22 18:02:39 -03:00
SpicerXD
e27f5522e2 Removed MotionInput Calibration (#4705)
Don't know why this is here.
It just seems to set the filter to an identity. Which then quickly returns to where its supposed to be anyways.
2023-04-22 15:31:28 +02:00
gdkchan
add2a9d151 Avoid LM service crashes by not reading more than the buffer size (#4701) 2023-04-20 17:10:17 +02:00
dependabot[bot]
9e50dd99d7 nuget: bump System.IdentityModel.Tokens.Jwt from 6.28.1 to 6.29.0 (#4694)
Bumps [System.IdentityModel.Tokens.Jwt](https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet) from 6.28.1 to 6.29.0.
- [Release notes](https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/releases)
- [Changelog](https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/blob/dev/CHANGELOG.md)
- [Commits](https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/compare/6.28.1...6.29.0)

---
updated-dependencies:
- dependency-name: System.IdentityModel.Tokens.Jwt
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-04-17 21:31:12 +02:00
dependabot[bot]
0dec91bb42 nuget: bump System.Management from 7.0.0 to 7.0.1 (#4695)
Bumps [System.Management](https://github.com/dotnet/runtime) from 7.0.0 to 7.0.1.
- [Release notes](https://github.com/dotnet/runtime/releases)
- [Commits](https://github.com/dotnet/runtime/compare/v7.0.0...v7.0.1)

---
updated-dependencies:
- dependency-name: System.Management
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-04-17 21:30:40 +02:00
gdkchan
d9b63353b0 Support copy between multisample and non-multisample depth textures (#4676)
* Support copy between multisample and non-multisample depth textures

* PR feedback
2023-04-17 08:13:53 +00:00
gdkchan
eabd0ec93f Revert "chore: Update Silk.NET to 2.17.1 (#4686)" (#4690)
This reverts commit 79d1c190db.
2023-04-16 20:56:27 -03:00
riperiperi
138d5dc64a Vulkan: HashTableSlim lookup optimization (#4688) 2023-04-16 14:57:01 -03:00
gdkchan
3e68a87d63 Change SMAA filter texture clear method (#4685)
* Change SMAA filter texture clear method

* Alpha should be 1

* Delete more unnecessary code
2023-04-16 14:26:22 -03:00
TSRBerry
69b6ef7a4a [GUI] Add network interface dropdown (#4597)
* Add network adapter dropdown from LDN build

* Ava: Add NetworkInterfaces to SettingsNetworkTab

* Add headless network interface option

* Add network interface dropdown to Avalonia

* Fix handling network interfaces without a gateway address

* gtk: Actually save selected network interface to config

* Increment config version
2023-04-16 15:25:20 +00:00
Mary
40e87c634e Fix a crash in Ryujinx.Headless.SDL2 when loading an app (#4687)
Caused by the recent application loader changes.
2023-04-16 16:50:30 +02:00
Mary
79d1c190db chore: Update Silk.NET to 2.17.1 (#4686) 2023-04-16 09:38:07 +00:00
Ac_K
2bc88467eb Update README.md 2023-04-16 09:37:31 +00:00
Vincenzo Nizza
baf8752e74 Ensure the updater doesn't delete hidden or system files (#4626)
* Copy desktop.ini to update directory if it exists in HomeDir

* EnumerateFilesToDelete() exclude files with "Hidden" and "System" attributes
2023-04-16 09:19:33 +00:00
dependabot[bot]
d5e4378aea nuget: bump DynamicData from 7.13.1 to 7.13.5 (#4654)
Bumps [DynamicData](https://github.com/reactiveui/DynamicData) from 7.13.1 to 7.13.5.
- [Release notes](https://github.com/reactiveui/DynamicData/releases)
- [Changelog](https://github.com/reactivemarbles/DynamicData/blob/main/ReleaseNotes.md)
- [Commits](https://github.com/reactiveui/DynamicData/compare/7.13.1...7.13.5)

---
updated-dependencies:
- dependency-name: DynamicData
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-04-16 09:02:06 +00:00
TSRBerry
6dbcdfea47 Ava: Fix nca extraction window never closing & minor cleanup (#4569)
* ava: Remove unused doWhileDeferred parameters

* ava: Minimally improve swkbd dialog

It's currently impossible to get the dialog to redirect focus to the InputBox.

* ava: Fix nca extraction dialog never closing

Also contains some minor cleanup
2023-04-16 07:09:02 +00:00
NitroTears
c5258cf082 Ability to hide file types in Game List (#4555)
* Added HiddenFileTypes to config state, and check to file enumeration

* Added hiddenfiletypes checkboxes to the UI

* Added Ava version of HiddenFileTypes

* Inverted Hide to Show with file types, minor formatting

* all variables with a reference to 'hidden' is now 'shown'

* one more variable name changed

* review feedback

* added FileTypes extension methof to get the correlating config value

* moved extension method to new folder and file in Ryujinx.Ui.Common

* added default case for ToggleFileType

* changed exception type to OutOfRangeException
2023-04-16 01:03:35 +00:00
Daniel Shala
5c89e22bb9 Added check for eventual symlink when displaying game files. (#4526)
* Added check for eventual symlink when displaying game files.

* Moved symlink check logic

* Moved symlink check logic

* Fixed prev commit

---------

Co-authored-by: Daniel Shala <danielshala00@gmail.com>
2023-04-15 16:11:24 +00:00
Alex Barney
11ecff2ff0 Rename Hipc to Cmif where appropriate (#3880) 2023-04-14 20:00:34 -03:00
MutantAura
4c3f09644a Move swkbd message null check into constructor (#4671) 2023-04-12 21:18:40 +02:00
TSRBerry
e187a8870a HLE: Deal with empty title names properly (#4643)
* hle: Deal with empty titleNames in some languages

* gui: Fix displaying the wrong title name

* Remove unnecessary bounds check

* Fix a NRE when getting the version string

* Restore empty string logic
2023-04-12 01:09:47 +00:00
riperiperi
a64fee29dc Vulkan: add situational "Fast Flush" mode (#4667)
* Flush in the middle of long command buffers.

* Vulkan: add situational "Fast Flush" mode

The AutoFlushCounter class was added to periodically flush Vulkan command buffers throughout a frame, which reduces latency to the GPU as commands are submitted and processed much sooner. This was done by allowing command buffers to flush when framebuffer attachments changed.

However, some games have incredibly long render passes with a large number of draws, and really aggressive data access that forces GPU sync.

The Vulkan backend could potentially end up building a single command buffer for 4-5ms if a pass has enough draws, such as in BOTW. In the scenario where sync is waited on immediately after submission, this would have to wait for the completion of a much longer command buffer than usual.

The solution is to force command buffer submission periodically in a "fast flush" mode. This will end up splitting render passes, but it will only enable if sync is aggressive enough.

This should improve performance in GPU limited scenarios, or in games that aggressively wait on synchronization. In some games, it may only kick in when res scaling. It won't trigger in games like SMO where sync is not an issue.

Improves performance in Pokemon Scarlet/Violet (res scaled) and BOTW (in general).

* Add conversions in milliseconds next to flush timers.
2023-04-11 09:23:41 +02:00
riperiperi
9ef94c8292 ARMeilleure: Move TPIDR_EL0 and TPIDRRO_EL0 to NativeContext (#4661)
* ARMeilleure: Move TPIDR_EL0 and TPIDRRO_EL0 to NativeContext

Some games access these system registers several tens of thousands of times in a second from many different threads. While this isn't really crippling, it is a lot of wasted time spent in a reverse pinvoke transition.

Example games are Pokemon Scarlet/Violet and BOTW. These games have a lot of different potential bottlenecks so it's unlikely you will see a consistent improvement, but it definitely disappears from the cpu profile.

* Remove unreachable code.

* Add ulong conversion for offsets

* Nit
2023-04-11 08:55:04 +02:00
riperiperi
915d6d044c OpenGL: Fix OBS/Overlays again by binding FB before present (#4668)
This seems to have been removed by the Post-Processing PR, but it is required for the display in OBS to be the right way up and properly scaled.

I've tested this with AA and FSR on MK8D and it seems to behave properly. Testing is welcome.
2023-04-11 08:32:31 +02:00
MutantAura
a4780ab33b Force activate parent window before dialog is shown (#4663) 2023-04-11 00:04:31 +02:00
TSRBerry
a947a45d81 gtk: Fix a NRE when disposing OpenGL (#4648) 2023-04-10 17:00:23 +02:00
riperiperi
9db73f74cf ARMeilleure: Respect FZ/RM flags for all floating point operations (#4618)
* ARMeilleure: Respect Fz flag for all floating point operations.

This is a change in strategy for emulating the Fz FPCR flag. Before, it was set before instructions that "needed it" and reset after. However, this missed a few hot instructions like the multiplication instruction, and the entirety of A32.

The new strategy is to set the Fz flag only in the following circumstances:

- Set to match FPCR before translated functions/loop are executed.
- Reset when calling SoftFloat methods, set when returning.
- Reset when exiting execution.

This allows us to remove the code around the existing Fz aware instructions, and get the accuracy benefits on all floating point instructions executed while in translated code.

Single step executions now need to be called with a context wrapper - right now it just contains the Fz flag initialization, and won't actually do anything on ARM.

This fixes a bug in Breath of the Wild where some physics interactions could randomly crash the game due to subnormal values not flushing to zero.

This is draft right now because I need to answer the questions:
- Does dotnet avoid changing the value of Mxcsr?
- Is it a good idea to assume that? Or should the flag set/restore be done on every managed method call, not just softfloat?
- If we assume that, do we want a unit test to verify the behaviour?

I recommend testing a bunch of games, especially games affected when this was originally added, such as #1611.

* Remove unused method

* Use FMA for Fmadd, Fmsub, Fnmadd, Fnmsub, Fmla, Fmls

...when available.

Similar implementation to A32

* Use FMA for Frecps, Frsqrts

* Don't set DAZ.

* Add round mode to ARM FP mode

* Fix mistakes

* Add test for FP state when calling managed methods

* Add explanatory comment to test.

* Cleanup

* Add A64 FPCR flags

* Vrintx_S A32 fast path on A64 backend

* Address feedback 1, re-enable DAZ

* Fix FMA instructions By Elem

* Address feedback
2023-04-10 12:22:58 +02:00
gdkchan
a1efd87c45 Implement remaining Arm64 HINT instructions as NOP (#4658)
* Implement remaining HINT instructions as NOP

* Split HINT encodings more to account for CSDB
2023-04-09 13:21:16 -03:00
jhorv
49be977588 Eliminate boxing allocations caused by ISampledData structs (#4556)
* Redesign use of ISampledData for accessing the SamplingNumber value on input data structs.

* Always read SamplingNumber as little-endian

* Restored field order for SixAxisSensorState. Rework to allow possibility of non-zero offsets for the SamplingNumber field. Set StructLayout Pack=8 - the KeyboardState struct is 4 bytes shorter with any other value.

* fix spelling

Co-authored-by: riperiperi <rhy3756547@hotmail.com>

* set Pack = 1 for ISampledDataStruct types, added Unknown field to KeyboardState

* extend size of KeyboardModifier

---------

Co-authored-by: riperiperi <rhy3756547@hotmail.com>
2023-04-05 17:42:32 -03:00
Mary
c95be55091 vulkan: Cleanup PhysicalDevice and Instance querying (#4632)
* vulkan: Move most of the properties enumeration to VulkanPhysicalDevice

That clean up a bit of duplicate logic.
Also move to use an hashset for device extensions.

* vulkan: Move instance querying to VulkanInstance

Also cleanup code to use span when possible instead of unsafe pointers.

* Address gdkchan's comments
2023-04-05 14:48:38 -03:00
6388 changed files with 449054 additions and 440971 deletions

View File

@@ -1,8 +1,7 @@
# Remove the line below if you want to inherit .editorconfig settings from higher directories
root = true
# C# files
[*.cs]
[*]
#### Core EditorConfig Options ####
@@ -12,8 +11,11 @@ indent_style = space
tab_width = 4
# New line preferences
end_of_line = crlf
insert_final_newline = false
end_of_line = lf
insert_final_newline = true
# C# files
[*.cs]
#### .NET Coding Conventions ####
@@ -59,7 +61,7 @@ dotnet_style_prefer_simplified_interpolation = true:suggestion
dotnet_style_readonly_field = true:suggestion
# Parameter preferences
dotnet_code_quality_unused_parameters = all:suggestion
dotnet_code_quality_unused_parameters = all:silent
#### C# Coding Conventions ####
@@ -85,7 +87,7 @@ csharp_style_expression_bodied_properties = true:silent
# Pattern matching preferences
csharp_style_pattern_matching_over_as_with_null_check = true:suggestion
csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion
csharp_style_prefer_switch_expression = true:suggestion
csharp_style_prefer_switch_expression = false:silent
# Null-checking preferences
csharp_style_conditional_delegate_call = true:suggestion
@@ -94,6 +96,7 @@ csharp_style_conditional_delegate_call = true:suggestion
csharp_prefer_static_local_function = true:suggestion
csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async:silent
csharp_style_prefer_readonly_struct = true
csharp_style_prefer_method_group_conversion = true
# Code-block preferences
csharp_prefer_braces = true:silent
@@ -109,6 +112,7 @@ csharp_style_prefer_range_operator = true:suggestion
csharp_style_throw_expression = true:suggestion
csharp_style_unused_value_assignment_preference = discard_variable:suggestion
csharp_style_unused_value_expression_statement_preference = discard_variable:silent
csharp_style_implicit_object_creation_when_type_is_apparent = true
# 'using' directive preferences
csharp_using_directive_placement = outside_namespace:silent
@@ -140,7 +144,6 @@ csharp_space_after_dot = false
csharp_space_after_keywords_in_control_flow_statements = true
csharp_space_after_semicolon_in_for_statement = true
csharp_space_around_binary_operators = before_and_after
csharp_space_around_declaration_statements = false
csharp_space_before_colon_in_inheritance_clause = true
csharp_space_before_comma = false
csharp_space_before_dot = false
@@ -158,23 +161,31 @@ csharp_space_between_square_brackets = false
# Wrapping preferences
csharp_preserve_single_line_blocks = true
csharp_preserve_single_line_statements = true
csharp_preserve_single_line_statements = false
#### Naming styles ####
# Naming rules
dotnet_naming_rule.interface_should_be_begins_with_i.severity = suggestion
dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface
dotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_i
dotnet_naming_rule.interfaces_should_be_prefixed_with_I.severity = suggestion
dotnet_naming_rule.interfaces_should_be_prefixed_with_I.symbols = interface
dotnet_naming_rule.interfaces_should_be_prefixed_with_I.style = IPascalCase
dotnet_naming_rule.types_should_be_pascal_case.severity = suggestion
dotnet_naming_rule.types_should_be_pascal_case.symbols = types
dotnet_naming_rule.types_should_be_pascal_case.style = pascal_case
dotnet_naming_rule.types_should_be_pascal_case.style = PascalCase
dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = suggestion
dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members
dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case
dotnet_naming_rule.non_field_members_should_be_pascal_case.style = PascalCase
dotnet_naming_rule.private_static_readonly_fields_should_be_camel_case_and_prefixed_with__.symbols = private_static_readonly_fields
dotnet_naming_rule.private_static_readonly_fields_should_be_camel_case_and_prefixed_with__.severity = suggestion
dotnet_naming_rule.private_static_readonly_fields_should_be_camel_case_and_prefixed_with__.style = _camelCase
dotnet_naming_rule.local_constants_should_be_pascal_case.symbols = local_constants
dotnet_naming_rule.local_constants_should_be_pascal_case.severity = suggestion
dotnet_naming_rule.local_constants_should_be_pascal_case.style = PascalCase
# Symbol specifications
@@ -190,14 +201,39 @@ dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, meth
dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
dotnet_naming_symbols.non_field_members.required_modifiers =
dotnet_naming_symbols.private_static_readonly_fields.applicable_kinds = field
dotnet_naming_symbols.private_static_readonly_fields.applicable_accessibilities = private
dotnet_naming_symbols.private_static_readonly_fields.required_modifiers = static, readonly
dotnet_naming_symbols.local_constants.applicable_kinds = local
dotnet_naming_symbols.local_constants.applicable_accessibilities = local
dotnet_naming_symbols.local_constants.required_modifiers = const
# Naming styles
dotnet_naming_style.pascal_case.required_prefix =
dotnet_naming_style.pascal_case.required_suffix =
dotnet_naming_style.pascal_case.word_separator =
dotnet_naming_style.pascal_case.capitalization = pascal_case
dotnet_naming_style._camelCase.required_prefix = _
dotnet_naming_style._camelCase.required_suffix =
dotnet_naming_style._camelCase.word_separator =
dotnet_naming_style._camelCase.capitalization = camel_case
dotnet_naming_style.begins_with_i.required_prefix = I
dotnet_naming_style.begins_with_i.required_suffix =
dotnet_naming_style.begins_with_i.word_separator =
dotnet_naming_style.begins_with_i.capitalization = pascal_case
dotnet_naming_style.PascalCase.required_prefix =
dotnet_naming_style.PascalCase.required_suffix =
dotnet_naming_style.PascalCase.word_separator =
dotnet_naming_style.PascalCase.capitalization = pascal_case
dotnet_naming_style.IPascalCase.required_prefix = I
dotnet_naming_style.IPascalCase.required_suffix =
dotnet_naming_style.IPascalCase.word_separator =
dotnet_naming_style.IPascalCase.capitalization = pascal_case
[src/Ryujinx.HLE/HOS/Services/**.cs]
# Disable "mark members as static" rule for services
dotnet_diagnostic.CA1822.severity = none
[src/Ryujinx.Ava/UI/ViewModels/**.cs]
# Disable "mark members as static" rule for ViewModels
dotnet_diagnostic.CA1822.severity = none
[src/Ryujinx.Tests/Cpu/*.cs]
# Disable naming rules for CPU tests
dotnet_diagnostic.IDE1006.severity = none

View File

@@ -0,0 +1,19 @@
name: Missing Shader Instruction
description: Shader Instruction is missing in Ryujinx.
title: "[GPU]"
labels: [gpu, not-implemented]
body:
- type: textarea
id: instruction
attributes:
label: Shader instruction
description: What shader instruction is missing?
validations:
required: true
- type: textarea
id: required
attributes:
label: Required by
description: Add links to the [compatibility list page(s)](https://github.com/Ryujinx/Ryujinx-Games-List/issues) of the game(s) that require this instruction.
validations:
required: true

33
.github/labeler.yml vendored Normal file
View File

@@ -0,0 +1,33 @@
audio: 'src/Ryujinx.Audio*/**'
cpu:
- 'src/ARMeilleure/**'
- 'src/Ryujinx.Cpu/**'
- 'src/Ryujinx.Memory/**'
gpu:
- 'src/Ryujinx.Graphics.*/**'
- 'src/Spv.Generator/**'
- 'src/Ryujinx.ShaderTools/**'
'graphics-backend:opengl': 'src/Ryujinx.Graphics.OpenGL/**'
'graphics-backend:vulkan':
- 'src/Ryujinx.Graphics.Vulkan/**'
- 'src/Spv.Generator/**'
gui:
- 'src/Ryujinx/**'
- 'src/Ryujinx.Ui.Common/**'
- 'src/Ryujinx.Ui.LocaleGenerator/**'
- 'src/Ryujinx.Ava/**'
horizon:
- 'src/Ryujinx.HLE/**'
- 'src/Ryujinx.Horizon*/**'
kernel: 'src/Ryujinx.HLE/HOS/Kernel/**'
infra:
- '.github/**'
- 'distribution/**'
- 'Directory.Packages.props'

32
.github/reviewers.yml vendored Normal file
View File

@@ -0,0 +1,32 @@
audio:
- marysaka
cpu:
- gdkchan
- riperiperi
- marysaka
- LDj3SNuD
gpu:
- gdkchan
- riperiperi
- marysaka
gui:
- Ack77
- emmauss
- TSRBerry
- marysaka
horizon:
- gdkchan
- Ack77
- marysaka
- TSRBerry
infra:
- marysaka
- TSRBerry
default:
- marysaka

79
.github/update_reviewers.py vendored Normal file
View File

@@ -0,0 +1,79 @@
from pathlib import Path
from typing import List, Set
from github import Github
from github.Repository import Repository
from github.GithubException import GithubException
import sys
import yaml
def add_reviewers(
reviewers: Set[str], team_reviewers: Set[str], new_entries: List[str]
):
for reviewer in new_entries:
if reviewer.startswith("@"):
team_reviewers.add(reviewer[1:])
else:
reviewers.add(reviewer)
def update_reviewers(config, repo: Repository, pr_id: int) -> int:
pull_request = repo.get_pull(pr_id)
if not pull_request:
sys.stderr.writable(f"Unknown PR #{pr_id}\n")
return 1
pull_request_author = pull_request.user.login
reviewers = set()
team_reviewers = set()
for label in pull_request.labels:
if label.name in config:
add_reviewers(reviewers, team_reviewers, config[label.name])
if "default" in config:
add_reviewers(reviewers, team_reviewers, config["default"])
if pull_request_author in reviewers:
reviewers.remove(pull_request_author)
try:
reviewers = list(reviewers)
team_reviewers = list(team_reviewers)
print(
f"Attempting to assign reviewers ({reviewers}) and team_reviewers ({team_reviewers})"
)
pull_request.create_review_request(reviewers, team_reviewers)
return 0
except GithubException as e:
sys.stderr.write(f"Cannot assign review request for PR #{pr_id}: {e}\n")
return 1
if __name__ == "__main__":
if len(sys.argv) != 5:
sys.stderr.write("usage: <token> <repo_path> <pr_id> <config_path>\n")
sys.exit(1)
token = sys.argv[1]
repo_path = sys.argv[2]
pr_id = int(sys.argv[3])
config_path = Path(sys.argv[4])
g = Github(token)
repo = g.get_repo(repo_path)
if not repo:
sys.stderr.write("Repository not found!\n")
sys.exit(1)
if not config_path.exists():
sys.stderr.write(f'Config "{config_path}" not found!\n')
sys.exit(1)
with open(config_path, "r") as f:
config = yaml.safe_load(f)
sys.exit(update_reviewers(config, repo, pr_id))

View File

@@ -1,27 +1,22 @@
name: Build job
on:
workflow_dispatch:
inputs: {}
#push:
# branches: [ master ]
# paths-ignore:
# - '.github/*'
# - '.github/ISSUE_TEMPLATE/**'
# - '*.yml'
# - 'README.md'
pull_request:
branches: [ master ]
paths-ignore:
- '.github/*'
- '.github/ISSUE_TEMPLATE/**'
- '*.yml'
- 'README.md'
workflow_call:
concurrency:
group: pr-builds-${{ github.event.number }}
cancel-in-progress: true
env:
POWERSHELL_TELEMETRY_OPTOUT: 1
DOTNET_CLI_TELEMETRY_OPTOUT: 1
RYUJINX_BASE_VERSION: "1.1.0"
jobs:
build:
name: ${{ matrix.os }} (${{ matrix.configuration }})
name: ${{ matrix.OS_NAME }} (${{ matrix.configuration }})
runs-on: ${{ matrix.os }}
timeout-minutes: 45
strategy:
matrix:
os: [ubuntu-latest, macOS-latest, windows-latest]
@@ -33,7 +28,7 @@ jobs:
RELEASE_ZIP_OS_NAME: linux_x64
- os: macOS-latest
OS_NAME: MacOS x64
OS_NAME: macOS x64
DOTNET_RUNTIME_IDENTIFIER: osx-x64
RELEASE_ZIP_OS_NAME: osx_x64
@@ -43,47 +38,107 @@ jobs:
RELEASE_ZIP_OS_NAME: win_x64
fail-fast: false
env:
POWERSHELL_TELEMETRY_OPTOUT: 1
DOTNET_CLI_TELEMETRY_OPTOUT: 1
RYUJINX_BASE_VERSION: "1.1.0"
steps:
- uses: actions/checkout@v3
- uses: actions/setup-dotnet@v3
with:
dotnet-version: 7.0.x
global-json-file: global.json
- name: Get git short hash
id: git_short_hash
run: echo "result=$(git rev-parse --short "${{ github.sha }}")" >> $GITHUB_OUTPUT
shell: bash
- name: Build
run: dotnet build -c "${{ matrix.configuration }}" -p:Version="${{ env.RYUJINX_BASE_VERSION }}" -p:SourceRevisionId="${{ steps.git_short_hash.outputs.result }}" -p:ExtraDefineConstants=DISABLE_UPDATER
- name: Test
run: dotnet test --no-build -c "${{ matrix.configuration }}"
- name: Publish Ryujinx
run: dotnet publish -c "${{ matrix.configuration }}" -r "${{ matrix.DOTNET_RUNTIME_IDENTIFIER }}" -o ./publish -p:Version="${{ env.RYUJINX_BASE_VERSION }}" -p:DebugType=embedded -p:SourceRevisionId="${{ steps.git_short_hash.outputs.result }}" -p:ExtraDefineConstants=DISABLE_UPDATER Ryujinx --self-contained true
if: github.event_name == 'pull_request'
run: dotnet publish -c "${{ matrix.configuration }}" -r "${{ matrix.DOTNET_RUNTIME_IDENTIFIER }}" -o ./publish -p:Version="${{ env.RYUJINX_BASE_VERSION }}" -p:DebugType=embedded -p:SourceRevisionId="${{ steps.git_short_hash.outputs.result }}" -p:ExtraDefineConstants=DISABLE_UPDATER src/Ryujinx --self-contained true
if: github.event_name == 'pull_request' && matrix.os != 'macOS-latest'
- name: Publish Ryujinx.Headless.SDL2
run: dotnet publish -c "${{ matrix.configuration }}" -r "${{ matrix.DOTNET_RUNTIME_IDENTIFIER }}" -o ./publish_sdl2_headless -p:Version="${{ env.RYUJINX_BASE_VERSION }}" -p:DebugType=embedded -p:SourceRevisionId="${{ steps.git_short_hash.outputs.result }}" -p:ExtraDefineConstants=DISABLE_UPDATER Ryujinx.Headless.SDL2 --self-contained true
if: github.event_name == 'pull_request'
run: dotnet publish -c "${{ matrix.configuration }}" -r "${{ matrix.DOTNET_RUNTIME_IDENTIFIER }}" -o ./publish_sdl2_headless -p:Version="${{ env.RYUJINX_BASE_VERSION }}" -p:DebugType=embedded -p:SourceRevisionId="${{ steps.git_short_hash.outputs.result }}" -p:ExtraDefineConstants=DISABLE_UPDATER src/Ryujinx.Headless.SDL2 --self-contained true
if: github.event_name == 'pull_request' && matrix.os != 'macOS-latest'
- name: Publish Ryujinx.Ava
run: dotnet publish -c "${{ matrix.configuration }}" -r "${{ matrix.DOTNET_RUNTIME_IDENTIFIER }}" -o ./publish_ava -p:Version="${{ env.RYUJINX_BASE_VERSION }}" -p:DebugType=embedded -p:SourceRevisionId="${{ steps.git_short_hash.outputs.result }}" -p:ExtraDefineConstants=DISABLE_UPDATER Ryujinx.Ava --self-contained true
if: github.event_name == 'pull_request'
run: dotnet publish -c "${{ matrix.configuration }}" -r "${{ matrix.DOTNET_RUNTIME_IDENTIFIER }}" -o ./publish_ava -p:Version="${{ env.RYUJINX_BASE_VERSION }}" -p:DebugType=embedded -p:SourceRevisionId="${{ steps.git_short_hash.outputs.result }}" -p:ExtraDefineConstants=DISABLE_UPDATER src/Ryujinx.Ava --self-contained true
if: github.event_name == 'pull_request' && matrix.os != 'macOS-latest'
- name: Set executable bit
run: |
chmod +x ./publish/Ryujinx ./publish/Ryujinx.sh
chmod +x ./publish_sdl2_headless/Ryujinx.Headless.SDL2 ./publish_sdl2_headless/Ryujinx.sh
chmod +x ./publish_ava/Ryujinx.Ava ./publish_ava/Ryujinx.sh
if: github.event_name == 'pull_request' && matrix.os == 'ubuntu-latest'
- name: Upload Ryujinx artifact
uses: actions/upload-artifact@v3
with:
name: ryujinx-${{ matrix.configuration }}-${{ env.RYUJINX_BASE_VERSION }}+${{ steps.git_short_hash.outputs.result }}-${{ matrix.RELEASE_ZIP_OS_NAME }}
path: publish
if: github.event_name == 'pull_request'
if: github.event_name == 'pull_request' && matrix.os != 'macOS-latest'
- name: Upload Ryujinx.Headless.SDL2 artifact
uses: actions/upload-artifact@v3
with:
name: sdl2-ryujinx-headless-${{ matrix.configuration }}-${{ env.RYUJINX_BASE_VERSION }}+${{ steps.git_short_hash.outputs.result }}-${{ matrix.RELEASE_ZIP_OS_NAME }}
path: publish_sdl2_headless
if: github.event_name == 'pull_request'
if: github.event_name == 'pull_request' && matrix.os != 'macOS-latest'
- name: Upload Ryujinx.Ava artifact
uses: actions/upload-artifact@v3
with:
name: ava-ryujinx-${{ matrix.configuration }}-${{ env.RYUJINX_BASE_VERSION }}+${{ steps.git_short_hash.outputs.result }}-${{ matrix.RELEASE_ZIP_OS_NAME }}
path: publish_ava
if: github.event_name == 'pull_request'
if: github.event_name == 'pull_request' && matrix.os != 'macOS-latest'
build_macos:
name: macOS Universal (${{ matrix.configuration }})
runs-on: ubuntu-latest
timeout-minutes: 45
strategy:
matrix:
configuration: [ Debug, Release ]
steps:
- uses: actions/checkout@v3
- uses: actions/setup-dotnet@v3
with:
global-json-file: global.json
- name: Setup LLVM 14
run: |
wget https://apt.llvm.org/llvm.sh
chmod +x llvm.sh
sudo ./llvm.sh 14
- name: Install rcodesign
run: |
mkdir -p $HOME/.bin
gh release download -R indygreg/apple-platform-rs -O apple-codesign.tar.gz -p 'apple-codesign-*-x86_64-unknown-linux-musl.tar.gz'
tar -xzvf apple-codesign.tar.gz --wildcards '*/rcodesign' --strip-components=1
rm apple-codesign.tar.gz
mv rcodesign $HOME/.bin/
echo "$HOME/.bin" >> $GITHUB_PATH
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Get git short hash
id: git_short_hash
run: echo "result=$(git rev-parse --short "${{ github.sha }}")" >> $GITHUB_OUTPUT
- name: Publish macOS
run: |
./distribution/macos/create_macos_build.sh . publish_tmp publish_ava ./distribution/macos/entitlements.xml "${{ env.RYUJINX_BASE_VERSION }}" "${{ steps.git_short_hash.outputs.result }}" "${{ matrix.configuration }}" "-p:ExtraDefineConstants=DISABLE_UPDATER"
- name: Upload Ryujinx.Ava artifact
uses: actions/upload-artifact@v3
with:
name: ava-ryujinx-${{ matrix.configuration }}-${{ env.RYUJINX_BASE_VERSION }}+${{ steps.git_short_hash.outputs.result }}-macos_universal
path: "publish_ava/*.tar.gz"
if: github.event_name == 'pull_request'

71
.github/workflows/checks.yml vendored Normal file
View File

@@ -0,0 +1,71 @@
name: Perform checks
on:
pull_request:
branches: [ master ]
paths:
- '**'
- '!.github/**'
- '!*.yml'
- '!*.config'
- '!README.md'
- '.github/workflows/*.yml'
permissions:
pull-requests: write
checks: write
concurrency:
group: pr-checks-${{ github.event.number }}
cancel-in-progress: true
jobs:
format:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- uses: actions/setup-dotnet@v3
with:
global-json-file: global.json
- run: dotnet restore
- name: Print dotnet format version
run: dotnet format --version
- name: Run dotnet format whitespace
run: |
dotnet format whitespace --verify-no-changes --report ./whitespace-report.json -v d
- name: Run dotnet format style
run: |
dotnet format style --severity info --verify-no-changes --report ./style-report.json -v d
# For some reason this step sometimes fails with exit code 139 (segfault?),
# so should that be the case we'll try again (3 tries max).
- name: Run dotnet format analyzers
run: |
attempt=0
exit_code=139
until [ $attempt -ge 3 ] || [ $exit_code -ne 139 ]; do
((attempt+=1))
exit_code=0
echo "Attempt: ${attempt}/3"
dotnet format analyzers --severity info --verify-no-changes --report ./analyzers-report.json -v d || exit_code=$?
done
exit $exit_code
- name: Upload report
if: failure()
uses: actions/upload-artifact@v3
with:
name: dotnet-format
path: ./*-report.json
pr_build:
uses: ./.github/workflows/build.yml
needs: format
secrets: inherit

View File

@@ -12,13 +12,14 @@ concurrency: flatpak-release
jobs:
release:
timeout-minutes: ${{ fromJSON(vars.JOB_TIMEOUT) }}
runs-on: ubuntu-latest
env:
NUGET_PACKAGES: ${{ github.workspace }}/.nuget/packages
GIT_COMMITTER_NAME: "RyujinxBot"
GIT_COMMITTER_EMAIL: "61127645+RyujinxBot@users.noreply.github.com"
RYUJINX_PROJECT_FILE: "Ryujinx/Ryujinx.csproj"
RYUJINX_PROJECT_FILE: "src/Ryujinx/Ryujinx.csproj"
NUGET_SOURCES_DESTDIR: "nuget-sources"
RYUJINX_VERSION: "${{ inputs.ryujinx_version }}"
@@ -168,4 +169,4 @@ jobs:
git config user.email "${{ env.GIT_COMMITTER_EMAIL }}"
git add .
git commit -m "$COMMIT_MESSAGE"
git push origin master
git push origin master

View File

@@ -1,12 +1,15 @@
name: Comment PR artifacts links
on:
workflow_run:
workflows: ['Build job']
workflows: ['Perform checks']
types: [completed]
jobs:
pr_comment:
if: github.event.workflow_run.event == 'pull_request' && github.event.workflow_run.conclusion == 'success'
runs-on: ubuntu-latest
timeout-minutes: ${{ fromJSON(vars.JOB_TIMEOUT) }}
steps:
- uses: actions/github-script@v6
with:
@@ -65,4 +68,4 @@ jobs:
} else {
core.info(`Creating a comment`);
await github.rest.issues.createComment({repo, owner, issue_number, body});
}
}

34
.github/workflows/pr_triage.yml vendored Normal file
View File

@@ -0,0 +1,34 @@
name: "Pull Request Triage"
on:
pull_request_target:
types: [opened, ready_for_review]
jobs:
triage:
permissions:
contents: read
pull-requests: write
runs-on: ubuntu-latest
steps:
# Grab sources to get update_reviewers.py and reviewers.yml
- name: Fetch sources
uses: actions/checkout@v3
with:
# Ensure we pin the source origin as pull_request_target run under forks.
fetch-depth: 0
repository: Ryujinx/Ryujinx
ref: master
- name: Update labels based on changes
uses: actions/labeler@v4
with:
sync-labels: true
dot: true
- name: Assign reviewers
run: |
pip3 install PyGithub
python3 .github/update_reviewers.py ${{ secrets.GITHUB_TOKEN }} ${{ github.repository }} ${{ github.event.pull_request.number }} .github/reviewers.yml
shell: bash

View File

@@ -6,9 +6,10 @@ on:
push:
branches: [ master ]
paths-ignore:
- '.github/*'
- '.github/ISSUE_TEMPLATE/**'
- '.github/**'
- '*.yml'
- '*.json'
- '*.config'
- 'README.md'
concurrency: release
@@ -22,98 +23,18 @@ env:
RYUJINX_TARGET_RELEASE_CHANNEL_REPO: "release-channel-master"
jobs:
release:
runs-on: windows-latest
tag:
name: Create tag
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-dotnet@v3
with:
global-json-file: global.json
- name: Get version info
id: version_info
run: |
echo "build_version=${{ env.RYUJINX_BASE_VERSION }}.${{ github.run_number }}" >> $GITHUB_OUTPUT
echo "git_short_hash=$(git rev-parse --short "${{ github.sha }}")" >> $GITHUB_OUTPUT
shell: bash
- name: Configure for release
run: |
sed -r --in-place 's/\%\%RYUJINX_BUILD_VERSION\%\%/${{ steps.version_info.outputs.build_version }}/g;' Ryujinx.Common/ReleaseInformation.cs
sed -r --in-place 's/\%\%RYUJINX_BUILD_GIT_HASH\%\%/${{ steps.version_info.outputs.git_short_hash }}/g;' Ryujinx.Common/ReleaseInformation.cs
sed -r --in-place 's/\%\%RYUJINX_TARGET_RELEASE_CHANNEL_NAME\%\%/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_NAME }}/g;' Ryujinx.Common/ReleaseInformation.cs
sed -r --in-place 's/\%\%RYUJINX_TARGET_RELEASE_CHANNEL_OWNER\%\%/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}/g;' Ryujinx.Common/ReleaseInformation.cs
sed -r --in-place 's/\%\%RYUJINX_TARGET_RELEASE_CHANNEL_REPO\%\%/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }}/g;' Ryujinx.Common/ReleaseInformation.cs
shell: bash
- name: Create output dir
run: "mkdir release_output"
- name: Publish Windows
run: |
dotnet publish -c Release -r win10-x64 -o ./publish_windows/publish -p:Version="${{ steps.version_info.outputs.build_version }}" -p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" -p:DebugType=embedded Ryujinx --self-contained true
dotnet publish -c Release -r win10-x64 -o ./publish_windows_sdl2_headless/publish -p:Version="${{ steps.version_info.outputs.build_version }}" -p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" -p:DebugType=embedded Ryujinx.Headless.SDL2 --self-contained true
dotnet publish -c Release -r win10-x64 -o ./publish_windows_ava/publish -p:Version="${{ steps.version_info.outputs.build_version }}" -p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" -p:DebugType=embedded Ryujinx.Ava --self-contained true
- name: Packing Windows builds
run: |
pushd publish_windows
7z a ../release_output/ryujinx-${{ steps.version_info.outputs.build_version }}-win_x64.zip publish
popd
pushd publish_windows_sdl2_headless
7z a ../release_output/sdl2-ryujinx-headless-${{ steps.version_info.outputs.build_version }}-win_x64.zip publish
popd
pushd publish_windows_ava
7z a ../release_output/test-ava-ryujinx-${{ steps.version_info.outputs.build_version }}-win_x64.zip publish
popd
shell: bash
- name: Publish Linux
run: |
dotnet publish -c Release -r linux-x64 -o ./publish_linux/publish -p:Version="${{ steps.version_info.outputs.build_version }}" -p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" -p:DebugType=embedded Ryujinx --self-contained true
dotnet publish -c Release -r linux-x64 -o ./publish_linux_sdl2_headless/publish -p:Version="${{ steps.version_info.outputs.build_version }}" -p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" -p:DebugType=embedded Ryujinx.Headless.SDL2 --self-contained true
dotnet publish -c Release -r linux-x64 -o ./publish_linux_ava/publish -p:Version="${{ steps.version_info.outputs.build_version }}" -p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" -p:DebugType=embedded Ryujinx.Ava --self-contained true
- name: Packing Linux builds
run: |
pushd publish_linux
tar --exclude "publish/Ryujinx" --exclude "publish/Ryujinx.sh" -cvf ../release_output/ryujinx-${{ steps.version_info.outputs.build_version }}-linux_x64.tar publish
python3 ../distribution/misc/add_tar_exec.py ../release_output/ryujinx-${{ steps.version_info.outputs.build_version }}-linux_x64.tar "publish/Ryujinx" "publish/Ryujinx"
python3 ../distribution/misc/add_tar_exec.py ../release_output/ryujinx-${{ steps.version_info.outputs.build_version }}-linux_x64.tar "publish/Ryujinx.sh" "publish/Ryujinx.sh"
gzip -9 < ../release_output/ryujinx-${{ steps.version_info.outputs.build_version }}-linux_x64.tar > ../release_output/ryujinx-${{ steps.version_info.outputs.build_version }}-linux_x64.tar.gz
rm ../release_output/ryujinx-${{ steps.version_info.outputs.build_version }}-linux_x64.tar
popd
pushd publish_linux_sdl2_headless
tar --exclude "publish/Ryujinx.Headless.SDL2" --exclude "publish/Ryujinx.sh" -cvf ../release_output/sdl2-ryujinx-headless-${{ steps.version_info.outputs.build_version }}-linux_x64.tar publish
python3 ../distribution/misc/add_tar_exec.py ../release_output/sdl2-ryujinx-headless-${{ steps.version_info.outputs.build_version }}-linux_x64.tar "publish/Ryujinx.Headless.SDL2" "publish/Ryujinx.Headless.SDL2"
python3 ../distribution/misc/add_tar_exec.py ../release_output/sdl2-ryujinx-headless-${{ steps.version_info.outputs.build_version }}-linux_x64.tar "publish/Ryujinx.sh" "publish/Ryujinx.sh"
gzip -9 < ../release_output/sdl2-ryujinx-headless-${{ steps.version_info.outputs.build_version }}-linux_x64.tar > ../release_output/sdl2-ryujinx-headless-${{ steps.version_info.outputs.build_version }}-linux_x64.tar.gz
rm ../release_output/sdl2-ryujinx-headless-${{ steps.version_info.outputs.build_version }}-linux_x64.tar
popd
pushd publish_linux_ava
tar --exclude "publish/Ryujinx.Ava" --exclude "publish/Ryujinx.sh" -cvf ../release_output/test-ava-ryujinx-${{ steps.version_info.outputs.build_version }}-linux_x64.tar publish
python3 ../distribution/misc/add_tar_exec.py ../release_output/test-ava-ryujinx-${{ steps.version_info.outputs.build_version }}-linux_x64.tar "publish/Ryujinx.Ava" "publish/Ryujinx.Ava"
python3 ../distribution/misc/add_tar_exec.py ../release_output/test-ava-ryujinx-${{ steps.version_info.outputs.build_version }}-linux_x64.tar "publish/Ryujinx.sh" "publish/Ryujinx.sh"
gzip -9 < ../release_output/test-ava-ryujinx-${{ steps.version_info.outputs.build_version }}-linux_x64.tar > ../release_output/test-ava-ryujinx-${{ steps.version_info.outputs.build_version }}-linux_x64.tar.gz
rm ../release_output/test-ava-ryujinx-${{ steps.version_info.outputs.build_version }}-linux_x64.tar
popd
shell: bash
- name: Pushing new release
uses: ncipollo/release-action@v1
with:
name: ${{ steps.version_info.outputs.build_version }}
artifacts: "release_output/*.tar.gz,release_output/*.zip"
tag: ${{ steps.version_info.outputs.build_version }}
body: "For more informations about this release please check out the official [Changelog](https://github.com/Ryujinx/Ryujinx/wiki/Changelog)."
allowUpdates: true
removeArtifacts: true
replacesArtifacts: true
owner: ${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}
repo: ${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }}
token: ${{ secrets.RELEASE_TOKEN }}
- name: Create tag
uses: actions/github-script@v5
uses: actions/github-script@v6
with:
script: |
github.rest.git.createRef({
@@ -123,9 +44,168 @@ jobs:
sha: context.sha
})
release:
name: Release ${{ matrix.OS_NAME }}
runs-on: ${{ matrix.os }}
timeout-minutes: ${{ fromJSON(vars.JOB_TIMEOUT) }}
strategy:
matrix:
os: [ ubuntu-latest, windows-latest ]
include:
- os: ubuntu-latest
OS_NAME: Linux x64
DOTNET_RUNTIME_IDENTIFIER: linux-x64
RELEASE_ZIP_OS_NAME: linux_x64
- os: windows-latest
OS_NAME: Windows x64
DOTNET_RUNTIME_IDENTIFIER: win10-x64
RELEASE_ZIP_OS_NAME: win_x64
steps:
- uses: actions/checkout@v3
- uses: actions/setup-dotnet@v3
with:
global-json-file: global.json
- name: Get version info
id: version_info
run: |
echo "build_version=${{ env.RYUJINX_BASE_VERSION }}.${{ github.run_number }}" >> $GITHUB_OUTPUT
echo "git_short_hash=$(git rev-parse --short "${{ github.sha }}")" >> $GITHUB_OUTPUT
shell: bash
- name: Configure for release
run: |
sed -r --in-place 's/\%\%RYUJINX_BUILD_VERSION\%\%/${{ steps.version_info.outputs.build_version }}/g;' src/Ryujinx.Common/ReleaseInformation.cs
sed -r --in-place 's/\%\%RYUJINX_BUILD_GIT_HASH\%\%/${{ steps.version_info.outputs.git_short_hash }}/g;' src/Ryujinx.Common/ReleaseInformation.cs
sed -r --in-place 's/\%\%RYUJINX_TARGET_RELEASE_CHANNEL_NAME\%\%/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_NAME }}/g;' src/Ryujinx.Common/ReleaseInformation.cs
sed -r --in-place 's/\%\%RYUJINX_TARGET_RELEASE_CHANNEL_OWNER\%\%/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}/g;' src/Ryujinx.Common/ReleaseInformation.cs
sed -r --in-place 's/\%\%RYUJINX_TARGET_RELEASE_CHANNEL_REPO\%\%/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }}/g;' src/Ryujinx.Common/ReleaseInformation.cs
shell: bash
- name: Create output dir
run: "mkdir release_output"
- name: Publish
run: |
dotnet publish -c Release -r "${{ matrix.DOTNET_RUNTIME_IDENTIFIER }}" -o ./publish_gtk/publish -p:Version="${{ steps.version_info.outputs.build_version }}" -p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" -p:DebugType=embedded src/Ryujinx --self-contained true
dotnet publish -c Release -r "${{ matrix.DOTNET_RUNTIME_IDENTIFIER }}" -o ./publish_sdl2_headless/publish -p:Version="${{ steps.version_info.outputs.build_version }}" -p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" -p:DebugType=embedded src/Ryujinx.Headless.SDL2 --self-contained true
dotnet publish -c Release -r "${{ matrix.DOTNET_RUNTIME_IDENTIFIER }}" -o ./publish_ava/publish -p:Version="${{ steps.version_info.outputs.build_version }}" -p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" -p:DebugType=embedded src/Ryujinx.Ava --self-contained true
- name: Packing Windows builds
if: matrix.os == 'windows-latest'
run: |
pushd publish_gtk
7z a ../release_output/ryujinx-${{ steps.version_info.outputs.build_version }}-win_x64.zip publish
popd
pushd publish_sdl2_headless
7z a ../release_output/sdl2-ryujinx-headless-${{ steps.version_info.outputs.build_version }}-win_x64.zip publish
popd
pushd publish_ava
7z a ../release_output/test-ava-ryujinx-${{ steps.version_info.outputs.build_version }}-win_x64.zip publish
popd
shell: bash
- name: Packing Linux builds
if: matrix.os == 'ubuntu-latest'
run: |
pushd publish_gtk
chmod +x publish/Ryujinx.sh publish/Ryujinx
tar -czvf ../release_output/ryujinx-${{ steps.version_info.outputs.build_version }}-linux_x64.tar.gz publish
popd
pushd publish_sdl2_headless
chmod +x publish/Ryujinx.sh publish/Ryujinx.Headless.SDL2
tar -czvf ../release_output/sdl2-ryujinx-headless-${{ steps.version_info.outputs.build_version }}-linux_x64.tar.gz publish
popd
pushd publish_ava
chmod +x publish/Ryujinx.sh publish/Ryujinx.Ava
tar -czvf ../release_output/test-ava-ryujinx-${{ steps.version_info.outputs.build_version }}-linux_x64.tar.gz publish
popd
shell: bash
- name: Pushing new release
uses: ncipollo/release-action@v1
with:
name: ${{ steps.version_info.outputs.build_version }}
artifacts: "release_output/*.tar.gz,release_output/*.zip"
tag: ${{ steps.version_info.outputs.build_version }}
body: "For more information about this release please check out the official [Changelog](https://github.com/Ryujinx/Ryujinx/wiki/Changelog)."
omitBodyDuringUpdate: true
allowUpdates: true
replacesArtifacts: true
owner: ${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}
repo: ${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }}
token: ${{ secrets.RELEASE_TOKEN }}
macos_release:
name: Release MacOS universal
runs-on: ubuntu-latest
timeout-minutes: ${{ fromJSON(vars.JOB_TIMEOUT) }}
steps:
- uses: actions/checkout@v3
- uses: actions/setup-dotnet@v3
with:
global-json-file: global.json
- name: Setup LLVM 14
run: |
wget https://apt.llvm.org/llvm.sh
chmod +x llvm.sh
sudo ./llvm.sh 14
- name: Install rcodesign
run: |
mkdir -p $HOME/.bin
gh release download -R indygreg/apple-platform-rs -O apple-codesign.tar.gz -p 'apple-codesign-*-x86_64-unknown-linux-musl.tar.gz'
tar -xzvf apple-codesign.tar.gz --wildcards '*/rcodesign' --strip-components=1
rm apple-codesign.tar.gz
mv rcodesign $HOME/.bin/
echo "$HOME/.bin" >> $GITHUB_PATH
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Get version info
id: version_info
run: |
echo "build_version=${{ env.RYUJINX_BASE_VERSION }}.${{ github.run_number }}" >> $GITHUB_OUTPUT
echo "git_short_hash=$(git rev-parse --short "${{ github.sha }}")" >> $GITHUB_OUTPUT
- name: Configure for release
run: |
sed -r --in-place 's/\%\%RYUJINX_BUILD_VERSION\%\%/${{ steps.version_info.outputs.build_version }}/g;' src/Ryujinx.Common/ReleaseInformation.cs
sed -r --in-place 's/\%\%RYUJINX_BUILD_GIT_HASH\%\%/${{ steps.version_info.outputs.git_short_hash }}/g;' src/Ryujinx.Common/ReleaseInformation.cs
sed -r --in-place 's/\%\%RYUJINX_TARGET_RELEASE_CHANNEL_NAME\%\%/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_NAME }}/g;' src/Ryujinx.Common/ReleaseInformation.cs
sed -r --in-place 's/\%\%RYUJINX_TARGET_RELEASE_CHANNEL_OWNER\%\%/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}/g;' src/Ryujinx.Common/ReleaseInformation.cs
sed -r --in-place 's/\%\%RYUJINX_TARGET_RELEASE_CHANNEL_REPO\%\%/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }}/g;' src/Ryujinx.Common/ReleaseInformation.cs
shell: bash
- name: Publish macOS
run: |
./distribution/macos/create_macos_build.sh . publish_tmp publish_ava ./distribution/macos/entitlements.xml "${{ steps.version_info.outputs.build_version }}" "${{ steps.version_info.outputs.git_short_hash }}" Release
- name: Pushing new release
uses: ncipollo/release-action@v1
with:
name: ${{ steps.version_info.outputs.build_version }}
artifacts: "publish_ava/*.tar.gz"
tag: ${{ steps.version_info.outputs.build_version }}
body: "For more information about this release please check out the official [Changelog](https://github.com/Ryujinx/Ryujinx/wiki/Changelog)."
omitBodyDuringUpdate: true
allowUpdates: true
replacesArtifacts: true
owner: ${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}
repo: ${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }}
token: ${{ secrets.RELEASE_TOKEN }}
flatpak_release:
uses: ./.github/workflows/flatpak.yml
needs: release
with:
ryujinx_version: "1.1.${{ github.run_number }}"
secrets: inherit
secrets: inherit

View File

@@ -1,42 +0,0 @@
using ARMeilleure.Common;
using System;
using System.Runtime.CompilerServices;
namespace ARMeilleure
{
static class Allocators
{
[ThreadStatic] private static ArenaAllocator _default;
[ThreadStatic] private static ArenaAllocator _operands;
[ThreadStatic] private static ArenaAllocator _operations;
[ThreadStatic] private static ArenaAllocator _references;
[ThreadStatic] private static ArenaAllocator _liveRanges;
[ThreadStatic] private static ArenaAllocator _liveIntervals;
public static ArenaAllocator Default => GetAllocator(ref _default, 256 * 1024, 4);
public static ArenaAllocator Operands => GetAllocator(ref _operands, 64 * 1024, 8);
public static ArenaAllocator Operations => GetAllocator(ref _operations, 64 * 1024, 8);
public static ArenaAllocator References => GetAllocator(ref _references, 64 * 1024, 8);
public static ArenaAllocator LiveRanges => GetAllocator(ref _liveRanges, 64 * 1024, 8);
public static ArenaAllocator LiveIntervals => GetAllocator(ref _liveIntervals, 64 * 1024, 8);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static ArenaAllocator GetAllocator(ref ArenaAllocator alloc, uint pageSize, uint pageCount)
{
if (alloc == null)
{
alloc = new ArenaAllocator(pageSize, pageCount);
}
return alloc;
}
public static void ResetAll()
{
Default.Reset();
Operands.Reset();
Operations.Reset();
References.Reset();
}
}
}

View File

@@ -1,270 +0,0 @@
using ARMeilleure.CodeGen.Optimizations;
using ARMeilleure.IntermediateRepresentation;
using ARMeilleure.Translation;
using System.Collections.Generic;
using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
using static ARMeilleure.IntermediateRepresentation.Operation.Factory;
namespace ARMeilleure.CodeGen.Arm64
{
static class Arm64Optimizer
{
private const int MaxConstantUses = 10000;
public static void RunPass(ControlFlowGraph cfg)
{
var constants = new Dictionary<ulong, Operand>();
Operand GetConstantCopy(BasicBlock block, Operation operation, Operand source)
{
// If the constant has many uses, we also force a new constant mov to be added, in order
// to avoid overflow of the counts field (that is limited to 16 bits).
if (!constants.TryGetValue(source.Value, out var constant) || constant.UsesCount > MaxConstantUses)
{
constant = Local(source.Type);
Operation copyOp = Operation(Instruction.Copy, constant, source);
block.Operations.AddBefore(operation, copyOp);
constants[source.Value] = constant;
}
return constant;
}
for (BasicBlock block = cfg.Blocks.First; block != null; block = block.ListNext)
{
constants.Clear();
Operation nextNode;
for (Operation node = block.Operations.First; node != default; node = nextNode)
{
nextNode = node.ListNext;
// Insert copies for constants that can't fit on a 32-bit immediate.
// Doing this early unblocks a few optimizations.
if (node.Instruction == Instruction.Add)
{
Operand src1 = node.GetSource(0);
Operand src2 = node.GetSource(1);
if (src1.Kind == OperandKind.Constant && (src1.Relocatable || ConstTooLong(src1, OperandType.I32)))
{
node.SetSource(0, GetConstantCopy(block, node, src1));
}
if (src2.Kind == OperandKind.Constant && (src2.Relocatable || ConstTooLong(src2, OperandType.I32)))
{
node.SetSource(1, GetConstantCopy(block, node, src2));
}
}
// Try to fold something like:
// lsl x1, x1, #2
// add x0, x0, x1
// ldr x0, [x0]
// add x2, x2, #16
// ldr x2, [x2]
// Into:
// ldr x0, [x0, x1, lsl #2]
// ldr x2, [x2, #16]
if (IsMemoryLoadOrStore(node.Instruction))
{
OperandType type;
if (node.Destination != default)
{
type = node.Destination.Type;
}
else
{
type = node.GetSource(1).Type;
}
Operand memOp = GetMemoryOperandOrNull(node.GetSource(0), type);
if (memOp != default)
{
node.SetSource(0, memOp);
}
}
}
}
Optimizer.RemoveUnusedNodes(cfg);
}
private static Operand GetMemoryOperandOrNull(Operand addr, OperandType type)
{
Operand baseOp = addr;
// First we check if the address is the result of a local X with immediate
// addition. If that is the case, then the baseOp is X, and the memory operand immediate
// becomes the addition immediate. Otherwise baseOp keeps being the address.
int imm = GetConstOp(ref baseOp, type);
if (imm != 0)
{
return MemoryOp(type, baseOp, default, Multiplier.x1, imm);
}
// Now we check if the baseOp is the result of a local Y with a local Z addition.
// If that is the case, we now set baseOp to Y and indexOp to Z. We further check
// if Z is the result of a left shift of local W by a value == 0 or == Log2(AccessSize),
// if that is the case, we set indexOp to W and adjust the scale value of the memory operand
// to match that of the left shift.
// There is one missed case, which is the address being a shift result, but this is
// probably not worth optimizing as it should never happen.
(Operand indexOp, Multiplier scale) = GetIndexOp(ref baseOp, type);
// If baseOp is still equal to address, then there's nothing that can be optimized.
if (baseOp == addr)
{
return default;
}
return MemoryOp(type, baseOp, indexOp, scale, 0);
}
private static int GetConstOp(ref Operand baseOp, OperandType accessType)
{
Operation operation = GetAsgOpWithInst(baseOp, Instruction.Add);
if (operation == default)
{
return 0;
}
Operand src1 = operation.GetSource(0);
Operand src2 = operation.GetSource(1);
Operand constOp;
Operand otherOp;
if (src1.Kind == OperandKind.Constant && src2.Kind == OperandKind.LocalVariable)
{
constOp = src1;
otherOp = src2;
}
else if (src1.Kind == OperandKind.LocalVariable && src2.Kind == OperandKind.Constant)
{
constOp = src2;
otherOp = src1;
}
else
{
return 0;
}
// If we have addition by a constant that we can't encode on the instruction,
// then we can't optimize it further.
if (ConstTooLong(constOp, accessType))
{
return 0;
}
baseOp = otherOp;
return constOp.AsInt32();
}
private static (Operand, Multiplier) GetIndexOp(ref Operand baseOp, OperandType accessType)
{
Operand indexOp = default;
Multiplier scale = Multiplier.x1;
Operation addOp = GetAsgOpWithInst(baseOp, Instruction.Add);
if (addOp == default)
{
return (indexOp, scale);
}
Operand src1 = addOp.GetSource(0);
Operand src2 = addOp.GetSource(1);
if (src1.Kind != OperandKind.LocalVariable || src2.Kind != OperandKind.LocalVariable)
{
return (indexOp, scale);
}
baseOp = src1;
indexOp = src2;
Operation shlOp = GetAsgOpWithInst(src1, Instruction.ShiftLeft);
bool indexOnSrc2 = false;
if (shlOp == default)
{
shlOp = GetAsgOpWithInst(src2, Instruction.ShiftLeft);
indexOnSrc2 = true;
}
if (shlOp != default)
{
Operand shSrc = shlOp.GetSource(0);
Operand shift = shlOp.GetSource(1);
int maxShift = Assembler.GetScaleForType(accessType);
if (shSrc.Kind == OperandKind.LocalVariable &&
shift.Kind == OperandKind.Constant &&
(shift.Value == 0 || shift.Value == (ulong)maxShift))
{
scale = shift.Value switch
{
1 => Multiplier.x2,
2 => Multiplier.x4,
3 => Multiplier.x8,
4 => Multiplier.x16,
_ => Multiplier.x1
};
baseOp = indexOnSrc2 ? src1 : src2;
indexOp = shSrc;
}
}
return (indexOp, scale);
}
private static Operation GetAsgOpWithInst(Operand op, Instruction inst)
{
// If we have multiple assignments, folding is not safe
// as the value may be different depending on the
// control flow path.
if (op.AssignmentsCount != 1)
{
return default;
}
Operation asgOp = op.Assignments[0];
if (asgOp.Instruction != inst)
{
return default;
}
return asgOp;
}
private static bool IsMemoryLoadOrStore(Instruction inst)
{
return inst == Instruction.Load || inst == Instruction.Store;
}
private static bool ConstTooLong(Operand constOp, OperandType accessType)
{
if ((uint)constOp.Value != constOp.Value)
{
return true;
}
return !CodeGenCommon.ConstFitsOnUImm12(constOp.AsInt32(), accessType);
}
}
}

View File

@@ -1,47 +0,0 @@
using ARMeilleure.IntermediateRepresentation;
using System;
namespace ARMeilleure.CodeGen.Arm64
{
enum ArmCondition
{
Eq = 0,
Ne = 1,
GeUn = 2,
LtUn = 3,
Mi = 4,
Pl = 5,
Vs = 6,
Vc = 7,
GtUn = 8,
LeUn = 9,
Ge = 10,
Lt = 11,
Gt = 12,
Le = 13,
Al = 14,
Nv = 15
}
static class ComparisonArm64Extensions
{
public static ArmCondition ToArmCondition(this Comparison comp)
{
return comp switch
{
Comparison.Equal => ArmCondition.Eq,
Comparison.NotEqual => ArmCondition.Ne,
Comparison.Greater => ArmCondition.Gt,
Comparison.LessOrEqual => ArmCondition.Le,
Comparison.GreaterUI => ArmCondition.GtUn,
Comparison.LessOrEqualUI => ArmCondition.LeUn,
Comparison.GreaterOrEqual => ArmCondition.Ge,
Comparison.Less => ArmCondition.Lt,
Comparison.GreaterOrEqualUI => ArmCondition.GeUn,
Comparison.LessUI => ArmCondition.LtUn,
_ => throw new ArgumentException(null, nameof(comp))
};
}
}
}

View File

@@ -1,14 +0,0 @@
namespace ARMeilleure.CodeGen.Arm64
{
enum ArmExtensionType
{
Uxtb = 0,
Uxth = 1,
Uxtw = 2,
Uxtx = 3,
Sxtb = 4,
Sxth = 5,
Sxtw = 6,
Sxtx = 7
}
}

View File

@@ -1,11 +0,0 @@
namespace ARMeilleure.CodeGen.Arm64
{
enum ArmShiftType
{
Lsl = 0,
Lsr = 1,
Asr = 2,
Ror = 3
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,96 +0,0 @@
using System;
namespace ARMeilleure.CodeGen.Arm64
{
static class CallingConvention
{
private const int RegistersMask = unchecked((int)0xffffffff);
// Some of those register have specific roles and can't be used as general purpose registers.
// X18 - Reserved for platform specific usage.
// X29 - Frame pointer.
// X30 - Return address.
// X31 - Not an actual register, in some cases maps to SP, and in others to ZR.
private const int ReservedRegsMask = (1 << CodeGenCommon.ReservedRegister) | (1 << 18) | (1 << 29) | (1 << 30) | (1 << 31);
public static int GetIntAvailableRegisters()
{
return RegistersMask & ~ReservedRegsMask;
}
public static int GetVecAvailableRegisters()
{
return RegistersMask;
}
public static int GetIntCallerSavedRegisters()
{
return (GetIntCalleeSavedRegisters() ^ RegistersMask) & ~ReservedRegsMask;
}
public static int GetFpCallerSavedRegisters()
{
return GetFpCalleeSavedRegisters() ^ RegistersMask;
}
public static int GetVecCallerSavedRegisters()
{
return GetVecCalleeSavedRegisters() ^ RegistersMask;
}
public static int GetIntCalleeSavedRegisters()
{
return 0x1ff80000; // X19 to X28
}
public static int GetFpCalleeSavedRegisters()
{
return 0xff00; // D8 to D15
}
public static int GetVecCalleeSavedRegisters()
{
return 0;
}
public static int GetArgumentsOnRegsCount()
{
return 8;
}
public static int GetIntArgumentRegister(int index)
{
if ((uint)index < (uint)GetArgumentsOnRegsCount())
{
return index;
}
throw new ArgumentOutOfRangeException(nameof(index));
}
public static int GetVecArgumentRegister(int index)
{
if ((uint)index < (uint)GetArgumentsOnRegsCount())
{
return index;
}
throw new ArgumentOutOfRangeException(nameof(index));
}
public static int GetIntReturnRegister()
{
return 0;
}
public static int GetIntReturnRegisterHigh()
{
return 1;
}
public static int GetVecReturnRegister()
{
return 0;
}
}
}

View File

@@ -1,91 +0,0 @@
using ARMeilleure.IntermediateRepresentation;
using System.Numerics;
namespace ARMeilleure.CodeGen.Arm64
{
static class CodeGenCommon
{
public const int TcAddressRegister = 8;
public const int ReservedRegister = 17;
public static bool ConstFitsOnSImm7(int value, int scale)
{
return (((value >> scale) << 25) >> (25 - scale)) == value;
}
public static bool ConstFitsOnSImm9(int value)
{
return ((value << 23) >> 23) == value;
}
public static bool ConstFitsOnUImm12(int value)
{
return (value & 0xfff) == value;
}
public static bool ConstFitsOnUImm12(int value, OperandType type)
{
int scale = Assembler.GetScaleForType(type);
return (((value >> scale) & 0xfff) << scale) == value;
}
public static bool TryEncodeBitMask(Operand operand, out int immN, out int immS, out int immR)
{
return TryEncodeBitMask(operand.Type, operand.Value, out immN, out immS, out immR);
}
public static bool TryEncodeBitMask(OperandType type, ulong value, out int immN, out int immS, out int immR)
{
if (type == OperandType.I32)
{
value |= value << 32;
}
return TryEncodeBitMask(value, out immN, out immS, out immR);
}
public static bool TryEncodeBitMask(ulong value, out int immN, out int immS, out int immR)
{
// Some special values also can't be encoded:
// 0 can't be encoded because we need to subtract 1 from onesCount (which would became negative if 0).
// A value with all bits set can't be encoded because it is reserved according to the spec, because:
// Any value AND all ones will be equal itself, so it's effectively a no-op.
// Any value OR all ones will be equal all ones, so one can just use MOV.
// Any value XOR all ones will be equal its inverse, so one can just use MVN.
if (value == 0 || value == ulong.MaxValue)
{
immN = 0;
immS = 0;
immR = 0;
return false;
}
// Normalize value, rotating it such that the LSB is 1: Ensures we get a complete element that has not
// been cut-in-half across the word boundary.
int rotation = BitOperations.TrailingZeroCount(value & (value + 1));
ulong rotatedValue = ulong.RotateRight(value, rotation);
// Now that we have a complete element in the LSB with the LSB = 1, determine size and number of ones
// in element.
int elementSize = BitOperations.TrailingZeroCount(rotatedValue & (rotatedValue + 1));
int onesInElement = BitOperations.TrailingZeroCount(~rotatedValue);
// Check the value is repeating; also ensures element size is a power of two.
if (ulong.RotateRight(value, elementSize) != value)
{
immN = 0;
immS = 0;
immR = 0;
return false;
}
immN = (elementSize >> 6) & 1;
immS = (((~elementSize + 1) << 1) | (onesInElement - 1)) & 0x3f;
immR = (elementSize - rotation) & (elementSize - 1);
return true;
}
}
}

View File

@@ -1,287 +0,0 @@
using ARMeilleure.CodeGen.Linking;
using ARMeilleure.CodeGen.RegisterAllocators;
using ARMeilleure.IntermediateRepresentation;
using Ryujinx.Common.Memory;
using System;
using System.Collections.Generic;
using System.IO;
namespace ARMeilleure.CodeGen.Arm64
{
class CodeGenContext
{
private const int BccInstLength = 4;
private const int CbnzInstLength = 4;
private const int LdrLitInstLength = 4;
private Stream _stream;
public int StreamOffset => (int)_stream.Length;
public AllocationResult AllocResult { get; }
public Assembler Assembler { get; }
public BasicBlock CurrBlock { get; private set; }
public bool HasCall { get; }
public int CallArgsRegionSize { get; }
public int FpLrSaveRegionSize { get; }
private readonly Dictionary<BasicBlock, long> _visitedBlocks;
private readonly Dictionary<BasicBlock, List<(ArmCondition Condition, long BranchPos)>> _pendingBranches;
private struct ConstantPoolEntry
{
public readonly int Offset;
public readonly Symbol Symbol;
public readonly List<(Operand, int)> LdrOffsets;
public ConstantPoolEntry(int offset, Symbol symbol)
{
Offset = offset;
Symbol = symbol;
LdrOffsets = new List<(Operand, int)>();
}
}
private readonly Dictionary<ulong, ConstantPoolEntry> _constantPool;
private bool _constantPoolWritten;
private long _constantPoolOffset;
private ArmCondition _jNearCondition;
private Operand _jNearValue;
private long _jNearPosition;
private readonly bool _relocatable;
public CodeGenContext(AllocationResult allocResult, int maxCallArgs, int blocksCount, bool relocatable)
{
_stream = MemoryStreamManager.Shared.GetStream();
AllocResult = allocResult;
Assembler = new Assembler(_stream);
bool hasCall = maxCallArgs >= 0;
HasCall = hasCall;
if (maxCallArgs < 0)
{
maxCallArgs = 0;
}
CallArgsRegionSize = maxCallArgs * 16;
FpLrSaveRegionSize = hasCall ? 16 : 0;
_visitedBlocks = new Dictionary<BasicBlock, long>();
_pendingBranches = new Dictionary<BasicBlock, List<(ArmCondition, long)>>();
_constantPool = new Dictionary<ulong, ConstantPoolEntry>();
_relocatable = relocatable;
}
public void EnterBlock(BasicBlock block)
{
CurrBlock = block;
long target = _stream.Position;
if (_pendingBranches.TryGetValue(block, out var list))
{
foreach (var tuple in list)
{
_stream.Seek(tuple.BranchPos, SeekOrigin.Begin);
WriteBranch(tuple.Condition, target);
}
_stream.Seek(target, SeekOrigin.Begin);
_pendingBranches.Remove(block);
}
_visitedBlocks.Add(block, target);
}
public void JumpTo(BasicBlock target)
{
JumpTo(ArmCondition.Al, target);
}
public void JumpTo(ArmCondition condition, BasicBlock target)
{
if (_visitedBlocks.TryGetValue(target, out long offset))
{
WriteBranch(condition, offset);
}
else
{
if (!_pendingBranches.TryGetValue(target, out var list))
{
list = new List<(ArmCondition, long)>();
_pendingBranches.Add(target, list);
}
list.Add((condition, _stream.Position));
_stream.Seek(BccInstLength, SeekOrigin.Current);
}
}
private void WriteBranch(ArmCondition condition, long to)
{
int imm = checked((int)(to - _stream.Position));
if (condition != ArmCondition.Al)
{
Assembler.B(condition, imm);
}
else
{
Assembler.B(imm);
}
}
public void JumpToNear(ArmCondition condition)
{
_jNearCondition = condition;
_jNearPosition = _stream.Position;
_stream.Seek(BccInstLength, SeekOrigin.Current);
}
public void JumpToNearIfNotZero(Operand value)
{
_jNearValue = value;
_jNearPosition = _stream.Position;
_stream.Seek(CbnzInstLength, SeekOrigin.Current);
}
public void JumpHere()
{
long currentPosition = _stream.Position;
long offset = currentPosition - _jNearPosition;
_stream.Seek(_jNearPosition, SeekOrigin.Begin);
if (_jNearValue != default)
{
Assembler.Cbnz(_jNearValue, checked((int)offset));
_jNearValue = default;
}
else
{
Assembler.B(_jNearCondition, checked((int)offset));
}
_stream.Seek(currentPosition, SeekOrigin.Begin);
}
public void ReserveRelocatableConstant(Operand rt, Symbol symbol, ulong value)
{
if (!_constantPool.TryGetValue(value, out ConstantPoolEntry cpe))
{
cpe = new ConstantPoolEntry(_constantPool.Count * sizeof(ulong), symbol);
_constantPool.Add(value, cpe);
}
cpe.LdrOffsets.Add((rt, (int)_stream.Position));
_stream.Seek(LdrLitInstLength, SeekOrigin.Current);
}
private long WriteConstantPool()
{
if (_constantPoolWritten)
{
return _constantPoolOffset;
}
long constantPoolBaseOffset = _stream.Position;
foreach (ulong value in _constantPool.Keys)
{
WriteUInt64(value);
}
foreach (ConstantPoolEntry cpe in _constantPool.Values)
{
foreach ((Operand rt, int ldrOffset) in cpe.LdrOffsets)
{
_stream.Seek(ldrOffset, SeekOrigin.Begin);
int absoluteOffset = checked((int)(constantPoolBaseOffset + cpe.Offset));
int pcRelativeOffset = absoluteOffset - ldrOffset;
Assembler.LdrLit(rt, pcRelativeOffset);
}
}
_stream.Seek(constantPoolBaseOffset + _constantPool.Count * sizeof(ulong), SeekOrigin.Begin);
_constantPoolOffset = constantPoolBaseOffset;
_constantPoolWritten = true;
return constantPoolBaseOffset;
}
public (byte[], RelocInfo) GetCode()
{
long constantPoolBaseOffset = WriteConstantPool();
byte[] code = new byte[_stream.Length];
long originalPosition = _stream.Position;
_stream.Seek(0, SeekOrigin.Begin);
_stream.Read(code, 0, code.Length);
_stream.Seek(originalPosition, SeekOrigin.Begin);
RelocInfo relocInfo;
if (_relocatable)
{
RelocEntry[] relocs = new RelocEntry[_constantPool.Count];
int index = 0;
foreach (ConstantPoolEntry cpe in _constantPool.Values)
{
if (cpe.Symbol.Type != SymbolType.None)
{
int absoluteOffset = checked((int)(constantPoolBaseOffset + cpe.Offset));
relocs[index++] = new RelocEntry(absoluteOffset, cpe.Symbol);
}
}
if (index != relocs.Length)
{
Array.Resize(ref relocs, index);
}
relocInfo = new RelocInfo(relocs);
}
else
{
relocInfo = new RelocInfo(Array.Empty<RelocEntry>());
}
return (code, relocInfo);
}
private void WriteUInt64(ulong value)
{
_stream.WriteByte((byte)(value >> 0));
_stream.WriteByte((byte)(value >> 8));
_stream.WriteByte((byte)(value >> 16));
_stream.WriteByte((byte)(value >> 24));
_stream.WriteByte((byte)(value >> 32));
_stream.WriteByte((byte)(value >> 40));
_stream.WriteByte((byte)(value >> 48));
_stream.WriteByte((byte)(value >> 56));
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,662 +0,0 @@
using ARMeilleure.IntermediateRepresentation;
using System;
using System.Diagnostics;
namespace ARMeilleure.CodeGen.Arm64
{
static class CodeGeneratorIntrinsic
{
public static void GenerateOperation(CodeGenContext context, Operation operation)
{
Intrinsic intrin = operation.Intrinsic;
IntrinsicInfo info = IntrinsicTable.GetInfo(intrin & ~(Intrinsic.Arm64VTypeMask | Intrinsic.Arm64VSizeMask));
switch (info.Type)
{
case IntrinsicType.ScalarUnary:
GenerateVectorUnary(
context,
0,
(uint)(intrin & Intrinsic.Arm64VSizeMask) >> (int)Intrinsic.Arm64VSizeShift,
info.Inst,
operation.Destination,
operation.GetSource(0));
break;
case IntrinsicType.ScalarUnaryByElem:
Debug.Assert(operation.GetSource(1).Kind == OperandKind.Constant);
GenerateVectorUnaryByElem(
context,
0,
(uint)(intrin & Intrinsic.Arm64VSizeMask) >> (int)Intrinsic.Arm64VSizeShift,
info.Inst,
(uint)operation.GetSource(1).AsInt32(),
operation.Destination,
operation.GetSource(0));
break;
case IntrinsicType.ScalarBinary:
GenerateVectorBinary(
context,
0,
(uint)(intrin & Intrinsic.Arm64VSizeMask) >> (int)Intrinsic.Arm64VSizeShift,
info.Inst,
operation.Destination,
operation.GetSource(0),
operation.GetSource(1));
break;
case IntrinsicType.ScalarBinaryFPByElem:
Debug.Assert(operation.GetSource(2).Kind == OperandKind.Constant);
GenerateVectorBinaryFPByElem(
context,
0,
(uint)(intrin & Intrinsic.Arm64VSizeMask) >> (int)Intrinsic.Arm64VSizeShift,
info.Inst,
(uint)operation.GetSource(2).AsInt32(),
operation.Destination,
operation.GetSource(0),
operation.GetSource(1));
break;
case IntrinsicType.ScalarBinaryRd:
GenerateVectorUnary(
context,
0,
(uint)(intrin & Intrinsic.Arm64VSizeMask) >> (int)Intrinsic.Arm64VSizeShift,
info.Inst,
operation.Destination,
operation.GetSource(1));
break;
case IntrinsicType.ScalarBinaryShl:
Debug.Assert(operation.GetSource(1).Kind == OperandKind.Constant);
GenerateVectorBinaryShlImm(
context,
0,
(uint)(intrin & Intrinsic.Arm64VSizeMask) >> (int)Intrinsic.Arm64VSizeShift,
info.Inst,
operation.Destination,
operation.GetSource(0),
(uint)operation.GetSource(1).AsInt32());
break;
case IntrinsicType.ScalarBinaryShr:
Debug.Assert(operation.GetSource(1).Kind == OperandKind.Constant);
GenerateVectorBinaryShrImm(
context,
0,
(uint)(intrin & Intrinsic.Arm64VSizeMask) >> (int)Intrinsic.Arm64VSizeShift,
info.Inst,
operation.Destination,
operation.GetSource(0),
(uint)operation.GetSource(1).AsInt32());
break;
case IntrinsicType.ScalarFPCompare:
GenerateScalarFPCompare(
context,
(uint)(intrin & Intrinsic.Arm64VSizeMask) >> (int)Intrinsic.Arm64VSizeShift,
info.Inst,
operation.Destination,
operation.GetSource(0),
operation.GetSource(1));
break;
case IntrinsicType.ScalarFPConvFixed:
Debug.Assert(operation.GetSource(1).Kind == OperandKind.Constant);
GenerateVectorBinaryShrImm(
context,
0,
((uint)(intrin & Intrinsic.Arm64VSizeMask) >> (int)Intrinsic.Arm64VSizeShift) + 2u,
info.Inst,
operation.Destination,
operation.GetSource(0),
(uint)operation.GetSource(1).AsInt32());
break;
case IntrinsicType.ScalarFPConvFixedGpr:
Debug.Assert(operation.GetSource(1).Kind == OperandKind.Constant);
GenerateScalarFPConvGpr(
context,
(uint)(intrin & Intrinsic.Arm64VSizeMask) >> (int)Intrinsic.Arm64VSizeShift,
info.Inst,
operation.Destination,
operation.GetSource(0),
(uint)operation.GetSource(1).AsInt32());
break;
case IntrinsicType.ScalarFPConvGpr:
GenerateScalarFPConvGpr(
context,
(uint)(intrin & Intrinsic.Arm64VSizeMask) >> (int)Intrinsic.Arm64VSizeShift,
info.Inst,
operation.Destination,
operation.GetSource(0));
break;
case IntrinsicType.ScalarTernary:
GenerateScalarTernary(
context,
(uint)(intrin & Intrinsic.Arm64VSizeMask) >> (int)Intrinsic.Arm64VSizeShift,
info.Inst,
operation.Destination,
operation.GetSource(1),
operation.GetSource(2),
operation.GetSource(0));
break;
case IntrinsicType.ScalarTernaryFPRdByElem:
Debug.Assert(operation.GetSource(3).Kind == OperandKind.Constant);
GenerateVectorBinaryFPByElem(
context,
0,
(uint)(intrin & Intrinsic.Arm64VSizeMask) >> (int)Intrinsic.Arm64VSizeShift,
info.Inst,
(uint)operation.GetSource(3).AsInt32(),
operation.Destination,
operation.GetSource(1),
operation.GetSource(2));
break;
case IntrinsicType.ScalarTernaryShlRd:
Debug.Assert(operation.GetSource(2).Kind == OperandKind.Constant);
GenerateVectorBinaryShlImm(
context,
0,
(uint)(intrin & Intrinsic.Arm64VSizeMask) >> (int)Intrinsic.Arm64VSizeShift,
info.Inst,
operation.Destination,
operation.GetSource(1),
(uint)operation.GetSource(2).AsInt32());
break;
case IntrinsicType.ScalarTernaryShrRd:
Debug.Assert(operation.GetSource(2).Kind == OperandKind.Constant);
GenerateVectorBinaryShrImm(
context,
0,
(uint)(intrin & Intrinsic.Arm64VSizeMask) >> (int)Intrinsic.Arm64VSizeShift,
info.Inst,
operation.Destination,
operation.GetSource(1),
(uint)operation.GetSource(2).AsInt32());
break;
case IntrinsicType.VectorUnary:
GenerateVectorUnary(
context,
(uint)(intrin & Intrinsic.Arm64VTypeMask) >> (int)Intrinsic.Arm64VTypeShift,
(uint)(intrin & Intrinsic.Arm64VSizeMask) >> (int)Intrinsic.Arm64VSizeShift,
info.Inst,
operation.Destination,
operation.GetSource(0));
break;
case IntrinsicType.VectorUnaryByElem:
Debug.Assert(operation.GetSource(1).Kind == OperandKind.Constant);
GenerateVectorUnaryByElem(
context,
(uint)(intrin & Intrinsic.Arm64VTypeMask) >> (int)Intrinsic.Arm64VTypeShift,
(uint)(intrin & Intrinsic.Arm64VSizeMask) >> (int)Intrinsic.Arm64VSizeShift,
info.Inst,
(uint)operation.GetSource(1).AsInt32(),
operation.Destination,
operation.GetSource(0));
break;
case IntrinsicType.VectorBinary:
GenerateVectorBinary(
context,
(uint)(intrin & Intrinsic.Arm64VTypeMask) >> (int)Intrinsic.Arm64VTypeShift,
(uint)(intrin & Intrinsic.Arm64VSizeMask) >> (int)Intrinsic.Arm64VSizeShift,
info.Inst,
operation.Destination,
operation.GetSource(0),
operation.GetSource(1));
break;
case IntrinsicType.VectorBinaryBitwise:
GenerateVectorBinary(
context,
(uint)(intrin & Intrinsic.Arm64VTypeMask) >> (int)Intrinsic.Arm64VTypeShift,
info.Inst,
operation.Destination,
operation.GetSource(0),
operation.GetSource(1));
break;
case IntrinsicType.VectorBinaryByElem:
Debug.Assert(operation.GetSource(2).Kind == OperandKind.Constant);
GenerateVectorBinaryByElem(
context,
(uint)(intrin & Intrinsic.Arm64VTypeMask) >> (int)Intrinsic.Arm64VTypeShift,
(uint)(intrin & Intrinsic.Arm64VSizeMask) >> (int)Intrinsic.Arm64VSizeShift,
info.Inst,
(uint)operation.GetSource(2).AsInt32(),
operation.Destination,
operation.GetSource(0),
operation.GetSource(1));
break;
case IntrinsicType.VectorBinaryFPByElem:
Debug.Assert(operation.GetSource(2).Kind == OperandKind.Constant);
GenerateVectorBinaryFPByElem(
context,
(uint)(intrin & Intrinsic.Arm64VTypeMask) >> (int)Intrinsic.Arm64VTypeShift,
(uint)(intrin & Intrinsic.Arm64VSizeMask) >> (int)Intrinsic.Arm64VSizeShift,
info.Inst,
(uint)operation.GetSource(2).AsInt32(),
operation.Destination,
operation.GetSource(0),
operation.GetSource(1));
break;
case IntrinsicType.VectorBinaryRd:
GenerateVectorUnary(
context,
(uint)(intrin & Intrinsic.Arm64VTypeMask) >> (int)Intrinsic.Arm64VTypeShift,
(uint)(intrin & Intrinsic.Arm64VSizeMask) >> (int)Intrinsic.Arm64VSizeShift,
info.Inst,
operation.Destination,
operation.GetSource(1));
break;
case IntrinsicType.VectorBinaryShl:
Debug.Assert(operation.GetSource(1).Kind == OperandKind.Constant);
GenerateVectorBinaryShlImm(
context,
(uint)(intrin & Intrinsic.Arm64VTypeMask) >> (int)Intrinsic.Arm64VTypeShift,
(uint)(intrin & Intrinsic.Arm64VSizeMask) >> (int)Intrinsic.Arm64VSizeShift,
info.Inst,
operation.Destination,
operation.GetSource(0),
(uint)operation.GetSource(1).AsInt32());
break;
case IntrinsicType.VectorBinaryShr:
Debug.Assert(operation.GetSource(1).Kind == OperandKind.Constant);
GenerateVectorBinaryShrImm(
context,
(uint)(intrin & Intrinsic.Arm64VTypeMask) >> (int)Intrinsic.Arm64VTypeShift,
(uint)(intrin & Intrinsic.Arm64VSizeMask) >> (int)Intrinsic.Arm64VSizeShift,
info.Inst,
operation.Destination,
operation.GetSource(0),
(uint)operation.GetSource(1).AsInt32());
break;
case IntrinsicType.VectorFPConvFixed:
Debug.Assert(operation.GetSource(1).Kind == OperandKind.Constant);
GenerateVectorBinaryShrImm(
context,
(uint)(intrin & Intrinsic.Arm64VTypeMask) >> (int)Intrinsic.Arm64VTypeShift,
((uint)(intrin & Intrinsic.Arm64VSizeMask) >> (int)Intrinsic.Arm64VSizeShift) + 2u,
info.Inst,
operation.Destination,
operation.GetSource(0),
(uint)operation.GetSource(1).AsInt32());
break;
case IntrinsicType.VectorInsertByElem:
Debug.Assert(operation.GetSource(1).Kind == OperandKind.Constant);
Debug.Assert(operation.GetSource(3).Kind == OperandKind.Constant);
GenerateVectorInsertByElem(
context,
(uint)(intrin & Intrinsic.Arm64VSizeMask) >> (int)Intrinsic.Arm64VSizeShift,
info.Inst,
(uint)operation.GetSource(3).AsInt32(),
(uint)operation.GetSource(1).AsInt32(),
operation.Destination,
operation.GetSource(2));
break;
case IntrinsicType.VectorLookupTable:
Debug.Assert((uint)(operation.SourcesCount - 2) <= 3);
for (int i = 1; i < operation.SourcesCount - 1; i++)
{
Register currReg = operation.GetSource(i).GetRegister();
Register prevReg = operation.GetSource(i - 1).GetRegister();
Debug.Assert(prevReg.Index + 1 == currReg.Index && currReg.Type == RegisterType.Vector);
}
GenerateVectorBinary(
context,
(uint)(intrin & Intrinsic.Arm64VTypeMask) >> (int)Intrinsic.Arm64VTypeShift,
info.Inst | ((uint)(operation.SourcesCount - 2) << 13),
operation.Destination,
operation.GetSource(0),
operation.GetSource(operation.SourcesCount - 1));
break;
case IntrinsicType.VectorTernaryFPRdByElem:
Debug.Assert(operation.GetSource(3).Kind == OperandKind.Constant);
GenerateVectorBinaryFPByElem(
context,
(uint)(intrin & Intrinsic.Arm64VTypeMask) >> (int)Intrinsic.Arm64VTypeShift,
(uint)(intrin & Intrinsic.Arm64VSizeMask) >> (int)Intrinsic.Arm64VSizeShift,
info.Inst,
(uint)operation.GetSource(3).AsInt32(),
operation.Destination,
operation.GetSource(1),
operation.GetSource(2));
break;
case IntrinsicType.VectorTernaryRd:
GenerateVectorBinary(
context,
(uint)(intrin & Intrinsic.Arm64VTypeMask) >> (int)Intrinsic.Arm64VTypeShift,
(uint)(intrin & Intrinsic.Arm64VSizeMask) >> (int)Intrinsic.Arm64VSizeShift,
info.Inst,
operation.Destination,
operation.GetSource(1),
operation.GetSource(2));
break;
case IntrinsicType.VectorTernaryRdBitwise:
GenerateVectorBinary(
context,
(uint)(intrin & Intrinsic.Arm64VTypeMask) >> (int)Intrinsic.Arm64VTypeShift,
info.Inst,
operation.Destination,
operation.GetSource(1),
operation.GetSource(2));
break;
case IntrinsicType.VectorTernaryRdByElem:
Debug.Assert(operation.GetSource(3).Kind == OperandKind.Constant);
GenerateVectorBinaryByElem(
context,
(uint)(intrin & Intrinsic.Arm64VTypeMask) >> (int)Intrinsic.Arm64VTypeShift,
(uint)(intrin & Intrinsic.Arm64VSizeMask) >> (int)Intrinsic.Arm64VSizeShift,
info.Inst,
(uint)operation.GetSource(3).AsInt32(),
operation.Destination,
operation.GetSource(1),
operation.GetSource(2));
break;
case IntrinsicType.VectorTernaryShlRd:
Debug.Assert(operation.GetSource(2).Kind == OperandKind.Constant);
GenerateVectorBinaryShlImm(
context,
(uint)(intrin & Intrinsic.Arm64VTypeMask) >> (int)Intrinsic.Arm64VTypeShift,
(uint)(intrin & Intrinsic.Arm64VSizeMask) >> (int)Intrinsic.Arm64VSizeShift,
info.Inst,
operation.Destination,
operation.GetSource(1),
(uint)operation.GetSource(2).AsInt32());
break;
case IntrinsicType.VectorTernaryShrRd:
Debug.Assert(operation.GetSource(2).Kind == OperandKind.Constant);
GenerateVectorBinaryShrImm(
context,
(uint)(intrin & Intrinsic.Arm64VTypeMask) >> (int)Intrinsic.Arm64VTypeShift,
(uint)(intrin & Intrinsic.Arm64VSizeMask) >> (int)Intrinsic.Arm64VSizeShift,
info.Inst,
operation.Destination,
operation.GetSource(1),
(uint)operation.GetSource(2).AsInt32());
break;
case IntrinsicType.GetRegister:
context.Assembler.WriteInstruction(info.Inst, operation.Destination);
break;
case IntrinsicType.SetRegister:
context.Assembler.WriteInstruction(info.Inst, operation.GetSource(0));
break;
default:
throw new NotImplementedException(info.Type.ToString());
}
}
private static void GenerateScalarFPCompare(
CodeGenContext context,
uint sz,
uint instruction,
Operand dest,
Operand rn,
Operand rm)
{
instruction |= (sz << 22);
if (rm.Kind == OperandKind.Constant && rm.Value == 0)
{
instruction |= 0b1000;
rm = rn;
}
context.Assembler.WriteInstructionRm16NoRet(instruction, rn, rm);
context.Assembler.Mrs(dest, 1, 3, 4, 2, 0);
}
private static void GenerateScalarFPConvGpr(
CodeGenContext context,
uint sz,
uint instruction,
Operand rd,
Operand rn)
{
instruction |= (sz << 22);
if (rd.Type.IsInteger())
{
context.Assembler.WriteInstructionAuto(instruction, rd, rn);
}
else
{
if (rn.Type == OperandType.I64)
{
instruction |= Assembler.SfFlag;
}
context.Assembler.WriteInstruction(instruction, rd, rn);
}
}
private static void GenerateScalarFPConvGpr(
CodeGenContext context,
uint sz,
uint instruction,
Operand rd,
Operand rn,
uint fBits)
{
Debug.Assert(fBits <= 64);
instruction |= (sz << 22);
instruction |= (64 - fBits) << 10;
if (rd.Type.IsInteger())
{
Debug.Assert(rd.Type != OperandType.I32 || fBits <= 32);
context.Assembler.WriteInstructionAuto(instruction, rd, rn);
}
else
{
if (rn.Type == OperandType.I64)
{
instruction |= Assembler.SfFlag;
}
else
{
Debug.Assert(fBits <= 32);
}
context.Assembler.WriteInstruction(instruction, rd, rn);
}
}
private static void GenerateScalarTernary(
CodeGenContext context,
uint sz,
uint instruction,
Operand rd,
Operand rn,
Operand rm,
Operand ra)
{
instruction |= (sz << 22);
context.Assembler.WriteInstruction(instruction, rd, rn, rm, ra);
}
private static void GenerateVectorUnary(
CodeGenContext context,
uint q,
uint sz,
uint instruction,
Operand rd,
Operand rn)
{
instruction |= (q << 30) | (sz << 22);
context.Assembler.WriteInstruction(instruction, rd, rn);
}
private static void GenerateVectorUnaryByElem(
CodeGenContext context,
uint q,
uint sz,
uint instruction,
uint srcIndex,
Operand rd,
Operand rn)
{
uint imm5 = (srcIndex << ((int)sz + 1)) | (1u << (int)sz);
instruction |= (q << 30) | (imm5 << 16);
context.Assembler.WriteInstruction(instruction, rd, rn);
}
private static void GenerateVectorBinary(
CodeGenContext context,
uint q,
uint instruction,
Operand rd,
Operand rn,
Operand rm)
{
instruction |= (q << 30);
context.Assembler.WriteInstructionRm16(instruction, rd, rn, rm);
}
private static void GenerateVectorBinary(
CodeGenContext context,
uint q,
uint sz,
uint instruction,
Operand rd,
Operand rn,
Operand rm)
{
instruction |= (q << 30) | (sz << 22);
context.Assembler.WriteInstructionRm16(instruction, rd, rn, rm);
}
private static void GenerateVectorBinaryByElem(
CodeGenContext context,
uint q,
uint size,
uint instruction,
uint srcIndex,
Operand rd,
Operand rn,
Operand rm)
{
instruction |= (q << 30) | (size << 22);
if (size == 2)
{
instruction |= ((srcIndex & 1) << 21) | ((srcIndex & 2) << 10);
}
else
{
instruction |= ((srcIndex & 3) << 20) | ((srcIndex & 4) << 9);
}
context.Assembler.WriteInstructionRm16(instruction, rd, rn, rm);
}
private static void GenerateVectorBinaryFPByElem(
CodeGenContext context,
uint q,
uint sz,
uint instruction,
uint srcIndex,
Operand rd,
Operand rn,
Operand rm)
{
instruction |= (q << 30) | (sz << 22);
if (sz != 0)
{
instruction |= (srcIndex & 1) << 11;
}
else
{
instruction |= ((srcIndex & 1) << 21) | ((srcIndex & 2) << 10);
}
context.Assembler.WriteInstructionRm16(instruction, rd, rn, rm);
}
private static void GenerateVectorBinaryShlImm(
CodeGenContext context,
uint q,
uint sz,
uint instruction,
Operand rd,
Operand rn,
uint shift)
{
instruction |= (q << 30);
Debug.Assert(shift >= 0 && shift < (8u << (int)sz));
uint imm = (8u << (int)sz) | (shift & (0x3fu >> (int)(3 - sz)));
instruction |= (imm << 16);
context.Assembler.WriteInstruction(instruction, rd, rn);
}
private static void GenerateVectorBinaryShrImm(
CodeGenContext context,
uint q,
uint sz,
uint instruction,
Operand rd,
Operand rn,
uint shift)
{
instruction |= (q << 30);
Debug.Assert(shift > 0 && shift <= (8u << (int)sz));
uint imm = (8u << (int)sz) | ((8u << (int)sz) - shift);
instruction |= (imm << 16);
context.Assembler.WriteInstruction(instruction, rd, rn);
}
private static void GenerateVectorInsertByElem(
CodeGenContext context,
uint sz,
uint instruction,
uint srcIndex,
uint dstIndex,
Operand rd,
Operand rn)
{
uint imm4 = srcIndex << (int)sz;
uint imm5 = (dstIndex << ((int)sz + 1)) | (1u << (int)sz);
instruction |= imm4 << 11;
instruction |= imm5 << 16;
context.Assembler.WriteInstruction(instruction, rd, rn);
}
}
}

View File

@@ -1,185 +0,0 @@
using System;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Intrinsics.Arm;
using System.Runtime.Versioning;
namespace ARMeilleure.CodeGen.Arm64
{
static partial class HardwareCapabilities
{
static HardwareCapabilities()
{
if (!ArmBase.Arm64.IsSupported)
{
return;
}
if (OperatingSystem.IsLinux())
{
LinuxFeatureInfoHwCap = (LinuxFeatureFlagsHwCap)getauxval(AT_HWCAP);
LinuxFeatureInfoHwCap2 = (LinuxFeatureFlagsHwCap2)getauxval(AT_HWCAP2);
}
if (OperatingSystem.IsMacOS())
{
for (int i = 0; i < _sysctlNames.Length; i++)
{
if (CheckSysctlName(_sysctlNames[i]))
{
MacOsFeatureInfo |= (MacOsFeatureFlags)(1 << i);
}
}
}
}
#region Linux
private const ulong AT_HWCAP = 16;
private const ulong AT_HWCAP2 = 26;
[LibraryImport("libc", SetLastError = true)]
private static partial ulong getauxval(ulong type);
[Flags]
public enum LinuxFeatureFlagsHwCap : ulong
{
Fp = 1 << 0,
Asimd = 1 << 1,
Evtstrm = 1 << 2,
Aes = 1 << 3,
Pmull = 1 << 4,
Sha1 = 1 << 5,
Sha2 = 1 << 6,
Crc32 = 1 << 7,
Atomics = 1 << 8,
FpHp = 1 << 9,
AsimdHp = 1 << 10,
CpuId = 1 << 11,
AsimdRdm = 1 << 12,
Jscvt = 1 << 13,
Fcma = 1 << 14,
Lrcpc = 1 << 15,
DcpOp = 1 << 16,
Sha3 = 1 << 17,
Sm3 = 1 << 18,
Sm4 = 1 << 19,
AsimdDp = 1 << 20,
Sha512 = 1 << 21,
Sve = 1 << 22,
AsimdFhm = 1 << 23,
Dit = 1 << 24,
Uscat = 1 << 25,
Ilrcpc = 1 << 26,
FlagM = 1 << 27,
Ssbs = 1 << 28,
Sb = 1 << 29,
Paca = 1 << 30,
Pacg = 1UL << 31
}
[Flags]
public enum LinuxFeatureFlagsHwCap2 : ulong
{
Dcpodp = 1 << 0,
Sve2 = 1 << 1,
SveAes = 1 << 2,
SvePmull = 1 << 3,
SveBitperm = 1 << 4,
SveSha3 = 1 << 5,
SveSm4 = 1 << 6,
FlagM2 = 1 << 7,
Frint = 1 << 8,
SveI8mm = 1 << 9,
SveF32mm = 1 << 10,
SveF64mm = 1 << 11,
SveBf16 = 1 << 12,
I8mm = 1 << 13,
Bf16 = 1 << 14,
Dgh = 1 << 15,
Rng = 1 << 16,
Bti = 1 << 17,
Mte = 1 << 18,
Ecv = 1 << 19,
Afp = 1 << 20,
Rpres = 1 << 21,
Mte3 = 1 << 22,
Sme = 1 << 23,
Sme_i16i64 = 1 << 24,
Sme_f64f64 = 1 << 25,
Sme_i8i32 = 1 << 26,
Sme_f16f32 = 1 << 27,
Sme_b16f32 = 1 << 28,
Sme_f32f32 = 1 << 29,
Sme_fa64 = 1 << 30,
Wfxt = 1UL << 31,
Ebf16 = 1UL << 32,
Sve_Ebf16 = 1UL << 33,
Cssc = 1UL << 34,
Rprfm = 1UL << 35,
Sve2p1 = 1UL << 36
}
public static LinuxFeatureFlagsHwCap LinuxFeatureInfoHwCap { get; } = 0;
public static LinuxFeatureFlagsHwCap2 LinuxFeatureInfoHwCap2 { get; } = 0;
#endregion
#region macOS
[LibraryImport("libSystem.dylib", SetLastError = true)]
private static unsafe partial int sysctlbyname([MarshalAs(UnmanagedType.LPStr)] string name, out int oldValue, ref ulong oldSize, IntPtr newValue, ulong newValueSize);
[SupportedOSPlatform("macos")]
private static bool CheckSysctlName(string name)
{
ulong size = sizeof(int);
if (sysctlbyname(name, out int val, ref size, IntPtr.Zero, 0) == 0 && size == sizeof(int))
{
return val != 0;
}
return false;
}
private static string[] _sysctlNames = new string[]
{
"hw.optional.floatingpoint",
"hw.optional.AdvSIMD",
"hw.optional.arm.FEAT_FP16",
"hw.optional.arm.FEAT_AES",
"hw.optional.arm.FEAT_PMULL",
"hw.optional.arm.FEAT_LSE",
"hw.optional.armv8_crc32",
"hw.optional.arm.FEAT_SHA1",
"hw.optional.arm.FEAT_SHA256"
};
[Flags]
public enum MacOsFeatureFlags
{
Fp = 1 << 0,
AdvSimd = 1 << 1,
Fp16 = 1 << 2,
Aes = 1 << 3,
Pmull = 1 << 4,
Lse = 1 << 5,
Crc32 = 1 << 6,
Sha1 = 1 << 7,
Sha256 = 1 << 8
}
public static MacOsFeatureFlags MacOsFeatureInfo { get; } = 0;
#endregion
public static bool SupportsAdvSimd => LinuxFeatureInfoHwCap.HasFlag(LinuxFeatureFlagsHwCap.Asimd) || MacOsFeatureInfo.HasFlag(MacOsFeatureFlags.AdvSimd);
public static bool SupportsAes => LinuxFeatureInfoHwCap.HasFlag(LinuxFeatureFlagsHwCap.Aes) || MacOsFeatureInfo.HasFlag(MacOsFeatureFlags.Aes);
public static bool SupportsPmull => LinuxFeatureInfoHwCap.HasFlag(LinuxFeatureFlagsHwCap.Pmull) || MacOsFeatureInfo.HasFlag(MacOsFeatureFlags.Pmull);
public static bool SupportsLse => LinuxFeatureInfoHwCap.HasFlag(LinuxFeatureFlagsHwCap.Atomics) || MacOsFeatureInfo.HasFlag(MacOsFeatureFlags.Lse);
public static bool SupportsCrc32 => LinuxFeatureInfoHwCap.HasFlag(LinuxFeatureFlagsHwCap.Crc32) || MacOsFeatureInfo.HasFlag(MacOsFeatureFlags.Crc32);
public static bool SupportsSha1 => LinuxFeatureInfoHwCap.HasFlag(LinuxFeatureFlagsHwCap.Sha1) || MacOsFeatureInfo.HasFlag(MacOsFeatureFlags.Sha1);
public static bool SupportsSha256 => LinuxFeatureInfoHwCap.HasFlag(LinuxFeatureFlagsHwCap.Sha2) || MacOsFeatureInfo.HasFlag(MacOsFeatureFlags.Sha256);
}
}

View File

@@ -1,14 +0,0 @@
namespace ARMeilleure.CodeGen.Arm64
{
struct IntrinsicInfo
{
public uint Inst { get; }
public IntrinsicType Type { get; }
public IntrinsicInfo(uint inst, IntrinsicType type)
{
Inst = inst;
Type = type;
}
}
}

View File

@@ -1,461 +0,0 @@
using ARMeilleure.Common;
using ARMeilleure.IntermediateRepresentation;
namespace ARMeilleure.CodeGen.Arm64
{
static class IntrinsicTable
{
private static IntrinsicInfo[] _intrinTable;
static IntrinsicTable()
{
_intrinTable = new IntrinsicInfo[EnumUtils.GetCount(typeof(Intrinsic))];
Add(Intrinsic.Arm64AbsS, new IntrinsicInfo(0x5e20b800u, IntrinsicType.ScalarUnary));
Add(Intrinsic.Arm64AbsV, new IntrinsicInfo(0x0e20b800u, IntrinsicType.VectorUnary));
Add(Intrinsic.Arm64AddhnV, new IntrinsicInfo(0x0e204000u, IntrinsicType.VectorTernaryRd));
Add(Intrinsic.Arm64AddpS, new IntrinsicInfo(0x5e31b800u, IntrinsicType.ScalarUnary));
Add(Intrinsic.Arm64AddpV, new IntrinsicInfo(0x0e20bc00u, IntrinsicType.VectorBinary));
Add(Intrinsic.Arm64AddvV, new IntrinsicInfo(0x0e31b800u, IntrinsicType.VectorUnary));
Add(Intrinsic.Arm64AddS, new IntrinsicInfo(0x5e208400u, IntrinsicType.ScalarBinary));
Add(Intrinsic.Arm64AddV, new IntrinsicInfo(0x0e208400u, IntrinsicType.VectorBinary));
Add(Intrinsic.Arm64AesdV, new IntrinsicInfo(0x4e285800u, IntrinsicType.Vector128Unary));
Add(Intrinsic.Arm64AeseV, new IntrinsicInfo(0x4e284800u, IntrinsicType.Vector128Unary));
Add(Intrinsic.Arm64AesimcV, new IntrinsicInfo(0x4e287800u, IntrinsicType.Vector128Unary));
Add(Intrinsic.Arm64AesmcV, new IntrinsicInfo(0x4e286800u, IntrinsicType.Vector128Unary));
Add(Intrinsic.Arm64AndV, new IntrinsicInfo(0x0e201c00u, IntrinsicType.VectorBinaryBitwise));
Add(Intrinsic.Arm64BicVi, new IntrinsicInfo(0x2f001400u, IntrinsicType.VectorBinaryBitwiseImm));
Add(Intrinsic.Arm64BicV, new IntrinsicInfo(0x0e601c00u, IntrinsicType.VectorBinaryBitwise));
Add(Intrinsic.Arm64BifV, new IntrinsicInfo(0x2ee01c00u, IntrinsicType.VectorTernaryRdBitwise));
Add(Intrinsic.Arm64BitV, new IntrinsicInfo(0x2ea01c00u, IntrinsicType.VectorTernaryRdBitwise));
Add(Intrinsic.Arm64BslV, new IntrinsicInfo(0x2e601c00u, IntrinsicType.VectorTernaryRdBitwise));
Add(Intrinsic.Arm64ClsV, new IntrinsicInfo(0x0e204800u, IntrinsicType.VectorUnary));
Add(Intrinsic.Arm64ClzV, new IntrinsicInfo(0x2e204800u, IntrinsicType.VectorUnary));
Add(Intrinsic.Arm64CmeqS, new IntrinsicInfo(0x7e208c00u, IntrinsicType.ScalarBinary));
Add(Intrinsic.Arm64CmeqV, new IntrinsicInfo(0x2e208c00u, IntrinsicType.VectorBinary));
Add(Intrinsic.Arm64CmeqSz, new IntrinsicInfo(0x5e209800u, IntrinsicType.ScalarUnary));
Add(Intrinsic.Arm64CmeqVz, new IntrinsicInfo(0x0e209800u, IntrinsicType.VectorUnary));
Add(Intrinsic.Arm64CmgeS, new IntrinsicInfo(0x5e203c00u, IntrinsicType.ScalarBinary));
Add(Intrinsic.Arm64CmgeV, new IntrinsicInfo(0x0e203c00u, IntrinsicType.VectorBinary));
Add(Intrinsic.Arm64CmgeSz, new IntrinsicInfo(0x7e208800u, IntrinsicType.ScalarUnary));
Add(Intrinsic.Arm64CmgeVz, new IntrinsicInfo(0x2e208800u, IntrinsicType.VectorUnary));
Add(Intrinsic.Arm64CmgtS, new IntrinsicInfo(0x5e203400u, IntrinsicType.ScalarBinary));
Add(Intrinsic.Arm64CmgtV, new IntrinsicInfo(0x0e203400u, IntrinsicType.VectorBinary));
Add(Intrinsic.Arm64CmgtSz, new IntrinsicInfo(0x5e208800u, IntrinsicType.ScalarUnary));
Add(Intrinsic.Arm64CmgtVz, new IntrinsicInfo(0x0e208800u, IntrinsicType.VectorUnary));
Add(Intrinsic.Arm64CmhiS, new IntrinsicInfo(0x7e203400u, IntrinsicType.ScalarBinary));
Add(Intrinsic.Arm64CmhiV, new IntrinsicInfo(0x2e203400u, IntrinsicType.VectorBinary));
Add(Intrinsic.Arm64CmhsS, new IntrinsicInfo(0x7e203c00u, IntrinsicType.ScalarBinary));
Add(Intrinsic.Arm64CmhsV, new IntrinsicInfo(0x2e203c00u, IntrinsicType.VectorBinary));
Add(Intrinsic.Arm64CmleSz, new IntrinsicInfo(0x7e209800u, IntrinsicType.ScalarUnary));
Add(Intrinsic.Arm64CmleVz, new IntrinsicInfo(0x2e209800u, IntrinsicType.VectorUnary));
Add(Intrinsic.Arm64CmltSz, new IntrinsicInfo(0x5e20a800u, IntrinsicType.ScalarUnary));
Add(Intrinsic.Arm64CmltVz, new IntrinsicInfo(0x0e20a800u, IntrinsicType.VectorUnary));
Add(Intrinsic.Arm64CmtstS, new IntrinsicInfo(0x5e208c00u, IntrinsicType.ScalarBinary));
Add(Intrinsic.Arm64CmtstV, new IntrinsicInfo(0x0e208c00u, IntrinsicType.VectorBinary));
Add(Intrinsic.Arm64CntV, new IntrinsicInfo(0x0e205800u, IntrinsicType.VectorUnary));
Add(Intrinsic.Arm64DupSe, new IntrinsicInfo(0x5e000400u, IntrinsicType.ScalarUnaryByElem));
Add(Intrinsic.Arm64DupVe, new IntrinsicInfo(0x0e000400u, IntrinsicType.VectorUnaryByElem));
Add(Intrinsic.Arm64DupGp, new IntrinsicInfo(0x0e000c00u, IntrinsicType.VectorUnaryByElem));
Add(Intrinsic.Arm64EorV, new IntrinsicInfo(0x2e201c00u, IntrinsicType.VectorBinaryBitwise));
Add(Intrinsic.Arm64ExtV, new IntrinsicInfo(0x2e000000u, IntrinsicType.VectorExt));
Add(Intrinsic.Arm64FabdS, new IntrinsicInfo(0x7ea0d400u, IntrinsicType.ScalarBinary));
Add(Intrinsic.Arm64FabdV, new IntrinsicInfo(0x2ea0d400u, IntrinsicType.VectorBinary));
Add(Intrinsic.Arm64FabsV, new IntrinsicInfo(0x0ea0f800u, IntrinsicType.VectorUnary));
Add(Intrinsic.Arm64FabsS, new IntrinsicInfo(0x1e20c000u, IntrinsicType.ScalarUnary));
Add(Intrinsic.Arm64FacgeS, new IntrinsicInfo(0x7e20ec00u, IntrinsicType.ScalarBinary));
Add(Intrinsic.Arm64FacgeV, new IntrinsicInfo(0x2e20ec00u, IntrinsicType.VectorBinary));
Add(Intrinsic.Arm64FacgtS, new IntrinsicInfo(0x7ea0ec00u, IntrinsicType.ScalarBinary));
Add(Intrinsic.Arm64FacgtV, new IntrinsicInfo(0x2ea0ec00u, IntrinsicType.VectorBinary));
Add(Intrinsic.Arm64FaddpS, new IntrinsicInfo(0x7e30d800u, IntrinsicType.ScalarUnary));
Add(Intrinsic.Arm64FaddpV, new IntrinsicInfo(0x2e20d400u, IntrinsicType.VectorBinary));
Add(Intrinsic.Arm64FaddV, new IntrinsicInfo(0x0e20d400u, IntrinsicType.VectorBinary));
Add(Intrinsic.Arm64FaddS, new IntrinsicInfo(0x1e202800u, IntrinsicType.ScalarBinary));
Add(Intrinsic.Arm64FccmpeS, new IntrinsicInfo(0x1e200410u, IntrinsicType.ScalarFPCompareCond));
Add(Intrinsic.Arm64FccmpS, new IntrinsicInfo(0x1e200400u, IntrinsicType.ScalarFPCompareCond));
Add(Intrinsic.Arm64FcmeqS, new IntrinsicInfo(0x5e20e400u, IntrinsicType.ScalarBinary));
Add(Intrinsic.Arm64FcmeqV, new IntrinsicInfo(0x0e20e400u, IntrinsicType.VectorBinary));
Add(Intrinsic.Arm64FcmeqSz, new IntrinsicInfo(0x5ea0d800u, IntrinsicType.ScalarUnary));
Add(Intrinsic.Arm64FcmeqVz, new IntrinsicInfo(0x0ea0d800u, IntrinsicType.VectorUnary));
Add(Intrinsic.Arm64FcmgeS, new IntrinsicInfo(0x7e20e400u, IntrinsicType.ScalarBinary));
Add(Intrinsic.Arm64FcmgeV, new IntrinsicInfo(0x2e20e400u, IntrinsicType.VectorBinary));
Add(Intrinsic.Arm64FcmgeSz, new IntrinsicInfo(0x7ea0c800u, IntrinsicType.ScalarUnary));
Add(Intrinsic.Arm64FcmgeVz, new IntrinsicInfo(0x2ea0c800u, IntrinsicType.VectorUnary));
Add(Intrinsic.Arm64FcmgtS, new IntrinsicInfo(0x7ea0e400u, IntrinsicType.ScalarBinary));
Add(Intrinsic.Arm64FcmgtV, new IntrinsicInfo(0x2ea0e400u, IntrinsicType.VectorBinary));
Add(Intrinsic.Arm64FcmgtSz, new IntrinsicInfo(0x5ea0c800u, IntrinsicType.ScalarUnary));
Add(Intrinsic.Arm64FcmgtVz, new IntrinsicInfo(0x0ea0c800u, IntrinsicType.VectorUnary));
Add(Intrinsic.Arm64FcmleSz, new IntrinsicInfo(0x7ea0d800u, IntrinsicType.ScalarUnary));
Add(Intrinsic.Arm64FcmleVz, new IntrinsicInfo(0x2ea0d800u, IntrinsicType.VectorUnary));
Add(Intrinsic.Arm64FcmltSz, new IntrinsicInfo(0x5ea0e800u, IntrinsicType.ScalarUnary));
Add(Intrinsic.Arm64FcmltVz, new IntrinsicInfo(0x0ea0e800u, IntrinsicType.VectorUnary));
Add(Intrinsic.Arm64FcmpeS, new IntrinsicInfo(0x1e202010u, IntrinsicType.ScalarFPCompare));
Add(Intrinsic.Arm64FcmpS, new IntrinsicInfo(0x1e202000u, IntrinsicType.ScalarFPCompare));
Add(Intrinsic.Arm64FcselS, new IntrinsicInfo(0x1e200c00u, IntrinsicType.ScalarFcsel));
Add(Intrinsic.Arm64FcvtasS, new IntrinsicInfo(0x5e21c800u, IntrinsicType.ScalarUnary));
Add(Intrinsic.Arm64FcvtasV, new IntrinsicInfo(0x0e21c800u, IntrinsicType.VectorUnary));
Add(Intrinsic.Arm64FcvtasGp, new IntrinsicInfo(0x1e240000u, IntrinsicType.ScalarFPConvGpr));
Add(Intrinsic.Arm64FcvtauS, new IntrinsicInfo(0x7e21c800u, IntrinsicType.ScalarUnary));
Add(Intrinsic.Arm64FcvtauV, new IntrinsicInfo(0x2e21c800u, IntrinsicType.VectorUnary));
Add(Intrinsic.Arm64FcvtauGp, new IntrinsicInfo(0x1e250000u, IntrinsicType.ScalarFPConvGpr));
Add(Intrinsic.Arm64FcvtlV, new IntrinsicInfo(0x0e217800u, IntrinsicType.VectorUnary));
Add(Intrinsic.Arm64FcvtmsS, new IntrinsicInfo(0x5e21b800u, IntrinsicType.ScalarUnary));
Add(Intrinsic.Arm64FcvtmsV, new IntrinsicInfo(0x0e21b800u, IntrinsicType.VectorUnary));
Add(Intrinsic.Arm64FcvtmsGp, new IntrinsicInfo(0x1e300000u, IntrinsicType.ScalarFPConvGpr));
Add(Intrinsic.Arm64FcvtmuS, new IntrinsicInfo(0x7e21b800u, IntrinsicType.ScalarUnary));
Add(Intrinsic.Arm64FcvtmuV, new IntrinsicInfo(0x2e21b800u, IntrinsicType.VectorUnary));
Add(Intrinsic.Arm64FcvtmuGp, new IntrinsicInfo(0x1e310000u, IntrinsicType.ScalarFPConvGpr));
Add(Intrinsic.Arm64FcvtnsS, new IntrinsicInfo(0x5e21a800u, IntrinsicType.ScalarUnary));
Add(Intrinsic.Arm64FcvtnsV, new IntrinsicInfo(0x0e21a800u, IntrinsicType.VectorUnary));
Add(Intrinsic.Arm64FcvtnsGp, new IntrinsicInfo(0x1e200000u, IntrinsicType.ScalarFPConvGpr));
Add(Intrinsic.Arm64FcvtnuS, new IntrinsicInfo(0x7e21a800u, IntrinsicType.ScalarUnary));
Add(Intrinsic.Arm64FcvtnuV, new IntrinsicInfo(0x2e21a800u, IntrinsicType.VectorUnary));
Add(Intrinsic.Arm64FcvtnuGp, new IntrinsicInfo(0x1e210000u, IntrinsicType.ScalarFPConvGpr));
Add(Intrinsic.Arm64FcvtnV, new IntrinsicInfo(0x0e216800u, IntrinsicType.VectorBinaryRd));
Add(Intrinsic.Arm64FcvtpsS, new IntrinsicInfo(0x5ea1a800u, IntrinsicType.ScalarUnary));
Add(Intrinsic.Arm64FcvtpsV, new IntrinsicInfo(0x0ea1a800u, IntrinsicType.VectorUnary));
Add(Intrinsic.Arm64FcvtpsGp, new IntrinsicInfo(0x1e280000u, IntrinsicType.ScalarFPConvGpr));
Add(Intrinsic.Arm64FcvtpuS, new IntrinsicInfo(0x7ea1a800u, IntrinsicType.ScalarUnary));
Add(Intrinsic.Arm64FcvtpuV, new IntrinsicInfo(0x2ea1a800u, IntrinsicType.VectorUnary));
Add(Intrinsic.Arm64FcvtpuGp, new IntrinsicInfo(0x1e290000u, IntrinsicType.ScalarFPConvGpr));
Add(Intrinsic.Arm64FcvtxnS, new IntrinsicInfo(0x7e216800u, IntrinsicType.ScalarUnary));
Add(Intrinsic.Arm64FcvtxnV, new IntrinsicInfo(0x2e216800u, IntrinsicType.VectorUnary));
Add(Intrinsic.Arm64FcvtzsSFixed, new IntrinsicInfo(0x5f00fc00u, IntrinsicType.ScalarFPConvFixed));
Add(Intrinsic.Arm64FcvtzsVFixed, new IntrinsicInfo(0x0f00fc00u, IntrinsicType.VectorFPConvFixed));
Add(Intrinsic.Arm64FcvtzsS, new IntrinsicInfo(0x5ea1b800u, IntrinsicType.ScalarUnary));
Add(Intrinsic.Arm64FcvtzsV, new IntrinsicInfo(0x0ea1b800u, IntrinsicType.VectorUnary));
Add(Intrinsic.Arm64FcvtzsGpFixed, new IntrinsicInfo(0x1e180000u, IntrinsicType.ScalarFPConvFixedGpr));
Add(Intrinsic.Arm64FcvtzsGp, new IntrinsicInfo(0x1e380000u, IntrinsicType.ScalarFPConvGpr));
Add(Intrinsic.Arm64FcvtzuSFixed, new IntrinsicInfo(0x7f00fc00u, IntrinsicType.ScalarFPConvFixed));
Add(Intrinsic.Arm64FcvtzuVFixed, new IntrinsicInfo(0x2f00fc00u, IntrinsicType.VectorFPConvFixed));
Add(Intrinsic.Arm64FcvtzuS, new IntrinsicInfo(0x7ea1b800u, IntrinsicType.ScalarUnary));
Add(Intrinsic.Arm64FcvtzuV, new IntrinsicInfo(0x2ea1b800u, IntrinsicType.VectorUnary));
Add(Intrinsic.Arm64FcvtzuGpFixed, new IntrinsicInfo(0x1e190000u, IntrinsicType.ScalarFPConvFixedGpr));
Add(Intrinsic.Arm64FcvtzuGp, new IntrinsicInfo(0x1e390000u, IntrinsicType.ScalarFPConvGpr));
Add(Intrinsic.Arm64FcvtS, new IntrinsicInfo(0x1e224000u, IntrinsicType.ScalarFPConv));
Add(Intrinsic.Arm64FdivV, new IntrinsicInfo(0x2e20fc00u, IntrinsicType.VectorBinary));
Add(Intrinsic.Arm64FdivS, new IntrinsicInfo(0x1e201800u, IntrinsicType.ScalarBinary));
Add(Intrinsic.Arm64FmaddS, new IntrinsicInfo(0x1f000000u, IntrinsicType.ScalarTernary));
Add(Intrinsic.Arm64FmaxnmpS, new IntrinsicInfo(0x7e30c800u, IntrinsicType.ScalarUnary));
Add(Intrinsic.Arm64FmaxnmpV, new IntrinsicInfo(0x2e20c400u, IntrinsicType.VectorBinary));
Add(Intrinsic.Arm64FmaxnmvV, new IntrinsicInfo(0x2e30c800u, IntrinsicType.VectorUnary));
Add(Intrinsic.Arm64FmaxnmV, new IntrinsicInfo(0x0e20c400u, IntrinsicType.VectorBinary));
Add(Intrinsic.Arm64FmaxnmS, new IntrinsicInfo(0x1e206800u, IntrinsicType.ScalarBinary));
Add(Intrinsic.Arm64FmaxpS, new IntrinsicInfo(0x7e30f800u, IntrinsicType.ScalarUnary));
Add(Intrinsic.Arm64FmaxpV, new IntrinsicInfo(0x2e20f400u, IntrinsicType.VectorBinary));
Add(Intrinsic.Arm64FmaxvV, new IntrinsicInfo(0x2e30f800u, IntrinsicType.VectorUnary));
Add(Intrinsic.Arm64FmaxV, new IntrinsicInfo(0x0e20f400u, IntrinsicType.VectorBinary));
Add(Intrinsic.Arm64FmaxS, new IntrinsicInfo(0x1e204800u, IntrinsicType.ScalarBinary));
Add(Intrinsic.Arm64FminnmpS, new IntrinsicInfo(0x7eb0c800u, IntrinsicType.ScalarUnary));
Add(Intrinsic.Arm64FminnmpV, new IntrinsicInfo(0x2ea0c400u, IntrinsicType.VectorBinary));
Add(Intrinsic.Arm64FminnmvV, new IntrinsicInfo(0x2eb0c800u, IntrinsicType.VectorUnary));
Add(Intrinsic.Arm64FminnmV, new IntrinsicInfo(0x0ea0c400u, IntrinsicType.VectorBinary));
Add(Intrinsic.Arm64FminnmS, new IntrinsicInfo(0x1e207800u, IntrinsicType.ScalarBinary));
Add(Intrinsic.Arm64FminpS, new IntrinsicInfo(0x7eb0f800u, IntrinsicType.ScalarUnary));
Add(Intrinsic.Arm64FminpV, new IntrinsicInfo(0x2ea0f400u, IntrinsicType.VectorBinary));
Add(Intrinsic.Arm64FminvV, new IntrinsicInfo(0x2eb0f800u, IntrinsicType.VectorUnary));
Add(Intrinsic.Arm64FminV, new IntrinsicInfo(0x0ea0f400u, IntrinsicType.VectorBinary));
Add(Intrinsic.Arm64FminS, new IntrinsicInfo(0x1e205800u, IntrinsicType.ScalarBinary));
Add(Intrinsic.Arm64FmlaSe, new IntrinsicInfo(0x5f801000u, IntrinsicType.ScalarTernaryFPRdByElem));
Add(Intrinsic.Arm64FmlaVe, new IntrinsicInfo(0x0f801000u, IntrinsicType.VectorTernaryFPRdByElem));
Add(Intrinsic.Arm64FmlaV, new IntrinsicInfo(0x0e20cc00u, IntrinsicType.VectorTernaryRd));
Add(Intrinsic.Arm64FmlsSe, new IntrinsicInfo(0x5f805000u, IntrinsicType.ScalarTernaryFPRdByElem));
Add(Intrinsic.Arm64FmlsVe, new IntrinsicInfo(0x0f805000u, IntrinsicType.VectorTernaryFPRdByElem));
Add(Intrinsic.Arm64FmlsV, new IntrinsicInfo(0x0ea0cc00u, IntrinsicType.VectorTernaryRd));
Add(Intrinsic.Arm64FmovVi, new IntrinsicInfo(0x0f00f400u, IntrinsicType.VectorFmovi));
Add(Intrinsic.Arm64FmovS, new IntrinsicInfo(0x1e204000u, IntrinsicType.ScalarUnary));
Add(Intrinsic.Arm64FmovGp, new IntrinsicInfo(0x1e260000u, IntrinsicType.ScalarFPConvGpr));
Add(Intrinsic.Arm64FmovSi, new IntrinsicInfo(0x1e201000u, IntrinsicType.ScalarFmovi));
Add(Intrinsic.Arm64FmsubS, new IntrinsicInfo(0x1f008000u, IntrinsicType.ScalarTernary));
Add(Intrinsic.Arm64FmulxSe, new IntrinsicInfo(0x7f809000u, IntrinsicType.ScalarBinaryFPByElem));
Add(Intrinsic.Arm64FmulxVe, new IntrinsicInfo(0x2f809000u, IntrinsicType.VectorBinaryFPByElem));
Add(Intrinsic.Arm64FmulxS, new IntrinsicInfo(0x5e20dc00u, IntrinsicType.ScalarBinary));
Add(Intrinsic.Arm64FmulxV, new IntrinsicInfo(0x0e20dc00u, IntrinsicType.VectorBinary));
Add(Intrinsic.Arm64FmulSe, new IntrinsicInfo(0x5f809000u, IntrinsicType.ScalarBinaryFPByElem));
Add(Intrinsic.Arm64FmulVe, new IntrinsicInfo(0x0f809000u, IntrinsicType.VectorBinaryFPByElem));
Add(Intrinsic.Arm64FmulV, new IntrinsicInfo(0x2e20dc00u, IntrinsicType.VectorBinary));
Add(Intrinsic.Arm64FmulS, new IntrinsicInfo(0x1e200800u, IntrinsicType.ScalarBinary));
Add(Intrinsic.Arm64FnegV, new IntrinsicInfo(0x2ea0f800u, IntrinsicType.VectorUnary));
Add(Intrinsic.Arm64FnegS, new IntrinsicInfo(0x1e214000u, IntrinsicType.ScalarUnary));
Add(Intrinsic.Arm64FnmaddS, new IntrinsicInfo(0x1f200000u, IntrinsicType.ScalarTernary));
Add(Intrinsic.Arm64FnmsubS, new IntrinsicInfo(0x1f208000u, IntrinsicType.ScalarTernary));
Add(Intrinsic.Arm64FnmulS, new IntrinsicInfo(0x1e208800u, IntrinsicType.ScalarBinary));
Add(Intrinsic.Arm64FrecpeS, new IntrinsicInfo(0x5ea1d800u, IntrinsicType.ScalarUnary));
Add(Intrinsic.Arm64FrecpeV, new IntrinsicInfo(0x0ea1d800u, IntrinsicType.VectorUnary));
Add(Intrinsic.Arm64FrecpsS, new IntrinsicInfo(0x5e20fc00u, IntrinsicType.ScalarBinary));
Add(Intrinsic.Arm64FrecpsV, new IntrinsicInfo(0x0e20fc00u, IntrinsicType.VectorBinary));
Add(Intrinsic.Arm64FrecpxS, new IntrinsicInfo(0x5ea1f800u, IntrinsicType.ScalarUnary));
Add(Intrinsic.Arm64FrintaV, new IntrinsicInfo(0x2e218800u, IntrinsicType.VectorUnary));
Add(Intrinsic.Arm64FrintaS, new IntrinsicInfo(0x1e264000u, IntrinsicType.ScalarUnary));
Add(Intrinsic.Arm64FrintiV, new IntrinsicInfo(0x2ea19800u, IntrinsicType.VectorUnary));
Add(Intrinsic.Arm64FrintiS, new IntrinsicInfo(0x1e27c000u, IntrinsicType.ScalarUnary));
Add(Intrinsic.Arm64FrintmV, new IntrinsicInfo(0x0e219800u, IntrinsicType.VectorUnary));
Add(Intrinsic.Arm64FrintmS, new IntrinsicInfo(0x1e254000u, IntrinsicType.ScalarUnary));
Add(Intrinsic.Arm64FrintnV, new IntrinsicInfo(0x0e218800u, IntrinsicType.VectorUnary));
Add(Intrinsic.Arm64FrintnS, new IntrinsicInfo(0x1e244000u, IntrinsicType.ScalarUnary));
Add(Intrinsic.Arm64FrintpV, new IntrinsicInfo(0x0ea18800u, IntrinsicType.VectorUnary));
Add(Intrinsic.Arm64FrintpS, new IntrinsicInfo(0x1e24c000u, IntrinsicType.ScalarUnary));
Add(Intrinsic.Arm64FrintxV, new IntrinsicInfo(0x2e219800u, IntrinsicType.VectorUnary));
Add(Intrinsic.Arm64FrintxS, new IntrinsicInfo(0x1e274000u, IntrinsicType.ScalarUnary));
Add(Intrinsic.Arm64FrintzV, new IntrinsicInfo(0x0ea19800u, IntrinsicType.VectorUnary));
Add(Intrinsic.Arm64FrintzS, new IntrinsicInfo(0x1e25c000u, IntrinsicType.ScalarUnary));
Add(Intrinsic.Arm64FrsqrteS, new IntrinsicInfo(0x7ea1d800u, IntrinsicType.ScalarUnary));
Add(Intrinsic.Arm64FrsqrteV, new IntrinsicInfo(0x2ea1d800u, IntrinsicType.VectorUnary));
Add(Intrinsic.Arm64FrsqrtsS, new IntrinsicInfo(0x5ea0fc00u, IntrinsicType.ScalarBinary));
Add(Intrinsic.Arm64FrsqrtsV, new IntrinsicInfo(0x0ea0fc00u, IntrinsicType.VectorBinary));
Add(Intrinsic.Arm64FsqrtV, new IntrinsicInfo(0x2ea1f800u, IntrinsicType.VectorUnary));
Add(Intrinsic.Arm64FsqrtS, new IntrinsicInfo(0x1e21c000u, IntrinsicType.ScalarUnary));
Add(Intrinsic.Arm64FsubV, new IntrinsicInfo(0x0ea0d400u, IntrinsicType.VectorBinary));
Add(Intrinsic.Arm64FsubS, new IntrinsicInfo(0x1e203800u, IntrinsicType.ScalarBinary));
Add(Intrinsic.Arm64InsVe, new IntrinsicInfo(0x6e000400u, IntrinsicType.VectorInsertByElem));
Add(Intrinsic.Arm64InsGp, new IntrinsicInfo(0x4e001c00u, IntrinsicType.ScalarUnaryByElem));
Add(Intrinsic.Arm64Ld1rV, new IntrinsicInfo(0x0d40c000u, IntrinsicType.VectorLdSt));
Add(Intrinsic.Arm64Ld1Vms, new IntrinsicInfo(0x0c402000u, IntrinsicType.VectorLdSt));
Add(Intrinsic.Arm64Ld1Vss, new IntrinsicInfo(0x0d400000u, IntrinsicType.VectorLdStSs));
Add(Intrinsic.Arm64Ld2rV, new IntrinsicInfo(0x0d60c000u, IntrinsicType.VectorLdSt));
Add(Intrinsic.Arm64Ld2Vms, new IntrinsicInfo(0x0c408000u, IntrinsicType.VectorLdSt));
Add(Intrinsic.Arm64Ld2Vss, new IntrinsicInfo(0x0d600000u, IntrinsicType.VectorLdStSs));
Add(Intrinsic.Arm64Ld3rV, new IntrinsicInfo(0x0d40e000u, IntrinsicType.VectorLdSt));
Add(Intrinsic.Arm64Ld3Vms, new IntrinsicInfo(0x0c404000u, IntrinsicType.VectorLdSt));
Add(Intrinsic.Arm64Ld3Vss, new IntrinsicInfo(0x0d402000u, IntrinsicType.VectorLdStSs));
Add(Intrinsic.Arm64Ld4rV, new IntrinsicInfo(0x0d60e000u, IntrinsicType.VectorLdSt));
Add(Intrinsic.Arm64Ld4Vms, new IntrinsicInfo(0x0c400000u, IntrinsicType.VectorLdSt));
Add(Intrinsic.Arm64Ld4Vss, new IntrinsicInfo(0x0d602000u, IntrinsicType.VectorLdStSs));
Add(Intrinsic.Arm64MlaVe, new IntrinsicInfo(0x2f000000u, IntrinsicType.VectorTernaryRdByElem));
Add(Intrinsic.Arm64MlaV, new IntrinsicInfo(0x0e209400u, IntrinsicType.VectorTernaryRd));
Add(Intrinsic.Arm64MlsVe, new IntrinsicInfo(0x2f004000u, IntrinsicType.VectorTernaryRdByElem));
Add(Intrinsic.Arm64MlsV, new IntrinsicInfo(0x2e209400u, IntrinsicType.VectorTernaryRd));
Add(Intrinsic.Arm64MoviV, new IntrinsicInfo(0x0f000400u, IntrinsicType.VectorMovi));
Add(Intrinsic.Arm64MrsFpsr, new IntrinsicInfo(0xd53b4420u, IntrinsicType.GetRegister));
Add(Intrinsic.Arm64MsrFpsr, new IntrinsicInfo(0xd51b4420u, IntrinsicType.SetRegister));
Add(Intrinsic.Arm64MulVe, new IntrinsicInfo(0x0f008000u, IntrinsicType.VectorBinaryByElem));
Add(Intrinsic.Arm64MulV, new IntrinsicInfo(0x0e209c00u, IntrinsicType.VectorBinary));
Add(Intrinsic.Arm64MvniV, new IntrinsicInfo(0x2f000400u, IntrinsicType.VectorMvni));
Add(Intrinsic.Arm64NegS, new IntrinsicInfo(0x7e20b800u, IntrinsicType.ScalarUnary));
Add(Intrinsic.Arm64NegV, new IntrinsicInfo(0x2e20b800u, IntrinsicType.VectorUnary));
Add(Intrinsic.Arm64NotV, new IntrinsicInfo(0x2e205800u, IntrinsicType.VectorUnaryBitwise));
Add(Intrinsic.Arm64OrnV, new IntrinsicInfo(0x0ee01c00u, IntrinsicType.VectorBinaryBitwise));
Add(Intrinsic.Arm64OrrVi, new IntrinsicInfo(0x0f001400u, IntrinsicType.VectorBinaryBitwiseImm));
Add(Intrinsic.Arm64OrrV, new IntrinsicInfo(0x0ea01c00u, IntrinsicType.VectorBinaryBitwise));
Add(Intrinsic.Arm64PmullV, new IntrinsicInfo(0x0e20e000u, IntrinsicType.VectorBinary));
Add(Intrinsic.Arm64PmulV, new IntrinsicInfo(0x2e209c00u, IntrinsicType.VectorBinary));
Add(Intrinsic.Arm64RaddhnV, new IntrinsicInfo(0x2e204000u, IntrinsicType.VectorTernaryRd));
Add(Intrinsic.Arm64RbitV, new IntrinsicInfo(0x2e605800u, IntrinsicType.VectorUnaryBitwise));
Add(Intrinsic.Arm64Rev16V, new IntrinsicInfo(0x0e201800u, IntrinsicType.VectorUnary));
Add(Intrinsic.Arm64Rev32V, new IntrinsicInfo(0x2e200800u, IntrinsicType.VectorUnary));
Add(Intrinsic.Arm64Rev64V, new IntrinsicInfo(0x0e200800u, IntrinsicType.VectorUnary));
Add(Intrinsic.Arm64RshrnV, new IntrinsicInfo(0x0f008c00u, IntrinsicType.VectorTernaryShrRd));
Add(Intrinsic.Arm64RsubhnV, new IntrinsicInfo(0x2e206000u, IntrinsicType.VectorTernaryRd));
Add(Intrinsic.Arm64SabalV, new IntrinsicInfo(0x0e205000u, IntrinsicType.VectorTernaryRd));
Add(Intrinsic.Arm64SabaV, new IntrinsicInfo(0x0e207c00u, IntrinsicType.VectorTernaryRd));
Add(Intrinsic.Arm64SabdlV, new IntrinsicInfo(0x0e207000u, IntrinsicType.VectorBinary));
Add(Intrinsic.Arm64SabdV, new IntrinsicInfo(0x0e207400u, IntrinsicType.VectorBinary));
Add(Intrinsic.Arm64SadalpV, new IntrinsicInfo(0x0e206800u, IntrinsicType.VectorBinaryRd));
Add(Intrinsic.Arm64SaddlpV, new IntrinsicInfo(0x0e202800u, IntrinsicType.VectorUnary));
Add(Intrinsic.Arm64SaddlvV, new IntrinsicInfo(0x0e303800u, IntrinsicType.VectorUnary));
Add(Intrinsic.Arm64SaddlV, new IntrinsicInfo(0x0e200000u, IntrinsicType.VectorBinary));
Add(Intrinsic.Arm64SaddwV, new IntrinsicInfo(0x0e201000u, IntrinsicType.VectorBinary));
Add(Intrinsic.Arm64ScvtfSFixed, new IntrinsicInfo(0x5f00e400u, IntrinsicType.ScalarFPConvFixed));
Add(Intrinsic.Arm64ScvtfVFixed, new IntrinsicInfo(0x0f00e400u, IntrinsicType.VectorFPConvFixed));
Add(Intrinsic.Arm64ScvtfS, new IntrinsicInfo(0x5e21d800u, IntrinsicType.ScalarUnary));
Add(Intrinsic.Arm64ScvtfV, new IntrinsicInfo(0x0e21d800u, IntrinsicType.VectorUnary));
Add(Intrinsic.Arm64ScvtfGpFixed, new IntrinsicInfo(0x1e020000u, IntrinsicType.ScalarFPConvFixedGpr));
Add(Intrinsic.Arm64ScvtfGp, new IntrinsicInfo(0x1e220000u, IntrinsicType.ScalarFPConvGpr));
Add(Intrinsic.Arm64Sha1cV, new IntrinsicInfo(0x5e000000u, IntrinsicType.Vector128Binary));
Add(Intrinsic.Arm64Sha1hV, new IntrinsicInfo(0x5e280800u, IntrinsicType.Vector128Unary));
Add(Intrinsic.Arm64Sha1mV, new IntrinsicInfo(0x5e002000u, IntrinsicType.Vector128Binary));
Add(Intrinsic.Arm64Sha1pV, new IntrinsicInfo(0x5e001000u, IntrinsicType.Vector128Binary));
Add(Intrinsic.Arm64Sha1su0V, new IntrinsicInfo(0x5e003000u, IntrinsicType.Vector128Binary));
Add(Intrinsic.Arm64Sha1su1V, new IntrinsicInfo(0x5e281800u, IntrinsicType.Vector128Unary));
Add(Intrinsic.Arm64Sha256h2V, new IntrinsicInfo(0x5e005000u, IntrinsicType.Vector128Binary));
Add(Intrinsic.Arm64Sha256hV, new IntrinsicInfo(0x5e004000u, IntrinsicType.Vector128Binary));
Add(Intrinsic.Arm64Sha256su0V, new IntrinsicInfo(0x5e282800u, IntrinsicType.Vector128Unary));
Add(Intrinsic.Arm64Sha256su1V, new IntrinsicInfo(0x5e006000u, IntrinsicType.Vector128Binary));
Add(Intrinsic.Arm64ShaddV, new IntrinsicInfo(0x0e200400u, IntrinsicType.VectorBinary));
Add(Intrinsic.Arm64ShllV, new IntrinsicInfo(0x2e213800u, IntrinsicType.VectorUnary));
Add(Intrinsic.Arm64ShlS, new IntrinsicInfo(0x5f005400u, IntrinsicType.ScalarBinaryShl));
Add(Intrinsic.Arm64ShlV, new IntrinsicInfo(0x0f005400u, IntrinsicType.VectorBinaryShl));
Add(Intrinsic.Arm64ShrnV, new IntrinsicInfo(0x0f008400u, IntrinsicType.VectorTernaryShrRd));
Add(Intrinsic.Arm64ShsubV, new IntrinsicInfo(0x0e202400u, IntrinsicType.VectorBinary));
Add(Intrinsic.Arm64SliS, new IntrinsicInfo(0x7f005400u, IntrinsicType.ScalarTernaryShlRd));
Add(Intrinsic.Arm64SliV, new IntrinsicInfo(0x2f005400u, IntrinsicType.VectorTernaryShlRd));
Add(Intrinsic.Arm64SmaxpV, new IntrinsicInfo(0x0e20a400u, IntrinsicType.VectorBinary));
Add(Intrinsic.Arm64SmaxvV, new IntrinsicInfo(0x0e30a800u, IntrinsicType.VectorUnary));
Add(Intrinsic.Arm64SmaxV, new IntrinsicInfo(0x0e206400u, IntrinsicType.VectorBinary));
Add(Intrinsic.Arm64SminpV, new IntrinsicInfo(0x0e20ac00u, IntrinsicType.VectorBinary));
Add(Intrinsic.Arm64SminvV, new IntrinsicInfo(0x0e31a800u, IntrinsicType.VectorUnary));
Add(Intrinsic.Arm64SminV, new IntrinsicInfo(0x0e206c00u, IntrinsicType.VectorBinary));
Add(Intrinsic.Arm64SmlalVe, new IntrinsicInfo(0x0f002000u, IntrinsicType.VectorTernaryRdByElem));
Add(Intrinsic.Arm64SmlalV, new IntrinsicInfo(0x0e208000u, IntrinsicType.VectorTernaryRd));
Add(Intrinsic.Arm64SmlslVe, new IntrinsicInfo(0x0f006000u, IntrinsicType.VectorTernaryRdByElem));
Add(Intrinsic.Arm64SmlslV, new IntrinsicInfo(0x0e20a000u, IntrinsicType.VectorTernaryRd));
Add(Intrinsic.Arm64SmovV, new IntrinsicInfo(0x0e002c00u, IntrinsicType.VectorUnaryByElem));
Add(Intrinsic.Arm64SmullVe, new IntrinsicInfo(0x0f00a000u, IntrinsicType.VectorBinaryByElem));
Add(Intrinsic.Arm64SmullV, new IntrinsicInfo(0x0e20c000u, IntrinsicType.VectorBinary));
Add(Intrinsic.Arm64SqabsS, new IntrinsicInfo(0x5e207800u, IntrinsicType.ScalarUnary));
Add(Intrinsic.Arm64SqabsV, new IntrinsicInfo(0x0e207800u, IntrinsicType.VectorUnary));
Add(Intrinsic.Arm64SqaddS, new IntrinsicInfo(0x5e200c00u, IntrinsicType.ScalarBinary));
Add(Intrinsic.Arm64SqaddV, new IntrinsicInfo(0x0e200c00u, IntrinsicType.VectorBinary));
Add(Intrinsic.Arm64SqdmlalSe, new IntrinsicInfo(0x5f003000u, IntrinsicType.ScalarBinaryByElem));
Add(Intrinsic.Arm64SqdmlalVe, new IntrinsicInfo(0x0f003000u, IntrinsicType.VectorBinaryByElem));
Add(Intrinsic.Arm64SqdmlalS, new IntrinsicInfo(0x5e209000u, IntrinsicType.ScalarBinary));
Add(Intrinsic.Arm64SqdmlalV, new IntrinsicInfo(0x0e209000u, IntrinsicType.VectorBinary));
Add(Intrinsic.Arm64SqdmlslSe, new IntrinsicInfo(0x5f007000u, IntrinsicType.ScalarBinaryByElem));
Add(Intrinsic.Arm64SqdmlslVe, new IntrinsicInfo(0x0f007000u, IntrinsicType.VectorBinaryByElem));
Add(Intrinsic.Arm64SqdmlslS, new IntrinsicInfo(0x5e20b000u, IntrinsicType.ScalarBinary));
Add(Intrinsic.Arm64SqdmlslV, new IntrinsicInfo(0x0e20b000u, IntrinsicType.VectorBinary));
Add(Intrinsic.Arm64SqdmulhSe, new IntrinsicInfo(0x5f00c000u, IntrinsicType.ScalarBinaryByElem));
Add(Intrinsic.Arm64SqdmulhVe, new IntrinsicInfo(0x0f00c000u, IntrinsicType.VectorBinaryByElem));
Add(Intrinsic.Arm64SqdmulhS, new IntrinsicInfo(0x5e20b400u, IntrinsicType.ScalarBinary));
Add(Intrinsic.Arm64SqdmulhV, new IntrinsicInfo(0x0e20b400u, IntrinsicType.VectorBinary));
Add(Intrinsic.Arm64SqdmullSe, new IntrinsicInfo(0x5f00b000u, IntrinsicType.ScalarBinaryByElem));
Add(Intrinsic.Arm64SqdmullVe, new IntrinsicInfo(0x0f00b000u, IntrinsicType.VectorBinaryByElem));
Add(Intrinsic.Arm64SqdmullS, new IntrinsicInfo(0x5e20d000u, IntrinsicType.ScalarBinary));
Add(Intrinsic.Arm64SqdmullV, new IntrinsicInfo(0x0e20d000u, IntrinsicType.VectorBinary));
Add(Intrinsic.Arm64SqnegS, new IntrinsicInfo(0x7e207800u, IntrinsicType.ScalarUnary));
Add(Intrinsic.Arm64SqnegV, new IntrinsicInfo(0x2e207800u, IntrinsicType.VectorUnary));
Add(Intrinsic.Arm64SqrdmulhSe, new IntrinsicInfo(0x5f00d000u, IntrinsicType.ScalarBinaryByElem));
Add(Intrinsic.Arm64SqrdmulhVe, new IntrinsicInfo(0x0f00d000u, IntrinsicType.VectorBinaryByElem));
Add(Intrinsic.Arm64SqrdmulhS, new IntrinsicInfo(0x7e20b400u, IntrinsicType.ScalarBinary));
Add(Intrinsic.Arm64SqrdmulhV, new IntrinsicInfo(0x2e20b400u, IntrinsicType.VectorBinary));
Add(Intrinsic.Arm64SqrshlS, new IntrinsicInfo(0x5e205c00u, IntrinsicType.ScalarBinary));
Add(Intrinsic.Arm64SqrshlV, new IntrinsicInfo(0x0e205c00u, IntrinsicType.VectorBinary));
Add(Intrinsic.Arm64SqrshrnS, new IntrinsicInfo(0x5f009c00u, IntrinsicType.ScalarTernaryShrRd));
Add(Intrinsic.Arm64SqrshrnV, new IntrinsicInfo(0x0f009c00u, IntrinsicType.VectorTernaryShrRd));
Add(Intrinsic.Arm64SqrshrunS, new IntrinsicInfo(0x7f008c00u, IntrinsicType.ScalarTernaryShrRd));
Add(Intrinsic.Arm64SqrshrunV, new IntrinsicInfo(0x2f008c00u, IntrinsicType.VectorTernaryShrRd));
Add(Intrinsic.Arm64SqshluS, new IntrinsicInfo(0x7f006400u, IntrinsicType.ScalarBinaryShl));
Add(Intrinsic.Arm64SqshluV, new IntrinsicInfo(0x2f006400u, IntrinsicType.VectorBinaryShl));
Add(Intrinsic.Arm64SqshlSi, new IntrinsicInfo(0x5f007400u, IntrinsicType.ScalarBinaryShl));
Add(Intrinsic.Arm64SqshlVi, new IntrinsicInfo(0x0f007400u, IntrinsicType.VectorBinaryShl));
Add(Intrinsic.Arm64SqshlS, new IntrinsicInfo(0x5e204c00u, IntrinsicType.ScalarBinary));
Add(Intrinsic.Arm64SqshlV, new IntrinsicInfo(0x0e204c00u, IntrinsicType.VectorBinary));
Add(Intrinsic.Arm64SqshrnS, new IntrinsicInfo(0x5f009400u, IntrinsicType.ScalarTernaryShrRd));
Add(Intrinsic.Arm64SqshrnV, new IntrinsicInfo(0x0f009400u, IntrinsicType.VectorTernaryShrRd));
Add(Intrinsic.Arm64SqshrunS, new IntrinsicInfo(0x7f008400u, IntrinsicType.ScalarTernaryShrRd));
Add(Intrinsic.Arm64SqshrunV, new IntrinsicInfo(0x2f008400u, IntrinsicType.VectorTernaryShrRd));
Add(Intrinsic.Arm64SqsubS, new IntrinsicInfo(0x5e202c00u, IntrinsicType.ScalarBinary));
Add(Intrinsic.Arm64SqsubV, new IntrinsicInfo(0x0e202c00u, IntrinsicType.VectorBinary));
Add(Intrinsic.Arm64SqxtnS, new IntrinsicInfo(0x5e214800u, IntrinsicType.ScalarBinaryRd));
Add(Intrinsic.Arm64SqxtnV, new IntrinsicInfo(0x0e214800u, IntrinsicType.VectorBinaryRd));
Add(Intrinsic.Arm64SqxtunS, new IntrinsicInfo(0x7e212800u, IntrinsicType.ScalarBinaryRd));
Add(Intrinsic.Arm64SqxtunV, new IntrinsicInfo(0x2e212800u, IntrinsicType.VectorBinaryRd));
Add(Intrinsic.Arm64SrhaddV, new IntrinsicInfo(0x0e201400u, IntrinsicType.VectorBinary));
Add(Intrinsic.Arm64SriS, new IntrinsicInfo(0x7f004400u, IntrinsicType.ScalarTernaryShrRd));
Add(Intrinsic.Arm64SriV, new IntrinsicInfo(0x2f004400u, IntrinsicType.VectorTernaryShrRd));
Add(Intrinsic.Arm64SrshlS, new IntrinsicInfo(0x5e205400u, IntrinsicType.ScalarBinary));
Add(Intrinsic.Arm64SrshlV, new IntrinsicInfo(0x0e205400u, IntrinsicType.VectorBinary));
Add(Intrinsic.Arm64SrshrS, new IntrinsicInfo(0x5f002400u, IntrinsicType.ScalarBinaryShr));
Add(Intrinsic.Arm64SrshrV, new IntrinsicInfo(0x0f002400u, IntrinsicType.VectorBinaryShr));
Add(Intrinsic.Arm64SrsraS, new IntrinsicInfo(0x5f003400u, IntrinsicType.ScalarTernaryShrRd));
Add(Intrinsic.Arm64SrsraV, new IntrinsicInfo(0x0f003400u, IntrinsicType.VectorTernaryShrRd));
Add(Intrinsic.Arm64SshllV, new IntrinsicInfo(0x0f00a400u, IntrinsicType.VectorBinaryShl));
Add(Intrinsic.Arm64SshlS, new IntrinsicInfo(0x5e204400u, IntrinsicType.ScalarBinary));
Add(Intrinsic.Arm64SshlV, new IntrinsicInfo(0x0e204400u, IntrinsicType.VectorBinary));
Add(Intrinsic.Arm64SshrS, new IntrinsicInfo(0x5f000400u, IntrinsicType.ScalarBinaryShr));
Add(Intrinsic.Arm64SshrV, new IntrinsicInfo(0x0f000400u, IntrinsicType.VectorBinaryShr));
Add(Intrinsic.Arm64SsraS, new IntrinsicInfo(0x5f001400u, IntrinsicType.ScalarTernaryShrRd));
Add(Intrinsic.Arm64SsraV, new IntrinsicInfo(0x0f001400u, IntrinsicType.VectorTernaryShrRd));
Add(Intrinsic.Arm64SsublV, new IntrinsicInfo(0x0e202000u, IntrinsicType.VectorBinary));
Add(Intrinsic.Arm64SsubwV, new IntrinsicInfo(0x0e203000u, IntrinsicType.VectorBinary));
Add(Intrinsic.Arm64St1Vms, new IntrinsicInfo(0x0c002000u, IntrinsicType.VectorLdSt));
Add(Intrinsic.Arm64St1Vss, new IntrinsicInfo(0x0d000000u, IntrinsicType.VectorLdStSs));
Add(Intrinsic.Arm64St2Vms, new IntrinsicInfo(0x0c008000u, IntrinsicType.VectorLdSt));
Add(Intrinsic.Arm64St2Vss, new IntrinsicInfo(0x0d200000u, IntrinsicType.VectorLdStSs));
Add(Intrinsic.Arm64St3Vms, new IntrinsicInfo(0x0c004000u, IntrinsicType.VectorLdSt));
Add(Intrinsic.Arm64St3Vss, new IntrinsicInfo(0x0d002000u, IntrinsicType.VectorLdStSs));
Add(Intrinsic.Arm64St4Vms, new IntrinsicInfo(0x0c000000u, IntrinsicType.VectorLdSt));
Add(Intrinsic.Arm64St4Vss, new IntrinsicInfo(0x0d202000u, IntrinsicType.VectorLdStSs));
Add(Intrinsic.Arm64SubhnV, new IntrinsicInfo(0x0e206000u, IntrinsicType.VectorTernaryRd));
Add(Intrinsic.Arm64SubS, new IntrinsicInfo(0x7e208400u, IntrinsicType.ScalarBinary));
Add(Intrinsic.Arm64SubV, new IntrinsicInfo(0x2e208400u, IntrinsicType.VectorBinary));
Add(Intrinsic.Arm64SuqaddS, new IntrinsicInfo(0x5e203800u, IntrinsicType.ScalarBinaryRd));
Add(Intrinsic.Arm64SuqaddV, new IntrinsicInfo(0x0e203800u, IntrinsicType.VectorBinaryRd));
Add(Intrinsic.Arm64TblV, new IntrinsicInfo(0x0e000000u, IntrinsicType.VectorLookupTable));
Add(Intrinsic.Arm64TbxV, new IntrinsicInfo(0x0e001000u, IntrinsicType.VectorLookupTable));
Add(Intrinsic.Arm64Trn1V, new IntrinsicInfo(0x0e002800u, IntrinsicType.VectorBinary));
Add(Intrinsic.Arm64Trn2V, new IntrinsicInfo(0x0e006800u, IntrinsicType.VectorBinary));
Add(Intrinsic.Arm64UabalV, new IntrinsicInfo(0x2e205000u, IntrinsicType.VectorTernaryRd));
Add(Intrinsic.Arm64UabaV, new IntrinsicInfo(0x2e207c00u, IntrinsicType.VectorTernaryRd));
Add(Intrinsic.Arm64UabdlV, new IntrinsicInfo(0x2e207000u, IntrinsicType.VectorBinary));
Add(Intrinsic.Arm64UabdV, new IntrinsicInfo(0x2e207400u, IntrinsicType.VectorBinary));
Add(Intrinsic.Arm64UadalpV, new IntrinsicInfo(0x2e206800u, IntrinsicType.VectorBinaryRd));
Add(Intrinsic.Arm64UaddlpV, new IntrinsicInfo(0x2e202800u, IntrinsicType.VectorUnary));
Add(Intrinsic.Arm64UaddlvV, new IntrinsicInfo(0x2e303800u, IntrinsicType.VectorUnary));
Add(Intrinsic.Arm64UaddlV, new IntrinsicInfo(0x2e200000u, IntrinsicType.VectorBinary));
Add(Intrinsic.Arm64UaddwV, new IntrinsicInfo(0x2e201000u, IntrinsicType.VectorBinary));
Add(Intrinsic.Arm64UcvtfSFixed, new IntrinsicInfo(0x7f00e400u, IntrinsicType.ScalarFPConvFixed));
Add(Intrinsic.Arm64UcvtfVFixed, new IntrinsicInfo(0x2f00e400u, IntrinsicType.VectorFPConvFixed));
Add(Intrinsic.Arm64UcvtfS, new IntrinsicInfo(0x7e21d800u, IntrinsicType.ScalarUnary));
Add(Intrinsic.Arm64UcvtfV, new IntrinsicInfo(0x2e21d800u, IntrinsicType.VectorUnary));
Add(Intrinsic.Arm64UcvtfGpFixed, new IntrinsicInfo(0x1e030000u, IntrinsicType.ScalarFPConvFixedGpr));
Add(Intrinsic.Arm64UcvtfGp, new IntrinsicInfo(0x1e230000u, IntrinsicType.ScalarFPConvGpr));
Add(Intrinsic.Arm64UhaddV, new IntrinsicInfo(0x2e200400u, IntrinsicType.VectorBinary));
Add(Intrinsic.Arm64UhsubV, new IntrinsicInfo(0x2e202400u, IntrinsicType.VectorBinary));
Add(Intrinsic.Arm64UmaxpV, new IntrinsicInfo(0x2e20a400u, IntrinsicType.VectorBinary));
Add(Intrinsic.Arm64UmaxvV, new IntrinsicInfo(0x2e30a800u, IntrinsicType.VectorUnary));
Add(Intrinsic.Arm64UmaxV, new IntrinsicInfo(0x2e206400u, IntrinsicType.VectorBinary));
Add(Intrinsic.Arm64UminpV, new IntrinsicInfo(0x2e20ac00u, IntrinsicType.VectorBinary));
Add(Intrinsic.Arm64UminvV, new IntrinsicInfo(0x2e31a800u, IntrinsicType.VectorUnary));
Add(Intrinsic.Arm64UminV, new IntrinsicInfo(0x2e206c00u, IntrinsicType.VectorBinary));
Add(Intrinsic.Arm64UmlalVe, new IntrinsicInfo(0x2f002000u, IntrinsicType.VectorTernaryRdByElem));
Add(Intrinsic.Arm64UmlalV, new IntrinsicInfo(0x2e208000u, IntrinsicType.VectorTernaryRd));
Add(Intrinsic.Arm64UmlslVe, new IntrinsicInfo(0x2f006000u, IntrinsicType.VectorTernaryRdByElem));
Add(Intrinsic.Arm64UmlslV, new IntrinsicInfo(0x2e20a000u, IntrinsicType.VectorTernaryRd));
Add(Intrinsic.Arm64UmovV, new IntrinsicInfo(0x0e003c00u, IntrinsicType.VectorUnaryByElem));
Add(Intrinsic.Arm64UmullVe, new IntrinsicInfo(0x2f00a000u, IntrinsicType.VectorBinaryByElem));
Add(Intrinsic.Arm64UmullV, new IntrinsicInfo(0x2e20c000u, IntrinsicType.VectorBinary));
Add(Intrinsic.Arm64UqaddS, new IntrinsicInfo(0x7e200c00u, IntrinsicType.ScalarBinary));
Add(Intrinsic.Arm64UqaddV, new IntrinsicInfo(0x2e200c00u, IntrinsicType.VectorBinary));
Add(Intrinsic.Arm64UqrshlS, new IntrinsicInfo(0x7e205c00u, IntrinsicType.ScalarBinary));
Add(Intrinsic.Arm64UqrshlV, new IntrinsicInfo(0x2e205c00u, IntrinsicType.VectorBinary));
Add(Intrinsic.Arm64UqrshrnS, new IntrinsicInfo(0x7f009c00u, IntrinsicType.ScalarTernaryShrRd));
Add(Intrinsic.Arm64UqrshrnV, new IntrinsicInfo(0x2f009c00u, IntrinsicType.VectorTernaryShrRd));
Add(Intrinsic.Arm64UqshlSi, new IntrinsicInfo(0x7f007400u, IntrinsicType.ScalarBinaryShl));
Add(Intrinsic.Arm64UqshlVi, new IntrinsicInfo(0x2f007400u, IntrinsicType.VectorBinaryShl));
Add(Intrinsic.Arm64UqshlS, new IntrinsicInfo(0x7e204c00u, IntrinsicType.ScalarBinary));
Add(Intrinsic.Arm64UqshlV, new IntrinsicInfo(0x2e204c00u, IntrinsicType.VectorBinary));
Add(Intrinsic.Arm64UqshrnS, new IntrinsicInfo(0x7f009400u, IntrinsicType.ScalarTernaryShrRd));
Add(Intrinsic.Arm64UqshrnV, new IntrinsicInfo(0x2f009400u, IntrinsicType.VectorTernaryShrRd));
Add(Intrinsic.Arm64UqsubS, new IntrinsicInfo(0x7e202c00u, IntrinsicType.ScalarBinary));
Add(Intrinsic.Arm64UqsubV, new IntrinsicInfo(0x2e202c00u, IntrinsicType.VectorBinary));
Add(Intrinsic.Arm64UqxtnS, new IntrinsicInfo(0x7e214800u, IntrinsicType.ScalarBinaryRd));
Add(Intrinsic.Arm64UqxtnV, new IntrinsicInfo(0x2e214800u, IntrinsicType.VectorBinaryRd));
Add(Intrinsic.Arm64UrecpeV, new IntrinsicInfo(0x0ea1c800u, IntrinsicType.VectorUnary));
Add(Intrinsic.Arm64UrhaddV, new IntrinsicInfo(0x2e201400u, IntrinsicType.VectorBinary));
Add(Intrinsic.Arm64UrshlS, new IntrinsicInfo(0x7e205400u, IntrinsicType.ScalarBinary));
Add(Intrinsic.Arm64UrshlV, new IntrinsicInfo(0x2e205400u, IntrinsicType.VectorBinary));
Add(Intrinsic.Arm64UrshrS, new IntrinsicInfo(0x7f002400u, IntrinsicType.ScalarBinaryShr));
Add(Intrinsic.Arm64UrshrV, new IntrinsicInfo(0x2f002400u, IntrinsicType.VectorBinaryShr));
Add(Intrinsic.Arm64UrsqrteV, new IntrinsicInfo(0x2ea1c800u, IntrinsicType.VectorUnary));
Add(Intrinsic.Arm64UrsraS, new IntrinsicInfo(0x7f003400u, IntrinsicType.ScalarTernaryShrRd));
Add(Intrinsic.Arm64UrsraV, new IntrinsicInfo(0x2f003400u, IntrinsicType.VectorTernaryShrRd));
Add(Intrinsic.Arm64UshllV, new IntrinsicInfo(0x2f00a400u, IntrinsicType.VectorBinaryShl));
Add(Intrinsic.Arm64UshlS, new IntrinsicInfo(0x7e204400u, IntrinsicType.ScalarBinary));
Add(Intrinsic.Arm64UshlV, new IntrinsicInfo(0x2e204400u, IntrinsicType.VectorBinary));
Add(Intrinsic.Arm64UshrS, new IntrinsicInfo(0x7f000400u, IntrinsicType.ScalarBinaryShr));
Add(Intrinsic.Arm64UshrV, new IntrinsicInfo(0x2f000400u, IntrinsicType.VectorBinaryShr));
Add(Intrinsic.Arm64UsqaddS, new IntrinsicInfo(0x7e203800u, IntrinsicType.ScalarBinaryRd));
Add(Intrinsic.Arm64UsqaddV, new IntrinsicInfo(0x2e203800u, IntrinsicType.VectorBinaryRd));
Add(Intrinsic.Arm64UsraS, new IntrinsicInfo(0x7f001400u, IntrinsicType.ScalarTernaryShrRd));
Add(Intrinsic.Arm64UsraV, new IntrinsicInfo(0x2f001400u, IntrinsicType.VectorTernaryShrRd));
Add(Intrinsic.Arm64UsublV, new IntrinsicInfo(0x2e202000u, IntrinsicType.VectorBinary));
Add(Intrinsic.Arm64UsubwV, new IntrinsicInfo(0x2e203000u, IntrinsicType.VectorBinary));
Add(Intrinsic.Arm64Uzp1V, new IntrinsicInfo(0x0e001800u, IntrinsicType.VectorBinary));
Add(Intrinsic.Arm64Uzp2V, new IntrinsicInfo(0x0e005800u, IntrinsicType.VectorBinary));
Add(Intrinsic.Arm64XtnV, new IntrinsicInfo(0x0e212800u, IntrinsicType.VectorUnary));
Add(Intrinsic.Arm64Zip1V, new IntrinsicInfo(0x0e003800u, IntrinsicType.VectorBinary));
Add(Intrinsic.Arm64Zip2V, new IntrinsicInfo(0x0e007800u, IntrinsicType.VectorBinary));
}
private static void Add(Intrinsic intrin, IntrinsicInfo info)
{
_intrinTable[(int)intrin] = info;
}
public static IntrinsicInfo GetInfo(Intrinsic intrin)
{
return _intrinTable[(int)intrin];
}
}
}

View File

@@ -1,59 +0,0 @@
namespace ARMeilleure.CodeGen.Arm64
{
enum IntrinsicType
{
ScalarUnary,
ScalarUnaryByElem,
ScalarBinary,
ScalarBinaryByElem,
ScalarBinaryFPByElem,
ScalarBinaryRd,
ScalarBinaryShl,
ScalarBinaryShr,
ScalarFcsel,
ScalarFmovi,
ScalarFPCompare,
ScalarFPCompareCond,
ScalarFPConv,
ScalarFPConvFixed,
ScalarFPConvFixedGpr,
ScalarFPConvGpr,
ScalarTernary,
ScalarTernaryFPRdByElem,
ScalarTernaryShlRd,
ScalarTernaryShrRd,
VectorUnary,
VectorUnaryBitwise,
VectorUnaryByElem,
VectorBinary,
VectorBinaryBitwise,
VectorBinaryBitwiseImm,
VectorBinaryByElem,
VectorBinaryFPByElem,
VectorBinaryRd,
VectorBinaryShl,
VectorBinaryShr,
VectorExt,
VectorFmovi,
VectorFPConvFixed,
VectorInsertByElem,
VectorLdSt,
VectorLdStSs,
VectorLookupTable,
VectorMovi,
VectorMvni,
VectorTernaryFPRdByElem,
VectorTernaryRd,
VectorTernaryRdBitwise,
VectorTernaryRdByElem,
VectorTernaryShlRd,
VectorTernaryShrRd,
Vector128Unary,
Vector128Binary,
GetRegister,
SetRegister
}
}

View File

@@ -1,892 +0,0 @@
using ARMeilleure.CodeGen.RegisterAllocators;
using ARMeilleure.IntermediateRepresentation;
using ARMeilleure.Translation;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
using static ARMeilleure.IntermediateRepresentation.Operation.Factory;
namespace ARMeilleure.CodeGen.Arm64
{
static class PreAllocator
{
private class ConstantDict
{
private readonly Dictionary<(ulong, OperandType), Operand> _constants;
public ConstantDict()
{
_constants = new Dictionary<(ulong, OperandType), Operand>();
}
public void Add(ulong value, OperandType type, Operand local)
{
_constants.Add((value, type), local);
}
public bool TryGetValue(ulong value, OperandType type, out Operand local)
{
return _constants.TryGetValue((value, type), out local);
}
}
public static void RunPass(CompilerContext cctx, StackAllocator stackAlloc, out int maxCallArgs)
{
maxCallArgs = -1;
Span<Operation> buffer = default;
Operand[] preservedArgs = new Operand[CallingConvention.GetArgumentsOnRegsCount()];
for (BasicBlock block = cctx.Cfg.Blocks.First; block != null; block = block.ListNext)
{
ConstantDict constants = new ConstantDict();
Operation nextNode;
for (Operation node = block.Operations.First; node != default; node = nextNode)
{
nextNode = node.ListNext;
if (node.Instruction == Instruction.Phi)
{
continue;
}
InsertConstantRegCopies(constants, block.Operations, node);
InsertDestructiveRegCopies(block.Operations, node);
switch (node.Instruction)
{
case Instruction.Call:
// Get the maximum number of arguments used on a call.
// On windows, when a struct is returned from the call,
// we also need to pass the pointer where the struct
// should be written on the first argument.
int argsCount = node.SourcesCount - 1;
if (node.Destination != default && node.Destination.Type == OperandType.V128)
{
argsCount++;
}
if (maxCallArgs < argsCount)
{
maxCallArgs = argsCount;
}
// Copy values to registers expected by the function
// being called, as mandated by the ABI.
InsertCallCopies(constants, block.Operations, node);
break;
case Instruction.CompareAndSwap:
case Instruction.CompareAndSwap16:
case Instruction.CompareAndSwap8:
nextNode = GenerateCompareAndSwap(block.Operations, node);
break;
case Instruction.LoadArgument:
nextNode = InsertLoadArgumentCopy(cctx, ref buffer, block.Operations, preservedArgs, node);
break;
case Instruction.Return:
InsertReturnCopy(block.Operations, node);
break;
case Instruction.Tailcall:
InsertTailcallCopies(constants, block.Operations, stackAlloc, node, node);
break;
}
}
}
}
private static void InsertConstantRegCopies(ConstantDict constants, IntrusiveList<Operation> nodes, Operation node)
{
if (node.SourcesCount == 0 || IsIntrinsicWithConst(node))
{
return;
}
Instruction inst = node.Instruction;
Operand src1 = node.GetSource(0);
Operand src2;
if (src1.Kind == OperandKind.Constant)
{
if (!src1.Type.IsInteger())
{
// Handle non-integer types (FP32, FP64 and V128).
// For instructions without an immediate operand, we do the following:
// - Insert a copy with the constant value (as integer) to a GPR.
// - Insert a copy from the GPR to a XMM register.
// - Replace the constant use with the XMM register.
src1 = AddFloatConstantCopy(constants, nodes, node, src1);
node.SetSource(0, src1);
}
else if (!HasConstSrc1(node, src1.Value))
{
// Handle integer types.
// Most ALU instructions accepts a 32-bits immediate on the second operand.
// We need to ensure the following:
// - If the constant is on operand 1, we need to move it.
// -- But first, we try to swap operand 1 and 2 if the instruction is commutative.
// -- Doing so may allow us to encode the constant as operand 2 and avoid a copy.
// - If the constant is on operand 2, we check if the instruction supports it,
// if not, we also add a copy. 64-bits constants are usually not supported.
if (IsCommutative(node))
{
src2 = node.GetSource(1);
Operand temp = src1;
src1 = src2;
src2 = temp;
node.SetSource(0, src1);
node.SetSource(1, src2);
}
if (src1.Kind == OperandKind.Constant)
{
src1 = AddIntConstantCopy(constants, nodes, node, src1);
node.SetSource(0, src1);
}
}
}
if (node.SourcesCount < 2)
{
return;
}
src2 = node.GetSource(1);
if (src2.Kind == OperandKind.Constant)
{
if (!src2.Type.IsInteger())
{
src2 = AddFloatConstantCopy(constants, nodes, node, src2);
node.SetSource(1, src2);
}
else if (!HasConstSrc2(inst, src2))
{
src2 = AddIntConstantCopy(constants, nodes, node, src2);
node.SetSource(1, src2);
}
}
if (node.SourcesCount < 3 ||
node.Instruction == Instruction.BranchIf ||
node.Instruction == Instruction.Compare ||
node.Instruction == Instruction.VectorInsert ||
node.Instruction == Instruction.VectorInsert16 ||
node.Instruction == Instruction.VectorInsert8)
{
return;
}
for (int srcIndex = 2; srcIndex < node.SourcesCount; srcIndex++)
{
Operand src = node.GetSource(srcIndex);
if (src.Kind == OperandKind.Constant)
{
if (!src.Type.IsInteger())
{
src = AddFloatConstantCopy(constants, nodes, node, src);
node.SetSource(srcIndex, src);
}
else
{
src = AddIntConstantCopy(constants, nodes, node, src);
node.SetSource(srcIndex, src);
}
}
}
}
private static void InsertDestructiveRegCopies(IntrusiveList<Operation> nodes, Operation node)
{
if (node.Destination == default || node.SourcesCount == 0)
{
return;
}
Operand dest = node.Destination;
Operand src1 = node.GetSource(0);
if (IsSameOperandDestSrc1(node) && src1.Kind == OperandKind.LocalVariable)
{
bool useNewLocal = false;
for (int srcIndex = 1; srcIndex < node.SourcesCount; srcIndex++)
{
if (node.GetSource(srcIndex) == dest)
{
useNewLocal = true;
break;
}
}
if (useNewLocal)
{
// Dest is being used as some source already, we need to use a new
// local to store the temporary value, otherwise the value on dest
// local would be overwritten.
Operand temp = Local(dest.Type);
nodes.AddBefore(node, Operation(Instruction.Copy, temp, src1));
node.SetSource(0, temp);
nodes.AddAfter(node, Operation(Instruction.Copy, dest, temp));
node.Destination = temp;
}
else
{
nodes.AddBefore(node, Operation(Instruction.Copy, dest, src1));
node.SetSource(0, dest);
}
}
}
private static void InsertCallCopies(ConstantDict constants, IntrusiveList<Operation> nodes, Operation node)
{
Operation operation = node;
Operand dest = operation.Destination;
List<Operand> sources = new List<Operand>
{
operation.GetSource(0)
};
int argsCount = operation.SourcesCount - 1;
int intMax = CallingConvention.GetArgumentsOnRegsCount();
int vecMax = CallingConvention.GetArgumentsOnRegsCount();
int intCount = 0;
int vecCount = 0;
int stackOffset = 0;
for (int index = 0; index < argsCount; index++)
{
Operand source = operation.GetSource(index + 1);
bool passOnReg;
if (source.Type.IsInteger())
{
passOnReg = intCount < intMax;
}
else if (source.Type == OperandType.V128)
{
passOnReg = intCount + 1 < intMax;
}
else
{
passOnReg = vecCount < vecMax;
}
if (source.Type == OperandType.V128 && passOnReg)
{
// V128 is a struct, we pass each half on a GPR if possible.
Operand argReg = Gpr(CallingConvention.GetIntArgumentRegister(intCount++), OperandType.I64);
Operand argReg2 = Gpr(CallingConvention.GetIntArgumentRegister(intCount++), OperandType.I64);
nodes.AddBefore(node, Operation(Instruction.VectorExtract, argReg, source, Const(0)));
nodes.AddBefore(node, Operation(Instruction.VectorExtract, argReg2, source, Const(1)));
continue;
}
if (passOnReg)
{
Operand argReg = source.Type.IsInteger()
? Gpr(CallingConvention.GetIntArgumentRegister(intCount++), source.Type)
: Xmm(CallingConvention.GetVecArgumentRegister(vecCount++), source.Type);
Operation copyOp = Operation(Instruction.Copy, argReg, source);
InsertConstantRegCopies(constants, nodes, nodes.AddBefore(node, copyOp));
sources.Add(argReg);
}
else
{
Operand offset = Const(stackOffset);
Operation spillOp = Operation(Instruction.SpillArg, default, offset, source);
InsertConstantRegCopies(constants, nodes, nodes.AddBefore(node, spillOp));
stackOffset += source.Type.GetSizeInBytes();
}
}
if (dest != default)
{
if (dest.Type == OperandType.V128)
{
Operand retLReg = Gpr(CallingConvention.GetIntReturnRegister(), OperandType.I64);
Operand retHReg = Gpr(CallingConvention.GetIntReturnRegisterHigh(), OperandType.I64);
node = nodes.AddAfter(node, Operation(Instruction.VectorCreateScalar, dest, retLReg));
nodes.AddAfter(node, Operation(Instruction.VectorInsert, dest, dest, retHReg, Const(1)));
operation.Destination = default;
}
else
{
Operand retReg = dest.Type.IsInteger()
? Gpr(CallingConvention.GetIntReturnRegister(), dest.Type)
: Xmm(CallingConvention.GetVecReturnRegister(), dest.Type);
Operation copyOp = Operation(Instruction.Copy, dest, retReg);
nodes.AddAfter(node, copyOp);
operation.Destination = retReg;
}
}
operation.SetSources(sources.ToArray());
}
private static void InsertTailcallCopies(
ConstantDict constants,
IntrusiveList<Operation> nodes,
StackAllocator stackAlloc,
Operation node,
Operation operation)
{
List<Operand> sources = new List<Operand>
{
operation.GetSource(0)
};
int argsCount = operation.SourcesCount - 1;
int intMax = CallingConvention.GetArgumentsOnRegsCount();
int vecMax = CallingConvention.GetArgumentsOnRegsCount();
int intCount = 0;
int vecCount = 0;
// Handle arguments passed on registers.
for (int index = 0; index < argsCount; index++)
{
Operand source = operation.GetSource(1 + index);
bool passOnReg;
if (source.Type.IsInteger())
{
passOnReg = intCount + 1 < intMax;
}
else
{
passOnReg = vecCount < vecMax;
}
if (source.Type == OperandType.V128 && passOnReg)
{
// V128 is a struct, we pass each half on a GPR if possible.
Operand argReg = Gpr(CallingConvention.GetIntArgumentRegister(intCount++), OperandType.I64);
Operand argReg2 = Gpr(CallingConvention.GetIntArgumentRegister(intCount++), OperandType.I64);
nodes.AddBefore(node, Operation(Instruction.VectorExtract, argReg, source, Const(0)));
nodes.AddBefore(node, Operation(Instruction.VectorExtract, argReg2, source, Const(1)));
continue;
}
if (passOnReg)
{
Operand argReg = source.Type.IsInteger()
? Gpr(CallingConvention.GetIntArgumentRegister(intCount++), source.Type)
: Xmm(CallingConvention.GetVecArgumentRegister(vecCount++), source.Type);
Operation copyOp = Operation(Instruction.Copy, argReg, source);
InsertConstantRegCopies(constants, nodes, nodes.AddBefore(node, copyOp));
sources.Add(argReg);
}
else
{
throw new NotImplementedException("Spilling is not currently supported for tail calls. (too many arguments)");
}
}
// The target address must be on the return registers, since we
// don't return anything and it is guaranteed to not be a
// callee saved register (which would be trashed on the epilogue).
Operand tcAddress = Gpr(CodeGenCommon.TcAddressRegister, OperandType.I64);
Operation addrCopyOp = Operation(Instruction.Copy, tcAddress, operation.GetSource(0));
nodes.AddBefore(node, addrCopyOp);
sources[0] = tcAddress;
operation.SetSources(sources.ToArray());
}
private static Operation GenerateCompareAndSwap(IntrusiveList<Operation> nodes, Operation node)
{
Operand expected = node.GetSource(1);
if (expected.Type == OperandType.V128)
{
Operand dest = node.Destination;
Operand expectedLow = Local(OperandType.I64);
Operand expectedHigh = Local(OperandType.I64);
Operand desiredLow = Local(OperandType.I64);
Operand desiredHigh = Local(OperandType.I64);
Operand actualLow = Local(OperandType.I64);
Operand actualHigh = Local(OperandType.I64);
Operand address = node.GetSource(0);
Operand desired = node.GetSource(2);
void SplitOperand(Operand source, Operand low, Operand high)
{
nodes.AddBefore(node, Operation(Instruction.VectorExtract, low, source, Const(0)));
nodes.AddBefore(node, Operation(Instruction.VectorExtract, high, source, Const(1)));
}
SplitOperand(expected, expectedLow, expectedHigh);
SplitOperand(desired, desiredLow, desiredHigh);
Operation operation = node;
// Update the sources and destinations with split 64-bit halfs of the whole 128-bit values.
// We also need a additional registers that will be used to store temporary information.
operation.SetDestinations(new[] { actualLow, actualHigh, Local(OperandType.I64), Local(OperandType.I64) });
operation.SetSources(new[] { address, expectedLow, expectedHigh, desiredLow, desiredHigh });
// Add some dummy uses of the input operands, as the CAS operation will be a loop,
// so they can't be used as destination operand.
for (int i = 0; i < operation.SourcesCount; i++)
{
Operand src = operation.GetSource(i);
node = nodes.AddAfter(node, Operation(Instruction.Copy, src, src));
}
// Assemble the vector with the 64-bit values at the given memory location.
node = nodes.AddAfter(node, Operation(Instruction.VectorCreateScalar, dest, actualLow));
node = nodes.AddAfter(node, Operation(Instruction.VectorInsert, dest, dest, actualHigh, Const(1)));
}
else
{
// We need a additional register where the store result will be written to.
node.SetDestinations(new[] { node.Destination, Local(OperandType.I32) });
// Add some dummy uses of the input operands, as the CAS operation will be a loop,
// so they can't be used as destination operand.
Operation operation = node;
for (int i = 0; i < operation.SourcesCount; i++)
{
Operand src = operation.GetSource(i);
node = nodes.AddAfter(node, Operation(Instruction.Copy, src, src));
}
}
return node.ListNext;
}
private static void InsertReturnCopy(IntrusiveList<Operation> nodes, Operation node)
{
if (node.SourcesCount == 0)
{
return;
}
Operand source = node.GetSource(0);
if (source.Type == OperandType.V128)
{
Operand retLReg = Gpr(CallingConvention.GetIntReturnRegister(), OperandType.I64);
Operand retHReg = Gpr(CallingConvention.GetIntReturnRegisterHigh(), OperandType.I64);
nodes.AddBefore(node, Operation(Instruction.VectorExtract, retLReg, source, Const(0)));
nodes.AddBefore(node, Operation(Instruction.VectorExtract, retHReg, source, Const(1)));
}
else
{
Operand retReg = source.Type.IsInteger()
? Gpr(CallingConvention.GetIntReturnRegister(), source.Type)
: Xmm(CallingConvention.GetVecReturnRegister(), source.Type);
Operation retCopyOp = Operation(Instruction.Copy, retReg, source);
nodes.AddBefore(node, retCopyOp);
}
}
private static Operation InsertLoadArgumentCopy(
CompilerContext cctx,
ref Span<Operation> buffer,
IntrusiveList<Operation> nodes,
Operand[] preservedArgs,
Operation node)
{
Operand source = node.GetSource(0);
Debug.Assert(source.Kind == OperandKind.Constant, "Non-constant LoadArgument source kind.");
int index = source.AsInt32();
int intCount = 0;
int vecCount = 0;
for (int cIndex = 0; cIndex < index; cIndex++)
{
OperandType argType = cctx.FuncArgTypes[cIndex];
if (argType.IsInteger())
{
intCount++;
}
else if (argType == OperandType.V128)
{
intCount += 2;
}
else
{
vecCount++;
}
}
bool passOnReg;
if (source.Type.IsInteger())
{
passOnReg = intCount < CallingConvention.GetArgumentsOnRegsCount();
}
else if (source.Type == OperandType.V128)
{
passOnReg = intCount + 1 < CallingConvention.GetArgumentsOnRegsCount();
}
else
{
passOnReg = vecCount < CallingConvention.GetArgumentsOnRegsCount();
}
if (passOnReg)
{
Operand dest = node.Destination;
if (preservedArgs[index] == default)
{
if (dest.Type == OperandType.V128)
{
// V128 is a struct, we pass each half on a GPR if possible.
Operand pArg = Local(OperandType.V128);
Operand argLReg = Gpr(CallingConvention.GetIntArgumentRegister(intCount), OperandType.I64);
Operand argHReg = Gpr(CallingConvention.GetIntArgumentRegister(intCount + 1), OperandType.I64);
Operation copyL = Operation(Instruction.VectorCreateScalar, pArg, argLReg);
Operation copyH = Operation(Instruction.VectorInsert, pArg, pArg, argHReg, Const(1));
cctx.Cfg.Entry.Operations.AddFirst(copyH);
cctx.Cfg.Entry.Operations.AddFirst(copyL);
preservedArgs[index] = pArg;
}
else
{
Operand pArg = Local(dest.Type);
Operand argReg = dest.Type.IsInteger()
? Gpr(CallingConvention.GetIntArgumentRegister(intCount), dest.Type)
: Xmm(CallingConvention.GetVecArgumentRegister(vecCount), dest.Type);
Operation copyOp = Operation(Instruction.Copy, pArg, argReg);
cctx.Cfg.Entry.Operations.AddFirst(copyOp);
preservedArgs[index] = pArg;
}
}
Operation nextNode;
if (dest.AssignmentsCount == 1)
{
// Let's propagate the argument if we can to avoid copies.
PreAllocatorCommon.Propagate(ref buffer, dest, preservedArgs[index]);
nextNode = node.ListNext;
}
else
{
Operation argCopyOp = Operation(Instruction.Copy, dest, preservedArgs[index]);
nextNode = nodes.AddBefore(node, argCopyOp);
}
Delete(nodes, node);
return nextNode;
}
else
{
// TODO: Pass on stack.
return node;
}
}
private static Operand AddFloatConstantCopy(
ConstantDict constants,
IntrusiveList<Operation> nodes,
Operation node,
Operand source)
{
Operand temp = Local(source.Type);
Operand intConst = AddIntConstantCopy(constants, nodes, node, GetIntConst(source));
Operation copyOp = Operation(Instruction.VectorCreateScalar, temp, intConst);
nodes.AddBefore(node, copyOp);
return temp;
}
private static Operand AddIntConstantCopy(
ConstantDict constants,
IntrusiveList<Operation> nodes,
Operation node,
Operand source)
{
if (constants.TryGetValue(source.Value, source.Type, out Operand temp))
{
return temp;
}
temp = Local(source.Type);
Operation copyOp = Operation(Instruction.Copy, temp, source);
nodes.AddBefore(node, copyOp);
constants.Add(source.Value, source.Type, temp);
return temp;
}
private static Operand GetIntConst(Operand value)
{
if (value.Type == OperandType.FP32)
{
return Const(value.AsInt32());
}
else if (value.Type == OperandType.FP64)
{
return Const(value.AsInt64());
}
return value;
}
private static void Delete(IntrusiveList<Operation> nodes, Operation node)
{
node.Destination = default;
for (int index = 0; index < node.SourcesCount; index++)
{
node.SetSource(index, default);
}
nodes.Remove(node);
}
private static Operand Gpr(int register, OperandType type)
{
return Register(register, RegisterType.Integer, type);
}
private static Operand Xmm(int register, OperandType type)
{
return Register(register, RegisterType.Vector, type);
}
private static bool IsSameOperandDestSrc1(Operation operation)
{
switch (operation.Instruction)
{
case Instruction.Extended:
return IsSameOperandDestSrc1(operation.Intrinsic);
case Instruction.VectorInsert:
case Instruction.VectorInsert16:
case Instruction.VectorInsert8:
return true;
}
return false;
}
private static bool IsSameOperandDestSrc1(Intrinsic intrinsic)
{
IntrinsicInfo info = IntrinsicTable.GetInfo(intrinsic & ~(Intrinsic.Arm64VTypeMask | Intrinsic.Arm64VSizeMask));
return info.Type == IntrinsicType.ScalarBinaryRd ||
info.Type == IntrinsicType.ScalarTernaryFPRdByElem ||
info.Type == IntrinsicType.ScalarTernaryShlRd ||
info.Type == IntrinsicType.ScalarTernaryShrRd ||
info.Type == IntrinsicType.VectorBinaryRd ||
info.Type == IntrinsicType.VectorInsertByElem ||
info.Type == IntrinsicType.VectorTernaryRd ||
info.Type == IntrinsicType.VectorTernaryRdBitwise ||
info.Type == IntrinsicType.VectorTernaryFPRdByElem ||
info.Type == IntrinsicType.VectorTernaryRdByElem ||
info.Type == IntrinsicType.VectorTernaryShlRd ||
info.Type == IntrinsicType.VectorTernaryShrRd;
}
private static bool HasConstSrc1(Operation node, ulong value)
{
switch (node.Instruction)
{
case Instruction.Add:
case Instruction.BranchIf:
case Instruction.Compare:
case Instruction.Subtract:
// The immediate encoding of those instructions does not allow Rn to be
// XZR (it will be SP instead), so we can't allow a Rn constant in this case.
return value == 0 && NotConstOrConst0(node.GetSource(1));
case Instruction.BitwiseAnd:
case Instruction.BitwiseExclusiveOr:
case Instruction.BitwiseNot:
case Instruction.BitwiseOr:
case Instruction.ByteSwap:
case Instruction.CountLeadingZeros:
case Instruction.Multiply:
case Instruction.Negate:
case Instruction.RotateRight:
case Instruction.ShiftLeft:
case Instruction.ShiftRightSI:
case Instruction.ShiftRightUI:
return value == 0;
case Instruction.Copy:
case Instruction.LoadArgument:
case Instruction.Spill:
case Instruction.SpillArg:
return true;
case Instruction.Extended:
return value == 0;
}
return false;
}
private static bool NotConstOrConst0(Operand operand)
{
return operand.Kind != OperandKind.Constant || operand.Value == 0;
}
private static bool HasConstSrc2(Instruction inst, Operand operand)
{
ulong value = operand.Value;
switch (inst)
{
case Instruction.Add:
case Instruction.BranchIf:
case Instruction.Compare:
case Instruction.Subtract:
return ConstFitsOnUImm12Sh(value);
case Instruction.BitwiseAnd:
case Instruction.BitwiseExclusiveOr:
case Instruction.BitwiseOr:
return value == 0 || CodeGenCommon.TryEncodeBitMask(operand, out _, out _, out _);
case Instruction.Multiply:
case Instruction.Store:
case Instruction.Store16:
case Instruction.Store8:
return value == 0;
case Instruction.RotateRight:
case Instruction.ShiftLeft:
case Instruction.ShiftRightSI:
case Instruction.ShiftRightUI:
case Instruction.VectorExtract:
case Instruction.VectorExtract16:
case Instruction.VectorExtract8:
return true;
case Instruction.Extended:
// TODO: Check if actual intrinsic is supposed to have consts here?
// Right now we only hit this case for fixed-point int <-> FP conversion instructions.
return true;
}
return false;
}
private static bool IsCommutative(Operation operation)
{
switch (operation.Instruction)
{
case Instruction.Add:
case Instruction.BitwiseAnd:
case Instruction.BitwiseExclusiveOr:
case Instruction.BitwiseOr:
case Instruction.Multiply:
return true;
case Instruction.BranchIf:
case Instruction.Compare:
{
Operand comp = operation.GetSource(2);
Debug.Assert(comp.Kind == OperandKind.Constant);
var compType = (Comparison)comp.AsInt32();
return compType == Comparison.Equal || compType == Comparison.NotEqual;
}
}
return false;
}
private static bool ConstFitsOnUImm12Sh(ulong value)
{
return (value & ~0xfffUL) == 0 || (value & ~0xfff000UL) == 0;
}
private static bool IsIntrinsicWithConst(Operation operation)
{
bool isIntrinsic = IsIntrinsic(operation.Instruction);
if (isIntrinsic)
{
Intrinsic intrinsic = operation.Intrinsic;
IntrinsicInfo info = IntrinsicTable.GetInfo(intrinsic & ~(Intrinsic.Arm64VTypeMask | Intrinsic.Arm64VSizeMask));
// Those have integer inputs that don't support consts.
return info.Type != IntrinsicType.ScalarFPConvGpr &&
info.Type != IntrinsicType.ScalarFPConvFixedGpr &&
info.Type != IntrinsicType.SetRegister;
}
return false;
}
private static bool IsIntrinsic(Instruction inst)
{
return inst == Instruction.Extended;
}
}
}

View File

@@ -1,68 +0,0 @@
using ARMeilleure.CodeGen.Linking;
using ARMeilleure.CodeGen.Unwinding;
using ARMeilleure.Translation.Cache;
using System;
using System.Runtime.InteropServices;
namespace ARMeilleure.CodeGen
{
/// <summary>
/// Represents a compiled function.
/// </summary>
readonly struct CompiledFunction
{
/// <summary>
/// Gets the machine code of the <see cref="CompiledFunction"/>.
/// </summary>
public byte[] Code { get; }
/// <summary>
/// Gets the <see cref="Unwinding.UnwindInfo"/> of the <see cref="CompiledFunction"/>.
/// </summary>
public UnwindInfo UnwindInfo { get; }
/// <summary>
/// Gets the <see cref="Linking.RelocInfo"/> of the <see cref="CompiledFunction"/>.
/// </summary>
public RelocInfo RelocInfo { get; }
/// <summary>
/// Initializes a new instance of the <see cref="CompiledFunction"/> struct with the specified machine code,
/// unwind info and relocation info.
/// </summary>
/// <param name="code">Machine code</param>
/// <param name="unwindInfo">Unwind info</param>
/// <param name="relocInfo">Relocation info</param>
internal CompiledFunction(byte[] code, UnwindInfo unwindInfo, RelocInfo relocInfo)
{
Code = code;
UnwindInfo = unwindInfo;
RelocInfo = relocInfo;
}
/// <summary>
/// Maps the <see cref="CompiledFunction"/> onto the <see cref="JitCache"/> and returns a delegate of type
/// <typeparamref name="T"/> pointing to the mapped function.
/// </summary>
/// <typeparam name="T">Type of delegate</typeparam>
/// <returns>A delegate of type <typeparamref name="T"/> pointing to the mapped function</returns>
public T Map<T>()
{
return MapWithPointer<T>(out _);
}
/// <summary>
/// Maps the <see cref="CompiledFunction"/> onto the <see cref="JitCache"/> and returns a delegate of type
/// <typeparamref name="T"/> pointing to the mapped function.
/// </summary>
/// <typeparam name="T">Type of delegate</typeparam>
/// <param name="codePointer">Pointer to the function code in memory</param>
/// <returns>A delegate of type <typeparamref name="T"/> pointing to the mapped function</returns>
public T MapWithPointer<T>(out IntPtr codePointer)
{
codePointer = JitCache.Map(this);
return Marshal.GetDelegateForFunctionPointer<T>(codePointer);
}
}
}

View File

@@ -1,38 +0,0 @@
namespace ARMeilleure.CodeGen.Linking
{
/// <summary>
/// Represents a relocation.
/// </summary>
readonly struct RelocEntry
{
public const int Stride = 13; // Bytes.
/// <summary>
/// Gets the position of the relocation.
/// </summary>
public int Position { get; }
/// <summary>
/// Gets the <see cref="Symbol"/> of the relocation.
/// </summary>
public Symbol Symbol { get; }
/// <summary>
/// Initializes a new instance of the <see cref="RelocEntry"/> struct with the specified position and
/// <see cref="Symbol"/>.
/// </summary>
/// <param name="position">Position of relocation</param>
/// <param name="symbol">Symbol of relocation</param>
public RelocEntry(int position, Symbol symbol)
{
Position = position;
Symbol = symbol;
}
/// <inheritdoc/>
public override string ToString()
{
return $"({nameof(Position)} = {Position}, {nameof(Symbol)} = {Symbol})";
}
}
}

View File

@@ -1,32 +0,0 @@
using System;
namespace ARMeilleure.CodeGen.Linking
{
/// <summary>
/// Represents relocation information about a <see cref="CompiledFunction"/>.
/// </summary>
readonly struct RelocInfo
{
/// <summary>
/// Gets an empty <see cref="RelocInfo"/>.
/// </summary>
public static RelocInfo Empty { get; } = new RelocInfo(null);
private readonly RelocEntry[] _entries;
/// <summary>
/// Gets the set of <see cref="RelocEntry"/>.
/// </summary>
public ReadOnlySpan<RelocEntry> Entries => _entries;
/// <summary>
/// Initializes a new instance of the <see cref="RelocInfo"/> struct with the specified set of
/// <see cref="RelocEntry"/>.
/// </summary>
/// <param name="entries">Set of <see cref="RelocInfo"/> to use</param>
public RelocInfo(RelocEntry[] entries)
{
_entries = entries;
}
}
}

View File

@@ -1,28 +0,0 @@
namespace ARMeilleure.CodeGen.Linking
{
/// <summary>
/// Types of <see cref="Symbol"/>.
/// </summary>
enum SymbolType : byte
{
/// <summary>
/// Refers to nothing, i.e no symbol.
/// </summary>
None,
/// <summary>
/// Refers to an entry in <see cref="Translation.Delegates"/>.
/// </summary>
DelegateTable,
/// <summary>
/// Refers to an entry in <see cref="Translation.Translator.FunctionTable"/>.
/// </summary>
FunctionTable,
/// <summary>
/// Refers to a special symbol which is handled by <see cref="Translation.PTC.Ptc.PatchCode"/>.
/// </summary>
Special
}
}

View File

@@ -1,346 +0,0 @@
using ARMeilleure.IntermediateRepresentation;
using System;
using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
namespace ARMeilleure.CodeGen.Optimizations
{
static class ConstantFolding
{
public static void RunPass(Operation operation)
{
if (operation.Destination == default || operation.SourcesCount == 0)
{
return;
}
if (!AreAllSourcesConstant(operation))
{
return;
}
OperandType type = operation.Destination.Type;
switch (operation.Instruction)
{
case Instruction.Add:
if (operation.GetSource(0).Relocatable ||
operation.GetSource(1).Relocatable)
{
break;
}
if (type == OperandType.I32)
{
EvaluateBinaryI32(operation, (x, y) => x + y);
}
else if (type == OperandType.I64)
{
EvaluateBinaryI64(operation, (x, y) => x + y);
}
break;
case Instruction.BitwiseAnd:
if (type == OperandType.I32)
{
EvaluateBinaryI32(operation, (x, y) => x & y);
}
else if (type == OperandType.I64)
{
EvaluateBinaryI64(operation, (x, y) => x & y);
}
break;
case Instruction.BitwiseExclusiveOr:
if (type == OperandType.I32)
{
EvaluateBinaryI32(operation, (x, y) => x ^ y);
}
else if (type == OperandType.I64)
{
EvaluateBinaryI64(operation, (x, y) => x ^ y);
}
break;
case Instruction.BitwiseNot:
if (type == OperandType.I32)
{
EvaluateUnaryI32(operation, (x) => ~x);
}
else if (type == OperandType.I64)
{
EvaluateUnaryI64(operation, (x) => ~x);
}
break;
case Instruction.BitwiseOr:
if (type == OperandType.I32)
{
EvaluateBinaryI32(operation, (x, y) => x | y);
}
else if (type == OperandType.I64)
{
EvaluateBinaryI64(operation, (x, y) => x | y);
}
break;
case Instruction.ConvertI64ToI32:
if (type == OperandType.I32)
{
EvaluateUnaryI32(operation, (x) => x);
}
break;
case Instruction.Compare:
if (type == OperandType.I32 &&
operation.GetSource(0).Type == type &&
operation.GetSource(1).Type == type)
{
switch ((Comparison)operation.GetSource(2).Value)
{
case Comparison.Equal:
EvaluateBinaryI32(operation, (x, y) => x == y ? 1 : 0);
break;
case Comparison.NotEqual:
EvaluateBinaryI32(operation, (x, y) => x != y ? 1 : 0);
break;
case Comparison.Greater:
EvaluateBinaryI32(operation, (x, y) => x > y ? 1 : 0);
break;
case Comparison.LessOrEqual:
EvaluateBinaryI32(operation, (x, y) => x <= y ? 1 : 0);
break;
case Comparison.GreaterUI:
EvaluateBinaryI32(operation, (x, y) => (uint)x > (uint)y ? 1 : 0);
break;
case Comparison.LessOrEqualUI:
EvaluateBinaryI32(operation, (x, y) => (uint)x <= (uint)y ? 1 : 0);
break;
case Comparison.GreaterOrEqual:
EvaluateBinaryI32(operation, (x, y) => x >= y ? 1 : 0);
break;
case Comparison.Less:
EvaluateBinaryI32(operation, (x, y) => x < y ? 1 : 0);
break;
case Comparison.GreaterOrEqualUI:
EvaluateBinaryI32(operation, (x, y) => (uint)x >= (uint)y ? 1 : 0);
break;
case Comparison.LessUI:
EvaluateBinaryI32(operation, (x, y) => (uint)x < (uint)y ? 1 : 0);
break;
}
}
break;
case Instruction.Copy:
if (type == OperandType.I32)
{
EvaluateUnaryI32(operation, (x) => x);
}
else if (type == OperandType.I64)
{
EvaluateUnaryI64(operation, (x) => x);
}
break;
case Instruction.Divide:
if (type == OperandType.I32)
{
EvaluateBinaryI32(operation, (x, y) => y != 0 ? x / y : 0);
}
else if (type == OperandType.I64)
{
EvaluateBinaryI64(operation, (x, y) => y != 0 ? x / y : 0);
}
break;
case Instruction.DivideUI:
if (type == OperandType.I32)
{
EvaluateBinaryI32(operation, (x, y) => y != 0 ? (int)((uint)x / (uint)y) : 0);
}
else if (type == OperandType.I64)
{
EvaluateBinaryI64(operation, (x, y) => y != 0 ? (long)((ulong)x / (ulong)y) : 0);
}
break;
case Instruction.Multiply:
if (type == OperandType.I32)
{
EvaluateBinaryI32(operation, (x, y) => x * y);
}
else if (type == OperandType.I64)
{
EvaluateBinaryI64(operation, (x, y) => x * y);
}
break;
case Instruction.Negate:
if (type == OperandType.I32)
{
EvaluateUnaryI32(operation, (x) => -x);
}
else if (type == OperandType.I64)
{
EvaluateUnaryI64(operation, (x) => -x);
}
break;
case Instruction.ShiftLeft:
if (type == OperandType.I32)
{
EvaluateBinaryI32(operation, (x, y) => x << y);
}
else if (type == OperandType.I64)
{
EvaluateBinaryI64(operation, (x, y) => x << (int)y);
}
break;
case Instruction.ShiftRightSI:
if (type == OperandType.I32)
{
EvaluateBinaryI32(operation, (x, y) => x >> y);
}
else if (type == OperandType.I64)
{
EvaluateBinaryI64(operation, (x, y) => x >> (int)y);
}
break;
case Instruction.ShiftRightUI:
if (type == OperandType.I32)
{
EvaluateBinaryI32(operation, (x, y) => (int)((uint)x >> y));
}
else if (type == OperandType.I64)
{
EvaluateBinaryI64(operation, (x, y) => (long)((ulong)x >> (int)y));
}
break;
case Instruction.SignExtend16:
if (type == OperandType.I32)
{
EvaluateUnaryI32(operation, (x) => (short)x);
}
else if (type == OperandType.I64)
{
EvaluateUnaryI64(operation, (x) => (short)x);
}
break;
case Instruction.SignExtend32:
if (type == OperandType.I32)
{
EvaluateUnaryI32(operation, (x) => x);
}
else if (type == OperandType.I64)
{
EvaluateUnaryI64(operation, (x) => (int)x);
}
break;
case Instruction.SignExtend8:
if (type == OperandType.I32)
{
EvaluateUnaryI32(operation, (x) => (sbyte)x);
}
else if (type == OperandType.I64)
{
EvaluateUnaryI64(operation, (x) => (sbyte)x);
}
break;
case Instruction.ZeroExtend16:
if (type == OperandType.I32)
{
EvaluateUnaryI32(operation, (x) => (ushort)x);
}
else if (type == OperandType.I64)
{
EvaluateUnaryI64(operation, (x) => (ushort)x);
}
break;
case Instruction.ZeroExtend32:
if (type == OperandType.I32)
{
EvaluateUnaryI32(operation, (x) => x);
}
else if (type == OperandType.I64)
{
EvaluateUnaryI64(operation, (x) => (uint)x);
}
break;
case Instruction.ZeroExtend8:
if (type == OperandType.I32)
{
EvaluateUnaryI32(operation, (x) => (byte)x);
}
else if (type == OperandType.I64)
{
EvaluateUnaryI64(operation, (x) => (byte)x);
}
break;
case Instruction.Subtract:
if (type == OperandType.I32)
{
EvaluateBinaryI32(operation, (x, y) => x - y);
}
else if (type == OperandType.I64)
{
EvaluateBinaryI64(operation, (x, y) => x - y);
}
break;
}
}
private static bool AreAllSourcesConstant(Operation operation)
{
for (int index = 0; index < operation.SourcesCount; index++)
{
Operand srcOp = operation.GetSource(index);
if (srcOp.Kind != OperandKind.Constant)
{
return false;
}
}
return true;
}
private static void EvaluateUnaryI32(Operation operation, Func<int, int> op)
{
int x = operation.GetSource(0).AsInt32();
operation.TurnIntoCopy(Const(op(x)));
}
private static void EvaluateUnaryI64(Operation operation, Func<long, long> op)
{
long x = operation.GetSource(0).AsInt64();
operation.TurnIntoCopy(Const(op(x)));
}
private static void EvaluateBinaryI32(Operation operation, Func<int, int, int> op)
{
int x = operation.GetSource(0).AsInt32();
int y = operation.GetSource(1).AsInt32();
operation.TurnIntoCopy(Const(op(x, y)));
}
private static void EvaluateBinaryI64(Operation operation, Func<long, long, long> op)
{
long x = operation.GetSource(0).AsInt64();
long y = operation.GetSource(1).AsInt64();
operation.TurnIntoCopy(Const(op(x, y)));
}
}
}

View File

@@ -1,252 +0,0 @@
using ARMeilleure.IntermediateRepresentation;
using ARMeilleure.Translation;
using System;
using System.Diagnostics;
using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
namespace ARMeilleure.CodeGen.Optimizations
{
static class Optimizer
{
public static void RunPass(ControlFlowGraph cfg)
{
// Scratch buffer used to store uses.
Span<Operation> buffer = default;
bool modified;
do
{
modified = false;
for (BasicBlock block = cfg.Blocks.Last; block != null; block = block.ListPrevious)
{
Operation node;
Operation prevNode;
for (node = block.Operations.Last; node != default; node = prevNode)
{
prevNode = node.ListPrevious;
if (IsUnused(node))
{
RemoveNode(block, node);
modified = true;
continue;
}
else if (node.Instruction == Instruction.Phi)
{
continue;
}
ConstantFolding.RunPass(node);
Simplification.RunPass(node);
if (DestIsSingleLocalVar(node))
{
if (IsPropagableCompare(node))
{
modified |= PropagateCompare(ref buffer, node);
if (modified && IsUnused(node))
{
RemoveNode(block, node);
}
}
else if (IsPropagableCopy(node))
{
PropagateCopy(ref buffer, node);
RemoveNode(block, node);
modified = true;
}
}
}
}
}
while (modified);
}
public static void RemoveUnusedNodes(ControlFlowGraph cfg)
{
bool modified;
do
{
modified = false;
for (BasicBlock block = cfg.Blocks.Last; block != null; block = block.ListPrevious)
{
Operation node;
Operation prevNode;
for (node = block.Operations.Last; node != default; node = prevNode)
{
prevNode = node.ListPrevious;
if (IsUnused(node))
{
RemoveNode(block, node);
modified = true;
}
}
}
}
while (modified);
}
private static bool PropagateCompare(ref Span<Operation> buffer, Operation compOp)
{
// Try to propagate Compare operations into their BranchIf uses, when these BranchIf uses are in the form
// of:
//
// - BranchIf %x, 0x0, Equal ;; i.e BranchIfFalse %x
// - BranchIf %x, 0x0, NotEqual ;; i.e BranchIfTrue %x
//
// The commutative property of Equal and NotEqual is taken into consideration as well.
//
// For example:
//
// %x = Compare %a, %b, comp
// BranchIf %x, 0x0, NotEqual
//
// =>
//
// BranchIf %a, %b, comp
static bool IsZeroBranch(Operation operation, out Comparison compType)
{
compType = Comparison.Equal;
if (operation.Instruction != Instruction.BranchIf)
{
return false;
}
Operand src1 = operation.GetSource(0);
Operand src2 = operation.GetSource(1);
Operand comp = operation.GetSource(2);
compType = (Comparison)comp.AsInt32();
return (src1.Kind == OperandKind.Constant && src1.Value == 0) ||
(src2.Kind == OperandKind.Constant && src2.Value == 0);
}
bool modified = false;
Operand dest = compOp.Destination;
Operand src1 = compOp.GetSource(0);
Operand src2 = compOp.GetSource(1);
Operand comp = compOp.GetSource(2);
Comparison compType = (Comparison)comp.AsInt32();
Span<Operation> uses = dest.GetUses(ref buffer);
foreach (Operation use in uses)
{
// If operation is a BranchIf and has a constant value 0 in its RHS or LHS source operands.
if (IsZeroBranch(use, out Comparison otherCompType))
{
Comparison propCompType;
if (otherCompType == Comparison.NotEqual)
{
propCompType = compType;
}
else if (otherCompType == Comparison.Equal)
{
propCompType = compType.Invert();
}
else
{
continue;
}
use.SetSource(0, src1);
use.SetSource(1, src2);
use.SetSource(2, Const((int)propCompType));
modified = true;
}
}
return modified;
}
private static void PropagateCopy(ref Span<Operation> buffer, Operation copyOp)
{
// Propagate copy source operand to all uses of the destination operand.
Operand dest = copyOp.Destination;
Operand source = copyOp.GetSource(0);
Span<Operation> uses = dest.GetUses(ref buffer);
foreach (Operation use in uses)
{
for (int index = 0; index < use.SourcesCount; index++)
{
if (use.GetSource(index) == dest)
{
use.SetSource(index, source);
}
}
}
}
private static void RemoveNode(BasicBlock block, Operation node)
{
// Remove a node from the nodes list, and also remove itself
// from all the use lists on the operands that this node uses.
block.Operations.Remove(node);
for (int index = 0; index < node.SourcesCount; index++)
{
node.SetSource(index, default);
}
Debug.Assert(node.Destination == default || node.Destination.UsesCount == 0);
node.Destination = default;
}
private static bool IsUnused(Operation node)
{
return DestIsSingleLocalVar(node) && node.Destination.UsesCount == 0 && !HasSideEffects(node);
}
private static bool DestIsSingleLocalVar(Operation node)
{
return node.DestinationsCount == 1 && node.Destination.Kind == OperandKind.LocalVariable;
}
private static bool HasSideEffects(Operation node)
{
return node.Instruction == Instruction.Call
|| node.Instruction == Instruction.Tailcall
|| node.Instruction == Instruction.CompareAndSwap
|| node.Instruction == Instruction.CompareAndSwap16
|| node.Instruction == Instruction.CompareAndSwap8;
}
private static bool IsPropagableCompare(Operation operation)
{
return operation.Instruction == Instruction.Compare;
}
private static bool IsPropagableCopy(Operation operation)
{
if (operation.Instruction != Instruction.Copy)
{
return false;
}
return operation.Destination.Type == operation.GetSource(0).Type;
}
}
}

View File

@@ -1,183 +0,0 @@
using ARMeilleure.IntermediateRepresentation;
using System;
using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
namespace ARMeilleure.CodeGen.Optimizations
{
static class Simplification
{
public static void RunPass(Operation operation)
{
switch (operation.Instruction)
{
case Instruction.Add:
if (operation.GetSource(0).Relocatable ||
operation.GetSource(1).Relocatable)
{
break;
}
TryEliminateBinaryOpComutative(operation, 0);
break;
case Instruction.BitwiseAnd:
TryEliminateBitwiseAnd(operation);
break;
case Instruction.BitwiseOr:
TryEliminateBitwiseOr(operation);
break;
case Instruction.BitwiseExclusiveOr:
TryEliminateBitwiseExclusiveOr(operation);
break;
case Instruction.ConditionalSelect:
TryEliminateConditionalSelect(operation);
break;
case Instruction.Divide:
TryEliminateBinaryOpY(operation, 1);
break;
case Instruction.Multiply:
TryEliminateBinaryOpComutative(operation, 1);
break;
case Instruction.ShiftLeft:
case Instruction.ShiftRightSI:
case Instruction.ShiftRightUI:
case Instruction.Subtract:
TryEliminateBinaryOpY(operation, 0);
break;
}
}
private static void TryEliminateBitwiseAnd(Operation operation)
{
// Try to recognize and optimize those 3 patterns (in order):
// x & 0xFFFFFFFF == x, 0xFFFFFFFF & y == y,
// x & 0x00000000 == 0x00000000, 0x00000000 & y == 0x00000000
Operand x = operation.GetSource(0);
Operand y = operation.GetSource(1);
if (IsConstEqual(x, AllOnes(x.Type)))
{
operation.TurnIntoCopy(y);
}
else if (IsConstEqual(y, AllOnes(y.Type)))
{
operation.TurnIntoCopy(x);
}
else if (IsConstEqual(x, 0) || IsConstEqual(y, 0))
{
operation.TurnIntoCopy(Const(x.Type, 0));
}
}
private static void TryEliminateBitwiseOr(Operation operation)
{
// Try to recognize and optimize those 3 patterns (in order):
// x | 0x00000000 == x, 0x00000000 | y == y,
// x | 0xFFFFFFFF == 0xFFFFFFFF, 0xFFFFFFFF | y == 0xFFFFFFFF
Operand x = operation.GetSource(0);
Operand y = operation.GetSource(1);
if (IsConstEqual(x, 0))
{
operation.TurnIntoCopy(y);
}
else if (IsConstEqual(y, 0))
{
operation.TurnIntoCopy(x);
}
else if (IsConstEqual(x, AllOnes(x.Type)) || IsConstEqual(y, AllOnes(y.Type)))
{
operation.TurnIntoCopy(Const(AllOnes(x.Type)));
}
}
private static void TryEliminateBitwiseExclusiveOr(Operation operation)
{
// Try to recognize and optimize those 2 patterns (in order):
// x ^ y == 0x00000000 when x == y
// 0x00000000 ^ y == y, x ^ 0x00000000 == x
Operand x = operation.GetSource(0);
Operand y = operation.GetSource(1);
if (x == y && x.Type.IsInteger())
{
operation.TurnIntoCopy(Const(x.Type, 0));
}
else
{
TryEliminateBinaryOpComutative(operation, 0);
}
}
private static void TryEliminateBinaryOpY(Operation operation, ulong comparand)
{
Operand x = operation.GetSource(0);
Operand y = operation.GetSource(1);
if (IsConstEqual(y, comparand))
{
operation.TurnIntoCopy(x);
}
}
private static void TryEliminateBinaryOpComutative(Operation operation, ulong comparand)
{
Operand x = operation.GetSource(0);
Operand y = operation.GetSource(1);
if (IsConstEqual(x, comparand))
{
operation.TurnIntoCopy(y);
}
else if (IsConstEqual(y, comparand))
{
operation.TurnIntoCopy(x);
}
}
private static void TryEliminateConditionalSelect(Operation operation)
{
Operand cond = operation.GetSource(0);
if (cond.Kind != OperandKind.Constant)
{
return;
}
// The condition is constant, we can turn it into a copy, and select
// the source based on the condition value.
int srcIndex = cond.Value != 0 ? 1 : 2;
Operand source = operation.GetSource(srcIndex);
operation.TurnIntoCopy(source);
}
private static bool IsConstEqual(Operand operand, ulong comparand)
{
if (operand.Kind != OperandKind.Constant || !operand.Type.IsInteger())
{
return false;
}
return operand.Value == comparand;
}
private static ulong AllOnes(OperandType type)
{
switch (type)
{
case OperandType.I32: return ~0U;
case OperandType.I64: return ~0UL;
}
throw new ArgumentException("Invalid operand type \"" + type + "\".");
}
}
}

View File

@@ -1,19 +0,0 @@
namespace ARMeilleure.CodeGen.RegisterAllocators
{
readonly struct AllocationResult
{
public int IntUsedRegisters { get; }
public int VecUsedRegisters { get; }
public int SpillRegionSize { get; }
public AllocationResult(
int intUsedRegisters,
int vecUsedRegisters,
int spillRegionSize)
{
IntUsedRegisters = intUsedRegisters;
VecUsedRegisters = vecUsedRegisters;
SpillRegionSize = spillRegionSize;
}
}
}

View File

@@ -1,259 +0,0 @@
using ARMeilleure.IntermediateRepresentation;
using System;
using System.Collections.Generic;
using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
using static ARMeilleure.IntermediateRepresentation.Operation.Factory;
namespace ARMeilleure.CodeGen.RegisterAllocators
{
class CopyResolver
{
private class ParallelCopy
{
private readonly struct Copy
{
public Register Dest { get; }
public Register Source { get; }
public OperandType Type { get; }
public Copy(Register dest, Register source, OperandType type)
{
Dest = dest;
Source = source;
Type = type;
}
}
private readonly List<Copy> _copies;
public int Count => _copies.Count;
public ParallelCopy()
{
_copies = new List<Copy>();
}
public void AddCopy(Register dest, Register source, OperandType type)
{
_copies.Add(new Copy(dest, source, type));
}
public void Sequence(List<Operation> sequence)
{
Dictionary<Register, Register> locations = new Dictionary<Register, Register>();
Dictionary<Register, Register> sources = new Dictionary<Register, Register>();
Dictionary<Register, OperandType> types = new Dictionary<Register, OperandType>();
Queue<Register> pendingQueue = new Queue<Register>();
Queue<Register> readyQueue = new Queue<Register>();
foreach (Copy copy in _copies)
{
locations[copy.Source] = copy.Source;
sources[copy.Dest] = copy.Source;
types[copy.Dest] = copy.Type;
pendingQueue.Enqueue(copy.Dest);
}
foreach (Copy copy in _copies)
{
// If the destination is not used anywhere, we can assign it immediately.
if (!locations.ContainsKey(copy.Dest))
{
readyQueue.Enqueue(copy.Dest);
}
}
while (pendingQueue.TryDequeue(out Register current))
{
Register copyDest;
Register origSource;
Register copySource;
while (readyQueue.TryDequeue(out copyDest))
{
origSource = sources[copyDest];
copySource = locations[origSource];
OperandType type = types[copyDest];
EmitCopy(sequence, GetRegister(copyDest, type), GetRegister(copySource, type));
locations[origSource] = copyDest;
if (origSource == copySource && sources.ContainsKey(origSource))
{
readyQueue.Enqueue(origSource);
}
}
copyDest = current;
origSource = sources[copyDest];
copySource = locations[origSource];
if (copyDest != copySource)
{
OperandType type = types[copyDest];
type = type.IsInteger() ? OperandType.I64 : OperandType.V128;
EmitXorSwap(sequence, GetRegister(copyDest, type), GetRegister(copySource, type));
locations[origSource] = copyDest;
Register swapOther = copySource;
if (copyDest != locations[sources[copySource]])
{
// Find the other swap destination register.
// To do that, we search all the pending registers, and pick
// the one where the copy source register is equal to the
// current destination register being processed (copyDest).
foreach (Register pending in pendingQueue)
{
// Is this a copy of pending <- copyDest?
if (copyDest == locations[sources[pending]])
{
swapOther = pending;
break;
}
}
}
// The value that was previously at "copyDest" now lives on
// "copySource" thanks to the swap, now we need to update the
// location for the next copy that is supposed to copy the value
// that used to live on "copyDest".
locations[sources[swapOther]] = copySource;
}
}
}
private static void EmitCopy(List<Operation> sequence, Operand x, Operand y)
{
sequence.Add(Operation(Instruction.Copy, x, y));
}
private static void EmitXorSwap(List<Operation> sequence, Operand x, Operand y)
{
sequence.Add(Operation(Instruction.BitwiseExclusiveOr, x, x, y));
sequence.Add(Operation(Instruction.BitwiseExclusiveOr, y, y, x));
sequence.Add(Operation(Instruction.BitwiseExclusiveOr, x, x, y));
}
}
private Queue<Operation> _fillQueue = null;
private Queue<Operation> _spillQueue = null;
private ParallelCopy _parallelCopy = null;
public bool HasCopy { get; private set; }
public void AddSplit(LiveInterval left, LiveInterval right)
{
if (left.Local != right.Local)
{
throw new ArgumentException("Intervals of different variables are not allowed.");
}
OperandType type = left.Local.Type;
if (left.IsSpilled && !right.IsSpilled)
{
// Move from the stack to a register.
AddSplitFill(left, right, type);
}
else if (!left.IsSpilled && right.IsSpilled)
{
// Move from a register to the stack.
AddSplitSpill(left, right, type);
}
else if (!left.IsSpilled && !right.IsSpilled && left.Register != right.Register)
{
// Move from one register to another.
AddSplitCopy(left, right, type);
}
else if (left.SpillOffset != right.SpillOffset)
{
// This would be the stack-to-stack move case, but this is not supported.
throw new ArgumentException("Both intervals were spilled.");
}
}
private void AddSplitFill(LiveInterval left, LiveInterval right, OperandType type)
{
if (_fillQueue == null)
{
_fillQueue = new Queue<Operation>();
}
Operand register = GetRegister(right.Register, type);
Operand offset = Const(left.SpillOffset);
_fillQueue.Enqueue(Operation(Instruction.Fill, register, offset));
HasCopy = true;
}
private void AddSplitSpill(LiveInterval left, LiveInterval right, OperandType type)
{
if (_spillQueue == null)
{
_spillQueue = new Queue<Operation>();
}
Operand offset = Const(right.SpillOffset);
Operand register = GetRegister(left.Register, type);
_spillQueue.Enqueue(Operation(Instruction.Spill, default, offset, register));
HasCopy = true;
}
private void AddSplitCopy(LiveInterval left, LiveInterval right, OperandType type)
{
if (_parallelCopy == null)
{
_parallelCopy = new ParallelCopy();
}
_parallelCopy.AddCopy(right.Register, left.Register, type);
HasCopy = true;
}
public Operation[] Sequence()
{
List<Operation> sequence = new List<Operation>();
if (_spillQueue != null)
{
while (_spillQueue.TryDequeue(out Operation spillOp))
{
sequence.Add(spillOp);
}
}
_parallelCopy?.Sequence(sequence);
if (_fillQueue != null)
{
while (_fillQueue.TryDequeue(out Operation fillOp))
{
sequence.Add(fillOp);
}
}
return sequence.ToArray();
}
private static Operand GetRegister(Register reg, OperandType type)
{
return Register(reg.Index, reg.Type, type);
}
}
}

View File

@@ -1,454 +0,0 @@
using ARMeilleure.IntermediateRepresentation;
using ARMeilleure.Translation;
using System;
using System.Diagnostics;
using System.Numerics;
using System.Runtime.CompilerServices;
using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
using static ARMeilleure.IntermediateRepresentation.Operation.Factory;
namespace ARMeilleure.CodeGen.RegisterAllocators
{
class HybridAllocator : IRegisterAllocator
{
private readonly struct BlockInfo
{
public bool HasCall { get; }
public int IntFixedRegisters { get; }
public int VecFixedRegisters { get; }
public BlockInfo(bool hasCall, int intFixedRegisters, int vecFixedRegisters)
{
HasCall = hasCall;
IntFixedRegisters = intFixedRegisters;
VecFixedRegisters = vecFixedRegisters;
}
}
private struct LocalInfo
{
public int Uses { get; set; }
public int UsesAllocated { get; set; }
public int Sequence { get; set; }
public Operand Temp { get; set; }
public Operand Register { get; set; }
public Operand SpillOffset { get; set; }
public OperandType Type { get; }
private int _first;
private int _last;
public bool IsBlockLocal => _first == _last;
public LocalInfo(OperandType type, int uses, int blkIndex)
{
Uses = uses;
Type = type;
UsesAllocated = 0;
Sequence = 0;
Temp = default;
Register = default;
SpillOffset = default;
_first = -1;
_last = -1;
SetBlockIndex(blkIndex);
}
public void SetBlockIndex(int blkIndex)
{
if (_first == -1 || blkIndex < _first)
{
_first = blkIndex;
}
if (_last == -1 || blkIndex > _last)
{
_last = blkIndex;
}
}
}
private const int MaxIROperands = 4;
// The "visited" state is stored in the MSB of the local's value.
private const ulong VisitedMask = 1ul << 63;
private BlockInfo[] _blockInfo;
private LocalInfo[] _localInfo;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static bool IsVisited(Operand local)
{
Debug.Assert(local.Kind == OperandKind.LocalVariable);
return (local.GetValueUnsafe() & VisitedMask) != 0;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static void SetVisited(Operand local)
{
Debug.Assert(local.Kind == OperandKind.LocalVariable);
local.GetValueUnsafe() |= VisitedMask;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private ref LocalInfo GetLocalInfo(Operand local)
{
Debug.Assert(local.Kind == OperandKind.LocalVariable);
Debug.Assert(IsVisited(local), "Local variable not visited. Used before defined?");
return ref _localInfo[(uint)local.GetValueUnsafe() - 1];
}
public AllocationResult RunPass(ControlFlowGraph cfg, StackAllocator stackAlloc, RegisterMasks regMasks)
{
int intUsedRegisters = 0;
int vecUsedRegisters = 0;
int intFreeRegisters = regMasks.IntAvailableRegisters;
int vecFreeRegisters = regMasks.VecAvailableRegisters;
_blockInfo = new BlockInfo[cfg.Blocks.Count];
_localInfo = new LocalInfo[cfg.Blocks.Count * 3];
int localInfoCount = 0;
for (int index = cfg.PostOrderBlocks.Length - 1; index >= 0; index--)
{
BasicBlock block = cfg.PostOrderBlocks[index];
int intFixedRegisters = 0;
int vecFixedRegisters = 0;
bool hasCall = false;
for (Operation node = block.Operations.First; node != default; node = node.ListNext)
{
if (node.Instruction == Instruction.Call)
{
hasCall = true;
}
foreach (Operand source in node.SourcesUnsafe)
{
if (source.Kind == OperandKind.LocalVariable)
{
GetLocalInfo(source).SetBlockIndex(block.Index);
}
else if (source.Kind == OperandKind.Memory)
{
MemoryOperand memOp = source.GetMemory();
if (memOp.BaseAddress != default)
{
GetLocalInfo(memOp.BaseAddress).SetBlockIndex(block.Index);
}
if (memOp.Index != default)
{
GetLocalInfo(memOp.Index).SetBlockIndex(block.Index);
}
}
}
foreach (Operand dest in node.DestinationsUnsafe)
{
if (dest.Kind == OperandKind.LocalVariable)
{
if (IsVisited(dest))
{
GetLocalInfo(dest).SetBlockIndex(block.Index);
}
else
{
dest.NumberLocal(++localInfoCount);
if (localInfoCount > _localInfo.Length)
{
Array.Resize(ref _localInfo, localInfoCount * 2);
}
SetVisited(dest);
GetLocalInfo(dest) = new LocalInfo(dest.Type, UsesCount(dest), block.Index);
}
}
else if (dest.Kind == OperandKind.Register)
{
if (dest.Type.IsInteger())
{
intFixedRegisters |= 1 << dest.GetRegister().Index;
}
else
{
vecFixedRegisters |= 1 << dest.GetRegister().Index;
}
}
}
}
_blockInfo[block.Index] = new BlockInfo(hasCall, intFixedRegisters, vecFixedRegisters);
}
int sequence = 0;
for (int index = cfg.PostOrderBlocks.Length - 1; index >= 0; index--)
{
BasicBlock block = cfg.PostOrderBlocks[index];
ref BlockInfo blkInfo = ref _blockInfo[block.Index];
int intLocalFreeRegisters = intFreeRegisters & ~blkInfo.IntFixedRegisters;
int vecLocalFreeRegisters = vecFreeRegisters & ~blkInfo.VecFixedRegisters;
int intCallerSavedRegisters = blkInfo.HasCall ? regMasks.IntCallerSavedRegisters : 0;
int vecCallerSavedRegisters = blkInfo.HasCall ? regMasks.VecCallerSavedRegisters : 0;
int intSpillTempRegisters = SelectSpillTemps(
intCallerSavedRegisters & ~blkInfo.IntFixedRegisters,
intLocalFreeRegisters);
int vecSpillTempRegisters = SelectSpillTemps(
vecCallerSavedRegisters & ~blkInfo.VecFixedRegisters,
vecLocalFreeRegisters);
intLocalFreeRegisters &= ~(intSpillTempRegisters | intCallerSavedRegisters);
vecLocalFreeRegisters &= ~(vecSpillTempRegisters | vecCallerSavedRegisters);
for (Operation node = block.Operations.First; node != default; node = node.ListNext)
{
int intLocalUse = 0;
int vecLocalUse = 0;
Operand AllocateRegister(Operand local)
{
ref LocalInfo info = ref GetLocalInfo(local);
info.UsesAllocated++;
Debug.Assert(info.UsesAllocated <= info.Uses);
if (info.Register != default)
{
if (info.UsesAllocated == info.Uses)
{
Register reg = info.Register.GetRegister();
if (local.Type.IsInteger())
{
intLocalFreeRegisters |= 1 << reg.Index;
}
else
{
vecLocalFreeRegisters |= 1 << reg.Index;
}
}
return info.Register;
}
else
{
Operand temp = info.Temp;
if (temp == default || info.Sequence != sequence)
{
temp = local.Type.IsInteger()
? GetSpillTemp(local, intSpillTempRegisters, ref intLocalUse)
: GetSpillTemp(local, vecSpillTempRegisters, ref vecLocalUse);
info.Sequence = sequence;
info.Temp = temp;
}
Operation fillOp = Operation(Instruction.Fill, temp, info.SpillOffset);
block.Operations.AddBefore(node, fillOp);
return temp;
}
}
bool folded = false;
// If operation is a copy of a local and that local is living on the stack, we turn the copy into
// a fill, instead of inserting a fill before it.
if (node.Instruction == Instruction.Copy)
{
Operand source = node.GetSource(0);
if (source.Kind == OperandKind.LocalVariable)
{
ref LocalInfo info = ref GetLocalInfo(source);
if (info.Register == default)
{
Operation fillOp = Operation(Instruction.Fill, node.Destination, info.SpillOffset);
block.Operations.AddBefore(node, fillOp);
block.Operations.Remove(node);
node = fillOp;
folded = true;
}
}
}
if (!folded)
{
foreach (ref Operand source in node.SourcesUnsafe)
{
if (source.Kind == OperandKind.LocalVariable)
{
source = AllocateRegister(source);
}
else if (source.Kind == OperandKind.Memory)
{
MemoryOperand memOp = source.GetMemory();
if (memOp.BaseAddress != default)
{
memOp.BaseAddress = AllocateRegister(memOp.BaseAddress);
}
if (memOp.Index != default)
{
memOp.Index = AllocateRegister(memOp.Index);
}
}
}
}
int intLocalAsg = 0;
int vecLocalAsg = 0;
foreach (ref Operand dest in node.DestinationsUnsafe)
{
if (dest.Kind != OperandKind.LocalVariable)
{
continue;
}
ref LocalInfo info = ref GetLocalInfo(dest);
if (info.UsesAllocated == 0)
{
int mask = dest.Type.IsInteger()
? intLocalFreeRegisters
: vecLocalFreeRegisters;
if (info.IsBlockLocal && mask != 0)
{
int selectedReg = BitOperations.TrailingZeroCount(mask);
info.Register = Register(selectedReg, info.Type.ToRegisterType(), info.Type);
if (dest.Type.IsInteger())
{
intLocalFreeRegisters &= ~(1 << selectedReg);
intUsedRegisters |= 1 << selectedReg;
}
else
{
vecLocalFreeRegisters &= ~(1 << selectedReg);
vecUsedRegisters |= 1 << selectedReg;
}
}
else
{
info.Register = default;
info.SpillOffset = Const(stackAlloc.Allocate(dest.Type.GetSizeInBytes()));
}
}
info.UsesAllocated++;
Debug.Assert(info.UsesAllocated <= info.Uses);
if (info.Register != default)
{
dest = info.Register;
}
else
{
Operand temp = info.Temp;
if (temp == default || info.Sequence != sequence)
{
temp = dest.Type.IsInteger()
? GetSpillTemp(dest, intSpillTempRegisters, ref intLocalAsg)
: GetSpillTemp(dest, vecSpillTempRegisters, ref vecLocalAsg);
info.Sequence = sequence;
info.Temp = temp;
}
dest = temp;
Operation spillOp = Operation(Instruction.Spill, default, info.SpillOffset, temp);
block.Operations.AddAfter(node, spillOp);
node = spillOp;
}
}
sequence++;
intUsedRegisters |= intLocalAsg | intLocalUse;
vecUsedRegisters |= vecLocalAsg | vecLocalUse;
}
}
return new AllocationResult(intUsedRegisters, vecUsedRegisters, stackAlloc.TotalSize);
}
private static int SelectSpillTemps(int mask0, int mask1)
{
int selection = 0;
int count = 0;
while (count < MaxIROperands && mask0 != 0)
{
int mask = mask0 & -mask0;
selection |= mask;
mask0 &= ~mask;
count++;
}
while (count < MaxIROperands && mask1 != 0)
{
int mask = mask1 & -mask1;
selection |= mask;
mask1 &= ~mask;
count++;
}
Debug.Assert(count == MaxIROperands, "No enough registers for spill temps.");
return selection;
}
private static Operand GetSpillTemp(Operand local, int freeMask, ref int useMask)
{
int selectedReg = BitOperations.TrailingZeroCount(freeMask & ~useMask);
useMask |= 1 << selectedReg;
return Register(selectedReg, local.Type.ToRegisterType(), local.Type);
}
private static int UsesCount(Operand local)
{
return local.AssignmentsCount + local.UsesCount;
}
}
}

View File

@@ -1,12 +0,0 @@
using ARMeilleure.Translation;
namespace ARMeilleure.CodeGen.RegisterAllocators
{
interface IRegisterAllocator
{
AllocationResult RunPass(
ControlFlowGraph cfg,
StackAllocator stackAlloc,
RegisterMasks regMasks);
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,396 +0,0 @@
using ARMeilleure.IntermediateRepresentation;
using System;
using System.Collections.Generic;
using System.Diagnostics;
namespace ARMeilleure.CodeGen.RegisterAllocators
{
unsafe readonly struct LiveInterval : IComparable<LiveInterval>
{
public const int NotFound = -1;
private struct Data
{
public int End;
public int SpillOffset;
public LiveRange FirstRange;
public LiveRange PrevRange;
public LiveRange CurrRange;
public LiveInterval Parent;
public UseList Uses;
public LiveIntervalList Children;
public Operand Local;
public Register Register;
public bool IsFixed;
public bool IsFixedAndUsed;
}
private readonly Data* _data;
private ref int End => ref _data->End;
private ref LiveRange FirstRange => ref _data->FirstRange;
private ref LiveRange CurrRange => ref _data->CurrRange;
private ref LiveRange PrevRange => ref _data->PrevRange;
private ref LiveInterval Parent => ref _data->Parent;
private ref UseList Uses => ref _data->Uses;
private ref LiveIntervalList Children => ref _data->Children;
public Operand Local => _data->Local;
public ref Register Register => ref _data->Register;
public ref int SpillOffset => ref _data->SpillOffset;
public bool IsFixed => _data->IsFixed;
public ref bool IsFixedAndUsed => ref _data->IsFixedAndUsed;
public bool IsEmpty => FirstRange == default;
public bool IsSplit => Children.Count != 0;
public bool IsSpilled => SpillOffset != -1;
public int UsesCount => Uses.Count;
public LiveInterval(Operand local = default, LiveInterval parent = default)
{
_data = Allocators.LiveIntervals.Allocate<Data>();
*_data = default;
_data->IsFixed = false;
_data->Local = local;
Parent = parent == default ? this : parent;
Uses = new UseList();
Children = new LiveIntervalList();
FirstRange = default;
CurrRange = default;
PrevRange = default;
SpillOffset = -1;
}
public LiveInterval(Register register) : this(local: default, parent: default)
{
_data->IsFixed = true;
Register = register;
}
public void Reset()
{
PrevRange = default;
CurrRange = FirstRange;
}
public void Forward(int position)
{
LiveRange prev = PrevRange;
LiveRange curr = CurrRange;
while (curr != default && curr.Start < position && !curr.Overlaps(position))
{
prev = curr;
curr = curr.Next;
}
PrevRange = prev;
CurrRange = curr;
}
public int GetStart()
{
Debug.Assert(!IsEmpty, "Empty LiveInterval cannot have a start position.");
return FirstRange.Start;
}
public void SetStart(int position)
{
if (FirstRange != default)
{
Debug.Assert(position != FirstRange.End);
FirstRange.Start = position;
}
else
{
FirstRange = new LiveRange(position, position + 1);
End = position + 1;
}
}
public int GetEnd()
{
Debug.Assert(!IsEmpty, "Empty LiveInterval cannot have an end position.");
return End;
}
public void AddRange(int start, int end)
{
Debug.Assert(start < end, $"Invalid range start position {start}, {end}");
if (FirstRange != default)
{
// If the new range ends exactly where the first range start, then coalesce together.
if (end == FirstRange.Start)
{
FirstRange.Start = start;
return;
}
// If the new range is already contained, then coalesce together.
else if (FirstRange.Overlaps(start, end))
{
FirstRange.Start = Math.Min(FirstRange.Start, start);
FirstRange.End = Math.Max(FirstRange.End, end);
End = Math.Max(End, end);
Debug.Assert(FirstRange.Next == default || !FirstRange.Overlaps(FirstRange.Next));
return;
}
}
FirstRange = new LiveRange(start, end, FirstRange);
End = Math.Max(End, end);
Debug.Assert(FirstRange.Next == default || !FirstRange.Overlaps(FirstRange.Next));
}
public void AddUsePosition(int position)
{
Uses.Add(position);
}
public bool Overlaps(int position)
{
LiveRange curr = CurrRange;
while (curr != default && curr.Start <= position)
{
if (curr.Overlaps(position))
{
return true;
}
curr = curr.Next;
}
return false;
}
public bool Overlaps(LiveInterval other)
{
return GetOverlapPosition(other) != NotFound;
}
public int GetOverlapPosition(LiveInterval other)
{
LiveRange a = CurrRange;
LiveRange b = other.CurrRange;
while (a != default)
{
while (b != default && b.Start < a.Start)
{
if (a.Overlaps(b))
{
return a.Start;
}
b = b.Next;
}
if (b == default)
{
break;
}
else if (a.Overlaps(b))
{
return a.Start;
}
a = a.Next;
}
return NotFound;
}
public ReadOnlySpan<LiveInterval> SplitChildren()
{
return Parent.Children.Span;
}
public ReadOnlySpan<int> UsePositions()
{
return Uses.Span;
}
public int FirstUse()
{
return Uses.FirstUse;
}
public int NextUseAfter(int position)
{
return Uses.NextUse(position);
}
public LiveInterval Split(int position)
{
LiveInterval result = new(Local, Parent);
result.End = End;
LiveRange prev = PrevRange;
LiveRange curr = CurrRange;
while (curr != default && curr.Start < position && !curr.Overlaps(position))
{
prev = curr;
curr = curr.Next;
}
if (curr.Start >= position)
{
prev.Next = default;
result.FirstRange = curr;
End = prev.End;
}
else
{
result.FirstRange = new LiveRange(position, curr.End, curr.Next);
curr.End = position;
curr.Next = default;
End = curr.End;
}
result.Uses = Uses.Split(position);
AddSplitChild(result);
Debug.Assert(!IsEmpty, "Left interval is empty after split.");
Debug.Assert(!result.IsEmpty, "Right interval is empty after split.");
// Make sure the iterator in the new split is pointing to the start.
result.Reset();
return result;
}
private void AddSplitChild(LiveInterval child)
{
Debug.Assert(!child.IsEmpty, "Trying to insert an empty interval.");
Parent.Children.Add(child);
}
public LiveInterval GetSplitChild(int position)
{
if (Overlaps(position))
{
return this;
}
foreach (LiveInterval splitChild in SplitChildren())
{
if (splitChild.Overlaps(position))
{
return splitChild;
}
else if (splitChild.GetStart() > position)
{
break;
}
}
return default;
}
public bool TrySpillWithSiblingOffset()
{
foreach (LiveInterval splitChild in SplitChildren())
{
if (splitChild.IsSpilled)
{
Spill(splitChild.SpillOffset);
return true;
}
}
return false;
}
public void Spill(int offset)
{
SpillOffset = offset;
}
public int CompareTo(LiveInterval interval)
{
if (FirstRange == default || interval.FirstRange == default)
{
return 0;
}
return GetStart().CompareTo(interval.GetStart());
}
public bool Equals(LiveInterval interval)
{
return interval._data == _data;
}
public override bool Equals(object obj)
{
return obj is LiveInterval interval && Equals(interval);
}
public static bool operator ==(LiveInterval a, LiveInterval b)
{
return a.Equals(b);
}
public static bool operator !=(LiveInterval a, LiveInterval b)
{
return !a.Equals(b);
}
public override int GetHashCode()
{
return HashCode.Combine((IntPtr)_data);
}
public override string ToString()
{
LiveInterval self = this;
IEnumerable<string> GetRanges()
{
LiveRange curr = self.CurrRange;
while (curr != default)
{
if (curr == self.CurrRange)
{
yield return "*" + curr;
}
else
{
yield return curr.ToString();
}
curr = curr.Next;
}
}
return string.Join(", ", GetRanges());
}
}
}

View File

@@ -1,40 +0,0 @@
using System;
namespace ARMeilleure.CodeGen.RegisterAllocators
{
unsafe struct LiveIntervalList
{
private LiveInterval* _items;
private int _count;
private int _capacity;
public int Count => _count;
public Span<LiveInterval> Span => new(_items, _count);
public void Add(LiveInterval interval)
{
if (_count + 1 > _capacity)
{
var oldSpan = Span;
_capacity = Math.Max(4, _capacity * 2);
_items = Allocators.References.Allocate<LiveInterval>((uint)_capacity);
var newSpan = Span;
oldSpan.CopyTo(newSpan);
}
int position = interval.GetStart();
int i = _count - 1;
while (i >= 0 && _items[i].GetStart() > position)
{
_items[i + 1] = _items[i--];
}
_items[i + 1] = interval;
_count++;
}
}
}

View File

@@ -1,74 +0,0 @@
using System;
namespace ARMeilleure.CodeGen.RegisterAllocators
{
unsafe readonly struct LiveRange : IEquatable<LiveRange>
{
private struct Data
{
public int Start;
public int End;
public LiveRange Next;
}
private readonly Data* _data;
public ref int Start => ref _data->Start;
public ref int End => ref _data->End;
public ref LiveRange Next => ref _data->Next;
public LiveRange(int start, int end, LiveRange next = default)
{
_data = Allocators.LiveRanges.Allocate<Data>();
Start = start;
End = end;
Next = next;
}
public bool Overlaps(int start, int end)
{
return Start < end && start < End;
}
public bool Overlaps(LiveRange range)
{
return Start < range.End && range.Start < End;
}
public bool Overlaps(int position)
{
return position >= Start && position < End;
}
public bool Equals(LiveRange range)
{
return range._data == _data;
}
public override bool Equals(object obj)
{
return obj is LiveRange range && Equals(range);
}
public static bool operator ==(LiveRange a, LiveRange b)
{
return a.Equals(b);
}
public static bool operator !=(LiveRange a, LiveRange b)
{
return !a.Equals(b);
}
public override int GetHashCode()
{
return HashCode.Combine((IntPtr)_data);
}
public override string ToString()
{
return $"[{Start}, {End})";
}
}
}

View File

@@ -1,50 +0,0 @@
using ARMeilleure.IntermediateRepresentation;
using System;
namespace ARMeilleure.CodeGen.RegisterAllocators
{
readonly struct RegisterMasks
{
public int IntAvailableRegisters { get; }
public int VecAvailableRegisters { get; }
public int IntCallerSavedRegisters { get; }
public int VecCallerSavedRegisters { get; }
public int IntCalleeSavedRegisters { get; }
public int VecCalleeSavedRegisters { get; }
public int RegistersCount { get; }
public RegisterMasks(
int intAvailableRegisters,
int vecAvailableRegisters,
int intCallerSavedRegisters,
int vecCallerSavedRegisters,
int intCalleeSavedRegisters,
int vecCalleeSavedRegisters,
int registersCount)
{
IntAvailableRegisters = intAvailableRegisters;
VecAvailableRegisters = vecAvailableRegisters;
IntCallerSavedRegisters = intCallerSavedRegisters;
VecCallerSavedRegisters = vecCallerSavedRegisters;
IntCalleeSavedRegisters = intCalleeSavedRegisters;
VecCalleeSavedRegisters = vecCalleeSavedRegisters;
RegistersCount = registersCount;
}
public int GetAvailableRegisters(RegisterType type)
{
if (type == RegisterType.Integer)
{
return IntAvailableRegisters;
}
else if (type == RegisterType.Vector)
{
return VecAvailableRegisters;
}
else
{
throw new ArgumentException($"Invalid register type \"{type}\".");
}
}
}
}

View File

@@ -1,25 +0,0 @@
using ARMeilleure.IntermediateRepresentation;
namespace ARMeilleure.CodeGen.RegisterAllocators
{
class StackAllocator
{
private int _offset;
public int TotalSize => _offset;
public int Allocate(OperandType type)
{
return Allocate(type.GetSizeInBytes());
}
public int Allocate(int sizeInBytes)
{
int offset = _offset;
_offset += sizeInBytes;
return offset;
}
}
}

View File

@@ -1,84 +0,0 @@
using System;
namespace ARMeilleure.CodeGen.RegisterAllocators
{
unsafe struct UseList
{
private int* _items;
private int _capacity;
private int _count;
public int Count => _count;
public int FirstUse => _count > 0 ? _items[_count - 1] : LiveInterval.NotFound;
public Span<int> Span => new(_items, _count);
public void Add(int position)
{
if (_count + 1 > _capacity)
{
var oldSpan = Span;
_capacity = Math.Max(4, _capacity * 2);
_items = Allocators.Default.Allocate<int>((uint)_capacity);
var newSpan = Span;
oldSpan.CopyTo(newSpan);
}
// Use positions are usually inserted in descending order, so inserting in descending order is faster,
// since the number of half exchanges is reduced.
int i = _count - 1;
while (i >= 0 && _items[i] < position)
{
_items[i + 1] = _items[i--];
}
_items[i + 1] = position;
_count++;
}
public int NextUse(int position)
{
int index = NextUseIndex(position);
return index != LiveInterval.NotFound ? _items[index] : LiveInterval.NotFound;
}
public int NextUseIndex(int position)
{
int i = _count - 1;
if (i == -1 || position > _items[0])
{
return LiveInterval.NotFound;
}
while (i >= 0 && _items[i] < position)
{
i--;
}
return i;
}
public UseList Split(int position)
{
int index = NextUseIndex(position);
// Since the list is in descending order, the new split list takes the front of the list and the current
// list takes the back of the list.
UseList result = new();
result._count = index + 1;
result._capacity = result._count;
result._items = _items;
_count = _count - result._count;
_capacity = _count;
_items = _items + result._count;
return result;
}
}
}

View File

@@ -1,16 +0,0 @@
namespace ARMeilleure.CodeGen.Unwinding
{
struct UnwindInfo
{
public const int Stride = 4; // Bytes.
public UnwindPushEntry[] PushEntries { get; }
public int PrologSize { get; }
public UnwindInfo(UnwindPushEntry[] pushEntries, int prologSize)
{
PushEntries = pushEntries;
PrologSize = prologSize;
}
}
}

View File

@@ -1,11 +0,0 @@
namespace ARMeilleure.CodeGen.Unwinding
{
enum UnwindPseudoOp
{
PushReg = 0,
SetFrame = 1,
AllocStack = 2,
SaveReg = 3,
SaveXmm128 = 4
}
}

View File

@@ -1,20 +0,0 @@
namespace ARMeilleure.CodeGen.Unwinding
{
struct UnwindPushEntry
{
public const int Stride = 16; // Bytes.
public UnwindPseudoOp PseudoOp { get; }
public int PrologOffset { get; }
public int RegIndex { get; }
public int StackOffsetOrAllocSize { get; }
public UnwindPushEntry(UnwindPseudoOp pseudoOp, int prologOffset, int regIndex = -1, int stackOffsetOrAllocSize = -1)
{
PseudoOp = pseudoOp;
PrologOffset = prologOffset;
RegIndex = regIndex;
StackOffsetOrAllocSize = stackOffsetOrAllocSize;
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,293 +0,0 @@
using System;
namespace ARMeilleure.CodeGen.X86
{
partial class Assembler
{
public static bool SupportsVexPrefix(X86Instruction inst)
{
return _instTable[(int)inst].Flags.HasFlag(InstructionFlags.Vex);
}
private const int BadOp = 0;
[Flags]
private enum InstructionFlags
{
None = 0,
RegOnly = 1 << 0,
Reg8Src = 1 << 1,
Reg8Dest = 1 << 2,
RexW = 1 << 3,
Vex = 1 << 4,
Evex = 1 << 5,
PrefixBit = 16,
PrefixMask = 7 << PrefixBit,
Prefix66 = 1 << PrefixBit,
PrefixF3 = 2 << PrefixBit,
PrefixF2 = 4 << PrefixBit
}
private readonly struct InstructionInfo
{
public int OpRMR { get; }
public int OpRMImm8 { get; }
public int OpRMImm32 { get; }
public int OpRImm64 { get; }
public int OpRRM { get; }
public InstructionFlags Flags { get; }
public InstructionInfo(
int opRMR,
int opRMImm8,
int opRMImm32,
int opRImm64,
int opRRM,
InstructionFlags flags)
{
OpRMR = opRMR;
OpRMImm8 = opRMImm8;
OpRMImm32 = opRMImm32;
OpRImm64 = opRImm64;
OpRRM = opRRM;
Flags = flags;
}
}
private readonly static InstructionInfo[] _instTable;
static Assembler()
{
_instTable = new InstructionInfo[(int)X86Instruction.Count];
// Name RM/R RM/I8 RM/I32 R/I64 R/RM Flags
Add(X86Instruction.Add, new InstructionInfo(0x00000001, 0x00000083, 0x00000081, BadOp, 0x00000003, InstructionFlags.None));
Add(X86Instruction.Addpd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f58, InstructionFlags.Vex | InstructionFlags.Prefix66));
Add(X86Instruction.Addps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f58, InstructionFlags.Vex));
Add(X86Instruction.Addsd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f58, InstructionFlags.Vex | InstructionFlags.PrefixF2));
Add(X86Instruction.Addss, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f58, InstructionFlags.Vex | InstructionFlags.PrefixF3));
Add(X86Instruction.Aesdec, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f38de, InstructionFlags.Vex | InstructionFlags.Prefix66));
Add(X86Instruction.Aesdeclast, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f38df, InstructionFlags.Vex | InstructionFlags.Prefix66));
Add(X86Instruction.Aesenc, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f38dc, InstructionFlags.Vex | InstructionFlags.Prefix66));
Add(X86Instruction.Aesenclast, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f38dd, InstructionFlags.Vex | InstructionFlags.Prefix66));
Add(X86Instruction.Aesimc, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f38db, InstructionFlags.Vex | InstructionFlags.Prefix66));
Add(X86Instruction.And, new InstructionInfo(0x00000021, 0x04000083, 0x04000081, BadOp, 0x00000023, InstructionFlags.None));
Add(X86Instruction.Andnpd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f55, InstructionFlags.Vex | InstructionFlags.Prefix66));
Add(X86Instruction.Andnps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f55, InstructionFlags.Vex));
Add(X86Instruction.Andpd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f54, InstructionFlags.Vex | InstructionFlags.Prefix66));
Add(X86Instruction.Andps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f54, InstructionFlags.Vex));
Add(X86Instruction.Blendvpd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3815, InstructionFlags.Prefix66));
Add(X86Instruction.Blendvps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3814, InstructionFlags.Prefix66));
Add(X86Instruction.Bsr, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fbd, InstructionFlags.None));
Add(X86Instruction.Bswap, new InstructionInfo(0x00000fc8, BadOp, BadOp, BadOp, BadOp, InstructionFlags.RegOnly));
Add(X86Instruction.Call, new InstructionInfo(0x020000ff, BadOp, BadOp, BadOp, BadOp, InstructionFlags.None));
Add(X86Instruction.Cmovcc, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f40, InstructionFlags.None));
Add(X86Instruction.Cmp, new InstructionInfo(0x00000039, 0x07000083, 0x07000081, BadOp, 0x0000003b, InstructionFlags.None));
Add(X86Instruction.Cmppd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fc2, InstructionFlags.Vex | InstructionFlags.Prefix66));
Add(X86Instruction.Cmpps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fc2, InstructionFlags.Vex));
Add(X86Instruction.Cmpsd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fc2, InstructionFlags.Vex | InstructionFlags.PrefixF2));
Add(X86Instruction.Cmpss, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fc2, InstructionFlags.Vex | InstructionFlags.PrefixF3));
Add(X86Instruction.Cmpxchg, new InstructionInfo(0x00000fb1, BadOp, BadOp, BadOp, BadOp, InstructionFlags.None));
Add(X86Instruction.Cmpxchg16b, new InstructionInfo(0x01000fc7, BadOp, BadOp, BadOp, BadOp, InstructionFlags.RexW));
Add(X86Instruction.Cmpxchg8, new InstructionInfo(0x00000fb0, BadOp, BadOp, BadOp, BadOp, InstructionFlags.Reg8Src));
Add(X86Instruction.Comisd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f2f, InstructionFlags.Vex | InstructionFlags.Prefix66));
Add(X86Instruction.Comiss, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f2f, InstructionFlags.Vex));
Add(X86Instruction.Crc32, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f38f1, InstructionFlags.PrefixF2));
Add(X86Instruction.Crc32_16, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f38f1, InstructionFlags.PrefixF2 | InstructionFlags.Prefix66));
Add(X86Instruction.Crc32_8, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f38f0, InstructionFlags.PrefixF2 | InstructionFlags.Reg8Src));
Add(X86Instruction.Cvtdq2pd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fe6, InstructionFlags.Vex | InstructionFlags.PrefixF3));
Add(X86Instruction.Cvtdq2ps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f5b, InstructionFlags.Vex));
Add(X86Instruction.Cvtpd2dq, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fe6, InstructionFlags.Vex | InstructionFlags.PrefixF2));
Add(X86Instruction.Cvtpd2ps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f5a, InstructionFlags.Vex | InstructionFlags.Prefix66));
Add(X86Instruction.Cvtps2dq, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f5b, InstructionFlags.Vex | InstructionFlags.Prefix66));
Add(X86Instruction.Cvtps2pd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f5a, InstructionFlags.Vex));
Add(X86Instruction.Cvtsd2si, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f2d, InstructionFlags.Vex | InstructionFlags.PrefixF2));
Add(X86Instruction.Cvtsd2ss, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f5a, InstructionFlags.Vex | InstructionFlags.PrefixF2));
Add(X86Instruction.Cvtsi2sd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f2a, InstructionFlags.Vex | InstructionFlags.PrefixF2));
Add(X86Instruction.Cvtsi2ss, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f2a, InstructionFlags.Vex | InstructionFlags.PrefixF3));
Add(X86Instruction.Cvtss2sd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f5a, InstructionFlags.Vex | InstructionFlags.PrefixF3));
Add(X86Instruction.Cvtss2si, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f2d, InstructionFlags.Vex | InstructionFlags.PrefixF3));
Add(X86Instruction.Div, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x060000f7, InstructionFlags.None));
Add(X86Instruction.Divpd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f5e, InstructionFlags.Vex | InstructionFlags.Prefix66));
Add(X86Instruction.Divps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f5e, InstructionFlags.Vex));
Add(X86Instruction.Divsd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f5e, InstructionFlags.Vex | InstructionFlags.PrefixF2));
Add(X86Instruction.Divss, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f5e, InstructionFlags.Vex | InstructionFlags.PrefixF3));
Add(X86Instruction.Gf2p8affineqb, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3ace, InstructionFlags.Prefix66));
Add(X86Instruction.Haddpd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f7c, InstructionFlags.Vex | InstructionFlags.Prefix66));
Add(X86Instruction.Haddps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f7c, InstructionFlags.Vex | InstructionFlags.PrefixF2));
Add(X86Instruction.Idiv, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x070000f7, InstructionFlags.None));
Add(X86Instruction.Imul, new InstructionInfo(BadOp, 0x0000006b, 0x00000069, BadOp, 0x00000faf, InstructionFlags.None));
Add(X86Instruction.Imul128, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x050000f7, InstructionFlags.None));
Add(X86Instruction.Insertps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3a21, InstructionFlags.Vex | InstructionFlags.Prefix66));
Add(X86Instruction.Jmp, new InstructionInfo(0x040000ff, BadOp, BadOp, BadOp, BadOp, InstructionFlags.None));
Add(X86Instruction.Ldmxcsr, new InstructionInfo(0x02000fae, BadOp, BadOp, BadOp, BadOp, InstructionFlags.Vex));
Add(X86Instruction.Lea, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x0000008d, InstructionFlags.None));
Add(X86Instruction.Maxpd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f5f, InstructionFlags.Vex | InstructionFlags.Prefix66));
Add(X86Instruction.Maxps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f5f, InstructionFlags.Vex));
Add(X86Instruction.Maxsd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f5f, InstructionFlags.Vex | InstructionFlags.PrefixF2));
Add(X86Instruction.Maxss, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f5f, InstructionFlags.Vex | InstructionFlags.PrefixF3));
Add(X86Instruction.Minpd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f5d, InstructionFlags.Vex | InstructionFlags.Prefix66));
Add(X86Instruction.Minps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f5d, InstructionFlags.Vex));
Add(X86Instruction.Minsd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f5d, InstructionFlags.Vex | InstructionFlags.PrefixF2));
Add(X86Instruction.Minss, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f5d, InstructionFlags.Vex | InstructionFlags.PrefixF3));
Add(X86Instruction.Mov, new InstructionInfo(0x00000089, BadOp, 0x000000c7, 0x000000b8, 0x0000008b, InstructionFlags.None));
Add(X86Instruction.Mov16, new InstructionInfo(0x00000089, BadOp, 0x000000c7, BadOp, 0x0000008b, InstructionFlags.Prefix66));
Add(X86Instruction.Mov8, new InstructionInfo(0x00000088, 0x000000c6, BadOp, BadOp, 0x0000008a, InstructionFlags.Reg8Src | InstructionFlags.Reg8Dest));
Add(X86Instruction.Movd, new InstructionInfo(0x00000f7e, BadOp, BadOp, BadOp, 0x00000f6e, InstructionFlags.Vex | InstructionFlags.Prefix66));
Add(X86Instruction.Movdqu, new InstructionInfo(0x00000f7f, BadOp, BadOp, BadOp, 0x00000f6f, InstructionFlags.Vex | InstructionFlags.PrefixF3));
Add(X86Instruction.Movhlps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f12, InstructionFlags.Vex));
Add(X86Instruction.Movlhps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f16, InstructionFlags.Vex));
Add(X86Instruction.Movq, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f7e, InstructionFlags.Vex | InstructionFlags.PrefixF3));
Add(X86Instruction.Movsd, new InstructionInfo(0x00000f11, BadOp, BadOp, BadOp, 0x00000f10, InstructionFlags.Vex | InstructionFlags.PrefixF2));
Add(X86Instruction.Movss, new InstructionInfo(0x00000f11, BadOp, BadOp, BadOp, 0x00000f10, InstructionFlags.Vex | InstructionFlags.PrefixF3));
Add(X86Instruction.Movsx16, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fbf, InstructionFlags.None));
Add(X86Instruction.Movsx32, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000063, InstructionFlags.None));
Add(X86Instruction.Movsx8, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fbe, InstructionFlags.Reg8Src));
Add(X86Instruction.Movzx16, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fb7, InstructionFlags.None));
Add(X86Instruction.Movzx8, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fb6, InstructionFlags.Reg8Src));
Add(X86Instruction.Mul128, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x040000f7, InstructionFlags.None));
Add(X86Instruction.Mulpd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f59, InstructionFlags.Vex | InstructionFlags.Prefix66));
Add(X86Instruction.Mulps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f59, InstructionFlags.Vex));
Add(X86Instruction.Mulsd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f59, InstructionFlags.Vex | InstructionFlags.PrefixF2));
Add(X86Instruction.Mulss, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f59, InstructionFlags.Vex | InstructionFlags.PrefixF3));
Add(X86Instruction.Neg, new InstructionInfo(0x030000f7, BadOp, BadOp, BadOp, BadOp, InstructionFlags.None));
Add(X86Instruction.Not, new InstructionInfo(0x020000f7, BadOp, BadOp, BadOp, BadOp, InstructionFlags.None));
Add(X86Instruction.Or, new InstructionInfo(0x00000009, 0x01000083, 0x01000081, BadOp, 0x0000000b, InstructionFlags.None));
Add(X86Instruction.Paddb, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000ffc, InstructionFlags.Vex | InstructionFlags.Prefix66));
Add(X86Instruction.Paddd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000ffe, InstructionFlags.Vex | InstructionFlags.Prefix66));
Add(X86Instruction.Paddq, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fd4, InstructionFlags.Vex | InstructionFlags.Prefix66));
Add(X86Instruction.Paddw, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000ffd, InstructionFlags.Vex | InstructionFlags.Prefix66));
Add(X86Instruction.Palignr, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3a0f, InstructionFlags.Vex | InstructionFlags.Prefix66));
Add(X86Instruction.Pand, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fdb, InstructionFlags.Vex | InstructionFlags.Prefix66));
Add(X86Instruction.Pandn, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fdf, InstructionFlags.Vex | InstructionFlags.Prefix66));
Add(X86Instruction.Pavgb, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fe0, InstructionFlags.Vex | InstructionFlags.Prefix66));
Add(X86Instruction.Pavgw, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fe3, InstructionFlags.Vex | InstructionFlags.Prefix66));
Add(X86Instruction.Pblendvb, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3810, InstructionFlags.Prefix66));
Add(X86Instruction.Pclmulqdq, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3a44, InstructionFlags.Vex | InstructionFlags.Prefix66));
Add(X86Instruction.Pcmpeqb, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f74, InstructionFlags.Vex | InstructionFlags.Prefix66));
Add(X86Instruction.Pcmpeqd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f76, InstructionFlags.Vex | InstructionFlags.Prefix66));
Add(X86Instruction.Pcmpeqq, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3829, InstructionFlags.Vex | InstructionFlags.Prefix66));
Add(X86Instruction.Pcmpeqw, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f75, InstructionFlags.Vex | InstructionFlags.Prefix66));
Add(X86Instruction.Pcmpgtb, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f64, InstructionFlags.Vex | InstructionFlags.Prefix66));
Add(X86Instruction.Pcmpgtd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f66, InstructionFlags.Vex | InstructionFlags.Prefix66));
Add(X86Instruction.Pcmpgtq, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3837, InstructionFlags.Vex | InstructionFlags.Prefix66));
Add(X86Instruction.Pcmpgtw, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f65, InstructionFlags.Vex | InstructionFlags.Prefix66));
Add(X86Instruction.Pextrb, new InstructionInfo(0x000f3a14, BadOp, BadOp, BadOp, BadOp, InstructionFlags.Vex | InstructionFlags.Prefix66));
Add(X86Instruction.Pextrd, new InstructionInfo(0x000f3a16, BadOp, BadOp, BadOp, BadOp, InstructionFlags.Vex | InstructionFlags.Prefix66));
Add(X86Instruction.Pextrq, new InstructionInfo(0x000f3a16, BadOp, BadOp, BadOp, BadOp, InstructionFlags.Vex | InstructionFlags.RexW | InstructionFlags.Prefix66));
Add(X86Instruction.Pextrw, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fc5, InstructionFlags.Vex | InstructionFlags.Prefix66));
Add(X86Instruction.Pinsrb, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3a20, InstructionFlags.Vex | InstructionFlags.Prefix66));
Add(X86Instruction.Pinsrd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3a22, InstructionFlags.Vex | InstructionFlags.Prefix66));
Add(X86Instruction.Pinsrq, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3a22, InstructionFlags.Vex | InstructionFlags.RexW | InstructionFlags.Prefix66));
Add(X86Instruction.Pinsrw, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fc4, InstructionFlags.Vex | InstructionFlags.Prefix66));
Add(X86Instruction.Pmaxsb, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f383c, InstructionFlags.Vex | InstructionFlags.Prefix66));
Add(X86Instruction.Pmaxsd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f383d, InstructionFlags.Vex | InstructionFlags.Prefix66));
Add(X86Instruction.Pmaxsw, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fee, InstructionFlags.Vex | InstructionFlags.Prefix66));
Add(X86Instruction.Pmaxub, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fde, InstructionFlags.Vex | InstructionFlags.Prefix66));
Add(X86Instruction.Pmaxud, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f383f, InstructionFlags.Vex | InstructionFlags.Prefix66));
Add(X86Instruction.Pmaxuw, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f383e, InstructionFlags.Vex | InstructionFlags.Prefix66));
Add(X86Instruction.Pminsb, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3838, InstructionFlags.Vex | InstructionFlags.Prefix66));
Add(X86Instruction.Pminsd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3839, InstructionFlags.Vex | InstructionFlags.Prefix66));
Add(X86Instruction.Pminsw, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fea, InstructionFlags.Vex | InstructionFlags.Prefix66));
Add(X86Instruction.Pminub, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fda, InstructionFlags.Vex | InstructionFlags.Prefix66));
Add(X86Instruction.Pminud, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f383b, InstructionFlags.Vex | InstructionFlags.Prefix66));
Add(X86Instruction.Pminuw, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f383a, InstructionFlags.Vex | InstructionFlags.Prefix66));
Add(X86Instruction.Pmovsxbw, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3820, InstructionFlags.Vex | InstructionFlags.Prefix66));
Add(X86Instruction.Pmovsxdq, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3825, InstructionFlags.Vex | InstructionFlags.Prefix66));
Add(X86Instruction.Pmovsxwd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3823, InstructionFlags.Vex | InstructionFlags.Prefix66));
Add(X86Instruction.Pmovzxbw, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3830, InstructionFlags.Vex | InstructionFlags.Prefix66));
Add(X86Instruction.Pmovzxdq, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3835, InstructionFlags.Vex | InstructionFlags.Prefix66));
Add(X86Instruction.Pmovzxwd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3833, InstructionFlags.Vex | InstructionFlags.Prefix66));
Add(X86Instruction.Pmulld, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3840, InstructionFlags.Vex | InstructionFlags.Prefix66));
Add(X86Instruction.Pmullw, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fd5, InstructionFlags.Vex | InstructionFlags.Prefix66));
Add(X86Instruction.Pop, new InstructionInfo(0x0000008f, BadOp, BadOp, BadOp, BadOp, InstructionFlags.None));
Add(X86Instruction.Popcnt, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fb8, InstructionFlags.PrefixF3));
Add(X86Instruction.Por, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000feb, InstructionFlags.Vex | InstructionFlags.Prefix66));
Add(X86Instruction.Pshufb, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3800, InstructionFlags.Vex | InstructionFlags.Prefix66));
Add(X86Instruction.Pshufd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f70, InstructionFlags.Vex | InstructionFlags.Prefix66));
Add(X86Instruction.Pslld, new InstructionInfo(BadOp, 0x06000f72, BadOp, BadOp, 0x00000ff2, InstructionFlags.Vex | InstructionFlags.Prefix66));
Add(X86Instruction.Pslldq, new InstructionInfo(BadOp, 0x07000f73, BadOp, BadOp, BadOp, InstructionFlags.Vex | InstructionFlags.Prefix66));
Add(X86Instruction.Psllq, new InstructionInfo(BadOp, 0x06000f73, BadOp, BadOp, 0x00000ff3, InstructionFlags.Vex | InstructionFlags.Prefix66));
Add(X86Instruction.Psllw, new InstructionInfo(BadOp, 0x06000f71, BadOp, BadOp, 0x00000ff1, InstructionFlags.Vex | InstructionFlags.Prefix66));
Add(X86Instruction.Psrad, new InstructionInfo(BadOp, 0x04000f72, BadOp, BadOp, 0x00000fe2, InstructionFlags.Vex | InstructionFlags.Prefix66));
Add(X86Instruction.Psraw, new InstructionInfo(BadOp, 0x04000f71, BadOp, BadOp, 0x00000fe1, InstructionFlags.Vex | InstructionFlags.Prefix66));
Add(X86Instruction.Psrld, new InstructionInfo(BadOp, 0x02000f72, BadOp, BadOp, 0x00000fd2, InstructionFlags.Vex | InstructionFlags.Prefix66));
Add(X86Instruction.Psrlq, new InstructionInfo(BadOp, 0x02000f73, BadOp, BadOp, 0x00000fd3, InstructionFlags.Vex | InstructionFlags.Prefix66));
Add(X86Instruction.Psrldq, new InstructionInfo(BadOp, 0x03000f73, BadOp, BadOp, BadOp, InstructionFlags.Vex | InstructionFlags.Prefix66));
Add(X86Instruction.Psrlw, new InstructionInfo(BadOp, 0x02000f71, BadOp, BadOp, 0x00000fd1, InstructionFlags.Vex | InstructionFlags.Prefix66));
Add(X86Instruction.Psubb, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000ff8, InstructionFlags.Vex | InstructionFlags.Prefix66));
Add(X86Instruction.Psubd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000ffa, InstructionFlags.Vex | InstructionFlags.Prefix66));
Add(X86Instruction.Psubq, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000ffb, InstructionFlags.Vex | InstructionFlags.Prefix66));
Add(X86Instruction.Psubw, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000ff9, InstructionFlags.Vex | InstructionFlags.Prefix66));
Add(X86Instruction.Punpckhbw, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f68, InstructionFlags.Vex | InstructionFlags.Prefix66));
Add(X86Instruction.Punpckhdq, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f6a, InstructionFlags.Vex | InstructionFlags.Prefix66));
Add(X86Instruction.Punpckhqdq, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f6d, InstructionFlags.Vex | InstructionFlags.Prefix66));
Add(X86Instruction.Punpckhwd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f69, InstructionFlags.Vex | InstructionFlags.Prefix66));
Add(X86Instruction.Punpcklbw, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f60, InstructionFlags.Vex | InstructionFlags.Prefix66));
Add(X86Instruction.Punpckldq, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f62, InstructionFlags.Vex | InstructionFlags.Prefix66));
Add(X86Instruction.Punpcklqdq, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f6c, InstructionFlags.Vex | InstructionFlags.Prefix66));
Add(X86Instruction.Punpcklwd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f61, InstructionFlags.Vex | InstructionFlags.Prefix66));
Add(X86Instruction.Push, new InstructionInfo(BadOp, 0x0000006a, 0x00000068, BadOp, 0x060000ff, InstructionFlags.None));
Add(X86Instruction.Pxor, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fef, InstructionFlags.Vex | InstructionFlags.Prefix66));
Add(X86Instruction.Rcpps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f53, InstructionFlags.Vex));
Add(X86Instruction.Rcpss, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f53, InstructionFlags.Vex | InstructionFlags.PrefixF3));
Add(X86Instruction.Ror, new InstructionInfo(0x010000d3, 0x010000c1, BadOp, BadOp, BadOp, InstructionFlags.None));
Add(X86Instruction.Roundpd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3a09, InstructionFlags.Vex | InstructionFlags.Prefix66));
Add(X86Instruction.Roundps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3a08, InstructionFlags.Vex | InstructionFlags.Prefix66));
Add(X86Instruction.Roundsd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3a0b, InstructionFlags.Vex | InstructionFlags.Prefix66));
Add(X86Instruction.Roundss, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3a0a, InstructionFlags.Vex | InstructionFlags.Prefix66));
Add(X86Instruction.Rsqrtps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f52, InstructionFlags.Vex));
Add(X86Instruction.Rsqrtss, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f52, InstructionFlags.Vex | InstructionFlags.PrefixF3));
Add(X86Instruction.Sar, new InstructionInfo(0x070000d3, 0x070000c1, BadOp, BadOp, BadOp, InstructionFlags.None));
Add(X86Instruction.Setcc, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f90, InstructionFlags.Reg8Dest));
Add(X86Instruction.Sha256Msg1, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f38cc, InstructionFlags.None));
Add(X86Instruction.Sha256Msg2, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f38cd, InstructionFlags.None));
Add(X86Instruction.Sha256Rnds2, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f38cb, InstructionFlags.None));
Add(X86Instruction.Shl, new InstructionInfo(0x040000d3, 0x040000c1, BadOp, BadOp, BadOp, InstructionFlags.None));
Add(X86Instruction.Shr, new InstructionInfo(0x050000d3, 0x050000c1, BadOp, BadOp, BadOp, InstructionFlags.None));
Add(X86Instruction.Shufpd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fc6, InstructionFlags.Vex | InstructionFlags.Prefix66));
Add(X86Instruction.Shufps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fc6, InstructionFlags.Vex));
Add(X86Instruction.Sqrtpd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f51, InstructionFlags.Vex | InstructionFlags.Prefix66));
Add(X86Instruction.Sqrtps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f51, InstructionFlags.Vex));
Add(X86Instruction.Sqrtsd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f51, InstructionFlags.Vex | InstructionFlags.PrefixF2));
Add(X86Instruction.Sqrtss, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f51, InstructionFlags.Vex | InstructionFlags.PrefixF3));
Add(X86Instruction.Stmxcsr, new InstructionInfo(0x03000fae, BadOp, BadOp, BadOp, BadOp, InstructionFlags.Vex));
Add(X86Instruction.Sub, new InstructionInfo(0x00000029, 0x05000083, 0x05000081, BadOp, 0x0000002b, InstructionFlags.None));
Add(X86Instruction.Subpd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f5c, InstructionFlags.Vex | InstructionFlags.Prefix66));
Add(X86Instruction.Subps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f5c, InstructionFlags.Vex));
Add(X86Instruction.Subsd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f5c, InstructionFlags.Vex | InstructionFlags.PrefixF2));
Add(X86Instruction.Subss, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f5c, InstructionFlags.Vex | InstructionFlags.PrefixF3));
Add(X86Instruction.Test, new InstructionInfo(0x00000085, BadOp, 0x000000f7, BadOp, BadOp, InstructionFlags.None));
Add(X86Instruction.Unpckhpd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f15, InstructionFlags.Vex | InstructionFlags.Prefix66));
Add(X86Instruction.Unpckhps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f15, InstructionFlags.Vex));
Add(X86Instruction.Unpcklpd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f14, InstructionFlags.Vex | InstructionFlags.Prefix66));
Add(X86Instruction.Unpcklps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f14, InstructionFlags.Vex));
Add(X86Instruction.Vblendvpd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3a4b, InstructionFlags.Vex | InstructionFlags.Prefix66));
Add(X86Instruction.Vblendvps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3a4a, InstructionFlags.Vex | InstructionFlags.Prefix66));
Add(X86Instruction.Vcvtph2ps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3813, InstructionFlags.Vex | InstructionFlags.Prefix66));
Add(X86Instruction.Vcvtps2ph, new InstructionInfo(0x000f3a1d, BadOp, BadOp, BadOp, BadOp, InstructionFlags.Vex | InstructionFlags.Prefix66));
Add(X86Instruction.Vfmadd231ps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f38b8, InstructionFlags.Vex | InstructionFlags.Prefix66));
Add(X86Instruction.Vfmadd231sd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f38b9, InstructionFlags.Vex | InstructionFlags.Prefix66 | InstructionFlags.RexW));
Add(X86Instruction.Vfmadd231ss, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f38b9, InstructionFlags.Vex | InstructionFlags.Prefix66));
Add(X86Instruction.Vfmsub231sd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f38bb, InstructionFlags.Vex | InstructionFlags.Prefix66 | InstructionFlags.RexW));
Add(X86Instruction.Vfmsub231ss, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f38bb, InstructionFlags.Vex | InstructionFlags.Prefix66));
Add(X86Instruction.Vfnmadd231ps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f38bc, InstructionFlags.Vex | InstructionFlags.Prefix66));
Add(X86Instruction.Vfnmadd231sd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f38bd, InstructionFlags.Vex | InstructionFlags.Prefix66 | InstructionFlags.RexW));
Add(X86Instruction.Vfnmadd231ss, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f38bd, InstructionFlags.Vex | InstructionFlags.Prefix66));
Add(X86Instruction.Vfnmsub231sd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f38bf, InstructionFlags.Vex | InstructionFlags.Prefix66 | InstructionFlags.RexW));
Add(X86Instruction.Vfnmsub231ss, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f38bf, InstructionFlags.Vex | InstructionFlags.Prefix66));
Add(X86Instruction.Vpblendvb, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3a4c, InstructionFlags.Vex | InstructionFlags.Prefix66));
Add(X86Instruction.Vpternlogd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3a25, InstructionFlags.Evex | InstructionFlags.Prefix66));
Add(X86Instruction.Xor, new InstructionInfo(0x00000031, 0x06000083, 0x06000081, BadOp, 0x00000033, InstructionFlags.None));
Add(X86Instruction.Xorpd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f57, InstructionFlags.Vex | InstructionFlags.Prefix66));
Add(X86Instruction.Xorps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f57, InstructionFlags.Vex));
static void Add(X86Instruction inst, in InstructionInfo info)
{
_instTable[(int)inst] = info;
}
}
}
}

View File

@@ -1,8 +0,0 @@
namespace ARMeilleure.CodeGen.X86
{
enum CallConvName
{
SystemV,
Windows
}
}

View File

@@ -1,158 +0,0 @@
using System;
namespace ARMeilleure.CodeGen.X86
{
static class CallingConvention
{
private const int RegistersMask = 0xffff;
public static int GetIntAvailableRegisters()
{
return RegistersMask & ~(1 << (int)X86Register.Rsp);
}
public static int GetVecAvailableRegisters()
{
return RegistersMask;
}
public static int GetIntCallerSavedRegisters()
{
if (GetCurrentCallConv() == CallConvName.Windows)
{
return (1 << (int)X86Register.Rax) |
(1 << (int)X86Register.Rcx) |
(1 << (int)X86Register.Rdx) |
(1 << (int)X86Register.R8) |
(1 << (int)X86Register.R9) |
(1 << (int)X86Register.R10) |
(1 << (int)X86Register.R11);
}
else /* if (GetCurrentCallConv() == CallConvName.SystemV) */
{
return (1 << (int)X86Register.Rax) |
(1 << (int)X86Register.Rcx) |
(1 << (int)X86Register.Rdx) |
(1 << (int)X86Register.Rsi) |
(1 << (int)X86Register.Rdi) |
(1 << (int)X86Register.R8) |
(1 << (int)X86Register.R9) |
(1 << (int)X86Register.R10) |
(1 << (int)X86Register.R11);
}
}
public static int GetVecCallerSavedRegisters()
{
if (GetCurrentCallConv() == CallConvName.Windows)
{
return (1 << (int)X86Register.Xmm0) |
(1 << (int)X86Register.Xmm1) |
(1 << (int)X86Register.Xmm2) |
(1 << (int)X86Register.Xmm3) |
(1 << (int)X86Register.Xmm4) |
(1 << (int)X86Register.Xmm5);
}
else /* if (GetCurrentCallConv() == CallConvName.SystemV) */
{
return RegistersMask;
}
}
public static int GetIntCalleeSavedRegisters()
{
return GetIntCallerSavedRegisters() ^ RegistersMask;
}
public static int GetVecCalleeSavedRegisters()
{
return GetVecCallerSavedRegisters() ^ RegistersMask;
}
public static int GetArgumentsOnRegsCount()
{
return 4;
}
public static int GetIntArgumentsOnRegsCount()
{
return 6;
}
public static int GetVecArgumentsOnRegsCount()
{
return 8;
}
public static X86Register GetIntArgumentRegister(int index)
{
if (GetCurrentCallConv() == CallConvName.Windows)
{
switch (index)
{
case 0: return X86Register.Rcx;
case 1: return X86Register.Rdx;
case 2: return X86Register.R8;
case 3: return X86Register.R9;
}
}
else /* if (GetCurrentCallConv() == CallConvName.SystemV) */
{
switch (index)
{
case 0: return X86Register.Rdi;
case 1: return X86Register.Rsi;
case 2: return X86Register.Rdx;
case 3: return X86Register.Rcx;
case 4: return X86Register.R8;
case 5: return X86Register.R9;
}
}
throw new ArgumentOutOfRangeException(nameof(index));
}
public static X86Register GetVecArgumentRegister(int index)
{
int count;
if (GetCurrentCallConv() == CallConvName.Windows)
{
count = 4;
}
else /* if (GetCurrentCallConv() == CallConvName.SystemV) */
{
count = 8;
}
if ((uint)index < count)
{
return X86Register.Xmm0 + index;
}
throw new ArgumentOutOfRangeException(nameof(index));
}
public static X86Register GetIntReturnRegister()
{
return X86Register.Rax;
}
public static X86Register GetIntReturnRegisterHigh()
{
return X86Register.Rdx;
}
public static X86Register GetVecReturnRegister()
{
return X86Register.Xmm0;
}
public static CallConvName GetCurrentCallConv()
{
return OperatingSystem.IsWindows()
? CallConvName.Windows
: CallConvName.SystemV;
}
}
}

View File

@@ -1,105 +0,0 @@
using ARMeilleure.CodeGen.RegisterAllocators;
using ARMeilleure.IntermediateRepresentation;
using Ryujinx.Common.Memory;
using System.IO;
using System.Numerics;
namespace ARMeilleure.CodeGen.X86
{
class CodeGenContext
{
private readonly Stream _stream;
private readonly Operand[] _blockLabels;
public int StreamOffset => (int)_stream.Length;
public AllocationResult AllocResult { get; }
public Assembler Assembler { get; }
public BasicBlock CurrBlock { get; private set; }
public int CallArgsRegionSize { get; }
public int XmmSaveRegionSize { get; }
public CodeGenContext(AllocationResult allocResult, int maxCallArgs, int blocksCount, bool relocatable)
{
_stream = MemoryStreamManager.Shared.GetStream();
_blockLabels = new Operand[blocksCount];
AllocResult = allocResult;
Assembler = new Assembler(_stream, relocatable);
CallArgsRegionSize = GetCallArgsRegionSize(allocResult, maxCallArgs, out int xmmSaveRegionSize);
XmmSaveRegionSize = xmmSaveRegionSize;
}
private static int GetCallArgsRegionSize(AllocationResult allocResult, int maxCallArgs, out int xmmSaveRegionSize)
{
// We need to add 8 bytes to the total size, as the call to this function already pushed 8 bytes (the
// return address).
int intMask = CallingConvention.GetIntCalleeSavedRegisters() & allocResult.IntUsedRegisters;
int vecMask = CallingConvention.GetVecCalleeSavedRegisters() & allocResult.VecUsedRegisters;
xmmSaveRegionSize = BitOperations.PopCount((uint)vecMask) * 16;
int calleeSaveRegionSize = BitOperations.PopCount((uint)intMask) * 8 + xmmSaveRegionSize + 8;
int argsCount = maxCallArgs;
if (argsCount < 0)
{
// When the function has no calls, argsCount is -1. In this case, we don't need to allocate the shadow
// space.
argsCount = 0;
}
else if (argsCount < 4)
{
// The ABI mandates that the space for at least 4 arguments is reserved on the stack (this is called
// shadow space).
argsCount = 4;
}
// TODO: Align XMM save region to 16 bytes because unwinding on Windows requires it.
int frameSize = calleeSaveRegionSize + allocResult.SpillRegionSize;
// TODO: Instead of always multiplying by 16 (the largest possible size of a variable, since a V128 has 16
// bytes), we should calculate the exact size consumed by the arguments passed to the called functions on
// the stack.
int callArgsAndFrameSize = frameSize + argsCount * 16;
// Ensure that the Stack Pointer will be aligned to 16 bytes.
callArgsAndFrameSize = (callArgsAndFrameSize + 0xf) & ~0xf;
return callArgsAndFrameSize - frameSize;
}
public void EnterBlock(BasicBlock block)
{
Assembler.MarkLabel(GetLabel(block));
CurrBlock = block;
}
public void JumpTo(BasicBlock target)
{
Assembler.Jmp(GetLabel(target));
}
public void JumpTo(X86Condition condition, BasicBlock target)
{
Assembler.Jcc(condition, GetLabel(target));
}
private Operand GetLabel(BasicBlock block)
{
ref Operand label = ref _blockLabels[block.Index];
if (label == default)
{
label = Operand.Factory.Label();
}
return label;
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,144 +0,0 @@
using Ryujinx.Memory;
using System;
using System.Runtime.InteropServices;
using System.Runtime.Intrinsics.X86;
namespace ARMeilleure.CodeGen.X86
{
static class HardwareCapabilities
{
private delegate uint GetXcr0();
static HardwareCapabilities()
{
if (!X86Base.IsSupported)
{
return;
}
(int maxNum, _, _, _) = X86Base.CpuId(0x00000000, 0x00000000);
(_, _, int ecx1, int edx1) = X86Base.CpuId(0x00000001, 0x00000000);
FeatureInfo1Edx = (FeatureFlags1Edx)edx1;
FeatureInfo1Ecx = (FeatureFlags1Ecx)ecx1;
if (maxNum >= 7)
{
(_, int ebx7, int ecx7, _) = X86Base.CpuId(0x00000007, 0x00000000);
FeatureInfo7Ebx = (FeatureFlags7Ebx)ebx7;
FeatureInfo7Ecx = (FeatureFlags7Ecx)ecx7;
}
Xcr0InfoEax = (Xcr0FlagsEax)GetXcr0Eax();
}
private static uint GetXcr0Eax()
{
if (!FeatureInfo1Ecx.HasFlag(FeatureFlags1Ecx.Xsave))
{
// XSAVE feature required for xgetbv
return 0;
}
ReadOnlySpan<byte> asmGetXcr0 = new byte[]
{
0x31, 0xc9, // xor ecx, ecx
0xf, 0x01, 0xd0, // xgetbv
0xc3, // ret
};
using MemoryBlock memGetXcr0 = new MemoryBlock((ulong)asmGetXcr0.Length);
memGetXcr0.Write(0, asmGetXcr0);
memGetXcr0.Reprotect(0, (ulong)asmGetXcr0.Length, MemoryPermission.ReadAndExecute);
var fGetXcr0 = Marshal.GetDelegateForFunctionPointer<GetXcr0>(memGetXcr0.Pointer);
return fGetXcr0();
}
[Flags]
public enum FeatureFlags1Edx
{
Sse = 1 << 25,
Sse2 = 1 << 26
}
[Flags]
public enum FeatureFlags1Ecx
{
Sse3 = 1 << 0,
Pclmulqdq = 1 << 1,
Ssse3 = 1 << 9,
Fma = 1 << 12,
Sse41 = 1 << 19,
Sse42 = 1 << 20,
Popcnt = 1 << 23,
Aes = 1 << 25,
Xsave = 1 << 26,
Osxsave = 1 << 27,
Avx = 1 << 28,
F16c = 1 << 29
}
[Flags]
public enum FeatureFlags7Ebx
{
Avx2 = 1 << 5,
Avx512f = 1 << 16,
Avx512dq = 1 << 17,
Sha = 1 << 29,
Avx512bw = 1 << 30,
Avx512vl = 1 << 31
}
[Flags]
public enum FeatureFlags7Ecx
{
Gfni = 1 << 8,
}
[Flags]
public enum Xcr0FlagsEax
{
Sse = 1 << 1,
YmmHi128 = 1 << 2,
Opmask = 1 << 5,
ZmmHi256 = 1 << 6,
Hi16Zmm = 1 << 7
}
public static FeatureFlags1Edx FeatureInfo1Edx { get; }
public static FeatureFlags1Ecx FeatureInfo1Ecx { get; }
public static FeatureFlags7Ebx FeatureInfo7Ebx { get; } = 0;
public static FeatureFlags7Ecx FeatureInfo7Ecx { get; } = 0;
public static Xcr0FlagsEax Xcr0InfoEax { get; } = 0;
public static bool SupportsSse => FeatureInfo1Edx.HasFlag(FeatureFlags1Edx.Sse);
public static bool SupportsSse2 => FeatureInfo1Edx.HasFlag(FeatureFlags1Edx.Sse2);
public static bool SupportsSse3 => FeatureInfo1Ecx.HasFlag(FeatureFlags1Ecx.Sse3);
public static bool SupportsPclmulqdq => FeatureInfo1Ecx.HasFlag(FeatureFlags1Ecx.Pclmulqdq);
public static bool SupportsSsse3 => FeatureInfo1Ecx.HasFlag(FeatureFlags1Ecx.Ssse3);
public static bool SupportsFma => FeatureInfo1Ecx.HasFlag(FeatureFlags1Ecx.Fma);
public static bool SupportsSse41 => FeatureInfo1Ecx.HasFlag(FeatureFlags1Ecx.Sse41);
public static bool SupportsSse42 => FeatureInfo1Ecx.HasFlag(FeatureFlags1Ecx.Sse42);
public static bool SupportsPopcnt => FeatureInfo1Ecx.HasFlag(FeatureFlags1Ecx.Popcnt);
public static bool SupportsAesni => FeatureInfo1Ecx.HasFlag(FeatureFlags1Ecx.Aes);
public static bool SupportsAvx => FeatureInfo1Ecx.HasFlag(FeatureFlags1Ecx.Avx | FeatureFlags1Ecx.Xsave | FeatureFlags1Ecx.Osxsave) && Xcr0InfoEax.HasFlag(Xcr0FlagsEax.Sse | Xcr0FlagsEax.YmmHi128);
public static bool SupportsAvx2 => FeatureInfo7Ebx.HasFlag(FeatureFlags7Ebx.Avx2) && SupportsAvx;
public static bool SupportsAvx512F => FeatureInfo7Ebx.HasFlag(FeatureFlags7Ebx.Avx512f) && FeatureInfo1Ecx.HasFlag(FeatureFlags1Ecx.Xsave | FeatureFlags1Ecx.Osxsave)
&& Xcr0InfoEax.HasFlag(Xcr0FlagsEax.Sse | Xcr0FlagsEax.YmmHi128 | Xcr0FlagsEax.Opmask | Xcr0FlagsEax.ZmmHi256 | Xcr0FlagsEax.Hi16Zmm);
public static bool SupportsAvx512Vl => FeatureInfo7Ebx.HasFlag(FeatureFlags7Ebx.Avx512vl) && SupportsAvx512F;
public static bool SupportsAvx512Bw => FeatureInfo7Ebx.HasFlag(FeatureFlags7Ebx.Avx512bw) && SupportsAvx512F;
public static bool SupportsAvx512Dq => FeatureInfo7Ebx.HasFlag(FeatureFlags7Ebx.Avx512dq) && SupportsAvx512F;
public static bool SupportsF16c => FeatureInfo1Ecx.HasFlag(FeatureFlags1Ecx.F16c);
public static bool SupportsSha => FeatureInfo7Ebx.HasFlag(FeatureFlags7Ebx.Sha);
public static bool SupportsGfni => FeatureInfo7Ecx.HasFlag(FeatureFlags7Ecx.Gfni);
public static bool ForceLegacySse { get; set; }
public static bool SupportsVexEncoding => SupportsAvx && !ForceLegacySse;
public static bool SupportsEvexEncoding => SupportsAvx512F && !ForceLegacySse;
}
}

View File

@@ -1,14 +0,0 @@
namespace ARMeilleure.CodeGen.X86
{
readonly struct IntrinsicInfo
{
public X86Instruction Inst { get; }
public IntrinsicType Type { get; }
public IntrinsicInfo(X86Instruction inst, IntrinsicType type)
{
Inst = inst;
Type = type;
}
}
}

View File

@@ -1,198 +0,0 @@
using ARMeilleure.Common;
using ARMeilleure.IntermediateRepresentation;
namespace ARMeilleure.CodeGen.X86
{
static class IntrinsicTable
{
private static IntrinsicInfo[] _intrinTable;
static IntrinsicTable()
{
_intrinTable = new IntrinsicInfo[EnumUtils.GetCount(typeof(Intrinsic))];
Add(Intrinsic.X86Addpd, new IntrinsicInfo(X86Instruction.Addpd, IntrinsicType.Binary));
Add(Intrinsic.X86Addps, new IntrinsicInfo(X86Instruction.Addps, IntrinsicType.Binary));
Add(Intrinsic.X86Addsd, new IntrinsicInfo(X86Instruction.Addsd, IntrinsicType.Binary));
Add(Intrinsic.X86Addss, new IntrinsicInfo(X86Instruction.Addss, IntrinsicType.Binary));
Add(Intrinsic.X86Aesdec, new IntrinsicInfo(X86Instruction.Aesdec, IntrinsicType.Binary));
Add(Intrinsic.X86Aesdeclast, new IntrinsicInfo(X86Instruction.Aesdeclast, IntrinsicType.Binary));
Add(Intrinsic.X86Aesenc, new IntrinsicInfo(X86Instruction.Aesenc, IntrinsicType.Binary));
Add(Intrinsic.X86Aesenclast, new IntrinsicInfo(X86Instruction.Aesenclast, IntrinsicType.Binary));
Add(Intrinsic.X86Aesimc, new IntrinsicInfo(X86Instruction.Aesimc, IntrinsicType.Unary));
Add(Intrinsic.X86Andnpd, new IntrinsicInfo(X86Instruction.Andnpd, IntrinsicType.Binary));
Add(Intrinsic.X86Andnps, new IntrinsicInfo(X86Instruction.Andnps, IntrinsicType.Binary));
Add(Intrinsic.X86Andpd, new IntrinsicInfo(X86Instruction.Andpd, IntrinsicType.Binary));
Add(Intrinsic.X86Andps, new IntrinsicInfo(X86Instruction.Andps, IntrinsicType.Binary));
Add(Intrinsic.X86Blendvpd, new IntrinsicInfo(X86Instruction.Blendvpd, IntrinsicType.Ternary));
Add(Intrinsic.X86Blendvps, new IntrinsicInfo(X86Instruction.Blendvps, IntrinsicType.Ternary));
Add(Intrinsic.X86Cmppd, new IntrinsicInfo(X86Instruction.Cmppd, IntrinsicType.TernaryImm));
Add(Intrinsic.X86Cmpps, new IntrinsicInfo(X86Instruction.Cmpps, IntrinsicType.TernaryImm));
Add(Intrinsic.X86Cmpsd, new IntrinsicInfo(X86Instruction.Cmpsd, IntrinsicType.TernaryImm));
Add(Intrinsic.X86Cmpss, new IntrinsicInfo(X86Instruction.Cmpss, IntrinsicType.TernaryImm));
Add(Intrinsic.X86Comisdeq, new IntrinsicInfo(X86Instruction.Comisd, IntrinsicType.Comis_));
Add(Intrinsic.X86Comisdge, new IntrinsicInfo(X86Instruction.Comisd, IntrinsicType.Comis_));
Add(Intrinsic.X86Comisdlt, new IntrinsicInfo(X86Instruction.Comisd, IntrinsicType.Comis_));
Add(Intrinsic.X86Comisseq, new IntrinsicInfo(X86Instruction.Comiss, IntrinsicType.Comis_));
Add(Intrinsic.X86Comissge, new IntrinsicInfo(X86Instruction.Comiss, IntrinsicType.Comis_));
Add(Intrinsic.X86Comisslt, new IntrinsicInfo(X86Instruction.Comiss, IntrinsicType.Comis_));
Add(Intrinsic.X86Crc32, new IntrinsicInfo(X86Instruction.Crc32, IntrinsicType.Crc32));
Add(Intrinsic.X86Crc32_16, new IntrinsicInfo(X86Instruction.Crc32_16, IntrinsicType.Crc32));
Add(Intrinsic.X86Crc32_8, new IntrinsicInfo(X86Instruction.Crc32_8, IntrinsicType.Crc32));
Add(Intrinsic.X86Cvtdq2pd, new IntrinsicInfo(X86Instruction.Cvtdq2pd, IntrinsicType.Unary));
Add(Intrinsic.X86Cvtdq2ps, new IntrinsicInfo(X86Instruction.Cvtdq2ps, IntrinsicType.Unary));
Add(Intrinsic.X86Cvtpd2dq, new IntrinsicInfo(X86Instruction.Cvtpd2dq, IntrinsicType.Unary));
Add(Intrinsic.X86Cvtpd2ps, new IntrinsicInfo(X86Instruction.Cvtpd2ps, IntrinsicType.Unary));
Add(Intrinsic.X86Cvtps2dq, new IntrinsicInfo(X86Instruction.Cvtps2dq, IntrinsicType.Unary));
Add(Intrinsic.X86Cvtps2pd, new IntrinsicInfo(X86Instruction.Cvtps2pd, IntrinsicType.Unary));
Add(Intrinsic.X86Cvtsd2si, new IntrinsicInfo(X86Instruction.Cvtsd2si, IntrinsicType.UnaryToGpr));
Add(Intrinsic.X86Cvtsd2ss, new IntrinsicInfo(X86Instruction.Cvtsd2ss, IntrinsicType.Binary));
Add(Intrinsic.X86Cvtsi2sd, new IntrinsicInfo(X86Instruction.Cvtsi2sd, IntrinsicType.BinaryGpr));
Add(Intrinsic.X86Cvtsi2si, new IntrinsicInfo(X86Instruction.Movd, IntrinsicType.UnaryToGpr));
Add(Intrinsic.X86Cvtsi2ss, new IntrinsicInfo(X86Instruction.Cvtsi2ss, IntrinsicType.BinaryGpr));
Add(Intrinsic.X86Cvtss2sd, new IntrinsicInfo(X86Instruction.Cvtss2sd, IntrinsicType.Binary));
Add(Intrinsic.X86Cvtss2si, new IntrinsicInfo(X86Instruction.Cvtss2si, IntrinsicType.UnaryToGpr));
Add(Intrinsic.X86Divpd, new IntrinsicInfo(X86Instruction.Divpd, IntrinsicType.Binary));
Add(Intrinsic.X86Divps, new IntrinsicInfo(X86Instruction.Divps, IntrinsicType.Binary));
Add(Intrinsic.X86Divsd, new IntrinsicInfo(X86Instruction.Divsd, IntrinsicType.Binary));
Add(Intrinsic.X86Divss, new IntrinsicInfo(X86Instruction.Divss, IntrinsicType.Binary));
Add(Intrinsic.X86Gf2p8affineqb, new IntrinsicInfo(X86Instruction.Gf2p8affineqb, IntrinsicType.TernaryImm));
Add(Intrinsic.X86Haddpd, new IntrinsicInfo(X86Instruction.Haddpd, IntrinsicType.Binary));
Add(Intrinsic.X86Haddps, new IntrinsicInfo(X86Instruction.Haddps, IntrinsicType.Binary));
Add(Intrinsic.X86Insertps, new IntrinsicInfo(X86Instruction.Insertps, IntrinsicType.TernaryImm));
Add(Intrinsic.X86Maxpd, new IntrinsicInfo(X86Instruction.Maxpd, IntrinsicType.Binary));
Add(Intrinsic.X86Maxps, new IntrinsicInfo(X86Instruction.Maxps, IntrinsicType.Binary));
Add(Intrinsic.X86Maxsd, new IntrinsicInfo(X86Instruction.Maxsd, IntrinsicType.Binary));
Add(Intrinsic.X86Maxss, new IntrinsicInfo(X86Instruction.Maxss, IntrinsicType.Binary));
Add(Intrinsic.X86Minpd, new IntrinsicInfo(X86Instruction.Minpd, IntrinsicType.Binary));
Add(Intrinsic.X86Minps, new IntrinsicInfo(X86Instruction.Minps, IntrinsicType.Binary));
Add(Intrinsic.X86Minsd, new IntrinsicInfo(X86Instruction.Minsd, IntrinsicType.Binary));
Add(Intrinsic.X86Minss, new IntrinsicInfo(X86Instruction.Minss, IntrinsicType.Binary));
Add(Intrinsic.X86Movhlps, new IntrinsicInfo(X86Instruction.Movhlps, IntrinsicType.Binary));
Add(Intrinsic.X86Movlhps, new IntrinsicInfo(X86Instruction.Movlhps, IntrinsicType.Binary));
Add(Intrinsic.X86Movss, new IntrinsicInfo(X86Instruction.Movss, IntrinsicType.Binary));
Add(Intrinsic.X86Mulpd, new IntrinsicInfo(X86Instruction.Mulpd, IntrinsicType.Binary));
Add(Intrinsic.X86Mulps, new IntrinsicInfo(X86Instruction.Mulps, IntrinsicType.Binary));
Add(Intrinsic.X86Mulsd, new IntrinsicInfo(X86Instruction.Mulsd, IntrinsicType.Binary));
Add(Intrinsic.X86Mulss, new IntrinsicInfo(X86Instruction.Mulss, IntrinsicType.Binary));
Add(Intrinsic.X86Mxcsrmb, new IntrinsicInfo(X86Instruction.None, IntrinsicType.Mxcsr)); // Mask bits.
Add(Intrinsic.X86Mxcsrub, new IntrinsicInfo(X86Instruction.None, IntrinsicType.Mxcsr)); // Unmask bits.
Add(Intrinsic.X86Paddb, new IntrinsicInfo(X86Instruction.Paddb, IntrinsicType.Binary));
Add(Intrinsic.X86Paddd, new IntrinsicInfo(X86Instruction.Paddd, IntrinsicType.Binary));
Add(Intrinsic.X86Paddq, new IntrinsicInfo(X86Instruction.Paddq, IntrinsicType.Binary));
Add(Intrinsic.X86Paddw, new IntrinsicInfo(X86Instruction.Paddw, IntrinsicType.Binary));
Add(Intrinsic.X86Palignr, new IntrinsicInfo(X86Instruction.Palignr, IntrinsicType.TernaryImm));
Add(Intrinsic.X86Pand, new IntrinsicInfo(X86Instruction.Pand, IntrinsicType.Binary));
Add(Intrinsic.X86Pandn, new IntrinsicInfo(X86Instruction.Pandn, IntrinsicType.Binary));
Add(Intrinsic.X86Pavgb, new IntrinsicInfo(X86Instruction.Pavgb, IntrinsicType.Binary));
Add(Intrinsic.X86Pavgw, new IntrinsicInfo(X86Instruction.Pavgw, IntrinsicType.Binary));
Add(Intrinsic.X86Pblendvb, new IntrinsicInfo(X86Instruction.Pblendvb, IntrinsicType.Ternary));
Add(Intrinsic.X86Pclmulqdq, new IntrinsicInfo(X86Instruction.Pclmulqdq, IntrinsicType.TernaryImm));
Add(Intrinsic.X86Pcmpeqb, new IntrinsicInfo(X86Instruction.Pcmpeqb, IntrinsicType.Binary));
Add(Intrinsic.X86Pcmpeqd, new IntrinsicInfo(X86Instruction.Pcmpeqd, IntrinsicType.Binary));
Add(Intrinsic.X86Pcmpeqq, new IntrinsicInfo(X86Instruction.Pcmpeqq, IntrinsicType.Binary));
Add(Intrinsic.X86Pcmpeqw, new IntrinsicInfo(X86Instruction.Pcmpeqw, IntrinsicType.Binary));
Add(Intrinsic.X86Pcmpgtb, new IntrinsicInfo(X86Instruction.Pcmpgtb, IntrinsicType.Binary));
Add(Intrinsic.X86Pcmpgtd, new IntrinsicInfo(X86Instruction.Pcmpgtd, IntrinsicType.Binary));
Add(Intrinsic.X86Pcmpgtq, new IntrinsicInfo(X86Instruction.Pcmpgtq, IntrinsicType.Binary));
Add(Intrinsic.X86Pcmpgtw, new IntrinsicInfo(X86Instruction.Pcmpgtw, IntrinsicType.Binary));
Add(Intrinsic.X86Pmaxsb, new IntrinsicInfo(X86Instruction.Pmaxsb, IntrinsicType.Binary));
Add(Intrinsic.X86Pmaxsd, new IntrinsicInfo(X86Instruction.Pmaxsd, IntrinsicType.Binary));
Add(Intrinsic.X86Pmaxsw, new IntrinsicInfo(X86Instruction.Pmaxsw, IntrinsicType.Binary));
Add(Intrinsic.X86Pmaxub, new IntrinsicInfo(X86Instruction.Pmaxub, IntrinsicType.Binary));
Add(Intrinsic.X86Pmaxud, new IntrinsicInfo(X86Instruction.Pmaxud, IntrinsicType.Binary));
Add(Intrinsic.X86Pmaxuw, new IntrinsicInfo(X86Instruction.Pmaxuw, IntrinsicType.Binary));
Add(Intrinsic.X86Pminsb, new IntrinsicInfo(X86Instruction.Pminsb, IntrinsicType.Binary));
Add(Intrinsic.X86Pminsd, new IntrinsicInfo(X86Instruction.Pminsd, IntrinsicType.Binary));
Add(Intrinsic.X86Pminsw, new IntrinsicInfo(X86Instruction.Pminsw, IntrinsicType.Binary));
Add(Intrinsic.X86Pminub, new IntrinsicInfo(X86Instruction.Pminub, IntrinsicType.Binary));
Add(Intrinsic.X86Pminud, new IntrinsicInfo(X86Instruction.Pminud, IntrinsicType.Binary));
Add(Intrinsic.X86Pminuw, new IntrinsicInfo(X86Instruction.Pminuw, IntrinsicType.Binary));
Add(Intrinsic.X86Pmovsxbw, new IntrinsicInfo(X86Instruction.Pmovsxbw, IntrinsicType.Unary));
Add(Intrinsic.X86Pmovsxdq, new IntrinsicInfo(X86Instruction.Pmovsxdq, IntrinsicType.Unary));
Add(Intrinsic.X86Pmovsxwd, new IntrinsicInfo(X86Instruction.Pmovsxwd, IntrinsicType.Unary));
Add(Intrinsic.X86Pmovzxbw, new IntrinsicInfo(X86Instruction.Pmovzxbw, IntrinsicType.Unary));
Add(Intrinsic.X86Pmovzxdq, new IntrinsicInfo(X86Instruction.Pmovzxdq, IntrinsicType.Unary));
Add(Intrinsic.X86Pmovzxwd, new IntrinsicInfo(X86Instruction.Pmovzxwd, IntrinsicType.Unary));
Add(Intrinsic.X86Pmulld, new IntrinsicInfo(X86Instruction.Pmulld, IntrinsicType.Binary));
Add(Intrinsic.X86Pmullw, new IntrinsicInfo(X86Instruction.Pmullw, IntrinsicType.Binary));
Add(Intrinsic.X86Popcnt, new IntrinsicInfo(X86Instruction.Popcnt, IntrinsicType.PopCount));
Add(Intrinsic.X86Por, new IntrinsicInfo(X86Instruction.Por, IntrinsicType.Binary));
Add(Intrinsic.X86Pshufb, new IntrinsicInfo(X86Instruction.Pshufb, IntrinsicType.Binary));
Add(Intrinsic.X86Pshufd, new IntrinsicInfo(X86Instruction.Pshufd, IntrinsicType.BinaryImm));
Add(Intrinsic.X86Pslld, new IntrinsicInfo(X86Instruction.Pslld, IntrinsicType.Binary));
Add(Intrinsic.X86Pslldq, new IntrinsicInfo(X86Instruction.Pslldq, IntrinsicType.Binary));
Add(Intrinsic.X86Psllq, new IntrinsicInfo(X86Instruction.Psllq, IntrinsicType.Binary));
Add(Intrinsic.X86Psllw, new IntrinsicInfo(X86Instruction.Psllw, IntrinsicType.Binary));
Add(Intrinsic.X86Psrad, new IntrinsicInfo(X86Instruction.Psrad, IntrinsicType.Binary));
Add(Intrinsic.X86Psraw, new IntrinsicInfo(X86Instruction.Psraw, IntrinsicType.Binary));
Add(Intrinsic.X86Psrld, new IntrinsicInfo(X86Instruction.Psrld, IntrinsicType.Binary));
Add(Intrinsic.X86Psrlq, new IntrinsicInfo(X86Instruction.Psrlq, IntrinsicType.Binary));
Add(Intrinsic.X86Psrldq, new IntrinsicInfo(X86Instruction.Psrldq, IntrinsicType.Binary));
Add(Intrinsic.X86Psrlw, new IntrinsicInfo(X86Instruction.Psrlw, IntrinsicType.Binary));
Add(Intrinsic.X86Psubb, new IntrinsicInfo(X86Instruction.Psubb, IntrinsicType.Binary));
Add(Intrinsic.X86Psubd, new IntrinsicInfo(X86Instruction.Psubd, IntrinsicType.Binary));
Add(Intrinsic.X86Psubq, new IntrinsicInfo(X86Instruction.Psubq, IntrinsicType.Binary));
Add(Intrinsic.X86Psubw, new IntrinsicInfo(X86Instruction.Psubw, IntrinsicType.Binary));
Add(Intrinsic.X86Punpckhbw, new IntrinsicInfo(X86Instruction.Punpckhbw, IntrinsicType.Binary));
Add(Intrinsic.X86Punpckhdq, new IntrinsicInfo(X86Instruction.Punpckhdq, IntrinsicType.Binary));
Add(Intrinsic.X86Punpckhqdq, new IntrinsicInfo(X86Instruction.Punpckhqdq, IntrinsicType.Binary));
Add(Intrinsic.X86Punpckhwd, new IntrinsicInfo(X86Instruction.Punpckhwd, IntrinsicType.Binary));
Add(Intrinsic.X86Punpcklbw, new IntrinsicInfo(X86Instruction.Punpcklbw, IntrinsicType.Binary));
Add(Intrinsic.X86Punpckldq, new IntrinsicInfo(X86Instruction.Punpckldq, IntrinsicType.Binary));
Add(Intrinsic.X86Punpcklqdq, new IntrinsicInfo(X86Instruction.Punpcklqdq, IntrinsicType.Binary));
Add(Intrinsic.X86Punpcklwd, new IntrinsicInfo(X86Instruction.Punpcklwd, IntrinsicType.Binary));
Add(Intrinsic.X86Pxor, new IntrinsicInfo(X86Instruction.Pxor, IntrinsicType.Binary));
Add(Intrinsic.X86Rcpps, new IntrinsicInfo(X86Instruction.Rcpps, IntrinsicType.Unary));
Add(Intrinsic.X86Rcpss, new IntrinsicInfo(X86Instruction.Rcpss, IntrinsicType.Unary));
Add(Intrinsic.X86Roundpd, new IntrinsicInfo(X86Instruction.Roundpd, IntrinsicType.BinaryImm));
Add(Intrinsic.X86Roundps, new IntrinsicInfo(X86Instruction.Roundps, IntrinsicType.BinaryImm));
Add(Intrinsic.X86Roundsd, new IntrinsicInfo(X86Instruction.Roundsd, IntrinsicType.BinaryImm));
Add(Intrinsic.X86Roundss, new IntrinsicInfo(X86Instruction.Roundss, IntrinsicType.BinaryImm));
Add(Intrinsic.X86Rsqrtps, new IntrinsicInfo(X86Instruction.Rsqrtps, IntrinsicType.Unary));
Add(Intrinsic.X86Rsqrtss, new IntrinsicInfo(X86Instruction.Rsqrtss, IntrinsicType.Unary));
Add(Intrinsic.X86Sha256Msg1, new IntrinsicInfo(X86Instruction.Sha256Msg1, IntrinsicType.Binary));
Add(Intrinsic.X86Sha256Msg2, new IntrinsicInfo(X86Instruction.Sha256Msg2, IntrinsicType.Binary));
Add(Intrinsic.X86Sha256Rnds2, new IntrinsicInfo(X86Instruction.Sha256Rnds2, IntrinsicType.Ternary));
Add(Intrinsic.X86Shufpd, new IntrinsicInfo(X86Instruction.Shufpd, IntrinsicType.TernaryImm));
Add(Intrinsic.X86Shufps, new IntrinsicInfo(X86Instruction.Shufps, IntrinsicType.TernaryImm));
Add(Intrinsic.X86Sqrtpd, new IntrinsicInfo(X86Instruction.Sqrtpd, IntrinsicType.Unary));
Add(Intrinsic.X86Sqrtps, new IntrinsicInfo(X86Instruction.Sqrtps, IntrinsicType.Unary));
Add(Intrinsic.X86Sqrtsd, new IntrinsicInfo(X86Instruction.Sqrtsd, IntrinsicType.Unary));
Add(Intrinsic.X86Sqrtss, new IntrinsicInfo(X86Instruction.Sqrtss, IntrinsicType.Unary));
Add(Intrinsic.X86Subpd, new IntrinsicInfo(X86Instruction.Subpd, IntrinsicType.Binary));
Add(Intrinsic.X86Subps, new IntrinsicInfo(X86Instruction.Subps, IntrinsicType.Binary));
Add(Intrinsic.X86Subsd, new IntrinsicInfo(X86Instruction.Subsd, IntrinsicType.Binary));
Add(Intrinsic.X86Subss, new IntrinsicInfo(X86Instruction.Subss, IntrinsicType.Binary));
Add(Intrinsic.X86Unpckhpd, new IntrinsicInfo(X86Instruction.Unpckhpd, IntrinsicType.Binary));
Add(Intrinsic.X86Unpckhps, new IntrinsicInfo(X86Instruction.Unpckhps, IntrinsicType.Binary));
Add(Intrinsic.X86Unpcklpd, new IntrinsicInfo(X86Instruction.Unpcklpd, IntrinsicType.Binary));
Add(Intrinsic.X86Unpcklps, new IntrinsicInfo(X86Instruction.Unpcklps, IntrinsicType.Binary));
Add(Intrinsic.X86Vcvtph2ps, new IntrinsicInfo(X86Instruction.Vcvtph2ps, IntrinsicType.Unary));
Add(Intrinsic.X86Vcvtps2ph, new IntrinsicInfo(X86Instruction.Vcvtps2ph, IntrinsicType.BinaryImm));
Add(Intrinsic.X86Vfmadd231ps, new IntrinsicInfo(X86Instruction.Vfmadd231ps, IntrinsicType.Fma));
Add(Intrinsic.X86Vfmadd231sd, new IntrinsicInfo(X86Instruction.Vfmadd231sd, IntrinsicType.Fma));
Add(Intrinsic.X86Vfmadd231ss, new IntrinsicInfo(X86Instruction.Vfmadd231ss, IntrinsicType.Fma));
Add(Intrinsic.X86Vfmsub231sd, new IntrinsicInfo(X86Instruction.Vfmsub231sd, IntrinsicType.Fma));
Add(Intrinsic.X86Vfmsub231ss, new IntrinsicInfo(X86Instruction.Vfmsub231ss, IntrinsicType.Fma));
Add(Intrinsic.X86Vfnmadd231ps, new IntrinsicInfo(X86Instruction.Vfnmadd231ps, IntrinsicType.Fma));
Add(Intrinsic.X86Vfnmadd231sd, new IntrinsicInfo(X86Instruction.Vfnmadd231sd, IntrinsicType.Fma));
Add(Intrinsic.X86Vfnmadd231ss, new IntrinsicInfo(X86Instruction.Vfnmadd231ss, IntrinsicType.Fma));
Add(Intrinsic.X86Vfnmsub231sd, new IntrinsicInfo(X86Instruction.Vfnmsub231sd, IntrinsicType.Fma));
Add(Intrinsic.X86Vfnmsub231ss, new IntrinsicInfo(X86Instruction.Vfnmsub231ss, IntrinsicType.Fma));
Add(Intrinsic.X86Vpternlogd, new IntrinsicInfo(X86Instruction.Vpternlogd, IntrinsicType.TernaryImm));
Add(Intrinsic.X86Xorpd, new IntrinsicInfo(X86Instruction.Xorpd, IntrinsicType.Binary));
Add(Intrinsic.X86Xorps, new IntrinsicInfo(X86Instruction.Xorps, IntrinsicType.Binary));
}
private static void Add(Intrinsic intrin, IntrinsicInfo info)
{
_intrinTable[(int)intrin] = info;
}
public static IntrinsicInfo GetInfo(Intrinsic intrin)
{
return _intrinTable[(int)intrin];
}
}
}

View File

@@ -1,18 +0,0 @@
namespace ARMeilleure.CodeGen.X86
{
enum IntrinsicType
{
Comis_,
Mxcsr,
PopCount,
Unary,
UnaryToGpr,
Binary,
BinaryGpr,
BinaryImm,
Crc32,
Ternary,
TernaryImm,
Fma
}
}

View File

@@ -1,790 +0,0 @@
using ARMeilleure.CodeGen.RegisterAllocators;
using ARMeilleure.IntermediateRepresentation;
using ARMeilleure.Translation;
using System;
using System.Diagnostics;
using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
using static ARMeilleure.IntermediateRepresentation.Operation.Factory;
namespace ARMeilleure.CodeGen.X86
{
class PreAllocator
{
public static void RunPass(CompilerContext cctx, StackAllocator stackAlloc, out int maxCallArgs)
{
maxCallArgs = -1;
Span<Operation> buffer = default;
CallConvName callConv = CallingConvention.GetCurrentCallConv();
Operand[] preservedArgs = new Operand[CallingConvention.GetArgumentsOnRegsCount()];
for (BasicBlock block = cctx.Cfg.Blocks.First; block != null; block = block.ListNext)
{
Operation nextNode;
for (Operation node = block.Operations.First; node != default; node = nextNode)
{
nextNode = node.ListNext;
if (node.Instruction == Instruction.Phi)
{
continue;
}
InsertConstantRegCopies(block.Operations, node);
InsertDestructiveRegCopies(block.Operations, node);
InsertConstrainedRegCopies(block.Operations, node);
switch (node.Instruction)
{
case Instruction.Call:
// Get the maximum number of arguments used on a call.
// On windows, when a struct is returned from the call,
// we also need to pass the pointer where the struct
// should be written on the first argument.
int argsCount = node.SourcesCount - 1;
if (node.Destination != default && node.Destination.Type == OperandType.V128)
{
argsCount++;
}
if (maxCallArgs < argsCount)
{
maxCallArgs = argsCount;
}
// Copy values to registers expected by the function
// being called, as mandated by the ABI.
if (callConv == CallConvName.Windows)
{
PreAllocatorWindows.InsertCallCopies(block.Operations, stackAlloc, node);
}
else /* if (callConv == CallConvName.SystemV) */
{
PreAllocatorSystemV.InsertCallCopies(block.Operations, node);
}
break;
case Instruction.ConvertToFPUI:
GenerateConvertToFPUI(block.Operations, node);
break;
case Instruction.LoadArgument:
if (callConv == CallConvName.Windows)
{
nextNode = PreAllocatorWindows.InsertLoadArgumentCopy(cctx, ref buffer, block.Operations, preservedArgs, node);
}
else /* if (callConv == CallConvName.SystemV) */
{
nextNode = PreAllocatorSystemV.InsertLoadArgumentCopy(cctx, ref buffer, block.Operations, preservedArgs, node);
}
break;
case Instruction.Negate:
if (!node.GetSource(0).Type.IsInteger())
{
GenerateNegate(block.Operations, node);
}
break;
case Instruction.Return:
if (callConv == CallConvName.Windows)
{
PreAllocatorWindows.InsertReturnCopy(cctx, block.Operations, preservedArgs, node);
}
else /* if (callConv == CallConvName.SystemV) */
{
PreAllocatorSystemV.InsertReturnCopy(block.Operations, node);
}
break;
case Instruction.Tailcall:
if (callConv == CallConvName.Windows)
{
PreAllocatorWindows.InsertTailcallCopies(block.Operations, stackAlloc, node);
}
else
{
PreAllocatorSystemV.InsertTailcallCopies(block.Operations, stackAlloc, node);
}
break;
case Instruction.VectorInsert8:
if (!HardwareCapabilities.SupportsSse41)
{
GenerateVectorInsert8(block.Operations, node);
}
break;
case Instruction.Extended:
if (node.Intrinsic == Intrinsic.X86Mxcsrmb || node.Intrinsic == Intrinsic.X86Mxcsrub)
{
int stackOffset = stackAlloc.Allocate(OperandType.I32);
node.SetSources(new Operand[] { Const(stackOffset), node.GetSource(0) });
}
break;
}
}
}
}
protected static void InsertConstantRegCopies(IntrusiveList<Operation> nodes, Operation node)
{
if (node.SourcesCount == 0 || IsXmmIntrinsic(node))
{
return;
}
Instruction inst = node.Instruction;
Operand src1 = node.GetSource(0);
Operand src2;
if (src1.Kind == OperandKind.Constant)
{
if (!src1.Type.IsInteger())
{
// Handle non-integer types (FP32, FP64 and V128).
// For instructions without an immediate operand, we do the following:
// - Insert a copy with the constant value (as integer) to a GPR.
// - Insert a copy from the GPR to a XMM register.
// - Replace the constant use with the XMM register.
src1 = AddXmmCopy(nodes, node, src1);
node.SetSource(0, src1);
}
else if (!HasConstSrc1(inst))
{
// Handle integer types.
// Most ALU instructions accepts a 32-bits immediate on the second operand.
// We need to ensure the following:
// - If the constant is on operand 1, we need to move it.
// -- But first, we try to swap operand 1 and 2 if the instruction is commutative.
// -- Doing so may allow us to encode the constant as operand 2 and avoid a copy.
// - If the constant is on operand 2, we check if the instruction supports it,
// if not, we also add a copy. 64-bits constants are usually not supported.
if (IsCommutative(node))
{
src2 = node.GetSource(1);
Operand temp = src1;
src1 = src2;
src2 = temp;
node.SetSource(0, src1);
node.SetSource(1, src2);
}
if (src1.Kind == OperandKind.Constant)
{
src1 = AddCopy(nodes, node, src1);
node.SetSource(0, src1);
}
}
}
if (node.SourcesCount < 2)
{
return;
}
src2 = node.GetSource(1);
if (src2.Kind == OperandKind.Constant)
{
if (!src2.Type.IsInteger())
{
src2 = AddXmmCopy(nodes, node, src2);
node.SetSource(1, src2);
}
else if (!HasConstSrc2(inst) || CodeGenCommon.IsLongConst(src2))
{
src2 = AddCopy(nodes, node, src2);
node.SetSource(1, src2);
}
}
}
protected static void InsertConstrainedRegCopies(IntrusiveList<Operation> nodes, Operation node)
{
Operand dest = node.Destination;
switch (node.Instruction)
{
case Instruction.CompareAndSwap:
case Instruction.CompareAndSwap16:
case Instruction.CompareAndSwap8:
{
OperandType type = node.GetSource(1).Type;
if (type == OperandType.V128)
{
// Handle the many restrictions of the compare and exchange (16 bytes) instruction:
// - The expected value should be in RDX:RAX.
// - The new value to be written should be in RCX:RBX.
// - The value at the memory location is loaded to RDX:RAX.
void SplitOperand(Operand source, Operand lr, Operand hr)
{
nodes.AddBefore(node, Operation(Instruction.VectorExtract, lr, source, Const(0)));
nodes.AddBefore(node, Operation(Instruction.VectorExtract, hr, source, Const(1)));
}
Operand rax = Gpr(X86Register.Rax, OperandType.I64);
Operand rbx = Gpr(X86Register.Rbx, OperandType.I64);
Operand rcx = Gpr(X86Register.Rcx, OperandType.I64);
Operand rdx = Gpr(X86Register.Rdx, OperandType.I64);
SplitOperand(node.GetSource(1), rax, rdx);
SplitOperand(node.GetSource(2), rbx, rcx);
Operation operation = node;
node = nodes.AddAfter(node, Operation(Instruction.VectorCreateScalar, dest, rax));
nodes.AddAfter(node, Operation(Instruction.VectorInsert, dest, dest, rdx, Const(1)));
operation.SetDestinations(new Operand[] { rdx, rax });
operation.SetSources(new Operand[] { operation.GetSource(0), rdx, rax, rcx, rbx });
}
else
{
// Handle the many restrictions of the compare and exchange (32/64) instruction:
// - The expected value should be in (E/R)AX.
// - The value at the memory location is loaded to (E/R)AX.
Operand expected = node.GetSource(1);
Operand newValue = node.GetSource(2);
Operand rax = Gpr(X86Register.Rax, expected.Type);
nodes.AddBefore(node, Operation(Instruction.Copy, rax, expected));
// We need to store the new value into a temp, since it may
// be a constant, and this instruction does not support immediate operands.
Operand temp = Local(newValue.Type);
nodes.AddBefore(node, Operation(Instruction.Copy, temp, newValue));
node.SetSources(new Operand[] { node.GetSource(0), rax, temp });
nodes.AddAfter(node, Operation(Instruction.Copy, dest, rax));
node.Destination = rax;
}
break;
}
case Instruction.Divide:
case Instruction.DivideUI:
{
// Handle the many restrictions of the division instructions:
// - The dividend is always in RDX:RAX.
// - The result is always in RAX.
// - Additionally it also writes the remainder in RDX.
if (dest.Type.IsInteger())
{
Operand src1 = node.GetSource(0);
Operand rax = Gpr(X86Register.Rax, src1.Type);
Operand rdx = Gpr(X86Register.Rdx, src1.Type);
nodes.AddBefore(node, Operation(Instruction.Copy, rax, src1));
nodes.AddBefore(node, Operation(Instruction.Clobber, rdx));
nodes.AddAfter(node, Operation(Instruction.Copy, dest, rax));
node.SetSources(new Operand[] { rdx, rax, node.GetSource(1) });
node.Destination = rax;
}
break;
}
case Instruction.Extended:
{
bool isBlend = node.Intrinsic == Intrinsic.X86Blendvpd ||
node.Intrinsic == Intrinsic.X86Blendvps ||
node.Intrinsic == Intrinsic.X86Pblendvb;
// 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.
if ((isBlend && !HardwareCapabilities.SupportsVexEncoding) || node.Intrinsic == Intrinsic.X86Sha256Rnds2)
{
Operand xmm0 = Xmm(X86Register.Xmm0, OperandType.V128);
nodes.AddBefore(node, Operation(Instruction.Copy, xmm0, node.GetSource(2)));
node.SetSource(2, xmm0);
}
break;
}
case Instruction.Multiply64HighSI:
case Instruction.Multiply64HighUI:
{
// Handle the many restrictions of the i64 * i64 = i128 multiply instructions:
// - The multiplicand is always in RAX.
// - The lower 64-bits of the result is always in RAX.
// - The higher 64-bits of the result is always in RDX.
Operand src1 = node.GetSource(0);
Operand rax = Gpr(X86Register.Rax, src1.Type);
Operand rdx = Gpr(X86Register.Rdx, src1.Type);
nodes.AddBefore(node, Operation(Instruction.Copy, rax, src1));
node.SetSource(0, rax);
nodes.AddAfter(node, Operation(Instruction.Copy, dest, rdx));
node.SetDestinations(new Operand[] { rdx, rax });
break;
}
case Instruction.RotateRight:
case Instruction.ShiftLeft:
case Instruction.ShiftRightSI:
case Instruction.ShiftRightUI:
{
// The shift register is always implied to be CL (low 8-bits of RCX or ECX).
if (node.GetSource(1).Kind == OperandKind.LocalVariable)
{
Operand rcx = Gpr(X86Register.Rcx, OperandType.I32);
nodes.AddBefore(node, Operation(Instruction.Copy, rcx, node.GetSource(1)));
node.SetSource(1, rcx);
}
break;
}
}
}
protected static void InsertDestructiveRegCopies(IntrusiveList<Operation> nodes, Operation node)
{
if (node.Destination == default || node.SourcesCount == 0)
{
return;
}
Instruction inst = node.Instruction;
Operand dest = node.Destination;
Operand src1 = node.GetSource(0);
// The multiply instruction (that maps to IMUL) is somewhat special, it has
// a three operand form where the second source is a immediate value.
bool threeOperandForm = inst == Instruction.Multiply && node.GetSource(1).Kind == OperandKind.Constant;
if (IsSameOperandDestSrc1(node) && src1.Kind == OperandKind.LocalVariable && !threeOperandForm)
{
bool useNewLocal = false;
for (int srcIndex = 1; srcIndex < node.SourcesCount; srcIndex++)
{
if (node.GetSource(srcIndex) == dest)
{
useNewLocal = true;
break;
}
}
if (useNewLocal)
{
// Dest is being used as some source already, we need to use a new
// local to store the temporary value, otherwise the value on dest
// local would be overwritten.
Operand temp = Local(dest.Type);
nodes.AddBefore(node, Operation(Instruction.Copy, temp, src1));
node.SetSource(0, temp);
nodes.AddAfter(node, Operation(Instruction.Copy, dest, temp));
node.Destination = temp;
}
else
{
nodes.AddBefore(node, Operation(Instruction.Copy, dest, src1));
node.SetSource(0, dest);
}
}
else if (inst == Instruction.ConditionalSelect)
{
Operand src2 = node.GetSource(1);
Operand src3 = node.GetSource(2);
if (src1 == dest || src2 == dest)
{
Operand temp = Local(dest.Type);
nodes.AddBefore(node, Operation(Instruction.Copy, temp, src3));
node.SetSource(2, temp);
nodes.AddAfter(node, Operation(Instruction.Copy, dest, temp));
node.Destination = temp;
}
else
{
nodes.AddBefore(node, Operation(Instruction.Copy, dest, src3));
node.SetSource(2, dest);
}
}
}
private static void GenerateConvertToFPUI(IntrusiveList<Operation> nodes, Operation node)
{
// Unsigned integer to FP conversions are not supported on X86.
// We need to turn them into signed integer to FP conversions, and
// adjust the final result.
Operand dest = node.Destination;
Operand source = node.GetSource(0);
Debug.Assert(source.Type.IsInteger(), $"Invalid source type \"{source.Type}\".");
Operation currentNode = node;
if (source.Type == OperandType.I32)
{
// For 32-bits integers, we can just zero-extend to 64-bits,
// and then use the 64-bits signed conversion instructions.
Operand zex = Local(OperandType.I64);
node = nodes.AddAfter(node, Operation(Instruction.ZeroExtend32, zex, source));
node = nodes.AddAfter(node, Operation(Instruction.ConvertToFP, dest, zex));
}
else /* if (source.Type == OperandType.I64) */
{
// For 64-bits integers, we need to do the following:
// - Ensure that the integer has the most significant bit clear.
// -- This can be done by shifting the value right by 1, that is, dividing by 2.
// -- The least significant bit is lost in this case though.
// - We can then convert the shifted value with a signed integer instruction.
// - The result still needs to be corrected after that.
// -- First, we need to multiply the result by 2, as we divided it by 2 before.
// --- This can be done efficiently by adding the result to itself.
// -- Then, we need to add the least significant bit that was shifted out.
// --- We can convert the least significant bit to float, and add it to the result.
Operand lsb = Local(OperandType.I64);
Operand half = Local(OperandType.I64);
Operand lsbF = Local(dest.Type);
node = nodes.AddAfter(node, Operation(Instruction.Copy, lsb, source));
node = nodes.AddAfter(node, Operation(Instruction.Copy, half, source));
node = nodes.AddAfter(node, Operation(Instruction.BitwiseAnd, lsb, lsb, Const(1L)));
node = nodes.AddAfter(node, Operation(Instruction.ShiftRightUI, half, half, Const(1)));
node = nodes.AddAfter(node, Operation(Instruction.ConvertToFP, lsbF, lsb));
node = nodes.AddAfter(node, Operation(Instruction.ConvertToFP, dest, half));
node = nodes.AddAfter(node, Operation(Instruction.Add, dest, dest, dest));
nodes.AddAfter(node, Operation(Instruction.Add, dest, dest, lsbF));
}
Delete(nodes, currentNode);
}
private static void GenerateNegate(IntrusiveList<Operation> nodes, Operation node)
{
// There's no SSE FP negate instruction, so we need to transform that into
// a XOR of the value to be negated with a mask with the highest bit set.
// This also produces -0 for a negation of the value 0.
Operand dest = node.Destination;
Operand source = node.GetSource(0);
Debug.Assert(dest.Type == OperandType.FP32 ||
dest.Type == OperandType.FP64, $"Invalid destination type \"{dest.Type}\".");
Operation currentNode = node;
Operand res = Local(dest.Type);
node = nodes.AddAfter(node, Operation(Instruction.VectorOne, res));
if (dest.Type == OperandType.FP32)
{
node = nodes.AddAfter(node, Operation(Intrinsic.X86Pslld, res, res, Const(31)));
}
else /* if (dest.Type == OperandType.FP64) */
{
node = nodes.AddAfter(node, Operation(Intrinsic.X86Psllq, res, res, Const(63)));
}
node = nodes.AddAfter(node, Operation(Intrinsic.X86Xorps, res, res, source));
nodes.AddAfter(node, Operation(Instruction.Copy, dest, res));
Delete(nodes, currentNode);
}
private static void GenerateVectorInsert8(IntrusiveList<Operation> nodes, Operation node)
{
// Handle vector insertion, when SSE 4.1 is not supported.
Operand dest = node.Destination;
Operand src1 = node.GetSource(0); // Vector
Operand src2 = node.GetSource(1); // Value
Operand src3 = node.GetSource(2); // Index
Debug.Assert(src3.Kind == OperandKind.Constant);
byte index = src3.AsByte();
Debug.Assert(index < 16);
Operation currentNode = node;
Operand temp1 = Local(OperandType.I32);
Operand temp2 = Local(OperandType.I32);
node = nodes.AddAfter(node, Operation(Instruction.Copy, temp2, src2));
Operation vextOp = Operation(Instruction.VectorExtract16, temp1, src1, Const(index >> 1));
node = nodes.AddAfter(node, vextOp);
if ((index & 1) != 0)
{
node = nodes.AddAfter(node, Operation(Instruction.ZeroExtend8, temp1, temp1));
node = nodes.AddAfter(node, Operation(Instruction.ShiftLeft, temp2, temp2, Const(8)));
node = nodes.AddAfter(node, Operation(Instruction.BitwiseOr, temp1, temp1, temp2));
}
else
{
node = nodes.AddAfter(node, Operation(Instruction.ZeroExtend8, temp2, temp2));
node = nodes.AddAfter(node, Operation(Instruction.BitwiseAnd, temp1, temp1, Const(0xff00)));
node = nodes.AddAfter(node, Operation(Instruction.BitwiseOr, temp1, temp1, temp2));
}
Operation vinsOp = Operation(Instruction.VectorInsert16, dest, src1, temp1, Const(index >> 1));
nodes.AddAfter(node, vinsOp);
Delete(nodes, currentNode);
}
protected static Operand AddXmmCopy(IntrusiveList<Operation> nodes, Operation node, Operand source)
{
Operand temp = Local(source.Type);
Operand intConst = AddCopy(nodes, node, GetIntConst(source));
Operation copyOp = Operation(Instruction.VectorCreateScalar, temp, intConst);
nodes.AddBefore(node, copyOp);
return temp;
}
protected static Operand AddCopy(IntrusiveList<Operation> nodes, Operation node, Operand source)
{
Operand temp = Local(source.Type);
Operation copyOp = Operation(Instruction.Copy, temp, source);
nodes.AddBefore(node, copyOp);
return temp;
}
private static Operand GetIntConst(Operand value)
{
if (value.Type == OperandType.FP32)
{
return Const(value.AsInt32());
}
else if (value.Type == OperandType.FP64)
{
return Const(value.AsInt64());
}
return value;
}
protected static void Delete(IntrusiveList<Operation> nodes, Operation node)
{
node.Destination = default;
for (int index = 0; index < node.SourcesCount; index++)
{
node.SetSource(index, default);
}
nodes.Remove(node);
}
protected static Operand Gpr(X86Register register, OperandType type)
{
return Register((int)register, RegisterType.Integer, type);
}
protected static Operand Xmm(X86Register register, OperandType type)
{
return Register((int)register, RegisterType.Vector, type);
}
private static bool IsSameOperandDestSrc1(Operation operation)
{
switch (operation.Instruction)
{
case Instruction.Add:
return !HardwareCapabilities.SupportsVexEncoding && !operation.Destination.Type.IsInteger();
case Instruction.Multiply:
case Instruction.Subtract:
return !HardwareCapabilities.SupportsVexEncoding || operation.Destination.Type.IsInteger();
case Instruction.BitwiseAnd:
case Instruction.BitwiseExclusiveOr:
case Instruction.BitwiseNot:
case Instruction.BitwiseOr:
case Instruction.ByteSwap:
case Instruction.Negate:
case Instruction.RotateRight:
case Instruction.ShiftLeft:
case Instruction.ShiftRightSI:
case Instruction.ShiftRightUI:
return true;
case Instruction.Divide:
return !HardwareCapabilities.SupportsVexEncoding && !operation.Destination.Type.IsInteger();
case Instruction.VectorInsert:
case Instruction.VectorInsert16:
case Instruction.VectorInsert8:
return !HardwareCapabilities.SupportsVexEncoding;
case Instruction.Extended:
return IsIntrinsicSameOperandDestSrc1(operation);
}
return IsVexSameOperandDestSrc1(operation);
}
private static bool IsIntrinsicSameOperandDestSrc1(Operation operation)
{
IntrinsicInfo info = IntrinsicTable.GetInfo(operation.Intrinsic);
return info.Type == IntrinsicType.Crc32 || info.Type == IntrinsicType.Fma || IsVexSameOperandDestSrc1(operation);
}
private static bool IsVexSameOperandDestSrc1(Operation operation)
{
if (IsIntrinsic(operation.Instruction))
{
IntrinsicInfo info = IntrinsicTable.GetInfo(operation.Intrinsic);
bool hasVex = HardwareCapabilities.SupportsVexEncoding && Assembler.SupportsVexPrefix(info.Inst);
bool isUnary = operation.SourcesCount < 2;
bool hasVecDest = operation.Destination != default && operation.Destination.Type == OperandType.V128;
return !hasVex && !isUnary && hasVecDest;
}
return false;
}
private static bool HasConstSrc1(Instruction inst)
{
switch (inst)
{
case Instruction.Copy:
case Instruction.LoadArgument:
case Instruction.Spill:
case Instruction.SpillArg:
return true;
}
return false;
}
private static bool HasConstSrc2(Instruction inst)
{
switch (inst)
{
case Instruction.Add:
case Instruction.BitwiseAnd:
case Instruction.BitwiseExclusiveOr:
case Instruction.BitwiseOr:
case Instruction.BranchIf:
case Instruction.Compare:
case Instruction.Multiply:
case Instruction.RotateRight:
case Instruction.ShiftLeft:
case Instruction.ShiftRightSI:
case Instruction.ShiftRightUI:
case Instruction.Store:
case Instruction.Store16:
case Instruction.Store8:
case Instruction.Subtract:
case Instruction.VectorExtract:
case Instruction.VectorExtract16:
case Instruction.VectorExtract8:
return true;
}
return false;
}
private static bool IsCommutative(Operation operation)
{
switch (operation.Instruction)
{
case Instruction.Add:
case Instruction.BitwiseAnd:
case Instruction.BitwiseExclusiveOr:
case Instruction.BitwiseOr:
case Instruction.Multiply:
return true;
case Instruction.BranchIf:
case Instruction.Compare:
{
Operand comp = operation.GetSource(2);
Debug.Assert(comp.Kind == OperandKind.Constant);
var compType = (Comparison)comp.AsInt32();
return compType == Comparison.Equal || compType == Comparison.NotEqual;
}
}
return false;
}
private static bool IsIntrinsic(Instruction inst)
{
return inst == Instruction.Extended;
}
private static bool IsXmmIntrinsic(Operation operation)
{
if (operation.Instruction != Instruction.Extended)
{
return false;
}
IntrinsicInfo info = IntrinsicTable.GetInfo(operation.Intrinsic);
return info.Type != IntrinsicType.Crc32;
}
}
}

View File

@@ -1,334 +0,0 @@
using ARMeilleure.CodeGen.RegisterAllocators;
using ARMeilleure.IntermediateRepresentation;
using ARMeilleure.Translation;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
using static ARMeilleure.IntermediateRepresentation.Operation.Factory;
namespace ARMeilleure.CodeGen.X86
{
class PreAllocatorSystemV : PreAllocator
{
public static void InsertCallCopies(IntrusiveList<Operation> nodes, Operation node)
{
Operand dest = node.Destination;
List<Operand> sources = new List<Operand>
{
node.GetSource(0)
};
int argsCount = node.SourcesCount - 1;
int intMax = CallingConvention.GetIntArgumentsOnRegsCount();
int vecMax = CallingConvention.GetVecArgumentsOnRegsCount();
int intCount = 0;
int vecCount = 0;
int stackOffset = 0;
for (int index = 0; index < argsCount; index++)
{
Operand source = node.GetSource(index + 1);
bool passOnReg;
if (source.Type.IsInteger())
{
passOnReg = intCount < intMax;
}
else if (source.Type == OperandType.V128)
{
passOnReg = intCount + 1 < intMax;
}
else
{
passOnReg = vecCount < vecMax;
}
if (source.Type == OperandType.V128 && passOnReg)
{
// V128 is a struct, we pass each half on a GPR if possible.
Operand argReg = Gpr(CallingConvention.GetIntArgumentRegister(intCount++), OperandType.I64);
Operand argReg2 = Gpr(CallingConvention.GetIntArgumentRegister(intCount++), OperandType.I64);
nodes.AddBefore(node, Operation(Instruction.VectorExtract, argReg, source, Const(0)));
nodes.AddBefore(node, Operation(Instruction.VectorExtract, argReg2, source, Const(1)));
continue;
}
if (passOnReg)
{
Operand argReg = source.Type.IsInteger()
? Gpr(CallingConvention.GetIntArgumentRegister(intCount++), source.Type)
: Xmm(CallingConvention.GetVecArgumentRegister(vecCount++), source.Type);
Operation copyOp = Operation(Instruction.Copy, argReg, source);
InsertConstantRegCopies(nodes, nodes.AddBefore(node, copyOp));
sources.Add(argReg);
}
else
{
Operand offset = Const(stackOffset);
Operation spillOp = Operation(Instruction.SpillArg, default, offset, source);
InsertConstantRegCopies(nodes, nodes.AddBefore(node, spillOp));
stackOffset += source.Type.GetSizeInBytes();
}
}
node.SetSources(sources.ToArray());
if (dest != default)
{
if (dest.Type == OperandType.V128)
{
Operand retLReg = Gpr(CallingConvention.GetIntReturnRegister(), OperandType.I64);
Operand retHReg = Gpr(CallingConvention.GetIntReturnRegisterHigh(), OperandType.I64);
Operation operation = node;
node = nodes.AddAfter(node, Operation(Instruction.VectorCreateScalar, dest, retLReg));
nodes.AddAfter(node, Operation(Instruction.VectorInsert, dest, dest, retHReg, Const(1)));
operation.Destination = default;
}
else
{
Operand retReg = dest.Type.IsInteger()
? Gpr(CallingConvention.GetIntReturnRegister(), dest.Type)
: Xmm(CallingConvention.GetVecReturnRegister(), dest.Type);
Operation copyOp = Operation(Instruction.Copy, dest, retReg);
nodes.AddAfter(node, copyOp);
node.Destination = retReg;
}
}
}
public static void InsertTailcallCopies(IntrusiveList<Operation> nodes, StackAllocator stackAlloc, Operation node)
{
List<Operand> sources = new List<Operand>
{
node.GetSource(0)
};
int argsCount = node.SourcesCount - 1;
int intMax = CallingConvention.GetIntArgumentsOnRegsCount();
int vecMax = CallingConvention.GetVecArgumentsOnRegsCount();
int intCount = 0;
int vecCount = 0;
// Handle arguments passed on registers.
for (int index = 0; index < argsCount; index++)
{
Operand source = node.GetSource(1 + index);
bool passOnReg;
if (source.Type.IsInteger())
{
passOnReg = intCount + 1 < intMax;
}
else
{
passOnReg = vecCount < vecMax;
}
if (source.Type == OperandType.V128 && passOnReg)
{
// V128 is a struct, we pass each half on a GPR if possible.
Operand argReg = Gpr(CallingConvention.GetIntArgumentRegister(intCount++), OperandType.I64);
Operand argReg2 = Gpr(CallingConvention.GetIntArgumentRegister(intCount++), OperandType.I64);
nodes.AddBefore(node, Operation(Instruction.VectorExtract, argReg, source, Const(0)));
nodes.AddBefore(node, Operation(Instruction.VectorExtract, argReg2, source, Const(1)));
continue;
}
if (passOnReg)
{
Operand argReg = source.Type.IsInteger()
? Gpr(CallingConvention.GetIntArgumentRegister(intCount++), source.Type)
: Xmm(CallingConvention.GetVecArgumentRegister(vecCount++), source.Type);
Operation copyOp = Operation(Instruction.Copy, argReg, source);
InsertConstantRegCopies(nodes, nodes.AddBefore(node, copyOp));
sources.Add(argReg);
}
else
{
throw new NotImplementedException("Spilling is not currently supported for tail calls. (too many arguments)");
}
}
// The target address must be on the return registers, since we
// don't return anything and it is guaranteed to not be a
// callee saved register (which would be trashed on the epilogue).
Operand retReg = Gpr(CallingConvention.GetIntReturnRegister(), OperandType.I64);
Operation addrCopyOp = Operation(Instruction.Copy, retReg, node.GetSource(0));
nodes.AddBefore(node, addrCopyOp);
sources[0] = retReg;
node.SetSources(sources.ToArray());
}
public static Operation InsertLoadArgumentCopy(
CompilerContext cctx,
ref Span<Operation> buffer,
IntrusiveList<Operation> nodes,
Operand[] preservedArgs,
Operation node)
{
Operand source = node.GetSource(0);
Debug.Assert(source.Kind == OperandKind.Constant, "Non-constant LoadArgument source kind.");
int index = source.AsInt32();
int intCount = 0;
int vecCount = 0;
for (int cIndex = 0; cIndex < index; cIndex++)
{
OperandType argType = cctx.FuncArgTypes[cIndex];
if (argType.IsInteger())
{
intCount++;
}
else if (argType == OperandType.V128)
{
intCount += 2;
}
else
{
vecCount++;
}
}
bool passOnReg;
if (source.Type.IsInteger())
{
passOnReg = intCount < CallingConvention.GetIntArgumentsOnRegsCount();
}
else if (source.Type == OperandType.V128)
{
passOnReg = intCount + 1 < CallingConvention.GetIntArgumentsOnRegsCount();
}
else
{
passOnReg = vecCount < CallingConvention.GetVecArgumentsOnRegsCount();
}
if (passOnReg)
{
Operand dest = node.Destination;
if (preservedArgs[index] == default)
{
if (dest.Type == OperandType.V128)
{
// V128 is a struct, we pass each half on a GPR if possible.
Operand pArg = Local(OperandType.V128);
Operand argLReg = Gpr(CallingConvention.GetIntArgumentRegister(intCount), OperandType.I64);
Operand argHReg = Gpr(CallingConvention.GetIntArgumentRegister(intCount + 1), OperandType.I64);
Operation copyL = Operation(Instruction.VectorCreateScalar, pArg, argLReg);
Operation copyH = Operation(Instruction.VectorInsert, pArg, pArg, argHReg, Const(1));
cctx.Cfg.Entry.Operations.AddFirst(copyH);
cctx.Cfg.Entry.Operations.AddFirst(copyL);
preservedArgs[index] = pArg;
}
else
{
Operand pArg = Local(dest.Type);
Operand argReg = dest.Type.IsInteger()
? Gpr(CallingConvention.GetIntArgumentRegister(intCount), dest.Type)
: Xmm(CallingConvention.GetVecArgumentRegister(vecCount), dest.Type);
Operation copyOp = Operation(Instruction.Copy, pArg, argReg);
cctx.Cfg.Entry.Operations.AddFirst(copyOp);
preservedArgs[index] = pArg;
}
}
Operation nextNode;
if (dest.AssignmentsCount == 1)
{
// Let's propagate the argument if we can to avoid copies.
PreAllocatorCommon.Propagate(ref buffer, dest, preservedArgs[index]);
nextNode = node.ListNext;
}
else
{
Operation argCopyOp = Operation(Instruction.Copy, dest, preservedArgs[index]);
nextNode = nodes.AddBefore(node, argCopyOp);
}
Delete(nodes, node);
return nextNode;
}
else
{
// TODO: Pass on stack.
return node;
}
}
public static void InsertReturnCopy(IntrusiveList<Operation> nodes, Operation node)
{
if (node.SourcesCount == 0)
{
return;
}
Operand source = node.GetSource(0);
if (source.Type == OperandType.V128)
{
Operand retLReg = Gpr(CallingConvention.GetIntReturnRegister(), OperandType.I64);
Operand retHReg = Gpr(CallingConvention.GetIntReturnRegisterHigh(), OperandType.I64);
nodes.AddBefore(node, Operation(Instruction.VectorExtract, retLReg, source, Const(0)));
nodes.AddBefore(node, Operation(Instruction.VectorExtract, retHReg, source, Const(1)));
}
else
{
Operand retReg = source.Type.IsInteger()
? Gpr(CallingConvention.GetIntReturnRegister(), source.Type)
: Xmm(CallingConvention.GetVecReturnRegister(), source.Type);
Operation retCopyOp = Operation(Instruction.Copy, retReg, source);
nodes.AddBefore(node, retCopyOp);
}
}
}
}

View File

@@ -1,327 +0,0 @@
using ARMeilleure.CodeGen.RegisterAllocators;
using ARMeilleure.IntermediateRepresentation;
using ARMeilleure.Translation;
using System;
using System.Diagnostics;
using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
using static ARMeilleure.IntermediateRepresentation.Operation.Factory;
namespace ARMeilleure.CodeGen.X86
{
class PreAllocatorWindows : PreAllocator
{
public static void InsertCallCopies(IntrusiveList<Operation> nodes, StackAllocator stackAlloc, Operation node)
{
Operand dest = node.Destination;
// Handle struct arguments.
int retArgs = 0;
int stackAllocOffset = 0;
int AllocateOnStack(int size)
{
// We assume that the stack allocator is initially empty (TotalSize = 0).
// Taking that into account, we can reuse the space allocated for other
// calls by keeping track of our own allocated size (stackAllocOffset).
// If the space allocated is not big enough, then we just expand it.
int offset = stackAllocOffset;
if (stackAllocOffset + size > stackAlloc.TotalSize)
{
stackAlloc.Allocate((stackAllocOffset + size) - stackAlloc.TotalSize);
}
stackAllocOffset += size;
return offset;
}
Operand arg0Reg = default;
if (dest != default && dest.Type == OperandType.V128)
{
int stackOffset = AllocateOnStack(dest.Type.GetSizeInBytes());
arg0Reg = Gpr(CallingConvention.GetIntArgumentRegister(0), OperandType.I64);
Operation allocOp = Operation(Instruction.StackAlloc, arg0Reg, Const(stackOffset));
nodes.AddBefore(node, allocOp);
retArgs = 1;
}
int argsCount = node.SourcesCount - 1;
int maxArgs = CallingConvention.GetArgumentsOnRegsCount() - retArgs;
if (argsCount > maxArgs)
{
argsCount = maxArgs;
}
Operand[] sources = new Operand[1 + retArgs + argsCount];
sources[0] = node.GetSource(0);
if (arg0Reg != default)
{
sources[1] = arg0Reg;
}
for (int index = 1; index < node.SourcesCount; index++)
{
Operand source = node.GetSource(index);
if (source.Type == OperandType.V128)
{
Operand stackAddr = Local(OperandType.I64);
int stackOffset = AllocateOnStack(source.Type.GetSizeInBytes());
nodes.AddBefore(node, Operation(Instruction.StackAlloc, stackAddr, Const(stackOffset)));
Operation storeOp = Operation(Instruction.Store, default, stackAddr, source);
InsertConstantRegCopies(nodes, nodes.AddBefore(node, storeOp));
node.SetSource(index, stackAddr);
}
}
// Handle arguments passed on registers.
for (int index = 0; index < argsCount; index++)
{
Operand source = node.GetSource(index + 1);
Operand argReg;
int argIndex = index + retArgs;
if (source.Type.IsInteger())
{
argReg = Gpr(CallingConvention.GetIntArgumentRegister(argIndex), source.Type);
}
else
{
argReg = Xmm(CallingConvention.GetVecArgumentRegister(argIndex), source.Type);
}
Operation copyOp = Operation(Instruction.Copy, argReg, source);
InsertConstantRegCopies(nodes, nodes.AddBefore(node, copyOp));
sources[1 + retArgs + index] = argReg;
}
// The remaining arguments (those that are not passed on registers)
// should be passed on the stack, we write them to the stack with "SpillArg".
for (int index = argsCount; index < node.SourcesCount - 1; index++)
{
Operand source = node.GetSource(index + 1);
Operand offset = Const((index + retArgs) * 8);
Operation spillOp = Operation(Instruction.SpillArg, default, offset, source);
InsertConstantRegCopies(nodes, nodes.AddBefore(node, spillOp));
}
if (dest != default)
{
if (dest.Type == OperandType.V128)
{
Operand retValueAddr = Local(OperandType.I64);
nodes.AddBefore(node, Operation(Instruction.Copy, retValueAddr, arg0Reg));
Operation loadOp = Operation(Instruction.Load, dest, retValueAddr);
nodes.AddAfter(node, loadOp);
node.Destination = default;
}
else
{
Operand retReg = dest.Type.IsInteger()
? Gpr(CallingConvention.GetIntReturnRegister(), dest.Type)
: Xmm(CallingConvention.GetVecReturnRegister(), dest.Type);
Operation copyOp = Operation(Instruction.Copy, dest, retReg);
nodes.AddAfter(node, copyOp);
node.Destination = retReg;
}
}
node.SetSources(sources);
}
public static void InsertTailcallCopies(IntrusiveList<Operation> nodes, StackAllocator stackAlloc, Operation node)
{
int argsCount = node.SourcesCount - 1;
int maxArgs = CallingConvention.GetArgumentsOnRegsCount();
if (argsCount > maxArgs)
{
throw new NotImplementedException("Spilling is not currently supported for tail calls. (too many arguments)");
}
Operand[] sources = new Operand[1 + argsCount];
// Handle arguments passed on registers.
for (int index = 0; index < argsCount; index++)
{
Operand source = node.GetSource(1 + index);
Operand argReg = source.Type.IsInteger()
? Gpr(CallingConvention.GetIntArgumentRegister(index), source.Type)
: Xmm(CallingConvention.GetVecArgumentRegister(index), source.Type);
Operation copyOp = Operation(Instruction.Copy, argReg, source);
InsertConstantRegCopies(nodes, nodes.AddBefore(node, copyOp));
sources[1 + index] = argReg;
}
// The target address must be on the return registers, since we
// don't return anything and it is guaranteed to not be a
// callee saved register (which would be trashed on the epilogue).
Operand retReg = Gpr(CallingConvention.GetIntReturnRegister(), OperandType.I64);
Operation addrCopyOp = Operation(Instruction.Copy, retReg, node.GetSource(0));
nodes.AddBefore(node, addrCopyOp);
sources[0] = retReg;
node.SetSources(sources);
}
public static Operation InsertLoadArgumentCopy(
CompilerContext cctx,
ref Span<Operation> buffer,
IntrusiveList<Operation> nodes,
Operand[] preservedArgs,
Operation node)
{
Operand source = node.GetSource(0);
Debug.Assert(source.Kind == OperandKind.Constant, "Non-constant LoadArgument source kind.");
int retArgs = cctx.FuncReturnType == OperandType.V128 ? 1 : 0;
int index = source.AsInt32() + retArgs;
if (index < CallingConvention.GetArgumentsOnRegsCount())
{
Operand dest = node.Destination;
if (preservedArgs[index] == default)
{
Operand argReg, pArg;
if (dest.Type.IsInteger())
{
argReg = Gpr(CallingConvention.GetIntArgumentRegister(index), dest.Type);
pArg = Local(dest.Type);
}
else if (dest.Type == OperandType.V128)
{
argReg = Gpr(CallingConvention.GetIntArgumentRegister(index), OperandType.I64);
pArg = Local(OperandType.I64);
}
else
{
argReg = Xmm(CallingConvention.GetVecArgumentRegister(index), dest.Type);
pArg = Local(dest.Type);
}
Operation copyOp = Operation(Instruction.Copy, pArg, argReg);
cctx.Cfg.Entry.Operations.AddFirst(copyOp);
preservedArgs[index] = pArg;
}
Operation nextNode;
if (dest.Type != OperandType.V128 && dest.AssignmentsCount == 1)
{
// Let's propagate the argument if we can to avoid copies.
PreAllocatorCommon.Propagate(ref buffer, dest, preservedArgs[index]);
nextNode = node.ListNext;
}
else
{
Operation argCopyOp = Operation(dest.Type == OperandType.V128
? Instruction.Load
: Instruction.Copy, dest, preservedArgs[index]);
nextNode = nodes.AddBefore(node, argCopyOp);
}
Delete(nodes, node);
return nextNode;
}
else
{
// TODO: Pass on stack.
return node;
}
}
public static void InsertReturnCopy(
CompilerContext cctx,
IntrusiveList<Operation> nodes,
Operand[] preservedArgs,
Operation node)
{
if (node.SourcesCount == 0)
{
return;
}
Operand source = node.GetSource(0);
Operand retReg;
if (source.Type.IsInteger())
{
retReg = Gpr(CallingConvention.GetIntReturnRegister(), source.Type);
}
else if (source.Type == OperandType.V128)
{
if (preservedArgs[0] == default)
{
Operand preservedArg = Local(OperandType.I64);
Operand arg0 = Gpr(CallingConvention.GetIntArgumentRegister(0), OperandType.I64);
Operation copyOp = Operation(Instruction.Copy, preservedArg, arg0);
cctx.Cfg.Entry.Operations.AddFirst(copyOp);
preservedArgs[0] = preservedArg;
}
retReg = preservedArgs[0];
}
else
{
retReg = Xmm(CallingConvention.GetVecReturnRegister(), source.Type);
}
if (source.Type == OperandType.V128)
{
Operation retStoreOp = Operation(Instruction.Store, default, retReg, source);
nodes.AddBefore(node, retStoreOp);
}
else
{
Operation retCopyOp = Operation(Instruction.Copy, retReg, source);
nodes.AddBefore(node, retCopyOp);
}
node.SetSources(Array.Empty<Operand>());
}
}
}

View File

@@ -1,47 +0,0 @@
using ARMeilleure.IntermediateRepresentation;
using System;
namespace ARMeilleure.CodeGen.X86
{
enum X86Condition
{
Overflow = 0x0,
NotOverflow = 0x1,
Below = 0x2,
AboveOrEqual = 0x3,
Equal = 0x4,
NotEqual = 0x5,
BelowOrEqual = 0x6,
Above = 0x7,
Sign = 0x8,
NotSign = 0x9,
ParityEven = 0xa,
ParityOdd = 0xb,
Less = 0xc,
GreaterOrEqual = 0xd,
LessOrEqual = 0xe,
Greater = 0xf
}
static class ComparisonX86Extensions
{
public static X86Condition ToX86Condition(this Comparison comp)
{
return comp switch
{
Comparison.Equal => X86Condition.Equal,
Comparison.NotEqual => X86Condition.NotEqual,
Comparison.Greater => X86Condition.Greater,
Comparison.LessOrEqual => X86Condition.LessOrEqual,
Comparison.GreaterUI => X86Condition.Above,
Comparison.LessOrEqualUI => X86Condition.BelowOrEqual,
Comparison.GreaterOrEqual => X86Condition.GreaterOrEqual,
Comparison.Less => X86Condition.Less,
Comparison.GreaterOrEqualUI => X86Condition.AboveOrEqual,
Comparison.LessUI => X86Condition.Below,
_ => throw new ArgumentException(null, nameof(comp))
};
}
}
}

View File

@@ -1,229 +0,0 @@
namespace ARMeilleure.CodeGen.X86
{
enum X86Instruction
{
None,
Add,
Addpd,
Addps,
Addsd,
Addss,
Aesdec,
Aesdeclast,
Aesenc,
Aesenclast,
Aesimc,
And,
Andnpd,
Andnps,
Andpd,
Andps,
Blendvpd,
Blendvps,
Bsr,
Bswap,
Call,
Cmovcc,
Cmp,
Cmppd,
Cmpps,
Cmpsd,
Cmpss,
Cmpxchg,
Cmpxchg16b,
Cmpxchg8,
Comisd,
Comiss,
Crc32,
Crc32_16,
Crc32_8,
Cvtdq2pd,
Cvtdq2ps,
Cvtpd2dq,
Cvtpd2ps,
Cvtps2dq,
Cvtps2pd,
Cvtsd2si,
Cvtsd2ss,
Cvtsi2sd,
Cvtsi2ss,
Cvtss2sd,
Cvtss2si,
Div,
Divpd,
Divps,
Divsd,
Divss,
Gf2p8affineqb,
Haddpd,
Haddps,
Idiv,
Imul,
Imul128,
Insertps,
Jmp,
Ldmxcsr,
Lea,
Maxpd,
Maxps,
Maxsd,
Maxss,
Minpd,
Minps,
Minsd,
Minss,
Mov,
Mov16,
Mov8,
Movd,
Movdqu,
Movhlps,
Movlhps,
Movq,
Movsd,
Movss,
Movsx16,
Movsx32,
Movsx8,
Movzx16,
Movzx8,
Mul128,
Mulpd,
Mulps,
Mulsd,
Mulss,
Neg,
Not,
Or,
Paddb,
Paddd,
Paddq,
Paddw,
Palignr,
Pand,
Pandn,
Pavgb,
Pavgw,
Pblendvb,
Pclmulqdq,
Pcmpeqb,
Pcmpeqd,
Pcmpeqq,
Pcmpeqw,
Pcmpgtb,
Pcmpgtd,
Pcmpgtq,
Pcmpgtw,
Pextrb,
Pextrd,
Pextrq,
Pextrw,
Pinsrb,
Pinsrd,
Pinsrq,
Pinsrw,
Pmaxsb,
Pmaxsd,
Pmaxsw,
Pmaxub,
Pmaxud,
Pmaxuw,
Pminsb,
Pminsd,
Pminsw,
Pminub,
Pminud,
Pminuw,
Pmovsxbw,
Pmovsxdq,
Pmovsxwd,
Pmovzxbw,
Pmovzxdq,
Pmovzxwd,
Pmulld,
Pmullw,
Pop,
Popcnt,
Por,
Pshufb,
Pshufd,
Pslld,
Pslldq,
Psllq,
Psllw,
Psrad,
Psraw,
Psrld,
Psrlq,
Psrldq,
Psrlw,
Psubb,
Psubd,
Psubq,
Psubw,
Punpckhbw,
Punpckhdq,
Punpckhqdq,
Punpckhwd,
Punpcklbw,
Punpckldq,
Punpcklqdq,
Punpcklwd,
Push,
Pxor,
Rcpps,
Rcpss,
Ror,
Roundpd,
Roundps,
Roundsd,
Roundss,
Rsqrtps,
Rsqrtss,
Sar,
Setcc,
Sha256Msg1,
Sha256Msg2,
Sha256Rnds2,
Shl,
Shr,
Shufpd,
Shufps,
Sqrtpd,
Sqrtps,
Sqrtsd,
Sqrtss,
Stmxcsr,
Sub,
Subpd,
Subps,
Subsd,
Subss,
Test,
Unpckhpd,
Unpckhps,
Unpcklpd,
Unpcklps,
Vblendvpd,
Vblendvps,
Vcvtph2ps,
Vcvtps2ph,
Vfmadd231ps,
Vfmadd231sd,
Vfmadd231ss,
Vfmsub231sd,
Vfmsub231ss,
Vfnmadd231ps,
Vfnmadd231sd,
Vfnmadd231ss,
Vfnmsub231sd,
Vfnmsub231ss,
Vpblendvb,
Vpternlogd,
Xor,
Xorpd,
Xorps,
Count
}
}

View File

@@ -1,259 +0,0 @@
using ARMeilleure.CodeGen.Optimizations;
using ARMeilleure.IntermediateRepresentation;
using ARMeilleure.Translation;
using System.Collections.Generic;
using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
using static ARMeilleure.IntermediateRepresentation.Operation.Factory;
namespace ARMeilleure.CodeGen.X86
{
static class X86Optimizer
{
private const int MaxConstantUses = 10000;
public static void RunPass(ControlFlowGraph cfg)
{
var constants = new Dictionary<ulong, Operand>();
Operand GetConstantCopy(BasicBlock block, Operation operation, Operand source)
{
// If the constant has many uses, we also force a new constant mov to be added, in order
// to avoid overflow of the counts field (that is limited to 16 bits).
if (!constants.TryGetValue(source.Value, out var constant) || constant.UsesCount > MaxConstantUses)
{
constant = Local(source.Type);
Operation copyOp = Operation(Instruction.Copy, constant, source);
block.Operations.AddBefore(operation, copyOp);
constants[source.Value] = constant;
}
return constant;
}
for (BasicBlock block = cfg.Blocks.First; block != null; block = block.ListNext)
{
constants.Clear();
Operation nextNode;
for (Operation node = block.Operations.First; node != default; node = nextNode)
{
nextNode = node.ListNext;
// Insert copies for constants that can't fit on a 32-bits immediate.
// Doing this early unblocks a few optimizations.
if (node.Instruction == Instruction.Add)
{
Operand src1 = node.GetSource(0);
Operand src2 = node.GetSource(1);
if (src1.Kind == OperandKind.Constant && (src1.Relocatable || CodeGenCommon.IsLongConst(src1)))
{
node.SetSource(0, GetConstantCopy(block, node, src1));
}
if (src2.Kind == OperandKind.Constant && (src2.Relocatable || CodeGenCommon.IsLongConst(src2)))
{
node.SetSource(1, GetConstantCopy(block, node, src2));
}
}
// Try to fold something like:
// shl rbx, 2
// add rax, rbx
// add rax, 0xcafe
// mov rax, [rax]
// Into:
// mov rax, [rax+rbx*4+0xcafe]
if (IsMemoryLoadOrStore(node.Instruction))
{
OperandType type;
if (node.Destination != default)
{
type = node.Destination.Type;
}
else
{
type = node.GetSource(1).Type;
}
Operand memOp = GetMemoryOperandOrNull(node.GetSource(0), type);
if (memOp != default)
{
node.SetSource(0, memOp);
}
}
}
}
Optimizer.RemoveUnusedNodes(cfg);
}
private static Operand GetMemoryOperandOrNull(Operand addr, OperandType type)
{
Operand baseOp = addr;
// First we check if the address is the result of a local X with 32-bits immediate
// addition. If that is the case, then the baseOp is X, and the memory operand immediate
// becomes the addition immediate. Otherwise baseOp keeps being the address.
int imm = GetConstOp(ref baseOp);
// Now we check if the baseOp is the result of a local Y with a local Z addition.
// If that is the case, we now set baseOp to Y and indexOp to Z. We further check
// if Z is the result of a left shift of local W by a value >= 0 and <= 3, if that
// is the case, we set indexOp to W and adjust the scale value of the memory operand
// to match that of the left shift.
// There is one missed case, which is the address being a shift result, but this is
// probably not worth optimizing as it should never happen.
(Operand indexOp, Multiplier scale) = GetIndexOp(ref baseOp);
// If baseOp is still equal to address, then there's nothing that can be optimized.
if (baseOp == addr)
{
return default;
}
if (imm == 0 && scale == Multiplier.x1 && indexOp != default)
{
imm = GetConstOp(ref indexOp);
}
return MemoryOp(type, baseOp, indexOp, scale, imm);
}
private static int GetConstOp(ref Operand baseOp)
{
Operation operation = GetAsgOpWithInst(baseOp, Instruction.Add);
if (operation == default)
{
return 0;
}
Operand src1 = operation.GetSource(0);
Operand src2 = operation.GetSource(1);
Operand constOp;
Operand otherOp;
if (src1.Kind == OperandKind.Constant && src2.Kind == OperandKind.LocalVariable)
{
constOp = src1;
otherOp = src2;
}
else if (src1.Kind == OperandKind.LocalVariable && src2.Kind == OperandKind.Constant)
{
constOp = src2;
otherOp = src1;
}
else
{
return 0;
}
// If we have addition by 64-bits constant, then we can't optimize it further,
// as we can't encode a 64-bits immediate on the memory operand.
if (CodeGenCommon.IsLongConst(constOp))
{
return 0;
}
baseOp = otherOp;
return constOp.AsInt32();
}
private static (Operand, Multiplier) GetIndexOp(ref Operand baseOp)
{
Operand indexOp = default;
Multiplier scale = Multiplier.x1;
Operation addOp = GetAsgOpWithInst(baseOp, Instruction.Add);
if (addOp == default)
{
return (indexOp, scale);
}
Operand src1 = addOp.GetSource(0);
Operand src2 = addOp.GetSource(1);
if (src1.Kind != OperandKind.LocalVariable || src2.Kind != OperandKind.LocalVariable)
{
return (indexOp, scale);
}
baseOp = src1;
indexOp = src2;
Operation shlOp = GetAsgOpWithInst(src1, Instruction.ShiftLeft);
bool indexOnSrc2 = false;
if (shlOp == default)
{
shlOp = GetAsgOpWithInst(src2, Instruction.ShiftLeft);
indexOnSrc2 = true;
}
if (shlOp != default)
{
Operand shSrc = shlOp.GetSource(0);
Operand shift = shlOp.GetSource(1);
if (shSrc.Kind == OperandKind.LocalVariable && shift.Kind == OperandKind.Constant && shift.Value <= 3)
{
scale = shift.Value switch
{
1 => Multiplier.x2,
2 => Multiplier.x4,
3 => Multiplier.x8,
_ => Multiplier.x1
};
baseOp = indexOnSrc2 ? src1 : src2;
indexOp = shSrc;
}
}
return (indexOp, scale);
}
private static Operation GetAsgOpWithInst(Operand op, Instruction inst)
{
// If we have multiple assignments, folding is not safe
// as the value may be different depending on the
// control flow path.
if (op.AssignmentsCount != 1)
{
return default;
}
Operation asgOp = op.Assignments[0];
if (asgOp.Instruction != inst)
{
return default;
}
return asgOp;
}
private static bool IsMemoryLoadOrStore(Instruction inst)
{
return inst == Instruction.Load ||
inst == Instruction.Load16 ||
inst == Instruction.Load8 ||
inst == Instruction.Store ||
inst == Instruction.Store16 ||
inst == Instruction.Store8;
}
}
}

View File

@@ -1,41 +0,0 @@
namespace ARMeilleure.CodeGen.X86
{
enum X86Register
{
Invalid = -1,
Rax = 0,
Rcx = 1,
Rdx = 2,
Rbx = 3,
Rsp = 4,
Rbp = 5,
Rsi = 6,
Rdi = 7,
R8 = 8,
R9 = 9,
R10 = 10,
R11 = 11,
R12 = 12,
R13 = 13,
R14 = 14,
R15 = 15,
Xmm0 = 0,
Xmm1 = 1,
Xmm2 = 2,
Xmm3 = 3,
Xmm4 = 4,
Xmm5 = 5,
Xmm6 = 6,
Xmm7 = 7,
Xmm8 = 8,
Xmm9 = 9,
Xmm10 = 10,
Xmm11 = 11,
Xmm12 = 12,
Xmm13 = 13,
Xmm14 = 14,
Xmm15 = 15
}
}

View File

@@ -1,187 +0,0 @@
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
namespace ARMeilleure.Common
{
unsafe sealed class ArenaAllocator : Allocator
{
private class PageInfo
{
public byte* Pointer;
public byte Unused;
public int UnusedCounter;
}
private int _lastReset;
private ulong _index;
private int _pageIndex;
private PageInfo _page;
private List<PageInfo> _pages;
private readonly ulong _pageSize;
private readonly uint _pageCount;
private readonly List<IntPtr> _extras;
public ArenaAllocator(uint pageSize, uint pageCount)
{
_lastReset = Environment.TickCount;
// Set _index to pageSize so that the first allocation goes through the slow path.
_index = pageSize;
_pageIndex = -1;
_page = null;
_pages = new List<PageInfo>();
_pageSize = pageSize;
_pageCount = pageCount;
_extras = new List<IntPtr>();
}
public Span<T> AllocateSpan<T>(ulong count) where T : unmanaged
{
return new Span<T>(Allocate<T>(count), (int)count);
}
public override void* Allocate(ulong size)
{
if (_index + size <= _pageSize)
{
byte* result = _page.Pointer + _index;
_index += size;
return result;
}
return AllocateSlow(size);
}
[MethodImpl(MethodImplOptions.NoInlining)]
private void* AllocateSlow(ulong size)
{
if (size > _pageSize)
{
void* extra = NativeAllocator.Instance.Allocate(size);
_extras.Add((IntPtr)extra);
return extra;
}
if (_index + size > _pageSize)
{
_index = 0;
_pageIndex++;
}
if (_pageIndex < _pages.Count)
{
_page = _pages[_pageIndex];
_page.Unused = 0;
}
else
{
_page = new PageInfo();
_page.Pointer = (byte*)NativeAllocator.Instance.Allocate(_pageSize);
_pages.Add(_page);
}
byte* result = _page.Pointer + _index;
_index += size;
return result;
}
public override void Free(void* block) { }
public void Reset()
{
_index = _pageSize;
_pageIndex = -1;
_page = null;
// Free excess pages that was allocated.
while (_pages.Count > _pageCount)
{
NativeAllocator.Instance.Free(_pages[_pages.Count - 1].Pointer);
_pages.RemoveAt(_pages.Count - 1);
}
// Free extra blocks that are not page-sized
foreach (IntPtr ptr in _extras)
{
NativeAllocator.Instance.Free((void*)ptr);
}
_extras.Clear();
// Free pooled pages that has not been used in a while. Remove pages at the back first, because we try to
// keep the pages at the front alive, since they're more likely to be hot and in the d-cache.
bool removing = true;
// If arena is used frequently, keep pages for longer. Otherwise keep pages for a shorter amount of time.
int now = Environment.TickCount;
int count = (now - _lastReset) switch {
>= 5000 => 0,
>= 2500 => 50,
>= 1000 => 100,
>= 10 => 1500,
_ => 5000
};
for (int i = _pages.Count - 1; i >= 0; i--)
{
PageInfo page = _pages[i];
if (page.Unused == 0)
{
page.UnusedCounter = 0;
}
page.UnusedCounter += page.Unused;
page.Unused = 1;
// If page not used after `count` resets, remove it.
if (removing && page.UnusedCounter >= count)
{
NativeAllocator.Instance.Free(page.Pointer);
_pages.RemoveAt(i);
}
else
{
removing = false;
}
}
_lastReset = now;
}
protected override void Dispose(bool disposing)
{
if (_pages != null)
{
foreach (PageInfo info in _pages)
{
NativeAllocator.Instance.Free(info.Pointer);
}
foreach (IntPtr ptr in _extras)
{
NativeAllocator.Instance.Free((void*)ptr);
}
_pages = null;
}
}
~ArenaAllocator()
{
Dispose(false);
}
}
}

View File

@@ -1,222 +0,0 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Numerics;
using System.Runtime.CompilerServices;
namespace ARMeilleure.Common
{
unsafe class BitMap : IEnumerable<int>, IDisposable
{
private const int IntSize = 64;
private const int IntMask = IntSize - 1;
private int _count;
private long* _masks;
private readonly Allocator _allocator;
public BitMap(Allocator allocator)
{
_allocator = allocator;
}
public BitMap(Allocator allocator, int capacity) : this(allocator)
{
EnsureCapacity(capacity);
}
public bool Set(int bit)
{
EnsureCapacity(bit + 1);
int wordIndex = bit / IntSize;
int wordBit = bit & IntMask;
long wordMask = 1L << wordBit;
if ((_masks[wordIndex] & wordMask) != 0)
{
return false;
}
_masks[wordIndex] |= wordMask;
return true;
}
public void Clear(int bit)
{
EnsureCapacity(bit + 1);
int wordIndex = bit / IntSize;
int wordBit = bit & IntMask;
long wordMask = 1L << wordBit;
_masks[wordIndex] &= ~wordMask;
}
public bool IsSet(int bit)
{
EnsureCapacity(bit + 1);
int wordIndex = bit / IntSize;
int wordBit = bit & IntMask;
return (_masks[wordIndex] & (1L << wordBit)) != 0;
}
public int FindFirstUnset()
{
for (int index = 0; index < _count; index++)
{
long mask = _masks[index];
if (mask != -1L)
{
return BitOperations.TrailingZeroCount(~mask) + index * IntSize;
}
}
return _count * IntSize;
}
public bool Set(BitMap map)
{
EnsureCapacity(map._count * IntSize);
bool modified = false;
for (int index = 0; index < _count; index++)
{
long newValue = _masks[index] | map._masks[index];
if (_masks[index] != newValue)
{
_masks[index] = newValue;
modified = true;
}
}
return modified;
}
public bool Clear(BitMap map)
{
EnsureCapacity(map._count * IntSize);
bool modified = false;
for (int index = 0; index < _count; index++)
{
long newValue = _masks[index] & ~map._masks[index];
if (_masks[index] != newValue)
{
_masks[index] = newValue;
modified = true;
}
}
return modified;
}
private void EnsureCapacity(int size)
{
int count = (size + IntMask) / IntSize;
if (count > _count)
{
var oldMask = _masks;
var oldSpan = new Span<long>(_masks, _count);
_masks = _allocator.Allocate<long>((uint)count);
_count = count;
var newSpan = new Span<long>(_masks, _count);
oldSpan.CopyTo(newSpan);
newSpan.Slice(oldSpan.Length).Clear();
_allocator.Free(oldMask);
}
}
public void Dispose()
{
if (_masks != null)
{
_allocator.Free(_masks);
_masks = null;
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
IEnumerator<int> IEnumerable<int>.GetEnumerator()
{
return GetEnumerator();
}
public Enumerator GetEnumerator()
{
return new Enumerator(this);
}
public struct Enumerator : IEnumerator<int>
{
private long _index;
private long _mask;
private int _bit;
private readonly BitMap _map;
public int Current => (int)_index * IntSize + _bit;
object IEnumerator.Current => Current;
public Enumerator(BitMap map)
{
_index = -1;
_mask = 0;
_bit = 0;
_map = map;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool MoveNext()
{
if (_mask != 0)
{
_mask &= ~(1L << _bit);
}
// Manually hoist these loads, because RyuJIT does not.
long count = (uint)_map._count;
long* masks = _map._masks;
while (_mask == 0)
{
if (++_index >= count)
{
return false;
}
_mask = masks[_index];
}
_bit = BitOperations.TrailingZeroCount(_mask);
return true;
}
public void Reset() { }
public void Dispose() { }
}
}
}

View File

@@ -1,101 +0,0 @@
using System;
using System.Collections.Generic;
namespace ARMeilleure.Decoders
{
class Block
{
public ulong Address { get; set; }
public ulong EndAddress { get; set; }
public Block Next { get; set; }
public Block Branch { get; set; }
public bool Exit { get; set; }
public List<OpCode> OpCodes { get; }
public Block()
{
OpCodes = new List<OpCode>();
}
public Block(ulong address) : this()
{
Address = address;
}
public void Split(Block rightBlock)
{
int splitIndex = BinarySearch(OpCodes, rightBlock.Address);
if (OpCodes[splitIndex].Address < rightBlock.Address)
{
splitIndex++;
}
int splitCount = OpCodes.Count - splitIndex;
if (splitCount <= 0)
{
throw new ArgumentException("Can't split at right block address.");
}
rightBlock.EndAddress = EndAddress;
rightBlock.Next = Next;
rightBlock.Branch = Branch;
rightBlock.OpCodes.AddRange(OpCodes.GetRange(splitIndex, splitCount));
EndAddress = rightBlock.Address;
Next = rightBlock;
Branch = null;
OpCodes.RemoveRange(splitIndex, splitCount);
}
private static int BinarySearch(List<OpCode> opCodes, ulong address)
{
int left = 0;
int middle = 0;
int right = opCodes.Count - 1;
while (left <= right)
{
int size = right - left;
middle = left + (size >> 1);
OpCode opCode = opCodes[middle];
if (address == (ulong)opCode.Address)
{
break;
}
if (address < (ulong)opCode.Address)
{
right = middle - 1;
}
else
{
left = middle + 1;
}
}
return middle;
}
public OpCode GetLastOp()
{
if (OpCodes.Count > 0)
{
return OpCodes[OpCodes.Count - 1];
}
return null;
}
}
}

View File

@@ -1,32 +0,0 @@
namespace ARMeilleure.Decoders
{
enum Condition
{
Eq = 0,
Ne = 1,
GeUn = 2,
LtUn = 3,
Mi = 4,
Pl = 5,
Vs = 6,
Vc = 7,
GtUn = 8,
LeUn = 9,
Ge = 10,
Lt = 11,
Gt = 12,
Le = 13,
Al = 14,
Nv = 15
}
static class ConditionExtensions
{
public static Condition Invert(this Condition cond)
{
// Bit 0 of all conditions is basically a negation bit, so
// inverting this bit has the effect of inverting the condition.
return (Condition)((int)cond ^ 1);
}
}
}

View File

@@ -1,10 +0,0 @@
namespace ARMeilleure.Decoders
{
enum DataOp
{
Adr = 0,
Arithmetic = 1,
Logical = 2,
BitField = 3
}
}

View File

@@ -1,391 +0,0 @@
using ARMeilleure.Decoders.Optimizations;
using ARMeilleure.Instructions;
using ARMeilleure.Memory;
using ARMeilleure.State;
using System;
using System.Collections.Generic;
using System.Diagnostics;
namespace ARMeilleure.Decoders
{
static class Decoder
{
// We define a limit on the number of instructions that a function may have,
// this prevents functions being potentially too large, which would
// take too long to compile and use too much memory.
private const int MaxInstsPerFunction = 2500;
// For lower code quality translation, we set a lower limit since we're blocking execution.
private const int MaxInstsPerFunctionLowCq = 500;
public static Block[] Decode(IMemoryManager memory, ulong address, ExecutionMode mode, bool highCq, DecoderMode dMode)
{
List<Block> blocks = new List<Block>();
Queue<Block> workQueue = new Queue<Block>();
Dictionary<ulong, Block> visited = new Dictionary<ulong, Block>();
Debug.Assert(MaxInstsPerFunctionLowCq <= MaxInstsPerFunction);
int opsCount = 0;
int instructionLimit = highCq ? MaxInstsPerFunction : MaxInstsPerFunctionLowCq;
Block GetBlock(ulong blkAddress)
{
if (!visited.TryGetValue(blkAddress, out Block block))
{
block = new Block(blkAddress);
if ((dMode != DecoderMode.MultipleBlocks && visited.Count >= 1) || opsCount > instructionLimit || !memory.IsMapped(blkAddress))
{
block.Exit = true;
block.EndAddress = blkAddress;
}
workQueue.Enqueue(block);
visited.Add(blkAddress, block);
}
return block;
}
GetBlock(address);
while (workQueue.TryDequeue(out Block currBlock))
{
// Check if the current block is inside another block.
if (BinarySearch(blocks, currBlock.Address, out int nBlkIndex))
{
Block nBlock = blocks[nBlkIndex];
if (nBlock.Address == currBlock.Address)
{
throw new InvalidOperationException("Found duplicate block address on the list.");
}
currBlock.Exit = false;
nBlock.Split(currBlock);
blocks.Insert(nBlkIndex + 1, currBlock);
continue;
}
if (!currBlock.Exit)
{
// If we have a block after the current one, set the limit address.
ulong limitAddress = ulong.MaxValue;
if (nBlkIndex != blocks.Count)
{
Block nBlock = blocks[nBlkIndex];
int nextIndex = nBlkIndex + 1;
if (nBlock.Address < currBlock.Address && nextIndex < blocks.Count)
{
limitAddress = blocks[nextIndex].Address;
}
else if (nBlock.Address > currBlock.Address)
{
limitAddress = blocks[nBlkIndex].Address;
}
}
if (dMode == DecoderMode.SingleInstruction)
{
// Only read at most one instruction
limitAddress = currBlock.Address + 1;
}
FillBlock(memory, mode, currBlock, limitAddress);
opsCount += currBlock.OpCodes.Count;
if (currBlock.OpCodes.Count != 0)
{
// Set child blocks. "Branch" is the block the branch instruction
// points to (when taken), "Next" is the block at the next address,
// executed when the branch is not taken. For Unconditional Branches
// (except BL/BLR that are sub calls) or end of executable, Next is null.
OpCode lastOp = currBlock.GetLastOp();
bool isCall = IsCall(lastOp);
if (lastOp is IOpCodeBImm op && !isCall)
{
currBlock.Branch = GetBlock((ulong)op.Immediate);
}
if (isCall || !(IsUnconditionalBranch(lastOp) || IsTrap(lastOp)))
{
currBlock.Next = GetBlock(currBlock.EndAddress);
}
}
}
// Insert the new block on the list (sorted by address).
if (blocks.Count != 0)
{
Block nBlock = blocks[nBlkIndex];
blocks.Insert(nBlkIndex + (nBlock.Address < currBlock.Address ? 1 : 0), currBlock);
}
else
{
blocks.Add(currBlock);
}
}
if (blocks.Count == 1 && blocks[0].OpCodes.Count == 0)
{
Debug.Assert(blocks[0].Exit);
Debug.Assert(blocks[0].Address == blocks[0].EndAddress);
throw new InvalidOperationException($"Decoded a single empty exit block. Entry point = 0x{address:X}.");
}
if (dMode == DecoderMode.MultipleBlocks)
{
return TailCallRemover.RunPass(address, blocks);
}
else
{
return blocks.ToArray();
}
}
public static bool BinarySearch(List<Block> blocks, ulong address, out int index)
{
index = 0;
int left = 0;
int right = blocks.Count - 1;
while (left <= right)
{
int size = right - left;
int middle = left + (size >> 1);
Block block = blocks[middle];
index = middle;
if (address >= block.Address && address < block.EndAddress)
{
return true;
}
if (address < block.Address)
{
right = middle - 1;
}
else
{
left = middle + 1;
}
}
return false;
}
private static void FillBlock(
IMemoryManager memory,
ExecutionMode mode,
Block block,
ulong limitAddress)
{
ulong address = block.Address;
int itBlockSize = 0;
OpCode opCode;
do
{
if (address >= limitAddress && itBlockSize == 0)
{
break;
}
opCode = DecodeOpCode(memory, address, mode);
block.OpCodes.Add(opCode);
address += (ulong)opCode.OpCodeSizeInBytes;
if (opCode is OpCodeT16IfThen it)
{
itBlockSize = it.IfThenBlockSize;
}
else if (itBlockSize > 0)
{
itBlockSize--;
}
}
while (!(IsBranch(opCode) || IsException(opCode)));
block.EndAddress = address;
}
private static bool IsBranch(OpCode opCode)
{
return opCode is OpCodeBImm ||
opCode is OpCodeBReg || IsAarch32Branch(opCode);
}
private static bool IsUnconditionalBranch(OpCode opCode)
{
return opCode is OpCodeBImmAl ||
opCode is OpCodeBReg || IsAarch32UnconditionalBranch(opCode);
}
private static bool IsAarch32UnconditionalBranch(OpCode opCode)
{
if (!(opCode is OpCode32 op))
{
return false;
}
// Compare and branch instructions are always conditional.
if (opCode.Instruction.Name == InstName.Cbz ||
opCode.Instruction.Name == InstName.Cbnz)
{
return false;
}
// Note: On ARM32, most instructions have conditional execution,
// so there's no "Always" (unconditional) branch like on ARM64.
// We need to check if the condition is "Always" instead.
return IsAarch32Branch(op) && op.Cond >= Condition.Al;
}
private static bool IsAarch32Branch(OpCode opCode)
{
// Note: On ARM32, most ALU operations can write to R15 (PC),
// so we must consider such operations as a branch in potential aswell.
if (opCode is IOpCode32Alu opAlu && opAlu.Rd == RegisterAlias.Aarch32Pc)
{
if (opCode is OpCodeT32)
{
return opCode.Instruction.Name != InstName.Tst && opCode.Instruction.Name != InstName.Teq &&
opCode.Instruction.Name != InstName.Cmp && opCode.Instruction.Name != InstName.Cmn;
}
return true;
}
// Same thing for memory operations. We have the cases where PC is a target
// 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
// be "undefined" depending on the CPU, so compilers should not produce that.
if (opCode is IOpCode32Mem || opCode is IOpCode32MemMult)
{
int rt, rn;
bool wBack, isLoad;
if (opCode is IOpCode32Mem opMem)
{
rt = opMem.Rt;
rn = opMem.Rn;
wBack = opMem.WBack;
isLoad = opMem.IsLoad;
// For the dual load, we also need to take into account the
// case were Rt2 == 15 (PC).
if (rt == 14 && opMem.Instruction.Name == InstName.Ldrd)
{
rt = RegisterAlias.Aarch32Pc;
}
}
else if (opCode is IOpCode32MemMult opMemMult)
{
const int pcMask = 1 << RegisterAlias.Aarch32Pc;
rt = (opMemMult.RegisterMask & pcMask) != 0 ? RegisterAlias.Aarch32Pc : 0;
rn = opMemMult.Rn;
wBack = opMemMult.PostOffset != 0;
isLoad = opMemMult.IsLoad;
}
else
{
throw new NotImplementedException($"The type \"{opCode.GetType().Name}\" is not implemented on the decoder.");
}
if ((rt == RegisterAlias.Aarch32Pc && isLoad) ||
(rn == RegisterAlias.Aarch32Pc && wBack))
{
return true;
}
}
// Explicit branch instructions.
return opCode is IOpCode32BImm ||
opCode is IOpCode32BReg;
}
private static bool IsCall(OpCode opCode)
{
return opCode.Instruction.Name == InstName.Bl ||
opCode.Instruction.Name == InstName.Blr ||
opCode.Instruction.Name == InstName.Blx;
}
private static bool IsException(OpCode opCode)
{
return IsTrap(opCode) || opCode.Instruction.Name == InstName.Svc;
}
private static bool IsTrap(OpCode opCode)
{
return opCode.Instruction.Name == InstName.Brk ||
opCode.Instruction.Name == InstName.Trap ||
opCode.Instruction.Name == InstName.Und;
}
public static OpCode DecodeOpCode(IMemoryManager memory, ulong address, ExecutionMode mode)
{
int opCode = memory.Read<int>(address);
InstDescriptor inst;
OpCodeTable.MakeOp makeOp;
if (mode == ExecutionMode.Aarch64)
{
(inst, makeOp) = OpCodeTable.GetInstA64(opCode);
}
else
{
if (mode == ExecutionMode.Aarch32Arm)
{
(inst, makeOp) = OpCodeTable.GetInstA32(opCode);
}
else /* if (mode == ExecutionMode.Aarch32Thumb) */
{
(inst, makeOp) = OpCodeTable.GetInstT32(opCode);
}
}
if (makeOp != null)
{
return makeOp(inst, address, opCode);
}
else
{
if (mode == ExecutionMode.Aarch32Thumb)
{
return new OpCodeT16(inst, address, opCode);
}
else
{
return new OpCode(inst, address, opCode);
}
}
}
}
}

View File

@@ -1,167 +0,0 @@
using ARMeilleure.Common;
namespace ARMeilleure.Decoders
{
static class DecoderHelper
{
static DecoderHelper()
{
Imm8ToFP32Table = BuildImm8ToFP32Table();
Imm8ToFP64Table = BuildImm8ToFP64Table();
}
public static readonly uint[] Imm8ToFP32Table;
public static readonly ulong[] Imm8ToFP64Table;
private static uint[] BuildImm8ToFP32Table()
{
uint[] tbl = new uint[256];
for (int idx = 0; idx < tbl.Length; idx++)
{
tbl[idx] = ExpandImm8ToFP32((uint)idx);
}
return tbl;
}
private static ulong[] BuildImm8ToFP64Table()
{
ulong[] tbl = new ulong[256];
for (int idx = 0; idx < tbl.Length; idx++)
{
tbl[idx] = ExpandImm8ToFP64((ulong)idx);
}
return tbl;
}
// abcdefgh -> aBbbbbbc defgh000 00000000 00000000 (B = ~b)
private static uint ExpandImm8ToFP32(uint imm)
{
uint MoveBit(uint bits, int from, int to)
{
return ((bits >> from) & 1U) << to;
}
return MoveBit(imm, 7, 31) | MoveBit(~imm, 6, 30) |
MoveBit(imm, 6, 29) | MoveBit( imm, 6, 28) |
MoveBit(imm, 6, 27) | MoveBit( imm, 6, 26) |
MoveBit(imm, 6, 25) | MoveBit( imm, 5, 24) |
MoveBit(imm, 4, 23) | MoveBit( imm, 3, 22) |
MoveBit(imm, 2, 21) | MoveBit( imm, 1, 20) |
MoveBit(imm, 0, 19);
}
// abcdefgh -> aBbbbbbb bbcdefgh 00000000 00000000 00000000 00000000 00000000 00000000 (B = ~b)
private static ulong ExpandImm8ToFP64(ulong imm)
{
ulong MoveBit(ulong bits, int from, int to)
{
return ((bits >> from) & 1UL) << to;
}
return MoveBit(imm, 7, 63) | MoveBit(~imm, 6, 62) |
MoveBit(imm, 6, 61) | MoveBit( imm, 6, 60) |
MoveBit(imm, 6, 59) | MoveBit( imm, 6, 58) |
MoveBit(imm, 6, 57) | MoveBit( imm, 6, 56) |
MoveBit(imm, 6, 55) | MoveBit( imm, 6, 54) |
MoveBit(imm, 5, 53) | MoveBit( imm, 4, 52) |
MoveBit(imm, 3, 51) | MoveBit( imm, 2, 50) |
MoveBit(imm, 1, 49) | MoveBit( imm, 0, 48);
}
public struct BitMask
{
public long WMask;
public long TMask;
public int Pos;
public int Shift;
public bool IsUndefined;
public static BitMask Invalid => new BitMask { IsUndefined = true };
}
public static BitMask DecodeBitMask(int opCode, bool immediate)
{
int immS = (opCode >> 10) & 0x3f;
int immR = (opCode >> 16) & 0x3f;
int n = (opCode >> 22) & 1;
int sf = (opCode >> 31) & 1;
int length = BitUtils.HighestBitSet((~immS & 0x3f) | (n << 6));
if (length < 1 || (sf == 0 && n != 0))
{
return BitMask.Invalid;
}
int size = 1 << length;
int levels = size - 1;
int s = immS & levels;
int r = immR & levels;
if (immediate && s == levels)
{
return BitMask.Invalid;
}
long wMask = BitUtils.FillWithOnes(s + 1);
long tMask = BitUtils.FillWithOnes(((s - r) & levels) + 1);
if (r > 0)
{
wMask = BitUtils.RotateRight(wMask, r, size);
wMask &= BitUtils.FillWithOnes(size);
}
return new BitMask()
{
WMask = BitUtils.Replicate(wMask, size),
TMask = BitUtils.Replicate(tMask, size),
Pos = immS,
Shift = immR
};
}
public static long DecodeImm24_2(int opCode)
{
return ((long)opCode << 40) >> 38;
}
public static long DecodeImm26_2(int opCode)
{
return ((long)opCode << 38) >> 36;
}
public static long DecodeImmS19_2(int opCode)
{
return (((long)opCode << 40) >> 43) & ~3;
}
public static long DecodeImmS14_2(int opCode)
{
return (((long)opCode << 45) >> 48) & ~3;
}
public static bool VectorArgumentsInvalid(bool q, params int[] args)
{
if (q)
{
for (int i = 0; i < args.Length; i++)
{
if ((args[i] & 1) == 1)
{
return true;
}
}
}
return false;
}
}
}

View File

@@ -1,9 +0,0 @@
namespace ARMeilleure.Decoders
{
enum DecoderMode
{
MultipleBlocks,
SingleBlock,
SingleInstruction,
}
}

View File

@@ -1,17 +0,0 @@
using ARMeilleure.IntermediateRepresentation;
namespace ARMeilleure.Decoders
{
interface IOpCode
{
ulong Address { get; }
InstDescriptor Instruction { get; }
RegisterSize RegisterSize { get; }
int GetBitsCount();
OperandType GetOperandType();
}
}

View File

@@ -1,9 +0,0 @@
namespace ARMeilleure.Decoders
{
interface IOpCode32 : IOpCode
{
Condition Cond { get; }
uint GetPc();
}
}

View File

@@ -1,8 +0,0 @@
namespace ARMeilleure.Decoders
{
interface IOpCode32Alu : IOpCode32, IOpCode32HasSetFlags
{
int Rd { get; }
int Rn { get; }
}
}

View File

@@ -1,9 +0,0 @@
namespace ARMeilleure.Decoders
{
interface IOpCode32AluImm : IOpCode32Alu
{
int Immediate { get; }
bool IsRotated { get; }
}
}

View File

@@ -1,7 +0,0 @@
namespace ARMeilleure.Decoders
{
interface IOpCode32AluImm16 : IOpCode32Alu
{
int Immediate { get; }
}
}

View File

@@ -1,10 +0,0 @@
namespace ARMeilleure.Decoders
{
interface IOpCode32AluRsImm : IOpCode32Alu
{
int Rm { get; }
int Immediate { get; }
ShiftType ShiftType { get; }
}
}

View File

@@ -1,10 +0,0 @@
namespace ARMeilleure.Decoders
{
interface IOpCode32AluRsReg : IOpCode32Alu
{
int Rm { get; }
int Rs { get; }
ShiftType ShiftType { get; }
}
}

View File

@@ -1,4 +0,0 @@
namespace ARMeilleure.Decoders
{
interface IOpCode32BImm : IOpCode32, IOpCodeBImm { }
}

View File

@@ -1,7 +0,0 @@
namespace ARMeilleure.Decoders
{
interface IOpCode32BReg : IOpCode32
{
int Rm { get; }
}
}

View File

@@ -1,7 +0,0 @@
namespace ARMeilleure.Decoders
{
interface IOpCode32Exception
{
int Id { get; }
}
}

View File

@@ -1,7 +0,0 @@
namespace ARMeilleure.Decoders
{
interface IOpCode32HasSetFlags
{
bool? SetFlags { get; }
}
}

View File

@@ -1,16 +0,0 @@
namespace ARMeilleure.Decoders
{
interface IOpCode32Mem : IOpCode32
{
int Rt { get; }
int Rt2 => Rt | 1;
int Rn { get; }
bool WBack { get; }
bool IsLoad { get; }
bool Index { get; }
bool Add { get; }
int Immediate { get; }
}
}

View File

@@ -1,15 +0,0 @@
namespace ARMeilleure.Decoders
{
interface IOpCode32MemMult : IOpCode32
{
int Rn { get; }
int RegisterMask { get; }
int PostOffset { get; }
bool IsLoad { get; }
int Offset { get; }
}
}

View File

@@ -1,7 +0,0 @@
namespace ARMeilleure.Decoders
{
interface IOpCode32MemReg : IOpCode32Mem
{
int Rm { get; }
}
}

View File

@@ -1,8 +0,0 @@
namespace ARMeilleure.Decoders
{
interface IOpCode32MemRsImm : IOpCode32Mem
{
int Rm { get; }
ShiftType ShiftType { get; }
}
}

View File

@@ -1,10 +0,0 @@
namespace ARMeilleure.Decoders
{
interface IOpCodeAlu : IOpCode
{
int Rd { get; }
int Rn { get; }
DataOp DataOp { get; }
}
}

View File

@@ -1,7 +0,0 @@
namespace ARMeilleure.Decoders
{
interface IOpCodeAluImm : IOpCodeAlu
{
long Immediate { get; }
}
}

View File

@@ -1,10 +0,0 @@
namespace ARMeilleure.Decoders
{
interface IOpCodeAluRs : IOpCodeAlu
{
int Shift { get; }
int Rm { get; }
ShiftType ShiftType { get; }
}
}

View File

@@ -1,10 +0,0 @@
namespace ARMeilleure.Decoders
{
interface IOpCodeAluRx : IOpCodeAlu
{
int Shift { get; }
int Rm { get; }
IntType IntType { get; }
}
}

View File

@@ -1,7 +0,0 @@
namespace ARMeilleure.Decoders
{
interface IOpCodeBImm : IOpCode
{
long Immediate { get; }
}
}

View File

@@ -1,7 +0,0 @@
namespace ARMeilleure.Decoders
{
interface IOpCodeCond : IOpCode
{
Condition Cond { get; }
}
}

View File

@@ -1,11 +0,0 @@
namespace ARMeilleure.Decoders
{
interface IOpCodeLit : IOpCode
{
int Rt { get; }
long Immediate { get; }
int Size { get; }
bool Signed { get; }
bool Prefetch { get; }
}
}

View File

@@ -1,7 +0,0 @@
namespace ARMeilleure.Decoders
{
interface IOpCodeSimd : IOpCode
{
int Size { get; }
}
}

View File

@@ -1,18 +0,0 @@
using ARMeilleure.Instructions;
namespace ARMeilleure.Decoders
{
readonly struct InstDescriptor
{
public static InstDescriptor Undefined => new InstDescriptor(InstName.Und, InstEmit.Und);
public InstName Name { get; }
public InstEmitter Emitter { get; }
public InstDescriptor(InstName name, InstEmitter emitter)
{
Name = name;
Emitter = emitter;
}
}
}

View File

@@ -1,6 +0,0 @@
using ARMeilleure.Translation;
namespace ARMeilleure.Decoders
{
delegate void InstEmitter(ArmEmitterContext context);
}

View File

@@ -1,14 +0,0 @@
namespace ARMeilleure.Decoders
{
enum IntType
{
UInt8 = 0,
UInt16 = 1,
UInt32 = 2,
UInt64 = 3,
Int8 = 4,
Int16 = 5,
Int32 = 6,
Int64 = 7
}
}

View File

@@ -1,49 +0,0 @@
using ARMeilleure.IntermediateRepresentation;
using System;
namespace ARMeilleure.Decoders
{
class OpCode : IOpCode
{
public ulong Address { get; }
public int RawOpCode { get; }
public int OpCodeSizeInBytes { get; protected set; } = 4;
public InstDescriptor Instruction { get; protected set; }
public RegisterSize RegisterSize { get; protected set; }
public static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode(inst, address, opCode);
public OpCode(InstDescriptor inst, ulong address, int opCode)
{
Instruction = inst;
Address = address;
RawOpCode = opCode;
RegisterSize = RegisterSize.Int64;
}
public int GetPairsCount() => GetBitsCount() / 16;
public int GetBytesCount() => GetBitsCount() / 8;
public int GetBitsCount()
{
switch (RegisterSize)
{
case RegisterSize.Int32: return 32;
case RegisterSize.Int64: return 64;
case RegisterSize.Simd64: return 64;
case RegisterSize.Simd128: return 128;
}
throw new InvalidOperationException();
}
public OperandType GetOperandType()
{
return RegisterSize == RegisterSize.Int32 ? OperandType.I32 : OperandType.I64;
}
}
}

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