Compare commits

..

1 commit

Author SHA1 Message Date
dependabot[bot]
b2aed882d6
nuget: bump Ryujinx.Graphics.Vulkan.Dependencies.MoltenVK
Bumps Ryujinx.Graphics.Vulkan.Dependencies.MoltenVK from 1.2.0 to 1.2.3.

---
updated-dependencies:
- dependency-name: Ryujinx.Graphics.Vulkan.Dependencies.MoltenVK
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-05-31 07:09:40 +00:00
4132 changed files with 64147 additions and 157315 deletions

View file

@ -1,31 +1,19 @@
# Remove the line below if you want to inherit .editorconfig settings from higher directories # Remove the line below if you want to inherit .editorconfig settings from higher directories
root = true root = true
[*] # C# files
[*.cs]
#### Core EditorConfig Options #### #### Core EditorConfig Options ####
# Set default charset
charset = utf-8
# Indentation and spacing # Indentation and spacing
indent_size = 4 indent_size = 4
indent_style = space indent_style = space
tab_width = 4 tab_width = 4
# New line preferences # New line preferences
end_of_line = lf end_of_line = crlf
insert_final_newline = true insert_final_newline = false
# Markdown, JSON, YAML, props and csproj files
[*.{md,json,yml,props,csproj}]
# Indentation and spacing
indent_size = 2
tab_width = 2
# C# files
[*.cs]
#### .NET Coding Conventions #### #### .NET Coding Conventions ####
@ -71,7 +59,7 @@ dotnet_style_prefer_simplified_interpolation = true:suggestion
dotnet_style_readonly_field = true:suggestion dotnet_style_readonly_field = true:suggestion
# Parameter preferences # Parameter preferences
dotnet_code_quality_unused_parameters = all:silent dotnet_code_quality_unused_parameters = all:suggestion
#### C# Coding Conventions #### #### C# Coding Conventions ####
@ -97,7 +85,7 @@ csharp_style_expression_bodied_properties = true:silent
# Pattern matching preferences # Pattern matching preferences
csharp_style_pattern_matching_over_as_with_null_check = true:suggestion csharp_style_pattern_matching_over_as_with_null_check = true:suggestion
csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion
csharp_style_prefer_switch_expression = false:silent csharp_style_prefer_switch_expression = true:suggestion
# Null-checking preferences # Null-checking preferences
csharp_style_conditional_delegate_call = true:suggestion csharp_style_conditional_delegate_call = true:suggestion
@ -106,7 +94,6 @@ csharp_style_conditional_delegate_call = true:suggestion
csharp_prefer_static_local_function = 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_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_readonly_struct = true
csharp_style_prefer_method_group_conversion = true
# Code-block preferences # Code-block preferences
csharp_prefer_braces = true:silent csharp_prefer_braces = true:silent
@ -122,7 +109,6 @@ csharp_style_prefer_range_operator = true:suggestion
csharp_style_throw_expression = true:suggestion csharp_style_throw_expression = true:suggestion
csharp_style_unused_value_assignment_preference = discard_variable:suggestion csharp_style_unused_value_assignment_preference = discard_variable:suggestion
csharp_style_unused_value_expression_statement_preference = discard_variable:silent csharp_style_unused_value_expression_statement_preference = discard_variable:silent
csharp_style_implicit_object_creation_when_type_is_apparent = true
# 'using' directive preferences # 'using' directive preferences
csharp_using_directive_placement = outside_namespace:silent csharp_using_directive_placement = outside_namespace:silent
@ -154,6 +140,7 @@ csharp_space_after_dot = false
csharp_space_after_keywords_in_control_flow_statements = true csharp_space_after_keywords_in_control_flow_statements = true
csharp_space_after_semicolon_in_for_statement = true csharp_space_after_semicolon_in_for_statement = true
csharp_space_around_binary_operators = before_and_after 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_colon_in_inheritance_clause = true
csharp_space_before_comma = false csharp_space_before_comma = false
csharp_space_before_dot = false csharp_space_before_dot = false
@ -171,31 +158,23 @@ csharp_space_between_square_brackets = false
# Wrapping preferences # Wrapping preferences
csharp_preserve_single_line_blocks = true csharp_preserve_single_line_blocks = true
csharp_preserve_single_line_statements = false csharp_preserve_single_line_statements = true
#### Naming styles #### #### Naming styles ####
# Naming rules # Naming rules
dotnet_naming_rule.interfaces_should_be_prefixed_with_I.severity = suggestion dotnet_naming_rule.interface_should_be_begins_with_i.severity = suggestion
dotnet_naming_rule.interfaces_should_be_prefixed_with_I.symbols = interface dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface
dotnet_naming_rule.interfaces_should_be_prefixed_with_I.style = IPascalCase dotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_i
dotnet_naming_rule.types_should_be_pascal_case.severity = suggestion 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.symbols = types
dotnet_naming_rule.types_should_be_pascal_case.style = PascalCase dotnet_naming_rule.types_should_be_pascal_case.style = pascal_case
dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = suggestion 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.symbols = non_field_members
dotnet_naming_rule.non_field_members_should_be_pascal_case.style = PascalCase dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case
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 # Symbol specifications
@ -211,62 +190,14 @@ 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.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
dotnet_naming_symbols.non_field_members.required_modifiers = 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 # Naming styles
dotnet_naming_style._camelCase.required_prefix = _ dotnet_naming_style.pascal_case.required_prefix =
dotnet_naming_style._camelCase.required_suffix = dotnet_naming_style.pascal_case.required_suffix =
dotnet_naming_style._camelCase.word_separator = dotnet_naming_style.pascal_case.word_separator =
dotnet_naming_style._camelCase.capitalization = camel_case dotnet_naming_style.pascal_case.capitalization = pascal_case
dotnet_naming_style.PascalCase.required_prefix = dotnet_naming_style.begins_with_i.required_prefix = I
dotnet_naming_style.PascalCase.required_suffix = dotnet_naming_style.begins_with_i.required_suffix =
dotnet_naming_style.PascalCase.word_separator = dotnet_naming_style.begins_with_i.word_separator =
dotnet_naming_style.PascalCase.capitalization = pascal_case dotnet_naming_style.begins_with_i.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
# TODO:
# .NET 8 migration (new warnings are caused by the NET 8 C# compiler and analyzer)
# The following info messages might need to be fixed in the source code instead of hiding the actual message
# Without the following lines, dotnet format would fail
# Disable "Collection initialization can be simplified"
dotnet_diagnostic.IDE0028.severity = none
dotnet_diagnostic.IDE0300.severity = none
dotnet_diagnostic.IDE0301.severity = none
dotnet_diagnostic.IDE0302.severity = none
dotnet_diagnostic.IDE0305.severity = none
# Disable "'new' expression can be simplified"
dotnet_diagnostic.IDE0090.severity = none
# Disable "Use primary constructor"
dotnet_diagnostic.IDE0290.severity = none
# Disable "Member '' does not access instance data and can be marked as static"
dotnet_diagnostic.CA1822.severity = none
# Disable "Change type of field '' from '' to '' for improved performance"
dotnet_diagnostic.CA1859.severity = none
# Disable "Prefer 'static readonly' fields over constant array arguments if the called method is called repeatedly and is not mutating the passed array"
dotnet_diagnostic.CA1861.severity = none
# Disable "Prefer using 'string.Equals(string, StringComparison)' to perform a case-insensitive comparison, but keep in mind that this might cause subtle changes in behavior, so make sure to conduct thorough testing after applying the suggestion, or if culturally sensitive comparison is not required, consider using 'StringComparison.OrdinalIgnoreCase'"
dotnet_diagnostic.CA1862.severity = none
[src/Ryujinx/UI/ViewModels/**.cs]
# Disable "mark members as static" rule for ViewModels
dotnet_diagnostic.CA1822.severity = none
[src/Ryujinx.HLE/HOS/Services/**.cs]
# Disable "mark members as static" rule for services
dotnet_diagnostic.CA1822.severity = none
[src/Ryujinx.Tests/Cpu/*.cs]
# Disable naming rules for CPU tests
dotnet_diagnostic.IDE1006.severity = none

View file

@ -23,7 +23,7 @@ body:
attributes: attributes:
label: Log file label: Log file
description: A log file will help our developers to better diagnose and fix the issue. description: A log file will help our developers to better diagnose and fix the issue.
placeholder: Logs files can be found under "Logs" folder in Ryujinx program folder. They can also be accessed by opening Ryujinx, then going to File > Open Logs Folder. You can drag and drop the log on to the text area (do not copy paste). placeholder: Logs files can be found under "Logs" folder in Ryujinx program folder. You can drag and drop the log on to the text area
validations: validations:
required: true required: true
- type: input - type: input

View file

@ -1,7 +1,6 @@
name: Feature Request name: Feature Request
description: Suggest a new feature for Ryujinx. description: Suggest a new feature for Ryujinx.
title: "[Feature Request]" title: "[Feature Request]"
labels: enhancement
body: body:
- type: textarea - type: textarea
id: overview id: overview

View file

@ -1,19 +0,0 @@
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

18
.github/csc.json vendored
View file

@ -1,18 +0,0 @@
{
"problemMatcher": [
{
"owner": "csc",
"pattern": [
{
"regexp": "^((?:\\\\|/)(?:[^\\\\/:]+(?:\\\\|/))+[^\\\\/]+)\\((\\d+),(\\d+)\\):\\s+([a-zA-Z]+)\\s+([^:]+):\\s+([^[]+)\\s+\\[",
"file": 1,
"line": 2,
"column": 3,
"severity": 4,
"code": 5,
"message": 6
}
]
}
]
}

View file

@ -7,34 +7,18 @@ updates:
labels: labels:
- "infra" - "infra"
reviewers: reviewers:
- TSRBerry - marysaka
commit-message: commit-message:
prefix: "ci" prefix: "ci"
- package-ecosystem: nuget - package-ecosystem: nuget
directory: / directory: /
open-pull-requests-limit: 10 open-pull-requests-limit: 5
schedule: schedule:
interval: daily interval: daily
labels: labels:
- "infra" - "infra"
reviewers: reviewers:
- TSRBerry - marysaka
commit-message: commit-message:
prefix: nuget prefix: nuget
groups:
Avalonia:
patterns:
- "*Avalonia*"
Silk.NET:
patterns:
- "Silk.NET*"
OpenTK:
patterns:
- "OpenTK*"
SixLabors:
patterns:
- "SixLabors*"
NUnit:
patterns:
- "NUnit*"

35
.github/labeler.yml vendored
View file

@ -1,35 +0,0 @@
audio:
- changed-files:
- any-glob-to-any-file: 'src/Ryujinx.Audio*/**'
cpu:
- changed-files:
- any-glob-to-any-file: ['src/ARMeilleure/**', 'src/Ryujinx.Cpu/**', 'src/Ryujinx.Memory/**']
gpu:
- changed-files:
- any-glob-to-any-file: ['src/Ryujinx.Graphics.*/**', 'src/Spv.Generator/**', 'src/Ryujinx.ShaderTools/**']
'graphics-backend:opengl':
- changed-files:
- any-glob-to-any-file: 'src/Ryujinx.Graphics.OpenGL/**'
'graphics-backend:vulkan':
- changed-files:
- any-glob-to-any-file: ['src/Ryujinx.Graphics.Vulkan/**', 'src/Spv.Generator/**']
gui:
- changed-files:
- any-glob-to-any-file: ['src/Ryujinx/**', 'src/Ryujinx.UI.Common/**', 'src/Ryujinx.UI.LocaleGenerator/**', 'src/Ryujinx.Gtk3/**']
horizon:
- changed-files:
- any-glob-to-any-file: ['src/Ryujinx.HLE/**', 'src/Ryujinx.Horizon/**']
kernel:
- changed-files:
- any-glob-to-any-file: 'src/Ryujinx.HLE/HOS/Kernel/**'
infra:
- changed-files:
- any-glob-to-any-file: ['.github/**', 'distribution/**', 'Directory.Packages.props']

25
.github/reviewers.yml vendored
View file

@ -1,25 +0,0 @@
cpu:
- gdkchan
- riperiperi
- LDj3SNuD
gpu:
- gdkchan
- riperiperi
gui:
- Ack77
- emmauss
- TSRBerry
horizon:
- gdkchan
- Ack77
- TSRBerry
infra:
- TSRBerry
default:
- '@developers'

View file

@ -1,7 +1,22 @@
name: Build job name: Build job
on: on:
workflow_call: 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'
env: env:
POWERSHELL_TELEMETRY_OPTOUT: 1 POWERSHELL_TELEMETRY_OPTOUT: 1
@ -10,94 +25,87 @@ env:
jobs: jobs:
build: build:
name: ${{ matrix.platform.name }} (${{ matrix.configuration }}) name: ${{ matrix.OS_NAME }} (${{ matrix.configuration }})
runs-on: ${{ matrix.platform.os }} runs-on: ${{ matrix.os }}
timeout-minutes: 45 timeout-minutes: 45
strategy: strategy:
matrix: matrix:
os: [ubuntu-latest, macOS-latest, windows-latest]
configuration: [Debug, Release] configuration: [Debug, Release]
platform: include:
- { name: win-x64, os: windows-latest, zip_os_name: win_x64 } - os: ubuntu-latest
- { name: linux-x64, os: ubuntu-latest, zip_os_name: linux_x64 } OS_NAME: Linux x64
- { name: linux-arm64, os: ubuntu-latest, zip_os_name: linux_arm64 } DOTNET_RUNTIME_IDENTIFIER: linux-x64
- { name: osx-x64, os: macos-13, zip_os_name: osx_x64 } RELEASE_ZIP_OS_NAME: linux_x64
- os: macOS-latest
OS_NAME: macOS x64
DOTNET_RUNTIME_IDENTIFIER: osx-x64
RELEASE_ZIP_OS_NAME: osx_x64
- os: windows-latest
OS_NAME: Windows x64
DOTNET_RUNTIME_IDENTIFIER: win10-x64
RELEASE_ZIP_OS_NAME: win_x64
fail-fast: false fail-fast: false
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v3
- uses: actions/setup-dotnet@v4 - uses: actions/setup-dotnet@v3
with: with:
global-json-file: global.json global-json-file: global.json
- name: Overwrite csc problem matcher
run: echo "::add-matcher::.github/csc.json"
- name: Get git short hash - name: Get git short hash
id: git_short_hash id: git_short_hash
run: echo "result=$(git rev-parse --short "${{ github.sha }}")" >> $GITHUB_OUTPUT run: echo "result=$(git rev-parse --short "${{ github.sha }}")" >> $GITHUB_OUTPUT
shell: bash shell: bash
- name: Change config filename
run: sed -r --in-place 's/\%\%RYUJINX_CONFIG_FILE_NAME\%\%/PRConfig\.json/g;' src/Ryujinx.Common/ReleaseInformation.cs
shell: bash
if: github.event_name == 'pull_request' && matrix.platform.os != 'macos-13'
- name: Change config filename for macOS
run: sed -r -i '' 's/\%\%RYUJINX_CONFIG_FILE_NAME\%\%/PRConfig\.json/g;' src/Ryujinx.Common/ReleaseInformation.cs
shell: bash
if: github.event_name == 'pull_request' && matrix.platform.os == 'macos-13'
- name: Build - 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 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 - name: Test
uses: TSRBerry/unstable-commands@v1 run: dotnet test --no-build -c "${{ matrix.configuration }}"
with:
commands: dotnet test --no-build -c "${{ matrix.configuration }}"
timeout-minutes: 10
retry-codes: 139
if: matrix.platform.name != 'linux-arm64'
- name: Publish Ryujinx - name: Publish Ryujinx
run: dotnet publish -c "${{ matrix.configuration }}" -r "${{ matrix.platform.name }}" -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 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.platform.os != 'macos-13' if: github.event_name == 'pull_request' && matrix.os != 'macOS-latest'
- name: Publish Ryujinx.Headless.SDL2 - name: Publish Ryujinx.Headless.SDL2
run: dotnet publish -c "${{ matrix.configuration }}" -r "${{ matrix.platform.name }}" -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 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.platform.os != 'macos-13' if: github.event_name == 'pull_request' && matrix.os != 'macOS-latest'
- name: Publish Ryujinx.Gtk3 - name: Publish Ryujinx.Ava
run: dotnet publish -c "${{ matrix.configuration }}" -r "${{ matrix.platform.name }}" -o ./publish_gtk -p:Version="${{ env.RYUJINX_BASE_VERSION }}" -p:DebugType=embedded -p:SourceRevisionId="${{ steps.git_short_hash.outputs.result }}" -p:ExtraDefineConstants=DISABLE_UPDATER src/Ryujinx.Gtk3 --self-contained true 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.platform.os != 'macos-13' if: github.event_name == 'pull_request' && matrix.os != 'macOS-latest'
- name: Set executable bit - name: Set executable bit
run: | run: |
chmod +x ./publish/Ryujinx ./publish/Ryujinx.sh chmod +x ./publish/Ryujinx ./publish/Ryujinx.sh
chmod +x ./publish_sdl2_headless/Ryujinx.Headless.SDL2 ./publish_sdl2_headless/Ryujinx.sh chmod +x ./publish_sdl2_headless/Ryujinx.Headless.SDL2 ./publish_sdl2_headless/Ryujinx.sh
chmod +x ./publish_gtk/Ryujinx.Gtk3 ./publish_gtk/Ryujinx.sh chmod +x ./publish_ava/Ryujinx.Ava ./publish_ava/Ryujinx.sh
if: github.event_name == 'pull_request' && matrix.platform.os == 'ubuntu-latest' if: github.event_name == 'pull_request' && matrix.os == 'ubuntu-latest'
- name: Upload Ryujinx artifact - name: Upload Ryujinx artifact
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v3
with: with:
name: ryujinx-${{ matrix.configuration }}-${{ env.RYUJINX_BASE_VERSION }}+${{ steps.git_short_hash.outputs.result }}-${{ matrix.platform.zip_os_name }} name: ryujinx-${{ matrix.configuration }}-${{ env.RYUJINX_BASE_VERSION }}+${{ steps.git_short_hash.outputs.result }}-${{ matrix.RELEASE_ZIP_OS_NAME }}
path: publish path: publish
if: github.event_name == 'pull_request' && matrix.platform.os != 'macos-13' if: github.event_name == 'pull_request' && matrix.os != 'macOS-latest'
- name: Upload Ryujinx.Headless.SDL2 artifact - name: Upload Ryujinx.Headless.SDL2 artifact
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v3
with: with:
name: sdl2-ryujinx-headless-${{ matrix.configuration }}-${{ env.RYUJINX_BASE_VERSION }}+${{ steps.git_short_hash.outputs.result }}-${{ matrix.platform.zip_os_name }} 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 path: publish_sdl2_headless
if: github.event_name == 'pull_request' && matrix.platform.os != 'macos-13' if: github.event_name == 'pull_request' && matrix.os != 'macOS-latest'
- name: Upload Ryujinx.Gtk3 artifact - name: Upload Ryujinx.Ava artifact
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v3
with: with:
name: gtk-ryujinx-${{ matrix.configuration }}-${{ env.RYUJINX_BASE_VERSION }}+${{ steps.git_short_hash.outputs.result }}-${{ matrix.platform.zip_os_name }} name: ava-ryujinx-${{ matrix.configuration }}-${{ env.RYUJINX_BASE_VERSION }}+${{ steps.git_short_hash.outputs.result }}-${{ matrix.RELEASE_ZIP_OS_NAME }}
path: publish_gtk path: publish_ava
if: github.event_name == 'pull_request' && matrix.platform.os != 'macos-13' if: github.event_name == 'pull_request' && matrix.os != 'macOS-latest'
build_macos: build_macos:
name: macOS Universal (${{ matrix.configuration }}) name: macOS Universal (${{ matrix.configuration }})
@ -108,9 +116,9 @@ jobs:
configuration: [ Debug, Release ] configuration: [ Debug, Release ]
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v3
- uses: actions/setup-dotnet@v4 - uses: actions/setup-dotnet@v3
with: with:
global-json-file: global.json global-json-file: global.json
@ -135,29 +143,13 @@ jobs:
id: git_short_hash id: git_short_hash
run: echo "result=$(git rev-parse --short "${{ github.sha }}")" >> $GITHUB_OUTPUT run: echo "result=$(git rev-parse --short "${{ github.sha }}")" >> $GITHUB_OUTPUT
- name: Change config filename - name: Publish macOS
run: sed -r --in-place 's/\%\%RYUJINX_CONFIG_FILE_NAME\%\%/PRConfig\.json/g;' src/Ryujinx.Common/ReleaseInformation.cs
shell: bash
if: github.event_name == 'pull_request'
- name: Publish macOS Ryujinx
run: | run: |
./distribution/macos/create_macos_build_ava.sh . publish_tmp publish ./distribution/macos/entitlements.xml "${{ env.RYUJINX_BASE_VERSION }}" "${{ steps.git_short_hash.outputs.result }}" "${{ matrix.configuration }}" "-p:ExtraDefineConstants=DISABLE_UPDATER" ./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: Publish macOS Ryujinx.Headless.SDL2 - name: Upload Ryujinx.Ava artifact
run: | uses: actions/upload-artifact@v3
./distribution/macos/create_macos_build_headless.sh . publish_tmp_headless publish_headless ./distribution/macos/entitlements.xml "${{ env.RYUJINX_BASE_VERSION }}" "${{ steps.git_short_hash.outputs.result }}" "${{ matrix.configuration }}" "-p:ExtraDefineConstants=DISABLE_UPDATER"
- name: Upload Ryujinx artifact
uses: actions/upload-artifact@v4
with: with:
name: ryujinx-${{ matrix.configuration }}-${{ env.RYUJINX_BASE_VERSION }}+${{ steps.git_short_hash.outputs.result }}-macos_universal name: ava-ryujinx-${{ matrix.configuration }}-${{ env.RYUJINX_BASE_VERSION }}+${{ steps.git_short_hash.outputs.result }}-macos_universal
path: "publish/*.tar.gz" path: "publish_ava/*.tar.gz"
if: github.event_name == 'pull_request'
- name: Upload Ryujinx.Headless.SDL2 artifact
uses: actions/upload-artifact@v4
with:
name: sdl2-ryujinx-headless-${{ matrix.configuration }}-${{ env.RYUJINX_BASE_VERSION }}+${{ steps.git_short_hash.outputs.result }}-macos_universal
path: "publish_headless/*.tar.gz"
if: github.event_name == 'pull_request' if: github.event_name == 'pull_request'

View file

@ -1,74 +0,0 @@
name: Perform checks
on:
pull_request:
branches: [ master ]
paths:
- '**'
- '!.github/**'
- '!*.yml'
- '!*.config'
- '!*.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@v4
with:
fetch-depth: 0
- uses: actions/setup-dotnet@v4
with:
global-json-file: global.json
- name: Overwrite csc problem matcher
run: echo "::add-matcher::.github/csc.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
# For some unknown reason this step sometimes fails with exit code 139 (segfault?),
# so in that case we'll try again (3 tries max).
- name: Run dotnet format style
uses: TSRBerry/unstable-commands@v1
with:
commands: dotnet format style --severity info --verify-no-changes --report ./style-report.json -v d
timeout-minutes: 5
retry-codes: 139
# For some unknown reason this step sometimes fails with exit code 139 (segfault?),
# so in that case we'll try again (3 tries max).
- name: Run dotnet format analyzers
uses: TSRBerry/unstable-commands@v1
with:
commands: dotnet format analyzers --severity info --verify-no-changes --report ./analyzers-report.json -v d
timeout-minutes: 5
retry-codes: 139
- name: Upload report
if: failure()
uses: actions/upload-artifact@v4
with:
name: dotnet-format
path: ./*-report.json
pr_build:
uses: ./.github/workflows/build.yml
needs: format
secrets: inherit

View file

@ -24,11 +24,11 @@ jobs:
RYUJINX_VERSION: "${{ inputs.ryujinx_version }}" RYUJINX_VERSION: "${{ inputs.ryujinx_version }}"
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v3
with: with:
path: Ryujinx path: Ryujinx
- uses: actions/setup-dotnet@v4 - uses: actions/setup-dotnet@v3
with: with:
global-json-file: Ryujinx/global.json global-json-file: Ryujinx/global.json
@ -38,7 +38,7 @@ jobs:
run: | run: |
echo "git_hash=$(git rev-parse HEAD)" >> $GITHUB_OUTPUT echo "git_hash=$(git rev-parse HEAD)" >> $GITHUB_OUTPUT
- uses: actions/checkout@v4 - uses: actions/checkout@v3
with: with:
repository: flathub/org.ryujinx.Ryujinx repository: flathub/org.ryujinx.Ryujinx
token: ${{ secrets.RYUJINX_BOT_PAT }} token: ${{ secrets.RYUJINX_BOT_PAT }}
@ -49,78 +49,38 @@ jobs:
run: python -m pip install PyYAML lxml run: python -m pip install PyYAML lxml
- name: Restore Nuget packages - name: Restore Nuget packages
# With .NET 8.0.100, Microsoft.NET.ILLink.Tasks isn't restored by default and only seems to appears when publishing. run: dotnet restore Ryujinx/${{ env.RYUJINX_PROJECT_FILE }}
# So we just publish to grab the dependencies
run: |
dotnet publish -c Release -r linux-x64 Ryujinx/${{ env.RYUJINX_PROJECT_FILE }} --self-contained
dotnet publish -c Release -r linux-arm64 Ryujinx/${{ env.RYUJINX_PROJECT_FILE }} --self-contained
- name: Generate nuget_sources.json - name: Generate nuget_sources.json
shell: python shell: python
run: | run: |
import hashlib
from pathlib import Path from pathlib import Path
import base64 import base64
import binascii import binascii
import json import json
import os import os
import urllib.request
sources = [] sources = []
for path in Path(os.environ['NUGET_PACKAGES']).glob('**/*.nupkg.sha512'):
name = path.parent.parent.name
version = path.parent.name
filename = '{}.{}.nupkg'.format(name, version)
url = 'https://api.nuget.org/v3-flatcontainer/{}/{}/{}'.format(name, version, filename)
def create_source_from_external(name, version): with path.open() as fp:
full_dir_path = Path(os.environ["NUGET_PACKAGES"]).joinpath(name).joinpath(version) sha512 = binascii.hexlify(base64.b64decode(fp.read())).decode('ascii')
os.makedirs(full_dir_path, exist_ok=True)
filename = "{}.{}.nupkg".format(name, version) sources.append({
url = "https://api.nuget.org/v3-flatcontainer/{}/{}/{}".format( 'type': 'file',
name, version, filename 'url': url,
) 'sha512': sha512,
'dest': os.environ['NUGET_SOURCES_DESTDIR'],
'dest-filename': filename,
})
print(f"Processing {url}...") with open('flathub/nuget_sources.json', 'w') as fp:
response = urllib.request.urlopen(url) json.dump(sources, fp, indent=4)
sha512 = hashlib.sha512(response.read()).hexdigest()
return {
"type": "file",
"url": url,
"sha512": sha512,
"dest": os.environ["NUGET_SOURCES_DESTDIR"],
"dest-filename": filename,
}
has_added_x64_apphost = False
for path in Path(os.environ["NUGET_PACKAGES"]).glob("**/*.nupkg.sha512"):
name = path.parent.parent.name
version = path.parent.name
filename = "{}.{}.nupkg".format(name, version)
url = "https://api.nuget.org/v3-flatcontainer/{}/{}/{}".format(
name, version, filename
)
with path.open() as fp:
sha512 = binascii.hexlify(base64.b64decode(fp.read())).decode("ascii")
sources.append(
{
"type": "file",
"url": url,
"sha512": sha512,
"dest": os.environ["NUGET_SOURCES_DESTDIR"],
"dest-filename": filename,
}
)
# .NET will not add current installed application host to the list, force inject it here.
if not has_added_x64_apphost and name.startswith('microsoft.netcore.app.host'):
sources.append(create_source_from_external("microsoft.netcore.app.host.linux-x64", version))
has_added_x64_apphost = True
with open("flathub/nuget_sources.json", "w") as fp:
json.dump(sources, fp, indent=4)
- name: Update flatpak metadata - name: Update flatpak metadata
id: metadata id: metadata

View file

@ -1,41 +0,0 @@
name: Mako
on:
discussion:
types: [created, edited, answered, unanswered, category_changed]
discussion_comment:
types: [created, edited]
gollum:
issue_comment:
types: [created, edited]
issues:
types: [opened, edited, reopened, pinned, milestoned, demilestoned, assigned, unassigned, labeled, unlabeled]
pull_request_target:
types: [opened, edited, reopened, synchronize, ready_for_review, assigned, unassigned]
jobs:
tasks:
name: Run Ryujinx tasks
permissions:
actions: read
contents: read
discussions: write
issues: write
pull-requests: write
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
if: github.event_name == 'pull_request_target'
with:
# Ensure we pin the source origin as pull_request_target run under forks.
fetch-depth: 0
repository: Ryujinx/Ryujinx
ref: master
- name: Run Mako command
uses: Ryujinx/Ryujinx-Mako@master
with:
command: exec-ryujinx-tasks
args: --event-name "${{ github.event_name }}" --event-path "${{ github.event_path }}" -w "${{ github.workspace }}" "${{ github.repository }}" "${{ github.run_id }}"
app_id: ${{ secrets.MAKO_APP_ID }}
private_key: ${{ secrets.MAKO_PRIVATE_KEY }}
installation_id: ${{ secrets.MAKO_INSTALLATION_ID }}

View file

@ -1,10 +1,8 @@
name: Comment PR artifacts links name: Comment PR artifacts links
on: on:
workflow_run: workflow_run:
workflows: ['Perform checks'] workflows: ['Build job']
types: [completed] types: [completed]
jobs: jobs:
pr_comment: pr_comment:
if: github.event.workflow_run.event == 'pull_request' && github.event.workflow_run.conclusion == 'success' if: github.event.workflow_run.event == 'pull_request' && github.event.workflow_run.conclusion == 'success'
@ -39,24 +37,24 @@ jobs:
return core.error(`No artifacts found`); return core.error(`No artifacts found`);
} }
let body = `Download the artifacts for this pull request:\n`; let body = `Download the artifacts for this pull request:\n`;
let hidden_gtk_artifacts = `\n\n <details><summary>Old GUI (GTK3)</summary>\n`; let hidden_avalonia_artifacts = `\n\n <details><summary>Experimental GUI (Avalonia)</summary>\n`;
let hidden_headless_artifacts = `\n\n <details><summary>GUI-less (SDL2)</summary>\n`; let hidden_headless_artifacts = `\n\n <details><summary>GUI-less (SDL2)</summary>\n`;
let hidden_debug_artifacts = `\n\n <details><summary>Only for Developers</summary>\n`; let hidden_debug_artifacts = `\n\n <details><summary>Only for Developers</summary>\n`;
for (const art of artifacts) { for (const art of artifacts) {
if(art.name.includes('Debug')) { if(art.name.includes('Debug')) {
hidden_debug_artifacts += `\n* [${art.name}](https://nightly.link/${owner}/${repo}/actions/artifacts/${art.id}.zip)`; hidden_debug_artifacts += `\n* [${art.name}](https://nightly.link/${owner}/${repo}/actions/artifacts/${art.id}.zip)`;
} else if(art.name.includes('gtk-ryujinx')) { } else if(art.name.includes('ava-ryujinx')) {
hidden_gtk_artifacts += `\n* [${art.name}](https://nightly.link/${owner}/${repo}/actions/artifacts/${art.id}.zip)`; hidden_avalonia_artifacts += `\n* [${art.name}](https://nightly.link/${owner}/${repo}/actions/artifacts/${art.id}.zip)`;
} else if(art.name.includes('sdl2-ryujinx-headless')) { } else if(art.name.includes('sdl2-ryujinx-headless')) {
hidden_headless_artifacts += `\n* [${art.name}](https://nightly.link/${owner}/${repo}/actions/artifacts/${art.id}.zip)`; hidden_headless_artifacts += `\n* [${art.name}](https://nightly.link/${owner}/${repo}/actions/artifacts/${art.id}.zip)`;
} else { } else {
body += `\n* [${art.name}](https://nightly.link/${owner}/${repo}/actions/artifacts/${art.id}.zip)`; body += `\n* [${art.name}](https://nightly.link/${owner}/${repo}/actions/artifacts/${art.id}.zip)`;
} }
} }
hidden_gtk_artifacts += `\n</details>`; hidden_avalonia_artifacts += `\n</details>`;
hidden_headless_artifacts += `\n</details>`; hidden_headless_artifacts += `\n</details>`;
hidden_debug_artifacts += `\n</details>`; hidden_debug_artifacts += `\n</details>`;
body += hidden_gtk_artifacts; body += hidden_avalonia_artifacts;
body += hidden_headless_artifacts; body += hidden_headless_artifacts;
body += hidden_debug_artifacts; body += hidden_debug_artifacts;

View file

@ -1,28 +0,0 @@
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 latest labeler.yml
- name: Fetch sources
uses: actions/checkout@v4
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@v5
with:
sync-labels: true
dot: true

View file

@ -6,11 +6,10 @@ on:
push: push:
branches: [ master ] branches: [ master ]
paths-ignore: paths-ignore:
- '.github/**' - '.github/*'
- '.github/ISSUE_TEMPLATE/**'
- '*.yml' - '*.yml'
- '*.json' - 'README.md'
- '*.config'
- '*.md'
concurrency: release concurrency: release
@ -25,7 +24,7 @@ env:
jobs: jobs:
tag: tag:
name: Create tag name: Create tag
runs-on: ubuntu-20.04 runs-on: ubuntu-latest
steps: steps:
- name: Get version info - name: Get version info
id: version_info id: version_info
@ -44,37 +43,30 @@ jobs:
sha: context.sha sha: context.sha
}) })
- name: Create release
uses: ncipollo/release-action@v1
with:
name: ${{ steps.version_info.outputs.build_version }}
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
owner: ${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}
repo: ${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }}
token: ${{ secrets.RELEASE_TOKEN }}
release: release:
name: Release for ${{ matrix.platform.name }} name: Release ${{ matrix.OS_NAME }}
runs-on: ${{ matrix.platform.os }} runs-on: ${{ matrix.os }}
timeout-minutes: ${{ fromJSON(vars.JOB_TIMEOUT) }} timeout-minutes: ${{ fromJSON(vars.JOB_TIMEOUT) }}
strategy: strategy:
matrix: matrix:
platform: os: [ ubuntu-latest, windows-latest ]
- { name: win-x64, os: windows-latest, zip_os_name: win_x64 } include:
- { name: linux-x64, os: ubuntu-latest, zip_os_name: linux_x64 } - os: ubuntu-latest
- { name: linux-arm64, os: ubuntu-latest, zip_os_name: linux_arm64 } OS_NAME: Linux x64
steps: DOTNET_RUNTIME_IDENTIFIER: linux-x64
- uses: actions/checkout@v4 RELEASE_ZIP_OS_NAME: linux_x64
- uses: actions/setup-dotnet@v4 - 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: with:
global-json-file: global.json global-json-file: global.json
- name: Overwrite csc problem matcher
run: echo "::add-matcher::.github/csc.json"
- name: Get version info - name: Get version info
id: version_info id: version_info
run: | run: |
@ -89,7 +81,6 @@ jobs:
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_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_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 sed -r --in-place 's/\%\%RYUJINX_TARGET_RELEASE_CHANNEL_REPO\%\%/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }}/g;' src/Ryujinx.Common/ReleaseInformation.cs
sed -r --in-place 's/\%\%RYUJINX_CONFIG_FILE_NAME\%\%/Config\.json/g;' src/Ryujinx.Common/ReleaseInformation.cs
shell: bash shell: bash
- name: Create output dir - name: Create output dir
@ -97,36 +88,42 @@ jobs:
- name: Publish - name: Publish
run: | run: |
dotnet publish -c Release -r "${{ matrix.platform.name }}" -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 --self-contained true 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.platform.name }}" -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_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 - name: Packing Windows builds
if: matrix.platform.os == 'windows-latest' if: matrix.os == 'windows-latest'
run: | run: |
pushd publish_ava pushd publish_gtk
cp publish/Ryujinx.exe publish/Ryujinx.Ava.exe 7z a ../release_output/ryujinx-${{ steps.version_info.outputs.build_version }}-win_x64.zip publish
7z a ../release_output/ryujinx-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.zip publish
7z a ../release_output/test-ava-ryujinx-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.zip publish
popd popd
pushd publish_sdl2_headless pushd publish_sdl2_headless
7z a ../release_output/sdl2-ryujinx-headless-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.zip publish 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 popd
shell: bash shell: bash
- name: Packing Linux builds - name: Packing Linux builds
if: matrix.platform.os == 'ubuntu-latest' if: matrix.os == 'ubuntu-latest'
run: | run: |
pushd publish_ava pushd publish_gtk
cp publish/Ryujinx publish/Ryujinx.Ava chmod +x publish/Ryujinx.sh publish/Ryujinx
chmod +x publish/Ryujinx.sh publish/Ryujinx.Ava publish/Ryujinx tar -czvf ../release_output/ryujinx-${{ steps.version_info.outputs.build_version }}-linux_x64.tar.gz publish
tar -czvf ../release_output/ryujinx-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.tar.gz publish
tar -czvf ../release_output/test-ava-ryujinx-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.tar.gz publish
popd popd
pushd publish_sdl2_headless pushd publish_sdl2_headless
chmod +x publish/Ryujinx.sh publish/Ryujinx.Headless.SDL2 chmod +x publish/Ryujinx.sh publish/Ryujinx.Headless.SDL2
tar -czvf ../release_output/sdl2-ryujinx-headless-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.tar.gz publish 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 popd
shell: bash shell: bash
@ -149,17 +146,17 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
timeout-minutes: ${{ fromJSON(vars.JOB_TIMEOUT) }} timeout-minutes: ${{ fromJSON(vars.JOB_TIMEOUT) }}
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v3
- uses: actions/setup-dotnet@v4 - uses: actions/setup-dotnet@v3
with: with:
global-json-file: global.json global-json-file: global.json
- name: Setup LLVM 15 - name: Setup LLVM 14
run: | run: |
wget https://apt.llvm.org/llvm.sh wget https://apt.llvm.org/llvm.sh
chmod +x llvm.sh chmod +x llvm.sh
sudo ./llvm.sh 15 sudo ./llvm.sh 14
- name: Install rcodesign - name: Install rcodesign
run: | run: |
@ -185,22 +182,17 @@ jobs:
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_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_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 sed -r --in-place 's/\%\%RYUJINX_TARGET_RELEASE_CHANNEL_REPO\%\%/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }}/g;' src/Ryujinx.Common/ReleaseInformation.cs
sed -r --in-place 's/\%\%RYUJINX_CONFIG_FILE_NAME\%\%/Config\.json/g;' src/Ryujinx.Common/ReleaseInformation.cs
shell: bash shell: bash
- name: Publish macOS Ryujinx - name: Publish macOS
run: | run: |
./distribution/macos/create_macos_build_ava.sh . publish_tmp_ava publish_ava ./distribution/macos/entitlements.xml "${{ steps.version_info.outputs.build_version }}" "${{ steps.version_info.outputs.git_short_hash }}" Release ./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: Publish macOS Ryujinx.Headless.SDL2
run: |
./distribution/macos/create_macos_build_headless.sh . publish_tmp_headless publish_headless ./distribution/macos/entitlements.xml "${{ steps.version_info.outputs.build_version }}" "${{ steps.version_info.outputs.git_short_hash }}" Release
- name: Pushing new release - name: Pushing new release
uses: ncipollo/release-action@v1 uses: ncipollo/release-action@v1
with: with:
name: ${{ steps.version_info.outputs.build_version }} name: ${{ steps.version_info.outputs.build_version }}
artifacts: "publish_ava/*.tar.gz, publish_headless/*.tar.gz" artifacts: "publish_ava/*.tar.gz"
tag: ${{ steps.version_info.outputs.build_version }} 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)." body: "For more information about this release please check out the official [Changelog](https://github.com/Ryujinx/Ryujinx/wiki/Changelog)."
omitBodyDuringUpdate: true omitBodyDuringUpdate: true

View file

@ -1,147 +0,0 @@
# Contribution to Ryujinx
You can contribute to Ryujinx with PRs, testing of PRs and issues. Contributing code and other implementations is greatly appreciated alongside simply filing issues for problems you encounter.
Please read the entire document before continuing as it can potentially save everyone involved a significant amount of time.
# Quick Links
* [Code Style Documentation](docs/coding-guidelines/coding-style.md)
* [Pull Request Guidelines](docs/workflow/pr-guide.md)
## Reporting Issues
We always welcome bug reports, feature proposals and overall feedback. Here are a few tips on how you can make reporting your issue as effective as possible.
### Identify Where to Report
The Ryujinx codebase is distributed across multiple repositories in the [Ryujinx organization](https://github.com/Ryujinx). Depending on the feedback you might want to file the issue on a different repo. Here are a few common repos:
* [Ryujinx/Ryujinx](https://github.com/Ryujinx/Ryujinx) Ryujinx core project files.
* [Ryujinx/Ryujinx-Games-List](https://github.com/Ryujinx/Ryujinx-Games-List) Ryujinx game compatibility list.
* [Ryujinx/Ryujinx-Website](https://github.com/Ryujinx/Ryujinx-Website) Ryujinx website source code.
* [Ryujinx/Ryujinx-Ldn-Website](https://github.com/Ryujinx/Ryujinx-Ldn-Website) Ryujinx LDN website source code.
### Finding Existing Issues
Before filing a new issue, please search our [open issues](https://github.com/Ryujinx/Ryujinx/issues) to check if it already exists.
If you do find an existing issue, please include your own feedback in the discussion. Do consider upvoting (👍 reaction) the original post, as this helps us prioritize popular issues in our backlog.
### Writing a Good Feature Request
Please review any feature requests already opened to both check it has not already been suggested, and to familiarize yourself with the format. When ready to submit a proposal, please use the [Feature Request issue template](https://github.com/Ryujinx/Ryujinx/issues/new?assignees=&labels=&projects=&template=feature_request.yml&title=%5BFeature+Request%5D).
### Writing a Good Bug Report
Good bug reports make it easier for maintainers to verify and root cause the underlying problem. The better a bug report, the faster the problem will be resolved.
Ideally, a bug report should contain the following information:
* A high-level description of the problem.
* A _minimal reproduction_, i.e. the smallest time commitment/configuration required to reproduce the wrong behavior. This can be in the form of a small homebrew application, or by providing a save file and reproduction steps for a specific game.
* A description of the _expected behavior_, contrasted with the _actual behavior_ observed.
* Information on the environment: OS/distro, CPU, GPU (including driver), RAM etc.
* A Ryujinx log file of the run instance where the issue occurred. Log files can be found in `[Executable Folder]/Logs` and are named chronologically.
* Additional information, e.g. is it a regression from previous versions? Are there any known workarounds?
When ready to submit a bug report, please use the [Bug Report issue template](https://github.com/Ryujinx/Ryujinx/issues/new?assignees=&labels=bug&projects=&template=bug_report.yml&title=%5BBug%5D).
## Contributing Changes
Project maintainers will merge changes that both improve the project and meet our standards for code quality.
The [Pull Request Guide](docs/workflow/pr-guide.md) and [License](https://github.com/Ryujinx/Ryujinx/blob/master/LICENSE.txt) docs define additional guidance.
### DOs and DON'Ts
Please do:
* **DO** follow our [coding style](docs/coding-guidelines/coding-style.md) (C# code-specific).
* **DO** give priority to the current style of the project or file you're changing even if it diverges from the general guidelines.
* **DO** keep the discussions focused. When a new or related topic comes up
it's often better to create new issue than to side track the discussion.
* **DO** clearly state on an issue that you are going to take on implementing it.
* **DO** blog and tweet (or whatever) about your contributions, frequently!
Please do not:
* **DON'T** make PRs for style changes.
* **DON'T** surprise us with big pull requests. Instead, file an issue and talk with us on Discord to start
a discussion so we can agree on a direction before you invest a large amount
of time.
* **DON'T** commit code that you didn't write. If you find code that you think is a good fit to add to Ryujinx, file an issue or talk to us on Discord to start a discussion before proceeding.
* **DON'T** submit PRs that alter licensing related files or headers. If you believe there's a problem with them, file an issue and we'll be happy to discuss it.
### Suggested Workflow
We use and recommend the following workflow:
1. Create or find an issue for your work.
- You can skip this step for trivial changes.
- Get agreement from the team and the community that your proposed change is a good one if it is of significant size or changes core functionality.
- Clearly state that you are going to take on implementing it, if that's the case. You can request that the issue be assigned to you. Note: The issue filer and the implementer don't have to be the same person.
2. Create a personal fork of the repository on GitHub (if you don't already have one).
3. In your fork, create a branch off of main (`git checkout -b mybranch`).
- Branches are useful since they isolate your changes from incoming changes from upstream. They also enable you to create multiple PRs from the same fork.
4. Make and commit your changes to your branch.
- [Build Instructions](https://github.com/Ryujinx/Ryujinx#building) explains how to build and test.
- Commit messages should be clear statements of action and intent.
6. Build the repository with your changes.
- Make sure that the builds are clean.
- Make sure that `dotnet format` has been run and any corrections tested and committed.
7. Create a pull request (PR) against the Ryujinx/Ryujinx repository's **main** branch.
- State in the description what issue or improvement your change is addressing.
- Check if all the Continuous Integration checks are passing. Refer to [Actions](https://github.com/Ryujinx/Ryujinx/actions) to check for outstanding errors.
8. Wait for feedback or approval of your changes from the [core development team](https://github.com/orgs/Ryujinx/teams/developers)
- Details about the pull request [review procedure](docs/workflow/ci/pr-guide.md).
9. When the team members have signed off, and all checks are green, your PR will be merged.
- The next official build will automatically include your change.
- You can delete the branch you used for making the change.
### Good First Issues
The team marks the most straightforward issues as [good first issues](https://github.com/Ryujinx/Ryujinx/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22). This set of issues is the place to start if you are interested in contributing but new to the codebase.
### Commit Messages
Please format commit messages as follows (based on [A Note About Git Commit Messages](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html)):
```
Summarize change in 50 characters or less
Provide more detail after the first line. Leave one blank line below the
summary and wrap all lines at 72 characters or less.
If the change fixes an issue, leave another blank line after the final
paragraph and indicate which issue is fixed in the specific format
below.
Fix #42
```
Also do your best to factor commits appropriately, not too large with unrelated things in the same commit, and not too small with the same small change applied N times in N different commits.
### PR - CI Process
The [Ryujinx continuous integration](https://github.com/Ryujinx/Ryujinx/actions) (CI) system will automatically perform the required builds and run tests (including the ones you are expected to run) for PRs. Builds and test runs must be clean or have bugs properly filed against flaky/unexpected failures that are unrelated to your change.
If the CI build fails for any reason, the PR actions tab should be consulted for further information on the failure. There are a few usual suspects for such a failure:
* `dotnet format` has not been run on the PR and has outstanding stylistic issues.
* There is an error within the PR that fails a test or errors the compiler.
* Random failure of the workflow can occasionally result in a CI failure. In this scenario a maintainer will manually restart the job.
### PR Feedback
Ryujinx team and community members will provide feedback on your change. Community feedback is highly valued. You may see the absence of team feedback if the community has already provided good review feedback.
Two Ryujinx team members must review and approve every PR prior to merge. They will often reply with "LGTM, see nit". That means that the PR will be merged once the feedback is resolved. "LGTM" == "looks good to me".
There are lots of thoughts and [approaches](https://github.com/antlr/antlr4-cpp/blob/master/CONTRIBUTING.md#emoji) for how to efficiently discuss changes. It is best to be clear and explicit with your feedback. Please be patient with people who might not understand the finer details about your approach to feedback.
#### Copying Changes from Other Projects
Ryujinx uses some implementations and frameworks from other projects. The following rules must be followed for PRs that include changes from another project:
- The license of the file is [permissive](https://en.wikipedia.org/wiki/Permissive_free_software_licence).
- The license of the file is left in-tact.
- The contribution is correctly attributed in the [3rd party notices](https://github.com/Ryujinx/Ryujinx/blob/master/distribution/legal/THIRDPARTY.md) file in the repository, as needed.

View file

@ -3,50 +3,51 @@
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally> <ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageVersion Include="Avalonia" Version="11.0.10" /> <PackageVersion Include="Avalonia" Version="0.10.21" />
<PackageVersion Include="Avalonia.Controls.DataGrid" Version="11.0.10" /> <PackageVersion Include="Avalonia.Controls.DataGrid" Version="0.10.21" />
<PackageVersion Include="Avalonia.Desktop" Version="11.0.10" /> <PackageVersion Include="Avalonia.Desktop" Version="0.10.21" />
<PackageVersion Include="Avalonia.Diagnostics" Version="11.0.10" /> <PackageVersion Include="Avalonia.Diagnostics" Version="0.10.21" />
<PackageVersion Include="Avalonia.Markup.Xaml.Loader" Version="11.0.10" /> <PackageVersion Include="Avalonia.Markup.Xaml.Loader" Version="0.10.21" />
<PackageVersion Include="Avalonia.Svg" Version="11.0.0.18" /> <PackageVersion Include="Avalonia.Svg" Version="0.10.18" />
<PackageVersion Include="Avalonia.Svg.Skia" Version="11.0.0.18" /> <PackageVersion Include="Avalonia.Svg.Skia" Version="0.10.18" />
<PackageVersion Include="CommandLineParser" Version="2.9.1" /> <PackageVersion Include="CommandLineParser" Version="2.9.1" />
<PackageVersion Include="Concentus" Version="2.2.0" /> <PackageVersion Include="Concentus" Version="1.1.7" />
<PackageVersion Include="DiscordRichPresence" Version="1.2.1.24" /> <PackageVersion Include="DiscordRichPresence" Version="1.1.3.18" />
<PackageVersion Include="DynamicData" Version="9.0.4" /> <PackageVersion Include="DynamicData" Version="7.13.8" />
<PackageVersion Include="FluentAvaloniaUI" Version="2.0.5" /> <PackageVersion Include="FluentAvaloniaUI" Version="1.4.5" />
<PackageVersion Include="GtkSharp.Dependencies" Version="1.1.1" /> <PackageVersion Include="GtkSharp.Dependencies" Version="1.1.1" />
<PackageVersion Include="GtkSharp.Dependencies.osx" Version="0.0.5" /> <PackageVersion Include="GtkSharp.Dependencies.osx" Version="0.0.5" />
<PackageVersion Include="LibHac" Version="0.19.0" /> <PackageVersion Include="jp2masa.Avalonia.Flexbox" Version="0.2.0" />
<PackageVersion Include="LibHac" Version="0.18.0" />
<PackageVersion Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.4" /> <PackageVersion Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.4" />
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="4.9.2" /> <PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="4.5.0" />
<PackageVersion Include="Microsoft.IdentityModel.JsonWebTokens" Version="8.0.1" /> <PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.6.0" />
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.9.0" /> <PackageVersion Include="Microsoft.IO.RecyclableMemoryStream" Version="2.3.2" />
<PackageVersion Include="Microsoft.IO.RecyclableMemoryStream" Version="3.0.1" />
<PackageVersion Include="MsgPack.Cli" Version="1.0.1" /> <PackageVersion Include="MsgPack.Cli" Version="1.0.1" />
<PackageVersion Include="NetCoreServer" Version="8.0.7" />
<PackageVersion Include="NUnit" Version="3.13.3" /> <PackageVersion Include="NUnit" Version="3.13.3" />
<PackageVersion Include="NUnit3TestAdapter" Version="4.1.0" /> <PackageVersion Include="NUnit3TestAdapter" Version="4.1.0" />
<PackageVersion Include="OpenTK.Core" Version="4.8.2" /> <PackageVersion Include="OpenTK.Core" Version="4.7.7" />
<PackageVersion Include="OpenTK.Graphics" Version="4.8.2" /> <PackageVersion Include="OpenTK.Graphics" Version="4.7.7" />
<PackageVersion Include="OpenTK.Audio.OpenAL" Version="4.8.2" /> <PackageVersion Include="OpenTK.OpenAL" Version="4.7.7" />
<PackageVersion Include="OpenTK.Windowing.GraphicsLibraryFramework" Version="4.8.2" /> <PackageVersion Include="OpenTK.Windowing.GraphicsLibraryFramework" Version="4.7.7" />
<PackageVersion Include="Ryujinx.Audio.OpenAL.Dependencies" Version="1.21.0.1" /> <PackageVersion Include="Ryujinx.Audio.OpenAL.Dependencies" Version="1.21.0.1" />
<PackageVersion Include="Ryujinx.Graphics.Nvdec.Dependencies" Version="5.0.3-build14" /> <PackageVersion Include="Ryujinx.Graphics.Nvdec.Dependencies" Version="5.0.1-build13" />
<PackageVersion Include="Ryujinx.Graphics.Vulkan.Dependencies.MoltenVK" Version="1.2.0" /> <PackageVersion Include="Ryujinx.Graphics.Vulkan.Dependencies.MoltenVK" Version="1.2.3" />
<PackageVersion Include="Ryujinx.GtkSharp" Version="3.24.24.59-ryujinx" /> <PackageVersion Include="Ryujinx.GtkSharp" Version="3.24.24.59-ryujinx" />
<PackageVersion Include="Ryujinx.SDL2-CS" Version="2.30.0-build32" /> <PackageVersion Include="Ryujinx.SDL2-CS" Version="2.26.3-build25" />
<PackageVersion Include="securifybv.ShellLink" Version="0.1.0" />
<PackageVersion Include="shaderc.net" Version="0.1.0" /> <PackageVersion Include="shaderc.net" Version="0.1.0" />
<PackageVersion Include="SharpZipLib" Version="1.4.2" /> <PackageVersion Include="SharpZipLib" Version="1.4.2" />
<PackageVersion Include="Silk.NET.Vulkan" Version="2.21.0" /> <PackageVersion Include="Silk.NET.Vulkan" Version="2.16.0" />
<PackageVersion Include="Silk.NET.Vulkan.Extensions.EXT" Version="2.21.0" /> <PackageVersion Include="Silk.NET.Vulkan.Extensions.EXT" Version="2.16.0" />
<PackageVersion Include="Silk.NET.Vulkan.Extensions.KHR" Version="2.21.0" /> <PackageVersion Include="Silk.NET.Vulkan.Extensions.KHR" Version="2.16.0" />
<PackageVersion Include="SkiaSharp" Version="2.88.7" /> <PackageVersion Include="SixLabors.ImageSharp" Version="1.0.4" />
<PackageVersion Include="SkiaSharp.NativeAssets.Linux" Version="2.88.7" /> <PackageVersion Include="SixLabors.ImageSharp.Drawing" Version="1.0.0-beta11" />
<PackageVersion Include="SPB" Version="0.0.4-build32" /> <PackageVersion Include="SPB" Version="0.0.4-build28" />
<PackageVersion Include="System.IO.Hashing" Version="8.0.0" /> <PackageVersion Include="System.Drawing.Common" Version="7.0.0" />
<PackageVersion Include="System.Management" Version="8.0.0" /> <PackageVersion Include="System.IdentityModel.Tokens.Jwt" Version="6.30.1" />
<PackageVersion Include="System.IO.Hashing" Version="7.0.0" />
<PackageVersion Include="System.Management" Version="7.0.1" />
<PackageVersion Include="UnicornEngine.Unicorn" Version="2.0.2-rc1-fb78016" /> <PackageVersion Include="UnicornEngine.Unicorn" Version="2.0.2-rc1-fb78016" />
<PackageVersion Include="XamlNameReferenceGenerator" Version="1.6.1" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View file

@ -1,21 +1,21 @@
<h1 align="center"> <h1 align="center">
<br> <br>
<a href="https://ryujinx.org/"><img src="https://raw.githubusercontent.com/Ryujinx/Ryujinx/master/distribution/misc/Logo.svg" alt="Ryujinx" width="150"></a> <a href="https://ryujinx.org/"><img src="https://i.imgur.com/WcCj6Rt.png" alt="Ryujinx" width="150"></a>
<br> <br>
<b>Ryujinx</b> <b>Ryujinx</b>
<br> <br>
<sub><sup><b>(REE-YOU-JINX)</b></sup></sub> <sub><sup><b>(REE-YOU-JINX)</b></sup></sub>
<br> <br>
</h1> </h1>
<p align="center"> <p align="center">
Ryujinx is an open-source Nintendo Switch emulator, created by gdkchan, written in C#. Ryujinx is an open-source Nintendo Switch emulator, created by gdkchan, written in C#.
This emulator aims at providing excellent accuracy and performance, a user-friendly interface and consistent builds. This emulator aims at providing excellent accuracy and performance, a user-friendly interface and consistent builds.
It was written from scratch and development on the project began in September 2017. It was written from scratch and development on the project began in September 2017. Ryujinx is available on Github under the <a href="https://github.com/Ryujinx/Ryujinx/blob/master/LICENSE.txt" target="_blank">MIT license</a>. <br />
Ryujinx is available on Github under the <a href="https://github.com/Ryujinx/Ryujinx/blob/master/LICENSE.txt" target="_blank">MIT license</a>.
<br />
</p>
</p>
<p align="center"> <p align="center">
<a href="https://github.com/Ryujinx/Ryujinx/actions/workflows/release.yml"> <a href="https://github.com/Ryujinx/Ryujinx/actions/workflows/release.yml">
<img src="https://github.com/Ryujinx/Ryujinx/actions/workflows/release.yml/badge.svg" <img src="https://github.com/Ryujinx/Ryujinx/actions/workflows/release.yml/badge.svg"
@ -34,111 +34,87 @@
<img src="https://raw.githubusercontent.com/Ryujinx/Ryujinx-Website/master/public/assets/images/shell.png"> <img src="https://raw.githubusercontent.com/Ryujinx/Ryujinx-Website/master/public/assets/images/shell.png">
</p> </p>
<h5 align="center">
</h5>
## Compatibility ## Compatibility
As of May 2024, Ryujinx has been tested on approximately 4,300 titles; As of April 2023, Ryujinx has been tested on approximately 4,050 titles; over 4,000 boot past menus and into gameplay, with roughly 3,400 of those being considered playable.
over 4,100 boot past menus and into gameplay, with roughly 3,550 of those being considered playable. You can check out the compatibility list [here](https://github.com/Ryujinx/Ryujinx-Games-List/issues). Anyone is free to submit a new game test or update an existing game test entry; simply follow the new issue template and testing guidelines, or post as a reply to the applicable game issue. Use the search function to see if a game has been tested already!
You can check out the compatibility list [here](https://github.com/Ryujinx/Ryujinx-Games-List/issues).
Anyone is free to submit a new game test or update an existing game test entry;
simply follow the new issue template and testing guidelines, or post as a reply to the applicable game issue.
Use the search function to see if a game has been tested already!
## Usage ## Usage
To run this emulator, your PC must be equipped with at least 8GiB of RAM; To run this emulator, your PC must be equipped with at least 8GiB of RAM; failing to meet this requirement may result in a poor gameplay experience or unexpected crashes.
failing to meet this requirement may result in a poor gameplay experience or unexpected crashes.
See our [Setup & Configuration Guide](https://github.com/Ryujinx/Ryujinx/wiki/Ryujinx-Setup-&-Configuration-Guide) on how to set up the emulator. See our [Setup & Configuration Guide](https://github.com/Ryujinx/Ryujinx/wiki/Ryujinx-Setup-&-Configuration-Guide) on how to set up the emulator.
For our Local Wireless (LDN) builds, see our [Multiplayer: Local Play/Local Wireless Guide For our Local Wireless and LAN builds, see our [Multiplayer: Local Play/Local Wireless Guide
](https://github.com/Ryujinx/Ryujinx/wiki/Multiplayer-(LDN-Local-Wireless)-Guide). ](https://github.com/Ryujinx/Ryujinx/wiki/Multiplayer-(LDN-Local-Wireless)-Guide).
Avalonia UI comes with translations for various languages. See [Crowdin](https://crwd.in/ryujinx) for more information. Avalonia UI comes with translations for various languages. See [Crowdin](https://crwd.in/ryujinx) for more information.
## Latest build ## Latest build
These builds are compiled automatically for each commit on the master branch. These builds are compiled automatically for each commit on the master branch. While we strive to ensure optimal stability and performance prior to pushing an update, our automated builds **may be unstable or completely broken.**
While we strive to ensure optimal stability and performance prior to pushing an update, our automated builds **may be unstable or completely broken**.
If you want to see details on updates to the emulator, you can visit our [Changelog](https://github.com/Ryujinx/Ryujinx/wiki/Changelog). If you want to see details on updates to the emulator, you can visit our [Changelog](https://github.com/Ryujinx/Ryujinx/wiki/Changelog).
The latest automatic build for Windows, macOS, and Linux can be found on the [Official Website](https://ryujinx.org/download). The latest automatic build for Windows, macOS, and Linux can be found on the [Official Website](https://ryujinx.org/download).
## Documentation
If you are planning to contribute or just want to learn more about this project please read through our [documentation](docs/README.md).
## Building ## Building
If you wish to build the emulator yourself, follow these steps: If you wish to build the emulator yourself, follow these steps:
### Step 1 ### Step 1
Install the X64 version of [.NET 7.0 (or higher) SDK](https://dotnet.microsoft.com/download/dotnet/7.0).
Install the [.NET 8.0 (or higher) SDK](https://dotnet.microsoft.com/download/dotnet/8.0).
Make sure your SDK version is higher or equal to the required version specified in [global.json](global.json).
### Step 2 ### Step 2
Either use `git clone https://github.com/Ryujinx/Ryujinx` on the command line to clone the repository or use Code --> Download zip button to get the files. Either use `git clone https://github.com/Ryujinx/Ryujinx` on the command line to clone the repository or use Code --> Download zip button to get the files.
### Step 3 ### Step 3
To build Ryujinx, open a command prompt inside the project directory. To build Ryujinx, open a command prompt inside the project directory. You can quickly access it on Windows by holding shift in File Explorer, then right clicking and selecting `Open command window here`. Then type the following command:
You can quickly access it on Windows by holding shift in File Explorer, then right clicking and selecting `Open command window here`. `dotnet build -c Release -o build`
Then type the following command: `dotnet build -c Release -o build`
the built files will be found in the newly created build directory. the built files will be found in the newly created build directory.
Ryujinx system files are stored in the `Ryujinx` folder. Ryujinx system files are stored in the `Ryujinx` folder. This folder is located in the user folder, which can be accessed by clicking `Open Ryujinx Folder` under the File menu in the GUI.
This folder is located in the user folder, which can be accessed by clicking `Open Ryujinx Folder` under the File menu in the GUI.
## Features ## Features
- **Audio** - **Audio**
Audio output is entirely supported, audio input (microphone) isn't supported. Audio output is entirely supported, audio input (microphone) isn't supported. We use C# wrappers for [OpenAL](https://openal-soft.org/), and [SDL2](https://www.libsdl.org/) & [libsoundio](http://libsound.io/) as fallbacks.
We use C# wrappers for [OpenAL](https://openal-soft.org/), and [SDL2](https://www.libsdl.org/) & [libsoundio](http://libsound.io/) as fallbacks.
- **CPU** - **CPU**
The CPU emulator, ARMeilleure, emulates an ARMv8 CPU and currently has support for most 64-bit ARMv8 and some of the ARMv7 (and older) instructions, including partial 32-bit support. The CPU emulator, ARMeilleure, emulates an ARMv8 CPU and currently has support for most 64-bit ARMv8 and some of the ARMv7 (and older) instructions, including partial 32-bit support. It translates the ARM code to a custom IR, performs a few optimizations, and turns that into x86 code.
It translates the ARM code to a custom IR, performs a few optimizations, and turns that into x86 code. There are three memory manager options available depending on the user's preference, leveraging both software-based (slower) and host-mapped modes (much faster). The fastest option (host, unchecked) is set by default.
There are three memory manager options available depending on the user's preference, leveraging both software-based (slower) and host-mapped modes (much faster). Ryujinx also features an optional Profiled Persistent Translation Cache, which essentially caches translated functions so that they do not need to be translated every time the game loads. The net result is a significant reduction in load times (the amount of time between launching a game and arriving at the title screen) for nearly every game. NOTE: this feature is enabled by default in the Options menu > System tab. You must launch the game at least twice to the title screen or beyond before performance improvements are unlocked on the third launch! These improvements are permanent and do not require any extra launches going forward.
The fastest option (host, unchecked) is set by default.
Ryujinx also features an optional Profiled Persistent Translation Cache, which essentially caches translated functions so that they do not need to be translated every time the game loads.
The net result is a significant reduction in load times (the amount of time between launching a game and arriving at the title screen) for nearly every game.
NOTE: This feature is enabled by default in the Options menu > System tab.
You must launch the game at least twice to the title screen or beyond before performance improvements are unlocked on the third launch!
These improvements are permanent and do not require any extra launches going forward.
- **GPU** - **GPU**
The GPU emulator emulates the Switch's Maxwell GPU using either the OpenGL (version 4.5 minimum), Vulkan, or Metal (via MoltenVK) APIs through a custom build of OpenTK or Silk.NET respectively. The GPU emulator emulates the Switch's Maxwell GPU using either the OpenGL (version 4.5 minimum), Vulkan, or Metal (via MoltenVK) APIs through a custom build of OpenTK or Silk.NET respectively. There are currently six graphics enhancements available to the end user in Ryujinx: Disk Shader Caching, Resolution Scaling, Anti-Aliasing, Scaling Filters (including FSR), Anisotropic Filtering and Aspect Ratio Adjustment. These enhancements can be adjusted or toggled as desired in the GUI.
There are currently six graphics enhancements available to the end user in Ryujinx: Disk Shader Caching, Resolution Scaling, Anti-Aliasing, Scaling Filters (including FSR), Anisotropic Filtering and Aspect Ratio Adjustment.
These enhancements can be adjusted or toggled as desired in the GUI.
- **Input** - **Input**
We currently have support for keyboard, mouse, touch input, JoyCon input support, and nearly all controllers. We currently have support for keyboard, mouse, touch input, JoyCon input support, and nearly all controllers. Motion controls are natively supported in most cases; for dual-JoyCon motion support, DS4Windows or BetterJoy are currently required.
Motion controls are natively supported in most cases; for dual-JoyCon motion support, DS4Windows or BetterJoy are currently required. In all scenarios, you can set up everything inside the input configuration menu.
In all scenarios, you can set up everything inside the input configuration menu.
- **DLC & Modifications** - **DLC & Modifications**
Ryujinx is able to manage add-on content/downloadable content through the GUI. Ryujinx is able to manage add-on content/downloadable content through the GUI. Mods (romfs, exefs, and runtime mods such as cheats) are also supported; the GUI contains a shortcut to open the respective mods folder for a particular game.
Mods (romfs, exefs, and runtime mods such as cheats) are also supported;
the GUI contains a shortcut to open the respective mods folder for a particular game.
- **Configuration** - **Configuration**
The emulator has settings for enabling or disabling some logging, remapping controllers, and more. The emulator has settings for enabling or disabling some logging, remapping controllers, and more. You can configure all of them through the graphical interface or manually through the config file, `Config.json`, found in the user folder which can be accessed by clicking `Open Ryujinx Folder` under the File menu in the GUI.
You can configure all of them through the graphical interface or manually through the config file, `Config.json`, found in the user folder which can be accessed by clicking `Open Ryujinx Folder` under the File menu in the GUI.
## Contact ## Contact
If you have contributions, suggestions, need emulator support or just want to get in touch with the team, join our [Discord server](https://discord.com/invite/Ryujinx). If you have contributions, suggestions, need emulator support or just want to get in touch with the team, join our [Discord server](https://discord.com/invite/Ryujinx). You may also review our [FAQ](https://github.com/Ryujinx/Ryujinx/wiki/Frequently-Asked-Questions).
You may also review our [FAQ](https://github.com/Ryujinx/Ryujinx/wiki/Frequently-Asked-Questions).
## Donations ## Donations
@ -158,13 +134,10 @@ All funds received through Patreon are considered a donation to support the proj
## License ## License
This software is licensed under the terms of the [MIT license](LICENSE.txt). This software is licensed under the terms of the <a href="https://github.com/Ryujinx/Ryujinx/blob/master/LICENSE.txt" target="_blank">MIT license.</a></i><br />
This project makes use of code authored by the libvpx project, licensed under BSD and the ffmpeg project, licensed under LGPLv3. This project makes use of code authored by the libvpx project, licensed under BSD and the ffmpeg project, licensed under LGPLv3.
See [LICENSE.txt](LICENSE.txt) and [THIRDPARTY.md](distribution/legal/THIRDPARTY.md) for more details. See [LICENSE.txt](LICENSE.txt) and [THIRDPARTY.md](distribution/legal/THIRDPARTY.md) for more details.
## Credits ## Credits
- [LibHac](https://github.com/Thealexbarney/LibHac) is used for our file-system. - [LibHac](https://github.com/Thealexbarney/LibHac) is used for our file-system.
- [AmiiboAPI](https://www.amiiboapi.com) is used in our Amiibo emulation. - [AmiiboAPI](https://www.amiiboapi.com) is used in our Amiibo emulation.
- [ldn_mitm](https://github.com/spacemeowx2/ldn_mitm) is used for one of our available multiplayer modes.
- [ShellLink](https://github.com/securifybv/ShellLink) is used for Windows shortcut generation.

View file

@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17 # Visual Studio Version 17
VisualStudioVersion = 17.1.32228.430 VisualStudioVersion = 17.1.32228.430
MinimumVisualStudioVersion = 10.0.40219.1 MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Gtk3", "src\Ryujinx.Gtk3\Ryujinx.Gtk3.csproj", "{074045D4-3ED2-4711-9169-E385F2BFB5A0}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx", "src\Ryujinx\Ryujinx.csproj", "{074045D4-3ED2-4711-9169-E385F2BFB5A0}"
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Tests", "src\Ryujinx.Tests\Ryujinx.Tests.csproj", "{EBB55AEA-C7D7-4DEB-BF96-FA1789E225E9}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Tests", "src\Ryujinx.Tests\Ryujinx.Tests.csproj", "{EBB55AEA-C7D7-4DEB-BF96-FA1789E225E9}"
EndProject EndProject
@ -69,9 +69,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Headless.SDL2", "sr
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Graphics.Nvdec.FFmpeg", "src\Ryujinx.Graphics.Nvdec.FFmpeg\Ryujinx.Graphics.Nvdec.FFmpeg.csproj", "{BEE1C184-C9A4-410B-8DFC-FB74D5C93AEB}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Graphics.Nvdec.FFmpeg", "src\Ryujinx.Graphics.Nvdec.FFmpeg\Ryujinx.Graphics.Nvdec.FFmpeg.csproj", "{BEE1C184-C9A4-410B-8DFC-FB74D5C93AEB}"
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx", "src\Ryujinx\Ryujinx.csproj", "{7C1B2721-13DA-4B62-B046-C626605ECCE6}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Ava", "src\Ryujinx.Ava\Ryujinx.Ava.csproj", "{7C1B2721-13DA-4B62-B046-C626605ECCE6}"
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.UI.Common", "src\Ryujinx.UI.Common\Ryujinx.UI.Common.csproj", "{BA161CA0-CD65-4E6E-B644-51C8D1E542DC}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Ui.Common", "src\Ryujinx.Ui.Common\Ryujinx.Ui.Common.csproj", "{BA161CA0-CD65-4E6E-B644-51C8D1E542DC}"
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Horizon.Generators", "src\Ryujinx.Horizon.Generators\Ryujinx.Horizon.Generators.csproj", "{6AE2A5E8-4C5A-48B9-997B-E1455C0355C6}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Horizon.Generators", "src\Ryujinx.Horizon.Generators\Ryujinx.Horizon.Generators.csproj", "{6AE2A5E8-4C5A-48B9-997B-E1455C0355C6}"
EndProject EndProject
@ -79,7 +79,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Graphics.Vulkan", "
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Spv.Generator", "src\Spv.Generator\Spv.Generator.csproj", "{2BCB3D7A-38C0-4FE7-8FDA-374C6AD56D0E}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Spv.Generator", "src\Spv.Generator\Spv.Generator.csproj", "{2BCB3D7A-38C0-4FE7-8FDA-374C6AD56D0E}"
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.UI.LocaleGenerator", "src\Ryujinx.UI.LocaleGenerator\Ryujinx.UI.LocaleGenerator.csproj", "{77D01AD9-2C98-478E-AE1D-8F7100738FB4}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Ui.LocaleGenerator", "src\Ryujinx.Ui.LocaleGenerator\Ryujinx.Ui.LocaleGenerator.csproj", "{77D01AD9-2C98-478E-AE1D-8F7100738FB4}"
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Horizon.Common", "src\Ryujinx.Horizon.Common\Ryujinx.Horizon.Common.csproj", "{77F96ECE-4952-42DB-A528-DED25572A573}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Horizon.Common", "src\Ryujinx.Horizon.Common\Ryujinx.Horizon.Common.csproj", "{77F96ECE-4952-42DB-A528-DED25572A573}"
EndProject EndProject
@ -87,8 +87,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Horizon", "src\Ryuj
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Horizon.Kernel.Generators", "src\Ryujinx.Horizon.Kernel.Generators\Ryujinx.Horizon.Kernel.Generators.csproj", "{7F55A45D-4E1D-4A36-ADD3-87F29A285AA2}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Horizon.Kernel.Generators", "src\Ryujinx.Horizon.Kernel.Generators\Ryujinx.Horizon.Kernel.Generators.csproj", "{7F55A45D-4E1D-4A36-ADD3-87F29A285AA2}"
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.HLE.Generators", "src\Ryujinx.HLE.Generators\Ryujinx.HLE.Generators.csproj", "{B575BCDE-2FD8-4A5D-8756-31CDD7FE81F0}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU Debug|Any CPU = Debug|Any CPU
@ -251,10 +249,6 @@ Global
{7F55A45D-4E1D-4A36-ADD3-87F29A285AA2}.Debug|Any CPU.Build.0 = Debug|Any CPU {7F55A45D-4E1D-4A36-ADD3-87F29A285AA2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7F55A45D-4E1D-4A36-ADD3-87F29A285AA2}.Release|Any CPU.ActiveCfg = Release|Any CPU {7F55A45D-4E1D-4A36-ADD3-87F29A285AA2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7F55A45D-4E1D-4A36-ADD3-87F29A285AA2}.Release|Any CPU.Build.0 = Release|Any CPU {7F55A45D-4E1D-4A36-ADD3-87F29A285AA2}.Release|Any CPU.Build.0 = Release|Any CPU
{B575BCDE-2FD8-4A5D-8756-31CDD7FE81F0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B575BCDE-2FD8-4A5D-8756-31CDD7FE81F0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B575BCDE-2FD8-4A5D-8756-31CDD7FE81F0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B575BCDE-2FD8-4A5D-8756-31CDD7FE81F0}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE

View file

@ -4,8 +4,6 @@
<s:String x:Key="/Default/CodeStyle/CSharpVarKeywordUsage/ForOtherTypes/@EntryValue">UseExplicitType</s:String> <s:String x:Key="/Default/CodeStyle/CSharpVarKeywordUsage/ForOtherTypes/@EntryValue">UseExplicitType</s:String>
<s:String x:Key="/Default/CodeStyle/CSharpVarKeywordUsage/ForSimpleTypes/@EntryValue">UseExplicitType</s:String> <s:String x:Key="/Default/CodeStyle/CSharpVarKeywordUsage/ForSimpleTypes/@EntryValue">UseExplicitType</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=TypesAndNamespaces/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb"&gt;&lt;ExtraRule Prefix="I" Suffix="" Style="AaBb" /&gt;&lt;/Policy&gt;</s:String> <s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=TypesAndNamespaces/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb"&gt;&lt;ExtraRule Prefix="I" Suffix="" Style="AaBb" /&gt;&lt;/Policy&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/UserRules/=a0b4bc4d_002Dd13b_002D4a37_002Db37e_002Dc9c6864e4302/@EntryIndexedValue">&lt;Policy&gt;&lt;Descriptor Staticness="Any" AccessRightKinds="Any" Description="Types and namespaces"&gt;&lt;ElementKinds&gt;&lt;Kind Name="NAMESPACE" /&gt;&lt;Kind Name="CLASS" /&gt;&lt;Kind Name="STRUCT" /&gt;&lt;Kind Name="ENUM" /&gt;&lt;Kind Name="DELEGATE" /&gt;&lt;/ElementKinds&gt;&lt;/Descriptor&gt;&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb"&gt;&lt;ExtraRule Prefix="I" Suffix="" Style="AaBb" /&gt;&lt;/Policy&gt;&lt;/Policy&gt;</s:String>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EPredefinedNamingRulesToUserRulesUpgrade/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=ASET/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=ASET/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Astc/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=Astc/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Luma/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=Luma/@EntryIndexedValue">True</s:Boolean>

View file

@ -682,32 +682,3 @@
END OF TERMS AND CONDITIONS END OF TERMS AND CONDITIONS
``` ```
</details> </details>
# ShellLink (MIT)
<details>
<summary>See License</summary>
```
MIT License
Copyright (c) 2017 Yorick Koster, Securify B.V.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
```
</details>

View file

@ -3,7 +3,7 @@ Version=1.0
Name=Ryujinx Name=Ryujinx
Type=Application Type=Application
Icon=Ryujinx Icon=Ryujinx
Exec=Ryujinx.sh %f Exec=env DOTNET_EnableAlternateStackCheck=1 Ryujinx %f
Comment=A Nintendo Switch Emulator Comment=A Nintendo Switch Emulator
GenericName=Nintendo Switch Emulator GenericName=Nintendo Switch Emulator
Terminal=false Terminal=false

15
distribution/linux/Ryujinx.sh Executable file → Normal file
View file

@ -1,23 +1,20 @@
#!/bin/sh #!/bin/sh
SCRIPT_DIR=$(dirname "$(realpath "$0")") SCRIPT_DIR=$(dirname "$(realpath "$0")")
RYUJINX_BIN="Ryujinx"
if [ -f "$SCRIPT_DIR/Ryujinx.Ava" ]; then
RYUJINX_BIN="Ryujinx.Ava"
fi
if [ -f "$SCRIPT_DIR/Ryujinx.Headless.SDL2" ]; then if [ -f "$SCRIPT_DIR/Ryujinx.Headless.SDL2" ]; then
RYUJINX_BIN="Ryujinx.Headless.SDL2" RYUJINX_BIN="Ryujinx.Headless.SDL2"
fi fi
if [ -f "$SCRIPT_DIR/Ryujinx" ]; then
RYUJINX_BIN="Ryujinx"
fi
if [ -z "$RYUJINX_BIN" ]; then
exit 1
fi
COMMAND="env DOTNET_EnableAlternateStackCheck=1" COMMAND="env DOTNET_EnableAlternateStackCheck=1"
if command -v gamemoderun > /dev/null 2>&1; then if command -v gamemoderun > /dev/null 2>&1; then
COMMAND="$COMMAND gamemoderun" COMMAND="$COMMAND gamemoderun"
fi fi
exec $COMMAND "$SCRIPT_DIR/$RYUJINX_BIN" "$@" $COMMAND "$SCRIPT_DIR/$RYUJINX_BIN" "$@"

View file

@ -1,13 +0,0 @@
[Desktop Entry]
Version=1.0
Name={0}
Type=Application
Icon={1}
Exec={2} %f
Comment=Nintendo Switch application
GenericName=Nintendo Switch Emulator
Terminal=false
Categories=Game;Emulator;
Keywords=Switch;Nintendo;Emulator;
StartupWMClass=Ryujinx
PrefersNonDefaultGPU=true

View file

@ -10,25 +10,14 @@
<string>Ryujinx</string> <string>Ryujinx</string>
<key>CFBundleIconFile</key> <key>CFBundleIconFile</key>
<string>Ryujinx.icns</string> <string>Ryujinx.icns</string>
<key>CFBundleDocumentTypes</key> <key>CFBundleTypeExtensions</key>
<array> <array>
<dict> <string>nca</string>
<key>CFBundleTypeExtensions</key> <string>nro</string>
<array> <string>nso</string>
<string>nca</string> <string>nsp</string>
<string>nro</string> <string>xci</string>
<string>nso</string> </array>
<string>nsp</string>
<string>xci</string>
</array>
<key>CFBundleTypeName</key>
<string>Nintendo Switch File</string>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
<key>LSHandlerRank</key>
<string>Default</string>
</dict>
</array>
<key>CFBundleIdentifier</key> <key>CFBundleIdentifier</key>
<string>org.ryujinx.Ryujinx</string> <string>org.ryujinx.Ryujinx</string>
<key>CFBundleInfoDictionaryVersion</key> <key>CFBundleInfoDictionaryVersion</key>
@ -50,120 +39,10 @@
<key>CSResourcesFileMapped</key> <key>CSResourcesFileMapped</key>
<true/> <true/>
<key>NSHumanReadableCopyright</key> <key>NSHumanReadableCopyright</key>
<string>Copyright © 2018 - 2023 Ryujinx Team and Contributors.</string> <string>Copyright © 2018 - 2022 Ryujinx Team and Contributors.</string>
<key>LSApplicationCategoryType</key> <key>LSApplicationCategoryType</key>
<string>public.app-category.games</string> <string>public.app-category.games</string>
<key>LSMinimumSystemVersion</key> <key>LSMinimumSystemVersion</key>
<string>12.0</string> <string>11.0</string>
<key>UTExportedTypeDeclarations</key>
<array>
<dict>
<key>UTTypeDescription</key>
<string>Extensible Application Markup Language</string>
<key>UTTypeConformsTo</key>
<array>
<string>public.xml</string>
</array>
<key>UTTypeIdentifier</key>
<string>com.ryujinx.xaml</string>
<key>UTTypeTagSpecification</key>
<dict>
<key>public.filename-extension</key>
<array>
<string>xaml</string>
</array>
</dict>
</dict>
<dict>
<key>UTTypeDescription</key>
<string>Nintendo Submission Package</string>
<key>UTTypeConformsTo</key>
<array>
<string>public.data</string>
</array>
<key>UTTypeIdentifier</key>
<string>com.ryujinx.nsp</string>
<key>UTTypeTagSpecification</key>
<dict>
<key>public.filename-extension</key>
<array>
<string>nsp</string>
</array>
</dict>
</dict>
<dict>
<key>UTTypeDescription</key>
<string>Nintendo Switch Cartridge</string>
<key>UTTypeConformsTo</key>
<array>
<string>public.data</string>
</array>
<key>UTTypeIdentifier</key>
<string>com.ryujinx.xci</string>
<key>UTTypeTagSpecification</key>
<dict>
<key>public.filename-extension</key>
<array>
<string>xci</string>
</array>
</dict>
</dict>
<dict>
<key>UTTypeDescription</key>
<string>Nintendo Content Archive</string>
<key>UTTypeConformsTo</key>
<array>
<string>public.data</string>
</array>
<key>UTTypeIdentifier</key>
<string>com.ryujinx.nca</string>
<key>UTTypeTagSpecification</key>
<dict>
<key>public.filename-extension</key>
<array>
<string>nca</string>
</array>
</dict>
</dict>
<dict>
<key>UTTypeDescription</key>
<string>Nintendo Relocatable Object</string>
<key>UTTypeConformsTo</key>
<array>
<string>public.data</string>
</array>
<key>UTTypeIdentifier</key>
<string>com.ryujinx.nro</string>
<key>UTTypeTagSpecification</key>
<dict>
<key>public.filename-extension</key>
<array>
<string>nro</string>
</array>
</dict>
</dict>
<dict>
<key>UTTypeDescription</key>
<string>Nintendo Shared Object</string>
<key>UTTypeConformsTo</key>
<array>
<string>public.data</string>
</array>
<key>UTTypeIdentifier</key>
<string>com.ryujinx.nso</string>
<key>UTTypeTagSpecification</key>
<dict>
<key>public.filename-extension</key>
<array>
<string>nso</string>
</array>
</dict>
</dict>
</array>
<key>LSEnvironment</key>
<dict>
<key>DOTNET_DefaultStackSize</key>
<string>200000</string>
</dict>
</dict> </dict>
</plist> </plist>

View file

@ -14,8 +14,8 @@ mkdir "$APP_BUNDLE_DIRECTORY/Contents/Frameworks"
mkdir "$APP_BUNDLE_DIRECTORY/Contents/MacOS" mkdir "$APP_BUNDLE_DIRECTORY/Contents/MacOS"
mkdir "$APP_BUNDLE_DIRECTORY/Contents/Resources" mkdir "$APP_BUNDLE_DIRECTORY/Contents/Resources"
# Copy executable and nsure executable can be executed # Copy executables first
cp "$PUBLISH_DIRECTORY/Ryujinx" "$APP_BUNDLE_DIRECTORY/Contents/MacOS/Ryujinx" cp "$PUBLISH_DIRECTORY/Ryujinx.Ava" "$APP_BUNDLE_DIRECTORY/Contents/MacOS/Ryujinx"
chmod u+x "$APP_BUNDLE_DIRECTORY/Contents/MacOS/Ryujinx" chmod u+x "$APP_BUNDLE_DIRECTORY/Contents/MacOS/Ryujinx"
# Then all libraries # Then all libraries

View file

@ -22,9 +22,9 @@ EXTRA_ARGS=$8
if [ "$VERSION" == "1.1.0" ]; if [ "$VERSION" == "1.1.0" ];
then then
RELEASE_TAR_FILE_NAME=ryujinx-$CONFIGURATION-$VERSION+$SOURCE_REVISION_ID-macos_universal.app.tar RELEASE_TAR_FILE_NAME=test-ava-ryujinx-$CONFIGURATION-$VERSION+$SOURCE_REVISION_ID-macos_universal.app.tar
else else
RELEASE_TAR_FILE_NAME=ryujinx-$VERSION-macos_universal.app.tar RELEASE_TAR_FILE_NAME=test-ava-ryujinx-$VERSION-macos_universal.app.tar
fi fi
ARM64_APP_BUNDLE="$TEMP_DIRECTORY/output_arm64/Ryujinx.app" ARM64_APP_BUNDLE="$TEMP_DIRECTORY/output_arm64/Ryujinx.app"
@ -35,12 +35,12 @@ EXECUTABLE_SUB_PATH=Contents/MacOS/Ryujinx
rm -rf "$TEMP_DIRECTORY" rm -rf "$TEMP_DIRECTORY"
mkdir -p "$TEMP_DIRECTORY" mkdir -p "$TEMP_DIRECTORY"
DOTNET_COMMON_ARGS=(-p:DebugType=embedded -p:Version="$VERSION" -p:SourceRevisionId="$SOURCE_REVISION_ID" --self-contained true $EXTRA_ARGS) DOTNET_COMMON_ARGS="-p:DebugType=embedded -p:Version=$VERSION -p:SourceRevisionId=$SOURCE_REVISION_ID --self-contained true $EXTRA_ARGS"
dotnet restore dotnet restore
dotnet build -c "$CONFIGURATION" src/Ryujinx dotnet build -c $CONFIGURATION src/Ryujinx.Ava
dotnet publish -c "$CONFIGURATION" -r osx-arm64 -o "$TEMP_DIRECTORY/publish_arm64" "${DOTNET_COMMON_ARGS[@]}" src/Ryujinx dotnet publish -c $CONFIGURATION -r osx-arm64 -o "$TEMP_DIRECTORY/publish_arm64" $DOTNET_COMMON_ARGS src/Ryujinx.Ava
dotnet publish -c "$CONFIGURATION" -r osx-x64 -o "$TEMP_DIRECTORY/publish_x64" "${DOTNET_COMMON_ARGS[@]}" src/Ryujinx dotnet publish -c $CONFIGURATION -r osx-x64 -o "$TEMP_DIRECTORY/publish_x64" $DOTNET_COMMON_ARGS src/Ryujinx.Ava
# Get rid of the support library for ARMeilleure for x64 (that's only for arm64) # Get rid of the support library for ARMeilleure for x64 (that's only for arm64)
rm -rf "$TEMP_DIRECTORY/publish_x64/libarmeilleure-jitsupport.dylib" rm -rf "$TEMP_DIRECTORY/publish_x64/libarmeilleure-jitsupport.dylib"
@ -104,17 +104,10 @@ fi
echo "Creating archive" echo "Creating archive"
pushd "$OUTPUT_DIRECTORY" pushd "$OUTPUT_DIRECTORY"
tar --exclude "Ryujinx.app/Contents/MacOS/Ryujinx" -cvf "$RELEASE_TAR_FILE_NAME" Ryujinx.app 1> /dev/null tar --exclude "Ryujinx.app/Contents/MacOS/Ryujinx" -cvf $RELEASE_TAR_FILE_NAME Ryujinx.app 1> /dev/null
python3 "$BASE_DIR/distribution/misc/add_tar_exec.py" "$RELEASE_TAR_FILE_NAME" "Ryujinx.app/Contents/MacOS/Ryujinx" "Ryujinx.app/Contents/MacOS/Ryujinx" python3 "$BASE_DIR/distribution/misc/add_tar_exec.py" $RELEASE_TAR_FILE_NAME "Ryujinx.app/Contents/MacOS/Ryujinx" "Ryujinx.app/Contents/MacOS/Ryujinx"
gzip -9 < "$RELEASE_TAR_FILE_NAME" > "$RELEASE_TAR_FILE_NAME.gz" gzip -9 < $RELEASE_TAR_FILE_NAME > $RELEASE_TAR_FILE_NAME.gz
rm "$RELEASE_TAR_FILE_NAME" rm $RELEASE_TAR_FILE_NAME
# Create legacy update package for Avalonia to not left behind old testers.
if [ "$VERSION" != "1.1.0" ];
then
cp $RELEASE_TAR_FILE_NAME.gz test-ava-ryujinx-$VERSION-macos_universal.app.tar.gz
fi
popd popd
echo "Done" echo "Done"

View file

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

View file

@ -1,8 +0,0 @@
#!/bin/sh
launch_arch="$(uname -m)"
if [ "$(sysctl -in sysctl.proc_translated)" = "1" ]
then
launch_arch="arm64"
fi
arch -$launch_arch {0} {1}

View file

@ -1,35 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleExecutable</key>
<string>{0}</string>
<key>CFBundleGetInfoString</key>
<string>{1}</string>
<key>CFBundleIconFile</key>
<string>{2}</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleVersion</key>
<string>1.0</string>
<key>NSHighResolutionCapable</key>
<true/>
<key>CSResourcesFileMapped</key>
<true/>
<key>NSHumanReadableCopyright</key>
<string>Copyright © 2018 - 2023 Ryujinx Team and Contributors.</string>
<key>LSApplicationCategoryType</key>
<string>public.app-category.games</string>
<key>LSMinimumSystemVersion</key>
<string>11.0</string>
<key>UIPrerenderedIcon</key>
<true/>
<key>LSEnvironment</key>
<dict>
<key>DOTNET_DefaultStackSize</key>
<string>200000</string>
</dict>
</dict>
</plist>

View file

@ -5,7 +5,7 @@ set -e
INSTALL_DIRECTORY=$1 INSTALL_DIRECTORY=$1
NEW_APP_DIRECTORY=$2 NEW_APP_DIRECTORY=$2
APP_PID=$3 APP_PID=$3
APP_ARGUMENTS=("${@:4}") APP_ARGUMENTS="${@:4}"
error_handler() { error_handler() {
local lineno="$1" local lineno="$1"
@ -33,7 +33,7 @@ trap 'error_handler ${LINENO}' ERR
attempt=0 attempt=0
while true; do while true; do
if lsof -p "$APP_PID" +r 1 &>/dev/null || ps -p "$APP_PID" &>/dev/null; then if lsof -p $APP_PID +r 1 &>/dev/null || ps -p "$APP_PID" &>/dev/null; then
if [ "$attempt" -eq 4 ]; then if [ "$attempt" -eq 4 ]; then
exit 1 exit 1
fi fi
@ -53,5 +53,5 @@ mv "$NEW_APP_DIRECTORY" "$INSTALL_DIRECTORY"
if [ "$#" -le 3 ]; then if [ "$#" -le 3 ]; then
open -a "$INSTALL_DIRECTORY" open -a "$INSTALL_DIRECTORY"
else else
open -a "$INSTALL_DIRECTORY" --args "${APP_ARGUMENTS[@]}" open -a "$INSTALL_DIRECTORY" --args "$APP_ARGUMENTS"
fi fi

View file

@ -1,35 +0,0 @@
# Documents Index
This repo includes several documents that explain both high-level and low-level concepts about Ryujinx and its functions. These are very useful for contributors, to get context that can be very difficult to acquire from just reading code.
Intro to Ryujinx
==================
Ryujinx is an open-source Nintendo Switch emulator, created by gdkchan, written in C#.
* The CPU emulator, ARMeilleure, emulates an ARMv8 CPU and currently has support for most 64-bit ARMv8 and some of the ARMv7 (and older) instructions.
* The GPU emulator emulates the Switch's Maxwell GPU using either the OpenGL (version 4.5 minimum), Vulkan, or Metal (via MoltenVK) APIs through a custom build of OpenTK or Silk.NET respectively.
* Audio output is entirely supported via C# wrappers for SDL2, with OpenAL & libsoundio as fallbacks.
Getting Started
===============
- [Installing the .NET SDK](https://dotnet.microsoft.com/download)
- [Official .NET Docs](https://docs.microsoft.com/dotnet/core/)
Contributing (Building, testing, benchmarking, profiling, etc.)
===============
If you want to contribute a code change to this repo, start here.
- [Contributor Guide](../CONTRIBUTING.md)
Coding Guidelines
=================
- [C# coding style](coding-guidelines/coding-style.md)
- [Service Implementation Guidelines - WIP](https://gist.github.com/gdkchan/84ba88cd50efbe58d1babfaa7cd7c455)
Project Docs
=================
To be added. Many project files will contain basic XML docs for key functions and classes in the meantime.

View file

@ -1,116 +0,0 @@
# C# Coding Style
The general rule we follow is "use Visual Studio defaults".
Using an IDE that supports the `.editorconfig` standard will make this much simpler.
1. We use [Allman style](http://en.wikipedia.org/wiki/Indent_style#Allman_style) braces, where each brace begins on a new line. A single line statement block can go without braces but the block must be properly indented on its own line and must not be nested in other statement blocks that use braces (See rule 18 for more details). One exception is that a `using` statement is permitted to be nested within another `using` statement by starting on the following line at the same indentation level, even if the nested `using` contains a controlled block.
2. We use four spaces of indentation (no tabs).
3. We use `_camelCase` for internal and private fields and use `readonly` where possible. Prefix internal and private instance fields with `_`, static fields with `s_` and thread static fields with `t_`. When used on static fields, `readonly` should come after `static` (e.g. `static readonly` not `readonly static`). Public fields should be used sparingly and should use PascalCasing with no prefix when used.
4. We avoid `this.` unless absolutely necessary.
5. We always specify the visibility, even if it's the default (e.g.
`private string _foo` not `string _foo`). Visibility should be the first modifier (e.g.
`public abstract` not `abstract public`).
6. Namespace imports should be specified at the top of the file, *outside* of `namespace` declarations.
7. Avoid more than one empty line at any time. For example, do not have two
blank lines between members of a type.
8. Avoid spurious free spaces.
For example avoid `if (someVar == 0)...`, where the dots mark the spurious free spaces.
Consider enabling "View White Space (Ctrl+R, Ctrl+W)" or "Edit -> Advanced -> View White Space" if using Visual Studio to aid detection.
9. If a file happens to differ in style from these guidelines (e.g. private members are named `m_member`
rather than `_member`), the existing style in that file takes precedence.
10. We only use `var` when the type is explicitly named on the right-hand side, typically due to either `new` or an explicit cast, e.g. `var stream = new FileStream(...)` not `var stream = OpenStandardInput()`.
- Similarly, target-typed `new()` can only be used when the type is explicitly named on the left-hand side, in a variable definition statement or a field definition statement. e.g. `FileStream stream = new(...);`, but not `stream = new(...);` (where the type was specified on a previous line).
11. We use language keywords instead of BCL types (e.g. `int, string, float` instead of `Int32, String, Single`, etc) for both type references as well as method calls (e.g. `int.Parse` instead of `Int32.Parse`). See issue [#13976](https://github.com/dotnet/runtime/issues/13976) for examples.
12. We use PascalCasing to name all our constant local variables and fields. The only exception is for interop code where the constant value should exactly match the name and value of the code you are calling via interop.
13. We use PascalCasing for all method names, including local functions.
14. We use ```nameof(...)``` instead of ```"..."``` whenever possible and relevant.
15. Fields should be specified at the top within type declarations.
16. When including non-ASCII characters in the source code use Unicode escape sequences (\uXXXX) instead of literal characters. Literal non-ASCII characters occasionally get garbled by a tool or editor.
17. When using labels (for goto), indent the label one less than the current indentation.
18. When using a single-statement if, we follow these conventions:
- Never use single-line form (for example: `if (source == null) throw new ArgumentNullException("source");`)
- Using braces is always accepted, and required if any block of an `if`/`else if`/.../`else` compound statement uses braces or if a single statement body spans multiple lines.
- Braces may be omitted only if the body of *every* block associated with an `if`/`else if`/.../`else` compound statement is placed on a single line.
19. Make all internal and private types static or sealed unless derivation from them is required. As with any implementation detail, they can be changed if/when derivation is required in the future.
20. XML docs should be used when writing interfaces or when a class/method is deemed sufficient in scope or complexity.
21. So-called [Magic Numbers](https://en.wikipedia.org/wiki/Magic_number_(programming)) should be defined as named constants before use (for example `for (int i = 56; i < 68; i++)` could read `for (int i = _currentAge; i < _retireAge; i++)`).
This may be ignored for trivial or syntactically common statements.
An [EditorConfig](https://editorconfig.org "EditorConfig homepage") file (`.editorconfig`) has been provided at the root of the runtime repository, enabling C# auto-formatting conforming to the above guidelines.
### Example File:
``ShaderCache.cs:``
```C#
using Ryujinx.Common.Configuration;
using Ryujinx.Common.Logging;
using Ryujinx.Graphics.GAL;
using Ryujinx.Graphics.Gpu.Engine.Threed;
using Ryujinx.Graphics.Gpu.Engine.Types;
using Ryujinx.Graphics.Gpu.Image;
using Ryujinx.Graphics.Gpu.Memory;
using Ryujinx.Graphics.Gpu.Shader.DiskCache;
using Ryujinx.Graphics.Shader;
using Ryujinx.Graphics.Shader.Translation;
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading;
namespace Ryujinx.Graphics.Gpu.Shader
{
/// <summary>
/// Memory cache of shader code.
/// </summary>
class ShaderCache : IDisposable
{
/// <summary>
/// Default flags used on the shader translation process.
/// </summary>
public const TranslationFlags DefaultFlags = TranslationFlags.DebugMode;
private readonly struct TranslatedShader
{
public readonly CachedShaderStage Shader;
public readonly ShaderProgram Program;
public TranslatedShader(CachedShaderStage shader, ShaderProgram program)
{
Shader = shader;
Program = program;
}
}
...
/// <summary>
/// Processes the queue of shaders that must save their binaries to the disk cache.
/// </summary>
public void ProcessShaderCacheQueue()
{
// Check to see if the binaries for previously compiled shaders are ready, and save them out.
while (_programsToSaveQueue.TryPeek(out ProgramToSave programToSave))
{
ProgramLinkStatus result = programToSave.HostProgram.CheckProgramLink(false);
if (result != ProgramLinkStatus.Incomplete)
{
if (result == ProgramLinkStatus.Success)
{
_cacheWriter.AddShader(programToSave.CachedProgram, programToSave.BinaryCode ?? programToSave.HostProgram.GetBinary());
}
_programsToSaveQueue.Dequeue();
}
else
{
break;
}
}
}
}
}
```
For other languages, our current best guidance is consistency. When editing files, keep new code and changes consistent with the style in the files. For new files, it should conform to the style for that component. If there is a completely new component, anything that is reasonably broadly accepted is fine.

View file

@ -1,56 +0,0 @@
# Pull Request Guide
## Contributing Rules
All contributions to Ryujinx/Ryujinx repository are made via pull requests (PRs) rather than through direct commits. The pull requests are reviewed and merged by the maintainers after a review and at least two approvals from the core development team.
To merge pull requests, you must have write permissions in the repository.
## Quick Code Review Rules
* Do not mix unrelated changes in one pull request. For example, a code style change should never be mixed with a bug fix.
* All changes should follow the existing code style. You can read more about our code style at [docs/coding-guidelines](../coding-guidelines/coding-style.md).
* Adding external dependencies is to be avoided unless not doing so would introduce _significant_ complexity. Any dependency addition should be justified and discussed before merge.
* Use Draft pull requests for changes you are still working on but want early CI loop feedback. When you think your changes are ready for review, [change the status](https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/changing-the-stage-of-a-pull-request) of your pull request.
* Rebase your changes when required or directly requested. Changes should always be commited on top of the upstream branch, not the other way around.
* If you are asked to make changes during the review process do them as a new commit.
* Only resolve GitHub conversations with reviewers once they have been addressed with a commit, or via a mutual agreement.
## Pull Request Ownership
Every pull request will have automatically have labels and reviewers assigned. The label not only indicates the code segment which the change touches but also the area reviewers to be assigned.
If during the code review process a merge conflict occurs, the PR author is responsible for its resolution. Help will be provided if necessary although GitHub makes this easier by allowing simple conflict resolution using the [conflict-editor](https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/resolving-a-merge-conflict-on-github).
## Pull Request Builds
When submitting a PR to the `Ryujinx/Ryujinx` repository, various builds will run validating many areas to ensure we keep developer productivity and product quality high. These various workflows can be tracked in the [Actions](https://github.com/Ryujinx/Ryujinx/actions) tab of the repository. If the job continues to completion, the build artifacts will be uploaded and posted as a comment in the PR discussion.
## Review Turnaround Times
Ryujinx is a project that is maintained by volunteers on a completely free-time basis. As such we cannot guarantee any particular timeframe for pull request review and approval. Weeks to months are common for larger (>500 line) PRs but there are some additional best practises to avoid review purgatory.
* Make the reviewers life easier wherever possible. Make use of descriptive commit names, code comments and XML docs where applicable.
* If there is disagreement on feedback then always lean on the side of the development team and community over any personal opinion.
* We're human. We miss things. We forget things. If there has been radio silence on your changes for a substantial period of time then do not hesitate to reach out directly either with something simple like "bump" on GitHub or a directly on Discord.
To re-iterate, make the review as easy for us as possible, respond promptly and be comfortable to interact directly with us for anything else.
## Merging Pull Requests
Anyone with write access can merge a pull request manually when the following conditions have been met:
* The PR has been approved by two reviewers and any other objections are addressed.
* You can request follow up reviews from the original reviewers if they requested changes.
* The PR successfully builds and passes all tests in the Continuous Integration (CI) system. In case of failures, refer to the [Actions](https://github.com/Ryujinx/Ryujinx/actions) tab of your PR.
Typically, PRs are merged as one commit (squash merges). It creates a simpler history than a Merge Commit. "Special circumstances" are rare, and typically mean that there are a series of cleanly separated changes that will be too hard to understand if squashed together, or for some reason we want to preserve the ability to dissect them.
## Blocking Pull Request Merging
If for whatever reason you would like to move your pull request back to an in-progress status to avoid merging it in the current form, you can turn the PR into a draft PR by selecting the option under the reviewers section. Alternatively, you can do that by adding [WIP] prefix to the pull request title.
## Old Pull Request Policy
From time to time we will review older PRs and check them for relevance. If we find the PR is inactive or no longer applies, we will close it. As the PR owner, you can simply reopen it if you feel your closed PR needs our attention.

View file

@ -1,6 +1,6 @@
{ {
"sdk": { "sdk": {
"version": "8.0.100", "version": "7.0.200",
"rollForward": "latestFeature" "rollForward": "latestFeature"
} }
} }

View file

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net8.0</TargetFramework> <TargetFramework>net7.0</TargetFramework>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks> <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup> </PropertyGroup>

View file

@ -1,4 +1,4 @@
using ARMeilleure.Common; using ARMeilleure.Common;
using System; using System;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
@ -23,7 +23,10 @@ namespace ARMeilleure
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private static ArenaAllocator GetAllocator(ref ArenaAllocator alloc, uint pageSize, uint pageCount) private static ArenaAllocator GetAllocator(ref ArenaAllocator alloc, uint pageSize, uint pageCount)
{ {
alloc ??= new ArenaAllocator(pageSize, pageCount); if (alloc == null)
{
alloc = new ArenaAllocator(pageSize, pageCount);
}
return alloc; return alloc;
} }

View file

@ -221,7 +221,7 @@ namespace ARMeilleure.CodeGen.Arm64
2 => Multiplier.x4, 2 => Multiplier.x4,
3 => Multiplier.x8, 3 => Multiplier.x8,
4 => Multiplier.x16, 4 => Multiplier.x16,
_ => Multiplier.x1, _ => Multiplier.x1
}; };
baseOp = indexOnSrc2 ? src1 : src2; baseOp = indexOnSrc2 ? src1 : src2;

View file

@ -5,22 +5,22 @@ namespace ARMeilleure.CodeGen.Arm64
{ {
enum ArmCondition enum ArmCondition
{ {
Eq = 0, Eq = 0,
Ne = 1, Ne = 1,
GeUn = 2, GeUn = 2,
LtUn = 3, LtUn = 3,
Mi = 4, Mi = 4,
Pl = 5, Pl = 5,
Vs = 6, Vs = 6,
Vc = 7, Vc = 7,
GtUn = 8, GtUn = 8,
LeUn = 9, LeUn = 9,
Ge = 10, Ge = 10,
Lt = 11, Lt = 11,
Gt = 12, Gt = 12,
Le = 13, Le = 13,
Al = 14, Al = 14,
Nv = 15, Nv = 15
} }
static class ComparisonArm64Extensions static class ComparisonArm64Extensions
@ -29,7 +29,6 @@ namespace ARMeilleure.CodeGen.Arm64
{ {
return comp switch return comp switch
{ {
#pragma warning disable IDE0055 // Disable formatting
Comparison.Equal => ArmCondition.Eq, Comparison.Equal => ArmCondition.Eq,
Comparison.NotEqual => ArmCondition.Ne, Comparison.NotEqual => ArmCondition.Ne,
Comparison.Greater => ArmCondition.Gt, Comparison.Greater => ArmCondition.Gt,
@ -40,9 +39,8 @@ namespace ARMeilleure.CodeGen.Arm64
Comparison.Less => ArmCondition.Lt, Comparison.Less => ArmCondition.Lt,
Comparison.GreaterOrEqualUI => ArmCondition.GeUn, Comparison.GreaterOrEqualUI => ArmCondition.GeUn,
Comparison.LessUI => ArmCondition.LtUn, Comparison.LessUI => ArmCondition.LtUn,
#pragma warning restore IDE0055
_ => throw new ArgumentException(null, nameof(comp)), _ => throw new ArgumentException(null, nameof(comp))
}; };
} }
} }

View file

@ -9,6 +9,6 @@ namespace ARMeilleure.CodeGen.Arm64
Sxtb = 4, Sxtb = 4,
Sxth = 5, Sxth = 5,
Sxtw = 6, Sxtw = 6,
Sxtx = 7, Sxtx = 7
} }
} }

View file

@ -6,6 +6,6 @@ namespace ARMeilleure.CodeGen.Arm64
Lsl = 0, Lsl = 0,
Lsr = 1, Lsr = 1,
Asr = 2, Asr = 2,
Ror = 3, Ror = 3
} }
} }

View file

@ -188,7 +188,7 @@ namespace ARMeilleure.CodeGen.Arm64
uint rmode = topHalf ? 1u << 19 : 0u; uint rmode = topHalf ? 1u << 19 : 0u;
uint ftype = rd.Type == OperandType.FP64 || rn.Type == OperandType.FP64 ? 1u << 22 : 0u; uint ftype = rd.Type == OperandType.FP64 || rn.Type == OperandType.FP64 ? 1u << 22 : 0u;
uint sf = rd.Type == OperandType.I64 || rn.Type == OperandType.I64 ? SfFlag : 0u; uint sf = rd.Type == OperandType.I64 || rn.Type == OperandType.I64 ? SfFlag : 0u;
WriteUInt32(0x1e260000u | (opcode << 16) | rmode | ftype | sf | EncodeReg(rd) | (EncodeReg(rn) << 5)); WriteUInt32(0x1e260000u | (opcode << 16) | rmode | ftype | sf | EncodeReg(rd) | (EncodeReg(rn) << 5));
} }
@ -992,7 +992,7 @@ namespace ARMeilleure.CodeGen.Arm64
{ {
OperandType.FP32 => 0, OperandType.FP32 => 0,
OperandType.FP64 => 1, OperandType.FP64 => 1,
_ => 2, _ => 2
}; };
instruction = vecInst | ((uint)opc << 30); instruction = vecInst | ((uint)opc << 30);
@ -1124,11 +1124,10 @@ namespace ARMeilleure.CodeGen.Arm64
OperandType.FP32 => 2, OperandType.FP32 => 2,
OperandType.FP64 => 3, OperandType.FP64 => 3,
OperandType.V128 => 4, OperandType.V128 => 4,
_ => throw new ArgumentException($"Invalid type {type}."), _ => throw new ArgumentException($"Invalid type {type}.")
}; };
} }
#pragma warning disable IDE0051 // Remove unused private member
private void WriteInt16(short value) private void WriteInt16(short value)
{ {
WriteUInt16((ushort)value); WriteUInt16((ushort)value);
@ -1143,7 +1142,6 @@ namespace ARMeilleure.CodeGen.Arm64
{ {
_stream.WriteByte(value); _stream.WriteByte(value);
} }
#pragma warning restore IDE0051
private void WriteUInt16(ushort value) private void WriteUInt16(ushort value)
{ {

View file

@ -14,7 +14,7 @@ namespace ARMeilleure.CodeGen.Arm64
private const int CbnzInstLength = 4; private const int CbnzInstLength = 4;
private const int LdrLitInstLength = 4; private const int LdrLitInstLength = 4;
private readonly Stream _stream; private Stream _stream;
public int StreamOffset => (int)_stream.Length; public int StreamOffset => (int)_stream.Length;
@ -32,7 +32,7 @@ namespace ARMeilleure.CodeGen.Arm64
private readonly Dictionary<BasicBlock, long> _visitedBlocks; private readonly Dictionary<BasicBlock, long> _visitedBlocks;
private readonly Dictionary<BasicBlock, List<(ArmCondition Condition, long BranchPos)>> _pendingBranches; private readonly Dictionary<BasicBlock, List<(ArmCondition Condition, long BranchPos)>> _pendingBranches;
private readonly struct ConstantPoolEntry private struct ConstantPoolEntry
{ {
public readonly int Offset; public readonly int Offset;
public readonly Symbol Symbol; public readonly Symbol Symbol;
@ -58,7 +58,7 @@ namespace ARMeilleure.CodeGen.Arm64
private readonly bool _relocatable; private readonly bool _relocatable;
public CodeGenContext(AllocationResult allocResult, int maxCallArgs, bool relocatable) public CodeGenContext(AllocationResult allocResult, int maxCallArgs, int blocksCount, bool relocatable)
{ {
_stream = MemoryStreamManager.Shared.GetStream(); _stream = MemoryStreamManager.Shared.GetStream();
@ -93,10 +93,10 @@ namespace ARMeilleure.CodeGen.Arm64
if (_pendingBranches.TryGetValue(block, out var list)) if (_pendingBranches.TryGetValue(block, out var list))
{ {
foreach ((ArmCondition condition, long branchPos) in list) foreach (var tuple in list)
{ {
_stream.Seek(branchPos, SeekOrigin.Begin); _stream.Seek(tuple.BranchPos, SeekOrigin.Begin);
WriteBranch(condition, target); WriteBranch(tuple.Condition, target);
} }
_stream.Seek(target, SeekOrigin.Begin); _stream.Seek(target, SeekOrigin.Begin);
@ -237,7 +237,7 @@ namespace ARMeilleure.CodeGen.Arm64
long originalPosition = _stream.Position; long originalPosition = _stream.Position;
_stream.Seek(0, SeekOrigin.Begin); _stream.Seek(0, SeekOrigin.Begin);
_stream.ReadExactly(code, 0, code.Length); _stream.Read(code, 0, code.Length);
_stream.Seek(originalPosition, SeekOrigin.Begin); _stream.Seek(originalPosition, SeekOrigin.Begin);
RelocInfo relocInfo; RelocInfo relocInfo;

View file

@ -10,6 +10,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Numerics; using System.Numerics;
using static ARMeilleure.IntermediateRepresentation.Operand; using static ARMeilleure.IntermediateRepresentation.Operand;
using static ARMeilleure.IntermediateRepresentation.Operand.Factory; using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
@ -30,16 +31,15 @@ namespace ARMeilleure.CodeGen.Arm64
{ {
Byte, Byte,
Hword, Hword,
Auto, Auto
} }
private static readonly Action<CodeGenContext, Operation>[] _instTable; private static Action<CodeGenContext, Operation>[] _instTable;
static CodeGenerator() static CodeGenerator()
{ {
_instTable = new Action<CodeGenContext, Operation>[EnumUtils.GetCount(typeof(Instruction))]; _instTable = new Action<CodeGenContext, Operation>[EnumUtils.GetCount(typeof(Instruction))];
#pragma warning disable IDE0055 // Disable formatting
Add(Instruction.Add, GenerateAdd); Add(Instruction.Add, GenerateAdd);
Add(Instruction.BitwiseAnd, GenerateBitwiseAnd); Add(Instruction.BitwiseAnd, GenerateBitwiseAnd);
Add(Instruction.BitwiseExclusiveOr, GenerateBitwiseExclusiveOr); Add(Instruction.BitwiseExclusiveOr, GenerateBitwiseExclusiveOr);
@ -48,7 +48,7 @@ namespace ARMeilleure.CodeGen.Arm64
Add(Instruction.BranchIf, GenerateBranchIf); Add(Instruction.BranchIf, GenerateBranchIf);
Add(Instruction.ByteSwap, GenerateByteSwap); Add(Instruction.ByteSwap, GenerateByteSwap);
Add(Instruction.Call, GenerateCall); Add(Instruction.Call, GenerateCall);
// Add(Instruction.Clobber, GenerateClobber); //Add(Instruction.Clobber, GenerateClobber);
Add(Instruction.Compare, GenerateCompare); Add(Instruction.Compare, GenerateCompare);
Add(Instruction.CompareAndSwap, GenerateCompareAndSwap); Add(Instruction.CompareAndSwap, GenerateCompareAndSwap);
Add(Instruction.CompareAndSwap16, GenerateCompareAndSwap16); Add(Instruction.CompareAndSwap16, GenerateCompareAndSwap16);
@ -100,7 +100,6 @@ namespace ARMeilleure.CodeGen.Arm64
Add(Instruction.ZeroExtend16, GenerateZeroExtend16); Add(Instruction.ZeroExtend16, GenerateZeroExtend16);
Add(Instruction.ZeroExtend32, GenerateZeroExtend32); Add(Instruction.ZeroExtend32, GenerateZeroExtend32);
Add(Instruction.ZeroExtend8, GenerateZeroExtend8); Add(Instruction.ZeroExtend8, GenerateZeroExtend8);
#pragma warning restore IDE0055
static void Add(Instruction inst, Action<CodeGenContext, Operation> func) static void Add(Instruction inst, Action<CodeGenContext, Operation> func)
{ {
@ -132,7 +131,7 @@ namespace ARMeilleure.CodeGen.Arm64
StackAllocator stackAlloc = new(); StackAllocator stackAlloc = new();
PreAllocator.RunPass(cctx, out int maxCallArgs); PreAllocator.RunPass(cctx, stackAlloc, out int maxCallArgs);
Logger.EndPass(PassName.PreAllocation, cfg); Logger.EndPass(PassName.PreAllocation, cfg);
@ -169,9 +168,11 @@ namespace ARMeilleure.CodeGen.Arm64
Logger.StartPass(PassName.CodeGeneration); Logger.StartPass(PassName.CodeGeneration);
//Console.Error.WriteLine(IRDumper.GetDump(cfg));
bool relocatable = (cctx.Options & CompilerOptions.Relocatable) != 0; bool relocatable = (cctx.Options & CompilerOptions.Relocatable) != 0;
CodeGenContext context = new(allocResult, maxCallArgs, relocatable); CodeGenContext context = new(allocResult, maxCallArgs, cfg.Blocks.Count, relocatable);
UnwindInfo unwindInfo = WritePrologue(context); UnwindInfo unwindInfo = WritePrologue(context);
@ -293,7 +294,7 @@ namespace ARMeilleure.CodeGen.Arm64
private static void GenerateBitwiseNot(CodeGenContext context, Operation operation) private static void GenerateBitwiseNot(CodeGenContext context, Operation operation)
{ {
Operand dest = operation.Destination; Operand dest = operation.Destination;
Operand source = operation.GetSource(0); Operand source = operation.GetSource(0);
ValidateUnOp(dest, source); ValidateUnOp(dest, source);
@ -331,7 +332,7 @@ namespace ARMeilleure.CodeGen.Arm64
private static void GenerateByteSwap(CodeGenContext context, Operation operation) private static void GenerateByteSwap(CodeGenContext context, Operation operation)
{ {
Operand dest = operation.Destination; Operand dest = operation.Destination;
Operand source = operation.GetSource(0); Operand source = operation.GetSource(0);
ValidateUnOp(dest, source); ValidateUnOp(dest, source);
@ -365,15 +366,15 @@ namespace ARMeilleure.CodeGen.Arm64
{ {
if (operation.SourcesCount == 5) // CompareAndSwap128 has 5 sources, compared to CompareAndSwap64/32's 3. if (operation.SourcesCount == 5) // CompareAndSwap128 has 5 sources, compared to CompareAndSwap64/32's 3.
{ {
Operand actualLow = operation.GetDestination(0); Operand actualLow = operation.GetDestination(0);
Operand actualHigh = operation.GetDestination(1); Operand actualHigh = operation.GetDestination(1);
Operand temp0 = operation.GetDestination(2); Operand temp0 = operation.GetDestination(2);
Operand temp1 = operation.GetDestination(3); Operand temp1 = operation.GetDestination(3);
Operand address = operation.GetSource(0); Operand address = operation.GetSource(0);
Operand expectedLow = operation.GetSource(1); Operand expectedLow = operation.GetSource(1);
Operand expectedHigh = operation.GetSource(2); Operand expectedHigh = operation.GetSource(2);
Operand desiredLow = operation.GetSource(3); Operand desiredLow = operation.GetSource(3);
Operand desiredHigh = operation.GetSource(4); Operand desiredHigh = operation.GetSource(4);
GenerateAtomicDcas( GenerateAtomicDcas(
context, context,
@ -389,11 +390,11 @@ namespace ARMeilleure.CodeGen.Arm64
} }
else else
{ {
Operand actual = operation.GetDestination(0); Operand actual = operation.GetDestination(0);
Operand result = operation.GetDestination(1); Operand result = operation.GetDestination(1);
Operand address = operation.GetSource(0); Operand address = operation.GetSource(0);
Operand expected = operation.GetSource(1); Operand expected = operation.GetSource(1);
Operand desired = operation.GetSource(2); Operand desired = operation.GetSource(2);
GenerateAtomicCas(context, address, expected, desired, actual, result, AccessSize.Auto); GenerateAtomicCas(context, address, expected, desired, actual, result, AccessSize.Auto);
} }
@ -401,22 +402,22 @@ namespace ARMeilleure.CodeGen.Arm64
private static void GenerateCompareAndSwap16(CodeGenContext context, Operation operation) private static void GenerateCompareAndSwap16(CodeGenContext context, Operation operation)
{ {
Operand actual = operation.GetDestination(0); Operand actual = operation.GetDestination(0);
Operand result = operation.GetDestination(1); Operand result = operation.GetDestination(1);
Operand address = operation.GetSource(0); Operand address = operation.GetSource(0);
Operand expected = operation.GetSource(1); Operand expected = operation.GetSource(1);
Operand desired = operation.GetSource(2); Operand desired = operation.GetSource(2);
GenerateAtomicCas(context, address, expected, desired, actual, result, AccessSize.Hword); GenerateAtomicCas(context, address, expected, desired, actual, result, AccessSize.Hword);
} }
private static void GenerateCompareAndSwap8(CodeGenContext context, Operation operation) private static void GenerateCompareAndSwap8(CodeGenContext context, Operation operation)
{ {
Operand actual = operation.GetDestination(0); Operand actual = operation.GetDestination(0);
Operand result = operation.GetDestination(1); Operand result = operation.GetDestination(1);
Operand address = operation.GetSource(0); Operand address = operation.GetSource(0);
Operand expected = operation.GetSource(1); Operand expected = operation.GetSource(1);
Operand desired = operation.GetSource(2); Operand desired = operation.GetSource(2);
GenerateAtomicCas(context, address, expected, desired, actual, result, AccessSize.Byte); GenerateAtomicCas(context, address, expected, desired, actual, result, AccessSize.Byte);
} }
@ -445,13 +446,13 @@ namespace ARMeilleure.CodeGen.Arm64
Debug.Assert(dest.Type.IsInteger()); Debug.Assert(dest.Type.IsInteger());
Debug.Assert(src1.Type == OperandType.I32); Debug.Assert(src1.Type == OperandType.I32);
context.Assembler.Cmp(src1, Const(src1.Type, 0)); context.Assembler.Cmp (src1, Const(src1.Type, 0));
context.Assembler.Csel(dest, src2, src3, ArmCondition.Ne); context.Assembler.Csel(dest, src2, src3, ArmCondition.Ne);
} }
private static void GenerateConvertI64ToI32(CodeGenContext context, Operation operation) private static void GenerateConvertI64ToI32(CodeGenContext context, Operation operation)
{ {
Operand dest = operation.Destination; Operand dest = operation.Destination;
Operand source = operation.GetSource(0); Operand source = operation.GetSource(0);
Debug.Assert(dest.Type == OperandType.I32 && source.Type == OperandType.I64); Debug.Assert(dest.Type == OperandType.I32 && source.Type == OperandType.I64);
@ -461,7 +462,7 @@ namespace ARMeilleure.CodeGen.Arm64
private static void GenerateConvertToFP(CodeGenContext context, Operation operation) private static void GenerateConvertToFP(CodeGenContext context, Operation operation)
{ {
Operand dest = operation.Destination; Operand dest = operation.Destination;
Operand source = operation.GetSource(0); Operand source = operation.GetSource(0);
Debug.Assert(dest.Type == OperandType.FP32 || dest.Type == OperandType.FP64); Debug.Assert(dest.Type == OperandType.FP32 || dest.Type == OperandType.FP64);
@ -480,7 +481,7 @@ namespace ARMeilleure.CodeGen.Arm64
private static void GenerateConvertToFPUI(CodeGenContext context, Operation operation) private static void GenerateConvertToFPUI(CodeGenContext context, Operation operation)
{ {
Operand dest = operation.Destination; Operand dest = operation.Destination;
Operand source = operation.GetSource(0); Operand source = operation.GetSource(0);
Debug.Assert(dest.Type == OperandType.FP32 || dest.Type == OperandType.FP64); Debug.Assert(dest.Type == OperandType.FP32 || dest.Type == OperandType.FP64);
@ -492,7 +493,7 @@ namespace ARMeilleure.CodeGen.Arm64
private static void GenerateCopy(CodeGenContext context, Operation operation) private static void GenerateCopy(CodeGenContext context, Operation operation)
{ {
Operand dest = operation.Destination; Operand dest = operation.Destination;
Operand source = operation.GetSource(0); Operand source = operation.GetSource(0);
EnsureSameType(dest, source); EnsureSameType(dest, source);
@ -524,7 +525,7 @@ namespace ARMeilleure.CodeGen.Arm64
private static void GenerateCountLeadingZeros(CodeGenContext context, Operation operation) private static void GenerateCountLeadingZeros(CodeGenContext context, Operation operation)
{ {
Operand dest = operation.Destination; Operand dest = operation.Destination;
Operand source = operation.GetSource(0); Operand source = operation.GetSource(0);
EnsureSameType(dest, source); EnsureSameType(dest, source);
@ -536,9 +537,9 @@ namespace ARMeilleure.CodeGen.Arm64
private static void GenerateDivide(CodeGenContext context, Operation operation) private static void GenerateDivide(CodeGenContext context, Operation operation)
{ {
Operand dest = operation.Destination; Operand dest = operation.Destination;
Operand dividend = operation.GetSource(0); Operand dividend = operation.GetSource(0);
Operand divisor = operation.GetSource(1); Operand divisor = operation.GetSource(1);
ValidateBinOp(dest, dividend, divisor); ValidateBinOp(dest, dividend, divisor);
@ -554,9 +555,9 @@ namespace ARMeilleure.CodeGen.Arm64
private static void GenerateDivideUI(CodeGenContext context, Operation operation) private static void GenerateDivideUI(CodeGenContext context, Operation operation)
{ {
Operand dest = operation.Destination; Operand dest = operation.Destination;
Operand dividend = operation.GetSource(0); Operand dividend = operation.GetSource(0);
Operand divisor = operation.GetSource(1); Operand divisor = operation.GetSource(1);
ValidateBinOp(dest, dividend, divisor); ValidateBinOp(dest, dividend, divisor);
@ -565,7 +566,7 @@ namespace ARMeilleure.CodeGen.Arm64
private static void GenerateLoad(CodeGenContext context, Operation operation) private static void GenerateLoad(CodeGenContext context, Operation operation)
{ {
Operand value = operation.Destination; Operand value = operation.Destination;
Operand address = operation.GetSource(0); Operand address = operation.GetSource(0);
context.Assembler.Ldr(value, address); context.Assembler.Ldr(value, address);
@ -573,7 +574,7 @@ namespace ARMeilleure.CodeGen.Arm64
private static void GenerateLoad16(CodeGenContext context, Operation operation) private static void GenerateLoad16(CodeGenContext context, Operation operation)
{ {
Operand value = operation.Destination; Operand value = operation.Destination;
Operand address = operation.GetSource(0); Operand address = operation.GetSource(0);
Debug.Assert(value.Type.IsInteger()); Debug.Assert(value.Type.IsInteger());
@ -583,7 +584,7 @@ namespace ARMeilleure.CodeGen.Arm64
private static void GenerateLoad8(CodeGenContext context, Operation operation) private static void GenerateLoad8(CodeGenContext context, Operation operation)
{ {
Operand value = operation.Destination; Operand value = operation.Destination;
Operand address = operation.GetSource(0); Operand address = operation.GetSource(0);
Debug.Assert(value.Type.IsInteger()); Debug.Assert(value.Type.IsInteger());
@ -642,7 +643,7 @@ namespace ARMeilleure.CodeGen.Arm64
private static void GenerateNegate(CodeGenContext context, Operation operation) private static void GenerateNegate(CodeGenContext context, Operation operation)
{ {
Operand dest = operation.Destination; Operand dest = operation.Destination;
Operand source = operation.GetSource(0); Operand source = operation.GetSource(0);
ValidateUnOp(dest, source); ValidateUnOp(dest, source);
@ -729,7 +730,7 @@ namespace ARMeilleure.CodeGen.Arm64
private static void GenerateSignExtend16(CodeGenContext context, Operation operation) private static void GenerateSignExtend16(CodeGenContext context, Operation operation)
{ {
Operand dest = operation.Destination; Operand dest = operation.Destination;
Operand source = operation.GetSource(0); Operand source = operation.GetSource(0);
Debug.Assert(dest.Type.IsInteger() && source.Type.IsInteger()); Debug.Assert(dest.Type.IsInteger() && source.Type.IsInteger());
@ -739,7 +740,7 @@ namespace ARMeilleure.CodeGen.Arm64
private static void GenerateSignExtend32(CodeGenContext context, Operation operation) private static void GenerateSignExtend32(CodeGenContext context, Operation operation)
{ {
Operand dest = operation.Destination; Operand dest = operation.Destination;
Operand source = operation.GetSource(0); Operand source = operation.GetSource(0);
Debug.Assert(dest.Type.IsInteger() && source.Type.IsInteger()); Debug.Assert(dest.Type.IsInteger() && source.Type.IsInteger());
@ -749,7 +750,7 @@ namespace ARMeilleure.CodeGen.Arm64
private static void GenerateSignExtend8(CodeGenContext context, Operation operation) private static void GenerateSignExtend8(CodeGenContext context, Operation operation)
{ {
Operand dest = operation.Destination; Operand dest = operation.Destination;
Operand source = operation.GetSource(0); Operand source = operation.GetSource(0);
Debug.Assert(dest.Type.IsInteger() && source.Type.IsInteger()); Debug.Assert(dest.Type.IsInteger() && source.Type.IsInteger());
@ -759,7 +760,7 @@ namespace ARMeilleure.CodeGen.Arm64
private static void GenerateFill(CodeGenContext context, Operation operation) private static void GenerateFill(CodeGenContext context, Operation operation)
{ {
Operand dest = operation.Destination; Operand dest = operation.Destination;
Operand offset = operation.GetSource(0); Operand offset = operation.GetSource(0);
Debug.Assert(offset.Kind == OperandKind.Constant); Debug.Assert(offset.Kind == OperandKind.Constant);
@ -800,7 +801,7 @@ namespace ARMeilleure.CodeGen.Arm64
private static void GenerateStackAlloc(CodeGenContext context, Operation operation) private static void GenerateStackAlloc(CodeGenContext context, Operation operation)
{ {
Operand dest = operation.Destination; Operand dest = operation.Destination;
Operand offset = operation.GetSource(0); Operand offset = operation.GetSource(0);
Debug.Assert(offset.Kind == OperandKind.Constant); Debug.Assert(offset.Kind == OperandKind.Constant);
@ -812,7 +813,7 @@ namespace ARMeilleure.CodeGen.Arm64
private static void GenerateStore(CodeGenContext context, Operation operation) private static void GenerateStore(CodeGenContext context, Operation operation)
{ {
Operand value = operation.GetSource(1); Operand value = operation.GetSource(1);
Operand address = operation.GetSource(0); Operand address = operation.GetSource(0);
context.Assembler.Str(value, address); context.Assembler.Str(value, address);
@ -820,7 +821,7 @@ namespace ARMeilleure.CodeGen.Arm64
private static void GenerateStore16(CodeGenContext context, Operation operation) private static void GenerateStore16(CodeGenContext context, Operation operation)
{ {
Operand value = operation.GetSource(1); Operand value = operation.GetSource(1);
Operand address = operation.GetSource(0); Operand address = operation.GetSource(0);
Debug.Assert(value.Type.IsInteger()); Debug.Assert(value.Type.IsInteger());
@ -830,7 +831,7 @@ namespace ARMeilleure.CodeGen.Arm64
private static void GenerateStore8(CodeGenContext context, Operation operation) private static void GenerateStore8(CodeGenContext context, Operation operation)
{ {
Operand value = operation.GetSource(1); Operand value = operation.GetSource(1);
Operand address = operation.GetSource(0); Operand address = operation.GetSource(0);
Debug.Assert(value.Type.IsInteger()); Debug.Assert(value.Type.IsInteger());
@ -877,7 +878,7 @@ namespace ARMeilleure.CodeGen.Arm64
private static void GenerateVectorCreateScalar(CodeGenContext context, Operation operation) private static void GenerateVectorCreateScalar(CodeGenContext context, Operation operation)
{ {
Operand dest = operation.Destination; Operand dest = operation.Destination;
Operand source = operation.GetSource(0); Operand source = operation.GetSource(0);
if (dest != default) if (dest != default)
@ -1023,7 +1024,7 @@ namespace ARMeilleure.CodeGen.Arm64
private static void GenerateVectorZeroUpper64(CodeGenContext context, Operation operation) private static void GenerateVectorZeroUpper64(CodeGenContext context, Operation operation)
{ {
Operand dest = operation.Destination; Operand dest = operation.Destination;
Operand source = operation.GetSource(0); Operand source = operation.GetSource(0);
Debug.Assert(dest.Type == OperandType.V128 && source.Type == OperandType.V128); Debug.Assert(dest.Type == OperandType.V128 && source.Type == OperandType.V128);
@ -1033,7 +1034,7 @@ namespace ARMeilleure.CodeGen.Arm64
private static void GenerateVectorZeroUpper96(CodeGenContext context, Operation operation) private static void GenerateVectorZeroUpper96(CodeGenContext context, Operation operation)
{ {
Operand dest = operation.Destination; Operand dest = operation.Destination;
Operand source = operation.GetSource(0); Operand source = operation.GetSource(0);
Debug.Assert(dest.Type == OperandType.V128 && source.Type == OperandType.V128); Debug.Assert(dest.Type == OperandType.V128 && source.Type == OperandType.V128);
@ -1043,7 +1044,7 @@ namespace ARMeilleure.CodeGen.Arm64
private static void GenerateZeroExtend16(CodeGenContext context, Operation operation) private static void GenerateZeroExtend16(CodeGenContext context, Operation operation)
{ {
Operand dest = operation.Destination; Operand dest = operation.Destination;
Operand source = operation.GetSource(0); Operand source = operation.GetSource(0);
Debug.Assert(dest.Type.IsInteger() && source.Type.IsInteger()); Debug.Assert(dest.Type.IsInteger() && source.Type.IsInteger());
@ -1053,7 +1054,7 @@ namespace ARMeilleure.CodeGen.Arm64
private static void GenerateZeroExtend32(CodeGenContext context, Operation operation) private static void GenerateZeroExtend32(CodeGenContext context, Operation operation)
{ {
Operand dest = operation.Destination; Operand dest = operation.Destination;
Operand source = operation.GetSource(0); Operand source = operation.GetSource(0);
Debug.Assert(dest.Type.IsInteger() && source.Type.IsInteger()); Debug.Assert(dest.Type.IsInteger() && source.Type.IsInteger());
@ -1069,7 +1070,7 @@ namespace ARMeilleure.CodeGen.Arm64
private static void GenerateZeroExtend8(CodeGenContext context, Operation operation) private static void GenerateZeroExtend8(CodeGenContext context, Operation operation)
{ {
Operand dest = operation.Destination; Operand dest = operation.Destination;
Operand source = operation.GetSource(0); Operand source = operation.GetSource(0);
Debug.Assert(dest.Type.IsInteger() && source.Type.IsInteger()); Debug.Assert(dest.Type.IsInteger() && source.Type.IsInteger());
@ -1079,7 +1080,7 @@ namespace ARMeilleure.CodeGen.Arm64
private static UnwindInfo WritePrologue(CodeGenContext context) private static UnwindInfo WritePrologue(CodeGenContext context)
{ {
List<UnwindPushEntry> pushEntries = new(); List<UnwindPushEntry> pushEntries = new List<UnwindPushEntry>();
Operand rsp = Register(SpRegister); Operand rsp = Register(SpRegister);
@ -1569,13 +1570,11 @@ namespace ARMeilleure.CodeGen.Arm64
Debug.Assert(op1.Type == op3.Type); Debug.Assert(op1.Type == op3.Type);
} }
#pragma warning disable IDE0051 // Remove unused private member
private static void EnsureSameType(Operand op1, Operand op2, Operand op3, Operand op4) private static void EnsureSameType(Operand op1, Operand op2, Operand op3, Operand op4)
{ {
Debug.Assert(op1.Type == op2.Type); Debug.Assert(op1.Type == op2.Type);
Debug.Assert(op1.Type == op3.Type); Debug.Assert(op1.Type == op3.Type);
Debug.Assert(op1.Type == op4.Type); Debug.Assert(op1.Type == op4.Type);
} }
#pragma warning restore IDE0051
} }
} }

View file

@ -179,35 +179,6 @@ namespace ARMeilleure.CodeGen.Arm64
(uint)operation.GetSource(2).AsInt32()); (uint)operation.GetSource(2).AsInt32());
break; break;
case IntrinsicType.Vector128Unary:
GenerateVectorUnary(
context,
1,
0,
info.Inst,
operation.Destination,
operation.GetSource(0));
break;
case IntrinsicType.Vector128Binary:
GenerateVectorBinary(
context,
1,
0,
info.Inst,
operation.Destination,
operation.GetSource(0),
operation.GetSource(1));
break;
case IntrinsicType.Vector128BinaryRd:
GenerateVectorUnary(
context,
1,
0,
info.Inst,
operation.Destination,
operation.GetSource(1));
break;
case IntrinsicType.VectorUnary: case IntrinsicType.VectorUnary:
GenerateVectorUnary( GenerateVectorUnary(
context, context,

View file

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

View file

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

View file

@ -5,13 +5,12 @@ namespace ARMeilleure.CodeGen.Arm64
{ {
static class IntrinsicTable static class IntrinsicTable
{ {
private static readonly IntrinsicInfo[] _intrinTable; private static IntrinsicInfo[] _intrinTable;
static IntrinsicTable() static IntrinsicTable()
{ {
_intrinTable = new IntrinsicInfo[EnumUtils.GetCount(typeof(Intrinsic))]; _intrinTable = new IntrinsicInfo[EnumUtils.GetCount(typeof(Intrinsic))];
#pragma warning disable IDE0055 // Disable formatting
Add(Intrinsic.Arm64AbsS, new IntrinsicInfo(0x5e20b800u, IntrinsicType.ScalarUnary)); Add(Intrinsic.Arm64AbsS, new IntrinsicInfo(0x5e20b800u, IntrinsicType.ScalarUnary));
Add(Intrinsic.Arm64AbsV, new IntrinsicInfo(0x0e20b800u, IntrinsicType.VectorUnary)); Add(Intrinsic.Arm64AbsV, new IntrinsicInfo(0x0e20b800u, IntrinsicType.VectorUnary));
Add(Intrinsic.Arm64AddhnV, new IntrinsicInfo(0x0e204000u, IntrinsicType.VectorTernaryRd)); Add(Intrinsic.Arm64AddhnV, new IntrinsicInfo(0x0e204000u, IntrinsicType.VectorTernaryRd));
@ -20,8 +19,8 @@ namespace ARMeilleure.CodeGen.Arm64
Add(Intrinsic.Arm64AddvV, new IntrinsicInfo(0x0e31b800u, IntrinsicType.VectorUnary)); Add(Intrinsic.Arm64AddvV, new IntrinsicInfo(0x0e31b800u, IntrinsicType.VectorUnary));
Add(Intrinsic.Arm64AddS, new IntrinsicInfo(0x5e208400u, IntrinsicType.ScalarBinary)); Add(Intrinsic.Arm64AddS, new IntrinsicInfo(0x5e208400u, IntrinsicType.ScalarBinary));
Add(Intrinsic.Arm64AddV, new IntrinsicInfo(0x0e208400u, IntrinsicType.VectorBinary)); Add(Intrinsic.Arm64AddV, new IntrinsicInfo(0x0e208400u, IntrinsicType.VectorBinary));
Add(Intrinsic.Arm64AesdV, new IntrinsicInfo(0x4e285800u, IntrinsicType.Vector128BinaryRd)); Add(Intrinsic.Arm64AesdV, new IntrinsicInfo(0x4e285800u, IntrinsicType.Vector128Unary));
Add(Intrinsic.Arm64AeseV, new IntrinsicInfo(0x4e284800u, IntrinsicType.Vector128BinaryRd)); Add(Intrinsic.Arm64AeseV, new IntrinsicInfo(0x4e284800u, IntrinsicType.Vector128Unary));
Add(Intrinsic.Arm64AesimcV, new IntrinsicInfo(0x4e287800u, IntrinsicType.Vector128Unary)); Add(Intrinsic.Arm64AesimcV, new IntrinsicInfo(0x4e287800u, IntrinsicType.Vector128Unary));
Add(Intrinsic.Arm64AesmcV, new IntrinsicInfo(0x4e286800u, IntrinsicType.Vector128Unary)); Add(Intrinsic.Arm64AesmcV, new IntrinsicInfo(0x4e286800u, IntrinsicType.Vector128Unary));
Add(Intrinsic.Arm64AndV, new IntrinsicInfo(0x0e201c00u, IntrinsicType.VectorBinaryBitwise)); Add(Intrinsic.Arm64AndV, new IntrinsicInfo(0x0e201c00u, IntrinsicType.VectorBinaryBitwise));
@ -449,7 +448,6 @@ namespace ARMeilleure.CodeGen.Arm64
Add(Intrinsic.Arm64XtnV, new IntrinsicInfo(0x0e212800u, IntrinsicType.VectorUnary)); Add(Intrinsic.Arm64XtnV, new IntrinsicInfo(0x0e212800u, IntrinsicType.VectorUnary));
Add(Intrinsic.Arm64Zip1V, new IntrinsicInfo(0x0e003800u, IntrinsicType.VectorBinary)); Add(Intrinsic.Arm64Zip1V, new IntrinsicInfo(0x0e003800u, IntrinsicType.VectorBinary));
Add(Intrinsic.Arm64Zip2V, new IntrinsicInfo(0x0e007800u, IntrinsicType.VectorBinary)); Add(Intrinsic.Arm64Zip2V, new IntrinsicInfo(0x0e007800u, IntrinsicType.VectorBinary));
#pragma warning restore IDE0055
} }
private static void Add(Intrinsic intrin, IntrinsicInfo info) private static void Add(Intrinsic intrin, IntrinsicInfo info)

View file

@ -23,10 +23,6 @@ namespace ARMeilleure.CodeGen.Arm64
ScalarTernaryShlRd, ScalarTernaryShlRd,
ScalarTernaryShrRd, ScalarTernaryShrRd,
Vector128Unary,
Vector128Binary,
Vector128BinaryRd,
VectorUnary, VectorUnary,
VectorUnaryBitwise, VectorUnaryBitwise,
VectorUnaryByElem, VectorUnaryByElem,
@ -54,7 +50,10 @@ namespace ARMeilleure.CodeGen.Arm64
VectorTernaryShlRd, VectorTernaryShlRd,
VectorTernaryShrRd, VectorTernaryShrRd,
Vector128Unary,
Vector128Binary,
GetRegister, GetRegister,
SetRegister, SetRegister
} }
} }

View file

@ -1,3 +1,4 @@
using ARMeilleure.CodeGen.RegisterAllocators;
using ARMeilleure.IntermediateRepresentation; using ARMeilleure.IntermediateRepresentation;
using ARMeilleure.Translation; using ARMeilleure.Translation;
using System; using System;
@ -30,7 +31,7 @@ namespace ARMeilleure.CodeGen.Arm64
} }
} }
public static void RunPass(CompilerContext cctx, out int maxCallArgs) public static void RunPass(CompilerContext cctx, StackAllocator stackAlloc, out int maxCallArgs)
{ {
maxCallArgs = -1; maxCallArgs = -1;
@ -40,7 +41,7 @@ namespace ARMeilleure.CodeGen.Arm64
for (BasicBlock block = cctx.Cfg.Blocks.First; block != null; block = block.ListNext) for (BasicBlock block = cctx.Cfg.Blocks.First; block != null; block = block.ListNext)
{ {
ConstantDict constants = new(); ConstantDict constants = new ConstantDict();
Operation nextNode; Operation nextNode;
@ -91,7 +92,7 @@ namespace ARMeilleure.CodeGen.Arm64
InsertReturnCopy(block.Operations, node); InsertReturnCopy(block.Operations, node);
break; break;
case Instruction.Tailcall: case Instruction.Tailcall:
InsertTailcallCopies(constants, block.Operations, node, node); InsertTailcallCopies(constants, block.Operations, stackAlloc, node, node);
break; break;
} }
} }
@ -137,7 +138,10 @@ namespace ARMeilleure.CodeGen.Arm64
{ {
src2 = node.GetSource(1); src2 = node.GetSource(1);
(src2, src1) = (src1, src2); Operand temp = src1;
src1 = src2;
src2 = temp;
node.SetSource(0, src1); node.SetSource(0, src1);
node.SetSource(1, src2); node.SetSource(1, src2);
@ -261,9 +265,9 @@ namespace ARMeilleure.CodeGen.Arm64
Operand dest = operation.Destination; Operand dest = operation.Destination;
List<Operand> sources = new() List<Operand> sources = new List<Operand>
{ {
operation.GetSource(0), operation.GetSource(0)
}; };
int argsCount = operation.SourcesCount - 1; int argsCount = operation.SourcesCount - 1;
@ -298,10 +302,10 @@ namespace ARMeilleure.CodeGen.Arm64
if (source.Type == OperandType.V128 && passOnReg) if (source.Type == OperandType.V128 && passOnReg)
{ {
// V128 is a struct, we pass each half on a GPR if possible. // V128 is a struct, we pass each half on a GPR if possible.
Operand argReg = Gpr(CallingConvention.GetIntArgumentRegister(intCount++), OperandType.I64); Operand argReg = Gpr(CallingConvention.GetIntArgumentRegister(intCount++), OperandType.I64);
Operand argReg2 = 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, argReg, source, Const(0)));
nodes.AddBefore(node, Operation(Instruction.VectorExtract, argReg2, source, Const(1))); nodes.AddBefore(node, Operation(Instruction.VectorExtract, argReg2, source, Const(1)));
continue; continue;
@ -335,7 +339,7 @@ namespace ARMeilleure.CodeGen.Arm64
{ {
if (dest.Type == OperandType.V128) if (dest.Type == OperandType.V128)
{ {
Operand retLReg = Gpr(CallingConvention.GetIntReturnRegister(), OperandType.I64); Operand retLReg = Gpr(CallingConvention.GetIntReturnRegister(), OperandType.I64);
Operand retHReg = Gpr(CallingConvention.GetIntReturnRegisterHigh(), OperandType.I64); Operand retHReg = Gpr(CallingConvention.GetIntReturnRegisterHigh(), OperandType.I64);
node = nodes.AddAfter(node, Operation(Instruction.VectorCreateScalar, dest, retLReg)); node = nodes.AddAfter(node, Operation(Instruction.VectorCreateScalar, dest, retLReg));
@ -360,14 +364,16 @@ namespace ARMeilleure.CodeGen.Arm64
operation.SetSources(sources.ToArray()); operation.SetSources(sources.ToArray());
} }
private static void InsertTailcallCopies(ConstantDict constants, private static void InsertTailcallCopies(
ConstantDict constants,
IntrusiveList<Operation> nodes, IntrusiveList<Operation> nodes,
StackAllocator stackAlloc,
Operation node, Operation node,
Operation operation) Operation operation)
{ {
List<Operand> sources = new() List<Operand> sources = new List<Operand>
{ {
operation.GetSource(0), operation.GetSource(0)
}; };
int argsCount = operation.SourcesCount - 1; int argsCount = operation.SourcesCount - 1;
@ -397,7 +403,7 @@ namespace ARMeilleure.CodeGen.Arm64
if (source.Type == OperandType.V128 && passOnReg) if (source.Type == OperandType.V128 && passOnReg)
{ {
// V128 is a struct, we pass each half on a GPR if possible. // V128 is a struct, we pass each half on a GPR if possible.
Operand argReg = Gpr(CallingConvention.GetIntArgumentRegister(intCount++), OperandType.I64); Operand argReg = Gpr(CallingConvention.GetIntArgumentRegister(intCount++), OperandType.I64);
Operand argReg2 = 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, argReg, source, Const(0)));
@ -513,7 +519,7 @@ namespace ARMeilleure.CodeGen.Arm64
if (source.Type == OperandType.V128) if (source.Type == OperandType.V128)
{ {
Operand retLReg = Gpr(CallingConvention.GetIntReturnRegister(), OperandType.I64); Operand retLReg = Gpr(CallingConvention.GetIntReturnRegister(), OperandType.I64);
Operand retHReg = Gpr(CallingConvention.GetIntReturnRegisterHigh(), 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, retLReg, source, Const(0)));
@ -740,7 +746,6 @@ namespace ARMeilleure.CodeGen.Arm64
info.Type == IntrinsicType.ScalarTernaryFPRdByElem || info.Type == IntrinsicType.ScalarTernaryFPRdByElem ||
info.Type == IntrinsicType.ScalarTernaryShlRd || info.Type == IntrinsicType.ScalarTernaryShlRd ||
info.Type == IntrinsicType.ScalarTernaryShrRd || info.Type == IntrinsicType.ScalarTernaryShrRd ||
info.Type == IntrinsicType.Vector128BinaryRd ||
info.Type == IntrinsicType.VectorBinaryRd || info.Type == IntrinsicType.VectorBinaryRd ||
info.Type == IntrinsicType.VectorInsertByElem || info.Type == IntrinsicType.VectorInsertByElem ||
info.Type == IntrinsicType.VectorTernaryRd || info.Type == IntrinsicType.VectorTernaryRd ||

View file

@ -35,9 +35,9 @@ namespace ARMeilleure.CodeGen
/// <param name="relocInfo">Relocation info</param> /// <param name="relocInfo">Relocation info</param>
internal CompiledFunction(byte[] code, UnwindInfo unwindInfo, RelocInfo relocInfo) internal CompiledFunction(byte[] code, UnwindInfo unwindInfo, RelocInfo relocInfo)
{ {
Code = code; Code = code;
UnwindInfo = unwindInfo; UnwindInfo = unwindInfo;
RelocInfo = relocInfo; RelocInfo = relocInfo;
} }
/// <summary> /// <summary>

View file

@ -1,4 +1,4 @@
using System; using System;
namespace ARMeilleure.CodeGen.Linking namespace ARMeilleure.CodeGen.Linking
{ {

View file

@ -1,4 +1,4 @@
namespace ARMeilleure.CodeGen.Linking namespace ARMeilleure.CodeGen.Linking
{ {
/// <summary> /// <summary>
/// Types of <see cref="Symbol"/>. /// Types of <see cref="Symbol"/>.
@ -23,6 +23,6 @@ namespace ARMeilleure.CodeGen.Linking
/// <summary> /// <summary>
/// Refers to a special symbol which is handled by <see cref="Translation.PTC.Ptc.PatchCode"/>. /// Refers to a special symbol which is handled by <see cref="Translation.PTC.Ptc.PatchCode"/>.
/// </summary> /// </summary>
Special, Special
} }
} }

View file

@ -1,4 +1,4 @@
using ARMeilleure.IntermediateRepresentation; using ARMeilleure.IntermediateRepresentation;
using ARMeilleure.Translation; using ARMeilleure.Translation;
using System.Diagnostics; using System.Diagnostics;
using static ARMeilleure.IntermediateRepresentation.Operand.Factory; using static ARMeilleure.IntermediateRepresentation.Operand.Factory;

View file

@ -164,7 +164,7 @@ namespace ARMeilleure.CodeGen.Optimizations
} }
break; break;
case Instruction.Multiply: case Instruction.Multiply:
if (type == OperandType.I32) if (type == OperandType.I32)
{ {
EvaluateBinaryI32(operation, (x, y) => x * y); EvaluateBinaryI32(operation, (x, y) => x * y);

View file

@ -182,7 +182,7 @@ namespace ARMeilleure.CodeGen.Optimizations
private static void PropagateCopy(ref Span<Operation> buffer, Operation copyOp) private static void PropagateCopy(ref Span<Operation> buffer, Operation copyOp)
{ {
// Propagate copy source operand to all uses of the destination operand. // Propagate copy source operand to all uses of the destination operand.
Operand dest = copyOp.Destination; Operand dest = copyOp.Destination;
Operand source = copyOp.GetSource(0); Operand source = copyOp.GetSource(0);
Span<Operation> uses = dest.GetUses(ref buffer); Span<Operation> uses = dest.GetUses(ref buffer);

View file

@ -171,12 +171,13 @@ namespace ARMeilleure.CodeGen.Optimizations
private static ulong AllOnes(OperandType type) private static ulong AllOnes(OperandType type)
{ {
return type switch switch (type)
{ {
OperandType.I32 => ~0U, case OperandType.I32: return ~0U;
OperandType.I64 => ~0UL, case OperandType.I64: return ~0UL;
_ => throw new ArgumentException("Invalid operand type \"" + type + "\"."), }
};
throw new ArgumentException("Invalid operand type \"" + type + "\".");
} }
} }
} }

View file

@ -1,4 +1,4 @@
using ARMeilleure.IntermediateRepresentation; using ARMeilleure.IntermediateRepresentation;
using ARMeilleure.Translation; using ARMeilleure.Translation;
using static ARMeilleure.IntermediateRepresentation.Operation.Factory; using static ARMeilleure.IntermediateRepresentation.Operation.Factory;

View file

@ -4,7 +4,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
{ {
public int IntUsedRegisters { get; } public int IntUsedRegisters { get; }
public int VecUsedRegisters { get; } public int VecUsedRegisters { get; }
public int SpillRegionSize { get; } public int SpillRegionSize { get; }
public AllocationResult( public AllocationResult(
int intUsedRegisters, int intUsedRegisters,
@ -13,7 +13,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
{ {
IntUsedRegisters = intUsedRegisters; IntUsedRegisters = intUsedRegisters;
VecUsedRegisters = vecUsedRegisters; VecUsedRegisters = vecUsedRegisters;
SpillRegionSize = spillRegionSize; SpillRegionSize = spillRegionSize;
} }
} }
} }

View file

@ -1,6 +1,7 @@
using ARMeilleure.IntermediateRepresentation; using ARMeilleure.IntermediateRepresentation;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using static ARMeilleure.IntermediateRepresentation.Operand.Factory; using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
using static ARMeilleure.IntermediateRepresentation.Operation.Factory; using static ARMeilleure.IntermediateRepresentation.Operation.Factory;
@ -12,16 +13,16 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
{ {
private readonly struct Copy private readonly struct Copy
{ {
public Register Dest { get; } public Register Dest { get; }
public Register Source { get; } public Register Source { get; }
public OperandType Type { get; } public OperandType Type { get; }
public Copy(Register dest, Register source, OperandType type) public Copy(Register dest, Register source, OperandType type)
{ {
Dest = dest; Dest = dest;
Source = source; Source = source;
Type = type; Type = type;
} }
} }
@ -41,19 +42,19 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
public void Sequence(List<Operation> sequence) public void Sequence(List<Operation> sequence)
{ {
Dictionary<Register, Register> locations = new(); Dictionary<Register, Register> locations = new Dictionary<Register, Register>();
Dictionary<Register, Register> sources = new(); Dictionary<Register, Register> sources = new Dictionary<Register, Register>();
Dictionary<Register, OperandType> types = new(); Dictionary<Register, OperandType> types = new Dictionary<Register, OperandType>();
Queue<Register> pendingQueue = new(); Queue<Register> pendingQueue = new Queue<Register>();
Queue<Register> readyQueue = new(); Queue<Register> readyQueue = new Queue<Register>();
foreach (Copy copy in _copies) foreach (Copy copy in _copies)
{ {
locations[copy.Source] = copy.Source; locations[copy.Source] = copy.Source;
sources[copy.Dest] = copy.Source; sources[copy.Dest] = copy.Source;
types[copy.Dest] = copy.Type; types[copy.Dest] = copy.Type;
pendingQueue.Enqueue(copy.Dest); pendingQueue.Enqueue(copy.Dest);
} }
@ -90,7 +91,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
} }
} }
copyDest = current; copyDest = current;
origSource = sources[copyDest]; origSource = sources[copyDest];
copySource = locations[origSource]; copySource = locations[origSource];
@ -185,7 +186,10 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
private void AddSplitFill(LiveInterval left, LiveInterval right, OperandType type) private void AddSplitFill(LiveInterval left, LiveInterval right, OperandType type)
{ {
_fillQueue ??= new Queue<Operation>(); if (_fillQueue == null)
{
_fillQueue = new Queue<Operation>();
}
Operand register = GetRegister(right.Register, type); Operand register = GetRegister(right.Register, type);
Operand offset = Const(left.SpillOffset); Operand offset = Const(left.SpillOffset);
@ -197,7 +201,10 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
private void AddSplitSpill(LiveInterval left, LiveInterval right, OperandType type) private void AddSplitSpill(LiveInterval left, LiveInterval right, OperandType type)
{ {
_spillQueue ??= new Queue<Operation>(); if (_spillQueue == null)
{
_spillQueue = new Queue<Operation>();
}
Operand offset = Const(right.SpillOffset); Operand offset = Const(right.SpillOffset);
Operand register = GetRegister(left.Register, type); Operand register = GetRegister(left.Register, type);
@ -209,7 +216,10 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
private void AddSplitCopy(LiveInterval left, LiveInterval right, OperandType type) private void AddSplitCopy(LiveInterval left, LiveInterval right, OperandType type)
{ {
_parallelCopy ??= new ParallelCopy(); if (_parallelCopy == null)
{
_parallelCopy = new ParallelCopy();
}
_parallelCopy.AddCopy(right.Register, left.Register, type); _parallelCopy.AddCopy(right.Register, left.Register, type);
@ -218,7 +228,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
public Operation[] Sequence() public Operation[] Sequence()
{ {
List<Operation> sequence = new(); List<Operation> sequence = new List<Operation>();
if (_spillQueue != null) if (_spillQueue != null)
{ {

View file

@ -20,7 +20,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
public BlockInfo(bool hasCall, int intFixedRegisters, int vecFixedRegisters) public BlockInfo(bool hasCall, int intFixedRegisters, int vecFixedRegisters)
{ {
HasCall = hasCall; HasCall = hasCall;
IntFixedRegisters = intFixedRegisters; IntFixedRegisters = intFixedRegisters;
VecFixedRegisters = vecFixedRegisters; VecFixedRegisters = vecFixedRegisters;
} }
@ -39,7 +39,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
private int _first; private int _first;
private int _last; private int _last;
public readonly bool IsBlockLocal => _first == _last; public bool IsBlockLocal => _first == _last;
public LocalInfo(OperandType type, int uses, int blkIndex) public LocalInfo(OperandType type, int uses, int blkIndex)
{ {
@ -53,7 +53,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
SpillOffset = default; SpillOffset = default;
_first = -1; _first = -1;
_last = -1; _last = -1;
SetBlockIndex(blkIndex); SetBlockIndex(blkIndex);
} }
@ -348,17 +348,17 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
if (dest.Type.IsInteger()) if (dest.Type.IsInteger())
{ {
intLocalFreeRegisters &= ~(1 << selectedReg); intLocalFreeRegisters &= ~(1 << selectedReg);
intUsedRegisters |= 1 << selectedReg; intUsedRegisters |= 1 << selectedReg;
} }
else else
{ {
vecLocalFreeRegisters &= ~(1 << selectedReg); vecLocalFreeRegisters &= ~(1 << selectedReg);
vecUsedRegisters |= 1 << selectedReg; vecUsedRegisters |= 1 << selectedReg;
} }
} }
else else
{ {
info.Register = default; info.Register = default;
info.SpillOffset = Const(stackAlloc.Allocate(dest.Type.GetSizeInBytes())); info.SpillOffset = Const(stackAlloc.Allocate(dest.Type.GetSizeInBytes()));
} }
} }
@ -382,7 +382,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
: GetSpillTemp(dest, vecSpillTempRegisters, ref vecLocalAsg); : GetSpillTemp(dest, vecSpillTempRegisters, ref vecLocalAsg);
info.Sequence = sequence; info.Sequence = sequence;
info.Temp = temp; info.Temp = temp;
} }
dest = temp; dest = temp;
@ -408,7 +408,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
private static int SelectSpillTemps(int mask0, int mask1) private static int SelectSpillTemps(int mask0, int mask1)
{ {
int selection = 0; int selection = 0;
int count = 0; int count = 0;
while (count < MaxIROperands && mask0 != 0) while (count < MaxIROperands && mask0 != 0)
{ {

View file

@ -14,7 +14,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
// http://www.christianwimmer.at/Publications/Wimmer04a/Wimmer04a.pdf // http://www.christianwimmer.at/Publications/Wimmer04a/Wimmer04a.pdf
class LinearScanAllocator : IRegisterAllocator class LinearScanAllocator : IRegisterAllocator
{ {
private const int InstructionGap = 2; private const int InstructionGap = 2;
private const int InstructionGapMask = InstructionGap - 1; private const int InstructionGapMask = InstructionGap - 1;
private HashSet<int> _blockEdges; private HashSet<int> _blockEdges;
@ -33,7 +33,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
public StackAllocator StackAlloc { get; } public StackAllocator StackAlloc { get; }
public BitMap Active { get; } public BitMap Active { get; }
public BitMap Inactive { get; } public BitMap Inactive { get; }
public int IntUsedRegisters { get; set; } public int IntUsedRegisters { get; set; }
@ -47,9 +47,9 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
public AllocationContext(StackAllocator stackAlloc, RegisterMasks masks, int intervalsCount) public AllocationContext(StackAllocator stackAlloc, RegisterMasks masks, int intervalsCount)
{ {
StackAlloc = stackAlloc; StackAlloc = stackAlloc;
Masks = masks; Masks = masks;
Active = new BitMap(Allocators.Default, intervalsCount); Active = new BitMap(Allocators.Default, intervalsCount);
Inactive = new BitMap(Allocators.Default, intervalsCount); Inactive = new BitMap(Allocators.Default, intervalsCount);
PopulateFreePositions(RegisterType.Integer, out _intFreePositions, out _intFreePositionsCount); PopulateFreePositions(RegisterType.Integer, out _intFreePositions, out _intFreePositionsCount);
@ -251,20 +251,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
} }
} }
// If this is a copy destination variable, we prefer the register used for the copy source. int selectedReg = GetHighestValueIndex(freePositions);
// If the register is available, then the copy can be eliminated later as both source
// and destination will use the same register.
int selectedReg;
if (current.TryGetCopySourceRegister(out int preferredReg) && freePositions[preferredReg] >= current.GetEnd())
{
selectedReg = preferredReg;
}
else
{
selectedReg = GetHighestValueIndex(freePositions);
}
int selectedNextUse = freePositions[selectedReg]; int selectedNextUse = freePositions[selectedReg];
// Intervals starts and ends at odd positions, unless they span an entire // Intervals starts and ends at odd positions, unless they span an entire
@ -444,7 +431,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
} }
} }
private static int GetHighestValueIndex(ReadOnlySpan<int> span) private static int GetHighestValueIndex(Span<int> span)
{ {
int highest = int.MinValue; int highest = int.MinValue;
@ -456,7 +443,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
if (highest < current) if (highest < current)
{ {
highest = current; highest = current;
selected = index; selected = index;
if (current == int.MaxValue) if (current == int.MaxValue)
@ -498,9 +485,9 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
private void SplitAndSpillOverlappingInterval( private void SplitAndSpillOverlappingInterval(
AllocationContext context, AllocationContext context,
LiveInterval current, LiveInterval current,
LiveInterval interval, LiveInterval interval,
int registersCount) int registersCount)
{ {
// If there's a next use after the start of the current interval, // If there's a next use after the start of the current interval,
// we need to split the spilled interval twice, and re-insert it // we need to split the spilled interval twice, and re-insert it
@ -543,8 +530,8 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
private void InsertInterval(LiveInterval interval, int registersCount) private void InsertInterval(LiveInterval interval, int registersCount)
{ {
Debug.Assert(interval.UsesCount != 0, "Trying to insert a interval without uses."); Debug.Assert(interval.UsesCount != 0, "Trying to insert a interval without uses.");
Debug.Assert(!interval.IsEmpty, "Trying to insert a empty interval."); Debug.Assert(!interval.IsEmpty, "Trying to insert a empty interval.");
Debug.Assert(!interval.IsSpilled, "Trying to insert a spilled interval."); Debug.Assert(!interval.IsSpilled, "Trying to insert a spilled interval.");
int startIndex = registersCount * 2; int startIndex = registersCount * 2;
@ -558,9 +545,9 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
_intervals.Insert(insertIndex, interval); _intervals.Insert(insertIndex, interval);
} }
private static void Spill(AllocationContext context, LiveInterval interval) private void Spill(AllocationContext context, LiveInterval interval)
{ {
Debug.Assert(!interval.IsFixed, "Trying to spill a fixed interval."); Debug.Assert(!interval.IsFixed, "Trying to spill a fixed interval.");
Debug.Assert(interval.UsesCount == 0, "Trying to spill a interval with uses."); Debug.Assert(interval.UsesCount == 0, "Trying to spill a interval with uses.");
// We first check if any of the siblings were spilled, if so we can reuse // We first check if any of the siblings were spilled, if so we can reuse
@ -574,7 +561,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
private void InsertSplitCopies() private void InsertSplitCopies()
{ {
Dictionary<int, CopyResolver> copyResolvers = new(); Dictionary<int, CopyResolver> copyResolvers = new Dictionary<int, CopyResolver>();
CopyResolver GetCopyResolver(int position) CopyResolver GetCopyResolver(int position)
{ {
@ -681,15 +668,18 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
continue; continue;
} }
int lEnd = _blockRanges[block.Index].End - 1; int lEnd = _blockRanges[block.Index].End - 1;
int rStart = _blockRanges[succIndex].Start; int rStart = _blockRanges[succIndex].Start;
LiveInterval left = interval.GetSplitChild(lEnd); LiveInterval left = interval.GetSplitChild(lEnd);
LiveInterval right = interval.GetSplitChild(rStart); LiveInterval right = interval.GetSplitChild(rStart);
if (left != default && right != default && left != right) if (left != default && right != default && left != right)
{ {
copyResolver ??= new CopyResolver(); if (copyResolver == null)
{
copyResolver = new CopyResolver();
}
copyResolver.AddSplit(left, right); copyResolver.AddSplit(left, right);
} }
@ -811,12 +801,12 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
// The "visited" state is stored in the MSB of the local's value. // The "visited" state is stored in the MSB of the local's value.
const ulong VisitedMask = 1ul << 63; const ulong VisitedMask = 1ul << 63;
static bool IsVisited(Operand local) bool IsVisited(Operand local)
{ {
return (local.GetValueUnsafe() & VisitedMask) != 0; return (local.GetValueUnsafe() & VisitedMask) != 0;
} }
static void SetVisited(Operand local) void SetVisited(Operand local)
{ {
local.GetValueUnsafe() |= VisitedMask; local.GetValueUnsafe() |= VisitedMask;
} }
@ -839,25 +829,9 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
{ {
dest.NumberLocal(_intervals.Count); dest.NumberLocal(_intervals.Count);
LiveInterval interval = new LiveInterval(dest); _intervals.Add(new LiveInterval(dest));
_intervals.Add(interval);
SetVisited(dest); SetVisited(dest);
// If this is a copy (or copy-like operation), set the copy source interval as well.
// This is used for register preferencing later on, which allows the copy to be eliminated
// in some cases.
if (node.Instruction == Instruction.Copy || node.Instruction == Instruction.ZeroExtend32)
{
Operand source = node.GetSource(0);
if (source.Kind == OperandKind.LocalVariable &&
source.GetLocalNumber() > 0 &&
(node.Instruction == Instruction.Copy || source.Type == OperandType.I32))
{
interval.SetCopySource(_intervals[source.GetLocalNumber()]);
}
}
} }
} }
} }
@ -882,14 +856,14 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
int mapSize = _intervals.Count; int mapSize = _intervals.Count;
BitMap[] blkLiveGen = new BitMap[cfg.Blocks.Count]; BitMap[] blkLiveGen = new BitMap[cfg.Blocks.Count];
BitMap[] blkLiveKill = new BitMap[cfg.Blocks.Count]; BitMap[] blkLiveKill = new BitMap[cfg.Blocks.Count];
// Compute local live sets. // Compute local live sets.
for (BasicBlock block = cfg.Blocks.First; block != null; block = block.ListNext) for (BasicBlock block = cfg.Blocks.First; block != null; block = block.ListNext)
{ {
BitMap liveGen = new(Allocators.Default, mapSize); BitMap liveGen = new BitMap(Allocators.Default, mapSize);
BitMap liveKill = new(Allocators.Default, mapSize); BitMap liveKill = new BitMap(Allocators.Default, mapSize);
for (Operation node = block.Operations.First; node != default; node = node.ListNext) for (Operation node = block.Operations.First; node != default; node = node.ListNext)
{ {
@ -936,17 +910,17 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
} }
} }
blkLiveGen[block.Index] = liveGen; blkLiveGen [block.Index] = liveGen;
blkLiveKill[block.Index] = liveKill; blkLiveKill[block.Index] = liveKill;
} }
// Compute global live sets. // Compute global live sets.
BitMap[] blkLiveIn = new BitMap[cfg.Blocks.Count]; BitMap[] blkLiveIn = new BitMap[cfg.Blocks.Count];
BitMap[] blkLiveOut = new BitMap[cfg.Blocks.Count]; BitMap[] blkLiveOut = new BitMap[cfg.Blocks.Count];
for (int index = 0; index < cfg.Blocks.Count; index++) for (int index = 0; index < cfg.Blocks.Count; index++)
{ {
blkLiveIn[index] = new BitMap(Allocators.Default, mapSize); blkLiveIn [index] = new BitMap(Allocators.Default, mapSize);
blkLiveOut[index] = new BitMap(Allocators.Default, mapSize); blkLiveOut[index] = new BitMap(Allocators.Default, mapSize);
} }
@ -971,9 +945,9 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
BitMap liveIn = blkLiveIn[block.Index]; BitMap liveIn = blkLiveIn[block.Index];
liveIn.Set(liveOut); liveIn.Set (liveOut);
liveIn.Clear(blkLiveKill[block.Index]); liveIn.Clear(blkLiveKill[block.Index]);
liveIn.Set(blkLiveGen[block.Index]); liveIn.Set (blkLiveGen [block.Index]);
} }
} }
while (modified); while (modified);
@ -995,7 +969,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
int instCount = Math.Max(block.Operations.Count, 1); int instCount = Math.Max(block.Operations.Count, 1);
int blockStart = operationPos - instCount * InstructionGap; int blockStart = operationPos - instCount * InstructionGap;
int blockEnd = operationPos; int blockEnd = operationPos;
_blockRanges[block.Index] = new LiveRange(blockStart, blockEnd); _blockRanges[block.Index] = new LiveRange(blockStart, blockEnd);
@ -1087,7 +1061,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
{ {
int regIndex = BitOperations.TrailingZeroCount(mask); int regIndex = BitOperations.TrailingZeroCount(mask);
Register callerSavedReg = new(regIndex, regType); Register callerSavedReg = new Register(regIndex, regType);
LiveInterval interval = _intervals[GetRegisterId(callerSavedReg)]; LiveInterval interval = _intervals[GetRegisterId(callerSavedReg)];

View file

@ -19,7 +19,6 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
public LiveRange CurrRange; public LiveRange CurrRange;
public LiveInterval Parent; public LiveInterval Parent;
public LiveInterval CopySource;
public UseList Uses; public UseList Uses;
public LiveIntervalList Children; public LiveIntervalList Children;
@ -38,7 +37,6 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
private ref LiveRange CurrRange => ref _data->CurrRange; private ref LiveRange CurrRange => ref _data->CurrRange;
private ref LiveRange PrevRange => ref _data->PrevRange; private ref LiveRange PrevRange => ref _data->PrevRange;
private ref LiveInterval Parent => ref _data->Parent; private ref LiveInterval Parent => ref _data->Parent;
private ref LiveInterval CopySource => ref _data->CopySource;
private ref UseList Uses => ref _data->Uses; private ref UseList Uses => ref _data->Uses;
private ref LiveIntervalList Children => ref _data->Children; private ref LiveIntervalList Children => ref _data->Children;
@ -80,25 +78,6 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
Register = register; Register = register;
} }
public void SetCopySource(LiveInterval copySource)
{
CopySource = copySource;
}
public bool TryGetCopySourceRegister(out int copySourceRegIndex)
{
if (CopySource._data != null)
{
copySourceRegIndex = CopySource.Register.Index;
return true;
}
copySourceRegIndex = 0;
return false;
}
public void Reset() public void Reset()
{ {
PrevRange = default; PrevRange = default;
@ -261,10 +240,8 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
public LiveInterval Split(int position) public LiveInterval Split(int position)
{ {
LiveInterval result = new(Local, Parent) LiveInterval result = new(Local, Parent);
{ result.End = End;
End = End,
};
LiveRange prev = PrevRange; LiveRange prev = PrevRange;
LiveRange curr = CurrRange; LiveRange curr = CurrRange;

View file

@ -1,4 +1,4 @@
using System; using System;
namespace ARMeilleure.CodeGen.RegisterAllocators namespace ARMeilleure.CodeGen.RegisterAllocators
{ {
@ -8,8 +8,8 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
private int _count; private int _count;
private int _capacity; private int _capacity;
public readonly int Count => _count; public int Count => _count;
public readonly Span<LiveInterval> Span => new(_items, _count); public Span<LiveInterval> Span => new(_items, _count);
public void Add(LiveInterval interval) public void Add(LiveInterval interval)
{ {

View file

@ -5,8 +5,8 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
{ {
readonly struct RegisterMasks readonly struct RegisterMasks
{ {
public int IntAvailableRegisters { get; } public int IntAvailableRegisters { get; }
public int VecAvailableRegisters { get; } public int VecAvailableRegisters { get; }
public int IntCallerSavedRegisters { get; } public int IntCallerSavedRegisters { get; }
public int VecCallerSavedRegisters { get; } public int VecCallerSavedRegisters { get; }
public int IntCalleeSavedRegisters { get; } public int IntCalleeSavedRegisters { get; }
@ -22,13 +22,13 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
int vecCalleeSavedRegisters, int vecCalleeSavedRegisters,
int registersCount) int registersCount)
{ {
IntAvailableRegisters = intAvailableRegisters; IntAvailableRegisters = intAvailableRegisters;
VecAvailableRegisters = vecAvailableRegisters; VecAvailableRegisters = vecAvailableRegisters;
IntCallerSavedRegisters = intCallerSavedRegisters; IntCallerSavedRegisters = intCallerSavedRegisters;
VecCallerSavedRegisters = vecCallerSavedRegisters; VecCallerSavedRegisters = vecCallerSavedRegisters;
IntCalleeSavedRegisters = intCalleeSavedRegisters; IntCalleeSavedRegisters = intCalleeSavedRegisters;
VecCalleeSavedRegisters = vecCalleeSavedRegisters; VecCalleeSavedRegisters = vecCalleeSavedRegisters;
RegistersCount = registersCount; RegistersCount = registersCount;
} }
public int GetAvailableRegisters(RegisterType type) public int GetAvailableRegisters(RegisterType type)

View file

@ -1,4 +1,4 @@
using System; using System;
namespace ARMeilleure.CodeGen.RegisterAllocators namespace ARMeilleure.CodeGen.RegisterAllocators
{ {
@ -6,15 +6,15 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
{ {
private int* _items; private int* _items;
private int _capacity; private int _capacity;
private int _count;
public int Count { get; private set; } public int Count => _count;
public int FirstUse => _count > 0 ? _items[_count - 1] : LiveInterval.NotFound;
public readonly int FirstUse => Count > 0 ? _items[Count - 1] : LiveInterval.NotFound; public Span<int> Span => new(_items, _count);
public readonly Span<int> Span => new(_items, Count);
public void Add(int position) public void Add(int position)
{ {
if (Count + 1 > _capacity) if (_count + 1 > _capacity)
{ {
var oldSpan = Span; var oldSpan = Span;
@ -28,7 +28,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
// Use positions are usually inserted in descending order, so inserting in descending order is faster, // Use positions are usually inserted in descending order, so inserting in descending order is faster,
// since the number of half exchanges is reduced. // since the number of half exchanges is reduced.
int i = Count - 1; int i = _count - 1;
while (i >= 0 && _items[i] < position) while (i >= 0 && _items[i] < position)
{ {
@ -36,19 +36,19 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
} }
_items[i + 1] = position; _items[i + 1] = position;
Count++; _count++;
} }
public readonly int NextUse(int position) public int NextUse(int position)
{ {
int index = NextUseIndex(position); int index = NextUseIndex(position);
return index != LiveInterval.NotFound ? _items[index] : LiveInterval.NotFound; return index != LiveInterval.NotFound ? _items[index] : LiveInterval.NotFound;
} }
public readonly int NextUseIndex(int position) public int NextUseIndex(int position)
{ {
int i = Count - 1; int i = _count - 1;
if (i == -1 || position > _items[0]) if (i == -1 || position > _items[0])
{ {
@ -69,16 +69,14 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
// Since the list is in descending order, the new split list takes the front of the list and the current // 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. // list takes the back of the list.
UseList result = new() UseList result = new();
{ result._count = index + 1;
Count = index + 1, result._capacity = result._count;
};
result._capacity = result.Count;
result._items = _items; result._items = _items;
Count -= result.Count; _count = _count - result._count;
_capacity = Count; _capacity = _count;
_items += result.Count; _items = _items + result._count;
return result; return result;
} }

View file

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

View file

@ -15,7 +15,7 @@ namespace ARMeilleure.CodeGen.X86
private const int OpModRMBits = 24; private const int OpModRMBits = 24;
private const byte RexPrefix = 0x40; private const byte RexPrefix = 0x40;
private const byte RexWPrefix = 0x48; private const byte RexWPrefix = 0x48;
private const byte LockPrefix = 0xf0; private const byte LockPrefix = 0xf0;
@ -799,7 +799,7 @@ namespace ARMeilleure.CodeGen.X86
{ {
JumpIndex = _jumps.Count - 1, JumpIndex = _jumps.Count - 1,
Position = (int)_stream.Position, Position = (int)_stream.Position,
Symbol = source.Symbol, Symbol = source.Symbol
}); });
} }
@ -959,7 +959,7 @@ namespace ARMeilleure.CodeGen.X86
} }
} }
bool needsSibByte = false; bool needsSibByte = false;
bool needsDisplacement = false; bool needsDisplacement = false;
int sib = 0; int sib = 0;
@ -971,7 +971,7 @@ namespace ARMeilleure.CodeGen.X86
X86Register baseRegLow = (X86Register)(baseReg.Index & 0b111); X86Register baseRegLow = (X86Register)(baseReg.Index & 0b111);
needsSibByte = memOp.Index != default || baseRegLow == X86Register.Rsp; needsSibByte = memOp.Index != default || baseRegLow == X86Register.Rsp;
needsDisplacement = memOp.Displacement != 0 || baseRegLow == X86Register.Rbp; needsDisplacement = memOp.Displacement != 0 || baseRegLow == X86Register.Rbp;
if (needsDisplacement) if (needsDisplacement)
@ -1049,7 +1049,7 @@ namespace ARMeilleure.CodeGen.X86
InstructionFlags.Prefix66 => 1, InstructionFlags.Prefix66 => 1,
InstructionFlags.PrefixF3 => 2, InstructionFlags.PrefixF3 => 2,
InstructionFlags.PrefixF2 => 3, InstructionFlags.PrefixF2 => 3,
_ => 0, _ => 0
}; };
if (src1 != default) if (src1 != default)
@ -1081,19 +1081,11 @@ namespace ARMeilleure.CodeGen.X86
switch (opCodeHigh) switch (opCodeHigh)
{ {
case 0xf: case 0xf: vexByte1 |= 1; break;
vexByte1 |= 1; case 0xf38: vexByte1 |= 2; break;
break; case 0xf3a: vexByte1 |= 3; break;
case 0xf38:
vexByte1 |= 2;
break;
case 0xf3a:
vexByte1 |= 3;
break;
default: default: Debug.Assert(false, $"Failed to VEX encode opcode 0x{opCode:X}."); break;
Debug.Assert(false, $"Failed to VEX encode opcode 0x{opCode:X}.");
break;
} }
vexByte2 |= (rexPrefix & 8) << 4; vexByte2 |= (rexPrefix & 8) << 4;
@ -1199,19 +1191,11 @@ namespace ARMeilleure.CodeGen.X86
switch ((ushort)(opCode >> 8)) switch ((ushort)(opCode >> 8))
{ {
case 0xf00: case 0xf00: mm = 0b01; break;
mm = 0b01; case 0xf38: mm = 0b10; break;
break; case 0xf3a: mm = 0b11; break;
case 0xf38:
mm = 0b10;
break;
case 0xf3a:
mm = 0b11;
break;
default: default: Debug.Fail($"Failed to EVEX encode opcode 0x{opCode:X}."); break;
Debug.Fail($"Failed to EVEX encode opcode 0x{opCode:X}.");
break;
} }
WriteByte( WriteByte(
@ -1233,7 +1217,7 @@ namespace ARMeilleure.CodeGen.X86
InstructionFlags.Prefix66 => 0b01, InstructionFlags.Prefix66 => 0b01,
InstructionFlags.PrefixF3 => 0b10, InstructionFlags.PrefixF3 => 0b10,
InstructionFlags.PrefixF2 => 0b11, InstructionFlags.PrefixF2 => 0b11,
_ => 0, _ => 0
}; };
WriteByte( WriteByte(
(byte)( (byte)(
@ -1249,19 +1233,11 @@ namespace ARMeilleure.CodeGen.X86
byte ll = 0b00; byte ll = 0b00;
switch (registerWidth) switch (registerWidth)
{ {
case 128: case 128: ll = 0b00; break;
ll = 0b00; case 256: ll = 0b01; break;
break; case 512: ll = 0b10; break;
case 256:
ll = 0b01;
break;
case 512:
ll = 0b10;
break;
default: default: Debug.Fail($"Invalid EVEX vector register width {registerWidth}."); break;
Debug.Fail($"Invalid EVEX vector register width {registerWidth}.");
break;
} }
// Embedded broadcast in the case of a memory operand // Embedded broadcast in the case of a memory operand
bool bcast = broadcast; bool bcast = broadcast;
@ -1339,7 +1315,10 @@ namespace ARMeilleure.CodeGen.X86
ref Jump jump = ref jumps[i]; ref Jump jump = ref jumps[i];
// If jump target not resolved yet, resolve it. // If jump target not resolved yet, resolve it.
jump.JumpTarget ??= _labels[jump.JumpLabel]; if (jump.JumpTarget == null)
{
jump.JumpTarget = _labels[jump.JumpLabel];
}
long jumpTarget = jump.JumpTarget.Value; long jumpTarget = jump.JumpTarget.Value;
long offset = jumpTarget - jump.JumpPosition; long offset = jumpTarget - jump.JumpPosition;
@ -1444,7 +1423,7 @@ namespace ARMeilleure.CodeGen.X86
Span<byte> buffer = new byte[jump.JumpPosition - _stream.Position]; Span<byte> buffer = new byte[jump.JumpPosition - _stream.Position];
_stream.ReadExactly(buffer); _stream.Read(buffer);
_stream.Seek(ReservedBytesForJump, SeekOrigin.Current); _stream.Seek(ReservedBytesForJump, SeekOrigin.Current);
codeStream.Write(buffer); codeStream.Write(buffer);

View file

@ -1,5 +1,4 @@
using System; using System;
using System.Diagnostics.CodeAnalysis;
namespace ARMeilleure.CodeGen.X86 namespace ARMeilleure.CodeGen.X86
{ {
@ -13,48 +12,47 @@ namespace ARMeilleure.CodeGen.X86
private const int BadOp = 0; private const int BadOp = 0;
[Flags] [Flags]
[SuppressMessage("Design", "CA1069: Enums values should not be duplicated")]
private enum InstructionFlags private enum InstructionFlags
{ {
None = 0, None = 0,
RegOnly = 1 << 0, RegOnly = 1 << 0,
Reg8Src = 1 << 1, Reg8Src = 1 << 1,
Reg8Dest = 1 << 2, Reg8Dest = 1 << 2,
RexW = 1 << 3, RexW = 1 << 3,
Vex = 1 << 4, Vex = 1 << 4,
Evex = 1 << 5, Evex = 1 << 5,
PrefixBit = 16, PrefixBit = 16,
PrefixMask = 7 << PrefixBit, PrefixMask = 7 << PrefixBit,
Prefix66 = 1 << PrefixBit, Prefix66 = 1 << PrefixBit,
PrefixF3 = 2 << PrefixBit, PrefixF3 = 2 << PrefixBit,
PrefixF2 = 4 << PrefixBit, PrefixF2 = 4 << PrefixBit
} }
private readonly struct InstructionInfo private readonly struct InstructionInfo
{ {
public int OpRMR { get; } public int OpRMR { get; }
public int OpRMImm8 { get; } public int OpRMImm8 { get; }
public int OpRMImm32 { get; } public int OpRMImm32 { get; }
public int OpRImm64 { get; } public int OpRImm64 { get; }
public int OpRRM { get; } public int OpRRM { get; }
public InstructionFlags Flags { get; } public InstructionFlags Flags { get; }
public InstructionInfo( public InstructionInfo(
int opRMR, int opRMR,
int opRMImm8, int opRMImm8,
int opRMImm32, int opRMImm32,
int opRImm64, int opRImm64,
int opRRM, int opRRM,
InstructionFlags flags) InstructionFlags flags)
{ {
OpRMR = opRMR; OpRMR = opRMR;
OpRMImm8 = opRMImm8; OpRMImm8 = opRMImm8;
OpRMImm32 = opRMImm32; OpRMImm32 = opRMImm32;
OpRImm64 = opRImm64; OpRImm64 = opRImm64;
OpRRM = opRRM; OpRRM = opRRM;
Flags = flags; Flags = flags;
} }
} }
@ -64,7 +62,6 @@ namespace ARMeilleure.CodeGen.X86
{ {
_instTable = new InstructionInfo[(int)X86Instruction.Count]; _instTable = new InstructionInfo[(int)X86Instruction.Count];
#pragma warning disable IDE0055 // Disable formatting
// Name RM/R RM/I8 RM/I32 R/I64 R/RM Flags // 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.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.Addpd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f58, InstructionFlags.Vex | InstructionFlags.Prefix66));
@ -288,7 +285,6 @@ namespace ARMeilleure.CodeGen.X86
Add(X86Instruction.Xor, new InstructionInfo(0x00000031, 0x06000083, 0x06000081, BadOp, 0x00000033, InstructionFlags.None)); 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.Xorpd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f57, InstructionFlags.Vex | InstructionFlags.Prefix66));
Add(X86Instruction.Xorps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f57, InstructionFlags.Vex)); Add(X86Instruction.Xorps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f57, InstructionFlags.Vex));
#pragma warning restore IDE0055
static void Add(X86Instruction inst, in InstructionInfo info) static void Add(X86Instruction inst, in InstructionInfo info)
{ {

View file

@ -3,6 +3,6 @@ namespace ARMeilleure.CodeGen.X86
enum CallConvName enum CallConvName
{ {
SystemV, SystemV,
Windows, Windows
} }
} }

View file

@ -20,7 +20,6 @@ namespace ARMeilleure.CodeGen.X86
{ {
if (GetCurrentCallConv() == CallConvName.Windows) if (GetCurrentCallConv() == CallConvName.Windows)
{ {
#pragma warning disable IDE0055 // Disable formatting
return (1 << (int)X86Register.Rax) | return (1 << (int)X86Register.Rax) |
(1 << (int)X86Register.Rcx) | (1 << (int)X86Register.Rcx) |
(1 << (int)X86Register.Rdx) | (1 << (int)X86Register.Rdx) |
@ -40,7 +39,6 @@ namespace ARMeilleure.CodeGen.X86
(1 << (int)X86Register.R9) | (1 << (int)X86Register.R9) |
(1 << (int)X86Register.R10) | (1 << (int)X86Register.R10) |
(1 << (int)X86Register.R11); (1 << (int)X86Register.R11);
#pragma warning restore IDE0055
} }
} }
@ -92,32 +90,22 @@ namespace ARMeilleure.CodeGen.X86
{ {
switch (index) switch (index)
{ {
case 0: case 0: return X86Register.Rcx;
return X86Register.Rcx; case 1: return X86Register.Rdx;
case 1: case 2: return X86Register.R8;
return X86Register.Rdx; case 3: return X86Register.R9;
case 2:
return X86Register.R8;
case 3:
return X86Register.R9;
} }
} }
else /* if (GetCurrentCallConv() == CallConvName.SystemV) */ else /* if (GetCurrentCallConv() == CallConvName.SystemV) */
{ {
switch (index) switch (index)
{ {
case 0: case 0: return X86Register.Rdi;
return X86Register.Rdi; case 1: return X86Register.Rsi;
case 1: case 2: return X86Register.Rdx;
return X86Register.Rsi; case 3: return X86Register.Rcx;
case 2: case 4: return X86Register.R8;
return X86Register.Rdx; case 5: return X86Register.R9;
case 3:
return X86Register.Rcx;
case 4:
return X86Register.R8;
case 5:
return X86Register.R9;
} }
} }

View file

@ -1,4 +1,4 @@
using ARMeilleure.IntermediateRepresentation; using ARMeilleure.IntermediateRepresentation;
namespace ARMeilleure.CodeGen.X86 namespace ARMeilleure.CodeGen.X86
{ {

View file

@ -30,7 +30,7 @@ namespace ARMeilleure.CodeGen.X86
Assembler = new Assembler(_stream, relocatable); Assembler = new Assembler(_stream, relocatable);
CallArgsRegionSize = GetCallArgsRegionSize(allocResult, maxCallArgs, out int xmmSaveRegionSize); CallArgsRegionSize = GetCallArgsRegionSize(allocResult, maxCallArgs, out int xmmSaveRegionSize);
XmmSaveRegionSize = xmmSaveRegionSize; XmmSaveRegionSize = xmmSaveRegionSize;
} }
private static int GetCallArgsRegionSize(AllocationResult allocResult, int maxCallArgs, out int xmmSaveRegionSize) private static int GetCallArgsRegionSize(AllocationResult allocResult, int maxCallArgs, out int xmmSaveRegionSize)

View file

@ -17,7 +17,7 @@ namespace ARMeilleure.CodeGen.X86
static class CodeGenerator static class CodeGenerator
{ {
private const int RegistersCount = 16; private const int RegistersCount = 16;
private const int PageSize = 0x1000; private const int PageSize = 0x1000;
private const int StackGuardSize = 0x2000; private const int StackGuardSize = 0x2000;
private static readonly Action<CodeGenContext, Operation>[] _instTable; private static readonly Action<CodeGenContext, Operation>[] _instTable;
@ -26,7 +26,6 @@ namespace ARMeilleure.CodeGen.X86
{ {
_instTable = new Action<CodeGenContext, Operation>[EnumUtils.GetCount(typeof(Instruction))]; _instTable = new Action<CodeGenContext, Operation>[EnumUtils.GetCount(typeof(Instruction))];
#pragma warning disable IDE0055 // Disable formatting
Add(Instruction.Add, GenerateAdd); Add(Instruction.Add, GenerateAdd);
Add(Instruction.BitwiseAnd, GenerateBitwiseAnd); Add(Instruction.BitwiseAnd, GenerateBitwiseAnd);
Add(Instruction.BitwiseExclusiveOr, GenerateBitwiseExclusiveOr); Add(Instruction.BitwiseExclusiveOr, GenerateBitwiseExclusiveOr);
@ -86,7 +85,6 @@ namespace ARMeilleure.CodeGen.X86
Add(Instruction.ZeroExtend16, GenerateZeroExtend16); Add(Instruction.ZeroExtend16, GenerateZeroExtend16);
Add(Instruction.ZeroExtend32, GenerateZeroExtend32); Add(Instruction.ZeroExtend32, GenerateZeroExtend32);
Add(Instruction.ZeroExtend8, GenerateZeroExtend8); Add(Instruction.ZeroExtend8, GenerateZeroExtend8);
#pragma warning restore IDE0055
static void Add(Instruction inst, Action<CodeGenContext, Operation> func) static void Add(Instruction inst, Action<CodeGenContext, Operation> func)
{ {
@ -205,290 +203,290 @@ namespace ARMeilleure.CodeGen.X86
switch (info.Type) switch (info.Type)
{ {
case IntrinsicType.Comis_: case IntrinsicType.Comis_:
{
Operand dest = operation.Destination;
Operand src1 = operation.GetSource(0);
Operand src2 = operation.GetSource(1);
switch (operation.Intrinsic)
{ {
Operand dest = operation.Destination; case Intrinsic.X86Comisdeq:
Operand src1 = operation.GetSource(0); context.Assembler.Comisd(src1, src2);
Operand src2 = operation.GetSource(1); context.Assembler.Setcc(dest, X86Condition.Equal);
break;
switch (operation.Intrinsic) case Intrinsic.X86Comisdge:
{ context.Assembler.Comisd(src1, src2);
case Intrinsic.X86Comisdeq: context.Assembler.Setcc(dest, X86Condition.AboveOrEqual);
context.Assembler.Comisd(src1, src2); break;
context.Assembler.Setcc(dest, X86Condition.Equal);
break;
case Intrinsic.X86Comisdge: case Intrinsic.X86Comisdlt:
context.Assembler.Comisd(src1, src2); context.Assembler.Comisd(src1, src2);
context.Assembler.Setcc(dest, X86Condition.AboveOrEqual); context.Assembler.Setcc(dest, X86Condition.Below);
break; break;
case Intrinsic.X86Comisdlt: case Intrinsic.X86Comisseq:
context.Assembler.Comisd(src1, src2); context.Assembler.Comiss(src1, src2);
context.Assembler.Setcc(dest, X86Condition.Below); context.Assembler.Setcc(dest, X86Condition.Equal);
break; break;
case Intrinsic.X86Comisseq: case Intrinsic.X86Comissge:
context.Assembler.Comiss(src1, src2); context.Assembler.Comiss(src1, src2);
context.Assembler.Setcc(dest, X86Condition.Equal); context.Assembler.Setcc(dest, X86Condition.AboveOrEqual);
break; break;
case Intrinsic.X86Comissge: case Intrinsic.X86Comisslt:
context.Assembler.Comiss(src1, src2); context.Assembler.Comiss(src1, src2);
context.Assembler.Setcc(dest, X86Condition.AboveOrEqual); context.Assembler.Setcc(dest, X86Condition.Below);
break; break;
case Intrinsic.X86Comisslt:
context.Assembler.Comiss(src1, src2);
context.Assembler.Setcc(dest, X86Condition.Below);
break;
}
context.Assembler.Movzx8(dest, dest, OperandType.I32);
break;
} }
context.Assembler.Movzx8(dest, dest, OperandType.I32);
break;
}
case IntrinsicType.Mxcsr: case IntrinsicType.Mxcsr:
{
Operand offset = operation.GetSource(0);
Debug.Assert(offset.Kind == OperandKind.Constant);
Debug.Assert(offset.Type == OperandType.I32);
int offs = offset.AsInt32() + context.CallArgsRegionSize;
Operand rsp = Register(X86Register.Rsp);
Operand memOp = MemoryOp(OperandType.I32, rsp, default, Multiplier.x1, offs);
Debug.Assert(HardwareCapabilities.SupportsSse || HardwareCapabilities.SupportsVexEncoding);
if (operation.Intrinsic == Intrinsic.X86Ldmxcsr)
{ {
Operand offset = operation.GetSource(0); Operand bits = operation.GetSource(1);
Debug.Assert(bits.Type == OperandType.I32);
Debug.Assert(offset.Kind == OperandKind.Constant); context.Assembler.Mov(memOp, bits, OperandType.I32);
Debug.Assert(offset.Type == OperandType.I32); context.Assembler.Ldmxcsr(memOp);
int offs = offset.AsInt32() + context.CallArgsRegionSize;
Operand rsp = Register(X86Register.Rsp);
Operand memOp = MemoryOp(OperandType.I32, rsp, default, Multiplier.x1, offs);
Debug.Assert(HardwareCapabilities.SupportsSse || HardwareCapabilities.SupportsVexEncoding);
if (operation.Intrinsic == Intrinsic.X86Ldmxcsr)
{
Operand bits = operation.GetSource(1);
Debug.Assert(bits.Type == OperandType.I32);
context.Assembler.Mov(memOp, bits, OperandType.I32);
context.Assembler.Ldmxcsr(memOp);
}
else if (operation.Intrinsic == Intrinsic.X86Stmxcsr)
{
Operand dest = operation.Destination;
Debug.Assert(dest.Type == OperandType.I32);
context.Assembler.Stmxcsr(memOp);
context.Assembler.Mov(dest, memOp, OperandType.I32);
}
break;
} }
else if (operation.Intrinsic == Intrinsic.X86Stmxcsr)
{
Operand dest = operation.Destination;
Debug.Assert(dest.Type == OperandType.I32);
context.Assembler.Stmxcsr(memOp);
context.Assembler.Mov(dest, memOp, OperandType.I32);
}
break;
}
case IntrinsicType.PopCount: case IntrinsicType.PopCount:
{ {
Operand dest = operation.Destination; Operand dest = operation.Destination;
Operand source = operation.GetSource(0); Operand source = operation.GetSource(0);
EnsureSameType(dest, source); EnsureSameType(dest, source);
Debug.Assert(dest.Type.IsInteger()); Debug.Assert(dest.Type.IsInteger());
context.Assembler.Popcnt(dest, source, dest.Type); context.Assembler.Popcnt(dest, source, dest.Type);
break; break;
} }
case IntrinsicType.Unary: case IntrinsicType.Unary:
{ {
Operand dest = operation.Destination; Operand dest = operation.Destination;
Operand source = operation.GetSource(0); Operand source = operation.GetSource(0);
EnsureSameType(dest, source); EnsureSameType(dest, source);
Debug.Assert(!dest.Type.IsInteger()); Debug.Assert(!dest.Type.IsInteger());
context.Assembler.WriteInstruction(info.Inst, dest, source); context.Assembler.WriteInstruction(info.Inst, dest, source);
break; break;
} }
case IntrinsicType.UnaryToGpr: case IntrinsicType.UnaryToGpr:
{
Operand dest = operation.Destination;
Operand source = operation.GetSource(0);
Debug.Assert(dest.Type.IsInteger() && !source.Type.IsInteger());
if (operation.Intrinsic == Intrinsic.X86Cvtsi2si)
{ {
Operand dest = operation.Destination; if (dest.Type == OperandType.I32)
Operand source = operation.GetSource(0);
Debug.Assert(dest.Type.IsInteger() && !source.Type.IsInteger());
if (operation.Intrinsic == Intrinsic.X86Cvtsi2si)
{ {
if (dest.Type == OperandType.I32) context.Assembler.Movd(dest, source); // int _mm_cvtsi128_si32(__m128i a)
{
context.Assembler.Movd(dest, source); // int _mm_cvtsi128_si32(__m128i a)
}
else /* if (dest.Type == OperandType.I64) */
{
context.Assembler.Movq(dest, source); // __int64 _mm_cvtsi128_si64(__m128i a)
}
} }
else else /* if (dest.Type == OperandType.I64) */
{ {
context.Assembler.WriteInstruction(info.Inst, dest, source, dest.Type); context.Assembler.Movq(dest, source); // __int64 _mm_cvtsi128_si64(__m128i a)
} }
break;
} }
else
{
context.Assembler.WriteInstruction(info.Inst, dest, source, dest.Type);
}
break;
}
case IntrinsicType.Binary: case IntrinsicType.Binary:
{
Operand dest = operation.Destination;
Operand src1 = operation.GetSource(0);
Operand src2 = operation.GetSource(1);
EnsureSameType(dest, src1);
if (!HardwareCapabilities.SupportsVexEncoding)
{ {
Operand dest = operation.Destination; EnsureSameReg(dest, src1);
Operand src1 = operation.GetSource(0);
Operand src2 = operation.GetSource(1);
EnsureSameType(dest, src1);
if (!HardwareCapabilities.SupportsVexEncoding)
{
EnsureSameReg(dest, src1);
}
Debug.Assert(!dest.Type.IsInteger());
Debug.Assert(!src2.Type.IsInteger() || src2.Kind == OperandKind.Constant);
context.Assembler.WriteInstruction(info.Inst, dest, src1, src2);
break;
} }
Debug.Assert(!dest.Type.IsInteger());
Debug.Assert(!src2.Type.IsInteger() || src2.Kind == OperandKind.Constant);
context.Assembler.WriteInstruction(info.Inst, dest, src1, src2);
break;
}
case IntrinsicType.BinaryGpr: case IntrinsicType.BinaryGpr:
{
Operand dest = operation.Destination;
Operand src1 = operation.GetSource(0);
Operand src2 = operation.GetSource(1);
EnsureSameType(dest, src1);
if (!HardwareCapabilities.SupportsVexEncoding)
{ {
Operand dest = operation.Destination; EnsureSameReg(dest, src1);
Operand src1 = operation.GetSource(0);
Operand src2 = operation.GetSource(1);
EnsureSameType(dest, src1);
if (!HardwareCapabilities.SupportsVexEncoding)
{
EnsureSameReg(dest, src1);
}
Debug.Assert(!dest.Type.IsInteger() && src2.Type.IsInteger());
context.Assembler.WriteInstruction(info.Inst, dest, src1, src2, src2.Type);
break;
} }
Debug.Assert(!dest.Type.IsInteger() && src2.Type.IsInteger());
context.Assembler.WriteInstruction(info.Inst, dest, src1, src2, src2.Type);
break;
}
case IntrinsicType.Crc32: case IntrinsicType.Crc32:
{ {
Operand dest = operation.Destination; Operand dest = operation.Destination;
Operand src1 = operation.GetSource(0); Operand src1 = operation.GetSource(0);
Operand src2 = operation.GetSource(1); Operand src2 = operation.GetSource(1);
EnsureSameReg(dest, src1); EnsureSameReg(dest, src1);
Debug.Assert(dest.Type.IsInteger() && src1.Type.IsInteger() && src2.Type.IsInteger()); Debug.Assert(dest.Type.IsInteger() && src1.Type.IsInteger() && src2.Type.IsInteger());
context.Assembler.WriteInstruction(info.Inst, dest, src2, dest.Type); context.Assembler.WriteInstruction(info.Inst, dest, src2, dest.Type);
break; break;
} }
case IntrinsicType.BinaryImm: case IntrinsicType.BinaryImm:
{
Operand dest = operation.Destination;
Operand src1 = operation.GetSource(0);
Operand src2 = operation.GetSource(1);
EnsureSameType(dest, src1);
if (!HardwareCapabilities.SupportsVexEncoding)
{ {
Operand dest = operation.Destination; EnsureSameReg(dest, src1);
Operand src1 = operation.GetSource(0);
Operand src2 = operation.GetSource(1);
EnsureSameType(dest, src1);
if (!HardwareCapabilities.SupportsVexEncoding)
{
EnsureSameReg(dest, src1);
}
Debug.Assert(!dest.Type.IsInteger() && src2.Kind == OperandKind.Constant);
context.Assembler.WriteInstruction(info.Inst, dest, src1, src2.AsByte());
break;
} }
Debug.Assert(!dest.Type.IsInteger() && src2.Kind == OperandKind.Constant);
context.Assembler.WriteInstruction(info.Inst, dest, src1, src2.AsByte());
break;
}
case IntrinsicType.Ternary: case IntrinsicType.Ternary:
{
Operand dest = operation.Destination;
Operand src1 = operation.GetSource(0);
Operand src2 = operation.GetSource(1);
Operand src3 = operation.GetSource(2);
EnsureSameType(dest, src1, src2, src3);
Debug.Assert(!dest.Type.IsInteger());
if (info.Inst == X86Instruction.Blendvpd && HardwareCapabilities.SupportsVexEncoding)
{ {
Operand dest = operation.Destination; context.Assembler.WriteInstruction(X86Instruction.Vblendvpd, dest, src1, src2, src3);
Operand src1 = operation.GetSource(0);
Operand src2 = operation.GetSource(1);
Operand src3 = operation.GetSource(2);
EnsureSameType(dest, src1, src2, src3);
Debug.Assert(!dest.Type.IsInteger());
if (info.Inst == X86Instruction.Blendvpd && HardwareCapabilities.SupportsVexEncoding)
{
context.Assembler.WriteInstruction(X86Instruction.Vblendvpd, dest, src1, src2, src3);
}
else if (info.Inst == X86Instruction.Blendvps && HardwareCapabilities.SupportsVexEncoding)
{
context.Assembler.WriteInstruction(X86Instruction.Vblendvps, dest, src1, src2, src3);
}
else if (info.Inst == X86Instruction.Pblendvb && HardwareCapabilities.SupportsVexEncoding)
{
context.Assembler.WriteInstruction(X86Instruction.Vpblendvb, dest, src1, src2, src3);
}
else
{
EnsureSameReg(dest, src1);
Debug.Assert(src3.GetRegister().Index == 0);
context.Assembler.WriteInstruction(info.Inst, dest, src1, src2);
}
break;
} }
else if (info.Inst == X86Instruction.Blendvps && HardwareCapabilities.SupportsVexEncoding)
{
context.Assembler.WriteInstruction(X86Instruction.Vblendvps, dest, src1, src2, src3);
}
else if (info.Inst == X86Instruction.Pblendvb && HardwareCapabilities.SupportsVexEncoding)
{
context.Assembler.WriteInstruction(X86Instruction.Vpblendvb, dest, src1, src2, src3);
}
else
{
EnsureSameReg(dest, src1);
Debug.Assert(src3.GetRegister().Index == 0);
context.Assembler.WriteInstruction(info.Inst, dest, src1, src2);
}
break;
}
case IntrinsicType.TernaryImm: case IntrinsicType.TernaryImm:
{
Operand dest = operation.Destination;
Operand src1 = operation.GetSource(0);
Operand src2 = operation.GetSource(1);
Operand src3 = operation.GetSource(2);
EnsureSameType(dest, src1, src2);
if (!HardwareCapabilities.SupportsVexEncoding)
{ {
Operand dest = operation.Destination; EnsureSameReg(dest, src1);
Operand src1 = operation.GetSource(0);
Operand src2 = operation.GetSource(1);
Operand src3 = operation.GetSource(2);
EnsureSameType(dest, src1, src2);
if (!HardwareCapabilities.SupportsVexEncoding)
{
EnsureSameReg(dest, src1);
}
Debug.Assert(!dest.Type.IsInteger() && src3.Kind == OperandKind.Constant);
context.Assembler.WriteInstruction(info.Inst, dest, src1, src2, src3.AsByte());
break;
} }
Debug.Assert(!dest.Type.IsInteger() && src3.Kind == OperandKind.Constant);
context.Assembler.WriteInstruction(info.Inst, dest, src1, src2, src3.AsByte());
break;
}
case IntrinsicType.Fma: case IntrinsicType.Fma:
{ {
Operand dest = operation.Destination; Operand dest = operation.Destination;
Operand src1 = operation.GetSource(0); Operand src1 = operation.GetSource(0);
Operand src2 = operation.GetSource(1); Operand src2 = operation.GetSource(1);
Operand src3 = operation.GetSource(2); Operand src3 = operation.GetSource(2);
Debug.Assert(HardwareCapabilities.SupportsVexEncoding); Debug.Assert(HardwareCapabilities.SupportsVexEncoding);
Debug.Assert(dest.Kind == OperandKind.Register && src1.Kind == OperandKind.Register && src2.Kind == OperandKind.Register); Debug.Assert(dest.Kind == OperandKind.Register && src1.Kind == OperandKind.Register && src2.Kind == OperandKind.Register);
Debug.Assert(src3.Kind == OperandKind.Register || src3.Kind == OperandKind.Memory); Debug.Assert(src3.Kind == OperandKind.Register || src3.Kind == OperandKind.Memory);
EnsureSameType(dest, src1, src2, src3); EnsureSameType(dest, src1, src2, src3);
Debug.Assert(dest.Type == OperandType.V128); Debug.Assert(dest.Type == OperandType.V128);
Debug.Assert(dest.Value == src1.Value); Debug.Assert(dest.Value == src1.Value);
context.Assembler.WriteInstruction(info.Inst, dest, src2, src3); context.Assembler.WriteInstruction(info.Inst, dest, src2, src3);
break; break;
} }
} }
} }
else else
@ -594,7 +592,7 @@ namespace ARMeilleure.CodeGen.X86
private static void GenerateBitwiseNot(CodeGenContext context, Operation operation) private static void GenerateBitwiseNot(CodeGenContext context, Operation operation)
{ {
Operand dest = operation.Destination; Operand dest = operation.Destination;
Operand source = operation.GetSource(0); Operand source = operation.GetSource(0);
ValidateUnOp(dest, source); ValidateUnOp(dest, source);
@ -632,7 +630,7 @@ namespace ARMeilleure.CodeGen.X86
private static void GenerateByteSwap(CodeGenContext context, Operation operation) private static void GenerateByteSwap(CodeGenContext context, Operation operation)
{ {
Operand dest = operation.Destination; Operand dest = operation.Destination;
Operand source = operation.GetSource(0); Operand source = operation.GetSource(0);
ValidateUnOp(dest, source); ValidateUnOp(dest, source);
@ -763,19 +761,19 @@ namespace ARMeilleure.CodeGen.X86
Operand src2 = operation.GetSource(1); Operand src2 = operation.GetSource(1);
Operand src3 = operation.GetSource(2); Operand src3 = operation.GetSource(2);
EnsureSameReg(dest, src3); EnsureSameReg (dest, src3);
EnsureSameType(dest, src2, src3); EnsureSameType(dest, src2, src3);
Debug.Assert(dest.Type.IsInteger()); Debug.Assert(dest.Type.IsInteger());
Debug.Assert(src1.Type == OperandType.I32); Debug.Assert(src1.Type == OperandType.I32);
context.Assembler.Test(src1, src1, src1.Type); context.Assembler.Test (src1, src1, src1.Type);
context.Assembler.Cmovcc(dest, src2, dest.Type, X86Condition.NotEqual); context.Assembler.Cmovcc(dest, src2, dest.Type, X86Condition.NotEqual);
} }
private static void GenerateConvertI64ToI32(CodeGenContext context, Operation operation) private static void GenerateConvertI64ToI32(CodeGenContext context, Operation operation)
{ {
Operand dest = operation.Destination; Operand dest = operation.Destination;
Operand source = operation.GetSource(0); Operand source = operation.GetSource(0);
Debug.Assert(dest.Type == OperandType.I32 && source.Type == OperandType.I64); Debug.Assert(dest.Type == OperandType.I32 && source.Type == OperandType.I64);
@ -785,7 +783,7 @@ namespace ARMeilleure.CodeGen.X86
private static void GenerateConvertToFP(CodeGenContext context, Operation operation) private static void GenerateConvertToFP(CodeGenContext context, Operation operation)
{ {
Operand dest = operation.Destination; Operand dest = operation.Destination;
Operand source = operation.GetSource(0); Operand source = operation.GetSource(0);
Debug.Assert(dest.Type == OperandType.FP32 || dest.Type == OperandType.FP64); Debug.Assert(dest.Type == OperandType.FP32 || dest.Type == OperandType.FP64);
@ -796,7 +794,7 @@ namespace ARMeilleure.CodeGen.X86
if (source.Type.IsInteger()) if (source.Type.IsInteger())
{ {
context.Assembler.Xorps(dest, dest, dest); context.Assembler.Xorps (dest, dest, dest);
context.Assembler.Cvtsi2ss(dest, dest, source, source.Type); context.Assembler.Cvtsi2ss(dest, dest, source, source.Type);
} }
else /* if (source.Type == OperandType.FP64) */ else /* if (source.Type == OperandType.FP64) */
@ -812,7 +810,7 @@ namespace ARMeilleure.CodeGen.X86
if (source.Type.IsInteger()) if (source.Type.IsInteger())
{ {
context.Assembler.Xorps(dest, dest, dest); context.Assembler.Xorps (dest, dest, dest);
context.Assembler.Cvtsi2sd(dest, dest, source, source.Type); context.Assembler.Cvtsi2sd(dest, dest, source, source.Type);
} }
else /* if (source.Type == OperandType.FP32) */ else /* if (source.Type == OperandType.FP32) */
@ -826,7 +824,7 @@ namespace ARMeilleure.CodeGen.X86
private static void GenerateCopy(CodeGenContext context, Operation operation) private static void GenerateCopy(CodeGenContext context, Operation operation)
{ {
Operand dest = operation.Destination; Operand dest = operation.Destination;
Operand source = operation.GetSource(0); Operand source = operation.GetSource(0);
EnsureSameType(dest, source); EnsureSameType(dest, source);
@ -839,7 +837,7 @@ namespace ARMeilleure.CodeGen.X86
return; return;
} }
if (dest.Kind == OperandKind.Register && if (dest.Kind == OperandKind.Register &&
source.Kind == OperandKind.Constant && source.Value == 0) source.Kind == OperandKind.Constant && source.Value == 0)
{ {
// Assemble "mov reg, 0" as "xor reg, reg" as the later is more efficient. // Assemble "mov reg, 0" as "xor reg, reg" as the later is more efficient.
@ -857,7 +855,7 @@ namespace ARMeilleure.CodeGen.X86
private static void GenerateCountLeadingZeros(CodeGenContext context, Operation operation) private static void GenerateCountLeadingZeros(CodeGenContext context, Operation operation)
{ {
Operand dest = operation.Destination; Operand dest = operation.Destination;
Operand source = operation.GetSource(0); Operand source = operation.GetSource(0);
EnsureSameType(dest, source); EnsureSameType(dest, source);
@ -890,9 +888,9 @@ namespace ARMeilleure.CodeGen.X86
private static void GenerateDivide(CodeGenContext context, Operation operation) private static void GenerateDivide(CodeGenContext context, Operation operation)
{ {
Operand dest = operation.Destination; Operand dest = operation.Destination;
Operand dividend = operation.GetSource(0); Operand dividend = operation.GetSource(0);
Operand divisor = operation.GetSource(1); Operand divisor = operation.GetSource(1);
if (!dest.Type.IsInteger()) if (!dest.Type.IsInteger())
{ {
@ -940,7 +938,7 @@ namespace ARMeilleure.CodeGen.X86
private static void GenerateFill(CodeGenContext context, Operation operation) private static void GenerateFill(CodeGenContext context, Operation operation)
{ {
Operand dest = operation.Destination; Operand dest = operation.Destination;
Operand offset = operation.GetSource(0); Operand offset = operation.GetSource(0);
Debug.Assert(offset.Kind == OperandKind.Constant); Debug.Assert(offset.Kind == OperandKind.Constant);
@ -956,7 +954,7 @@ namespace ARMeilleure.CodeGen.X86
private static void GenerateLoad(CodeGenContext context, Operation operation) private static void GenerateLoad(CodeGenContext context, Operation operation)
{ {
Operand value = operation.Destination; Operand value = operation.Destination;
Operand address = Memory(operation.GetSource(0), value.Type); Operand address = Memory(operation.GetSource(0), value.Type);
GenerateLoad(context, address, value); GenerateLoad(context, address, value);
@ -964,7 +962,7 @@ namespace ARMeilleure.CodeGen.X86
private static void GenerateLoad16(CodeGenContext context, Operation operation) private static void GenerateLoad16(CodeGenContext context, Operation operation)
{ {
Operand value = operation.Destination; Operand value = operation.Destination;
Operand address = Memory(operation.GetSource(0), value.Type); Operand address = Memory(operation.GetSource(0), value.Type);
Debug.Assert(value.Type.IsInteger()); Debug.Assert(value.Type.IsInteger());
@ -974,7 +972,7 @@ namespace ARMeilleure.CodeGen.X86
private static void GenerateLoad8(CodeGenContext context, Operation operation) private static void GenerateLoad8(CodeGenContext context, Operation operation)
{ {
Operand value = operation.Destination; Operand value = operation.Destination;
Operand address = Memory(operation.GetSource(0), value.Type); Operand address = Memory(operation.GetSource(0), value.Type);
Debug.Assert(value.Type.IsInteger()); Debug.Assert(value.Type.IsInteger());
@ -1041,7 +1039,7 @@ namespace ARMeilleure.CodeGen.X86
private static void GenerateNegate(CodeGenContext context, Operation operation) private static void GenerateNegate(CodeGenContext context, Operation operation)
{ {
Operand dest = operation.Destination; Operand dest = operation.Destination;
Operand source = operation.GetSource(0); Operand source = operation.GetSource(0);
ValidateUnOp(dest, source); ValidateUnOp(dest, source);
@ -1104,7 +1102,7 @@ namespace ARMeilleure.CodeGen.X86
private static void GenerateSignExtend16(CodeGenContext context, Operation operation) private static void GenerateSignExtend16(CodeGenContext context, Operation operation)
{ {
Operand dest = operation.Destination; Operand dest = operation.Destination;
Operand source = operation.GetSource(0); Operand source = operation.GetSource(0);
Debug.Assert(dest.Type.IsInteger() && source.Type.IsInteger()); Debug.Assert(dest.Type.IsInteger() && source.Type.IsInteger());
@ -1114,7 +1112,7 @@ namespace ARMeilleure.CodeGen.X86
private static void GenerateSignExtend32(CodeGenContext context, Operation operation) private static void GenerateSignExtend32(CodeGenContext context, Operation operation)
{ {
Operand dest = operation.Destination; Operand dest = operation.Destination;
Operand source = operation.GetSource(0); Operand source = operation.GetSource(0);
Debug.Assert(dest.Type.IsInteger() && source.Type.IsInteger()); Debug.Assert(dest.Type.IsInteger() && source.Type.IsInteger());
@ -1124,7 +1122,7 @@ namespace ARMeilleure.CodeGen.X86
private static void GenerateSignExtend8(CodeGenContext context, Operation operation) private static void GenerateSignExtend8(CodeGenContext context, Operation operation)
{ {
Operand dest = operation.Destination; Operand dest = operation.Destination;
Operand source = operation.GetSource(0); Operand source = operation.GetSource(0);
Debug.Assert(dest.Type.IsInteger() && source.Type.IsInteger()); Debug.Assert(dest.Type.IsInteger() && source.Type.IsInteger());
@ -1160,7 +1158,7 @@ namespace ARMeilleure.CodeGen.X86
private static void GenerateStackAlloc(CodeGenContext context, Operation operation) private static void GenerateStackAlloc(CodeGenContext context, Operation operation)
{ {
Operand dest = operation.Destination; Operand dest = operation.Destination;
Operand offset = operation.GetSource(0); Operand offset = operation.GetSource(0);
Debug.Assert(offset.Kind == OperandKind.Constant); Debug.Assert(offset.Kind == OperandKind.Constant);
@ -1176,7 +1174,7 @@ namespace ARMeilleure.CodeGen.X86
private static void GenerateStore(CodeGenContext context, Operation operation) private static void GenerateStore(CodeGenContext context, Operation operation)
{ {
Operand value = operation.GetSource(1); Operand value = operation.GetSource(1);
Operand address = Memory(operation.GetSource(0), value.Type); Operand address = Memory(operation.GetSource(0), value.Type);
GenerateStore(context, address, value); GenerateStore(context, address, value);
@ -1184,7 +1182,7 @@ namespace ARMeilleure.CodeGen.X86
private static void GenerateStore16(CodeGenContext context, Operation operation) private static void GenerateStore16(CodeGenContext context, Operation operation)
{ {
Operand value = operation.GetSource(1); Operand value = operation.GetSource(1);
Operand address = Memory(operation.GetSource(0), value.Type); Operand address = Memory(operation.GetSource(0), value.Type);
Debug.Assert(value.Type.IsInteger()); Debug.Assert(value.Type.IsInteger());
@ -1194,7 +1192,7 @@ namespace ARMeilleure.CodeGen.X86
private static void GenerateStore8(CodeGenContext context, Operation operation) private static void GenerateStore8(CodeGenContext context, Operation operation)
{ {
Operand value = operation.GetSource(1); Operand value = operation.GetSource(1);
Operand address = Memory(operation.GetSource(0), value.Type); Operand address = Memory(operation.GetSource(0), value.Type);
Debug.Assert(value.Type.IsInteger()); Debug.Assert(value.Type.IsInteger());
@ -1233,7 +1231,7 @@ namespace ARMeilleure.CodeGen.X86
private static void GenerateVectorCreateScalar(CodeGenContext context, Operation operation) private static void GenerateVectorCreateScalar(CodeGenContext context, Operation operation)
{ {
Operand dest = operation.Destination; Operand dest = operation.Destination;
Operand source = operation.GetSource(0); Operand source = operation.GetSource(0);
Debug.Assert(!dest.Type.IsInteger() && source.Type.IsInteger()); Debug.Assert(!dest.Type.IsInteger() && source.Type.IsInteger());
@ -1280,7 +1278,7 @@ namespace ARMeilleure.CodeGen.X86
mask1 = BitUtils.RotateRight(mask1, 8 - index * 2, 8); mask1 = BitUtils.RotateRight(mask1, 8 - index * 2, 8);
context.Assembler.Pshufd(src1, src1, (byte)mask0); context.Assembler.Pshufd(src1, src1, (byte)mask0);
context.Assembler.Movd(dest, src1); context.Assembler.Movd (dest, src1);
context.Assembler.Pshufd(src1, src1, (byte)mask1); context.Assembler.Pshufd(src1, src1, (byte)mask1);
} }
} }
@ -1296,11 +1294,11 @@ namespace ARMeilleure.CodeGen.X86
} }
else else
{ {
const byte Mask = 0b01_00_11_10; const byte mask = 0b01_00_11_10;
context.Assembler.Pshufd(src1, src1, Mask); context.Assembler.Pshufd(src1, src1, mask);
context.Assembler.Movq(dest, src1); context.Assembler.Movq (dest, src1);
context.Assembler.Pshufd(src1, src1, Mask); context.Assembler.Pshufd(src1, src1, mask);
} }
} }
else else
@ -1310,7 +1308,7 @@ namespace ARMeilleure.CodeGen.X86
(index == 1 && dest.Type == OperandType.FP64)) (index == 1 && dest.Type == OperandType.FP64))
{ {
context.Assembler.Movhlps(dest, dest, src1); context.Assembler.Movhlps(dest, dest, src1);
context.Assembler.Movq(dest, dest); context.Assembler.Movq (dest, dest);
} }
else else
{ {
@ -1457,11 +1455,11 @@ namespace ARMeilleure.CodeGen.X86
int mask0 = 0b11_10_01_00; int mask0 = 0b11_10_01_00;
int mask1 = 0b11_10_01_00; int mask1 = 0b11_10_01_00;
mask0 = BitUtils.RotateRight(mask0, index * 2, 8); mask0 = BitUtils.RotateRight(mask0, index * 2, 8);
mask1 = BitUtils.RotateRight(mask1, 8 - index * 2, 8); mask1 = BitUtils.RotateRight(mask1, 8 - index * 2, 8);
context.Assembler.Pshufd(src1, src1, (byte)mask0); // Lane to be inserted in position 0. context.Assembler.Pshufd(src1, src1, (byte)mask0); // Lane to be inserted in position 0.
context.Assembler.Movss(dest, src1, src2); // dest[127:0] = src1[127:32] | src2[31:0] context.Assembler.Movss (dest, src1, src2); // dest[127:0] = src1[127:32] | src2[31:0]
context.Assembler.Pshufd(dest, dest, (byte)mask1); // Inserted lane in original position. context.Assembler.Pshufd(dest, dest, (byte)mask1); // Inserted lane in original position.
if (dest.GetRegister() != src1.GetRegister()) if (dest.GetRegister() != src1.GetRegister())
@ -1557,7 +1555,7 @@ namespace ARMeilleure.CodeGen.X86
private static void GenerateVectorZeroUpper64(CodeGenContext context, Operation operation) private static void GenerateVectorZeroUpper64(CodeGenContext context, Operation operation)
{ {
Operand dest = operation.Destination; Operand dest = operation.Destination;
Operand source = operation.GetSource(0); Operand source = operation.GetSource(0);
Debug.Assert(dest.Type == OperandType.V128 && source.Type == OperandType.V128); Debug.Assert(dest.Type == OperandType.V128 && source.Type == OperandType.V128);
@ -1567,7 +1565,7 @@ namespace ARMeilleure.CodeGen.X86
private static void GenerateVectorZeroUpper96(CodeGenContext context, Operation operation) private static void GenerateVectorZeroUpper96(CodeGenContext context, Operation operation)
{ {
Operand dest = operation.Destination; Operand dest = operation.Destination;
Operand source = operation.GetSource(0); Operand source = operation.GetSource(0);
Debug.Assert(dest.Type == OperandType.V128 && source.Type == OperandType.V128); Debug.Assert(dest.Type == OperandType.V128 && source.Type == OperandType.V128);
@ -1577,7 +1575,7 @@ namespace ARMeilleure.CodeGen.X86
private static void GenerateZeroExtend16(CodeGenContext context, Operation operation) private static void GenerateZeroExtend16(CodeGenContext context, Operation operation)
{ {
Operand dest = operation.Destination; Operand dest = operation.Destination;
Operand source = operation.GetSource(0); Operand source = operation.GetSource(0);
Debug.Assert(dest.Type.IsInteger() && source.Type.IsInteger()); Debug.Assert(dest.Type.IsInteger() && source.Type.IsInteger());
@ -1587,7 +1585,7 @@ namespace ARMeilleure.CodeGen.X86
private static void GenerateZeroExtend32(CodeGenContext context, Operation operation) private static void GenerateZeroExtend32(CodeGenContext context, Operation operation)
{ {
Operand dest = operation.Destination; Operand dest = operation.Destination;
Operand source = operation.GetSource(0); Operand source = operation.GetSource(0);
Debug.Assert(dest.Type.IsInteger() && source.Type.IsInteger()); Debug.Assert(dest.Type.IsInteger() && source.Type.IsInteger());
@ -1603,7 +1601,7 @@ namespace ARMeilleure.CodeGen.X86
private static void GenerateZeroExtend8(CodeGenContext context, Operation operation) private static void GenerateZeroExtend8(CodeGenContext context, Operation operation)
{ {
Operand dest = operation.Destination; Operand dest = operation.Destination;
Operand source = operation.GetSource(0); Operand source = operation.GetSource(0);
Debug.Assert(dest.Type.IsInteger() && source.Type.IsInteger()); Debug.Assert(dest.Type.IsInteger() && source.Type.IsInteger());
@ -1615,25 +1613,13 @@ namespace ARMeilleure.CodeGen.X86
{ {
switch (value.Type) switch (value.Type)
{ {
case OperandType.I32: case OperandType.I32: context.Assembler.Mov (value, address, OperandType.I32); break;
context.Assembler.Mov(value, address, OperandType.I32); case OperandType.I64: context.Assembler.Mov (value, address, OperandType.I64); break;
break; case OperandType.FP32: context.Assembler.Movd (value, address); break;
case OperandType.I64: case OperandType.FP64: context.Assembler.Movq (value, address); break;
context.Assembler.Mov(value, address, OperandType.I64); case OperandType.V128: context.Assembler.Movdqu(value, address); break;
break;
case OperandType.FP32:
context.Assembler.Movd(value, address);
break;
case OperandType.FP64:
context.Assembler.Movq(value, address);
break;
case OperandType.V128:
context.Assembler.Movdqu(value, address);
break;
default: default: Debug.Assert(false); break;
Debug.Assert(false);
break;
} }
} }
@ -1641,25 +1627,13 @@ namespace ARMeilleure.CodeGen.X86
{ {
switch (value.Type) switch (value.Type)
{ {
case OperandType.I32: case OperandType.I32: context.Assembler.Mov (address, value, OperandType.I32); break;
context.Assembler.Mov(address, value, OperandType.I32); case OperandType.I64: context.Assembler.Mov (address, value, OperandType.I64); break;
break; case OperandType.FP32: context.Assembler.Movd (address, value); break;
case OperandType.I64: case OperandType.FP64: context.Assembler.Movq (address, value); break;
context.Assembler.Mov(address, value, OperandType.I64); case OperandType.V128: context.Assembler.Movdqu(address, value); break;
break;
case OperandType.FP32:
context.Assembler.Movd(address, value);
break;
case OperandType.FP64:
context.Assembler.Movq(address, value);
break;
case OperandType.V128:
context.Assembler.Movdqu(address, value);
break;
default: default: Debug.Assert(false); break;
Debug.Assert(false);
break;
} }
} }
@ -1696,21 +1670,21 @@ namespace ARMeilleure.CodeGen.X86
[Conditional("DEBUG")] [Conditional("DEBUG")]
private static void ValidateUnOp(Operand dest, Operand source) private static void ValidateUnOp(Operand dest, Operand source)
{ {
EnsureSameReg(dest, source); EnsureSameReg (dest, source);
EnsureSameType(dest, source); EnsureSameType(dest, source);
} }
[Conditional("DEBUG")] [Conditional("DEBUG")]
private static void ValidateBinOp(Operand dest, Operand src1, Operand src2) private static void ValidateBinOp(Operand dest, Operand src1, Operand src2)
{ {
EnsureSameReg(dest, src1); EnsureSameReg (dest, src1);
EnsureSameType(dest, src1, src2); EnsureSameType(dest, src1, src2);
} }
[Conditional("DEBUG")] [Conditional("DEBUG")]
private static void ValidateShift(Operand dest, Operand src1, Operand src2) private static void ValidateShift(Operand dest, Operand src1, Operand src2)
{ {
EnsureSameReg(dest, src1); EnsureSameReg (dest, src1);
EnsureSameType(dest, src1); EnsureSameType(dest, src1);
Debug.Assert(dest.Type.IsInteger() && src2.Type == OperandType.I32); Debug.Assert(dest.Type.IsInteger() && src2.Type == OperandType.I32);
@ -1748,7 +1722,7 @@ namespace ARMeilleure.CodeGen.X86
private static UnwindInfo WritePrologue(CodeGenContext context) private static UnwindInfo WritePrologue(CodeGenContext context)
{ {
List<UnwindPushEntry> pushEntries = new(); List<UnwindPushEntry> pushEntries = new List<UnwindPushEntry>();
Operand rsp = Register(X86Register.Rsp); Operand rsp = Register(X86Register.Rsp);
@ -1853,11 +1827,11 @@ namespace ARMeilleure.CodeGen.X86
// that the OS will map all pages that we'll use. We do that by // that the OS will map all pages that we'll use. We do that by
// doing a dummy read on those pages, forcing a page fault and // doing a dummy read on those pages, forcing a page fault and
// the OS to map them. If they are already mapped, nothing happens. // the OS to map them. If they are already mapped, nothing happens.
const int PageMask = PageSize - 1; const int pageMask = PageSize - 1;
size = (size + PageMask) & ~PageMask; size = (size + pageMask) & ~pageMask;
Operand rsp = Register(X86Register.Rsp); Operand rsp = Register(X86Register.Rsp);
Operand temp = Register(CallingConvention.GetIntReturnRegister()); Operand temp = Register(CallingConvention.GetIntReturnRegister());
for (int offset = PageSize; offset < size; offset += PageSize) for (int offset = PageSize; offset < size; offset += PageSize)

View file

@ -47,7 +47,7 @@ namespace ARMeilleure.CodeGen.X86
0xc3, // ret 0xc3, // ret
}; };
using MemoryBlock memGetXcr0 = new((ulong)asmGetXcr0.Length); using MemoryBlock memGetXcr0 = new MemoryBlock((ulong)asmGetXcr0.Length);
memGetXcr0.Write(0, asmGetXcr0); memGetXcr0.Write(0, asmGetXcr0);
@ -62,7 +62,7 @@ namespace ARMeilleure.CodeGen.X86
public enum FeatureFlags1Edx public enum FeatureFlags1Edx
{ {
Sse = 1 << 25, Sse = 1 << 25,
Sse2 = 1 << 26, Sse2 = 1 << 26
} }
[Flags] [Flags]
@ -79,7 +79,7 @@ namespace ARMeilleure.CodeGen.X86
Xsave = 1 << 26, Xsave = 1 << 26,
Osxsave = 1 << 27, Osxsave = 1 << 27,
Avx = 1 << 28, Avx = 1 << 28,
F16c = 1 << 29, F16c = 1 << 29
} }
[Flags] [Flags]
@ -90,7 +90,7 @@ namespace ARMeilleure.CodeGen.X86
Avx512dq = 1 << 17, Avx512dq = 1 << 17,
Sha = 1 << 29, Sha = 1 << 29,
Avx512bw = 1 << 30, Avx512bw = 1 << 30,
Avx512vl = 1 << 31, Avx512vl = 1 << 31
} }
[Flags] [Flags]
@ -106,7 +106,7 @@ namespace ARMeilleure.CodeGen.X86
YmmHi128 = 1 << 2, YmmHi128 = 1 << 2,
Opmask = 1 << 5, Opmask = 1 << 5,
ZmmHi256 = 1 << 6, ZmmHi256 = 1 << 6,
Hi16Zmm = 1 << 7, Hi16Zmm = 1 << 7
} }
public static FeatureFlags1Edx FeatureInfo1Edx { get; } public static FeatureFlags1Edx FeatureInfo1Edx { get; }

View file

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

View file

@ -5,13 +5,12 @@ namespace ARMeilleure.CodeGen.X86
{ {
static class IntrinsicTable static class IntrinsicTable
{ {
private static readonly IntrinsicInfo[] _intrinTable; private static IntrinsicInfo[] _intrinTable;
static IntrinsicTable() static IntrinsicTable()
{ {
_intrinTable = new IntrinsicInfo[EnumUtils.GetCount(typeof(Intrinsic))]; _intrinTable = new IntrinsicInfo[EnumUtils.GetCount(typeof(Intrinsic))];
#pragma warning disable IDE0055 // Disable formatting
Add(Intrinsic.X86Addpd, new IntrinsicInfo(X86Instruction.Addpd, IntrinsicType.Binary)); Add(Intrinsic.X86Addpd, new IntrinsicInfo(X86Instruction.Addpd, IntrinsicType.Binary));
Add(Intrinsic.X86Addps, new IntrinsicInfo(X86Instruction.Addps, IntrinsicType.Binary)); Add(Intrinsic.X86Addps, new IntrinsicInfo(X86Instruction.Addps, IntrinsicType.Binary));
Add(Intrinsic.X86Addsd, new IntrinsicInfo(X86Instruction.Addsd, IntrinsicType.Binary)); Add(Intrinsic.X86Addsd, new IntrinsicInfo(X86Instruction.Addsd, IntrinsicType.Binary));
@ -186,7 +185,6 @@ namespace ARMeilleure.CodeGen.X86
Add(Intrinsic.X86Vpternlogd, new IntrinsicInfo(X86Instruction.Vpternlogd, IntrinsicType.TernaryImm)); Add(Intrinsic.X86Vpternlogd, new IntrinsicInfo(X86Instruction.Vpternlogd, IntrinsicType.TernaryImm));
Add(Intrinsic.X86Xorpd, new IntrinsicInfo(X86Instruction.Xorpd, IntrinsicType.Binary)); Add(Intrinsic.X86Xorpd, new IntrinsicInfo(X86Instruction.Xorpd, IntrinsicType.Binary));
Add(Intrinsic.X86Xorps, new IntrinsicInfo(X86Instruction.Xorps, IntrinsicType.Binary)); Add(Intrinsic.X86Xorps, new IntrinsicInfo(X86Instruction.Xorps, IntrinsicType.Binary));
#pragma warning restore IDE0055
} }
private static void Add(Intrinsic intrin, IntrinsicInfo info) private static void Add(Intrinsic intrin, IntrinsicInfo info)

View file

@ -13,6 +13,6 @@ namespace ARMeilleure.CodeGen.X86
Crc32, Crc32,
Ternary, Ternary,
TernaryImm, TernaryImm,
Fma, Fma
} }
} }

View file

@ -1,4 +1,4 @@
using System; using System;
namespace ARMeilleure.CodeGen.X86 namespace ARMeilleure.CodeGen.X86
{ {
@ -10,6 +10,6 @@ namespace ARMeilleure.CodeGen.X86
Rlo = 1 << 13, // Round Mode low bit. Rlo = 1 << 13, // Round Mode low bit.
Um = 1 << 11, // Underflow Mask. Um = 1 << 11, // Underflow Mask.
Dm = 1 << 8, // Denormal Mask. Dm = 1 << 8, // Denormal Mask.
Daz = 1 << 6, // Denormals Are Zero. Daz = 1 << 6 // Denormals Are Zero.
} }
} }

View file

@ -104,11 +104,11 @@ namespace ARMeilleure.CodeGen.X86
case Instruction.Tailcall: case Instruction.Tailcall:
if (callConv == CallConvName.Windows) if (callConv == CallConvName.Windows)
{ {
PreAllocatorWindows.InsertTailcallCopies(block.Operations, node); PreAllocatorWindows.InsertTailcallCopies(block.Operations, stackAlloc, node);
} }
else else
{ {
PreAllocatorSystemV.InsertTailcallCopies(block.Operations, node); PreAllocatorSystemV.InsertTailcallCopies(block.Operations, stackAlloc, node);
} }
break; break;
@ -177,7 +177,10 @@ namespace ARMeilleure.CodeGen.X86
{ {
src2 = node.GetSource(1); src2 = node.GetSource(1);
(src2, src1) = (src1, src2); Operand temp = src1;
src1 = src2;
src2 = temp;
node.SetSource(0, src1); node.SetSource(0, src1);
node.SetSource(1, src2); node.SetSource(1, src2);
@ -225,151 +228,151 @@ namespace ARMeilleure.CodeGen.X86
case Instruction.CompareAndSwap: case Instruction.CompareAndSwap:
case Instruction.CompareAndSwap16: case Instruction.CompareAndSwap16:
case Instruction.CompareAndSwap8: case Instruction.CompareAndSwap8:
{
OperandType type = node.GetSource(1).Type;
if (type == OperandType.V128)
{ {
OperandType type = node.GetSource(1).Type; // Handle the many restrictions of the compare and exchange (16 bytes) instruction:
// - The expected value should be in RDX:RAX.
if (type == OperandType.V128) // - 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)
{ {
// Handle the many restrictions of the compare and exchange (16 bytes) instruction: nodes.AddBefore(node, Operation(Instruction.VectorExtract, lr, source, Const(0)));
// - The expected value should be in RDX:RAX. nodes.AddBefore(node, Operation(Instruction.VectorExtract, hr, source, Const(1)));
// - 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; 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.Divide:
case Instruction.DivideUI: 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())
{ {
// 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 src1 = node.GetSource(0);
Operand rax = Gpr(X86Register.Rax, src1.Type); Operand rax = Gpr(X86Register.Rax, src1.Type);
Operand rdx = Gpr(X86Register.Rdx, src1.Type); Operand rdx = Gpr(X86Register.Rdx, src1.Type);
nodes.AddBefore(node, Operation(Instruction.Copy, rax, src1)); nodes.AddBefore(node, Operation(Instruction.Copy, rax, src1));
nodes.AddBefore(node, Operation(Instruction.Clobber, rdx));
node.SetSource(0, rax); nodes.AddAfter(node, Operation(Instruction.Copy, dest, rax));
nodes.AddAfter(node, Operation(Instruction.Copy, dest, rdx)); node.SetSources(new Operand[] { rdx, rax, node.GetSource(1) });
node.Destination = rax;
node.SetDestinations(new Operand[] { rdx, rax });
break;
} }
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.RotateRight:
case Instruction.ShiftLeft: case Instruction.ShiftLeft:
case Instruction.ShiftRightSI: case Instruction.ShiftRightSI:
case Instruction.ShiftRightUI: 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)
{ {
// The shift register is always implied to be CL (low 8-bits of RCX or ECX). Operand rcx = Gpr(X86Register.Rcx, OperandType.I32);
if (node.GetSource(1).Kind == OperandKind.LocalVariable)
{
Operand rcx = Gpr(X86Register.Rcx, OperandType.I32);
nodes.AddBefore(node, Operation(Instruction.Copy, rcx, node.GetSource(1))); nodes.AddBefore(node, Operation(Instruction.Copy, rcx, node.GetSource(1)));
node.SetSource(1, rcx); node.SetSource(1, rcx);
}
break;
} }
break;
}
} }
} }
@ -456,7 +459,7 @@ namespace ARMeilleure.CodeGen.X86
// Unsigned integer to FP conversions are not supported on X86. // Unsigned integer to FP conversions are not supported on X86.
// We need to turn them into signed integer to FP conversions, and // We need to turn them into signed integer to FP conversions, and
// adjust the final result. // adjust the final result.
Operand dest = node.Destination; Operand dest = node.Destination;
Operand source = node.GetSource(0); Operand source = node.GetSource(0);
Debug.Assert(source.Type.IsInteger(), $"Invalid source type \"{source.Type}\"."); Debug.Assert(source.Type.IsInteger(), $"Invalid source type \"{source.Type}\".");
@ -469,8 +472,8 @@ namespace ARMeilleure.CodeGen.X86
// and then use the 64-bits signed conversion instructions. // and then use the 64-bits signed conversion instructions.
Operand zex = Local(OperandType.I64); Operand zex = Local(OperandType.I64);
node = nodes.AddAfter(node, Operation(Instruction.ZeroExtend32, zex, source)); node = nodes.AddAfter(node, Operation(Instruction.ZeroExtend32, zex, source));
nodes.AddAfter(node, Operation(Instruction.ConvertToFP, dest, zex)); node = nodes.AddAfter(node, Operation(Instruction.ConvertToFP, dest, zex));
} }
else /* if (source.Type == OperandType.I64) */ else /* if (source.Type == OperandType.I64) */
{ {
@ -484,15 +487,15 @@ namespace ARMeilleure.CodeGen.X86
// --- This can be done efficiently by adding the result to itself. // --- This can be done efficiently by adding the result to itself.
// -- Then, we need to add the least significant bit that was shifted out. // -- 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. // --- We can convert the least significant bit to float, and add it to the result.
Operand lsb = Local(OperandType.I64); Operand lsb = Local(OperandType.I64);
Operand half = Local(OperandType.I64); Operand half = Local(OperandType.I64);
Operand lsbF = Local(dest.Type); Operand lsbF = Local(dest.Type);
node = nodes.AddAfter(node, Operation(Instruction.Copy, lsb, source)); node = nodes.AddAfter(node, Operation(Instruction.Copy, lsb, source));
node = nodes.AddAfter(node, Operation(Instruction.Copy, half, 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.BitwiseAnd, lsb, lsb, Const(1L)));
node = nodes.AddAfter(node, Operation(Instruction.ShiftRightUI, half, half, Const(1))); 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, lsbF, lsb));
@ -510,7 +513,7 @@ namespace ARMeilleure.CodeGen.X86
// There's no SSE FP negate instruction, so we need to transform that into // 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. // 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. // This also produces -0 for a negation of the value 0.
Operand dest = node.Destination; Operand dest = node.Destination;
Operand source = node.GetSource(0); Operand source = node.GetSource(0);
Debug.Assert(dest.Type == OperandType.FP32 || Debug.Assert(dest.Type == OperandType.FP32 ||
@ -566,14 +569,14 @@ namespace ARMeilleure.CodeGen.X86
if ((index & 1) != 0) if ((index & 1) != 0)
{ {
node = nodes.AddAfter(node, Operation(Instruction.ZeroExtend8, temp1, temp1)); 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.ShiftLeft, temp2, temp2, Const(8)));
node = nodes.AddAfter(node, Operation(Instruction.BitwiseOr, temp1, temp1, temp2)); node = nodes.AddAfter(node, Operation(Instruction.BitwiseOr, temp1, temp1, temp2));
} }
else else
{ {
node = nodes.AddAfter(node, Operation(Instruction.ZeroExtend8, temp2, temp2)); 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.BitwiseAnd, temp1, temp1, Const(0xff00)));
node = nodes.AddAfter(node, Operation(Instruction.BitwiseOr, temp1, temp1, temp2)); node = nodes.AddAfter(node, Operation(Instruction.BitwiseOr, temp1, temp1, temp2));
} }
Operation vinsOp = Operation(Instruction.VectorInsert16, dest, src1, temp1, Const(index >> 1)); Operation vinsOp = Operation(Instruction.VectorInsert16, dest, src1, temp1, Const(index >> 1));
@ -706,11 +709,16 @@ namespace ARMeilleure.CodeGen.X86
private static bool HasConstSrc1(Instruction inst) private static bool HasConstSrc1(Instruction inst)
{ {
return inst switch switch (inst)
{ {
Instruction.Copy or Instruction.LoadArgument or Instruction.Spill or Instruction.SpillArg => true, case Instruction.Copy:
_ => false, case Instruction.LoadArgument:
}; case Instruction.Spill:
case Instruction.SpillArg:
return true;
}
return false;
} }
private static bool HasConstSrc2(Instruction inst) private static bool HasConstSrc2(Instruction inst)
@ -754,15 +762,15 @@ namespace ARMeilleure.CodeGen.X86
case Instruction.BranchIf: case Instruction.BranchIf:
case Instruction.Compare: case Instruction.Compare:
{ {
Operand comp = operation.GetSource(2); Operand comp = operation.GetSource(2);
Debug.Assert(comp.Kind == OperandKind.Constant); Debug.Assert(comp.Kind == OperandKind.Constant);
var compType = (Comparison)comp.AsInt32(); var compType = (Comparison)comp.AsInt32();
return compType == Comparison.Equal || compType == Comparison.NotEqual; return compType == Comparison.Equal || compType == Comparison.NotEqual;
} }
} }
return false; return false;

View file

@ -1,3 +1,4 @@
using ARMeilleure.CodeGen.RegisterAllocators;
using ARMeilleure.IntermediateRepresentation; using ARMeilleure.IntermediateRepresentation;
using ARMeilleure.Translation; using ARMeilleure.Translation;
using System; using System;
@ -14,9 +15,9 @@ namespace ARMeilleure.CodeGen.X86
{ {
Operand dest = node.Destination; Operand dest = node.Destination;
List<Operand> sources = new() List<Operand> sources = new List<Operand>
{ {
node.GetSource(0), node.GetSource(0)
}; };
int argsCount = node.SourcesCount - 1; int argsCount = node.SourcesCount - 1;
@ -51,10 +52,10 @@ namespace ARMeilleure.CodeGen.X86
if (source.Type == OperandType.V128 && passOnReg) if (source.Type == OperandType.V128 && passOnReg)
{ {
// V128 is a struct, we pass each half on a GPR if possible. // V128 is a struct, we pass each half on a GPR if possible.
Operand argReg = Gpr(CallingConvention.GetIntArgumentRegister(intCount++), OperandType.I64); Operand argReg = Gpr(CallingConvention.GetIntArgumentRegister(intCount++), OperandType.I64);
Operand argReg2 = 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, argReg, source, Const(0)));
nodes.AddBefore(node, Operation(Instruction.VectorExtract, argReg2, source, Const(1))); nodes.AddBefore(node, Operation(Instruction.VectorExtract, argReg2, source, Const(1)));
continue; continue;
@ -90,7 +91,7 @@ namespace ARMeilleure.CodeGen.X86
{ {
if (dest.Type == OperandType.V128) if (dest.Type == OperandType.V128)
{ {
Operand retLReg = Gpr(CallingConvention.GetIntReturnRegister(), OperandType.I64); Operand retLReg = Gpr(CallingConvention.GetIntReturnRegister(), OperandType.I64);
Operand retHReg = Gpr(CallingConvention.GetIntReturnRegisterHigh(), OperandType.I64); Operand retHReg = Gpr(CallingConvention.GetIntReturnRegisterHigh(), OperandType.I64);
Operation operation = node; Operation operation = node;
@ -115,11 +116,11 @@ namespace ARMeilleure.CodeGen.X86
} }
} }
public static void InsertTailcallCopies(IntrusiveList<Operation> nodes, Operation node) public static void InsertTailcallCopies(IntrusiveList<Operation> nodes, StackAllocator stackAlloc, Operation node)
{ {
List<Operand> sources = new() List<Operand> sources = new List<Operand>
{ {
node.GetSource(0), node.GetSource(0)
}; };
int argsCount = node.SourcesCount - 1; int argsCount = node.SourcesCount - 1;
@ -250,11 +251,11 @@ namespace ARMeilleure.CodeGen.X86
// V128 is a struct, we pass each half on a GPR if possible. // V128 is a struct, we pass each half on a GPR if possible.
Operand pArg = Local(OperandType.V128); Operand pArg = Local(OperandType.V128);
Operand argLReg = Gpr(CallingConvention.GetIntArgumentRegister(intCount), OperandType.I64); Operand argLReg = Gpr(CallingConvention.GetIntArgumentRegister(intCount), OperandType.I64);
Operand argHReg = Gpr(CallingConvention.GetIntArgumentRegister(intCount + 1), OperandType.I64); Operand argHReg = Gpr(CallingConvention.GetIntArgumentRegister(intCount + 1), OperandType.I64);
Operation copyL = Operation(Instruction.VectorCreateScalar, pArg, argLReg); Operation copyL = Operation(Instruction.VectorCreateScalar, pArg, argLReg);
Operation copyH = Operation(Instruction.VectorInsert, pArg, pArg, argHReg, Const(1)); Operation copyH = Operation(Instruction.VectorInsert, pArg, pArg, argHReg, Const(1));
cctx.Cfg.Entry.Operations.AddFirst(copyH); cctx.Cfg.Entry.Operations.AddFirst(copyH);
cctx.Cfg.Entry.Operations.AddFirst(copyL); cctx.Cfg.Entry.Operations.AddFirst(copyL);
@ -312,7 +313,7 @@ namespace ARMeilleure.CodeGen.X86
if (source.Type == OperandType.V128) if (source.Type == OperandType.V128)
{ {
Operand retLReg = Gpr(CallingConvention.GetIntReturnRegister(), OperandType.I64); Operand retLReg = Gpr(CallingConvention.GetIntReturnRegister(), OperandType.I64);
Operand retHReg = Gpr(CallingConvention.GetIntReturnRegisterHigh(), 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, retLReg, source, Const(0)));

View file

@ -155,7 +155,7 @@ namespace ARMeilleure.CodeGen.X86
node.SetSources(sources); node.SetSources(sources);
} }
public static void InsertTailcallCopies(IntrusiveList<Operation> nodes, Operation node) public static void InsertTailcallCopies(IntrusiveList<Operation> nodes, StackAllocator stackAlloc, Operation node)
{ {
int argsCount = node.SourcesCount - 1; int argsCount = node.SourcesCount - 1;
int maxArgs = CallingConvention.GetArgumentsOnRegsCount(); int maxArgs = CallingConvention.GetArgumentsOnRegsCount();

View file

@ -5,22 +5,22 @@ namespace ARMeilleure.CodeGen.X86
{ {
enum X86Condition enum X86Condition
{ {
Overflow = 0x0, Overflow = 0x0,
NotOverflow = 0x1, NotOverflow = 0x1,
Below = 0x2, Below = 0x2,
AboveOrEqual = 0x3, AboveOrEqual = 0x3,
Equal = 0x4, Equal = 0x4,
NotEqual = 0x5, NotEqual = 0x5,
BelowOrEqual = 0x6, BelowOrEqual = 0x6,
Above = 0x7, Above = 0x7,
Sign = 0x8, Sign = 0x8,
NotSign = 0x9, NotSign = 0x9,
ParityEven = 0xa, ParityEven = 0xa,
ParityOdd = 0xb, ParityOdd = 0xb,
Less = 0xc, Less = 0xc,
GreaterOrEqual = 0xd, GreaterOrEqual = 0xd,
LessOrEqual = 0xe, LessOrEqual = 0xe,
Greater = 0xf, Greater = 0xf
} }
static class ComparisonX86Extensions static class ComparisonX86Extensions
@ -29,7 +29,6 @@ namespace ARMeilleure.CodeGen.X86
{ {
return comp switch return comp switch
{ {
#pragma warning disable IDE0055 // Disable formatting
Comparison.Equal => X86Condition.Equal, Comparison.Equal => X86Condition.Equal,
Comparison.NotEqual => X86Condition.NotEqual, Comparison.NotEqual => X86Condition.NotEqual,
Comparison.Greater => X86Condition.Greater, Comparison.Greater => X86Condition.Greater,
@ -40,9 +39,8 @@ namespace ARMeilleure.CodeGen.X86
Comparison.Less => X86Condition.Less, Comparison.Less => X86Condition.Less,
Comparison.GreaterOrEqualUI => X86Condition.AboveOrEqual, Comparison.GreaterOrEqualUI => X86Condition.AboveOrEqual,
Comparison.LessUI => X86Condition.Below, Comparison.LessUI => X86Condition.Below,
#pragma warning restore IDE0055
_ => throw new ArgumentException(null, nameof(comp)), _ => throw new ArgumentException(null, nameof(comp))
}; };
} }
} }

View file

@ -226,6 +226,6 @@ namespace ARMeilleure.CodeGen.X86
Xorpd, Xorpd,
Xorps, Xorps,
Count, Count
} }
} }

View file

@ -1,4 +1,4 @@
using ARMeilleure.CodeGen.Optimizations; using ARMeilleure.CodeGen.Optimizations;
using ARMeilleure.IntermediateRepresentation; using ARMeilleure.IntermediateRepresentation;
using ARMeilleure.Translation; using ARMeilleure.Translation;
using System.Collections.Generic; using System.Collections.Generic;
@ -215,7 +215,7 @@ namespace ARMeilleure.CodeGen.X86
1 => Multiplier.x2, 1 => Multiplier.x2,
2 => Multiplier.x4, 2 => Multiplier.x4,
3 => Multiplier.x8, 3 => Multiplier.x8,
_ => Multiplier.x1, _ => Multiplier.x1
}; };
baseOp = indexOnSrc2 ? src1 : src2; baseOp = indexOnSrc2 ? src1 : src2;

View file

@ -1,8 +1,5 @@
using System.Diagnostics.CodeAnalysis;
namespace ARMeilleure.CodeGen.X86 namespace ARMeilleure.CodeGen.X86
{ {
[SuppressMessage("Design", "CA1069: Enums values should not be duplicated")]
enum X86Register enum X86Register
{ {
Invalid = -1, Invalid = -1,
@ -15,8 +12,8 @@ namespace ARMeilleure.CodeGen.X86
Rbp = 5, Rbp = 5,
Rsi = 6, Rsi = 6,
Rdi = 7, Rdi = 7,
R8 = 8, R8 = 8,
R9 = 9, R9 = 9,
R10 = 10, R10 = 10,
R11 = 11, R11 = 11,
R12 = 12, R12 = 12,
@ -24,21 +21,21 @@ namespace ARMeilleure.CodeGen.X86
R14 = 14, R14 = 14,
R15 = 15, R15 = 15,
Xmm0 = 0, Xmm0 = 0,
Xmm1 = 1, Xmm1 = 1,
Xmm2 = 2, Xmm2 = 2,
Xmm3 = 3, Xmm3 = 3,
Xmm4 = 4, Xmm4 = 4,
Xmm5 = 5, Xmm5 = 5,
Xmm6 = 6, Xmm6 = 6,
Xmm7 = 7, Xmm7 = 7,
Xmm8 = 8, Xmm8 = 8,
Xmm9 = 9, Xmm9 = 9,
Xmm10 = 10, Xmm10 = 10,
Xmm11 = 11, Xmm11 = 11,
Xmm12 = 12, Xmm12 = 12,
Xmm13 = 13, Xmm13 = 13,
Xmm14 = 14, Xmm14 = 14,
Xmm15 = 15, Xmm15 = 15
} }
} }

View file

@ -1,4 +1,4 @@
using ARMeilleure.Diagnostics; using ARMeilleure.Diagnostics;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
@ -9,7 +9,7 @@ namespace ARMeilleure.Common
/// Represents a table of guest address to a value. /// Represents a table of guest address to a value.
/// </summary> /// </summary>
/// <typeparam name="TEntry">Type of the value</typeparam> /// <typeparam name="TEntry">Type of the value</typeparam>
public unsafe class AddressTable<TEntry> : IDisposable where TEntry : unmanaged unsafe class AddressTable<TEntry> : IDisposable where TEntry : unmanaged
{ {
/// <summary> /// <summary>
/// Represents a level in an <see cref="AddressTable{TEntry}"/>. /// Represents a level in an <see cref="AddressTable{TEntry}"/>.

View file

@ -1,4 +1,4 @@
using System; using System;
namespace ARMeilleure.Common namespace ARMeilleure.Common
{ {

View file

@ -1,4 +1,4 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
@ -82,10 +82,8 @@ namespace ARMeilleure.Common
} }
else else
{ {
_page = new PageInfo _page = new PageInfo();
{ _page.Pointer = (byte*)NativeAllocator.Instance.Allocate(_pageSize);
Pointer = (byte*)NativeAllocator.Instance.Allocate(_pageSize),
};
_pages.Add(_page); _pages.Add(_page);
} }
@ -108,7 +106,7 @@ namespace ARMeilleure.Common
// Free excess pages that was allocated. // Free excess pages that was allocated.
while (_pages.Count > _pageCount) while (_pages.Count > _pageCount)
{ {
NativeAllocator.Instance.Free(_pages[^1].Pointer); NativeAllocator.Instance.Free(_pages[_pages.Count - 1].Pointer);
_pages.RemoveAt(_pages.Count - 1); _pages.RemoveAt(_pages.Count - 1);
} }
@ -127,13 +125,12 @@ namespace ARMeilleure.Common
// If arena is used frequently, keep pages for longer. Otherwise keep pages for a shorter amount of time. // If arena is used frequently, keep pages for longer. Otherwise keep pages for a shorter amount of time.
int now = Environment.TickCount; int now = Environment.TickCount;
int count = (now - _lastReset) switch int count = (now - _lastReset) switch {
{
>= 5000 => 0, >= 5000 => 0,
>= 2500 => 50, >= 2500 => 50,
>= 1000 => 100, >= 1000 => 100,
>= 10 => 1500, >= 10 => 1500,
_ => 5000, _ => 5000
}; };
for (int i = _pages.Count - 1; i >= 0; i--) for (int i = _pages.Count - 1; i >= 0; i--)

View file

@ -138,7 +138,7 @@ namespace ARMeilleure.Common
var newSpan = new Span<long>(_masks, _count); var newSpan = new Span<long>(_masks, _count);
oldSpan.CopyTo(newSpan); oldSpan.CopyTo(newSpan);
newSpan[oldSpan.Length..].Clear(); newSpan.Slice(oldSpan.Length).Clear();
_allocator.Free(oldMask); _allocator.Free(oldMask);
} }
@ -176,8 +176,8 @@ namespace ARMeilleure.Common
private int _bit; private int _bit;
private readonly BitMap _map; private readonly BitMap _map;
public readonly int Current => (int)_index * IntSize + _bit; public int Current => (int)_index * IntSize + _bit;
readonly object IEnumerator.Current => Current; object IEnumerator.Current => Current;
public Enumerator(BitMap map) public Enumerator(BitMap map)
{ {
@ -214,9 +214,9 @@ namespace ARMeilleure.Common
return true; return true;
} }
public readonly void Reset() { } public void Reset() { }
public readonly void Dispose() { } public void Dispose() { }
} }
} }
} }

View file

@ -1,4 +1,4 @@
using System; using System;
namespace ARMeilleure.Common namespace ARMeilleure.Common
{ {

View file

@ -1,4 +1,4 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Numerics; using System.Numerics;

View file

@ -1,4 +1,4 @@
using System; using System;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
namespace ARMeilleure.Common namespace ARMeilleure.Common

View file

@ -5,10 +5,10 @@ namespace ARMeilleure.Decoders
{ {
class Block class Block
{ {
public ulong Address { get; set; } public ulong Address { get; set; }
public ulong EndAddress { get; set; } public ulong EndAddress { get; set; }
public Block Next { get; set; } public Block Next { get; set; }
public Block Branch { get; set; } public Block Branch { get; set; }
public bool Exit { get; set; } public bool Exit { get; set; }
@ -43,14 +43,14 @@ namespace ARMeilleure.Decoders
rightBlock.EndAddress = EndAddress; rightBlock.EndAddress = EndAddress;
rightBlock.Next = Next; rightBlock.Next = Next;
rightBlock.Branch = Branch; rightBlock.Branch = Branch;
rightBlock.OpCodes.AddRange(OpCodes.GetRange(splitIndex, splitCount)); rightBlock.OpCodes.AddRange(OpCodes.GetRange(splitIndex, splitCount));
EndAddress = rightBlock.Address; EndAddress = rightBlock.Address;
Next = rightBlock; Next = rightBlock;
Branch = null; Branch = null;
OpCodes.RemoveRange(splitIndex, splitCount); OpCodes.RemoveRange(splitIndex, splitCount);
@ -58,9 +58,9 @@ namespace ARMeilleure.Decoders
private static int BinarySearch(List<OpCode> opCodes, ulong address) private static int BinarySearch(List<OpCode> opCodes, ulong address)
{ {
int left = 0; int left = 0;
int middle = 0; int middle = 0;
int right = opCodes.Count - 1; int right = opCodes.Count - 1;
while (left <= right) while (left <= right)
{ {
@ -92,7 +92,7 @@ namespace ARMeilleure.Decoders
{ {
if (OpCodes.Count > 0) if (OpCodes.Count > 0)
{ {
return OpCodes[^1]; return OpCodes[OpCodes.Count - 1];
} }
return null; return null;

View file

@ -2,22 +2,22 @@ namespace ARMeilleure.Decoders
{ {
enum Condition enum Condition
{ {
Eq = 0, Eq = 0,
Ne = 1, Ne = 1,
GeUn = 2, GeUn = 2,
LtUn = 3, LtUn = 3,
Mi = 4, Mi = 4,
Pl = 5, Pl = 5,
Vs = 6, Vs = 6,
Vc = 7, Vc = 7,
GtUn = 8, GtUn = 8,
LeUn = 9, LeUn = 9,
Ge = 10, Ge = 10,
Lt = 11, Lt = 11,
Gt = 12, Gt = 12,
Le = 13, Le = 13,
Al = 14, Al = 14,
Nv = 15, Nv = 15
} }
static class ConditionExtensions static class ConditionExtensions

View file

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

View file

@ -20,11 +20,11 @@ namespace ARMeilleure.Decoders
public static Block[] Decode(IMemoryManager memory, ulong address, ExecutionMode mode, bool highCq, DecoderMode dMode) public static Block[] Decode(IMemoryManager memory, ulong address, ExecutionMode mode, bool highCq, DecoderMode dMode)
{ {
List<Block> blocks = new(); List<Block> blocks = new List<Block>();
Queue<Block> workQueue = new(); Queue<Block> workQueue = new Queue<Block>();
Dictionary<ulong, Block> visited = new(); Dictionary<ulong, Block> visited = new Dictionary<ulong, Block>();
Debug.Assert(MaxInstsPerFunctionLowCq <= MaxInstsPerFunction); Debug.Assert(MaxInstsPerFunctionLowCq <= MaxInstsPerFunction);
@ -38,9 +38,7 @@ namespace ARMeilleure.Decoders
{ {
block = new Block(blkAddress); block = new Block(blkAddress);
if ((dMode != DecoderMode.MultipleBlocks && visited.Count >= 1) || if ((dMode != DecoderMode.MultipleBlocks && visited.Count >= 1) || opsCount > instructionLimit || !memory.IsMapped(blkAddress))
opsCount > instructionLimit ||
(visited.Count > 0 && !memory.IsMapped(blkAddress)))
{ {
block.Exit = true; block.Exit = true;
block.EndAddress = blkAddress; block.EndAddress = blkAddress;
@ -165,7 +163,7 @@ namespace ARMeilleure.Decoders
{ {
index = 0; index = 0;
int left = 0; int left = 0;
int right = blocks.Count - 1; int right = blocks.Count - 1;
while (left <= right) while (left <= right)
@ -198,9 +196,9 @@ namespace ARMeilleure.Decoders
private static void FillBlock( private static void FillBlock(
IMemoryManager memory, IMemoryManager memory,
ExecutionMode mode, ExecutionMode mode,
Block block, Block block,
ulong limitAddress) ulong limitAddress)
{ {
ulong address = block.Address; ulong address = block.Address;
int itBlockSize = 0; int itBlockSize = 0;
@ -243,12 +241,12 @@ namespace ARMeilleure.Decoders
private static bool IsUnconditionalBranch(OpCode opCode) private static bool IsUnconditionalBranch(OpCode opCode)
{ {
return opCode is OpCodeBImmAl || return opCode is OpCodeBImmAl ||
opCode is OpCodeBReg || IsAarch32UnconditionalBranch(opCode); opCode is OpCodeBReg || IsAarch32UnconditionalBranch(opCode);
} }
private static bool IsAarch32UnconditionalBranch(OpCode opCode) private static bool IsAarch32UnconditionalBranch(OpCode opCode)
{ {
if (opCode is not OpCode32 op) if (!(opCode is OpCode32 op))
{ {
return false; return false;
} }
@ -292,9 +290,9 @@ namespace ARMeilleure.Decoders
if (opCode is IOpCode32Mem opMem) if (opCode is IOpCode32Mem opMem)
{ {
rt = opMem.Rt; rt = opMem.Rt;
rn = opMem.Rn; rn = opMem.Rn;
wBack = opMem.WBack; wBack = opMem.WBack;
isLoad = opMem.IsLoad; isLoad = opMem.IsLoad;
// For the dual load, we also need to take into account the // For the dual load, we also need to take into account the
@ -306,12 +304,12 @@ namespace ARMeilleure.Decoders
} }
else if (opCode is IOpCode32MemMult opMemMult) else if (opCode is IOpCode32MemMult opMemMult)
{ {
const int PCMask = 1 << RegisterAlias.Aarch32Pc; const int pcMask = 1 << RegisterAlias.Aarch32Pc;
rt = (opMemMult.RegisterMask & PCMask) != 0 ? RegisterAlias.Aarch32Pc : 0; rt = (opMemMult.RegisterMask & pcMask) != 0 ? RegisterAlias.Aarch32Pc : 0;
rn = opMemMult.Rn; rn = opMemMult.Rn;
wBack = opMemMult.PostOffset != 0; wBack = opMemMult.PostOffset != 0;
isLoad = opMemMult.IsLoad; isLoad = opMemMult.IsLoad;
} }
else else
{ {

View file

@ -10,7 +10,7 @@ namespace ARMeilleure.Decoders
Imm8ToFP64Table = BuildImm8ToFP64Table(); Imm8ToFP64Table = BuildImm8ToFP64Table();
} }
public static readonly uint[] Imm8ToFP32Table; public static readonly uint[] Imm8ToFP32Table;
public static readonly ulong[] Imm8ToFP64Table; public static readonly ulong[] Imm8ToFP64Table;
private static uint[] BuildImm8ToFP32Table() private static uint[] BuildImm8ToFP32Table()
@ -40,47 +40,47 @@ namespace ARMeilleure.Decoders
// abcdefgh -> aBbbbbbc defgh000 00000000 00000000 (B = ~b) // abcdefgh -> aBbbbbbc defgh000 00000000 00000000 (B = ~b)
private static uint ExpandImm8ToFP32(uint imm) private static uint ExpandImm8ToFP32(uint imm)
{ {
static uint MoveBit(uint bits, int from, int to) uint MoveBit(uint bits, int from, int to)
{ {
return ((bits >> from) & 1U) << to; return ((bits >> from) & 1U) << to;
} }
return MoveBit(imm, 7, 31) | MoveBit(~imm, 6, 30) | return MoveBit(imm, 7, 31) | MoveBit(~imm, 6, 30) |
MoveBit(imm, 6, 29) | MoveBit(imm, 6, 28) | MoveBit(imm, 6, 29) | MoveBit( imm, 6, 28) |
MoveBit(imm, 6, 27) | MoveBit(imm, 6, 26) | MoveBit(imm, 6, 27) | MoveBit( imm, 6, 26) |
MoveBit(imm, 6, 25) | MoveBit(imm, 5, 24) | MoveBit(imm, 6, 25) | MoveBit( imm, 5, 24) |
MoveBit(imm, 4, 23) | MoveBit(imm, 3, 22) | MoveBit(imm, 4, 23) | MoveBit( imm, 3, 22) |
MoveBit(imm, 2, 21) | MoveBit(imm, 1, 20) | MoveBit(imm, 2, 21) | MoveBit( imm, 1, 20) |
MoveBit(imm, 0, 19); MoveBit(imm, 0, 19);
} }
// abcdefgh -> aBbbbbbb bbcdefgh 00000000 00000000 00000000 00000000 00000000 00000000 (B = ~b) // abcdefgh -> aBbbbbbb bbcdefgh 00000000 00000000 00000000 00000000 00000000 00000000 (B = ~b)
private static ulong ExpandImm8ToFP64(ulong imm) private static ulong ExpandImm8ToFP64(ulong imm)
{ {
static ulong MoveBit(ulong bits, int from, int to) ulong MoveBit(ulong bits, int from, int to)
{ {
return ((bits >> from) & 1UL) << to; return ((bits >> from) & 1UL) << to;
} }
return MoveBit(imm, 7, 63) | MoveBit(~imm, 6, 62) | return MoveBit(imm, 7, 63) | MoveBit(~imm, 6, 62) |
MoveBit(imm, 6, 61) | MoveBit(imm, 6, 60) | MoveBit(imm, 6, 61) | MoveBit( imm, 6, 60) |
MoveBit(imm, 6, 59) | MoveBit(imm, 6, 58) | MoveBit(imm, 6, 59) | MoveBit( imm, 6, 58) |
MoveBit(imm, 6, 57) | MoveBit(imm, 6, 56) | MoveBit(imm, 6, 57) | MoveBit( imm, 6, 56) |
MoveBit(imm, 6, 55) | MoveBit(imm, 6, 54) | MoveBit(imm, 6, 55) | MoveBit( imm, 6, 54) |
MoveBit(imm, 5, 53) | MoveBit(imm, 4, 52) | MoveBit(imm, 5, 53) | MoveBit( imm, 4, 52) |
MoveBit(imm, 3, 51) | MoveBit(imm, 2, 50) | MoveBit(imm, 3, 51) | MoveBit( imm, 2, 50) |
MoveBit(imm, 1, 49) | MoveBit(imm, 0, 48); MoveBit(imm, 1, 49) | MoveBit( imm, 0, 48);
} }
public struct BitMask public struct BitMask
{ {
public long WMask; public long WMask;
public long TMask; public long TMask;
public int Pos; public int Pos;
public int Shift; public int Shift;
public bool IsUndefined; public bool IsUndefined;
public static BitMask Invalid => new() { IsUndefined = true }; public static BitMask Invalid => new BitMask { IsUndefined = true };
} }
public static BitMask DecodeBitMask(int opCode, bool immediate) public static BitMask DecodeBitMask(int opCode, bool immediate)
@ -88,7 +88,7 @@ namespace ARMeilleure.Decoders
int immS = (opCode >> 10) & 0x3f; int immS = (opCode >> 10) & 0x3f;
int immR = (opCode >> 16) & 0x3f; int immR = (opCode >> 16) & 0x3f;
int n = (opCode >> 22) & 1; int n = (opCode >> 22) & 1;
int sf = (opCode >> 31) & 1; int sf = (opCode >> 31) & 1;
int length = BitUtils.HighestBitSet((~immS & 0x3f) | (n << 6)); int length = BitUtils.HighestBitSet((~immS & 0x3f) | (n << 6));
@ -115,7 +115,7 @@ namespace ARMeilleure.Decoders
if (r > 0) if (r > 0)
{ {
wMask = BitUtils.RotateRight(wMask, r, size); wMask = BitUtils.RotateRight(wMask, r, size);
wMask &= BitUtils.FillWithOnes(size); wMask &= BitUtils.FillWithOnes(size);
} }
@ -124,8 +124,8 @@ namespace ARMeilleure.Decoders
WMask = BitUtils.Replicate(wMask, size), WMask = BitUtils.Replicate(wMask, size),
TMask = BitUtils.Replicate(tMask, size), TMask = BitUtils.Replicate(tMask, size),
Pos = immS, Pos = immS,
Shift = immR, Shift = immR
}; };
} }

View file

@ -1,4 +1,4 @@
namespace ARMeilleure.Decoders namespace ARMeilleure.Decoders
{ {
enum DecoderMode enum DecoderMode
{ {

View file

@ -1,4 +1,4 @@
namespace ARMeilleure.Decoders namespace ARMeilleure.Decoders
{ {
interface IOpCode32AluBf interface IOpCode32AluBf
{ {

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