diff --git a/.editorconfig b/.editorconfig index 214e54692..9d695c7fb 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,8 +1,7 @@ # Remove the line below if you want to inherit .editorconfig settings from higher directories root = true -# C# files -[*.cs] +[*] #### Core EditorConfig Options #### @@ -12,8 +11,18 @@ indent_style = space tab_width = 4 # New line preferences -end_of_line = crlf -insert_final_newline = false +end_of_line = lf +insert_final_newline = true + +# JSON files +[*.json] + +# Indentation and spacing +indent_size = 2 +tab_width = 2 + +# C# files +[*.cs] #### .NET Coding Conventions #### @@ -59,10 +68,14 @@ dotnet_style_prefer_simplified_interpolation = true:suggestion dotnet_style_readonly_field = true:suggestion # Parameter preferences -dotnet_code_quality_unused_parameters = all:suggestion +dotnet_code_quality_unused_parameters = all:silent #### C# Coding Conventions #### +# Namespace preferences +csharp_style_namespace_declarations = block_scoped:warning +resharper_csharp_namespace_body = block_scoped + # var preferences csharp_style_var_elsewhere = false:silent csharp_style_var_for_built_in_types = false:silent @@ -81,7 +94,7 @@ csharp_style_expression_bodied_properties = true:silent # Pattern matching preferences csharp_style_pattern_matching_over_as_with_null_check = true:suggestion csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion -csharp_style_prefer_switch_expression = true:suggestion +csharp_style_prefer_switch_expression = false:silent # Null-checking preferences csharp_style_conditional_delegate_call = true:suggestion @@ -89,6 +102,8 @@ csharp_style_conditional_delegate_call = true:suggestion # Modifier preferences csharp_prefer_static_local_function = true:suggestion csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async:silent +csharp_style_prefer_readonly_struct = true +csharp_style_prefer_method_group_conversion = true # Code-block preferences csharp_prefer_braces = true:silent @@ -104,6 +119,7 @@ csharp_style_prefer_range_operator = true:suggestion csharp_style_throw_expression = true:suggestion csharp_style_unused_value_assignment_preference = discard_variable:suggestion csharp_style_unused_value_expression_statement_preference = discard_variable:silent +csharp_style_implicit_object_creation_when_type_is_apparent = true # 'using' directive preferences csharp_using_directive_placement = outside_namespace:silent @@ -135,7 +151,6 @@ csharp_space_after_dot = false csharp_space_after_keywords_in_control_flow_statements = true csharp_space_after_semicolon_in_for_statement = true csharp_space_around_binary_operators = before_and_after -csharp_space_around_declaration_statements = false csharp_space_before_colon_in_inheritance_clause = true csharp_space_before_comma = false csharp_space_before_dot = false @@ -153,23 +168,31 @@ csharp_space_between_square_brackets = false # Wrapping preferences csharp_preserve_single_line_blocks = true -csharp_preserve_single_line_statements = true +csharp_preserve_single_line_statements = false #### Naming styles #### # Naming rules -dotnet_naming_rule.interface_should_be_begins_with_i.severity = suggestion -dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface -dotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_i +dotnet_naming_rule.interfaces_should_be_prefixed_with_I.severity = suggestion +dotnet_naming_rule.interfaces_should_be_prefixed_with_I.symbols = interface +dotnet_naming_rule.interfaces_should_be_prefixed_with_I.style = IPascalCase dotnet_naming_rule.types_should_be_pascal_case.severity = suggestion dotnet_naming_rule.types_should_be_pascal_case.symbols = types -dotnet_naming_rule.types_should_be_pascal_case.style = pascal_case +dotnet_naming_rule.types_should_be_pascal_case.style = PascalCase dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = suggestion dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members -dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case +dotnet_naming_rule.non_field_members_should_be_pascal_case.style = PascalCase + +dotnet_naming_rule.private_static_readonly_fields_should_be_camel_case_and_prefixed_with__.symbols = private_static_readonly_fields +dotnet_naming_rule.private_static_readonly_fields_should_be_camel_case_and_prefixed_with__.severity = suggestion +dotnet_naming_rule.private_static_readonly_fields_should_be_camel_case_and_prefixed_with__.style = _camelCase + +dotnet_naming_rule.local_constants_should_be_pascal_case.symbols = local_constants +dotnet_naming_rule.local_constants_should_be_pascal_case.severity = suggestion +dotnet_naming_rule.local_constants_should_be_pascal_case.style = PascalCase # Symbol specifications @@ -185,14 +208,39 @@ dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, meth dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected dotnet_naming_symbols.non_field_members.required_modifiers = +dotnet_naming_symbols.private_static_readonly_fields.applicable_kinds = field +dotnet_naming_symbols.private_static_readonly_fields.applicable_accessibilities = private +dotnet_naming_symbols.private_static_readonly_fields.required_modifiers = static, readonly + +dotnet_naming_symbols.local_constants.applicable_kinds = local +dotnet_naming_symbols.local_constants.applicable_accessibilities = local +dotnet_naming_symbols.local_constants.required_modifiers = const + # Naming styles -dotnet_naming_style.pascal_case.required_prefix = -dotnet_naming_style.pascal_case.required_suffix = -dotnet_naming_style.pascal_case.word_separator = -dotnet_naming_style.pascal_case.capitalization = pascal_case +dotnet_naming_style._camelCase.required_prefix = _ +dotnet_naming_style._camelCase.required_suffix = +dotnet_naming_style._camelCase.word_separator = +dotnet_naming_style._camelCase.capitalization = camel_case -dotnet_naming_style.begins_with_i.required_prefix = I -dotnet_naming_style.begins_with_i.required_suffix = -dotnet_naming_style.begins_with_i.word_separator = -dotnet_naming_style.begins_with_i.capitalization = pascal_case \ No newline at end of file +dotnet_naming_style.PascalCase.required_prefix = +dotnet_naming_style.PascalCase.required_suffix = +dotnet_naming_style.PascalCase.word_separator = +dotnet_naming_style.PascalCase.capitalization = pascal_case + +dotnet_naming_style.IPascalCase.required_prefix = I +dotnet_naming_style.IPascalCase.required_suffix = +dotnet_naming_style.IPascalCase.word_separator = +dotnet_naming_style.IPascalCase.capitalization = pascal_case + +[src/Ryujinx.HLE/HOS/Services/**.cs] +# Disable "mark members as static" rule for services +dotnet_diagnostic.CA1822.severity = none + +[src/Ryujinx.Ava/UI/ViewModels/**.cs] +# Disable "mark members as static" rule for ViewModels +dotnet_diagnostic.CA1822.severity = none + +[src/Ryujinx.Tests/Cpu/*.cs] +# Disable naming rules for CPU tests +dotnet_diagnostic.IDE1006.severity = none diff --git a/.gitattributes b/.gitattributes index 1ff0c4230..e39a7f135 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,63 +1,4 @@ ############################################################################### # Set default behavior to automatically normalize line endings. ############################################################################### -* text=auto - -############################################################################### -# Set default behavior for command prompt diff. -# -# This is need for earlier builds of msysgit that does not have it on by -# default for csharp files. -# Note: This is only used by command line -############################################################################### -#*.cs diff=csharp - -############################################################################### -# Set the merge driver for project and solution files -# -# Merging from the command prompt will add diff markers to the files if there -# are conflicts (Merging from VS is not affected by the settings below, in VS -# the diff markers are never inserted). Diff markers may cause the following -# file extensions to fail to load in VS. An alternative would be to treat -# these files as binary and thus will always conflict and require user -# intervention with every merge. To do so, just uncomment the entries below -############################################################################### -#*.sln merge=binary -#*.csproj merge=binary -#*.vbproj merge=binary -#*.vcxproj merge=binary -#*.vcproj merge=binary -#*.dbproj merge=binary -#*.fsproj merge=binary -#*.lsproj merge=binary -#*.wixproj merge=binary -#*.modelproj merge=binary -#*.sqlproj merge=binary -#*.wwaproj merge=binary - -############################################################################### -# behavior for image files -# -# image files are treated as binary by default. -############################################################################### -#*.jpg binary -#*.png binary -#*.gif binary - -############################################################################### -# diff behavior for common document formats -# -# Convert binary document formats to text before diffing them. This feature -# is only available from the command line. Turn it on by uncommenting the -# entries below. -############################################################################### -#*.doc diff=astextplain -#*.DOC diff=astextplain -#*.docx diff=astextplain -#*.DOCX diff=astextplain -#*.dot diff=astextplain -#*.DOT diff=astextplain -#*.pdf diff=astextplain -#*.PDF diff=astextplain -#*.rtf diff=astextplain -#*.RTF diff=astextplain +* text=auto eol=lf diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md deleted file mode 100644 index cf1a7cc69..000000000 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ /dev/null @@ -1,43 +0,0 @@ ---- -name: Bug Report -about: Something doesn't work correctly in Ryujinx. Note that game-specific issues should be instead posted on the Game Compatibility List at https://github.com/Ryujinx/Ryujinx-Games-List, unless it is a provable regression. -#assignees: ---- - -## Bug Report - -[ If any section does not apply, replace its contents with "N/A". ]
-[ Lines between [ ] (square brackets) should be removed before posting. ] - -### What's the issue you encountered? - -[ Describe the issue in detail and what you were doing beforehand. ]
-[ Did you make any changes related to Ryujinx itself? ]
-[ If so, make sure to include details relating to what exactly you changed. ] - -### How can the issue be reproduced? - -[ Include a detailed step by step process for recreating your issue. ] - -### Log file - -[ Logs files can be found under ``Logs`` folder in Ryujinx program folder. ]
-[ If you don't include a crash report in instances of crash related issues, we will ask you one to provide one. ] - -### Environment? - -- Ryujinx version: 1.0.X
-[ Replace X's with the Ryujinx version at time of crash. ] -- Game version: X.X.X
-[ Replace X's with the game version at time of crash. ] -- System Specs: - - OS: *(e.g. Windows 10)* - - CPU: *(e.g. i7-6700)* - - GPU: *(e.g. NVIDIA RTX 2070)* - - RAM: *(e.g. 16GB)* -- Applied Mods : [ Yes (Which ones) / No ] - -### Additional context? - -Additional info about your environment:
-[ Any other information relevant to your issue. ] diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml new file mode 100644 index 000000000..68be1f5e0 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -0,0 +1,86 @@ +name: Bug Report +description: File a bug report +title: "[Bug]" +labels: bug +body: + - type: textarea + id: issue + attributes: + label: Description of the issue + description: What's the issue you encountered? + validations: + required: true + - type: textarea + id: repro + attributes: + label: Reproduction steps + description: How can the issue be reproduced? + placeholder: Describe each step as precisely as possible + validations: + required: true + - type: textarea + id: log + attributes: + label: Log file + description: A log file will help our developers to better diagnose and fix the issue. + placeholder: Logs files can be found under "Logs" folder in Ryujinx program folder. You can drag and drop the log on to the text area + validations: + required: true + - type: input + id: os + attributes: + label: OS + placeholder: "e.g. Windows 10" + validations: + required: true + - type: input + id: ryujinx-version + attributes: + label: Ryujinx version + placeholder: "e.g. 1.0.470" + validations: + required: true + - type: input + id: game-version + attributes: + label: Game version + placeholder: "e.g. 1.1.1" + validations: + required: false + - type: input + id: cpu + attributes: + label: CPU + placeholder: "e.g. i7-6700" + validations: + required: false + - type: input + id: gpu + attributes: + label: GPU + placeholder: "e.g. NVIDIA RTX 2070" + validations: + required: false + - type: input + id: ram + attributes: + label: RAM + placeholder: "e.g. 16GB" + validations: + required: false + - type: textarea + id: mods + attributes: + label: List of applied mods + placeholder: You can list applied mods here. + validations: + required: false + - type: textarea + id: additional-context + attributes: + label: Additional context? + description: | + - Additional info about your environment: + - Any other information relevant to your issue. + validations: + required: false \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md deleted file mode 100644 index f1855f269..000000000 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ /dev/null @@ -1,34 +0,0 @@ ---- -name: Feature Request -about: Suggest a new feature for Ryujinx. -#assignees: ---- - -## Feature Request - -[ If any section does not apply, replace its contents with "N/A". ]
-[ If you do not have the information needed for a section, replace its contents with "Unknown". ]
-[ Lines between [ ] (square brackets) are to be removed before posting. ]
- -[ Please search for existing [feature requests](https://github.com/Ryujinx/Ryujinx/issues) before you make your own request. ]
-[ Duplicate requests will be marked as such and you will be referred to the original request. ] - -### What feature are you suggesting? -#### Overview: -- [ Include the basic, high-level concepts for this feature here. ] - -#### Smaller Details: -- [ These may include specific methods of implementation etc. ] - -#### Nature of Request: -[ Remove all that do not apply to your request. ] -- Addition - - [ Ex: Addition of certain original features or features from other community projects. ] - - [ If you are suggesting porting features or including features from other projects, include what license they are distributed under and what, if any libraries those project use. ] -- Change -- Removal - - [Ex: Removal of certain features or implementation due to a specific issue/bug or because of low quality code, etc.] - -### Why would this feature be useful? -[ If this is a feature for an end-user, how does it benefit the end-user? ]
-[ If this feature is for developers, what does it add to Ryujinx that did not already exist? ] diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml new file mode 100644 index 000000000..383bbb151 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -0,0 +1,30 @@ +name: Feature Request +description: Suggest a new feature for Ryujinx. +title: "[Feature Request]" +body: + - type: textarea + id: overview + attributes: + label: Overview + description: Include the basic, high-level concepts for this feature here. + validations: + required: true + - type: textarea + id: details + attributes: + label: Smaller details + description: These may include specific methods of implementation etc. + validations: + required: true + - type: textarea + id: request + attributes: + label: Nature of request + validations: + required: true + - type: textarea + id: feature + attributes: + label: Why would this feature be useful? + validations: + required: true diff --git a/.github/ISSUE_TEMPLATE/missing_cpu_instruction.md b/.github/ISSUE_TEMPLATE/missing_cpu_instruction.md deleted file mode 100644 index abfda1159..000000000 --- a/.github/ISSUE_TEMPLATE/missing_cpu_instruction.md +++ /dev/null @@ -1,34 +0,0 @@ ---- -name: Missing CPU Instruction -about: CPU Instruction is missing in Ryujinx. -#assignees: ---- - -## Missing CPU Instruction - -[ If any section does not apply, replace its contents with "N/A". ]
-[ If you do not have the information needed for a section, replace its contents with "Unknown". ]
-[ Lines between [ ] (square brackets) are to be removed before posting. ] - -[ Please search for existing [missing CPU instruction](https://github.com/Ryujinx/Ryujinx/issues) before you make your own issue. ]
-[ See the following [issue](https://github.com/Ryujinx/Ryujinx/issues/1405) as an example ]
-[ Duplicate issue will be marked as such and you will be referred to the original request. ] - -### What CPU instruction is missing? - -Requires the *INSTRUCTION* instruction.
-[ Replace *INSTRUCTION* by the instruction name, e.g. VADDL.U16 ] - -``` -* -``` -[ Add the undefined instruction error message in the above code block ] - -### Instruction name -``` -* -``` -[ Include the name from [armconverter.com](https://armconverter.com/?disasm) or [shell-storm.org](http://shell-storm.org/online/Online-Assembler-and-Disassembler/?arch=arm64&endianness=big&dis_with_raw=True&dis_with_ins=True) in the above code block ] - -### Required by: -[ Add our (games list database)[https://github.com/Ryujinx/Ryujinx-Games-List/issues] links of games who require this instruction ] diff --git a/.github/ISSUE_TEMPLATE/missing_cpu_instruction.yml b/.github/ISSUE_TEMPLATE/missing_cpu_instruction.yml new file mode 100644 index 000000000..d815ddfd9 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/missing_cpu_instruction.yml @@ -0,0 +1,26 @@ +name: Missing CPU Instruction +description: CPU Instruction is missing in Ryujinx. +title: "[CPU]" +labels: [cpu, not-implemented] +body: + - type: textarea + id: instruction + attributes: + label: CPU instruction + description: What CPU instruction is missing? + validations: + required: true + - type: textarea + id: name + attributes: + label: Instruction name + description: Include the name from [armconverter.com](https://armconverter.com/?disasm) or [shell-storm.org](http://shell-storm.org/online/Online-Assembler-and-Disassembler/?arch=arm64&endianness=big&dis_with_raw=True&dis_with_ins=True) in the above code block + validations: + required: true + - type: textarea + id: required + attributes: + label: Required by + description: Add links to the [compatibility list page(s)](https://github.com/Ryujinx/Ryujinx-Games-List/issues) of the game(s) that require this instruction. + validations: + required: true diff --git a/.github/ISSUE_TEMPLATE/missing_service_call.md b/.github/ISSUE_TEMPLATE/missing_service_call.md deleted file mode 100644 index d221add83..000000000 --- a/.github/ISSUE_TEMPLATE/missing_service_call.md +++ /dev/null @@ -1,35 +0,0 @@ ---- -name: Missing Service Call -about: Service call is missing in Ryujinx. -#assignees: ---- - -## Missing Service Call - -[ If any section does not apply, replace its contents with "N/A". ]
-[ If you do not have the information needed for a section, replace its contents with "Unknown". ]
-[ Lines between [ ] (square brackets) are to be removed before posting. ] - -[ Please search for existing [missing service call](https://github.com/Ryujinx/Ryujinx/issues) before you make your own issue. ]
-[ See the following [issue](https://github.com/Ryujinx/Ryujinx/issues/1431) as an example ]
-[ Duplicate issue will be marked as such and you will be referred to the original request. ] - -### What service call is missing? - -*SERVICE* *INTERFACE*: *NUMBER* (*NAME*) is not implemented.
-[ Replace *SERVICE* by the service name, e.g. appletAE ]
-[ Replace *INTERFACE* by the interface name, e.g. IAllSystemAppletProxiesService ]
-[ Replace *NUMBER* by the call number, e.g. 100 ]
-[ Replace *NAME* by the call name, e.g. OpenSystemAppletProxy ]
-[ e.g. appletAE IAllSystemAppletProxiesService: 100 (OpenSystemAppletProxy) ] - -[ Add related links to the specific call from [Switchbrew](https://switchbrew.org/w/index.php?title=Services_API) and/or [SwIPC](https://reswitched.github.io/SwIPC/) ] - -### Service description -``` -* -``` -[ Include the description/explanation from [Switchbrew](https://switchbrew.org/w/index.php?title=Services_API) and/or [SwIPC](https://reswitched.github.io/SwIPC/) in the above code block ] - -### Required by: -[ Add our (games list database)[https://github.com/Ryujinx/Ryujinx-Games-List/issues] links of games who require this call ] diff --git a/.github/ISSUE_TEMPLATE/missing_service_call.yml b/.github/ISSUE_TEMPLATE/missing_service_call.yml new file mode 100644 index 000000000..80aae533b --- /dev/null +++ b/.github/ISSUE_TEMPLATE/missing_service_call.yml @@ -0,0 +1,25 @@ +name: Missing Service Call +description: Service call is missing in Ryujinx. +labels: not-implemented +body: + - type: textarea + id: instruction + attributes: + label: Service call + description: What service call is missing? + validations: + required: true + - type: textarea + id: name + attributes: + label: Service description + description: Include the description/explanation from [Switchbrew](https://switchbrew.org/w/index.php?title=Services_API) and/or [SwIPC](https://reswitched.github.io/SwIPC/) in the above code block + validations: + required: true + - type: textarea + id: required + attributes: + label: Required by + description: Add links to the [compatibility list page(s)](https://github.com/Ryujinx/Ryujinx-Games-List/issues) of the game(s) that require this service. + validations: + required: true \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/missing_shader_instruction.yml b/.github/ISSUE_TEMPLATE/missing_shader_instruction.yml new file mode 100644 index 000000000..df37859a5 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/missing_shader_instruction.yml @@ -0,0 +1,19 @@ +name: Missing Shader Instruction +description: Shader Instruction is missing in Ryujinx. +title: "[GPU]" +labels: [gpu, not-implemented] +body: + - type: textarea + id: instruction + attributes: + label: Shader instruction + description: What shader instruction is missing? + validations: + required: true + - type: textarea + id: required + attributes: + label: Required by + description: Add links to the [compatibility list page(s)](https://github.com/Ryujinx/Ryujinx-Games-List/issues) of the game(s) that require this instruction. + validations: + required: true diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 000000000..1516f8a7d --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,24 @@ +version: 2 +updates: + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: weekly + labels: + - "infra" + reviewers: + - marysaka + commit-message: + prefix: "ci" + + - package-ecosystem: nuget + directory: / + open-pull-requests-limit: 5 + schedule: + interval: daily + labels: + - "infra" + reviewers: + - marysaka + commit-message: + prefix: nuget diff --git a/.github/labeler.yml b/.github/labeler.yml new file mode 100644 index 000000000..587830be1 --- /dev/null +++ b/.github/labeler.yml @@ -0,0 +1,33 @@ +audio: 'src/Ryujinx.Audio*/**' + +cpu: + - 'src/ARMeilleure/**' + - 'src/Ryujinx.Cpu/**' + - 'src/Ryujinx.Memory/**' + +gpu: + - 'src/Ryujinx.Graphics.*/**' + - 'src/Spv.Generator/**' + - 'src/Ryujinx.ShaderTools/**' + +'graphics-backend:opengl': 'src/Ryujinx.Graphics.OpenGL/**' +'graphics-backend:vulkan': + - 'src/Ryujinx.Graphics.Vulkan/**' + - 'src/Spv.Generator/**' + +gui: + - 'src/Ryujinx/**' + - 'src/Ryujinx.Ui.Common/**' + - 'src/Ryujinx.Ui.LocaleGenerator/**' + - 'src/Ryujinx.Ava/**' + +horizon: + - 'src/Ryujinx.HLE/**' + - 'src/Ryujinx.Horizon*/**' + +kernel: 'src/Ryujinx.HLE/HOS/Kernel/**' + +infra: + - '.github/**' + - 'distribution/**' + - 'Directory.Packages.props' \ No newline at end of file diff --git a/.github/reviewers.yml b/.github/reviewers.yml new file mode 100644 index 000000000..c0dc59dd5 --- /dev/null +++ b/.github/reviewers.yml @@ -0,0 +1,32 @@ +audio: + - marysaka + +cpu: + - gdkchan + - riperiperi + - marysaka + - LDj3SNuD + +gpu: + - gdkchan + - riperiperi + - marysaka + +gui: + - Ack77 + - emmauss + - TSRBerry + - marysaka + +horizon: + - gdkchan + - Ack77 + - marysaka + - TSRBerry + +infra: + - marysaka + - TSRBerry + +default: + - marysaka diff --git a/.github/update_reviewers.py b/.github/update_reviewers.py new file mode 100644 index 000000000..14c0cc285 --- /dev/null +++ b/.github/update_reviewers.py @@ -0,0 +1,79 @@ +from pathlib import Path +from typing import List, Set +from github import Github +from github.Repository import Repository +from github.GithubException import GithubException + +import sys +import yaml + + +def add_reviewers( + reviewers: Set[str], team_reviewers: Set[str], new_entries: List[str] +): + for reviewer in new_entries: + if reviewer.startswith("@"): + team_reviewers.add(reviewer[1:]) + else: + reviewers.add(reviewer) + + +def update_reviewers(config, repo: Repository, pr_id: int) -> int: + pull_request = repo.get_pull(pr_id) + + if not pull_request: + sys.stderr.writable(f"Unknown PR #{pr_id}\n") + return 1 + + pull_request_author = pull_request.user.login + reviewers = set() + team_reviewers = set() + + for label in pull_request.labels: + if label.name in config: + add_reviewers(reviewers, team_reviewers, config[label.name]) + + if "default" in config: + add_reviewers(reviewers, team_reviewers, config["default"]) + + if pull_request_author in reviewers: + reviewers.remove(pull_request_author) + + try: + reviewers = list(reviewers) + team_reviewers = list(team_reviewers) + print( + f"Attempting to assign reviewers ({reviewers}) and team_reviewers ({team_reviewers})" + ) + pull_request.create_review_request(reviewers, team_reviewers) + return 0 + except GithubException as e: + sys.stderr.write(f"Cannot assign review request for PR #{pr_id}: {e}\n") + return 1 + + +if __name__ == "__main__": + if len(sys.argv) != 5: + sys.stderr.write("usage: \n") + sys.exit(1) + + token = sys.argv[1] + repo_path = sys.argv[2] + pr_id = int(sys.argv[3]) + config_path = Path(sys.argv[4]) + + g = Github(token) + repo = g.get_repo(repo_path) + + if not repo: + sys.stderr.write("Repository not found!\n") + sys.exit(1) + + if not config_path.exists(): + sys.stderr.write(f'Config "{config_path}" not found!\n') + sys.exit(1) + + with open(config_path, "r") as f: + config = yaml.safe_load(f) + + sys.exit(update_reviewers(config, repo, pr_id)) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index d0bc13055..bbc2eca80 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,27 +1,18 @@ name: Build job on: - workflow_dispatch: - inputs: {} - #push: - # branches: [ master ] - # paths-ignore: - # - '.github/*' - # - '.github/ISSUE_TEMPLATE/**' - # - '*.yml' - # - 'README.md' - pull_request: - branches: [ master ] - paths-ignore: - - '.github/*' - - '.github/ISSUE_TEMPLATE/**' - - '*.yml' - - 'README.md' + workflow_call: + +env: + POWERSHELL_TELEMETRY_OPTOUT: 1 + DOTNET_CLI_TELEMETRY_OPTOUT: 1 + RYUJINX_BASE_VERSION: "1.1.0" jobs: build: - name: ${{ matrix.os }} (${{ matrix.configuration }}) + name: ${{ matrix.OS_NAME }} (${{ matrix.configuration }}) runs-on: ${{ matrix.os }} + timeout-minutes: 45 strategy: matrix: os: [ubuntu-latest, macOS-latest, windows-latest] @@ -33,7 +24,7 @@ jobs: RELEASE_ZIP_OS_NAME: linux_x64 - os: macOS-latest - OS_NAME: MacOS x64 + OS_NAME: macOS x64 DOTNET_RUNTIME_IDENTIFIER: osx-x64 RELEASE_ZIP_OS_NAME: osx_x64 @@ -43,50 +34,111 @@ jobs: RELEASE_ZIP_OS_NAME: win_x64 fail-fast: false - env: - POWERSHELL_TELEMETRY_OPTOUT: 1 - DOTNET_CLI_TELEMETRY_OPTOUT: 1 - RYUJINX_BASE_VERSION: "1.1.0" steps: - - uses: actions/checkout@v2 - - uses: actions/setup-dotnet@v1 + - uses: actions/checkout@v3 + + - uses: actions/setup-dotnet@v3 with: - dotnet-version: 6.0.x - - name: Ensure NuGet Source - uses: fabriciomurta/ensure-nuget-source@v1 + global-json-file: global.json + - name: Get git short hash id: git_short_hash - run: echo "::set-output name=result::$(git rev-parse --short "${{ github.sha }}")" - - name: Clear - run: dotnet clean && dotnet nuget locals all --clear + run: echo "result=$(git rev-parse --short "${{ github.sha }}")" >> $GITHUB_OUTPUT + shell: bash + - name: Build - run: dotnet build -c "${{ matrix.configuration }}" /p:Version="${{ env.RYUJINX_BASE_VERSION }}" /p:SourceRevisionId="${{ steps.git_short_hash.outputs.result }}" /p:ExtraDefineConstants=DISABLE_UPDATER + run: dotnet build -c "${{ matrix.configuration }}" -p:Version="${{ env.RYUJINX_BASE_VERSION }}" -p:SourceRevisionId="${{ steps.git_short_hash.outputs.result }}" -p:ExtraDefineConstants=DISABLE_UPDATER + - name: Test - run: dotnet test -c "${{ matrix.configuration }}" + uses: TSRBerry/unstable-commands@v1 + with: + commands: dotnet test --no-build -c "${{ matrix.configuration }}" + timeout-minutes: 10 + retry-codes: 139 + - name: Publish Ryujinx - run: dotnet publish -c "${{ matrix.configuration }}" -r "${{ matrix.DOTNET_RUNTIME_IDENTIFIER }}" -o ./publish /p:Version="${{ env.RYUJINX_BASE_VERSION }}" /p:DebugType=embedded /p:SourceRevisionId="${{ steps.git_short_hash.outputs.result }}" /p:ExtraDefineConstants=DISABLE_UPDATER Ryujinx --self-contained - if: github.event_name == 'pull_request' + run: dotnet publish -c "${{ matrix.configuration }}" -r "${{ matrix.DOTNET_RUNTIME_IDENTIFIER }}" -o ./publish -p:Version="${{ env.RYUJINX_BASE_VERSION }}" -p:DebugType=embedded -p:SourceRevisionId="${{ steps.git_short_hash.outputs.result }}" -p:ExtraDefineConstants=DISABLE_UPDATER src/Ryujinx --self-contained true + if: github.event_name == 'pull_request' && matrix.os != 'macOS-latest' + - name: Publish Ryujinx.Headless.SDL2 - run: dotnet publish -c "${{ matrix.configuration }}" -r "${{ matrix.DOTNET_RUNTIME_IDENTIFIER }}" -o ./publish_sdl2_headless /p:Version="${{ env.RYUJINX_BASE_VERSION }}" /p:DebugType=embedded /p:SourceRevisionId="${{ steps.git_short_hash.outputs.result }}" /p:ExtraDefineConstants=DISABLE_UPDATER Ryujinx.Headless.SDL2 --self-contained - if: github.event_name == 'pull_request' + run: dotnet publish -c "${{ matrix.configuration }}" -r "${{ matrix.DOTNET_RUNTIME_IDENTIFIER }}" -o ./publish_sdl2_headless -p:Version="${{ env.RYUJINX_BASE_VERSION }}" -p:DebugType=embedded -p:SourceRevisionId="${{ steps.git_short_hash.outputs.result }}" -p:ExtraDefineConstants=DISABLE_UPDATER src/Ryujinx.Headless.SDL2 --self-contained true + if: github.event_name == 'pull_request' && matrix.os != 'macOS-latest' + - name: Publish Ryujinx.Ava - run: dotnet publish -c "${{ matrix.configuration }}" -r "${{ matrix.DOTNET_RUNTIME_IDENTIFIER }}" -o ./publish_ava /p:Version="1.0.0" /p:DebugType=embedded /p:SourceRevisionId="${{ steps.git_short_hash.outputs.result }}" /p:ExtraDefineConstants=DISABLE_UPDATER Ryujinx.Ava - if: github.event_name == 'pull_request' + run: dotnet publish -c "${{ matrix.configuration }}" -r "${{ matrix.DOTNET_RUNTIME_IDENTIFIER }}" -o ./publish_ava -p:Version="${{ env.RYUJINX_BASE_VERSION }}" -p:DebugType=embedded -p:SourceRevisionId="${{ steps.git_short_hash.outputs.result }}" -p:ExtraDefineConstants=DISABLE_UPDATER src/Ryujinx.Ava --self-contained true + if: github.event_name == 'pull_request' && matrix.os != 'macOS-latest' + + - name: Set executable bit + run: | + chmod +x ./publish/Ryujinx ./publish/Ryujinx.sh + chmod +x ./publish_sdl2_headless/Ryujinx.Headless.SDL2 ./publish_sdl2_headless/Ryujinx.sh + chmod +x ./publish_ava/Ryujinx.Ava ./publish_ava/Ryujinx.sh + if: github.event_name == 'pull_request' && matrix.os == 'ubuntu-latest' + - name: Upload Ryujinx artifact - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 with: name: ryujinx-${{ matrix.configuration }}-${{ env.RYUJINX_BASE_VERSION }}+${{ steps.git_short_hash.outputs.result }}-${{ matrix.RELEASE_ZIP_OS_NAME }} path: publish - if: github.event_name == 'pull_request' + if: github.event_name == 'pull_request' && matrix.os != 'macOS-latest' + - name: Upload Ryujinx.Headless.SDL2 artifact - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 with: name: sdl2-ryujinx-headless-${{ matrix.configuration }}-${{ env.RYUJINX_BASE_VERSION }}+${{ steps.git_short_hash.outputs.result }}-${{ matrix.RELEASE_ZIP_OS_NAME }} path: publish_sdl2_headless - if: github.event_name == 'pull_request' + if: github.event_name == 'pull_request' && matrix.os != 'macOS-latest' + - name: Upload Ryujinx.Ava artifact - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 with: name: ava-ryujinx-${{ matrix.configuration }}-${{ env.RYUJINX_BASE_VERSION }}+${{ steps.git_short_hash.outputs.result }}-${{ matrix.RELEASE_ZIP_OS_NAME }} path: publish_ava + if: github.event_name == 'pull_request' && matrix.os != 'macOS-latest' + + build_macos: + name: macOS Universal (${{ matrix.configuration }}) + runs-on: ubuntu-latest + timeout-minutes: 45 + strategy: + matrix: + configuration: [ Debug, Release ] + + steps: + - uses: actions/checkout@v3 + + - uses: actions/setup-dotnet@v3 + with: + global-json-file: global.json + + - name: Setup LLVM 14 + run: | + wget https://apt.llvm.org/llvm.sh + chmod +x llvm.sh + sudo ./llvm.sh 14 + + - name: Install rcodesign + run: | + mkdir -p $HOME/.bin + gh release download -R indygreg/apple-platform-rs -O apple-codesign.tar.gz -p 'apple-codesign-*-x86_64-unknown-linux-musl.tar.gz' + tar -xzvf apple-codesign.tar.gz --wildcards '*/rcodesign' --strip-components=1 + rm apple-codesign.tar.gz + mv rcodesign $HOME/.bin/ + echo "$HOME/.bin" >> $GITHUB_PATH + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Get git short hash + id: git_short_hash + run: echo "result=$(git rev-parse --short "${{ github.sha }}")" >> $GITHUB_OUTPUT + + - name: Publish macOS + run: | + ./distribution/macos/create_macos_build.sh . publish_tmp publish_ava ./distribution/macos/entitlements.xml "${{ env.RYUJINX_BASE_VERSION }}" "${{ steps.git_short_hash.outputs.result }}" "${{ matrix.configuration }}" "-p:ExtraDefineConstants=DISABLE_UPDATER" + + - name: Upload Ryujinx.Ava artifact + uses: actions/upload-artifact@v3 + with: + name: ava-ryujinx-${{ matrix.configuration }}-${{ env.RYUJINX_BASE_VERSION }}+${{ steps.git_short_hash.outputs.result }}-macos_universal + path: "publish_ava/*.tar.gz" if: github.event_name == 'pull_request' diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml new file mode 100644 index 000000000..94d0a342b --- /dev/null +++ b/.github/workflows/checks.yml @@ -0,0 +1,71 @@ +name: Perform checks + +on: + pull_request: + branches: [ master ] + paths: + - '**' + - '!.github/**' + - '!*.yml' + - '!*.config' + - '!README.md' + - '.github/workflows/*.yml' + +permissions: + pull-requests: write + checks: write + +concurrency: + group: pr-checks-${{ github.event.number }} + cancel-in-progress: true + +jobs: + format: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 0 + + - uses: actions/setup-dotnet@v3 + with: + global-json-file: global.json + + - run: dotnet restore + + - name: Print dotnet format version + run: dotnet format --version + + - name: Run dotnet format whitespace + run: | + dotnet format whitespace --verify-no-changes --report ./whitespace-report.json -v d + + # 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@v3 + with: + name: dotnet-format + path: ./*-report.json + + pr_build: + uses: ./.github/workflows/build.yml + needs: format + secrets: inherit diff --git a/.github/workflows/flatpak.yml b/.github/workflows/flatpak.yml new file mode 100644 index 000000000..d4380e05f --- /dev/null +++ b/.github/workflows/flatpak.yml @@ -0,0 +1,172 @@ +name: Flatpak release job + +on: + workflow_call: + inputs: + ryujinx_version: + required: true + type: string + + +concurrency: flatpak-release + +jobs: + release: + timeout-minutes: ${{ fromJSON(vars.JOB_TIMEOUT) }} + runs-on: ubuntu-latest + + env: + NUGET_PACKAGES: ${{ github.workspace }}/.nuget/packages + GIT_COMMITTER_NAME: "RyujinxBot" + GIT_COMMITTER_EMAIL: "61127645+RyujinxBot@users.noreply.github.com" + RYUJINX_PROJECT_FILE: "src/Ryujinx/Ryujinx.csproj" + NUGET_SOURCES_DESTDIR: "nuget-sources" + RYUJINX_VERSION: "${{ inputs.ryujinx_version }}" + + steps: + - uses: actions/checkout@v3 + with: + path: Ryujinx + + - uses: actions/setup-dotnet@v3 + with: + global-json-file: Ryujinx/global.json + + - name: Get version info + id: version_info + working-directory: Ryujinx + run: | + echo "git_hash=$(git rev-parse HEAD)" >> $GITHUB_OUTPUT + + - uses: actions/checkout@v3 + with: + repository: flathub/org.ryujinx.Ryujinx + token: ${{ secrets.RYUJINX_BOT_PAT }} + submodules: recursive + path: flathub + + - name: Install dependencies + run: python -m pip install PyYAML lxml + + - name: Restore Nuget packages + run: dotnet restore Ryujinx/${{ env.RYUJINX_PROJECT_FILE }} + + - name: Generate nuget_sources.json + shell: python + run: | + from pathlib import Path + import base64 + import binascii + import json + import os + + 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) + + 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, + }) + + with open('flathub/nuget_sources.json', 'w') as fp: + json.dump(sources, fp, indent=4) + + - name: Update flatpak metadata + id: metadata + env: + RYUJINX_GIT_HASH: ${{ steps.version_info.outputs.git_hash }} + shell: python + run: | + import hashlib + import hmac + import json + import os + import yaml + from datetime import datetime + from lxml import etree + + + # Ensure we don't destroy multiline strings + def str_presenter(dumper, data): + if len(data.splitlines()) > 1: + return dumper.represent_scalar("tag:yaml.org,2002:str", data, style="|") + return dumper.represent_scalar("tag:yaml.org,2002:str", data) + + + yaml.representer.SafeRepresenter.add_representer(str, str_presenter) + + yaml_file = "flathub/org.ryujinx.Ryujinx.yml" + xml_file = "flathub/org.ryujinx.Ryujinx.appdata.xml" + + with open(yaml_file, "r") as f: + data = yaml.safe_load(f) + + for source in data["modules"][0]["sources"]: + if type(source) is str: + continue + if ( + source["type"] == "git" + and source["url"] == "https://github.com/Ryujinx/Ryujinx.git" + ): + source["commit"] = os.environ['RYUJINX_GIT_HASH'] + + is_same_version = data["modules"][0]["build-options"]["env"]["RYUJINX_VERSION"] == os.environ['RYUJINX_VERSION'] + + with open(os.environ['GITHUB_OUTPUT'], "a") as gh_out: + if is_same_version: + gh_out.write(f"commit_message=Retry update to {os.environ['RYUJINX_VERSION']}") + else: + gh_out.write(f"commit_message=Update to {os.environ['RYUJINX_VERSION']}") + + if not is_same_version: + data["modules"][0]["build-options"]["env"]["RYUJINX_VERSION"] = os.environ['RYUJINX_VERSION'] + + with open(yaml_file, "w") as f: + yaml.safe_dump(data, f, sort_keys=False) + + parser = etree.XMLParser(remove_blank_text=True) + tree = etree.parse(xml_file, parser) + + root = tree.getroot() + + releases = root.find("releases") + + element = etree.Element("release") + element.set("version", os.environ['RYUJINX_VERSION']) + element.set("date", datetime.now().date().isoformat()) + releases.insert(0, element) + + # Ensure 4 spaces + etree.indent(root, space=" ") + + with open(xml_file, "wb") as f: + f.write( + etree.tostring( + tree, + pretty_print=True, + encoding="UTF-8", + doctype='', + ) + ) + + - name: Push flatpak update + working-directory: flathub + env: + COMMIT_MESSAGE: ${{ steps.metadata.outputs.commit_message }} + run: | + git config user.name "${{ env.GIT_COMMITTER_NAME }}" + git config user.email "${{ env.GIT_COMMITTER_EMAIL }}" + git add . + git commit -m "$COMMIT_MESSAGE" + git push origin master \ No newline at end of file diff --git a/.github/workflows/nightly_pr_comment.yml b/.github/workflows/nightly_pr_comment.yml index 0ab77b178..f59a6be1f 100644 --- a/.github/workflows/nightly_pr_comment.yml +++ b/.github/workflows/nightly_pr_comment.yml @@ -1,14 +1,17 @@ name: Comment PR artifacts links + on: workflow_run: - workflows: ['Build job'] + workflows: ['Perform checks'] types: [completed] + jobs: pr_comment: if: github.event.workflow_run.event == 'pull_request' && github.event.workflow_run.conclusion == 'success' runs-on: ubuntu-latest + timeout-minutes: ${{ fromJSON(vars.JOB_TIMEOUT) }} steps: - - uses: actions/github-script@v3 + - uses: actions/github-script@v6 with: script: | const {owner, repo} = context.repo; @@ -16,7 +19,7 @@ jobs: const pull_head_sha = '${{github.event.workflow_run.head_sha}}'; const issue_number = await (async () => { - const pulls = await github.pulls.list({owner, repo}); + const pulls = await github.rest.pulls.list({owner, repo}); for await (const {data} of github.paginate.iterator(pulls)) { for (const pull of data) { if (pull.head.sha === pull_head_sha) { @@ -31,7 +34,7 @@ jobs: return core.error(`No matching pull request found`); } - const {data: {artifacts}} = await github.actions.listWorkflowRunArtifacts({owner, repo, run_id}); + const {data: {artifacts}} = await github.rest.actions.listWorkflowRunArtifacts({owner, repo, run_id}); if (!artifacts.length) { return core.error(`No artifacts found`); } @@ -57,12 +60,12 @@ jobs: body += hidden_headless_artifacts; body += hidden_debug_artifacts; - const {data: comments} = await github.issues.listComments({repo, owner, issue_number}); + const {data: comments} = await github.rest.issues.listComments({repo, owner, issue_number}); const existing_comment = comments.find((c) => c.user.login === 'github-actions[bot]'); if (existing_comment) { core.info(`Updating comment ${existing_comment.id}`); - await github.issues.updateComment({repo, owner, comment_id: existing_comment.id, body}); + await github.rest.issues.updateComment({repo, owner, comment_id: existing_comment.id, body}); } else { core.info(`Creating a comment`); - await github.issues.createComment({repo, owner, issue_number, body}); - } + await github.rest.issues.createComment({repo, owner, issue_number, body}); + } \ No newline at end of file diff --git a/.github/workflows/pr_triage.yml b/.github/workflows/pr_triage.yml new file mode 100644 index 000000000..cd90e645a --- /dev/null +++ b/.github/workflows/pr_triage.yml @@ -0,0 +1,35 @@ +name: "Pull Request Triage" +on: + pull_request_target: + types: [opened, ready_for_review] + +jobs: + triage: + permissions: + contents: read + pull-requests: write + + runs-on: ubuntu-latest + + steps: + # Grab sources to get update_reviewers.py and reviewers.yml + - name: Fetch sources + uses: actions/checkout@v3 + with: + # Ensure we pin the source origin as pull_request_target run under forks. + fetch-depth: 0 + repository: Ryujinx/Ryujinx + ref: master + + - name: Update labels based on changes + uses: actions/labeler@v4 + with: + sync-labels: true + dot: true + + - name: Assign reviewers + if: ! github.event.pull_request.draft + run: | + pip3 install PyGithub + python3 .github/update_reviewers.py ${{ secrets.GITHUB_TOKEN }} ${{ github.repository }} ${{ github.event.pull_request.number }} .github/reviewers.yml + shell: bash diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index e68ae3a61..63e6d0187 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -6,86 +6,124 @@ on: push: branches: [ master ] paths-ignore: - - '.github/*' - - '.github/ISSUE_TEMPLATE/**' + - '.github/**' - '*.yml' + - '*.json' + - '*.config' - 'README.md' +concurrency: release + +env: + POWERSHELL_TELEMETRY_OPTOUT: 1 + DOTNET_CLI_TELEMETRY_OPTOUT: 1 + RYUJINX_BASE_VERSION: "1.1" + RYUJINX_TARGET_RELEASE_CHANNEL_NAME: "master" + RYUJINX_TARGET_RELEASE_CHANNEL_OWNER: "Ryujinx" + RYUJINX_TARGET_RELEASE_CHANNEL_REPO: "release-channel-master" jobs: - release: - runs-on: windows-latest - - env: - POWERSHELL_TELEMETRY_OPTOUT: 1 - DOTNET_CLI_TELEMETRY_OPTOUT: 1 - RYUJINX_BASE_VERSION: "1.1" - RYUJINX_TARGET_RELEASE_CHANNEL_NAME: "master" - RYUJINX_TARGET_RELEASE_CHANNEL_OWNER: "Ryujinx" - RYUJINX_TARGET_RELEASE_CHANNEL_REPO: "release-channel-master" - + tag: + name: Create tag + runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - uses: actions/setup-dotnet@v1 - with: - dotnet-version: 6.0.x - - name: Ensure NuGet Source - uses: fabriciomurta/ensure-nuget-source@v1 - - name: Clear - run: dotnet clean && dotnet nuget locals all --clear - name: Get version info id: version_info run: | - echo "::set-output name=build_version::${{ env.RYUJINX_BASE_VERSION }}.${{ github.run_number }}" - echo "::set-output name=git_short_hash::$(git rev-parse --short "${{ github.sha }}")" + echo "build_version=${{ env.RYUJINX_BASE_VERSION }}.${{ github.run_number }}" >> $GITHUB_OUTPUT shell: bash + + - name: Create tag + uses: actions/github-script@v6 + with: + script: | + github.rest.git.createRef({ + owner: context.repo.owner, + repo: context.repo.repo, + ref: 'refs/tags/${{ steps.version_info.outputs.build_version }}', + sha: context.sha + }) + + release: + name: Release ${{ matrix.OS_NAME }} + runs-on: ${{ matrix.os }} + timeout-minutes: ${{ fromJSON(vars.JOB_TIMEOUT) }} + strategy: + matrix: + os: [ ubuntu-latest, windows-latest ] + include: + - os: ubuntu-latest + OS_NAME: Linux x64 + DOTNET_RUNTIME_IDENTIFIER: linux-x64 + RELEASE_ZIP_OS_NAME: linux_x64 + + - os: windows-latest + OS_NAME: Windows x64 + DOTNET_RUNTIME_IDENTIFIER: win10-x64 + RELEASE_ZIP_OS_NAME: win_x64 + steps: + - uses: actions/checkout@v3 + + - uses: actions/setup-dotnet@v3 + with: + global-json-file: global.json + + - name: Get version info + id: version_info + run: | + echo "build_version=${{ env.RYUJINX_BASE_VERSION }}.${{ github.run_number }}" >> $GITHUB_OUTPUT + echo "git_short_hash=$(git rev-parse --short "${{ github.sha }}")" >> $GITHUB_OUTPUT + shell: bash + - name: Configure for release run: | - sed -r --in-place 's/\%\%RYUJINX_BUILD_VERSION\%\%/${{ steps.version_info.outputs.build_version }}/g;' Ryujinx.Common/ReleaseInformations.cs - sed -r --in-place 's/\%\%RYUJINX_BUILD_GIT_HASH\%\%/${{ steps.version_info.outputs.git_short_hash }}/g;' Ryujinx.Common/ReleaseInformations.cs - sed -r --in-place 's/\%\%RYUJINX_TARGET_RELEASE_CHANNEL_NAME\%\%/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_NAME }}/g;' Ryujinx.Common/ReleaseInformations.cs - sed -r --in-place 's/\%\%RYUJINX_TARGET_RELEASE_CHANNEL_OWNER\%\%/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}/g;' Ryujinx.Common/ReleaseInformations.cs - sed -r --in-place 's/\%\%RYUJINX_TARGET_RELEASE_CHANNEL_REPO\%\%/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }}/g;' Ryujinx.Common/ReleaseInformations.cs + sed -r --in-place 's/\%\%RYUJINX_BUILD_VERSION\%\%/${{ steps.version_info.outputs.build_version }}/g;' src/Ryujinx.Common/ReleaseInformation.cs + sed -r --in-place 's/\%\%RYUJINX_BUILD_GIT_HASH\%\%/${{ steps.version_info.outputs.git_short_hash }}/g;' src/Ryujinx.Common/ReleaseInformation.cs + sed -r --in-place 's/\%\%RYUJINX_TARGET_RELEASE_CHANNEL_NAME\%\%/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_NAME }}/g;' src/Ryujinx.Common/ReleaseInformation.cs + sed -r --in-place 's/\%\%RYUJINX_TARGET_RELEASE_CHANNEL_OWNER\%\%/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}/g;' src/Ryujinx.Common/ReleaseInformation.cs + sed -r --in-place 's/\%\%RYUJINX_TARGET_RELEASE_CHANNEL_REPO\%\%/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }}/g;' src/Ryujinx.Common/ReleaseInformation.cs shell: bash + - name: Create output dir run: "mkdir release_output" - - name: Publish Windows + + - name: Publish run: | - dotnet publish -c Release -r win10-x64 -o ./publish_windows/publish /p:Version="${{ steps.version_info.outputs.build_version }}" /p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" /p:DebugType=embedded Ryujinx --self-contained - dotnet publish -c Release -r win10-x64 -o ./publish_windows_sdl2_headless/publish /p:Version="${{ steps.version_info.outputs.build_version }}" /p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" /p:DebugType=embedded Ryujinx.Headless.SDL2 --self-contained - dotnet publish -c Release -r win10-x64 -o ./publish_windows_ava/publish /p:Version="${{ steps.version_info.outputs.build_version }}" /p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" /p:DebugType=embedded Ryujinx.Ava --self-contained + dotnet publish -c Release -r "${{ matrix.DOTNET_RUNTIME_IDENTIFIER }}" -o ./publish_gtk/publish -p:Version="${{ steps.version_info.outputs.build_version }}" -p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" -p:DebugType=embedded src/Ryujinx --self-contained true + dotnet publish -c Release -r "${{ matrix.DOTNET_RUNTIME_IDENTIFIER }}" -o ./publish_sdl2_headless/publish -p:Version="${{ steps.version_info.outputs.build_version }}" -p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" -p:DebugType=embedded src/Ryujinx.Headless.SDL2 --self-contained true + dotnet publish -c Release -r "${{ matrix.DOTNET_RUNTIME_IDENTIFIER }}" -o ./publish_ava/publish -p:Version="${{ steps.version_info.outputs.build_version }}" -p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" -p:DebugType=embedded src/Ryujinx.Ava --self-contained true + - name: Packing Windows builds + if: matrix.os == 'windows-latest' run: | - pushd publish_windows + pushd publish_gtk 7z a ../release_output/ryujinx-${{ steps.version_info.outputs.build_version }}-win_x64.zip publish popd - pushd publish_windows_sdl2_headless + pushd publish_sdl2_headless 7z a ../release_output/sdl2-ryujinx-headless-${{ steps.version_info.outputs.build_version }}-win_x64.zip publish popd - pushd publish_windows_ava + pushd publish_ava 7z a ../release_output/test-ava-ryujinx-${{ steps.version_info.outputs.build_version }}-win_x64.zip publish popd shell: bash - - name: Publish Linux - run: | - dotnet publish -c Release -r linux-x64 -o ./publish_linux/publish /p:Version="${{ steps.version_info.outputs.build_version }}" /p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" /p:DebugType=embedded Ryujinx --self-contained - dotnet publish -c Release -r linux-x64 -o ./publish_linux_sdl2_headless/publish /p:Version="${{ steps.version_info.outputs.build_version }}" /p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" /p:DebugType=embedded Ryujinx.Headless.SDL2 --self-contained - dotnet publish -c Release -r linux-x64 -o ./publish_linux_ava/publish /p:Version="${{ steps.version_info.outputs.build_version }}" /p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" /p:DebugType=embedded Ryujinx.Ava --self-contained - - name: Packing Linux builds + if: matrix.os == 'ubuntu-latest' run: | - pushd publish_linux + pushd publish_gtk + chmod +x publish/Ryujinx.sh publish/Ryujinx tar -czvf ../release_output/ryujinx-${{ steps.version_info.outputs.build_version }}-linux_x64.tar.gz publish popd - pushd publish_linux_sdl2_headless + pushd publish_sdl2_headless + chmod +x publish/Ryujinx.sh publish/Ryujinx.Headless.SDL2 tar -czvf ../release_output/sdl2-ryujinx-headless-${{ steps.version_info.outputs.build_version }}-linux_x64.tar.gz publish popd - pushd publish_linux_ava + pushd publish_ava + chmod +x publish/Ryujinx.sh publish/Ryujinx.Ava tar -czvf ../release_output/test-ava-ryujinx-${{ steps.version_info.outputs.build_version }}-linux_x64.tar.gz publish popd shell: bash @@ -96,10 +134,78 @@ jobs: name: ${{ steps.version_info.outputs.build_version }} artifacts: "release_output/*.tar.gz,release_output/*.zip" tag: ${{ steps.version_info.outputs.build_version }} - body: "For more informations about this release please check out the official [Changelog](https://github.com/Ryujinx/Ryujinx/wiki/Changelog)." + body: "For more information about this release please check out the official [Changelog](https://github.com/Ryujinx/Ryujinx/wiki/Changelog)." + omitBodyDuringUpdate: true allowUpdates: true - removeArtifacts: true replacesArtifacts: true owner: ${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }} repo: ${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }} token: ${{ secrets.RELEASE_TOKEN }} + + macos_release: + name: Release MacOS universal + runs-on: ubuntu-latest + timeout-minutes: ${{ fromJSON(vars.JOB_TIMEOUT) }} + steps: + - uses: actions/checkout@v3 + + - uses: actions/setup-dotnet@v3 + with: + global-json-file: global.json + + - name: Setup LLVM 14 + run: | + wget https://apt.llvm.org/llvm.sh + chmod +x llvm.sh + sudo ./llvm.sh 14 + + - name: Install rcodesign + run: | + mkdir -p $HOME/.bin + gh release download -R indygreg/apple-platform-rs -O apple-codesign.tar.gz -p 'apple-codesign-*-x86_64-unknown-linux-musl.tar.gz' + tar -xzvf apple-codesign.tar.gz --wildcards '*/rcodesign' --strip-components=1 + rm apple-codesign.tar.gz + mv rcodesign $HOME/.bin/ + echo "$HOME/.bin" >> $GITHUB_PATH + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Get version info + id: version_info + run: | + echo "build_version=${{ env.RYUJINX_BASE_VERSION }}.${{ github.run_number }}" >> $GITHUB_OUTPUT + echo "git_short_hash=$(git rev-parse --short "${{ github.sha }}")" >> $GITHUB_OUTPUT + + - name: Configure for release + run: | + sed -r --in-place 's/\%\%RYUJINX_BUILD_VERSION\%\%/${{ steps.version_info.outputs.build_version }}/g;' src/Ryujinx.Common/ReleaseInformation.cs + sed -r --in-place 's/\%\%RYUJINX_BUILD_GIT_HASH\%\%/${{ steps.version_info.outputs.git_short_hash }}/g;' src/Ryujinx.Common/ReleaseInformation.cs + sed -r --in-place 's/\%\%RYUJINX_TARGET_RELEASE_CHANNEL_NAME\%\%/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_NAME }}/g;' src/Ryujinx.Common/ReleaseInformation.cs + sed -r --in-place 's/\%\%RYUJINX_TARGET_RELEASE_CHANNEL_OWNER\%\%/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}/g;' src/Ryujinx.Common/ReleaseInformation.cs + sed -r --in-place 's/\%\%RYUJINX_TARGET_RELEASE_CHANNEL_REPO\%\%/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }}/g;' src/Ryujinx.Common/ReleaseInformation.cs + shell: bash + + - name: Publish macOS + run: | + ./distribution/macos/create_macos_build.sh . publish_tmp publish_ava ./distribution/macos/entitlements.xml "${{ steps.version_info.outputs.build_version }}" "${{ steps.version_info.outputs.git_short_hash }}" Release + + - name: Pushing new release + uses: ncipollo/release-action@v1 + with: + name: ${{ steps.version_info.outputs.build_version }} + artifacts: "publish_ava/*.tar.gz" + tag: ${{ steps.version_info.outputs.build_version }} + body: "For more information about this release please check out the official [Changelog](https://github.com/Ryujinx/Ryujinx/wiki/Changelog)." + omitBodyDuringUpdate: true + allowUpdates: true + replacesArtifacts: true + owner: ${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }} + repo: ${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }} + token: ${{ secrets.RELEASE_TOKEN }} + + flatpak_release: + uses: ./.github/workflows/flatpak.yml + needs: release + with: + ryujinx_version: "1.1.${{ github.run_number }}" + secrets: inherit \ No newline at end of file diff --git a/.gitignore b/.gitignore index 9432a953a..37b419d07 100644 --- a/.gitignore +++ b/.gitignore @@ -125,6 +125,9 @@ ClientBin/ packages/* *.config +# Include nuget.config +!nuget.config + # RIA/Silverlight projects Generated_Code/ @@ -167,3 +170,6 @@ launchSettings.json # NetCore Publishing Profiles PublishProfiles/ + +# Glade backup files +*.glade~ diff --git a/ARMeilleure/ARMeilleure.csproj b/ARMeilleure/ARMeilleure.csproj deleted file mode 100644 index e29e33e89..000000000 --- a/ARMeilleure/ARMeilleure.csproj +++ /dev/null @@ -1,12 +0,0 @@ - - - - net6.0 - true - - - - - - - diff --git a/ARMeilleure/CodeGen/CompiledFunction.cs b/ARMeilleure/CodeGen/CompiledFunction.cs deleted file mode 100644 index ab5e88ebb..000000000 --- a/ARMeilleure/CodeGen/CompiledFunction.cs +++ /dev/null @@ -1,56 +0,0 @@ -using ARMeilleure.CodeGen.Linking; -using ARMeilleure.CodeGen.Unwinding; -using ARMeilleure.Translation.Cache; -using System; -using System.Runtime.InteropServices; - -namespace ARMeilleure.CodeGen -{ - /// - /// Represents a compiled function. - /// - readonly struct CompiledFunction - { - /// - /// Gets the machine code of the . - /// - public byte[] Code { get; } - - /// - /// Gets the of the . - /// - public UnwindInfo UnwindInfo { get; } - - /// - /// Gets the of the . - /// - public RelocInfo RelocInfo { get; } - - /// - /// Initializes a new instance of the struct with the specified machine code, - /// unwind info and relocation info. - /// - /// Machine code - /// Unwind info - /// Relocation info - internal CompiledFunction(byte[] code, UnwindInfo unwindInfo, RelocInfo relocInfo) - { - Code = code; - UnwindInfo = unwindInfo; - RelocInfo = relocInfo; - } - - /// - /// Maps the onto the and returns a delegate of type - /// pointing to the mapped function. - /// - /// Type of delegate - /// A delegate of type pointing to the mapped function - public T Map() - { - IntPtr codePtr = JitCache.Map(this); - - return Marshal.GetDelegateForFunctionPointer(codePtr); - } - } -} \ No newline at end of file diff --git a/ARMeilleure/CodeGen/Optimizations/ConstantFolding.cs b/ARMeilleure/CodeGen/Optimizations/ConstantFolding.cs deleted file mode 100644 index 0423c2559..000000000 --- a/ARMeilleure/CodeGen/Optimizations/ConstantFolding.cs +++ /dev/null @@ -1,305 +0,0 @@ -using ARMeilleure.IntermediateRepresentation; -using System; -using static ARMeilleure.IntermediateRepresentation.Operand.Factory; - -namespace ARMeilleure.CodeGen.Optimizations -{ - static class ConstantFolding - { - public static void RunPass(Operation operation) - { - if (operation.Destination == default || operation.SourcesCount == 0) - { - return; - } - - if (!AreAllSourcesConstant(operation)) - { - return; - } - - OperandType type = operation.Destination.Type; - - switch (operation.Instruction) - { - case Instruction.Add: - if (operation.GetSource(0).Relocatable || - operation.GetSource(1).Relocatable) - { - break; - } - - if (type == OperandType.I32) - { - EvaluateBinaryI32(operation, (x, y) => x + y); - } - else if (type == OperandType.I64) - { - EvaluateBinaryI64(operation, (x, y) => x + y); - } - break; - - case Instruction.BitwiseAnd: - if (type == OperandType.I32) - { - EvaluateBinaryI32(operation, (x, y) => x & y); - } - else if (type == OperandType.I64) - { - EvaluateBinaryI64(operation, (x, y) => x & y); - } - break; - - case Instruction.BitwiseExclusiveOr: - if (type == OperandType.I32) - { - EvaluateBinaryI32(operation, (x, y) => x ^ y); - } - else if (type == OperandType.I64) - { - EvaluateBinaryI64(operation, (x, y) => x ^ y); - } - break; - - case Instruction.BitwiseNot: - if (type == OperandType.I32) - { - EvaluateUnaryI32(operation, (x) => ~x); - } - else if (type == OperandType.I64) - { - EvaluateUnaryI64(operation, (x) => ~x); - } - break; - - case Instruction.BitwiseOr: - if (type == OperandType.I32) - { - EvaluateBinaryI32(operation, (x, y) => x | y); - } - else if (type == OperandType.I64) - { - EvaluateBinaryI64(operation, (x, y) => x | y); - } - break; - - case Instruction.ConvertI64ToI32: - if (type == OperandType.I32) - { - EvaluateUnaryI32(operation, (x) => x); - } - break; - - case Instruction.Copy: - if (type == OperandType.I32) - { - EvaluateUnaryI32(operation, (x) => x); - } - else if (type == OperandType.I64) - { - EvaluateUnaryI64(operation, (x) => x); - } - break; - - case Instruction.Divide: - if (type == OperandType.I32) - { - EvaluateBinaryI32(operation, (x, y) => y != 0 ? x / y : 0); - } - else if (type == OperandType.I64) - { - EvaluateBinaryI64(operation, (x, y) => y != 0 ? x / y : 0); - } - break; - - case Instruction.DivideUI: - if (type == OperandType.I32) - { - EvaluateBinaryI32(operation, (x, y) => y != 0 ? (int)((uint)x / (uint)y) : 0); - } - else if (type == OperandType.I64) - { - EvaluateBinaryI64(operation, (x, y) => y != 0 ? (long)((ulong)x / (ulong)y) : 0); - } - break; - - case Instruction.Multiply: - if (type == OperandType.I32) - { - EvaluateBinaryI32(operation, (x, y) => x * y); - } - else if (type == OperandType.I64) - { - EvaluateBinaryI64(operation, (x, y) => x * y); - } - break; - - case Instruction.Negate: - if (type == OperandType.I32) - { - EvaluateUnaryI32(operation, (x) => -x); - } - else if (type == OperandType.I64) - { - EvaluateUnaryI64(operation, (x) => -x); - } - break; - - case Instruction.ShiftLeft: - if (type == OperandType.I32) - { - EvaluateBinaryI32(operation, (x, y) => x << y); - } - else if (type == OperandType.I64) - { - EvaluateBinaryI64(operation, (x, y) => x << (int)y); - } - break; - - case Instruction.ShiftRightSI: - if (type == OperandType.I32) - { - EvaluateBinaryI32(operation, (x, y) => x >> y); - } - else if (type == OperandType.I64) - { - EvaluateBinaryI64(operation, (x, y) => x >> (int)y); - } - break; - - case Instruction.ShiftRightUI: - if (type == OperandType.I32) - { - EvaluateBinaryI32(operation, (x, y) => (int)((uint)x >> y)); - } - else if (type == OperandType.I64) - { - EvaluateBinaryI64(operation, (x, y) => (long)((ulong)x >> (int)y)); - } - break; - - case Instruction.SignExtend16: - if (type == OperandType.I32) - { - EvaluateUnaryI32(operation, (x) => (short)x); - } - else if (type == OperandType.I64) - { - EvaluateUnaryI64(operation, (x) => (short)x); - } - break; - - case Instruction.SignExtend32: - if (type == OperandType.I32) - { - EvaluateUnaryI32(operation, (x) => x); - } - else if (type == OperandType.I64) - { - EvaluateUnaryI64(operation, (x) => (int)x); - } - break; - - case Instruction.SignExtend8: - if (type == OperandType.I32) - { - EvaluateUnaryI32(operation, (x) => (sbyte)x); - } - else if (type == OperandType.I64) - { - EvaluateUnaryI64(operation, (x) => (sbyte)x); - } - break; - - case Instruction.ZeroExtend16: - if (type == OperandType.I32) - { - EvaluateUnaryI32(operation, (x) => (ushort)x); - } - else if (type == OperandType.I64) - { - EvaluateUnaryI64(operation, (x) => (ushort)x); - } - break; - - case Instruction.ZeroExtend32: - if (type == OperandType.I32) - { - EvaluateUnaryI32(operation, (x) => x); - } - else if (type == OperandType.I64) - { - EvaluateUnaryI64(operation, (x) => (uint)x); - } - break; - - case Instruction.ZeroExtend8: - if (type == OperandType.I32) - { - EvaluateUnaryI32(operation, (x) => (byte)x); - } - else if (type == OperandType.I64) - { - EvaluateUnaryI64(operation, (x) => (byte)x); - } - break; - - case Instruction.Subtract: - if (type == OperandType.I32) - { - EvaluateBinaryI32(operation, (x, y) => x - y); - } - else if (type == OperandType.I64) - { - EvaluateBinaryI64(operation, (x, y) => x - y); - } - break; - } - } - - private static bool AreAllSourcesConstant(Operation operation) - { - for (int index = 0; index < operation.SourcesCount; index++) - { - Operand srcOp = operation.GetSource(index); - - if (srcOp.Kind != OperandKind.Constant) - { - return false; - } - } - - return true; - } - - private static void EvaluateUnaryI32(Operation operation, Func op) - { - int x = operation.GetSource(0).AsInt32(); - - operation.TurnIntoCopy(Const(op(x))); - } - - private static void EvaluateUnaryI64(Operation operation, Func op) - { - long x = operation.GetSource(0).AsInt64(); - - operation.TurnIntoCopy(Const(op(x))); - } - - private static void EvaluateBinaryI32(Operation operation, Func op) - { - int x = operation.GetSource(0).AsInt32(); - int y = operation.GetSource(1).AsInt32(); - - operation.TurnIntoCopy(Const(op(x, y))); - } - - private static void EvaluateBinaryI64(Operation operation, Func op) - { - long x = operation.GetSource(0).AsInt64(); - long y = operation.GetSource(1).AsInt64(); - - operation.TurnIntoCopy(Const(op(x, y))); - } - } -} \ No newline at end of file diff --git a/ARMeilleure/CodeGen/Optimizations/Optimizer.cs b/ARMeilleure/CodeGen/Optimizations/Optimizer.cs deleted file mode 100644 index 919e996bd..000000000 --- a/ARMeilleure/CodeGen/Optimizations/Optimizer.cs +++ /dev/null @@ -1,266 +0,0 @@ -using ARMeilleure.IntermediateRepresentation; -using ARMeilleure.Translation; -using System; -using System.Diagnostics; -using static ARMeilleure.IntermediateRepresentation.Operand.Factory; - -namespace ARMeilleure.CodeGen.Optimizations -{ - static class Optimizer - { - public static void RunPass(ControlFlowGraph cfg) - { - // Scratch buffer used to store uses. - Span buffer = default; - - bool modified; - - do - { - modified = false; - - for (BasicBlock block = cfg.Blocks.Last; block != null; block = block.ListPrevious) - { - Operation node; - Operation prevNode; - - for (node = block.Operations.Last; node != default; node = prevNode) - { - prevNode = node.ListPrevious; - - if (IsUnused(node)) - { - RemoveNode(block, node); - - modified = true; - - continue; - } - else if (node.Instruction == Instruction.Phi) - { - continue; - } - - ConstantFolding.RunPass(node); - Simplification.RunPass(node); - - if (DestIsLocalVar(node)) - { - if (IsPropagableCompare(node)) - { - modified |= PropagateCompare(ref buffer, node); - - if (modified && IsUnused(node)) - { - RemoveNode(block, node); - } - } - else if (IsPropagableCopy(node)) - { - PropagateCopy(ref buffer, node); - - RemoveNode(block, node); - - modified = true; - } - } - } - } - } - while (modified); - } - - public static void RemoveUnusedNodes(ControlFlowGraph cfg) - { - bool modified; - - do - { - modified = false; - - for (BasicBlock block = cfg.Blocks.Last; block != null; block = block.ListPrevious) - { - Operation node; - Operation prevNode; - - for (node = block.Operations.Last; node != default; node = prevNode) - { - prevNode = node.ListPrevious; - - if (IsUnused(node)) - { - RemoveNode(block, node); - - modified = true; - } - } - } - } - while (modified); - } - - private static Span GetUses(ref Span buffer, Operand operand) - { - ReadOnlySpan uses = operand.Uses; - - if (buffer.Length < uses.Length) - { - buffer = Allocators.Default.AllocateSpan((uint)uses.Length); - } - - uses.CopyTo(buffer); - - return buffer.Slice(0, uses.Length); - } - - private static bool PropagateCompare(ref Span buffer, Operation compOp) - { - // Try to propagate Compare operations into their BranchIf uses, when these BranchIf uses are in the form - // of: - // - // - BranchIf %x, 0x0, Equal ;; i.e BranchIfFalse %x - // - BranchIf %x, 0x0, NotEqual ;; i.e BranchIfTrue %x - // - // The commutative property of Equal and NotEqual is taken into consideration as well. - // - // For example: - // - // %x = Compare %a, %b, comp - // BranchIf %x, 0x0, NotEqual - // - // => - // - // BranchIf %a, %b, comp - - static bool IsZeroBranch(Operation operation, out Comparison compType) - { - compType = Comparison.Equal; - - if (operation.Instruction != Instruction.BranchIf) - { - return false; - } - - Operand src1 = operation.GetSource(0); - Operand src2 = operation.GetSource(1); - Operand comp = operation.GetSource(2); - - compType = (Comparison)comp.AsInt32(); - - return (src1.Kind == OperandKind.Constant && src1.Value == 0) || - (src2.Kind == OperandKind.Constant && src2.Value == 0); - } - - bool modified = false; - - Operand dest = compOp.Destination; - Operand src1 = compOp.GetSource(0); - Operand src2 = compOp.GetSource(1); - Operand comp = compOp.GetSource(2); - - Comparison compType = (Comparison)comp.AsInt32(); - - Span uses = GetUses(ref buffer, dest); - - foreach (Operation use in uses) - { - // If operation is a BranchIf and has a constant value 0 in its RHS or LHS source operands. - if (IsZeroBranch(use, out Comparison otherCompType)) - { - Comparison propCompType; - - if (otherCompType == Comparison.NotEqual) - { - propCompType = compType; - } - else if (otherCompType == Comparison.Equal) - { - propCompType = compType.Invert(); - } - else - { - continue; - } - - use.SetSource(0, src1); - use.SetSource(1, src2); - use.SetSource(2, Const((int)propCompType)); - - modified = true; - } - } - - return modified; - } - - private static void PropagateCopy(ref Span buffer, Operation copyOp) - { - // Propagate copy source operand to all uses of the destination operand. - Operand dest = copyOp.Destination; - Operand source = copyOp.GetSource(0); - - Span uses = GetUses(ref buffer, dest); - - foreach (Operation use in uses) - { - for (int index = 0; index < use.SourcesCount; index++) - { - if (use.GetSource(index) == dest) - { - use.SetSource(index, source); - } - } - } - } - - private static void RemoveNode(BasicBlock block, Operation node) - { - // Remove a node from the nodes list, and also remove itself - // from all the use lists on the operands that this node uses. - block.Operations.Remove(node); - - for (int index = 0; index < node.SourcesCount; index++) - { - node.SetSource(index, default); - } - - Debug.Assert(node.Destination == default || node.Destination.UsesCount == 0); - - node.Destination = default; - } - - private static bool IsUnused(Operation node) - { - return DestIsLocalVar(node) && node.Destination.UsesCount == 0 && !HasSideEffects(node); - } - - private static bool DestIsLocalVar(Operation node) - { - return node.Destination != default && node.Destination.Kind == OperandKind.LocalVariable; - } - - private static bool HasSideEffects(Operation node) - { - return node.Instruction == Instruction.Call - || node.Instruction == Instruction.Tailcall - || node.Instruction == Instruction.CompareAndSwap - || node.Instruction == Instruction.CompareAndSwap16 - || node.Instruction == Instruction.CompareAndSwap8; - } - - private static bool IsPropagableCompare(Operation operation) - { - return operation.Instruction == Instruction.Compare; - } - - private static bool IsPropagableCopy(Operation operation) - { - if (operation.Instruction != Instruction.Copy) - { - return false; - } - - return operation.Destination.Type == operation.GetSource(0).Type; - } - } -} \ No newline at end of file diff --git a/ARMeilleure/CodeGen/Optimizations/Simplification.cs b/ARMeilleure/CodeGen/Optimizations/Simplification.cs deleted file mode 100644 index a439d6424..000000000 --- a/ARMeilleure/CodeGen/Optimizations/Simplification.cs +++ /dev/null @@ -1,183 +0,0 @@ -using ARMeilleure.IntermediateRepresentation; -using System; -using static ARMeilleure.IntermediateRepresentation.Operand.Factory; - -namespace ARMeilleure.CodeGen.Optimizations -{ - static class Simplification - { - public static void RunPass(Operation operation) - { - switch (operation.Instruction) - { - case Instruction.Add: - if (operation.GetSource(0).Relocatable || - operation.GetSource(1).Relocatable) - { - break; - } - - TryEliminateBinaryOpComutative(operation, 0); - break; - - case Instruction.BitwiseAnd: - TryEliminateBitwiseAnd(operation); - break; - - case Instruction.BitwiseOr: - TryEliminateBitwiseOr(operation); - break; - - case Instruction.BitwiseExclusiveOr: - TryEliminateBitwiseExclusiveOr(operation); - break; - - case Instruction.ConditionalSelect: - TryEliminateConditionalSelect(operation); - break; - - case Instruction.Divide: - TryEliminateBinaryOpY(operation, 1); - break; - - case Instruction.Multiply: - TryEliminateBinaryOpComutative(operation, 1); - break; - - case Instruction.ShiftLeft: - case Instruction.ShiftRightSI: - case Instruction.ShiftRightUI: - case Instruction.Subtract: - TryEliminateBinaryOpY(operation, 0); - break; - } - } - - private static void TryEliminateBitwiseAnd(Operation operation) - { - // Try to recognize and optimize those 3 patterns (in order): - // x & 0xFFFFFFFF == x, 0xFFFFFFFF & y == y, - // x & 0x00000000 == 0x00000000, 0x00000000 & y == 0x00000000 - Operand x = operation.GetSource(0); - Operand y = operation.GetSource(1); - - if (IsConstEqual(x, AllOnes(x.Type))) - { - operation.TurnIntoCopy(y); - } - else if (IsConstEqual(y, AllOnes(y.Type))) - { - operation.TurnIntoCopy(x); - } - else if (IsConstEqual(x, 0) || IsConstEqual(y, 0)) - { - operation.TurnIntoCopy(Const(x.Type, 0)); - } - } - - private static void TryEliminateBitwiseOr(Operation operation) - { - // Try to recognize and optimize those 3 patterns (in order): - // x | 0x00000000 == x, 0x00000000 | y == y, - // x | 0xFFFFFFFF == 0xFFFFFFFF, 0xFFFFFFFF | y == 0xFFFFFFFF - Operand x = operation.GetSource(0); - Operand y = operation.GetSource(1); - - if (IsConstEqual(x, 0)) - { - operation.TurnIntoCopy(y); - } - else if (IsConstEqual(y, 0)) - { - operation.TurnIntoCopy(x); - } - else if (IsConstEqual(x, AllOnes(x.Type)) || IsConstEqual(y, AllOnes(y.Type))) - { - operation.TurnIntoCopy(Const(AllOnes(x.Type))); - } - } - - private static void TryEliminateBitwiseExclusiveOr(Operation operation) - { - // Try to recognize and optimize those 2 patterns (in order): - // x ^ y == 0x00000000 when x == y - // 0x00000000 ^ y == y, x ^ 0x00000000 == x - Operand x = operation.GetSource(0); - Operand y = operation.GetSource(1); - - if (x == y && x.Type.IsInteger()) - { - operation.TurnIntoCopy(Const(x.Type, 0)); - } - else - { - TryEliminateBinaryOpComutative(operation, 0); - } - } - - private static void TryEliminateBinaryOpY(Operation operation, ulong comparand) - { - Operand x = operation.GetSource(0); - Operand y = operation.GetSource(1); - - if (IsConstEqual(y, comparand)) - { - operation.TurnIntoCopy(x); - } - } - - private static void TryEliminateBinaryOpComutative(Operation operation, ulong comparand) - { - Operand x = operation.GetSource(0); - Operand y = operation.GetSource(1); - - if (IsConstEqual(x, comparand)) - { - operation.TurnIntoCopy(y); - } - else if (IsConstEqual(y, comparand)) - { - operation.TurnIntoCopy(x); - } - } - - private static void TryEliminateConditionalSelect(Operation operation) - { - Operand cond = operation.GetSource(0); - - if (cond.Kind != OperandKind.Constant) - { - return; - } - - // The condition is constant, we can turn it into a copy, and select - // the source based on the condition value. - int srcIndex = cond.Value != 0 ? 1 : 2; - - Operand source = operation.GetSource(srcIndex); - - operation.TurnIntoCopy(source); - } - - private static bool IsConstEqual(Operand operand, ulong comparand) - { - if (operand.Kind != OperandKind.Constant || !operand.Type.IsInteger()) - { - return false; - } - - return operand.Value == comparand; - } - - private static ulong AllOnes(OperandType type) - { - switch (type) - { - case OperandType.I32: return ~0U; - case OperandType.I64: return ~0UL; - } - - throw new ArgumentException("Invalid operand type \"" + type + "\"."); - } - } -} \ No newline at end of file diff --git a/ARMeilleure/CodeGen/RegisterAllocators/UseList.cs b/ARMeilleure/CodeGen/RegisterAllocators/UseList.cs deleted file mode 100644 index c89f0854d..000000000 --- a/ARMeilleure/CodeGen/RegisterAllocators/UseList.cs +++ /dev/null @@ -1,84 +0,0 @@ -using System; - -namespace ARMeilleure.CodeGen.RegisterAllocators -{ - unsafe struct UseList - { - private int* _items; - private int _capacity; - private int _count; - - public int Count => _count; - public int FirstUse => _count > 0 ? _items[_count - 1] : LiveInterval.NotFound; - public Span Span => new(_items, _count); - - public void Add(int position) - { - if (_count + 1 > _capacity) - { - var oldSpan = Span; - - _capacity = Math.Max(4, _capacity * 2); - _items = Allocators.Default.Allocate((uint)_capacity); - - var newSpan = Span; - - oldSpan.CopyTo(newSpan); - } - - // Use positions are usually inserted in descending order, so inserting in descending order is faster, - // since the number of half exchanges is reduced. - int i = _count - 1; - - while (i >= 0 && _items[i] < position) - { - _items[i + 1] = _items[i--]; - } - - _items[i + 1] = position; - _count++; - } - - public int NextUse(int position) - { - int index = NextUseIndex(position); - - return index != LiveInterval.NotFound ? _items[index] : LiveInterval.NotFound; - } - - public int NextUseIndex(int position) - { - int i = _count - 1; - - if (i == -1 || position > _items[0]) - { - return LiveInterval.NotFound; - } - - while (i >= 0 && _items[i] < position) - { - i--; - } - - return i; - } - - public UseList Split(int position) - { - int index = NextUseIndex(position); - - // Since the list is in descending order, the new split list takes the front of the list and the current - // list takes the back of the list. - UseList result = new(); - result._count = index + 1; - result._capacity = result._count; - result._items = _items; - - _count = _count - result._count; - _capacity = _count; - _items = _items + result._count; - - return result; - } - } -} \ No newline at end of file diff --git a/ARMeilleure/CodeGen/Unwinding/UnwindPseudoOp.cs b/ARMeilleure/CodeGen/Unwinding/UnwindPseudoOp.cs deleted file mode 100644 index 4a8288a28..000000000 --- a/ARMeilleure/CodeGen/Unwinding/UnwindPseudoOp.cs +++ /dev/null @@ -1,11 +0,0 @@ -namespace ARMeilleure.CodeGen.Unwinding -{ - enum UnwindPseudoOp - { - PushReg = 0, - SetFrame = 1, - AllocStack = 2, - SaveReg = 3, - SaveXmm128 = 4 - } -} \ No newline at end of file diff --git a/ARMeilleure/CodeGen/X86/Assembler.cs b/ARMeilleure/CodeGen/X86/Assembler.cs deleted file mode 100644 index c15deadc5..000000000 --- a/ARMeilleure/CodeGen/X86/Assembler.cs +++ /dev/null @@ -1,1455 +0,0 @@ -using ARMeilleure.CodeGen.Linking; -using ARMeilleure.IntermediateRepresentation; -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.IO; -using System.Runtime.InteropServices; - -namespace ARMeilleure.CodeGen.X86 -{ - partial class Assembler - { - private const int ReservedBytesForJump = 1; - - private const int OpModRMBits = 24; - - private const byte RexPrefix = 0x40; - private const byte RexWPrefix = 0x48; - private const byte LockPrefix = 0xf0; - - private const int MaxRegNumber = 15; - - private struct Jump - { - public bool IsConditional { get; } - public X86Condition Condition { get; } - public Operand JumpLabel { get; } - public long? JumpTarget { get; set; } - public long JumpPosition { get; } - public long Offset { get; set; } - public int InstSize { get; set; } - - public Jump(Operand jumpLabel, long jumpPosition) - { - IsConditional = false; - Condition = 0; - JumpLabel = jumpLabel; - JumpTarget = null; - JumpPosition = jumpPosition; - - Offset = 0; - InstSize = 0; - } - - public Jump(X86Condition condition, Operand jumpLabel, long jumpPosition) - { - IsConditional = true; - Condition = condition; - JumpLabel = jumpLabel; - JumpTarget = null; - JumpPosition = jumpPosition; - - Offset = 0; - InstSize = 0; - } - } - - private struct Reloc - { - public int JumpIndex { get; set; } - public int Position { get; set; } - public Symbol Symbol { get; set; } - } - - private readonly List _jumps; - private readonly List _relocs; - private readonly Dictionary _labels; - private readonly Stream _stream; - - public bool HasRelocs => _relocs != null; - - public Assembler(Stream stream, bool relocatable) - { - _stream = stream; - _labels = new Dictionary(); - _jumps = new List(); - - _relocs = relocatable ? new List() : null; - } - - public void MarkLabel(Operand label) - { - _labels.Add(label, _stream.Position); - } - - public void Add(Operand dest, Operand source, OperandType type) - { - WriteInstruction(dest, source, type, X86Instruction.Add); - } - - public void Addsd(Operand dest, Operand src1, Operand src2) - { - WriteInstruction(dest, src1, src2, X86Instruction.Addsd); - } - - public void Addss(Operand dest, Operand src1, Operand src2) - { - WriteInstruction(dest, src1, src2, X86Instruction.Addss); - } - - public void And(Operand dest, Operand source, OperandType type) - { - WriteInstruction(dest, source, type, X86Instruction.And); - } - - public void Bsr(Operand dest, Operand source, OperandType type) - { - WriteInstruction(dest, source, type, X86Instruction.Bsr); - } - - public void Bswap(Operand dest) - { - WriteInstruction(dest, default, dest.Type, X86Instruction.Bswap); - } - - public void Call(Operand dest) - { - WriteInstruction(dest, default, OperandType.None, X86Instruction.Call); - } - - public void Cdq() - { - WriteByte(0x99); - } - - public void Cmovcc(Operand dest, Operand source, OperandType type, X86Condition condition) - { - ref readonly InstructionInfo info = ref _instTable[(int)X86Instruction.Cmovcc]; - - WriteOpCode(dest, default, source, type, info.Flags, info.OpRRM | (int)condition, rrm: true); - } - - public void Cmp(Operand src1, Operand src2, OperandType type) - { - WriteInstruction(src1, src2, type, X86Instruction.Cmp); - } - - public void Cqo() - { - WriteByte(0x48); - WriteByte(0x99); - } - - public void Cmpxchg(Operand memOp, Operand src) - { - Debug.Assert(memOp.Kind == OperandKind.Memory); - - WriteByte(LockPrefix); - - WriteInstruction(memOp, src, src.Type, X86Instruction.Cmpxchg); - } - - public void Cmpxchg16(Operand memOp, Operand src) - { - Debug.Assert(memOp.Kind == OperandKind.Memory); - - WriteByte(LockPrefix); - WriteByte(0x66); - - WriteInstruction(memOp, src, src.Type, X86Instruction.Cmpxchg); - } - - public void Cmpxchg16b(Operand memOp) - { - Debug.Assert(memOp.Kind == OperandKind.Memory); - - WriteByte(LockPrefix); - - WriteInstruction(memOp, default, OperandType.None, X86Instruction.Cmpxchg16b); - } - - public void Cmpxchg8(Operand memOp, Operand src) - { - Debug.Assert(memOp.Kind == OperandKind.Memory); - - WriteByte(LockPrefix); - - WriteInstruction(memOp, src, src.Type, X86Instruction.Cmpxchg8); - } - - public void Comisd(Operand src1, Operand src2) - { - WriteInstruction(src1, default, src2, X86Instruction.Comisd); - } - - public void Comiss(Operand src1, Operand src2) - { - WriteInstruction(src1, default, src2, X86Instruction.Comiss); - } - - public void Cvtsd2ss(Operand dest, Operand src1, Operand src2) - { - WriteInstruction(dest, src1, src2, X86Instruction.Cvtsd2ss); - } - - public void Cvtsi2sd(Operand dest, Operand src1, Operand src2, OperandType type) - { - WriteInstruction(dest, src1, src2, X86Instruction.Cvtsi2sd, type); - } - - public void Cvtsi2ss(Operand dest, Operand src1, Operand src2, OperandType type) - { - WriteInstruction(dest, src1, src2, X86Instruction.Cvtsi2ss, type); - } - - public void Cvtss2sd(Operand dest, Operand src1, Operand src2) - { - WriteInstruction(dest, src1, src2, X86Instruction.Cvtss2sd); - } - - public void Div(Operand source) - { - WriteInstruction(default, source, source.Type, X86Instruction.Div); - } - - public void Divsd(Operand dest, Operand src1, Operand src2) - { - WriteInstruction(dest, src1, src2, X86Instruction.Divsd); - } - - public void Divss(Operand dest, Operand src1, Operand src2) - { - WriteInstruction(dest, src1, src2, X86Instruction.Divss); - } - - public void Idiv(Operand source) - { - WriteInstruction(default, source, source.Type, X86Instruction.Idiv); - } - - public void Imul(Operand source) - { - WriteInstruction(default, source, source.Type, X86Instruction.Imul128); - } - - public void Imul(Operand dest, Operand source, OperandType type) - { - if (source.Kind != OperandKind.Register) - { - throw new ArgumentException($"Invalid source operand kind \"{source.Kind}\"."); - } - - WriteInstruction(dest, source, type, X86Instruction.Imul); - } - - public void Imul(Operand dest, Operand src1, Operand src2, OperandType type) - { - ref readonly InstructionInfo info = ref _instTable[(int)X86Instruction.Imul]; - - if (src2.Kind != OperandKind.Constant) - { - throw new ArgumentException($"Invalid source 2 operand kind \"{src2.Kind}\"."); - } - - if (IsImm8(src2.Value, src2.Type) && info.OpRMImm8 != BadOp) - { - WriteOpCode(dest, default, src1, type, info.Flags, info.OpRMImm8, rrm: true); - - WriteByte(src2.AsByte()); - } - else if (IsImm32(src2.Value, src2.Type) && info.OpRMImm32 != BadOp) - { - WriteOpCode(dest, default, src1, type, info.Flags, info.OpRMImm32, rrm: true); - - WriteInt32(src2.AsInt32()); - } - else - { - throw new ArgumentException($"Failed to encode constant 0x{src2.Value:X}."); - } - } - - public void Insertps(Operand dest, Operand src1, Operand src2, byte imm) - { - WriteInstruction(dest, src1, src2, X86Instruction.Insertps); - - WriteByte(imm); - } - - public void Jcc(X86Condition condition, Operand dest) - { - if (dest.Kind == OperandKind.Label) - { - _jumps.Add(new Jump(condition, dest, _stream.Position)); - - // ReservedBytesForJump - WriteByte(0); - } - else - { - throw new ArgumentException("Destination operand must be of kind Label", nameof(dest)); - } - } - - public void Jcc(X86Condition condition, long offset) - { - if (ConstFitsOnS8(offset)) - { - WriteByte((byte)(0x70 | (int)condition)); - - WriteByte((byte)offset); - } - else if (ConstFitsOnS32(offset)) - { - WriteByte(0x0f); - WriteByte((byte)(0x80 | (int)condition)); - - WriteInt32((int)offset); - } - else - { - throw new ArgumentOutOfRangeException(nameof(offset)); - } - } - - public void Jmp(long offset) - { - if (ConstFitsOnS8(offset)) - { - WriteByte(0xeb); - - WriteByte((byte)offset); - } - else if (ConstFitsOnS32(offset)) - { - WriteByte(0xe9); - - WriteInt32((int)offset); - } - else - { - throw new ArgumentOutOfRangeException(nameof(offset)); - } - } - - public void Jmp(Operand dest) - { - if (dest.Kind == OperandKind.Label) - { - _jumps.Add(new Jump(dest, _stream.Position)); - - // ReservedBytesForJump - WriteByte(0); - } - else - { - WriteInstruction(dest, default, OperandType.None, X86Instruction.Jmp); - } - } - - public void Ldmxcsr(Operand dest) - { - WriteInstruction(dest, default, OperandType.I32, X86Instruction.Ldmxcsr); - } - - public void Lea(Operand dest, Operand source, OperandType type) - { - WriteInstruction(dest, source, type, X86Instruction.Lea); - } - - public void LockOr(Operand dest, Operand source, OperandType type) - { - WriteByte(LockPrefix); - WriteInstruction(dest, source, type, X86Instruction.Or); - } - - public void Mov(Operand dest, Operand source, OperandType type) - { - WriteInstruction(dest, source, type, X86Instruction.Mov); - } - - public void Mov16(Operand dest, Operand source) - { - WriteInstruction(dest, source, OperandType.None, X86Instruction.Mov16); - } - - public void Mov8(Operand dest, Operand source) - { - WriteInstruction(dest, source, OperandType.None, X86Instruction.Mov8); - } - - public void Movd(Operand dest, Operand source) - { - ref readonly InstructionInfo info = ref _instTable[(int)X86Instruction.Movd]; - - if (source.Type.IsInteger() || source.Kind == OperandKind.Memory) - { - WriteOpCode(dest, default, source, OperandType.None, info.Flags, info.OpRRM, rrm: true); - } - else - { - WriteOpCode(dest, default, source, OperandType.None, info.Flags, info.OpRMR); - } - } - - public void Movdqu(Operand dest, Operand source) - { - WriteInstruction(dest, default, source, X86Instruction.Movdqu); - } - - public void Movhlps(Operand dest, Operand src1, Operand src2) - { - WriteInstruction(dest, src1, src2, X86Instruction.Movhlps); - } - - public void Movlhps(Operand dest, Operand src1, Operand src2) - { - WriteInstruction(dest, src1, src2, X86Instruction.Movlhps); - } - - public void Movq(Operand dest, Operand source) - { - ref readonly InstructionInfo info = ref _instTable[(int)X86Instruction.Movd]; - - InstructionFlags flags = info.Flags | InstructionFlags.RexW; - - if (source.Type.IsInteger() || source.Kind == OperandKind.Memory) - { - WriteOpCode(dest, default, source, OperandType.None, flags, info.OpRRM, rrm: true); - } - else if (dest.Type.IsInteger() || dest.Kind == OperandKind.Memory) - { - WriteOpCode(dest, default, source, OperandType.None, flags, info.OpRMR); - } - else - { - WriteInstruction(dest, source, OperandType.None, X86Instruction.Movq); - } - } - - public void Movsd(Operand dest, Operand src1, Operand src2) - { - WriteInstruction(dest, src1, src2, X86Instruction.Movsd); - } - - public void Movss(Operand dest, Operand src1, Operand src2) - { - WriteInstruction(dest, src1, src2, X86Instruction.Movss); - } - - public void Movsx16(Operand dest, Operand source, OperandType type) - { - WriteInstruction(dest, source, type, X86Instruction.Movsx16); - } - - public void Movsx32(Operand dest, Operand source, OperandType type) - { - WriteInstruction(dest, source, type, X86Instruction.Movsx32); - } - - public void Movsx8(Operand dest, Operand source, OperandType type) - { - WriteInstruction(dest, source, type, X86Instruction.Movsx8); - } - - public void Movzx16(Operand dest, Operand source, OperandType type) - { - WriteInstruction(dest, source, type, X86Instruction.Movzx16); - } - - public void Movzx8(Operand dest, Operand source, OperandType type) - { - WriteInstruction(dest, source, type, X86Instruction.Movzx8); - } - - public void Mul(Operand source) - { - WriteInstruction(default, source, source.Type, X86Instruction.Mul128); - } - - public void Mulsd(Operand dest, Operand src1, Operand src2) - { - WriteInstruction(dest, src1, src2, X86Instruction.Mulsd); - } - - public void Mulss(Operand dest, Operand src1, Operand src2) - { - WriteInstruction(dest, src1, src2, X86Instruction.Mulss); - } - - public void Neg(Operand dest) - { - WriteInstruction(dest, default, dest.Type, X86Instruction.Neg); - } - - public void Not(Operand dest) - { - WriteInstruction(dest, default, dest.Type, X86Instruction.Not); - } - - public void Or(Operand dest, Operand source, OperandType type) - { - WriteInstruction(dest, source, type, X86Instruction.Or); - } - - public void Pclmulqdq(Operand dest, Operand source, byte imm) - { - WriteInstruction(dest, default, source, X86Instruction.Pclmulqdq); - - WriteByte(imm); - } - - public void Pcmpeqw(Operand dest, Operand src1, Operand src2) - { - WriteInstruction(dest, src1, src2, X86Instruction.Pcmpeqw); - } - - public void Pextrb(Operand dest, Operand source, byte imm) - { - WriteInstruction(dest, default, source, X86Instruction.Pextrb); - - WriteByte(imm); - } - - public void Pextrd(Operand dest, Operand source, byte imm) - { - WriteInstruction(dest, default, source, X86Instruction.Pextrd); - - WriteByte(imm); - } - - public void Pextrq(Operand dest, Operand source, byte imm) - { - WriteInstruction(dest, default, source, X86Instruction.Pextrq); - - WriteByte(imm); - } - - public void Pextrw(Operand dest, Operand source, byte imm) - { - WriteInstruction(dest, default, source, X86Instruction.Pextrw); - - WriteByte(imm); - } - - public void Pinsrb(Operand dest, Operand src1, Operand src2, byte imm) - { - WriteInstruction(dest, src1, src2, X86Instruction.Pinsrb); - - WriteByte(imm); - } - - public void Pinsrd(Operand dest, Operand src1, Operand src2, byte imm) - { - WriteInstruction(dest, src1, src2, X86Instruction.Pinsrd); - - WriteByte(imm); - } - - public void Pinsrq(Operand dest, Operand src1, Operand src2, byte imm) - { - WriteInstruction(dest, src1, src2, X86Instruction.Pinsrq); - - WriteByte(imm); - } - - public void Pinsrw(Operand dest, Operand src1, Operand src2, byte imm) - { - WriteInstruction(dest, src1, src2, X86Instruction.Pinsrw); - - WriteByte(imm); - } - - public void Pop(Operand dest) - { - if (dest.Kind == OperandKind.Register) - { - WriteCompactInst(dest, 0x58); - } - else - { - WriteInstruction(dest, default, dest.Type, X86Instruction.Pop); - } - } - - public void Popcnt(Operand dest, Operand source, OperandType type) - { - WriteInstruction(dest, source, type, X86Instruction.Popcnt); - } - - public void Pshufd(Operand dest, Operand source, byte imm) - { - WriteInstruction(dest, default, source, X86Instruction.Pshufd); - - WriteByte(imm); - } - - public void Push(Operand source) - { - if (source.Kind == OperandKind.Register) - { - WriteCompactInst(source, 0x50); - } - else - { - WriteInstruction(default, source, source.Type, X86Instruction.Push); - } - } - - public void Return() - { - WriteByte(0xc3); - } - - public void Ror(Operand dest, Operand source, OperandType type) - { - WriteShiftInst(dest, source, type, X86Instruction.Ror); - } - - public void Sar(Operand dest, Operand source, OperandType type) - { - WriteShiftInst(dest, source, type, X86Instruction.Sar); - } - - public void Shl(Operand dest, Operand source, OperandType type) - { - WriteShiftInst(dest, source, type, X86Instruction.Shl); - } - - public void Shr(Operand dest, Operand source, OperandType type) - { - WriteShiftInst(dest, source, type, X86Instruction.Shr); - } - - public void Setcc(Operand dest, X86Condition condition) - { - ref readonly InstructionInfo info = ref _instTable[(int)X86Instruction.Setcc]; - - WriteOpCode(dest, default, default, OperandType.None, info.Flags, info.OpRRM | (int)condition); - } - - public void Stmxcsr(Operand dest) - { - WriteInstruction(dest, default, OperandType.I32, X86Instruction.Stmxcsr); - } - - public void Sub(Operand dest, Operand source, OperandType type) - { - WriteInstruction(dest, source, type, X86Instruction.Sub); - } - - public void Subsd(Operand dest, Operand src1, Operand src2) - { - WriteInstruction(dest, src1, src2, X86Instruction.Subsd); - } - - public void Subss(Operand dest, Operand src1, Operand src2) - { - WriteInstruction(dest, src1, src2, X86Instruction.Subss); - } - - public void Test(Operand src1, Operand src2, OperandType type) - { - WriteInstruction(src1, src2, type, X86Instruction.Test); - } - - public void Xor(Operand dest, Operand source, OperandType type) - { - WriteInstruction(dest, source, type, X86Instruction.Xor); - } - - public void Xorps(Operand dest, Operand src1, Operand src2) - { - WriteInstruction(dest, src1, src2, X86Instruction.Xorps); - } - - public void WriteInstruction( - X86Instruction inst, - Operand dest, - Operand source, - OperandType type = OperandType.None) - { - WriteInstruction(dest, default, source, inst, type); - } - - public void WriteInstruction(X86Instruction inst, Operand dest, Operand src1, Operand src2) - { - if (src2.Kind == OperandKind.Constant) - { - WriteInstruction(src1, dest, src2, inst); - } - else - { - WriteInstruction(dest, src1, src2, inst); - } - } - - public void WriteInstruction( - X86Instruction inst, - Operand dest, - Operand src1, - Operand src2, - OperandType type) - { - WriteInstruction(dest, src1, src2, inst, type); - } - - public void WriteInstruction(X86Instruction inst, Operand dest, Operand source, byte imm) - { - WriteInstruction(dest, default, source, inst); - - WriteByte(imm); - } - - public void WriteInstruction( - X86Instruction inst, - Operand dest, - Operand src1, - Operand src2, - Operand src3) - { - // 3+ operands can only be encoded with the VEX encoding scheme. - Debug.Assert(HardwareCapabilities.SupportsVexEncoding); - - WriteInstruction(dest, src1, src2, inst); - - WriteByte((byte)(src3.AsByte() << 4)); - } - - public void WriteInstruction( - X86Instruction inst, - Operand dest, - Operand src1, - Operand src2, - byte imm) - { - WriteInstruction(dest, src1, src2, inst); - - WriteByte(imm); - } - - private void WriteShiftInst(Operand dest, Operand source, OperandType type, X86Instruction inst) - { - if (source.Kind == OperandKind.Register) - { - X86Register shiftReg = (X86Register)source.GetRegister().Index; - - Debug.Assert(shiftReg == X86Register.Rcx, $"Invalid shift register \"{shiftReg}\"."); - - source = default; - } - else if (source.Kind == OperandKind.Constant) - { - source = Operand.Factory.Const((int)source.Value & (dest.Type == OperandType.I32 ? 0x1f : 0x3f)); - } - - WriteInstruction(dest, source, type, inst); - } - - private void WriteInstruction(Operand dest, Operand source, OperandType type, X86Instruction inst) - { - ref readonly InstructionInfo info = ref _instTable[(int)inst]; - - if (source != default) - { - if (source.Kind == OperandKind.Constant) - { - ulong imm = source.Value; - - if (inst == X86Instruction.Mov8) - { - WriteOpCode(dest, default, default, type, info.Flags, info.OpRMImm8); - - WriteByte((byte)imm); - } - else if (inst == X86Instruction.Mov16) - { - WriteOpCode(dest, default, default, type, info.Flags, info.OpRMImm32); - - WriteInt16((short)imm); - } - else if (IsImm8(imm, type) && info.OpRMImm8 != BadOp) - { - WriteOpCode(dest, default, default, type, info.Flags, info.OpRMImm8); - - WriteByte((byte)imm); - } - else if (!source.Relocatable && IsImm32(imm, type) && info.OpRMImm32 != BadOp) - { - WriteOpCode(dest, default, default, type, info.Flags, info.OpRMImm32); - - WriteInt32((int)imm); - } - else if (dest != default && dest.Kind == OperandKind.Register && info.OpRImm64 != BadOp) - { - int rexPrefix = GetRexPrefix(dest, source, type, rrm: false); - - if (rexPrefix != 0) - { - WriteByte((byte)rexPrefix); - } - - WriteByte((byte)(info.OpRImm64 + (dest.GetRegister().Index & 0b111))); - - if (HasRelocs && source.Relocatable) - { - _relocs.Add(new Reloc - { - JumpIndex = _jumps.Count - 1, - Position = (int)_stream.Position, - Symbol = source.Symbol - }); - } - - WriteUInt64(imm); - } - else - { - throw new ArgumentException($"Failed to encode constant 0x{imm:X}."); - } - } - else if (source.Kind == OperandKind.Register && info.OpRMR != BadOp) - { - WriteOpCode(dest, default, source, type, info.Flags, info.OpRMR); - } - else if (info.OpRRM != BadOp) - { - WriteOpCode(dest, default, source, type, info.Flags, info.OpRRM, rrm: true); - } - else - { - throw new ArgumentException($"Invalid source operand kind \"{source.Kind}\"."); - } - } - else if (info.OpRRM != BadOp) - { - WriteOpCode(dest, default, source, type, info.Flags, info.OpRRM, rrm: true); - } - else if (info.OpRMR != BadOp) - { - WriteOpCode(dest, default, source, type, info.Flags, info.OpRMR); - } - else - { - throw new ArgumentNullException(nameof(source)); - } - } - - private void WriteInstruction( - Operand dest, - Operand src1, - Operand src2, - X86Instruction inst, - OperandType type = OperandType.None) - { - ref readonly InstructionInfo info = ref _instTable[(int)inst]; - - if (src2 != default) - { - if (src2.Kind == OperandKind.Constant) - { - ulong imm = src2.Value; - - if ((byte)imm == imm && info.OpRMImm8 != BadOp) - { - WriteOpCode(dest, src1, default, type, info.Flags, info.OpRMImm8); - - WriteByte((byte)imm); - } - else - { - throw new ArgumentException($"Failed to encode constant 0x{imm:X}."); - } - } - else if (src2.Kind == OperandKind.Register && info.OpRMR != BadOp) - { - WriteOpCode(dest, src1, src2, type, info.Flags, info.OpRMR); - } - else if (info.OpRRM != BadOp) - { - WriteOpCode(dest, src1, src2, type, info.Flags, info.OpRRM, rrm: true); - } - else - { - throw new ArgumentException($"Invalid source operand kind \"{src2.Kind}\"."); - } - } - else if (info.OpRRM != BadOp) - { - WriteOpCode(dest, src1, src2, type, info.Flags, info.OpRRM, rrm: true); - } - else if (info.OpRMR != BadOp) - { - WriteOpCode(dest, src1, src2, type, info.Flags, info.OpRMR); - } - else - { - throw new ArgumentNullException(nameof(src2)); - } - } - - private void WriteOpCode( - Operand dest, - Operand src1, - Operand src2, - OperandType type, - InstructionFlags flags, - int opCode, - bool rrm = false) - { - int rexPrefix = GetRexPrefix(dest, src2, type, rrm); - - if ((flags & InstructionFlags.RexW) != 0) - { - rexPrefix |= RexWPrefix; - } - - int modRM = (opCode >> OpModRMBits) << 3; - - MemoryOperand memOp = default; - bool hasMemOp = false; - - if (dest != default) - { - if (dest.Kind == OperandKind.Register) - { - int regIndex = dest.GetRegister().Index; - - modRM |= (regIndex & 0b111) << (rrm ? 3 : 0); - - if ((flags & InstructionFlags.Reg8Dest) != 0 && regIndex >= 4) - { - rexPrefix |= RexPrefix; - } - } - else if (dest.Kind == OperandKind.Memory) - { - memOp = dest.GetMemory(); - hasMemOp = true; - } - else - { - throw new ArgumentException("Invalid destination operand kind \"" + dest.Kind + "\"."); - } - } - - if (src2 != default) - { - if (src2.Kind == OperandKind.Register) - { - int regIndex = src2.GetRegister().Index; - - modRM |= (regIndex & 0b111) << (rrm ? 0 : 3); - - if ((flags & InstructionFlags.Reg8Src) != 0 && regIndex >= 4) - { - rexPrefix |= RexPrefix; - } - } - else if (src2.Kind == OperandKind.Memory && !hasMemOp) - { - memOp = src2.GetMemory(); - hasMemOp = true; - } - else - { - throw new ArgumentException("Invalid source operand kind \"" + src2.Kind + "\"."); - } - } - - bool needsSibByte = false; - bool needsDisplacement = false; - - int sib = 0; - - if (hasMemOp) - { - // Either source or destination is a memory operand. - Register baseReg = memOp.BaseAddress.GetRegister(); - - X86Register baseRegLow = (X86Register)(baseReg.Index & 0b111); - - needsSibByte = memOp.Index != default || baseRegLow == X86Register.Rsp; - needsDisplacement = memOp.Displacement != 0 || baseRegLow == X86Register.Rbp; - - if (needsDisplacement) - { - if (ConstFitsOnS8(memOp.Displacement)) - { - modRM |= 0x40; - } - else /* if (ConstFitsOnS32(memOp.Displacement)) */ - { - modRM |= 0x80; - } - } - - if (baseReg.Index >= 8) - { - Debug.Assert((uint)baseReg.Index <= MaxRegNumber); - - rexPrefix |= RexPrefix | (baseReg.Index >> 3); - } - - if (needsSibByte) - { - sib = (int)baseRegLow; - - if (memOp.Index != default) - { - int indexReg = memOp.Index.GetRegister().Index; - - Debug.Assert(indexReg != (int)X86Register.Rsp, "Using RSP as index register on the memory operand is not allowed."); - - if (indexReg >= 8) - { - Debug.Assert((uint)indexReg <= MaxRegNumber); - - rexPrefix |= RexPrefix | (indexReg >> 3) << 1; - } - - sib |= (indexReg & 0b111) << 3; - } - else - { - sib |= 0b100 << 3; - } - - sib |= (int)memOp.Scale << 6; - - modRM |= 0b100; - } - else - { - modRM |= (int)baseRegLow; - } - } - else - { - // Source and destination are registers. - modRM |= 0xc0; - } - - Debug.Assert(opCode != BadOp, "Invalid opcode value."); - - if ((flags & InstructionFlags.Vex) != 0 && HardwareCapabilities.SupportsVexEncoding) - { - // In a vex encoding, only one prefix can be active at a time. The active prefix is encoded in the second byte using two bits. - - int vexByte2 = (flags & InstructionFlags.PrefixMask) switch - { - InstructionFlags.Prefix66 => 1, - InstructionFlags.PrefixF3 => 2, - InstructionFlags.PrefixF2 => 3, - _ => 0 - }; - - if (src1 != default) - { - vexByte2 |= (src1.GetRegister().Index ^ 0xf) << 3; - } - else - { - vexByte2 |= 0b1111 << 3; - } - - ushort opCodeHigh = (ushort)(opCode >> 8); - - if ((rexPrefix & 0b1011) == 0 && opCodeHigh == 0xf) - { - // Two-byte form. - WriteByte(0xc5); - - vexByte2 |= (~rexPrefix & 4) << 5; - - WriteByte((byte)vexByte2); - } - else - { - // Three-byte form. - WriteByte(0xc4); - - int vexByte1 = (~rexPrefix & 7) << 5; - - switch (opCodeHigh) - { - case 0xf: vexByte1 |= 1; break; - case 0xf38: vexByte1 |= 2; break; - case 0xf3a: vexByte1 |= 3; break; - - default: Debug.Assert(false, $"Failed to VEX encode opcode 0x{opCode:X}."); break; - } - - vexByte2 |= (rexPrefix & 8) << 4; - - WriteByte((byte)vexByte1); - WriteByte((byte)vexByte2); - } - - opCode &= 0xff; - } - else - { - if (flags.HasFlag(InstructionFlags.Prefix66)) - { - WriteByte(0x66); - } - - if (flags.HasFlag(InstructionFlags.PrefixF2)) - { - WriteByte(0xf2); - } - - if (flags.HasFlag(InstructionFlags.PrefixF3)) - { - WriteByte(0xf3); - } - - if (rexPrefix != 0) - { - WriteByte((byte)rexPrefix); - } - } - - if (dest != default && (flags & InstructionFlags.RegOnly) != 0) - { - opCode += dest.GetRegister().Index & 7; - } - - if ((opCode & 0xff0000) != 0) - { - WriteByte((byte)(opCode >> 16)); - } - - if ((opCode & 0xff00) != 0) - { - WriteByte((byte)(opCode >> 8)); - } - - WriteByte((byte)opCode); - - if ((flags & InstructionFlags.RegOnly) == 0) - { - WriteByte((byte)modRM); - - if (needsSibByte) - { - WriteByte((byte)sib); - } - - if (needsDisplacement) - { - if (ConstFitsOnS8(memOp.Displacement)) - { - WriteByte((byte)memOp.Displacement); - } - else /* if (ConstFitsOnS32(memOp.Displacement)) */ - { - WriteInt32(memOp.Displacement); - } - } - } - } - - private void WriteCompactInst(Operand operand, int opCode) - { - int regIndex = operand.GetRegister().Index; - - if (regIndex >= 8) - { - WriteByte(0x41); - } - - WriteByte((byte)(opCode + (regIndex & 0b111))); - } - - private static int GetRexPrefix(Operand dest, Operand source, OperandType type, bool rrm) - { - int rexPrefix = 0; - - if (Is64Bits(type)) - { - rexPrefix = RexWPrefix; - } - - void SetRegisterHighBit(Register reg, int bit) - { - if (reg.Index >= 8) - { - rexPrefix |= RexPrefix | (reg.Index >> 3) << bit; - } - } - - if (dest != default && dest.Kind == OperandKind.Register) - { - SetRegisterHighBit(dest.GetRegister(), rrm ? 2 : 0); - } - - if (source != default && source.Kind == OperandKind.Register) - { - SetRegisterHighBit(source.GetRegister(), rrm ? 0 : 2); - } - - return rexPrefix; - } - - public (byte[], RelocInfo) GetCode() - { - var jumps = CollectionsMarshal.AsSpan(_jumps); - var relocs = CollectionsMarshal.AsSpan(_relocs); - - // Write jump relative offsets. - bool modified; - - do - { - modified = false; - - for (int i = 0; i < jumps.Length; i++) - { - ref Jump jump = ref jumps[i]; - - // If jump target not resolved yet, resolve it. - if (jump.JumpTarget == null) - { - jump.JumpTarget = _labels[jump.JumpLabel]; - } - - long jumpTarget = jump.JumpTarget.Value; - long offset = jumpTarget - jump.JumpPosition; - - if (offset < 0) - { - for (int j = i - 1; j >= 0; j--) - { - ref Jump jump2 = ref jumps[j]; - - if (jump2.JumpPosition < jumpTarget) - { - break; - } - - offset -= jump2.InstSize - ReservedBytesForJump; - } - } - else - { - for (int j = i + 1; j < jumps.Length; j++) - { - ref Jump jump2 = ref jumps[j]; - - if (jump2.JumpPosition >= jumpTarget) - { - break; - } - - offset += jump2.InstSize - ReservedBytesForJump; - } - - offset -= ReservedBytesForJump; - } - - if (jump.IsConditional) - { - jump.InstSize = GetJccLength(offset); - } - else - { - jump.InstSize = GetJmpLength(offset); - } - - // The jump is relative to the next instruction, not the current one. - // Since we didn't know the next instruction address when calculating - // the offset (as the size of the current jump instruction was not known), - // we now need to compensate the offset with the jump instruction size. - // It's also worth noting that: - // - This is only needed for backward jumps. - // - The GetJmpLength and GetJccLength also compensates the offset - // internally when computing the jump instruction size. - if (offset < 0) - { - offset -= jump.InstSize; - } - - if (jump.Offset != offset) - { - jump.Offset = offset; - - modified = true; - } - } - } - while (modified); - - // Write the code, ignoring the dummy bytes after jumps, into a new stream. - _stream.Seek(0, SeekOrigin.Begin); - - using var codeStream = new MemoryStream(); - var assembler = new Assembler(codeStream, HasRelocs); - - bool hasRelocs = HasRelocs; - int relocIndex = 0; - int relocOffset = 0; - var relocEntries = hasRelocs - ? new RelocEntry[relocs.Length] - : Array.Empty(); - - for (int i = 0; i < jumps.Length; i++) - { - ref Jump jump = ref jumps[i]; - - // If has relocations, calculate their new positions compensating for jumps. - if (hasRelocs) - { - relocOffset += jump.InstSize - ReservedBytesForJump; - - for (; relocIndex < relocEntries.Length; relocIndex++) - { - ref Reloc reloc = ref relocs[relocIndex]; - - if (reloc.JumpIndex > i) - { - break; - } - - relocEntries[relocIndex] = new RelocEntry(reloc.Position + relocOffset, reloc.Symbol); - } - } - - Span buffer = new byte[jump.JumpPosition - _stream.Position]; - - _stream.Read(buffer); - _stream.Seek(ReservedBytesForJump, SeekOrigin.Current); - - codeStream.Write(buffer); - - if (jump.IsConditional) - { - assembler.Jcc(jump.Condition, jump.Offset); - } - else - { - assembler.Jmp(jump.Offset); - } - } - - // Write remaining relocations. This case happens when there are no jumps assembled. - for (; relocIndex < relocEntries.Length; relocIndex++) - { - ref Reloc reloc = ref relocs[relocIndex]; - - relocEntries[relocIndex] = new RelocEntry(reloc.Position + relocOffset, reloc.Symbol); - } - - _stream.CopyTo(codeStream); - - var code = codeStream.ToArray(); - var relocInfo = new RelocInfo(relocEntries); - - return (code, relocInfo); - } - - private static bool Is64Bits(OperandType type) - { - return type == OperandType.I64 || type == OperandType.FP64; - } - - private static bool IsImm8(ulong immediate, OperandType type) - { - long value = type == OperandType.I32 ? (int)immediate : (long)immediate; - - return ConstFitsOnS8(value); - } - - private static bool IsImm32(ulong immediate, OperandType type) - { - long value = type == OperandType.I32 ? (int)immediate : (long)immediate; - - return ConstFitsOnS32(value); - } - - private static int GetJccLength(long offset) - { - if (ConstFitsOnS8(offset < 0 ? offset - 2 : offset)) - { - return 2; - } - else if (ConstFitsOnS32(offset < 0 ? offset - 6 : offset)) - { - return 6; - } - else - { - throw new ArgumentOutOfRangeException(nameof(offset)); - } - } - - private static int GetJmpLength(long offset) - { - if (ConstFitsOnS8(offset < 0 ? offset - 2 : offset)) - { - return 2; - } - else if (ConstFitsOnS32(offset < 0 ? offset - 5 : offset)) - { - return 5; - } - else - { - throw new ArgumentOutOfRangeException(nameof(offset)); - } - } - - private static bool ConstFitsOnS8(long value) - { - return value == (sbyte)value; - } - - private static bool ConstFitsOnS32(long value) - { - return value == (int)value; - } - - private void WriteInt16(short value) - { - WriteUInt16((ushort)value); - } - - private void WriteInt32(int value) - { - WriteUInt32((uint)value); - } - - private void WriteByte(byte value) - { - _stream.WriteByte(value); - } - - private void WriteUInt16(ushort value) - { - _stream.WriteByte((byte)(value >> 0)); - _stream.WriteByte((byte)(value >> 8)); - } - - private void WriteUInt32(uint value) - { - _stream.WriteByte((byte)(value >> 0)); - _stream.WriteByte((byte)(value >> 8)); - _stream.WriteByte((byte)(value >> 16)); - _stream.WriteByte((byte)(value >> 24)); - } - - private void WriteUInt64(ulong value) - { - _stream.WriteByte((byte)(value >> 0)); - _stream.WriteByte((byte)(value >> 8)); - _stream.WriteByte((byte)(value >> 16)); - _stream.WriteByte((byte)(value >> 24)); - _stream.WriteByte((byte)(value >> 32)); - _stream.WriteByte((byte)(value >> 40)); - _stream.WriteByte((byte)(value >> 48)); - _stream.WriteByte((byte)(value >> 56)); - } - } -} \ No newline at end of file diff --git a/ARMeilleure/CodeGen/X86/AssemblerTable.cs b/ARMeilleure/CodeGen/X86/AssemblerTable.cs deleted file mode 100644 index e40ffad48..000000000 --- a/ARMeilleure/CodeGen/X86/AssemblerTable.cs +++ /dev/null @@ -1,290 +0,0 @@ -using System; - -namespace ARMeilleure.CodeGen.X86 -{ - partial class Assembler - { - public static bool SupportsVexPrefix(X86Instruction inst) - { - return _instTable[(int)inst].Flags.HasFlag(InstructionFlags.Vex); - } - - private const int BadOp = 0; - - [Flags] - private enum InstructionFlags - { - None = 0, - RegOnly = 1 << 0, - Reg8Src = 1 << 1, - Reg8Dest = 1 << 2, - RexW = 1 << 3, - Vex = 1 << 4, - - PrefixBit = 16, - PrefixMask = 7 << PrefixBit, - Prefix66 = 1 << PrefixBit, - PrefixF3 = 2 << PrefixBit, - PrefixF2 = 4 << PrefixBit - } - - private readonly struct InstructionInfo - { - public int OpRMR { get; } - public int OpRMImm8 { get; } - public int OpRMImm32 { get; } - public int OpRImm64 { get; } - public int OpRRM { get; } - - public InstructionFlags Flags { get; } - - public InstructionInfo( - int opRMR, - int opRMImm8, - int opRMImm32, - int opRImm64, - int opRRM, - InstructionFlags flags) - { - OpRMR = opRMR; - OpRMImm8 = opRMImm8; - OpRMImm32 = opRMImm32; - OpRImm64 = opRImm64; - OpRRM = opRRM; - Flags = flags; - } - } - - private readonly static InstructionInfo[] _instTable; - - static Assembler() - { - _instTable = new InstructionInfo[(int)X86Instruction.Count]; - - // Name RM/R RM/I8 RM/I32 R/I64 R/RM Flags - Add(X86Instruction.Add, new InstructionInfo(0x00000001, 0x00000083, 0x00000081, BadOp, 0x00000003, InstructionFlags.None)); - Add(X86Instruction.Addpd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f58, InstructionFlags.Vex | InstructionFlags.Prefix66)); - Add(X86Instruction.Addps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f58, InstructionFlags.Vex)); - Add(X86Instruction.Addsd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f58, InstructionFlags.Vex | InstructionFlags.PrefixF2)); - Add(X86Instruction.Addss, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f58, InstructionFlags.Vex | InstructionFlags.PrefixF3)); - Add(X86Instruction.Aesdec, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f38de, InstructionFlags.Vex | InstructionFlags.Prefix66)); - Add(X86Instruction.Aesdeclast, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f38df, InstructionFlags.Vex | InstructionFlags.Prefix66)); - Add(X86Instruction.Aesenc, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f38dc, InstructionFlags.Vex | InstructionFlags.Prefix66)); - Add(X86Instruction.Aesenclast, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f38dd, InstructionFlags.Vex | InstructionFlags.Prefix66)); - Add(X86Instruction.Aesimc, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f38db, InstructionFlags.Vex | InstructionFlags.Prefix66)); - Add(X86Instruction.And, new InstructionInfo(0x00000021, 0x04000083, 0x04000081, BadOp, 0x00000023, InstructionFlags.None)); - Add(X86Instruction.Andnpd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f55, InstructionFlags.Vex | InstructionFlags.Prefix66)); - Add(X86Instruction.Andnps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f55, InstructionFlags.Vex)); - Add(X86Instruction.Andpd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f54, InstructionFlags.Vex | InstructionFlags.Prefix66)); - Add(X86Instruction.Andps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f54, InstructionFlags.Vex)); - Add(X86Instruction.Blendvpd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3815, InstructionFlags.Prefix66)); - Add(X86Instruction.Blendvps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3814, InstructionFlags.Prefix66)); - Add(X86Instruction.Bsr, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fbd, InstructionFlags.None)); - Add(X86Instruction.Bswap, new InstructionInfo(0x00000fc8, BadOp, BadOp, BadOp, BadOp, InstructionFlags.RegOnly)); - Add(X86Instruction.Call, new InstructionInfo(0x020000ff, BadOp, BadOp, BadOp, BadOp, InstructionFlags.None)); - Add(X86Instruction.Cmovcc, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f40, InstructionFlags.None)); - Add(X86Instruction.Cmp, new InstructionInfo(0x00000039, 0x07000083, 0x07000081, BadOp, 0x0000003b, InstructionFlags.None)); - Add(X86Instruction.Cmppd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fc2, InstructionFlags.Vex | InstructionFlags.Prefix66)); - Add(X86Instruction.Cmpps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fc2, InstructionFlags.Vex)); - Add(X86Instruction.Cmpsd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fc2, InstructionFlags.Vex | InstructionFlags.PrefixF2)); - Add(X86Instruction.Cmpss, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fc2, InstructionFlags.Vex | InstructionFlags.PrefixF3)); - Add(X86Instruction.Cmpxchg, new InstructionInfo(0x00000fb1, BadOp, BadOp, BadOp, BadOp, InstructionFlags.None)); - Add(X86Instruction.Cmpxchg16b, new InstructionInfo(0x01000fc7, BadOp, BadOp, BadOp, BadOp, InstructionFlags.RexW)); - Add(X86Instruction.Cmpxchg8, new InstructionInfo(0x00000fb0, BadOp, BadOp, BadOp, BadOp, InstructionFlags.Reg8Src)); - Add(X86Instruction.Comisd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f2f, InstructionFlags.Vex | InstructionFlags.Prefix66)); - Add(X86Instruction.Comiss, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f2f, InstructionFlags.Vex)); - Add(X86Instruction.Crc32, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f38f1, InstructionFlags.PrefixF2)); - Add(X86Instruction.Crc32_16, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f38f1, InstructionFlags.PrefixF2 | InstructionFlags.Prefix66)); - Add(X86Instruction.Crc32_8, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f38f0, InstructionFlags.PrefixF2 | InstructionFlags.Reg8Src)); - Add(X86Instruction.Cvtdq2pd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fe6, InstructionFlags.Vex | InstructionFlags.PrefixF3)); - Add(X86Instruction.Cvtdq2ps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f5b, InstructionFlags.Vex)); - Add(X86Instruction.Cvtpd2dq, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fe6, InstructionFlags.Vex | InstructionFlags.PrefixF2)); - Add(X86Instruction.Cvtpd2ps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f5a, InstructionFlags.Vex | InstructionFlags.Prefix66)); - Add(X86Instruction.Cvtps2dq, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f5b, InstructionFlags.Vex | InstructionFlags.Prefix66)); - Add(X86Instruction.Cvtps2pd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f5a, InstructionFlags.Vex)); - Add(X86Instruction.Cvtsd2si, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f2d, InstructionFlags.Vex | InstructionFlags.PrefixF2)); - Add(X86Instruction.Cvtsd2ss, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f5a, InstructionFlags.Vex | InstructionFlags.PrefixF2)); - Add(X86Instruction.Cvtsi2sd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f2a, InstructionFlags.Vex | InstructionFlags.PrefixF2)); - Add(X86Instruction.Cvtsi2ss, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f2a, InstructionFlags.Vex | InstructionFlags.PrefixF3)); - Add(X86Instruction.Cvtss2sd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f5a, InstructionFlags.Vex | InstructionFlags.PrefixF3)); - Add(X86Instruction.Cvtss2si, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f2d, InstructionFlags.Vex | InstructionFlags.PrefixF3)); - Add(X86Instruction.Div, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x060000f7, InstructionFlags.None)); - Add(X86Instruction.Divpd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f5e, InstructionFlags.Vex | InstructionFlags.Prefix66)); - Add(X86Instruction.Divps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f5e, InstructionFlags.Vex)); - Add(X86Instruction.Divsd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f5e, InstructionFlags.Vex | InstructionFlags.PrefixF2)); - Add(X86Instruction.Divss, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f5e, InstructionFlags.Vex | InstructionFlags.PrefixF3)); - Add(X86Instruction.Haddpd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f7c, InstructionFlags.Vex | InstructionFlags.Prefix66)); - Add(X86Instruction.Haddps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f7c, InstructionFlags.Vex | InstructionFlags.PrefixF2)); - Add(X86Instruction.Idiv, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x070000f7, InstructionFlags.None)); - Add(X86Instruction.Imul, new InstructionInfo(BadOp, 0x0000006b, 0x00000069, BadOp, 0x00000faf, InstructionFlags.None)); - Add(X86Instruction.Imul128, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x050000f7, InstructionFlags.None)); - Add(X86Instruction.Insertps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3a21, InstructionFlags.Vex | InstructionFlags.Prefix66)); - Add(X86Instruction.Jmp, new InstructionInfo(0x040000ff, BadOp, BadOp, BadOp, BadOp, InstructionFlags.None)); - Add(X86Instruction.Ldmxcsr, new InstructionInfo(0x02000fae, BadOp, BadOp, BadOp, BadOp, InstructionFlags.Vex)); - Add(X86Instruction.Lea, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x0000008d, InstructionFlags.None)); - Add(X86Instruction.Maxpd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f5f, InstructionFlags.Vex | InstructionFlags.Prefix66)); - Add(X86Instruction.Maxps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f5f, InstructionFlags.Vex)); - Add(X86Instruction.Maxsd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f5f, InstructionFlags.Vex | InstructionFlags.PrefixF2)); - Add(X86Instruction.Maxss, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f5f, InstructionFlags.Vex | InstructionFlags.PrefixF3)); - Add(X86Instruction.Minpd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f5d, InstructionFlags.Vex | InstructionFlags.Prefix66)); - Add(X86Instruction.Minps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f5d, InstructionFlags.Vex)); - Add(X86Instruction.Minsd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f5d, InstructionFlags.Vex | InstructionFlags.PrefixF2)); - Add(X86Instruction.Minss, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f5d, InstructionFlags.Vex | InstructionFlags.PrefixF3)); - Add(X86Instruction.Mov, new InstructionInfo(0x00000089, BadOp, 0x000000c7, 0x000000b8, 0x0000008b, InstructionFlags.None)); - Add(X86Instruction.Mov16, new InstructionInfo(0x00000089, BadOp, 0x000000c7, BadOp, 0x0000008b, InstructionFlags.Prefix66)); - Add(X86Instruction.Mov8, new InstructionInfo(0x00000088, 0x000000c6, BadOp, BadOp, 0x0000008a, InstructionFlags.Reg8Src | InstructionFlags.Reg8Dest)); - Add(X86Instruction.Movd, new InstructionInfo(0x00000f7e, BadOp, BadOp, BadOp, 0x00000f6e, InstructionFlags.Vex | InstructionFlags.Prefix66)); - Add(X86Instruction.Movdqu, new InstructionInfo(0x00000f7f, BadOp, BadOp, BadOp, 0x00000f6f, InstructionFlags.Vex | InstructionFlags.PrefixF3)); - Add(X86Instruction.Movhlps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f12, InstructionFlags.Vex)); - Add(X86Instruction.Movlhps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f16, InstructionFlags.Vex)); - Add(X86Instruction.Movq, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f7e, InstructionFlags.Vex | InstructionFlags.PrefixF3)); - Add(X86Instruction.Movsd, new InstructionInfo(0x00000f11, BadOp, BadOp, BadOp, 0x00000f10, InstructionFlags.Vex | InstructionFlags.PrefixF2)); - Add(X86Instruction.Movss, new InstructionInfo(0x00000f11, BadOp, BadOp, BadOp, 0x00000f10, InstructionFlags.Vex | InstructionFlags.PrefixF3)); - Add(X86Instruction.Movsx16, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fbf, InstructionFlags.None)); - Add(X86Instruction.Movsx32, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000063, InstructionFlags.None)); - Add(X86Instruction.Movsx8, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fbe, InstructionFlags.Reg8Src)); - Add(X86Instruction.Movzx16, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fb7, InstructionFlags.None)); - Add(X86Instruction.Movzx8, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fb6, InstructionFlags.Reg8Src)); - Add(X86Instruction.Mul128, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x040000f7, InstructionFlags.None)); - Add(X86Instruction.Mulpd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f59, InstructionFlags.Vex | InstructionFlags.Prefix66)); - Add(X86Instruction.Mulps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f59, InstructionFlags.Vex)); - Add(X86Instruction.Mulsd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f59, InstructionFlags.Vex | InstructionFlags.PrefixF2)); - Add(X86Instruction.Mulss, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f59, InstructionFlags.Vex | InstructionFlags.PrefixF3)); - Add(X86Instruction.Neg, new InstructionInfo(0x030000f7, BadOp, BadOp, BadOp, BadOp, InstructionFlags.None)); - Add(X86Instruction.Not, new InstructionInfo(0x020000f7, BadOp, BadOp, BadOp, BadOp, InstructionFlags.None)); - Add(X86Instruction.Or, new InstructionInfo(0x00000009, 0x01000083, 0x01000081, BadOp, 0x0000000b, InstructionFlags.None)); - Add(X86Instruction.Paddb, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000ffc, InstructionFlags.Vex | InstructionFlags.Prefix66)); - Add(X86Instruction.Paddd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000ffe, InstructionFlags.Vex | InstructionFlags.Prefix66)); - Add(X86Instruction.Paddq, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fd4, InstructionFlags.Vex | InstructionFlags.Prefix66)); - Add(X86Instruction.Paddw, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000ffd, InstructionFlags.Vex | InstructionFlags.Prefix66)); - Add(X86Instruction.Palignr, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3a0f, InstructionFlags.Vex | InstructionFlags.Prefix66)); - Add(X86Instruction.Pand, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fdb, InstructionFlags.Vex | InstructionFlags.Prefix66)); - Add(X86Instruction.Pandn, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fdf, InstructionFlags.Vex | InstructionFlags.Prefix66)); - Add(X86Instruction.Pavgb, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fe0, InstructionFlags.Vex | InstructionFlags.Prefix66)); - Add(X86Instruction.Pavgw, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fe3, InstructionFlags.Vex | InstructionFlags.Prefix66)); - Add(X86Instruction.Pblendvb, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3810, InstructionFlags.Prefix66)); - Add(X86Instruction.Pclmulqdq, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3a44, InstructionFlags.Vex | InstructionFlags.Prefix66)); - Add(X86Instruction.Pcmpeqb, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f74, InstructionFlags.Vex | InstructionFlags.Prefix66)); - Add(X86Instruction.Pcmpeqd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f76, InstructionFlags.Vex | InstructionFlags.Prefix66)); - Add(X86Instruction.Pcmpeqq, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3829, InstructionFlags.Vex | InstructionFlags.Prefix66)); - Add(X86Instruction.Pcmpeqw, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f75, InstructionFlags.Vex | InstructionFlags.Prefix66)); - Add(X86Instruction.Pcmpgtb, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f64, InstructionFlags.Vex | InstructionFlags.Prefix66)); - Add(X86Instruction.Pcmpgtd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f66, InstructionFlags.Vex | InstructionFlags.Prefix66)); - Add(X86Instruction.Pcmpgtq, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3837, InstructionFlags.Vex | InstructionFlags.Prefix66)); - Add(X86Instruction.Pcmpgtw, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f65, InstructionFlags.Vex | InstructionFlags.Prefix66)); - Add(X86Instruction.Pextrb, new InstructionInfo(0x000f3a14, BadOp, BadOp, BadOp, BadOp, InstructionFlags.Vex | InstructionFlags.Prefix66)); - Add(X86Instruction.Pextrd, new InstructionInfo(0x000f3a16, BadOp, BadOp, BadOp, BadOp, InstructionFlags.Vex | InstructionFlags.Prefix66)); - Add(X86Instruction.Pextrq, new InstructionInfo(0x000f3a16, BadOp, BadOp, BadOp, BadOp, InstructionFlags.Vex | InstructionFlags.RexW | InstructionFlags.Prefix66)); - Add(X86Instruction.Pextrw, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fc5, InstructionFlags.Vex | InstructionFlags.Prefix66)); - Add(X86Instruction.Pinsrb, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3a20, InstructionFlags.Vex | InstructionFlags.Prefix66)); - Add(X86Instruction.Pinsrd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3a22, InstructionFlags.Vex | InstructionFlags.Prefix66)); - Add(X86Instruction.Pinsrq, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3a22, InstructionFlags.Vex | InstructionFlags.RexW | InstructionFlags.Prefix66)); - Add(X86Instruction.Pinsrw, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fc4, InstructionFlags.Vex | InstructionFlags.Prefix66)); - Add(X86Instruction.Pmaxsb, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f383c, InstructionFlags.Vex | InstructionFlags.Prefix66)); - Add(X86Instruction.Pmaxsd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f383d, InstructionFlags.Vex | InstructionFlags.Prefix66)); - Add(X86Instruction.Pmaxsw, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fee, InstructionFlags.Vex | InstructionFlags.Prefix66)); - Add(X86Instruction.Pmaxub, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fde, InstructionFlags.Vex | InstructionFlags.Prefix66)); - Add(X86Instruction.Pmaxud, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f383f, InstructionFlags.Vex | InstructionFlags.Prefix66)); - Add(X86Instruction.Pmaxuw, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f383e, InstructionFlags.Vex | InstructionFlags.Prefix66)); - Add(X86Instruction.Pminsb, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3838, InstructionFlags.Vex | InstructionFlags.Prefix66)); - Add(X86Instruction.Pminsd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3839, InstructionFlags.Vex | InstructionFlags.Prefix66)); - Add(X86Instruction.Pminsw, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fea, InstructionFlags.Vex | InstructionFlags.Prefix66)); - Add(X86Instruction.Pminub, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fda, InstructionFlags.Vex | InstructionFlags.Prefix66)); - Add(X86Instruction.Pminud, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f383b, InstructionFlags.Vex | InstructionFlags.Prefix66)); - Add(X86Instruction.Pminuw, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f383a, InstructionFlags.Vex | InstructionFlags.Prefix66)); - Add(X86Instruction.Pmovsxbw, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3820, InstructionFlags.Vex | InstructionFlags.Prefix66)); - Add(X86Instruction.Pmovsxdq, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3825, InstructionFlags.Vex | InstructionFlags.Prefix66)); - Add(X86Instruction.Pmovsxwd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3823, InstructionFlags.Vex | InstructionFlags.Prefix66)); - Add(X86Instruction.Pmovzxbw, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3830, InstructionFlags.Vex | InstructionFlags.Prefix66)); - Add(X86Instruction.Pmovzxdq, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3835, InstructionFlags.Vex | InstructionFlags.Prefix66)); - Add(X86Instruction.Pmovzxwd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3833, InstructionFlags.Vex | InstructionFlags.Prefix66)); - Add(X86Instruction.Pmulld, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3840, InstructionFlags.Vex | InstructionFlags.Prefix66)); - Add(X86Instruction.Pmullw, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fd5, InstructionFlags.Vex | InstructionFlags.Prefix66)); - Add(X86Instruction.Pop, new InstructionInfo(0x0000008f, BadOp, BadOp, BadOp, BadOp, InstructionFlags.None)); - Add(X86Instruction.Popcnt, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fb8, InstructionFlags.PrefixF3)); - Add(X86Instruction.Por, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000feb, InstructionFlags.Vex | InstructionFlags.Prefix66)); - Add(X86Instruction.Pshufb, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3800, InstructionFlags.Vex | InstructionFlags.Prefix66)); - Add(X86Instruction.Pshufd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f70, InstructionFlags.Vex | InstructionFlags.Prefix66)); - Add(X86Instruction.Pslld, new InstructionInfo(BadOp, 0x06000f72, BadOp, BadOp, 0x00000ff2, InstructionFlags.Vex | InstructionFlags.Prefix66)); - Add(X86Instruction.Pslldq, new InstructionInfo(BadOp, 0x07000f73, BadOp, BadOp, BadOp, InstructionFlags.Vex | InstructionFlags.Prefix66)); - Add(X86Instruction.Psllq, new InstructionInfo(BadOp, 0x06000f73, BadOp, BadOp, 0x00000ff3, InstructionFlags.Vex | InstructionFlags.Prefix66)); - Add(X86Instruction.Psllw, new InstructionInfo(BadOp, 0x06000f71, BadOp, BadOp, 0x00000ff1, InstructionFlags.Vex | InstructionFlags.Prefix66)); - Add(X86Instruction.Psrad, new InstructionInfo(BadOp, 0x04000f72, BadOp, BadOp, 0x00000fe2, InstructionFlags.Vex | InstructionFlags.Prefix66)); - Add(X86Instruction.Psraw, new InstructionInfo(BadOp, 0x04000f71, BadOp, BadOp, 0x00000fe1, InstructionFlags.Vex | InstructionFlags.Prefix66)); - Add(X86Instruction.Psrld, new InstructionInfo(BadOp, 0x02000f72, BadOp, BadOp, 0x00000fd2, InstructionFlags.Vex | InstructionFlags.Prefix66)); - Add(X86Instruction.Psrlq, new InstructionInfo(BadOp, 0x02000f73, BadOp, BadOp, 0x00000fd3, InstructionFlags.Vex | InstructionFlags.Prefix66)); - Add(X86Instruction.Psrldq, new InstructionInfo(BadOp, 0x03000f73, BadOp, BadOp, BadOp, InstructionFlags.Vex | InstructionFlags.Prefix66)); - Add(X86Instruction.Psrlw, new InstructionInfo(BadOp, 0x02000f71, BadOp, BadOp, 0x00000fd1, InstructionFlags.Vex | InstructionFlags.Prefix66)); - Add(X86Instruction.Psubb, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000ff8, InstructionFlags.Vex | InstructionFlags.Prefix66)); - Add(X86Instruction.Psubd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000ffa, InstructionFlags.Vex | InstructionFlags.Prefix66)); - Add(X86Instruction.Psubq, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000ffb, InstructionFlags.Vex | InstructionFlags.Prefix66)); - Add(X86Instruction.Psubw, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000ff9, InstructionFlags.Vex | InstructionFlags.Prefix66)); - Add(X86Instruction.Punpckhbw, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f68, InstructionFlags.Vex | InstructionFlags.Prefix66)); - Add(X86Instruction.Punpckhdq, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f6a, InstructionFlags.Vex | InstructionFlags.Prefix66)); - Add(X86Instruction.Punpckhqdq, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f6d, InstructionFlags.Vex | InstructionFlags.Prefix66)); - Add(X86Instruction.Punpckhwd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f69, InstructionFlags.Vex | InstructionFlags.Prefix66)); - Add(X86Instruction.Punpcklbw, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f60, InstructionFlags.Vex | InstructionFlags.Prefix66)); - Add(X86Instruction.Punpckldq, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f62, InstructionFlags.Vex | InstructionFlags.Prefix66)); - Add(X86Instruction.Punpcklqdq, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f6c, InstructionFlags.Vex | InstructionFlags.Prefix66)); - Add(X86Instruction.Punpcklwd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f61, InstructionFlags.Vex | InstructionFlags.Prefix66)); - Add(X86Instruction.Push, new InstructionInfo(BadOp, 0x0000006a, 0x00000068, BadOp, 0x060000ff, InstructionFlags.None)); - Add(X86Instruction.Pxor, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fef, InstructionFlags.Vex | InstructionFlags.Prefix66)); - Add(X86Instruction.Rcpps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f53, InstructionFlags.Vex)); - Add(X86Instruction.Rcpss, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f53, InstructionFlags.Vex | InstructionFlags.PrefixF3)); - Add(X86Instruction.Ror, new InstructionInfo(0x010000d3, 0x010000c1, BadOp, BadOp, BadOp, InstructionFlags.None)); - Add(X86Instruction.Roundpd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3a09, InstructionFlags.Vex | InstructionFlags.Prefix66)); - Add(X86Instruction.Roundps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3a08, InstructionFlags.Vex | InstructionFlags.Prefix66)); - Add(X86Instruction.Roundsd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3a0b, InstructionFlags.Vex | InstructionFlags.Prefix66)); - Add(X86Instruction.Roundss, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3a0a, InstructionFlags.Vex | InstructionFlags.Prefix66)); - Add(X86Instruction.Rsqrtps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f52, InstructionFlags.Vex)); - Add(X86Instruction.Rsqrtss, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f52, InstructionFlags.Vex | InstructionFlags.PrefixF3)); - Add(X86Instruction.Sar, new InstructionInfo(0x070000d3, 0x070000c1, BadOp, BadOp, BadOp, InstructionFlags.None)); - Add(X86Instruction.Setcc, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f90, InstructionFlags.Reg8Dest)); - Add(X86Instruction.Sha256Msg1, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f38cc, InstructionFlags.None)); - Add(X86Instruction.Sha256Msg2, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f38cd, InstructionFlags.None)); - Add(X86Instruction.Sha256Rnds2, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f38cb, InstructionFlags.None)); - Add(X86Instruction.Shl, new InstructionInfo(0x040000d3, 0x040000c1, BadOp, BadOp, BadOp, InstructionFlags.None)); - Add(X86Instruction.Shr, new InstructionInfo(0x050000d3, 0x050000c1, BadOp, BadOp, BadOp, InstructionFlags.None)); - Add(X86Instruction.Shufpd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fc6, InstructionFlags.Vex | InstructionFlags.Prefix66)); - Add(X86Instruction.Shufps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fc6, InstructionFlags.Vex)); - Add(X86Instruction.Sqrtpd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f51, InstructionFlags.Vex | InstructionFlags.Prefix66)); - Add(X86Instruction.Sqrtps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f51, InstructionFlags.Vex)); - Add(X86Instruction.Sqrtsd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f51, InstructionFlags.Vex | InstructionFlags.PrefixF2)); - Add(X86Instruction.Sqrtss, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f51, InstructionFlags.Vex | InstructionFlags.PrefixF3)); - Add(X86Instruction.Stmxcsr, new InstructionInfo(0x03000fae, BadOp, BadOp, BadOp, BadOp, InstructionFlags.Vex)); - Add(X86Instruction.Sub, new InstructionInfo(0x00000029, 0x05000083, 0x05000081, BadOp, 0x0000002b, InstructionFlags.None)); - Add(X86Instruction.Subpd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f5c, InstructionFlags.Vex | InstructionFlags.Prefix66)); - Add(X86Instruction.Subps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f5c, InstructionFlags.Vex)); - Add(X86Instruction.Subsd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f5c, InstructionFlags.Vex | InstructionFlags.PrefixF2)); - Add(X86Instruction.Subss, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f5c, InstructionFlags.Vex | InstructionFlags.PrefixF3)); - Add(X86Instruction.Test, new InstructionInfo(0x00000085, BadOp, 0x000000f7, BadOp, BadOp, InstructionFlags.None)); - Add(X86Instruction.Unpckhpd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f15, InstructionFlags.Vex | InstructionFlags.Prefix66)); - Add(X86Instruction.Unpckhps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f15, InstructionFlags.Vex)); - Add(X86Instruction.Unpcklpd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f14, InstructionFlags.Vex | InstructionFlags.Prefix66)); - Add(X86Instruction.Unpcklps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f14, InstructionFlags.Vex)); - Add(X86Instruction.Vblendvpd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3a4b, InstructionFlags.Vex | InstructionFlags.Prefix66)); - Add(X86Instruction.Vblendvps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3a4a, InstructionFlags.Vex | InstructionFlags.Prefix66)); - Add(X86Instruction.Vcvtph2ps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3813, InstructionFlags.Vex | InstructionFlags.Prefix66)); - Add(X86Instruction.Vcvtps2ph, new InstructionInfo(0x000f3a1d, BadOp, BadOp, BadOp, BadOp, InstructionFlags.Vex | InstructionFlags.Prefix66)); - Add(X86Instruction.Vfmadd231ps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f38b8, InstructionFlags.Vex | InstructionFlags.Prefix66)); - Add(X86Instruction.Vfmadd231sd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f38b9, InstructionFlags.Vex | InstructionFlags.Prefix66 | InstructionFlags.RexW)); - Add(X86Instruction.Vfmadd231ss, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f38b9, InstructionFlags.Vex | InstructionFlags.Prefix66)); - Add(X86Instruction.Vfmsub231sd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f38bb, InstructionFlags.Vex | InstructionFlags.Prefix66 | InstructionFlags.RexW)); - Add(X86Instruction.Vfmsub231ss, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f38bb, InstructionFlags.Vex | InstructionFlags.Prefix66)); - Add(X86Instruction.Vfnmadd231ps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f38bc, InstructionFlags.Vex | InstructionFlags.Prefix66)); - Add(X86Instruction.Vfnmadd231sd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f38bd, InstructionFlags.Vex | InstructionFlags.Prefix66 | InstructionFlags.RexW)); - Add(X86Instruction.Vfnmadd231ss, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f38bd, InstructionFlags.Vex | InstructionFlags.Prefix66)); - Add(X86Instruction.Vfnmsub231sd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f38bf, InstructionFlags.Vex | InstructionFlags.Prefix66 | InstructionFlags.RexW)); - Add(X86Instruction.Vfnmsub231ss, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f38bf, InstructionFlags.Vex | InstructionFlags.Prefix66)); - Add(X86Instruction.Vpblendvb, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3a4c, InstructionFlags.Vex | InstructionFlags.Prefix66)); - Add(X86Instruction.Xor, new InstructionInfo(0x00000031, 0x06000083, 0x06000081, BadOp, 0x00000033, InstructionFlags.None)); - Add(X86Instruction.Xorpd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f57, InstructionFlags.Vex | InstructionFlags.Prefix66)); - Add(X86Instruction.Xorps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f57, InstructionFlags.Vex)); - - static void Add(X86Instruction inst, in InstructionInfo info) - { - _instTable[(int)inst] = info; - } - } - } -} diff --git a/ARMeilleure/CodeGen/X86/CallingConvention.cs b/ARMeilleure/CodeGen/X86/CallingConvention.cs deleted file mode 100644 index 953fef5b0..000000000 --- a/ARMeilleure/CodeGen/X86/CallingConvention.cs +++ /dev/null @@ -1,158 +0,0 @@ -using System; - -namespace ARMeilleure.CodeGen.X86 -{ - static class CallingConvention - { - private const int RegistersMask = 0xffff; - - public static int GetIntAvailableRegisters() - { - return RegistersMask & ~(1 << (int)X86Register.Rsp); - } - - public static int GetVecAvailableRegisters() - { - return RegistersMask; - } - - public static int GetIntCallerSavedRegisters() - { - if (GetCurrentCallConv() == CallConvName.Windows) - { - return (1 << (int)X86Register.Rax) | - (1 << (int)X86Register.Rcx) | - (1 << (int)X86Register.Rdx) | - (1 << (int)X86Register.R8) | - (1 << (int)X86Register.R9) | - (1 << (int)X86Register.R10) | - (1 << (int)X86Register.R11); - } - else /* if (GetCurrentCallConv() == CallConvName.SystemV) */ - { - return (1 << (int)X86Register.Rax) | - (1 << (int)X86Register.Rcx) | - (1 << (int)X86Register.Rdx) | - (1 << (int)X86Register.Rsi) | - (1 << (int)X86Register.Rdi) | - (1 << (int)X86Register.R8) | - (1 << (int)X86Register.R9) | - (1 << (int)X86Register.R10) | - (1 << (int)X86Register.R11); - } - } - - public static int GetVecCallerSavedRegisters() - { - if (GetCurrentCallConv() == CallConvName.Windows) - { - return (1 << (int)X86Register.Xmm0) | - (1 << (int)X86Register.Xmm1) | - (1 << (int)X86Register.Xmm2) | - (1 << (int)X86Register.Xmm3) | - (1 << (int)X86Register.Xmm4) | - (1 << (int)X86Register.Xmm5); - } - else /* if (GetCurrentCallConv() == CallConvName.SystemV) */ - { - return RegistersMask; - } - } - - public static int GetIntCalleeSavedRegisters() - { - return GetIntCallerSavedRegisters() ^ RegistersMask; - } - - public static int GetVecCalleeSavedRegisters() - { - return GetVecCallerSavedRegisters() ^ RegistersMask; - } - - public static int GetArgumentsOnRegsCount() - { - return 4; - } - - public static int GetIntArgumentsOnRegsCount() - { - return 6; - } - - public static int GetVecArgumentsOnRegsCount() - { - return 8; - } - - public static X86Register GetIntArgumentRegister(int index) - { - if (GetCurrentCallConv() == CallConvName.Windows) - { - switch (index) - { - case 0: return X86Register.Rcx; - case 1: return X86Register.Rdx; - case 2: return X86Register.R8; - case 3: return X86Register.R9; - } - } - else /* if (GetCurrentCallConv() == CallConvName.SystemV) */ - { - switch (index) - { - case 0: return X86Register.Rdi; - case 1: return X86Register.Rsi; - case 2: return X86Register.Rdx; - case 3: return X86Register.Rcx; - case 4: return X86Register.R8; - case 5: return X86Register.R9; - } - } - - throw new ArgumentOutOfRangeException(nameof(index)); - } - - public static X86Register GetVecArgumentRegister(int index) - { - int count; - - if (GetCurrentCallConv() == CallConvName.Windows) - { - count = 4; - } - else /* if (GetCurrentCallConv() == CallConvName.SystemV) */ - { - count = 8; - } - - if ((uint)index < count) - { - return X86Register.Xmm0 + index; - } - - throw new ArgumentOutOfRangeException(nameof(index)); - } - - public static X86Register GetIntReturnRegister() - { - return X86Register.Rax; - } - - public static X86Register GetIntReturnRegisterHigh() - { - return X86Register.Rdx; - } - - public static X86Register GetVecReturnRegister() - { - return X86Register.Xmm0; - } - - public static CallConvName GetCurrentCallConv() - { - return OperatingSystem.IsWindows() - ? CallConvName.Windows - : CallConvName.SystemV; - } - } -} \ No newline at end of file diff --git a/ARMeilleure/CodeGen/X86/CodeGenContext.cs b/ARMeilleure/CodeGen/X86/CodeGenContext.cs deleted file mode 100644 index eee71bd78..000000000 --- a/ARMeilleure/CodeGen/X86/CodeGenContext.cs +++ /dev/null @@ -1,104 +0,0 @@ -using ARMeilleure.CodeGen.RegisterAllocators; -using ARMeilleure.IntermediateRepresentation; -using System.IO; -using System.Numerics; - -namespace ARMeilleure.CodeGen.X86 -{ - class CodeGenContext - { - private readonly Stream _stream; - private readonly Operand[] _blockLabels; - - public int StreamOffset => (int)_stream.Length; - - public AllocationResult AllocResult { get; } - - public Assembler Assembler { get; } - public BasicBlock CurrBlock { get; private set; } - - public int CallArgsRegionSize { get; } - public int XmmSaveRegionSize { get; } - - public CodeGenContext(AllocationResult allocResult, int maxCallArgs, int blocksCount, bool relocatable) - { - _stream = new MemoryStream(); - _blockLabels = new Operand[blocksCount]; - - AllocResult = allocResult; - Assembler = new Assembler(_stream, relocatable); - - CallArgsRegionSize = GetCallArgsRegionSize(allocResult, maxCallArgs, out int xmmSaveRegionSize); - XmmSaveRegionSize = xmmSaveRegionSize; - } - - private static int GetCallArgsRegionSize(AllocationResult allocResult, int maxCallArgs, out int xmmSaveRegionSize) - { - // We need to add 8 bytes to the total size, as the call to this function already pushed 8 bytes (the - // return address). - int intMask = CallingConvention.GetIntCalleeSavedRegisters() & allocResult.IntUsedRegisters; - int vecMask = CallingConvention.GetVecCalleeSavedRegisters() & allocResult.VecUsedRegisters; - - xmmSaveRegionSize = BitOperations.PopCount((uint)vecMask) * 16; - - int calleeSaveRegionSize = BitOperations.PopCount((uint)intMask) * 8 + xmmSaveRegionSize + 8; - - int argsCount = maxCallArgs; - - if (argsCount < 0) - { - // When the function has no calls, argsCount is -1. In this case, we don't need to allocate the shadow - // space. - argsCount = 0; - } - else if (argsCount < 4) - { - // The ABI mandates that the space for at least 4 arguments is reserved on the stack (this is called - // shadow space). - argsCount = 4; - } - - // TODO: Align XMM save region to 16 bytes because unwinding on Windows requires it. - int frameSize = calleeSaveRegionSize + allocResult.SpillRegionSize; - - // TODO: Instead of always multiplying by 16 (the largest possible size of a variable, since a V128 has 16 - // bytes), we should calculate the exact size consumed by the arguments passed to the called functions on - // the stack. - int callArgsAndFrameSize = frameSize + argsCount * 16; - - // Ensure that the Stack Pointer will be aligned to 16 bytes. - callArgsAndFrameSize = (callArgsAndFrameSize + 0xf) & ~0xf; - - return callArgsAndFrameSize - frameSize; - } - - public void EnterBlock(BasicBlock block) - { - Assembler.MarkLabel(GetLabel(block)); - - CurrBlock = block; - } - - public void JumpTo(BasicBlock target) - { - Assembler.Jmp(GetLabel(target)); - } - - public void JumpTo(X86Condition condition, BasicBlock target) - { - Assembler.Jcc(condition, GetLabel(target)); - } - - private Operand GetLabel(BasicBlock block) - { - ref Operand label = ref _blockLabels[block.Index]; - - if (label == default) - { - label = Operand.Factory.Label(); - } - - return label; - } - } -} \ No newline at end of file diff --git a/ARMeilleure/CodeGen/X86/CodeGenerator.cs b/ARMeilleure/CodeGen/X86/CodeGenerator.cs deleted file mode 100644 index 8d8d3b0a2..000000000 --- a/ARMeilleure/CodeGen/X86/CodeGenerator.cs +++ /dev/null @@ -1,1856 +0,0 @@ -using ARMeilleure.CodeGen.Linking; -using ARMeilleure.CodeGen.Optimizations; -using ARMeilleure.CodeGen.RegisterAllocators; -using ARMeilleure.CodeGen.Unwinding; -using ARMeilleure.Common; -using ARMeilleure.Diagnostics; -using ARMeilleure.IntermediateRepresentation; -using ARMeilleure.Translation; -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Numerics; -using static ARMeilleure.IntermediateRepresentation.Operand.Factory; - -namespace ARMeilleure.CodeGen.X86 -{ - static class CodeGenerator - { - private const int PageSize = 0x1000; - private const int StackGuardSize = 0x2000; - - private static readonly Action[] _instTable; - - static CodeGenerator() - { - _instTable = new Action[EnumUtils.GetCount(typeof(Instruction))]; - - Add(Instruction.Add, GenerateAdd); - Add(Instruction.BitwiseAnd, GenerateBitwiseAnd); - Add(Instruction.BitwiseExclusiveOr, GenerateBitwiseExclusiveOr); - Add(Instruction.BitwiseNot, GenerateBitwiseNot); - Add(Instruction.BitwiseOr, GenerateBitwiseOr); - Add(Instruction.BranchIf, GenerateBranchIf); - Add(Instruction.ByteSwap, GenerateByteSwap); - Add(Instruction.Call, GenerateCall); - Add(Instruction.Clobber, GenerateClobber); - Add(Instruction.Compare, GenerateCompare); - Add(Instruction.CompareAndSwap, GenerateCompareAndSwap); - Add(Instruction.CompareAndSwap16, GenerateCompareAndSwap16); - Add(Instruction.CompareAndSwap8, GenerateCompareAndSwap8); - Add(Instruction.ConditionalSelect, GenerateConditionalSelect); - Add(Instruction.ConvertI64ToI32, GenerateConvertI64ToI32); - Add(Instruction.ConvertToFP, GenerateConvertToFP); - Add(Instruction.Copy, GenerateCopy); - Add(Instruction.CountLeadingZeros, GenerateCountLeadingZeros); - Add(Instruction.Divide, GenerateDivide); - Add(Instruction.DivideUI, GenerateDivideUI); - Add(Instruction.Fill, GenerateFill); - Add(Instruction.Load, GenerateLoad); - Add(Instruction.Load16, GenerateLoad16); - Add(Instruction.Load8, GenerateLoad8); - Add(Instruction.MemoryBarrier, GenerateMemoryBarrier); - Add(Instruction.Multiply, GenerateMultiply); - Add(Instruction.Multiply64HighSI, GenerateMultiply64HighSI); - Add(Instruction.Multiply64HighUI, GenerateMultiply64HighUI); - Add(Instruction.Negate, GenerateNegate); - Add(Instruction.Return, GenerateReturn); - Add(Instruction.RotateRight, GenerateRotateRight); - Add(Instruction.ShiftLeft, GenerateShiftLeft); - Add(Instruction.ShiftRightSI, GenerateShiftRightSI); - Add(Instruction.ShiftRightUI, GenerateShiftRightUI); - Add(Instruction.SignExtend16, GenerateSignExtend16); - Add(Instruction.SignExtend32, GenerateSignExtend32); - Add(Instruction.SignExtend8, GenerateSignExtend8); - Add(Instruction.Spill, GenerateSpill); - Add(Instruction.SpillArg, GenerateSpillArg); - Add(Instruction.StackAlloc, GenerateStackAlloc); - Add(Instruction.Store, GenerateStore); - Add(Instruction.Store16, GenerateStore16); - Add(Instruction.Store8, GenerateStore8); - Add(Instruction.Subtract, GenerateSubtract); - Add(Instruction.Tailcall, GenerateTailcall); - Add(Instruction.VectorCreateScalar, GenerateVectorCreateScalar); - Add(Instruction.VectorExtract, GenerateVectorExtract); - Add(Instruction.VectorExtract16, GenerateVectorExtract16); - Add(Instruction.VectorExtract8, GenerateVectorExtract8); - Add(Instruction.VectorInsert, GenerateVectorInsert); - Add(Instruction.VectorInsert16, GenerateVectorInsert16); - Add(Instruction.VectorInsert8, GenerateVectorInsert8); - Add(Instruction.VectorOne, GenerateVectorOne); - Add(Instruction.VectorZero, GenerateVectorZero); - Add(Instruction.VectorZeroUpper64, GenerateVectorZeroUpper64); - Add(Instruction.VectorZeroUpper96, GenerateVectorZeroUpper96); - Add(Instruction.ZeroExtend16, GenerateZeroExtend16); - Add(Instruction.ZeroExtend32, GenerateZeroExtend32); - Add(Instruction.ZeroExtend8, GenerateZeroExtend8); - - static void Add(Instruction inst, Action func) - { - _instTable[(int)inst] = func; - } - } - - public static CompiledFunction Generate(CompilerContext cctx) - { - ControlFlowGraph cfg = cctx.Cfg; - - Logger.StartPass(PassName.Optimization); - - if (cctx.Options.HasFlag(CompilerOptions.Optimize)) - { - if (cctx.Options.HasFlag(CompilerOptions.SsaForm)) - { - Optimizer.RunPass(cfg); - } - - BlockPlacement.RunPass(cfg); - } - - X86Optimizer.RunPass(cfg); - - Logger.EndPass(PassName.Optimization, cfg); - - Logger.StartPass(PassName.PreAllocation); - - StackAllocator stackAlloc = new(); - - PreAllocator.RunPass(cctx, stackAlloc, out int maxCallArgs); - - Logger.EndPass(PassName.PreAllocation, cfg); - - Logger.StartPass(PassName.RegisterAllocation); - - if (cctx.Options.HasFlag(CompilerOptions.SsaForm)) - { - Ssa.Deconstruct(cfg); - } - - IRegisterAllocator regAlloc; - - if (cctx.Options.HasFlag(CompilerOptions.Lsra)) - { - regAlloc = new LinearScanAllocator(); - } - else - { - regAlloc = new HybridAllocator(); - } - - RegisterMasks regMasks = new( - CallingConvention.GetIntAvailableRegisters(), - CallingConvention.GetVecAvailableRegisters(), - CallingConvention.GetIntCallerSavedRegisters(), - CallingConvention.GetVecCallerSavedRegisters(), - CallingConvention.GetIntCalleeSavedRegisters(), - CallingConvention.GetVecCalleeSavedRegisters()); - - AllocationResult allocResult = regAlloc.RunPass(cfg, stackAlloc, regMasks); - - Logger.EndPass(PassName.RegisterAllocation, cfg); - - Logger.StartPass(PassName.CodeGeneration); - - bool relocatable = (cctx.Options & CompilerOptions.Relocatable) != 0; - - CodeGenContext context = new(allocResult, maxCallArgs, cfg.Blocks.Count, relocatable); - - UnwindInfo unwindInfo = WritePrologue(context); - - for (BasicBlock block = cfg.Blocks.First; block != null; block = block.ListNext) - { - context.EnterBlock(block); - - for (Operation node = block.Operations.First; node != default; node = node.ListNext) - { - GenerateOperation(context, node); - } - - if (block.SuccessorsCount == 0) - { - // The only blocks which can have 0 successors are exit blocks. - Operation last = block.Operations.Last; - - Debug.Assert(last.Instruction == Instruction.Tailcall || - last.Instruction == Instruction.Return); - } - else - { - BasicBlock succ = block.GetSuccessor(0); - - if (succ != block.ListNext) - { - context.JumpTo(succ); - } - } - } - - (byte[] code, RelocInfo relocInfo) = context.Assembler.GetCode(); - - Logger.EndPass(PassName.CodeGeneration); - - return new CompiledFunction(code, unwindInfo, relocInfo); - } - - private static void GenerateOperation(CodeGenContext context, Operation operation) - { - if (operation.Instruction == Instruction.Extended) - { - IntrinsicInfo info = IntrinsicTable.GetInfo(operation.Intrinsic); - - switch (info.Type) - { - case IntrinsicType.Comis_: - { - Operand dest = operation.Destination; - Operand src1 = operation.GetSource(0); - Operand src2 = operation.GetSource(1); - - switch (operation.Intrinsic) - { - case Intrinsic.X86Comisdeq: - context.Assembler.Comisd(src1, src2); - context.Assembler.Setcc(dest, X86Condition.Equal); - break; - - case Intrinsic.X86Comisdge: - context.Assembler.Comisd(src1, src2); - context.Assembler.Setcc(dest, X86Condition.AboveOrEqual); - break; - - case Intrinsic.X86Comisdlt: - context.Assembler.Comisd(src1, src2); - context.Assembler.Setcc(dest, X86Condition.Below); - break; - - case Intrinsic.X86Comisseq: - context.Assembler.Comiss(src1, src2); - context.Assembler.Setcc(dest, X86Condition.Equal); - break; - - case Intrinsic.X86Comissge: - context.Assembler.Comiss(src1, src2); - context.Assembler.Setcc(dest, X86Condition.AboveOrEqual); - break; - - case Intrinsic.X86Comisslt: - context.Assembler.Comiss(src1, src2); - context.Assembler.Setcc(dest, X86Condition.Below); - break; - } - - context.Assembler.Movzx8(dest, dest, OperandType.I32); - - break; - } - - case IntrinsicType.Mxcsr: - { - Operand offset = operation.GetSource(0); - Operand bits = operation.GetSource(1); - - Debug.Assert(offset.Kind == OperandKind.Constant && bits.Kind == OperandKind.Constant); - Debug.Assert(offset.Type == OperandType.I32 && bits.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); - - context.Assembler.Stmxcsr(memOp); - - if (operation.Intrinsic == Intrinsic.X86Mxcsrmb) - { - context.Assembler.Or(memOp, bits, OperandType.I32); - } - else /* if (intrinOp.Intrinsic == Intrinsic.X86Mxcsrub) */ - { - Operand notBits = Const(~bits.AsInt32()); - - context.Assembler.And(memOp, notBits, OperandType.I32); - } - - context.Assembler.Ldmxcsr(memOp); - - break; - } - - case IntrinsicType.PopCount: - { - Operand dest = operation.Destination; - Operand source = operation.GetSource(0); - - EnsureSameType(dest, source); - - Debug.Assert(dest.Type.IsInteger()); - - context.Assembler.Popcnt(dest, source, dest.Type); - - break; - } - - case IntrinsicType.Unary: - { - Operand dest = operation.Destination; - Operand source = operation.GetSource(0); - - EnsureSameType(dest, source); - - Debug.Assert(!dest.Type.IsInteger()); - - context.Assembler.WriteInstruction(info.Inst, dest, source); - - break; - } - - 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) - { - if (dest.Type == OperandType.I32) - { - 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 - { - context.Assembler.WriteInstruction(info.Inst, dest, source, dest.Type); - } - - break; - } - - case IntrinsicType.Binary: - { - Operand dest = operation.Destination; - 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; - } - - case IntrinsicType.BinaryGpr: - { - Operand dest = operation.Destination; - 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; - } - - case IntrinsicType.Crc32: - { - Operand dest = operation.Destination; - Operand src1 = operation.GetSource(0); - Operand src2 = operation.GetSource(1); - - EnsureSameReg(dest, src1); - - Debug.Assert(dest.Type.IsInteger() && src1.Type.IsInteger() && src2.Type.IsInteger()); - - context.Assembler.WriteInstruction(info.Inst, dest, src2, dest.Type); - - break; - } - - case IntrinsicType.BinaryImm: - { - Operand dest = operation.Destination; - 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; - } - - 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) - { - 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; - } - - 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) - { - EnsureSameReg(dest, src1); - } - - Debug.Assert(!dest.Type.IsInteger() && src3.Kind == OperandKind.Constant); - - context.Assembler.WriteInstruction(info.Inst, dest, src1, src2, src3.AsByte()); - - break; - } - - case IntrinsicType.Fma: - { - Operand dest = operation.Destination; - Operand src1 = operation.GetSource(0); - Operand src2 = operation.GetSource(1); - Operand src3 = operation.GetSource(2); - - Debug.Assert(HardwareCapabilities.SupportsVexEncoding); - - Debug.Assert(dest.Kind == OperandKind.Register && src1.Kind == OperandKind.Register && src2.Kind == OperandKind.Register); - Debug.Assert(src3.Kind == OperandKind.Register || src3.Kind == OperandKind.Memory); - - EnsureSameType(dest, src1, src2, src3); - Debug.Assert(dest.Type == OperandType.V128); - - Debug.Assert(dest.Value == src1.Value); - - context.Assembler.WriteInstruction(info.Inst, dest, src2, src3); - - break; - } - } - } - else - { - Action func = _instTable[(int)operation.Instruction]; - - if (func != null) - { - func(context, operation); - } - else - { - throw new ArgumentException($"Invalid instruction \"{operation.Instruction}\"."); - } - } - } - - private static void GenerateAdd(CodeGenContext context, Operation operation) - { - Operand dest = operation.Destination; - Operand src1 = operation.GetSource(0); - Operand src2 = operation.GetSource(1); - - if (dest.Type.IsInteger()) - { - // If Destination and Source 1 Operands are the same, perform a standard add as there are no benefits to using LEA. - if (dest.Kind == src1.Kind && dest.Value == src1.Value) - { - ValidateBinOp(dest, src1, src2); - - context.Assembler.Add(dest, src2, dest.Type); - } - else - { - EnsureSameType(dest, src1, src2); - - int offset; - Operand index; - - if (src2.Kind == OperandKind.Constant) - { - offset = src2.AsInt32(); - index = default; - } - else - { - offset = 0; - index = src2; - } - - Operand memOp = MemoryOp(dest.Type, src1, index, Multiplier.x1, offset); - - context.Assembler.Lea(dest, memOp, dest.Type); - } - } - else - { - ValidateBinOp(dest, src1, src2); - - if (dest.Type == OperandType.FP32) - { - context.Assembler.Addss(dest, src1, src2); - } - else /* if (dest.Type == OperandType.FP64) */ - { - context.Assembler.Addsd(dest, src1, src2); - } - } - } - - private static void GenerateBitwiseAnd(CodeGenContext context, Operation operation) - { - Operand dest = operation.Destination; - Operand src1 = operation.GetSource(0); - Operand src2 = operation.GetSource(1); - - ValidateBinOp(dest, src1, src2); - - Debug.Assert(dest.Type.IsInteger()); - - // Note: GenerateCompareCommon makes the assumption that BitwiseAnd will emit only a single `and` - // instruction. - context.Assembler.And(dest, src2, dest.Type); - } - - private static void GenerateBitwiseExclusiveOr(CodeGenContext context, Operation operation) - { - Operand dest = operation.Destination; - Operand src1 = operation.GetSource(0); - Operand src2 = operation.GetSource(1); - - ValidateBinOp(dest, src1, src2); - - if (dest.Type.IsInteger()) - { - context.Assembler.Xor(dest, src2, dest.Type); - } - else - { - context.Assembler.Xorps(dest, src1, src2); - } - } - - private static void GenerateBitwiseNot(CodeGenContext context, Operation operation) - { - Operand dest = operation.Destination; - Operand source = operation.GetSource(0); - - ValidateUnOp(dest, source); - - Debug.Assert(dest.Type.IsInteger()); - - context.Assembler.Not(dest); - } - - private static void GenerateBitwiseOr(CodeGenContext context, Operation operation) - { - Operand dest = operation.Destination; - Operand src1 = operation.GetSource(0); - Operand src2 = operation.GetSource(1); - - ValidateBinOp(dest, src1, src2); - - Debug.Assert(dest.Type.IsInteger()); - - context.Assembler.Or(dest, src2, dest.Type); - } - - private static void GenerateBranchIf(CodeGenContext context, Operation operation) - { - Operand comp = operation.GetSource(2); - - Debug.Assert(comp.Kind == OperandKind.Constant); - - var cond = ((Comparison)comp.AsInt32()).ToX86Condition(); - - GenerateCompareCommon(context, operation); - - context.JumpTo(cond, context.CurrBlock.GetSuccessor(1)); - } - - private static void GenerateByteSwap(CodeGenContext context, Operation operation) - { - Operand dest = operation.Destination; - Operand source = operation.GetSource(0); - - ValidateUnOp(dest, source); - - Debug.Assert(dest.Type.IsInteger()); - - context.Assembler.Bswap(dest); - } - - private static void GenerateCall(CodeGenContext context, Operation operation) - { - context.Assembler.Call(operation.GetSource(0)); - } - - private static void GenerateClobber(CodeGenContext context, Operation operation) - { - // This is only used to indicate that a register is clobbered to the - // register allocator, we don't need to produce any code. - } - - private static void GenerateCompare(CodeGenContext context, Operation operation) - { - Operand dest = operation.Destination; - Operand comp = operation.GetSource(2); - - Debug.Assert(dest.Type == OperandType.I32); - Debug.Assert(comp.Kind == OperandKind.Constant); - - var cond = ((Comparison)comp.AsInt32()).ToX86Condition(); - - GenerateCompareCommon(context, operation); - - context.Assembler.Setcc(dest, cond); - context.Assembler.Movzx8(dest, dest, OperandType.I32); - } - - private static void GenerateCompareCommon(CodeGenContext context, Operation operation) - { - Operand src1 = operation.GetSource(0); - Operand src2 = operation.GetSource(1); - - EnsureSameType(src1, src2); - - Debug.Assert(src1.Type.IsInteger()); - - if (src2.Kind == OperandKind.Constant && src2.Value == 0) - { - if (MatchOperation(operation.ListPrevious, Instruction.BitwiseAnd, src1.Type, src1.GetRegister())) - { - // Since the `test` and `and` instruction set the status flags in the same way, we can omit the - // `test r,r` instruction when it is immediately preceded by an `and r,*` instruction. - // - // For example: - // - // and eax, 0x3 - // test eax, eax - // jz .L0 - // - // => - // - // and eax, 0x3 - // jz .L0 - } - else - { - context.Assembler.Test(src1, src1, src1.Type); - } - } - else - { - context.Assembler.Cmp(src1, src2, src1.Type); - } - } - - private static void GenerateCompareAndSwap(CodeGenContext context, Operation operation) - { - Operand src1 = operation.GetSource(0); - - if (operation.SourcesCount == 5) // CompareAndSwap128 has 5 sources, compared to CompareAndSwap64/32's 3. - { - Operand memOp = MemoryOp(OperandType.I64, src1); - - context.Assembler.Cmpxchg16b(memOp); - } - else - { - Operand src2 = operation.GetSource(1); - Operand src3 = operation.GetSource(2); - - EnsureSameType(src2, src3); - - Operand memOp = MemoryOp(src3.Type, src1); - - context.Assembler.Cmpxchg(memOp, src3); - } - } - - private static void GenerateCompareAndSwap16(CodeGenContext context, Operation operation) - { - Operand src1 = operation.GetSource(0); - Operand src2 = operation.GetSource(1); - Operand src3 = operation.GetSource(2); - - EnsureSameType(src2, src3); - - Operand memOp = MemoryOp(src3.Type, src1); - - context.Assembler.Cmpxchg16(memOp, src3); - } - - private static void GenerateCompareAndSwap8(CodeGenContext context, Operation operation) - { - Operand src1 = operation.GetSource(0); - Operand src2 = operation.GetSource(1); - Operand src3 = operation.GetSource(2); - - EnsureSameType(src2, src3); - - Operand memOp = MemoryOp(src3.Type, src1); - - context.Assembler.Cmpxchg8(memOp, src3); - } - - private static void GenerateConditionalSelect(CodeGenContext context, Operation operation) - { - Operand dest = operation.Destination; - Operand src1 = operation.GetSource(0); - Operand src2 = operation.GetSource(1); - Operand src3 = operation.GetSource(2); - - EnsureSameReg (dest, src3); - EnsureSameType(dest, src2, src3); - - Debug.Assert(dest.Type.IsInteger()); - Debug.Assert(src1.Type == OperandType.I32); - - context.Assembler.Test (src1, src1, src1.Type); - context.Assembler.Cmovcc(dest, src2, dest.Type, X86Condition.NotEqual); - } - - private static void GenerateConvertI64ToI32(CodeGenContext context, Operation operation) - { - Operand dest = operation.Destination; - Operand source = operation.GetSource(0); - - Debug.Assert(dest.Type == OperandType.I32 && source.Type == OperandType.I64); - - context.Assembler.Mov(dest, source, OperandType.I32); - } - - private static void GenerateConvertToFP(CodeGenContext context, Operation operation) - { - Operand dest = operation.Destination; - Operand source = operation.GetSource(0); - - Debug.Assert(dest.Type == OperandType.FP32 || dest.Type == OperandType.FP64); - - if (dest.Type == OperandType.FP32) - { - Debug.Assert(source.Type.IsInteger() || source.Type == OperandType.FP64); - - if (source.Type.IsInteger()) - { - context.Assembler.Xorps (dest, dest, dest); - context.Assembler.Cvtsi2ss(dest, dest, source, source.Type); - } - else /* if (source.Type == OperandType.FP64) */ - { - context.Assembler.Cvtsd2ss(dest, dest, source); - - GenerateZeroUpper96(context, dest, dest); - } - } - else /* if (dest.Type == OperandType.FP64) */ - { - Debug.Assert(source.Type.IsInteger() || source.Type == OperandType.FP32); - - if (source.Type.IsInteger()) - { - context.Assembler.Xorps (dest, dest, dest); - context.Assembler.Cvtsi2sd(dest, dest, source, source.Type); - } - else /* if (source.Type == OperandType.FP32) */ - { - context.Assembler.Cvtss2sd(dest, dest, source); - - GenerateZeroUpper64(context, dest, dest); - } - } - } - - private static void GenerateCopy(CodeGenContext context, Operation operation) - { - Operand dest = operation.Destination; - Operand source = operation.GetSource(0); - - EnsureSameType(dest, source); - - Debug.Assert(dest.Type.IsInteger() || source.Kind != OperandKind.Constant); - - // Moves to the same register are useless. - if (dest.Kind == source.Kind && dest.Value == source.Value) - { - return; - } - - if (dest.Kind == OperandKind.Register && - source.Kind == OperandKind.Constant && source.Value == 0) - { - // Assemble "mov reg, 0" as "xor reg, reg" as the later is more efficient. - context.Assembler.Xor(dest, dest, OperandType.I32); - } - else if (dest.Type.IsInteger()) - { - context.Assembler.Mov(dest, source, dest.Type); - } - else - { - context.Assembler.Movdqu(dest, source); - } - } - - private static void GenerateCountLeadingZeros(CodeGenContext context, Operation operation) - { - Operand dest = operation.Destination; - Operand source = operation.GetSource(0); - - EnsureSameType(dest, source); - - Debug.Assert(dest.Type.IsInteger()); - - context.Assembler.Bsr(dest, source, dest.Type); - - int operandSize = dest.Type == OperandType.I32 ? 32 : 64; - int operandMask = operandSize - 1; - - // When the input operand is 0, the result is undefined, however the - // ZF flag is set. We are supposed to return the operand size on that - // case. So, add an additional jump to handle that case, by moving the - // operand size constant to the destination register. - Operand neLabel = Label(); - - context.Assembler.Jcc(X86Condition.NotEqual, neLabel); - - context.Assembler.Mov(dest, Const(operandSize | operandMask), OperandType.I32); - - context.Assembler.MarkLabel(neLabel); - - // BSR returns the zero based index of the last bit set on the operand, - // starting from the least significant bit. However we are supposed to - // return the number of 0 bits on the high end. So, we invert the result - // of the BSR using XOR to get the correct value. - context.Assembler.Xor(dest, Const(operandMask), OperandType.I32); - } - - private static void GenerateDivide(CodeGenContext context, Operation operation) - { - Operand dest = operation.Destination; - Operand dividend = operation.GetSource(0); - Operand divisor = operation.GetSource(1); - - if (!dest.Type.IsInteger()) - { - ValidateBinOp(dest, dividend, divisor); - } - - if (dest.Type.IsInteger()) - { - divisor = operation.GetSource(2); - - EnsureSameType(dest, divisor); - - if (divisor.Type == OperandType.I32) - { - context.Assembler.Cdq(); - } - else - { - context.Assembler.Cqo(); - } - - context.Assembler.Idiv(divisor); - } - else if (dest.Type == OperandType.FP32) - { - context.Assembler.Divss(dest, dividend, divisor); - } - else /* if (dest.Type == OperandType.FP64) */ - { - context.Assembler.Divsd(dest, dividend, divisor); - } - } - - private static void GenerateDivideUI(CodeGenContext context, Operation operation) - { - Operand divisor = operation.GetSource(2); - - Operand rdx = Register(X86Register.Rdx); - - Debug.Assert(divisor.Type.IsInteger()); - - context.Assembler.Xor(rdx, rdx, OperandType.I32); - context.Assembler.Div(divisor); - } - - private static void GenerateFill(CodeGenContext context, Operation operation) - { - Operand dest = operation.Destination; - Operand offset = operation.GetSource(0); - - Debug.Assert(offset.Kind == OperandKind.Constant); - - int offs = offset.AsInt32() + context.CallArgsRegionSize; - - Operand rsp = Register(X86Register.Rsp); - - Operand memOp = MemoryOp(dest.Type, rsp, default, Multiplier.x1, offs); - - GenerateLoad(context, memOp, dest); - } - - private static void GenerateLoad(CodeGenContext context, Operation operation) - { - Operand value = operation.Destination; - Operand address = Memory(operation.GetSource(0), value.Type); - - GenerateLoad(context, address, value); - } - - private static void GenerateLoad16(CodeGenContext context, Operation operation) - { - Operand value = operation.Destination; - Operand address = Memory(operation.GetSource(0), value.Type); - - Debug.Assert(value.Type.IsInteger()); - - context.Assembler.Movzx16(value, address, value.Type); - } - - private static void GenerateLoad8(CodeGenContext context, Operation operation) - { - Operand value = operation.Destination; - Operand address = Memory(operation.GetSource(0), value.Type); - - Debug.Assert(value.Type.IsInteger()); - - context.Assembler.Movzx8(value, address, value.Type); - } - - private static void GenerateMemoryBarrier(CodeGenContext context, Operation operation) - { - context.Assembler.LockOr(MemoryOp(OperandType.I64, Register(X86Register.Rsp)), Const(0), OperandType.I32); - } - - private static void GenerateMultiply(CodeGenContext context, Operation operation) - { - Operand dest = operation.Destination; - Operand src1 = operation.GetSource(0); - Operand src2 = operation.GetSource(1); - - if (src2.Kind != OperandKind.Constant) - { - EnsureSameReg(dest, src1); - } - - EnsureSameType(dest, src1, src2); - - if (dest.Type.IsInteger()) - { - if (src2.Kind == OperandKind.Constant) - { - context.Assembler.Imul(dest, src1, src2, dest.Type); - } - else - { - context.Assembler.Imul(dest, src2, dest.Type); - } - } - else if (dest.Type == OperandType.FP32) - { - context.Assembler.Mulss(dest, src1, src2); - } - else /* if (dest.Type == OperandType.FP64) */ - { - context.Assembler.Mulsd(dest, src1, src2); - } - } - - private static void GenerateMultiply64HighSI(CodeGenContext context, Operation operation) - { - Operand source = operation.GetSource(1); - - Debug.Assert(source.Type == OperandType.I64); - - context.Assembler.Imul(source); - } - - private static void GenerateMultiply64HighUI(CodeGenContext context, Operation operation) - { - Operand source = operation.GetSource(1); - - Debug.Assert(source.Type == OperandType.I64); - - context.Assembler.Mul(source); - } - - private static void GenerateNegate(CodeGenContext context, Operation operation) - { - Operand dest = operation.Destination; - Operand source = operation.GetSource(0); - - ValidateUnOp(dest, source); - - Debug.Assert(dest.Type.IsInteger()); - - context.Assembler.Neg(dest); - } - - private static void GenerateReturn(CodeGenContext context, Operation operation) - { - WriteEpilogue(context); - - context.Assembler.Return(); - } - - private static void GenerateRotateRight(CodeGenContext context, Operation operation) - { - Operand dest = operation.Destination; - Operand src1 = operation.GetSource(0); - Operand src2 = operation.GetSource(1); - - ValidateShift(dest, src1, src2); - - context.Assembler.Ror(dest, src2, dest.Type); - } - - private static void GenerateShiftLeft(CodeGenContext context, Operation operation) - { - Operand dest = operation.Destination; - Operand src1 = operation.GetSource(0); - Operand src2 = operation.GetSource(1); - - ValidateShift(dest, src1, src2); - - context.Assembler.Shl(dest, src2, dest.Type); - } - - private static void GenerateShiftRightSI(CodeGenContext context, Operation operation) - { - Operand dest = operation.Destination; - Operand src1 = operation.GetSource(0); - Operand src2 = operation.GetSource(1); - - ValidateShift(dest, src1, src2); - - context.Assembler.Sar(dest, src2, dest.Type); - } - - private static void GenerateShiftRightUI(CodeGenContext context, Operation operation) - { - Operand dest = operation.Destination; - Operand src1 = operation.GetSource(0); - Operand src2 = operation.GetSource(1); - - ValidateShift(dest, src1, src2); - - context.Assembler.Shr(dest, src2, dest.Type); - } - - private static void GenerateSignExtend16(CodeGenContext context, Operation operation) - { - Operand dest = operation.Destination; - Operand source = operation.GetSource(0); - - Debug.Assert(dest.Type.IsInteger() && source.Type.IsInteger()); - - context.Assembler.Movsx16(dest, source, dest.Type); - } - - private static void GenerateSignExtend32(CodeGenContext context, Operation operation) - { - Operand dest = operation.Destination; - Operand source = operation.GetSource(0); - - Debug.Assert(dest.Type.IsInteger() && source.Type.IsInteger()); - - context.Assembler.Movsx32(dest, source, dest.Type); - } - - private static void GenerateSignExtend8(CodeGenContext context, Operation operation) - { - Operand dest = operation.Destination; - Operand source = operation.GetSource(0); - - Debug.Assert(dest.Type.IsInteger() && source.Type.IsInteger()); - - context.Assembler.Movsx8(dest, source, dest.Type); - } - - private static void GenerateSpill(CodeGenContext context, Operation operation) - { - GenerateSpill(context, operation, context.CallArgsRegionSize); - } - - private static void GenerateSpillArg(CodeGenContext context, Operation operation) - { - GenerateSpill(context, operation, 0); - } - - private static void GenerateSpill(CodeGenContext context, Operation operation, int baseOffset) - { - Operand offset = operation.GetSource(0); - Operand source = operation.GetSource(1); - - Debug.Assert(offset.Kind == OperandKind.Constant); - - int offs = offset.AsInt32() + baseOffset; - - Operand rsp = Register(X86Register.Rsp); - - Operand memOp = MemoryOp(source.Type, rsp, default, Multiplier.x1, offs); - - GenerateStore(context, memOp, source); - } - - private static void GenerateStackAlloc(CodeGenContext context, Operation operation) - { - Operand dest = operation.Destination; - Operand offset = operation.GetSource(0); - - Debug.Assert(offset.Kind == OperandKind.Constant); - - int offs = offset.AsInt32() + context.CallArgsRegionSize; - - Operand rsp = Register(X86Register.Rsp); - - Operand memOp = MemoryOp(OperandType.I64, rsp, default, Multiplier.x1, offs); - - context.Assembler.Lea(dest, memOp, OperandType.I64); - } - - private static void GenerateStore(CodeGenContext context, Operation operation) - { - Operand value = operation.GetSource(1); - Operand address = Memory(operation.GetSource(0), value.Type); - - GenerateStore(context, address, value); - } - - private static void GenerateStore16(CodeGenContext context, Operation operation) - { - Operand value = operation.GetSource(1); - Operand address = Memory(operation.GetSource(0), value.Type); - - Debug.Assert(value.Type.IsInteger()); - - context.Assembler.Mov16(address, value); - } - - private static void GenerateStore8(CodeGenContext context, Operation operation) - { - Operand value = operation.GetSource(1); - Operand address = Memory(operation.GetSource(0), value.Type); - - Debug.Assert(value.Type.IsInteger()); - - context.Assembler.Mov8(address, value); - } - - private static void GenerateSubtract(CodeGenContext context, Operation operation) - { - Operand dest = operation.Destination; - Operand src1 = operation.GetSource(0); - Operand src2 = operation.GetSource(1); - - ValidateBinOp(dest, src1, src2); - - if (dest.Type.IsInteger()) - { - context.Assembler.Sub(dest, src2, dest.Type); - } - else if (dest.Type == OperandType.FP32) - { - context.Assembler.Subss(dest, src1, src2); - } - else /* if (dest.Type == OperandType.FP64) */ - { - context.Assembler.Subsd(dest, src1, src2); - } - } - - private static void GenerateTailcall(CodeGenContext context, Operation operation) - { - WriteEpilogue(context); - - context.Assembler.Jmp(operation.GetSource(0)); - } - - private static void GenerateVectorCreateScalar(CodeGenContext context, Operation operation) - { - Operand dest = operation.Destination; - Operand source = operation.GetSource(0); - - Debug.Assert(!dest.Type.IsInteger() && source.Type.IsInteger()); - - if (source.Type == OperandType.I32) - { - context.Assembler.Movd(dest, source); // (__m128i _mm_cvtsi32_si128(int a)) - } - else /* if (source.Type == OperandType.I64) */ - { - context.Assembler.Movq(dest, source); // (__m128i _mm_cvtsi64_si128(__int64 a)) - } - } - - private static void GenerateVectorExtract(CodeGenContext context, Operation operation) - { - Operand dest = operation.Destination; //Value - Operand src1 = operation.GetSource(0); //Vector - Operand src2 = operation.GetSource(1); //Index - - Debug.Assert(src1.Type == OperandType.V128); - Debug.Assert(src2.Kind == OperandKind.Constant); - - byte index = src2.AsByte(); - - Debug.Assert(index < OperandType.V128.GetSizeInBytes() / dest.Type.GetSizeInBytes()); - - if (dest.Type == OperandType.I32) - { - if (index == 0) - { - context.Assembler.Movd(dest, src1); - } - else if (HardwareCapabilities.SupportsSse41) - { - context.Assembler.Pextrd(dest, src1, index); - } - else - { - int mask0 = 0b11_10_01_00; - int mask1 = 0b11_10_01_00; - - mask0 = BitUtils.RotateRight(mask0, index * 2, 8); - mask1 = BitUtils.RotateRight(mask1, 8 - index * 2, 8); - - context.Assembler.Pshufd(src1, src1, (byte)mask0); - context.Assembler.Movd (dest, src1); - context.Assembler.Pshufd(src1, src1, (byte)mask1); - } - } - else if (dest.Type == OperandType.I64) - { - if (index == 0) - { - context.Assembler.Movq(dest, src1); - } - else if (HardwareCapabilities.SupportsSse41) - { - context.Assembler.Pextrq(dest, src1, index); - } - else - { - const byte mask = 0b01_00_11_10; - - context.Assembler.Pshufd(src1, src1, mask); - context.Assembler.Movq (dest, src1); - context.Assembler.Pshufd(src1, src1, mask); - } - } - else - { - // Floating-point types. - if ((index >= 2 && dest.Type == OperandType.FP32) || - (index == 1 && dest.Type == OperandType.FP64)) - { - context.Assembler.Movhlps(dest, dest, src1); - context.Assembler.Movq (dest, dest); - } - else - { - context.Assembler.Movq(dest, src1); - } - - if (dest.Type == OperandType.FP32) - { - context.Assembler.Pshufd(dest, dest, (byte)(0xfc | (index & 1))); - } - } - } - - private static void GenerateVectorExtract16(CodeGenContext context, Operation operation) - { - Operand dest = operation.Destination; //Value - Operand src1 = operation.GetSource(0); //Vector - Operand src2 = operation.GetSource(1); //Index - - Debug.Assert(src1.Type == OperandType.V128); - Debug.Assert(src2.Kind == OperandKind.Constant); - - byte index = src2.AsByte(); - - Debug.Assert(index < 8); - - context.Assembler.Pextrw(dest, src1, index); - } - - private static void GenerateVectorExtract8(CodeGenContext context, Operation operation) - { - Operand dest = operation.Destination; //Value - Operand src1 = operation.GetSource(0); //Vector - Operand src2 = operation.GetSource(1); //Index - - Debug.Assert(src1.Type == OperandType.V128); - Debug.Assert(src2.Kind == OperandKind.Constant); - - byte index = src2.AsByte(); - - Debug.Assert(index < 16); - - if (HardwareCapabilities.SupportsSse41) - { - context.Assembler.Pextrb(dest, src1, index); - } - else - { - context.Assembler.Pextrw(dest, src1, (byte)(index >> 1)); - - if ((index & 1) != 0) - { - context.Assembler.Shr(dest, Const(8), OperandType.I32); - } - else - { - context.Assembler.Movzx8(dest, dest, OperandType.I32); - } - } - } - - private static void GenerateVectorInsert(CodeGenContext context, Operation operation) - { - Operand dest = operation.Destination; - Operand src1 = operation.GetSource(0); //Vector - Operand src2 = operation.GetSource(1); //Value - Operand src3 = operation.GetSource(2); //Index - - if (!HardwareCapabilities.SupportsVexEncoding) - { - EnsureSameReg(dest, src1); - } - - Debug.Assert(src1.Type == OperandType.V128); - Debug.Assert(src3.Kind == OperandKind.Constant); - - byte index = src3.AsByte(); - - void InsertIntSse2(int words) - { - if (dest.GetRegister() != src1.GetRegister()) - { - context.Assembler.Movdqu(dest, src1); - } - - for (int word = 0; word < words; word++) - { - // Insert lower 16-bits. - context.Assembler.Pinsrw(dest, dest, src2, (byte)(index * words + word)); - - // Move next word down. - context.Assembler.Ror(src2, Const(16), src2.Type); - } - } - - if (src2.Type == OperandType.I32) - { - Debug.Assert(index < 4); - - if (HardwareCapabilities.SupportsSse41) - { - context.Assembler.Pinsrd(dest, src1, src2, index); - } - else - { - InsertIntSse2(2); - } - } - else if (src2.Type == OperandType.I64) - { - Debug.Assert(index < 2); - - if (HardwareCapabilities.SupportsSse41) - { - context.Assembler.Pinsrq(dest, src1, src2, index); - } - else - { - InsertIntSse2(4); - } - } - else if (src2.Type == OperandType.FP32) - { - Debug.Assert(index < 4); - - if (index != 0) - { - if (HardwareCapabilities.SupportsSse41) - { - context.Assembler.Insertps(dest, src1, src2, (byte)(index << 4)); - } - else - { - if (src1.GetRegister() == src2.GetRegister()) - { - int mask = 0b11_10_01_00; - - mask &= ~(0b11 << index * 2); - - context.Assembler.Pshufd(dest, src1, (byte)mask); - } - else - { - int mask0 = 0b11_10_01_00; - int mask1 = 0b11_10_01_00; - - mask0 = BitUtils.RotateRight(mask0, 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.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. - - if (dest.GetRegister() != src1.GetRegister()) - { - context.Assembler.Pshufd(src1, src1, (byte)mask1); // Restore src1. - } - } - } - } - else - { - context.Assembler.Movss(dest, src1, src2); - } - } - else /* if (src2.Type == OperandType.FP64) */ - { - Debug.Assert(index < 2); - - if (index != 0) - { - context.Assembler.Movlhps(dest, src1, src2); - } - else - { - context.Assembler.Movsd(dest, src1, src2); - } - } - } - - private static void GenerateVectorInsert16(CodeGenContext context, Operation operation) - { - Operand dest = operation.Destination; - Operand src1 = operation.GetSource(0); //Vector - Operand src2 = operation.GetSource(1); //Value - Operand src3 = operation.GetSource(2); //Index - - if (!HardwareCapabilities.SupportsVexEncoding) - { - EnsureSameReg(dest, src1); - } - - Debug.Assert(src1.Type == OperandType.V128); - Debug.Assert(src3.Kind == OperandKind.Constant); - - byte index = src3.AsByte(); - - context.Assembler.Pinsrw(dest, src1, src2, index); - } - - private static void GenerateVectorInsert8(CodeGenContext context, Operation operation) - { - Operand dest = operation.Destination; - Operand src1 = operation.GetSource(0); //Vector - Operand src2 = operation.GetSource(1); //Value - Operand src3 = operation.GetSource(2); //Index - - // It's not possible to emulate this instruction without - // SSE 4.1 support without the use of a temporary register, - // so we instead handle that case on the pre-allocator when - // SSE 4.1 is not supported on the CPU. - Debug.Assert(HardwareCapabilities.SupportsSse41); - - if (!HardwareCapabilities.SupportsVexEncoding) - { - EnsureSameReg(dest, src1); - } - - Debug.Assert(src1.Type == OperandType.V128); - Debug.Assert(src3.Kind == OperandKind.Constant); - - byte index = src3.AsByte(); - - context.Assembler.Pinsrb(dest, src1, src2, index); - } - - private static void GenerateVectorOne(CodeGenContext context, Operation operation) - { - Operand dest = operation.Destination; - - Debug.Assert(!dest.Type.IsInteger()); - - context.Assembler.Pcmpeqw(dest, dest, dest); - } - - private static void GenerateVectorZero(CodeGenContext context, Operation operation) - { - Operand dest = operation.Destination; - - Debug.Assert(!dest.Type.IsInteger()); - - context.Assembler.Xorps(dest, dest, dest); - } - - private static void GenerateVectorZeroUpper64(CodeGenContext context, Operation operation) - { - Operand dest = operation.Destination; - Operand source = operation.GetSource(0); - - Debug.Assert(dest.Type == OperandType.V128 && source.Type == OperandType.V128); - - GenerateZeroUpper64(context, dest, source); - } - - private static void GenerateVectorZeroUpper96(CodeGenContext context, Operation operation) - { - Operand dest = operation.Destination; - Operand source = operation.GetSource(0); - - Debug.Assert(dest.Type == OperandType.V128 && source.Type == OperandType.V128); - - GenerateZeroUpper96(context, dest, source); - } - - private static void GenerateZeroExtend16(CodeGenContext context, Operation operation) - { - Operand dest = operation.Destination; - Operand source = operation.GetSource(0); - - Debug.Assert(dest.Type.IsInteger() && source.Type.IsInteger()); - - context.Assembler.Movzx16(dest, source, OperandType.I32); - } - - private static void GenerateZeroExtend32(CodeGenContext context, Operation operation) - { - Operand dest = operation.Destination; - Operand source = operation.GetSource(0); - - Debug.Assert(dest.Type.IsInteger() && source.Type.IsInteger()); - - context.Assembler.Mov(dest, source, OperandType.I32); - } - - private static void GenerateZeroExtend8(CodeGenContext context, Operation operation) - { - Operand dest = operation.Destination; - Operand source = operation.GetSource(0); - - Debug.Assert(dest.Type.IsInteger() && source.Type.IsInteger()); - - context.Assembler.Movzx8(dest, source, OperandType.I32); - } - - private static void GenerateLoad(CodeGenContext context, Operand address, Operand value) - { - switch (value.Type) - { - case OperandType.I32: context.Assembler.Mov (value, address, OperandType.I32); break; - case OperandType.I64: context.Assembler.Mov (value, address, OperandType.I64); 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: Debug.Assert(false); break; - } - } - - private static void GenerateStore(CodeGenContext context, Operand address, Operand value) - { - switch (value.Type) - { - case OperandType.I32: context.Assembler.Mov (address, value, OperandType.I32); break; - case OperandType.I64: context.Assembler.Mov (address, value, OperandType.I64); 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: Debug.Assert(false); break; - } - } - - private static void GenerateZeroUpper64(CodeGenContext context, Operand dest, Operand source) - { - context.Assembler.Movq(dest, source); - } - - private static void GenerateZeroUpper96(CodeGenContext context, Operand dest, Operand source) - { - context.Assembler.Movq(dest, source); - context.Assembler.Pshufd(dest, dest, 0xfc); - } - - private static bool MatchOperation(Operation node, Instruction inst, OperandType destType, Register destReg) - { - if (node == default || node.DestinationsCount == 0) - { - return false; - } - - if (node.Instruction != inst) - { - return false; - } - - Operand dest = node.Destination; - - return dest.Kind == OperandKind.Register && - dest.Type == destType && - dest.GetRegister() == destReg; - } - - [Conditional("DEBUG")] - private static void ValidateUnOp(Operand dest, Operand source) - { - EnsureSameReg (dest, source); - EnsureSameType(dest, source); - } - - [Conditional("DEBUG")] - private static void ValidateBinOp(Operand dest, Operand src1, Operand src2) - { - EnsureSameReg (dest, src1); - EnsureSameType(dest, src1, src2); - } - - [Conditional("DEBUG")] - private static void ValidateShift(Operand dest, Operand src1, Operand src2) - { - EnsureSameReg (dest, src1); - EnsureSameType(dest, src1); - - Debug.Assert(dest.Type.IsInteger() && src2.Type == OperandType.I32); - } - - private static void EnsureSameReg(Operand op1, Operand op2) - { - if (!op1.Type.IsInteger() && HardwareCapabilities.SupportsVexEncoding) - { - return; - } - - Debug.Assert(op1.Kind == OperandKind.Register || op1.Kind == OperandKind.Memory); - Debug.Assert(op1.Kind == op2.Kind); - Debug.Assert(op1.Value == op2.Value); - } - - private static void EnsureSameType(Operand op1, Operand op2) - { - Debug.Assert(op1.Type == op2.Type); - } - - private static void EnsureSameType(Operand op1, Operand op2, Operand op3) - { - Debug.Assert(op1.Type == op2.Type); - Debug.Assert(op1.Type == op3.Type); - } - - private static void EnsureSameType(Operand op1, Operand op2, Operand op3, Operand op4) - { - Debug.Assert(op1.Type == op2.Type); - Debug.Assert(op1.Type == op3.Type); - Debug.Assert(op1.Type == op4.Type); - } - - private static UnwindInfo WritePrologue(CodeGenContext context) - { - List pushEntries = new List(); - - Operand rsp = Register(X86Register.Rsp); - - int mask = CallingConvention.GetIntCalleeSavedRegisters() & context.AllocResult.IntUsedRegisters; - - while (mask != 0) - { - int bit = BitOperations.TrailingZeroCount(mask); - - context.Assembler.Push(Register((X86Register)bit)); - - pushEntries.Add(new UnwindPushEntry(UnwindPseudoOp.PushReg, context.StreamOffset, regIndex: bit)); - - mask &= ~(1 << bit); - } - - int reservedStackSize = context.CallArgsRegionSize + context.AllocResult.SpillRegionSize; - - reservedStackSize += context.XmmSaveRegionSize; - - if (reservedStackSize >= StackGuardSize) - { - GenerateInlineStackProbe(context, reservedStackSize); - } - - if (reservedStackSize != 0) - { - context.Assembler.Sub(rsp, Const(reservedStackSize), OperandType.I64); - - pushEntries.Add(new UnwindPushEntry(UnwindPseudoOp.AllocStack, context.StreamOffset, stackOffsetOrAllocSize: reservedStackSize)); - } - - int offset = reservedStackSize; - - mask = CallingConvention.GetVecCalleeSavedRegisters() & context.AllocResult.VecUsedRegisters; - - while (mask != 0) - { - int bit = BitOperations.TrailingZeroCount(mask); - - offset -= 16; - - Operand memOp = MemoryOp(OperandType.V128, rsp, default, Multiplier.x1, offset); - - context.Assembler.Movdqu(memOp, Xmm((X86Register)bit)); - - pushEntries.Add(new UnwindPushEntry(UnwindPseudoOp.SaveXmm128, context.StreamOffset, bit, offset)); - - mask &= ~(1 << bit); - } - - return new UnwindInfo(pushEntries.ToArray(), context.StreamOffset); - } - - private static void WriteEpilogue(CodeGenContext context) - { - Operand rsp = Register(X86Register.Rsp); - - int reservedStackSize = context.CallArgsRegionSize + context.AllocResult.SpillRegionSize; - - reservedStackSize += context.XmmSaveRegionSize; - - int offset = reservedStackSize; - - int mask = CallingConvention.GetVecCalleeSavedRegisters() & context.AllocResult.VecUsedRegisters; - - while (mask != 0) - { - int bit = BitOperations.TrailingZeroCount(mask); - - offset -= 16; - - Operand memOp = MemoryOp(OperandType.V128, rsp, default, Multiplier.x1, offset); - - context.Assembler.Movdqu(Xmm((X86Register)bit), memOp); - - mask &= ~(1 << bit); - } - - if (reservedStackSize != 0) - { - context.Assembler.Add(rsp, Const(reservedStackSize), OperandType.I64); - } - - mask = CallingConvention.GetIntCalleeSavedRegisters() & context.AllocResult.IntUsedRegisters; - - while (mask != 0) - { - int bit = BitUtils.HighestBitSet(mask); - - context.Assembler.Pop(Register((X86Register)bit)); - - mask &= ~(1 << bit); - } - } - - private static void GenerateInlineStackProbe(CodeGenContext context, int size) - { - // Windows does lazy stack allocation, and there are just 2 - // guard pages on the end of the stack. So, if the allocation - // size we make is greater than this guard size, we must ensure - // 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 - // the OS to map them. If they are already mapped, nothing happens. - const int pageMask = PageSize - 1; - - size = (size + pageMask) & ~pageMask; - - Operand rsp = Register(X86Register.Rsp); - Operand temp = Register(CallingConvention.GetIntReturnRegister()); - - for (int offset = PageSize; offset < size; offset += PageSize) - { - Operand memOp = MemoryOp(OperandType.I32, rsp, default, Multiplier.x1, -offset); - - context.Assembler.Mov(temp, memOp, OperandType.I32); - } - } - - private static Operand Memory(Operand operand, OperandType type) - { - if (operand.Kind == OperandKind.Memory) - { - return operand; - } - - return MemoryOp(type, operand); - } - - private static Operand Register(X86Register register, OperandType type = OperandType.I64) - { - return Operand.Factory.Register((int)register, RegisterType.Integer, type); - } - - private static Operand Xmm(X86Register register) - { - return Operand.Factory.Register((int)register, RegisterType.Vector, OperandType.V128); - } - } -} \ No newline at end of file diff --git a/ARMeilleure/CodeGen/X86/HardwareCapabilities.cs b/ARMeilleure/CodeGen/X86/HardwareCapabilities.cs deleted file mode 100644 index a29dd5bef..000000000 --- a/ARMeilleure/CodeGen/X86/HardwareCapabilities.cs +++ /dev/null @@ -1,80 +0,0 @@ -using System; -using System.Runtime.Intrinsics.X86; - -namespace ARMeilleure.CodeGen.X86 -{ - static class HardwareCapabilities - { - static HardwareCapabilities() - { - if (!X86Base.IsSupported) - { - return; - } - - (int maxNum, _, _, _) = X86Base.CpuId(0x00000000, 0x00000000); - - (_, _, int ecx1, int edx1) = X86Base.CpuId(0x00000001, 0x00000000); - FeatureInfo1Edx = (FeatureFlags1Edx)edx1; - FeatureInfo1Ecx = (FeatureFlags1Ecx)ecx1; - - if (maxNum >= 7) - { - (_, int ebx7, _, _) = X86Base.CpuId(0x00000007, 0x00000000); - FeatureInfo7Ebx = (FeatureFlags7Ebx)ebx7; - } - } - - [Flags] - public enum FeatureFlags1Edx - { - Sse = 1 << 25, - Sse2 = 1 << 26 - } - - [Flags] - public enum FeatureFlags1Ecx - { - Sse3 = 1 << 0, - Pclmulqdq = 1 << 1, - Ssse3 = 1 << 9, - Fma = 1 << 12, - Sse41 = 1 << 19, - Sse42 = 1 << 20, - Popcnt = 1 << 23, - Aes = 1 << 25, - Avx = 1 << 28, - F16c = 1 << 29 - } - - [Flags] - public enum FeatureFlags7Ebx - { - Avx2 = 1 << 5, - Sha = 1 << 29 - } - - public static FeatureFlags1Edx FeatureInfo1Edx { get; } - public static FeatureFlags1Ecx FeatureInfo1Ecx { get; } - public static FeatureFlags7Ebx FeatureInfo7Ebx { get; } = 0; - - public static bool SupportsSse => FeatureInfo1Edx.HasFlag(FeatureFlags1Edx.Sse); - public static bool SupportsSse2 => FeatureInfo1Edx.HasFlag(FeatureFlags1Edx.Sse2); - public static bool SupportsSse3 => FeatureInfo1Ecx.HasFlag(FeatureFlags1Ecx.Sse3); - public static bool SupportsPclmulqdq => FeatureInfo1Ecx.HasFlag(FeatureFlags1Ecx.Pclmulqdq); - public static bool SupportsSsse3 => FeatureInfo1Ecx.HasFlag(FeatureFlags1Ecx.Ssse3); - public static bool SupportsFma => FeatureInfo1Ecx.HasFlag(FeatureFlags1Ecx.Fma); - public static bool SupportsSse41 => FeatureInfo1Ecx.HasFlag(FeatureFlags1Ecx.Sse41); - public static bool SupportsSse42 => FeatureInfo1Ecx.HasFlag(FeatureFlags1Ecx.Sse42); - public static bool SupportsPopcnt => FeatureInfo1Ecx.HasFlag(FeatureFlags1Ecx.Popcnt); - public static bool SupportsAesni => FeatureInfo1Ecx.HasFlag(FeatureFlags1Ecx.Aes); - public static bool SupportsAvx => FeatureInfo1Ecx.HasFlag(FeatureFlags1Ecx.Avx); - public static bool SupportsAvx2 => FeatureInfo7Ebx.HasFlag(FeatureFlags7Ebx.Avx2) && SupportsAvx; - public static bool SupportsF16c => FeatureInfo1Ecx.HasFlag(FeatureFlags1Ecx.F16c); - public static bool SupportsSha => FeatureInfo7Ebx.HasFlag(FeatureFlags7Ebx.Sha); - - public static bool ForceLegacySse { get; set; } - - public static bool SupportsVexEncoding => SupportsAvx && !ForceLegacySse; - } -} \ No newline at end of file diff --git a/ARMeilleure/CodeGen/X86/IntrinsicInfo.cs b/ARMeilleure/CodeGen/X86/IntrinsicInfo.cs deleted file mode 100644 index b1af352bc..000000000 --- a/ARMeilleure/CodeGen/X86/IntrinsicInfo.cs +++ /dev/null @@ -1,14 +0,0 @@ -namespace ARMeilleure.CodeGen.X86 -{ - struct IntrinsicInfo - { - public X86Instruction Inst { get; } - public IntrinsicType Type { get; } - - public IntrinsicInfo(X86Instruction inst, IntrinsicType type) - { - Inst = inst; - Type = type; - } - } -} \ No newline at end of file diff --git a/ARMeilleure/CodeGen/X86/IntrinsicTable.cs b/ARMeilleure/CodeGen/X86/IntrinsicTable.cs deleted file mode 100644 index ada86cfae..000000000 --- a/ARMeilleure/CodeGen/X86/IntrinsicTable.cs +++ /dev/null @@ -1,198 +0,0 @@ -using ARMeilleure.Common; -using ARMeilleure.IntermediateRepresentation; - -namespace ARMeilleure.CodeGen.X86 -{ - static class IntrinsicTable - { - private const int BadOp = 0; - - private static IntrinsicInfo[] _intrinTable; - - static IntrinsicTable() - { - _intrinTable = new IntrinsicInfo[EnumUtils.GetCount(typeof(Intrinsic))]; - - Add(Intrinsic.X86Addpd, new IntrinsicInfo(X86Instruction.Addpd, IntrinsicType.Binary)); - Add(Intrinsic.X86Addps, new IntrinsicInfo(X86Instruction.Addps, IntrinsicType.Binary)); - Add(Intrinsic.X86Addsd, new IntrinsicInfo(X86Instruction.Addsd, IntrinsicType.Binary)); - Add(Intrinsic.X86Addss, new IntrinsicInfo(X86Instruction.Addss, IntrinsicType.Binary)); - Add(Intrinsic.X86Aesdec, new IntrinsicInfo(X86Instruction.Aesdec, IntrinsicType.Binary)); - Add(Intrinsic.X86Aesdeclast, new IntrinsicInfo(X86Instruction.Aesdeclast, IntrinsicType.Binary)); - Add(Intrinsic.X86Aesenc, new IntrinsicInfo(X86Instruction.Aesenc, IntrinsicType.Binary)); - Add(Intrinsic.X86Aesenclast, new IntrinsicInfo(X86Instruction.Aesenclast, IntrinsicType.Binary)); - Add(Intrinsic.X86Aesimc, new IntrinsicInfo(X86Instruction.Aesimc, IntrinsicType.Unary)); - Add(Intrinsic.X86Andnpd, new IntrinsicInfo(X86Instruction.Andnpd, IntrinsicType.Binary)); - Add(Intrinsic.X86Andnps, new IntrinsicInfo(X86Instruction.Andnps, IntrinsicType.Binary)); - Add(Intrinsic.X86Andpd, new IntrinsicInfo(X86Instruction.Andpd, IntrinsicType.Binary)); - Add(Intrinsic.X86Andps, new IntrinsicInfo(X86Instruction.Andps, IntrinsicType.Binary)); - Add(Intrinsic.X86Blendvpd, new IntrinsicInfo(X86Instruction.Blendvpd, IntrinsicType.Ternary)); - Add(Intrinsic.X86Blendvps, new IntrinsicInfo(X86Instruction.Blendvps, IntrinsicType.Ternary)); - Add(Intrinsic.X86Cmppd, new IntrinsicInfo(X86Instruction.Cmppd, IntrinsicType.TernaryImm)); - Add(Intrinsic.X86Cmpps, new IntrinsicInfo(X86Instruction.Cmpps, IntrinsicType.TernaryImm)); - Add(Intrinsic.X86Cmpsd, new IntrinsicInfo(X86Instruction.Cmpsd, IntrinsicType.TernaryImm)); - Add(Intrinsic.X86Cmpss, new IntrinsicInfo(X86Instruction.Cmpss, IntrinsicType.TernaryImm)); - Add(Intrinsic.X86Comisdeq, new IntrinsicInfo(X86Instruction.Comisd, IntrinsicType.Comis_)); - Add(Intrinsic.X86Comisdge, new IntrinsicInfo(X86Instruction.Comisd, IntrinsicType.Comis_)); - Add(Intrinsic.X86Comisdlt, new IntrinsicInfo(X86Instruction.Comisd, IntrinsicType.Comis_)); - Add(Intrinsic.X86Comisseq, new IntrinsicInfo(X86Instruction.Comiss, IntrinsicType.Comis_)); - Add(Intrinsic.X86Comissge, new IntrinsicInfo(X86Instruction.Comiss, IntrinsicType.Comis_)); - Add(Intrinsic.X86Comisslt, new IntrinsicInfo(X86Instruction.Comiss, IntrinsicType.Comis_)); - Add(Intrinsic.X86Crc32, new IntrinsicInfo(X86Instruction.Crc32, IntrinsicType.Crc32)); - Add(Intrinsic.X86Crc32_16, new IntrinsicInfo(X86Instruction.Crc32_16, IntrinsicType.Crc32)); - Add(Intrinsic.X86Crc32_8, new IntrinsicInfo(X86Instruction.Crc32_8, IntrinsicType.Crc32)); - Add(Intrinsic.X86Cvtdq2pd, new IntrinsicInfo(X86Instruction.Cvtdq2pd, IntrinsicType.Unary)); - Add(Intrinsic.X86Cvtdq2ps, new IntrinsicInfo(X86Instruction.Cvtdq2ps, IntrinsicType.Unary)); - Add(Intrinsic.X86Cvtpd2dq, new IntrinsicInfo(X86Instruction.Cvtpd2dq, IntrinsicType.Unary)); - Add(Intrinsic.X86Cvtpd2ps, new IntrinsicInfo(X86Instruction.Cvtpd2ps, IntrinsicType.Unary)); - Add(Intrinsic.X86Cvtps2dq, new IntrinsicInfo(X86Instruction.Cvtps2dq, IntrinsicType.Unary)); - Add(Intrinsic.X86Cvtps2pd, new IntrinsicInfo(X86Instruction.Cvtps2pd, IntrinsicType.Unary)); - Add(Intrinsic.X86Cvtsd2si, new IntrinsicInfo(X86Instruction.Cvtsd2si, IntrinsicType.UnaryToGpr)); - Add(Intrinsic.X86Cvtsd2ss, new IntrinsicInfo(X86Instruction.Cvtsd2ss, IntrinsicType.Binary)); - Add(Intrinsic.X86Cvtsi2sd, new IntrinsicInfo(X86Instruction.Cvtsi2sd, IntrinsicType.BinaryGpr)); - Add(Intrinsic.X86Cvtsi2si, new IntrinsicInfo(X86Instruction.Movd, IntrinsicType.UnaryToGpr)); - Add(Intrinsic.X86Cvtsi2ss, new IntrinsicInfo(X86Instruction.Cvtsi2ss, IntrinsicType.BinaryGpr)); - Add(Intrinsic.X86Cvtss2sd, new IntrinsicInfo(X86Instruction.Cvtss2sd, IntrinsicType.Binary)); - Add(Intrinsic.X86Cvtss2si, new IntrinsicInfo(X86Instruction.Cvtss2si, IntrinsicType.UnaryToGpr)); - Add(Intrinsic.X86Divpd, new IntrinsicInfo(X86Instruction.Divpd, IntrinsicType.Binary)); - Add(Intrinsic.X86Divps, new IntrinsicInfo(X86Instruction.Divps, IntrinsicType.Binary)); - Add(Intrinsic.X86Divsd, new IntrinsicInfo(X86Instruction.Divsd, IntrinsicType.Binary)); - Add(Intrinsic.X86Divss, new IntrinsicInfo(X86Instruction.Divss, IntrinsicType.Binary)); - Add(Intrinsic.X86Haddpd, new IntrinsicInfo(X86Instruction.Haddpd, IntrinsicType.Binary)); - Add(Intrinsic.X86Haddps, new IntrinsicInfo(X86Instruction.Haddps, IntrinsicType.Binary)); - Add(Intrinsic.X86Insertps, new IntrinsicInfo(X86Instruction.Insertps, IntrinsicType.TernaryImm)); - Add(Intrinsic.X86Maxpd, new IntrinsicInfo(X86Instruction.Maxpd, IntrinsicType.Binary)); - Add(Intrinsic.X86Maxps, new IntrinsicInfo(X86Instruction.Maxps, IntrinsicType.Binary)); - Add(Intrinsic.X86Maxsd, new IntrinsicInfo(X86Instruction.Maxsd, IntrinsicType.Binary)); - Add(Intrinsic.X86Maxss, new IntrinsicInfo(X86Instruction.Maxss, IntrinsicType.Binary)); - Add(Intrinsic.X86Minpd, new IntrinsicInfo(X86Instruction.Minpd, IntrinsicType.Binary)); - Add(Intrinsic.X86Minps, new IntrinsicInfo(X86Instruction.Minps, IntrinsicType.Binary)); - Add(Intrinsic.X86Minsd, new IntrinsicInfo(X86Instruction.Minsd, IntrinsicType.Binary)); - Add(Intrinsic.X86Minss, new IntrinsicInfo(X86Instruction.Minss, IntrinsicType.Binary)); - Add(Intrinsic.X86Movhlps, new IntrinsicInfo(X86Instruction.Movhlps, IntrinsicType.Binary)); - Add(Intrinsic.X86Movlhps, new IntrinsicInfo(X86Instruction.Movlhps, IntrinsicType.Binary)); - Add(Intrinsic.X86Movss, new IntrinsicInfo(X86Instruction.Movss, IntrinsicType.Binary)); - Add(Intrinsic.X86Mulpd, new IntrinsicInfo(X86Instruction.Mulpd, IntrinsicType.Binary)); - Add(Intrinsic.X86Mulps, new IntrinsicInfo(X86Instruction.Mulps, IntrinsicType.Binary)); - Add(Intrinsic.X86Mulsd, new IntrinsicInfo(X86Instruction.Mulsd, IntrinsicType.Binary)); - Add(Intrinsic.X86Mulss, new IntrinsicInfo(X86Instruction.Mulss, IntrinsicType.Binary)); - Add(Intrinsic.X86Mxcsrmb, new IntrinsicInfo(X86Instruction.None, IntrinsicType.Mxcsr)); // Mask bits. - Add(Intrinsic.X86Mxcsrub, new IntrinsicInfo(X86Instruction.None, IntrinsicType.Mxcsr)); // Unmask bits. - Add(Intrinsic.X86Paddb, new IntrinsicInfo(X86Instruction.Paddb, IntrinsicType.Binary)); - Add(Intrinsic.X86Paddd, new IntrinsicInfo(X86Instruction.Paddd, IntrinsicType.Binary)); - Add(Intrinsic.X86Paddq, new IntrinsicInfo(X86Instruction.Paddq, IntrinsicType.Binary)); - Add(Intrinsic.X86Paddw, new IntrinsicInfo(X86Instruction.Paddw, IntrinsicType.Binary)); - Add(Intrinsic.X86Palignr, new IntrinsicInfo(X86Instruction.Palignr, IntrinsicType.TernaryImm)); - Add(Intrinsic.X86Pand, new IntrinsicInfo(X86Instruction.Pand, IntrinsicType.Binary)); - Add(Intrinsic.X86Pandn, new IntrinsicInfo(X86Instruction.Pandn, IntrinsicType.Binary)); - Add(Intrinsic.X86Pavgb, new IntrinsicInfo(X86Instruction.Pavgb, IntrinsicType.Binary)); - Add(Intrinsic.X86Pavgw, new IntrinsicInfo(X86Instruction.Pavgw, IntrinsicType.Binary)); - Add(Intrinsic.X86Pblendvb, new IntrinsicInfo(X86Instruction.Pblendvb, IntrinsicType.Ternary)); - Add(Intrinsic.X86Pclmulqdq, new IntrinsicInfo(X86Instruction.Pclmulqdq, IntrinsicType.TernaryImm)); - Add(Intrinsic.X86Pcmpeqb, new IntrinsicInfo(X86Instruction.Pcmpeqb, IntrinsicType.Binary)); - Add(Intrinsic.X86Pcmpeqd, new IntrinsicInfo(X86Instruction.Pcmpeqd, IntrinsicType.Binary)); - Add(Intrinsic.X86Pcmpeqq, new IntrinsicInfo(X86Instruction.Pcmpeqq, IntrinsicType.Binary)); - Add(Intrinsic.X86Pcmpeqw, new IntrinsicInfo(X86Instruction.Pcmpeqw, IntrinsicType.Binary)); - Add(Intrinsic.X86Pcmpgtb, new IntrinsicInfo(X86Instruction.Pcmpgtb, IntrinsicType.Binary)); - Add(Intrinsic.X86Pcmpgtd, new IntrinsicInfo(X86Instruction.Pcmpgtd, IntrinsicType.Binary)); - Add(Intrinsic.X86Pcmpgtq, new IntrinsicInfo(X86Instruction.Pcmpgtq, IntrinsicType.Binary)); - Add(Intrinsic.X86Pcmpgtw, new IntrinsicInfo(X86Instruction.Pcmpgtw, IntrinsicType.Binary)); - Add(Intrinsic.X86Pmaxsb, new IntrinsicInfo(X86Instruction.Pmaxsb, IntrinsicType.Binary)); - Add(Intrinsic.X86Pmaxsd, new IntrinsicInfo(X86Instruction.Pmaxsd, IntrinsicType.Binary)); - Add(Intrinsic.X86Pmaxsw, new IntrinsicInfo(X86Instruction.Pmaxsw, IntrinsicType.Binary)); - Add(Intrinsic.X86Pmaxub, new IntrinsicInfo(X86Instruction.Pmaxub, IntrinsicType.Binary)); - Add(Intrinsic.X86Pmaxud, new IntrinsicInfo(X86Instruction.Pmaxud, IntrinsicType.Binary)); - Add(Intrinsic.X86Pmaxuw, new IntrinsicInfo(X86Instruction.Pmaxuw, IntrinsicType.Binary)); - Add(Intrinsic.X86Pminsb, new IntrinsicInfo(X86Instruction.Pminsb, IntrinsicType.Binary)); - Add(Intrinsic.X86Pminsd, new IntrinsicInfo(X86Instruction.Pminsd, IntrinsicType.Binary)); - Add(Intrinsic.X86Pminsw, new IntrinsicInfo(X86Instruction.Pminsw, IntrinsicType.Binary)); - Add(Intrinsic.X86Pminub, new IntrinsicInfo(X86Instruction.Pminub, IntrinsicType.Binary)); - Add(Intrinsic.X86Pminud, new IntrinsicInfo(X86Instruction.Pminud, IntrinsicType.Binary)); - Add(Intrinsic.X86Pminuw, new IntrinsicInfo(X86Instruction.Pminuw, IntrinsicType.Binary)); - Add(Intrinsic.X86Pmovsxbw, new IntrinsicInfo(X86Instruction.Pmovsxbw, IntrinsicType.Unary)); - Add(Intrinsic.X86Pmovsxdq, new IntrinsicInfo(X86Instruction.Pmovsxdq, IntrinsicType.Unary)); - Add(Intrinsic.X86Pmovsxwd, new IntrinsicInfo(X86Instruction.Pmovsxwd, IntrinsicType.Unary)); - Add(Intrinsic.X86Pmovzxbw, new IntrinsicInfo(X86Instruction.Pmovzxbw, IntrinsicType.Unary)); - Add(Intrinsic.X86Pmovzxdq, new IntrinsicInfo(X86Instruction.Pmovzxdq, IntrinsicType.Unary)); - Add(Intrinsic.X86Pmovzxwd, new IntrinsicInfo(X86Instruction.Pmovzxwd, IntrinsicType.Unary)); - Add(Intrinsic.X86Pmulld, new IntrinsicInfo(X86Instruction.Pmulld, IntrinsicType.Binary)); - Add(Intrinsic.X86Pmullw, new IntrinsicInfo(X86Instruction.Pmullw, IntrinsicType.Binary)); - Add(Intrinsic.X86Popcnt, new IntrinsicInfo(X86Instruction.Popcnt, IntrinsicType.PopCount)); - Add(Intrinsic.X86Por, new IntrinsicInfo(X86Instruction.Por, IntrinsicType.Binary)); - Add(Intrinsic.X86Pshufb, new IntrinsicInfo(X86Instruction.Pshufb, IntrinsicType.Binary)); - Add(Intrinsic.X86Pshufd, new IntrinsicInfo(X86Instruction.Pshufd, IntrinsicType.BinaryImm)); - Add(Intrinsic.X86Pslld, new IntrinsicInfo(X86Instruction.Pslld, IntrinsicType.Binary)); - Add(Intrinsic.X86Pslldq, new IntrinsicInfo(X86Instruction.Pslldq, IntrinsicType.Binary)); - Add(Intrinsic.X86Psllq, new IntrinsicInfo(X86Instruction.Psllq, IntrinsicType.Binary)); - Add(Intrinsic.X86Psllw, new IntrinsicInfo(X86Instruction.Psllw, IntrinsicType.Binary)); - Add(Intrinsic.X86Psrad, new IntrinsicInfo(X86Instruction.Psrad, IntrinsicType.Binary)); - Add(Intrinsic.X86Psraw, new IntrinsicInfo(X86Instruction.Psraw, IntrinsicType.Binary)); - Add(Intrinsic.X86Psrld, new IntrinsicInfo(X86Instruction.Psrld, IntrinsicType.Binary)); - Add(Intrinsic.X86Psrlq, new IntrinsicInfo(X86Instruction.Psrlq, IntrinsicType.Binary)); - Add(Intrinsic.X86Psrldq, new IntrinsicInfo(X86Instruction.Psrldq, IntrinsicType.Binary)); - Add(Intrinsic.X86Psrlw, new IntrinsicInfo(X86Instruction.Psrlw, IntrinsicType.Binary)); - Add(Intrinsic.X86Psubb, new IntrinsicInfo(X86Instruction.Psubb, IntrinsicType.Binary)); - Add(Intrinsic.X86Psubd, new IntrinsicInfo(X86Instruction.Psubd, IntrinsicType.Binary)); - Add(Intrinsic.X86Psubq, new IntrinsicInfo(X86Instruction.Psubq, IntrinsicType.Binary)); - Add(Intrinsic.X86Psubw, new IntrinsicInfo(X86Instruction.Psubw, IntrinsicType.Binary)); - Add(Intrinsic.X86Punpckhbw, new IntrinsicInfo(X86Instruction.Punpckhbw, IntrinsicType.Binary)); - Add(Intrinsic.X86Punpckhdq, new IntrinsicInfo(X86Instruction.Punpckhdq, IntrinsicType.Binary)); - Add(Intrinsic.X86Punpckhqdq, new IntrinsicInfo(X86Instruction.Punpckhqdq, IntrinsicType.Binary)); - Add(Intrinsic.X86Punpckhwd, new IntrinsicInfo(X86Instruction.Punpckhwd, IntrinsicType.Binary)); - Add(Intrinsic.X86Punpcklbw, new IntrinsicInfo(X86Instruction.Punpcklbw, IntrinsicType.Binary)); - Add(Intrinsic.X86Punpckldq, new IntrinsicInfo(X86Instruction.Punpckldq, IntrinsicType.Binary)); - Add(Intrinsic.X86Punpcklqdq, new IntrinsicInfo(X86Instruction.Punpcklqdq, IntrinsicType.Binary)); - Add(Intrinsic.X86Punpcklwd, new IntrinsicInfo(X86Instruction.Punpcklwd, IntrinsicType.Binary)); - Add(Intrinsic.X86Pxor, new IntrinsicInfo(X86Instruction.Pxor, IntrinsicType.Binary)); - Add(Intrinsic.X86Rcpps, new IntrinsicInfo(X86Instruction.Rcpps, IntrinsicType.Unary)); - Add(Intrinsic.X86Rcpss, new IntrinsicInfo(X86Instruction.Rcpss, IntrinsicType.Unary)); - Add(Intrinsic.X86Roundpd, new IntrinsicInfo(X86Instruction.Roundpd, IntrinsicType.BinaryImm)); - Add(Intrinsic.X86Roundps, new IntrinsicInfo(X86Instruction.Roundps, IntrinsicType.BinaryImm)); - Add(Intrinsic.X86Roundsd, new IntrinsicInfo(X86Instruction.Roundsd, IntrinsicType.BinaryImm)); - Add(Intrinsic.X86Roundss, new IntrinsicInfo(X86Instruction.Roundss, IntrinsicType.BinaryImm)); - Add(Intrinsic.X86Rsqrtps, new IntrinsicInfo(X86Instruction.Rsqrtps, IntrinsicType.Unary)); - Add(Intrinsic.X86Rsqrtss, new IntrinsicInfo(X86Instruction.Rsqrtss, IntrinsicType.Unary)); - Add(Intrinsic.X86Sha256Msg1, new IntrinsicInfo(X86Instruction.Sha256Msg1, IntrinsicType.Binary)); - Add(Intrinsic.X86Sha256Msg2, new IntrinsicInfo(X86Instruction.Sha256Msg2, IntrinsicType.Binary)); - Add(Intrinsic.X86Sha256Rnds2, new IntrinsicInfo(X86Instruction.Sha256Rnds2, IntrinsicType.Ternary)); - Add(Intrinsic.X86Shufpd, new IntrinsicInfo(X86Instruction.Shufpd, IntrinsicType.TernaryImm)); - Add(Intrinsic.X86Shufps, new IntrinsicInfo(X86Instruction.Shufps, IntrinsicType.TernaryImm)); - Add(Intrinsic.X86Sqrtpd, new IntrinsicInfo(X86Instruction.Sqrtpd, IntrinsicType.Unary)); - Add(Intrinsic.X86Sqrtps, new IntrinsicInfo(X86Instruction.Sqrtps, IntrinsicType.Unary)); - Add(Intrinsic.X86Sqrtsd, new IntrinsicInfo(X86Instruction.Sqrtsd, IntrinsicType.Unary)); - Add(Intrinsic.X86Sqrtss, new IntrinsicInfo(X86Instruction.Sqrtss, IntrinsicType.Unary)); - Add(Intrinsic.X86Subpd, new IntrinsicInfo(X86Instruction.Subpd, IntrinsicType.Binary)); - Add(Intrinsic.X86Subps, new IntrinsicInfo(X86Instruction.Subps, IntrinsicType.Binary)); - Add(Intrinsic.X86Subsd, new IntrinsicInfo(X86Instruction.Subsd, IntrinsicType.Binary)); - Add(Intrinsic.X86Subss, new IntrinsicInfo(X86Instruction.Subss, IntrinsicType.Binary)); - Add(Intrinsic.X86Unpckhpd, new IntrinsicInfo(X86Instruction.Unpckhpd, IntrinsicType.Binary)); - Add(Intrinsic.X86Unpckhps, new IntrinsicInfo(X86Instruction.Unpckhps, IntrinsicType.Binary)); - Add(Intrinsic.X86Unpcklpd, new IntrinsicInfo(X86Instruction.Unpcklpd, IntrinsicType.Binary)); - Add(Intrinsic.X86Unpcklps, new IntrinsicInfo(X86Instruction.Unpcklps, IntrinsicType.Binary)); - Add(Intrinsic.X86Vcvtph2ps, new IntrinsicInfo(X86Instruction.Vcvtph2ps, IntrinsicType.Unary)); - Add(Intrinsic.X86Vcvtps2ph, new IntrinsicInfo(X86Instruction.Vcvtps2ph, IntrinsicType.BinaryImm)); - Add(Intrinsic.X86Vfmadd231ps, new IntrinsicInfo(X86Instruction.Vfmadd231ps, IntrinsicType.Fma)); - Add(Intrinsic.X86Vfmadd231sd, new IntrinsicInfo(X86Instruction.Vfmadd231sd, IntrinsicType.Fma)); - Add(Intrinsic.X86Vfmadd231ss, new IntrinsicInfo(X86Instruction.Vfmadd231ss, IntrinsicType.Fma)); - Add(Intrinsic.X86Vfmsub231sd, new IntrinsicInfo(X86Instruction.Vfmsub231sd, IntrinsicType.Fma)); - Add(Intrinsic.X86Vfmsub231ss, new IntrinsicInfo(X86Instruction.Vfmsub231ss, IntrinsicType.Fma)); - Add(Intrinsic.X86Vfnmadd231ps, new IntrinsicInfo(X86Instruction.Vfnmadd231ps, IntrinsicType.Fma)); - Add(Intrinsic.X86Vfnmadd231sd, new IntrinsicInfo(X86Instruction.Vfnmadd231sd, IntrinsicType.Fma)); - Add(Intrinsic.X86Vfnmadd231ss, new IntrinsicInfo(X86Instruction.Vfnmadd231ss, IntrinsicType.Fma)); - Add(Intrinsic.X86Vfnmsub231sd, new IntrinsicInfo(X86Instruction.Vfnmsub231sd, IntrinsicType.Fma)); - Add(Intrinsic.X86Vfnmsub231ss, new IntrinsicInfo(X86Instruction.Vfnmsub231ss, IntrinsicType.Fma)); - Add(Intrinsic.X86Xorpd, new IntrinsicInfo(X86Instruction.Xorpd, IntrinsicType.Binary)); - Add(Intrinsic.X86Xorps, new IntrinsicInfo(X86Instruction.Xorps, IntrinsicType.Binary)); - } - - private static void Add(Intrinsic intrin, IntrinsicInfo info) - { - _intrinTable[(int)intrin] = info; - } - - public static IntrinsicInfo GetInfo(Intrinsic intrin) - { - return _intrinTable[(int)intrin]; - } - } -} \ No newline at end of file diff --git a/ARMeilleure/CodeGen/X86/IntrinsicType.cs b/ARMeilleure/CodeGen/X86/IntrinsicType.cs deleted file mode 100644 index 5a9c14afa..000000000 --- a/ARMeilleure/CodeGen/X86/IntrinsicType.cs +++ /dev/null @@ -1,18 +0,0 @@ -namespace ARMeilleure.CodeGen.X86 -{ - enum IntrinsicType - { - Comis_, - Mxcsr, - PopCount, - Unary, - UnaryToGpr, - Binary, - BinaryGpr, - BinaryImm, - Crc32, - Ternary, - TernaryImm, - Fma - } -} \ No newline at end of file diff --git a/ARMeilleure/CodeGen/X86/PreAllocator.cs b/ARMeilleure/CodeGen/X86/PreAllocator.cs deleted file mode 100644 index dd73a1dd0..000000000 --- a/ARMeilleure/CodeGen/X86/PreAllocator.cs +++ /dev/null @@ -1,1402 +0,0 @@ -using ARMeilleure.CodeGen.RegisterAllocators; -using ARMeilleure.IntermediateRepresentation; -using ARMeilleure.Translation; -using System; -using System.Collections.Generic; -using System.Diagnostics; -using static ARMeilleure.IntermediateRepresentation.Operand.Factory; -using static ARMeilleure.IntermediateRepresentation.Operation.Factory; - -namespace ARMeilleure.CodeGen.X86 -{ - static class PreAllocator - { - public static void RunPass(CompilerContext cctx, StackAllocator stackAlloc, out int maxCallArgs) - { - maxCallArgs = -1; - - CallConvName callConv = CallingConvention.GetCurrentCallConv(); - - Operand[] preservedArgs = new Operand[CallingConvention.GetArgumentsOnRegsCount()]; - - for (BasicBlock block = cctx.Cfg.Blocks.First; block != null; block = block.ListNext) - { - Operation nextNode; - - for (Operation node = block.Operations.First; node != default; node = nextNode) - { - nextNode = node.ListNext; - - if (node.Instruction == Instruction.Phi) - { - continue; - } - - HandleConstantRegCopy(block.Operations, node); - HandleDestructiveRegCopy(block.Operations, node); - HandleConstrainedRegCopy(block.Operations, node); - - switch (node.Instruction) - { - case Instruction.Call: - // Get the maximum number of arguments used on a call. - // On windows, when a struct is returned from the call, - // we also need to pass the pointer where the struct - // should be written on the first argument. - int argsCount = node.SourcesCount - 1; - - if (node.Destination != default && node.Destination.Type == OperandType.V128) - { - argsCount++; - } - - if (maxCallArgs < argsCount) - { - maxCallArgs = argsCount; - } - - // Copy values to registers expected by the function - // being called, as mandated by the ABI. - if (callConv == CallConvName.Windows) - { - HandleCallWindowsAbi(block.Operations, stackAlloc, node); - } - else /* if (callConv == CallConvName.SystemV) */ - { - HandleCallSystemVAbi(block.Operations, node); - } - break; - - case Instruction.ConvertToFPUI: - HandleConvertToFPUI(block.Operations, node); - break; - - case Instruction.LoadArgument: - if (callConv == CallConvName.Windows) - { - nextNode = HandleLoadArgumentWindowsAbi(cctx, block.Operations, preservedArgs, node); - } - else /* if (callConv == CallConvName.SystemV) */ - { - nextNode = HandleLoadArgumentSystemVAbi(cctx, block.Operations, preservedArgs, node); - } - break; - - case Instruction.Negate: - if (!node.GetSource(0).Type.IsInteger()) - { - HandleNegate(block.Operations, node); - } - break; - - case Instruction.Return: - if (callConv == CallConvName.Windows) - { - HandleReturnWindowsAbi(cctx, block.Operations, preservedArgs, node); - } - else /* if (callConv == CallConvName.SystemV) */ - { - HandleReturnSystemVAbi(block.Operations, node); - } - break; - - case Instruction.Tailcall: - if (callConv == CallConvName.Windows) - { - HandleTailcallWindowsAbi(block.Operations, stackAlloc, node); - } - else - { - HandleTailcallSystemVAbi(block.Operations, stackAlloc, node); - } - break; - - case Instruction.VectorInsert8: - if (!HardwareCapabilities.SupportsSse41) - { - HandleVectorInsert8(block.Operations, node); - } - break; - - case Instruction.Extended: - if (node.Intrinsic == Intrinsic.X86Mxcsrmb || node.Intrinsic == Intrinsic.X86Mxcsrub) - { - int stackOffset = stackAlloc.Allocate(OperandType.I32); - - node.SetSources(new Operand[] { Const(stackOffset), node.GetSource(0) }); - } - break; - } - } - } - } - - private static void HandleConstantRegCopy(IntrusiveList nodes, Operation node) - { - if (node.SourcesCount == 0 || IsXmmIntrinsic(node)) - { - return; - } - - Instruction inst = node.Instruction; - - Operand src1 = node.GetSource(0); - Operand src2; - - if (src1.Kind == OperandKind.Constant) - { - if (!src1.Type.IsInteger()) - { - // Handle non-integer types (FP32, FP64 and V128). - // For instructions without an immediate operand, we do the following: - // - Insert a copy with the constant value (as integer) to a GPR. - // - Insert a copy from the GPR to a XMM register. - // - Replace the constant use with the XMM register. - src1 = AddXmmCopy(nodes, node, src1); - - node.SetSource(0, src1); - } - else if (!HasConstSrc1(inst)) - { - // Handle integer types. - // Most ALU instructions accepts a 32-bits immediate on the second operand. - // We need to ensure the following: - // - If the constant is on operand 1, we need to move it. - // -- But first, we try to swap operand 1 and 2 if the instruction is commutative. - // -- Doing so may allow us to encode the constant as operand 2 and avoid a copy. - // - If the constant is on operand 2, we check if the instruction supports it, - // if not, we also add a copy. 64-bits constants are usually not supported. - if (IsCommutative(node)) - { - src2 = node.GetSource(1); - - Operand temp = src1; - - src1 = src2; - src2 = temp; - - node.SetSource(0, src1); - node.SetSource(1, src2); - } - - if (src1.Kind == OperandKind.Constant) - { - src1 = AddCopy(nodes, node, src1); - - node.SetSource(0, src1); - } - } - } - - if (node.SourcesCount < 2) - { - return; - } - - src2 = node.GetSource(1); - - if (src2.Kind == OperandKind.Constant) - { - if (!src2.Type.IsInteger()) - { - src2 = AddXmmCopy(nodes, node, src2); - - node.SetSource(1, src2); - } - else if (!HasConstSrc2(inst) || CodeGenCommon.IsLongConst(src2)) - { - src2 = AddCopy(nodes, node, src2); - - node.SetSource(1, src2); - } - } - } - - private static void HandleConstrainedRegCopy(IntrusiveList nodes, Operation node) - { - Operand dest = node.Destination; - - switch (node.Instruction) - { - case Instruction.CompareAndSwap: - case Instruction.CompareAndSwap16: - case Instruction.CompareAndSwap8: - { - OperandType type = node.GetSource(1).Type; - - if (type == OperandType.V128) - { - // Handle the many restrictions of the compare and exchange (16 bytes) instruction: - // - The expected value should be in RDX:RAX. - // - The new value to be written should be in RCX:RBX. - // - The value at the memory location is loaded to RDX:RAX. - void SplitOperand(Operand source, Operand lr, Operand hr) - { - nodes.AddBefore(node, Operation(Instruction.VectorExtract, lr, source, Const(0))); - nodes.AddBefore(node, Operation(Instruction.VectorExtract, hr, source, Const(1))); - } - - Operand rax = Gpr(X86Register.Rax, OperandType.I64); - Operand rbx = Gpr(X86Register.Rbx, OperandType.I64); - Operand rcx = Gpr(X86Register.Rcx, OperandType.I64); - Operand rdx = Gpr(X86Register.Rdx, OperandType.I64); - - SplitOperand(node.GetSource(1), rax, rdx); - SplitOperand(node.GetSource(2), rbx, rcx); - - Operation operation = node; - - node = nodes.AddAfter(node, Operation(Instruction.VectorCreateScalar, dest, rax)); - nodes.AddAfter(node, Operation(Instruction.VectorInsert, dest, dest, rdx, Const(1))); - - operation.SetDestinations(new Operand[] { rdx, rax }); - operation.SetSources(new Operand[] { operation.GetSource(0), rdx, rax, rcx, rbx }); - } - else - { - // Handle the many restrictions of the compare and exchange (32/64) instruction: - // - The expected value should be in (E/R)AX. - // - The value at the memory location is loaded to (E/R)AX. - Operand expected = node.GetSource(1); - Operand newValue = node.GetSource(2); - - Operand rax = Gpr(X86Register.Rax, expected.Type); - - nodes.AddBefore(node, Operation(Instruction.Copy, rax, expected)); - - // We need to store the new value into a temp, since it may - // be a constant, and this instruction does not support immediate operands. - Operand temp = Local(newValue.Type); - - nodes.AddBefore(node, Operation(Instruction.Copy, temp, newValue)); - - node.SetSources(new Operand[] { node.GetSource(0), rax, temp }); - - nodes.AddAfter(node, Operation(Instruction.Copy, dest, rax)); - - node.Destination = rax; - } - - break; - } - - case Instruction.Divide: - case Instruction.DivideUI: - { - // Handle the many restrictions of the division instructions: - // - The dividend is always in RDX:RAX. - // - The result is always in RAX. - // - Additionally it also writes the remainder in RDX. - if (dest.Type.IsInteger()) - { - Operand src1 = node.GetSource(0); - - Operand rax = Gpr(X86Register.Rax, src1.Type); - Operand rdx = Gpr(X86Register.Rdx, src1.Type); - - nodes.AddBefore(node, Operation(Instruction.Copy, rax, src1)); - nodes.AddBefore(node, Operation(Instruction.Clobber, rdx)); - - nodes.AddAfter(node, Operation(Instruction.Copy, dest, rax)); - - node.SetSources(new Operand[] { rdx, rax, node.GetSource(1) }); - node.Destination = rax; - } - - break; - } - - case Instruction.Extended: - { - bool isBlend = node.Intrinsic == Intrinsic.X86Blendvpd || - node.Intrinsic == Intrinsic.X86Blendvps || - node.Intrinsic == Intrinsic.X86Pblendvb; - - // BLENDVPD, BLENDVPS, PBLENDVB last operand is always implied to be XMM0 when VEX is not supported. - // SHA256RNDS2 always has an implied XMM0 as a last operand. - if ((isBlend && !HardwareCapabilities.SupportsVexEncoding) || node.Intrinsic == Intrinsic.X86Sha256Rnds2) - { - Operand xmm0 = Xmm(X86Register.Xmm0, OperandType.V128); - - nodes.AddBefore(node, Operation(Instruction.Copy, xmm0, node.GetSource(2))); - - node.SetSource(2, xmm0); - } - - break; - } - - case Instruction.Multiply64HighSI: - case Instruction.Multiply64HighUI: - { - // Handle the many restrictions of the i64 * i64 = i128 multiply instructions: - // - The multiplicand is always in RAX. - // - The lower 64-bits of the result is always in RAX. - // - The higher 64-bits of the result is always in RDX. - Operand src1 = node.GetSource(0); - - Operand rax = Gpr(X86Register.Rax, src1.Type); - Operand rdx = Gpr(X86Register.Rdx, src1.Type); - - nodes.AddBefore(node, Operation(Instruction.Copy, rax, src1)); - - node.SetSource(0, rax); - - nodes.AddAfter(node, Operation(Instruction.Copy, dest, rdx)); - - node.SetDestinations(new Operand[] { rdx, rax }); - - break; - } - - case Instruction.RotateRight: - case Instruction.ShiftLeft: - case Instruction.ShiftRightSI: - case Instruction.ShiftRightUI: - { - // The shift register is always implied to be CL (low 8-bits of RCX or ECX). - if (node.GetSource(1).Kind == OperandKind.LocalVariable) - { - Operand rcx = Gpr(X86Register.Rcx, OperandType.I32); - - nodes.AddBefore(node, Operation(Instruction.Copy, rcx, node.GetSource(1))); - - node.SetSource(1, rcx); - } - - break; - } - } - } - - private static void HandleDestructiveRegCopy(IntrusiveList nodes, Operation node) - { - if (node.Destination == default || node.SourcesCount == 0) - { - return; - } - - Instruction inst = node.Instruction; - - Operand dest = node.Destination; - Operand src1 = node.GetSource(0); - - // The multiply instruction (that maps to IMUL) is somewhat special, it has - // a three operand form where the second source is a immediate value. - bool threeOperandForm = inst == Instruction.Multiply && node.GetSource(1).Kind == OperandKind.Constant; - - if (IsSameOperandDestSrc1(node) && src1.Kind == OperandKind.LocalVariable && !threeOperandForm) - { - bool useNewLocal = false; - - for (int srcIndex = 1; srcIndex < node.SourcesCount; srcIndex++) - { - if (node.GetSource(srcIndex) == dest) - { - useNewLocal = true; - - break; - } - } - - if (useNewLocal) - { - // Dest is being used as some source already, we need to use a new - // local to store the temporary value, otherwise the value on dest - // local would be overwritten. - Operand temp = Local(dest.Type); - - nodes.AddBefore(node, Operation(Instruction.Copy, temp, src1)); - - node.SetSource(0, temp); - - nodes.AddAfter(node, Operation(Instruction.Copy, dest, temp)); - - node.Destination = temp; - } - else - { - nodes.AddBefore(node, Operation(Instruction.Copy, dest, src1)); - - node.SetSource(0, dest); - } - } - else if (inst == Instruction.ConditionalSelect) - { - Operand src2 = node.GetSource(1); - Operand src3 = node.GetSource(2); - - if (src1 == dest || src2 == dest) - { - Operand temp = Local(dest.Type); - - nodes.AddBefore(node, Operation(Instruction.Copy, temp, src3)); - - node.SetSource(2, temp); - - nodes.AddAfter(node, Operation(Instruction.Copy, dest, temp)); - - node.Destination = temp; - } - else - { - nodes.AddBefore(node, Operation(Instruction.Copy, dest, src3)); - - node.SetSource(2, dest); - } - } - } - - private static void HandleConvertToFPUI(IntrusiveList nodes, Operation node) - { - // Unsigned integer to FP conversions are not supported on X86. - // We need to turn them into signed integer to FP conversions, and - // adjust the final result. - Operand dest = node.Destination; - Operand source = node.GetSource(0); - - Debug.Assert(source.Type.IsInteger(), $"Invalid source type \"{source.Type}\"."); - - Operation currentNode = node; - - if (source.Type == OperandType.I32) - { - // For 32-bits integers, we can just zero-extend to 64-bits, - // and then use the 64-bits signed conversion instructions. - Operand zex = Local(OperandType.I64); - - node = nodes.AddAfter(node, Operation(Instruction.ZeroExtend32, zex, source)); - node = nodes.AddAfter(node, Operation(Instruction.ConvertToFP, dest, zex)); - } - else /* if (source.Type == OperandType.I64) */ - { - // For 64-bits integers, we need to do the following: - // - Ensure that the integer has the most significant bit clear. - // -- This can be done by shifting the value right by 1, that is, dividing by 2. - // -- The least significant bit is lost in this case though. - // - We can then convert the shifted value with a signed integer instruction. - // - The result still needs to be corrected after that. - // -- First, we need to multiply the result by 2, as we divided it by 2 before. - // --- This can be done efficiently by adding the result to itself. - // -- Then, we need to add the least significant bit that was shifted out. - // --- We can convert the least significant bit to float, and add it to the result. - Operand lsb = Local(OperandType.I64); - Operand half = Local(OperandType.I64); - - Operand lsbF = Local(dest.Type); - - node = nodes.AddAfter(node, Operation(Instruction.Copy, lsb, source)); - node = nodes.AddAfter(node, Operation(Instruction.Copy, half, source)); - - node = nodes.AddAfter(node, Operation(Instruction.BitwiseAnd, lsb, lsb, Const(1L))); - node = nodes.AddAfter(node, Operation(Instruction.ShiftRightUI, half, half, Const(1))); - - node = nodes.AddAfter(node, Operation(Instruction.ConvertToFP, lsbF, lsb)); - node = nodes.AddAfter(node, Operation(Instruction.ConvertToFP, dest, half)); - - node = nodes.AddAfter(node, Operation(Instruction.Add, dest, dest, dest)); - nodes.AddAfter(node, Operation(Instruction.Add, dest, dest, lsbF)); - } - - Delete(nodes, currentNode); - } - - private static void HandleNegate(IntrusiveList nodes, Operation node) - { - // There's no SSE FP negate instruction, so we need to transform that into - // a XOR of the value to be negated with a mask with the highest bit set. - // This also produces -0 for a negation of the value 0. - Operand dest = node.Destination; - Operand source = node.GetSource(0); - - Debug.Assert(dest.Type == OperandType.FP32 || - dest.Type == OperandType.FP64, $"Invalid destination type \"{dest.Type}\"."); - - Operation currentNode = node; - - Operand res = Local(dest.Type); - - node = nodes.AddAfter(node, Operation(Instruction.VectorOne, res)); - - if (dest.Type == OperandType.FP32) - { - node = nodes.AddAfter(node, Operation(Intrinsic.X86Pslld, res, res, Const(31))); - } - else /* if (dest.Type == OperandType.FP64) */ - { - node = nodes.AddAfter(node, Operation(Intrinsic.X86Psllq, res, res, Const(63))); - } - - node = nodes.AddAfter(node, Operation(Intrinsic.X86Xorps, res, res, source)); - - nodes.AddAfter(node, Operation(Instruction.Copy, dest, res)); - - Delete(nodes, currentNode); - } - - private static void HandleVectorInsert8(IntrusiveList nodes, Operation node) - { - // Handle vector insertion, when SSE 4.1 is not supported. - Operand dest = node.Destination; - Operand src1 = node.GetSource(0); // Vector - Operand src2 = node.GetSource(1); // Value - Operand src3 = node.GetSource(2); // Index - - Debug.Assert(src3.Kind == OperandKind.Constant); - - byte index = src3.AsByte(); - - Debug.Assert(index < 16); - - Operation currentNode = node; - - Operand temp1 = Local(OperandType.I32); - Operand temp2 = Local(OperandType.I32); - - node = nodes.AddAfter(node, Operation(Instruction.Copy, temp2, src2)); - - Operation vextOp = Operation(Instruction.VectorExtract16, temp1, src1, Const(index >> 1)); - - node = nodes.AddAfter(node, vextOp); - - if ((index & 1) != 0) - { - node = nodes.AddAfter(node, Operation(Instruction.ZeroExtend8, temp1, temp1)); - node = nodes.AddAfter(node, Operation(Instruction.ShiftLeft, temp2, temp2, Const(8))); - node = nodes.AddAfter(node, Operation(Instruction.BitwiseOr, temp1, temp1, temp2)); - } - else - { - node = nodes.AddAfter(node, Operation(Instruction.ZeroExtend8, temp2, temp2)); - node = nodes.AddAfter(node, Operation(Instruction.BitwiseAnd, temp1, temp1, Const(0xff00))); - node = nodes.AddAfter(node, Operation(Instruction.BitwiseOr, temp1, temp1, temp2)); - } - - Operation vinsOp = Operation(Instruction.VectorInsert16, dest, src1, temp1, Const(index >> 1)); - - nodes.AddAfter(node, vinsOp); - - Delete(nodes, currentNode); - } - - private static void HandleCallWindowsAbi(IntrusiveList nodes, StackAllocator stackAlloc, Operation node) - { - Operand dest = node.Destination; - - // Handle struct arguments. - int retArgs = 0; - int stackAllocOffset = 0; - - int AllocateOnStack(int size) - { - // We assume that the stack allocator is initially empty (TotalSize = 0). - // Taking that into account, we can reuse the space allocated for other - // calls by keeping track of our own allocated size (stackAllocOffset). - // If the space allocated is not big enough, then we just expand it. - int offset = stackAllocOffset; - - if (stackAllocOffset + size > stackAlloc.TotalSize) - { - stackAlloc.Allocate((stackAllocOffset + size) - stackAlloc.TotalSize); - } - - stackAllocOffset += size; - - return offset; - } - - Operand arg0Reg = default; - - if (dest != default && dest.Type == OperandType.V128) - { - int stackOffset = AllocateOnStack(dest.Type.GetSizeInBytes()); - - arg0Reg = Gpr(CallingConvention.GetIntArgumentRegister(0), OperandType.I64); - - Operation allocOp = Operation(Instruction.StackAlloc, arg0Reg, Const(stackOffset)); - - nodes.AddBefore(node, allocOp); - - retArgs = 1; - } - - int argsCount = node.SourcesCount - 1; - int maxArgs = CallingConvention.GetArgumentsOnRegsCount() - retArgs; - - if (argsCount > maxArgs) - { - argsCount = maxArgs; - } - - Operand[] sources = new Operand[1 + retArgs + argsCount]; - - sources[0] = node.GetSource(0); - - if (arg0Reg != default) - { - sources[1] = arg0Reg; - } - - for (int index = 1; index < node.SourcesCount; index++) - { - Operand source = node.GetSource(index); - - if (source.Type == OperandType.V128) - { - Operand stackAddr = Local(OperandType.I64); - - int stackOffset = AllocateOnStack(source.Type.GetSizeInBytes()); - - nodes.AddBefore(node, Operation(Instruction.StackAlloc, stackAddr, Const(stackOffset))); - - Operation storeOp = Operation(Instruction.Store, default, stackAddr, source); - - HandleConstantRegCopy(nodes, nodes.AddBefore(node, storeOp)); - - node.SetSource(index, stackAddr); - } - } - - // Handle arguments passed on registers. - for (int index = 0; index < argsCount; index++) - { - Operand source = node.GetSource(index + 1); - Operand argReg; - - int argIndex = index + retArgs; - - if (source.Type.IsInteger()) - { - argReg = Gpr(CallingConvention.GetIntArgumentRegister(argIndex), source.Type); - } - else - { - argReg = Xmm(CallingConvention.GetVecArgumentRegister(argIndex), source.Type); - } - - Operation copyOp = Operation(Instruction.Copy, argReg, source); - - HandleConstantRegCopy(nodes, nodes.AddBefore(node, copyOp)); - - sources[1 + retArgs + index] = argReg; - } - - // The remaining arguments (those that are not passed on registers) - // should be passed on the stack, we write them to the stack with "SpillArg". - for (int index = argsCount; index < node.SourcesCount - 1; index++) - { - Operand source = node.GetSource(index + 1); - Operand offset = Const((index + retArgs) * 8); - - Operation spillOp = Operation(Instruction.SpillArg, default, offset, source); - - HandleConstantRegCopy(nodes, nodes.AddBefore(node, spillOp)); - } - - if (dest != default) - { - if (dest.Type == OperandType.V128) - { - Operand retValueAddr = Local(OperandType.I64); - - nodes.AddBefore(node, Operation(Instruction.Copy, retValueAddr, arg0Reg)); - - Operation loadOp = Operation(Instruction.Load, dest, retValueAddr); - - nodes.AddAfter(node, loadOp); - - node.Destination = default; - } - else - { - Operand retReg = dest.Type.IsInteger() - ? Gpr(CallingConvention.GetIntReturnRegister(), dest.Type) - : Xmm(CallingConvention.GetVecReturnRegister(), dest.Type); - - Operation copyOp = Operation(Instruction.Copy, dest, retReg); - - nodes.AddAfter(node, copyOp); - - node.Destination = retReg; - } - } - - node.SetSources(sources); - } - - private static void HandleCallSystemVAbi(IntrusiveList nodes, Operation node) - { - Operand dest = node.Destination; - - List sources = new List - { - node.GetSource(0) - }; - - int argsCount = node.SourcesCount - 1; - - int intMax = CallingConvention.GetIntArgumentsOnRegsCount(); - int vecMax = CallingConvention.GetVecArgumentsOnRegsCount(); - - int intCount = 0; - int vecCount = 0; - - int stackOffset = 0; - - for (int index = 0; index < argsCount; index++) - { - Operand source = node.GetSource(index + 1); - - bool passOnReg; - - if (source.Type.IsInteger()) - { - passOnReg = intCount < intMax; - } - else if (source.Type == OperandType.V128) - { - passOnReg = intCount + 1 < intMax; - } - else - { - passOnReg = vecCount < vecMax; - } - - if (source.Type == OperandType.V128 && passOnReg) - { - // V128 is a struct, we pass each half on a GPR if possible. - Operand argReg = Gpr(CallingConvention.GetIntArgumentRegister(intCount++), OperandType.I64); - Operand argReg2 = Gpr(CallingConvention.GetIntArgumentRegister(intCount++), OperandType.I64); - - nodes.AddBefore(node, Operation(Instruction.VectorExtract, argReg, source, Const(0))); - nodes.AddBefore(node, Operation(Instruction.VectorExtract, argReg2, source, Const(1))); - - continue; - } - - if (passOnReg) - { - Operand argReg = source.Type.IsInteger() - ? Gpr(CallingConvention.GetIntArgumentRegister(intCount++), source.Type) - : Xmm(CallingConvention.GetVecArgumentRegister(vecCount++), source.Type); - - Operation copyOp = Operation(Instruction.Copy, argReg, source); - - HandleConstantRegCopy(nodes, nodes.AddBefore(node, copyOp)); - - sources.Add(argReg); - } - else - { - Operand offset = Const(stackOffset); - - Operation spillOp = Operation(Instruction.SpillArg, default, offset, source); - - HandleConstantRegCopy(nodes, nodes.AddBefore(node, spillOp)); - - stackOffset += source.Type.GetSizeInBytes(); - } - } - - node.SetSources(sources.ToArray()); - - if (dest != default) - { - if (dest.Type == OperandType.V128) - { - Operand retLReg = Gpr(CallingConvention.GetIntReturnRegister(), OperandType.I64); - Operand retHReg = Gpr(CallingConvention.GetIntReturnRegisterHigh(), OperandType.I64); - - Operation operation = node; - - node = nodes.AddAfter(node, Operation(Instruction.VectorCreateScalar, dest, retLReg)); - nodes.AddAfter(node, Operation(Instruction.VectorInsert, dest, dest, retHReg, Const(1))); - - operation.Destination = default; - } - else - { - Operand retReg = dest.Type.IsInteger() - ? Gpr(CallingConvention.GetIntReturnRegister(), dest.Type) - : Xmm(CallingConvention.GetVecReturnRegister(), dest.Type); - - Operation copyOp = Operation(Instruction.Copy, dest, retReg); - - nodes.AddAfter(node, copyOp); - - node.Destination = retReg; - } - } - } - - private static void HandleTailcallSystemVAbi(IntrusiveList nodes, StackAllocator stackAlloc, Operation node) - { - List sources = new List - { - node.GetSource(0) - }; - - int argsCount = node.SourcesCount - 1; - - int intMax = CallingConvention.GetIntArgumentsOnRegsCount(); - int vecMax = CallingConvention.GetVecArgumentsOnRegsCount(); - - int intCount = 0; - int vecCount = 0; - - // Handle arguments passed on registers. - for (int index = 0; index < argsCount; index++) - { - Operand source = node.GetSource(1 + index); - - bool passOnReg; - - if (source.Type.IsInteger()) - { - passOnReg = intCount + 1 < intMax; - } - else - { - passOnReg = vecCount < vecMax; - } - - if (source.Type == OperandType.V128 && passOnReg) - { - // V128 is a struct, we pass each half on a GPR if possible. - Operand argReg = Gpr(CallingConvention.GetIntArgumentRegister(intCount++), OperandType.I64); - Operand argReg2 = Gpr(CallingConvention.GetIntArgumentRegister(intCount++), OperandType.I64); - - nodes.AddBefore(node, Operation(Instruction.VectorExtract, argReg, source, Const(0))); - nodes.AddBefore(node, Operation(Instruction.VectorExtract, argReg2, source, Const(1))); - - continue; - } - - if (passOnReg) - { - Operand argReg = source.Type.IsInteger() - ? Gpr(CallingConvention.GetIntArgumentRegister(intCount++), source.Type) - : Xmm(CallingConvention.GetVecArgumentRegister(vecCount++), source.Type); - - Operation copyOp = Operation(Instruction.Copy, argReg, source); - - HandleConstantRegCopy(nodes, nodes.AddBefore(node, copyOp)); - - sources.Add(argReg); - } - else - { - throw new NotImplementedException("Spilling is not currently supported for tail calls. (too many arguments)"); - } - } - - // The target address must be on the return registers, since we - // don't return anything and it is guaranteed to not be a - // callee saved register (which would be trashed on the epilogue). - Operand retReg = Gpr(CallingConvention.GetIntReturnRegister(), OperandType.I64); - - Operation addrCopyOp = Operation(Instruction.Copy, retReg, node.GetSource(0)); - - nodes.AddBefore(node, addrCopyOp); - - sources[0] = retReg; - - node.SetSources(sources.ToArray()); - } - - private static void HandleTailcallWindowsAbi(IntrusiveList nodes, StackAllocator stackAlloc, Operation node) - { - int argsCount = node.SourcesCount - 1; - int maxArgs = CallingConvention.GetArgumentsOnRegsCount(); - - if (argsCount > maxArgs) - { - throw new NotImplementedException("Spilling is not currently supported for tail calls. (too many arguments)"); - } - - Operand[] sources = new Operand[1 + argsCount]; - - // Handle arguments passed on registers. - for (int index = 0; index < argsCount; index++) - { - Operand source = node.GetSource(1 + index); - Operand argReg = source.Type.IsInteger() - ? Gpr(CallingConvention.GetIntArgumentRegister(index), source.Type) - : Xmm(CallingConvention.GetVecArgumentRegister(index), source.Type); - - Operation copyOp = Operation(Instruction.Copy, argReg, source); - - HandleConstantRegCopy(nodes, nodes.AddBefore(node, copyOp)); - - sources[1 + index] = argReg; - } - - // The target address must be on the return registers, since we - // don't return anything and it is guaranteed to not be a - // callee saved register (which would be trashed on the epilogue). - Operand retReg = Gpr(CallingConvention.GetIntReturnRegister(), OperandType.I64); - - Operation addrCopyOp = Operation(Instruction.Copy, retReg, node.GetSource(0)); - - nodes.AddBefore(node, addrCopyOp); - - sources[0] = retReg; - - node.SetSources(sources); - } - - private static Operation HandleLoadArgumentWindowsAbi( - CompilerContext cctx, - IntrusiveList nodes, - Operand[] preservedArgs, - Operation node) - { - Operand source = node.GetSource(0); - - Debug.Assert(source.Kind == OperandKind.Constant, "Non-constant LoadArgument source kind."); - - int retArgs = cctx.FuncReturnType == OperandType.V128 ? 1 : 0; - - int index = source.AsInt32() + retArgs; - - if (index < CallingConvention.GetArgumentsOnRegsCount()) - { - Operand dest = node.Destination; - - if (preservedArgs[index] == default) - { - Operand argReg, pArg; - - if (dest.Type.IsInteger()) - { - argReg = Gpr(CallingConvention.GetIntArgumentRegister(index), dest.Type); - pArg = Local(dest.Type); - } - else if (dest.Type == OperandType.V128) - { - argReg = Gpr(CallingConvention.GetIntArgumentRegister(index), OperandType.I64); - pArg = Local(OperandType.I64); - } - else - { - argReg = Xmm(CallingConvention.GetVecArgumentRegister(index), dest.Type); - pArg = Local(dest.Type); - } - - Operation copyOp = Operation(Instruction.Copy, pArg, argReg); - - cctx.Cfg.Entry.Operations.AddFirst(copyOp); - - preservedArgs[index] = pArg; - } - - Operation argCopyOp = Operation(dest.Type == OperandType.V128 - ? Instruction.Load - : Instruction.Copy, dest, preservedArgs[index]); - - Operation newNode = nodes.AddBefore(node, argCopyOp); - - Delete(nodes, node); - - return newNode; - } - else - { - // TODO: Pass on stack. - return node; - } - } - - private static Operation HandleLoadArgumentSystemVAbi( - CompilerContext cctx, - IntrusiveList nodes, - Operand[] preservedArgs, - Operation node) - { - Operand source = node.GetSource(0); - - Debug.Assert(source.Kind == OperandKind.Constant, "Non-constant LoadArgument source kind."); - - int index = source.AsInt32(); - - int intCount = 0; - int vecCount = 0; - - for (int cIndex = 0; cIndex < index; cIndex++) - { - OperandType argType = cctx.FuncArgTypes[cIndex]; - - if (argType.IsInteger()) - { - intCount++; - } - else if (argType == OperandType.V128) - { - intCount += 2; - } - else - { - vecCount++; - } - } - - bool passOnReg; - - if (source.Type.IsInteger()) - { - passOnReg = intCount < CallingConvention.GetIntArgumentsOnRegsCount(); - } - else if (source.Type == OperandType.V128) - { - passOnReg = intCount + 1 < CallingConvention.GetIntArgumentsOnRegsCount(); - } - else - { - passOnReg = vecCount < CallingConvention.GetVecArgumentsOnRegsCount(); - } - - if (passOnReg) - { - Operand dest = node.Destination; - - if (preservedArgs[index] == default) - { - if (dest.Type == OperandType.V128) - { - // V128 is a struct, we pass each half on a GPR if possible. - Operand pArg = Local(OperandType.V128); - - Operand argLReg = Gpr(CallingConvention.GetIntArgumentRegister(intCount), OperandType.I64); - Operand argHReg = Gpr(CallingConvention.GetIntArgumentRegister(intCount + 1), OperandType.I64); - - Operation copyL = Operation(Instruction.VectorCreateScalar, pArg, argLReg); - Operation copyH = Operation(Instruction.VectorInsert, pArg, pArg, argHReg, Const(1)); - - cctx.Cfg.Entry.Operations.AddFirst(copyH); - cctx.Cfg.Entry.Operations.AddFirst(copyL); - - preservedArgs[index] = pArg; - } - else - { - Operand pArg = Local(dest.Type); - - Operand argReg = dest.Type.IsInteger() - ? Gpr(CallingConvention.GetIntArgumentRegister(intCount), dest.Type) - : Xmm(CallingConvention.GetVecArgumentRegister(vecCount), dest.Type); - - Operation copyOp = Operation(Instruction.Copy, pArg, argReg); - - cctx.Cfg.Entry.Operations.AddFirst(copyOp); - - preservedArgs[index] = pArg; - } - } - - Operation argCopyOp = Operation(Instruction.Copy, dest, preservedArgs[index]); - - Operation newNode = nodes.AddBefore(node, argCopyOp); - - Delete(nodes, node); - - return newNode; - } - else - { - // TODO: Pass on stack. - return node; - } - } - - private static void HandleReturnWindowsAbi( - CompilerContext cctx, - IntrusiveList nodes, - Operand[] preservedArgs, - Operation node) - { - if (node.SourcesCount == 0) - { - return; - } - - Operand source = node.GetSource(0); - Operand retReg; - - if (source.Type.IsInteger()) - { - retReg = Gpr(CallingConvention.GetIntReturnRegister(), source.Type); - } - else if (source.Type == OperandType.V128) - { - if (preservedArgs[0] == default) - { - Operand preservedArg = Local(OperandType.I64); - Operand arg0 = Gpr(CallingConvention.GetIntArgumentRegister(0), OperandType.I64); - - Operation copyOp = Operation(Instruction.Copy, preservedArg, arg0); - - cctx.Cfg.Entry.Operations.AddFirst(copyOp); - - preservedArgs[0] = preservedArg; - } - - retReg = preservedArgs[0]; - } - else - { - retReg = Xmm(CallingConvention.GetVecReturnRegister(), source.Type); - } - - if (source.Type == OperandType.V128) - { - Operation retStoreOp = Operation(Instruction.Store, default, retReg, source); - - nodes.AddBefore(node, retStoreOp); - } - else - { - Operation retCopyOp = Operation(Instruction.Copy, retReg, source); - - nodes.AddBefore(node, retCopyOp); - } - - node.SetSources(Array.Empty()); - } - - private static void HandleReturnSystemVAbi(IntrusiveList nodes, Operation node) - { - if (node.SourcesCount == 0) - { - return; - } - - Operand source = node.GetSource(0); - - if (source.Type == OperandType.V128) - { - Operand retLReg = Gpr(CallingConvention.GetIntReturnRegister(), OperandType.I64); - Operand retHReg = Gpr(CallingConvention.GetIntReturnRegisterHigh(), OperandType.I64); - - nodes.AddBefore(node, Operation(Instruction.VectorExtract, retLReg, source, Const(0))); - nodes.AddBefore(node, Operation(Instruction.VectorExtract, retHReg, source, Const(1))); - } - else - { - Operand retReg = source.Type.IsInteger() - ? Gpr(CallingConvention.GetIntReturnRegister(), source.Type) - : Xmm(CallingConvention.GetVecReturnRegister(), source.Type); - - Operation retCopyOp = Operation(Instruction.Copy, retReg, source); - - nodes.AddBefore(node, retCopyOp); - } - } - - private static Operand AddXmmCopy(IntrusiveList nodes, Operation node, Operand source) - { - Operand temp = Local(source.Type); - Operand intConst = AddCopy(nodes, node, GetIntConst(source)); - - Operation copyOp = Operation(Instruction.VectorCreateScalar, temp, intConst); - - nodes.AddBefore(node, copyOp); - - return temp; - } - - private static Operand AddCopy(IntrusiveList nodes, Operation node, Operand source) - { - Operand temp = Local(source.Type); - - Operation copyOp = Operation(Instruction.Copy, temp, source); - - nodes.AddBefore(node, copyOp); - - return temp; - } - - private static Operand GetIntConst(Operand value) - { - if (value.Type == OperandType.FP32) - { - return Const(value.AsInt32()); - } - else if (value.Type == OperandType.FP64) - { - return Const(value.AsInt64()); - } - - return value; - } - - private static void Delete(IntrusiveList nodes, Operation node) - { - node.Destination = default; - - for (int index = 0; index < node.SourcesCount; index++) - { - node.SetSource(index, default); - } - - nodes.Remove(node); - } - - private static Operand Gpr(X86Register register, OperandType type) - { - return Register((int)register, RegisterType.Integer, type); - } - - private static Operand Xmm(X86Register register, OperandType type) - { - return Register((int)register, RegisterType.Vector, type); - } - - private static bool IsSameOperandDestSrc1(Operation operation) - { - switch (operation.Instruction) - { - case Instruction.Add: - return !HardwareCapabilities.SupportsVexEncoding && !operation.Destination.Type.IsInteger(); - case Instruction.Multiply: - case Instruction.Subtract: - return !HardwareCapabilities.SupportsVexEncoding || operation.Destination.Type.IsInteger(); - - case Instruction.BitwiseAnd: - case Instruction.BitwiseExclusiveOr: - case Instruction.BitwiseNot: - case Instruction.BitwiseOr: - case Instruction.ByteSwap: - case Instruction.Negate: - case Instruction.RotateRight: - case Instruction.ShiftLeft: - case Instruction.ShiftRightSI: - case Instruction.ShiftRightUI: - return true; - - case Instruction.Divide: - return !HardwareCapabilities.SupportsVexEncoding && !operation.Destination.Type.IsInteger(); - - case Instruction.VectorInsert: - case Instruction.VectorInsert16: - case Instruction.VectorInsert8: - return !HardwareCapabilities.SupportsVexEncoding; - - case Instruction.Extended: - return IsIntrinsicSameOperandDestSrc1(operation); - } - - return IsVexSameOperandDestSrc1(operation); - } - - private static bool IsIntrinsicSameOperandDestSrc1(Operation operation) - { - IntrinsicInfo info = IntrinsicTable.GetInfo(operation.Intrinsic); - - return info.Type == IntrinsicType.Crc32 || info.Type == IntrinsicType.Fma || IsVexSameOperandDestSrc1(operation); - } - - private static bool IsVexSameOperandDestSrc1(Operation operation) - { - if (IsIntrinsic(operation.Instruction)) - { - IntrinsicInfo info = IntrinsicTable.GetInfo(operation.Intrinsic); - - bool hasVex = HardwareCapabilities.SupportsVexEncoding && Assembler.SupportsVexPrefix(info.Inst); - - bool isUnary = operation.SourcesCount < 2; - - bool hasVecDest = operation.Destination != default && operation.Destination.Type == OperandType.V128; - - return !hasVex && !isUnary && hasVecDest; - } - - return false; - } - - private static bool HasConstSrc1(Instruction inst) - { - switch (inst) - { - case Instruction.Copy: - case Instruction.LoadArgument: - case Instruction.Spill: - case Instruction.SpillArg: - return true; - } - - return false; - } - - private static bool HasConstSrc2(Instruction inst) - { - switch (inst) - { - case Instruction.Add: - case Instruction.BitwiseAnd: - case Instruction.BitwiseExclusiveOr: - case Instruction.BitwiseOr: - case Instruction.BranchIf: - case Instruction.Compare: - case Instruction.Multiply: - case Instruction.RotateRight: - case Instruction.ShiftLeft: - case Instruction.ShiftRightSI: - case Instruction.ShiftRightUI: - case Instruction.Store: - case Instruction.Store16: - case Instruction.Store8: - case Instruction.Subtract: - case Instruction.VectorExtract: - case Instruction.VectorExtract16: - case Instruction.VectorExtract8: - return true; - } - - return false; - } - - private static bool IsCommutative(Operation operation) - { - switch (operation.Instruction) - { - case Instruction.Add: - case Instruction.BitwiseAnd: - case Instruction.BitwiseExclusiveOr: - case Instruction.BitwiseOr: - case Instruction.Multiply: - return true; - - case Instruction.BranchIf: - case Instruction.Compare: - { - Operand comp = operation.GetSource(2); - - Debug.Assert(comp.Kind == OperandKind.Constant); - - var compType = (Comparison)comp.AsInt32(); - - return compType == Comparison.Equal || compType == Comparison.NotEqual; - } - } - - return false; - } - - private static bool IsIntrinsic(Instruction inst) - { - return inst == Instruction.Extended; - } - - private static bool IsXmmIntrinsic(Operation operation) - { - if (operation.Instruction != Instruction.Extended) - { - return false; - } - - IntrinsicInfo info = IntrinsicTable.GetInfo(operation.Intrinsic); - - return info.Type != IntrinsicType.Crc32; - } - } -} \ No newline at end of file diff --git a/ARMeilleure/CodeGen/X86/X86Condition.cs b/ARMeilleure/CodeGen/X86/X86Condition.cs deleted file mode 100644 index c82cbdec5..000000000 --- a/ARMeilleure/CodeGen/X86/X86Condition.cs +++ /dev/null @@ -1,47 +0,0 @@ -using ARMeilleure.IntermediateRepresentation; -using System; - -namespace ARMeilleure.CodeGen.X86 -{ - enum X86Condition - { - Overflow = 0x0, - NotOverflow = 0x1, - Below = 0x2, - AboveOrEqual = 0x3, - Equal = 0x4, - NotEqual = 0x5, - BelowOrEqual = 0x6, - Above = 0x7, - Sign = 0x8, - NotSign = 0x9, - ParityEven = 0xa, - ParityOdd = 0xb, - Less = 0xc, - GreaterOrEqual = 0xd, - LessOrEqual = 0xe, - Greater = 0xf - } - - static class ComparisonX86Extensions - { - public static X86Condition ToX86Condition(this Comparison comp) - { - return comp switch - { - Comparison.Equal => X86Condition.Equal, - Comparison.NotEqual => X86Condition.NotEqual, - Comparison.Greater => X86Condition.Greater, - Comparison.LessOrEqual => X86Condition.LessOrEqual, - Comparison.GreaterUI => X86Condition.Above, - Comparison.LessOrEqualUI => X86Condition.BelowOrEqual, - Comparison.GreaterOrEqual => X86Condition.GreaterOrEqual, - Comparison.Less => X86Condition.Less, - Comparison.GreaterOrEqualUI => X86Condition.AboveOrEqual, - Comparison.LessUI => X86Condition.Below, - - _ => throw new ArgumentException(null, nameof(comp)) - }; - } - } -} \ No newline at end of file diff --git a/ARMeilleure/CodeGen/X86/X86Register.cs b/ARMeilleure/CodeGen/X86/X86Register.cs deleted file mode 100644 index 01f63e311..000000000 --- a/ARMeilleure/CodeGen/X86/X86Register.cs +++ /dev/null @@ -1,41 +0,0 @@ -namespace ARMeilleure.CodeGen.X86 -{ - enum X86Register - { - Invalid = -1, - - Rax = 0, - Rcx = 1, - Rdx = 2, - Rbx = 3, - Rsp = 4, - Rbp = 5, - Rsi = 6, - Rdi = 7, - R8 = 8, - R9 = 9, - R10 = 10, - R11 = 11, - R12 = 12, - R13 = 13, - R14 = 14, - R15 = 15, - - Xmm0 = 0, - Xmm1 = 1, - Xmm2 = 2, - Xmm3 = 3, - Xmm4 = 4, - Xmm5 = 5, - Xmm6 = 6, - Xmm7 = 7, - Xmm8 = 8, - Xmm9 = 9, - Xmm10 = 10, - Xmm11 = 11, - Xmm12 = 12, - Xmm13 = 13, - Xmm14 = 14, - Xmm15 = 15 - } -} \ No newline at end of file diff --git a/ARMeilleure/Common/BitMap.cs b/ARMeilleure/Common/BitMap.cs deleted file mode 100644 index 27ef031f3..000000000 --- a/ARMeilleure/Common/BitMap.cs +++ /dev/null @@ -1,222 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Numerics; -using System.Runtime.CompilerServices; - -namespace ARMeilleure.Common -{ - unsafe class BitMap : IEnumerable, IDisposable - { - private const int IntSize = 64; - private const int IntMask = IntSize - 1; - - private int _count; - private long* _masks; - private readonly Allocator _allocator; - - public BitMap(Allocator allocator) - { - _allocator = allocator; - } - - public BitMap(Allocator allocator, int capacity) : this(allocator) - { - EnsureCapacity(capacity); - } - - public bool Set(int bit) - { - EnsureCapacity(bit + 1); - - int wordIndex = bit / IntSize; - int wordBit = bit & IntMask; - - long wordMask = 1L << wordBit; - - if ((_masks[wordIndex] & wordMask) != 0) - { - return false; - } - - _masks[wordIndex] |= wordMask; - - return true; - } - - public void Clear(int bit) - { - EnsureCapacity(bit + 1); - - int wordIndex = bit / IntSize; - int wordBit = bit & IntMask; - - long wordMask = 1L << wordBit; - - _masks[wordIndex] &= ~wordMask; - } - - public bool IsSet(int bit) - { - EnsureCapacity(bit + 1); - - int wordIndex = bit / IntSize; - int wordBit = bit & IntMask; - - return (_masks[wordIndex] & (1L << wordBit)) != 0; - } - - public int FindFirstUnset() - { - for (int index = 0; index < _count; index++) - { - long mask = _masks[index]; - - if (mask != -1L) - { - return BitOperations.TrailingZeroCount(~mask) + index * IntSize; - } - } - - return _count * IntSize; - } - - public bool Set(BitMap map) - { - EnsureCapacity(map._count * IntSize); - - bool modified = false; - - for (int index = 0; index < _count; index++) - { - long newValue = _masks[index] | map._masks[index]; - - if (_masks[index] != newValue) - { - _masks[index] = newValue; - - modified = true; - } - } - - return modified; - } - - public bool Clear(BitMap map) - { - EnsureCapacity(map._count * IntSize); - - bool modified = false; - - for (int index = 0; index < _count; index++) - { - long newValue = _masks[index] & ~map._masks[index]; - - if (_masks[index] != newValue) - { - _masks[index] = newValue; - - modified = true; - } - } - - return modified; - } - - private void EnsureCapacity(int size) - { - int count = (size + IntMask) / IntSize; - - if (count > _count) - { - var oldMask = _masks; - var oldSpan = new Span(_masks, _count); - - _masks = _allocator.Allocate((uint)count); - _count = count; - - var newSpan = new Span(_masks, _count); - - oldSpan.CopyTo(newSpan); - newSpan.Slice(oldSpan.Length).Clear(); - - _allocator.Free(oldMask); - } - } - - public void Dispose() - { - if (_masks != null) - { - _allocator.Free(_masks); - - _masks = null; - } - } - - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - - public Enumerator GetEnumerator() - { - return new Enumerator(this); - } - - public struct Enumerator : IEnumerator - { - private long _index; - private long _mask; - private int _bit; - private readonly BitMap _map; - - public int Current => (int)_index * IntSize + _bit; - object IEnumerator.Current => Current; - - public Enumerator(BitMap map) - { - _index = -1; - _mask = 0; - _bit = 0; - _map = map; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool MoveNext() - { - if (_mask != 0) - { - _mask &= ~(1L << _bit); - } - - // Manually hoist these loads, because RyuJIT does not. - long count = (uint)_map._count; - long* masks = _map._masks; - - while (_mask == 0) - { - if (++_index >= count) - { - return false; - } - - _mask = masks[_index]; - } - - _bit = BitOperations.TrailingZeroCount(_mask); - - return true; - } - - public void Reset() { } - - public void Dispose() { } - } - } -} \ No newline at end of file diff --git a/ARMeilleure/Common/BitUtils.cs b/ARMeilleure/Common/BitUtils.cs deleted file mode 100644 index 51160eff0..000000000 --- a/ARMeilleure/Common/BitUtils.cs +++ /dev/null @@ -1,61 +0,0 @@ -using System.Numerics; - -namespace ARMeilleure.Common -{ - static class BitUtils - { - private static readonly sbyte[] HbsNibbleLut; - - static BitUtils() - { - HbsNibbleLut = new sbyte[] { -1, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3 }; - } - - public static long FillWithOnes(int bits) - { - return bits == 64 ? -1L : (1L << bits) - 1; - } - - public static int HighestBitSet(int value) - { - return 31 - BitOperations.LeadingZeroCount((uint)value); - } - - public static int HighestBitSetNibble(int value) - { - return HbsNibbleLut[value]; - } - - public static long Replicate(long bits, int size) - { - long output = 0; - - for (int bit = 0; bit < 64; bit += size) - { - output |= bits << bit; - } - - return output; - } - - public static int RotateRight(int bits, int shift, int size) - { - return (int)RotateRight((uint)bits, shift, size); - } - - public static uint RotateRight(uint bits, int shift, int size) - { - return (bits >> shift) | (bits << (size - shift)); - } - - public static long RotateRight(long bits, int shift, int size) - { - return (long)RotateRight((ulong)bits, shift, size); - } - - public static ulong RotateRight(ulong bits, int shift, int size) - { - return (bits >> shift) | (bits << (size - shift)); - } - } -} diff --git a/ARMeilleure/Decoders/Block.cs b/ARMeilleure/Decoders/Block.cs deleted file mode 100644 index f296d299d..000000000 --- a/ARMeilleure/Decoders/Block.cs +++ /dev/null @@ -1,101 +0,0 @@ -using System; -using System.Collections.Generic; - -namespace ARMeilleure.Decoders -{ - class Block - { - public ulong Address { get; set; } - public ulong EndAddress { get; set; } - - public Block Next { get; set; } - public Block Branch { get; set; } - - public bool Exit { get; set; } - - public List OpCodes { get; } - - public Block() - { - OpCodes = new List(); - } - - public Block(ulong address) : this() - { - Address = address; - } - - public void Split(Block rightBlock) - { - int splitIndex = BinarySearch(OpCodes, rightBlock.Address); - - if (OpCodes[splitIndex].Address < rightBlock.Address) - { - splitIndex++; - } - - int splitCount = OpCodes.Count - splitIndex; - - if (splitCount <= 0) - { - throw new ArgumentException("Can't split at right block address."); - } - - rightBlock.EndAddress = EndAddress; - - rightBlock.Next = Next; - rightBlock.Branch = Branch; - - rightBlock.OpCodes.AddRange(OpCodes.GetRange(splitIndex, splitCount)); - - EndAddress = rightBlock.Address; - - Next = rightBlock; - Branch = null; - - OpCodes.RemoveRange(splitIndex, splitCount); - } - - private static int BinarySearch(List opCodes, ulong address) - { - int left = 0; - int middle = 0; - int right = opCodes.Count - 1; - - while (left <= right) - { - int size = right - left; - - middle = left + (size >> 1); - - OpCode opCode = opCodes[middle]; - - if (address == (ulong)opCode.Address) - { - break; - } - - if (address < (ulong)opCode.Address) - { - right = middle - 1; - } - else - { - left = middle + 1; - } - } - - return middle; - } - - public OpCode GetLastOp() - { - if (OpCodes.Count > 0) - { - return OpCodes[OpCodes.Count - 1]; - } - - return null; - } - } -} \ No newline at end of file diff --git a/ARMeilleure/Decoders/Condition.cs b/ARMeilleure/Decoders/Condition.cs deleted file mode 100644 index 727f897da..000000000 --- a/ARMeilleure/Decoders/Condition.cs +++ /dev/null @@ -1,32 +0,0 @@ -namespace ARMeilleure.Decoders -{ - enum Condition - { - Eq = 0, - Ne = 1, - GeUn = 2, - LtUn = 3, - Mi = 4, - Pl = 5, - Vs = 6, - Vc = 7, - GtUn = 8, - LeUn = 9, - Ge = 10, - Lt = 11, - Gt = 12, - Le = 13, - Al = 14, - Nv = 15 - } - - static class ConditionExtensions - { - public static Condition Invert(this Condition cond) - { - // Bit 0 of all conditions is basically a negation bit, so - // inverting this bit has the effect of inverting the condition. - return (Condition)((int)cond ^ 1); - } - } -} \ No newline at end of file diff --git a/ARMeilleure/Decoders/DataOp.cs b/ARMeilleure/Decoders/DataOp.cs deleted file mode 100644 index 464d00898..000000000 --- a/ARMeilleure/Decoders/DataOp.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace ARMeilleure.Decoders -{ - enum DataOp - { - Adr = 0, - Arithmetic = 1, - Logical = 2, - BitField = 3 - } -} \ No newline at end of file diff --git a/ARMeilleure/Decoders/Decoder.cs b/ARMeilleure/Decoders/Decoder.cs deleted file mode 100644 index 426465aaa..000000000 --- a/ARMeilleure/Decoders/Decoder.cs +++ /dev/null @@ -1,391 +0,0 @@ -using ARMeilleure.Decoders.Optimizations; -using ARMeilleure.Instructions; -using ARMeilleure.Memory; -using ARMeilleure.State; -using System; -using System.Collections.Generic; -using System.Diagnostics; - -namespace ARMeilleure.Decoders -{ - static class Decoder - { - // We define a limit on the number of instructions that a function may have, - // this prevents functions being potentially too large, which would - // take too long to compile and use too much memory. - private const int MaxInstsPerFunction = 2500; - - // For lower code quality translation, we set a lower limit since we're blocking execution. - private const int MaxInstsPerFunctionLowCq = 500; - - public static Block[] Decode(IMemoryManager memory, ulong address, ExecutionMode mode, bool highCq, DecoderMode dMode) - { - List blocks = new List(); - - Queue workQueue = new Queue(); - - Dictionary visited = new Dictionary(); - - Debug.Assert(MaxInstsPerFunctionLowCq <= MaxInstsPerFunction); - - int opsCount = 0; - - int instructionLimit = highCq ? MaxInstsPerFunction : MaxInstsPerFunctionLowCq; - - Block GetBlock(ulong blkAddress) - { - if (!visited.TryGetValue(blkAddress, out Block block)) - { - block = new Block(blkAddress); - - if ((dMode != DecoderMode.MultipleBlocks && visited.Count >= 1) || opsCount > instructionLimit || !memory.IsMapped(blkAddress)) - { - block.Exit = true; - block.EndAddress = blkAddress; - } - - workQueue.Enqueue(block); - - visited.Add(blkAddress, block); - } - - return block; - } - - GetBlock(address); - - while (workQueue.TryDequeue(out Block currBlock)) - { - // Check if the current block is inside another block. - if (BinarySearch(blocks, currBlock.Address, out int nBlkIndex)) - { - Block nBlock = blocks[nBlkIndex]; - - if (nBlock.Address == currBlock.Address) - { - throw new InvalidOperationException("Found duplicate block address on the list."); - } - - currBlock.Exit = false; - - nBlock.Split(currBlock); - - blocks.Insert(nBlkIndex + 1, currBlock); - - continue; - } - - if (!currBlock.Exit) - { - // If we have a block after the current one, set the limit address. - ulong limitAddress = ulong.MaxValue; - - if (nBlkIndex != blocks.Count) - { - Block nBlock = blocks[nBlkIndex]; - - int nextIndex = nBlkIndex + 1; - - if (nBlock.Address < currBlock.Address && nextIndex < blocks.Count) - { - limitAddress = blocks[nextIndex].Address; - } - else if (nBlock.Address > currBlock.Address) - { - limitAddress = blocks[nBlkIndex].Address; - } - } - - if (dMode == DecoderMode.SingleInstruction) - { - // Only read at most one instruction - limitAddress = currBlock.Address + 1; - } - - FillBlock(memory, mode, currBlock, limitAddress); - - opsCount += currBlock.OpCodes.Count; - - if (currBlock.OpCodes.Count != 0) - { - // Set child blocks. "Branch" is the block the branch instruction - // points to (when taken), "Next" is the block at the next address, - // executed when the branch is not taken. For Unconditional Branches - // (except BL/BLR that are sub calls) or end of executable, Next is null. - OpCode lastOp = currBlock.GetLastOp(); - - bool isCall = IsCall(lastOp); - - if (lastOp is IOpCodeBImm op && !isCall) - { - currBlock.Branch = GetBlock((ulong)op.Immediate); - } - - if (isCall || !(IsUnconditionalBranch(lastOp) || IsTrap(lastOp))) - { - currBlock.Next = GetBlock(currBlock.EndAddress); - } - } - } - - // Insert the new block on the list (sorted by address). - if (blocks.Count != 0) - { - Block nBlock = blocks[nBlkIndex]; - - blocks.Insert(nBlkIndex + (nBlock.Address < currBlock.Address ? 1 : 0), currBlock); - } - else - { - blocks.Add(currBlock); - } - } - - if (blocks.Count == 1 && blocks[0].OpCodes.Count == 0) - { - Debug.Assert(blocks[0].Exit); - Debug.Assert(blocks[0].Address == blocks[0].EndAddress); - - throw new InvalidOperationException($"Decoded a single empty exit block. Entry point = 0x{address:X}."); - } - - if (dMode == DecoderMode.MultipleBlocks) - { - return TailCallRemover.RunPass(address, blocks); - } - else - { - return blocks.ToArray(); - } - } - - public static bool BinarySearch(List blocks, ulong address, out int index) - { - index = 0; - - int left = 0; - int right = blocks.Count - 1; - - while (left <= right) - { - int size = right - left; - - int middle = left + (size >> 1); - - Block block = blocks[middle]; - - index = middle; - - if (address >= block.Address && address < block.EndAddress) - { - return true; - } - - if (address < block.Address) - { - right = middle - 1; - } - else - { - left = middle + 1; - } - } - - return false; - } - - private static void FillBlock( - IMemoryManager memory, - ExecutionMode mode, - Block block, - ulong limitAddress) - { - ulong address = block.Address; - int itBlockSize = 0; - - OpCode opCode; - - do - { - if (address >= limitAddress && itBlockSize == 0) - { - break; - } - - opCode = DecodeOpCode(memory, address, mode); - - block.OpCodes.Add(opCode); - - address += (ulong)opCode.OpCodeSizeInBytes; - - if (opCode is OpCodeT16IfThen it) - { - itBlockSize = it.IfThenBlockSize; - } - else if (itBlockSize > 0) - { - itBlockSize--; - } - } - while (!(IsBranch(opCode) || IsException(opCode))); - - block.EndAddress = address; - } - - private static bool IsBranch(OpCode opCode) - { - return opCode is OpCodeBImm || - opCode is OpCodeBReg || IsAarch32Branch(opCode); - } - - private static bool IsUnconditionalBranch(OpCode opCode) - { - return opCode is OpCodeBImmAl || - opCode is OpCodeBReg || IsAarch32UnconditionalBranch(opCode); - } - - private static bool IsAarch32UnconditionalBranch(OpCode opCode) - { - if (!(opCode is OpCode32 op)) - { - return false; - } - - // Compare and branch instructions are always conditional. - if (opCode.Instruction.Name == InstName.Cbz || - opCode.Instruction.Name == InstName.Cbnz) - { - return false; - } - - // Note: On ARM32, most instructions have conditional execution, - // so there's no "Always" (unconditional) branch like on ARM64. - // We need to check if the condition is "Always" instead. - return IsAarch32Branch(op) && op.Cond >= Condition.Al; - } - - private static bool IsAarch32Branch(OpCode opCode) - { - // Note: On ARM32, most ALU operations can write to R15 (PC), - // so we must consider such operations as a branch in potential aswell. - if (opCode is IOpCode32Alu opAlu && opAlu.Rd == RegisterAlias.Aarch32Pc) - { - if (opCode is OpCodeT32) - { - return opCode.Instruction.Name != InstName.Tst && opCode.Instruction.Name != InstName.Teq && - opCode.Instruction.Name != InstName.Cmp && opCode.Instruction.Name != InstName.Cmn; - } - return true; - } - - // Same thing for memory operations. We have the cases where PC is a target - // register (Rt == 15 or (mask & (1 << 15)) != 0), and cases where there is - // a write back to PC (wback == true && Rn == 15), however the later may - // be "undefined" depending on the CPU, so compilers should not produce that. - if (opCode is IOpCode32Mem || opCode is IOpCode32MemMult) - { - int rt, rn; - - bool wBack, isLoad; - - if (opCode is IOpCode32Mem opMem) - { - rt = opMem.Rt; - rn = opMem.Rn; - wBack = opMem.WBack; - isLoad = opMem.IsLoad; - - // For the dual load, we also need to take into account the - // case were Rt2 == 15 (PC). - if (rt == 14 && opMem.Instruction.Name == InstName.Ldrd) - { - rt = RegisterAlias.Aarch32Pc; - } - } - else if (opCode is IOpCode32MemMult opMemMult) - { - const int pcMask = 1 << RegisterAlias.Aarch32Pc; - - rt = (opMemMult.RegisterMask & pcMask) != 0 ? RegisterAlias.Aarch32Pc : 0; - rn = opMemMult.Rn; - wBack = opMemMult.PostOffset != 0; - isLoad = opMemMult.IsLoad; - } - else - { - throw new NotImplementedException($"The type \"{opCode.GetType().Name}\" is not implemented on the decoder."); - } - - if ((rt == RegisterAlias.Aarch32Pc && isLoad) || - (rn == RegisterAlias.Aarch32Pc && wBack)) - { - return true; - } - } - - // Explicit branch instructions. - return opCode is IOpCode32BImm || - opCode is IOpCode32BReg; - } - - private static bool IsCall(OpCode opCode) - { - return opCode.Instruction.Name == InstName.Bl || - opCode.Instruction.Name == InstName.Blr || - opCode.Instruction.Name == InstName.Blx; - } - - private static bool IsException(OpCode opCode) - { - return IsTrap(opCode) || opCode.Instruction.Name == InstName.Svc; - } - - private static bool IsTrap(OpCode opCode) - { - return opCode.Instruction.Name == InstName.Brk || - opCode.Instruction.Name == InstName.Trap || - opCode.Instruction.Name == InstName.Und; - } - - public static OpCode DecodeOpCode(IMemoryManager memory, ulong address, ExecutionMode mode) - { - int opCode = memory.Read(address); - - InstDescriptor inst; - - OpCodeTable.MakeOp makeOp; - - if (mode == ExecutionMode.Aarch64) - { - (inst, makeOp) = OpCodeTable.GetInstA64(opCode); - } - else - { - if (mode == ExecutionMode.Aarch32Arm) - { - (inst, makeOp) = OpCodeTable.GetInstA32(opCode); - } - else /* if (mode == ExecutionMode.Aarch32Thumb) */ - { - (inst, makeOp) = OpCodeTable.GetInstT32(opCode); - } - } - - if (makeOp != null) - { - return makeOp(inst, address, opCode); - } - else - { - if (mode == ExecutionMode.Aarch32Thumb) - { - return new OpCodeT16(inst, address, opCode); - } - else - { - return new OpCode(inst, address, opCode); - } - } - } - } -} \ No newline at end of file diff --git a/ARMeilleure/Decoders/DecoderHelper.cs b/ARMeilleure/Decoders/DecoderHelper.cs deleted file mode 100644 index 38f98c39c..000000000 --- a/ARMeilleure/Decoders/DecoderHelper.cs +++ /dev/null @@ -1,167 +0,0 @@ -using ARMeilleure.Common; - -namespace ARMeilleure.Decoders -{ - static class DecoderHelper - { - static DecoderHelper() - { - Imm8ToFP32Table = BuildImm8ToFP32Table(); - Imm8ToFP64Table = BuildImm8ToFP64Table(); - } - - public static readonly uint[] Imm8ToFP32Table; - public static readonly ulong[] Imm8ToFP64Table; - - private static uint[] BuildImm8ToFP32Table() - { - uint[] tbl = new uint[256]; - - for (int idx = 0; idx < 256; idx++) - { - tbl[idx] = ExpandImm8ToFP32((uint)idx); - } - - return tbl; - } - - private static ulong[] BuildImm8ToFP64Table() - { - ulong[] tbl = new ulong[256]; - - for (int idx = 0; idx < 256; idx++) - { - tbl[idx] = ExpandImm8ToFP64((ulong)idx); - } - - return tbl; - } - - // abcdefgh -> aBbbbbbc defgh000 00000000 00000000 (B = ~b) - private static uint ExpandImm8ToFP32(uint imm) - { - uint MoveBit(uint bits, int from, int to) - { - return ((bits >> from) & 1U) << to; - } - - return MoveBit(imm, 7, 31) | MoveBit(~imm, 6, 30) | - MoveBit(imm, 6, 29) | MoveBit( imm, 6, 28) | - MoveBit(imm, 6, 27) | MoveBit( imm, 6, 26) | - MoveBit(imm, 6, 25) | MoveBit( imm, 5, 24) | - MoveBit(imm, 4, 23) | MoveBit( imm, 3, 22) | - MoveBit(imm, 2, 21) | MoveBit( imm, 1, 20) | - MoveBit(imm, 0, 19); - } - - // abcdefgh -> aBbbbbbb bbcdefgh 00000000 00000000 00000000 00000000 00000000 00000000 (B = ~b) - private static ulong ExpandImm8ToFP64(ulong imm) - { - ulong MoveBit(ulong bits, int from, int to) - { - return ((bits >> from) & 1UL) << to; - } - - return MoveBit(imm, 7, 63) | MoveBit(~imm, 6, 62) | - MoveBit(imm, 6, 61) | MoveBit( imm, 6, 60) | - MoveBit(imm, 6, 59) | MoveBit( imm, 6, 58) | - MoveBit(imm, 6, 57) | MoveBit( imm, 6, 56) | - MoveBit(imm, 6, 55) | MoveBit( imm, 6, 54) | - MoveBit(imm, 5, 53) | MoveBit( imm, 4, 52) | - MoveBit(imm, 3, 51) | MoveBit( imm, 2, 50) | - MoveBit(imm, 1, 49) | MoveBit( imm, 0, 48); - } - - public struct BitMask - { - public long WMask; - public long TMask; - public int Pos; - public int Shift; - public bool IsUndefined; - - public static BitMask Invalid => new BitMask { IsUndefined = true }; - } - - public static BitMask DecodeBitMask(int opCode, bool immediate) - { - int immS = (opCode >> 10) & 0x3f; - int immR = (opCode >> 16) & 0x3f; - - int n = (opCode >> 22) & 1; - int sf = (opCode >> 31) & 1; - - int length = BitUtils.HighestBitSet((~immS & 0x3f) | (n << 6)); - - if (length < 1 || (sf == 0 && n != 0)) - { - return BitMask.Invalid; - } - - int size = 1 << length; - - int levels = size - 1; - - int s = immS & levels; - int r = immR & levels; - - if (immediate && s == levels) - { - return BitMask.Invalid; - } - - long wMask = BitUtils.FillWithOnes(s + 1); - long tMask = BitUtils.FillWithOnes(((s - r) & levels) + 1); - - if (r > 0) - { - wMask = BitUtils.RotateRight(wMask, r, size); - wMask &= BitUtils.FillWithOnes(size); - } - - return new BitMask() - { - WMask = BitUtils.Replicate(wMask, size), - TMask = BitUtils.Replicate(tMask, size), - - Pos = immS, - Shift = immR - }; - } - - public static long DecodeImm24_2(int opCode) - { - return ((long)opCode << 40) >> 38; - } - - public static long DecodeImm26_2(int opCode) - { - return ((long)opCode << 38) >> 36; - } - - public static long DecodeImmS19_2(int opCode) - { - return (((long)opCode << 40) >> 43) & ~3; - } - - public static long DecodeImmS14_2(int opCode) - { - return (((long)opCode << 45) >> 48) & ~3; - } - - public static bool VectorArgumentsInvalid(bool q, params int[] args) - { - if (q) - { - for (int i = 0; i < args.Length; i++) - { - if ((args[i] & 1) == 1) - { - return true; - } - } - } - return false; - } - } -} \ No newline at end of file diff --git a/ARMeilleure/Decoders/IOpCode32Exception.cs b/ARMeilleure/Decoders/IOpCode32Exception.cs deleted file mode 100644 index 82819bddd..000000000 --- a/ARMeilleure/Decoders/IOpCode32Exception.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace ARMeilleure.Decoders; - -interface IOpCode32Exception -{ - int Id { get; } -} \ No newline at end of file diff --git a/ARMeilleure/Decoders/IOpCodeLit.cs b/ARMeilleure/Decoders/IOpCodeLit.cs deleted file mode 100644 index 74084a457..000000000 --- a/ARMeilleure/Decoders/IOpCodeLit.cs +++ /dev/null @@ -1,11 +0,0 @@ -namespace ARMeilleure.Decoders -{ - interface IOpCodeLit : IOpCode - { - int Rt { get; } - long Immediate { get; } - int Size { get; } - bool Signed { get; } - bool Prefetch { get; } - } -} \ No newline at end of file diff --git a/ARMeilleure/Decoders/InstDescriptor.cs b/ARMeilleure/Decoders/InstDescriptor.cs deleted file mode 100644 index 29966d6dd..000000000 --- a/ARMeilleure/Decoders/InstDescriptor.cs +++ /dev/null @@ -1,18 +0,0 @@ -using ARMeilleure.Instructions; - -namespace ARMeilleure.Decoders -{ - struct InstDescriptor - { - public static InstDescriptor Undefined => new InstDescriptor(InstName.Und, InstEmit.Und); - - public InstName Name { get; } - public InstEmitter Emitter { get; } - - public InstDescriptor(InstName name, InstEmitter emitter) - { - Name = name; - Emitter = emitter; - } - } -} \ No newline at end of file diff --git a/ARMeilleure/Decoders/InstEmitter.cs b/ARMeilleure/Decoders/InstEmitter.cs deleted file mode 100644 index a8b526569..000000000 --- a/ARMeilleure/Decoders/InstEmitter.cs +++ /dev/null @@ -1,6 +0,0 @@ -using ARMeilleure.Translation; - -namespace ARMeilleure.Decoders -{ - delegate void InstEmitter(ArmEmitterContext context); -} \ No newline at end of file diff --git a/ARMeilleure/Decoders/IntType.cs b/ARMeilleure/Decoders/IntType.cs deleted file mode 100644 index 244e96805..000000000 --- a/ARMeilleure/Decoders/IntType.cs +++ /dev/null @@ -1,14 +0,0 @@ -namespace ARMeilleure.Decoders -{ - enum IntType - { - UInt8 = 0, - UInt16 = 1, - UInt32 = 2, - UInt64 = 3, - Int8 = 4, - Int16 = 5, - Int32 = 6, - Int64 = 7 - } -} \ No newline at end of file diff --git a/ARMeilleure/Decoders/OpCode.cs b/ARMeilleure/Decoders/OpCode.cs deleted file mode 100644 index f9aed7924..000000000 --- a/ARMeilleure/Decoders/OpCode.cs +++ /dev/null @@ -1,49 +0,0 @@ -using ARMeilleure.IntermediateRepresentation; -using System; - -namespace ARMeilleure.Decoders -{ - class OpCode : IOpCode - { - public ulong Address { get; } - public int RawOpCode { get; } - - public int OpCodeSizeInBytes { get; protected set; } = 4; - - public InstDescriptor Instruction { get; protected set; } - - public RegisterSize RegisterSize { get; protected set; } - - public static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode(inst, address, opCode); - - public OpCode(InstDescriptor inst, ulong address, int opCode) - { - Instruction = inst; - Address = address; - RawOpCode = opCode; - - RegisterSize = RegisterSize.Int64; - } - - public int GetPairsCount() => GetBitsCount() / 16; - public int GetBytesCount() => GetBitsCount() / 8; - - public int GetBitsCount() - { - switch (RegisterSize) - { - case RegisterSize.Int32: return 32; - case RegisterSize.Int64: return 64; - case RegisterSize.Simd64: return 64; - case RegisterSize.Simd128: return 128; - } - - throw new InvalidOperationException(); - } - - public OperandType GetOperandType() - { - return RegisterSize == RegisterSize.Int32 ? OperandType.I32 : OperandType.I64; - } - } -} \ No newline at end of file diff --git a/ARMeilleure/Decoders/OpCode32Mem.cs b/ARMeilleure/Decoders/OpCode32Mem.cs deleted file mode 100644 index ceb1e49f5..000000000 --- a/ARMeilleure/Decoders/OpCode32Mem.cs +++ /dev/null @@ -1,39 +0,0 @@ -using ARMeilleure.Instructions; - -namespace ARMeilleure.Decoders -{ - class OpCode32Mem : OpCode32, IOpCode32Mem - { - public int Rt { get; protected set; } - public int Rn { get; } - - public int Immediate { get; protected set; } - - public bool Index { get; } - public bool Add { get; } - public bool WBack { get; } - public bool Unprivileged { get; } - - public bool IsLoad { get; } - - public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32Mem(inst, address, opCode); - - public OpCode32Mem(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode) - { - Rt = (opCode >> 12) & 0xf; - Rn = (opCode >> 16) & 0xf; - - bool isLoad = (opCode & (1 << 20)) != 0; - bool w = (opCode & (1 << 21)) != 0; - bool u = (opCode & (1 << 23)) != 0; - bool p = (opCode & (1 << 24)) != 0; - - Index = p; - Add = u; - WBack = !p || w; - Unprivileged = !p && w; - - IsLoad = isLoad || inst.Name == InstName.Ldrd; - } - } -} \ No newline at end of file diff --git a/ARMeilleure/Decoders/OpCodeAdr.cs b/ARMeilleure/Decoders/OpCodeAdr.cs deleted file mode 100644 index 9655c766c..000000000 --- a/ARMeilleure/Decoders/OpCodeAdr.cs +++ /dev/null @@ -1,19 +0,0 @@ -namespace ARMeilleure.Decoders -{ - class OpCodeAdr : OpCode - { - public int Rd { get; } - - public long Immediate { get; } - - public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeAdr(inst, address, opCode); - - public OpCodeAdr(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode) - { - Rd = opCode & 0x1f; - - Immediate = DecoderHelper.DecodeImmS19_2(opCode); - Immediate |= ((long)opCode >> 29) & 3; - } - } -} \ No newline at end of file diff --git a/ARMeilleure/Decoders/OpCodeMem.cs b/ARMeilleure/Decoders/OpCodeMem.cs deleted file mode 100644 index 0ba2bcd18..000000000 --- a/ARMeilleure/Decoders/OpCodeMem.cs +++ /dev/null @@ -1,19 +0,0 @@ -namespace ARMeilleure.Decoders -{ - class OpCodeMem : OpCode - { - public int Rt { get; protected set; } - public int Rn { get; protected set; } - public int Size { get; protected set; } - public bool Extend64 { get; protected set; } - - public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeMem(inst, address, opCode); - - public OpCodeMem(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode) - { - Rt = (opCode >> 0) & 0x1f; - Rn = (opCode >> 5) & 0x1f; - Size = (opCode >> 30) & 0x3; - } - } -} \ No newline at end of file diff --git a/ARMeilleure/Decoders/OpCodeMemLit.cs b/ARMeilleure/Decoders/OpCodeMemLit.cs deleted file mode 100644 index 986d66340..000000000 --- a/ARMeilleure/Decoders/OpCodeMemLit.cs +++ /dev/null @@ -1,28 +0,0 @@ -namespace ARMeilleure.Decoders -{ - class OpCodeMemLit : OpCode, IOpCodeLit - { - public int Rt { get; } - public long Immediate { get; } - public int Size { get; } - public bool Signed { get; } - public bool Prefetch { get; } - - public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeMemLit(inst, address, opCode); - - public OpCodeMemLit(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode) - { - Rt = opCode & 0x1f; - - Immediate = (long)address + DecoderHelper.DecodeImmS19_2(opCode); - - switch ((opCode >> 30) & 3) - { - case 0: Size = 2; Signed = false; Prefetch = false; break; - case 1: Size = 3; Signed = false; Prefetch = false; break; - case 2: Size = 2; Signed = true; Prefetch = false; break; - case 3: Size = 0; Signed = false; Prefetch = true; break; - } - } - } -} \ No newline at end of file diff --git a/ARMeilleure/Decoders/OpCodeMemPair.cs b/ARMeilleure/Decoders/OpCodeMemPair.cs deleted file mode 100644 index 21018033d..000000000 --- a/ARMeilleure/Decoders/OpCodeMemPair.cs +++ /dev/null @@ -1,25 +0,0 @@ -namespace ARMeilleure.Decoders -{ - class OpCodeMemPair : OpCodeMemImm - { - public int Rt2 { get; } - - public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeMemPair(inst, address, opCode); - - public OpCodeMemPair(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode) - { - Rt2 = (opCode >> 10) & 0x1f; - WBack = ((opCode >> 23) & 0x1) != 0; - PostIdx = ((opCode >> 23) & 0x3) == 1; - Extend64 = ((opCode >> 30) & 0x3) == 1; - Size = ((opCode >> 31) & 0x1) | 2; - - DecodeImm(opCode); - } - - protected void DecodeImm(int opCode) - { - Immediate = ((long)(opCode >> 15) << 57) >> (57 - Size); - } - } -} \ No newline at end of file diff --git a/ARMeilleure/Decoders/OpCodeMemReg.cs b/ARMeilleure/Decoders/OpCodeMemReg.cs deleted file mode 100644 index 73d6c5d2c..000000000 --- a/ARMeilleure/Decoders/OpCodeMemReg.cs +++ /dev/null @@ -1,20 +0,0 @@ -namespace ARMeilleure.Decoders -{ - class OpCodeMemReg : OpCodeMem - { - public bool Shift { get; } - public int Rm { get; } - - public IntType IntType { get; } - - public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeMemReg(inst, address, opCode); - - public OpCodeMemReg(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode) - { - Shift = ((opCode >> 12) & 0x1) != 0; - IntType = (IntType)((opCode >> 13) & 0x7); - Rm = (opCode >> 16) & 0x1f; - Extend64 = ((opCode >> 22) & 0x3) == 2; - } - } -} \ No newline at end of file diff --git a/ARMeilleure/Decoders/OpCodeSimd.cs b/ARMeilleure/Decoders/OpCodeSimd.cs deleted file mode 100644 index 85713690a..000000000 --- a/ARMeilleure/Decoders/OpCodeSimd.cs +++ /dev/null @@ -1,24 +0,0 @@ -namespace ARMeilleure.Decoders -{ - class OpCodeSimd : OpCode, IOpCodeSimd - { - public int Rd { get; } - public int Rn { get; } - public int Opc { get; } - public int Size { get; protected set; } - - public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeSimd(inst, address, opCode); - - public OpCodeSimd(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode) - { - Rd = (opCode >> 0) & 0x1f; - Rn = (opCode >> 5) & 0x1f; - Opc = (opCode >> 15) & 0x3; - Size = (opCode >> 22) & 0x3; - - RegisterSize = ((opCode >> 30) & 1) != 0 - ? RegisterSize.Simd128 - : RegisterSize.Simd64; - } - } -} \ No newline at end of file diff --git a/ARMeilleure/Decoders/OpCodeSimdIns.cs b/ARMeilleure/Decoders/OpCodeSimdIns.cs deleted file mode 100644 index f6f9249d1..000000000 --- a/ARMeilleure/Decoders/OpCodeSimdIns.cs +++ /dev/null @@ -1,36 +0,0 @@ -namespace ARMeilleure.Decoders -{ - class OpCodeSimdIns : OpCodeSimd - { - public int SrcIndex { get; } - public int DstIndex { get; } - - public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeSimdIns(inst, address, opCode); - - public OpCodeSimdIns(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode) - { - int imm4 = (opCode >> 11) & 0xf; - int imm5 = (opCode >> 16) & 0x1f; - - if (imm5 == 0b10000) - { - Instruction = InstDescriptor.Undefined; - - return; - } - - Size = imm5 & -imm5; - - switch (Size) - { - case 1: Size = 0; break; - case 2: Size = 1; break; - case 4: Size = 2; break; - case 8: Size = 3; break; - } - - SrcIndex = imm4 >> Size; - DstIndex = imm5 >> (Size + 1); - } - } -} \ No newline at end of file diff --git a/ARMeilleure/Decoders/OpCodeSimdMemMs.cs b/ARMeilleure/Decoders/OpCodeSimdMemMs.cs deleted file mode 100644 index 8922c18f6..000000000 --- a/ARMeilleure/Decoders/OpCodeSimdMemMs.cs +++ /dev/null @@ -1,48 +0,0 @@ -namespace ARMeilleure.Decoders -{ - class OpCodeSimdMemMs : OpCodeMemReg, IOpCodeSimd - { - public int Reps { get; } - public int SElems { get; } - public int Elems { get; } - public bool WBack { get; } - - public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeSimdMemMs(inst, address, opCode); - - public OpCodeSimdMemMs(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode) - { - switch ((opCode >> 12) & 0xf) - { - case 0b0000: Reps = 1; SElems = 4; break; - case 0b0010: Reps = 4; SElems = 1; break; - case 0b0100: Reps = 1; SElems = 3; break; - case 0b0110: Reps = 3; SElems = 1; break; - case 0b0111: Reps = 1; SElems = 1; break; - case 0b1000: Reps = 1; SElems = 2; break; - case 0b1010: Reps = 2; SElems = 1; break; - - default: Instruction = InstDescriptor.Undefined; return; - } - - Size = (opCode >> 10) & 3; - WBack = ((opCode >> 23) & 1) != 0; - - bool q = ((opCode >> 30) & 1) != 0; - - if (!q && Size == 3 && SElems != 1) - { - Instruction = InstDescriptor.Undefined; - - return; - } - - Extend64 = false; - - RegisterSize = q - ? RegisterSize.Simd128 - : RegisterSize.Simd64; - - Elems = (GetBitsCount() >> 3) >> Size; - } - } -} \ No newline at end of file diff --git a/ARMeilleure/Decoders/OpCodeSimdMemSs.cs b/ARMeilleure/Decoders/OpCodeSimdMemSs.cs deleted file mode 100644 index 44abdd389..000000000 --- a/ARMeilleure/Decoders/OpCodeSimdMemSs.cs +++ /dev/null @@ -1,97 +0,0 @@ -namespace ARMeilleure.Decoders -{ - class OpCodeSimdMemSs : OpCodeMemReg, IOpCodeSimd - { - public int SElems { get; } - public int Index { get; } - public bool Replicate { get; } - public bool WBack { get; } - - public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeSimdMemSs(inst, address, opCode); - - public OpCodeSimdMemSs(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode) - { - int size = (opCode >> 10) & 3; - int s = (opCode >> 12) & 1; - int sElems = (opCode >> 12) & 2; - int scale = (opCode >> 14) & 3; - int l = (opCode >> 22) & 1; - int q = (opCode >> 30) & 1; - - sElems |= (opCode >> 21) & 1; - - sElems++; - - int index = (q << 3) | (s << 2) | size; - - switch (scale) - { - case 1: - { - if ((size & 1) != 0) - { - Instruction = InstDescriptor.Undefined; - - return; - } - - index >>= 1; - - break; - } - - case 2: - { - if ((size & 2) != 0 || - ((size & 1) != 0 && s != 0)) - { - Instruction = InstDescriptor.Undefined; - - return; - } - - if ((size & 1) != 0) - { - index >>= 3; - - scale = 3; - } - else - { - index >>= 2; - } - - break; - } - - case 3: - { - if (l == 0 || s != 0) - { - Instruction = InstDescriptor.Undefined; - - return; - } - - scale = size; - - Replicate = true; - - break; - } - } - - Index = index; - SElems = sElems; - Size = scale; - - Extend64 = false; - - WBack = ((opCode >> 23) & 1) != 0; - - RegisterSize = q != 0 - ? RegisterSize.Simd128 - : RegisterSize.Simd64; - } - } -} \ No newline at end of file diff --git a/ARMeilleure/Decoders/OpCodeSimdReg.cs b/ARMeilleure/Decoders/OpCodeSimdReg.cs deleted file mode 100644 index ac4f71dae..000000000 --- a/ARMeilleure/Decoders/OpCodeSimdReg.cs +++ /dev/null @@ -1,18 +0,0 @@ -namespace ARMeilleure.Decoders -{ - class OpCodeSimdReg : OpCodeSimd - { - public bool Bit3 { get; } - public int Ra { get; } - public int Rm { get; protected set; } - - public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeSimdReg(inst, address, opCode); - - public OpCodeSimdReg(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode) - { - Bit3 = ((opCode >> 3) & 0x1) != 0; - Ra = (opCode >> 10) & 0x1f; - Rm = (opCode >> 16) & 0x1f; - } - } -} \ No newline at end of file diff --git a/ARMeilleure/Decoders/OpCodeSystem.cs b/ARMeilleure/Decoders/OpCodeSystem.cs deleted file mode 100644 index 4d79421a8..000000000 --- a/ARMeilleure/Decoders/OpCodeSystem.cs +++ /dev/null @@ -1,24 +0,0 @@ -namespace ARMeilleure.Decoders -{ - class OpCodeSystem : OpCode - { - public int Rt { get; } - public int Op2 { get; } - public int CRm { get; } - public int CRn { get; } - public int Op1 { get; } - public int Op0 { get; } - - public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeSystem(inst, address, opCode); - - public OpCodeSystem(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode) - { - Rt = (opCode >> 0) & 0x1f; - Op2 = (opCode >> 5) & 0x7; - CRm = (opCode >> 8) & 0xf; - CRn = (opCode >> 12) & 0xf; - Op1 = (opCode >> 16) & 0x7; - Op0 = ((opCode >> 19) & 0x1) | 2; - } - } -} \ No newline at end of file diff --git a/ARMeilleure/Decoders/OpCodeT16MemImm5.cs b/ARMeilleure/Decoders/OpCodeT16MemImm5.cs deleted file mode 100644 index 20ef31e27..000000000 --- a/ARMeilleure/Decoders/OpCodeT16MemImm5.cs +++ /dev/null @@ -1,58 +0,0 @@ -using ARMeilleure.Instructions; -using System; - -namespace ARMeilleure.Decoders -{ - class OpCodeT16MemImm5 : OpCodeT16, IOpCode32Mem - { - public int Rt { get; } - public int Rn { get; } - - public bool WBack => false; - public bool IsLoad { get; } - public bool Index => true; - public bool Add => true; - - public int Immediate { get; } - - public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT16MemImm5(inst, address, opCode); - - public OpCodeT16MemImm5(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode) - { - Rt = (opCode >> 0) & 7; - Rn = (opCode >> 3) & 7; - - switch (inst.Name) - { - case InstName.Ldr: - case InstName.Ldrb: - case InstName.Ldrh: - IsLoad = true; - break; - case InstName.Str: - case InstName.Strb: - case InstName.Strh: - IsLoad = false; - break; - } - - switch (inst.Name) - { - case InstName.Str: - case InstName.Ldr: - Immediate = ((opCode >> 6) & 0x1f) << 2; - break; - case InstName.Strb: - case InstName.Ldrb: - Immediate = ((opCode >> 6) & 0x1f); - break; - case InstName.Strh: - case InstName.Ldrh: - Immediate = ((opCode >> 6) & 0x1f) << 1; - break; - default: - throw new InvalidOperationException(); - } - } - } -} diff --git a/ARMeilleure/Diagnostics/Logger.cs b/ARMeilleure/Diagnostics/Logger.cs deleted file mode 100644 index 07a60667e..000000000 --- a/ARMeilleure/Diagnostics/Logger.cs +++ /dev/null @@ -1,56 +0,0 @@ -using ARMeilleure.Translation; -using System; -using System.Diagnostics; - -namespace ARMeilleure.Diagnostics -{ - static class Logger - { - private static long _startTime; - - private static long[] _accumulatedTime; - - static Logger() - { - _accumulatedTime = new long[(int)PassName.Count]; - } - - [Conditional("M_DEBUG")] - public static void StartPass(PassName name) - { - WriteOutput(name + " pass started..."); - - _startTime = Stopwatch.GetTimestamp(); - } - - [Conditional("M_DEBUG")] - public static void EndPass(PassName name, ControlFlowGraph cfg) - { - EndPass(name); - - WriteOutput("IR after " + name + " pass:"); - - WriteOutput(IRDumper.GetDump(cfg)); - } - - [Conditional("M_DEBUG")] - public static void EndPass(PassName name) - { - long elapsedTime = Stopwatch.GetTimestamp() - _startTime; - - _accumulatedTime[(int)name] += elapsedTime; - - WriteOutput($"{name} pass ended after {GetMilliseconds(_accumulatedTime[(int)name])} ms..."); - } - - private static long GetMilliseconds(long ticks) - { - return (long)(((double)ticks / Stopwatch.Frequency) * 1000); - } - - private static void WriteOutput(string text) - { - Console.WriteLine(text); - } - } -} \ No newline at end of file diff --git a/ARMeilleure/Instructions/InstEmitAluHelper.cs b/ARMeilleure/Instructions/InstEmitAluHelper.cs deleted file mode 100644 index 994878ad7..000000000 --- a/ARMeilleure/Instructions/InstEmitAluHelper.cs +++ /dev/null @@ -1,613 +0,0 @@ -using ARMeilleure.Decoders; -using ARMeilleure.IntermediateRepresentation; -using ARMeilleure.State; -using ARMeilleure.Translation; -using System; -using System.Diagnostics; - -using static ARMeilleure.Instructions.InstEmitHelper; -using static ARMeilleure.IntermediateRepresentation.Operand.Factory; - -namespace ARMeilleure.Instructions -{ - static class InstEmitAluHelper - { - public static bool ShouldSetFlags(ArmEmitterContext context) - { - IOpCode32HasSetFlags op = (IOpCode32HasSetFlags)context.CurrOp; - - if (op.SetFlags == null) - { - return !context.IsInIfThenBlock; - } - - return op.SetFlags.Value; - } - - public static void EmitNZFlagsCheck(ArmEmitterContext context, Operand d) - { - SetFlag(context, PState.NFlag, context.ICompareLess (d, Const(d.Type, 0))); - SetFlag(context, PState.ZFlag, context.ICompareEqual(d, Const(d.Type, 0))); - } - - public static void EmitAdcsCCheck(ArmEmitterContext context, Operand n, Operand d) - { - // C = (Rd == Rn && CIn) || Rd < Rn - Operand cIn = GetFlag(PState.CFlag); - - Operand cOut = context.BitwiseAnd(context.ICompareEqual(d, n), cIn); - - cOut = context.BitwiseOr(cOut, context.ICompareLessUI(d, n)); - - SetFlag(context, PState.CFlag, cOut); - } - - public static void EmitAddsCCheck(ArmEmitterContext context, Operand n, Operand d) - { - // C = Rd < Rn - SetFlag(context, PState.CFlag, context.ICompareLessUI(d, n)); - } - - public static void EmitAddsVCheck(ArmEmitterContext context, Operand n, Operand m, Operand d) - { - // V = (Rd ^ Rn) & ~(Rn ^ Rm) < 0 - Operand vOut = context.BitwiseExclusiveOr(d, n); - - vOut = context.BitwiseAnd(vOut, context.BitwiseNot(context.BitwiseExclusiveOr(n, m))); - - vOut = context.ICompareLess(vOut, Const(vOut.Type, 0)); - - SetFlag(context, PState.VFlag, vOut); - } - - public static void EmitSbcsCCheck(ArmEmitterContext context, Operand n, Operand m) - { - // C = (Rn == Rm && CIn) || Rn > Rm - Operand cIn = GetFlag(PState.CFlag); - - Operand cOut = context.BitwiseAnd(context.ICompareEqual(n, m), cIn); - - cOut = context.BitwiseOr(cOut, context.ICompareGreaterUI(n, m)); - - SetFlag(context, PState.CFlag, cOut); - } - - public static void EmitSubsCCheck(ArmEmitterContext context, Operand n, Operand m) - { - // C = Rn >= Rm - SetFlag(context, PState.CFlag, context.ICompareGreaterOrEqualUI(n, m)); - } - - public static void EmitSubsVCheck(ArmEmitterContext context, Operand n, Operand m, Operand d) - { - // V = (Rd ^ Rn) & (Rn ^ Rm) < 0 - Operand vOut = context.BitwiseExclusiveOr(d, n); - - vOut = context.BitwiseAnd(vOut, context.BitwiseExclusiveOr(n, m)); - - vOut = context.ICompareLess(vOut, Const(vOut.Type, 0)); - - SetFlag(context, PState.VFlag, vOut); - } - - public static Operand EmitReverseBits32Op(ArmEmitterContext context, Operand op) - { - Debug.Assert(op.Type == OperandType.I32); - - Operand val = context.BitwiseOr(context.ShiftRightUI(context.BitwiseAnd(op, Const(0xaaaaaaaau)), Const(1)), - context.ShiftLeft(context.BitwiseAnd(op, Const(0x55555555u)), Const(1))); - - val = context.BitwiseOr(context.ShiftRightUI(context.BitwiseAnd(val, Const(0xccccccccu)), Const(2)), - context.ShiftLeft(context.BitwiseAnd(val, Const(0x33333333u)), Const(2))); - val = context.BitwiseOr(context.ShiftRightUI(context.BitwiseAnd(val, Const(0xf0f0f0f0u)), Const(4)), - context.ShiftLeft(context.BitwiseAnd(val, Const(0x0f0f0f0fu)), Const(4))); - val = context.BitwiseOr(context.ShiftRightUI(context.BitwiseAnd(val, Const(0xff00ff00u)), Const(8)), - context.ShiftLeft(context.BitwiseAnd(val, Const(0x00ff00ffu)), Const(8))); - - return context.BitwiseOr(context.ShiftRightUI(val, Const(16)), context.ShiftLeft(val, Const(16))); - } - - public static Operand EmitReverseBytes16_64Op(ArmEmitterContext context, Operand op) - { - Debug.Assert(op.Type == OperandType.I64); - - return context.BitwiseOr(context.ShiftRightUI(context.BitwiseAnd(op, Const(0xff00ff00ff00ff00ul)), Const(8)), - context.ShiftLeft(context.BitwiseAnd(op, Const(0x00ff00ff00ff00fful)), Const(8))); - } - - public static Operand EmitReverseBytes16_32Op(ArmEmitterContext context, Operand op) - { - Debug.Assert(op.Type == OperandType.I32); - - Operand val = EmitReverseBytes16_64Op(context, context.ZeroExtend32(OperandType.I64, op)); - - return context.ConvertI64ToI32(val); - } - - private static void EmitAluWritePc(ArmEmitterContext context, Operand value) - { - Debug.Assert(value.Type == OperandType.I32); - - if (((OpCode32)context.CurrOp).IsThumb) - { - bool isReturn = IsA32Return(context); - if (!isReturn) - { - context.StoreToContext(); - } - - InstEmitFlowHelper.EmitVirtualJump(context, value, isReturn); - } - else - { - EmitBxWritePc(context, value); - } - } - - public static void EmitGenericAluStoreA32(ArmEmitterContext context, int rd, bool setFlags, Operand value) - { - Debug.Assert(value.Type == OperandType.I32); - - if (rd == RegisterAlias.Aarch32Pc && setFlags) - { - if (setFlags) - { - // TODO: Load SPSR etc. - - EmitBxWritePc(context, value); - } - else - { - EmitAluWritePc(context, value); - } - } - else - { - SetIntA32(context, rd, value); - } - } - - public static Operand GetAluN(ArmEmitterContext context) - { - if (context.CurrOp is IOpCodeAlu op) - { - if (op.DataOp == DataOp.Logical || op is IOpCodeAluRs) - { - return GetIntOrZR(context, op.Rn); - } - else - { - return GetIntOrSP(context, op.Rn); - } - } - else if (context.CurrOp is IOpCode32Alu op32) - { - return GetIntA32(context, op32.Rn); - } - else - { - throw InvalidOpCodeType(context.CurrOp); - } - } - - public static Operand GetAluM(ArmEmitterContext context, bool setCarry = true) - { - switch (context.CurrOp) - { - // ARM32. - case IOpCode32AluImm op: - { - if (ShouldSetFlags(context) && op.IsRotated && setCarry) - { - SetFlag(context, PState.CFlag, Const((uint)op.Immediate >> 31)); - } - - return Const(op.Immediate); - } - - case IOpCode32AluImm16 op: return Const(op.Immediate); - - case IOpCode32AluRsImm op: return GetMShiftedByImmediate(context, op, setCarry); - case IOpCode32AluRsReg op: return GetMShiftedByReg(context, op, setCarry); - - case IOpCode32AluReg op: return GetIntA32(context, op.Rm); - - // ARM64. - case IOpCodeAluImm op: - { - if (op.GetOperandType() == OperandType.I32) - { - return Const((int)op.Immediate); - } - else - { - return Const(op.Immediate); - } - } - - case IOpCodeAluRs op: - { - Operand value = GetIntOrZR(context, op.Rm); - - switch (op.ShiftType) - { - case ShiftType.Lsl: value = context.ShiftLeft (value, Const(op.Shift)); break; - case ShiftType.Lsr: value = context.ShiftRightUI(value, Const(op.Shift)); break; - case ShiftType.Asr: value = context.ShiftRightSI(value, Const(op.Shift)); break; - case ShiftType.Ror: value = context.RotateRight (value, Const(op.Shift)); break; - } - - return value; - } - - case IOpCodeAluRx op: - { - Operand value = GetExtendedM(context, op.Rm, op.IntType); - - value = context.ShiftLeft(value, Const(op.Shift)); - - return value; - } - - default: throw InvalidOpCodeType(context.CurrOp); - } - } - - private static Exception InvalidOpCodeType(OpCode opCode) - { - return new InvalidOperationException($"Invalid OpCode type \"{opCode?.GetType().Name ?? "null"}\"."); - } - - // ARM32 helpers. - public static Operand GetMShiftedByImmediate(ArmEmitterContext context, IOpCode32AluRsImm op, bool setCarry) - { - Operand m = GetIntA32(context, op.Rm); - - int shift = op.Immediate; - - if (shift == 0) - { - switch (op.ShiftType) - { - case ShiftType.Lsr: shift = 32; break; - case ShiftType.Asr: shift = 32; break; - case ShiftType.Ror: shift = 1; break; - } - } - - if (shift != 0) - { - setCarry &= ShouldSetFlags(context); - - switch (op.ShiftType) - { - case ShiftType.Lsl: m = GetLslC(context, m, setCarry, shift); break; - case ShiftType.Lsr: m = GetLsrC(context, m, setCarry, shift); break; - case ShiftType.Asr: m = GetAsrC(context, m, setCarry, shift); break; - case ShiftType.Ror: - if (op.Immediate != 0) - { - m = GetRorC(context, m, setCarry, shift); - } - else - { - m = GetRrxC(context, m, setCarry); - } - break; - } - } - - return m; - } - - public static int DecodeImmShift(ShiftType shiftType, int shift) - { - if (shift == 0) - { - switch (shiftType) - { - case ShiftType.Lsr: shift = 32; break; - case ShiftType.Asr: shift = 32; break; - case ShiftType.Ror: shift = 1; break; - } - } - - return shift; - } - - public static Operand GetMShiftedByReg(ArmEmitterContext context, IOpCode32AluRsReg op, bool setCarry) - { - Operand m = GetIntA32(context, op.Rm); - Operand s = context.ZeroExtend8(OperandType.I32, GetIntA32(context, op.Rs)); - Operand shiftIsZero = context.ICompareEqual(s, Const(0)); - - Operand zeroResult = m; - Operand shiftResult = m; - - setCarry &= ShouldSetFlags(context); - - switch (op.ShiftType) - { - case ShiftType.Lsl: shiftResult = EmitLslC(context, m, setCarry, s, shiftIsZero); break; - case ShiftType.Lsr: shiftResult = EmitLsrC(context, m, setCarry, s, shiftIsZero); break; - case ShiftType.Asr: shiftResult = EmitAsrC(context, m, setCarry, s, shiftIsZero); break; - case ShiftType.Ror: shiftResult = EmitRorC(context, m, setCarry, s, shiftIsZero); break; - } - - return context.ConditionalSelect(shiftIsZero, zeroResult, shiftResult); - } - - public static void EmitIfHelper(ArmEmitterContext context, Operand boolValue, Action action, bool expected = true) - { - Debug.Assert(boolValue.Type == OperandType.I32); - - Operand endLabel = Label(); - - if (expected) - { - context.BranchIfFalse(endLabel, boolValue); - } - else - { - context.BranchIfTrue(endLabel, boolValue); - } - - action(); - - context.MarkLabel(endLabel); - } - - public static Operand EmitLslC(ArmEmitterContext context, Operand m, bool setCarry, Operand shift, Operand shiftIsZero) - { - Debug.Assert(m.Type == OperandType.I32 && shift.Type == OperandType.I32 && shiftIsZero.Type == OperandType.I32); - - Operand shiftLarge = context.ICompareGreaterOrEqual(shift, Const(32)); - Operand result = context.ShiftLeft(m, shift); - if (setCarry) - { - EmitIfHelper(context, shiftIsZero, () => - { - Operand cOut = context.ShiftRightUI(m, context.Subtract(Const(32), shift)); - - cOut = context.BitwiseAnd(cOut, Const(1)); - cOut = context.ConditionalSelect(context.ICompareGreater(shift, Const(32)), Const(0), cOut); - - SetFlag(context, PState.CFlag, cOut); - }, false); - } - - return context.ConditionalSelect(shiftLarge, Const(0), result); - } - - public static Operand GetLslC(ArmEmitterContext context, Operand m, bool setCarry, int shift) - { - Debug.Assert(m.Type == OperandType.I32); - - if ((uint)shift > 32) - { - return GetShiftByMoreThan32(context, setCarry); - } - else if (shift == 32) - { - if (setCarry) - { - SetCarryMLsb(context, m); - } - - return Const(0); - } - else - { - if (setCarry) - { - Operand cOut = context.ShiftRightUI(m, Const(32 - shift)); - - cOut = context.BitwiseAnd(cOut, Const(1)); - - SetFlag(context, PState.CFlag, cOut); - } - - return context.ShiftLeft(m, Const(shift)); - } - } - - public static Operand EmitLsrC(ArmEmitterContext context, Operand m, bool setCarry, Operand shift, Operand shiftIsZero) - { - Debug.Assert(m.Type == OperandType.I32 && shift.Type == OperandType.I32 && shiftIsZero.Type == OperandType.I32); - - Operand shiftLarge = context.ICompareGreaterOrEqual(shift, Const(32)); - Operand result = context.ShiftRightUI(m, shift); - if (setCarry) - { - EmitIfHelper(context, shiftIsZero, () => - { - Operand cOut = context.ShiftRightUI(m, context.Subtract(shift, Const(1))); - - cOut = context.BitwiseAnd(cOut, Const(1)); - cOut = context.ConditionalSelect(context.ICompareGreater(shift, Const(32)), Const(0), cOut); - - SetFlag(context, PState.CFlag, cOut); - }, false); - } - - return context.ConditionalSelect(shiftLarge, Const(0), result); - } - - public static Operand GetLsrC(ArmEmitterContext context, Operand m, bool setCarry, int shift) - { - Debug.Assert(m.Type == OperandType.I32); - - if ((uint)shift > 32) - { - return GetShiftByMoreThan32(context, setCarry); - } - else if (shift == 32) - { - if (setCarry) - { - SetCarryMMsb(context, m); - } - - return Const(0); - } - else - { - if (setCarry) - { - SetCarryMShrOut(context, m, shift); - } - - return context.ShiftRightUI(m, Const(shift)); - } - } - - private static Operand GetShiftByMoreThan32(ArmEmitterContext context, bool setCarry) - { - if (setCarry) - { - SetFlag(context, PState.CFlag, Const(0)); - } - - return Const(0); - } - - public static Operand EmitAsrC(ArmEmitterContext context, Operand m, bool setCarry, Operand shift, Operand shiftIsZero) - { - Debug.Assert(m.Type == OperandType.I32 && shift.Type == OperandType.I32 && shiftIsZero.Type == OperandType.I32); - - Operand l32Result; - Operand ge32Result; - - Operand less32 = context.ICompareLess(shift, Const(32)); - - ge32Result = context.ShiftRightSI(m, Const(31)); - - if (setCarry) - { - EmitIfHelper(context, context.BitwiseOr(less32, shiftIsZero), () => - { - SetCarryMLsb(context, ge32Result); - }, false); - } - - l32Result = context.ShiftRightSI(m, shift); - if (setCarry) - { - EmitIfHelper(context, context.BitwiseAnd(less32, context.BitwiseNot(shiftIsZero)), () => - { - Operand cOut = context.ShiftRightUI(m, context.Subtract(shift, Const(1))); - - cOut = context.BitwiseAnd(cOut, Const(1)); - - SetFlag(context, PState.CFlag, cOut); - }); - } - - return context.ConditionalSelect(less32, l32Result, ge32Result); - } - - public static Operand GetAsrC(ArmEmitterContext context, Operand m, bool setCarry, int shift) - { - Debug.Assert(m.Type == OperandType.I32); - - if ((uint)shift >= 32) - { - m = context.ShiftRightSI(m, Const(31)); - - if (setCarry) - { - SetCarryMLsb(context, m); - } - - return m; - } - else - { - if (setCarry) - { - SetCarryMShrOut(context, m, shift); - } - - return context.ShiftRightSI(m, Const(shift)); - } - } - - public static Operand EmitRorC(ArmEmitterContext context, Operand m, bool setCarry, Operand shift, Operand shiftIsZero) - { - Debug.Assert(m.Type == OperandType.I32 && shift.Type == OperandType.I32 && shiftIsZero.Type == OperandType.I32); - - shift = context.BitwiseAnd(shift, Const(0x1f)); - m = context.RotateRight(m, shift); - - if (setCarry) - { - EmitIfHelper(context, shiftIsZero, () => - { - SetCarryMMsb(context, m); - }, false); - } - - return m; - } - - public static Operand GetRorC(ArmEmitterContext context, Operand m, bool setCarry, int shift) - { - Debug.Assert(m.Type == OperandType.I32); - - shift &= 0x1f; - - m = context.RotateRight(m, Const(shift)); - - if (setCarry) - { - SetCarryMMsb(context, m); - } - - return m; - } - - public static Operand GetRrxC(ArmEmitterContext context, Operand m, bool setCarry) - { - Debug.Assert(m.Type == OperandType.I32); - - // Rotate right by 1 with carry. - Operand cIn = context.Copy(GetFlag(PState.CFlag)); - - if (setCarry) - { - SetCarryMLsb(context, m); - } - - m = context.ShiftRightUI(m, Const(1)); - - m = context.BitwiseOr(m, context.ShiftLeft(cIn, Const(31))); - - return m; - } - - private static void SetCarryMLsb(ArmEmitterContext context, Operand m) - { - Debug.Assert(m.Type == OperandType.I32); - - SetFlag(context, PState.CFlag, context.BitwiseAnd(m, Const(1))); - } - - private static void SetCarryMMsb(ArmEmitterContext context, Operand m) - { - Debug.Assert(m.Type == OperandType.I32); - - SetFlag(context, PState.CFlag, context.ShiftRightUI(m, Const(31))); - } - - private static void SetCarryMShrOut(ArmEmitterContext context, Operand m, int shift) - { - Debug.Assert(m.Type == OperandType.I32); - - Operand cOut = context.ShiftRightUI(m, Const(shift - 1)); - - cOut = context.BitwiseAnd(cOut, Const(1)); - - SetFlag(context, PState.CFlag, cOut); - } - } -} diff --git a/ARMeilleure/Instructions/InstEmitHelper.cs b/ARMeilleure/Instructions/InstEmitHelper.cs deleted file mode 100644 index a22bb3fb7..000000000 --- a/ARMeilleure/Instructions/InstEmitHelper.cs +++ /dev/null @@ -1,264 +0,0 @@ -using ARMeilleure.Decoders; -using ARMeilleure.IntermediateRepresentation; -using ARMeilleure.State; -using ARMeilleure.Translation; -using System; - -using static ARMeilleure.IntermediateRepresentation.Operand.Factory; - -namespace ARMeilleure.Instructions -{ - static class InstEmitHelper - { - public static Operand GetExtendedM(ArmEmitterContext context, int rm, IntType type) - { - Operand value = GetIntOrZR(context, rm); - - switch (type) - { - case IntType.UInt8: value = context.ZeroExtend8 (value.Type, value); break; - case IntType.UInt16: value = context.ZeroExtend16(value.Type, value); break; - case IntType.UInt32: value = context.ZeroExtend32(value.Type, value); break; - - case IntType.Int8: value = context.SignExtend8 (value.Type, value); break; - case IntType.Int16: value = context.SignExtend16(value.Type, value); break; - case IntType.Int32: value = context.SignExtend32(value.Type, value); break; - } - - return value; - } - - public static Operand GetIntA32(ArmEmitterContext context, int regIndex) - { - if (regIndex == RegisterAlias.Aarch32Pc) - { - OpCode32 op = (OpCode32)context.CurrOp; - - return Const((int)op.GetPc()); - } - else - { - return Register(GetRegisterAlias(context.Mode, regIndex), RegisterType.Integer, OperandType.I32); - } - } - - public static Operand GetIntA32AlignedPC(ArmEmitterContext context, int regIndex) - { - if (regIndex == RegisterAlias.Aarch32Pc) - { - OpCode32 op = (OpCode32)context.CurrOp; - - return Const((int)(op.GetPc() & 0xfffffffc)); - } - else - { - return Register(GetRegisterAlias(context.Mode, regIndex), RegisterType.Integer, OperandType.I32); - } - } - - public static Operand GetVecA32(int regIndex) - { - return Register(regIndex, RegisterType.Vector, OperandType.V128); - } - - public static void SetIntA32(ArmEmitterContext context, int regIndex, Operand value) - { - if (regIndex == RegisterAlias.Aarch32Pc) - { - if (!IsA32Return(context)) - { - context.StoreToContext(); - } - - EmitBxWritePc(context, value); - } - else - { - if (value.Type == OperandType.I64) - { - value = context.ConvertI64ToI32(value); - } - Operand reg = Register(GetRegisterAlias(context.Mode, regIndex), RegisterType.Integer, OperandType.I32); - - context.Copy(reg, value); - } - } - - public static int GetRegisterAlias(Aarch32Mode mode, int regIndex) - { - // Only registers >= 8 are banked, - // with registers in the range [8, 12] being - // banked for the FIQ mode, and registers - // 13 and 14 being banked for all modes. - if ((uint)regIndex < 8) - { - return regIndex; - } - - return GetBankedRegisterAlias(mode, regIndex); - } - - public static int GetBankedRegisterAlias(Aarch32Mode mode, int regIndex) - { - switch (regIndex) - { - case 8: return mode == Aarch32Mode.Fiq - ? RegisterAlias.R8Fiq - : RegisterAlias.R8Usr; - - case 9: return mode == Aarch32Mode.Fiq - ? RegisterAlias.R9Fiq - : RegisterAlias.R9Usr; - - case 10: return mode == Aarch32Mode.Fiq - ? RegisterAlias.R10Fiq - : RegisterAlias.R10Usr; - - case 11: return mode == Aarch32Mode.Fiq - ? RegisterAlias.R11Fiq - : RegisterAlias.R11Usr; - - case 12: return mode == Aarch32Mode.Fiq - ? RegisterAlias.R12Fiq - : RegisterAlias.R12Usr; - - case 13: - switch (mode) - { - case Aarch32Mode.User: - case Aarch32Mode.System: return RegisterAlias.SpUsr; - case Aarch32Mode.Fiq: return RegisterAlias.SpFiq; - case Aarch32Mode.Irq: return RegisterAlias.SpIrq; - case Aarch32Mode.Supervisor: return RegisterAlias.SpSvc; - case Aarch32Mode.Abort: return RegisterAlias.SpAbt; - case Aarch32Mode.Hypervisor: return RegisterAlias.SpHyp; - case Aarch32Mode.Undefined: return RegisterAlias.SpUnd; - - default: throw new ArgumentException(nameof(mode)); - } - - case 14: - switch (mode) - { - case Aarch32Mode.User: - case Aarch32Mode.Hypervisor: - case Aarch32Mode.System: return RegisterAlias.LrUsr; - case Aarch32Mode.Fiq: return RegisterAlias.LrFiq; - case Aarch32Mode.Irq: return RegisterAlias.LrIrq; - case Aarch32Mode.Supervisor: return RegisterAlias.LrSvc; - case Aarch32Mode.Abort: return RegisterAlias.LrAbt; - case Aarch32Mode.Undefined: return RegisterAlias.LrUnd; - - default: throw new ArgumentException(nameof(mode)); - } - - default: throw new ArgumentOutOfRangeException(nameof(regIndex)); - } - } - - public static bool IsA32Return(ArmEmitterContext context) - { - switch (context.CurrOp) - { - case IOpCode32MemMult op: - return true; // Setting PC using LDM is nearly always a return. - case OpCode32AluRsImm op: - return op.Rm == RegisterAlias.Aarch32Lr; - case OpCode32AluRsReg op: - return op.Rm == RegisterAlias.Aarch32Lr; - case OpCode32AluReg op: - return op.Rm == RegisterAlias.Aarch32Lr; - case OpCode32Mem op: - return op.Rn == RegisterAlias.Aarch32Sp && op.WBack && !op.Index; // Setting PC to an address stored on the stack is nearly always a return. - } - return false; - } - - public static void EmitBxWritePc(ArmEmitterContext context, Operand pc, int sourceRegister = 0) - { - bool isReturn = sourceRegister == RegisterAlias.Aarch32Lr || IsA32Return(context); - Operand mode = context.BitwiseAnd(pc, Const(1)); - - SetFlag(context, PState.TFlag, mode); - - Operand addr = context.ConditionalSelect(mode, context.BitwiseAnd(pc, Const(~1)), context.BitwiseAnd(pc, Const(~3))); - - InstEmitFlowHelper.EmitVirtualJump(context, addr, isReturn); - } - - public static Operand GetIntOrZR(ArmEmitterContext context, int regIndex) - { - if (regIndex == RegisterConsts.ZeroIndex) - { - OperandType type = context.CurrOp.GetOperandType(); - - return type == OperandType.I32 ? Const(0) : Const(0L); - } - else - { - return GetIntOrSP(context, regIndex); - } - } - - public static void SetIntOrZR(ArmEmitterContext context, int regIndex, Operand value) - { - if (regIndex == RegisterConsts.ZeroIndex) - { - return; - } - - SetIntOrSP(context, regIndex, value); - } - - public static Operand GetIntOrSP(ArmEmitterContext context, int regIndex) - { - Operand value = Register(regIndex, RegisterType.Integer, OperandType.I64); - - if (context.CurrOp.RegisterSize == RegisterSize.Int32) - { - value = context.ConvertI64ToI32(value); - } - - return value; - } - - public static void SetIntOrSP(ArmEmitterContext context, int regIndex, Operand value) - { - Operand reg = Register(regIndex, RegisterType.Integer, OperandType.I64); - - if (value.Type == OperandType.I32) - { - value = context.ZeroExtend32(OperandType.I64, value); - } - - context.Copy(reg, value); - } - - public static Operand GetVec(int regIndex) - { - return Register(regIndex, RegisterType.Vector, OperandType.V128); - } - - public static Operand GetFlag(PState stateFlag) - { - return Register((int)stateFlag, RegisterType.Flag, OperandType.I32); - } - - public static Operand GetFpFlag(FPState stateFlag) - { - return Register((int)stateFlag, RegisterType.FpFlag, OperandType.I32); - } - - public static void SetFlag(ArmEmitterContext context, PState stateFlag, Operand value) - { - context.Copy(GetFlag(stateFlag), value); - - context.MarkFlagSet(stateFlag); - } - - public static void SetFpFlag(ArmEmitterContext context, FPState stateFlag, Operand value) - { - context.Copy(GetFpFlag(stateFlag), value); - } - } -} diff --git a/ARMeilleure/Instructions/InstEmitMemory.cs b/ARMeilleure/Instructions/InstEmitMemory.cs deleted file mode 100644 index 7baed14c8..000000000 --- a/ARMeilleure/Instructions/InstEmitMemory.cs +++ /dev/null @@ -1,184 +0,0 @@ -using ARMeilleure.Decoders; -using ARMeilleure.IntermediateRepresentation; -using ARMeilleure.Translation; - -using static ARMeilleure.Instructions.InstEmitHelper; -using static ARMeilleure.Instructions.InstEmitMemoryHelper; -using static ARMeilleure.IntermediateRepresentation.Operand.Factory; - -namespace ARMeilleure.Instructions -{ - static partial class InstEmit - { - public static void Adr(ArmEmitterContext context) - { - OpCodeAdr op = (OpCodeAdr)context.CurrOp; - - SetIntOrZR(context, op.Rd, Const(op.Address + (ulong)op.Immediate)); - } - - public static void Adrp(ArmEmitterContext context) - { - OpCodeAdr op = (OpCodeAdr)context.CurrOp; - - ulong address = (op.Address & ~0xfffUL) + ((ulong)op.Immediate << 12); - - SetIntOrZR(context, op.Rd, Const(address)); - } - - public static void Ldr(ArmEmitterContext context) => EmitLdr(context, signed: false); - public static void Ldrs(ArmEmitterContext context) => EmitLdr(context, signed: true); - - private static void EmitLdr(ArmEmitterContext context, bool signed) - { - OpCodeMem op = (OpCodeMem)context.CurrOp; - - Operand address = GetAddress(context); - - if (signed && op.Extend64) - { - EmitLoadSx64(context, address, op.Rt, op.Size); - } - else if (signed) - { - EmitLoadSx32(context, address, op.Rt, op.Size); - } - else - { - EmitLoadZx(context, address, op.Rt, op.Size); - } - - EmitWBackIfNeeded(context, address); - } - - public static void Ldr_Literal(ArmEmitterContext context) - { - IOpCodeLit op = (IOpCodeLit)context.CurrOp; - - if (op.Prefetch) - { - return; - } - - if (op.Signed) - { - EmitLoadSx64(context, Const(op.Immediate), op.Rt, op.Size); - } - else - { - EmitLoadZx(context, Const(op.Immediate), op.Rt, op.Size); - } - } - - public static void Ldp(ArmEmitterContext context) - { - OpCodeMemPair op = (OpCodeMemPair)context.CurrOp; - - void EmitLoad(int rt, Operand ldAddr) - { - if (op.Extend64) - { - EmitLoadSx64(context, ldAddr, rt, op.Size); - } - else - { - EmitLoadZx(context, ldAddr, rt, op.Size); - } - } - - Operand address = GetAddress(context); - Operand address2 = GetAddress(context, 1L << op.Size); - - EmitLoad(op.Rt, address); - EmitLoad(op.Rt2, address2); - - EmitWBackIfNeeded(context, address); - } - - public static void Str(ArmEmitterContext context) - { - OpCodeMem op = (OpCodeMem)context.CurrOp; - - Operand address = GetAddress(context); - - EmitStore(context, address, op.Rt, op.Size); - - EmitWBackIfNeeded(context, address); - } - - public static void Stp(ArmEmitterContext context) - { - OpCodeMemPair op = (OpCodeMemPair)context.CurrOp; - - Operand address = GetAddress(context); - Operand address2 = GetAddress(context, 1L << op.Size); - - EmitStore(context, address, op.Rt, op.Size); - EmitStore(context, address2, op.Rt2, op.Size); - - EmitWBackIfNeeded(context, address); - } - - private static Operand GetAddress(ArmEmitterContext context, long addend = 0) - { - Operand address = default; - - switch (context.CurrOp) - { - case OpCodeMemImm op: - { - address = context.Copy(GetIntOrSP(context, op.Rn)); - - // Pre-indexing. - if (!op.PostIdx) - { - address = context.Add(address, Const(op.Immediate + addend)); - } - else if (addend != 0) - { - address = context.Add(address, Const(addend)); - } - - break; - } - - case OpCodeMemReg op: - { - Operand n = GetIntOrSP(context, op.Rn); - - Operand m = GetExtendedM(context, op.Rm, op.IntType); - - if (op.Shift) - { - m = context.ShiftLeft(m, Const(op.Size)); - } - - address = context.Add(n, m); - - if (addend != 0) - { - address = context.Add(address, Const(addend)); - } - - break; - } - } - - return address; - } - - private static void EmitWBackIfNeeded(ArmEmitterContext context, Operand address) - { - // Check whenever the current OpCode has post-indexed write back, if so write it. - if (context.CurrOp is OpCodeMemImm op && op.WBack) - { - if (op.PostIdx) - { - address = context.Add(address, Const(op.Immediate)); - } - - SetIntOrSP(context, op.Rn, address); - } - } - } -} \ No newline at end of file diff --git a/ARMeilleure/Instructions/InstEmitMemoryHelper.cs b/ARMeilleure/Instructions/InstEmitMemoryHelper.cs deleted file mode 100644 index f97e395ce..000000000 --- a/ARMeilleure/Instructions/InstEmitMemoryHelper.cs +++ /dev/null @@ -1,648 +0,0 @@ -using ARMeilleure.Decoders; -using ARMeilleure.IntermediateRepresentation; -using ARMeilleure.Memory; -using ARMeilleure.Translation; -using ARMeilleure.Translation.PTC; -using System; -using System.Reflection; - -using static ARMeilleure.Instructions.InstEmitHelper; -using static ARMeilleure.IntermediateRepresentation.Operand.Factory; - -namespace ARMeilleure.Instructions -{ - static class InstEmitMemoryHelper - { - private const int PageBits = 12; - private const int PageMask = (1 << PageBits) - 1; - - private enum Extension - { - Zx, - Sx32, - Sx64 - } - - public static void EmitLoadZx(ArmEmitterContext context, Operand address, int rt, int size) - { - EmitLoad(context, address, Extension.Zx, rt, size); - } - - public static void EmitLoadSx32(ArmEmitterContext context, Operand address, int rt, int size) - { - EmitLoad(context, address, Extension.Sx32, rt, size); - } - - public static void EmitLoadSx64(ArmEmitterContext context, Operand address, int rt, int size) - { - EmitLoad(context, address, Extension.Sx64, rt, size); - } - - private static void EmitLoad(ArmEmitterContext context, Operand address, Extension ext, int rt, int size) - { - bool isSimd = IsSimd(context); - - if ((uint)size > (isSimd ? 4 : 3)) - { - throw new ArgumentOutOfRangeException(nameof(size)); - } - - if (isSimd) - { - EmitReadVector(context, address, context.VectorZero(), rt, 0, size); - } - else - { - EmitReadInt(context, address, rt, size); - } - - if (!isSimd && !(context.CurrOp is OpCode32 && rt == State.RegisterAlias.Aarch32Pc)) - { - Operand value = GetInt(context, rt); - - if (ext == Extension.Sx32 || ext == Extension.Sx64) - { - OperandType destType = ext == Extension.Sx64 ? OperandType.I64 : OperandType.I32; - - switch (size) - { - case 0: value = context.SignExtend8 (destType, value); break; - case 1: value = context.SignExtend16(destType, value); break; - case 2: value = context.SignExtend32(destType, value); break; - } - } - - SetInt(context, rt, value); - } - } - - public static void EmitLoadSimd( - ArmEmitterContext context, - Operand address, - Operand vector, - int rt, - int elem, - int size) - { - EmitReadVector(context, address, vector, rt, elem, size); - } - - public static void EmitStore(ArmEmitterContext context, Operand address, int rt, int size) - { - bool isSimd = IsSimd(context); - - if ((uint)size > (isSimd ? 4 : 3)) - { - throw new ArgumentOutOfRangeException(nameof(size)); - } - - if (isSimd) - { - EmitWriteVector(context, address, rt, 0, size); - } - else - { - EmitWriteInt(context, address, rt, size); - } - } - - public static void EmitStoreSimd( - ArmEmitterContext context, - Operand address, - int rt, - int elem, - int size) - { - EmitWriteVector(context, address, rt, elem, size); - } - - private static bool IsSimd(ArmEmitterContext context) - { - return context.CurrOp is IOpCodeSimd && - !(context.CurrOp is OpCodeSimdMemMs || - context.CurrOp is OpCodeSimdMemSs); - } - - public static Operand EmitReadInt(ArmEmitterContext context, Operand address, int size) - { - Operand temp = context.AllocateLocal(size == 3 ? OperandType.I64 : OperandType.I32); - - Operand lblSlowPath = Label(); - Operand lblEnd = Label(); - - Operand physAddr = EmitPtPointerLoad(context, address, lblSlowPath, write: false, size); - - Operand value = default; - - switch (size) - { - case 0: value = context.Load8 (physAddr); break; - case 1: value = context.Load16(physAddr); break; - case 2: value = context.Load (OperandType.I32, physAddr); break; - case 3: value = context.Load (OperandType.I64, physAddr); break; - } - - context.Copy(temp, value); - - if (!context.Memory.Type.IsHostMapped()) - { - context.Branch(lblEnd); - - context.MarkLabel(lblSlowPath, BasicBlockFrequency.Cold); - - context.Copy(temp, EmitReadIntFallback(context, address, size)); - - context.MarkLabel(lblEnd); - } - - return temp; - } - - private static void EmitReadInt(ArmEmitterContext context, Operand address, int rt, int size) - { - Operand lblSlowPath = Label(); - Operand lblEnd = Label(); - - Operand physAddr = EmitPtPointerLoad(context, address, lblSlowPath, write: false, size); - - Operand value = default; - - switch (size) - { - case 0: value = context.Load8 (physAddr); break; - case 1: value = context.Load16(physAddr); break; - case 2: value = context.Load (OperandType.I32, physAddr); break; - case 3: value = context.Load (OperandType.I64, physAddr); break; - } - - SetInt(context, rt, value); - - if (!context.Memory.Type.IsHostMapped()) - { - context.Branch(lblEnd); - - context.MarkLabel(lblSlowPath, BasicBlockFrequency.Cold); - - EmitReadIntFallback(context, address, rt, size); - - context.MarkLabel(lblEnd); - } - } - - public static Operand EmitReadIntAligned(ArmEmitterContext context, Operand address, int size) - { - if ((uint)size > 4) - { - throw new ArgumentOutOfRangeException(nameof(size)); - } - - Operand physAddr = EmitPtPointerLoad(context, address, default, write: false, size); - - return size switch - { - 0 => context.Load8(physAddr), - 1 => context.Load16(physAddr), - 2 => context.Load(OperandType.I32, physAddr), - 3 => context.Load(OperandType.I64, physAddr), - _ => context.Load(OperandType.V128, physAddr) - }; - } - - private static void EmitReadVector( - ArmEmitterContext context, - Operand address, - Operand vector, - int rt, - int elem, - int size) - { - Operand lblSlowPath = Label(); - Operand lblEnd = Label(); - - Operand physAddr = EmitPtPointerLoad(context, address, lblSlowPath, write: false, size); - - Operand value = default; - - switch (size) - { - case 0: value = context.VectorInsert8 (vector, context.Load8(physAddr), elem); break; - case 1: value = context.VectorInsert16(vector, context.Load16(physAddr), elem); break; - case 2: value = context.VectorInsert (vector, context.Load(OperandType.I32, physAddr), elem); break; - case 3: value = context.VectorInsert (vector, context.Load(OperandType.I64, physAddr), elem); break; - case 4: value = context.Load (OperandType.V128, physAddr); break; - } - - context.Copy(GetVec(rt), value); - - if (!context.Memory.Type.IsHostMapped()) - { - context.Branch(lblEnd); - - context.MarkLabel(lblSlowPath, BasicBlockFrequency.Cold); - - EmitReadVectorFallback(context, address, vector, rt, elem, size); - - context.MarkLabel(lblEnd); - } - } - - private static Operand VectorCreate(ArmEmitterContext context, Operand value) - { - return context.VectorInsert(context.VectorZero(), value, 0); - } - - private static void EmitWriteInt(ArmEmitterContext context, Operand address, int rt, int size) - { - Operand lblSlowPath = Label(); - Operand lblEnd = Label(); - - Operand physAddr = EmitPtPointerLoad(context, address, lblSlowPath, write: true, size); - - Operand value = GetInt(context, rt); - - if (size < 3 && value.Type == OperandType.I64) - { - value = context.ConvertI64ToI32(value); - } - - switch (size) - { - case 0: context.Store8 (physAddr, value); break; - case 1: context.Store16(physAddr, value); break; - case 2: context.Store (physAddr, value); break; - case 3: context.Store (physAddr, value); break; - } - - if (!context.Memory.Type.IsHostMapped()) - { - context.Branch(lblEnd); - - context.MarkLabel(lblSlowPath, BasicBlockFrequency.Cold); - - EmitWriteIntFallback(context, address, rt, size); - - context.MarkLabel(lblEnd); - } - } - - public static void EmitWriteIntAligned(ArmEmitterContext context, Operand address, Operand value, int size) - { - if ((uint)size > 4) - { - throw new ArgumentOutOfRangeException(nameof(size)); - } - - Operand physAddr = EmitPtPointerLoad(context, address, default, write: true, size); - - if (size < 3 && value.Type == OperandType.I64) - { - value = context.ConvertI64ToI32(value); - } - - if (size == 0) - { - context.Store8(physAddr, value); - } - else if (size == 1) - { - context.Store16(physAddr, value); - } - else - { - context.Store(physAddr, value); - } - } - - private static void EmitWriteVector( - ArmEmitterContext context, - Operand address, - int rt, - int elem, - int size) - { - Operand lblSlowPath = Label(); - Operand lblEnd = Label(); - - Operand physAddr = EmitPtPointerLoad(context, address, lblSlowPath, write: true, size); - - Operand value = GetVec(rt); - - switch (size) - { - case 0: context.Store8 (physAddr, context.VectorExtract8(value, elem)); break; - case 1: context.Store16(physAddr, context.VectorExtract16(value, elem)); break; - case 2: context.Store (physAddr, context.VectorExtract(OperandType.I32, value, elem)); break; - case 3: context.Store (physAddr, context.VectorExtract(OperandType.I64, value, elem)); break; - case 4: context.Store (physAddr, value); break; - } - - if (!context.Memory.Type.IsHostMapped()) - { - context.Branch(lblEnd); - - context.MarkLabel(lblSlowPath, BasicBlockFrequency.Cold); - - EmitWriteVectorFallback(context, address, rt, elem, size); - - context.MarkLabel(lblEnd); - } - } - - public static Operand EmitPtPointerLoad(ArmEmitterContext context, Operand address, Operand lblSlowPath, bool write, int size) - { - if (context.Memory.Type.IsHostMapped()) - { - return EmitHostMappedPointer(context, address); - } - - int ptLevelBits = context.Memory.AddressSpaceBits - PageBits; - int ptLevelSize = 1 << ptLevelBits; - int ptLevelMask = ptLevelSize - 1; - - Operand addrRotated = size != 0 ? context.RotateRight(address, Const(size)) : address; - Operand addrShifted = context.ShiftRightUI(addrRotated, Const(PageBits - size)); - - Operand pte = !context.HasPtc - ? Const(context.Memory.PageTablePointer.ToInt64()) - : Const(context.Memory.PageTablePointer.ToInt64(), Ptc.PageTableSymbol); - - Operand pteOffset = context.BitwiseAnd(addrShifted, Const(addrShifted.Type, ptLevelMask)); - - if (pteOffset.Type == OperandType.I32) - { - pteOffset = context.ZeroExtend32(OperandType.I64, pteOffset); - } - - pte = context.Load(OperandType.I64, context.Add(pte, context.ShiftLeft(pteOffset, Const(3)))); - - if (addrShifted.Type == OperandType.I32) - { - addrShifted = context.ZeroExtend32(OperandType.I64, addrShifted); - } - - // If the VA is out of range, or not aligned to the access size, force PTE to 0 by masking it. - pte = context.BitwiseAnd(pte, context.ShiftRightSI(context.Add(addrShifted, Const(-(long)ptLevelSize)), Const(63))); - - if (lblSlowPath != default) - { - if (write) - { - context.BranchIf(lblSlowPath, pte, Const(0L), Comparison.LessOrEqual); - pte = context.BitwiseAnd(pte, Const(0xffffffffffffUL)); // Ignore any software protection bits. (they are still used by C# memory access) - } - else - { - pte = context.ShiftLeft(pte, Const(1)); - context.BranchIf(lblSlowPath, pte, Const(0L), Comparison.LessOrEqual); - pte = context.ShiftRightUI(pte, Const(1)); - } - } - else - { - // When no label is provided to jump to a slow path if the address is invalid, - // we do the validation ourselves, and throw if needed. - - Operand lblNotWatched = Label(); - - // Is the page currently being tracked for read/write? If so we need to call SignalMemoryTracking. - context.BranchIf(lblNotWatched, pte, Const(0L), Comparison.GreaterOrEqual, BasicBlockFrequency.Cold); - - // Signal memory tracking. Size here doesn't matter as address is assumed to be size aligned here. - context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SignalMemoryTracking)), address, Const(1UL), Const(write ? 1 : 0)); - context.MarkLabel(lblNotWatched); - - pte = context.BitwiseAnd(pte, Const(0xffffffffffffUL)); // Ignore any software protection bits. (they are still used by C# memory access) - - Operand lblNonNull = Label(); - - // Skip exception if the PTE address is non-null (not zero). - context.BranchIfTrue(lblNonNull, pte, BasicBlockFrequency.Cold); - - // The call is not expected to return (it should throw). - context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.ThrowInvalidMemoryAccess)), address); - context.MarkLabel(lblNonNull); - } - - Operand pageOffset = context.BitwiseAnd(address, Const(address.Type, PageMask)); - - if (pageOffset.Type == OperandType.I32) - { - pageOffset = context.ZeroExtend32(OperandType.I64, pageOffset); - } - - return context.Add(pte, pageOffset); - } - - public static Operand EmitHostMappedPointer(ArmEmitterContext context, Operand address) - { - if (address.Type == OperandType.I32) - { - address = context.ZeroExtend32(OperandType.I64, address); - } - - if (context.Memory.Type == MemoryManagerType.HostMapped) - { - Operand mask = Const(ulong.MaxValue >> (64 - context.Memory.AddressSpaceBits)); - address = context.BitwiseAnd(address, mask); - } - - Operand baseAddr = !context.HasPtc - ? Const(context.Memory.PageTablePointer.ToInt64()) - : Const(context.Memory.PageTablePointer.ToInt64(), Ptc.PageTableSymbol); - - return context.Add(baseAddr, address); - } - - private static void EmitReadIntFallback(ArmEmitterContext context, Operand address, int rt, int size) - { - SetInt(context, rt, EmitReadIntFallback(context, address, size)); - } - - private static Operand EmitReadIntFallback(ArmEmitterContext context, Operand address, int size) - { - MethodInfo info = null; - - switch (size) - { - case 0: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadByte)); break; - case 1: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadUInt16)); break; - case 2: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadUInt32)); break; - case 3: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadUInt64)); break; - } - - return context.Call(info, address); - } - - private static void EmitReadVectorFallback( - ArmEmitterContext context, - Operand address, - Operand vector, - int rt, - int elem, - int size) - { - MethodInfo info = null; - - switch (size) - { - case 0: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadByte)); break; - case 1: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadUInt16)); break; - case 2: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadUInt32)); break; - case 3: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadUInt64)); break; - case 4: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadVector128)); break; - } - - Operand value = context.Call(info, address); - - switch (size) - { - case 0: value = context.VectorInsert8 (vector, value, elem); break; - case 1: value = context.VectorInsert16(vector, value, elem); break; - case 2: value = context.VectorInsert (vector, value, elem); break; - case 3: value = context.VectorInsert (vector, value, elem); break; - } - - context.Copy(GetVec(rt), value); - } - - private static void EmitWriteIntFallback(ArmEmitterContext context, Operand address, int rt, int size) - { - MethodInfo info = null; - - switch (size) - { - case 0: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.WriteByte)); break; - case 1: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.WriteUInt16)); break; - case 2: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.WriteUInt32)); break; - case 3: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.WriteUInt64)); break; - } - - Operand value = GetInt(context, rt); - - if (size < 3 && value.Type == OperandType.I64) - { - value = context.ConvertI64ToI32(value); - } - - context.Call(info, address, value); - } - - private static void EmitWriteVectorFallback( - ArmEmitterContext context, - Operand address, - int rt, - int elem, - int size) - { - MethodInfo info = null; - - switch (size) - { - case 0: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.WriteByte)); break; - case 1: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.WriteUInt16)); break; - case 2: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.WriteUInt32)); break; - case 3: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.WriteUInt64)); break; - case 4: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.WriteVector128)); break; - } - - Operand value = default; - - if (size < 4) - { - switch (size) - { - case 0: value = context.VectorExtract8 (GetVec(rt), elem); break; - case 1: value = context.VectorExtract16(GetVec(rt), elem); break; - case 2: value = context.VectorExtract (OperandType.I32, GetVec(rt), elem); break; - case 3: value = context.VectorExtract (OperandType.I64, GetVec(rt), elem); break; - } - } - else - { - value = GetVec(rt); - } - - context.Call(info, address, value); - } - - private static Operand GetInt(ArmEmitterContext context, int rt) - { - return context.CurrOp is OpCode32 ? GetIntA32(context, rt) : GetIntOrZR(context, rt); - } - - private static void SetInt(ArmEmitterContext context, int rt, Operand value) - { - if (context.CurrOp is OpCode32) - { - SetIntA32(context, rt, value); - } - else - { - SetIntOrZR(context, rt, value); - } - } - - // ARM32 helpers. - public static Operand GetMemM(ArmEmitterContext context, bool setCarry = true) - { - switch (context.CurrOp) - { - case IOpCode32MemRsImm op: return GetMShiftedByImmediate(context, op, setCarry); - - case IOpCode32MemReg op: return GetIntA32(context, op.Rm); - - case IOpCode32Mem op: return Const(op.Immediate); - - case OpCode32SimdMemImm op: return Const(op.Immediate); - - default: throw InvalidOpCodeType(context.CurrOp); - } - } - - private static Exception InvalidOpCodeType(OpCode opCode) - { - return new InvalidOperationException($"Invalid OpCode type \"{opCode?.GetType().Name ?? "null"}\"."); - } - - public static Operand GetMShiftedByImmediate(ArmEmitterContext context, IOpCode32MemRsImm op, bool setCarry) - { - Operand m = GetIntA32(context, op.Rm); - - int shift = op.Immediate; - - if (shift == 0) - { - switch (op.ShiftType) - { - case ShiftType.Lsr: shift = 32; break; - case ShiftType.Asr: shift = 32; break; - case ShiftType.Ror: shift = 1; break; - } - } - - if (shift != 0) - { - setCarry &= false; - - switch (op.ShiftType) - { - case ShiftType.Lsl: m = InstEmitAluHelper.GetLslC(context, m, setCarry, shift); break; - case ShiftType.Lsr: m = InstEmitAluHelper.GetLsrC(context, m, setCarry, shift); break; - case ShiftType.Asr: m = InstEmitAluHelper.GetAsrC(context, m, setCarry, shift); break; - case ShiftType.Ror: - if (op.Immediate != 0) - { - m = InstEmitAluHelper.GetRorC(context, m, setCarry, shift); - } - else - { - m = InstEmitAluHelper.GetRrxC(context, m, setCarry); - } - break; - } - } - - return m; - } - } -} diff --git a/ARMeilleure/Instructions/InstEmitMove.cs b/ARMeilleure/Instructions/InstEmitMove.cs deleted file mode 100644 index d551bf2da..000000000 --- a/ARMeilleure/Instructions/InstEmitMove.cs +++ /dev/null @@ -1,41 +0,0 @@ -using ARMeilleure.Decoders; -using ARMeilleure.IntermediateRepresentation; -using ARMeilleure.Translation; - -using static ARMeilleure.Instructions.InstEmitHelper; -using static ARMeilleure.IntermediateRepresentation.Operand.Factory; - -namespace ARMeilleure.Instructions -{ - static partial class InstEmit - { - public static void Movk(ArmEmitterContext context) - { - OpCodeMov op = (OpCodeMov)context.CurrOp; - - OperandType type = op.GetOperandType(); - - Operand res = GetIntOrZR(context, op.Rd); - - res = context.BitwiseAnd(res, Const(type, ~(0xffffL << op.Bit))); - - res = context.BitwiseOr(res, Const(type, op.Immediate)); - - SetIntOrZR(context, op.Rd, res); - } - - public static void Movn(ArmEmitterContext context) - { - OpCodeMov op = (OpCodeMov)context.CurrOp; - - SetIntOrZR(context, op.Rd, Const(op.GetOperandType(), ~op.Immediate)); - } - - public static void Movz(ArmEmitterContext context) - { - OpCodeMov op = (OpCodeMov)context.CurrOp; - - SetIntOrZR(context, op.Rd, Const(op.GetOperandType(), op.Immediate)); - } - } -} \ No newline at end of file diff --git a/ARMeilleure/Instructions/InstEmitSimdArithmetic.cs b/ARMeilleure/Instructions/InstEmitSimdArithmetic.cs deleted file mode 100644 index a35e28a15..000000000 --- a/ARMeilleure/Instructions/InstEmitSimdArithmetic.cs +++ /dev/null @@ -1,4066 +0,0 @@ -// https://github.com/intel/ARM_NEON_2_x86_SSE/blob/master/NEON_2_SSE.h -// https://www.agner.org/optimize/#vectorclass @ vectori128.h - -using ARMeilleure.Decoders; -using ARMeilleure.IntermediateRepresentation; -using ARMeilleure.State; -using ARMeilleure.Translation; -using System; -using System.Diagnostics; - -using static ARMeilleure.Instructions.InstEmitHelper; -using static ARMeilleure.Instructions.InstEmitSimdHelper; -using static ARMeilleure.Instructions.InstEmitSimdHelper32; -using static ARMeilleure.IntermediateRepresentation.Operand.Factory; - -namespace ARMeilleure.Instructions -{ - using Func2I = Func; - - static partial class InstEmit - { - public static void Abs_S(ArmEmitterContext context) - { - EmitScalarUnaryOpSx(context, (op1) => EmitAbs(context, op1)); - } - - public static void Abs_V(ArmEmitterContext context) - { - EmitVectorUnaryOpSx(context, (op1) => EmitAbs(context, op1)); - } - - public static void Add_S(ArmEmitterContext context) - { - EmitScalarBinaryOpZx(context, (op1, op2) => context.Add(op1, op2)); - } - - public static void Add_V(ArmEmitterContext context) - { - if (Optimizations.UseSse2) - { - OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp; - - Operand n = GetVec(op.Rn); - Operand m = GetVec(op.Rm); - - Intrinsic addInst = X86PaddInstruction[op.Size]; - - Operand res = context.AddIntrinsic(addInst, n, m); - - if (op.RegisterSize == RegisterSize.Simd64) - { - res = context.VectorZeroUpper64(res); - } - - context.Copy(GetVec(op.Rd), res); - } - else - { - EmitVectorBinaryOpZx(context, (op1, op2) => context.Add(op1, op2)); - } - } - - public static void Addhn_V(ArmEmitterContext context) - { - EmitHighNarrow(context, (op1, op2) => context.Add(op1, op2), round: false); - } - - public static void Addp_S(ArmEmitterContext context) - { - OpCodeSimd op = (OpCodeSimd)context.CurrOp; - - Operand ne0 = EmitVectorExtractZx(context, op.Rn, 0, op.Size); - Operand ne1 = EmitVectorExtractZx(context, op.Rn, 1, op.Size); - - Operand res = context.Add(ne0, ne1); - - context.Copy(GetVec(op.Rd), EmitVectorInsert(context, context.VectorZero(), res, 0, op.Size)); - } - - public static void Addp_V(ArmEmitterContext context) - { - if (Optimizations.UseSsse3) - { - EmitSsse3VectorPairwiseOp(context, X86PaddInstruction); - } - else - { - EmitVectorPairwiseOpZx(context, (op1, op2) => context.Add(op1, op2)); - } - } - - public static void Addv_V(ArmEmitterContext context) - { - EmitVectorAcrossVectorOpZx(context, (op1, op2) => context.Add(op1, op2)); - } - - public static void Cls_V(ArmEmitterContext context) - { - OpCodeSimd op = (OpCodeSimd)context.CurrOp; - - Operand res = context.VectorZero(); - - int elems = op.GetBytesCount() >> op.Size; - - int eSize = 8 << op.Size; - - for (int index = 0; index < elems; index++) - { - Operand ne = EmitVectorExtractZx(context, op.Rn, index, op.Size); - - Operand de = context.Call(typeof(SoftFallback).GetMethod(nameof(SoftFallback.CountLeadingSigns)), ne, Const(eSize)); - - res = EmitVectorInsert(context, res, de, index, op.Size); - } - - context.Copy(GetVec(op.Rd), res); - } - - public static void Clz_V(ArmEmitterContext context) - { - OpCodeSimd op = (OpCodeSimd)context.CurrOp; - - int eSize = 8 << op.Size; - - Operand res = eSize switch { - 8 => Clz_V_I8 (context, GetVec(op.Rn)), - 16 => Clz_V_I16(context, GetVec(op.Rn)), - 32 => Clz_V_I32(context, GetVec(op.Rn)), - _ => default - }; - - if (res != default) - { - if (op.RegisterSize == RegisterSize.Simd64) - { - res = context.VectorZeroUpper64(res); - } - } - else - { - int elems = op.GetBytesCount() >> op.Size; - - res = context.VectorZero(); - - for (int index = 0; index < elems; index++) - { - Operand ne = EmitVectorExtractZx(context, op.Rn, index, op.Size); - - Operand de = context.Call(typeof(SoftFallback).GetMethod(nameof(SoftFallback.CountLeadingZeros)), ne, Const(eSize)); - - res = EmitVectorInsert(context, res, de, index, op.Size); - } - } - - context.Copy(GetVec(op.Rd), res); - } - - private static Operand Clz_V_I8(ArmEmitterContext context, Operand arg) - { - if (!Optimizations.UseSsse3) - { - return default; - } - - // CLZ nibble table. - Operand clzTable = X86GetScalar(context, 0x01_01_01_01_02_02_03_04); - - Operand maskLow = X86GetAllElements(context, 0x0f_0f_0f_0f); - Operand c04 = X86GetAllElements(context, 0x04_04_04_04); - - // CLZ of low 4 bits of elements in arg. - Operand loClz = context.AddIntrinsic(Intrinsic.X86Pshufb, clzTable, arg); - - // Get the high 4 bits of elements in arg. - Operand hiArg = context.AddIntrinsic(Intrinsic.X86Psrlw, arg, Const(4)); - hiArg = context.AddIntrinsic(Intrinsic.X86Pand, hiArg, maskLow); - - // CLZ of high 4 bits of elements in arg. - Operand hiClz = context.AddIntrinsic(Intrinsic.X86Pshufb, clzTable, hiArg); - - // If high 4 bits are not all zero, we discard the CLZ of the low 4 bits. - Operand mask = context.AddIntrinsic(Intrinsic.X86Pcmpeqb, hiClz, c04); - loClz = context.AddIntrinsic(Intrinsic.X86Pand, loClz, mask); - - return context.AddIntrinsic(Intrinsic.X86Paddb, loClz, hiClz); - } - - private static Operand Clz_V_I16(ArmEmitterContext context, Operand arg) - { - if (!Optimizations.UseSsse3) - { - return default; - } - - Operand maskSwap = X86GetElements(context, 0x80_0f_80_0d_80_0b_80_09, 0x80_07_80_05_80_03_80_01); - Operand maskLow = X86GetAllElements(context, 0x00ff_00ff); - Operand c0008 = X86GetAllElements(context, 0x0008_0008); - - // CLZ pair of high 8 and low 8 bits of elements in arg. - Operand hiloClz = Clz_V_I8(context, arg); - // Get CLZ of low 8 bits in each pair. - Operand loClz = context.AddIntrinsic(Intrinsic.X86Pand, hiloClz, maskLow); - // Get CLZ of high 8 bits in each pair. - Operand hiClz = context.AddIntrinsic(Intrinsic.X86Pshufb, hiloClz, maskSwap); - - // If high 8 bits are not all zero, we discard the CLZ of the low 8 bits. - Operand mask = context.AddIntrinsic(Intrinsic.X86Pcmpeqw, hiClz, c0008); - loClz = context.AddIntrinsic(Intrinsic.X86Pand, loClz, mask); - - return context.AddIntrinsic(Intrinsic.X86Paddw, loClz, hiClz); - } - - private static Operand Clz_V_I32(ArmEmitterContext context, Operand arg) - { - // TODO: Use vplzcntd when AVX-512 is supported. - if (!Optimizations.UseSse2) - { - return default; - } - - Operand AddVectorI32(Operand op0, Operand op1) => context.AddIntrinsic(Intrinsic.X86Paddd, op0, op1); - Operand SubVectorI32(Operand op0, Operand op1) => context.AddIntrinsic(Intrinsic.X86Psubd, op0, op1); - Operand ShiftRightVectorUI32(Operand op0, int imm8) => context.AddIntrinsic(Intrinsic.X86Psrld, op0, Const(imm8)); - Operand OrVector(Operand op0, Operand op1) => context.AddIntrinsic(Intrinsic.X86Por, op0, op1); - Operand AndVector(Operand op0, Operand op1) => context.AddIntrinsic(Intrinsic.X86Pand, op0, op1); - Operand NotVector(Operand op0) => context.AddIntrinsic(Intrinsic.X86Pandn, op0, context.VectorOne()); - - Operand c55555555 = X86GetAllElements(context, 0x55555555); - Operand c33333333 = X86GetAllElements(context, 0x33333333); - Operand c0f0f0f0f = X86GetAllElements(context, 0x0f0f0f0f); - Operand c0000003f = X86GetAllElements(context, 0x0000003f); - - Operand tmp0; - Operand tmp1; - Operand res; - - // Set all bits after highest set bit to 1. - res = OrVector(ShiftRightVectorUI32(arg, 1), arg); - res = OrVector(ShiftRightVectorUI32(res, 2), res); - res = OrVector(ShiftRightVectorUI32(res, 4), res); - res = OrVector(ShiftRightVectorUI32(res, 8), res); - res = OrVector(ShiftRightVectorUI32(res, 16), res); - - // Make leading 0s into leading 1s. - res = NotVector(res); - - // Count leading 1s, which is the population count. - tmp0 = ShiftRightVectorUI32(res, 1); - tmp0 = AndVector(tmp0, c55555555); - res = SubVectorI32(res, tmp0); - - tmp0 = ShiftRightVectorUI32(res, 2); - tmp0 = AndVector(tmp0, c33333333); - tmp1 = AndVector(res, c33333333); - res = AddVectorI32(tmp0, tmp1); - - tmp0 = ShiftRightVectorUI32(res, 4); - tmp0 = AddVectorI32(tmp0, res); - res = AndVector(tmp0, c0f0f0f0f); - - tmp0 = ShiftRightVectorUI32(res, 8); - res = AddVectorI32(tmp0, res); - - tmp0 = ShiftRightVectorUI32(res, 16); - res = AddVectorI32(tmp0, res); - - res = AndVector(res, c0000003f); - - return res; - } - - public static void Cnt_V(ArmEmitterContext context) - { - OpCodeSimd op = (OpCodeSimd)context.CurrOp; - - Operand res = context.VectorZero(); - - int elems = op.RegisterSize == RegisterSize.Simd128 ? 16 : 8; - - for (int index = 0; index < elems; index++) - { - Operand ne = EmitVectorExtractZx(context, op.Rn, index, 0); - - Operand de; - - if (Optimizations.UsePopCnt) - { - de = context.AddIntrinsicLong(Intrinsic.X86Popcnt, ne); - } - else - { - de = EmitCountSetBits8(context, ne); - } - - res = EmitVectorInsert(context, res, de, index, 0); - } - - context.Copy(GetVec(op.Rd), res); - } - - public static void Fabd_S(ArmEmitterContext context) - { - if (Optimizations.FastFP && Optimizations.UseSse2) - { - OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp; - - int sizeF = op.Size & 1; - - if (sizeF == 0) - { - Operand res = context.AddIntrinsic(Intrinsic.X86Subss, GetVec(op.Rn), GetVec(op.Rm)); - - res = EmitFloatAbs(context, res, true, false); - - context.Copy(GetVec(op.Rd), context.VectorZeroUpper96(res)); - } - else /* if (sizeF == 1) */ - { - Operand res = context.AddIntrinsic(Intrinsic.X86Subsd, GetVec(op.Rn), GetVec(op.Rm)); - - res = EmitFloatAbs(context, res, false, false); - - context.Copy(GetVec(op.Rd), context.VectorZeroUpper64(res)); - } - } - else - { - EmitScalarBinaryOpF(context, (op1, op2) => - { - Operand res = EmitSoftFloatCall(context, nameof(SoftFloat32.FPSub), op1, op2); - - return EmitUnaryMathCall(context, nameof(Math.Abs), res); - }); - } - } - - public static void Fabd_V(ArmEmitterContext context) - { - if (Optimizations.FastFP && Optimizations.UseSse2) - { - OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp; - - int sizeF = op.Size & 1; - - if (sizeF == 0) - { - Operand res = context.AddIntrinsic(Intrinsic.X86Subps, GetVec(op.Rn), GetVec(op.Rm)); - - res = EmitFloatAbs(context, res, true, true); - - if (op.RegisterSize == RegisterSize.Simd64) - { - res = context.VectorZeroUpper64(res); - } - - context.Copy(GetVec(op.Rd), res); - } - else /* if (sizeF == 1) */ - { - Operand res = context.AddIntrinsic(Intrinsic.X86Subpd, GetVec(op.Rn), GetVec(op.Rm)); - - res = EmitFloatAbs(context, res, false, true); - - context.Copy(GetVec(op.Rd), res); - } - } - else - { - EmitVectorBinaryOpF(context, (op1, op2) => - { - Operand res = EmitSoftFloatCall(context, nameof(SoftFloat32.FPSub), op1, op2); - - return EmitUnaryMathCall(context, nameof(Math.Abs), res); - }); - } - } - - public static void Fabs_S(ArmEmitterContext context) - { - if (Optimizations.UseSse2) - { - OpCodeSimd op = (OpCodeSimd)context.CurrOp; - - if (op.Size == 0) - { - Operand res = EmitFloatAbs(context, GetVec(op.Rn), true, false); - - context.Copy(GetVec(op.Rd), context.VectorZeroUpper96(res)); - } - else /* if (op.Size == 1) */ - { - Operand res = EmitFloatAbs(context, GetVec(op.Rn), false, false); - - context.Copy(GetVec(op.Rd), context.VectorZeroUpper64(res)); - } - } - else - { - EmitScalarUnaryOpF(context, (op1) => - { - return EmitUnaryMathCall(context, nameof(Math.Abs), op1); - }); - } - } - - public static void Fabs_V(ArmEmitterContext context) - { - if (Optimizations.UseSse2) - { - OpCodeSimd op = (OpCodeSimd)context.CurrOp; - - int sizeF = op.Size & 1; - - if (sizeF == 0) - { - Operand res = EmitFloatAbs(context, GetVec(op.Rn), true, true); - - if (op.RegisterSize == RegisterSize.Simd64) - { - res = context.VectorZeroUpper64(res); - } - - context.Copy(GetVec(op.Rd), res); - } - else /* if (sizeF == 1) */ - { - Operand res = EmitFloatAbs(context, GetVec(op.Rn), false, true); - - context.Copy(GetVec(op.Rd), res); - } - } - else - { - EmitVectorUnaryOpF(context, (op1) => - { - return EmitUnaryMathCall(context, nameof(Math.Abs), op1); - }); - } - } - - public static void Fadd_S(ArmEmitterContext context) - { - if (Optimizations.FastFP && Optimizations.UseSse2) - { - EmitScalarBinaryOpF(context, Intrinsic.X86Addss, Intrinsic.X86Addsd); - } - else if (Optimizations.FastFP) - { - EmitScalarBinaryOpF(context, (op1, op2) => context.Add(op1, op2)); - } - else - { - EmitScalarBinaryOpF(context, (op1, op2) => - { - return EmitSoftFloatCall(context, nameof(SoftFloat32.FPAdd), op1, op2); - }); - } - } - - public static void Fadd_V(ArmEmitterContext context) - { - if (Optimizations.FastFP && Optimizations.UseSse2) - { - EmitVectorBinaryOpF(context, Intrinsic.X86Addps, Intrinsic.X86Addpd); - } - else if (Optimizations.FastFP) - { - EmitVectorBinaryOpF(context, (op1, op2) => context.Add(op1, op2)); - } - else - { - EmitVectorBinaryOpF(context, (op1, op2) => - { - return EmitSoftFloatCall(context, nameof(SoftFloat32.FPAdd), op1, op2); - }); - } - } - - public static void Faddp_S(ArmEmitterContext context) - { - if (Optimizations.FastFP && Optimizations.UseSse3) - { - OpCodeSimd op = (OpCodeSimd)context.CurrOp; - - if ((op.Size & 1) == 0) - { - Operand res = context.AddIntrinsic(Intrinsic.X86Haddps, GetVec(op.Rn), GetVec(op.Rn)); - - context.Copy(GetVec(op.Rd), context.VectorZeroUpper96(res)); - } - else /* if ((op.Size & 1) == 1) */ - { - Operand res = context.AddIntrinsic(Intrinsic.X86Haddpd, GetVec(op.Rn), GetVec(op.Rn)); - - context.Copy(GetVec(op.Rd), context.VectorZeroUpper64(res)); - } - } - else - { - EmitScalarPairwiseOpF(context, (op1, op2) => - { - return EmitSoftFloatCall(context, nameof(SoftFloat32.FPAdd), op1, op2); - }); - } - } - - public static void Faddp_V(ArmEmitterContext context) - { - if (Optimizations.FastFP && Optimizations.UseSse41) - { - EmitSse2VectorPairwiseOpF(context, (op1, op2) => - { - return EmitSse41ProcessNaNsOpF(context, (op1, op2) => - { - return EmitSseOrAvxHandleFzModeOpF(context, (op1, op2) => - { - IOpCodeSimd op = (IOpCodeSimd)context.CurrOp; - - Intrinsic addInst = (op.Size & 1) == 0 ? Intrinsic.X86Addps : Intrinsic.X86Addpd; - - return context.AddIntrinsic(addInst, op1, op2); - }, scalar: false, op1, op2); - }, scalar: false, op1, op2); - }); - } - else - { - EmitVectorPairwiseOpF(context, (op1, op2) => - { - return EmitSoftFloatCall(context, nameof(SoftFloat32.FPAdd), op1, op2); - }); - } - } - - public static void Fdiv_S(ArmEmitterContext context) - { - if (Optimizations.FastFP && Optimizations.UseSse2) - { - EmitScalarBinaryOpF(context, Intrinsic.X86Divss, Intrinsic.X86Divsd); - } - else if (Optimizations.FastFP) - { - EmitScalarBinaryOpF(context, (op1, op2) => context.Divide(op1, op2)); - } - else - { - EmitScalarBinaryOpF(context, (op1, op2) => - { - return EmitSoftFloatCall(context, nameof(SoftFloat32.FPDiv), op1, op2); - }); - } - } - - public static void Fdiv_V(ArmEmitterContext context) - { - if (Optimizations.FastFP && Optimizations.UseSse2) - { - EmitVectorBinaryOpF(context, Intrinsic.X86Divps, Intrinsic.X86Divpd); - } - else if (Optimizations.FastFP) - { - EmitVectorBinaryOpF(context, (op1, op2) => context.Divide(op1, op2)); - } - else - { - EmitVectorBinaryOpF(context, (op1, op2) => - { - return EmitSoftFloatCall(context, nameof(SoftFloat32.FPDiv), op1, op2); - }); - } - } - - public static void Fmadd_S(ArmEmitterContext context) // Fused. - { - if (Optimizations.FastFP && Optimizations.UseSse2) - { - OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp; - - Operand d = GetVec(op.Rd); - Operand a = GetVec(op.Ra); - Operand n = GetVec(op.Rn); - Operand m = GetVec(op.Rm); - - if (op.Size == 0) - { - Operand res = context.AddIntrinsic(Intrinsic.X86Mulss, n, m); - res = context.AddIntrinsic(Intrinsic.X86Addss, a, res); - - context.Copy(d, context.VectorZeroUpper96(res)); - } - else /* if (op.Size == 1) */ - { - Operand res = context.AddIntrinsic(Intrinsic.X86Mulsd, n, m); - res = context.AddIntrinsic(Intrinsic.X86Addsd, a, res); - - context.Copy(d, context.VectorZeroUpper64(res)); - } - } - else - { - EmitScalarTernaryRaOpF(context, (op1, op2, op3) => - { - return EmitSoftFloatCall(context, nameof(SoftFloat32.FPMulAdd), op1, op2, op3); - }); - } - } - - public static void Fmax_S(ArmEmitterContext context) - { - if (Optimizations.FastFP && Optimizations.UseSse41) - { - EmitSse41ProcessNaNsOpF(context, (op1, op2) => - { - return EmitSseOrAvxHandleFzModeOpF(context, (op1, op2) => - { - return EmitSse2VectorMaxMinOpF(context, op1, op2, isMax: true); - }, scalar: true, op1, op2); - }, scalar: true); - } - else - { - EmitScalarBinaryOpF(context, (op1, op2) => - { - return EmitSoftFloatCall(context, nameof(SoftFloat32.FPMax), op1, op2); - }); - } - } - - public static void Fmax_V(ArmEmitterContext context) - { - if (Optimizations.FastFP && Optimizations.UseSse41) - { - EmitSse41ProcessNaNsOpF(context, (op1, op2) => - { - return EmitSseOrAvxHandleFzModeOpF(context, (op1, op2) => - { - return EmitSse2VectorMaxMinOpF(context, op1, op2, isMax: true); - }, scalar: false, op1, op2); - }, scalar: false); - } - else - { - EmitVectorBinaryOpF(context, (op1, op2) => - { - return EmitSoftFloatCall(context, nameof(SoftFloat32.FPMax), op1, op2); - }); - } - } - - public static void Fmaxnm_S(ArmEmitterContext context) - { - if (Optimizations.FastFP && Optimizations.UseSse41) - { - EmitSse41MaxMinNumOpF(context, isMaxNum: true, scalar: true); - } - else - { - EmitScalarBinaryOpF(context, (op1, op2) => - { - return EmitSoftFloatCall(context, nameof(SoftFloat32.FPMaxNum), op1, op2); - }); - } - } - - public static void Fmaxnm_V(ArmEmitterContext context) - { - if (Optimizations.FastFP && Optimizations.UseSse41) - { - EmitSse41MaxMinNumOpF(context, isMaxNum: true, scalar: false); - } - else - { - EmitVectorBinaryOpF(context, (op1, op2) => - { - return EmitSoftFloatCall(context, nameof(SoftFloat32.FPMaxNum), op1, op2); - }); - } - } - - public static void Fmaxnmp_S(ArmEmitterContext context) - { - if (Optimizations.FastFP && Optimizations.UseSse41) - { - EmitSse2ScalarPairwiseOpF(context, (op1, op2) => - { - return EmitSse41MaxMinNumOpF(context, isMaxNum: true, scalar: true, op1, op2); - }); - } - else - { - EmitScalarPairwiseOpF(context, (op1, op2) => - { - return EmitSoftFloatCall(context, nameof(SoftFloat32.FPMaxNum), op1, op2); - }); - } - } - - public static void Fmaxnmp_V(ArmEmitterContext context) - { - if (Optimizations.FastFP && Optimizations.UseSse41) - { - EmitSse2VectorPairwiseOpF(context, (op1, op2) => - { - return EmitSse41MaxMinNumOpF(context, isMaxNum: true, scalar: false, op1, op2); - }); - } - else - { - EmitVectorPairwiseOpF(context, (op1, op2) => - { - return EmitSoftFloatCall(context, nameof(SoftFloat32.FPMaxNum), op1, op2); - }); - } - } - - public static void Fmaxnmv_V(ArmEmitterContext context) - { - if (Optimizations.FastFP && Optimizations.UseSse41) - { - EmitSse2VectorAcrossVectorOpF(context, (op1, op2) => - { - return EmitSse41MaxMinNumOpF(context, isMaxNum: true, scalar: false, op1, op2); - }); - } - else - { - EmitVectorAcrossVectorOpF(context, (op1, op2) => - { - return EmitSoftFloatCall(context, nameof(SoftFloat32.FPMaxNum), op1, op2); - }); - } - } - - public static void Fmaxp_V(ArmEmitterContext context) - { - if (Optimizations.FastFP && Optimizations.UseSse41) - { - EmitSse2VectorPairwiseOpF(context, (op1, op2) => - { - return EmitSse41ProcessNaNsOpF(context, (op1, op2) => - { - return EmitSseOrAvxHandleFzModeOpF(context, (op1, op2) => - { - return EmitSse2VectorMaxMinOpF(context, op1, op2, isMax: true); - }, scalar: false, op1, op2); - }, scalar: false, op1, op2); - }); - } - else - { - EmitVectorPairwiseOpF(context, (op1, op2) => - { - return EmitSoftFloatCall(context, nameof(SoftFloat32.FPMax), op1, op2); - }); - } - } - - public static void Fmaxv_V(ArmEmitterContext context) - { - if (Optimizations.FastFP && Optimizations.UseSse41) - { - EmitSse2VectorAcrossVectorOpF(context, (op1, op2) => - { - return EmitSse41ProcessNaNsOpF(context, (op1, op2) => - { - return EmitSseOrAvxHandleFzModeOpF(context, (op1, op2) => - { - return EmitSse2VectorMaxMinOpF(context, op1, op2, isMax: true); - }, scalar: false, op1, op2); - }, scalar: false, op1, op2); - }); - } - else - { - EmitVectorAcrossVectorOpF(context, (op1, op2) => - { - return EmitSoftFloatCall(context, nameof(SoftFloat32.FPMax), op1, op2); - }); - } - } - - public static void Fmin_S(ArmEmitterContext context) - { - if (Optimizations.FastFP && Optimizations.UseSse41) - { - EmitSse41ProcessNaNsOpF(context, (op1, op2) => - { - return EmitSseOrAvxHandleFzModeOpF(context, (op1, op2) => - { - return EmitSse2VectorMaxMinOpF(context, op1, op2, isMax: false); - }, scalar: true, op1, op2); - }, scalar: true); - } - else - { - EmitScalarBinaryOpF(context, (op1, op2) => - { - return EmitSoftFloatCall(context, nameof(SoftFloat32.FPMin), op1, op2); - }); - } - } - - public static void Fmin_V(ArmEmitterContext context) - { - if (Optimizations.FastFP && Optimizations.UseSse41) - { - EmitSse41ProcessNaNsOpF(context, (op1, op2) => - { - return EmitSseOrAvxHandleFzModeOpF(context, (op1, op2) => - { - return EmitSse2VectorMaxMinOpF(context, op1, op2, isMax: false); - }, scalar: false, op1, op2); - }, scalar: false); - } - else - { - EmitVectorBinaryOpF(context, (op1, op2) => - { - return EmitSoftFloatCall(context, nameof(SoftFloat32.FPMin), op1, op2); - }); - } - } - - public static void Fminnm_S(ArmEmitterContext context) - { - if (Optimizations.FastFP && Optimizations.UseSse41) - { - EmitSse41MaxMinNumOpF(context, isMaxNum: false, scalar: true); - } - else - { - EmitScalarBinaryOpF(context, (op1, op2) => - { - return EmitSoftFloatCall(context, nameof(SoftFloat32.FPMinNum), op1, op2); - }); - } - } - - public static void Fminnm_V(ArmEmitterContext context) - { - if (Optimizations.FastFP && Optimizations.UseSse41) - { - EmitSse41MaxMinNumOpF(context, isMaxNum: false, scalar: false); - } - else - { - EmitVectorBinaryOpF(context, (op1, op2) => - { - return EmitSoftFloatCall(context, nameof(SoftFloat32.FPMinNum), op1, op2); - }); - } - } - - public static void Fminnmp_S(ArmEmitterContext context) - { - if (Optimizations.FastFP && Optimizations.UseSse41) - { - EmitSse2ScalarPairwiseOpF(context, (op1, op2) => - { - return EmitSse41MaxMinNumOpF(context, isMaxNum: false, scalar: true, op1, op2); - }); - } - else - { - EmitScalarPairwiseOpF(context, (op1, op2) => - { - return EmitSoftFloatCall(context, nameof(SoftFloat32.FPMinNum), op1, op2); - }); - } - } - - public static void Fminnmp_V(ArmEmitterContext context) - { - if (Optimizations.FastFP && Optimizations.UseSse41) - { - EmitSse2VectorPairwiseOpF(context, (op1, op2) => - { - return EmitSse41MaxMinNumOpF(context, isMaxNum: false, scalar: false, op1, op2); - }); - } - else - { - EmitVectorPairwiseOpF(context, (op1, op2) => - { - return EmitSoftFloatCall(context, nameof(SoftFloat32.FPMinNum), op1, op2); - }); - } - } - - public static void Fminnmv_V(ArmEmitterContext context) - { - if (Optimizations.FastFP && Optimizations.UseSse41) - { - EmitSse2VectorAcrossVectorOpF(context, (op1, op2) => - { - return EmitSse41MaxMinNumOpF(context, isMaxNum: false, scalar: false, op1, op2); - }); - } - else - { - EmitVectorAcrossVectorOpF(context, (op1, op2) => - { - return EmitSoftFloatCall(context, nameof(SoftFloat32.FPMinNum), op1, op2); - }); - } - } - - public static void Fminp_V(ArmEmitterContext context) - { - if (Optimizations.FastFP && Optimizations.UseSse41) - { - EmitSse2VectorPairwiseOpF(context, (op1, op2) => - { - return EmitSse41ProcessNaNsOpF(context, (op1, op2) => - { - return EmitSseOrAvxHandleFzModeOpF(context, (op1, op2) => - { - return EmitSse2VectorMaxMinOpF(context, op1, op2, isMax: false); - }, scalar: false, op1, op2); - }, scalar: false, op1, op2); - }); - } - else - { - EmitVectorPairwiseOpF(context, (op1, op2) => - { - return EmitSoftFloatCall(context, nameof(SoftFloat32.FPMin), op1, op2); - }); - } - } - - public static void Fminv_V(ArmEmitterContext context) - { - if (Optimizations.FastFP && Optimizations.UseSse41) - { - EmitSse2VectorAcrossVectorOpF(context, (op1, op2) => - { - return EmitSse41ProcessNaNsOpF(context, (op1, op2) => - { - return EmitSseOrAvxHandleFzModeOpF(context, (op1, op2) => - { - return EmitSse2VectorMaxMinOpF(context, op1, op2, isMax: false); - }, scalar: false, op1, op2); - }, scalar: false, op1, op2); - }); - } - else - { - EmitVectorAcrossVectorOpF(context, (op1, op2) => - { - return EmitSoftFloatCall(context, nameof(SoftFloat32.FPMin), op1, op2); - }); - } - } - - public static void Fmla_Se(ArmEmitterContext context) // Fused. - { - EmitScalarTernaryOpByElemF(context, (op1, op2, op3) => - { - return context.Add(op1, context.Multiply(op2, op3)); - }); - } - - public static void Fmla_V(ArmEmitterContext context) // Fused. - { - if (Optimizations.FastFP && Optimizations.UseSse2) - { - OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp; - - Operand d = GetVec(op.Rd); - Operand n = GetVec(op.Rn); - Operand m = GetVec(op.Rm); - - int sizeF = op.Size & 1; - - if (sizeF == 0) - { - Operand res = context.AddIntrinsic(Intrinsic.X86Mulps, n, m); - - res = context.AddIntrinsic(Intrinsic.X86Addps, d, res); - - if (op.RegisterSize == RegisterSize.Simd64) - { - res = context.VectorZeroUpper64(res); - } - - context.Copy(d, res); - } - else /* if (sizeF == 1) */ - { - Operand res = context.AddIntrinsic(Intrinsic.X86Mulpd, n, m); - - res = context.AddIntrinsic(Intrinsic.X86Addpd, d, res); - - context.Copy(d, res); - } - } - else - { - EmitVectorTernaryOpF(context, (op1, op2, op3) => - { - return EmitSoftFloatCall(context, nameof(SoftFloat32.FPMulAdd), op1, op2, op3); - }); - } - } - - public static void Fmla_Ve(ArmEmitterContext context) // Fused. - { - if (Optimizations.FastFP && Optimizations.UseSse2) - { - OpCodeSimdRegElemF op = (OpCodeSimdRegElemF)context.CurrOp; - - Operand d = GetVec(op.Rd); - Operand n = GetVec(op.Rn); - Operand m = GetVec(op.Rm); - - int sizeF = op.Size & 1; - - if (sizeF == 0) - { - int shuffleMask = op.Index | op.Index << 2 | op.Index << 4 | op.Index << 6; - - Operand res = context.AddIntrinsic(Intrinsic.X86Shufps, m, m, Const(shuffleMask)); - - res = context.AddIntrinsic(Intrinsic.X86Mulps, n, res); - res = context.AddIntrinsic(Intrinsic.X86Addps, d, res); - - if (op.RegisterSize == RegisterSize.Simd64) - { - res = context.VectorZeroUpper64(res); - } - - context.Copy(d, res); - } - else /* if (sizeF == 1) */ - { - int shuffleMask = op.Index | op.Index << 1; - - Operand res = context.AddIntrinsic(Intrinsic.X86Shufpd, m, m, Const(shuffleMask)); - - res = context.AddIntrinsic(Intrinsic.X86Mulpd, n, res); - res = context.AddIntrinsic(Intrinsic.X86Addpd, d, res); - - context.Copy(d, res); - } - } - else - { - EmitVectorTernaryOpByElemF(context, (op1, op2, op3) => - { - return EmitSoftFloatCall(context, nameof(SoftFloat32.FPMulAdd), op1, op2, op3); - }); - } - } - - public static void Fmls_Se(ArmEmitterContext context) // Fused. - { - EmitScalarTernaryOpByElemF(context, (op1, op2, op3) => - { - return context.Subtract(op1, context.Multiply(op2, op3)); - }); - } - - public static void Fmls_V(ArmEmitterContext context) // Fused. - { - if (Optimizations.FastFP && Optimizations.UseSse2) - { - OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp; - - Operand d = GetVec(op.Rd); - Operand n = GetVec(op.Rn); - Operand m = GetVec(op.Rm); - - int sizeF = op.Size & 1; - - if (sizeF == 0) - { - Operand res = context.AddIntrinsic(Intrinsic.X86Mulps, n, m); - - res = context.AddIntrinsic(Intrinsic.X86Subps, d, res); - - if (op.RegisterSize == RegisterSize.Simd64) - { - res = context.VectorZeroUpper64(res); - } - - context.Copy(d, res); - } - else /* if (sizeF == 1) */ - { - Operand res = context.AddIntrinsic(Intrinsic.X86Mulpd, n, m); - - res = context.AddIntrinsic(Intrinsic.X86Subpd, d, res); - - context.Copy(d, res); - } - } - else - { - EmitVectorTernaryOpF(context, (op1, op2, op3) => - { - return EmitSoftFloatCall(context, nameof(SoftFloat32.FPMulSub), op1, op2, op3); - }); - } - } - - public static void Fmls_Ve(ArmEmitterContext context) // Fused. - { - if (Optimizations.FastFP && Optimizations.UseSse2) - { - OpCodeSimdRegElemF op = (OpCodeSimdRegElemF)context.CurrOp; - - Operand d = GetVec(op.Rd); - Operand n = GetVec(op.Rn); - Operand m = GetVec(op.Rm); - - int sizeF = op.Size & 1; - - if (sizeF == 0) - { - int shuffleMask = op.Index | op.Index << 2 | op.Index << 4 | op.Index << 6; - - Operand res = context.AddIntrinsic(Intrinsic.X86Shufps, m, m, Const(shuffleMask)); - - res = context.AddIntrinsic(Intrinsic.X86Mulps, n, res); - res = context.AddIntrinsic(Intrinsic.X86Subps, d, res); - - if (op.RegisterSize == RegisterSize.Simd64) - { - res = context.VectorZeroUpper64(res); - } - - context.Copy(d, res); - } - else /* if (sizeF == 1) */ - { - int shuffleMask = op.Index | op.Index << 1; - - Operand res = context.AddIntrinsic(Intrinsic.X86Shufpd, m, m, Const(shuffleMask)); - - res = context.AddIntrinsic(Intrinsic.X86Mulpd, n, res); - res = context.AddIntrinsic(Intrinsic.X86Subpd, d, res); - - context.Copy(d, res); - } - } - else - { - EmitVectorTernaryOpByElemF(context, (op1, op2, op3) => - { - return EmitSoftFloatCall(context, nameof(SoftFloat32.FPMulSub), op1, op2, op3); - }); - } - } - - public static void Fmsub_S(ArmEmitterContext context) // Fused. - { - if (Optimizations.FastFP && Optimizations.UseSse2) - { - OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp; - - Operand d = GetVec(op.Rd); - Operand a = GetVec(op.Ra); - Operand n = GetVec(op.Rn); - Operand m = GetVec(op.Rm); - - if (op.Size == 0) - { - Operand res = context.AddIntrinsic(Intrinsic.X86Mulss, n, m); - res = context.AddIntrinsic(Intrinsic.X86Subss, a, res); - - context.Copy(d, context.VectorZeroUpper96(res)); - } - else /* if (op.Size == 1) */ - { - Operand res = context.AddIntrinsic(Intrinsic.X86Mulsd, n, m); - res = context.AddIntrinsic(Intrinsic.X86Subsd, a, res); - - context.Copy(d, context.VectorZeroUpper64(res)); - } - } - else - { - EmitScalarTernaryRaOpF(context, (op1, op2, op3) => - { - return EmitSoftFloatCall(context, nameof(SoftFloat32.FPMulSub), op1, op2, op3); - }); - } - } - - public static void Fmul_S(ArmEmitterContext context) - { - if (Optimizations.FastFP && Optimizations.UseSse2) - { - EmitScalarBinaryOpF(context, Intrinsic.X86Mulss, Intrinsic.X86Mulsd); - } - else if (Optimizations.FastFP) - { - EmitScalarBinaryOpF(context, (op1, op2) => context.Multiply(op1, op2)); - } - else - { - EmitScalarBinaryOpF(context, (op1, op2) => - { - return EmitSoftFloatCall(context, nameof(SoftFloat32.FPMul), op1, op2); - }); - } - } - - public static void Fmul_Se(ArmEmitterContext context) - { - EmitScalarBinaryOpByElemF(context, (op1, op2) => context.Multiply(op1, op2)); - } - - public static void Fmul_V(ArmEmitterContext context) - { - if (Optimizations.FastFP && Optimizations.UseSse2) - { - EmitVectorBinaryOpF(context, Intrinsic.X86Mulps, Intrinsic.X86Mulpd); - } - else if (Optimizations.FastFP) - { - EmitVectorBinaryOpF(context, (op1, op2) => context.Multiply(op1, op2)); - } - else - { - EmitVectorBinaryOpF(context, (op1, op2) => - { - return EmitSoftFloatCall(context, nameof(SoftFloat32.FPMul), op1, op2); - }); - } - } - - public static void Fmul_Ve(ArmEmitterContext context) - { - if (Optimizations.FastFP && Optimizations.UseSse2) - { - OpCodeSimdRegElemF op = (OpCodeSimdRegElemF)context.CurrOp; - - Operand n = GetVec(op.Rn); - Operand m = GetVec(op.Rm); - - int sizeF = op.Size & 1; - - if (sizeF == 0) - { - int shuffleMask = op.Index | op.Index << 2 | op.Index << 4 | op.Index << 6; - - Operand res = context.AddIntrinsic(Intrinsic.X86Shufps, m, m, Const(shuffleMask)); - - res = context.AddIntrinsic(Intrinsic.X86Mulps, n, res); - - if (op.RegisterSize == RegisterSize.Simd64) - { - res = context.VectorZeroUpper64(res); - } - - context.Copy(GetVec(op.Rd), res); - } - else /* if (sizeF == 1) */ - { - int shuffleMask = op.Index | op.Index << 1; - - Operand res = context.AddIntrinsic(Intrinsic.X86Shufpd, m, m, Const(shuffleMask)); - - res = context.AddIntrinsic(Intrinsic.X86Mulpd, n, res); - - context.Copy(GetVec(op.Rd), res); - } - } - else if (Optimizations.FastFP) - { - EmitVectorBinaryOpByElemF(context, (op1, op2) => context.Multiply(op1, op2)); - } - else - { - EmitVectorBinaryOpByElemF(context, (op1, op2) => - { - return EmitSoftFloatCall(context, nameof(SoftFloat32.FPMul), op1, op2); - }); - } - } - - public static void Fmulx_S(ArmEmitterContext context) - { - EmitScalarBinaryOpF(context, (op1, op2) => - { - return EmitSoftFloatCall(context, nameof(SoftFloat32.FPMulX), op1, op2); - }); - } - - public static void Fmulx_Se(ArmEmitterContext context) - { - EmitScalarBinaryOpByElemF(context, (op1, op2) => - { - return EmitSoftFloatCall(context, nameof(SoftFloat32.FPMulX), op1, op2); - }); - } - - public static void Fmulx_V(ArmEmitterContext context) - { - EmitVectorBinaryOpF(context, (op1, op2) => - { - return EmitSoftFloatCall(context, nameof(SoftFloat32.FPMulX), op1, op2); - }); - } - - public static void Fmulx_Ve(ArmEmitterContext context) - { - EmitVectorBinaryOpByElemF(context, (op1, op2) => - { - return EmitSoftFloatCall(context, nameof(SoftFloat32.FPMulX), op1, op2); - }); - } - - public static void Fneg_S(ArmEmitterContext context) - { - if (Optimizations.UseSse2) - { - OpCodeSimd op = (OpCodeSimd)context.CurrOp; - - if (op.Size == 0) - { - Operand mask = X86GetScalar(context, -0f); - - Operand res = context.AddIntrinsic(Intrinsic.X86Xorps, mask, GetVec(op.Rn)); - - context.Copy(GetVec(op.Rd), context.VectorZeroUpper96(res)); - } - else /* if (op.Size == 1) */ - { - Operand mask = X86GetScalar(context, -0d); - - Operand res = context.AddIntrinsic(Intrinsic.X86Xorpd, mask, GetVec(op.Rn)); - - context.Copy(GetVec(op.Rd), context.VectorZeroUpper64(res)); - } - } - else - { - EmitScalarUnaryOpF(context, (op1) => context.Negate(op1)); - } - } - - public static void Fneg_V(ArmEmitterContext context) - { - if (Optimizations.UseSse2) - { - OpCodeSimd op = (OpCodeSimd)context.CurrOp; - - int sizeF = op.Size & 1; - - if (sizeF == 0) - { - Operand mask = X86GetAllElements(context, -0f); - - Operand res = context.AddIntrinsic(Intrinsic.X86Xorps, mask, GetVec(op.Rn)); - - if (op.RegisterSize == RegisterSize.Simd64) - { - res = context.VectorZeroUpper64(res); - } - - context.Copy(GetVec(op.Rd), res); - } - else /* if (sizeF == 1) */ - { - Operand mask = X86GetAllElements(context, -0d); - - Operand res = context.AddIntrinsic(Intrinsic.X86Xorpd, mask, GetVec(op.Rn)); - - context.Copy(GetVec(op.Rd), res); - } - } - else - { - EmitVectorUnaryOpF(context, (op1) => context.Negate(op1)); - } - } - - public static void Fnmadd_S(ArmEmitterContext context) // Fused. - { - if (Optimizations.FastFP && Optimizations.UseSse2) - { - OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp; - - Operand d = GetVec(op.Rd); - Operand a = GetVec(op.Ra); - Operand n = GetVec(op.Rn); - Operand m = GetVec(op.Rm); - - if (op.Size == 0) - { - Operand mask = X86GetScalar(context, -0f); - - Operand aNeg = context.AddIntrinsic(Intrinsic.X86Xorps, mask, a); - - Operand res = context.AddIntrinsic(Intrinsic.X86Mulss, n, m); - res = context.AddIntrinsic(Intrinsic.X86Subss, aNeg, res); - - context.Copy(d, context.VectorZeroUpper96(res)); - } - else /* if (op.Size == 1) */ - { - Operand mask = X86GetScalar(context, -0d); - - Operand aNeg = context.AddIntrinsic(Intrinsic.X86Xorpd, mask, a); - - Operand res = context.AddIntrinsic(Intrinsic.X86Mulsd, n, m); - res = context.AddIntrinsic(Intrinsic.X86Subsd, aNeg, res); - - context.Copy(d, context.VectorZeroUpper64(res)); - } - } - else - { - EmitScalarTernaryRaOpF(context, (op1, op2, op3) => - { - return EmitSoftFloatCall(context, nameof(SoftFloat32.FPNegMulAdd), op1, op2, op3); - }); - } - } - - public static void Fnmsub_S(ArmEmitterContext context) // Fused. - { - if (Optimizations.FastFP && Optimizations.UseSse2) - { - OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp; - - Operand d = GetVec(op.Rd); - Operand a = GetVec(op.Ra); - Operand n = GetVec(op.Rn); - Operand m = GetVec(op.Rm); - - if (op.Size == 0) - { - Operand mask = X86GetScalar(context, -0f); - - Operand aNeg = context.AddIntrinsic(Intrinsic.X86Xorps, mask, a); - - Operand res = context.AddIntrinsic(Intrinsic.X86Mulss, n, m); - res = context.AddIntrinsic(Intrinsic.X86Addss, aNeg, res); - - context.Copy(d, context.VectorZeroUpper96(res)); - } - else /* if (op.Size == 1) */ - { - Operand mask = X86GetScalar(context, -0d); - - Operand aNeg = context.AddIntrinsic(Intrinsic.X86Xorpd, mask, a); - - Operand res = context.AddIntrinsic(Intrinsic.X86Mulsd, n, m); - res = context.AddIntrinsic(Intrinsic.X86Addsd, aNeg, res); - - context.Copy(d, context.VectorZeroUpper64(res)); - } - } - else - { - EmitScalarTernaryRaOpF(context, (op1, op2, op3) => - { - return EmitSoftFloatCall(context, nameof(SoftFloat32.FPNegMulSub), op1, op2, op3); - }); - } - } - - public static void Fnmul_S(ArmEmitterContext context) - { - EmitScalarBinaryOpF(context, (op1, op2) => context.Negate(context.Multiply(op1, op2))); - } - - public static void Frecpe_S(ArmEmitterContext context) - { - OpCodeSimd op = (OpCodeSimd)context.CurrOp; - - int sizeF = op.Size & 1; - - if (Optimizations.FastFP && Optimizations.UseSse41 && sizeF == 0) - { - Operand res = EmitSse41Round32Exp8OpF(context, context.AddIntrinsic(Intrinsic.X86Rcpss, GetVec(op.Rn)), scalar: true); - - context.Copy(GetVec(op.Rd), context.VectorZeroUpper96(res)); - } - else - { - EmitScalarUnaryOpF(context, (op1) => - { - return EmitSoftFloatCall(context, nameof(SoftFloat32.FPRecipEstimate), op1); - }); - } - } - - public static void Frecpe_V(ArmEmitterContext context) - { - OpCodeSimd op = (OpCodeSimd)context.CurrOp; - - int sizeF = op.Size & 1; - - if (Optimizations.FastFP && Optimizations.UseSse41 && sizeF == 0) - { - Operand res = EmitSse41Round32Exp8OpF(context, context.AddIntrinsic(Intrinsic.X86Rcpps, GetVec(op.Rn)), scalar: false); - - if (op.RegisterSize == RegisterSize.Simd64) - { - res = context.VectorZeroUpper64(res); - } - - context.Copy(GetVec(op.Rd), res); - } - else - { - EmitVectorUnaryOpF(context, (op1) => - { - return EmitSoftFloatCall(context, nameof(SoftFloat32.FPRecipEstimate), op1); - }); - } - } - - public static void Frecps_S(ArmEmitterContext context) // Fused. - { - if (Optimizations.FastFP && Optimizations.UseSse41) - { - OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp; - - Operand n = GetVec(op.Rn); - Operand m = GetVec(op.Rm); - - int sizeF = op.Size & 1; - - if (sizeF == 0) - { - Operand mask = X86GetScalar(context, 2f); - - Operand res = context.AddIntrinsic(Intrinsic.X86Mulss, n, m); - - res = context.AddIntrinsic(Intrinsic.X86Subss, mask, res); - res = EmitSse41RecipStepSelectOpF(context, n, m, res, mask, scalar: true, sizeF); - - context.Copy(GetVec(op.Rd), context.VectorZeroUpper96(res)); - } - else /* if (sizeF == 1) */ - { - Operand mask = X86GetScalar(context, 2d); - - Operand res = context.AddIntrinsic(Intrinsic.X86Mulsd, n, m); - - res = context.AddIntrinsic(Intrinsic.X86Subsd, mask, res); - res = EmitSse41RecipStepSelectOpF(context, n, m, res, mask, scalar: true, sizeF); - - context.Copy(GetVec(op.Rd), context.VectorZeroUpper64(res)); - } - } - else - { - EmitScalarBinaryOpF(context, (op1, op2) => - { - return EmitSoftFloatCall(context, nameof(SoftFloat32.FPRecipStepFused), op1, op2); - }); - } - } - - public static void Frecps_V(ArmEmitterContext context) // Fused. - { - if (Optimizations.FastFP && Optimizations.UseSse41) - { - OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp; - - Operand n = GetVec(op.Rn); - Operand m = GetVec(op.Rm); - - int sizeF = op.Size & 1; - - if (sizeF == 0) - { - Operand mask = X86GetAllElements(context, 2f); - - Operand res = context.AddIntrinsic(Intrinsic.X86Mulps, n, m); - res = EmitSse41RecipStepSelectOpF(context, n, m, res, mask, scalar: false, sizeF); - - res = context.AddIntrinsic(Intrinsic.X86Subps, mask, res); - - if (op.RegisterSize == RegisterSize.Simd64) - { - res = context.VectorZeroUpper64(res); - } - - context.Copy(GetVec(op.Rd), res); - } - else /* if (sizeF == 1) */ - { - Operand mask = X86GetAllElements(context, 2d); - - Operand res = context.AddIntrinsic(Intrinsic.X86Mulpd, n, m); - res = EmitSse41RecipStepSelectOpF(context, n, m, res, mask, scalar: false, sizeF); - - res = context.AddIntrinsic(Intrinsic.X86Subpd, mask, res); - - context.Copy(GetVec(op.Rd), res); - } - } - else - { - EmitVectorBinaryOpF(context, (op1, op2) => - { - return EmitSoftFloatCall(context, nameof(SoftFloat32.FPRecipStepFused), op1, op2); - }); - } - } - - public static void Frecpx_S(ArmEmitterContext context) - { - EmitScalarUnaryOpF(context, (op1) => - { - return EmitSoftFloatCall(context, nameof(SoftFloat32.FPRecpX), op1); - }); - } - - public static void Frinta_S(ArmEmitterContext context) - { - EmitScalarUnaryOpF(context, (op1) => - { - return EmitRoundMathCall(context, MidpointRounding.AwayFromZero, op1); - }); - } - - public static void Frinta_V(ArmEmitterContext context) - { - EmitVectorUnaryOpF(context, (op1) => - { - return EmitRoundMathCall(context, MidpointRounding.AwayFromZero, op1); - }); - } - - public static void Frinti_S(ArmEmitterContext context) - { - EmitScalarUnaryOpF(context, (op1) => - { - return EmitRoundByRMode(context, op1); - }); - } - - public static void Frinti_V(ArmEmitterContext context) - { - EmitVectorUnaryOpF(context, (op1) => - { - return EmitRoundByRMode(context, op1); - }); - } - - public static void Frintm_S(ArmEmitterContext context) - { - if (Optimizations.UseSse41) - { - EmitSse41ScalarRoundOpF(context, FPRoundingMode.TowardsMinusInfinity); - } - else - { - EmitScalarUnaryOpF(context, (op1) => - { - return EmitUnaryMathCall(context, nameof(Math.Floor), op1); - }); - } - } - - public static void Frintm_V(ArmEmitterContext context) - { - if (Optimizations.UseSse41) - { - EmitSse41VectorRoundOpF(context, FPRoundingMode.TowardsMinusInfinity); - } - else - { - EmitVectorUnaryOpF(context, (op1) => - { - return EmitUnaryMathCall(context, nameof(Math.Floor), op1); - }); - } - } - - public static void Frintn_S(ArmEmitterContext context) - { - if (Optimizations.UseSse41) - { - EmitSse41ScalarRoundOpF(context, FPRoundingMode.ToNearest); - } - else - { - EmitScalarUnaryOpF(context, (op1) => - { - return EmitRoundMathCall(context, MidpointRounding.ToEven, op1); - }); - } - } - - public static void Frintn_V(ArmEmitterContext context) - { - if (Optimizations.UseSse41) - { - EmitSse41VectorRoundOpF(context, FPRoundingMode.ToNearest); - } - else - { - EmitVectorUnaryOpF(context, (op1) => - { - return EmitRoundMathCall(context, MidpointRounding.ToEven, op1); - }); - } - } - - public static void Frintp_S(ArmEmitterContext context) - { - if (Optimizations.UseSse41) - { - EmitSse41ScalarRoundOpF(context, FPRoundingMode.TowardsPlusInfinity); - } - else - { - EmitScalarUnaryOpF(context, (op1) => - { - return EmitUnaryMathCall(context, nameof(Math.Ceiling), op1); - }); - } - } - - public static void Frintp_V(ArmEmitterContext context) - { - if (Optimizations.UseSse41) - { - EmitSse41VectorRoundOpF(context, FPRoundingMode.TowardsPlusInfinity); - } - else - { - EmitVectorUnaryOpF(context, (op1) => - { - return EmitUnaryMathCall(context, nameof(Math.Ceiling), op1); - }); - } - } - - public static void Frintx_S(ArmEmitterContext context) - { - EmitScalarUnaryOpF(context, (op1) => - { - return EmitRoundByRMode(context, op1); - }); - } - - public static void Frintx_V(ArmEmitterContext context) - { - EmitVectorUnaryOpF(context, (op1) => - { - return EmitRoundByRMode(context, op1); - }); - } - - public static void Frintz_S(ArmEmitterContext context) - { - if (Optimizations.UseSse41) - { - EmitSse41ScalarRoundOpF(context, FPRoundingMode.TowardsZero); - } - else - { - EmitScalarUnaryOpF(context, (op1) => - { - return EmitUnaryMathCall(context, nameof(Math.Truncate), op1); - }); - } - } - - public static void Frintz_V(ArmEmitterContext context) - { - if (Optimizations.UseSse41) - { - EmitSse41VectorRoundOpF(context, FPRoundingMode.TowardsZero); - } - else - { - EmitVectorUnaryOpF(context, (op1) => - { - return EmitUnaryMathCall(context, nameof(Math.Truncate), op1); - }); - } - } - - public static void Frsqrte_S(ArmEmitterContext context) - { - OpCodeSimd op = (OpCodeSimd)context.CurrOp; - - int sizeF = op.Size & 1; - - if (Optimizations.FastFP && Optimizations.UseSse41 && sizeF == 0) - { - Operand res = EmitSse41Round32Exp8OpF(context, context.AddIntrinsic(Intrinsic.X86Rsqrtss, GetVec(op.Rn)), scalar: true); - - context.Copy(GetVec(op.Rd), context.VectorZeroUpper96(res)); - } - else - { - EmitScalarUnaryOpF(context, (op1) => - { - return EmitSoftFloatCall(context, nameof(SoftFloat32.FPRSqrtEstimate), op1); - }); - } - } - - public static void Frsqrte_V(ArmEmitterContext context) - { - OpCodeSimd op = (OpCodeSimd)context.CurrOp; - - int sizeF = op.Size & 1; - - if (Optimizations.FastFP && Optimizations.UseSse41 && sizeF == 0) - { - Operand res = EmitSse41Round32Exp8OpF(context, context.AddIntrinsic(Intrinsic.X86Rsqrtps, GetVec(op.Rn)), scalar: false); - - if (op.RegisterSize == RegisterSize.Simd64) - { - res = context.VectorZeroUpper64(res); - } - - context.Copy(GetVec(op.Rd), res); - } - else - { - EmitVectorUnaryOpF(context, (op1) => - { - return EmitSoftFloatCall(context, nameof(SoftFloat32.FPRSqrtEstimate), op1); - }); - } - } - - public static void Frsqrts_S(ArmEmitterContext context) // Fused. - { - if (Optimizations.FastFP && Optimizations.UseSse41) - { - OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp; - - Operand n = GetVec(op.Rn); - Operand m = GetVec(op.Rm); - - int sizeF = op.Size & 1; - - if (sizeF == 0) - { - Operand maskHalf = X86GetScalar(context, 0.5f); - Operand maskThree = X86GetScalar(context, 3f); - Operand maskOneHalf = X86GetScalar(context, 1.5f); - - Operand res = context.AddIntrinsic(Intrinsic.X86Mulss, n, m); - - res = context.AddIntrinsic(Intrinsic.X86Subss, maskThree, res); - res = context.AddIntrinsic(Intrinsic.X86Mulss, maskHalf, res); - res = EmitSse41RecipStepSelectOpF(context, n, m, res, maskOneHalf, scalar: true, sizeF); - - context.Copy(GetVec(op.Rd), context.VectorZeroUpper96(res)); - } - else /* if (sizeF == 1) */ - { - Operand maskHalf = X86GetScalar(context, 0.5d); - Operand maskThree = X86GetScalar(context, 3d); - Operand maskOneHalf = X86GetScalar(context, 1.5d); - - Operand res = context.AddIntrinsic(Intrinsic.X86Mulsd, n, m); - - res = context.AddIntrinsic(Intrinsic.X86Subsd, maskThree, res); - res = context.AddIntrinsic(Intrinsic.X86Mulsd, maskHalf, res); - res = EmitSse41RecipStepSelectOpF(context, n, m, res, maskOneHalf, scalar: true, sizeF); - - context.Copy(GetVec(op.Rd), context.VectorZeroUpper64(res)); - } - } - else - { - EmitScalarBinaryOpF(context, (op1, op2) => - { - return EmitSoftFloatCall(context, nameof(SoftFloat32.FPRSqrtStepFused), op1, op2); - }); - } - } - - public static void Frsqrts_V(ArmEmitterContext context) // Fused. - { - if (Optimizations.FastFP && Optimizations.UseSse41) - { - OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp; - - Operand n = GetVec(op.Rn); - Operand m = GetVec(op.Rm); - - int sizeF = op.Size & 1; - - if (sizeF == 0) - { - Operand maskHalf = X86GetAllElements(context, 0.5f); - Operand maskThree = X86GetAllElements(context, 3f); - Operand maskOneHalf = X86GetAllElements(context, 1.5f); - - Operand res = context.AddIntrinsic(Intrinsic.X86Mulps, n, m); - - res = context.AddIntrinsic(Intrinsic.X86Subps, maskThree, res); - res = context.AddIntrinsic(Intrinsic.X86Mulps, maskHalf, res); - res = EmitSse41RecipStepSelectOpF(context, n, m, res, maskOneHalf, scalar: false, sizeF); - - if (op.RegisterSize == RegisterSize.Simd64) - { - res = context.VectorZeroUpper64(res); - } - - context.Copy(GetVec(op.Rd), res); - } - else /* if (sizeF == 1) */ - { - Operand maskHalf = X86GetAllElements(context, 0.5d); - Operand maskThree = X86GetAllElements(context, 3d); - Operand maskOneHalf = X86GetAllElements(context, 1.5d); - - Operand res = context.AddIntrinsic(Intrinsic.X86Mulpd, n, m); - - res = context.AddIntrinsic(Intrinsic.X86Subpd, maskThree, res); - res = context.AddIntrinsic(Intrinsic.X86Mulpd, maskHalf, res); - res = EmitSse41RecipStepSelectOpF(context, n, m, res, maskOneHalf, scalar: false, sizeF); - - context.Copy(GetVec(op.Rd), res); - } - } - else - { - EmitVectorBinaryOpF(context, (op1, op2) => - { - return EmitSoftFloatCall(context, nameof(SoftFloat32.FPRSqrtStepFused), op1, op2); - }); - } - } - - public static void Fsqrt_S(ArmEmitterContext context) - { - if (Optimizations.FastFP && Optimizations.UseSse2) - { - EmitScalarUnaryOpF(context, Intrinsic.X86Sqrtss, Intrinsic.X86Sqrtsd); - } - else - { - EmitScalarUnaryOpF(context, (op1) => - { - return EmitSoftFloatCall(context, nameof(SoftFloat32.FPSqrt), op1); - }); - } - } - - public static void Fsqrt_V(ArmEmitterContext context) - { - if (Optimizations.FastFP && Optimizations.UseSse2) - { - EmitVectorUnaryOpF(context, Intrinsic.X86Sqrtps, Intrinsic.X86Sqrtpd); - } - else - { - EmitVectorUnaryOpF(context, (op1) => - { - return EmitSoftFloatCall(context, nameof(SoftFloat32.FPSqrt), op1); - }); - } - } - - public static void Fsub_S(ArmEmitterContext context) - { - if (Optimizations.FastFP && Optimizations.UseSse2) - { - EmitScalarBinaryOpF(context, Intrinsic.X86Subss, Intrinsic.X86Subsd); - } - else if (Optimizations.FastFP) - { - EmitScalarBinaryOpF(context, (op1, op2) => context.Subtract(op1, op2)); - } - else - { - EmitScalarBinaryOpF(context, (op1, op2) => - { - return EmitSoftFloatCall(context, nameof(SoftFloat32.FPSub), op1, op2); - }); - } - } - - public static void Fsub_V(ArmEmitterContext context) - { - if (Optimizations.FastFP && Optimizations.UseSse2) - { - EmitVectorBinaryOpF(context, Intrinsic.X86Subps, Intrinsic.X86Subpd); - } - else if (Optimizations.FastFP) - { - EmitVectorBinaryOpF(context, (op1, op2) => context.Subtract(op1, op2)); - } - else - { - EmitVectorBinaryOpF(context, (op1, op2) => - { - return EmitSoftFloatCall(context, nameof(SoftFloat32.FPSub), op1, op2); - }); - } - } - - public static void Mla_V(ArmEmitterContext context) - { - if (Optimizations.UseSse41) - { - EmitSse41VectorMul_AddSub(context, AddSub.Add); - } - else - { - EmitVectorTernaryOpZx(context, (op1, op2, op3) => - { - return context.Add(op1, context.Multiply(op2, op3)); - }); - } - } - - public static void Mla_Ve(ArmEmitterContext context) - { - EmitVectorTernaryOpByElemZx(context, (op1, op2, op3) => - { - return context.Add(op1, context.Multiply(op2, op3)); - }); - } - - public static void Mls_V(ArmEmitterContext context) - { - if (Optimizations.UseSse41) - { - EmitSse41VectorMul_AddSub(context, AddSub.Subtract); - } - else - { - EmitVectorTernaryOpZx(context, (op1, op2, op3) => - { - return context.Subtract(op1, context.Multiply(op2, op3)); - }); - } - } - - public static void Mls_Ve(ArmEmitterContext context) - { - EmitVectorTernaryOpByElemZx(context, (op1, op2, op3) => - { - return context.Subtract(op1, context.Multiply(op2, op3)); - }); - } - - public static void Mul_V(ArmEmitterContext context) - { - if (Optimizations.UseSse41) - { - EmitSse41VectorMul_AddSub(context, AddSub.None); - } - else - { - EmitVectorBinaryOpZx(context, (op1, op2) => context.Multiply(op1, op2)); - } - } - - public static void Mul_Ve(ArmEmitterContext context) - { - EmitVectorBinaryOpByElemZx(context, (op1, op2) => context.Multiply(op1, op2)); - } - - public static void Neg_S(ArmEmitterContext context) - { - EmitScalarUnaryOpSx(context, (op1) => context.Negate(op1)); - } - - public static void Neg_V(ArmEmitterContext context) - { - if (Optimizations.UseSse2) - { - OpCodeSimd op = (OpCodeSimd)context.CurrOp; - - Intrinsic subInst = X86PsubInstruction[op.Size]; - - Operand res = context.AddIntrinsic(subInst, context.VectorZero(), GetVec(op.Rn)); - - if (op.RegisterSize == RegisterSize.Simd64) - { - res = context.VectorZeroUpper64(res); - } - - context.Copy(GetVec(op.Rd), res); - } - else - { - EmitVectorUnaryOpSx(context, (op1) => context.Negate(op1)); - } - } - - public static void Pmull_V(ArmEmitterContext context) - { - OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp; - - if (Optimizations.UsePclmulqdq && op.Size == 3) - { - Operand n = GetVec(op.Rn); - Operand m = GetVec(op.Rm); - - int imm8 = op.RegisterSize == RegisterSize.Simd64 ? 0b0000_0000 : 0b0001_0001; - - Operand res = context.AddIntrinsic(Intrinsic.X86Pclmulqdq, n, m, Const(imm8)); - - context.Copy(GetVec(op.Rd), res); - } - else if (Optimizations.UseSse41) - { - Operand n = GetVec(op.Rn); - Operand m = GetVec(op.Rm); - - if (op.RegisterSize == RegisterSize.Simd64) - { - n = context.VectorZeroUpper64(n); - m = context.VectorZeroUpper64(m); - } - else /* if (op.RegisterSize == RegisterSize.Simd128) */ - { - n = context.AddIntrinsic(Intrinsic.X86Psrldq, n, Const(8)); - m = context.AddIntrinsic(Intrinsic.X86Psrldq, m, Const(8)); - } - - Operand res = context.VectorZero(); - - if (op.Size == 0) - { - n = context.AddIntrinsic(Intrinsic.X86Pmovzxbw, n); - m = context.AddIntrinsic(Intrinsic.X86Pmovzxbw, m); - - for (int i = 0; i < 8; i++) - { - Operand mask = context.AddIntrinsic(Intrinsic.X86Psllw, n, Const(15 - i)); - mask = context.AddIntrinsic(Intrinsic.X86Psraw, mask, Const(15)); - - Operand tmp = context.AddIntrinsic(Intrinsic.X86Psllw, m, Const(i)); - tmp = context.AddIntrinsic(Intrinsic.X86Pand, tmp, mask); - - res = context.AddIntrinsic(Intrinsic.X86Pxor, res, tmp); - } - } - else /* if (op.Size == 3) */ - { - Operand zero = context.VectorZero(); - - for (int i = 0; i < 64; i++) - { - Operand mask = context.AddIntrinsic(Intrinsic.X86Movlhps, n, n); - mask = context.AddIntrinsic(Intrinsic.X86Psllq, mask, Const(63 - i)); - mask = context.AddIntrinsic(Intrinsic.X86Psrlq, mask, Const(63)); - mask = context.AddIntrinsic(Intrinsic.X86Psubq, zero, mask); - - Operand tmp = EmitSse2Sll_128(context, m, i); - tmp = context.AddIntrinsic(Intrinsic.X86Pand, tmp, mask); - - res = context.AddIntrinsic(Intrinsic.X86Pxor, res, tmp); - } - } - - context.Copy(GetVec(op.Rd), res); - } - else - { - Operand n = GetVec(op.Rn); - Operand m = GetVec(op.Rm); - - Operand res; - - if (op.Size == 0) - { - res = context.VectorZero(); - - int part = op.RegisterSize == RegisterSize.Simd64 ? 0 : 8; - - for (int index = 0; index < 8; index++) - { - Operand ne = context.VectorExtract8(n, part + index); - Operand me = context.VectorExtract8(m, part + index); - - Operand de = EmitPolynomialMultiply(context, ne, me, 8); - - res = EmitVectorInsert(context, res, de, index, 1); - } - } - else /* if (op.Size == 3) */ - { - int part = op.RegisterSize == RegisterSize.Simd64 ? 0 : 1; - - Operand ne = context.VectorExtract(OperandType.I64, n, part); - Operand me = context.VectorExtract(OperandType.I64, m, part); - - res = context.Call(typeof(SoftFallback).GetMethod(nameof(SoftFallback.PolynomialMult64_128)), ne, me); - } - - context.Copy(GetVec(op.Rd), res); - } - } - - public static void Raddhn_V(ArmEmitterContext context) - { - EmitHighNarrow(context, (op1, op2) => context.Add(op1, op2), round: true); - } - - public static void Rsubhn_V(ArmEmitterContext context) - { - EmitHighNarrow(context, (op1, op2) => context.Subtract(op1, op2), round: true); - } - - public static void Saba_V(ArmEmitterContext context) - { - EmitVectorTernaryOpSx(context, (op1, op2, op3) => - { - return context.Add(op1, EmitAbs(context, context.Subtract(op2, op3))); - }); - } - - public static void Sabal_V(ArmEmitterContext context) - { - EmitVectorWidenRnRmTernaryOpSx(context, (op1, op2, op3) => - { - return context.Add(op1, EmitAbs(context, context.Subtract(op2, op3))); - }); - } - - public static void Sabd_V(ArmEmitterContext context) - { - if (Optimizations.UseSse41) - { - OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp; - - Operand n = GetVec(op.Rn); - Operand m = GetVec(op.Rm); - - EmitSse41VectorSabdOp(context, op, n, m, isLong: false); - } - else - { - EmitVectorBinaryOpSx(context, (op1, op2) => - { - return EmitAbs(context, context.Subtract(op1, op2)); - }); - } - } - - public static void Sabdl_V(ArmEmitterContext context) - { - OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp; - - if (Optimizations.UseSse41 && op.Size < 2) - { - Operand n = GetVec(op.Rn); - Operand m = GetVec(op.Rm); - - if (op.RegisterSize == RegisterSize.Simd128) - { - n = context.AddIntrinsic(Intrinsic.X86Psrldq, n, Const(8)); - m = context.AddIntrinsic(Intrinsic.X86Psrldq, m, Const(8)); - } - - Intrinsic movInst = op.Size == 0 - ? Intrinsic.X86Pmovsxbw - : Intrinsic.X86Pmovsxwd; - - n = context.AddIntrinsic(movInst, n); - m = context.AddIntrinsic(movInst, m); - - EmitSse41VectorSabdOp(context, op, n, m, isLong: true); - } - else - { - EmitVectorWidenRnRmBinaryOpSx(context, (op1, op2) => - { - return EmitAbs(context, context.Subtract(op1, op2)); - }); - } - } - - public static void Sadalp_V(ArmEmitterContext context) - { - EmitAddLongPairwise(context, signed: true, accumulate: true); - } - - public static void Saddl_V(ArmEmitterContext context) - { - if (Optimizations.UseSse41) - { - OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp; - - Operand n = GetVec(op.Rn); - Operand m = GetVec(op.Rm); - - if (op.RegisterSize == RegisterSize.Simd128) - { - n = context.AddIntrinsic(Intrinsic.X86Psrldq, n, Const(8)); - m = context.AddIntrinsic(Intrinsic.X86Psrldq, m, Const(8)); - } - - Intrinsic movInst = X86PmovsxInstruction[op.Size]; - - n = context.AddIntrinsic(movInst, n); - m = context.AddIntrinsic(movInst, m); - - Intrinsic addInst = X86PaddInstruction[op.Size + 1]; - - context.Copy(GetVec(op.Rd), context.AddIntrinsic(addInst, n, m)); - } - else - { - EmitVectorWidenRnRmBinaryOpSx(context, (op1, op2) => context.Add(op1, op2)); - } - } - - public static void Saddlp_V(ArmEmitterContext context) - { - EmitAddLongPairwise(context, signed: true, accumulate: false); - } - - public static void Saddlv_V(ArmEmitterContext context) - { - EmitVectorLongAcrossVectorOpSx(context, (op1, op2) => context.Add(op1, op2)); - } - - public static void Saddw_V(ArmEmitterContext context) - { - if (Optimizations.UseSse41) - { - OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp; - - Operand n = GetVec(op.Rn); - Operand m = GetVec(op.Rm); - - if (op.RegisterSize == RegisterSize.Simd128) - { - m = context.AddIntrinsic(Intrinsic.X86Psrldq, m, Const(8)); - } - - Intrinsic movInst = X86PmovsxInstruction[op.Size]; - - m = context.AddIntrinsic(movInst, m); - - Intrinsic addInst = X86PaddInstruction[op.Size + 1]; - - context.Copy(GetVec(op.Rd), context.AddIntrinsic(addInst, n, m)); - } - else - { - EmitVectorWidenRmBinaryOpSx(context, (op1, op2) => context.Add(op1, op2)); - } - } - - public static void Shadd_V(ArmEmitterContext context) - { - OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp; - - if (Optimizations.UseSse2 && op.Size > 0) - { - Operand n = GetVec(op.Rn); - Operand m = GetVec(op.Rm); - - Operand res = context.AddIntrinsic(Intrinsic.X86Pand, n, m); - Operand res2 = context.AddIntrinsic(Intrinsic.X86Pxor, n, m); - - Intrinsic shiftInst = op.Size == 1 ? Intrinsic.X86Psraw : Intrinsic.X86Psrad; - - res2 = context.AddIntrinsic(shiftInst, res2, Const(1)); - - Intrinsic addInst = X86PaddInstruction[op.Size]; - - res = context.AddIntrinsic(addInst, res, res2); - - if (op.RegisterSize == RegisterSize.Simd64) - { - res = context.VectorZeroUpper64(res); - } - - context.Copy(GetVec(op.Rd), res); - } - else - { - EmitVectorBinaryOpSx(context, (op1, op2) => - { - return context.ShiftRightSI(context.Add(op1, op2), Const(1)); - }); - } - } - - public static void Shsub_V(ArmEmitterContext context) - { - OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp; - - if (Optimizations.UseSse2 && op.Size < 2) - { - Operand n = GetVec(op.Rn); - Operand m = GetVec(op.Rm); - - Operand mask = X86GetAllElements(context, (int)(op.Size == 0 ? 0x80808080u : 0x80008000u)); - - Intrinsic addInst = X86PaddInstruction[op.Size]; - - Operand nPlusMask = context.AddIntrinsic(addInst, n, mask); - Operand mPlusMask = context.AddIntrinsic(addInst, m, mask); - - Intrinsic avgInst = op.Size == 0 ? Intrinsic.X86Pavgb : Intrinsic.X86Pavgw; - - Operand res = context.AddIntrinsic(avgInst, nPlusMask, mPlusMask); - - Intrinsic subInst = X86PsubInstruction[op.Size]; - - res = context.AddIntrinsic(subInst, nPlusMask, res); - - if (op.RegisterSize == RegisterSize.Simd64) - { - res = context.VectorZeroUpper64(res); - } - - context.Copy(GetVec(op.Rd), res); - } - else - { - EmitVectorBinaryOpSx(context, (op1, op2) => - { - return context.ShiftRightSI(context.Subtract(op1, op2), Const(1)); - }); - } - } - - public static void Smax_V(ArmEmitterContext context) - { - if (Optimizations.UseSse41) - { - OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp; - - Operand n = GetVec(op.Rn); - Operand m = GetVec(op.Rm); - - Intrinsic maxInst = X86PmaxsInstruction[op.Size]; - - Operand res = context.AddIntrinsic(maxInst, n, m); - - if (op.RegisterSize == RegisterSize.Simd64) - { - res = context.VectorZeroUpper64(res); - } - - context.Copy(GetVec(op.Rd), res); - } - else - { - EmitVectorBinaryOpSx(context, (op1, op2) => EmitMax64Op(context, op1, op2, signed: true)); - } - } - - public static void Smaxp_V(ArmEmitterContext context) - { - if (Optimizations.UseSsse3) - { - EmitSsse3VectorPairwiseOp(context, X86PmaxsInstruction); - } - else - { - EmitVectorPairwiseOpSx(context, (op1, op2) => EmitMax64Op(context, op1, op2, signed: true)); - } - } - - public static void Smaxv_V(ArmEmitterContext context) - { - EmitVectorAcrossVectorOpSx(context, (op1, op2) => EmitMax64Op(context, op1, op2, signed: true)); - } - - public static void Smin_V(ArmEmitterContext context) - { - if (Optimizations.UseSse41) - { - OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp; - - Operand n = GetVec(op.Rn); - Operand m = GetVec(op.Rm); - - Intrinsic minInst = X86PminsInstruction[op.Size]; - - Operand res = context.AddIntrinsic(minInst, n, m); - - if (op.RegisterSize == RegisterSize.Simd64) - { - res = context.VectorZeroUpper64(res); - } - - context.Copy(GetVec(op.Rd), res); - } - else - { - EmitVectorBinaryOpSx(context, (op1, op2) => EmitMin64Op(context, op1, op2, signed: true)); - } - } - - public static void Sminp_V(ArmEmitterContext context) - { - if (Optimizations.UseSsse3) - { - EmitSsse3VectorPairwiseOp(context, X86PminsInstruction); - } - else - { - EmitVectorPairwiseOpSx(context, (op1, op2) => EmitMin64Op(context, op1, op2, signed: true)); - } - } - - public static void Sminv_V(ArmEmitterContext context) - { - EmitVectorAcrossVectorOpSx(context, (op1, op2) => EmitMin64Op(context, op1, op2, signed: true)); - } - - public static void Smlal_V(ArmEmitterContext context) - { - OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp; - - if (Optimizations.UseSse41 && op.Size < 2) - { - Operand d = GetVec(op.Rd); - Operand n = GetVec(op.Rn); - Operand m = GetVec(op.Rm); - - if (op.RegisterSize == RegisterSize.Simd128) - { - n = context.AddIntrinsic(Intrinsic.X86Psrldq, n, Const(8)); - m = context.AddIntrinsic(Intrinsic.X86Psrldq, m, Const(8)); - } - - Intrinsic movInst = X86PmovsxInstruction[op.Size]; - - n = context.AddIntrinsic(movInst, n); - m = context.AddIntrinsic(movInst, m); - - Intrinsic mullInst = op.Size == 0 ? Intrinsic.X86Pmullw : Intrinsic.X86Pmulld; - - Operand res = context.AddIntrinsic(mullInst, n, m); - - Intrinsic addInst = X86PaddInstruction[op.Size + 1]; - - context.Copy(d, context.AddIntrinsic(addInst, d, res)); - } - else - { - EmitVectorWidenRnRmTernaryOpSx(context, (op1, op2, op3) => - { - return context.Add(op1, context.Multiply(op2, op3)); - }); - } - } - - public static void Smlal_Ve(ArmEmitterContext context) - { - EmitVectorWidenTernaryOpByElemSx(context, (op1, op2, op3) => - { - return context.Add(op1, context.Multiply(op2, op3)); - }); - } - - public static void Smlsl_V(ArmEmitterContext context) - { - OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp; - - if (Optimizations.UseSse41 && op.Size < 2) - { - Operand d = GetVec(op.Rd); - Operand n = GetVec(op.Rn); - Operand m = GetVec(op.Rm); - - if (op.RegisterSize == RegisterSize.Simd128) - { - n = context.AddIntrinsic(Intrinsic.X86Psrldq, n, Const(8)); - m = context.AddIntrinsic(Intrinsic.X86Psrldq, m, Const(8)); - } - - Intrinsic movInst = op.Size == 0 ? Intrinsic.X86Pmovsxbw : Intrinsic.X86Pmovsxwd; - - n = context.AddIntrinsic(movInst, n); - m = context.AddIntrinsic(movInst, m); - - Intrinsic mullInst = op.Size == 0 ? Intrinsic.X86Pmullw : Intrinsic.X86Pmulld; - - Operand res = context.AddIntrinsic(mullInst, n, m); - - Intrinsic subInst = X86PsubInstruction[op.Size + 1]; - - context.Copy(d, context.AddIntrinsic(subInst, d, res)); - } - else - { - EmitVectorWidenRnRmTernaryOpSx(context, (op1, op2, op3) => - { - return context.Subtract(op1, context.Multiply(op2, op3)); - }); - } - } - - public static void Smlsl_Ve(ArmEmitterContext context) - { - EmitVectorWidenTernaryOpByElemSx(context, (op1, op2, op3) => - { - return context.Subtract(op1, context.Multiply(op2, op3)); - }); - } - - public static void Smull_V(ArmEmitterContext context) - { - EmitVectorWidenRnRmBinaryOpSx(context, (op1, op2) => context.Multiply(op1, op2)); - } - - public static void Smull_Ve(ArmEmitterContext context) - { - EmitVectorWidenBinaryOpByElemSx(context, (op1, op2) => context.Multiply(op1, op2)); - } - - public static void Sqabs_S(ArmEmitterContext context) - { - EmitScalarSaturatingUnaryOpSx(context, (op1) => EmitAbs(context, op1)); - } - - public static void Sqabs_V(ArmEmitterContext context) - { - EmitVectorSaturatingUnaryOpSx(context, (op1) => EmitAbs(context, op1)); - } - - public static void Sqadd_S(ArmEmitterContext context) - { - EmitScalarSaturatingBinaryOpSx(context, flags: SaturatingFlags.Add); - } - - public static void Sqadd_V(ArmEmitterContext context) - { - EmitVectorSaturatingBinaryOpSx(context, flags: SaturatingFlags.Add); - } - - public static void Sqdmulh_S(ArmEmitterContext context) - { - EmitScalarSaturatingBinaryOpSx(context, (op1, op2) => EmitDoublingMultiplyHighHalf(context, op1, op2, round: false)); - } - - public static void Sqdmulh_V(ArmEmitterContext context) - { - EmitVectorSaturatingBinaryOpSx(context, (op1, op2) => EmitDoublingMultiplyHighHalf(context, op1, op2, round: false)); - } - - public static void Sqdmulh_Ve(ArmEmitterContext context) - { - EmitVectorSaturatingBinaryOpByElemSx(context, (op1, op2) => EmitDoublingMultiplyHighHalf(context, op1, op2, round: false)); - } - - public static void Sqneg_S(ArmEmitterContext context) - { - EmitScalarSaturatingUnaryOpSx(context, (op1) => context.Negate(op1)); - } - - public static void Sqneg_V(ArmEmitterContext context) - { - EmitVectorSaturatingUnaryOpSx(context, (op1) => context.Negate(op1)); - } - - public static void Sqrdmulh_S(ArmEmitterContext context) - { - EmitScalarSaturatingBinaryOpSx(context, (op1, op2) => EmitDoublingMultiplyHighHalf(context, op1, op2, round: true)); - } - - public static void Sqrdmulh_V(ArmEmitterContext context) - { - EmitVectorSaturatingBinaryOpSx(context, (op1, op2) => EmitDoublingMultiplyHighHalf(context, op1, op2, round: true)); - } - - public static void Sqrdmulh_Ve(ArmEmitterContext context) - { - EmitVectorSaturatingBinaryOpByElemSx(context, (op1, op2) => EmitDoublingMultiplyHighHalf(context, op1, op2, round: true)); - } - - public static void Sqsub_S(ArmEmitterContext context) - { - EmitScalarSaturatingBinaryOpSx(context, flags: SaturatingFlags.Sub); - } - - public static void Sqsub_V(ArmEmitterContext context) - { - EmitVectorSaturatingBinaryOpSx(context, flags: SaturatingFlags.Sub); - } - - public static void Sqxtn_S(ArmEmitterContext context) - { - EmitSaturatingNarrowOp(context, SaturatingNarrowFlags.ScalarSxSx); - } - - public static void Sqxtn_V(ArmEmitterContext context) - { - EmitSaturatingNarrowOp(context, SaturatingNarrowFlags.VectorSxSx); - } - - public static void Sqxtun_S(ArmEmitterContext context) - { - EmitSaturatingNarrowOp(context, SaturatingNarrowFlags.ScalarSxZx); - } - - public static void Sqxtun_V(ArmEmitterContext context) - { - EmitSaturatingNarrowOp(context, SaturatingNarrowFlags.VectorSxZx); - } - - public static void Srhadd_V(ArmEmitterContext context) - { - OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp; - - if (Optimizations.UseSse2 && op.Size < 2) - { - Operand n = GetVec(op.Rn); - Operand m = GetVec(op.Rm); - - Operand mask = X86GetAllElements(context, (int)(op.Size == 0 ? 0x80808080u : 0x80008000u)); - - Intrinsic subInst = X86PsubInstruction[op.Size]; - - Operand nMinusMask = context.AddIntrinsic(subInst, n, mask); - Operand mMinusMask = context.AddIntrinsic(subInst, m, mask); - - Intrinsic avgInst = op.Size == 0 ? Intrinsic.X86Pavgb : Intrinsic.X86Pavgw; - - Operand res = context.AddIntrinsic(avgInst, nMinusMask, mMinusMask); - - Intrinsic addInst = X86PaddInstruction[op.Size]; - - res = context.AddIntrinsic(addInst, mask, res); - - if (op.RegisterSize == RegisterSize.Simd64) - { - res = context.VectorZeroUpper64(res); - } - - context.Copy(GetVec(op.Rd), res); - } - else - { - EmitVectorBinaryOpSx(context, (op1, op2) => - { - Operand res = context.Add(op1, op2); - - res = context.Add(res, Const(1L)); - - return context.ShiftRightSI(res, Const(1)); - }); - } - } - - public static void Ssubl_V(ArmEmitterContext context) - { - if (Optimizations.UseSse41) - { - OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp; - - Operand n = GetVec(op.Rn); - Operand m = GetVec(op.Rm); - - if (op.RegisterSize == RegisterSize.Simd128) - { - n = context.AddIntrinsic(Intrinsic.X86Psrldq, n, Const(8)); - m = context.AddIntrinsic(Intrinsic.X86Psrldq, m, Const(8)); - } - - Intrinsic movInst = X86PmovsxInstruction[op.Size]; - - n = context.AddIntrinsic(movInst, n); - m = context.AddIntrinsic(movInst, m); - - Intrinsic subInst = X86PsubInstruction[op.Size + 1]; - - context.Copy(GetVec(op.Rd), context.AddIntrinsic(subInst, n, m)); - } - else - { - EmitVectorWidenRnRmBinaryOpSx(context, (op1, op2) => context.Subtract(op1, op2)); - } - } - - public static void Ssubw_V(ArmEmitterContext context) - { - if (Optimizations.UseSse41) - { - OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp; - - Operand n = GetVec(op.Rn); - Operand m = GetVec(op.Rm); - - if (op.RegisterSize == RegisterSize.Simd128) - { - m = context.AddIntrinsic(Intrinsic.X86Psrldq, m, Const(8)); - } - - Intrinsic movInst = X86PmovsxInstruction[op.Size]; - - m = context.AddIntrinsic(movInst, m); - - Intrinsic subInst = X86PsubInstruction[op.Size + 1]; - - context.Copy(GetVec(op.Rd), context.AddIntrinsic(subInst, n, m)); - } - else - { - EmitVectorWidenRmBinaryOpSx(context, (op1, op2) => context.Subtract(op1, op2)); - } - } - - public static void Sub_S(ArmEmitterContext context) - { - EmitScalarBinaryOpZx(context, (op1, op2) => context.Subtract(op1, op2)); - } - - public static void Sub_V(ArmEmitterContext context) - { - if (Optimizations.UseSse2) - { - OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp; - - Operand n = GetVec(op.Rn); - Operand m = GetVec(op.Rm); - - Intrinsic subInst = X86PsubInstruction[op.Size]; - - Operand res = context.AddIntrinsic(subInst, n, m); - - if (op.RegisterSize == RegisterSize.Simd64) - { - res = context.VectorZeroUpper64(res); - } - - context.Copy(GetVec(op.Rd), res); - } - else - { - EmitVectorBinaryOpZx(context, (op1, op2) => context.Subtract(op1, op2)); - } - } - - public static void Subhn_V(ArmEmitterContext context) - { - EmitHighNarrow(context, (op1, op2) => context.Subtract(op1, op2), round: false); - } - - public static void Suqadd_S(ArmEmitterContext context) - { - EmitScalarSaturatingBinaryOpSx(context, flags: SaturatingFlags.Accumulate); - } - - public static void Suqadd_V(ArmEmitterContext context) - { - EmitVectorSaturatingBinaryOpSx(context, flags: SaturatingFlags.Accumulate); - } - - public static void Uaba_V(ArmEmitterContext context) - { - EmitVectorTernaryOpZx(context, (op1, op2, op3) => - { - return context.Add(op1, EmitAbs(context, context.Subtract(op2, op3))); - }); - } - - public static void Uabal_V(ArmEmitterContext context) - { - EmitVectorWidenRnRmTernaryOpZx(context, (op1, op2, op3) => - { - return context.Add(op1, EmitAbs(context, context.Subtract(op2, op3))); - }); - } - - public static void Uabd_V(ArmEmitterContext context) - { - if (Optimizations.UseSse41) - { - OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp; - - Operand n = GetVec(op.Rn); - Operand m = GetVec(op.Rm); - - EmitSse41VectorUabdOp(context, op, n, m, isLong: false); - } - else - { - EmitVectorBinaryOpZx(context, (op1, op2) => - { - return EmitAbs(context, context.Subtract(op1, op2)); - }); - } - } - - public static void Uabdl_V(ArmEmitterContext context) - { - OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp; - - if (Optimizations.UseSse41 && op.Size < 2) - { - Operand n = GetVec(op.Rn); - Operand m = GetVec(op.Rm); - - if (op.RegisterSize == RegisterSize.Simd128) - { - n = context.AddIntrinsic(Intrinsic.X86Psrldq, n, Const(8)); - m = context.AddIntrinsic(Intrinsic.X86Psrldq, m, Const(8)); - } - - Intrinsic movInst = op.Size == 0 - ? Intrinsic.X86Pmovzxbw - : Intrinsic.X86Pmovzxwd; - - n = context.AddIntrinsic(movInst, n); - m = context.AddIntrinsic(movInst, m); - - EmitSse41VectorUabdOp(context, op, n, m, isLong: true); - } - else - { - EmitVectorWidenRnRmBinaryOpZx(context, (op1, op2) => - { - return EmitAbs(context, context.Subtract(op1, op2)); - }); - } - } - - public static void Uadalp_V(ArmEmitterContext context) - { - EmitAddLongPairwise(context, signed: false, accumulate: true); - } - - public static void Uaddl_V(ArmEmitterContext context) - { - if (Optimizations.UseSse41) - { - OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp; - - Operand n = GetVec(op.Rn); - Operand m = GetVec(op.Rm); - - if (op.RegisterSize == RegisterSize.Simd128) - { - n = context.AddIntrinsic(Intrinsic.X86Psrldq, n, Const(8)); - m = context.AddIntrinsic(Intrinsic.X86Psrldq, m, Const(8)); - } - - Intrinsic movInst = X86PmovzxInstruction[op.Size]; - - n = context.AddIntrinsic(movInst, n); - m = context.AddIntrinsic(movInst, m); - - Intrinsic addInst = X86PaddInstruction[op.Size + 1]; - - context.Copy(GetVec(op.Rd), context.AddIntrinsic(addInst, n, m)); - } - else - { - EmitVectorWidenRnRmBinaryOpZx(context, (op1, op2) => context.Add(op1, op2)); - } - } - - public static void Uaddlp_V(ArmEmitterContext context) - { - EmitAddLongPairwise(context, signed: false, accumulate: false); - } - - public static void Uaddlv_V(ArmEmitterContext context) - { - EmitVectorLongAcrossVectorOpZx(context, (op1, op2) => context.Add(op1, op2)); - } - - public static void Uaddw_V(ArmEmitterContext context) - { - if (Optimizations.UseSse41) - { - OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp; - - Operand n = GetVec(op.Rn); - Operand m = GetVec(op.Rm); - - if (op.RegisterSize == RegisterSize.Simd128) - { - m = context.AddIntrinsic(Intrinsic.X86Psrldq, m, Const(8)); - } - - Intrinsic movInst = X86PmovzxInstruction[op.Size]; - - m = context.AddIntrinsic(movInst, m); - - Intrinsic addInst = X86PaddInstruction[op.Size + 1]; - - context.Copy(GetVec(op.Rd), context.AddIntrinsic(addInst, n, m)); - } - else - { - EmitVectorWidenRmBinaryOpZx(context, (op1, op2) => context.Add(op1, op2)); - } - } - - public static void Uhadd_V(ArmEmitterContext context) - { - OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp; - - if (Optimizations.UseSse2 && op.Size > 0) - { - Operand n = GetVec(op.Rn); - Operand m = GetVec(op.Rm); - - Operand res = context.AddIntrinsic(Intrinsic.X86Pand, n, m); - Operand res2 = context.AddIntrinsic(Intrinsic.X86Pxor, n, m); - - Intrinsic shiftInst = op.Size == 1 ? Intrinsic.X86Psrlw : Intrinsic.X86Psrld; - - res2 = context.AddIntrinsic(shiftInst, res2, Const(1)); - - Intrinsic addInst = X86PaddInstruction[op.Size]; - - res = context.AddIntrinsic(addInst, res, res2); - - if (op.RegisterSize == RegisterSize.Simd64) - { - res = context.VectorZeroUpper64(res); - } - - context.Copy(GetVec(op.Rd), res); - } - else - { - EmitVectorBinaryOpZx(context, (op1, op2) => - { - return context.ShiftRightUI(context.Add(op1, op2), Const(1)); - }); - } - } - - public static void Uhsub_V(ArmEmitterContext context) - { - OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp; - - if (Optimizations.UseSse2 && op.Size < 2) - { - Operand n = GetVec(op.Rn); - Operand m = GetVec(op.Rm); - - Intrinsic avgInst = op.Size == 0 ? Intrinsic.X86Pavgb : Intrinsic.X86Pavgw; - - Operand res = context.AddIntrinsic(avgInst, n, m); - - Intrinsic subInst = X86PsubInstruction[op.Size]; - - res = context.AddIntrinsic(subInst, n, res); - - if (op.RegisterSize == RegisterSize.Simd64) - { - res = context.VectorZeroUpper64(res); - } - - context.Copy(GetVec(op.Rd), res); - } - else - { - EmitVectorBinaryOpZx(context, (op1, op2) => - { - return context.ShiftRightUI(context.Subtract(op1, op2), Const(1)); - }); - } - } - - public static void Umax_V(ArmEmitterContext context) - { - if (Optimizations.UseSse41) - { - OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp; - - Operand n = GetVec(op.Rn); - Operand m = GetVec(op.Rm); - - Intrinsic maxInst = X86PmaxuInstruction[op.Size]; - - Operand res = context.AddIntrinsic(maxInst, n, m); - - if (op.RegisterSize == RegisterSize.Simd64) - { - res = context.VectorZeroUpper64(res); - } - - context.Copy(GetVec(op.Rd), res); - } - else - { - EmitVectorBinaryOpZx(context, (op1, op2) => EmitMax64Op(context, op1, op2, signed: false)); - } - } - - public static void Umaxp_V(ArmEmitterContext context) - { - if (Optimizations.UseSsse3) - { - EmitSsse3VectorPairwiseOp(context, X86PmaxuInstruction); - } - else - { - EmitVectorPairwiseOpZx(context, (op1, op2) => EmitMax64Op(context, op1, op2, signed: false)); - } - } - - public static void Umaxv_V(ArmEmitterContext context) - { - EmitVectorAcrossVectorOpZx(context, (op1, op2) => EmitMax64Op(context, op1, op2, signed: false)); - } - - public static void Umin_V(ArmEmitterContext context) - { - if (Optimizations.UseSse41) - { - OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp; - - Operand n = GetVec(op.Rn); - Operand m = GetVec(op.Rm); - - Intrinsic minInst = X86PminuInstruction[op.Size]; - - Operand res = context.AddIntrinsic(minInst, n, m); - - if (op.RegisterSize == RegisterSize.Simd64) - { - res = context.VectorZeroUpper64(res); - } - - context.Copy(GetVec(op.Rd), res); - } - else - { - EmitVectorBinaryOpZx(context, (op1, op2) => EmitMin64Op(context, op1, op2, signed: false)); - } - } - - public static void Uminp_V(ArmEmitterContext context) - { - if (Optimizations.UseSsse3) - { - EmitSsse3VectorPairwiseOp(context, X86PminuInstruction); - } - else - { - EmitVectorPairwiseOpZx(context, (op1, op2) => EmitMin64Op(context, op1, op2, signed: false)); - } - } - - public static void Uminv_V(ArmEmitterContext context) - { - EmitVectorAcrossVectorOpZx(context, (op1, op2) => EmitMin64Op(context, op1, op2, signed: false)); - } - - public static void Umlal_V(ArmEmitterContext context) - { - OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp; - - if (Optimizations.UseSse41 && op.Size < 2) - { - Operand d = GetVec(op.Rd); - Operand n = GetVec(op.Rn); - Operand m = GetVec(op.Rm); - - if (op.RegisterSize == RegisterSize.Simd128) - { - n = context.AddIntrinsic(Intrinsic.X86Psrldq, n, Const(8)); - m = context.AddIntrinsic(Intrinsic.X86Psrldq, m, Const(8)); - } - - Intrinsic movInst = X86PmovzxInstruction[op.Size]; - - n = context.AddIntrinsic(movInst, n); - m = context.AddIntrinsic(movInst, m); - - Intrinsic mullInst = op.Size == 0 ? Intrinsic.X86Pmullw : Intrinsic.X86Pmulld; - - Operand res = context.AddIntrinsic(mullInst, n, m); - - Intrinsic addInst = X86PaddInstruction[op.Size + 1]; - - context.Copy(d, context.AddIntrinsic(addInst, d, res)); - } - else - { - EmitVectorWidenRnRmTernaryOpZx(context, (op1, op2, op3) => - { - return context.Add(op1, context.Multiply(op2, op3)); - }); - } - } - - public static void Umlal_Ve(ArmEmitterContext context) - { - EmitVectorWidenTernaryOpByElemZx(context, (op1, op2, op3) => - { - return context.Add(op1, context.Multiply(op2, op3)); - }); - } - - public static void Umlsl_V(ArmEmitterContext context) - { - OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp; - - if (Optimizations.UseSse41 && op.Size < 2) - { - Operand d = GetVec(op.Rd); - Operand n = GetVec(op.Rn); - Operand m = GetVec(op.Rm); - - if (op.RegisterSize == RegisterSize.Simd128) - { - n = context.AddIntrinsic(Intrinsic.X86Psrldq, n, Const(8)); - m = context.AddIntrinsic(Intrinsic.X86Psrldq, m, Const(8)); - } - - Intrinsic movInst = op.Size == 0 ? Intrinsic.X86Pmovzxbw : Intrinsic.X86Pmovzxwd; - - n = context.AddIntrinsic(movInst, n); - m = context.AddIntrinsic(movInst, m); - - Intrinsic mullInst = op.Size == 0 ? Intrinsic.X86Pmullw : Intrinsic.X86Pmulld; - - Operand res = context.AddIntrinsic(mullInst, n, m); - - Intrinsic subInst = X86PsubInstruction[op.Size + 1]; - - context.Copy(d, context.AddIntrinsic(subInst, d, res)); - } - else - { - EmitVectorWidenRnRmTernaryOpZx(context, (op1, op2, op3) => - { - return context.Subtract(op1, context.Multiply(op2, op3)); - }); - } - } - - public static void Umlsl_Ve(ArmEmitterContext context) - { - EmitVectorWidenTernaryOpByElemZx(context, (op1, op2, op3) => - { - return context.Subtract(op1, context.Multiply(op2, op3)); - }); - } - - public static void Umull_V(ArmEmitterContext context) - { - EmitVectorWidenRnRmBinaryOpZx(context, (op1, op2) => context.Multiply(op1, op2)); - } - - public static void Umull_Ve(ArmEmitterContext context) - { - EmitVectorWidenBinaryOpByElemZx(context, (op1, op2) => context.Multiply(op1, op2)); - } - - public static void Uqadd_S(ArmEmitterContext context) - { - EmitScalarSaturatingBinaryOpZx(context, SaturatingFlags.Add); - } - - public static void Uqadd_V(ArmEmitterContext context) - { - EmitVectorSaturatingBinaryOpZx(context, SaturatingFlags.Add); - } - - public static void Uqsub_S(ArmEmitterContext context) - { - EmitScalarSaturatingBinaryOpZx(context, SaturatingFlags.Sub); - } - - public static void Uqsub_V(ArmEmitterContext context) - { - EmitVectorSaturatingBinaryOpZx(context, SaturatingFlags.Sub); - } - - public static void Uqxtn_S(ArmEmitterContext context) - { - EmitSaturatingNarrowOp(context, SaturatingNarrowFlags.ScalarZxZx); - } - - public static void Uqxtn_V(ArmEmitterContext context) - { - EmitSaturatingNarrowOp(context, SaturatingNarrowFlags.VectorZxZx); - } - - public static void Urhadd_V(ArmEmitterContext context) - { - OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp; - - if (Optimizations.UseSse2 && op.Size < 2) - { - Operand n = GetVec(op.Rn); - Operand m = GetVec(op.Rm); - - Intrinsic avgInst = op.Size == 0 ? Intrinsic.X86Pavgb : Intrinsic.X86Pavgw; - - Operand res = context.AddIntrinsic(avgInst, n, m); - - if (op.RegisterSize == RegisterSize.Simd64) - { - res = context.VectorZeroUpper64(res); - } - - context.Copy(GetVec(op.Rd), res); - } - else - { - EmitVectorBinaryOpZx(context, (op1, op2) => - { - Operand res = context.Add(op1, op2); - - res = context.Add(res, Const(1L)); - - return context.ShiftRightUI(res, Const(1)); - }); - } - } - - public static void Usqadd_S(ArmEmitterContext context) - { - EmitScalarSaturatingBinaryOpZx(context, SaturatingFlags.Accumulate); - } - - public static void Usqadd_V(ArmEmitterContext context) - { - EmitVectorSaturatingBinaryOpZx(context, SaturatingFlags.Accumulate); - } - - public static void Usubl_V(ArmEmitterContext context) - { - if (Optimizations.UseSse41) - { - OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp; - - Operand n = GetVec(op.Rn); - Operand m = GetVec(op.Rm); - - if (op.RegisterSize == RegisterSize.Simd128) - { - n = context.AddIntrinsic(Intrinsic.X86Psrldq, n, Const(8)); - m = context.AddIntrinsic(Intrinsic.X86Psrldq, m, Const(8)); - } - - Intrinsic movInst = X86PmovzxInstruction[op.Size]; - - n = context.AddIntrinsic(movInst, n); - m = context.AddIntrinsic(movInst, m); - - Intrinsic subInst = X86PsubInstruction[op.Size + 1]; - - context.Copy(GetVec(op.Rd), context.AddIntrinsic(subInst, n, m)); - } - else - { - EmitVectorWidenRnRmBinaryOpZx(context, (op1, op2) => context.Subtract(op1, op2)); - } - } - - public static void Usubw_V(ArmEmitterContext context) - { - if (Optimizations.UseSse41) - { - OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp; - - Operand n = GetVec(op.Rn); - Operand m = GetVec(op.Rm); - - if (op.RegisterSize == RegisterSize.Simd128) - { - m = context.AddIntrinsic(Intrinsic.X86Psrldq, m, Const(8)); - } - - Intrinsic movInst = X86PmovzxInstruction[op.Size]; - - m = context.AddIntrinsic(movInst, m); - - Intrinsic subInst = X86PsubInstruction[op.Size + 1]; - - context.Copy(GetVec(op.Rd), context.AddIntrinsic(subInst, n, m)); - } - else - { - EmitVectorWidenRmBinaryOpZx(context, (op1, op2) => context.Subtract(op1, op2)); - } - } - - private static Operand EmitAbs(ArmEmitterContext context, Operand value) - { - Operand isPositive = context.ICompareGreaterOrEqual(value, Const(value.Type, 0)); - - return context.ConditionalSelect(isPositive, value, context.Negate(value)); - } - - private static void EmitAddLongPairwise(ArmEmitterContext context, bool signed, bool accumulate) - { - OpCodeSimd op = (OpCodeSimd)context.CurrOp; - - Operand res = context.VectorZero(); - - int pairs = op.GetPairsCount() >> op.Size; - - for (int index = 0; index < pairs; index++) - { - int pairIndex = index << 1; - - Operand ne0 = EmitVectorExtract(context, op.Rn, pairIndex, op.Size, signed); - Operand ne1 = EmitVectorExtract(context, op.Rn, pairIndex + 1, op.Size, signed); - - Operand e = context.Add(ne0, ne1); - - if (accumulate) - { - Operand de = EmitVectorExtract(context, op.Rd, index, op.Size + 1, signed); - - e = context.Add(e, de); - } - - res = EmitVectorInsert(context, res, e, index, op.Size + 1); - } - - context.Copy(GetVec(op.Rd), res); - } - - private static Operand EmitDoublingMultiplyHighHalf( - ArmEmitterContext context, - Operand n, - Operand m, - bool round) - { - OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp; - - int eSize = 8 << op.Size; - - Operand res = context.Multiply(n, m); - - if (!round) - { - res = context.ShiftRightSI(res, Const(eSize - 1)); - } - else - { - long roundConst = 1L << (eSize - 1); - - res = context.ShiftLeft(res, Const(1)); - - res = context.Add(res, Const(roundConst)); - - res = context.ShiftRightSI(res, Const(eSize)); - - Operand isIntMin = context.ICompareEqual(res, Const((long)int.MinValue)); - - res = context.ConditionalSelect(isIntMin, context.Negate(res), res); - } - - return res; - } - - private static void EmitHighNarrow(ArmEmitterContext context, Func2I emit, bool round) - { - OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp; - - int elems = 8 >> op.Size; - int eSize = 8 << op.Size; - - int part = op.RegisterSize == RegisterSize.Simd128 ? elems : 0; - - Operand d = GetVec(op.Rd); - - Operand res = part == 0 ? context.VectorZero() : context.Copy(d); - - long roundConst = 1L << (eSize - 1); - - for (int index = 0; index < elems; index++) - { - Operand ne = EmitVectorExtractZx(context, op.Rn, index, op.Size + 1); - Operand me = EmitVectorExtractZx(context, op.Rm, index, op.Size + 1); - - Operand de = emit(ne, me); - - if (round) - { - de = context.Add(de, Const(roundConst)); - } - - de = context.ShiftRightUI(de, Const(eSize)); - - res = EmitVectorInsert(context, res, de, part + index, op.Size); - } - - context.Copy(d, res); - } - - private static Operand EmitMax64Op(ArmEmitterContext context, Operand op1, Operand op2, bool signed) - { - Debug.Assert(op1.Type == OperandType.I64 && op2.Type == OperandType.I64); - - Operand cmp = signed - ? context.ICompareGreaterOrEqual (op1, op2) - : context.ICompareGreaterOrEqualUI(op1, op2); - - return context.ConditionalSelect(cmp, op1, op2); - } - - private static Operand EmitMin64Op(ArmEmitterContext context, Operand op1, Operand op2, bool signed) - { - Debug.Assert(op1.Type == OperandType.I64 && op2.Type == OperandType.I64); - - Operand cmp = signed - ? context.ICompareLessOrEqual (op1, op2) - : context.ICompareLessOrEqualUI(op1, op2); - - return context.ConditionalSelect(cmp, op1, op2); - } - - private static void EmitSse41ScalarRoundOpF(ArmEmitterContext context, FPRoundingMode roundMode) - { - OpCodeSimd op = (OpCodeSimd)context.CurrOp; - - Operand n = GetVec(op.Rn); - - Intrinsic inst = (op.Size & 1) != 0 ? Intrinsic.X86Roundsd : Intrinsic.X86Roundss; - - Operand res = context.AddIntrinsic(inst, n, Const(X86GetRoundControl(roundMode))); - - if ((op.Size & 1) != 0) - { - res = context.VectorZeroUpper64(res); - } - else - { - res = context.VectorZeroUpper96(res); - } - - context.Copy(GetVec(op.Rd), res); - } - - private static void EmitSse41VectorRoundOpF(ArmEmitterContext context, FPRoundingMode roundMode) - { - OpCodeSimd op = (OpCodeSimd)context.CurrOp; - - Operand n = GetVec(op.Rn); - - Intrinsic inst = (op.Size & 1) != 0 ? Intrinsic.X86Roundpd : Intrinsic.X86Roundps; - - Operand res = context.AddIntrinsic(inst, n, Const(X86GetRoundControl(roundMode))); - - if (op.RegisterSize == RegisterSize.Simd64) - { - res = context.VectorZeroUpper64(res); - } - - context.Copy(GetVec(op.Rd), res); - } - - private static Operand EmitSse41Round32Exp8OpF(ArmEmitterContext context, Operand value, bool scalar) - { - Operand roundMask; - Operand truncMask; - Operand expMask; - - if (scalar) - { - roundMask = X86GetScalar(context, 0x4000); - truncMask = X86GetScalar(context, unchecked((int)0xFFFF8000)); - expMask = X86GetScalar(context, 0x7F800000); - } - else - { - roundMask = X86GetAllElements(context, 0x4000); - truncMask = X86GetAllElements(context, unchecked((int)0xFFFF8000)); - expMask = X86GetAllElements(context, 0x7F800000); - } - - Operand oValue = value; - Operand masked = context.AddIntrinsic(Intrinsic.X86Pand, value, expMask); - Operand isNaNInf = context.AddIntrinsic(Intrinsic.X86Pcmpeqd, masked, expMask); - - value = context.AddIntrinsic(Intrinsic.X86Paddd, value, roundMask); - value = context.AddIntrinsic(Intrinsic.X86Pand, value, truncMask); - - return context.AddIntrinsic(Intrinsic.X86Blendvps, value, oValue, isNaNInf); - } - - private static Operand EmitSse41RecipStepSelectOpF( - ArmEmitterContext context, - Operand n, - Operand m, - Operand res, - Operand mask, - bool scalar, - int sizeF) - { - Intrinsic cmpOp; - Intrinsic shlOp; - Intrinsic blendOp; - Operand zero = context.VectorZero(); - Operand expMask; - - if (sizeF == 0) - { - cmpOp = Intrinsic.X86Pcmpeqd; - shlOp = Intrinsic.X86Pslld; - blendOp = Intrinsic.X86Blendvps; - expMask = scalar ? X86GetScalar(context, 0x7F800000 << 1) : X86GetAllElements(context, 0x7F800000 << 1); - } - else /* if (sizeF == 1) */ - { - cmpOp = Intrinsic.X86Pcmpeqq; - shlOp = Intrinsic.X86Psllq; - blendOp = Intrinsic.X86Blendvpd; - expMask = scalar ? X86GetScalar(context, 0x7FF0000000000000L << 1) : X86GetAllElements(context, 0x7FF0000000000000L << 1); - } - - n = context.AddIntrinsic(shlOp, n, Const(1)); - m = context.AddIntrinsic(shlOp, m, Const(1)); - - Operand nZero = context.AddIntrinsic(cmpOp, n, zero); - Operand mZero = context.AddIntrinsic(cmpOp, m, zero); - Operand nInf = context.AddIntrinsic(cmpOp, n, expMask); - Operand mInf = context.AddIntrinsic(cmpOp, m, expMask); - - Operand nmZero = context.AddIntrinsic(Intrinsic.X86Por, nZero, mZero); - Operand nmInf = context.AddIntrinsic(Intrinsic.X86Por, nInf, mInf); - Operand nmZeroInf = context.AddIntrinsic(Intrinsic.X86Pand, nmZero, nmInf); - - return context.AddIntrinsic(blendOp, res, mask, nmZeroInf); - } - - public static void EmitSse2VectorIsNaNOpF( - ArmEmitterContext context, - Operand opF, - out Operand qNaNMask, - out Operand sNaNMask, - bool? isQNaN = null) - { - IOpCodeSimd op = (IOpCodeSimd)context.CurrOp; - - if ((op.Size & 1) == 0) - { - const int QBit = 22; - - Operand qMask = X86GetAllElements(context, 1 << QBit); - - Operand mask1 = context.AddIntrinsic(Intrinsic.X86Cmpps, opF, opF, Const((int)CmpCondition.UnorderedQ)); - - Operand mask2 = context.AddIntrinsic(Intrinsic.X86Pand, opF, qMask); - mask2 = context.AddIntrinsic(Intrinsic.X86Cmpps, mask2, qMask, Const((int)CmpCondition.Equal)); - - qNaNMask = isQNaN == null || (bool)isQNaN ? context.AddIntrinsic(Intrinsic.X86Andps, mask2, mask1) : default; - sNaNMask = isQNaN == null || !(bool)isQNaN ? context.AddIntrinsic(Intrinsic.X86Andnps, mask2, mask1) : default; - } - else /* if ((op.Size & 1) == 1) */ - { - const int QBit = 51; - - Operand qMask = X86GetAllElements(context, 1L << QBit); - - Operand mask1 = context.AddIntrinsic(Intrinsic.X86Cmppd, opF, opF, Const((int)CmpCondition.UnorderedQ)); - - Operand mask2 = context.AddIntrinsic(Intrinsic.X86Pand, opF, qMask); - mask2 = context.AddIntrinsic(Intrinsic.X86Cmppd, mask2, qMask, Const((int)CmpCondition.Equal)); - - qNaNMask = isQNaN == null || (bool)isQNaN ? context.AddIntrinsic(Intrinsic.X86Andpd, mask2, mask1) : default; - sNaNMask = isQNaN == null || !(bool)isQNaN ? context.AddIntrinsic(Intrinsic.X86Andnpd, mask2, mask1) : default; - } - } - - public static Operand EmitSse41ProcessNaNsOpF( - ArmEmitterContext context, - Func2I emit, - bool scalar, - Operand n = default, - Operand m = default) - { - Operand nCopy = n == default ? context.Copy(GetVec(((OpCodeSimdReg)context.CurrOp).Rn)) : n; - Operand mCopy = m == default ? context.Copy(GetVec(((OpCodeSimdReg)context.CurrOp).Rm)) : m; - - EmitSse2VectorIsNaNOpF(context, nCopy, out Operand nQNaNMask, out Operand nSNaNMask); - EmitSse2VectorIsNaNOpF(context, mCopy, out _, out Operand mSNaNMask, isQNaN: false); - - int sizeF = ((IOpCodeSimd)context.CurrOp).Size & 1; - - if (sizeF == 0) - { - const int QBit = 22; - - Operand qMask = scalar ? X86GetScalar(context, 1 << QBit) : X86GetAllElements(context, 1 << QBit); - - Operand resNaNMask = context.AddIntrinsic(Intrinsic.X86Pandn, mSNaNMask, nQNaNMask); - resNaNMask = context.AddIntrinsic(Intrinsic.X86Por, resNaNMask, nSNaNMask); - - Operand resNaN = context.AddIntrinsic(Intrinsic.X86Blendvps, mCopy, nCopy, resNaNMask); - resNaN = context.AddIntrinsic(Intrinsic.X86Por, resNaN, qMask); - - Operand resMask = context.AddIntrinsic(Intrinsic.X86Cmpps, nCopy, mCopy, Const((int)CmpCondition.OrderedQ)); - - Operand res = context.AddIntrinsic(Intrinsic.X86Blendvps, resNaN, emit(nCopy, mCopy), resMask); - - if (n != default || m != default) - { - return res; - } - - if (scalar) - { - res = context.VectorZeroUpper96(res); - } - else if (((OpCodeSimdReg)context.CurrOp).RegisterSize == RegisterSize.Simd64) - { - res = context.VectorZeroUpper64(res); - } - - context.Copy(GetVec(((OpCodeSimdReg)context.CurrOp).Rd), res); - - return default; - } - else /* if (sizeF == 1) */ - { - const int QBit = 51; - - Operand qMask = scalar ? X86GetScalar(context, 1L << QBit) : X86GetAllElements(context, 1L << QBit); - - Operand resNaNMask = context.AddIntrinsic(Intrinsic.X86Pandn, mSNaNMask, nQNaNMask); - resNaNMask = context.AddIntrinsic(Intrinsic.X86Por, resNaNMask, nSNaNMask); - - Operand resNaN = context.AddIntrinsic(Intrinsic.X86Blendvpd, mCopy, nCopy, resNaNMask); - resNaN = context.AddIntrinsic(Intrinsic.X86Por, resNaN, qMask); - - Operand resMask = context.AddIntrinsic(Intrinsic.X86Cmppd, nCopy, mCopy, Const((int)CmpCondition.OrderedQ)); - - Operand res = context.AddIntrinsic(Intrinsic.X86Blendvpd, resNaN, emit(nCopy, mCopy), resMask); - - if (n != default || m != default) - { - return res; - } - - if (scalar) - { - res = context.VectorZeroUpper64(res); - } - - context.Copy(GetVec(((OpCodeSimdReg)context.CurrOp).Rd), res); - - return default; - } - } - - public static Operand EmitSseOrAvxHandleFzModeOpF( - ArmEmitterContext context, - Func2I emit, - bool scalar, - Operand n = default, - Operand m = default) - { - Operand nCopy = n == default ? context.Copy(GetVec(((OpCodeSimdReg)context.CurrOp).Rn)) : n; - Operand mCopy = m == default ? context.Copy(GetVec(((OpCodeSimdReg)context.CurrOp).Rm)) : m; - - EmitSseOrAvxEnterFtzAndDazModesOpF(context, out Operand isTrue); - - Operand res = emit(nCopy, mCopy); - - EmitSseOrAvxExitFtzAndDazModesOpF(context, isTrue); - - if (n != default || m != default) - { - return res; - } - - int sizeF = ((IOpCodeSimd)context.CurrOp).Size & 1; - - if (sizeF == 0) - { - if (scalar) - { - res = context.VectorZeroUpper96(res); - } - else if (((OpCodeSimdReg)context.CurrOp).RegisterSize == RegisterSize.Simd64) - { - res = context.VectorZeroUpper64(res); - } - } - else /* if (sizeF == 1) */ - { - if (scalar) - { - res = context.VectorZeroUpper64(res); - } - } - - context.Copy(GetVec(((OpCodeSimdReg)context.CurrOp).Rd), res); - - return default; - } - - private static Operand EmitSse2VectorMaxMinOpF(ArmEmitterContext context, Operand n, Operand m, bool isMax) - { - IOpCodeSimd op = (IOpCodeSimd)context.CurrOp; - - if ((op.Size & 1) == 0) - { - Operand mask = X86GetAllElements(context, -0f); - - Operand res = context.AddIntrinsic(isMax ? Intrinsic.X86Maxps : Intrinsic.X86Minps, n, m); - res = context.AddIntrinsic(Intrinsic.X86Andnps, mask, res); - - Operand resSign = context.AddIntrinsic(isMax ? Intrinsic.X86Pand : Intrinsic.X86Por, n, m); - resSign = context.AddIntrinsic(Intrinsic.X86Andps, mask, resSign); - - return context.AddIntrinsic(Intrinsic.X86Por, res, resSign); - } - else /* if ((op.Size & 1) == 1) */ - { - Operand mask = X86GetAllElements(context, -0d); - - Operand res = context.AddIntrinsic(isMax ? Intrinsic.X86Maxpd : Intrinsic.X86Minpd, n, m); - res = context.AddIntrinsic(Intrinsic.X86Andnpd, mask, res); - - Operand resSign = context.AddIntrinsic(isMax ? Intrinsic.X86Pand : Intrinsic.X86Por, n, m); - resSign = context.AddIntrinsic(Intrinsic.X86Andpd, mask, resSign); - - return context.AddIntrinsic(Intrinsic.X86Por, res, resSign); - } - } - - private static Operand EmitSse41MaxMinNumOpF( - ArmEmitterContext context, - bool isMaxNum, - bool scalar, - Operand n = default, - Operand m = default) - { - Operand nCopy = n == default ? context.Copy(GetVec(((OpCodeSimdReg)context.CurrOp).Rn)) : n; - Operand mCopy = m == default ? context.Copy(GetVec(((OpCodeSimdReg)context.CurrOp).Rm)) : m; - - EmitSse2VectorIsNaNOpF(context, nCopy, out Operand nQNaNMask, out _, isQNaN: true); - EmitSse2VectorIsNaNOpF(context, mCopy, out Operand mQNaNMask, out _, isQNaN: true); - - int sizeF = ((IOpCodeSimd)context.CurrOp).Size & 1; - - if (sizeF == 0) - { - Operand negInfMask = scalar - ? X86GetScalar (context, isMaxNum ? float.NegativeInfinity : float.PositiveInfinity) - : X86GetAllElements(context, isMaxNum ? float.NegativeInfinity : float.PositiveInfinity); - - Operand nMask = context.AddIntrinsic(Intrinsic.X86Andnps, mQNaNMask, nQNaNMask); - Operand mMask = context.AddIntrinsic(Intrinsic.X86Andnps, nQNaNMask, mQNaNMask); - - nCopy = context.AddIntrinsic(Intrinsic.X86Blendvps, nCopy, negInfMask, nMask); - mCopy = context.AddIntrinsic(Intrinsic.X86Blendvps, mCopy, negInfMask, mMask); - - Operand res = EmitSse41ProcessNaNsOpF(context, (op1, op2) => - { - return EmitSseOrAvxHandleFzModeOpF(context, (op1, op2) => - { - return EmitSse2VectorMaxMinOpF(context, op1, op2, isMax: isMaxNum); - }, scalar: scalar, op1, op2); - }, scalar: scalar, nCopy, mCopy); - - if (n != default || m != default) - { - return res; - } - - if (scalar) - { - res = context.VectorZeroUpper96(res); - } - else if (((OpCodeSimdReg)context.CurrOp).RegisterSize == RegisterSize.Simd64) - { - res = context.VectorZeroUpper64(res); - } - - context.Copy(GetVec(((OpCodeSimdReg)context.CurrOp).Rd), res); - - return default; - } - else /* if (sizeF == 1) */ - { - Operand negInfMask = scalar - ? X86GetScalar (context, isMaxNum ? double.NegativeInfinity : double.PositiveInfinity) - : X86GetAllElements(context, isMaxNum ? double.NegativeInfinity : double.PositiveInfinity); - - Operand nMask = context.AddIntrinsic(Intrinsic.X86Andnpd, mQNaNMask, nQNaNMask); - Operand mMask = context.AddIntrinsic(Intrinsic.X86Andnpd, nQNaNMask, mQNaNMask); - - nCopy = context.AddIntrinsic(Intrinsic.X86Blendvpd, nCopy, negInfMask, nMask); - mCopy = context.AddIntrinsic(Intrinsic.X86Blendvpd, mCopy, negInfMask, mMask); - - Operand res = EmitSse41ProcessNaNsOpF(context, (op1, op2) => - { - return EmitSseOrAvxHandleFzModeOpF(context, (op1, op2) => - { - return EmitSse2VectorMaxMinOpF(context, op1, op2, isMax: isMaxNum); - }, scalar: scalar, op1, op2); - }, scalar: scalar, nCopy, mCopy); - - if (n != default || m != default) - { - return res; - } - - if (scalar) - { - res = context.VectorZeroUpper64(res); - } - - context.Copy(GetVec(((OpCodeSimdReg)context.CurrOp).Rd), res); - - return default; - } - } - - private enum AddSub - { - None, - Add, - Subtract - } - - private static void EmitSse41VectorMul_AddSub(ArmEmitterContext context, AddSub addSub) - { - OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp; - - Operand n = GetVec(op.Rn); - Operand m = GetVec(op.Rm); - - Operand res; - - if (op.Size == 0) - { - Operand ns8 = context.AddIntrinsic(Intrinsic.X86Psrlw, n, Const(8)); - Operand ms8 = context.AddIntrinsic(Intrinsic.X86Psrlw, m, Const(8)); - - res = context.AddIntrinsic(Intrinsic.X86Pmullw, ns8, ms8); - - res = context.AddIntrinsic(Intrinsic.X86Psllw, res, Const(8)); - - Operand res2 = context.AddIntrinsic(Intrinsic.X86Pmullw, n, m); - - Operand mask = X86GetAllElements(context, 0x00FF00FF); - - res = context.AddIntrinsic(Intrinsic.X86Pblendvb, res, res2, mask); - } - else if (op.Size == 1) - { - res = context.AddIntrinsic(Intrinsic.X86Pmullw, n, m); - } - else - { - res = context.AddIntrinsic(Intrinsic.X86Pmulld, n, m); - } - - Operand d = GetVec(op.Rd); - - if (addSub == AddSub.Add) - { - Intrinsic addInst = X86PaddInstruction[op.Size]; - - res = context.AddIntrinsic(addInst, d, res); - } - else if (addSub == AddSub.Subtract) - { - Intrinsic subInst = X86PsubInstruction[op.Size]; - - res = context.AddIntrinsic(subInst, d, res); - } - - if (op.RegisterSize == RegisterSize.Simd64) - { - res = context.VectorZeroUpper64(res); - } - - context.Copy(d, res); - } - - private static void EmitSse41VectorSabdOp( - ArmEmitterContext context, - OpCodeSimdReg op, - Operand n, - Operand m, - bool isLong) - { - int size = isLong ? op.Size + 1 : op.Size; - - Intrinsic cmpgtInst = X86PcmpgtInstruction[size]; - - Operand cmpMask = context.AddIntrinsic(cmpgtInst, n, m); - - Intrinsic subInst = X86PsubInstruction[size]; - - Operand res = context.AddIntrinsic(subInst, n, m); - - res = context.AddIntrinsic(Intrinsic.X86Pand, cmpMask, res); - - Operand res2 = context.AddIntrinsic(subInst, m, n); - - res2 = context.AddIntrinsic(Intrinsic.X86Pandn, cmpMask, res2); - - res = context.AddIntrinsic(Intrinsic.X86Por, res, res2); - - if (!isLong && op.RegisterSize == RegisterSize.Simd64) - { - res = context.VectorZeroUpper64(res); - } - - context.Copy(GetVec(op.Rd), res); - } - - private static void EmitSse41VectorUabdOp( - ArmEmitterContext context, - OpCodeSimdReg op, - Operand n, - Operand m, - bool isLong) - { - int size = isLong ? op.Size + 1 : op.Size; - - Intrinsic maxInst = X86PmaxuInstruction[size]; - - Operand max = context.AddIntrinsic(maxInst, m, n); - - Intrinsic cmpeqInst = X86PcmpeqInstruction[size]; - - Operand cmpMask = context.AddIntrinsic(cmpeqInst, max, m); - - Operand onesMask = X86GetAllElements(context, -1L); - - cmpMask = context.AddIntrinsic(Intrinsic.X86Pandn, cmpMask, onesMask); - - Intrinsic subInst = X86PsubInstruction[size]; - - Operand res = context.AddIntrinsic(subInst, n, m); - Operand res2 = context.AddIntrinsic(subInst, m, n); - - res = context.AddIntrinsic(Intrinsic.X86Pand, cmpMask, res); - res2 = context.AddIntrinsic(Intrinsic.X86Pandn, cmpMask, res2); - - res = context.AddIntrinsic(Intrinsic.X86Por, res, res2); - - if (!isLong && op.RegisterSize == RegisterSize.Simd64) - { - res = context.VectorZeroUpper64(res); - } - - context.Copy(GetVec(op.Rd), res); - } - - private static Operand EmitSse2Sll_128(ArmEmitterContext context, Operand op, int shift) - { - // The upper part of op is assumed to be zero. - Debug.Assert(shift >= 0 && shift < 64); - - if (shift == 0) - { - return op; - } - - Operand high = context.AddIntrinsic(Intrinsic.X86Pslldq, op, Const(8)); - high = context.AddIntrinsic(Intrinsic.X86Psrlq, high, Const(64 - shift)); - - Operand low = context.AddIntrinsic(Intrinsic.X86Psllq, op, Const(shift)); - - return context.AddIntrinsic(Intrinsic.X86Por, high, low); - } - } -} diff --git a/ARMeilleure/Instructions/InstEmitSimdCvt.cs b/ARMeilleure/Instructions/InstEmitSimdCvt.cs deleted file mode 100644 index c8c427b79..000000000 --- a/ARMeilleure/Instructions/InstEmitSimdCvt.cs +++ /dev/null @@ -1,1619 +0,0 @@ -using ARMeilleure.Decoders; -using ARMeilleure.IntermediateRepresentation; -using ARMeilleure.State; -using ARMeilleure.Translation; -using System; -using System.Diagnostics; -using System.Reflection; - -using static ARMeilleure.Instructions.InstEmitHelper; -using static ARMeilleure.Instructions.InstEmitSimdHelper; -using static ARMeilleure.IntermediateRepresentation.Operand.Factory; - -namespace ARMeilleure.Instructions -{ - using Func1I = Func; - - static partial class InstEmit - { - public static void Fcvt_S(ArmEmitterContext context) - { - OpCodeSimd op = (OpCodeSimd)context.CurrOp; - - if (op.Size == 0 && op.Opc == 1) // Single -> Double. - { - if (Optimizations.UseSse2) - { - Operand n = GetVec(op.Rn); - - Operand res = context.AddIntrinsic(Intrinsic.X86Cvtss2sd, context.VectorZero(), n); - - context.Copy(GetVec(op.Rd), res); - } - else - { - Operand ne = context.VectorExtract(OperandType.FP32, GetVec(op.Rn), 0); - - Operand res = context.ConvertToFP(OperandType.FP64, ne); - - context.Copy(GetVec(op.Rd), context.VectorInsert(context.VectorZero(), res, 0)); - } - } - else if (op.Size == 1 && op.Opc == 0) // Double -> Single. - { - if (Optimizations.UseSse2) - { - Operand n = GetVec(op.Rn); - - Operand res = context.AddIntrinsic(Intrinsic.X86Cvtsd2ss, context.VectorZero(), n); - - context.Copy(GetVec(op.Rd), res); - } - else - { - Operand ne = context.VectorExtract(OperandType.FP64, GetVec(op.Rn), 0); - - Operand res = context.ConvertToFP(OperandType.FP32, ne); - - context.Copy(GetVec(op.Rd), context.VectorInsert(context.VectorZero(), res, 0)); - } - } - else if (op.Size == 0 && op.Opc == 3) // Single -> Half. - { - if (Optimizations.UseF16c) - { - Debug.Assert(!Optimizations.ForceLegacySse); - - Operand n = GetVec(op.Rn); - - Operand res = context.AddIntrinsic(Intrinsic.X86Vcvtps2ph, n, Const(X86GetRoundControl(FPRoundingMode.ToNearest))); - res = context.AddIntrinsic(Intrinsic.X86Pslldq, res, Const(14)); // VectorZeroUpper112() - res = context.AddIntrinsic(Intrinsic.X86Psrldq, res, Const(14)); - - context.Copy(GetVec(op.Rd), res); - } - else - { - Operand ne = context.VectorExtract(OperandType.FP32, GetVec(op.Rn), 0); - - context.StoreToContext(); - Operand res = context.Call(typeof(SoftFloat32_16).GetMethod(nameof(SoftFloat32_16.FPConvert)), ne); - context.LoadFromContext(); - - res = context.ZeroExtend16(OperandType.I64, res); - - context.Copy(GetVec(op.Rd), EmitVectorInsert(context, context.VectorZero(), res, 0, 1)); - } - } - else if (op.Size == 3 && op.Opc == 0) // Half -> Single. - { - if (Optimizations.UseF16c) - { - Debug.Assert(!Optimizations.ForceLegacySse); - - Operand res = context.AddIntrinsic(Intrinsic.X86Vcvtph2ps, GetVec(op.Rn)); - res = context.VectorZeroUpper96(res); - - context.Copy(GetVec(op.Rd), res); - } - else - { - Operand ne = EmitVectorExtractZx(context, op.Rn, 0, 1); - - context.StoreToContext(); - Operand res = context.Call(typeof(SoftFloat16_32).GetMethod(nameof(SoftFloat16_32.FPConvert)), ne); - context.LoadFromContext(); - - context.Copy(GetVec(op.Rd), context.VectorInsert(context.VectorZero(), res, 0)); - } - } - else if (op.Size == 1 && op.Opc == 3) // Double -> Half. - { - if (Optimizations.UseF16c) - { - Debug.Assert(!Optimizations.ForceLegacySse); - - Operand n = GetVec(op.Rn); - - Operand res = context.AddIntrinsic(Intrinsic.X86Cvtsd2ss, context.VectorZero(), n); - res = context.AddIntrinsic(Intrinsic.X86Vcvtps2ph, res, Const(X86GetRoundControl(FPRoundingMode.ToNearest))); - - context.Copy(GetVec(op.Rd), res); - } - else - { - Operand ne = context.VectorExtract(OperandType.FP64, GetVec(op.Rn), 0); - - context.StoreToContext(); - Operand res = context.Call(typeof(SoftFloat64_16).GetMethod(nameof(SoftFloat64_16.FPConvert)), ne); - context.LoadFromContext(); - - res = context.ZeroExtend16(OperandType.I64, res); - - context.Copy(GetVec(op.Rd), EmitVectorInsert(context, context.VectorZero(), res, 0, 1)); - } - } - else if (op.Size == 3 && op.Opc == 1) // Half -> Double. - { - if (Optimizations.UseF16c) - { - Operand n = GetVec(op.Rn); - - Operand res = context.AddIntrinsic(Intrinsic.X86Vcvtph2ps, GetVec(op.Rn)); - res = context.AddIntrinsic(Intrinsic.X86Cvtss2sd, context.VectorZero(), res); - res = context.VectorZeroUpper64(res); - - context.Copy(GetVec(op.Rd), res); - } - else - { - Operand ne = EmitVectorExtractZx(context, op.Rn, 0, 1); - - context.StoreToContext(); - Operand res = context.Call(typeof(SoftFloat16_64).GetMethod(nameof(SoftFloat16_64.FPConvert)), ne); - context.LoadFromContext(); - - context.Copy(GetVec(op.Rd), context.VectorInsert(context.VectorZero(), res, 0)); - } - } - else // Invalid encoding. - { - Debug.Assert(false, $"type == {op.Size} && opc == {op.Opc}"); - } - } - - public static void Fcvtas_Gp(ArmEmitterContext context) - { - EmitFcvt_s_Gp(context, (op1) => EmitRoundMathCall(context, MidpointRounding.AwayFromZero, op1)); - } - - public static void Fcvtas_S(ArmEmitterContext context) - { - EmitFcvt(context, (op1) => EmitRoundMathCall(context, MidpointRounding.AwayFromZero, op1), signed: true, scalar: true); - } - - public static void Fcvtas_V(ArmEmitterContext context) - { - EmitFcvt(context, (op1) => EmitRoundMathCall(context, MidpointRounding.AwayFromZero, op1), signed: true, scalar: false); - } - - public static void Fcvtau_Gp(ArmEmitterContext context) - { - EmitFcvt_u_Gp(context, (op1) => EmitRoundMathCall(context, MidpointRounding.AwayFromZero, op1)); - } - - public static void Fcvtau_S(ArmEmitterContext context) - { - EmitFcvt(context, (op1) => EmitRoundMathCall(context, MidpointRounding.AwayFromZero, op1), signed: false, scalar: true); - } - - public static void Fcvtau_V(ArmEmitterContext context) - { - EmitFcvt(context, (op1) => EmitRoundMathCall(context, MidpointRounding.AwayFromZero, op1), signed: false, scalar: false); - } - - public static void Fcvtl_V(ArmEmitterContext context) - { - OpCodeSimd op = (OpCodeSimd)context.CurrOp; - - int sizeF = op.Size & 1; - - if (Optimizations.UseSse2 && sizeF == 1) - { - Operand n = GetVec(op.Rn); - - Operand res = op.RegisterSize == RegisterSize.Simd128 ? context.AddIntrinsic(Intrinsic.X86Movhlps, n, n) : n; - res = context.AddIntrinsic(Intrinsic.X86Cvtps2pd, res); - - context.Copy(GetVec(op.Rd), res); - } - else if (Optimizations.UseF16c && sizeF == 0) - { - Debug.Assert(!Optimizations.ForceLegacySse); - - Operand n = GetVec(op.Rn); - - Operand res = op.RegisterSize == RegisterSize.Simd128 ? context.AddIntrinsic(Intrinsic.X86Movhlps, n, n) : n; - res = context.AddIntrinsic(Intrinsic.X86Vcvtph2ps, res); - - context.Copy(GetVec(op.Rd), res); - } - else - { - Operand res = context.VectorZero(); - - int elems = 4 >> sizeF; - - int part = op.RegisterSize == RegisterSize.Simd128 ? elems : 0; - - for (int index = 0; index < elems; index++) - { - if (sizeF == 0) - { - Operand ne = EmitVectorExtractZx(context, op.Rn, part + index, 1); - - context.StoreToContext(); - Operand e = context.Call(typeof(SoftFloat16_32).GetMethod(nameof(SoftFloat16_32.FPConvert)), ne); - context.LoadFromContext(); - - res = context.VectorInsert(res, e, index); - } - else /* if (sizeF == 1) */ - { - Operand ne = context.VectorExtract(OperandType.FP32, GetVec(op.Rn), part + index); - - Operand e = context.ConvertToFP(OperandType.FP64, ne); - - res = context.VectorInsert(res, e, index); - } - } - - context.Copy(GetVec(op.Rd), res); - } - } - - public static void Fcvtms_Gp(ArmEmitterContext context) - { - if (Optimizations.UseSse41) - { - EmitSse41Fcvts_Gp(context, FPRoundingMode.TowardsMinusInfinity, isFixed: false); - } - else - { - EmitFcvt_s_Gp(context, (op1) => EmitUnaryMathCall(context, nameof(Math.Floor), op1)); - } - } - - public static void Fcvtms_V(ArmEmitterContext context) - { - if (Optimizations.UseSse41) - { - EmitSse41FcvtsOpF(context, FPRoundingMode.TowardsMinusInfinity, scalar: false); - } - else - { - EmitFcvt(context, (op1) => EmitUnaryMathCall(context, nameof(Math.Floor), op1), signed: true, scalar: false); - } - } - - public static void Fcvtmu_Gp(ArmEmitterContext context) - { - if (Optimizations.UseSse41) - { - EmitSse41Fcvtu_Gp(context, FPRoundingMode.TowardsMinusInfinity, isFixed: false); - } - else - { - EmitFcvt_u_Gp(context, (op1) => EmitUnaryMathCall(context, nameof(Math.Floor), op1)); - } - } - - public static void Fcvtn_V(ArmEmitterContext context) - { - OpCodeSimd op = (OpCodeSimd)context.CurrOp; - - int sizeF = op.Size & 1; - - if (Optimizations.UseSse2 && sizeF == 1) - { - Operand d = GetVec(op.Rd); - - Intrinsic movInst = op.RegisterSize == RegisterSize.Simd128 ? Intrinsic.X86Movlhps : Intrinsic.X86Movhlps; - - Operand nInt = context.AddIntrinsic(Intrinsic.X86Cvtpd2ps, GetVec(op.Rn)); - nInt = context.AddIntrinsic(Intrinsic.X86Movlhps, nInt, nInt); - - Operand res = context.VectorZeroUpper64(d); - res = context.AddIntrinsic(movInst, res, nInt); - - context.Copy(d, res); - } - else if (Optimizations.UseF16c && sizeF == 0) - { - Debug.Assert(!Optimizations.ForceLegacySse); - - Operand d = GetVec(op.Rd); - Operand n = GetVec(op.Rn); - - Intrinsic movInst = op.RegisterSize == RegisterSize.Simd128 ? Intrinsic.X86Movlhps : Intrinsic.X86Movhlps; - - Operand nInt = context.AddIntrinsic(Intrinsic.X86Vcvtps2ph, n, Const(X86GetRoundControl(FPRoundingMode.ToNearest))); - nInt = context.AddIntrinsic(Intrinsic.X86Movlhps, nInt, nInt); - - Operand res = context.VectorZeroUpper64(d); - res = context.AddIntrinsic(movInst, res, nInt); - - context.Copy(d, res); - } - else - { - OperandType type = sizeF == 0 ? OperandType.FP32 : OperandType.FP64; - - int elems = 4 >> sizeF; - - int part = op.RegisterSize == RegisterSize.Simd128 ? elems : 0; - - Operand d = GetVec(op.Rd); - - Operand res = part == 0 ? context.VectorZero() : context.Copy(d); - - for (int index = 0; index < elems; index++) - { - Operand ne = context.VectorExtract(type, GetVec(op.Rn), 0); - - if (sizeF == 0) - { - context.StoreToContext(); - Operand e = context.Call(typeof(SoftFloat32_16).GetMethod(nameof(SoftFloat32_16.FPConvert)), ne); - context.LoadFromContext(); - - e = context.ZeroExtend16(OperandType.I64, e); - - res = EmitVectorInsert(context, res, e, part + index, 1); - } - else /* if (sizeF == 1) */ - { - Operand e = context.ConvertToFP(OperandType.FP32, ne); - - res = context.VectorInsert(res, e, part + index); - } - } - - context.Copy(d, res); - } - } - - public static void Fcvtns_Gp(ArmEmitterContext context) - { - if (Optimizations.UseSse41) - { - EmitSse41Fcvts_Gp(context, FPRoundingMode.ToNearest, isFixed: false); - } - else - { - EmitFcvt_s_Gp(context, (op1) => EmitRoundMathCall(context, MidpointRounding.ToEven, op1)); - } - } - - public static void Fcvtns_S(ArmEmitterContext context) - { - if (Optimizations.UseSse41) - { - EmitSse41FcvtsOpF(context, FPRoundingMode.ToNearest, scalar: true); - } - else - { - EmitFcvt(context, (op1) => EmitRoundMathCall(context, MidpointRounding.ToEven, op1), signed: true, scalar: true); - } - } - - public static void Fcvtns_V(ArmEmitterContext context) - { - if (Optimizations.UseSse41) - { - EmitSse41FcvtsOpF(context, FPRoundingMode.ToNearest, scalar: false); - } - else - { - EmitFcvt(context, (op1) => EmitRoundMathCall(context, MidpointRounding.ToEven, op1), signed: true, scalar: false); - } - } - - public static void Fcvtnu_S(ArmEmitterContext context) - { - if (Optimizations.UseSse41) - { - EmitSse41FcvtuOpF(context, FPRoundingMode.ToNearest, scalar: true); - } - else - { - EmitFcvt(context, (op1) => EmitRoundMathCall(context, MidpointRounding.ToEven, op1), signed: false, scalar: true); - } - } - - public static void Fcvtnu_V(ArmEmitterContext context) - { - if (Optimizations.UseSse41) - { - EmitSse41FcvtuOpF(context, FPRoundingMode.ToNearest, scalar: false); - } - else - { - EmitFcvt(context, (op1) => EmitRoundMathCall(context, MidpointRounding.ToEven, op1), signed: false, scalar: false); - } - } - - public static void Fcvtps_Gp(ArmEmitterContext context) - { - if (Optimizations.UseSse41) - { - EmitSse41Fcvts_Gp(context, FPRoundingMode.TowardsPlusInfinity, isFixed: false); - } - else - { - EmitFcvt_s_Gp(context, (op1) => EmitUnaryMathCall(context, nameof(Math.Ceiling), op1)); - } - } - - public static void Fcvtpu_Gp(ArmEmitterContext context) - { - if (Optimizations.UseSse41) - { - EmitSse41Fcvtu_Gp(context, FPRoundingMode.TowardsPlusInfinity, isFixed: false); - } - else - { - EmitFcvt_u_Gp(context, (op1) => EmitUnaryMathCall(context, nameof(Math.Ceiling), op1)); - } - } - - public static void Fcvtzs_Gp(ArmEmitterContext context) - { - if (Optimizations.UseSse41) - { - EmitSse41Fcvts_Gp(context, FPRoundingMode.TowardsZero, isFixed: false); - } - else - { - EmitFcvt_s_Gp(context, (op1) => op1); - } - } - - public static void Fcvtzs_Gp_Fixed(ArmEmitterContext context) - { - if (Optimizations.UseSse41) - { - EmitSse41Fcvts_Gp(context, FPRoundingMode.TowardsZero, isFixed: true); - } - else - { - EmitFcvtzs_Gp_Fixed(context); - } - } - - public static void Fcvtzs_S(ArmEmitterContext context) - { - if (Optimizations.UseSse41) - { - EmitSse41FcvtsOpF(context, FPRoundingMode.TowardsZero, scalar: true); - } - else - { - EmitFcvtz(context, signed: true, scalar: true); - } - } - - public static void Fcvtzs_V(ArmEmitterContext context) - { - if (Optimizations.UseSse41) - { - EmitSse41FcvtsOpF(context, FPRoundingMode.TowardsZero, scalar: false); - } - else - { - EmitFcvtz(context, signed: true, scalar: false); - } - } - - public static void Fcvtzs_V_Fixed(ArmEmitterContext context) - { - if (Optimizations.UseSse41) - { - EmitSse41FcvtsOpF(context, FPRoundingMode.TowardsZero, scalar: false); - } - else - { - EmitFcvtz(context, signed: true, scalar: false); - } - } - - public static void Fcvtzu_Gp(ArmEmitterContext context) - { - if (Optimizations.UseSse41) - { - EmitSse41Fcvtu_Gp(context, FPRoundingMode.TowardsZero, isFixed: false); - } - else - { - EmitFcvt_u_Gp(context, (op1) => op1); - } - } - - public static void Fcvtzu_Gp_Fixed(ArmEmitterContext context) - { - if (Optimizations.UseSse41) - { - EmitSse41Fcvtu_Gp(context, FPRoundingMode.TowardsZero, isFixed: true); - } - else - { - EmitFcvtzu_Gp_Fixed(context); - } - } - - public static void Fcvtzu_S(ArmEmitterContext context) - { - if (Optimizations.UseSse41) - { - EmitSse41FcvtuOpF(context, FPRoundingMode.TowardsZero, scalar: true); - } - else - { - EmitFcvtz(context, signed: false, scalar: true); - } - } - - public static void Fcvtzu_V(ArmEmitterContext context) - { - if (Optimizations.UseSse41) - { - EmitSse41FcvtuOpF(context, FPRoundingMode.TowardsZero, scalar: false); - } - else - { - EmitFcvtz(context, signed: false, scalar: false); - } - } - - public static void Fcvtzu_V_Fixed(ArmEmitterContext context) - { - if (Optimizations.UseSse41) - { - EmitSse41FcvtuOpF(context, FPRoundingMode.TowardsZero, scalar: false); - } - else - { - EmitFcvtz(context, signed: false, scalar: false); - } - } - - public static void Scvtf_Gp(ArmEmitterContext context) - { - OpCodeSimdCvt op = (OpCodeSimdCvt)context.CurrOp; - - Operand res = GetIntOrZR(context, op.Rn); - - if (op.RegisterSize == RegisterSize.Int32) - { - res = context.SignExtend32(OperandType.I64, res); - } - - res = EmitFPConvert(context, res, op.Size, signed: true); - - context.Copy(GetVec(op.Rd), context.VectorInsert(context.VectorZero(), res, 0)); - } - - public static void Scvtf_Gp_Fixed(ArmEmitterContext context) - { - OpCodeSimdCvt op = (OpCodeSimdCvt)context.CurrOp; - - Operand res = GetIntOrZR(context, op.Rn); - - if (op.RegisterSize == RegisterSize.Int32) - { - res = context.SignExtend32(OperandType.I64, res); - } - - res = EmitFPConvert(context, res, op.Size, signed: true); - - res = EmitI2fFBitsMul(context, res, op.FBits); - - context.Copy(GetVec(op.Rd), context.VectorInsert(context.VectorZero(), res, 0)); - } - - public static void Scvtf_S(ArmEmitterContext context) - { - if (Optimizations.UseSse2) - { - EmitSse2ScvtfOp(context, scalar: true); - } - else - { - EmitCvtf(context, signed: true, scalar: true); - } - } - - public static void Scvtf_S_Fixed(ArmEmitterContext context) - { - if (Optimizations.UseSse2) - { - EmitSse2ScvtfOp(context, scalar: true); - } - else - { - EmitCvtf(context, signed: true, scalar: true); - } - } - - public static void Scvtf_V(ArmEmitterContext context) - { - if (Optimizations.UseSse2) - { - EmitSse2ScvtfOp(context, scalar: false); - } - else - { - EmitCvtf(context, signed: true, scalar: false); - } - } - - public static void Scvtf_V_Fixed(ArmEmitterContext context) - { - if (Optimizations.UseSse2) - { - EmitSse2ScvtfOp(context, scalar: false); - } - else - { - EmitCvtf(context, signed: true, scalar: false); - } - } - - public static void Ucvtf_Gp(ArmEmitterContext context) - { - OpCodeSimdCvt op = (OpCodeSimdCvt)context.CurrOp; - - Operand res = GetIntOrZR(context, op.Rn); - - res = EmitFPConvert(context, res, op.Size, signed: false); - - context.Copy(GetVec(op.Rd), context.VectorInsert(context.VectorZero(), res, 0)); - } - - public static void Ucvtf_Gp_Fixed(ArmEmitterContext context) - { - OpCodeSimdCvt op = (OpCodeSimdCvt)context.CurrOp; - - Operand res = GetIntOrZR(context, op.Rn); - - res = EmitFPConvert(context, res, op.Size, signed: false); - - res = EmitI2fFBitsMul(context, res, op.FBits); - - context.Copy(GetVec(op.Rd), context.VectorInsert(context.VectorZero(), res, 0)); - } - - public static void Ucvtf_S(ArmEmitterContext context) - { - if (Optimizations.UseSse2) - { - EmitSse2UcvtfOp(context, scalar: true); - } - else - { - EmitCvtf(context, signed: false, scalar: true); - } - } - - public static void Ucvtf_S_Fixed(ArmEmitterContext context) - { - if (Optimizations.UseSse2) - { - EmitSse2UcvtfOp(context, scalar: true); - } - else - { - EmitCvtf(context, signed: false, scalar: true); - } - } - - public static void Ucvtf_V(ArmEmitterContext context) - { - if (Optimizations.UseSse2) - { - EmitSse2UcvtfOp(context, scalar: false); - } - else - { - EmitCvtf(context, signed: false, scalar: false); - } - } - - public static void Ucvtf_V_Fixed(ArmEmitterContext context) - { - if (Optimizations.UseSse2) - { - EmitSse2UcvtfOp(context, scalar: false); - } - else - { - EmitCvtf(context, signed: false, scalar: false); - } - } - - private static void EmitFcvt(ArmEmitterContext context, Func1I emit, bool signed, bool scalar) - { - OpCodeSimd op = (OpCodeSimd)context.CurrOp; - - Operand res = context.VectorZero(); - - Operand n = GetVec(op.Rn); - - int sizeF = op.Size & 1; - int sizeI = sizeF + 2; - - OperandType type = sizeF == 0 ? OperandType.FP32 : OperandType.FP64; - - int elems = !scalar ? op.GetBytesCount() >> sizeI : 1; - - for (int index = 0; index < elems; index++) - { - Operand ne = context.VectorExtract(type, n, index); - - Operand e = emit(ne); - - if (sizeF == 0) - { - MethodInfo info = signed - ? typeof(SoftFallback).GetMethod(nameof(SoftFallback.SatF32ToS32)) - : typeof(SoftFallback).GetMethod(nameof(SoftFallback.SatF32ToU32)); - - e = context.Call(info, e); - - e = context.ZeroExtend32(OperandType.I64, e); - } - else /* if (sizeF == 1) */ - { - MethodInfo info = signed - ? typeof(SoftFallback).GetMethod(nameof(SoftFallback.SatF64ToS64)) - : typeof(SoftFallback).GetMethod(nameof(SoftFallback.SatF64ToU64)); - - e = context.Call(info, e); - } - - res = EmitVectorInsert(context, res, e, index, sizeI); - } - - context.Copy(GetVec(op.Rd), res); - } - - private static void EmitFcvtz(ArmEmitterContext context, bool signed, bool scalar) - { - OpCodeSimd op = (OpCodeSimd)context.CurrOp; - - Operand res = context.VectorZero(); - - Operand n = GetVec(op.Rn); - - int sizeF = op.Size & 1; - int sizeI = sizeF + 2; - - OperandType type = sizeF == 0 ? OperandType.FP32 : OperandType.FP64; - - int fBits = GetFBits(context); - - int elems = !scalar ? op.GetBytesCount() >> sizeI : 1; - - for (int index = 0; index < elems; index++) - { - Operand ne = context.VectorExtract(type, n, index); - - Operand e = EmitF2iFBitsMul(context, ne, fBits); - - if (sizeF == 0) - { - MethodInfo info = signed - ? typeof(SoftFallback).GetMethod(nameof(SoftFallback.SatF32ToS32)) - : typeof(SoftFallback).GetMethod(nameof(SoftFallback.SatF32ToU32)); - - e = context.Call(info, e); - - e = context.ZeroExtend32(OperandType.I64, e); - } - else /* if (sizeF == 1) */ - { - MethodInfo info = signed - ? typeof(SoftFallback).GetMethod(nameof(SoftFallback.SatF64ToS64)) - : typeof(SoftFallback).GetMethod(nameof(SoftFallback.SatF64ToU64)); - - e = context.Call(info, e); - } - - res = EmitVectorInsert(context, res, e, index, sizeI); - } - - context.Copy(GetVec(op.Rd), res); - } - - private static void EmitFcvt_s_Gp(ArmEmitterContext context, Func1I emit) - { - EmitFcvt___Gp(context, emit, signed: true); - } - - private static void EmitFcvt_u_Gp(ArmEmitterContext context, Func1I emit) - { - EmitFcvt___Gp(context, emit, signed: false); - } - - private static void EmitFcvt___Gp(ArmEmitterContext context, Func1I emit, bool signed) - { - OpCodeSimdCvt op = (OpCodeSimdCvt)context.CurrOp; - - OperandType type = op.Size == 0 ? OperandType.FP32 : OperandType.FP64; - - Operand ne = context.VectorExtract(type, GetVec(op.Rn), 0); - - Operand res = signed - ? EmitScalarFcvts(context, emit(ne), 0) - : EmitScalarFcvtu(context, emit(ne), 0); - - SetIntOrZR(context, op.Rd, res); - } - - private static void EmitFcvtzs_Gp_Fixed(ArmEmitterContext context) - { - EmitFcvtz__Gp_Fixed(context, signed: true); - } - - private static void EmitFcvtzu_Gp_Fixed(ArmEmitterContext context) - { - EmitFcvtz__Gp_Fixed(context, signed: false); - } - - private static void EmitFcvtz__Gp_Fixed(ArmEmitterContext context, bool signed) - { - OpCodeSimdCvt op = (OpCodeSimdCvt)context.CurrOp; - - OperandType type = op.Size == 0 ? OperandType.FP32 : OperandType.FP64; - - Operand ne = context.VectorExtract(type, GetVec(op.Rn), 0); - - Operand res = signed - ? EmitScalarFcvts(context, ne, op.FBits) - : EmitScalarFcvtu(context, ne, op.FBits); - - SetIntOrZR(context, op.Rd, res); - } - - private static void EmitCvtf(ArmEmitterContext context, bool signed, bool scalar) - { - OpCodeSimd op = (OpCodeSimd)context.CurrOp; - - Operand res = context.VectorZero(); - - int sizeF = op.Size & 1; - int sizeI = sizeF + 2; - - int fBits = GetFBits(context); - - int elems = !scalar ? op.GetBytesCount() >> sizeI : 1; - - for (int index = 0; index < elems; index++) - { - Operand ne = EmitVectorLongExtract(context, op.Rn, index, sizeI); - - Operand e = EmitFPConvert(context, ne, sizeF, signed); - - e = EmitI2fFBitsMul(context, e, fBits); - - res = context.VectorInsert(res, e, index); - } - - context.Copy(GetVec(op.Rd), res); - } - - private static int GetFBits(ArmEmitterContext context) - { - if (context.CurrOp is OpCodeSimdShImm op) - { - return GetImmShr(op); - } - - return 0; - } - - private static Operand EmitFPConvert(ArmEmitterContext context, Operand value, int size, bool signed) - { - Debug.Assert(value.Type == OperandType.I32 || value.Type == OperandType.I64); - Debug.Assert((uint)size < 2); - - OperandType type = size == 0 ? OperandType.FP32 : OperandType.FP64; - - if (signed) - { - return context.ConvertToFP(type, value); - } - else - { - return context.ConvertToFPUI(type, value); - } - } - - private static Operand EmitScalarFcvts(ArmEmitterContext context, Operand value, int fBits) - { - Debug.Assert(value.Type == OperandType.FP32 || value.Type == OperandType.FP64); - - value = EmitF2iFBitsMul(context, value, fBits); - - MethodInfo info; - - if (context.CurrOp.RegisterSize == RegisterSize.Int32) - { - info = value.Type == OperandType.FP32 - ? typeof(SoftFallback).GetMethod(nameof(SoftFallback.SatF32ToS32)) - : typeof(SoftFallback).GetMethod(nameof(SoftFallback.SatF64ToS32)); - } - else - { - info = value.Type == OperandType.FP32 - ? typeof(SoftFallback).GetMethod(nameof(SoftFallback.SatF32ToS64)) - : typeof(SoftFallback).GetMethod(nameof(SoftFallback.SatF64ToS64)); - } - - return context.Call(info, value); - } - - private static Operand EmitScalarFcvtu(ArmEmitterContext context, Operand value, int fBits) - { - Debug.Assert(value.Type == OperandType.FP32 || value.Type == OperandType.FP64); - - value = EmitF2iFBitsMul(context, value, fBits); - - MethodInfo info; - - if (context.CurrOp.RegisterSize == RegisterSize.Int32) - { - info = value.Type == OperandType.FP32 - ? typeof(SoftFallback).GetMethod(nameof(SoftFallback.SatF32ToU32)) - : typeof(SoftFallback).GetMethod(nameof(SoftFallback.SatF64ToU32)); - } - else - { - info = value.Type == OperandType.FP32 - ? typeof(SoftFallback).GetMethod(nameof(SoftFallback.SatF32ToU64)) - : typeof(SoftFallback).GetMethod(nameof(SoftFallback.SatF64ToU64)); - } - - return context.Call(info, value); - } - - private static Operand EmitF2iFBitsMul(ArmEmitterContext context, Operand value, int fBits) - { - Debug.Assert(value.Type == OperandType.FP32 || value.Type == OperandType.FP64); - - if (fBits == 0) - { - return value; - } - - if (value.Type == OperandType.FP32) - { - return context.Multiply(value, ConstF(MathF.Pow(2f, fBits))); - } - else /* if (value.Type == OperandType.FP64) */ - { - return context.Multiply(value, ConstF(Math.Pow(2d, fBits))); - } - } - - private static Operand EmitI2fFBitsMul(ArmEmitterContext context, Operand value, int fBits) - { - Debug.Assert(value.Type == OperandType.FP32 || value.Type == OperandType.FP64); - - if (fBits == 0) - { - return value; - } - - if (value.Type == OperandType.FP32) - { - return context.Multiply(value, ConstF(1f / MathF.Pow(2f, fBits))); - } - else /* if (value.Type == OperandType.FP64) */ - { - return context.Multiply(value, ConstF(1d / Math.Pow(2d, fBits))); - } - } - - public static Operand EmitSse2CvtDoubleToInt64OpF(ArmEmitterContext context, Operand opF, bool scalar) - { - Debug.Assert(opF.Type == OperandType.V128); - - Operand longL = context.AddIntrinsicLong (Intrinsic.X86Cvtsd2si, opF); // opFL - Operand res = context.VectorCreateScalar(longL); - - if (!scalar) - { - Operand opFH = context.AddIntrinsic (Intrinsic.X86Movhlps, res, opF); // res doesn't matter. - Operand longH = context.AddIntrinsicLong (Intrinsic.X86Cvtsd2si, opFH); - Operand resH = context.VectorCreateScalar(longH); - res = context.AddIntrinsic (Intrinsic.X86Movlhps, res, resH); - } - - return res; - } - - private static Operand EmitSse2CvtInt64ToDoubleOp(ArmEmitterContext context, Operand op, bool scalar) - { - Debug.Assert(op.Type == OperandType.V128); - - Operand longL = context.AddIntrinsicLong(Intrinsic.X86Cvtsi2si, op); // opL - Operand res = context.AddIntrinsic (Intrinsic.X86Cvtsi2sd, context.VectorZero(), longL); - - if (!scalar) - { - Operand opH = context.AddIntrinsic (Intrinsic.X86Movhlps, res, op); // res doesn't matter. - Operand longH = context.AddIntrinsicLong(Intrinsic.X86Cvtsi2si, opH); - Operand resH = context.AddIntrinsic (Intrinsic.X86Cvtsi2sd, res, longH); // res doesn't matter. - res = context.AddIntrinsic (Intrinsic.X86Movlhps, res, resH); - } - - return res; - } - - private static void EmitSse2ScvtfOp(ArmEmitterContext context, bool scalar) - { - OpCodeSimd op = (OpCodeSimd)context.CurrOp; - - Operand n = GetVec(op.Rn); - - // sizeF == ((OpCodeSimdShImm)op).Size - 2 - int sizeF = op.Size & 1; - - if (sizeF == 0) - { - Operand res = context.AddIntrinsic(Intrinsic.X86Cvtdq2ps, n); - - if (op is OpCodeSimdShImm fixedOp) - { - int fBits = GetImmShr(fixedOp); - - // BitConverter.Int32BitsToSingle(fpScaled) == 1f / MathF.Pow(2f, fBits) - int fpScaled = 0x3F800000 - fBits * 0x800000; - - Operand fpScaledMask = scalar - ? X86GetScalar (context, fpScaled) - : X86GetAllElements(context, fpScaled); - - res = context.AddIntrinsic(Intrinsic.X86Mulps, res, fpScaledMask); - } - - if (scalar) - { - res = context.VectorZeroUpper96(res); - } - else if (op.RegisterSize == RegisterSize.Simd64) - { - res = context.VectorZeroUpper64(res); - } - - context.Copy(GetVec(op.Rd), res); - } - else /* if (sizeF == 1) */ - { - Operand res = EmitSse2CvtInt64ToDoubleOp(context, n, scalar); - - if (op is OpCodeSimdShImm fixedOp) - { - int fBits = GetImmShr(fixedOp); - - // BitConverter.Int64BitsToDouble(fpScaled) == 1d / Math.Pow(2d, fBits) - long fpScaled = 0x3FF0000000000000L - fBits * 0x10000000000000L; - - Operand fpScaledMask = scalar - ? X86GetScalar (context, fpScaled) - : X86GetAllElements(context, fpScaled); - - res = context.AddIntrinsic(Intrinsic.X86Mulpd, res, fpScaledMask); - } - - if (scalar) - { - res = context.VectorZeroUpper64(res); - } - - context.Copy(GetVec(op.Rd), res); - } - } - - private static void EmitSse2UcvtfOp(ArmEmitterContext context, bool scalar) - { - OpCodeSimd op = (OpCodeSimd)context.CurrOp; - - Operand n = GetVec(op.Rn); - - // sizeF == ((OpCodeSimdShImm)op).Size - 2 - int sizeF = op.Size & 1; - - if (sizeF == 0) - { - Operand mask = scalar // 65536.000f (1 << 16) - ? X86GetScalar (context, 0x47800000) - : X86GetAllElements(context, 0x47800000); - - Operand res = context.AddIntrinsic(Intrinsic.X86Psrld, n, Const(16)); - res = context.AddIntrinsic(Intrinsic.X86Cvtdq2ps, res); - res = context.AddIntrinsic(Intrinsic.X86Mulps, res, mask); - - Operand res2 = context.AddIntrinsic(Intrinsic.X86Pslld, n, Const(16)); - res2 = context.AddIntrinsic(Intrinsic.X86Psrld, res2, Const(16)); - res2 = context.AddIntrinsic(Intrinsic.X86Cvtdq2ps, res2); - - res = context.AddIntrinsic(Intrinsic.X86Addps, res, res2); - - if (op is OpCodeSimdShImm fixedOp) - { - int fBits = GetImmShr(fixedOp); - - // BitConverter.Int32BitsToSingle(fpScaled) == 1f / MathF.Pow(2f, fBits) - int fpScaled = 0x3F800000 - fBits * 0x800000; - - Operand fpScaledMask = scalar - ? X86GetScalar (context, fpScaled) - : X86GetAllElements(context, fpScaled); - - res = context.AddIntrinsic(Intrinsic.X86Mulps, res, fpScaledMask); - } - - if (scalar) - { - res = context.VectorZeroUpper96(res); - } - else if (op.RegisterSize == RegisterSize.Simd64) - { - res = context.VectorZeroUpper64(res); - } - - context.Copy(GetVec(op.Rd), res); - } - else /* if (sizeF == 1) */ - { - Operand mask = scalar // 4294967296.0000000d (1L << 32) - ? X86GetScalar (context, 0x41F0000000000000L) - : X86GetAllElements(context, 0x41F0000000000000L); - - Operand res = context.AddIntrinsic (Intrinsic.X86Psrlq, n, Const(32)); - res = EmitSse2CvtInt64ToDoubleOp(context, res, scalar); - res = context.AddIntrinsic (Intrinsic.X86Mulpd, res, mask); - - Operand res2 = context.AddIntrinsic (Intrinsic.X86Psllq, n, Const(32)); - res2 = context.AddIntrinsic (Intrinsic.X86Psrlq, res2, Const(32)); - res2 = EmitSse2CvtInt64ToDoubleOp(context, res2, scalar); - - res = context.AddIntrinsic(Intrinsic.X86Addpd, res, res2); - - if (op is OpCodeSimdShImm fixedOp) - { - int fBits = GetImmShr(fixedOp); - - // BitConverter.Int64BitsToDouble(fpScaled) == 1d / Math.Pow(2d, fBits) - long fpScaled = 0x3FF0000000000000L - fBits * 0x10000000000000L; - - Operand fpScaledMask = scalar - ? X86GetScalar (context, fpScaled) - : X86GetAllElements(context, fpScaled); - - res = context.AddIntrinsic(Intrinsic.X86Mulpd, res, fpScaledMask); - } - - if (scalar) - { - res = context.VectorZeroUpper64(res); - } - - context.Copy(GetVec(op.Rd), res); - } - } - - private static void EmitSse41FcvtsOpF(ArmEmitterContext context, FPRoundingMode roundMode, bool scalar) - { - OpCodeSimd op = (OpCodeSimd)context.CurrOp; - - Operand n = GetVec(op.Rn); - - // sizeF == ((OpCodeSimdShImm)op).Size - 2 - int sizeF = op.Size & 1; - - if (sizeF == 0) - { - Operand nRes = context.AddIntrinsic(Intrinsic.X86Cmpps, n, n, Const((int)CmpCondition.OrderedQ)); - nRes = context.AddIntrinsic(Intrinsic.X86Pand, nRes, n); - - if (op is OpCodeSimdShImm fixedOp) - { - int fBits = GetImmShr(fixedOp); - - // BitConverter.Int32BitsToSingle(fpScaled) == MathF.Pow(2f, fBits) - int fpScaled = 0x3F800000 + fBits * 0x800000; - - Operand fpScaledMask = scalar - ? X86GetScalar (context, fpScaled) - : X86GetAllElements(context, fpScaled); - - nRes = context.AddIntrinsic(Intrinsic.X86Mulps, nRes, fpScaledMask); - } - - nRes = context.AddIntrinsic(Intrinsic.X86Roundps, nRes, Const(X86GetRoundControl(roundMode))); - - Operand nInt = context.AddIntrinsic(Intrinsic.X86Cvtps2dq, nRes); - - Operand fpMaxValMask = scalar // 2.14748365E9f (2147483648) - ? X86GetScalar (context, 0x4F000000) - : X86GetAllElements(context, 0x4F000000); - - nRes = context.AddIntrinsic(Intrinsic.X86Cmpps, nRes, fpMaxValMask, Const((int)CmpCondition.NotLessThan)); - - Operand dRes = context.AddIntrinsic(Intrinsic.X86Pxor, nInt, nRes); - - if (scalar) - { - dRes = context.VectorZeroUpper96(dRes); - } - else if (op.RegisterSize == RegisterSize.Simd64) - { - dRes = context.VectorZeroUpper64(dRes); - } - - context.Copy(GetVec(op.Rd), dRes); - } - else /* if (sizeF == 1) */ - { - Operand nRes = context.AddIntrinsic(Intrinsic.X86Cmppd, n, n, Const((int)CmpCondition.OrderedQ)); - nRes = context.AddIntrinsic(Intrinsic.X86Pand, nRes, n); - - if (op is OpCodeSimdShImm fixedOp) - { - int fBits = GetImmShr(fixedOp); - - // BitConverter.Int64BitsToDouble(fpScaled) == Math.Pow(2d, fBits) - long fpScaled = 0x3FF0000000000000L + fBits * 0x10000000000000L; - - Operand fpScaledMask = scalar - ? X86GetScalar (context, fpScaled) - : X86GetAllElements(context, fpScaled); - - nRes = context.AddIntrinsic(Intrinsic.X86Mulpd, nRes, fpScaledMask); - } - - nRes = context.AddIntrinsic(Intrinsic.X86Roundpd, nRes, Const(X86GetRoundControl(roundMode))); - - Operand nLong = EmitSse2CvtDoubleToInt64OpF(context, nRes, scalar); - - Operand fpMaxValMask = scalar // 9.2233720368547760E18d (9223372036854775808) - ? X86GetScalar (context, 0x43E0000000000000L) - : X86GetAllElements(context, 0x43E0000000000000L); - - nRes = context.AddIntrinsic(Intrinsic.X86Cmppd, nRes, fpMaxValMask, Const((int)CmpCondition.NotLessThan)); - - Operand dRes = context.AddIntrinsic(Intrinsic.X86Pxor, nLong, nRes); - - if (scalar) - { - dRes = context.VectorZeroUpper64(dRes); - } - - context.Copy(GetVec(op.Rd), dRes); - } - } - - private static void EmitSse41FcvtuOpF(ArmEmitterContext context, FPRoundingMode roundMode, bool scalar) - { - OpCodeSimd op = (OpCodeSimd)context.CurrOp; - - Operand n = GetVec(op.Rn); - - // sizeF == ((OpCodeSimdShImm)op).Size - 2 - int sizeF = op.Size & 1; - - if (sizeF == 0) - { - Operand nRes = context.AddIntrinsic(Intrinsic.X86Cmpps, n, n, Const((int)CmpCondition.OrderedQ)); - nRes = context.AddIntrinsic(Intrinsic.X86Pand, nRes, n); - - if (op is OpCodeSimdShImm fixedOp) - { - int fBits = GetImmShr(fixedOp); - - // BitConverter.Int32BitsToSingle(fpScaled) == MathF.Pow(2f, fBits) - int fpScaled = 0x3F800000 + fBits * 0x800000; - - Operand fpScaledMask = scalar - ? X86GetScalar (context, fpScaled) - : X86GetAllElements(context, fpScaled); - - nRes = context.AddIntrinsic(Intrinsic.X86Mulps, nRes, fpScaledMask); - } - - nRes = context.AddIntrinsic(Intrinsic.X86Roundps, nRes, Const(X86GetRoundControl(roundMode))); - - Operand zero = context.VectorZero(); - - Operand nCmp = context.AddIntrinsic(Intrinsic.X86Cmpps, nRes, zero, Const((int)CmpCondition.NotLessThanOrEqual)); - nRes = context.AddIntrinsic(Intrinsic.X86Pand, nRes, nCmp); - - Operand fpMaxValMask = scalar // 2.14748365E9f (2147483648) - ? X86GetScalar (context, 0x4F000000) - : X86GetAllElements(context, 0x4F000000); - - Operand nInt = context.AddIntrinsic(Intrinsic.X86Cvtps2dq, nRes); - - nRes = context.AddIntrinsic(Intrinsic.X86Subps, nRes, fpMaxValMask); - - nCmp = context.AddIntrinsic(Intrinsic.X86Cmpps, nRes, zero, Const((int)CmpCondition.NotLessThanOrEqual)); - nRes = context.AddIntrinsic(Intrinsic.X86Pand, nRes, nCmp); - - Operand nInt2 = context.AddIntrinsic(Intrinsic.X86Cvtps2dq, nRes); - - nRes = context.AddIntrinsic(Intrinsic.X86Cmpps, nRes, fpMaxValMask, Const((int)CmpCondition.NotLessThan)); - - Operand dRes = context.AddIntrinsic(Intrinsic.X86Pxor, nInt2, nRes); - dRes = context.AddIntrinsic(Intrinsic.X86Paddd, dRes, nInt); - - if (scalar) - { - dRes = context.VectorZeroUpper96(dRes); - } - else if (op.RegisterSize == RegisterSize.Simd64) - { - dRes = context.VectorZeroUpper64(dRes); - } - - context.Copy(GetVec(op.Rd), dRes); - } - else /* if (sizeF == 1) */ - { - Operand nRes = context.AddIntrinsic(Intrinsic.X86Cmppd, n, n, Const((int)CmpCondition.OrderedQ)); - nRes = context.AddIntrinsic(Intrinsic.X86Pand, nRes, n); - - if (op is OpCodeSimdShImm fixedOp) - { - int fBits = GetImmShr(fixedOp); - - // BitConverter.Int64BitsToDouble(fpScaled) == Math.Pow(2d, fBits) - long fpScaled = 0x3FF0000000000000L + fBits * 0x10000000000000L; - - Operand fpScaledMask = scalar - ? X86GetScalar (context, fpScaled) - : X86GetAllElements(context, fpScaled); - - nRes = context.AddIntrinsic(Intrinsic.X86Mulpd, nRes, fpScaledMask); - } - - nRes = context.AddIntrinsic(Intrinsic.X86Roundpd, nRes, Const(X86GetRoundControl(roundMode))); - - Operand zero = context.VectorZero(); - - Operand nCmp = context.AddIntrinsic(Intrinsic.X86Cmppd, nRes, zero, Const((int)CmpCondition.NotLessThanOrEqual)); - nRes = context.AddIntrinsic(Intrinsic.X86Pand, nRes, nCmp); - - Operand fpMaxValMask = scalar // 9.2233720368547760E18d (9223372036854775808) - ? X86GetScalar (context, 0x43E0000000000000L) - : X86GetAllElements(context, 0x43E0000000000000L); - - Operand nLong = EmitSse2CvtDoubleToInt64OpF(context, nRes, scalar); - - nRes = context.AddIntrinsic(Intrinsic.X86Subpd, nRes, fpMaxValMask); - - nCmp = context.AddIntrinsic(Intrinsic.X86Cmppd, nRes, zero, Const((int)CmpCondition.NotLessThanOrEqual)); - nRes = context.AddIntrinsic(Intrinsic.X86Pand, nRes, nCmp); - - Operand nLong2 = EmitSse2CvtDoubleToInt64OpF(context, nRes, scalar); - - nRes = context.AddIntrinsic(Intrinsic.X86Cmppd, nRes, fpMaxValMask, Const((int)CmpCondition.NotLessThan)); - - Operand dRes = context.AddIntrinsic(Intrinsic.X86Pxor, nLong2, nRes); - dRes = context.AddIntrinsic(Intrinsic.X86Paddq, dRes, nLong); - - if (scalar) - { - dRes = context.VectorZeroUpper64(dRes); - } - - context.Copy(GetVec(op.Rd), dRes); - } - } - - private static void EmitSse41Fcvts_Gp(ArmEmitterContext context, FPRoundingMode roundMode, bool isFixed) - { - OpCodeSimdCvt op = (OpCodeSimdCvt)context.CurrOp; - - Operand n = GetVec(op.Rn); - - if (op.Size == 0) - { - Operand nRes = context.AddIntrinsic(Intrinsic.X86Cmpss, n, n, Const((int)CmpCondition.OrderedQ)); - nRes = context.AddIntrinsic(Intrinsic.X86Pand, nRes, n); - - if (isFixed) - { - // BitConverter.Int32BitsToSingle(fpScaled) == MathF.Pow(2f, op.FBits) - int fpScaled = 0x3F800000 + op.FBits * 0x800000; - - Operand fpScaledMask = X86GetScalar(context, fpScaled); - - nRes = context.AddIntrinsic(Intrinsic.X86Mulss, nRes, fpScaledMask); - } - - nRes = context.AddIntrinsic(Intrinsic.X86Roundss, nRes, Const(X86GetRoundControl(roundMode))); - - Operand nIntOrLong = op.RegisterSize == RegisterSize.Int32 - ? context.AddIntrinsicInt (Intrinsic.X86Cvtss2si, nRes) - : context.AddIntrinsicLong(Intrinsic.X86Cvtss2si, nRes); - - int fpMaxVal = op.RegisterSize == RegisterSize.Int32 - ? 0x4F000000 // 2.14748365E9f (2147483648) - : 0x5F000000; // 9.223372E18f (9223372036854775808) - - Operand fpMaxValMask = X86GetScalar(context, fpMaxVal); - - nRes = context.AddIntrinsic(Intrinsic.X86Cmpss, nRes, fpMaxValMask, Const((int)CmpCondition.NotLessThan)); - - Operand nInt = context.AddIntrinsicInt(Intrinsic.X86Cvtsi2si, nRes); - - if (op.RegisterSize == RegisterSize.Int64) - { - nInt = context.SignExtend32(OperandType.I64, nInt); - } - - Operand dRes = context.BitwiseExclusiveOr(nIntOrLong, nInt); - - SetIntOrZR(context, op.Rd, dRes); - } - else /* if (op.Size == 1) */ - { - Operand nRes = context.AddIntrinsic(Intrinsic.X86Cmpsd, n, n, Const((int)CmpCondition.OrderedQ)); - nRes = context.AddIntrinsic(Intrinsic.X86Pand, nRes, n); - - if (isFixed) - { - // BitConverter.Int64BitsToDouble(fpScaled) == Math.Pow(2d, op.FBits) - long fpScaled = 0x3FF0000000000000L + op.FBits * 0x10000000000000L; - - Operand fpScaledMask = X86GetScalar(context, fpScaled); - - nRes = context.AddIntrinsic(Intrinsic.X86Mulsd, nRes, fpScaledMask); - } - - nRes = context.AddIntrinsic(Intrinsic.X86Roundsd, nRes, Const(X86GetRoundControl(roundMode))); - - Operand nIntOrLong = op.RegisterSize == RegisterSize.Int32 - ? context.AddIntrinsicInt (Intrinsic.X86Cvtsd2si, nRes) - : context.AddIntrinsicLong(Intrinsic.X86Cvtsd2si, nRes); - - long fpMaxVal = op.RegisterSize == RegisterSize.Int32 - ? 0x41E0000000000000L // 2147483648.0000000d (2147483648) - : 0x43E0000000000000L; // 9.2233720368547760E18d (9223372036854775808) - - Operand fpMaxValMask = X86GetScalar(context, fpMaxVal); - - nRes = context.AddIntrinsic(Intrinsic.X86Cmpsd, nRes, fpMaxValMask, Const((int)CmpCondition.NotLessThan)); - - Operand nLong = context.AddIntrinsicLong(Intrinsic.X86Cvtsi2si, nRes); - - if (op.RegisterSize == RegisterSize.Int32) - { - nLong = context.ConvertI64ToI32(nLong); - } - - Operand dRes = context.BitwiseExclusiveOr(nIntOrLong, nLong); - - SetIntOrZR(context, op.Rd, dRes); - } - } - - private static void EmitSse41Fcvtu_Gp(ArmEmitterContext context, FPRoundingMode roundMode, bool isFixed) - { - OpCodeSimdCvt op = (OpCodeSimdCvt)context.CurrOp; - - Operand n = GetVec(op.Rn); - - if (op.Size == 0) - { - Operand nRes = context.AddIntrinsic(Intrinsic.X86Cmpss, n, n, Const((int)CmpCondition.OrderedQ)); - nRes = context.AddIntrinsic(Intrinsic.X86Pand, nRes, n); - - if (isFixed) - { - // BitConverter.Int32BitsToSingle(fpScaled) == MathF.Pow(2f, op.FBits) - int fpScaled = 0x3F800000 + op.FBits * 0x800000; - - Operand fpScaledMask = X86GetScalar(context, fpScaled); - - nRes = context.AddIntrinsic(Intrinsic.X86Mulss, nRes, fpScaledMask); - } - - nRes = context.AddIntrinsic(Intrinsic.X86Roundss, nRes, Const(X86GetRoundControl(roundMode))); - - Operand zero = context.VectorZero(); - - Operand nCmp = context.AddIntrinsic(Intrinsic.X86Cmpss, nRes, zero, Const((int)CmpCondition.NotLessThanOrEqual)); - nRes = context.AddIntrinsic(Intrinsic.X86Pand, nRes, nCmp); - - int fpMaxVal = op.RegisterSize == RegisterSize.Int32 - ? 0x4F000000 // 2.14748365E9f (2147483648) - : 0x5F000000; // 9.223372E18f (9223372036854775808) - - Operand fpMaxValMask = X86GetScalar(context, fpMaxVal); - - Operand nIntOrLong = op.RegisterSize == RegisterSize.Int32 - ? context.AddIntrinsicInt (Intrinsic.X86Cvtss2si, nRes) - : context.AddIntrinsicLong(Intrinsic.X86Cvtss2si, nRes); - - nRes = context.AddIntrinsic(Intrinsic.X86Subss, nRes, fpMaxValMask); - - nCmp = context.AddIntrinsic(Intrinsic.X86Cmpss, nRes, zero, Const((int)CmpCondition.NotLessThanOrEqual)); - nRes = context.AddIntrinsic(Intrinsic.X86Pand, nRes, nCmp); - - Operand nIntOrLong2 = op.RegisterSize == RegisterSize.Int32 - ? context.AddIntrinsicInt (Intrinsic.X86Cvtss2si, nRes) - : context.AddIntrinsicLong(Intrinsic.X86Cvtss2si, nRes); - - nRes = context.AddIntrinsic(Intrinsic.X86Cmpss, nRes, fpMaxValMask, Const((int)CmpCondition.NotLessThan)); - - Operand nInt = context.AddIntrinsicInt(Intrinsic.X86Cvtsi2si, nRes); - - if (op.RegisterSize == RegisterSize.Int64) - { - nInt = context.SignExtend32(OperandType.I64, nInt); - } - - Operand dRes = context.BitwiseExclusiveOr(nIntOrLong2, nInt); - dRes = context.Add(dRes, nIntOrLong); - - SetIntOrZR(context, op.Rd, dRes); - } - else /* if (op.Size == 1) */ - { - Operand nRes = context.AddIntrinsic(Intrinsic.X86Cmpsd, n, n, Const((int)CmpCondition.OrderedQ)); - nRes = context.AddIntrinsic(Intrinsic.X86Pand, nRes, n); - - if (isFixed) - { - // BitConverter.Int64BitsToDouble(fpScaled) == Math.Pow(2d, op.FBits) - long fpScaled = 0x3FF0000000000000L + op.FBits * 0x10000000000000L; - - Operand fpScaledMask = X86GetScalar(context, fpScaled); - - nRes = context.AddIntrinsic(Intrinsic.X86Mulsd, nRes, fpScaledMask); - } - - nRes = context.AddIntrinsic(Intrinsic.X86Roundsd, nRes, Const(X86GetRoundControl(roundMode))); - - Operand zero = context.VectorZero(); - - Operand nCmp = context.AddIntrinsic(Intrinsic.X86Cmpsd, nRes, zero, Const((int)CmpCondition.NotLessThanOrEqual)); - nRes = context.AddIntrinsic(Intrinsic.X86Pand, nRes, nCmp); - - long fpMaxVal = op.RegisterSize == RegisterSize.Int32 - ? 0x41E0000000000000L // 2147483648.0000000d (2147483648) - : 0x43E0000000000000L; // 9.2233720368547760E18d (9223372036854775808) - - Operand fpMaxValMask = X86GetScalar(context, fpMaxVal); - - Operand nIntOrLong = op.RegisterSize == RegisterSize.Int32 - ? context.AddIntrinsicInt (Intrinsic.X86Cvtsd2si, nRes) - : context.AddIntrinsicLong(Intrinsic.X86Cvtsd2si, nRes); - - nRes = context.AddIntrinsic(Intrinsic.X86Subsd, nRes, fpMaxValMask); - - nCmp = context.AddIntrinsic(Intrinsic.X86Cmpsd, nRes, zero, Const((int)CmpCondition.NotLessThanOrEqual)); - nRes = context.AddIntrinsic(Intrinsic.X86Pand, nRes, nCmp); - - Operand nIntOrLong2 = op.RegisterSize == RegisterSize.Int32 - ? context.AddIntrinsicInt (Intrinsic.X86Cvtsd2si, nRes) - : context.AddIntrinsicLong(Intrinsic.X86Cvtsd2si, nRes); - - nRes = context.AddIntrinsic(Intrinsic.X86Cmpsd, nRes, fpMaxValMask, Const((int)CmpCondition.NotLessThan)); - - Operand nLong = context.AddIntrinsicLong(Intrinsic.X86Cvtsi2si, nRes); - - if (op.RegisterSize == RegisterSize.Int32) - { - nLong = context.ConvertI64ToI32(nLong); - } - - Operand dRes = context.BitwiseExclusiveOr(nIntOrLong2, nLong); - dRes = context.Add(dRes, nIntOrLong); - - SetIntOrZR(context, op.Rd, dRes); - } - } - - private static Operand EmitVectorLongExtract(ArmEmitterContext context, int reg, int index, int size) - { - OperandType type = size == 3 ? OperandType.I64 : OperandType.I32; - - return context.VectorExtract(type, GetVec(reg), index); - } - } -} diff --git a/ARMeilleure/Instructions/InstEmitSimdCvt32.cs b/ARMeilleure/Instructions/InstEmitSimdCvt32.cs deleted file mode 100644 index 69ba42747..000000000 --- a/ARMeilleure/Instructions/InstEmitSimdCvt32.cs +++ /dev/null @@ -1,611 +0,0 @@ -using ARMeilleure.Decoders; -using ARMeilleure.IntermediateRepresentation; -using ARMeilleure.State; -using ARMeilleure.Translation; -using System; -using System.Diagnostics; -using System.Reflection; - -using static ARMeilleure.Instructions.InstEmitHelper; -using static ARMeilleure.Instructions.InstEmitSimdHelper; -using static ARMeilleure.Instructions.InstEmitSimdHelper32; -using static ARMeilleure.IntermediateRepresentation.Operand.Factory; - -namespace ARMeilleure.Instructions -{ - static partial class InstEmit32 - { - private static int FlipVdBits(int vd, bool lowBit) - { - if (lowBit) - { - // Move the low bit to the top. - return ((vd & 0x1) << 4) | (vd >> 1); - } - else - { - // Move the high bit to the bottom. - return ((vd & 0xf) << 1) | (vd >> 4); - } - } - - private static Operand EmitSaturateFloatToInt(ArmEmitterContext context, Operand op1, bool unsigned) - { - MethodInfo info; - - if (op1.Type == OperandType.FP64) - { - info = unsigned - ? typeof(SoftFallback).GetMethod(nameof(SoftFallback.SatF64ToU32)) - : typeof(SoftFallback).GetMethod(nameof(SoftFallback.SatF64ToS32)); - } - else - { - info = unsigned - ? typeof(SoftFallback).GetMethod(nameof(SoftFallback.SatF32ToU32)) - : typeof(SoftFallback).GetMethod(nameof(SoftFallback.SatF32ToS32)); - } - - return context.Call(info, op1); - } - - public static void Vcvt_V(ArmEmitterContext context) - { - OpCode32Simd op = (OpCode32Simd)context.CurrOp; - - bool unsigned = (op.Opc & 1) != 0; - bool toInteger = (op.Opc & 2) != 0; - OperandType floatSize = (op.Size == 2) ? OperandType.FP32 : OperandType.FP64; - - if (toInteger) - { - if (Optimizations.UseSse41) - { - EmitSse41ConvertVector32(context, FPRoundingMode.TowardsZero, !unsigned); - } - else - { - EmitVectorUnaryOpF32(context, (op1) => - { - return EmitSaturateFloatToInt(context, op1, unsigned); - }); - } - } - else - { - if (Optimizations.UseSse2) - { - EmitVectorUnaryOpSimd32(context, (n) => - { - if (unsigned) - { - Operand mask = X86GetAllElements(context, 0x47800000); - - Operand res = context.AddIntrinsic(Intrinsic.X86Psrld, n, Const(16)); - res = context.AddIntrinsic(Intrinsic.X86Cvtdq2ps, res); - res = context.AddIntrinsic(Intrinsic.X86Mulps, res, mask); - - Operand res2 = context.AddIntrinsic(Intrinsic.X86Pslld, n, Const(16)); - res2 = context.AddIntrinsic(Intrinsic.X86Psrld, res2, Const(16)); - res2 = context.AddIntrinsic(Intrinsic.X86Cvtdq2ps, res2); - - return context.AddIntrinsic(Intrinsic.X86Addps, res, res2); - } - else - { - return context.AddIntrinsic(Intrinsic.X86Cvtdq2ps, n); - } - }); - } - else - { - if (unsigned) - { - EmitVectorUnaryOpZx32(context, (op1) => EmitFPConvert(context, op1, floatSize, false)); - } - else - { - EmitVectorUnaryOpSx32(context, (op1) => EmitFPConvert(context, op1, floatSize, true)); - } - } - } - } - - public static void Vcvt_FD(ArmEmitterContext context) - { - OpCode32SimdS op = (OpCode32SimdS)context.CurrOp; - - int vm = op.Vm; - int vd; - if (op.Size == 3) - { - vd = FlipVdBits(op.Vd, false); - // Double to single. - Operand fp = ExtractScalar(context, OperandType.FP64, vm); - - Operand res = context.ConvertToFP(OperandType.FP32, fp); - - InsertScalar(context, vd, res); - } - else - { - vd = FlipVdBits(op.Vd, true); - // Single to double. - Operand fp = ExtractScalar(context, OperandType.FP32, vm); - - Operand res = context.ConvertToFP(OperandType.FP64, fp); - - InsertScalar(context, vd, res); - } - } - - // VCVT (floating-point to integer, floating-point) | VCVT (integer to floating-point, floating-point). - public static void Vcvt_FI(ArmEmitterContext context) - { - OpCode32SimdCvtFI op = (OpCode32SimdCvtFI)context.CurrOp; - - bool toInteger = (op.Opc2 & 0b100) != 0; - - OperandType floatSize = op.RegisterSize == RegisterSize.Int64 ? OperandType.FP64 : OperandType.FP32; - - if (toInteger) - { - bool unsigned = (op.Opc2 & 1) == 0; - bool roundWithFpscr = op.Opc != 1; - - if (!roundWithFpscr && Optimizations.UseSse41) - { - EmitSse41ConvertInt32(context, FPRoundingMode.TowardsZero, !unsigned); - } - else - { - Operand toConvert = ExtractScalar(context, floatSize, op.Vm); - - // TODO: Fast Path. - if (roundWithFpscr) - { - toConvert = EmitRoundByRMode(context, toConvert); - } - - // Round towards zero. - Operand asInteger = EmitSaturateFloatToInt(context, toConvert, unsigned); - - InsertScalar(context, op.Vd, asInteger); - } - } - else - { - bool unsigned = op.Opc == 0; - - Operand toConvert = ExtractScalar(context, OperandType.I32, op.Vm); - - Operand asFloat = EmitFPConvert(context, toConvert, floatSize, !unsigned); - - InsertScalar(context, op.Vd, asFloat); - } - } - - private static Operand EmitRoundMathCall(ArmEmitterContext context, MidpointRounding roundMode, Operand n) - { - IOpCode32Simd op = (IOpCode32Simd)context.CurrOp; - - string name = nameof(Math.Round); - - MethodInfo info = (op.Size & 1) == 0 - ? typeof(MathF).GetMethod(name, new Type[] { typeof(float), typeof(MidpointRounding) }) - : typeof(Math). GetMethod(name, new Type[] { typeof(double), typeof(MidpointRounding) }); - - return context.Call(info, n, Const((int)roundMode)); - } - - private static FPRoundingMode RMToRoundMode(int rm) - { - FPRoundingMode roundMode; - switch (rm) - { - case 0b01: - roundMode = FPRoundingMode.ToNearest; - break; - case 0b10: - roundMode = FPRoundingMode.TowardsPlusInfinity; - break; - case 0b11: - roundMode = FPRoundingMode.TowardsMinusInfinity; - break; - default: - throw new ArgumentOutOfRangeException(nameof(rm)); - } - return roundMode; - } - - // VCVTA/M/N/P (floating-point). - public static void Vcvt_RM(ArmEmitterContext context) - { - OpCode32SimdCvtFI op = (OpCode32SimdCvtFI)context.CurrOp; // toInteger == true (opCode<18> == 1 => Opc2<2> == 1). - - OperandType floatSize = op.RegisterSize == RegisterSize.Int64 ? OperandType.FP64 : OperandType.FP32; - - bool unsigned = op.Opc == 0; - int rm = op.Opc2 & 3; - - if (Optimizations.UseSse41 && rm != 0b00) - { - EmitSse41ConvertInt32(context, RMToRoundMode(rm), !unsigned); - } - else - { - Operand toConvert = ExtractScalar(context, floatSize, op.Vm); - - switch (rm) - { - case 0b00: // Away - toConvert = EmitRoundMathCall(context, MidpointRounding.AwayFromZero, toConvert); - break; - case 0b01: // Nearest - toConvert = EmitRoundMathCall(context, MidpointRounding.ToEven, toConvert); - break; - case 0b10: // Towards positive infinity - toConvert = EmitUnaryMathCall(context, nameof(Math.Ceiling), toConvert); - break; - case 0b11: // Towards negative infinity - toConvert = EmitUnaryMathCall(context, nameof(Math.Floor), toConvert); - break; - } - - Operand asInteger = EmitSaturateFloatToInt(context, toConvert, unsigned); - - InsertScalar(context, op.Vd, asInteger); - } - } - - // VRINTA/M/N/P (floating-point). - public static void Vrint_RM(ArmEmitterContext context) - { - OpCode32SimdS op = (OpCode32SimdS)context.CurrOp; - - OperandType floatSize = op.RegisterSize == RegisterSize.Int64 ? OperandType.FP64 : OperandType.FP32; - - int rm = op.Opc2 & 3; - - if (Optimizations.UseSse2 && rm != 0b00) - { - EmitScalarUnaryOpSimd32(context, (m) => - { - Intrinsic inst = (op.Size & 1) == 0 ? Intrinsic.X86Roundss : Intrinsic.X86Roundsd; - - FPRoundingMode roundMode = RMToRoundMode(rm); - - return context.AddIntrinsic(inst, m, Const(X86GetRoundControl(roundMode))); - }); - } - else - { - Operand toConvert = ExtractScalar(context, floatSize, op.Vm); - - switch (rm) - { - case 0b00: // Away - toConvert = EmitRoundMathCall(context, MidpointRounding.AwayFromZero, toConvert); - break; - case 0b01: // Nearest - toConvert = EmitRoundMathCall(context, MidpointRounding.ToEven, toConvert); - break; - case 0b10: // Towards positive infinity - toConvert = EmitUnaryMathCall(context, nameof(Math.Ceiling), toConvert); - break; - case 0b11: // Towards negative infinity - toConvert = EmitUnaryMathCall(context, nameof(Math.Floor), toConvert); - break; - } - - InsertScalar(context, op.Vd, toConvert); - } - } - - // VRINTA (vector). - public static void Vrinta_V(ArmEmitterContext context) - { - EmitVectorUnaryOpF32(context, (m) => EmitRoundMathCall(context, MidpointRounding.AwayFromZero, m)); - } - - // VRINTM (vector). - public static void Vrintm_V(ArmEmitterContext context) - { - if (Optimizations.UseSse2) - { - EmitVectorUnaryOpSimd32(context, (m) => - { - return context.AddIntrinsic(Intrinsic.X86Roundps, m, Const(X86GetRoundControl(FPRoundingMode.TowardsMinusInfinity))); - }); - } - else - { - EmitVectorUnaryOpF32(context, (m) => EmitUnaryMathCall(context, nameof(Math.Floor), m)); - } - } - - // VRINTN (vector). - public static void Vrintn_V(ArmEmitterContext context) - { - if (Optimizations.UseSse2) - { - EmitVectorUnaryOpSimd32(context, (m) => - { - return context.AddIntrinsic(Intrinsic.X86Roundps, m, Const(X86GetRoundControl(FPRoundingMode.ToNearest))); - }); - } - else - { - EmitVectorUnaryOpF32(context, (m) => EmitRoundMathCall(context, MidpointRounding.ToEven, m)); - } - } - - // VRINTP (vector). - public static void Vrintp_V(ArmEmitterContext context) - { - if (Optimizations.UseSse2) - { - EmitVectorUnaryOpSimd32(context, (m) => - { - return context.AddIntrinsic(Intrinsic.X86Roundps, m, Const(X86GetRoundControl(FPRoundingMode.TowardsPlusInfinity))); - }); - } - else - { - EmitVectorUnaryOpF32(context, (m) => EmitUnaryMathCall(context, nameof(Math.Ceiling), m)); - } - } - - // VRINTZ (floating-point). - public static void Vrint_Z(ArmEmitterContext context) - { - OpCode32SimdS op = (OpCode32SimdS)context.CurrOp; - - if (Optimizations.UseSse2) - { - EmitScalarUnaryOpSimd32(context, (m) => - { - Intrinsic inst = (op.Size & 1) == 0 ? Intrinsic.X86Roundss : Intrinsic.X86Roundsd; - return context.AddIntrinsic(inst, m, Const(X86GetRoundControl(FPRoundingMode.TowardsZero))); - }); - } - else - { - EmitScalarUnaryOpF32(context, (op1) => EmitUnaryMathCall(context, nameof(Math.Truncate), op1)); - } - } - - // VRINTX (floating-point). - public static void Vrintx_S(ArmEmitterContext context) - { - EmitScalarUnaryOpF32(context, (op1) => - { - return EmitRoundByRMode(context, op1); - }); - } - - private static Operand EmitFPConvert(ArmEmitterContext context, Operand value, OperandType type, bool signed) - { - Debug.Assert(value.Type == OperandType.I32 || value.Type == OperandType.I64); - - if (signed) - { - return context.ConvertToFP(type, value); - } - else - { - return context.ConvertToFPUI(type, value); - } - } - - private static void EmitSse41ConvertInt32(ArmEmitterContext context, FPRoundingMode roundMode, bool signed) - { - // A port of the similar round function in InstEmitSimdCvt. - OpCode32SimdCvtFI op = (OpCode32SimdCvtFI)context.CurrOp; - - bool doubleSize = (op.Size & 1) != 0; - int shift = doubleSize ? 1 : 2; - Operand n = GetVecA32(op.Vm >> shift); - n = EmitSwapScalar(context, n, op.Vm, doubleSize); - - if (!doubleSize) - { - Operand nRes = context.AddIntrinsic(Intrinsic.X86Cmpss, n, n, Const((int)CmpCondition.OrderedQ)); - nRes = context.AddIntrinsic(Intrinsic.X86Pand, nRes, n); - - nRes = context.AddIntrinsic(Intrinsic.X86Roundss, nRes, Const(X86GetRoundControl(roundMode))); - - Operand zero = context.VectorZero(); - - Operand nCmp; - Operand nIntOrLong2 = default; - - if (!signed) - { - nCmp = context.AddIntrinsic(Intrinsic.X86Cmpss, nRes, zero, Const((int)CmpCondition.NotLessThanOrEqual)); - nRes = context.AddIntrinsic(Intrinsic.X86Pand, nRes, nCmp); - } - - int fpMaxVal = 0x4F000000; // 2.14748365E9f (2147483648) - - Operand fpMaxValMask = X86GetScalar(context, fpMaxVal); - - Operand nIntOrLong = context.AddIntrinsicInt(Intrinsic.X86Cvtss2si, nRes); - - if (!signed) - { - nRes = context.AddIntrinsic(Intrinsic.X86Subss, nRes, fpMaxValMask); - - nCmp = context.AddIntrinsic(Intrinsic.X86Cmpss, nRes, zero, Const((int)CmpCondition.NotLessThanOrEqual)); - nRes = context.AddIntrinsic(Intrinsic.X86Pand, nRes, nCmp); - - nIntOrLong2 = context.AddIntrinsicInt(Intrinsic.X86Cvtss2si, nRes); - } - - nRes = context.AddIntrinsic(Intrinsic.X86Cmpss, nRes, fpMaxValMask, Const((int)CmpCondition.NotLessThan)); - - Operand nInt = context.AddIntrinsicInt(Intrinsic.X86Cvtsi2si, nRes); - - Operand dRes; - if (signed) - { - dRes = context.BitwiseExclusiveOr(nIntOrLong, nInt); - } - else - { - dRes = context.BitwiseExclusiveOr(nIntOrLong2, nInt); - dRes = context.Add(dRes, nIntOrLong); - } - - InsertScalar(context, op.Vd, dRes); - } - else - { - Operand nRes = context.AddIntrinsic(Intrinsic.X86Cmpsd, n, n, Const((int)CmpCondition.OrderedQ)); - nRes = context.AddIntrinsic(Intrinsic.X86Pand, nRes, n); - - nRes = context.AddIntrinsic(Intrinsic.X86Roundsd, nRes, Const(X86GetRoundControl(roundMode))); - - Operand zero = context.VectorZero(); - - Operand nCmp; - Operand nIntOrLong2 = default; - - if (!signed) - { - nCmp = context.AddIntrinsic(Intrinsic.X86Cmpsd, nRes, zero, Const((int)CmpCondition.NotLessThanOrEqual)); - nRes = context.AddIntrinsic(Intrinsic.X86Pand, nRes, nCmp); - } - - long fpMaxVal = 0x41E0000000000000L; // 2147483648.0000000d (2147483648) - - Operand fpMaxValMask = X86GetScalar(context, fpMaxVal); - - Operand nIntOrLong = context.AddIntrinsicInt(Intrinsic.X86Cvtsd2si, nRes); - - if (!signed) - { - nRes = context.AddIntrinsic(Intrinsic.X86Subsd, nRes, fpMaxValMask); - - nCmp = context.AddIntrinsic(Intrinsic.X86Cmpsd, nRes, zero, Const((int)CmpCondition.NotLessThanOrEqual)); - nRes = context.AddIntrinsic(Intrinsic.X86Pand, nRes, nCmp); - - nIntOrLong2 = context.AddIntrinsicInt(Intrinsic.X86Cvtsd2si, nRes); - } - - nRes = context.AddIntrinsic(Intrinsic.X86Cmpsd, nRes, fpMaxValMask, Const((int)CmpCondition.NotLessThan)); - - Operand nLong = context.AddIntrinsicLong(Intrinsic.X86Cvtsi2si, nRes); - nLong = context.ConvertI64ToI32(nLong); - - Operand dRes; - if (signed) - { - dRes = context.BitwiseExclusiveOr(nIntOrLong, nLong); - } - else - { - dRes = context.BitwiseExclusiveOr(nIntOrLong2, nLong); - dRes = context.Add(dRes, nIntOrLong); - } - - InsertScalar(context, op.Vd, dRes); - } - } - - private static void EmitSse41ConvertVector32(ArmEmitterContext context, FPRoundingMode roundMode, bool signed) - { - OpCode32Simd op = (OpCode32Simd)context.CurrOp; - - EmitVectorUnaryOpSimd32(context, (n) => - { - int sizeF = op.Size & 1; - - if (sizeF == 0) - { - Operand nRes = context.AddIntrinsic(Intrinsic.X86Cmpps, n, n, Const((int)CmpCondition.OrderedQ)); - nRes = context.AddIntrinsic(Intrinsic.X86Pand, nRes, n); - - nRes = context.AddIntrinsic(Intrinsic.X86Roundps, nRes, Const(X86GetRoundControl(roundMode))); - - Operand zero = context.VectorZero(); - Operand nCmp; - if (!signed) - { - nCmp = context.AddIntrinsic(Intrinsic.X86Cmpps, nRes, zero, Const((int)CmpCondition.NotLessThanOrEqual)); - nRes = context.AddIntrinsic(Intrinsic.X86Pand, nRes, nCmp); - } - - Operand fpMaxValMask = X86GetAllElements(context, 0x4F000000); // 2.14748365E9f (2147483648) - - Operand nInt = context.AddIntrinsic(Intrinsic.X86Cvtps2dq, nRes); - Operand nInt2 = default; - - if (!signed) - { - nRes = context.AddIntrinsic(Intrinsic.X86Subps, nRes, fpMaxValMask); - - nCmp = context.AddIntrinsic(Intrinsic.X86Cmpps, nRes, zero, Const((int)CmpCondition.NotLessThanOrEqual)); - nRes = context.AddIntrinsic(Intrinsic.X86Pand, nRes, nCmp); - - nInt2 = context.AddIntrinsic(Intrinsic.X86Cvtps2dq, nRes); - } - - nRes = context.AddIntrinsic(Intrinsic.X86Cmpps, nRes, fpMaxValMask, Const((int)CmpCondition.NotLessThan)); - - if (signed) - { - return context.AddIntrinsic(Intrinsic.X86Pxor, nInt, nRes); - } - else - { - Operand dRes = context.AddIntrinsic(Intrinsic.X86Pxor, nInt2, nRes); - return context.AddIntrinsic(Intrinsic.X86Paddd, dRes, nInt); - } - } - else /* if (sizeF == 1) */ - { - Operand nRes = context.AddIntrinsic(Intrinsic.X86Cmppd, n, n, Const((int)CmpCondition.OrderedQ)); - nRes = context.AddIntrinsic(Intrinsic.X86Pand, nRes, n); - - nRes = context.AddIntrinsic(Intrinsic.X86Roundpd, nRes, Const(X86GetRoundControl(roundMode))); - - Operand zero = context.VectorZero(); - Operand nCmp; - if (!signed) - { - nCmp = context.AddIntrinsic(Intrinsic.X86Cmppd, nRes, zero, Const((int)CmpCondition.NotLessThanOrEqual)); - nRes = context.AddIntrinsic(Intrinsic.X86Pand, nRes, nCmp); - } - - Operand fpMaxValMask = X86GetAllElements(context, 0x43E0000000000000L); // 9.2233720368547760E18d (9223372036854775808) - - Operand nLong = InstEmit.EmitSse2CvtDoubleToInt64OpF(context, nRes, false); - Operand nLong2 = default; - - if (!signed) - { - nRes = context.AddIntrinsic(Intrinsic.X86Subpd, nRes, fpMaxValMask); - - nCmp = context.AddIntrinsic(Intrinsic.X86Cmppd, nRes, zero, Const((int)CmpCondition.NotLessThanOrEqual)); - nRes = context.AddIntrinsic(Intrinsic.X86Pand, nRes, nCmp); - - nLong2 = InstEmit.EmitSse2CvtDoubleToInt64OpF(context, nRes, false); - } - - nRes = context.AddIntrinsic(Intrinsic.X86Cmppd, nRes, fpMaxValMask, Const((int)CmpCondition.NotLessThan)); - - if (signed) - { - return context.AddIntrinsic(Intrinsic.X86Pxor, nLong, nRes); - } - else - { - Operand dRes = context.AddIntrinsic(Intrinsic.X86Pxor, nLong2, nRes); - return context.AddIntrinsic(Intrinsic.X86Paddq, dRes, nLong); - } - } - }); - } - } -} diff --git a/ARMeilleure/Instructions/InstEmitSimdLogical.cs b/ARMeilleure/Instructions/InstEmitSimdLogical.cs deleted file mode 100644 index dbd1a1a00..000000000 --- a/ARMeilleure/Instructions/InstEmitSimdLogical.cs +++ /dev/null @@ -1,518 +0,0 @@ -using ARMeilleure.Decoders; -using ARMeilleure.IntermediateRepresentation; -using ARMeilleure.Translation; -using System; -using System.Diagnostics; - -using static ARMeilleure.Instructions.InstEmitHelper; -using static ARMeilleure.Instructions.InstEmitSimdHelper; -using static ARMeilleure.IntermediateRepresentation.Operand.Factory; - -namespace ARMeilleure.Instructions -{ - static partial class InstEmit - { - public static void And_V(ArmEmitterContext context) - { - if (Optimizations.UseSse2) - { - OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp; - - Operand n = GetVec(op.Rn); - Operand m = GetVec(op.Rm); - - Operand res = context.AddIntrinsic(Intrinsic.X86Pand, n, m); - - if (op.RegisterSize == RegisterSize.Simd64) - { - res = context.VectorZeroUpper64(res); - } - - context.Copy(GetVec(op.Rd), res); - } - else - { - EmitVectorBinaryOpZx(context, (op1, op2) => context.BitwiseAnd(op1, op2)); - } - } - - public static void Bic_V(ArmEmitterContext context) - { - if (Optimizations.UseSse2) - { - OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp; - - Operand n = GetVec(op.Rn); - Operand m = GetVec(op.Rm); - - Operand res = context.AddIntrinsic(Intrinsic.X86Pandn, m, n); - - if (op.RegisterSize == RegisterSize.Simd64) - { - res = context.VectorZeroUpper64(res); - } - - context.Copy(GetVec(op.Rd), res); - } - else - { - EmitVectorBinaryOpZx(context, (op1, op2) => - { - return context.BitwiseAnd(op1, context.BitwiseNot(op2)); - }); - } - } - - public static void Bic_Vi(ArmEmitterContext context) - { - if (Optimizations.UseSse2) - { - OpCodeSimdImm op = (OpCodeSimdImm)context.CurrOp; - - int eSize = 8 << op.Size; - - Operand d = GetVec(op.Rd); - Operand imm = eSize switch { - 16 => X86GetAllElements(context, (short)~op.Immediate), - 32 => X86GetAllElements(context, (int)~op.Immediate), - _ => throw new InvalidOperationException($"Invalid element size {eSize}.") - }; - - Operand res = context.AddIntrinsic(Intrinsic.X86Pand, d, imm); - - if (op.RegisterSize == RegisterSize.Simd64) - { - res = context.VectorZeroUpper64(res); - } - - context.Copy(GetVec(op.Rd), res); - } - else - { - EmitVectorImmBinaryOp(context, (op1, op2) => - { - return context.BitwiseAnd(op1, context.BitwiseNot(op2)); - }); - } - } - - public static void Bif_V(ArmEmitterContext context) - { - EmitBifBit(context, notRm: true); - } - - public static void Bit_V(ArmEmitterContext context) - { - EmitBifBit(context, notRm: false); - } - - private static void EmitBifBit(ArmEmitterContext context, bool notRm) - { - OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp; - - if (Optimizations.UseSse2) - { - Operand d = GetVec(op.Rd); - Operand n = GetVec(op.Rn); - Operand m = GetVec(op.Rm); - - Operand res = context.AddIntrinsic(Intrinsic.X86Pxor, n, d); - - if (notRm) - { - res = context.AddIntrinsic(Intrinsic.X86Pandn, m, res); - } - else - { - res = context.AddIntrinsic(Intrinsic.X86Pand, m, res); - } - - res = context.AddIntrinsic(Intrinsic.X86Pxor, d, res); - - if (op.RegisterSize == RegisterSize.Simd64) - { - res = context.VectorZeroUpper64(res); - } - - context.Copy(d, res); - } - else - { - Operand res = context.VectorZero(); - - int elems = op.RegisterSize == RegisterSize.Simd128 ? 2 : 1; - - for (int index = 0; index < elems; index++) - { - Operand d = EmitVectorExtractZx(context, op.Rd, index, 3); - Operand n = EmitVectorExtractZx(context, op.Rn, index, 3); - Operand m = EmitVectorExtractZx(context, op.Rm, index, 3); - - if (notRm) - { - m = context.BitwiseNot(m); - } - - Operand e = context.BitwiseExclusiveOr(d, n); - - e = context.BitwiseAnd(e, m); - e = context.BitwiseExclusiveOr(e, d); - - res = EmitVectorInsert(context, res, e, index, 3); - } - - context.Copy(GetVec(op.Rd), res); - } - } - - public static void Bsl_V(ArmEmitterContext context) - { - if (Optimizations.UseSse2) - { - OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp; - - Operand d = GetVec(op.Rd); - Operand n = GetVec(op.Rn); - Operand m = GetVec(op.Rm); - - Operand res = context.AddIntrinsic(Intrinsic.X86Pxor, n, m); - - res = context.AddIntrinsic(Intrinsic.X86Pand, res, d); - res = context.AddIntrinsic(Intrinsic.X86Pxor, res, m); - - if (op.RegisterSize == RegisterSize.Simd64) - { - res = context.VectorZeroUpper64(res); - } - - context.Copy(d, res); - } - else - { - EmitVectorTernaryOpZx(context, (op1, op2, op3) => - { - return context.BitwiseExclusiveOr( - context.BitwiseAnd(op1, - context.BitwiseExclusiveOr(op2, op3)), op3); - }); - } - } - - public static void Eor_V(ArmEmitterContext context) - { - if (Optimizations.UseSse2) - { - OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp; - - Operand n = GetVec(op.Rn); - Operand m = GetVec(op.Rm); - - Operand res = context.AddIntrinsic(Intrinsic.X86Pxor, n, m); - - if (op.RegisterSize == RegisterSize.Simd64) - { - res = context.VectorZeroUpper64(res); - } - - context.Copy(GetVec(op.Rd), res); - } - else - { - EmitVectorBinaryOpZx(context, (op1, op2) => context.BitwiseExclusiveOr(op1, op2)); - } - } - - public static void Not_V(ArmEmitterContext context) - { - if (Optimizations.UseSse2) - { - OpCodeSimd op = (OpCodeSimd)context.CurrOp; - - Operand n = GetVec(op.Rn); - - Operand mask = X86GetAllElements(context, -1L); - - Operand res = context.AddIntrinsic(Intrinsic.X86Pandn, n, mask); - - if (op.RegisterSize == RegisterSize.Simd64) - { - res = context.VectorZeroUpper64(res); - } - - context.Copy(GetVec(op.Rd), res); - } - else - { - EmitVectorUnaryOpZx(context, (op1) => context.BitwiseNot(op1)); - } - } - - public static void Orn_V(ArmEmitterContext context) - { - if (Optimizations.UseSse2) - { - OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp; - - Operand n = GetVec(op.Rn); - Operand m = GetVec(op.Rm); - - Operand mask = X86GetAllElements(context, -1L); - - Operand res = context.AddIntrinsic(Intrinsic.X86Pandn, m, mask); - - res = context.AddIntrinsic(Intrinsic.X86Por, res, n); - - if (op.RegisterSize == RegisterSize.Simd64) - { - res = context.VectorZeroUpper64(res); - } - - context.Copy(GetVec(op.Rd), res); - } - else - { - EmitVectorBinaryOpZx(context, (op1, op2) => - { - return context.BitwiseOr(op1, context.BitwiseNot(op2)); - }); - } - } - - public static void Orr_V(ArmEmitterContext context) - { - if (Optimizations.UseSse2) - { - OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp; - - Operand n = GetVec(op.Rn); - Operand m = GetVec(op.Rm); - - Operand res = context.AddIntrinsic(Intrinsic.X86Por, n, m); - - if (op.RegisterSize == RegisterSize.Simd64) - { - res = context.VectorZeroUpper64(res); - } - - context.Copy(GetVec(op.Rd), res); - } - else - { - EmitVectorBinaryOpZx(context, (op1, op2) => context.BitwiseOr(op1, op2)); - } - } - - public static void Orr_Vi(ArmEmitterContext context) - { - if (Optimizations.UseSse2) - { - OpCodeSimdImm op = (OpCodeSimdImm)context.CurrOp; - - int eSize = 8 << op.Size; - - Operand d = GetVec(op.Rd); - Operand imm = eSize switch { - 16 => X86GetAllElements(context, (short)op.Immediate), - 32 => X86GetAllElements(context, (int)op.Immediate), - _ => throw new InvalidOperationException($"Invalid element size {eSize}.") - }; - - Operand res = context.AddIntrinsic(Intrinsic.X86Por, d, imm); - - if (op.RegisterSize == RegisterSize.Simd64) - { - res = context.VectorZeroUpper64(res); - } - - context.Copy(GetVec(op.Rd), res); - } - else - { - EmitVectorImmBinaryOp(context, (op1, op2) => context.BitwiseOr(op1, op2)); - } - } - - public static void Rbit_V(ArmEmitterContext context) - { - OpCodeSimd op = (OpCodeSimd)context.CurrOp; - - Operand res = context.VectorZero(); - - int elems = op.RegisterSize == RegisterSize.Simd128 ? 16 : 8; - - for (int index = 0; index < elems; index++) - { - Operand ne = EmitVectorExtractZx(context, op.Rn, index, 0); - - Operand de = EmitReverseBits8Op(context, ne); - - res = EmitVectorInsert(context, res, de, index, 0); - } - - context.Copy(GetVec(op.Rd), res); - } - - private static Operand EmitReverseBits8Op(ArmEmitterContext context, Operand op) - { - Debug.Assert(op.Type == OperandType.I64); - - Operand val = context.BitwiseOr(context.ShiftRightUI(context.BitwiseAnd(op, Const(0xaaul)), Const(1)), - context.ShiftLeft (context.BitwiseAnd(op, Const(0x55ul)), Const(1))); - - val = context.BitwiseOr(context.ShiftRightUI(context.BitwiseAnd(val, Const(0xccul)), Const(2)), - context.ShiftLeft (context.BitwiseAnd(val, Const(0x33ul)), Const(2))); - - return context.BitwiseOr(context.ShiftRightUI(val, Const(4)), - context.ShiftLeft (context.BitwiseAnd(val, Const(0x0ful)), Const(4))); - } - - public static void Rev16_V(ArmEmitterContext context) - { - if (Optimizations.UseSsse3) - { - OpCodeSimd op = (OpCodeSimd)context.CurrOp; - - Operand n = GetVec(op.Rn); - - const long maskE0 = 06L << 56 | 07L << 48 | 04L << 40 | 05L << 32 | 02L << 24 | 03L << 16 | 00L << 8 | 01L << 0; - const long maskE1 = 14L << 56 | 15L << 48 | 12L << 40 | 13L << 32 | 10L << 24 | 11L << 16 | 08L << 8 | 09L << 0; - - Operand mask = X86GetScalar(context, maskE0); - - mask = EmitVectorInsert(context, mask, Const(maskE1), 1, 3); - - Operand res = context.AddIntrinsic(Intrinsic.X86Pshufb, n, mask); - - if (op.RegisterSize == RegisterSize.Simd64) - { - res = context.VectorZeroUpper64(res); - } - - context.Copy(GetVec(op.Rd), res); - } - else - { - EmitRev_V(context, containerSize: 1); - } - } - - public static void Rev32_V(ArmEmitterContext context) - { - if (Optimizations.UseSsse3) - { - OpCodeSimd op = (OpCodeSimd)context.CurrOp; - - Operand n = GetVec(op.Rn); - - Operand mask; - - if (op.Size == 0) - { - const long maskE0 = 04L << 56 | 05L << 48 | 06L << 40 | 07L << 32 | 00L << 24 | 01L << 16 | 02L << 8 | 03L << 0; - const long maskE1 = 12L << 56 | 13L << 48 | 14L << 40 | 15L << 32 | 08L << 24 | 09L << 16 | 10L << 8 | 11L << 0; - - mask = X86GetScalar(context, maskE0); - - mask = EmitVectorInsert(context, mask, Const(maskE1), 1, 3); - } - else /* if (op.Size == 1) */ - { - const long maskE0 = 05L << 56 | 04L << 48 | 07L << 40 | 06L << 32 | 01L << 24 | 00L << 16 | 03L << 8 | 02L << 0; - const long maskE1 = 13L << 56 | 12L << 48 | 15L << 40 | 14L << 32 | 09L << 24 | 08L << 16 | 11L << 8 | 10L << 0; - - mask = X86GetScalar(context, maskE0); - - mask = EmitVectorInsert(context, mask, Const(maskE1), 1, 3); - } - - Operand res = context.AddIntrinsic(Intrinsic.X86Pshufb, n, mask); - - if (op.RegisterSize == RegisterSize.Simd64) - { - res = context.VectorZeroUpper64(res); - } - - context.Copy(GetVec(op.Rd), res); - } - else - { - EmitRev_V(context, containerSize: 2); - } - } - - public static void Rev64_V(ArmEmitterContext context) - { - if (Optimizations.UseSsse3) - { - OpCodeSimd op = (OpCodeSimd)context.CurrOp; - - Operand n = GetVec(op.Rn); - - Operand mask; - - if (op.Size == 0) - { - const long maskE0 = 00L << 56 | 01L << 48 | 02L << 40 | 03L << 32 | 04L << 24 | 05L << 16 | 06L << 8 | 07L << 0; - const long maskE1 = 08L << 56 | 09L << 48 | 10L << 40 | 11L << 32 | 12L << 24 | 13L << 16 | 14L << 8 | 15L << 0; - - mask = X86GetScalar(context, maskE0); - - mask = EmitVectorInsert(context, mask, Const(maskE1), 1, 3); - } - else if (op.Size == 1) - { - const long maskE0 = 01L << 56 | 00L << 48 | 03L << 40 | 02L << 32 | 05L << 24 | 04L << 16 | 07L << 8 | 06L << 0; - const long maskE1 = 09L << 56 | 08L << 48 | 11L << 40 | 10L << 32 | 13L << 24 | 12L << 16 | 15L << 8 | 14L << 0; - - mask = X86GetScalar(context, maskE0); - - mask = EmitVectorInsert(context, mask, Const(maskE1), 1, 3); - } - else /* if (op.Size == 2) */ - { - const long maskE0 = 03L << 56 | 02L << 48 | 01L << 40 | 00L << 32 | 07L << 24 | 06L << 16 | 05L << 8 | 04L << 0; - const long maskE1 = 11L << 56 | 10L << 48 | 09L << 40 | 08L << 32 | 15L << 24 | 14L << 16 | 13L << 8 | 12L << 0; - - mask = X86GetScalar(context, maskE0); - - mask = EmitVectorInsert(context, mask, Const(maskE1), 1, 3); - } - - Operand res = context.AddIntrinsic(Intrinsic.X86Pshufb, n, mask); - - if (op.RegisterSize == RegisterSize.Simd64) - { - res = context.VectorZeroUpper64(res); - } - - context.Copy(GetVec(op.Rd), res); - } - else - { - EmitRev_V(context, containerSize: 3); - } - } - - private static void EmitRev_V(ArmEmitterContext context, int containerSize) - { - OpCodeSimd op = (OpCodeSimd)context.CurrOp; - - Operand res = context.VectorZero(); - - int elems = op.GetBytesCount() >> op.Size; - - int containerMask = (1 << (containerSize - op.Size)) - 1; - - for (int index = 0; index < elems; index++) - { - int revIndex = index ^ containerMask; - - Operand ne = EmitVectorExtractZx(context, op.Rn, revIndex, op.Size); - - res = EmitVectorInsert(context, res, ne, index, op.Size); - } - - context.Copy(GetVec(op.Rd), res); - } - } -} diff --git a/ARMeilleure/Instructions/InstEmitSimdLogical32.cs b/ARMeilleure/Instructions/InstEmitSimdLogical32.cs deleted file mode 100644 index dd686d4dd..000000000 --- a/ARMeilleure/Instructions/InstEmitSimdLogical32.cs +++ /dev/null @@ -1,221 +0,0 @@ -using ARMeilleure.Decoders; -using ARMeilleure.IntermediateRepresentation; -using ARMeilleure.Translation; - -using static ARMeilleure.Instructions.InstEmitHelper; -using static ARMeilleure.Instructions.InstEmitSimdHelper; -using static ARMeilleure.Instructions.InstEmitSimdHelper32; -using static ARMeilleure.IntermediateRepresentation.Operand.Factory; - -namespace ARMeilleure.Instructions -{ - static partial class InstEmit32 - { - public static void Vand_I(ArmEmitterContext context) - { - if (Optimizations.UseSse2) - { - EmitVectorBinaryOpSimd32(context, (n, m) => context.AddIntrinsic(Intrinsic.X86Pand, n, m)); - } - else - { - EmitVectorBinaryOpZx32(context, (op1, op2) => context.BitwiseAnd(op1, op2)); - } - } - - public static void Vbic_I(ArmEmitterContext context) - { - if (Optimizations.UseSse2) - { - EmitVectorBinaryOpSimd32(context, (n, m) => context.AddIntrinsic(Intrinsic.X86Pandn, m, n)); - } - else - { - EmitVectorBinaryOpZx32(context, (op1, op2) => context.BitwiseAnd(op1, context.BitwiseNot(op2))); - } - } - - public static void Vbic_II(ArmEmitterContext context) - { - OpCode32SimdImm op = (OpCode32SimdImm)context.CurrOp; - - long immediate = op.Immediate; - - // Replicate fields to fill the 64-bits, if size is < 64-bits. - switch (op.Size) - { - case 0: immediate *= 0x0101010101010101L; break; - case 1: immediate *= 0x0001000100010001L; break; - case 2: immediate *= 0x0000000100000001L; break; - } - - Operand imm = Const(immediate); - Operand res = GetVecA32(op.Qd); - - if (op.Q) - { - for (int elem = 0; elem < 2; elem++) - { - Operand de = EmitVectorExtractZx(context, op.Qd, elem, 3); - - res = EmitVectorInsert(context, res, context.BitwiseAnd(de, context.BitwiseNot(imm)), elem, 3); - } - } - else - { - Operand de = EmitVectorExtractZx(context, op.Qd, op.Vd & 1, 3); - - res = EmitVectorInsert(context, res, context.BitwiseAnd(de, context.BitwiseNot(imm)), op.Vd & 1, 3); - } - - context.Copy(GetVecA32(op.Qd), res); - } - - public static void Vbif(ArmEmitterContext context) - { - EmitBifBit(context, true); - } - - public static void Vbit(ArmEmitterContext context) - { - EmitBifBit(context, false); - } - - public static void Vbsl(ArmEmitterContext context) - { - if (Optimizations.UseSse2) - { - EmitVectorTernaryOpSimd32(context, (d, n, m) => - { - Operand res = context.AddIntrinsic(Intrinsic.X86Pxor, n, m); - res = context.AddIntrinsic(Intrinsic.X86Pand, res, d); - return context.AddIntrinsic(Intrinsic.X86Pxor, res, m); - }); - } - else - { - EmitVectorTernaryOpZx32(context, (op1, op2, op3) => - { - return context.BitwiseExclusiveOr( - context.BitwiseAnd(op1, - context.BitwiseExclusiveOr(op2, op3)), op3); - }); - } - } - - public static void Veor_I(ArmEmitterContext context) - { - if (Optimizations.UseSse2) - { - EmitVectorBinaryOpSimd32(context, (n, m) => context.AddIntrinsic(Intrinsic.X86Pxor, n, m)); - } - else - { - EmitVectorBinaryOpZx32(context, (op1, op2) => context.BitwiseExclusiveOr(op1, op2)); - } - } - - public static void Vorn_I(ArmEmitterContext context) - { - if (Optimizations.UseSse2) - { - Operand mask = context.VectorOne(); - - EmitVectorBinaryOpSimd32(context, (n, m) => - { - m = context.AddIntrinsic(Intrinsic.X86Pandn, m, mask); - return context.AddIntrinsic(Intrinsic.X86Por, n, m); - }); - } - else - { - EmitVectorBinaryOpZx32(context, (op1, op2) => context.BitwiseOr(op1, context.BitwiseNot(op2))); - } - } - - public static void Vorr_I(ArmEmitterContext context) - { - if (Optimizations.UseSse2) - { - EmitVectorBinaryOpSimd32(context, (n, m) => context.AddIntrinsic(Intrinsic.X86Por, n, m)); - } - else - { - EmitVectorBinaryOpZx32(context, (op1, op2) => context.BitwiseOr(op1, op2)); - } - } - - public static void Vorr_II(ArmEmitterContext context) - { - OpCode32SimdImm op = (OpCode32SimdImm)context.CurrOp; - - long immediate = op.Immediate; - - // Replicate fields to fill the 64-bits, if size is < 64-bits. - switch (op.Size) - { - case 0: immediate *= 0x0101010101010101L; break; - case 1: immediate *= 0x0001000100010001L; break; - case 2: immediate *= 0x0000000100000001L; break; - } - - Operand imm = Const(immediate); - Operand res = GetVecA32(op.Qd); - - if (op.Q) - { - for (int elem = 0; elem < 2; elem++) - { - Operand de = EmitVectorExtractZx(context, op.Qd, elem, 3); - - res = EmitVectorInsert(context, res, context.BitwiseOr(de, imm), elem, 3); - } - } - else - { - Operand de = EmitVectorExtractZx(context, op.Qd, op.Vd & 1, 3); - - res = EmitVectorInsert(context, res, context.BitwiseOr(de, imm), op.Vd & 1, 3); - } - - context.Copy(GetVecA32(op.Qd), res); - } - - public static void Vtst(ArmEmitterContext context) - { - EmitVectorBinaryOpZx32(context, (op1, op2) => - { - Operand isZero = context.ICompareEqual(context.BitwiseAnd(op1, op2), Const(0)); - return context.ConditionalSelect(isZero, Const(0), Const(-1)); - }); - } - - private static void EmitBifBit(ArmEmitterContext context, bool notRm) - { - OpCode32SimdReg op = (OpCode32SimdReg)context.CurrOp; - - if (Optimizations.UseSse2) - { - EmitVectorTernaryOpSimd32(context, (d, n, m) => - { - Operand res = context.AddIntrinsic(Intrinsic.X86Pxor, n, d); - res = context.AddIntrinsic((notRm) ? Intrinsic.X86Pandn : Intrinsic.X86Pand, m, res); - return context.AddIntrinsic(Intrinsic.X86Pxor, d, res); - }); - } - else - { - EmitVectorTernaryOpZx32(context, (d, n, m) => - { - if (notRm) - { - m = context.BitwiseNot(m); - } - return context.BitwiseExclusiveOr( - context.BitwiseAnd(m, - context.BitwiseExclusiveOr(d, n)), d); - }); - } - } - } -} diff --git a/ARMeilleure/Instructions/InstEmitSimdShift.cs b/ARMeilleure/Instructions/InstEmitSimdShift.cs deleted file mode 100644 index 146aeafa7..000000000 --- a/ARMeilleure/Instructions/InstEmitSimdShift.cs +++ /dev/null @@ -1,1284 +0,0 @@ -// https://github.com/intel/ARM_NEON_2_x86_SSE/blob/master/NEON_2_SSE.h - -using ARMeilleure.Decoders; -using ARMeilleure.IntermediateRepresentation; -using ARMeilleure.Translation; -using System; -using System.Diagnostics; -using System.Reflection; - -using static ARMeilleure.Instructions.InstEmitHelper; -using static ARMeilleure.Instructions.InstEmitSimdHelper; -using static ARMeilleure.IntermediateRepresentation.Operand.Factory; - -namespace ARMeilleure.Instructions -{ - using Func2I = Func; - - static partial class InstEmit - { -#region "Masks" - private static readonly long[] _masks_SliSri = new long[] // Replication masks. - { - 0x0101010101010101L, 0x0001000100010001L, 0x0000000100000001L, 0x0000000000000001L - }; -#endregion - - public static void Rshrn_V(ArmEmitterContext context) - { - if (Optimizations.UseSsse3) - { - OpCodeSimdShImm op = (OpCodeSimdShImm)context.CurrOp; - - int shift = GetImmShr(op); - - long roundConst = 1L << (shift - 1); - - Operand d = GetVec(op.Rd); - Operand n = GetVec(op.Rn); - - Operand dLow = context.VectorZeroUpper64(d); - - Operand mask = default; - - switch (op.Size + 1) - { - case 1: mask = X86GetAllElements(context, (int)roundConst * 0x00010001); break; - case 2: mask = X86GetAllElements(context, (int)roundConst); break; - case 3: mask = X86GetAllElements(context, roundConst); break; - } - - Intrinsic addInst = X86PaddInstruction[op.Size + 1]; - - Operand res = context.AddIntrinsic(addInst, n, mask); - - Intrinsic srlInst = X86PsrlInstruction[op.Size + 1]; - - res = context.AddIntrinsic(srlInst, res, Const(shift)); - - Operand mask2 = X86GetAllElements(context, EvenMasks[op.Size]); - - res = context.AddIntrinsic(Intrinsic.X86Pshufb, res, mask2); - - Intrinsic movInst = op.RegisterSize == RegisterSize.Simd128 - ? Intrinsic.X86Movlhps - : Intrinsic.X86Movhlps; - - res = context.AddIntrinsic(movInst, dLow, res); - - context.Copy(d, res); - } - else - { - EmitVectorShrImmNarrowOpZx(context, round: true); - } - } - - public static void Shl_S(ArmEmitterContext context) - { - OpCodeSimdShImm op = (OpCodeSimdShImm)context.CurrOp; - - int shift = GetImmShl(op); - - EmitScalarUnaryOpZx(context, (op1) => context.ShiftLeft(op1, Const(shift))); - } - - public static void Shl_V(ArmEmitterContext context) - { - OpCodeSimdShImm op = (OpCodeSimdShImm)context.CurrOp; - - int shift = GetImmShl(op); - - if (Optimizations.UseSse2 && op.Size > 0) - { - Operand n = GetVec(op.Rn); - - Intrinsic sllInst = X86PsllInstruction[op.Size]; - - Operand res = context.AddIntrinsic(sllInst, n, Const(shift)); - - if (op.RegisterSize == RegisterSize.Simd64) - { - res = context.VectorZeroUpper64(res); - } - - context.Copy(GetVec(op.Rd), res); - } - else - { - EmitVectorUnaryOpZx(context, (op1) => context.ShiftLeft(op1, Const(shift))); - } - } - - public static void Shll_V(ArmEmitterContext context) - { - OpCodeSimd op = (OpCodeSimd)context.CurrOp; - - int shift = 8 << op.Size; - - if (Optimizations.UseSse41) - { - Operand n = GetVec(op.Rn); - - if (op.RegisterSize == RegisterSize.Simd128) - { - n = context.AddIntrinsic(Intrinsic.X86Psrldq, n, Const(8)); - } - - Intrinsic movsxInst = X86PmovsxInstruction[op.Size]; - - Operand res = context.AddIntrinsic(movsxInst, n); - - Intrinsic sllInst = X86PsllInstruction[op.Size + 1]; - - res = context.AddIntrinsic(sllInst, res, Const(shift)); - - context.Copy(GetVec(op.Rd), res); - } - else - { - EmitVectorShImmWidenBinaryZx(context, (op1, op2) => context.ShiftLeft(op1, op2), shift); - } - } - - public static void Shrn_V(ArmEmitterContext context) - { - if (Optimizations.UseSsse3) - { - OpCodeSimdShImm op = (OpCodeSimdShImm)context.CurrOp; - - int shift = GetImmShr(op); - - Operand d = GetVec(op.Rd); - Operand n = GetVec(op.Rn); - - Operand dLow = context.VectorZeroUpper64(d); - - Intrinsic srlInst = X86PsrlInstruction[op.Size + 1]; - - Operand nShifted = context.AddIntrinsic(srlInst, n, Const(shift)); - - Operand mask = X86GetAllElements(context, EvenMasks[op.Size]); - - Operand res = context.AddIntrinsic(Intrinsic.X86Pshufb, nShifted, mask); - - Intrinsic movInst = op.RegisterSize == RegisterSize.Simd128 - ? Intrinsic.X86Movlhps - : Intrinsic.X86Movhlps; - - res = context.AddIntrinsic(movInst, dLow, res); - - context.Copy(d, res); - } - else - { - EmitVectorShrImmNarrowOpZx(context, round: false); - } - } - - public static void Sli_S(ArmEmitterContext context) - { - EmitSli(context, scalar: true); - } - - public static void Sli_V(ArmEmitterContext context) - { - EmitSli(context, scalar: false); - } - - public static void Sqrshl_V(ArmEmitterContext context) - { - EmitShlRegOp(context, ShlRegFlags.Signed | ShlRegFlags.Round | ShlRegFlags.Saturating); - } - - public static void Sqrshrn_S(ArmEmitterContext context) - { - EmitRoundShrImmSaturatingNarrowOp(context, ShrImmSaturatingNarrowFlags.ScalarSxSx); - } - - public static void Sqrshrn_V(ArmEmitterContext context) - { - EmitRoundShrImmSaturatingNarrowOp(context, ShrImmSaturatingNarrowFlags.VectorSxSx); - } - - public static void Sqrshrun_S(ArmEmitterContext context) - { - EmitRoundShrImmSaturatingNarrowOp(context, ShrImmSaturatingNarrowFlags.ScalarSxZx); - } - - public static void Sqrshrun_V(ArmEmitterContext context) - { - EmitRoundShrImmSaturatingNarrowOp(context, ShrImmSaturatingNarrowFlags.VectorSxZx); - } - - public static void Sqshl_V(ArmEmitterContext context) - { - EmitShlRegOp(context, ShlRegFlags.Signed | ShlRegFlags.Saturating); - } - - public static void Sqshrn_S(ArmEmitterContext context) - { - EmitShrImmSaturatingNarrowOp(context, ShrImmSaturatingNarrowFlags.ScalarSxSx); - } - - public static void Sqshrn_V(ArmEmitterContext context) - { - EmitShrImmSaturatingNarrowOp(context, ShrImmSaturatingNarrowFlags.VectorSxSx); - } - - public static void Sqshrun_S(ArmEmitterContext context) - { - EmitShrImmSaturatingNarrowOp(context, ShrImmSaturatingNarrowFlags.ScalarSxZx); - } - - public static void Sqshrun_V(ArmEmitterContext context) - { - EmitShrImmSaturatingNarrowOp(context, ShrImmSaturatingNarrowFlags.VectorSxZx); - } - - public static void Sri_S(ArmEmitterContext context) - { - EmitSri(context, scalar: true); - } - - public static void Sri_V(ArmEmitterContext context) - { - EmitSri(context, scalar: false); - } - - public static void Srshl_V(ArmEmitterContext context) - { - EmitShlRegOp(context, ShlRegFlags.Signed | ShlRegFlags.Round); - } - - public static void Srshr_S(ArmEmitterContext context) - { - EmitScalarShrImmOpSx(context, ShrImmFlags.Round); - } - - public static void Srshr_V(ArmEmitterContext context) - { - OpCodeSimdShImm op = (OpCodeSimdShImm)context.CurrOp; - - if (Optimizations.UseSse2 && op.Size > 0 && op.Size < 3) - { - int shift = GetImmShr(op); - int eSize = 8 << op.Size; - - Operand n = GetVec(op.Rn); - - Intrinsic sllInst = X86PsllInstruction[op.Size]; - - Operand res = context.AddIntrinsic(sllInst, n, Const(eSize - shift)); - - Intrinsic srlInst = X86PsrlInstruction[op.Size]; - - res = context.AddIntrinsic(srlInst, res, Const(eSize - 1)); - - Intrinsic sraInst = X86PsraInstruction[op.Size]; - - Operand nSra = context.AddIntrinsic(sraInst, n, Const(shift)); - - Intrinsic addInst = X86PaddInstruction[op.Size]; - - res = context.AddIntrinsic(addInst, res, nSra); - - if (op.RegisterSize == RegisterSize.Simd64) - { - res = context.VectorZeroUpper64(res); - } - - context.Copy(GetVec(op.Rd), res); - } - else - { - EmitVectorShrImmOpSx(context, ShrImmFlags.Round); - } - } - - public static void Srsra_S(ArmEmitterContext context) - { - EmitScalarShrImmOpSx(context, ShrImmFlags.Round | ShrImmFlags.Accumulate); - } - - public static void Srsra_V(ArmEmitterContext context) - { - OpCodeSimdShImm op = (OpCodeSimdShImm)context.CurrOp; - - if (Optimizations.UseSse2 && op.Size > 0 && op.Size < 3) - { - int shift = GetImmShr(op); - int eSize = 8 << op.Size; - - Operand d = GetVec(op.Rd); - Operand n = GetVec(op.Rn); - - Intrinsic sllInst = X86PsllInstruction[op.Size]; - - Operand res = context.AddIntrinsic(sllInst, n, Const(eSize - shift)); - - Intrinsic srlInst = X86PsrlInstruction[op.Size]; - - res = context.AddIntrinsic(srlInst, res, Const(eSize - 1)); - - Intrinsic sraInst = X86PsraInstruction[op.Size]; - - Operand nSra = context.AddIntrinsic(sraInst, n, Const(shift)); - - Intrinsic addInst = X86PaddInstruction[op.Size]; - - res = context.AddIntrinsic(addInst, res, nSra); - res = context.AddIntrinsic(addInst, res, d); - - if (op.RegisterSize == RegisterSize.Simd64) - { - res = context.VectorZeroUpper64(res); - } - - context.Copy(d, res); - } - else - { - EmitVectorShrImmOpSx(context, ShrImmFlags.Round | ShrImmFlags.Accumulate); - } - } - - public static void Sshl_S(ArmEmitterContext context) - { - EmitShlRegOp(context, ShlRegFlags.Scalar | ShlRegFlags.Signed); - } - - public static void Sshl_V(ArmEmitterContext context) - { - EmitShlRegOp(context, ShlRegFlags.Signed); - } - - public static void Sshll_V(ArmEmitterContext context) - { - OpCodeSimdShImm op = (OpCodeSimdShImm)context.CurrOp; - - int shift = GetImmShl(op); - - if (Optimizations.UseSse41) - { - Operand n = GetVec(op.Rn); - - if (op.RegisterSize == RegisterSize.Simd128) - { - n = context.AddIntrinsic(Intrinsic.X86Psrldq, n, Const(8)); - } - - Intrinsic movsxInst = X86PmovsxInstruction[op.Size]; - - Operand res = context.AddIntrinsic(movsxInst, n); - - if (shift != 0) - { - Intrinsic sllInst = X86PsllInstruction[op.Size + 1]; - - res = context.AddIntrinsic(sllInst, res, Const(shift)); - } - - context.Copy(GetVec(op.Rd), res); - } - else - { - EmitVectorShImmWidenBinarySx(context, (op1, op2) => context.ShiftLeft(op1, op2), shift); - } - } - - public static void Sshr_S(ArmEmitterContext context) - { - EmitShrImmOp(context, ShrImmFlags.ScalarSx); - } - - public static void Sshr_V(ArmEmitterContext context) - { - OpCodeSimdShImm op = (OpCodeSimdShImm)context.CurrOp; - - if (Optimizations.UseSse2 && op.Size > 0 && op.Size < 3) - { - int shift = GetImmShr(op); - - Operand n = GetVec(op.Rn); - - Intrinsic sraInst = X86PsraInstruction[op.Size]; - - Operand res = context.AddIntrinsic(sraInst, n, Const(shift)); - - if (op.RegisterSize == RegisterSize.Simd64) - { - res = context.VectorZeroUpper64(res); - } - - context.Copy(GetVec(op.Rd), res); - } - else - { - EmitShrImmOp(context, ShrImmFlags.VectorSx); - } - } - - public static void Ssra_S(ArmEmitterContext context) - { - EmitScalarShrImmOpSx(context, ShrImmFlags.Accumulate); - } - - public static void Ssra_V(ArmEmitterContext context) - { - OpCodeSimdShImm op = (OpCodeSimdShImm)context.CurrOp; - - if (Optimizations.UseSse2 && op.Size > 0 && op.Size < 3) - { - int shift = GetImmShr(op); - - Operand d = GetVec(op.Rd); - Operand n = GetVec(op.Rn); - - Intrinsic sraInst = X86PsraInstruction[op.Size]; - - Operand res = context.AddIntrinsic(sraInst, n, Const(shift)); - - Intrinsic addInst = X86PaddInstruction[op.Size]; - - res = context.AddIntrinsic(addInst, res, d); - - if (op.RegisterSize == RegisterSize.Simd64) - { - res = context.VectorZeroUpper64(res); - } - - context.Copy(d, res); - } - else - { - EmitVectorShrImmOpSx(context, ShrImmFlags.Accumulate); - } - } - - public static void Uqrshl_V(ArmEmitterContext context) - { - EmitShlRegOp(context, ShlRegFlags.Round | ShlRegFlags.Saturating); - } - - public static void Uqrshrn_S(ArmEmitterContext context) - { - EmitRoundShrImmSaturatingNarrowOp(context, ShrImmSaturatingNarrowFlags.ScalarZxZx); - } - - public static void Uqrshrn_V(ArmEmitterContext context) - { - EmitRoundShrImmSaturatingNarrowOp(context, ShrImmSaturatingNarrowFlags.VectorZxZx); - } - - public static void Uqshl_V(ArmEmitterContext context) - { - EmitShlRegOp(context, ShlRegFlags.Saturating); - } - - public static void Uqshrn_S(ArmEmitterContext context) - { - EmitShrImmSaturatingNarrowOp(context, ShrImmSaturatingNarrowFlags.ScalarZxZx); - } - - public static void Uqshrn_V(ArmEmitterContext context) - { - EmitShrImmSaturatingNarrowOp(context, ShrImmSaturatingNarrowFlags.VectorZxZx); - } - - public static void Urshl_V(ArmEmitterContext context) - { - EmitShlRegOp(context, ShlRegFlags.Round); - } - - public static void Urshr_S(ArmEmitterContext context) - { - EmitScalarShrImmOpZx(context, ShrImmFlags.Round); - } - - public static void Urshr_V(ArmEmitterContext context) - { - OpCodeSimdShImm op = (OpCodeSimdShImm)context.CurrOp; - - if (Optimizations.UseSse2 && op.Size > 0) - { - int shift = GetImmShr(op); - int eSize = 8 << op.Size; - - Operand n = GetVec(op.Rn); - - Intrinsic sllInst = X86PsllInstruction[op.Size]; - - Operand res = context.AddIntrinsic(sllInst, n, Const(eSize - shift)); - - Intrinsic srlInst = X86PsrlInstruction[op.Size]; - - res = context.AddIntrinsic(srlInst, res, Const(eSize - 1)); - - Operand nSrl = context.AddIntrinsic(srlInst, n, Const(shift)); - - Intrinsic addInst = X86PaddInstruction[op.Size]; - - res = context.AddIntrinsic(addInst, res, nSrl); - - if (op.RegisterSize == RegisterSize.Simd64) - { - res = context.VectorZeroUpper64(res); - } - - context.Copy(GetVec(op.Rd), res); - } - else - { - EmitVectorShrImmOpZx(context, ShrImmFlags.Round); - } - } - - public static void Ursra_S(ArmEmitterContext context) - { - EmitScalarShrImmOpZx(context, ShrImmFlags.Round | ShrImmFlags.Accumulate); - } - - public static void Ursra_V(ArmEmitterContext context) - { - OpCodeSimdShImm op = (OpCodeSimdShImm)context.CurrOp; - - if (Optimizations.UseSse2 && op.Size > 0) - { - int shift = GetImmShr(op); - int eSize = 8 << op.Size; - - Operand d = GetVec(op.Rd); - Operand n = GetVec(op.Rn); - - Intrinsic sllInst = X86PsllInstruction[op.Size]; - - Operand res = context.AddIntrinsic(sllInst, n, Const(eSize - shift)); - - Intrinsic srlInst = X86PsrlInstruction[op.Size]; - - res = context.AddIntrinsic(srlInst, res, Const(eSize - 1)); - - Operand nSrl = context.AddIntrinsic(srlInst, n, Const(shift)); - - Intrinsic addInst = X86PaddInstruction[op.Size]; - - res = context.AddIntrinsic(addInst, res, nSrl); - res = context.AddIntrinsic(addInst, res, d); - - if (op.RegisterSize == RegisterSize.Simd64) - { - res = context.VectorZeroUpper64(res); - } - - context.Copy(d, res); - } - else - { - EmitVectorShrImmOpZx(context, ShrImmFlags.Round | ShrImmFlags.Accumulate); - } - } - - public static void Ushl_S(ArmEmitterContext context) - { - EmitShlRegOp(context, ShlRegFlags.Scalar); - } - - public static void Ushl_V(ArmEmitterContext context) - { - EmitShlRegOp(context, ShlRegFlags.None); - } - - public static void Ushll_V(ArmEmitterContext context) - { - OpCodeSimdShImm op = (OpCodeSimdShImm)context.CurrOp; - - int shift = GetImmShl(op); - - if (Optimizations.UseSse41) - { - Operand n = GetVec(op.Rn); - - if (op.RegisterSize == RegisterSize.Simd128) - { - n = context.AddIntrinsic(Intrinsic.X86Psrldq, n, Const(8)); - } - - Intrinsic movzxInst = X86PmovzxInstruction[op.Size]; - - Operand res = context.AddIntrinsic(movzxInst, n); - - if (shift != 0) - { - Intrinsic sllInst = X86PsllInstruction[op.Size + 1]; - - res = context.AddIntrinsic(sllInst, res, Const(shift)); - } - - context.Copy(GetVec(op.Rd), res); - } - else - { - EmitVectorShImmWidenBinaryZx(context, (op1, op2) => context.ShiftLeft(op1, op2), shift); - } - } - - public static void Ushr_S(ArmEmitterContext context) - { - EmitShrImmOp(context, ShrImmFlags.ScalarZx); - } - - public static void Ushr_V(ArmEmitterContext context) - { - OpCodeSimdShImm op = (OpCodeSimdShImm)context.CurrOp; - - if (Optimizations.UseSse2 && op.Size > 0) - { - int shift = GetImmShr(op); - - Operand n = GetVec(op.Rn); - - Intrinsic srlInst = X86PsrlInstruction[op.Size]; - - Operand res = context.AddIntrinsic(srlInst, n, Const(shift)); - - if (op.RegisterSize == RegisterSize.Simd64) - { - res = context.VectorZeroUpper64(res); - } - - context.Copy(GetVec(op.Rd), res); - } - else - { - EmitShrImmOp(context, ShrImmFlags.VectorZx); - } - } - - public static void Usra_S(ArmEmitterContext context) - { - EmitScalarShrImmOpZx(context, ShrImmFlags.Accumulate); - } - - public static void Usra_V(ArmEmitterContext context) - { - OpCodeSimdShImm op = (OpCodeSimdShImm)context.CurrOp; - - if (Optimizations.UseSse2 && op.Size > 0) - { - int shift = GetImmShr(op); - - Operand d = GetVec(op.Rd); - Operand n = GetVec(op.Rn); - - Intrinsic srlInst = X86PsrlInstruction[op.Size]; - - Operand res = context.AddIntrinsic(srlInst, n, Const(shift)); - - Intrinsic addInst = X86PaddInstruction[op.Size]; - - res = context.AddIntrinsic(addInst, res, d); - - if (op.RegisterSize == RegisterSize.Simd64) - { - res = context.VectorZeroUpper64(res); - } - - context.Copy(d, res); - } - else - { - EmitVectorShrImmOpZx(context, ShrImmFlags.Accumulate); - } - } - - [Flags] - private enum ShrImmFlags - { - Scalar = 1 << 0, - Signed = 1 << 1, - - Round = 1 << 2, - Accumulate = 1 << 3, - - ScalarSx = Scalar | Signed, - ScalarZx = Scalar, - - VectorSx = Signed, - VectorZx = 0 - } - - private static void EmitScalarShrImmOpSx(ArmEmitterContext context, ShrImmFlags flags) - { - EmitShrImmOp(context, ShrImmFlags.ScalarSx | flags); - } - - private static void EmitScalarShrImmOpZx(ArmEmitterContext context, ShrImmFlags flags) - { - EmitShrImmOp(context, ShrImmFlags.ScalarZx | flags); - } - - private static void EmitVectorShrImmOpSx(ArmEmitterContext context, ShrImmFlags flags) - { - EmitShrImmOp(context, ShrImmFlags.VectorSx | flags); - } - - private static void EmitVectorShrImmOpZx(ArmEmitterContext context, ShrImmFlags flags) - { - EmitShrImmOp(context, ShrImmFlags.VectorZx | flags); - } - - private static void EmitShrImmOp(ArmEmitterContext context, ShrImmFlags flags) - { - OpCodeSimdShImm op = (OpCodeSimdShImm)context.CurrOp; - - Operand res = context.VectorZero(); - - bool scalar = (flags & ShrImmFlags.Scalar) != 0; - bool signed = (flags & ShrImmFlags.Signed) != 0; - bool round = (flags & ShrImmFlags.Round) != 0; - bool accumulate = (flags & ShrImmFlags.Accumulate) != 0; - - int shift = GetImmShr(op); - - long roundConst = 1L << (shift - 1); - - int elems = !scalar ? op.GetBytesCount() >> op.Size : 1; - - for (int index = 0; index < elems; index++) - { - Operand e = EmitVectorExtract(context, op.Rn, index, op.Size, signed); - - if (op.Size <= 2) - { - if (round) - { - e = context.Add(e, Const(roundConst)); - } - - e = signed ? context.ShiftRightSI(e, Const(shift)) : context.ShiftRightUI(e, Const(shift)); - } - else /* if (op.Size == 3) */ - { - e = EmitShrImm64(context, e, signed, round ? roundConst : 0L, shift); - } - - if (accumulate) - { - Operand de = EmitVectorExtract(context, op.Rd, index, op.Size, signed); - - e = context.Add(e, de); - } - - res = EmitVectorInsert(context, res, e, index, op.Size); - } - - context.Copy(GetVec(op.Rd), res); - } - - private static void EmitVectorShrImmNarrowOpZx(ArmEmitterContext context, bool round) - { - OpCodeSimdShImm op = (OpCodeSimdShImm)context.CurrOp; - - int shift = GetImmShr(op); - - long roundConst = 1L << (shift - 1); - - int elems = 8 >> op.Size; - - int part = op.RegisterSize == RegisterSize.Simd128 ? elems : 0; - - Operand d = GetVec(op.Rd); - - Operand res = part == 0 ? context.VectorZero() : context.Copy(d); - - for (int index = 0; index < elems; index++) - { - Operand e = EmitVectorExtractZx(context, op.Rn, index, op.Size + 1); - - if (round) - { - e = context.Add(e, Const(roundConst)); - } - - e = context.ShiftRightUI(e, Const(shift)); - - res = EmitVectorInsert(context, res, e, part + index, op.Size); - } - - context.Copy(d, res); - } - - [Flags] - private enum ShrImmSaturatingNarrowFlags - { - Scalar = 1 << 0, - SignedSrc = 1 << 1, - SignedDst = 1 << 2, - - Round = 1 << 3, - - ScalarSxSx = Scalar | SignedSrc | SignedDst, - ScalarSxZx = Scalar | SignedSrc, - ScalarZxZx = Scalar, - - VectorSxSx = SignedSrc | SignedDst, - VectorSxZx = SignedSrc, - VectorZxZx = 0 - } - - private static void EmitRoundShrImmSaturatingNarrowOp(ArmEmitterContext context, ShrImmSaturatingNarrowFlags flags) - { - EmitShrImmSaturatingNarrowOp(context, ShrImmSaturatingNarrowFlags.Round | flags); - } - - private static void EmitShrImmSaturatingNarrowOp(ArmEmitterContext context, ShrImmSaturatingNarrowFlags flags) - { - OpCodeSimdShImm op = (OpCodeSimdShImm)context.CurrOp; - - bool scalar = (flags & ShrImmSaturatingNarrowFlags.Scalar) != 0; - bool signedSrc = (flags & ShrImmSaturatingNarrowFlags.SignedSrc) != 0; - bool signedDst = (flags & ShrImmSaturatingNarrowFlags.SignedDst) != 0; - bool round = (flags & ShrImmSaturatingNarrowFlags.Round) != 0; - - int shift = GetImmShr(op); - - long roundConst = 1L << (shift - 1); - - int elems = !scalar ? 8 >> op.Size : 1; - - int part = !scalar && (op.RegisterSize == RegisterSize.Simd128) ? elems : 0; - - Operand d = GetVec(op.Rd); - - Operand res = part == 0 ? context.VectorZero() : context.Copy(d); - - for (int index = 0; index < elems; index++) - { - Operand e = EmitVectorExtract(context, op.Rn, index, op.Size + 1, signedSrc); - - if (op.Size <= 1 || !round) - { - if (round) - { - e = context.Add(e, Const(roundConst)); - } - - e = signedSrc ? context.ShiftRightSI(e, Const(shift)) : context.ShiftRightUI(e, Const(shift)); - } - else /* if (op.Size == 2 && round) */ - { - e = EmitShrImm64(context, e, signedSrc, roundConst, shift); // shift <= 32 - } - - e = signedSrc ? EmitSignedSrcSatQ(context, e, op.Size, signedDst) : EmitUnsignedSrcSatQ(context, e, op.Size, signedDst); - - res = EmitVectorInsert(context, res, e, part + index, op.Size); - } - - context.Copy(d, res); - } - - // dst64 = (Int(src64, signed) + roundConst) >> shift; - private static Operand EmitShrImm64( - ArmEmitterContext context, - Operand value, - bool signed, - long roundConst, - int shift) - { - MethodInfo info = signed - ? typeof(SoftFallback).GetMethod(nameof(SoftFallback.SignedShrImm64)) - : typeof(SoftFallback).GetMethod(nameof(SoftFallback.UnsignedShrImm64)); - - return context.Call(info, value, Const(roundConst), Const(shift)); - } - - private static void EmitVectorShImmWidenBinarySx(ArmEmitterContext context, Func2I emit, int imm) - { - EmitVectorShImmWidenBinaryOp(context, emit, imm, signed: true); - } - - private static void EmitVectorShImmWidenBinaryZx(ArmEmitterContext context, Func2I emit, int imm) - { - EmitVectorShImmWidenBinaryOp(context, emit, imm, signed: false); - } - - private static void EmitVectorShImmWidenBinaryOp(ArmEmitterContext context, Func2I emit, int imm, bool signed) - { - OpCodeSimd op = (OpCodeSimd)context.CurrOp; - - Operand res = context.VectorZero(); - - int elems = 8 >> op.Size; - - int part = op.RegisterSize == RegisterSize.Simd128 ? elems : 0; - - for (int index = 0; index < elems; index++) - { - Operand ne = EmitVectorExtract(context, op.Rn, part + index, op.Size, signed); - - res = EmitVectorInsert(context, res, emit(ne, Const(imm)), index, op.Size + 1); - } - - context.Copy(GetVec(op.Rd), res); - } - - private static void EmitSli(ArmEmitterContext context, bool scalar) - { - OpCodeSimdShImm op = (OpCodeSimdShImm)context.CurrOp; - - int shift = GetImmShl(op); - - ulong mask = shift != 0 ? ulong.MaxValue >> (64 - shift) : 0UL; - - if (Optimizations.UseSse2 && op.Size > 0) - { - Operand d = GetVec(op.Rd); - Operand n = GetVec(op.Rn); - - Intrinsic sllInst = X86PsllInstruction[op.Size]; - - Operand nShifted = context.AddIntrinsic(sllInst, n, Const(shift)); - - Operand dMask = X86GetAllElements(context, (long)mask * _masks_SliSri[op.Size]); - - Operand dMasked = context.AddIntrinsic(Intrinsic.X86Pand, d, dMask); - - Operand res = context.AddIntrinsic(Intrinsic.X86Por, nShifted, dMasked); - - if ((op.RegisterSize == RegisterSize.Simd64) || scalar) - { - res = context.VectorZeroUpper64(res); - } - - context.Copy(d, res); - } - else - { - Operand res = context.VectorZero(); - - int elems = !scalar ? op.GetBytesCount() >> op.Size : 1; - - for (int index = 0; index < elems; index++) - { - Operand ne = EmitVectorExtractZx(context, op.Rn, index, op.Size); - - Operand neShifted = context.ShiftLeft(ne, Const(shift)); - - Operand de = EmitVectorExtractZx(context, op.Rd, index, op.Size); - - Operand deMasked = context.BitwiseAnd(de, Const(mask)); - - Operand e = context.BitwiseOr(neShifted, deMasked); - - res = EmitVectorInsert(context, res, e, index, op.Size); - } - - context.Copy(GetVec(op.Rd), res); - } - } - - private static void EmitSri(ArmEmitterContext context, bool scalar) - { - OpCodeSimdShImm op = (OpCodeSimdShImm)context.CurrOp; - - int shift = GetImmShr(op); - int eSize = 8 << op.Size; - - ulong mask = (ulong.MaxValue << (eSize - shift)) & (ulong.MaxValue >> (64 - eSize)); - - if (Optimizations.UseSse2 && op.Size > 0) - { - Operand d = GetVec(op.Rd); - Operand n = GetVec(op.Rn); - - Intrinsic srlInst = X86PsrlInstruction[op.Size]; - - Operand nShifted = context.AddIntrinsic(srlInst, n, Const(shift)); - - Operand dMask = X86GetAllElements(context, (long)mask * _masks_SliSri[op.Size]); - - Operand dMasked = context.AddIntrinsic(Intrinsic.X86Pand, d, dMask); - - Operand res = context.AddIntrinsic(Intrinsic.X86Por, nShifted, dMasked); - - if ((op.RegisterSize == RegisterSize.Simd64) || scalar) - { - res = context.VectorZeroUpper64(res); - } - - context.Copy(d, res); - } - else - { - Operand res = context.VectorZero(); - - int elems = !scalar ? op.GetBytesCount() >> op.Size : 1; - - for (int index = 0; index < elems; index++) - { - Operand ne = EmitVectorExtractZx(context, op.Rn, index, op.Size); - - Operand neShifted = shift != 64 ? context.ShiftRightUI(ne, Const(shift)) : Const(0UL); - - Operand de = EmitVectorExtractZx(context, op.Rd, index, op.Size); - - Operand deMasked = context.BitwiseAnd(de, Const(mask)); - - Operand e = context.BitwiseOr(neShifted, deMasked); - - res = EmitVectorInsert(context, res, e, index, op.Size); - } - - context.Copy(GetVec(op.Rd), res); - } - } - - [Flags] - private enum ShlRegFlags - { - None = 0, - Scalar = 1 << 0, - Signed = 1 << 1, - Round = 1 << 2, - Saturating = 1 << 3 - } - - private static void EmitShlRegOp(ArmEmitterContext context, ShlRegFlags flags = ShlRegFlags.None) - { - bool scalar = flags.HasFlag(ShlRegFlags.Scalar); - bool signed = flags.HasFlag(ShlRegFlags.Signed); - bool round = flags.HasFlag(ShlRegFlags.Round); - bool saturating = flags.HasFlag(ShlRegFlags.Saturating); - - OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp; - - Operand res = context.VectorZero(); - - int elems = !scalar ? op.GetBytesCount() >> op.Size : 1; - - for (int index = 0; index < elems; index++) - { - Operand ne = EmitVectorExtract(context, op.Rn, index, op.Size, signed); - Operand me = EmitVectorExtractSx(context, op.Rm, index << op.Size, size: 0); - - Operand e = !saturating - ? EmitShlReg(context, ne, context.ConvertI64ToI32(me), round, op.Size, signed) - : EmitShlRegSatQ(context, ne, context.ConvertI64ToI32(me), round, op.Size, signed); - - res = EmitVectorInsert(context, res, e, index, op.Size); - } - - context.Copy(GetVec(op.Rd), res); - } - - // long SignedShlReg(long op, int shiftLsB, bool round, int size); - // ulong UnsignedShlReg(ulong op, int shiftLsB, bool round, int size); - private static Operand EmitShlReg(ArmEmitterContext context, Operand op, Operand shiftLsB, bool round, int size, bool signed) - { - int eSize = 8 << size; - - Debug.Assert(op.Type == OperandType.I64); - Debug.Assert(shiftLsB.Type == OperandType.I32); - Debug.Assert(eSize == 8 || eSize == 16 || eSize == 32 || eSize == 64); - - Operand lbl1 = Label(); - Operand lblEnd = Label(); - - Operand eSizeOp = Const(eSize); - Operand zero = Const(0); - Operand zeroL = Const(0L); - - Operand res = context.Copy(context.AllocateLocal(OperandType.I64), op); - - context.BranchIf(lbl1, shiftLsB, zero, Comparison.GreaterOrEqual); - context.Copy(res, signed - ? EmitSignedShrReg(context, op, context.Negate(shiftLsB), round, eSize) - : EmitUnsignedShrReg(context, op, context.Negate(shiftLsB), round, eSize)); - context.Branch(lblEnd); - - context.MarkLabel(lbl1); - context.BranchIf(lblEnd, shiftLsB, zero, Comparison.LessOrEqual); - Operand shl = context.ShiftLeft(op, shiftLsB); - Operand isGreaterOrEqual = context.ICompareGreaterOrEqual(shiftLsB, eSizeOp); - context.Copy(res, context.ConditionalSelect(isGreaterOrEqual, zeroL, shl)); - context.Branch(lblEnd); - - context.MarkLabel(lblEnd); - - return res; - } - - // long SignedShlRegSatQ(long op, int shiftLsB, bool round, int size); - // ulong UnsignedShlRegSatQ(ulong op, int shiftLsB, bool round, int size); - private static Operand EmitShlRegSatQ(ArmEmitterContext context, Operand op, Operand shiftLsB, bool round, int size, bool signed) - { - int eSize = 8 << size; - - Debug.Assert(op.Type == OperandType.I64); - Debug.Assert(shiftLsB.Type == OperandType.I32); - Debug.Assert(eSize == 8 || eSize == 16 || eSize == 32 || eSize == 64); - - Operand lbl1 = Label(); - Operand lbl2 = Label(); - Operand lblEnd = Label(); - - Operand eSizeOp = Const(eSize); - Operand zero = Const(0); - - Operand res = context.Copy(context.AllocateLocal(OperandType.I64), op); - - context.BranchIf(lbl1, shiftLsB, zero, Comparison.GreaterOrEqual); - context.Copy(res, signed - ? EmitSignedShrReg(context, op, context.Negate(shiftLsB), round, eSize) - : EmitUnsignedShrReg(context, op, context.Negate(shiftLsB), round, eSize)); - context.Branch(lblEnd); - - context.MarkLabel(lbl1); - context.BranchIf(lblEnd, shiftLsB, zero, Comparison.LessOrEqual); - context.BranchIf(lbl2, shiftLsB, eSizeOp, Comparison.Less); - context.Copy(res, signed - ? EmitSignedSignSatQ(context, op, size) - : EmitUnsignedSignSatQ(context, op, size)); - context.Branch(lblEnd); - - context.MarkLabel(lbl2); - Operand shl = context.ShiftLeft(op, shiftLsB); - if (eSize == 64) - { - Operand sarOrShr = signed - ? context.ShiftRightSI(shl, shiftLsB) - : context.ShiftRightUI(shl, shiftLsB); - context.Copy(res, shl); - context.BranchIf(lblEnd, sarOrShr, op, Comparison.Equal); - context.Copy(res, signed - ? EmitSignedSignSatQ(context, op, size) - : EmitUnsignedSignSatQ(context, op, size)); - } - else - { - context.Copy(res, signed - ? EmitSignedSrcSatQ(context, shl, size, signedDst: true) - : EmitUnsignedSrcSatQ(context, shl, size, signedDst: false)); - } - context.Branch(lblEnd); - - context.MarkLabel(lblEnd); - - return res; - } - - // shift := [1, 128]; eSize := {8, 16, 32, 64}. - // long SignedShrReg(long op, int shift, bool round, int eSize); - private static Operand EmitSignedShrReg(ArmEmitterContext context, Operand op, Operand shift, bool round, int eSize) - { - if (round) - { - Operand lblEnd = Label(); - - Operand eSizeOp = Const(eSize); - Operand zeroL = Const(0L); - Operand one = Const(1); - Operand oneL = Const(1L); - - Operand res = context.Copy(context.AllocateLocal(OperandType.I64), zeroL); - - context.BranchIf(lblEnd, shift, eSizeOp, Comparison.GreaterOrEqual); - Operand roundConst = context.ShiftLeft(oneL, context.Subtract(shift, one)); - Operand add = context.Add(op, roundConst); - Operand sar = context.ShiftRightSI(add, shift); - if (eSize == 64) - { - Operand shr = context.ShiftRightUI(add, shift); - Operand left = context.BitwiseAnd(context.Negate(op), context.BitwiseExclusiveOr(op, add)); - Operand isLess = context.ICompareLess(left, zeroL); - context.Copy(res, context.ConditionalSelect(isLess, shr, sar)); - } - else - { - context.Copy(res, sar); - } - context.Branch(lblEnd); - - context.MarkLabel(lblEnd); - - return res; - } - else - { - Operand lblEnd = Label(); - - Operand eSizeOp = Const(eSize); - Operand zeroL = Const(0L); - Operand negOneL = Const(-1L); - - Operand sar = context.ShiftRightSI(op, shift); - Operand res = context.Copy(context.AllocateLocal(OperandType.I64), sar); - - context.BranchIf(lblEnd, shift, eSizeOp, Comparison.Less); - Operand isLess = context.ICompareLess(op, zeroL); - context.Copy(res, context.ConditionalSelect(isLess, negOneL, zeroL)); - context.Branch(lblEnd); - - context.MarkLabel(lblEnd); - - return res; - } - } - - // shift := [1, 128]; eSize := {8, 16, 32, 64}. - // ulong UnsignedShrReg(ulong op, int shift, bool round, int eSize); - private static Operand EmitUnsignedShrReg(ArmEmitterContext context, Operand op, Operand shift, bool round, int eSize) - { - if (round) - { - Operand lblEnd = Label(); - - Operand zeroUL = Const(0UL); - Operand one = Const(1); - Operand oneUL = Const(1UL); - Operand eSizeMaxOp = Const(64); - Operand oneShl63UL = Const(1UL << 63); - - Operand res = context.Copy(context.AllocateLocal(OperandType.I64), zeroUL); - - context.BranchIf(lblEnd, shift, eSizeMaxOp, Comparison.Greater); - Operand roundConst = context.ShiftLeft(oneUL, context.Subtract(shift, one)); - Operand add = context.Add(op, roundConst); - Operand shr = context.ShiftRightUI(add, shift); - Operand isEqual = context.ICompareEqual(shift, eSizeMaxOp); - context.Copy(res, context.ConditionalSelect(isEqual, zeroUL, shr)); - if (eSize == 64) - { - context.BranchIf(lblEnd, add, op, Comparison.GreaterOrEqualUI); - Operand right = context.BitwiseOr(shr, context.ShiftRightUI(oneShl63UL, context.Subtract(shift, one))); - context.Copy(res, context.ConditionalSelect(isEqual, oneUL, right)); - } - context.Branch(lblEnd); - - context.MarkLabel(lblEnd); - - return res; - } - else - { - Operand lblEnd = Label(); - - Operand eSizeOp = Const(eSize); - Operand zeroUL = Const(0UL); - - Operand shr = context.ShiftRightUI(op, shift); - Operand res = context.Copy(context.AllocateLocal(OperandType.I64), shr); - - context.BranchIf(lblEnd, shift, eSizeOp, Comparison.Less); - context.Copy(res, zeroUL); - context.Branch(lblEnd); - - context.MarkLabel(lblEnd); - - return res; - } - } - } -} diff --git a/ARMeilleure/Instructions/InstEmitSystem.cs b/ARMeilleure/Instructions/InstEmitSystem.cs deleted file mode 100644 index cc32228c3..000000000 --- a/ARMeilleure/Instructions/InstEmitSystem.cs +++ /dev/null @@ -1,211 +0,0 @@ -using ARMeilleure.Decoders; -using ARMeilleure.IntermediateRepresentation; -using ARMeilleure.State; -using ARMeilleure.Translation; -using System; -using System.Reflection; - -using static ARMeilleure.Instructions.InstEmitHelper; -using static ARMeilleure.IntermediateRepresentation.Operand.Factory; - -namespace ARMeilleure.Instructions -{ - static partial class InstEmit - { - private const int DczSizeLog2 = 4; // Log2 size in words - public const int DczSizeInBytes = 4 << DczSizeLog2; - - public static void Isb(ArmEmitterContext context) - { - // Execute as no-op. - } - - public static void Mrs(ArmEmitterContext context) - { - OpCodeSystem op = (OpCodeSystem)context.CurrOp; - - MethodInfo info; - - switch (GetPackedId(op)) - { - case 0b11_011_0000_0000_001: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetCtrEl0)); break; - case 0b11_011_0000_0000_111: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetDczidEl0)); break; - case 0b11_011_0100_0010_000: EmitGetNzcv(context); return; - case 0b11_011_0100_0100_000: EmitGetFpcr(context); return; - case 0b11_011_0100_0100_001: EmitGetFpsr(context); return; - case 0b11_011_1101_0000_010: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetTpidrEl0)); break; - case 0b11_011_1101_0000_011: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetTpidrroEl0)); break; - case 0b11_011_1110_0000_000: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetCntfrqEl0)); break; - case 0b11_011_1110_0000_001: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetCntpctEl0)); break; - case 0b11_011_1110_0000_010: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetCntvctEl0)); break; - - default: throw new NotImplementedException($"Unknown MRS 0x{op.RawOpCode:X8} at 0x{op.Address:X16}."); - } - - SetIntOrZR(context, op.Rt, context.Call(info)); - } - - public static void Msr(ArmEmitterContext context) - { - OpCodeSystem op = (OpCodeSystem)context.CurrOp; - - MethodInfo info; - - switch (GetPackedId(op)) - { - case 0b11_011_0100_0010_000: EmitSetNzcv(context); return; - case 0b11_011_0100_0100_000: EmitSetFpcr(context); return; - case 0b11_011_0100_0100_001: EmitSetFpsr(context); return; - case 0b11_011_1101_0000_010: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetTpidrEl0)); break; - - default: throw new NotImplementedException($"Unknown MSR 0x{op.RawOpCode:X8} at 0x{op.Address:X16}."); - } - - context.Call(info, GetIntOrZR(context, op.Rt)); - } - - public static void Nop(ArmEmitterContext context) - { - // Do nothing. - } - - public static void Sys(ArmEmitterContext context) - { - // This instruction is used to do some operations on the CPU like cache invalidation, - // address translation and the like. - // We treat it as no-op here since we don't have any cache being emulated anyway. - OpCodeSystem op = (OpCodeSystem)context.CurrOp; - - switch (GetPackedId(op)) - { - case 0b11_011_0111_0100_001: - { - // DC ZVA - Operand t = GetIntOrZR(context, op.Rt); - - for (long offset = 0; offset < DczSizeInBytes; offset += 8) - { - Operand address = context.Add(t, Const(offset)); - - InstEmitMemoryHelper.EmitStore(context, address, RegisterConsts.ZeroIndex, 3); - } - - break; - } - - // No-op - case 0b11_011_0111_1110_001: // DC CIVAC - break; - - case 0b11_011_0111_0101_001: // IC IVAU - Operand target = Register(op.Rt, RegisterType.Integer, OperandType.I64); - context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.InvalidateCacheLine)), target); - break; - } - } - - private static int GetPackedId(OpCodeSystem op) - { - int id; - - id = op.Op2 << 0; - id |= op.CRm << 3; - id |= op.CRn << 7; - id |= op.Op1 << 11; - id |= op.Op0 << 14; - - return id; - } - - private static void EmitGetNzcv(ArmEmitterContext context) - { - OpCodeSystem op = (OpCodeSystem)context.CurrOp; - - Operand nzcv = context.ShiftLeft(GetFlag(PState.VFlag), Const((int)PState.VFlag)); - nzcv = context.BitwiseOr(nzcv, context.ShiftLeft(GetFlag(PState.CFlag), Const((int)PState.CFlag))); - nzcv = context.BitwiseOr(nzcv, context.ShiftLeft(GetFlag(PState.ZFlag), Const((int)PState.ZFlag))); - nzcv = context.BitwiseOr(nzcv, context.ShiftLeft(GetFlag(PState.NFlag), Const((int)PState.NFlag))); - - SetIntOrZR(context, op.Rt, nzcv); - } - - private static void EmitGetFpcr(ArmEmitterContext context) - { - OpCodeSystem op = (OpCodeSystem)context.CurrOp; - - Operand fpcr = Const(0); - - for (int flag = 0; flag < RegisterConsts.FpFlagsCount; flag++) - { - if (FPCR.Mask.HasFlag((FPCR)(1u << flag))) - { - fpcr = context.BitwiseOr(fpcr, context.ShiftLeft(GetFpFlag((FPState)flag), Const(flag))); - } - } - - SetIntOrZR(context, op.Rt, fpcr); - } - - private static void EmitGetFpsr(ArmEmitterContext context) - { - OpCodeSystem op = (OpCodeSystem)context.CurrOp; - - Operand fpsr = Const(0); - - for (int flag = 0; flag < RegisterConsts.FpFlagsCount; flag++) - { - if (FPSR.Mask.HasFlag((FPSR)(1u << flag))) - { - fpsr = context.BitwiseOr(fpsr, context.ShiftLeft(GetFpFlag((FPState)flag), Const(flag))); - } - } - - SetIntOrZR(context, op.Rt, fpsr); - } - - private static void EmitSetNzcv(ArmEmitterContext context) - { - OpCodeSystem op = (OpCodeSystem)context.CurrOp; - - Operand nzcv = GetIntOrZR(context, op.Rt); - nzcv = context.ConvertI64ToI32(nzcv); - - SetFlag(context, PState.VFlag, context.BitwiseAnd(context.ShiftRightUI(nzcv, Const((int)PState.VFlag)), Const(1))); - SetFlag(context, PState.CFlag, context.BitwiseAnd(context.ShiftRightUI(nzcv, Const((int)PState.CFlag)), Const(1))); - SetFlag(context, PState.ZFlag, context.BitwiseAnd(context.ShiftRightUI(nzcv, Const((int)PState.ZFlag)), Const(1))); - SetFlag(context, PState.NFlag, context.BitwiseAnd(context.ShiftRightUI(nzcv, Const((int)PState.NFlag)), Const(1))); - } - - private static void EmitSetFpcr(ArmEmitterContext context) - { - OpCodeSystem op = (OpCodeSystem)context.CurrOp; - - Operand fpcr = GetIntOrZR(context, op.Rt); - fpcr = context.ConvertI64ToI32(fpcr); - - for (int flag = 0; flag < RegisterConsts.FpFlagsCount; flag++) - { - if (FPCR.Mask.HasFlag((FPCR)(1u << flag))) - { - SetFpFlag(context, (FPState)flag, context.BitwiseAnd(context.ShiftRightUI(fpcr, Const(flag)), Const(1))); - } - } - } - - private static void EmitSetFpsr(ArmEmitterContext context) - { - OpCodeSystem op = (OpCodeSystem)context.CurrOp; - - Operand fpsr = GetIntOrZR(context, op.Rt); - fpsr = context.ConvertI64ToI32(fpsr); - - for (int flag = 0; flag < RegisterConsts.FpFlagsCount; flag++) - { - if (FPSR.Mask.HasFlag((FPSR)(1u << flag))) - { - SetFpFlag(context, (FPState)flag, context.BitwiseAnd(context.ShiftRightUI(fpsr, Const(flag)), Const(1))); - } - } - } - } -} diff --git a/ARMeilleure/Instructions/InstName.cs b/ARMeilleure/Instructions/InstName.cs deleted file mode 100644 index fd71d92e6..000000000 --- a/ARMeilleure/Instructions/InstName.cs +++ /dev/null @@ -1,685 +0,0 @@ -namespace ARMeilleure.Instructions -{ - enum InstName - { - // Base (AArch64) - Adc, - Adcs, - Add, - Adds, - Adr, - Adrp, - And, - Ands, - Asrv, - B, - B_Cond, - Bfm, - Bic, - Bics, - Bl, - Blr, - Br, - Brk, - Cbnz, - Cbz, - Ccmn, - Ccmp, - Clrex, - Cls, - Clz, - Crc32b, - Crc32h, - Crc32w, - Crc32x, - Crc32cb, - Crc32ch, - Crc32cw, - Crc32cx, - Csdb, - Csel, - Csinc, - Csinv, - Csneg, - Dmb, - Dsb, - Eon, - Eor, - Esb, - Extr, - Hint, - Isb, - It, - Ldar, - Ldaxp, - Ldaxr, - Ldp, - Ldr, - Ldr_Literal, - Ldrs, - Ldxr, - Ldxp, - Lslv, - Lsrv, - Madd, - Movk, - Movn, - Movz, - Mrs, - Msr, - Msub, - Nop, - Orn, - Orr, - Prfm, - Rbit, - Ret, - Rev16, - Rev32, - Rev64, - Rorv, - Sbc, - Sbcs, - Sbfm, - Sdiv, - Sel, - Sev, - Sevl, - Shsub8, - Smaddl, - Smsubl, - Smulh, - Smull, - Smulw_, - Ssat, - Ssat16, - Stlr, - Stlxp, - Stlxr, - Stp, - Str, - Stxp, - Stxr, - Sub, - Subs, - Svc, - Sxtb, - Sxth, - Sys, - Tbnz, - Tbz, - Tsb, - Ubfm, - Udiv, - Umaddl, - Umsubl, - Umulh, - Und, - Wfe, - Wfi, - Yield, - - // FP & SIMD (AArch64) - Abs_S, - Abs_V, - Add_S, - Add_V, - Addhn_V, - Addp_S, - Addp_V, - Addv_V, - Aesd_V, - Aese_V, - Aesimc_V, - Aesmc_V, - And_V, - Bic_V, - Bic_Vi, - Bif_V, - Bit_V, - Bsl_V, - Cls_V, - Clz_V, - Cmeq_S, - Cmeq_V, - Cmge_S, - Cmge_V, - Cmgt_S, - Cmgt_V, - Cmhi_S, - Cmhi_V, - Cmhs_S, - Cmhs_V, - Cmle_S, - Cmle_V, - Cmlt_S, - Cmlt_V, - Cmtst_S, - Cmtst_V, - Cnt_V, - Dup_Gp, - Dup_S, - Dup_V, - Eor_V, - Ext_V, - Fabd_S, - Fabd_V, - Fabs_S, - Fabs_V, - Facge_S, - Facge_V, - Facgt_S, - Facgt_V, - Fadd_S, - Fadd_V, - Faddp_S, - Faddp_V, - Fccmp_S, - Fccmpe_S, - Fcmeq_S, - Fcmeq_V, - Fcmge_S, - Fcmge_V, - Fcmgt_S, - Fcmgt_V, - Fcmle_S, - Fcmle_V, - Fcmlt_S, - Fcmlt_V, - Fcmp_S, - Fcmpe_S, - Fcsel_S, - Fcvt_S, - Fcvtas_Gp, - Fcvtas_S, - Fcvtas_V, - Fcvtau_Gp, - Fcvtau_S, - Fcvtau_V, - Fcvtl_V, - Fcvtms_Gp, - Fcvtms_V, - Fcvtmu_Gp, - Fcvtn_V, - Fcvtns_Gp, - Fcvtns_S, - Fcvtns_V, - Fcvtnu_S, - Fcvtnu_V, - Fcvtps_Gp, - Fcvtpu_Gp, - Fcvtzs_Gp, - Fcvtzs_Gp_Fixed, - Fcvtzs_S, - Fcvtzs_V, - Fcvtzs_V_Fixed, - Fcvtzu_Gp, - Fcvtzu_Gp_Fixed, - Fcvtzu_S, - Fcvtzu_V, - Fcvtzu_V_Fixed, - Fdiv_S, - Fdiv_V, - Fmadd_S, - Fmax_S, - Fmax_V, - Fmaxnm_S, - Fmaxnm_V, - Fmaxnmp_S, - Fmaxnmp_V, - Fmaxnmv_V, - Fmaxp_V, - Fmaxv_V, - Fmin_S, - Fmin_V, - Fminnm_S, - Fminnm_V, - Fminnmp_S, - Fminnmp_V, - Fminnmv_V, - Fminp_V, - Fminv_V, - Fmla_Se, - Fmla_V, - Fmla_Ve, - Fmls_Se, - Fmls_V, - Fmls_Ve, - Fmov_S, - Fmov_Si, - Fmov_Vi, - Fmov_Ftoi, - Fmov_Itof, - Fmov_Ftoi1, - Fmov_Itof1, - Fmsub_S, - Fmul_S, - Fmul_Se, - Fmul_V, - Fmul_Ve, - Fmulx_S, - Fmulx_Se, - Fmulx_V, - Fmulx_Ve, - Fneg_S, - Fneg_V, - Fnmadd_S, - Fnmsub_S, - Fnmul_S, - Frecpe_S, - Frecpe_V, - Frecps_S, - Frecps_V, - Frecpx_S, - Frinta_S, - Frinta_V, - Frinti_S, - Frinti_V, - Frintm_S, - Frintm_V, - Frintn_S, - Frintn_V, - Frintp_S, - Frintp_V, - Frintx_S, - Frintx_V, - Frintz_S, - Frintz_V, - Frsqrte_S, - Frsqrte_V, - Frsqrts_S, - Frsqrts_V, - Fsqrt_S, - Fsqrt_V, - Fsub_S, - Fsub_V, - Ins_Gp, - Ins_V, - Ld__Vms, - Ld__Vss, - Mla_V, - Mla_Ve, - Mls_V, - Mls_Ve, - Movi_V, - Mul_V, - Mul_Ve, - Mvni_V, - Neg_S, - Neg_V, - Not_V, - Orn_V, - Orr_V, - Orr_Vi, - Pmull_V, - Raddhn_V, - Rbit_V, - Rev16_V, - Rev32_V, - Rev64_V, - Rshrn_V, - Rsubhn_V, - Saba_V, - Sabal_V, - Sabd_V, - Sabdl_V, - Sadalp_V, - Saddl_V, - Saddlp_V, - Saddlv_V, - Saddw_V, - Scvtf_Gp, - Scvtf_Gp_Fixed, - Scvtf_S, - Scvtf_S_Fixed, - Scvtf_V, - Scvtf_V_Fixed, - Sha1c_V, - Sha1h_V, - Sha1m_V, - Sha1p_V, - Sha1su0_V, - Sha1su1_V, - Sha256h_V, - Sha256h2_V, - Sha256su0_V, - Sha256su1_V, - Shadd_V, - Shl_S, - Shl_V, - Shll_V, - Shrn_V, - Shsub_V, - Sli_S, - Sli_V, - Smax_V, - Smaxp_V, - Smaxv_V, - Smin_V, - Sminp_V, - Sminv_V, - Smlal_V, - Smlal_Ve, - Smlsl_V, - Smlsl_Ve, - Smov_S, - Smull_V, - Smull_Ve, - Sqabs_S, - Sqabs_V, - Sqadd_S, - Sqadd_V, - Sqdmulh_S, - Sqdmulh_V, - Sqdmulh_Ve, - Sqneg_S, - Sqneg_V, - Sqrdmulh_S, - Sqrdmulh_V, - Sqrdmulh_Ve, - Sqrshl_V, - Sqrshrn_S, - Sqrshrn_V, - Sqrshrun_S, - Sqrshrun_V, - Sqshl_V, - Sqshrn_S, - Sqshrn_V, - Sqshrun_S, - Sqshrun_V, - Sqsub_S, - Sqsub_V, - Sqxtn_S, - Sqxtn_V, - Sqxtun_S, - Sqxtun_V, - Srhadd_V, - Sri_S, - Sri_V, - Srshl_V, - Srshr_S, - Srshr_V, - Srsra_S, - Srsra_V, - Sshl_S, - Sshl_V, - Sshll_V, - Sshr_S, - Sshr_V, - Ssra_S, - Ssra_V, - Ssubl_V, - Ssubw_V, - St__Vms, - St__Vss, - Sub_S, - Sub_V, - Subhn_V, - Suqadd_S, - Suqadd_V, - Tbl_V, - Tbx_V, - Trn1_V, - Trn2_V, - Uaba_V, - Uabal_V, - Uabd_V, - Uabdl_V, - Uadalp_V, - Uaddl_V, - Uaddlp_V, - Uaddlv_V, - Uaddw_V, - Ucvtf_Gp, - Ucvtf_Gp_Fixed, - Ucvtf_S, - Ucvtf_S_Fixed, - Ucvtf_V, - Ucvtf_V_Fixed, - Uhadd_V, - Uhsub_V, - Umax_V, - Umaxp_V, - Umaxv_V, - Umin_V, - Uminp_V, - Uminv_V, - Umlal_V, - Umlal_Ve, - Umlsl_V, - Umlsl_Ve, - Umov_S, - Umull_V, - Umull_Ve, - Uqadd_S, - Uqadd_V, - Uqrshl_V, - Uqrshrn_S, - Uqrshrn_V, - Uqshl_V, - Uqshrn_S, - Uqshrn_V, - Uqsub_S, - Uqsub_V, - Uqxtn_S, - Uqxtn_V, - Urhadd_V, - Urshl_V, - Urshr_S, - Urshr_V, - Ursra_S, - Ursra_V, - Ushl_S, - Ushl_V, - Ushll_V, - Ushr_S, - Ushr_V, - Usqadd_S, - Usqadd_V, - Usra_S, - Usra_V, - Usubl_V, - Usubw_V, - Uzp1_V, - Uzp2_V, - Xtn_V, - Zip1_V, - Zip2_V, - - // Base (AArch32) - Bfc, - Bfi, - Blx, - Bx, - Cmp, - Cmn, - Movt, - Mul, - Lda, - Ldab, - Ldaex, - Ldaexb, - Ldaexd, - Ldaexh, - Ldah, - Ldm, - Ldrb, - Ldrd, - Ldrex, - Ldrexb, - Ldrexd, - Ldrexh, - Ldrh, - Ldrsb, - Ldrsh, - Mcr, - Mla, - Mls, - Mov, - Mrc, - Mrrc, - Mvn, - Pkh, - Pld, - Pop, - Push, - Rev, - Revsh, - Rsb, - Rsc, - Sadd8, - Sbfx, - Shadd8, - Smla__, - Smlal, - Smlal__, - Smlaw_, - Smmla, - Smmls, - Smul__, - Smmul, - Ssub8, - Stl, - Stlb, - Stlex, - Stlexb, - Stlexd, - Stlexh, - Stlh, - Stm, - Strb, - Strd, - Strex, - Strexb, - Strexd, - Strexh, - Strh, - Sxtb16, - Tbb, - Tbh, - Teq, - Trap, - Tst, - Uadd8, - Ubfx, - Uhadd8, - Uhsub8, - Umaal, - Umlal, - Umull, - Usat, - Usat16, - Usub8, - Uxtb, - Uxtb16, - Uxth, - - // FP & SIMD (AArch32) - Vabd, - Vabdl, - Vabs, - Vadd, - Vaddl, - Vaddw, - Vand, - Vbic, - Vbif, - Vbit, - Vbsl, - Vceq, - Vcge, - Vcgt, - Vcle, - Vclt, - Vcmp, - Vcmpe, - Vcnt, - Vcvt, - Vdiv, - Vdup, - Veor, - Vext, - Vfma, - Vfms, - Vfnma, - Vfnms, - Vhadd, - Vld1, - Vld2, - Vld3, - Vld4, - Vldm, - Vldr, - Vmax, - Vmaxnm, - Vmin, - Vminnm, - Vmla, - Vmlal, - Vmls, - Vmlsl, - Vmov, - Vmovl, - Vmovn, - Vmrs, - Vmsr, - Vmul, - Vmull, - Vmvn, - Vneg, - Vnmul, - Vnmla, - Vnmls, - Vorn, - Vorr, - Vpadd, - Vpaddl, - Vpmax, - Vpmin, - Vqadd, - Vqdmulh, - Vqmovn, - Vqmovun, - Vqrshrn, - Vqrshrun, - Vqshrn, - Vqshrun, - Vqsub, - Vrev, - Vrhadd, - Vrint, - Vrinta, - Vrintm, - Vrintn, - Vrintp, - Vrintx, - Vrshr, - Vrshrn, - Vsel, - Vshl, - Vshll, - Vshr, - Vshrn, - Vst1, - Vst2, - Vst3, - Vst4, - Vstm, - Vstr, - Vsqrt, - Vrecpe, - Vrecps, - Vrsqrte, - Vrsqrts, - Vrsra, - Vsra, - Vsub, - Vsubl, - Vsubw, - Vtbl, - Vtrn, - Vtst, - Vuzp, - Vzip, - } -} diff --git a/ARMeilleure/IntermediateRepresentation/BasicBlock.cs b/ARMeilleure/IntermediateRepresentation/BasicBlock.cs deleted file mode 100644 index 7cee52e58..000000000 --- a/ARMeilleure/IntermediateRepresentation/BasicBlock.cs +++ /dev/null @@ -1,166 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Runtime.CompilerServices; - -namespace ARMeilleure.IntermediateRepresentation -{ - class BasicBlock : IEquatable, IIntrusiveListNode - { - private const uint MaxSuccessors = 2; - - private int _succCount; - private BasicBlock _succ0; - private BasicBlock _succ1; - private HashSet _domFrontiers; - - public int Index { get; set; } - public BasicBlockFrequency Frequency { get; set; } - public BasicBlock ListPrevious { get; set; } - public BasicBlock ListNext { get; set; } - public IntrusiveList Operations { get; } - public List Predecessors { get; } - public BasicBlock ImmediateDominator { get; set; } - - public int SuccessorsCount => _succCount; - - public HashSet DominanceFrontiers - { - get - { - if (_domFrontiers == null) - { - _domFrontiers = new HashSet(); - } - - return _domFrontiers; - } - } - - public BasicBlock() : this(index: -1) { } - - public BasicBlock(int index) - { - Operations = new IntrusiveList(); - Predecessors = new List(); - - Index = index; - } - - public void AddSuccessor(BasicBlock block) - { - if (block == null) - { - ThrowNull(nameof(block)); - } - - if ((uint)_succCount + 1 > MaxSuccessors) - { - ThrowSuccessorOverflow(); - } - - block.Predecessors.Add(this); - - GetSuccessorUnsafe(_succCount++) = block; - } - - public void RemoveSuccessor(int index) - { - if ((uint)index >= (uint)_succCount) - { - ThrowOutOfRange(nameof(index)); - } - - ref BasicBlock oldBlock = ref GetSuccessorUnsafe(index); - - oldBlock.Predecessors.Remove(this); - oldBlock = null; - - if (index == 0) - { - _succ0 = _succ1; - } - - _succCount--; - } - - public BasicBlock GetSuccessor(int index) - { - if ((uint)index >= (uint)_succCount) - { - ThrowOutOfRange(nameof(index)); - } - - return GetSuccessorUnsafe(index); - } - - private ref BasicBlock GetSuccessorUnsafe(int index) - { - return ref Unsafe.Add(ref _succ0, index); - } - - public void SetSuccessor(int index, BasicBlock block) - { - if (block == null) - { - ThrowNull(nameof(block)); - } - - if ((uint)index >= (uint)_succCount) - { - ThrowOutOfRange(nameof(index)); - } - - ref BasicBlock oldBlock = ref GetSuccessorUnsafe(index); - - oldBlock.Predecessors.Remove(this); - block.Predecessors.Add(this); - - oldBlock = block; - } - - public void Append(Operation node) - { - Operation last = Operations.Last; - - // Append node before terminal or to end if no terminal. - if (last == default) - { - Operations.AddLast(node); - - return; - } - - switch (last.Instruction) - { - case Instruction.Return: - case Instruction.Tailcall: - case Instruction.BranchIf: - Operations.AddBefore(last, node); - break; - - default: - Operations.AddLast(node); - break; - } - } - - private static void ThrowNull(string name) => throw new ArgumentNullException(name); - private static void ThrowOutOfRange(string name) => throw new ArgumentOutOfRangeException(name); - private static void ThrowSuccessorOverflow() => throw new OverflowException($"BasicBlock can only have {MaxSuccessors} successors."); - - public bool Equals(BasicBlock other) - { - return other == this; - } - - public override bool Equals(object obj) - { - return Equals(obj as BasicBlock); - } - - public override int GetHashCode() - { - return base.GetHashCode(); - } - } -} \ No newline at end of file diff --git a/ARMeilleure/IntermediateRepresentation/Comparison.cs b/ARMeilleure/IntermediateRepresentation/Comparison.cs deleted file mode 100644 index 628ce1051..000000000 --- a/ARMeilleure/IntermediateRepresentation/Comparison.cs +++ /dev/null @@ -1,24 +0,0 @@ -namespace ARMeilleure.IntermediateRepresentation -{ - enum Comparison - { - Equal = 0, - NotEqual = 1, - Greater = 2, - LessOrEqual = 3, - GreaterUI = 4, - LessOrEqualUI = 5, - GreaterOrEqual = 6, - Less = 7, - GreaterOrEqualUI = 8, - LessUI = 9 - } - - static class ComparisonExtensions - { - public static Comparison Invert(this Comparison comp) - { - return (Comparison)((int)comp ^ 1); - } - } -} diff --git a/ARMeilleure/IntermediateRepresentation/Instruction.cs b/ARMeilleure/IntermediateRepresentation/Instruction.cs deleted file mode 100644 index b55fe1dac..000000000 --- a/ARMeilleure/IntermediateRepresentation/Instruction.cs +++ /dev/null @@ -1,72 +0,0 @@ -namespace ARMeilleure.IntermediateRepresentation -{ - enum Instruction : ushort - { - Add, - BitwiseAnd, - BitwiseExclusiveOr, - BitwiseNot, - BitwiseOr, - BranchIf, - ByteSwap, - Call, - Compare, - CompareAndSwap, - CompareAndSwap16, - CompareAndSwap8, - ConditionalSelect, - ConvertI64ToI32, - ConvertToFP, - ConvertToFPUI, - Copy, - CountLeadingZeros, - Divide, - DivideUI, - Load, - Load16, - Load8, - LoadArgument, - MemoryBarrier, - Multiply, - Multiply64HighSI, - Multiply64HighUI, - Negate, - Return, - RotateRight, - ShiftLeft, - ShiftRightSI, - ShiftRightUI, - SignExtend16, - SignExtend32, - SignExtend8, - StackAlloc, - Store, - Store16, - Store8, - Subtract, - Tailcall, - VectorCreateScalar, - VectorExtract, - VectorExtract16, - VectorExtract8, - VectorInsert, - VectorInsert16, - VectorInsert8, - VectorOne, - VectorZero, - VectorZeroUpper64, - VectorZeroUpper96, - ZeroExtend16, - ZeroExtend32, - ZeroExtend8, - - Clobber, - Extended, - Fill, - LoadFromContext, - Phi, - Spill, - SpillArg, - StoreToContext - } -} \ No newline at end of file diff --git a/ARMeilleure/IntermediateRepresentation/Intrinsic.cs b/ARMeilleure/IntermediateRepresentation/Intrinsic.cs deleted file mode 100644 index 71bfc3bec..000000000 --- a/ARMeilleure/IntermediateRepresentation/Intrinsic.cs +++ /dev/null @@ -1,176 +0,0 @@ -namespace ARMeilleure.IntermediateRepresentation -{ - enum Intrinsic : ushort - { - X86Addpd, - X86Addps, - X86Addsd, - X86Addss, - X86Aesdec, - X86Aesdeclast, - X86Aesenc, - X86Aesenclast, - X86Aesimc, - X86Andnpd, - X86Andnps, - X86Andpd, - X86Andps, - X86Blendvpd, - X86Blendvps, - X86Cmppd, - X86Cmpps, - X86Cmpsd, - X86Cmpss, - X86Comisdeq, - X86Comisdge, - X86Comisdlt, - X86Comisseq, - X86Comissge, - X86Comisslt, - X86Crc32, - X86Crc32_16, - X86Crc32_8, - X86Cvtdq2pd, - X86Cvtdq2ps, - X86Cvtpd2dq, - X86Cvtpd2ps, - X86Cvtps2dq, - X86Cvtps2pd, - X86Cvtsd2si, - X86Cvtsd2ss, - X86Cvtsi2sd, - X86Cvtsi2si, - X86Cvtsi2ss, - X86Cvtss2sd, - X86Cvtss2si, - X86Divpd, - X86Divps, - X86Divsd, - X86Divss, - X86Haddpd, - X86Haddps, - X86Insertps, - X86Maxpd, - X86Maxps, - X86Maxsd, - X86Maxss, - X86Minpd, - X86Minps, - X86Minsd, - X86Minss, - X86Movhlps, - X86Movlhps, - X86Movss, - X86Mulpd, - X86Mulps, - X86Mulsd, - X86Mulss, - X86Mxcsrmb, - X86Mxcsrub, - X86Paddb, - X86Paddd, - X86Paddq, - X86Paddw, - X86Palignr, - X86Pand, - X86Pandn, - X86Pavgb, - X86Pavgw, - X86Pblendvb, - X86Pclmulqdq, - X86Pcmpeqb, - X86Pcmpeqd, - X86Pcmpeqq, - X86Pcmpeqw, - X86Pcmpgtb, - X86Pcmpgtd, - X86Pcmpgtq, - X86Pcmpgtw, - X86Pmaxsb, - X86Pmaxsd, - X86Pmaxsw, - X86Pmaxub, - X86Pmaxud, - X86Pmaxuw, - X86Pminsb, - X86Pminsd, - X86Pminsw, - X86Pminub, - X86Pminud, - X86Pminuw, - X86Pmovsxbw, - X86Pmovsxdq, - X86Pmovsxwd, - X86Pmovzxbw, - X86Pmovzxdq, - X86Pmovzxwd, - X86Pmulld, - X86Pmullw, - X86Popcnt, - X86Por, - X86Pshufb, - X86Pshufd, - X86Pslld, - X86Pslldq, - X86Psllq, - X86Psllw, - X86Psrad, - X86Psraw, - X86Psrld, - X86Psrlq, - X86Psrldq, - X86Psrlw, - X86Psubb, - X86Psubd, - X86Psubq, - X86Psubw, - X86Punpckhbw, - X86Punpckhdq, - X86Punpckhqdq, - X86Punpckhwd, - X86Punpcklbw, - X86Punpckldq, - X86Punpcklqdq, - X86Punpcklwd, - X86Pxor, - X86Rcpps, - X86Rcpss, - X86Roundpd, - X86Roundps, - X86Roundsd, - X86Roundss, - X86Rsqrtps, - X86Rsqrtss, - X86Sha256Msg1, - X86Sha256Msg2, - X86Sha256Rnds2, - X86Shufpd, - X86Shufps, - X86Sqrtpd, - X86Sqrtps, - X86Sqrtsd, - X86Sqrtss, - X86Subpd, - X86Subps, - X86Subsd, - X86Subss, - X86Unpckhpd, - X86Unpckhps, - X86Unpcklpd, - X86Unpcklps, - X86Vcvtph2ps, - X86Vcvtps2ph, - X86Vfmadd231ps, - X86Vfmadd231sd, - X86Vfmadd231ss, - X86Vfmsub231sd, - X86Vfmsub231ss, - X86Vfnmadd231ps, - X86Vfnmadd231sd, - X86Vfnmadd231ss, - X86Vfnmsub231sd, - X86Vfnmsub231ss, - X86Xorpd, - X86Xorps - } -} \ No newline at end of file diff --git a/ARMeilleure/IntermediateRepresentation/Operand.cs b/ARMeilleure/IntermediateRepresentation/Operand.cs deleted file mode 100644 index b3aafa7ae..000000000 --- a/ARMeilleure/IntermediateRepresentation/Operand.cs +++ /dev/null @@ -1,587 +0,0 @@ -using ARMeilleure.CodeGen.Linking; -using ARMeilleure.Common; -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Runtime.CompilerServices; - -namespace ARMeilleure.IntermediateRepresentation -{ - unsafe struct Operand : IEquatable - { - internal struct Data - { - public byte Kind; - public byte Type; - public byte SymbolType; - public byte Padding; // Unused space. - public ushort AssignmentsCount; - public ushort AssignmentsCapacity; - public uint UsesCount; - public uint UsesCapacity; - public Operation* Assignments; - public Operation* Uses; - public ulong Value; - public ulong SymbolValue; - } - - private Data* _data; - - public OperandKind Kind - { - get => (OperandKind)_data->Kind; - private set => _data->Kind = (byte)value; - } - - public OperandType Type - { - get => (OperandType)_data->Type; - private set => _data->Type = (byte)value; - } - - public ulong Value - { - get => _data->Value; - private set => _data->Value = value; - } - - public Symbol Symbol - { - get - { - Debug.Assert(Kind != OperandKind.Memory); - - return new Symbol((SymbolType)_data->SymbolType, _data->SymbolValue); - } - private set - { - Debug.Assert(Kind != OperandKind.Memory); - - if (value.Type == SymbolType.None) - { - _data->SymbolType = (byte)SymbolType.None; - } - else - { - _data->SymbolType = (byte)value.Type; - _data->SymbolValue = value.Value; - } - } - } - - public ReadOnlySpan Assignments - { - get - { - Debug.Assert(Kind != OperandKind.Memory); - - return new ReadOnlySpan(_data->Assignments, _data->AssignmentsCount); - } - } - - public ReadOnlySpan Uses - { - get - { - Debug.Assert(Kind != OperandKind.Memory); - - return new ReadOnlySpan(_data->Uses, (int)_data->UsesCount); - } - } - - public int UsesCount => (int)_data->UsesCount; - public int AssignmentsCount => _data->AssignmentsCount; - - public bool Relocatable => Symbol.Type != SymbolType.None; - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Register GetRegister() - { - Debug.Assert(Kind == OperandKind.Register); - - return new Register((int)Value & 0xffffff, (RegisterType)(Value >> 24)); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public MemoryOperand GetMemory() - { - Debug.Assert(Kind == OperandKind.Memory); - - return new MemoryOperand(this); - } - - public int GetLocalNumber() - { - Debug.Assert(Kind == OperandKind.LocalVariable); - - return (int)Value; - } - - public byte AsByte() - { - return (byte)Value; - } - - public short AsInt16() - { - return (short)Value; - } - - public int AsInt32() - { - return (int)Value; - } - - public long AsInt64() - { - return (long)Value; - } - - public float AsFloat() - { - return BitConverter.Int32BitsToSingle((int)Value); - } - - public double AsDouble() - { - return BitConverter.Int64BitsToDouble((long)Value); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal ref ulong GetValueUnsafe() - { - return ref _data->Value; - } - - internal void NumberLocal(int number) - { - if (Kind != OperandKind.LocalVariable) - { - throw new InvalidOperationException("The operand is not a local variable."); - } - - Value = (ulong)number; - } - - public void AddAssignment(Operation operation) - { - if (Kind == OperandKind.LocalVariable) - { - Add(operation, ref _data->Assignments, ref _data->AssignmentsCount, ref _data->AssignmentsCapacity); - } - else if (Kind == OperandKind.Memory) - { - MemoryOperand memOp = GetMemory(); - Operand addr = memOp.BaseAddress; - Operand index = memOp.Index; - - if (addr != default) - { - Add(operation, ref addr._data->Assignments, ref addr._data->AssignmentsCount, ref addr._data->AssignmentsCapacity); - } - - if (index != default) - { - Add(operation, ref index._data->Assignments, ref index._data->AssignmentsCount, ref index._data->AssignmentsCapacity); - } - } - } - - public void RemoveAssignment(Operation operation) - { - if (Kind == OperandKind.LocalVariable) - { - Remove(operation, ref _data->Assignments, ref _data->AssignmentsCount); - } - else if (Kind == OperandKind.Memory) - { - MemoryOperand memOp = GetMemory(); - Operand addr = memOp.BaseAddress; - Operand index = memOp.Index; - - if (addr != default) - { - Remove(operation, ref addr._data->Assignments, ref addr._data->AssignmentsCount); - } - - if (index != default) - { - Remove(operation, ref index._data->Assignments, ref index._data->AssignmentsCount); - } - } - } - - public void AddUse(Operation operation) - { - if (Kind == OperandKind.LocalVariable) - { - Add(operation, ref _data->Uses, ref _data->UsesCount, ref _data->UsesCapacity); - } - else if (Kind == OperandKind.Memory) - { - MemoryOperand memOp = GetMemory(); - Operand addr = memOp.BaseAddress; - Operand index = memOp.Index; - - if (addr != default) - { - Add(operation, ref addr._data->Uses, ref addr._data->UsesCount, ref addr._data->UsesCapacity); - } - - if (index != default) - { - Add(operation, ref index._data->Uses, ref index._data->UsesCount, ref index._data->UsesCapacity); - } - } - } - - public void RemoveUse(Operation operation) - { - if (Kind == OperandKind.LocalVariable) - { - Remove(operation, ref _data->Uses, ref _data->UsesCount); - } - else if (Kind == OperandKind.Memory) - { - MemoryOperand memOp = GetMemory(); - Operand addr = memOp.BaseAddress; - Operand index = memOp.Index; - - if (addr != default) - { - Remove(operation, ref addr._data->Uses, ref addr._data->UsesCount); - } - - if (index != default) - { - Remove(operation, ref index._data->Uses, ref index._data->UsesCount); - } - } - } - - private static void New(ref T* data, ref ushort count, ref ushort capacity, ushort initialCapacity) where T : unmanaged - { - count = 0; - capacity = initialCapacity; - data = Allocators.References.Allocate(initialCapacity); - } - - private static void New(ref T* data, ref uint count, ref uint capacity, uint initialCapacity) where T : unmanaged - { - count = 0; - capacity = initialCapacity; - data = Allocators.References.Allocate(initialCapacity); - } - - private static void Add(T item, ref T* data, ref ushort count, ref ushort capacity) where T : unmanaged - { - if (count < capacity) - { - data[(uint)count++] = item; - - return; - } - - // Could not add item in the fast path, fallback onto the slow path. - ExpandAdd(item, ref data, ref count, ref capacity); - - static void ExpandAdd(T item, ref T* data, ref ushort count, ref ushort capacity) - { - ushort newCount = checked((ushort)(count + 1)); - ushort newCapacity = (ushort)Math.Min(capacity * 2, ushort.MaxValue); - - var oldSpan = new Span(data, count); - - capacity = newCapacity; - data = Allocators.References.Allocate(capacity); - - oldSpan.CopyTo(new Span(data, count)); - - data[count] = item; - count = newCount; - } - } - - private static void Add(T item, ref T* data, ref uint count, ref uint capacity) where T : unmanaged - { - if (count < capacity) - { - data[count++] = item; - - return; - } - - // Could not add item in the fast path, fallback onto the slow path. - ExpandAdd(item, ref data, ref count, ref capacity); - - static void ExpandAdd(T item, ref T* data, ref uint count, ref uint capacity) - { - uint newCount = checked(count + 1); - uint newCapacity = (uint)Math.Min(capacity * 2, int.MaxValue); - - if (newCapacity <= capacity) - { - throw new OverflowException(); - } - - var oldSpan = new Span(data, (int)count); - - capacity = newCapacity; - data = Allocators.References.Allocate(capacity); - - oldSpan.CopyTo(new Span(data, (int)count)); - - data[count] = item; - count = newCount; - } - } - - private static void Remove(in T item, ref T* data, ref ushort count) where T : unmanaged - { - var span = new Span(data, count); - - for (int i = 0; i < span.Length; i++) - { - if (EqualityComparer.Default.Equals(span[i], item)) - { - if (i + 1 < count) - { - span.Slice(i + 1).CopyTo(span.Slice(i)); - } - - count--; - - return; - } - } - } - - private static void Remove(in T item, ref T* data, ref uint count) where T : unmanaged - { - var span = new Span(data, (int)count); - - for (int i = 0; i < span.Length; i++) - { - if (EqualityComparer.Default.Equals(span[i], item)) - { - if (i + 1 < count) - { - span.Slice(i + 1).CopyTo(span.Slice(i)); - } - - count--; - - return; - } - } - } - - public override int GetHashCode() - { - if (Kind == OperandKind.LocalVariable) - { - return base.GetHashCode(); - } - else - { - return (int)Value ^ ((int)Kind << 16) ^ ((int)Type << 20); - } - } - - public bool Equals(Operand operand) - { - return operand._data == _data; - } - - public override bool Equals(object obj) - { - return obj is Operand operand && Equals(operand); - } - - public static bool operator ==(Operand a, Operand b) - { - return a.Equals(b); - } - - public static bool operator !=(Operand a, Operand b) - { - return !a.Equals(b); - } - - public static class Factory - { - private const int InternTableSize = 256; - private const int InternTableProbeLength = 8; - - [ThreadStatic] - private static Data* _internTable; - - private static Data* InternTable - { - get - { - if (_internTable == null) - { - _internTable = (Data*)NativeAllocator.Instance.Allocate((uint)sizeof(Data) * InternTableSize); - - // Make sure the table is zeroed. - new Span(_internTable, InternTableSize).Clear(); - } - - return _internTable; - } - } - - private static Operand Make(OperandKind kind, OperandType type, ulong value, Symbol symbol = default) - { - Debug.Assert(kind != OperandKind.None); - - Data* data = null; - - // If constant or register, then try to look up in the intern table before allocating. - if (kind == OperandKind.Constant || kind == OperandKind.Register) - { - uint hash = (uint)HashCode.Combine(kind, type, value); - - // Look in the next InternTableProbeLength slots for a match. - for (uint i = 0; i < InternTableProbeLength; i++) - { - Operand interned = new(); - interned._data = &InternTable[(hash + i) % InternTableSize]; - - // If slot matches the allocation request then return that slot. - if (interned.Kind == kind && interned.Type == type && interned.Value == value && interned.Symbol == symbol) - { - return interned; - } - // Otherwise if the slot is not occupied, we store in that slot. - else if (interned.Kind == OperandKind.None) - { - data = interned._data; - - break; - } - } - } - - // If we could not get a slot from the intern table, we allocate somewhere else and store there. - if (data == null) - { - data = Allocators.Operands.Allocate(); - } - - *data = default; - - Operand result = new(); - result._data = data; - result.Value = value; - result.Kind = kind; - result.Type = type; - - if (kind != OperandKind.Memory) - { - result.Symbol = symbol; - } - - // If local variable, then the use and def list is initialized with default sizes. - if (kind == OperandKind.LocalVariable) - { - New(ref result._data->Assignments, ref result._data->AssignmentsCount, ref result._data->AssignmentsCapacity, 1); - New(ref result._data->Uses, ref result._data->UsesCount, ref result._data->UsesCapacity, 4); - } - - return result; - } - - public static Operand Const(OperandType type, long value) - { - Debug.Assert(type is OperandType.I32 or OperandType.I64); - - return type == OperandType.I32 ? Const((int)value) : Const(value); - } - - public static Operand Const(bool value) - { - return Const(value ? 1 : 0); - } - - public static Operand Const(int value) - { - return Const((uint)value); - } - - public static Operand Const(uint value) - { - return Make(OperandKind.Constant, OperandType.I32, value); - } - - public static Operand Const(long value) - { - return Const(value, symbol: default); - } - - public static Operand Const(ref T reference, Symbol symbol = default) - { - return Const((long)Unsafe.AsPointer(ref reference), symbol); - } - - public static Operand Const(long value, Symbol symbol) - { - return Make(OperandKind.Constant, OperandType.I64, (ulong)value, symbol); - } - - public static Operand Const(ulong value) - { - return Make(OperandKind.Constant, OperandType.I64, value); - } - - public static Operand ConstF(float value) - { - return Make(OperandKind.Constant, OperandType.FP32, (ulong)BitConverter.SingleToInt32Bits(value)); - } - - public static Operand ConstF(double value) - { - return Make(OperandKind.Constant, OperandType.FP64, (ulong)BitConverter.DoubleToInt64Bits(value)); - } - - public static Operand Label() - { - return Make(OperandKind.Label, OperandType.None, 0); - } - - public static Operand Local(OperandType type) - { - return Make(OperandKind.LocalVariable, type, 0); - } - - public static Operand Register(int index, RegisterType regType, OperandType type) - { - return Make(OperandKind.Register, type, (ulong)((int)regType << 24 | index)); - } - - public static Operand Undef() - { - return Make(OperandKind.Undefined, OperandType.None, 0); - } - - public static Operand MemoryOp( - OperandType type, - Operand baseAddress, - Operand index = default, - Multiplier scale = Multiplier.x1, - int displacement = 0) - { - Operand result = Make(OperandKind.Memory, type, 0); - - MemoryOperand memory = result.GetMemory(); - memory.BaseAddress = baseAddress; - memory.Index = index; - memory.Scale = scale; - memory.Displacement = displacement; - - return result; - } - } - } -} \ No newline at end of file diff --git a/ARMeilleure/IntermediateRepresentation/OperandType.cs b/ARMeilleure/IntermediateRepresentation/OperandType.cs deleted file mode 100644 index bfdf5130c..000000000 --- a/ARMeilleure/IntermediateRepresentation/OperandType.cs +++ /dev/null @@ -1,51 +0,0 @@ -using System; - -namespace ARMeilleure.IntermediateRepresentation -{ - enum OperandType - { - None, - I32, - I64, - FP32, - FP64, - V128 - } - - static class OperandTypeExtensions - { - public static bool IsInteger(this OperandType type) - { - return type == OperandType.I32 || - type == OperandType.I64; - } - - public static RegisterType ToRegisterType(this OperandType type) - { - switch (type) - { - case OperandType.FP32: return RegisterType.Vector; - case OperandType.FP64: return RegisterType.Vector; - case OperandType.I32: return RegisterType.Integer; - case OperandType.I64: return RegisterType.Integer; - case OperandType.V128: return RegisterType.Vector; - } - - throw new InvalidOperationException($"Invalid operand type \"{type}\"."); - } - - public static int GetSizeInBytes(this OperandType type) - { - switch (type) - { - case OperandType.FP32: return 4; - case OperandType.FP64: return 8; - case OperandType.I32: return 4; - case OperandType.I64: return 8; - case OperandType.V128: return 16; - } - - throw new InvalidOperationException($"Invalid operand type \"{type}\"."); - } - } -} \ No newline at end of file diff --git a/ARMeilleure/IntermediateRepresentation/Operation.cs b/ARMeilleure/IntermediateRepresentation/Operation.cs deleted file mode 100644 index c71e143c3..000000000 --- a/ARMeilleure/IntermediateRepresentation/Operation.cs +++ /dev/null @@ -1,376 +0,0 @@ -using System; -using System.Diagnostics; -using System.Runtime.CompilerServices; - -namespace ARMeilleure.IntermediateRepresentation -{ - unsafe struct Operation : IEquatable, IIntrusiveListNode - { - internal struct Data - { - public ushort Instruction; - public ushort Intrinsic; - public ushort SourcesCount; - public ushort DestinationsCount; - public Operation ListPrevious; - public Operation ListNext; - public Operand* Destinations; - public Operand* Sources; - } - - private Data* _data; - - public Instruction Instruction - { - get => (Instruction)_data->Instruction; - private set => _data->Instruction = (ushort)value; - } - - public Intrinsic Intrinsic - { - get => (Intrinsic)_data->Intrinsic; - private set => _data->Intrinsic = (ushort)value; - } - - public Operation ListPrevious - { - get => _data->ListPrevious; - set => _data->ListPrevious = value; - } - - public Operation ListNext - { - get => _data->ListNext; - set => _data->ListNext = value; - } - - public Operand Destination - { - get => _data->DestinationsCount != 0 ? GetDestination(0) : default; - set => SetDestination(value); - } - - public int DestinationsCount => _data->DestinationsCount; - public int SourcesCount => _data->SourcesCount; - - internal Span DestinationsUnsafe => new(_data->Destinations, _data->DestinationsCount); - internal Span SourcesUnsafe => new(_data->Sources, _data->SourcesCount); - - public PhiOperation AsPhi() - { - Debug.Assert(Instruction == Instruction.Phi); - - return new PhiOperation(this); - } - - public Operand GetDestination(int index) - { - return DestinationsUnsafe[index]; - } - - public Operand GetSource(int index) - { - return SourcesUnsafe[index]; - } - - public void SetDestination(int index, Operand dest) - { - ref Operand curDest = ref DestinationsUnsafe[index]; - - RemoveAssignment(curDest); - AddAssignment(dest); - - curDest = dest; - } - - public void SetSource(int index, Operand src) - { - ref Operand curSrc = ref SourcesUnsafe[index]; - - RemoveUse(curSrc); - AddUse(src); - - curSrc = src; - } - - private void RemoveOldDestinations() - { - for (int i = 0; i < _data->DestinationsCount; i++) - { - RemoveAssignment(_data->Destinations[i]); - } - } - - public void SetDestination(Operand dest) - { - RemoveOldDestinations(); - - if (dest == default) - { - _data->DestinationsCount = 0; - } - else - { - EnsureCapacity(ref _data->Destinations, ref _data->DestinationsCount, 1); - - _data->Destinations[0] = dest; - - AddAssignment(dest); - } - } - - public void SetDestinations(Operand[] dests) - { - RemoveOldDestinations(); - - EnsureCapacity(ref _data->Destinations, ref _data->DestinationsCount, dests.Length); - - for (int index = 0; index < dests.Length; index++) - { - Operand newOp = dests[index]; - - _data->Destinations[index] = newOp; - - AddAssignment(newOp); - } - } - - private void RemoveOldSources() - { - for (int index = 0; index < _data->SourcesCount; index++) - { - RemoveUse(_data->Sources[index]); - } - } - - public void SetSource(Operand src) - { - RemoveOldSources(); - - if (src == default) - { - _data->SourcesCount = 0; - } - else - { - EnsureCapacity(ref _data->Sources, ref _data->SourcesCount, 1); - - _data->Sources[0] = src; - - AddUse(src); - } - } - - public void SetSources(Operand[] srcs) - { - RemoveOldSources(); - - EnsureCapacity(ref _data->Sources, ref _data->SourcesCount, srcs.Length); - - for (int index = 0; index < srcs.Length; index++) - { - Operand newOp = srcs[index]; - - _data->Sources[index] = newOp; - - AddUse(newOp); - } - } - - public void TurnIntoCopy(Operand source) - { - Instruction = Instruction.Copy; - - SetSource(source); - } - - private void AddAssignment(Operand op) - { - if (op != default) - { - op.AddAssignment(this); - } - } - - private void RemoveAssignment(Operand op) - { - if (op != default) - { - op.RemoveAssignment(this); - } - } - - private void AddUse(Operand op) - { - if (op != default) - { - op.AddUse(this); - } - } - - private void RemoveUse(Operand op) - { - if (op != default) - { - op.RemoveUse(this); - } - } - - public bool Equals(Operation operation) - { - return operation._data == _data; - } - - public override bool Equals(object obj) - { - return obj is Operation operation && Equals(operation); - } - - public override int GetHashCode() - { - return HashCode.Combine((IntPtr)_data); - } - - public static bool operator ==(Operation a, Operation b) - { - return a.Equals(b); - } - - public static bool operator !=(Operation a, Operation b) - { - return !a.Equals(b); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static void EnsureCapacity(ref Operand* list, ref ushort capacity, int newCapacity) - { - if (newCapacity > ushort.MaxValue) - { - ThrowOverflow(newCapacity); - } - // We only need to allocate a new buffer if we're increasing the size. - else if (newCapacity > capacity) - { - list = Allocators.References.Allocate((uint)newCapacity); - } - - capacity = (ushort)newCapacity; - } - - private static void ThrowOverflow(int count) => - throw new OverflowException($"Exceeded maximum size for Source or Destinations. Required {count}."); - - public static class Factory - { - private static Operation Make(Instruction inst, int destCount, int srcCount) - { - Data* data = Allocators.Operations.Allocate(); - *data = default; - - Operation result = new(); - result._data = data; - result.Instruction = inst; - - EnsureCapacity(ref result._data->Destinations, ref result._data->DestinationsCount, destCount); - EnsureCapacity(ref result._data->Sources, ref result._data->SourcesCount, srcCount); - - result.DestinationsUnsafe.Clear(); - result.SourcesUnsafe.Clear(); - - return result; - } - - public static Operation Operation(Instruction inst, Operand dest) - { - Operation result = Make(inst, 0, 0); - result.SetDestination(dest); - return result; - } - - public static Operation Operation(Instruction inst, Operand dest, Operand src0) - { - Operation result = Make(inst, 0, 1); - result.SetDestination(dest); - result.SetSource(0, src0); - return result; - } - - public static Operation Operation(Instruction inst, Operand dest, Operand src0, Operand src1) - { - Operation result = Make(inst, 0, 2); - result.SetDestination(dest); - result.SetSource(0, src0); - result.SetSource(1, src1); - return result; - } - - public static Operation Operation(Instruction inst, Operand dest, Operand src0, Operand src1, Operand src2) - { - Operation result = Make(inst, 0, 3); - result.SetDestination(dest); - result.SetSource(0, src0); - result.SetSource(1, src1); - result.SetSource(2, src2); - return result; - } - - public static Operation Operation(Instruction inst, Operand dest, int srcCount) - { - Operation result = Make(inst, 0, srcCount); - result.SetDestination(dest); - return result; - } - - public static Operation Operation(Instruction inst, Operand dest, Operand[] srcs) - { - Operation result = Make(inst, 0, srcs.Length); - - result.SetDestination(dest); - - for (int index = 0; index < srcs.Length; index++) - { - result.SetSource(index, srcs[index]); - } - - return result; - } - - public static Operation Operation(Intrinsic intrin, Operand dest, params Operand[] srcs) - { - Operation result = Make(Instruction.Extended, 0, srcs.Length); - - result.Intrinsic = intrin; - result.SetDestination(dest); - - for (int index = 0; index < srcs.Length; index++) - { - result.SetSource(index, srcs[index]); - } - - return result; - } - - public static Operation Operation(Instruction inst, Operand[] dests, Operand[] srcs) - { - Operation result = Make(inst, dests.Length, srcs.Length); - - for (int index = 0; index < dests.Length; index++) - { - result.SetDestination(index, dests[index]); - } - - for (int index = 0; index < srcs.Length; index++) - { - result.SetSource(index, srcs[index]); - } - - return result; - } - - public static Operation PhiOperation(Operand dest, int srcCount) - { - return Operation(Instruction.Phi, dest, srcCount * 2); - } - } - } -} \ No newline at end of file diff --git a/ARMeilleure/IntermediateRepresentation/Register.cs b/ARMeilleure/IntermediateRepresentation/Register.cs deleted file mode 100644 index 745b31538..000000000 --- a/ARMeilleure/IntermediateRepresentation/Register.cs +++ /dev/null @@ -1,43 +0,0 @@ -using System; - -namespace ARMeilleure.IntermediateRepresentation -{ - struct Register : IEquatable - { - public int Index { get; } - - public RegisterType Type { get; } - - public Register(int index, RegisterType type) - { - Index = index; - Type = type; - } - - public override int GetHashCode() - { - return (ushort)Index | ((int)Type << 16); - } - - public static bool operator ==(Register x, Register y) - { - return x.Equals(y); - } - - public static bool operator !=(Register x, Register y) - { - return !x.Equals(y); - } - - public override bool Equals(object obj) - { - return obj is Register reg && Equals(reg); - } - - public bool Equals(Register other) - { - return other.Index == Index && - other.Type == Type; - } - } -} \ No newline at end of file diff --git a/ARMeilleure/IntermediateRepresentation/RegisterType.cs b/ARMeilleure/IntermediateRepresentation/RegisterType.cs deleted file mode 100644 index 88ac6c124..000000000 --- a/ARMeilleure/IntermediateRepresentation/RegisterType.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace ARMeilleure.IntermediateRepresentation -{ - enum RegisterType - { - Integer, - Vector, - Flag, - FpFlag - } -} \ No newline at end of file diff --git a/ARMeilleure/Optimizations.cs b/ARMeilleure/Optimizations.cs deleted file mode 100644 index 19193971c..000000000 --- a/ARMeilleure/Optimizations.cs +++ /dev/null @@ -1,46 +0,0 @@ -using ARMeilleure.CodeGen.X86; - -namespace ARMeilleure -{ - public static class Optimizations - { - public static bool FastFP { get; set; } = true; - - public static bool AllowLcqInFunctionTable { get; set; } = true; - public static bool UseUnmanagedDispatchLoop { get; set; } = true; - - public static bool UseSseIfAvailable { get; set; } = true; - public static bool UseSse2IfAvailable { get; set; } = true; - public static bool UseSse3IfAvailable { get; set; } = true; - public static bool UseSsse3IfAvailable { get; set; } = true; - public static bool UseSse41IfAvailable { get; set; } = true; - public static bool UseSse42IfAvailable { get; set; } = true; - public static bool UsePopCntIfAvailable { get; set; } = true; - public static bool UseAvxIfAvailable { get; set; } = true; - public static bool UseF16cIfAvailable { get; set; } = true; - public static bool UseFmaIfAvailable { get; set; } = true; - public static bool UseAesniIfAvailable { get; set; } = true; - public static bool UsePclmulqdqIfAvailable { get; set; } = true; - public static bool UseShaIfAvailable { get; set; } = true; - - public static bool ForceLegacySse - { - get => HardwareCapabilities.ForceLegacySse; - set => HardwareCapabilities.ForceLegacySse = value; - } - - internal static bool UseSse => UseSseIfAvailable && HardwareCapabilities.SupportsSse; - internal static bool UseSse2 => UseSse2IfAvailable && HardwareCapabilities.SupportsSse2; - internal static bool UseSse3 => UseSse3IfAvailable && HardwareCapabilities.SupportsSse3; - internal static bool UseSsse3 => UseSsse3IfAvailable && HardwareCapabilities.SupportsSsse3; - internal static bool UseSse41 => UseSse41IfAvailable && HardwareCapabilities.SupportsSse41; - internal static bool UseSse42 => UseSse42IfAvailable && HardwareCapabilities.SupportsSse42; - internal static bool UsePopCnt => UsePopCntIfAvailable && HardwareCapabilities.SupportsPopcnt; - internal static bool UseAvx => UseAvxIfAvailable && HardwareCapabilities.SupportsAvx && !ForceLegacySse; - internal static bool UseF16c => UseF16cIfAvailable && HardwareCapabilities.SupportsF16c; - internal static bool UseFma => UseFmaIfAvailable && HardwareCapabilities.SupportsFma; - internal static bool UseAesni => UseAesniIfAvailable && HardwareCapabilities.SupportsAesni; - internal static bool UsePclmulqdq => UsePclmulqdqIfAvailable && HardwareCapabilities.SupportsPclmulqdq; - internal static bool UseSha => UseShaIfAvailable && HardwareCapabilities.SupportsSha; - } -} \ No newline at end of file diff --git a/ARMeilleure/Signal/NativeSignalHandler.cs b/ARMeilleure/Signal/NativeSignalHandler.cs deleted file mode 100644 index 0257f4403..000000000 --- a/ARMeilleure/Signal/NativeSignalHandler.cs +++ /dev/null @@ -1,338 +0,0 @@ -using ARMeilleure.IntermediateRepresentation; -using ARMeilleure.Translation; -using System; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -using static ARMeilleure.IntermediateRepresentation.Operand.Factory; - -namespace ARMeilleure.Signal -{ - [StructLayout(LayoutKind.Sequential, Pack = 1)] - struct SignalHandlerRange - { - public int IsActive; - public nuint RangeAddress; - public nuint RangeEndAddress; - public IntPtr ActionPointer; - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - struct SignalHandlerConfig - { - /// - /// The byte offset of the faulting address in the SigInfo or ExceptionRecord struct. - /// - public int StructAddressOffset; - - /// - /// The byte offset of the write flag in the SigInfo or ExceptionRecord struct. - /// - public int StructWriteOffset; - - /// - /// The sigaction handler that was registered before this one. (unix only) - /// - public nuint UnixOldSigaction; - - /// - /// The type of the previous sigaction. True for the 3 argument variant. (unix only) - /// - public int UnixOldSigaction3Arg; - - public SignalHandlerRange Range0; - public SignalHandlerRange Range1; - public SignalHandlerRange Range2; - public SignalHandlerRange Range3; - public SignalHandlerRange Range4; - public SignalHandlerRange Range5; - public SignalHandlerRange Range6; - public SignalHandlerRange Range7; - } - - public static class NativeSignalHandler - { - private delegate void UnixExceptionHandler(int sig, IntPtr info, IntPtr ucontext); - [UnmanagedFunctionPointer(CallingConvention.Winapi)] - private delegate int VectoredExceptionHandler(IntPtr exceptionInfo); - - private const int MaxTrackedRanges = 8; - - private const int StructAddressOffset = 0; - private const int StructWriteOffset = 4; - private const int UnixOldSigaction = 8; - private const int UnixOldSigaction3Arg = 16; - private const int RangeOffset = 20; - - private const int EXCEPTION_CONTINUE_SEARCH = 0; - private const int EXCEPTION_CONTINUE_EXECUTION = -1; - - private const uint EXCEPTION_ACCESS_VIOLATION = 0xc0000005; - - private const ulong PageSize = 0x1000; - private const ulong PageMask = PageSize - 1; - - private static IntPtr _handlerConfig; - private static IntPtr _signalHandlerPtr; - private static IntPtr _signalHandlerHandle; - - private static readonly object _lock = new object(); - private static bool _initialized; - - static NativeSignalHandler() - { - _handlerConfig = Marshal.AllocHGlobal(Unsafe.SizeOf()); - ref SignalHandlerConfig config = ref GetConfigRef(); - - config = new SignalHandlerConfig(); - } - - public static void InitializeSignalHandler() - { - if (_initialized) return; - - lock (_lock) - { - if (_initialized) return; - - bool unix = OperatingSystem.IsLinux() || OperatingSystem.IsMacOS(); - ref SignalHandlerConfig config = ref GetConfigRef(); - - if (unix) - { - // Unix siginfo struct locations. - // NOTE: These are incredibly likely to be different between kernel version and architectures. - - config.StructAddressOffset = OperatingSystem.IsMacOS() ? 24 : 16; // si_addr - config.StructWriteOffset = 8; // si_code - - _signalHandlerPtr = Marshal.GetFunctionPointerForDelegate(GenerateUnixSignalHandler(_handlerConfig)); - - SigAction old = UnixSignalHandlerRegistration.RegisterExceptionHandler(_signalHandlerPtr); - config.UnixOldSigaction = (nuint)(ulong)old.sa_handler; - config.UnixOldSigaction3Arg = old.sa_flags & 4; - } - else - { - config.StructAddressOffset = 40; // ExceptionInformation1 - config.StructWriteOffset = 32; // ExceptionInformation0 - - _signalHandlerPtr = Marshal.GetFunctionPointerForDelegate(GenerateWindowsSignalHandler(_handlerConfig)); - - _signalHandlerHandle = WindowsSignalHandlerRegistration.RegisterExceptionHandler(_signalHandlerPtr); - } - - _initialized = true; - } - } - - private static unsafe ref SignalHandlerConfig GetConfigRef() - { - return ref Unsafe.AsRef((void*)_handlerConfig); - } - - public static unsafe bool AddTrackedRegion(nuint address, nuint endAddress, IntPtr action) - { - var ranges = &((SignalHandlerConfig*)_handlerConfig)->Range0; - - for (int i = 0; i < MaxTrackedRanges; i++) - { - if (ranges[i].IsActive == 0) - { - ranges[i].RangeAddress = address; - ranges[i].RangeEndAddress = endAddress; - ranges[i].ActionPointer = action; - ranges[i].IsActive = 1; - - return true; - } - } - - return false; - } - - public static unsafe bool RemoveTrackedRegion(nuint address) - { - var ranges = &((SignalHandlerConfig*)_handlerConfig)->Range0; - - for (int i = 0; i < MaxTrackedRanges; i++) - { - if (ranges[i].IsActive == 1 && ranges[i].RangeAddress == address) - { - ranges[i].IsActive = 0; - - return true; - } - } - - return false; - } - - private static Operand EmitGenericRegionCheck(EmitterContext context, IntPtr signalStructPtr, Operand faultAddress, Operand isWrite) - { - Operand inRegionLocal = context.AllocateLocal(OperandType.I32); - context.Copy(inRegionLocal, Const(0)); - - Operand endLabel = Label(); - - for (int i = 0; i < MaxTrackedRanges; i++) - { - ulong rangeBaseOffset = (ulong)(RangeOffset + i * Unsafe.SizeOf()); - - Operand nextLabel = Label(); - - Operand isActive = context.Load(OperandType.I32, Const((ulong)signalStructPtr + rangeBaseOffset)); - - context.BranchIfFalse(nextLabel, isActive); - - Operand rangeAddress = context.Load(OperandType.I64, Const((ulong)signalStructPtr + rangeBaseOffset + 4)); - Operand rangeEndAddress = context.Load(OperandType.I64, Const((ulong)signalStructPtr + rangeBaseOffset + 12)); - - // Is the fault address within this tracked region? - Operand inRange = context.BitwiseAnd( - context.ICompare(faultAddress, rangeAddress, Comparison.GreaterOrEqualUI), - context.ICompare(faultAddress, rangeEndAddress, Comparison.LessUI) - ); - - // Only call tracking if in range. - context.BranchIfFalse(nextLabel, inRange, BasicBlockFrequency.Cold); - - Operand offset = context.BitwiseAnd(context.Subtract(faultAddress, rangeAddress), Const(~PageMask)); - - // Call the tracking action, with the pointer's relative offset to the base address. - Operand trackingActionPtr = context.Load(OperandType.I64, Const((ulong)signalStructPtr + rangeBaseOffset + 20)); - - context.Copy(inRegionLocal, Const(0)); - - Operand skipActionLabel = Label(); - - // Tracking action should be non-null to call it, otherwise assume false return. - context.BranchIfFalse(skipActionLabel, trackingActionPtr); - Operand result = context.Call(trackingActionPtr, OperandType.I32, offset, Const(PageSize), isWrite, Const(0)); - context.Copy(inRegionLocal, result); - - context.MarkLabel(skipActionLabel); - - // If the tracking action returns false or does not exist, it might be an invalid access due to a partial overlap on Windows. - if (OperatingSystem.IsWindows()) - { - context.BranchIfTrue(endLabel, inRegionLocal); - - context.Copy(inRegionLocal, WindowsPartialUnmapHandler.EmitRetryFromAccessViolation(context)); - } - - context.Branch(endLabel); - - context.MarkLabel(nextLabel); - } - - context.MarkLabel(endLabel); - - return context.Copy(inRegionLocal); - } - - private static UnixExceptionHandler GenerateUnixSignalHandler(IntPtr signalStructPtr) - { - EmitterContext context = new EmitterContext(); - - // (int sig, SigInfo* sigInfo, void* ucontext) - Operand sigInfoPtr = context.LoadArgument(OperandType.I64, 1); - - Operand structAddressOffset = context.Load(OperandType.I64, Const((ulong)signalStructPtr + StructAddressOffset)); - Operand structWriteOffset = context.Load(OperandType.I64, Const((ulong)signalStructPtr + StructWriteOffset)); - - Operand faultAddress = context.Load(OperandType.I64, context.Add(sigInfoPtr, context.ZeroExtend32(OperandType.I64, structAddressOffset))); - Operand writeFlag = context.Load(OperandType.I64, context.Add(sigInfoPtr, context.ZeroExtend32(OperandType.I64, structWriteOffset))); - - Operand isWrite = context.ICompareNotEqual(writeFlag, Const(0L)); // Normalize to 0/1. - - Operand isInRegion = EmitGenericRegionCheck(context, signalStructPtr, faultAddress, isWrite); - - Operand endLabel = Label(); - - context.BranchIfTrue(endLabel, isInRegion); - - Operand unixOldSigaction = context.Load(OperandType.I64, Const((ulong)signalStructPtr + UnixOldSigaction)); - Operand unixOldSigaction3Arg = context.Load(OperandType.I64, Const((ulong)signalStructPtr + UnixOldSigaction3Arg)); - Operand threeArgLabel = Label(); - - context.BranchIfTrue(threeArgLabel, unixOldSigaction3Arg); - - context.Call(unixOldSigaction, OperandType.None, context.LoadArgument(OperandType.I32, 0)); - context.Branch(endLabel); - - context.MarkLabel(threeArgLabel); - - context.Call(unixOldSigaction, - OperandType.None, - context.LoadArgument(OperandType.I32, 0), - sigInfoPtr, - context.LoadArgument(OperandType.I64, 2) - ); - - context.MarkLabel(endLabel); - - context.Return(); - - ControlFlowGraph cfg = context.GetControlFlowGraph(); - - OperandType[] argTypes = new OperandType[] { OperandType.I32, OperandType.I64, OperandType.I64 }; - - return Compiler.Compile(cfg, argTypes, OperandType.None, CompilerOptions.HighCq).Map(); - } - - private static VectoredExceptionHandler GenerateWindowsSignalHandler(IntPtr signalStructPtr) - { - EmitterContext context = new EmitterContext(); - - // (ExceptionPointers* exceptionInfo) - Operand exceptionInfoPtr = context.LoadArgument(OperandType.I64, 0); - Operand exceptionRecordPtr = context.Load(OperandType.I64, exceptionInfoPtr); - - // First thing's first - this catches a number of exceptions, but we only want access violations. - Operand validExceptionLabel = Label(); - - Operand exceptionCode = context.Load(OperandType.I32, exceptionRecordPtr); - - context.BranchIf(validExceptionLabel, exceptionCode, Const(EXCEPTION_ACCESS_VIOLATION), Comparison.Equal); - - context.Return(Const(EXCEPTION_CONTINUE_SEARCH)); // Don't handle this one. - - context.MarkLabel(validExceptionLabel); - - // Next, read the address of the invalid access, and whether it is a write or not. - - Operand structAddressOffset = context.Load(OperandType.I32, Const((ulong)signalStructPtr + StructAddressOffset)); - Operand structWriteOffset = context.Load(OperandType.I32, Const((ulong)signalStructPtr + StructWriteOffset)); - - Operand faultAddress = context.Load(OperandType.I64, context.Add(exceptionRecordPtr, context.ZeroExtend32(OperandType.I64, structAddressOffset))); - Operand writeFlag = context.Load(OperandType.I64, context.Add(exceptionRecordPtr, context.ZeroExtend32(OperandType.I64, structWriteOffset))); - - Operand isWrite = context.ICompareNotEqual(writeFlag, Const(0L)); // Normalize to 0/1. - - Operand isInRegion = EmitGenericRegionCheck(context, signalStructPtr, faultAddress, isWrite); - - Operand endLabel = Label(); - - // If the region check result is false, then run the next vectored exception handler. - - context.BranchIfTrue(endLabel, isInRegion); - - context.Return(Const(EXCEPTION_CONTINUE_SEARCH)); - - context.MarkLabel(endLabel); - - // Otherwise, return to execution. - - context.Return(Const(EXCEPTION_CONTINUE_EXECUTION)); - - // Compile and return the function. - - ControlFlowGraph cfg = context.GetControlFlowGraph(); - - OperandType[] argTypes = new OperandType[] { OperandType.I64 }; - - return Compiler.Compile(cfg, argTypes, OperandType.I32, CompilerOptions.HighCq).Map(); - } - } -} diff --git a/ARMeilleure/Signal/UnixSignalHandlerRegistration.cs b/ARMeilleure/Signal/UnixSignalHandlerRegistration.cs deleted file mode 100644 index 12bda3de2..000000000 --- a/ARMeilleure/Signal/UnixSignalHandlerRegistration.cs +++ /dev/null @@ -1,68 +0,0 @@ -using System; -using System.Runtime.InteropServices; - -namespace ARMeilleure.Signal -{ - [StructLayout(LayoutKind.Sequential, Pack = 1)] - unsafe struct SigSet - { - fixed long sa_mask[16]; - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - struct SigAction - { - public IntPtr sa_handler; - public SigSet sa_mask; - public int sa_flags; - public IntPtr sa_restorer; - } - - static class UnixSignalHandlerRegistration - { - private const int SIGSEGV = 11; - private const int SIGBUS = 10; - private const int SA_SIGINFO = 0x00000004; - - [DllImport("libc", SetLastError = true)] - private static extern int sigaction(int signum, ref SigAction sigAction, out SigAction oldAction); - - [DllImport("libc", SetLastError = true)] - private static extern int sigemptyset(ref SigSet set); - - public static SigAction RegisterExceptionHandler(IntPtr action) - { - SigAction sig = new SigAction - { - sa_handler = action, - sa_flags = SA_SIGINFO - }; - - sigemptyset(ref sig.sa_mask); - - int result = sigaction(SIGSEGV, ref sig, out SigAction old); - - if (result != 0) - { - throw new InvalidOperationException($"Could not register SIGSEGV sigaction. Error: {result}"); - } - - if (OperatingSystem.IsMacOS()) - { - result = sigaction(SIGBUS, ref sig, out SigAction oldb); - - if (result != 0) - { - throw new InvalidOperationException($"Could not register SIGBUS sigaction. Error: {result}"); - } - } - - return old; - } - - public static bool RestoreExceptionHandler(SigAction oldAction) - { - return sigaction(SIGSEGV, ref oldAction, out SigAction _) == 0 && (!OperatingSystem.IsMacOS() || sigaction(SIGBUS, ref oldAction, out SigAction _) == 0); - } - } -} diff --git a/ARMeilleure/Signal/WindowsSignalHandlerRegistration.cs b/ARMeilleure/Signal/WindowsSignalHandlerRegistration.cs deleted file mode 100644 index b74f1098b..000000000 --- a/ARMeilleure/Signal/WindowsSignalHandlerRegistration.cs +++ /dev/null @@ -1,44 +0,0 @@ -using System; -using System.Runtime.InteropServices; - -namespace ARMeilleure.Signal -{ - unsafe class WindowsSignalHandlerRegistration - { - [DllImport("kernel32.dll")] - private static extern IntPtr AddVectoredExceptionHandler(uint first, IntPtr handler); - - [DllImport("kernel32.dll")] - private static extern ulong RemoveVectoredExceptionHandler(IntPtr handle); - - [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Ansi)] - static extern IntPtr LoadLibrary([MarshalAs(UnmanagedType.LPStr)] string lpFileName); - - [DllImport("kernel32.dll", CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError = true)] - private static extern IntPtr GetProcAddress(IntPtr hModule, string procName); - - private static IntPtr _getCurrentThreadIdPtr; - - public static IntPtr RegisterExceptionHandler(IntPtr action) - { - return AddVectoredExceptionHandler(1, action); - } - - public static bool RemoveExceptionHandler(IntPtr handle) - { - return RemoveVectoredExceptionHandler(handle) != 0; - } - - public static IntPtr GetCurrentThreadIdFunc() - { - if (_getCurrentThreadIdPtr == IntPtr.Zero) - { - IntPtr handle = LoadLibrary("kernel32.dll"); - - _getCurrentThreadIdPtr = GetProcAddress(handle, "GetCurrentThreadId"); - } - - return _getCurrentThreadIdPtr; - } - } -} diff --git a/ARMeilleure/State/Aarch32Mode.cs b/ARMeilleure/State/Aarch32Mode.cs deleted file mode 100644 index 395e288aa..000000000 --- a/ARMeilleure/State/Aarch32Mode.cs +++ /dev/null @@ -1,15 +0,0 @@ -namespace ARMeilleure.State -{ - enum Aarch32Mode - { - User = 0b10000, - Fiq = 0b10001, - Irq = 0b10010, - Supervisor = 0b10011, - Monitor = 0b10110, - Abort = 0b10111, - Hypervisor = 0b11010, - Undefined = 0b11011, - System = 0b11111 - } -} \ No newline at end of file diff --git a/ARMeilleure/State/ExecutionMode.cs b/ARMeilleure/State/ExecutionMode.cs deleted file mode 100644 index 29154a255..000000000 --- a/ARMeilleure/State/ExecutionMode.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace ARMeilleure.State -{ - enum ExecutionMode : int - { - Aarch32Arm = 0, - Aarch32Thumb = 1, - Aarch64 = 2 - } -} \ No newline at end of file diff --git a/ARMeilleure/State/FPException.cs b/ARMeilleure/State/FPException.cs deleted file mode 100644 index e24e07af1..000000000 --- a/ARMeilleure/State/FPException.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace ARMeilleure.State -{ - enum FPException - { - InvalidOp = 0, - DivideByZero = 1, - Overflow = 2, - Underflow = 3, - Inexact = 4, - InputDenorm = 7 - } -} diff --git a/ARMeilleure/State/FPRoundingMode.cs b/ARMeilleure/State/FPRoundingMode.cs deleted file mode 100644 index ee4f87668..000000000 --- a/ARMeilleure/State/FPRoundingMode.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace ARMeilleure.State -{ - public enum FPRoundingMode - { - ToNearest = 0, - TowardsPlusInfinity = 1, - TowardsMinusInfinity = 2, - TowardsZero = 3 - } -} diff --git a/ARMeilleure/State/FPSCR.cs b/ARMeilleure/State/FPSCR.cs deleted file mode 100644 index d6d2fc26a..000000000 --- a/ARMeilleure/State/FPSCR.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System; - -namespace ARMeilleure.State -{ - [Flags] - public enum FPSCR : uint - { - V = 1u << 28, - C = 1u << 29, - Z = 1u << 30, - N = 1u << 31, - - Mask = N | Z | C | V | FPSR.Mask | FPCR.Mask // 0xFFC09F9Fu - } -} diff --git a/ARMeilleure/State/RegisterAlias.cs b/ARMeilleure/State/RegisterAlias.cs deleted file mode 100644 index 7ebfa2753..000000000 --- a/ARMeilleure/State/RegisterAlias.cs +++ /dev/null @@ -1,42 +0,0 @@ -namespace ARMeilleure.State -{ - static class RegisterAlias - { - public const int R8Usr = 8; - public const int R9Usr = 9; - public const int R10Usr = 10; - public const int R11Usr = 11; - public const int R12Usr = 12; - public const int SpUsr = 13; - public const int LrUsr = 14; - - public const int SpHyp = 15; - - public const int LrIrq = 16; - public const int SpIrq = 17; - - public const int LrSvc = 18; - public const int SpSvc = 19; - - public const int LrAbt = 20; - public const int SpAbt = 21; - - public const int LrUnd = 22; - public const int SpUnd = 23; - - public const int R8Fiq = 24; - public const int R9Fiq = 25; - public const int R10Fiq = 26; - public const int R11Fiq = 27; - public const int R12Fiq = 28; - public const int SpFiq = 29; - public const int LrFiq = 30; - - public const int Aarch32Sp = 13; - public const int Aarch32Lr = 14; - public const int Aarch32Pc = 15; - - public const int Lr = 30; - public const int Zr = 31; - } -} \ No newline at end of file diff --git a/ARMeilleure/State/RegisterConsts.cs b/ARMeilleure/State/RegisterConsts.cs deleted file mode 100644 index d62940808..000000000 --- a/ARMeilleure/State/RegisterConsts.cs +++ /dev/null @@ -1,15 +0,0 @@ -namespace ARMeilleure.State -{ - static class RegisterConsts - { - public const int IntRegsCount = 32; - public const int VecRegsCount = 32; - public const int FlagsCount = 32; - public const int FpFlagsCount = 32; - public const int IntAndVecRegsCount = IntRegsCount + VecRegsCount; - public const int FpFlagsOffset = IntRegsCount + VecRegsCount + FlagsCount; - public const int TotalCount = IntRegsCount + VecRegsCount + FlagsCount + FpFlagsCount; - - public const int ZeroIndex = 31; - } -} \ No newline at end of file diff --git a/ARMeilleure/Translation/Cache/JitCache.cs b/ARMeilleure/Translation/Cache/JitCache.cs deleted file mode 100644 index 24affa34e..000000000 --- a/ARMeilleure/Translation/Cache/JitCache.cs +++ /dev/null @@ -1,184 +0,0 @@ -using ARMeilleure.CodeGen; -using ARMeilleure.CodeGen.Unwinding; -using ARMeilleure.Memory; -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Runtime.InteropServices; - -namespace ARMeilleure.Translation.Cache -{ - static class JitCache - { - private const int PageSize = 4 * 1024; - private const int PageMask = PageSize - 1; - - private const int CodeAlignment = 4; // Bytes. - private const int CacheSize = 2047 * 1024 * 1024; - - private static ReservedRegion _jitRegion; - - private static CacheMemoryAllocator _cacheAllocator; - - private static readonly List _cacheEntries = new List(); - - private static readonly object _lock = new object(); - private static bool _initialized; - - public static IntPtr Base => _jitRegion.Pointer; - - public static void Initialize(IJitMemoryAllocator allocator) - { - if (_initialized) return; - - lock (_lock) - { - if (_initialized) return; - - _jitRegion = new ReservedRegion(allocator, CacheSize); - - _cacheAllocator = new CacheMemoryAllocator(CacheSize); - - if (OperatingSystem.IsWindows()) - { - JitUnwindWindows.InstallFunctionTableHandler(_jitRegion.Pointer, CacheSize, _jitRegion.Pointer + Allocate(PageSize)); - } - - _initialized = true; - } - } - - public static IntPtr Map(CompiledFunction func) - { - byte[] code = func.Code; - - lock (_lock) - { - Debug.Assert(_initialized); - - int funcOffset = Allocate(code.Length); - - IntPtr funcPtr = _jitRegion.Pointer + funcOffset; - - ReprotectAsWritable(funcOffset, code.Length); - - Marshal.Copy(code, 0, funcPtr, code.Length); - - ReprotectAsExecutable(funcOffset, code.Length); - - Add(funcOffset, code.Length, func.UnwindInfo); - - return funcPtr; - } - } - - public static void Unmap(IntPtr pointer) - { - lock (_lock) - { - Debug.Assert(_initialized); - - int funcOffset = (int)(pointer.ToInt64() - _jitRegion.Pointer.ToInt64()); - - bool result = TryFind(funcOffset, out CacheEntry entry); - Debug.Assert(result); - - _cacheAllocator.Free(funcOffset, AlignCodeSize(entry.Size)); - - Remove(funcOffset); - } - } - - private static void ReprotectAsWritable(int offset, int size) - { - int endOffs = offset + size; - - int regionStart = offset & ~PageMask; - int regionEnd = (endOffs + PageMask) & ~PageMask; - - _jitRegion.Block.MapAsRwx((ulong)regionStart, (ulong)(regionEnd - regionStart)); - } - - private static void ReprotectAsExecutable(int offset, int size) - { - int endOffs = offset + size; - - int regionStart = offset & ~PageMask; - int regionEnd = (endOffs + PageMask) & ~PageMask; - - _jitRegion.Block.MapAsRx((ulong)regionStart, (ulong)(regionEnd - regionStart)); - } - - private static int Allocate(int codeSize) - { - codeSize = AlignCodeSize(codeSize); - - int allocOffset = _cacheAllocator.Allocate(codeSize); - - if (allocOffset < 0) - { - throw new OutOfMemoryException("JIT Cache exhausted."); - } - - _jitRegion.ExpandIfNeeded((ulong)allocOffset + (ulong)codeSize); - - return allocOffset; - } - - private static int AlignCodeSize(int codeSize) - { - return checked(codeSize + (CodeAlignment - 1)) & ~(CodeAlignment - 1); - } - - private static void Add(int offset, int size, UnwindInfo unwindInfo) - { - CacheEntry entry = new CacheEntry(offset, size, unwindInfo); - - int index = _cacheEntries.BinarySearch(entry); - - if (index < 0) - { - index = ~index; - } - - _cacheEntries.Insert(index, entry); - } - - private static void Remove(int offset) - { - int index = _cacheEntries.BinarySearch(new CacheEntry(offset, 0, default)); - - if (index < 0) - { - index = ~index - 1; - } - - if (index >= 0) - { - _cacheEntries.RemoveAt(index); - } - } - - public static bool TryFind(int offset, out CacheEntry entry) - { - lock (_lock) - { - int index = _cacheEntries.BinarySearch(new CacheEntry(offset, 0, default)); - - if (index < 0) - { - index = ~index - 1; - } - - if (index >= 0) - { - entry = _cacheEntries[index]; - return true; - } - } - - entry = default; - return false; - } - } -} \ No newline at end of file diff --git a/ARMeilleure/Translation/Cache/JitUnwindWindows.cs b/ARMeilleure/Translation/Cache/JitUnwindWindows.cs deleted file mode 100644 index 072c0f51b..000000000 --- a/ARMeilleure/Translation/Cache/JitUnwindWindows.cs +++ /dev/null @@ -1,188 +0,0 @@ -// https://github.com/MicrosoftDocs/cpp-docs/blob/master/docs/build/exception-handling-x64.md - -using ARMeilleure.CodeGen.Unwinding; -using System; -using System.Diagnostics; -using System.Runtime.InteropServices; - -namespace ARMeilleure.Translation.Cache -{ - static class JitUnwindWindows - { - private const int MaxUnwindCodesArraySize = 32; // Must be an even value. - - private struct RuntimeFunction - { - public uint BeginAddress; - public uint EndAddress; - public uint UnwindData; - } - - private struct UnwindInfo - { - public byte VersionAndFlags; - public byte SizeOfProlog; - public byte CountOfUnwindCodes; - public byte FrameRegister; - public unsafe fixed ushort UnwindCodes[MaxUnwindCodesArraySize]; - } - - private enum UnwindOp - { - PushNonvol = 0, - AllocLarge = 1, - AllocSmall = 2, - SetFpreg = 3, - SaveNonvol = 4, - SaveNonvolFar = 5, - SaveXmm128 = 8, - SaveXmm128Far = 9, - PushMachframe = 10 - } - - private unsafe delegate RuntimeFunction* GetRuntimeFunctionCallback(ulong controlPc, IntPtr context); - - [DllImport("kernel32.dll", CharSet = CharSet.Unicode)] - private static unsafe extern bool RtlInstallFunctionTableCallback( - ulong tableIdentifier, - ulong baseAddress, - uint length, - GetRuntimeFunctionCallback callback, - IntPtr context, - string outOfProcessCallbackDll); - - private static GetRuntimeFunctionCallback _getRuntimeFunctionCallback; - - private static int _sizeOfRuntimeFunction; - - private unsafe static RuntimeFunction* _runtimeFunction; - - private unsafe static UnwindInfo* _unwindInfo; - - public static void InstallFunctionTableHandler(IntPtr codeCachePointer, uint codeCacheLength, IntPtr workBufferPtr) - { - ulong codeCachePtr = (ulong)codeCachePointer.ToInt64(); - - _sizeOfRuntimeFunction = Marshal.SizeOf(); - - bool result; - - unsafe - { - _runtimeFunction = (RuntimeFunction*)workBufferPtr; - - _unwindInfo = (UnwindInfo*)(workBufferPtr + _sizeOfRuntimeFunction); - - _getRuntimeFunctionCallback = new GetRuntimeFunctionCallback(FunctionTableHandler); - - result = RtlInstallFunctionTableCallback( - codeCachePtr | 3, - codeCachePtr, - codeCacheLength, - _getRuntimeFunctionCallback, - codeCachePointer, - null); - } - - if (!result) - { - throw new InvalidOperationException("Failure installing function table callback."); - } - } - - private static unsafe RuntimeFunction* FunctionTableHandler(ulong controlPc, IntPtr context) - { - int offset = (int)((long)controlPc - context.ToInt64()); - - if (!JitCache.TryFind(offset, out CacheEntry funcEntry)) - { - return null; // Not found. - } - - var unwindInfo = funcEntry.UnwindInfo; - - int codeIndex = 0; - - for (int index = unwindInfo.PushEntries.Length - 1; index >= 0; index--) - { - var entry = unwindInfo.PushEntries[index]; - - switch (entry.PseudoOp) - { - case UnwindPseudoOp.SaveXmm128: - { - int stackOffset = entry.StackOffsetOrAllocSize; - - Debug.Assert(stackOffset % 16 == 0); - - if (stackOffset <= 0xFFFF0) - { - _unwindInfo->UnwindCodes[codeIndex++] = PackUnwindOp(UnwindOp.SaveXmm128, entry.PrologOffset, entry.RegIndex); - _unwindInfo->UnwindCodes[codeIndex++] = (ushort)(stackOffset / 16); - } - else - { - _unwindInfo->UnwindCodes[codeIndex++] = PackUnwindOp(UnwindOp.SaveXmm128Far, entry.PrologOffset, entry.RegIndex); - _unwindInfo->UnwindCodes[codeIndex++] = (ushort)(stackOffset >> 0); - _unwindInfo->UnwindCodes[codeIndex++] = (ushort)(stackOffset >> 16); - } - - break; - } - - case UnwindPseudoOp.AllocStack: - { - int allocSize = entry.StackOffsetOrAllocSize; - - Debug.Assert(allocSize % 8 == 0); - - if (allocSize <= 128) - { - _unwindInfo->UnwindCodes[codeIndex++] = PackUnwindOp(UnwindOp.AllocSmall, entry.PrologOffset, (allocSize / 8) - 1); - } - else if (allocSize <= 0x7FFF8) - { - _unwindInfo->UnwindCodes[codeIndex++] = PackUnwindOp(UnwindOp.AllocLarge, entry.PrologOffset, 0); - _unwindInfo->UnwindCodes[codeIndex++] = (ushort)(allocSize / 8); - } - else - { - _unwindInfo->UnwindCodes[codeIndex++] = PackUnwindOp(UnwindOp.AllocLarge, entry.PrologOffset, 1); - _unwindInfo->UnwindCodes[codeIndex++] = (ushort)(allocSize >> 0); - _unwindInfo->UnwindCodes[codeIndex++] = (ushort)(allocSize >> 16); - } - - break; - } - - case UnwindPseudoOp.PushReg: - { - _unwindInfo->UnwindCodes[codeIndex++] = PackUnwindOp(UnwindOp.PushNonvol, entry.PrologOffset, entry.RegIndex); - - break; - } - - default: throw new NotImplementedException($"({nameof(entry.PseudoOp)} = {entry.PseudoOp})"); - } - } - - Debug.Assert(codeIndex <= MaxUnwindCodesArraySize); - - _unwindInfo->VersionAndFlags = 1; // Flags: The function has no handler. - _unwindInfo->SizeOfProlog = (byte)unwindInfo.PrologSize; - _unwindInfo->CountOfUnwindCodes = (byte)codeIndex; - _unwindInfo->FrameRegister = 0; - - _runtimeFunction->BeginAddress = (uint)funcEntry.Offset; - _runtimeFunction->EndAddress = (uint)(funcEntry.Offset + funcEntry.Size); - _runtimeFunction->UnwindData = (uint)_sizeOfRuntimeFunction; - - return _runtimeFunction; - } - - private static ushort PackUnwindOp(UnwindOp op, int prologOffset, int opInfo) - { - return (ushort)(prologOffset | ((int)op << 8) | (opInfo << 12)); - } - } -} \ No newline at end of file diff --git a/ARMeilleure/Translation/Compiler.cs b/ARMeilleure/Translation/Compiler.cs deleted file mode 100644 index 817bd487e..000000000 --- a/ARMeilleure/Translation/Compiler.cs +++ /dev/null @@ -1,55 +0,0 @@ -using ARMeilleure.CodeGen; -using ARMeilleure.CodeGen.Optimizations; -using ARMeilleure.CodeGen.X86; -using ARMeilleure.Diagnostics; -using ARMeilleure.IntermediateRepresentation; - -namespace ARMeilleure.Translation -{ - static class Compiler - { - public static CompiledFunction Compile( - ControlFlowGraph cfg, - OperandType[] argTypes, - OperandType retType, - CompilerOptions options) - { - CompilerContext cctx = new(cfg, argTypes, retType, options); - - if (options.HasFlag(CompilerOptions.Optimize)) - { - Logger.StartPass(PassName.TailMerge); - - TailMerge.RunPass(cctx); - - Logger.EndPass(PassName.TailMerge, cfg); - } - - if (options.HasFlag(CompilerOptions.SsaForm)) - { - Logger.StartPass(PassName.Dominance); - - Dominance.FindDominators(cfg); - Dominance.FindDominanceFrontiers(cfg); - - Logger.EndPass(PassName.Dominance); - - Logger.StartPass(PassName.SsaConstruction); - - Ssa.Construct(cfg); - - Logger.EndPass(PassName.SsaConstruction, cfg); - } - else - { - Logger.StartPass(PassName.RegisterToLocal); - - RegisterToLocal.Rename(cfg); - - Logger.EndPass(PassName.RegisterToLocal, cfg); - } - - return CodeGenerator.Generate(cctx); - } - } -} \ No newline at end of file diff --git a/ARMeilleure/Translation/CompilerContext.cs b/ARMeilleure/Translation/CompilerContext.cs deleted file mode 100644 index cfe5ad1e5..000000000 --- a/ARMeilleure/Translation/CompilerContext.cs +++ /dev/null @@ -1,26 +0,0 @@ -using ARMeilleure.IntermediateRepresentation; - -namespace ARMeilleure.Translation -{ - struct CompilerContext - { - public ControlFlowGraph Cfg { get; } - - public OperandType[] FuncArgTypes { get; } - public OperandType FuncReturnType { get; } - - public CompilerOptions Options { get; } - - public CompilerContext( - ControlFlowGraph cfg, - OperandType[] funcArgTypes, - OperandType funcReturnType, - CompilerOptions options) - { - Cfg = cfg; - FuncArgTypes = funcArgTypes; - FuncReturnType = funcReturnType; - Options = options; - } - } -} \ No newline at end of file diff --git a/ARMeilleure/Translation/CompilerOptions.cs b/ARMeilleure/Translation/CompilerOptions.cs deleted file mode 100644 index 0a07ed4ab..000000000 --- a/ARMeilleure/Translation/CompilerOptions.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System; - -namespace ARMeilleure.Translation -{ - [Flags] - enum CompilerOptions - { - None = 0, - SsaForm = 1 << 0, - Optimize = 1 << 1, - Lsra = 1 << 2, - Relocatable = 1 << 3, - - MediumCq = SsaForm | Optimize, - HighCq = SsaForm | Optimize | Lsra - } -} \ No newline at end of file diff --git a/ARMeilleure/Translation/ControlFlowGraph.cs b/ARMeilleure/Translation/ControlFlowGraph.cs deleted file mode 100644 index c935f1521..000000000 --- a/ARMeilleure/Translation/ControlFlowGraph.cs +++ /dev/null @@ -1,155 +0,0 @@ -using ARMeilleure.IntermediateRepresentation; -using System; -using System.Collections.Generic; -using System.Diagnostics; - -namespace ARMeilleure.Translation -{ - class ControlFlowGraph - { - private BasicBlock[] _postOrderBlocks; - private int[] _postOrderMap; - - public int LocalsCount { get; private set; } - public BasicBlock Entry { get; } - public IntrusiveList Blocks { get; } - public BasicBlock[] PostOrderBlocks => _postOrderBlocks; - public int[] PostOrderMap => _postOrderMap; - - public ControlFlowGraph(BasicBlock entry, IntrusiveList blocks, int localsCount) - { - Entry = entry; - Blocks = blocks; - LocalsCount = localsCount; - - Update(); - } - - public Operand AllocateLocal(OperandType type) - { - Operand result = Operand.Factory.Local(type); - - result.NumberLocal(++LocalsCount); - - return result; - } - - public void Update() - { - RemoveUnreachableBlocks(Blocks); - - var visited = new HashSet(); - var blockStack = new Stack(); - - Array.Resize(ref _postOrderBlocks, Blocks.Count); - Array.Resize(ref _postOrderMap, Blocks.Count); - - visited.Add(Entry); - blockStack.Push(Entry); - - int index = 0; - - while (blockStack.TryPop(out BasicBlock block)) - { - bool visitedNew = false; - - for (int i = 0; i < block.SuccessorsCount; i++) - { - BasicBlock succ = block.GetSuccessor(i); - - if (visited.Add(succ)) - { - blockStack.Push(block); - blockStack.Push(succ); - - visitedNew = true; - - break; - } - } - - if (!visitedNew) - { - PostOrderMap[block.Index] = index; - - PostOrderBlocks[index++] = block; - } - } - } - - private void RemoveUnreachableBlocks(IntrusiveList blocks) - { - var visited = new HashSet(); - var workQueue = new Queue(); - - visited.Add(Entry); - workQueue.Enqueue(Entry); - - while (workQueue.TryDequeue(out BasicBlock block)) - { - Debug.Assert(block.Index != -1, "Invalid block index."); - - for (int i = 0; i < block.SuccessorsCount; i++) - { - BasicBlock succ = block.GetSuccessor(i); - - if (visited.Add(succ)) - { - workQueue.Enqueue(succ); - } - } - } - - if (visited.Count < blocks.Count) - { - // Remove unreachable blocks and renumber. - int index = 0; - - for (BasicBlock block = blocks.First; block != null;) - { - BasicBlock nextBlock = block.ListNext; - - if (!visited.Contains(block)) - { - while (block.SuccessorsCount > 0) - { - block.RemoveSuccessor(index: block.SuccessorsCount - 1); - } - - blocks.Remove(block); - } - else - { - block.Index = index++; - } - - block = nextBlock; - } - } - } - - public BasicBlock SplitEdge(BasicBlock predecessor, BasicBlock successor) - { - BasicBlock splitBlock = new BasicBlock(Blocks.Count); - - for (int i = 0; i < predecessor.SuccessorsCount; i++) - { - if (predecessor.GetSuccessor(i) == successor) - { - predecessor.SetSuccessor(i, splitBlock); - } - } - - if (splitBlock.Predecessors.Count == 0) - { - throw new ArgumentException("Predecessor and successor are not connected."); - } - - splitBlock.AddSuccessor(successor); - - Blocks.AddBefore(successor, splitBlock); - - return splitBlock; - } - } -} \ No newline at end of file diff --git a/ARMeilleure/Translation/DelegateHelper.cs b/ARMeilleure/Translation/DelegateHelper.cs deleted file mode 100644 index f021d1160..000000000 --- a/ARMeilleure/Translation/DelegateHelper.cs +++ /dev/null @@ -1,107 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using System.Reflection.Emit; - -namespace ARMeilleure.Translation -{ - static class DelegateHelper - { - private const string DelegateTypesAssemblyName = "JitDelegateTypes"; - - private static readonly ModuleBuilder _modBuilder; - - private static readonly Dictionary _delegateTypesCache; - - static DelegateHelper() - { - AssemblyBuilder asmBuilder = AssemblyBuilder.DefineDynamicAssembly(new AssemblyName(DelegateTypesAssemblyName), AssemblyBuilderAccess.Run); - - _modBuilder = asmBuilder.DefineDynamicModule(DelegateTypesAssemblyName); - - _delegateTypesCache = new Dictionary(); - } - - public static Delegate GetDelegate(MethodInfo info) - { - if (info == null) - { - throw new ArgumentNullException(nameof(info)); - } - - Type[] parameters = info.GetParameters().Select(pI => pI.ParameterType).ToArray(); - Type returnType = info.ReturnType; - - Type delegateType = GetDelegateType(parameters, returnType); - - return Delegate.CreateDelegate(delegateType, info); - } - - private static Type GetDelegateType(Type[] parameters, Type returnType) - { - string key = GetFunctionSignatureKey(parameters, returnType); - - if (!_delegateTypesCache.TryGetValue(key, out Type delegateType)) - { - delegateType = MakeDelegateType(parameters, returnType, key); - - _delegateTypesCache.TryAdd(key, delegateType); - } - - return delegateType; - } - - private static string GetFunctionSignatureKey(Type[] parameters, Type returnType) - { - string sig = GetTypeName(returnType); - - foreach (Type type in parameters) - { - sig += '_' + GetTypeName(type); - } - - return sig; - } - - private static string GetTypeName(Type type) - { - return type.FullName.Replace(".", string.Empty); - } - - private const MethodAttributes CtorAttributes = - MethodAttributes.RTSpecialName | - MethodAttributes.HideBySig | - MethodAttributes.Public; - - private const TypeAttributes DelegateTypeAttributes = - TypeAttributes.Class | - TypeAttributes.Public | - TypeAttributes.Sealed | - TypeAttributes.AnsiClass | - TypeAttributes.AutoClass; - - private const MethodImplAttributes ImplAttributes = - MethodImplAttributes.Runtime | - MethodImplAttributes.Managed; - - private const MethodAttributes InvokeAttributes = - MethodAttributes.Public | - MethodAttributes.HideBySig | - MethodAttributes.NewSlot | - MethodAttributes.Virtual; - - private static readonly Type[] _delegateCtorSignature = { typeof(object), typeof(IntPtr) }; - - private static Type MakeDelegateType(Type[] parameters, Type returnType, string name) - { - TypeBuilder builder = _modBuilder.DefineType(name, DelegateTypeAttributes, typeof(MulticastDelegate)); - - builder.DefineConstructor(CtorAttributes, CallingConventions.Standard, _delegateCtorSignature).SetImplementationFlags(ImplAttributes); - - builder.DefineMethod("Invoke", InvokeAttributes, returnType, parameters).SetImplementationFlags(ImplAttributes); - - return builder.CreateTypeInfo(); - } - } -} diff --git a/ARMeilleure/Translation/Delegates.cs b/ARMeilleure/Translation/Delegates.cs deleted file mode 100644 index fef1f4ef7..000000000 --- a/ARMeilleure/Translation/Delegates.cs +++ /dev/null @@ -1,273 +0,0 @@ -using ARMeilleure.Instructions; -using System; -using System.Collections.Generic; -using System.Reflection; - -namespace ARMeilleure.Translation -{ - static class Delegates - { - public static bool TryGetDelegateFuncPtrByIndex(int index, out IntPtr funcPtr) - { - if (index >= 0 && index < _delegates.Count) - { - funcPtr = _delegates.Values[index].FuncPtr; // O(1). - - return true; - } - else - { - funcPtr = default; - - return false; - } - } - - public static IntPtr GetDelegateFuncPtrByIndex(int index) - { - if (index < 0 || index >= _delegates.Count) - { - throw new ArgumentOutOfRangeException($"({nameof(index)} = {index})"); - } - - return _delegates.Values[index].FuncPtr; // O(1). - } - - public static IntPtr GetDelegateFuncPtr(MethodInfo info) - { - if (info == null) - { - throw new ArgumentNullException(nameof(info)); - } - - string key = GetKey(info); - - if (!_delegates.TryGetValue(key, out DelegateInfo dlgInfo)) // O(log(n)). - { - throw new KeyNotFoundException($"({nameof(key)} = {key})"); - } - - return dlgInfo.FuncPtr; - } - - public static int GetDelegateIndex(MethodInfo info) - { - if (info == null) - { - throw new ArgumentNullException(nameof(info)); - } - - string key = GetKey(info); - - int index = _delegates.IndexOfKey(key); // O(log(n)). - - if (index == -1) - { - throw new KeyNotFoundException($"({nameof(key)} = {key})"); - } - - return index; - } - - private static void SetDelegateInfo(MethodInfo info) - { - string key = GetKey(info); - - Delegate dlg = DelegateHelper.GetDelegate(info); - - _delegates.Add(key, new DelegateInfo(dlg)); // ArgumentException (key). - } - - private static string GetKey(MethodInfo info) - { - return $"{info.DeclaringType.Name}.{info.Name}"; - } - - private static readonly SortedList _delegates; - - static Delegates() - { - _delegates = new SortedList(); - - SetDelegateInfo(typeof(Math).GetMethod(nameof(Math.Abs), new Type[] { typeof(double) })); - SetDelegateInfo(typeof(Math).GetMethod(nameof(Math.Ceiling), new Type[] { typeof(double) })); - SetDelegateInfo(typeof(Math).GetMethod(nameof(Math.Floor), new Type[] { typeof(double) })); - SetDelegateInfo(typeof(Math).GetMethod(nameof(Math.Round), new Type[] { typeof(double), typeof(MidpointRounding) })); - SetDelegateInfo(typeof(Math).GetMethod(nameof(Math.Truncate), new Type[] { typeof(double) })); - - SetDelegateInfo(typeof(MathF).GetMethod(nameof(MathF.Abs), new Type[] { typeof(float) })); - SetDelegateInfo(typeof(MathF).GetMethod(nameof(MathF.Ceiling), new Type[] { typeof(float) })); - SetDelegateInfo(typeof(MathF).GetMethod(nameof(MathF.Floor), new Type[] { typeof(float) })); - SetDelegateInfo(typeof(MathF).GetMethod(nameof(MathF.Round), new Type[] { typeof(float), typeof(MidpointRounding) })); - SetDelegateInfo(typeof(MathF).GetMethod(nameof(MathF.Truncate), new Type[] { typeof(float) })); - - SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.Break))); - SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.CheckSynchronization))); - SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.EnqueueForRejit))); - SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetCntfrqEl0))); - SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetCntpctEl0))); - SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetCntvctEl0))); - SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetCtrEl0))); - SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetDczidEl0))); - SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFunctionAddress))); - SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.InvalidateCacheLine))); - SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetTpidrroEl0))); - SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetTpidr32))); // A32 only. - SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetTpidrEl0))); - SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetTpidrEl032))); // A32 only. - SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadByte))); - SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadUInt16))); - SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadUInt32))); - SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadUInt64))); - SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadVector128))); - SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetTpidrEl0))); - SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetTpidrEl032))); // A32 only. - SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SignalMemoryTracking))); - SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SupervisorCall))); - SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.ThrowInvalidMemoryAccess))); - SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.Undefined))); - SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.WriteByte))); - SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.WriteUInt16))); - SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.WriteUInt32))); - SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.WriteUInt64))); - SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.WriteVector128))); - - SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.CountLeadingSigns))); - SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.CountLeadingZeros))); - SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Crc32b))); - SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Crc32cb))); - SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Crc32ch))); - SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Crc32cw))); - SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Crc32cx))); - SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Crc32h))); - SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Crc32w))); - SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Crc32x))); - SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Decrypt))); - SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Encrypt))); - SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.FixedRotate))); - SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.HashChoose))); - SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.HashLower))); - SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.HashMajority))); - SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.HashParity))); - SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.HashUpper))); - SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.InverseMixColumns))); - SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.MixColumns))); - SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.PolynomialMult64_128))); - SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.SatF32ToS32))); - SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.SatF32ToS64))); - SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.SatF32ToU32))); - SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.SatF32ToU64))); - SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.SatF64ToS32))); - SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.SatF64ToS64))); - SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.SatF64ToU32))); - SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.SatF64ToU64))); - SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Sha1SchedulePart1))); - SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Sha1SchedulePart2))); - SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Sha256SchedulePart1))); - SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Sha256SchedulePart2))); - SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.SignedShrImm64))); - SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Tbl1))); - SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Tbl2))); - SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Tbl3))); - SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Tbl4))); - SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Tbx1))); - SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Tbx2))); - SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Tbx3))); - SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Tbx4))); - SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.UnsignedShrImm64))); - - SetDelegateInfo(typeof(SoftFloat16_32).GetMethod(nameof(SoftFloat16_32.FPConvert))); - SetDelegateInfo(typeof(SoftFloat16_64).GetMethod(nameof(SoftFloat16_64.FPConvert))); - - SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPAdd))); - SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPAddFpscr))); // A32 only. - SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompare))); - SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareEQ))); - SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareEQFpscr))); // A32 only. - SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareGE))); - SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareGEFpscr))); // A32 only. - SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareGT))); - SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareGTFpscr))); // A32 only. - SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareLE))); - SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareLEFpscr))); // A32 only. - SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareLT))); - SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareLTFpscr))); // A32 only. - SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPDiv))); - SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMax))); - SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMaxFpscr))); // A32 only. - SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMaxNum))); - SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMaxNumFpscr))); // A32 only. - SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMin))); - SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMinFpscr))); // A32 only. - SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMinNum))); - SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMinNumFpscr))); // A32 only. - SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMul))); - SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMulFpscr))); // A32 only. - SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMulAdd))); - SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMulAddFpscr))); // A32 only. - SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMulSub))); - SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMulSubFpscr))); // A32 only. - SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMulX))); - SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPNegMulAdd))); - SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPNegMulSub))); - SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRecipEstimate))); - SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRecipEstimateFpscr))); // A32 only. - SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRecipStep))); // A32 only. - SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRecipStepFused))); - SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRecpX))); - SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRSqrtEstimate))); - SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRSqrtEstimateFpscr))); // A32 only. - SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRSqrtStep))); // A32 only. - SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRSqrtStepFused))); - SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPSqrt))); - SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPSub))); - - SetDelegateInfo(typeof(SoftFloat32_16).GetMethod(nameof(SoftFloat32_16.FPConvert))); - - SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPAdd))); - SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPAddFpscr))); // A32 only. - SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompare))); - SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareEQ))); - SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareEQFpscr))); // A32 only. - SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareGE))); - SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareGEFpscr))); // A32 only. - SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareGT))); - SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareGTFpscr))); // A32 only. - SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareLE))); - SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareLEFpscr))); // A32 only. - SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareLT))); - SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareLTFpscr))); // A32 only. - SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPDiv))); - SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMax))); - SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMaxFpscr))); // A32 only. - SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMaxNum))); - SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMaxNumFpscr))); // A32 only. - SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMin))); - SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMinFpscr))); // A32 only. - SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMinNum))); - SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMinNumFpscr))); // A32 only. - SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMul))); - SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMulFpscr))); // A32 only. - SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMulAdd))); - SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMulAddFpscr))); // A32 only. - SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMulSub))); - SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMulSubFpscr))); // A32 only. - SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMulX))); - SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPNegMulAdd))); - SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPNegMulSub))); - SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRecipEstimate))); - SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRecipEstimateFpscr))); // A32 only. - SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRecipStep))); // A32 only. - SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRecipStepFused))); - SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRecpX))); - SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRSqrtEstimate))); - SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRSqrtEstimateFpscr))); // A32 only. - SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRSqrtStep))); // A32 only. - SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRSqrtStepFused))); - SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPSqrt))); - SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPSub))); - - SetDelegateInfo(typeof(SoftFloat64_16).GetMethod(nameof(SoftFloat64_16.FPConvert))); - } - } -} diff --git a/ARMeilleure/Translation/DispatcherFunction.cs b/ARMeilleure/Translation/DispatcherFunction.cs deleted file mode 100644 index e3ea21f67..000000000 --- a/ARMeilleure/Translation/DispatcherFunction.cs +++ /dev/null @@ -1,6 +0,0 @@ -using System; - -namespace ARMeilleure.Translation -{ - delegate void DispatcherFunction(IntPtr nativeContext, ulong startAddress); -} diff --git a/ARMeilleure/Translation/Dominance.cs b/ARMeilleure/Translation/Dominance.cs deleted file mode 100644 index b9b961d15..000000000 --- a/ARMeilleure/Translation/Dominance.cs +++ /dev/null @@ -1,95 +0,0 @@ -using ARMeilleure.IntermediateRepresentation; -using System.Diagnostics; - -namespace ARMeilleure.Translation -{ - static class Dominance - { - // Those methods are an implementation of the algorithms on "A Simple, Fast Dominance Algorithm". - // https://www.cs.rice.edu/~keith/EMBED/dom.pdf - public static void FindDominators(ControlFlowGraph cfg) - { - BasicBlock Intersect(BasicBlock block1, BasicBlock block2) - { - while (block1 != block2) - { - while (cfg.PostOrderMap[block1.Index] < cfg.PostOrderMap[block2.Index]) - { - block1 = block1.ImmediateDominator; - } - - while (cfg.PostOrderMap[block2.Index] < cfg.PostOrderMap[block1.Index]) - { - block2 = block2.ImmediateDominator; - } - } - - return block1; - } - - cfg.Entry.ImmediateDominator = cfg.Entry; - - Debug.Assert(cfg.Entry == cfg.PostOrderBlocks[cfg.PostOrderBlocks.Length - 1]); - - bool modified; - - do - { - modified = false; - - for (int blkIndex = cfg.PostOrderBlocks.Length - 2; blkIndex >= 0; blkIndex--) - { - BasicBlock block = cfg.PostOrderBlocks[blkIndex]; - - BasicBlock newIDom = null; - - foreach (BasicBlock predecessor in block.Predecessors) - { - if (predecessor.ImmediateDominator != null) - { - if (newIDom != null) - { - newIDom = Intersect(predecessor, newIDom); - } - else - { - newIDom = predecessor; - } - } - } - - if (block.ImmediateDominator != newIDom) - { - block.ImmediateDominator = newIDom; - - modified = true; - } - } - } - while (modified); - } - - public static void FindDominanceFrontiers(ControlFlowGraph cfg) - { - for (BasicBlock block = cfg.Blocks.First; block != null; block = block.ListNext) - { - if (block.Predecessors.Count < 2) - { - continue; - } - - for (int pBlkIndex = 0; pBlkIndex < block.Predecessors.Count; pBlkIndex++) - { - BasicBlock current = block.Predecessors[pBlkIndex]; - - while (current != block.ImmediateDominator) - { - current.DominanceFrontiers.Add(block); - - current = current.ImmediateDominator; - } - } - } - } - } -} \ No newline at end of file diff --git a/ARMeilleure/Translation/EmitterContext.cs b/ARMeilleure/Translation/EmitterContext.cs deleted file mode 100644 index 8fcb4deec..000000000 --- a/ARMeilleure/Translation/EmitterContext.cs +++ /dev/null @@ -1,680 +0,0 @@ -using ARMeilleure.Diagnostics; -using ARMeilleure.IntermediateRepresentation; -using ARMeilleure.State; -using System; -using System.Collections.Generic; -using System.Reflection; -using static ARMeilleure.IntermediateRepresentation.Operand.Factory; - -namespace ARMeilleure.Translation -{ - class EmitterContext - { - private int _localsCount; - - private readonly Dictionary _irLabels; - private readonly IntrusiveList _irBlocks; - - private BasicBlock _irBlock; - private BasicBlock _ifBlock; - - private bool _needsNewBlock; - private BasicBlockFrequency _nextBlockFreq; - - public EmitterContext() - { - _localsCount = 0; - - _irLabels = new Dictionary(); - _irBlocks = new IntrusiveList(); - - _needsNewBlock = true; - _nextBlockFreq = BasicBlockFrequency.Default; - } - - public Operand AllocateLocal(OperandType type) - { - Operand local = Local(type); - - local.NumberLocal(++_localsCount); - - return local; - } - - public Operand Add(Operand op1, Operand op2) - { - return Add(Instruction.Add, Local(op1.Type), op1, op2); - } - - public Operand BitwiseAnd(Operand op1, Operand op2) - { - return Add(Instruction.BitwiseAnd, Local(op1.Type), op1, op2); - } - - public Operand BitwiseExclusiveOr(Operand op1, Operand op2) - { - return Add(Instruction.BitwiseExclusiveOr, Local(op1.Type), op1, op2); - } - - public Operand BitwiseNot(Operand op1) - { - return Add(Instruction.BitwiseNot, Local(op1.Type), op1); - } - - public Operand BitwiseOr(Operand op1, Operand op2) - { - return Add(Instruction.BitwiseOr, Local(op1.Type), op1, op2); - } - - public void Branch(Operand label) - { - NewNextBlockIfNeeded(); - - BranchToLabel(label, uncond: true, BasicBlockFrequency.Default); - } - - public void BranchIf(Operand label, Operand op1, Operand op2, Comparison comp, BasicBlockFrequency falseFreq = default) - { - Add(Instruction.BranchIf, default, op1, op2, Const((int)comp)); - - BranchToLabel(label, uncond: false, falseFreq); - } - - public void BranchIfFalse(Operand label, Operand op1, BasicBlockFrequency falseFreq = default) - { - BranchIf(label, op1, Const(op1.Type, 0), Comparison.Equal, falseFreq); - } - - public void BranchIfTrue(Operand label, Operand op1, BasicBlockFrequency falseFreq = default) - { - BranchIf(label, op1, Const(op1.Type, 0), Comparison.NotEqual, falseFreq); - } - - public Operand ByteSwap(Operand op1) - { - return Add(Instruction.ByteSwap, Local(op1.Type), op1); - } - - public virtual Operand Call(MethodInfo info, params Operand[] callArgs) - { - IntPtr funcPtr = Delegates.GetDelegateFuncPtr(info); - - OperandType returnType = GetOperandType(info.ReturnType); - - Symbols.Add((ulong)funcPtr.ToInt64(), info.Name); - - return Call(Const(funcPtr.ToInt64()), returnType, callArgs); - } - - protected static OperandType GetOperandType(Type type) - { - if (type == typeof(bool) || type == typeof(byte) || - type == typeof(char) || type == typeof(short) || - type == typeof(int) || type == typeof(sbyte) || - type == typeof(ushort) || type == typeof(uint)) - { - return OperandType.I32; - } - else if (type == typeof(long) || type == typeof(ulong)) - { - return OperandType.I64; - } - else if (type == typeof(double)) - { - return OperandType.FP64; - } - else if (type == typeof(float)) - { - return OperandType.FP32; - } - else if (type == typeof(V128)) - { - return OperandType.V128; - } - else if (type == typeof(void)) - { - return OperandType.None; - } - else - { - throw new ArgumentException($"Invalid type \"{type.Name}\"."); - } - } - - public Operand Call(Operand address, OperandType returnType, params Operand[] callArgs) - { - Operand[] args = new Operand[callArgs.Length + 1]; - - args[0] = address; - - Array.Copy(callArgs, 0, args, 1, callArgs.Length); - - if (returnType != OperandType.None) - { - return Add(Instruction.Call, Local(returnType), args); - } - else - { - return Add(Instruction.Call, default, args); - } - } - - public void Tailcall(Operand address, params Operand[] callArgs) - { - Operand[] args = new Operand[callArgs.Length + 1]; - - args[0] = address; - - Array.Copy(callArgs, 0, args, 1, callArgs.Length); - - Add(Instruction.Tailcall, default, args); - - _needsNewBlock = true; - } - - public Operand CompareAndSwap(Operand address, Operand expected, Operand desired) - { - return Add(Instruction.CompareAndSwap, Local(desired.Type), address, expected, desired); - } - - public Operand CompareAndSwap16(Operand address, Operand expected, Operand desired) - { - return Add(Instruction.CompareAndSwap16, Local(OperandType.I32), address, expected, desired); - } - - public Operand CompareAndSwap8(Operand address, Operand expected, Operand desired) - { - return Add(Instruction.CompareAndSwap8, Local(OperandType.I32), address, expected, desired); - } - - public Operand ConditionalSelect(Operand op1, Operand op2, Operand op3) - { - return Add(Instruction.ConditionalSelect, Local(op2.Type), op1, op2, op3); - } - - public Operand ConvertI64ToI32(Operand op1) - { - if (op1.Type != OperandType.I64) - { - throw new ArgumentException($"Invalid operand type \"{op1.Type}\"."); - } - - return Add(Instruction.ConvertI64ToI32, Local(OperandType.I32), op1); - } - - public Operand ConvertToFP(OperandType type, Operand op1) - { - return Add(Instruction.ConvertToFP, Local(type), op1); - } - - public Operand ConvertToFPUI(OperandType type, Operand op1) - { - return Add(Instruction.ConvertToFPUI, Local(type), op1); - } - - public Operand Copy(Operand op1) - { - return Add(Instruction.Copy, Local(op1.Type), op1); - } - - public Operand Copy(Operand dest, Operand op1) - { - if (dest.Kind != OperandKind.Register && - (dest.Kind != OperandKind.LocalVariable || dest.GetLocalNumber() == 0)) - { - throw new ArgumentException($"Destination operand must be a Register or a numbered LocalVariable."); - } - - return Add(Instruction.Copy, dest, op1); - } - - public Operand CountLeadingZeros(Operand op1) - { - return Add(Instruction.CountLeadingZeros, Local(op1.Type), op1); - } - - public Operand Divide(Operand op1, Operand op2) - { - return Add(Instruction.Divide, Local(op1.Type), op1, op2); - } - - public Operand DivideUI(Operand op1, Operand op2) - { - return Add(Instruction.DivideUI, Local(op1.Type), op1, op2); - } - - public Operand ICompare(Operand op1, Operand op2, Comparison comp) - { - return Add(Instruction.Compare, Local(OperandType.I32), op1, op2, Const((int)comp)); - } - - public Operand ICompareEqual(Operand op1, Operand op2) - { - return ICompare(op1, op2, Comparison.Equal); - } - - public Operand ICompareGreater(Operand op1, Operand op2) - { - return ICompare(op1, op2, Comparison.Greater); - } - - public Operand ICompareGreaterOrEqual(Operand op1, Operand op2) - { - return ICompare(op1, op2, Comparison.GreaterOrEqual); - } - - public Operand ICompareGreaterOrEqualUI(Operand op1, Operand op2) - { - return ICompare(op1, op2, Comparison.GreaterOrEqualUI); - } - - public Operand ICompareGreaterUI(Operand op1, Operand op2) - { - return ICompare(op1, op2, Comparison.GreaterUI); - } - - public Operand ICompareLess(Operand op1, Operand op2) - { - return ICompare(op1, op2, Comparison.Less); - } - - public Operand ICompareLessOrEqual(Operand op1, Operand op2) - { - return ICompare(op1, op2, Comparison.LessOrEqual); - } - - public Operand ICompareLessOrEqualUI(Operand op1, Operand op2) - { - return ICompare(op1, op2, Comparison.LessOrEqualUI); - } - - public Operand ICompareLessUI(Operand op1, Operand op2) - { - return ICompare(op1, op2, Comparison.LessUI); - } - - public Operand ICompareNotEqual(Operand op1, Operand op2) - { - return ICompare(op1, op2, Comparison.NotEqual); - } - - public Operand Load(OperandType type, Operand address) - { - return Add(Instruction.Load, Local(type), address); - } - - public Operand Load16(Operand address) - { - return Add(Instruction.Load16, Local(OperandType.I32), address); - } - - public Operand Load8(Operand address) - { - return Add(Instruction.Load8, Local(OperandType.I32), address); - } - - public Operand LoadArgument(OperandType type, int index) - { - return Add(Instruction.LoadArgument, Local(type), Const(index)); - } - - public void LoadFromContext() - { - _needsNewBlock = true; - - Add(Instruction.LoadFromContext); - } - - public void MemoryBarrier() - { - Add(Instruction.MemoryBarrier); - } - - public Operand Multiply(Operand op1, Operand op2) - { - return Add(Instruction.Multiply, Local(op1.Type), op1, op2); - } - - public Operand Multiply64HighSI(Operand op1, Operand op2) - { - return Add(Instruction.Multiply64HighSI, Local(OperandType.I64), op1, op2); - } - - public Operand Multiply64HighUI(Operand op1, Operand op2) - { - return Add(Instruction.Multiply64HighUI, Local(OperandType.I64), op1, op2); - } - - public Operand Negate(Operand op1) - { - return Add(Instruction.Negate, Local(op1.Type), op1); - } - - public void Return() - { - Add(Instruction.Return); - - _needsNewBlock = true; - } - - public void Return(Operand op1) - { - Add(Instruction.Return, default, op1); - - _needsNewBlock = true; - } - - public Operand RotateRight(Operand op1, Operand op2) - { - return Add(Instruction.RotateRight, Local(op1.Type), op1, op2); - } - - public Operand ShiftLeft(Operand op1, Operand op2) - { - return Add(Instruction.ShiftLeft, Local(op1.Type), op1, op2); - } - - public Operand ShiftRightSI(Operand op1, Operand op2) - { - return Add(Instruction.ShiftRightSI, Local(op1.Type), op1, op2); - } - - public Operand ShiftRightUI(Operand op1, Operand op2) - { - return Add(Instruction.ShiftRightUI, Local(op1.Type), op1, op2); - } - - public Operand SignExtend16(OperandType type, Operand op1) - { - return Add(Instruction.SignExtend16, Local(type), op1); - } - - public Operand SignExtend32(OperandType type, Operand op1) - { - return Add(Instruction.SignExtend32, Local(type), op1); - } - - public Operand SignExtend8(OperandType type, Operand op1) - { - return Add(Instruction.SignExtend8, Local(type), op1); - } - - public void Store(Operand address, Operand value) - { - Add(Instruction.Store, default, address, value); - } - - public void Store16(Operand address, Operand value) - { - Add(Instruction.Store16, default, address, value); - } - - public void Store8(Operand address, Operand value) - { - Add(Instruction.Store8, default, address, value); - } - - public void StoreToContext() - { - Add(Instruction.StoreToContext); - - _needsNewBlock = true; - } - - public Operand Subtract(Operand op1, Operand op2) - { - return Add(Instruction.Subtract, Local(op1.Type), op1, op2); - } - - public Operand VectorCreateScalar(Operand value) - { - return Add(Instruction.VectorCreateScalar, Local(OperandType.V128), value); - } - - public Operand VectorExtract(OperandType type, Operand vector, int index) - { - return Add(Instruction.VectorExtract, Local(type), vector, Const(index)); - } - - public Operand VectorExtract16(Operand vector, int index) - { - return Add(Instruction.VectorExtract16, Local(OperandType.I32), vector, Const(index)); - } - - public Operand VectorExtract8(Operand vector, int index) - { - return Add(Instruction.VectorExtract8, Local(OperandType.I32), vector, Const(index)); - } - - public Operand VectorInsert(Operand vector, Operand value, int index) - { - return Add(Instruction.VectorInsert, Local(OperandType.V128), vector, value, Const(index)); - } - - public Operand VectorInsert16(Operand vector, Operand value, int index) - { - return Add(Instruction.VectorInsert16, Local(OperandType.V128), vector, value, Const(index)); - } - - public Operand VectorInsert8(Operand vector, Operand value, int index) - { - return Add(Instruction.VectorInsert8, Local(OperandType.V128), vector, value, Const(index)); - } - - public Operand VectorOne() - { - return Add(Instruction.VectorOne, Local(OperandType.V128)); - } - - public Operand VectorZero() - { - return Add(Instruction.VectorZero, Local(OperandType.V128)); - } - - public Operand VectorZeroUpper64(Operand vector) - { - return Add(Instruction.VectorZeroUpper64, Local(OperandType.V128), vector); - } - - public Operand VectorZeroUpper96(Operand vector) - { - return Add(Instruction.VectorZeroUpper96, Local(OperandType.V128), vector); - } - - public Operand ZeroExtend16(OperandType type, Operand op1) - { - return Add(Instruction.ZeroExtend16, Local(type), op1); - } - - public Operand ZeroExtend32(OperandType type, Operand op1) - { - return Add(Instruction.ZeroExtend32, Local(type), op1); - } - - public Operand ZeroExtend8(OperandType type, Operand op1) - { - return Add(Instruction.ZeroExtend8, Local(type), op1); - } - - private void NewNextBlockIfNeeded() - { - if (_needsNewBlock) - { - NewNextBlock(); - } - } - - private Operand Add(Instruction inst, Operand dest = default) - { - NewNextBlockIfNeeded(); - - Operation operation = Operation.Factory.Operation(inst, dest); - - _irBlock.Operations.AddLast(operation); - - return dest; - } - - private Operand Add(Instruction inst, Operand dest, Operand[] sources) - { - NewNextBlockIfNeeded(); - - Operation operation = Operation.Factory.Operation(inst, dest, sources); - - _irBlock.Operations.AddLast(operation); - - return dest; - } - - private Operand Add(Instruction inst, Operand dest, Operand source0) - { - NewNextBlockIfNeeded(); - - Operation operation = Operation.Factory.Operation(inst, dest, source0); - - _irBlock.Operations.AddLast(operation); - - return dest; - } - - private Operand Add(Instruction inst, Operand dest, Operand source0, Operand source1) - { - NewNextBlockIfNeeded(); - - Operation operation = Operation.Factory.Operation(inst, dest, source0, source1); - - _irBlock.Operations.AddLast(operation); - - return dest; - } - - private Operand Add(Instruction inst, Operand dest, Operand source0, Operand source1, Operand source2) - { - NewNextBlockIfNeeded(); - - Operation operation = Operation.Factory.Operation(inst, dest, source0, source1, source2); - - _irBlock.Operations.AddLast(operation); - - return dest; - } - - public Operand AddIntrinsic(Intrinsic intrin, params Operand[] args) - { - return Add(intrin, Local(OperandType.V128), args); - } - - public Operand AddIntrinsicInt(Intrinsic intrin, params Operand[] args) - { - return Add(intrin, Local(OperandType.I32), args); - } - - public Operand AddIntrinsicLong(Intrinsic intrin, params Operand[] args) - { - return Add(intrin, Local(OperandType.I64), args); - } - - public void AddIntrinsicNoRet(Intrinsic intrin, params Operand[] args) - { - Add(intrin, default, args); - } - - private Operand Add(Intrinsic intrin, Operand dest, params Operand[] sources) - { - NewNextBlockIfNeeded(); - - Operation operation = Operation.Factory.Operation(intrin, dest, sources); - - _irBlock.Operations.AddLast(operation); - - return dest; - } - - private void BranchToLabel(Operand label, bool uncond, BasicBlockFrequency nextFreq) - { - if (!_irLabels.TryGetValue(label, out BasicBlock branchBlock)) - { - branchBlock = new BasicBlock(); - - _irLabels.Add(label, branchBlock); - } - - if (uncond) - { - _irBlock.AddSuccessor(branchBlock); - } - else - { - // Defer registration of successor to _irBlock so that the order of successors is correct. - _ifBlock = branchBlock; - } - - _needsNewBlock = true; - _nextBlockFreq = nextFreq; - } - - public void MarkLabel(Operand label, BasicBlockFrequency nextFreq = default) - { - _nextBlockFreq = nextFreq; - - if (_irLabels.TryGetValue(label, out BasicBlock nextBlock)) - { - nextBlock.Index = _irBlocks.Count; - - _irBlocks.AddLast(nextBlock); - - NextBlock(nextBlock); - } - else - { - NewNextBlock(); - - _irLabels.Add(label, _irBlock); - } - } - - private void NewNextBlock() - { - BasicBlock block = new BasicBlock(_irBlocks.Count); - - _irBlocks.AddLast(block); - - NextBlock(block); - } - - private void NextBlock(BasicBlock nextBlock) - { - if (_irBlock?.SuccessorsCount == 0 && !EndsWithUnconditional(_irBlock)) - { - _irBlock.AddSuccessor(nextBlock); - - if (_ifBlock != null) - { - _irBlock.AddSuccessor(_ifBlock); - - _ifBlock = null; - } - } - - _irBlock = nextBlock; - _irBlock.Frequency = _nextBlockFreq; - - _needsNewBlock = false; - _nextBlockFreq = BasicBlockFrequency.Default; - } - - private static bool EndsWithUnconditional(BasicBlock block) - { - Operation last = block.Operations.Last; - - return last != default && - (last.Instruction == Instruction.Return || - last.Instruction == Instruction.Tailcall); - } - - public ControlFlowGraph GetControlFlowGraph() - { - return new ControlFlowGraph(_irBlocks.First, _irBlocks, _localsCount); - } - } -} diff --git a/ARMeilleure/Translation/IntervalTree.cs b/ARMeilleure/Translation/IntervalTree.cs deleted file mode 100644 index 79662bc98..000000000 --- a/ARMeilleure/Translation/IntervalTree.cs +++ /dev/null @@ -1,754 +0,0 @@ -using System; -using System.Collections.Generic; - -namespace ARMeilleure.Translation -{ - /// - /// An Augmented Interval Tree based off of the "TreeDictionary"'s Red-Black Tree. Allows fast overlap checking of ranges. - /// - /// Key - /// Value - class IntervalTree where K : IComparable - { - private const int ArrayGrowthSize = 32; - - private const bool Black = true; - private const bool Red = false; - private IntervalTreeNode _root = null; - private int _count = 0; - - public int Count => _count; - - #region Public Methods - - /// - /// Gets the values of the interval whose key is . - /// - /// Key of the node value to get - /// Value with the given - /// True if the key is on the dictionary, false otherwise - public bool TryGet(K key, out V value) - { - IntervalTreeNode node = GetNode(key); - - if (node == null) - { - value = default; - return false; - } - - value = node.Value; - return true; - } - - /// - /// Returns the start addresses of the intervals whose start and end keys overlap the given range. - /// - /// Start of the range - /// End of the range - /// Overlaps array to place results in - /// Index to start writing results into the array. Defaults to 0 - /// Number of intervals found - public int Get(K start, K end, ref K[] overlaps, int overlapCount = 0) - { - GetKeys(_root, start, end, ref overlaps, ref overlapCount); - - return overlapCount; - } - - /// - /// Adds a new interval into the tree whose start is , end is and value is . - /// - /// Start of the range to add - /// End of the range to insert - /// Value to add - /// Optional factory used to create a new value if is already on the tree - /// is null - /// True if the value was added, false if the start key was already in the dictionary - public bool AddOrUpdate(K start, K end, V value, Func updateFactoryCallback) - { - if (value == null) - { - throw new ArgumentNullException(nameof(value)); - } - - return BSTInsert(start, end, value, updateFactoryCallback, out IntervalTreeNode node); - } - - /// - /// Gets an existing or adds a new interval into the tree whose start is , end is and value is . - /// - /// Start of the range to add - /// End of the range to insert - /// Value to add - /// is null - /// if is not yet on the tree, or the existing value otherwise - public V GetOrAdd(K start, K end, V value) - { - if (value == null) - { - throw new ArgumentNullException(nameof(value)); - } - - BSTInsert(start, end, value, null, out IntervalTreeNode node); - return node.Value; - } - - /// - /// Removes a value from the tree, searching for it with . - /// - /// Key of the node to remove - /// Number of deleted values - public int Remove(K key) - { - int removed = Delete(key); - - _count -= removed; - - return removed; - } - - /// - /// Adds all the nodes in the dictionary into . - /// - /// A list of all values sorted by Key Order - public List AsList() - { - List list = new List(); - - AddToList(_root, list); - - return list; - } - - #endregion - - #region Private Methods (BST) - - /// - /// Adds all values that are children of or contained within into , in Key Order. - /// - /// The node to search for values within - /// The list to add values to - private void AddToList(IntervalTreeNode node, List list) - { - if (node == null) - { - return; - } - - AddToList(node.Left, list); - - list.Add(node.Value); - - AddToList(node.Right, list); - } - - /// - /// Retrieve the node reference whose key is , or null if no such node exists. - /// - /// Key of the node to get - /// is null - /// Node reference in the tree - private IntervalTreeNode GetNode(K key) - { - if (key == null) - { - throw new ArgumentNullException(nameof(key)); - } - - IntervalTreeNode node = _root; - while (node != null) - { - int cmp = key.CompareTo(node.Start); - if (cmp < 0) - { - node = node.Left; - } - else if (cmp > 0) - { - node = node.Right; - } - else - { - return node; - } - } - return null; - } - - /// - /// Retrieve all keys that overlap the given start and end keys. - /// - /// Start of the range - /// End of the range - /// Overlaps array to place results in - /// Overlaps count to update - private void GetKeys(IntervalTreeNode node, K start, K end, ref K[] overlaps, ref int overlapCount) - { - if (node == null || start.CompareTo(node.Max) >= 0) - { - return; - } - - GetKeys(node.Left, start, end, ref overlaps, ref overlapCount); - - bool endsOnRight = end.CompareTo(node.Start) > 0; - if (endsOnRight) - { - if (start.CompareTo(node.End) < 0) - { - if (overlaps.Length >= overlapCount) - { - Array.Resize(ref overlaps, overlapCount + ArrayGrowthSize); - } - - overlaps[overlapCount++] = node.Start; - } - - GetKeys(node.Right, start, end, ref overlaps, ref overlapCount); - } - } - - /// - /// Propagate an increase in max value starting at the given node, heading up the tree. - /// This should only be called if the max increases - not for rebalancing or removals. - /// - /// The node to start propagating from - private void PropagateIncrease(IntervalTreeNode node) - { - K max = node.Max; - IntervalTreeNode ptr = node; - - while ((ptr = ptr.Parent) != null) - { - if (max.CompareTo(ptr.Max) > 0) - { - ptr.Max = max; - } - else - { - break; - } - } - } - - /// - /// Propagate recalculating max value starting at the given node, heading up the tree. - /// This fully recalculates the max value from all children when there is potential for it to decrease. - /// - /// The node to start propagating from - private void PropagateFull(IntervalTreeNode node) - { - IntervalTreeNode ptr = node; - - do - { - K max = ptr.End; - - if (ptr.Left != null && ptr.Left.Max.CompareTo(max) > 0) - { - max = ptr.Left.Max; - } - - if (ptr.Right != null && ptr.Right.Max.CompareTo(max) > 0) - { - max = ptr.Right.Max; - } - - ptr.Max = max; - } while ((ptr = ptr.Parent) != null); - } - - /// - /// Insertion Mechanism for the interval tree. Similar to a BST insert, with the start of the range as the key. - /// Iterates the tree starting from the root and inserts a new node where all children in the left subtree are less than , and all children in the right subtree are greater than . - /// Each node can contain multiple values, and has an end address which is the maximum of all those values. - /// Post insertion, the "max" value of the node and all parents are updated. - /// - /// Start of the range to insert - /// End of the range to insert - /// Value to insert - /// Optional factory used to create a new value if is already on the tree - /// Node that was inserted or modified - /// True if was not yet on the tree, false otherwise - private bool BSTInsert(K start, K end, V value, Func updateFactoryCallback, out IntervalTreeNode outNode) - { - IntervalTreeNode parent = null; - IntervalTreeNode node = _root; - - while (node != null) - { - parent = node; - int cmp = start.CompareTo(node.Start); - if (cmp < 0) - { - node = node.Left; - } - else if (cmp > 0) - { - node = node.Right; - } - else - { - outNode = node; - - if (updateFactoryCallback != null) - { - // Replace - node.Value = updateFactoryCallback(start, node.Value); - - int endCmp = end.CompareTo(node.End); - - if (endCmp > 0) - { - node.End = end; - if (end.CompareTo(node.Max) > 0) - { - node.Max = end; - PropagateIncrease(node); - RestoreBalanceAfterInsertion(node); - } - } - else if (endCmp < 0) - { - node.End = end; - PropagateFull(node); - } - } - - return false; - } - } - IntervalTreeNode newNode = new IntervalTreeNode(start, end, value, parent); - if (newNode.Parent == null) - { - _root = newNode; - } - else if (start.CompareTo(parent.Start) < 0) - { - parent.Left = newNode; - } - else - { - parent.Right = newNode; - } - - PropagateIncrease(newNode); - _count++; - RestoreBalanceAfterInsertion(newNode); - outNode = newNode; - return true; - } - - /// - /// Removes the value from the dictionary after searching for it with . - /// - /// Key to search for - /// Number of deleted values - private int Delete(K key) - { - IntervalTreeNode nodeToDelete = GetNode(key); - - if (nodeToDelete == null) - { - return 0; - } - - IntervalTreeNode replacementNode; - - if (LeftOf(nodeToDelete) == null || RightOf(nodeToDelete) == null) - { - replacementNode = nodeToDelete; - } - else - { - replacementNode = PredecessorOf(nodeToDelete); - } - - IntervalTreeNode tmp = LeftOf(replacementNode) ?? RightOf(replacementNode); - - if (tmp != null) - { - tmp.Parent = ParentOf(replacementNode); - } - - if (ParentOf(replacementNode) == null) - { - _root = tmp; - } - else if (replacementNode == LeftOf(ParentOf(replacementNode))) - { - ParentOf(replacementNode).Left = tmp; - } - else - { - ParentOf(replacementNode).Right = tmp; - } - - if (replacementNode != nodeToDelete) - { - nodeToDelete.Start = replacementNode.Start; - nodeToDelete.Value = replacementNode.Value; - nodeToDelete.End = replacementNode.End; - nodeToDelete.Max = replacementNode.Max; - } - - PropagateFull(replacementNode); - - if (tmp != null && ColorOf(replacementNode) == Black) - { - RestoreBalanceAfterRemoval(tmp); - } - - return 1; - } - - /// - /// Returns the node with the largest key where is considered the root node. - /// - /// Root Node - /// Node with the maximum key in the tree of - private static IntervalTreeNode Maximum(IntervalTreeNode node) - { - IntervalTreeNode tmp = node; - while (tmp.Right != null) - { - tmp = tmp.Right; - } - - return tmp; - } - - /// - /// Finds the node whose key is immediately less than . - /// - /// Node to find the predecessor of - /// Predecessor of - private static IntervalTreeNode PredecessorOf(IntervalTreeNode node) - { - if (node.Left != null) - { - return Maximum(node.Left); - } - IntervalTreeNode parent = node.Parent; - while (parent != null && node == parent.Left) - { - node = parent; - parent = parent.Parent; - } - return parent; - } - - #endregion - - #region Private Methods (RBL) - - private void RestoreBalanceAfterRemoval(IntervalTreeNode balanceNode) - { - IntervalTreeNode ptr = balanceNode; - - while (ptr != _root && ColorOf(ptr) == Black) - { - if (ptr == LeftOf(ParentOf(ptr))) - { - IntervalTreeNode sibling = RightOf(ParentOf(ptr)); - - if (ColorOf(sibling) == Red) - { - SetColor(sibling, Black); - SetColor(ParentOf(ptr), Red); - RotateLeft(ParentOf(ptr)); - sibling = RightOf(ParentOf(ptr)); - } - if (ColorOf(LeftOf(sibling)) == Black && ColorOf(RightOf(sibling)) == Black) - { - SetColor(sibling, Red); - ptr = ParentOf(ptr); - } - else - { - if (ColorOf(RightOf(sibling)) == Black) - { - SetColor(LeftOf(sibling), Black); - SetColor(sibling, Red); - RotateRight(sibling); - sibling = RightOf(ParentOf(ptr)); - } - SetColor(sibling, ColorOf(ParentOf(ptr))); - SetColor(ParentOf(ptr), Black); - SetColor(RightOf(sibling), Black); - RotateLeft(ParentOf(ptr)); - ptr = _root; - } - } - else - { - IntervalTreeNode sibling = LeftOf(ParentOf(ptr)); - - if (ColorOf(sibling) == Red) - { - SetColor(sibling, Black); - SetColor(ParentOf(ptr), Red); - RotateRight(ParentOf(ptr)); - sibling = LeftOf(ParentOf(ptr)); - } - if (ColorOf(RightOf(sibling)) == Black && ColorOf(LeftOf(sibling)) == Black) - { - SetColor(sibling, Red); - ptr = ParentOf(ptr); - } - else - { - if (ColorOf(LeftOf(sibling)) == Black) - { - SetColor(RightOf(sibling), Black); - SetColor(sibling, Red); - RotateLeft(sibling); - sibling = LeftOf(ParentOf(ptr)); - } - SetColor(sibling, ColorOf(ParentOf(ptr))); - SetColor(ParentOf(ptr), Black); - SetColor(LeftOf(sibling), Black); - RotateRight(ParentOf(ptr)); - ptr = _root; - } - } - } - SetColor(ptr, Black); - } - - private void RestoreBalanceAfterInsertion(IntervalTreeNode balanceNode) - { - SetColor(balanceNode, Red); - while (balanceNode != null && balanceNode != _root && ColorOf(ParentOf(balanceNode)) == Red) - { - if (ParentOf(balanceNode) == LeftOf(ParentOf(ParentOf(balanceNode)))) - { - IntervalTreeNode sibling = RightOf(ParentOf(ParentOf(balanceNode))); - - if (ColorOf(sibling) == Red) - { - SetColor(ParentOf(balanceNode), Black); - SetColor(sibling, Black); - SetColor(ParentOf(ParentOf(balanceNode)), Red); - balanceNode = ParentOf(ParentOf(balanceNode)); - } - else - { - if (balanceNode == RightOf(ParentOf(balanceNode))) - { - balanceNode = ParentOf(balanceNode); - RotateLeft(balanceNode); - } - SetColor(ParentOf(balanceNode), Black); - SetColor(ParentOf(ParentOf(balanceNode)), Red); - RotateRight(ParentOf(ParentOf(balanceNode))); - } - } - else - { - IntervalTreeNode sibling = LeftOf(ParentOf(ParentOf(balanceNode))); - - if (ColorOf(sibling) == Red) - { - SetColor(ParentOf(balanceNode), Black); - SetColor(sibling, Black); - SetColor(ParentOf(ParentOf(balanceNode)), Red); - balanceNode = ParentOf(ParentOf(balanceNode)); - } - else - { - if (balanceNode == LeftOf(ParentOf(balanceNode))) - { - balanceNode = ParentOf(balanceNode); - RotateRight(balanceNode); - } - SetColor(ParentOf(balanceNode), Black); - SetColor(ParentOf(ParentOf(balanceNode)), Red); - RotateLeft(ParentOf(ParentOf(balanceNode))); - } - } - } - SetColor(_root, Black); - } - - private void RotateLeft(IntervalTreeNode node) - { - if (node != null) - { - IntervalTreeNode right = RightOf(node); - node.Right = LeftOf(right); - if (node.Right != null) - { - node.Right.Parent = node; - } - IntervalTreeNode nodeParent = ParentOf(node); - right.Parent = nodeParent; - if (nodeParent == null) - { - _root = right; - } - else if (node == LeftOf(nodeParent)) - { - nodeParent.Left = right; - } - else - { - nodeParent.Right = right; - } - right.Left = node; - node.Parent = right; - - PropagateFull(node); - } - } - - private void RotateRight(IntervalTreeNode node) - { - if (node != null) - { - IntervalTreeNode left = LeftOf(node); - node.Left = RightOf(left); - if (node.Left != null) - { - node.Left.Parent = node; - } - IntervalTreeNode nodeParent = ParentOf(node); - left.Parent = nodeParent; - if (nodeParent == null) - { - _root = left; - } - else if (node == RightOf(nodeParent)) - { - nodeParent.Right = left; - } - else - { - nodeParent.Left = left; - } - left.Right = node; - node.Parent = left; - - PropagateFull(node); - } - } - - #endregion - - #region Safety-Methods - - // These methods save memory by allowing us to forego sentinel nil nodes, as well as serve as protection against NullReferenceExceptions. - - /// - /// Returns the color of , or Black if it is null. - /// - /// Node - /// The boolean color of , or black if null - private static bool ColorOf(IntervalTreeNode node) - { - return node == null || node.Color; - } - - /// - /// Sets the color of node to . - ///

- /// This method does nothing if is null. - ///
- /// Node to set the color of - /// Color (Boolean) - private static void SetColor(IntervalTreeNode node, bool color) - { - if (node != null) - { - node.Color = color; - } - } - - /// - /// This method returns the left node of , or null if is null. - /// - /// Node to retrieve the left child from - /// Left child of - private static IntervalTreeNode LeftOf(IntervalTreeNode node) - { - return node?.Left; - } - - /// - /// This method returns the right node of , or null if is null. - /// - /// Node to retrieve the right child from - /// Right child of - private static IntervalTreeNode RightOf(IntervalTreeNode node) - { - return node?.Right; - } - - /// - /// Returns the parent node of , or null if is null. - /// - /// Node to retrieve the parent from - /// Parent of - private static IntervalTreeNode ParentOf(IntervalTreeNode node) - { - return node?.Parent; - } - - #endregion - - public bool ContainsKey(K key) - { - return GetNode(key) != null; - } - - public void Clear() - { - _root = null; - _count = 0; - } - } - - /// - /// Represents a node in the IntervalTree which contains start and end keys of type K, and a value of generic type V. - /// - /// Key type of the node - /// Value type of the node - class IntervalTreeNode - { - public bool Color = true; - public IntervalTreeNode Left = null; - public IntervalTreeNode Right = null; - public IntervalTreeNode Parent = null; - - /// - /// The start of the range. - /// - public K Start; - - /// - /// The end of the range. - /// - public K End; - - /// - /// The maximum end value of this node and all its children. - /// - public K Max; - - /// - /// Value stored on this node. - /// - public V Value; - - public IntervalTreeNode(K start, K end, V value, IntervalTreeNode parent) - { - Start = start; - End = end; - Max = end; - Value = value; - Parent = parent; - } - } -} diff --git a/ARMeilleure/Translation/PTC/Ptc.cs b/ARMeilleure/Translation/PTC/Ptc.cs deleted file mode 100644 index f4ae411b7..000000000 --- a/ARMeilleure/Translation/PTC/Ptc.cs +++ /dev/null @@ -1,1097 +0,0 @@ -using ARMeilleure.CodeGen; -using ARMeilleure.CodeGen.Linking; -using ARMeilleure.CodeGen.Unwinding; -using ARMeilleure.CodeGen.X86; -using ARMeilleure.Common; -using ARMeilleure.Memory; -using Ryujinx.Common; -using Ryujinx.Common.Configuration; -using Ryujinx.Common.Logging; -using System; -using System.Buffers.Binary; -using System.Collections.Generic; -using System.Diagnostics; -using System.IO; -using System.IO.Compression; -using System.Runtime; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -using System.Threading; - -using static ARMeilleure.Translation.PTC.PtcFormatter; - -namespace ARMeilleure.Translation.PTC -{ - public static class Ptc - { - private const string OuterHeaderMagicString = "PTCohd\0\0"; - private const string InnerHeaderMagicString = "PTCihd\0\0"; - - private const uint InternalVersion = 3703; //! To be incremented manually for each change to the ARMeilleure project. - - private const string ActualDir = "0"; - private const string BackupDir = "1"; - - private const string TitleIdTextDefault = "0000000000000000"; - private const string DisplayVersionDefault = "0"; - - internal static readonly Symbol PageTableSymbol = new(SymbolType.Special, 1); - internal static readonly Symbol CountTableSymbol = new(SymbolType.Special, 2); - internal static readonly Symbol DispatchStubSymbol = new(SymbolType.Special, 3); - - private const byte FillingByte = 0x00; - private const CompressionLevel SaveCompressionLevel = CompressionLevel.Fastest; - - // Carriers. - private static MemoryStream _infosStream; - private static List _codesList; - private static MemoryStream _relocsStream; - private static MemoryStream _unwindInfosStream; - - private static readonly ulong _outerHeaderMagic; - private static readonly ulong _innerHeaderMagic; - - private static readonly ManualResetEvent _waitEvent; - - private static readonly object _lock; - - private static bool _disposed; - - internal static string TitleIdText { get; private set; } - internal static string DisplayVersion { get; private set; } - - private static MemoryManagerMode _memoryMode; - - internal static string CachePathActual { get; private set; } - internal static string CachePathBackup { get; private set; } - - internal static PtcState State { get; private set; } - - // Progress reporting helpers. - private static volatile int _translateCount; - private static volatile int _translateTotalCount; - public static event Action PtcStateChanged; - - static Ptc() - { - InitializeCarriers(); - - _outerHeaderMagic = BinaryPrimitives.ReadUInt64LittleEndian(EncodingCache.UTF8NoBOM.GetBytes(OuterHeaderMagicString).AsSpan()); - _innerHeaderMagic = BinaryPrimitives.ReadUInt64LittleEndian(EncodingCache.UTF8NoBOM.GetBytes(InnerHeaderMagicString).AsSpan()); - - _waitEvent = new ManualResetEvent(true); - - _lock = new object(); - - _disposed = false; - - TitleIdText = TitleIdTextDefault; - DisplayVersion = DisplayVersionDefault; - - CachePathActual = string.Empty; - CachePathBackup = string.Empty; - - Disable(); - } - - public static void Initialize(string titleIdText, string displayVersion, bool enabled, MemoryManagerMode memoryMode) - { - Wait(); - - PtcProfiler.Wait(); - PtcProfiler.ClearEntries(); - - Logger.Info?.Print(LogClass.Ptc, $"Initializing Profiled Persistent Translation Cache (enabled: {enabled})."); - - if (!enabled || string.IsNullOrEmpty(titleIdText) || titleIdText == TitleIdTextDefault) - { - TitleIdText = TitleIdTextDefault; - DisplayVersion = DisplayVersionDefault; - - CachePathActual = string.Empty; - CachePathBackup = string.Empty; - - Disable(); - - return; - } - - TitleIdText = titleIdText; - DisplayVersion = !string.IsNullOrEmpty(displayVersion) ? displayVersion : DisplayVersionDefault; - _memoryMode = memoryMode; - - string workPathActual = Path.Combine(AppDataManager.GamesDirPath, TitleIdText, "cache", "cpu", ActualDir); - string workPathBackup = Path.Combine(AppDataManager.GamesDirPath, TitleIdText, "cache", "cpu", BackupDir); - - if (!Directory.Exists(workPathActual)) - { - Directory.CreateDirectory(workPathActual); - } - - if (!Directory.Exists(workPathBackup)) - { - Directory.CreateDirectory(workPathBackup); - } - - CachePathActual = Path.Combine(workPathActual, DisplayVersion); - CachePathBackup = Path.Combine(workPathBackup, DisplayVersion); - - PreLoad(); - PtcProfiler.PreLoad(); - - Enable(); - } - - private static void InitializeCarriers() - { - _infosStream = new MemoryStream(); - _codesList = new List(); - _relocsStream = new MemoryStream(); - _unwindInfosStream = new MemoryStream(); - } - - private static void DisposeCarriers() - { - _infosStream.Dispose(); - _codesList.Clear(); - _relocsStream.Dispose(); - _unwindInfosStream.Dispose(); - } - - private static bool AreCarriersEmpty() - { - return _infosStream.Length == 0L && _codesList.Count == 0 && _relocsStream.Length == 0L && _unwindInfosStream.Length == 0L; - } - - private static void ResetCarriersIfNeeded() - { - if (AreCarriersEmpty()) - { - return; - } - - DisposeCarriers(); - - InitializeCarriers(); - } - - private static void PreLoad() - { - string fileNameActual = string.Concat(CachePathActual, ".cache"); - string fileNameBackup = string.Concat(CachePathBackup, ".cache"); - - FileInfo fileInfoActual = new FileInfo(fileNameActual); - FileInfo fileInfoBackup = new FileInfo(fileNameBackup); - - if (fileInfoActual.Exists && fileInfoActual.Length != 0L) - { - if (!Load(fileNameActual, false)) - { - if (fileInfoBackup.Exists && fileInfoBackup.Length != 0L) - { - Load(fileNameBackup, true); - } - } - } - else if (fileInfoBackup.Exists && fileInfoBackup.Length != 0L) - { - Load(fileNameBackup, true); - } - } - - private static unsafe bool Load(string fileName, bool isBackup) - { - using (FileStream compressedStream = new(fileName, FileMode.Open)) - using (DeflateStream deflateStream = new(compressedStream, CompressionMode.Decompress, true)) - { - OuterHeader outerHeader = DeserializeStructure(compressedStream); - - if (!outerHeader.IsHeaderValid()) - { - InvalidateCompressedStream(compressedStream); - - return false; - } - - if (outerHeader.Magic != _outerHeaderMagic) - { - InvalidateCompressedStream(compressedStream); - - return false; - } - - if (outerHeader.CacheFileVersion != InternalVersion) - { - InvalidateCompressedStream(compressedStream); - - return false; - } - - if (outerHeader.Endianness != GetEndianness()) - { - InvalidateCompressedStream(compressedStream); - - return false; - } - - if (outerHeader.FeatureInfo != GetFeatureInfo()) - { - InvalidateCompressedStream(compressedStream); - - return false; - } - - if (outerHeader.MemoryManagerMode != GetMemoryManagerMode()) - { - InvalidateCompressedStream(compressedStream); - - return false; - } - - if (outerHeader.OSPlatform != GetOSPlatform()) - { - InvalidateCompressedStream(compressedStream); - - return false; - } - - IntPtr intPtr = IntPtr.Zero; - - try - { - intPtr = Marshal.AllocHGlobal(new IntPtr(outerHeader.UncompressedStreamSize)); - - using (UnmanagedMemoryStream stream = new((byte*)intPtr.ToPointer(), outerHeader.UncompressedStreamSize, outerHeader.UncompressedStreamSize, FileAccess.ReadWrite)) - { - try - { - deflateStream.CopyTo(stream); - } - catch - { - InvalidateCompressedStream(compressedStream); - - return false; - } - - Debug.Assert(stream.Position == stream.Length); - - stream.Seek(0L, SeekOrigin.Begin); - - InnerHeader innerHeader = DeserializeStructure(stream); - - if (!innerHeader.IsHeaderValid()) - { - InvalidateCompressedStream(compressedStream); - - return false; - } - - if (innerHeader.Magic != _innerHeaderMagic) - { - InvalidateCompressedStream(compressedStream); - - return false; - } - - ReadOnlySpan infosBytes = new(stream.PositionPointer, innerHeader.InfosLength); - stream.Seek(innerHeader.InfosLength, SeekOrigin.Current); - - Hash128 infosHash = XXHash128.ComputeHash(infosBytes); - - if (innerHeader.InfosHash != infosHash) - { - InvalidateCompressedStream(compressedStream); - - return false; - } - - ReadOnlySpan codesBytes = (int)innerHeader.CodesLength > 0 ? new(stream.PositionPointer, (int)innerHeader.CodesLength) : ReadOnlySpan.Empty; - stream.Seek(innerHeader.CodesLength, SeekOrigin.Current); - - Hash128 codesHash = XXHash128.ComputeHash(codesBytes); - - if (innerHeader.CodesHash != codesHash) - { - InvalidateCompressedStream(compressedStream); - - return false; - } - - ReadOnlySpan relocsBytes = new(stream.PositionPointer, innerHeader.RelocsLength); - stream.Seek(innerHeader.RelocsLength, SeekOrigin.Current); - - Hash128 relocsHash = XXHash128.ComputeHash(relocsBytes); - - if (innerHeader.RelocsHash != relocsHash) - { - InvalidateCompressedStream(compressedStream); - - return false; - } - - ReadOnlySpan unwindInfosBytes = new(stream.PositionPointer, innerHeader.UnwindInfosLength); - stream.Seek(innerHeader.UnwindInfosLength, SeekOrigin.Current); - - Hash128 unwindInfosHash = XXHash128.ComputeHash(unwindInfosBytes); - - if (innerHeader.UnwindInfosHash != unwindInfosHash) - { - InvalidateCompressedStream(compressedStream); - - return false; - } - - Debug.Assert(stream.Position == stream.Length); - - stream.Seek((long)Unsafe.SizeOf(), SeekOrigin.Begin); - - _infosStream.Write(infosBytes); - stream.Seek(innerHeader.InfosLength, SeekOrigin.Current); - - _codesList.ReadFrom(stream); - - _relocsStream.Write(relocsBytes); - stream.Seek(innerHeader.RelocsLength, SeekOrigin.Current); - - _unwindInfosStream.Write(unwindInfosBytes); - stream.Seek(innerHeader.UnwindInfosLength, SeekOrigin.Current); - - Debug.Assert(stream.Position == stream.Length); - } - } - finally - { - if (intPtr != IntPtr.Zero) - { - Marshal.FreeHGlobal(intPtr); - } - } - } - - long fileSize = new FileInfo(fileName).Length; - - Logger.Info?.Print(LogClass.Ptc, $"{(isBackup ? "Loaded Backup Translation Cache" : "Loaded Translation Cache")} (size: {fileSize} bytes, translated functions: {GetEntriesCount()})."); - - return true; - } - - private static void InvalidateCompressedStream(FileStream compressedStream) - { - compressedStream.SetLength(0L); - } - - private static void PreSave() - { - _waitEvent.Reset(); - - try - { - string fileNameActual = string.Concat(CachePathActual, ".cache"); - string fileNameBackup = string.Concat(CachePathBackup, ".cache"); - - FileInfo fileInfoActual = new FileInfo(fileNameActual); - - if (fileInfoActual.Exists && fileInfoActual.Length != 0L) - { - File.Copy(fileNameActual, fileNameBackup, true); - } - - Save(fileNameActual); - } - finally - { - ResetCarriersIfNeeded(); - - GCSettings.LargeObjectHeapCompactionMode = GCLargeObjectHeapCompactionMode.CompactOnce; - } - - _waitEvent.Set(); - } - - private static unsafe void Save(string fileName) - { - int translatedFuncsCount; - - InnerHeader innerHeader = new InnerHeader(); - - innerHeader.Magic = _innerHeaderMagic; - - innerHeader.InfosLength = (int)_infosStream.Length; - innerHeader.CodesLength = _codesList.Length(); - innerHeader.RelocsLength = (int)_relocsStream.Length; - innerHeader.UnwindInfosLength = (int)_unwindInfosStream.Length; - - OuterHeader outerHeader = new OuterHeader(); - - outerHeader.Magic = _outerHeaderMagic; - - outerHeader.CacheFileVersion = InternalVersion; - outerHeader.Endianness = GetEndianness(); - outerHeader.FeatureInfo = GetFeatureInfo(); - outerHeader.MemoryManagerMode = GetMemoryManagerMode(); - outerHeader.OSPlatform = GetOSPlatform(); - - outerHeader.UncompressedStreamSize = - (long)Unsafe.SizeOf() + - innerHeader.InfosLength + - innerHeader.CodesLength + - innerHeader.RelocsLength + - innerHeader.UnwindInfosLength; - - outerHeader.SetHeaderHash(); - - IntPtr intPtr = IntPtr.Zero; - - try - { - intPtr = Marshal.AllocHGlobal(new IntPtr(outerHeader.UncompressedStreamSize)); - - using (UnmanagedMemoryStream stream = new((byte*)intPtr.ToPointer(), outerHeader.UncompressedStreamSize, outerHeader.UncompressedStreamSize, FileAccess.ReadWrite)) - { - stream.Seek((long)Unsafe.SizeOf(), SeekOrigin.Begin); - - ReadOnlySpan infosBytes = new(stream.PositionPointer, innerHeader.InfosLength); - _infosStream.WriteTo(stream); - - ReadOnlySpan codesBytes = (int)innerHeader.CodesLength > 0 ? new(stream.PositionPointer, (int)innerHeader.CodesLength) : ReadOnlySpan.Empty; - _codesList.WriteTo(stream); - - ReadOnlySpan relocsBytes = new(stream.PositionPointer, innerHeader.RelocsLength); - _relocsStream.WriteTo(stream); - - ReadOnlySpan unwindInfosBytes = new(stream.PositionPointer, innerHeader.UnwindInfosLength); - _unwindInfosStream.WriteTo(stream); - - Debug.Assert(stream.Position == stream.Length); - - innerHeader.InfosHash = XXHash128.ComputeHash(infosBytes); - innerHeader.CodesHash = XXHash128.ComputeHash(codesBytes); - innerHeader.RelocsHash = XXHash128.ComputeHash(relocsBytes); - innerHeader.UnwindInfosHash = XXHash128.ComputeHash(unwindInfosBytes); - - innerHeader.SetHeaderHash(); - - stream.Seek(0L, SeekOrigin.Begin); - SerializeStructure(stream, innerHeader); - - translatedFuncsCount = GetEntriesCount(); - - ResetCarriersIfNeeded(); - - using (FileStream compressedStream = new(fileName, FileMode.OpenOrCreate)) - using (DeflateStream deflateStream = new(compressedStream, SaveCompressionLevel, true)) - { - try - { - SerializeStructure(compressedStream, outerHeader); - - stream.Seek(0L, SeekOrigin.Begin); - stream.CopyTo(deflateStream); - } - catch - { - compressedStream.Position = 0L; - } - - if (compressedStream.Position < compressedStream.Length) - { - compressedStream.SetLength(compressedStream.Position); - } - } - } - } - finally - { - if (intPtr != IntPtr.Zero) - { - Marshal.FreeHGlobal(intPtr); - } - } - - long fileSize = new FileInfo(fileName).Length; - - if (fileSize != 0L) - { - Logger.Info?.Print(LogClass.Ptc, $"Saved Translation Cache (size: {fileSize} bytes, translated functions: {translatedFuncsCount})."); - } - } - - internal static void LoadTranslations(Translator translator) - { - if (AreCarriersEmpty()) - { - return; - } - - long infosStreamLength = _infosStream.Length; - long relocsStreamLength = _relocsStream.Length; - long unwindInfosStreamLength = _unwindInfosStream.Length; - - _infosStream.Seek(0L, SeekOrigin.Begin); - _relocsStream.Seek(0L, SeekOrigin.Begin); - _unwindInfosStream.Seek(0L, SeekOrigin.Begin); - - using (BinaryReader relocsReader = new(_relocsStream, EncodingCache.UTF8NoBOM, true)) - using (BinaryReader unwindInfosReader = new(_unwindInfosStream, EncodingCache.UTF8NoBOM, true)) - { - for (int index = 0; index < GetEntriesCount(); index++) - { - InfoEntry infoEntry = DeserializeStructure(_infosStream); - - if (infoEntry.Stubbed) - { - SkipCode(index, infoEntry.CodeLength); - SkipReloc(infoEntry.RelocEntriesCount); - SkipUnwindInfo(unwindInfosReader); - - continue; - } - - bool isEntryChanged = infoEntry.Hash != ComputeHash(translator.Memory, infoEntry.Address, infoEntry.GuestSize); - - if (isEntryChanged || (!infoEntry.HighCq && PtcProfiler.ProfiledFuncs.TryGetValue(infoEntry.Address, out var value) && value.HighCq)) - { - infoEntry.Stubbed = true; - infoEntry.CodeLength = 0; - UpdateInfo(infoEntry); - - StubCode(index); - StubReloc(infoEntry.RelocEntriesCount); - StubUnwindInfo(unwindInfosReader); - - if (isEntryChanged) - { - Logger.Info?.Print(LogClass.Ptc, $"Invalidated translated function (address: 0x{infoEntry.Address:X16})"); - } - - continue; - } - - byte[] code = ReadCode(index, infoEntry.CodeLength); - - Counter callCounter = null; - - if (infoEntry.RelocEntriesCount != 0) - { - RelocEntry[] relocEntries = GetRelocEntries(relocsReader, infoEntry.RelocEntriesCount); - - PatchCode(translator, code, relocEntries, out callCounter); - } - - UnwindInfo unwindInfo = ReadUnwindInfo(unwindInfosReader); - - TranslatedFunction func = FastTranslate(code, callCounter, infoEntry.GuestSize, unwindInfo, infoEntry.HighCq); - - translator.RegisterFunction(infoEntry.Address, func); - - bool isAddressUnique = translator.Functions.TryAdd(infoEntry.Address, infoEntry.GuestSize, func); - - Debug.Assert(isAddressUnique, $"The address 0x{infoEntry.Address:X16} is not unique."); - } - } - - if (_infosStream.Length != infosStreamLength || _infosStream.Position != infosStreamLength || - _relocsStream.Length != relocsStreamLength || _relocsStream.Position != relocsStreamLength || - _unwindInfosStream.Length != unwindInfosStreamLength || _unwindInfosStream.Position != unwindInfosStreamLength) - { - throw new Exception("The length of a memory stream has changed, or its position has not reached or has exceeded its end."); - } - - Logger.Info?.Print(LogClass.Ptc, $"{translator.Functions.Count} translated functions loaded"); - } - - private static int GetEntriesCount() - { - return _codesList.Count; - } - - [Conditional("DEBUG")] - private static void SkipCode(int index, int codeLength) - { - Debug.Assert(_codesList[index].Length == 0); - Debug.Assert(codeLength == 0); - } - - private static void SkipReloc(int relocEntriesCount) - { - _relocsStream.Seek(relocEntriesCount * RelocEntry.Stride, SeekOrigin.Current); - } - - private static void SkipUnwindInfo(BinaryReader unwindInfosReader) - { - int pushEntriesLength = unwindInfosReader.ReadInt32(); - - _unwindInfosStream.Seek(pushEntriesLength * UnwindPushEntry.Stride + UnwindInfo.Stride, SeekOrigin.Current); - } - - private static byte[] ReadCode(int index, int codeLength) - { - Debug.Assert(_codesList[index].Length == codeLength); - - return _codesList[index]; - } - - private static RelocEntry[] GetRelocEntries(BinaryReader relocsReader, int relocEntriesCount) - { - RelocEntry[] relocEntries = new RelocEntry[relocEntriesCount]; - - for (int i = 0; i < relocEntriesCount; i++) - { - int position = relocsReader.ReadInt32(); - SymbolType type = (SymbolType)relocsReader.ReadByte(); - ulong value = relocsReader.ReadUInt64(); - - relocEntries[i] = new RelocEntry(position, new Symbol(type, value)); - } - - return relocEntries; - } - - private static void PatchCode(Translator translator, Span code, RelocEntry[] relocEntries, out Counter callCounter) - { - callCounter = null; - - foreach (RelocEntry relocEntry in relocEntries) - { - IntPtr? imm = null; - Symbol symbol = relocEntry.Symbol; - - if (symbol.Type == SymbolType.FunctionTable) - { - ulong guestAddress = symbol.Value; - - if (translator.FunctionTable.IsValid(guestAddress)) - { - unsafe { imm = (IntPtr)Unsafe.AsPointer(ref translator.FunctionTable.GetValue(guestAddress)); } - } - } - else if (symbol.Type == SymbolType.DelegateTable) - { - int index = (int)symbol.Value; - - if (Delegates.TryGetDelegateFuncPtrByIndex(index, out IntPtr funcPtr)) - { - imm = funcPtr; - } - } - else if (symbol == PageTableSymbol) - { - imm = translator.Memory.PageTablePointer; - } - else if (symbol == CountTableSymbol) - { - if (callCounter == null) - { - callCounter = new Counter(translator.CountTable); - } - - unsafe { imm = (IntPtr)Unsafe.AsPointer(ref callCounter.Value); } - } - else if (symbol == DispatchStubSymbol) - { - imm = translator.Stubs.DispatchStub; - } - - if (imm == null) - { - throw new Exception($"Unexpected reloc entry {relocEntry}."); - } - - BinaryPrimitives.WriteUInt64LittleEndian(code.Slice(relocEntry.Position, 8), (ulong)imm.Value); - } - } - - private static UnwindInfo ReadUnwindInfo(BinaryReader unwindInfosReader) - { - int pushEntriesLength = unwindInfosReader.ReadInt32(); - - UnwindPushEntry[] pushEntries = new UnwindPushEntry[pushEntriesLength]; - - for (int i = 0; i < pushEntriesLength; i++) - { - int pseudoOp = unwindInfosReader.ReadInt32(); - int prologOffset = unwindInfosReader.ReadInt32(); - int regIndex = unwindInfosReader.ReadInt32(); - int stackOffsetOrAllocSize = unwindInfosReader.ReadInt32(); - - pushEntries[i] = new UnwindPushEntry((UnwindPseudoOp)pseudoOp, prologOffset, regIndex, stackOffsetOrAllocSize); - } - - int prologueSize = unwindInfosReader.ReadInt32(); - - return new UnwindInfo(pushEntries, prologueSize); - } - - private static TranslatedFunction FastTranslate( - byte[] code, - Counter callCounter, - ulong guestSize, - UnwindInfo unwindInfo, - bool highCq) - { - var cFunc = new CompiledFunction(code, unwindInfo, RelocInfo.Empty); - var gFunc = cFunc.Map(); - - return new TranslatedFunction(gFunc, callCounter, guestSize, highCq); - } - - private static void UpdateInfo(InfoEntry infoEntry) - { - _infosStream.Seek(-Unsafe.SizeOf(), SeekOrigin.Current); - - SerializeStructure(_infosStream, infoEntry); - } - - private static void StubCode(int index) - { - _codesList[index] = Array.Empty(); - } - - private static void StubReloc(int relocEntriesCount) - { - for (int i = 0; i < relocEntriesCount * RelocEntry.Stride; i++) - { - _relocsStream.WriteByte(FillingByte); - } - } - - private static void StubUnwindInfo(BinaryReader unwindInfosReader) - { - int pushEntriesLength = unwindInfosReader.ReadInt32(); - - for (int i = 0; i < pushEntriesLength * UnwindPushEntry.Stride + UnwindInfo.Stride; i++) - { - _unwindInfosStream.WriteByte(FillingByte); - } - } - - internal static void MakeAndSaveTranslations(Translator translator) - { - var profiledFuncsToTranslate = PtcProfiler.GetProfiledFuncsToTranslate(translator.Functions); - - _translateCount = 0; - _translateTotalCount = profiledFuncsToTranslate.Count; - - if (_translateTotalCount == 0) - { - ResetCarriersIfNeeded(); - - GCSettings.LargeObjectHeapCompactionMode = GCLargeObjectHeapCompactionMode.CompactOnce; - - return; - } - - int degreeOfParallelism = Environment.ProcessorCount; - - // If there are enough cores lying around, we leave one alone for other tasks. - if (degreeOfParallelism > 4) - { - degreeOfParallelism--; - } - - Logger.Info?.Print(LogClass.Ptc, $"{_translateCount} of {_translateTotalCount} functions translated | Thread count: {degreeOfParallelism}"); - - PtcStateChanged?.Invoke(PtcLoadingState.Start, _translateCount, _translateTotalCount); - - using AutoResetEvent progressReportEvent = new AutoResetEvent(false); - - Thread progressReportThread = new Thread(ReportProgress) - { - Name = "Ptc.ProgressReporter", - Priority = ThreadPriority.Lowest, - IsBackground = true - }; - - progressReportThread.Start(progressReportEvent); - - void TranslateFuncs() - { - while (profiledFuncsToTranslate.TryDequeue(out var item)) - { - ulong address = item.address; - - Debug.Assert(PtcProfiler.IsAddressInStaticCodeRange(address)); - - TranslatedFunction func = translator.Translate(address, item.funcProfile.Mode, item.funcProfile.HighCq); - - bool isAddressUnique = translator.Functions.TryAdd(address, func.GuestSize, func); - - Debug.Assert(isAddressUnique, $"The address 0x{address:X16} is not unique."); - - Interlocked.Increment(ref _translateCount); - - translator.RegisterFunction(address, func); - - if (State != PtcState.Enabled) - { - break; - } - } - } - - List threads = new List(); - - for (int i = 0; i < degreeOfParallelism; i++) - { - Thread thread = new Thread(TranslateFuncs); - thread.IsBackground = true; - - threads.Add(thread); - } - - Stopwatch sw = Stopwatch.StartNew(); - - threads.ForEach((thread) => thread.Start()); - threads.ForEach((thread) => thread.Join()); - - threads.Clear(); - - progressReportEvent.Set(); - progressReportThread.Join(); - - sw.Stop(); - - PtcStateChanged?.Invoke(PtcLoadingState.Loaded, _translateCount, _translateTotalCount); - - Logger.Info?.Print(LogClass.Ptc, $"{_translateCount} of {_translateTotalCount} functions translated | Thread count: {degreeOfParallelism} in {sw.Elapsed.TotalSeconds} s"); - - Thread preSaveThread = new Thread(PreSave); - preSaveThread.IsBackground = true; - preSaveThread.Start(); - } - - private static void ReportProgress(object state) - { - const int refreshRate = 50; // ms. - - AutoResetEvent endEvent = (AutoResetEvent)state; - - int count = 0; - - do - { - int newCount = _translateCount; - - if (count != newCount) - { - PtcStateChanged?.Invoke(PtcLoadingState.Loading, newCount, _translateTotalCount); - count = newCount; - } - } - while (!endEvent.WaitOne(refreshRate)); - } - - internal static Hash128 ComputeHash(IMemoryManager memory, ulong address, ulong guestSize) - { - return XXHash128.ComputeHash(memory.GetSpan(address, checked((int)(guestSize)))); - } - - internal static void WriteCompiledFunction(ulong address, ulong guestSize, Hash128 hash, bool highCq, CompiledFunction compiledFunc) - { - lock (_lock) - { - byte[] code = compiledFunc.Code; - RelocInfo relocInfo = compiledFunc.RelocInfo; - UnwindInfo unwindInfo = compiledFunc.UnwindInfo; - - InfoEntry infoEntry = new InfoEntry(); - - infoEntry.Address = address; - infoEntry.GuestSize = guestSize; - infoEntry.Hash = hash; - infoEntry.HighCq = highCq; - infoEntry.Stubbed = false; - infoEntry.CodeLength = code.Length; - infoEntry.RelocEntriesCount = relocInfo.Entries.Length; - - SerializeStructure(_infosStream, infoEntry); - - WriteCode(code.AsSpan()); - - // WriteReloc. - using var relocInfoWriter = new BinaryWriter(_relocsStream, EncodingCache.UTF8NoBOM, true); - - foreach (RelocEntry entry in relocInfo.Entries) - { - relocInfoWriter.Write(entry.Position); - relocInfoWriter.Write((byte)entry.Symbol.Type); - relocInfoWriter.Write(entry.Symbol.Value); - } - - // WriteUnwindInfo. - using var unwindInfoWriter = new BinaryWriter(_unwindInfosStream, EncodingCache.UTF8NoBOM, true); - - unwindInfoWriter.Write(unwindInfo.PushEntries.Length); - - foreach (UnwindPushEntry unwindPushEntry in unwindInfo.PushEntries) - { - unwindInfoWriter.Write((int)unwindPushEntry.PseudoOp); - unwindInfoWriter.Write(unwindPushEntry.PrologOffset); - unwindInfoWriter.Write(unwindPushEntry.RegIndex); - unwindInfoWriter.Write(unwindPushEntry.StackOffsetOrAllocSize); - } - - unwindInfoWriter.Write(unwindInfo.PrologSize); - } - } - - private static void WriteCode(ReadOnlySpan code) - { - _codesList.Add(code.ToArray()); - } - - internal static bool GetEndianness() - { - return BitConverter.IsLittleEndian; - } - - private static FeatureInfo GetFeatureInfo() - { - return new FeatureInfo( - (uint)HardwareCapabilities.FeatureInfo1Ecx, - (uint)HardwareCapabilities.FeatureInfo1Edx, - (uint)HardwareCapabilities.FeatureInfo7Ebx); - } - - private static byte GetMemoryManagerMode() - { - return (byte)_memoryMode; - } - - private static uint GetOSPlatform() - { - uint osPlatform = 0u; - - osPlatform |= (OperatingSystem.IsFreeBSD() ? 1u : 0u) << 0; - osPlatform |= (OperatingSystem.IsLinux() ? 1u : 0u) << 1; - osPlatform |= (OperatingSystem.IsMacOS() ? 1u : 0u) << 2; - osPlatform |= (OperatingSystem.IsWindows() ? 1u : 0u) << 3; - - return osPlatform; - } - - [StructLayout(LayoutKind.Sequential, Pack = 1/*, Size = 54*/)] - private struct OuterHeader - { - public ulong Magic; - - public uint CacheFileVersion; - - public bool Endianness; - public FeatureInfo FeatureInfo; - public byte MemoryManagerMode; - public uint OSPlatform; - - public long UncompressedStreamSize; - - public Hash128 HeaderHash; - - public void SetHeaderHash() - { - Span spanHeader = MemoryMarshal.CreateSpan(ref this, 1); - - HeaderHash = XXHash128.ComputeHash(MemoryMarshal.AsBytes(spanHeader).Slice(0, Unsafe.SizeOf() - Unsafe.SizeOf())); - } - - public bool IsHeaderValid() - { - Span spanHeader = MemoryMarshal.CreateSpan(ref this, 1); - - return XXHash128.ComputeHash(MemoryMarshal.AsBytes(spanHeader).Slice(0, Unsafe.SizeOf() - Unsafe.SizeOf())) == HeaderHash; - } - } - - [StructLayout(LayoutKind.Sequential, Pack = 1/*, Size = 12*/)] - private record struct FeatureInfo(uint FeatureInfo0, uint FeatureInfo1, uint FeatureInfo2); - - [StructLayout(LayoutKind.Sequential, Pack = 1/*, Size = 128*/)] - private struct InnerHeader - { - public ulong Magic; - - public int InfosLength; - public long CodesLength; - public int RelocsLength; - public int UnwindInfosLength; - - public Hash128 InfosHash; - public Hash128 CodesHash; - public Hash128 RelocsHash; - public Hash128 UnwindInfosHash; - - public Hash128 HeaderHash; - - public void SetHeaderHash() - { - Span spanHeader = MemoryMarshal.CreateSpan(ref this, 1); - - HeaderHash = XXHash128.ComputeHash(MemoryMarshal.AsBytes(spanHeader).Slice(0, Unsafe.SizeOf() - Unsafe.SizeOf())); - } - - public bool IsHeaderValid() - { - Span spanHeader = MemoryMarshal.CreateSpan(ref this, 1); - - return XXHash128.ComputeHash(MemoryMarshal.AsBytes(spanHeader).Slice(0, Unsafe.SizeOf() - Unsafe.SizeOf())) == HeaderHash; - } - } - - [StructLayout(LayoutKind.Sequential, Pack = 1/*, Size = 42*/)] - private struct InfoEntry - { - public ulong Address; - public ulong GuestSize; - public Hash128 Hash; - public bool HighCq; - public bool Stubbed; - public int CodeLength; - public int RelocEntriesCount; - } - - private static void Enable() - { - State = PtcState.Enabled; - } - - public static void Continue() - { - if (State == PtcState.Enabled) - { - State = PtcState.Continuing; - } - } - - public static void Close() - { - if (State == PtcState.Enabled || - State == PtcState.Continuing) - { - State = PtcState.Closing; - } - } - - internal static void Disable() - { - State = PtcState.Disabled; - } - - private static void Wait() - { - _waitEvent.WaitOne(); - } - - public static void Dispose() - { - if (!_disposed) - { - _disposed = true; - - Wait(); - _waitEvent.Dispose(); - - DisposeCarriers(); - } - } - } -} diff --git a/ARMeilleure/Translation/PTC/PtcProfiler.cs b/ARMeilleure/Translation/PTC/PtcProfiler.cs deleted file mode 100644 index bb70da8d0..000000000 --- a/ARMeilleure/Translation/PTC/PtcProfiler.cs +++ /dev/null @@ -1,416 +0,0 @@ -using ARMeilleure.State; -using Ryujinx.Common; -using Ryujinx.Common.Logging; -using System; -using System.Buffers.Binary; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.Diagnostics; -using System.IO; -using System.IO.Compression; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -using System.Threading; - -using static ARMeilleure.Translation.PTC.PtcFormatter; - -namespace ARMeilleure.Translation.PTC -{ - public static class PtcProfiler - { - private const string OuterHeaderMagicString = "Pohd\0\0\0\0"; - - private const uint InternalVersion = 1866; //! Not to be incremented manually for each change to the ARMeilleure project. - - private const int SaveInterval = 30; // Seconds. - - private const CompressionLevel SaveCompressionLevel = CompressionLevel.Fastest; - - private static readonly System.Timers.Timer _timer; - - private static readonly ulong _outerHeaderMagic; - - private static readonly ManualResetEvent _waitEvent; - - private static readonly object _lock; - - private static bool _disposed; - - private static Hash128 _lastHash; - - internal static Dictionary ProfiledFuncs { get; private set; } - - internal static bool Enabled { get; private set; } - - public static ulong StaticCodeStart { internal get; set; } - public static ulong StaticCodeSize { internal get; set; } - - static PtcProfiler() - { - _timer = new System.Timers.Timer((double)SaveInterval * 1000d); - _timer.Elapsed += PreSave; - - _outerHeaderMagic = BinaryPrimitives.ReadUInt64LittleEndian(EncodingCache.UTF8NoBOM.GetBytes(OuterHeaderMagicString).AsSpan()); - - _waitEvent = new ManualResetEvent(true); - - _lock = new object(); - - _disposed = false; - - ProfiledFuncs = new Dictionary(); - - Enabled = false; - } - - internal static void AddEntry(ulong address, ExecutionMode mode, bool highCq) - { - if (IsAddressInStaticCodeRange(address)) - { - Debug.Assert(!highCq); - - lock (_lock) - { - ProfiledFuncs.TryAdd(address, new FuncProfile(mode, highCq: false)); - } - } - } - - internal static void UpdateEntry(ulong address, ExecutionMode mode, bool highCq) - { - if (IsAddressInStaticCodeRange(address)) - { - Debug.Assert(highCq); - - lock (_lock) - { - Debug.Assert(ProfiledFuncs.ContainsKey(address)); - - ProfiledFuncs[address] = new FuncProfile(mode, highCq: true); - } - } - } - - internal static bool IsAddressInStaticCodeRange(ulong address) - { - return address >= StaticCodeStart && address < StaticCodeStart + StaticCodeSize; - } - - internal static ConcurrentQueue<(ulong address, FuncProfile funcProfile)> GetProfiledFuncsToTranslate(TranslatorCache funcs) - { - var profiledFuncsToTranslate = new ConcurrentQueue<(ulong address, FuncProfile funcProfile)>(); - - foreach (var profiledFunc in ProfiledFuncs) - { - if (!funcs.ContainsKey(profiledFunc.Key)) - { - profiledFuncsToTranslate.Enqueue((profiledFunc.Key, profiledFunc.Value)); - } - } - - return profiledFuncsToTranslate; - } - - internal static void ClearEntries() - { - ProfiledFuncs.Clear(); - ProfiledFuncs.TrimExcess(); - } - - internal static void PreLoad() - { - _lastHash = default; - - string fileNameActual = string.Concat(Ptc.CachePathActual, ".info"); - string fileNameBackup = string.Concat(Ptc.CachePathBackup, ".info"); - - FileInfo fileInfoActual = new FileInfo(fileNameActual); - FileInfo fileInfoBackup = new FileInfo(fileNameBackup); - - if (fileInfoActual.Exists && fileInfoActual.Length != 0L) - { - if (!Load(fileNameActual, false)) - { - if (fileInfoBackup.Exists && fileInfoBackup.Length != 0L) - { - Load(fileNameBackup, true); - } - } - } - else if (fileInfoBackup.Exists && fileInfoBackup.Length != 0L) - { - Load(fileNameBackup, true); - } - } - - private static bool Load(string fileName, bool isBackup) - { - using (FileStream compressedStream = new(fileName, FileMode.Open)) - using (DeflateStream deflateStream = new(compressedStream, CompressionMode.Decompress, true)) - { - OuterHeader outerHeader = DeserializeStructure(compressedStream); - - if (!outerHeader.IsHeaderValid()) - { - InvalidateCompressedStream(compressedStream); - - return false; - } - - if (outerHeader.Magic != _outerHeaderMagic) - { - InvalidateCompressedStream(compressedStream); - - return false; - } - - if (outerHeader.InfoFileVersion != InternalVersion) - { - InvalidateCompressedStream(compressedStream); - - return false; - } - - if (outerHeader.Endianness != Ptc.GetEndianness()) - { - InvalidateCompressedStream(compressedStream); - - return false; - } - - using (MemoryStream stream = new MemoryStream()) - { - Debug.Assert(stream.Seek(0L, SeekOrigin.Begin) == 0L && stream.Length == 0L); - - try - { - deflateStream.CopyTo(stream); - } - catch - { - InvalidateCompressedStream(compressedStream); - - return false; - } - - Debug.Assert(stream.Position == stream.Length); - - stream.Seek(0L, SeekOrigin.Begin); - - Hash128 expectedHash = DeserializeStructure(stream); - - Hash128 actualHash = XXHash128.ComputeHash(GetReadOnlySpan(stream)); - - if (actualHash != expectedHash) - { - InvalidateCompressedStream(compressedStream); - - return false; - } - - ProfiledFuncs = Deserialize(stream); - - Debug.Assert(stream.Position == stream.Length); - - _lastHash = actualHash; - } - } - - long fileSize = new FileInfo(fileName).Length; - - Logger.Info?.Print(LogClass.Ptc, $"{(isBackup ? "Loaded Backup Profiling Info" : "Loaded Profiling Info")} (size: {fileSize} bytes, profiled functions: {ProfiledFuncs.Count})."); - - return true; - } - - private static Dictionary Deserialize(Stream stream) - { - return DeserializeDictionary(stream, (stream) => DeserializeStructure(stream)); - } - - private static ReadOnlySpan GetReadOnlySpan(MemoryStream memoryStream) - { - return new(memoryStream.GetBuffer(), (int)memoryStream.Position, (int)memoryStream.Length - (int)memoryStream.Position); - } - - private static void InvalidateCompressedStream(FileStream compressedStream) - { - compressedStream.SetLength(0L); - } - - private static void PreSave(object source, System.Timers.ElapsedEventArgs e) - { - _waitEvent.Reset(); - - string fileNameActual = string.Concat(Ptc.CachePathActual, ".info"); - string fileNameBackup = string.Concat(Ptc.CachePathBackup, ".info"); - - FileInfo fileInfoActual = new FileInfo(fileNameActual); - - if (fileInfoActual.Exists && fileInfoActual.Length != 0L) - { - File.Copy(fileNameActual, fileNameBackup, true); - } - - Save(fileNameActual); - - _waitEvent.Set(); - } - - private static void Save(string fileName) - { - int profiledFuncsCount; - - OuterHeader outerHeader = new OuterHeader(); - - outerHeader.Magic = _outerHeaderMagic; - - outerHeader.InfoFileVersion = InternalVersion; - outerHeader.Endianness = Ptc.GetEndianness(); - - outerHeader.SetHeaderHash(); - - using (MemoryStream stream = new MemoryStream()) - { - Debug.Assert(stream.Seek(0L, SeekOrigin.Begin) == 0L && stream.Length == 0L); - - stream.Seek((long)Unsafe.SizeOf(), SeekOrigin.Begin); - - lock (_lock) - { - Serialize(stream, ProfiledFuncs); - - profiledFuncsCount = ProfiledFuncs.Count; - } - - Debug.Assert(stream.Position == stream.Length); - - stream.Seek((long)Unsafe.SizeOf(), SeekOrigin.Begin); - Hash128 hash = XXHash128.ComputeHash(GetReadOnlySpan(stream)); - - stream.Seek(0L, SeekOrigin.Begin); - SerializeStructure(stream, hash); - - if (hash == _lastHash) - { - return; - } - - using (FileStream compressedStream = new(fileName, FileMode.OpenOrCreate)) - using (DeflateStream deflateStream = new(compressedStream, SaveCompressionLevel, true)) - { - try - { - SerializeStructure(compressedStream, outerHeader); - - stream.WriteTo(deflateStream); - - _lastHash = hash; - } - catch - { - compressedStream.Position = 0L; - - _lastHash = default; - } - - if (compressedStream.Position < compressedStream.Length) - { - compressedStream.SetLength(compressedStream.Position); - } - } - } - - long fileSize = new FileInfo(fileName).Length; - - if (fileSize != 0L) - { - Logger.Info?.Print(LogClass.Ptc, $"Saved Profiling Info (size: {fileSize} bytes, profiled functions: {profiledFuncsCount})."); - } - } - - private static void Serialize(Stream stream, Dictionary profiledFuncs) - { - SerializeDictionary(stream, profiledFuncs, (stream, structure) => SerializeStructure(stream, structure)); - } - - [StructLayout(LayoutKind.Sequential, Pack = 1/*, Size = 29*/)] - private struct OuterHeader - { - public ulong Magic; - - public uint InfoFileVersion; - - public bool Endianness; - - public Hash128 HeaderHash; - - public void SetHeaderHash() - { - Span spanHeader = MemoryMarshal.CreateSpan(ref this, 1); - - HeaderHash = XXHash128.ComputeHash(MemoryMarshal.AsBytes(spanHeader).Slice(0, Unsafe.SizeOf() - Unsafe.SizeOf())); - } - - public bool IsHeaderValid() - { - Span spanHeader = MemoryMarshal.CreateSpan(ref this, 1); - - return XXHash128.ComputeHash(MemoryMarshal.AsBytes(spanHeader).Slice(0, Unsafe.SizeOf() - Unsafe.SizeOf())) == HeaderHash; - } - } - - [StructLayout(LayoutKind.Sequential, Pack = 1/*, Size = 5*/)] - internal struct FuncProfile - { - public ExecutionMode Mode; - public bool HighCq; - - public FuncProfile(ExecutionMode mode, bool highCq) - { - Mode = mode; - HighCq = highCq; - } - } - - internal static void Start() - { - if (Ptc.State == PtcState.Enabled || - Ptc.State == PtcState.Continuing) - { - Enabled = true; - - _timer.Enabled = true; - } - } - - public static void Stop() - { - Enabled = false; - - if (!_disposed) - { - _timer.Enabled = false; - } - } - - internal static void Wait() - { - _waitEvent.WaitOne(); - } - - public static void Dispose() - { - if (!_disposed) - { - _disposed = true; - - _timer.Elapsed -= PreSave; - _timer.Dispose(); - - Wait(); - _waitEvent.Dispose(); - } - } - } -} \ No newline at end of file diff --git a/ARMeilleure/Translation/RegisterUsage.cs b/ARMeilleure/Translation/RegisterUsage.cs deleted file mode 100644 index 775fa3abc..000000000 --- a/ARMeilleure/Translation/RegisterUsage.cs +++ /dev/null @@ -1,394 +0,0 @@ -using ARMeilleure.IntermediateRepresentation; -using ARMeilleure.State; -using System; -using System.Numerics; -using System.Runtime.Intrinsics; -using System.Runtime.Intrinsics.X86; -using static ARMeilleure.IntermediateRepresentation.Operand.Factory; -using static ARMeilleure.IntermediateRepresentation.Operation.Factory; - -namespace ARMeilleure.Translation -{ - static class RegisterUsage - { - private const int RegsCount = 32; - private const int RegsMask = RegsCount - 1; - - private struct RegisterMask : IEquatable - { - public long IntMask => Mask.GetElement(0); - public long VecMask => Mask.GetElement(1); - - public Vector128 Mask { get; } - - public RegisterMask(Vector128 mask) - { - Mask = mask; - } - - public RegisterMask(long intMask, long vecMask) - { - Mask = Vector128.Create(intMask, vecMask); - } - - public static RegisterMask operator &(RegisterMask x, RegisterMask y) - { - if (Sse2.IsSupported) - { - return new RegisterMask(Sse2.And(x.Mask, y.Mask)); - } - - return new RegisterMask(x.IntMask & y.IntMask, x.VecMask & y.VecMask); - } - - public static RegisterMask operator |(RegisterMask x, RegisterMask y) - { - if (Sse2.IsSupported) - { - return new RegisterMask(Sse2.Or(x.Mask, y.Mask)); - } - - return new RegisterMask(x.IntMask | y.IntMask, x.VecMask | y.VecMask); - } - - public static RegisterMask operator ~(RegisterMask x) - { - if (Sse2.IsSupported) - { - return new RegisterMask(Sse2.AndNot(x.Mask, Vector128.AllBitsSet)); - } - - return new RegisterMask(~x.IntMask, ~x.VecMask); - } - - public static bool operator ==(RegisterMask x, RegisterMask y) - { - return x.Equals(y); - } - - public static bool operator !=(RegisterMask x, RegisterMask y) - { - return !x.Equals(y); - } - - public override bool Equals(object obj) - { - return obj is RegisterMask regMask && Equals(regMask); - } - - public bool Equals(RegisterMask other) - { - return Mask.Equals(other.Mask); - } - - public override int GetHashCode() - { - return Mask.GetHashCode(); - } - } - - public static void RunPass(ControlFlowGraph cfg, ExecutionMode mode) - { - // Compute local register inputs and outputs used inside blocks. - RegisterMask[] localInputs = new RegisterMask[cfg.Blocks.Count]; - RegisterMask[] localOutputs = new RegisterMask[cfg.Blocks.Count]; - - for (BasicBlock block = cfg.Blocks.First; block != null; block = block.ListNext) - { - for (Operation node = block.Operations.First; node != default; node = node.ListNext) - { - for (int index = 0; index < node.SourcesCount; index++) - { - Operand source = node.GetSource(index); - - if (source.Kind == OperandKind.Register) - { - Register register = source.GetRegister(); - - localInputs[block.Index] |= GetMask(register) & ~localOutputs[block.Index]; - } - } - - if (node.Destination != default && node.Destination.Kind == OperandKind.Register) - { - localOutputs[block.Index] |= GetMask(node.Destination.GetRegister()); - } - } - } - - // Compute global register inputs and outputs used across blocks. - RegisterMask[] globalCmnOutputs = new RegisterMask[cfg.Blocks.Count]; - - RegisterMask[] globalInputs = new RegisterMask[cfg.Blocks.Count]; - RegisterMask[] globalOutputs = new RegisterMask[cfg.Blocks.Count]; - - bool modified; - bool firstPass = true; - - do - { - modified = false; - - // Compute register outputs. - for (int index = cfg.PostOrderBlocks.Length - 1; index >= 0; index--) - { - BasicBlock block = cfg.PostOrderBlocks[index]; - - if (block.Predecessors.Count != 0 && !HasContextLoad(block)) - { - BasicBlock predecessor = block.Predecessors[0]; - - RegisterMask cmnOutputs = localOutputs[predecessor.Index] | globalCmnOutputs[predecessor.Index]; - RegisterMask outputs = globalOutputs[predecessor.Index]; - - for (int pIndex = 1; pIndex < block.Predecessors.Count; pIndex++) - { - predecessor = block.Predecessors[pIndex]; - - cmnOutputs &= localOutputs[predecessor.Index] | globalCmnOutputs[predecessor.Index]; - outputs |= globalOutputs[predecessor.Index]; - } - - globalInputs[block.Index] |= outputs & ~cmnOutputs; - - if (!firstPass) - { - cmnOutputs &= globalCmnOutputs[block.Index]; - } - - modified |= Exchange(globalCmnOutputs, block.Index, cmnOutputs); - outputs |= localOutputs[block.Index]; - modified |= Exchange(globalOutputs, block.Index, globalOutputs[block.Index] | outputs); - } - else - { - modified |= Exchange(globalOutputs, block.Index, localOutputs[block.Index]); - } - } - - // Compute register inputs. - for (int index = 0; index < cfg.PostOrderBlocks.Length; index++) - { - BasicBlock block = cfg.PostOrderBlocks[index]; - - RegisterMask inputs = localInputs[block.Index]; - - for (int i = 0; i < block.SuccessorsCount; i++) - { - inputs |= globalInputs[block.GetSuccessor(i).Index]; - } - - inputs &= ~globalCmnOutputs[block.Index]; - - modified |= Exchange(globalInputs, block.Index, globalInputs[block.Index] | inputs); - } - - firstPass = false; - } - while (modified); - - // Insert load and store context instructions where needed. - for (BasicBlock block = cfg.Blocks.First; block != null; block = block.ListNext) - { - bool hasContextLoad = HasContextLoad(block); - - if (hasContextLoad) - { - block.Operations.Remove(block.Operations.First); - } - - Operand arg = default; - - // The only block without any predecessor should be the entry block. - // It always needs a context load as it is the first block to run. - if (block.Predecessors.Count == 0 || hasContextLoad) - { - long vecMask = globalInputs[block.Index].VecMask; - long intMask = globalInputs[block.Index].IntMask; - - if (vecMask != 0 || intMask != 0) - { - arg = Local(OperandType.I64); - - Operation loadArg = block.Operations.AddFirst(Operation(Instruction.LoadArgument, arg, Const(0))); - - LoadLocals(block, vecMask, RegisterType.Vector, mode, loadArg, arg); - LoadLocals(block, intMask, RegisterType.Integer, mode, loadArg, arg); - } - } - - bool hasContextStore = HasContextStore(block); - - if (hasContextStore) - { - block.Operations.Remove(block.Operations.Last); - } - - if (EndsWithReturn(block) || hasContextStore) - { - long vecMask = globalOutputs[block.Index].VecMask; - long intMask = globalOutputs[block.Index].IntMask; - - if (vecMask != 0 || intMask != 0) - { - if (arg == default) - { - arg = Local(OperandType.I64); - - block.Append(Operation(Instruction.LoadArgument, arg, Const(0))); - } - - StoreLocals(block, intMask, RegisterType.Integer, mode, arg); - StoreLocals(block, vecMask, RegisterType.Vector, mode, arg); - } - } - } - } - - private static bool HasContextLoad(BasicBlock block) - { - return StartsWith(block, Instruction.LoadFromContext) && block.Operations.First.SourcesCount == 0; - } - - private static bool HasContextStore(BasicBlock block) - { - return EndsWith(block, Instruction.StoreToContext) && block.Operations.Last.SourcesCount == 0; - } - - private static bool StartsWith(BasicBlock block, Instruction inst) - { - if (block.Operations.Count > 0) - { - Operation first = block.Operations.First; - - return first != default && first.Instruction == inst; - } - - return false; - } - - private static bool EndsWith(BasicBlock block, Instruction inst) - { - if (block.Operations.Count > 0) - { - Operation last = block.Operations.Last; - - return last != default && last.Instruction == inst; - } - - return false; - } - - private static RegisterMask GetMask(Register register) - { - long intMask = 0; - long vecMask = 0; - - switch (register.Type) - { - case RegisterType.Flag: intMask = (1L << RegsCount) << register.Index; break; - case RegisterType.Integer: intMask = 1L << register.Index; break; - case RegisterType.FpFlag: vecMask = (1L << RegsCount) << register.Index; break; - case RegisterType.Vector: vecMask = 1L << register.Index; break; - } - - return new RegisterMask(intMask, vecMask); - } - - private static bool Exchange(RegisterMask[] masks, int blkIndex, RegisterMask value) - { - ref RegisterMask curValue = ref masks[blkIndex]; - - bool changed = curValue != value; - - curValue = value; - - return changed; - } - - private static void LoadLocals( - BasicBlock block, - long inputs, - RegisterType baseType, - ExecutionMode mode, - Operation loadArg, - Operand arg) - { - while (inputs != 0) - { - int bit = 63 - BitOperations.LeadingZeroCount((ulong)inputs); - - Operand dest = GetRegFromBit(bit, baseType, mode); - Operand offset = Const((long)NativeContext.GetRegisterOffset(dest.GetRegister())); - Operand addr = Local(OperandType.I64); - - block.Operations.AddAfter(loadArg, Operation(Instruction.Load, dest, addr)); - block.Operations.AddAfter(loadArg, Operation(Instruction.Add, addr, arg, offset)); - - inputs &= ~(1L << bit); - } - } - - private static void StoreLocals( - BasicBlock block, - long outputs, - RegisterType baseType, - ExecutionMode mode, - Operand arg) - { - while (outputs != 0) - { - int bit = BitOperations.TrailingZeroCount(outputs); - - Operand source = GetRegFromBit(bit, baseType, mode); - Operand offset = Const((long)NativeContext.GetRegisterOffset(source.GetRegister())); - Operand addr = Local(OperandType.I64); - - block.Append(Operation(Instruction.Add, addr, arg, offset)); - block.Append(Operation(Instruction.Store, default, addr, source)); - - outputs &= ~(1L << bit); - } - } - - private static Operand GetRegFromBit(int bit, RegisterType baseType, ExecutionMode mode) - { - if (bit < RegsCount) - { - return Register(bit, baseType, GetOperandType(baseType, mode)); - } - else if (baseType == RegisterType.Integer) - { - return Register(bit & RegsMask, RegisterType.Flag, OperandType.I32); - } - else if (baseType == RegisterType.Vector) - { - return Register(bit & RegsMask, RegisterType.FpFlag, OperandType.I32); - } - else - { - throw new ArgumentOutOfRangeException(nameof(bit)); - } - } - - private static OperandType GetOperandType(RegisterType type, ExecutionMode mode) - { - switch (type) - { - case RegisterType.Flag: return OperandType.I32; - case RegisterType.FpFlag: return OperandType.I32; - case RegisterType.Integer: return (mode == ExecutionMode.Aarch64) ? OperandType.I64 : OperandType.I32; - case RegisterType.Vector: return OperandType.V128; - } - - throw new ArgumentException($"Invalid register type \"{type}\"."); - } - - private static bool EndsWithReturn(BasicBlock block) - { - Operation last = block.Operations.Last; - - return last != default && last.Instruction == Instruction.Return; - } - } -} \ No newline at end of file diff --git a/ARMeilleure/Translation/TranslatedFunction.cs b/ARMeilleure/Translation/TranslatedFunction.cs deleted file mode 100644 index 04dd769c1..000000000 --- a/ARMeilleure/Translation/TranslatedFunction.cs +++ /dev/null @@ -1,30 +0,0 @@ -using ARMeilleure.Common; -using System; -using System.Runtime.InteropServices; - -namespace ARMeilleure.Translation -{ - class TranslatedFunction - { - private readonly GuestFunction _func; // Ensure that this delegate will not be garbage collected. - - public Counter CallCounter { get; } - public ulong GuestSize { get; } - public bool HighCq { get; } - public IntPtr FuncPtr { get; } - - public TranslatedFunction(GuestFunction func, Counter callCounter, ulong guestSize, bool highCq) - { - _func = func; - CallCounter = callCounter; - GuestSize = guestSize; - HighCq = highCq; - FuncPtr = Marshal.GetFunctionPointerForDelegate(func); - } - - public ulong Execute(State.ExecutionContext context) - { - return _func(context.NativeContextPtr); - } - } -} \ No newline at end of file diff --git a/ARMeilleure/Translation/Translator.cs b/ARMeilleure/Translation/Translator.cs deleted file mode 100644 index 6b96180b9..000000000 --- a/ARMeilleure/Translation/Translator.cs +++ /dev/null @@ -1,544 +0,0 @@ -using ARMeilleure.CodeGen; -using ARMeilleure.Common; -using ARMeilleure.Decoders; -using ARMeilleure.Diagnostics; -using ARMeilleure.Instructions; -using ARMeilleure.IntermediateRepresentation; -using ARMeilleure.Memory; -using ARMeilleure.Signal; -using ARMeilleure.State; -using ARMeilleure.Translation.Cache; -using ARMeilleure.Translation.PTC; -using Ryujinx.Common; -using System; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.Diagnostics; -using System.Threading; -using static ARMeilleure.IntermediateRepresentation.Operand.Factory; - -namespace ARMeilleure.Translation -{ - public class Translator - { - private static readonly AddressTable.Level[] Levels64Bit = - new AddressTable.Level[] - { - new(31, 17), - new(23, 8), - new(15, 8), - new( 7, 8), - new( 2, 5) - }; - - private static readonly AddressTable.Level[] Levels32Bit = - new AddressTable.Level[] - { - new(31, 17), - new(23, 8), - new(15, 8), - new( 7, 8), - new( 1, 6) - }; - - private readonly IJitMemoryAllocator _allocator; - private readonly ConcurrentQueue> _oldFuncs; - - internal TranslatorCache Functions { get; } - internal AddressTable FunctionTable { get; } - internal EntryTable CountTable { get; } - internal TranslatorStubs Stubs { get; } - internal TranslatorQueue Queue { get; } - internal IMemoryManager Memory { get; } - - private volatile int _threadCount; - - // FIXME: Remove this once the init logic of the emulator will be redone. - public static readonly ManualResetEvent IsReadyForTranslation = new(false); - - public Translator(IJitMemoryAllocator allocator, IMemoryManager memory, bool for64Bits) - { - _allocator = allocator; - Memory = memory; - - _oldFuncs = new ConcurrentQueue>(); - - Queue = new TranslatorQueue(); - - JitCache.Initialize(allocator); - - CountTable = new EntryTable(); - Functions = new TranslatorCache(); - FunctionTable = new AddressTable(for64Bits ? Levels64Bit : Levels32Bit); - Stubs = new TranslatorStubs(this); - - FunctionTable.Fill = (ulong)Stubs.SlowDispatchStub; - - if (memory.Type.IsHostMapped()) - { - NativeSignalHandler.InitializeSignalHandler(); - } - } - - public void Execute(State.ExecutionContext context, ulong address) - { - if (Interlocked.Increment(ref _threadCount) == 1) - { - IsReadyForTranslation.WaitOne(); - - if (Ptc.State == PtcState.Enabled) - { - Debug.Assert(Functions.Count == 0); - Ptc.LoadTranslations(this); - Ptc.MakeAndSaveTranslations(this); - } - - PtcProfiler.Start(); - - Ptc.Disable(); - - // Simple heuristic, should be user configurable in future. (1 for 4 core/ht or less, 2 for 6 core + ht - // etc). All threads are normal priority except from the last, which just fills as much of the last core - // as the os lets it with a low priority. If we only have one rejit thread, it should be normal priority - // as highCq code is performance critical. - // - // TODO: Use physical cores rather than logical. This only really makes sense for processors with - // hyperthreading. Requires OS specific code. - int unboundedThreadCount = Math.Max(1, (Environment.ProcessorCount - 6) / 3); - int threadCount = Math.Min(4, unboundedThreadCount); - - for (int i = 0; i < threadCount; i++) - { - bool last = i != 0 && i == unboundedThreadCount - 1; - - Thread backgroundTranslatorThread = new Thread(BackgroundTranslate) - { - Name = "CPU.BackgroundTranslatorThread." + i, - Priority = last ? ThreadPriority.Lowest : ThreadPriority.Normal - }; - - backgroundTranslatorThread.Start(); - } - } - - Statistics.InitializeTimer(); - - NativeInterface.RegisterThread(context, Memory, this); - - if (Optimizations.UseUnmanagedDispatchLoop) - { - Stubs.DispatchLoop(context.NativeContextPtr, address); - } - else - { - do - { - address = ExecuteSingle(context, address); - } - while (context.Running && address != 0); - } - - NativeInterface.UnregisterThread(); - - if (Interlocked.Decrement(ref _threadCount) == 0) - { - ClearJitCache(); - - Queue.Dispose(); - Stubs.Dispose(); - FunctionTable.Dispose(); - CountTable.Dispose(); - } - } - - private ulong ExecuteSingle(State.ExecutionContext context, ulong address) - { - TranslatedFunction func = GetOrTranslate(address, context.ExecutionMode); - - Statistics.StartTimer(); - - ulong nextAddr = func.Execute(context); - - Statistics.StopTimer(address); - - return nextAddr; - } - - public ulong Step(State.ExecutionContext context, ulong address) - { - TranslatedFunction func = Translate(address, context.ExecutionMode, highCq: false, singleStep: true); - - address = func.Execute(context); - - EnqueueForDeletion(address, func); - - return address; - } - - internal TranslatedFunction GetOrTranslate(ulong address, ExecutionMode mode) - { - if (!Functions.TryGetValue(address, out TranslatedFunction func)) - { - func = Translate(address, mode, highCq: false); - - TranslatedFunction oldFunc = Functions.GetOrAdd(address, func.GuestSize, func); - - if (oldFunc != func) - { - JitCache.Unmap(func.FuncPtr); - func = oldFunc; - } - - if (PtcProfiler.Enabled) - { - PtcProfiler.AddEntry(address, mode, highCq: false); - } - - RegisterFunction(address, func); - } - - return func; - } - - internal void RegisterFunction(ulong guestAddress, TranslatedFunction func) - { - if (FunctionTable.IsValid(guestAddress) && (Optimizations.AllowLcqInFunctionTable || func.HighCq)) - { - Volatile.Write(ref FunctionTable.GetValue(guestAddress), (ulong)func.FuncPtr); - } - } - - internal TranslatedFunction Translate(ulong address, ExecutionMode mode, bool highCq, bool singleStep = false) - { - var context = new ArmEmitterContext( - Memory, - CountTable, - FunctionTable, - Stubs, - address, - highCq, - mode: Aarch32Mode.User); - - Logger.StartPass(PassName.Decoding); - - Block[] blocks = Decoder.Decode(Memory, address, mode, highCq, singleStep ? DecoderMode.SingleInstruction : DecoderMode.MultipleBlocks); - - Logger.EndPass(PassName.Decoding); - - Logger.StartPass(PassName.Translation); - - EmitSynchronization(context); - - if (blocks[0].Address != address) - { - context.Branch(context.GetLabel(address)); - } - - ControlFlowGraph cfg = EmitAndGetCFG(context, blocks, out Range funcRange, out Counter counter); - - ulong funcSize = funcRange.End - funcRange.Start; - - Logger.EndPass(PassName.Translation, cfg); - - Logger.StartPass(PassName.RegisterUsage); - - RegisterUsage.RunPass(cfg, mode); - - Logger.EndPass(PassName.RegisterUsage); - - var retType = OperandType.I64; - var argTypes = new OperandType[] { OperandType.I64 }; - - var options = highCq ? CompilerOptions.HighCq : CompilerOptions.None; - - if (context.HasPtc && !singleStep) - { - options |= CompilerOptions.Relocatable; - } - - CompiledFunction compiledFunc = Compiler.Compile(cfg, argTypes, retType, options); - - if (context.HasPtc && !singleStep) - { - Hash128 hash = Ptc.ComputeHash(Memory, address, funcSize); - - Ptc.WriteCompiledFunction(address, funcSize, hash, highCq, compiledFunc); - } - - GuestFunction func = compiledFunc.Map(); - - Allocators.ResetAll(); - - return new TranslatedFunction(func, counter, funcSize, highCq); - } - - private void BackgroundTranslate() - { - while (_threadCount != 0 && Queue.TryDequeue(out RejitRequest request)) - { - TranslatedFunction func = Translate(request.Address, request.Mode, highCq: true); - - Functions.AddOrUpdate(request.Address, func.GuestSize, func, (key, oldFunc) => - { - EnqueueForDeletion(key, oldFunc); - return func; - }); - - if (PtcProfiler.Enabled) - { - PtcProfiler.UpdateEntry(request.Address, request.Mode, highCq: true); - } - - RegisterFunction(request.Address, func); - } - } - - private struct Range - { - public ulong Start { get; } - public ulong End { get; } - - public Range(ulong start, ulong end) - { - Start = start; - End = end; - } - } - - private static ControlFlowGraph EmitAndGetCFG( - ArmEmitterContext context, - Block[] blocks, - out Range range, - out Counter counter) - { - counter = null; - - ulong rangeStart = ulong.MaxValue; - ulong rangeEnd = 0; - - for (int blkIndex = 0; blkIndex < blocks.Length; blkIndex++) - { - Block block = blocks[blkIndex]; - - if (!block.Exit) - { - if (rangeStart > block.Address) - { - rangeStart = block.Address; - } - - if (rangeEnd < block.EndAddress) - { - rangeEnd = block.EndAddress; - } - } - - if (block.Address == context.EntryAddress && !context.HighCq) - { - EmitRejitCheck(context, out counter); - } - - context.CurrBlock = block; - - context.MarkLabel(context.GetLabel(block.Address)); - - if (block.Exit) - { - // Left option here as it may be useful if we need to return to managed rather than tail call in - // future. (eg. for debug) - bool useReturns = false; - - InstEmitFlowHelper.EmitVirtualJump(context, Const(block.Address), isReturn: useReturns); - } - else - { - for (int opcIndex = 0; opcIndex < block.OpCodes.Count; opcIndex++) - { - OpCode opCode = block.OpCodes[opcIndex]; - - context.CurrOp = opCode; - - bool isLastOp = opcIndex == block.OpCodes.Count - 1; - - if (isLastOp && block.Branch != null && !block.Branch.Exit && block.Branch.Address <= block.Address) - { - EmitSynchronization(context); - } - - Operand lblPredicateSkip = default; - - if (context.IsInIfThenBlock && context.CurrentIfThenBlockCond != Condition.Al) - { - lblPredicateSkip = Label(); - - InstEmitFlowHelper.EmitCondBranch(context, lblPredicateSkip, context.CurrentIfThenBlockCond.Invert()); - } - - if (opCode is OpCode32 op && op.Cond < Condition.Al) - { - lblPredicateSkip = Label(); - - InstEmitFlowHelper.EmitCondBranch(context, lblPredicateSkip, op.Cond.Invert()); - } - - if (opCode.Instruction.Emitter != null) - { - opCode.Instruction.Emitter(context); - } - else - { - throw new InvalidOperationException($"Invalid instruction \"{opCode.Instruction.Name}\"."); - } - - if (lblPredicateSkip != default) - { - context.MarkLabel(lblPredicateSkip); - } - - if (context.IsInIfThenBlock && opCode.Instruction.Name != InstName.It) - { - context.AdvanceIfThenBlockState(); - } - } - } - } - - range = new Range(rangeStart, rangeEnd); - - return context.GetControlFlowGraph(); - } - - internal static void EmitRejitCheck(ArmEmitterContext context, out Counter counter) - { - const int MinsCallForRejit = 100; - - counter = new Counter(context.CountTable); - - Operand lblEnd = Label(); - - Operand address = !context.HasPtc ? - Const(ref counter.Value) : - Const(ref counter.Value, Ptc.CountTableSymbol); - - Operand curCount = context.Load(OperandType.I32, address); - Operand count = context.Add(curCount, Const(1)); - context.Store(address, count); - context.BranchIf(lblEnd, curCount, Const(MinsCallForRejit), Comparison.NotEqual, BasicBlockFrequency.Cold); - - context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.EnqueueForRejit)), Const(context.EntryAddress)); - - context.MarkLabel(lblEnd); - } - - internal static void EmitSynchronization(EmitterContext context) - { - long countOffs = NativeContext.GetCounterOffset(); - - Operand lblNonZero = Label(); - Operand lblExit = Label(); - - Operand countAddr = context.Add(context.LoadArgument(OperandType.I64, 0), Const(countOffs)); - Operand count = context.Load(OperandType.I32, countAddr); - context.BranchIfTrue(lblNonZero, count, BasicBlockFrequency.Cold); - - Operand running = context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.CheckSynchronization))); - context.BranchIfTrue(lblExit, running, BasicBlockFrequency.Cold); - - context.Return(Const(0L)); - - context.MarkLabel(lblNonZero); - count = context.Subtract(count, Const(1)); - context.Store(countAddr, count); - - context.MarkLabel(lblExit); - } - - public void InvalidateJitCacheRegion(ulong address, ulong size, bool clearRejitQueueOnly = false) - { - ulong[] overlapAddresses = Array.Empty(); - - int overlapsCount = Functions.GetOverlaps(address, size, ref overlapAddresses); - - if (overlapsCount != 0) - { - // If rejit is running, stop it as it may be trying to rejit a function on the invalidated region. - ClearRejitQueue(allowRequeue: true); - } - - if (clearRejitQueueOnly) - { - return; - } - - for (int index = 0; index < overlapsCount; index++) - { - ulong overlapAddress = overlapAddresses[index]; - - if (Functions.TryGetValue(overlapAddress, out TranslatedFunction overlap)) - { - Functions.Remove(overlapAddress); - Volatile.Write(ref FunctionTable.GetValue(overlapAddress), FunctionTable.Fill); - EnqueueForDeletion(overlapAddress, overlap); - } - } - - // TODO: Remove overlapping functions from the JitCache aswell. - // This should be done safely, with a mechanism to ensure the function is not being executed. - } - - internal void EnqueueForRejit(ulong guestAddress, ExecutionMode mode) - { - Queue.Enqueue(guestAddress, mode); - } - - private void EnqueueForDeletion(ulong guestAddress, TranslatedFunction func) - { - _oldFuncs.Enqueue(new(guestAddress, func)); - } - - private void ClearJitCache() - { - // Ensure no attempt will be made to compile new functions due to rejit. - ClearRejitQueue(allowRequeue: false); - - List functions = Functions.AsList(); - - foreach (var func in functions) - { - JitCache.Unmap(func.FuncPtr); - - func.CallCounter?.Dispose(); - } - - Functions.Clear(); - - while (_oldFuncs.TryDequeue(out var kv)) - { - JitCache.Unmap(kv.Value.FuncPtr); - - kv.Value.CallCounter?.Dispose(); - } - } - - private void ClearRejitQueue(bool allowRequeue) - { - if (!allowRequeue) - { - Queue.Clear(); - - return; - } - - lock (Queue.Sync) - { - while (Queue.Count > 0 && Queue.TryDequeue(out RejitRequest request)) - { - if (Functions.TryGetValue(request.Address, out var func) && func.CallCounter != null) - { - Volatile.Write(ref func.CallCounter.Value, 0); - } - } - } - } - } -} diff --git a/ARMeilleure/Translation/TranslatorStubs.cs b/ARMeilleure/Translation/TranslatorStubs.cs deleted file mode 100644 index 4ad6c2f23..000000000 --- a/ARMeilleure/Translation/TranslatorStubs.cs +++ /dev/null @@ -1,248 +0,0 @@ -using ARMeilleure.Instructions; -using ARMeilleure.IntermediateRepresentation; -using ARMeilleure.State; -using ARMeilleure.Translation.Cache; -using System; -using System.Reflection; -using System.Runtime.InteropServices; -using static ARMeilleure.IntermediateRepresentation.Operand.Factory; - -namespace ARMeilleure.Translation -{ - /// - /// Represents a stub manager. - /// - class TranslatorStubs : IDisposable - { - private static readonly Lazy _slowDispatchStub = new(GenerateSlowDispatchStub, isThreadSafe: true); - - private bool _disposed; - - private readonly Translator _translator; - private readonly Lazy _dispatchStub; - private readonly Lazy _dispatchLoop; - - /// - /// Gets the dispatch stub. - /// - /// instance was disposed - public IntPtr DispatchStub - { - get - { - if (_disposed) - { - throw new ObjectDisposedException(null); - } - - return _dispatchStub.Value; - } - } - - /// - /// Gets the slow dispatch stub. - /// - /// instance was disposed - public IntPtr SlowDispatchStub - { - get - { - if (_disposed) - { - throw new ObjectDisposedException(null); - } - - return _slowDispatchStub.Value; - } - } - - /// - /// Gets the dispatch loop function. - /// - /// instance was disposed - public DispatcherFunction DispatchLoop - { - get - { - if (_disposed) - { - throw new ObjectDisposedException(null); - } - - return _dispatchLoop.Value; - } - } - - /// - /// Initializes a new instance of the class with the specified - /// instance. - /// - /// instance to use - /// is null - public TranslatorStubs(Translator translator) - { - _translator = translator ?? throw new ArgumentNullException(nameof(translator)); - _dispatchStub = new(GenerateDispatchStub, isThreadSafe: true); - _dispatchLoop = new(GenerateDispatchLoop, isThreadSafe: true); - } - - /// - /// Releases all resources used by the instance. - /// - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - /// - /// Releases all unmanaged and optionally managed resources used by the instance. - /// - /// to dispose managed resources also; otherwise just unmanaged resouces - protected virtual void Dispose(bool disposing) - { - if (!_disposed) - { - if (_dispatchStub.IsValueCreated) - { - JitCache.Unmap(_dispatchStub.Value); - } - - if (_dispatchLoop.IsValueCreated) - { - JitCache.Unmap(Marshal.GetFunctionPointerForDelegate(_dispatchLoop.Value)); - } - - _disposed = true; - } - } - - /// - /// Frees resources used by the instance. - /// - ~TranslatorStubs() - { - Dispose(false); - } - - /// - /// Generates a . - /// - /// Generated - private IntPtr GenerateDispatchStub() - { - var context = new EmitterContext(); - - Operand lblFallback = Label(); - Operand lblEnd = Label(); - - // Load the target guest address from the native context. - Operand nativeContext = context.LoadArgument(OperandType.I64, 0); - Operand guestAddress = context.Load(OperandType.I64, - context.Add(nativeContext, Const((ulong)NativeContext.GetDispatchAddressOffset()))); - - // Check if guest address is within range of the AddressTable. - Operand masked = context.BitwiseAnd(guestAddress, Const(~_translator.FunctionTable.Mask)); - context.BranchIfTrue(lblFallback, masked); - - Operand index = default; - Operand page = Const((long)_translator.FunctionTable.Base); - - for (int i = 0; i < _translator.FunctionTable.Levels.Length; i++) - { - ref var level = ref _translator.FunctionTable.Levels[i]; - - // level.Mask is not used directly because it is more often bigger than 32-bits, so it will not - // be encoded as an immediate on x86's bitwise and operation. - Operand mask = Const(level.Mask >> level.Index); - - index = context.BitwiseAnd(context.ShiftRightUI(guestAddress, Const(level.Index)), mask); - - if (i < _translator.FunctionTable.Levels.Length - 1) - { - page = context.Load(OperandType.I64, context.Add(page, context.ShiftLeft(index, Const(3)))); - context.BranchIfFalse(lblFallback, page); - } - } - - Operand hostAddress; - Operand hostAddressAddr = context.Add(page, context.ShiftLeft(index, Const(3))); - hostAddress = context.Load(OperandType.I64, hostAddressAddr); - context.Tailcall(hostAddress, nativeContext); - - context.MarkLabel(lblFallback); - hostAddress = context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFunctionAddress)), guestAddress); - context.Tailcall(hostAddress, nativeContext); - - var cfg = context.GetControlFlowGraph(); - var retType = OperandType.I64; - var argTypes = new[] { OperandType.I64 }; - - var func = Compiler.Compile(cfg, argTypes, retType, CompilerOptions.HighCq).Map(); - - return Marshal.GetFunctionPointerForDelegate(func); - } - - /// - /// Generates a . - /// - /// Generated - private static IntPtr GenerateSlowDispatchStub() - { - var context = new EmitterContext(); - - // Load the target guest address from the native context. - Operand nativeContext = context.LoadArgument(OperandType.I64, 0); - Operand guestAddress = context.Load(OperandType.I64, - context.Add(nativeContext, Const((ulong)NativeContext.GetDispatchAddressOffset()))); - - MethodInfo getFuncAddress = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFunctionAddress)); - Operand hostAddress = context.Call(getFuncAddress, guestAddress); - context.Tailcall(hostAddress, nativeContext); - - var cfg = context.GetControlFlowGraph(); - var retType = OperandType.I64; - var argTypes = new[] { OperandType.I64 }; - - var func = Compiler.Compile(cfg, argTypes, retType, CompilerOptions.HighCq).Map(); - - return Marshal.GetFunctionPointerForDelegate(func); - } - - /// - /// Generates a function. - /// - /// function - private DispatcherFunction GenerateDispatchLoop() - { - var context = new EmitterContext(); - - Operand beginLbl = Label(); - Operand endLbl = Label(); - - Operand nativeContext = context.LoadArgument(OperandType.I64, 0); - Operand guestAddress = context.Copy( - context.AllocateLocal(OperandType.I64), - context.LoadArgument(OperandType.I64, 1)); - - Operand runningAddress = context.Add(nativeContext, Const((ulong)NativeContext.GetRunningOffset())); - Operand dispatchAddress = context.Add(nativeContext, Const((ulong)NativeContext.GetDispatchAddressOffset())); - - context.MarkLabel(beginLbl); - context.Store(dispatchAddress, guestAddress); - context.Copy(guestAddress, context.Call(Const((ulong)DispatchStub), OperandType.I64, nativeContext)); - context.BranchIfFalse(endLbl, guestAddress); - context.BranchIfFalse(endLbl, context.Load(OperandType.I32, runningAddress)); - context.Branch(beginLbl); - - context.MarkLabel(endLbl); - context.Return(); - - var cfg = context.GetControlFlowGraph(); - var retType = OperandType.None; - var argTypes = new[] { OperandType.I64, OperandType.I64 }; - - return Compiler.Compile(cfg, argTypes, retType, CompilerOptions.HighCq).Map(); - } - } -} diff --git a/Directory.Packages.props b/Directory.Packages.props new file mode 100644 index 000000000..fbae486c3 --- /dev/null +++ b/Directory.Packages.props @@ -0,0 +1,52 @@ + + + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/README.md b/README.md index 9a8581e06..7021abc45 100644 --- a/README.md +++ b/README.md @@ -21,6 +21,10 @@ + + + Discord @@ -36,18 +40,20 @@ ## Compatibility -As of September 2022, Ryujinx has been tested on approximately 3,600 titles; over 3,400 boot past menus and into gameplay, with roughly 2,700 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! +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. +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 -To run this emulator, your PC must be equipped with at least 8GB of RAM; failing to meet this requirement may result in a poor gameplay experience or unexpected crashes. +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. 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 and LAN builds, see our [Multiplayer: Local Play/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. + ## Latest build 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.** @@ -62,7 +68,7 @@ The latest automatic build for Windows, macOS, and Linux can be found on the [Of If you wish to build the emulator yourself, follow these steps: ### Step 1 -Install the X64 version of [.NET 6.0 (or higher) SDK](https://dotnet.microsoft.com/download/dotnet/6.0). +Install the X64 version of [.NET 7.0 (or higher) SDK](https://dotnet.microsoft.com/download/dotnet/7.0). ### 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. @@ -90,7 +96,7 @@ Ryujinx system files are stored in the `Ryujinx` folder. This folder is located - **GPU** - The GPU emulator emulates the Switch's Maxwell GPU using the OpenGL API (version 4.5 minimum) through a custom build of OpenTK. There are currently four graphics enhancements available to the end user in Ryujinx: disk shader caching, resolution scaling, aspect ratio adjustment and anisotropic filtering. These enhancements can be adjusted or toggled as desired in the GUI. + The GPU emulator emulates the Switch's Maxwell GPU using either the OpenGL (version 4.5 minimum), Vulkan, or Metal (via MoltenVK) APIs through a custom build of OpenTK or Silk.NET respectively. There are currently six graphics enhancements available to the end user in Ryujinx: Disk Shader Caching, Resolution Scaling, Anti-Aliasing, Scaling Filters (including FSR), Anisotropic Filtering and Aspect Ratio Adjustment. These enhancements can be adjusted or toggled as desired in the GUI. - **Input** diff --git a/Ryujinx.Audio.Backends.OpenAL/Ryujinx.Audio.Backends.OpenAL.csproj b/Ryujinx.Audio.Backends.OpenAL/Ryujinx.Audio.Backends.OpenAL.csproj deleted file mode 100644 index f1e783e6e..000000000 --- a/Ryujinx.Audio.Backends.OpenAL/Ryujinx.Audio.Backends.OpenAL.csproj +++ /dev/null @@ -1,15 +0,0 @@ - - - - net6.0 - - - - - - - - - - - diff --git a/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/MarshalExtensions.cs b/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/MarshalExtensions.cs deleted file mode 100644 index 5e86263ea..000000000 --- a/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/MarshalExtensions.cs +++ /dev/null @@ -1,38 +0,0 @@ -using System; -using System.Runtime.InteropServices; - -namespace SoundIOSharp -{ - public static class MarshalEx - { - public static double ReadDouble(IntPtr handle, int offset = 0) - { - return BitConverter.Int64BitsToDouble(Marshal.ReadInt64(handle, offset)); - } - - public static void WriteDouble(IntPtr handle, double value) - { - WriteDouble(handle, 0, value); - } - - public static void WriteDouble(IntPtr handle, int offset, double value) - { - Marshal.WriteInt64(handle, offset, BitConverter.DoubleToInt64Bits(value)); - } - - public static float ReadFloat(IntPtr handle, int offset = 0) - { - return BitConverter.Int32BitsToSingle(Marshal.ReadInt32(handle, offset)); - } - - public static void WriteFloat(IntPtr handle, float value) - { - WriteFloat(handle, 0, value); - } - - public static void WriteFloat(IntPtr handle, int offset, float value) - { - Marshal.WriteInt32(handle, offset, BitConverter.SingleToInt32Bits(value)); - } - } -} \ No newline at end of file diff --git a/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIO.cs b/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIO.cs deleted file mode 100644 index c4ce1887d..000000000 --- a/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIO.cs +++ /dev/null @@ -1,386 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Runtime.InteropServices; - -namespace SoundIOSharp -{ - public class SoundIO : IDisposable - { - Pointer handle; - - public SoundIO() - { - handle = Natives.soundio_create(); - } - - internal SoundIO(Pointer handle) - { - this.handle = handle; - } - - public void Dispose () - { - foreach (var h in allocated_hglobals) - { - Marshal.FreeHGlobal(h); - } - - Natives.soundio_destroy(handle); - } - - // Equality (based on handle) - - public override bool Equals(object other) - { - var d = other as SoundIO; - - return d != null && this.handle == d.handle; - } - - public override int GetHashCode() - { - return (int)(IntPtr)handle; - } - - public static bool operator == (SoundIO obj1, SoundIO obj2) - { - return obj1 is null ? obj2 is null : obj1.Equals(obj2); - } - - public static bool operator != (SoundIO obj1, SoundIO obj2) - { - return obj1 is null ? obj2 is object : !obj1.Equals(obj2); - } - - // fields - - // FIXME: this should be taken care in more centralized/decent manner... we don't want to write - // this kind of code anywhere we need string marshaling. - List allocated_hglobals = new List(); - - public string ApplicationName { - get { return Marshal.PtrToStringAnsi(Marshal.ReadIntPtr(handle, app_name_offset)); } - set - { - unsafe - { - var existing = Marshal.ReadIntPtr(handle, app_name_offset); - if (allocated_hglobals.Contains (existing)) - { - allocated_hglobals.Remove(existing); - Marshal.FreeHGlobal(existing); - } - - var ptr = Marshal.StringToHGlobalAnsi(value); - Marshal.WriteIntPtr(handle, app_name_offset, ptr); - allocated_hglobals.Add(ptr); - } - } - } - - static readonly int app_name_offset = (int)Marshal.OffsetOf("app_name"); - - public SoundIOBackend CurrentBackend - { - get { return (SoundIOBackend)Marshal.ReadInt32(handle, current_backend_offset); } - } - - static readonly int current_backend_offset = (int)Marshal.OffsetOf("current_backend"); - - // emit_rtprio_warning - public Action EmitRealtimePriorityWarning - { - get { return emit_rtprio_warning; } - set - { - emit_rtprio_warning = value; - - var ptr = Marshal.GetFunctionPointerForDelegate(on_devices_change); - - Marshal.WriteIntPtr(handle, emit_rtprio_warning_offset, ptr); - } - } - - static readonly int emit_rtprio_warning_offset = (int)Marshal.OffsetOf("emit_rtprio_warning"); - - Action emit_rtprio_warning; - - // jack_error_callback - public Action JackErrorCallback - { - get { return jack_error_callback; } - set - { - jack_error_callback = value; - if (value == null) - { - jack_error_callback = null; - } - else - { - jack_error_callback_native = msg => jack_error_callback(msg); - } - - var ptr = Marshal.GetFunctionPointerForDelegate(jack_error_callback_native); - Marshal.WriteIntPtr(handle, jack_error_callback_offset, ptr); - } - } - - static readonly int jack_error_callback_offset = (int)Marshal.OffsetOf("jack_error_callback"); - - Action jack_error_callback; - delegate void jack_error_delegate(string message); - jack_error_delegate jack_error_callback_native; - - // jack_info_callback - public Action JackInfoCallback - { - get { return jack_info_callback; } - set - { - jack_info_callback = value; - if (value == null) - { - jack_info_callback = null; - } - else - { - jack_info_callback_native = msg => jack_info_callback(msg); - } - - var ptr = Marshal.GetFunctionPointerForDelegate(jack_info_callback_native); - Marshal.WriteIntPtr(handle, jack_info_callback_offset, ptr); - } - } - - static readonly int jack_info_callback_offset = (int)Marshal.OffsetOf("jack_info_callback"); - - Action jack_info_callback; - delegate void jack_info_delegate(string message); - jack_info_delegate jack_info_callback_native; - - // on_backend_disconnect - public Action OnBackendDisconnect - { - get { return on_backend_disconnect; } - set - { - on_backend_disconnect = value; - if (value == null) - { - on_backend_disconnect_native = null; - } - else - { - on_backend_disconnect_native = (sio, err) => on_backend_disconnect(err); - } - - var ptr = Marshal.GetFunctionPointerForDelegate(on_backend_disconnect_native); - Marshal.WriteIntPtr(handle, on_backend_disconnect_offset, ptr); - } - } - - static readonly int on_backend_disconnect_offset = (int)Marshal.OffsetOf("on_backend_disconnect"); - - Action on_backend_disconnect; - delegate void on_backend_disconnect_delegate(IntPtr handle, int errorCode); - on_backend_disconnect_delegate on_backend_disconnect_native; - - // on_devices_change - public Action OnDevicesChange - { - get { return on_devices_change; } - set - { - on_devices_change = value; - if (value == null) - { - on_devices_change_native = null; - } - else - { - on_devices_change_native = sio => on_devices_change(); - } - - var ptr = Marshal.GetFunctionPointerForDelegate(on_devices_change_native); - Marshal.WriteIntPtr(handle, on_devices_change_offset, ptr); - } - } - - static readonly int on_devices_change_offset = (int)Marshal.OffsetOf("on_devices_change"); - - Action on_devices_change; - delegate void on_devices_change_delegate(IntPtr handle); - on_devices_change_delegate on_devices_change_native; - - // on_events_signal - public Action OnEventsSignal - { - get { return on_events_signal; } - set - { - on_events_signal = value; - if (value == null) - { - on_events_signal_native = null; - } - else - { - on_events_signal_native = sio => on_events_signal(); - } - - var ptr = Marshal.GetFunctionPointerForDelegate(on_events_signal_native); - Marshal.WriteIntPtr(handle, on_events_signal_offset, ptr); - } - } - - static readonly int on_events_signal_offset = (int)Marshal.OffsetOf("on_events_signal"); - - Action on_events_signal; - delegate void on_events_signal_delegate(IntPtr handle); - on_events_signal_delegate on_events_signal_native; - - - // functions - - public int BackendCount - { - get { return Natives.soundio_backend_count(handle); } - } - - public int InputDeviceCount - { - get { return Natives.soundio_input_device_count(handle); } - } - - public int OutputDeviceCount - { - get { return Natives.soundio_output_device_count(handle); } - } - - public int DefaultInputDeviceIndex - { - get { return Natives.soundio_default_input_device_index(handle); } - } - - public int DefaultOutputDeviceIndex - { - get { return Natives.soundio_default_output_device_index(handle); } - } - - public SoundIOBackend GetBackend(int index) - { - return (SoundIOBackend)Natives.soundio_get_backend(handle, index); - } - - public SoundIODevice GetInputDevice(int index) - { - return new SoundIODevice(Natives.soundio_get_input_device(handle, index)); - } - - public SoundIODevice GetOutputDevice(int index) - { - return new SoundIODevice(Natives.soundio_get_output_device(handle, index)); - } - - public void Connect() - { - var ret = (SoundIoError)Natives.soundio_connect(handle); - if (ret != SoundIoError.SoundIoErrorNone) - { - throw new SoundIOException(ret); - } - } - - public void ConnectBackend(SoundIOBackend backend) - { - var ret = (SoundIoError)Natives.soundio_connect_backend(handle, (SoundIoBackend)backend); - if (ret != SoundIoError.SoundIoErrorNone) - { - throw new SoundIOException(ret); - } - } - - public void Disconnect() - { - Natives.soundio_disconnect(handle); - } - - public void FlushEvents() - { - Natives.soundio_flush_events(handle); - } - - public void WaitEvents() - { - Natives.soundio_wait_events(handle); - } - - public void Wakeup() - { - Natives.soundio_wakeup(handle); - } - - public void ForceDeviceScan() - { - Natives.soundio_force_device_scan(handle); - } - - public SoundIORingBuffer CreateRingBuffer(int capacity) - { - return new SoundIORingBuffer(Natives.soundio_ring_buffer_create(handle, capacity)); - } - - // static methods - - public static string VersionString - { - get { return Marshal.PtrToStringAnsi(Natives.soundio_version_string()); } - } - - public static int VersionMajor - { - get { return Natives.soundio_version_major(); } - } - - public static int VersionMinor - { - get { return Natives.soundio_version_minor(); } - } - - public static int VersionPatch - { - get { return Natives.soundio_version_patch(); } - } - - public static string GetBackendName(SoundIOBackend backend) - { - return Marshal.PtrToStringAnsi(Natives.soundio_backend_name((SoundIoBackend)backend)); - } - - public static bool HaveBackend(SoundIOBackend backend) - { - return Natives.soundio_have_backend((SoundIoBackend)backend); - } - - public static int GetBytesPerSample(SoundIOFormat format) - { - return Natives.soundio_get_bytes_per_sample((SoundIoFormat)format); - } - - public static int GetBytesPerFrame(SoundIOFormat format, int channelCount) - { - return Natives.soundio_get_bytes_per_frame((SoundIoFormat)format, channelCount); - } - - public static int GetBytesPerSecond(SoundIOFormat format, int channelCount, int sampleRate) - { - return Natives.soundio_get_bytes_per_second((SoundIoFormat)format, channelCount, sampleRate); - } - - public static string GetSoundFormatName(SoundIOFormat format) - { - return Marshal.PtrToStringAnsi(Natives.soundio_format_string((SoundIoFormat)format)); - } - } -} \ No newline at end of file diff --git a/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIOBackend.cs b/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIOBackend.cs deleted file mode 100644 index fd1058047..000000000 --- a/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIOBackend.cs +++ /dev/null @@ -1,13 +0,0 @@ -namespace SoundIOSharp -{ - public enum SoundIOBackend - { - None, - Jack, - PulseAudio, - Alsa, - CoreAudio, - Wasapi, - Dummy - } -} \ No newline at end of file diff --git a/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIOChannelArea.cs b/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIOChannelArea.cs deleted file mode 100644 index c15fb7447..000000000 --- a/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIOChannelArea.cs +++ /dev/null @@ -1,30 +0,0 @@ -using System; -using System.Runtime.InteropServices; - -namespace SoundIOSharp -{ - public struct SoundIOChannelArea - { - internal SoundIOChannelArea(Pointer handle) - { - this.handle = handle; - } - - Pointer handle; - - public IntPtr Pointer - { - get { return Marshal.ReadIntPtr(handle, ptr_offset); } - set { Marshal.WriteIntPtr(handle, ptr_offset, value); } - } - - static readonly int ptr_offset = (int)Marshal.OffsetOf("ptr"); - - public int Step - { - get { return Marshal.ReadInt32(handle, step_offset); } - } - - static readonly int step_offset = (int)Marshal.OffsetOf("step"); - } -} \ No newline at end of file diff --git a/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIOChannelAreas.cs b/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIOChannelAreas.cs deleted file mode 100644 index e0f375b96..000000000 --- a/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIOChannelAreas.cs +++ /dev/null @@ -1,34 +0,0 @@ -using System; -using System.Runtime.InteropServices; - -namespace SoundIOSharp -{ - public struct SoundIOChannelAreas - { - static readonly int native_size = Marshal.SizeOf(); - - internal SoundIOChannelAreas(IntPtr head, int channelCount, int frameCount) - { - this.head = head; - this.channel_count = channelCount; - this.frame_count = frameCount; - } - - IntPtr head; - int channel_count; - int frame_count; - - public bool IsEmpty - { - get { return head == IntPtr.Zero; } - } - - public SoundIOChannelArea GetArea(int channel) - { - return new SoundIOChannelArea(head + native_size * channel); - } - - public int ChannelCount => channel_count; - public int FrameCount => frame_count; - } -} \ No newline at end of file diff --git a/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIOChannelId.cs b/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIOChannelId.cs deleted file mode 100644 index 002669dcf..000000000 --- a/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIOChannelId.cs +++ /dev/null @@ -1,75 +0,0 @@ -namespace SoundIOSharp -{ - public enum SoundIOChannelId - { - Invalid, - FrontLeft, - FrontRight, - FrontCenter, - Lfe, - BackLeft, - BackRight, - FrontLeftCenter, - FrontRightCenter, - BackCenter, - SideLeft, - SideRight, - TopCenter, - TopFrontLeft, - TopFrontCenter, - TopFrontRight, - TopBackLeft, - TopBackCenter, - TopBackRight, - BackLeftCenter, - BackRightCenter, - FrontLeftWide, - FrontRightWide, - FrontLeftHigh, - FrontCenterHigh, - FrontRightHigh, - TopFrontLeftCenter, - TopFrontRightCenter, - TopSideLeft, - TopSideRight, - LeftLfe, - RightLfe, - Lfe2, - BottomCenter, - BottomLeftCenter, - BottomRightCenter, - MsMid, - MsSide, - AmbisonicW, - AmbisonicX, - AmbisonicY, - AmbisonicZ, - XyX, - XyY, - HeadphonesLeft, - HeadphonesRight, - ClickTrack, - ForeignLanguage, - HearingImpaired, - Narration, - Haptic, - DialogCentricMix, - Aux, - Aux0, - Aux1, - Aux2, - Aux3, - Aux4, - Aux5, - Aux6, - Aux7, - Aux8, - Aux9, - Aux10, - Aux11, - Aux12, - Aux13, - Aux14, - Aux15 - } -} \ No newline at end of file diff --git a/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIOChannelLayout.cs b/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIOChannelLayout.cs deleted file mode 100644 index cff6114fa..000000000 --- a/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIOChannelLayout.cs +++ /dev/null @@ -1,116 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Runtime.InteropServices; - -namespace SoundIOSharp -{ - public struct SoundIOChannelLayout - { - public static int BuiltInCount - { - get { return Natives.soundio_channel_layout_builtin_count(); } - } - - public static SoundIOChannelLayout GetBuiltIn(int index) - { - return new SoundIOChannelLayout(Natives.soundio_channel_layout_get_builtin(index)); - } - - public static SoundIOChannelLayout GetDefault(int channelCount) - { - var handle = Natives.soundio_channel_layout_get_default(channelCount); - - return new SoundIOChannelLayout (handle); - } - - public static SoundIOChannelId ParseChannelId(string name) - { - var ptr = Marshal.StringToHGlobalAnsi(name); - - try - { - return (SoundIOChannelId)Natives.soundio_parse_channel_id(ptr, name.Length); - } - finally - { - Marshal.FreeHGlobal(ptr); - } - } - - // instance members - - internal SoundIOChannelLayout(Pointer handle) - { - this.handle = handle; - } - - readonly Pointer handle; - - public bool IsNull - { - get { return handle.Handle == IntPtr.Zero; } - } - - internal IntPtr Handle - { - get { return handle; } - } - - public int ChannelCount - { - get { return IsNull ? 0 : Marshal.ReadInt32((IntPtr)handle + channel_count_offset); } - } - - static readonly int channel_count_offset = (int)Marshal.OffsetOf("channel_count"); - - public string Name - { - get { return IsNull ? null : Marshal.PtrToStringAnsi(Marshal.ReadIntPtr((IntPtr)handle + name_offset)); } - } - - static readonly int name_offset = (int)Marshal.OffsetOf("name"); - - public IEnumerable Channels - { - get - { - if (IsNull) yield break; - - for (int i = 0; i < 24; i++) - { - yield return (SoundIOChannelId)Marshal.ReadInt32((IntPtr)handle + channels_offset + sizeof(SoundIoChannelId) * i); - } - } - } - - static readonly int channels_offset = (int)Marshal.OffsetOf("channels"); - - public override bool Equals(object other) - { - if (!(other is SoundIOChannelLayout)) return false; - - var s = (SoundIOChannelLayout) other; - - return handle == s.handle || Natives.soundio_channel_layout_equal(handle, s.handle); - } - - public override int GetHashCode() - { - return handle.GetHashCode(); - } - - public string DetectBuiltInName() - { - if (IsNull) throw new InvalidOperationException(); - - return Natives.soundio_channel_layout_detect_builtin(handle) ? Name : null; - } - - public int FindChannel(SoundIOChannelId channel) - { - if (IsNull) throw new InvalidOperationException(); - - return Natives.soundio_channel_layout_find_channel(handle, (SoundIoChannelId)channel); - } - } -} \ No newline at end of file diff --git a/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIODevice.cs b/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIODevice.cs deleted file mode 100644 index 6e7c49649..000000000 --- a/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIODevice.cs +++ /dev/null @@ -1,267 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Runtime.InteropServices; - -namespace SoundIOSharp -{ - public class SoundIODevice - { - public static SoundIOChannelLayout BestMatchingChannelLayout(SoundIODevice device1, SoundIODevice device2) - { - var ptr1 = Marshal.ReadIntPtr(device1.handle, layouts_offset); - var ptr2 = Marshal.ReadIntPtr(device2.handle, layouts_offset); - - return new SoundIOChannelLayout(Natives.soundio_best_matching_channel_layout(ptr1, device1.LayoutCount, ptr2, device2.LayoutCount)); - } - - internal SoundIODevice(Pointer handle) - { - this.handle = handle; - } - - readonly Pointer handle; - - // Equality (based on handle and native func) - - public override bool Equals(object other) - { - var d = other as SoundIODevice; - - return d != null && (this.handle == d.handle || Natives.soundio_device_equal (this.handle, d.handle)); - } - - public override int GetHashCode() - { - return (int)(IntPtr)handle; - } - - public static bool operator == (SoundIODevice obj1, SoundIODevice obj2) - { - return obj1 is null ? obj2 is null : obj1.Equals(obj2); - } - - public static bool operator != (SoundIODevice obj1, SoundIODevice obj2) - { - return obj1 is null ? obj2 is object : !obj1.Equals(obj2); - } - - // fields - - public SoundIODeviceAim Aim - { - get { return (SoundIODeviceAim)Marshal.ReadInt32(handle, aim_offset); } - } - - static readonly int aim_offset = (int)Marshal.OffsetOf("aim"); - - public SoundIOFormat CurrentFormat - { - get { return (SoundIOFormat)Marshal.ReadInt32(handle, current_format_offset); } - } - - static readonly int current_format_offset = (int)Marshal.OffsetOf("current_format"); - - public SoundIOChannelLayout CurrentLayout - { - get { return new SoundIOChannelLayout((IntPtr)handle + current_layout_offset); } - } - - static readonly int current_layout_offset = (int)Marshal.OffsetOf("current_layout"); - - public int FormatCount - { - get { return Marshal.ReadInt32(handle, format_count_offset); } - } - - static readonly int format_count_offset = (int)Marshal.OffsetOf("format_count"); - - public IEnumerable Formats - { - get - { - var ptr = Marshal.ReadIntPtr(handle, formats_offset); - - for (int i = 0; i < FormatCount; i++) - { - yield return (SoundIOFormat)Marshal.ReadInt32(ptr, i); - } - } - } - - static readonly int formats_offset = (int)Marshal.OffsetOf("formats"); - - public string Id - { - get { return Marshal.PtrToStringAnsi(Marshal.ReadIntPtr(handle, id_offset)); } - } - - static readonly int id_offset = (int)Marshal.OffsetOf("id"); - - public bool IsRaw - { - get { return Marshal.ReadInt32(handle, is_raw_offset) != 0; } - } - - static readonly int is_raw_offset = (int)Marshal.OffsetOf("is_raw"); - - public int LayoutCount - { - get { return Marshal.ReadInt32(handle, layout_count_offset); } - } - - static readonly int layout_count_offset = (int)Marshal.OffsetOf("layout_count"); - - public IEnumerable Layouts - { - get - { - var ptr = Marshal.ReadIntPtr (handle, layouts_offset); - - for (int i = 0; i < LayoutCount; i++) - { - yield return new SoundIOChannelLayout(ptr + i * Marshal.SizeOf()); - } - } - } - - static readonly int layouts_offset = (int)Marshal.OffsetOf("layouts"); - - public string Name - { - get { return Marshal.PtrToStringAnsi(Marshal.ReadIntPtr(handle, name_offset)); } - } - - static readonly int name_offset = (int)Marshal.OffsetOf("name"); - - public int ProbeError - { - get { return Marshal.ReadInt32(handle, probe_error_offset); } - } - - static readonly int probe_error_offset = (int)Marshal.OffsetOf("probe_error"); - - public int ReferenceCount - { - get { return Marshal.ReadInt32(handle, ref_count_offset); } - } - - static readonly int ref_count_offset = (int)Marshal.OffsetOf("ref_count"); - - public int SampleRateCount - { - get { return Marshal.ReadInt32(handle, sample_rate_count_offset); } - } - - static readonly int sample_rate_count_offset = (int)Marshal.OffsetOf("sample_rate_count"); - - public IEnumerable SampleRates - { - get - { - var ptr = Marshal.ReadIntPtr(handle, sample_rates_offset); - - for (int i = 0; i < SampleRateCount; i++) - { - yield return new SoundIOSampleRateRange(Marshal.ReadInt32(ptr, i * 2), Marshal.ReadInt32(ptr, i * 2 + 1)); - } - } - } - - static readonly int sample_rates_offset = (int)Marshal.OffsetOf("sample_rates"); - - public double SoftwareLatencyCurrent - { - get { return MarshalEx.ReadDouble(handle, software_latency_current_offset); } - set { MarshalEx.WriteDouble(handle, software_latency_current_offset, value); } - } - - static readonly int software_latency_current_offset = (int)Marshal.OffsetOf("software_latency_current"); - - public double SoftwareLatencyMin - { - get { return MarshalEx.ReadDouble(handle, software_latency_min_offset); } - set { MarshalEx.WriteDouble(handle, software_latency_min_offset, value); } - } - - static readonly int software_latency_min_offset = (int)Marshal.OffsetOf("software_latency_min"); - - public double SoftwareLatencyMax - { - get { return MarshalEx.ReadDouble(handle, software_latency_max_offset); } - set { MarshalEx.WriteDouble(handle, software_latency_max_offset, value); } - } - - static readonly int software_latency_max_offset = (int)Marshal.OffsetOf("software_latency_max"); - - public SoundIO SoundIO - { - get { return new SoundIO(Marshal.ReadIntPtr(handle, soundio_offset)); } - } - - static readonly int soundio_offset = (int)Marshal.OffsetOf("soundio"); - - // functions - - public void AddReference() - { - Natives.soundio_device_ref(handle); - } - - public void RemoveReference() - { - Natives.soundio_device_unref(handle); - } - - public void SortDeviceChannelLayouts() - { - Natives.soundio_device_sort_channel_layouts(handle); - } - - public static readonly SoundIOFormat S16NE = BitConverter.IsLittleEndian ? SoundIOFormat.S16LE : SoundIOFormat.S16BE; - public static readonly SoundIOFormat U16NE = BitConverter.IsLittleEndian ? SoundIOFormat.U16LE : SoundIOFormat.U16BE; - public static readonly SoundIOFormat S24NE = BitConverter.IsLittleEndian ? SoundIOFormat.S24LE : SoundIOFormat.S24BE; - public static readonly SoundIOFormat U24NE = BitConverter.IsLittleEndian ? SoundIOFormat.U24LE : SoundIOFormat.U24BE; - public static readonly SoundIOFormat S32NE = BitConverter.IsLittleEndian ? SoundIOFormat.S32LE : SoundIOFormat.S32BE; - public static readonly SoundIOFormat U32NE = BitConverter.IsLittleEndian ? SoundIOFormat.U32LE : SoundIOFormat.U32BE; - public static readonly SoundIOFormat Float32NE = BitConverter.IsLittleEndian ? SoundIOFormat.Float32LE : SoundIOFormat.Float32BE; - public static readonly SoundIOFormat Float64NE = BitConverter.IsLittleEndian ? SoundIOFormat.Float64LE : SoundIOFormat.Float64BE; - public static readonly SoundIOFormat S16FE = !BitConverter.IsLittleEndian ? SoundIOFormat.S16LE : SoundIOFormat.S16BE; - public static readonly SoundIOFormat U16FE = !BitConverter.IsLittleEndian ? SoundIOFormat.U16LE : SoundIOFormat.U16BE; - public static readonly SoundIOFormat S24FE = !BitConverter.IsLittleEndian ? SoundIOFormat.S24LE : SoundIOFormat.S24BE; - public static readonly SoundIOFormat U24FE = !BitConverter.IsLittleEndian ? SoundIOFormat.U24LE : SoundIOFormat.U24BE; - public static readonly SoundIOFormat S32FE = !BitConverter.IsLittleEndian ? SoundIOFormat.S32LE : SoundIOFormat.S32BE; - public static readonly SoundIOFormat U32FE = !BitConverter.IsLittleEndian ? SoundIOFormat.U32LE : SoundIOFormat.U32BE; - public static readonly SoundIOFormat Float32FE = !BitConverter.IsLittleEndian ? SoundIOFormat.Float32LE : SoundIOFormat.Float32BE; - public static readonly SoundIOFormat Float64FE = !BitConverter.IsLittleEndian ? SoundIOFormat.Float64LE : SoundIOFormat.Float64BE; - - public bool SupportsFormat(SoundIOFormat format) - { - return Natives.soundio_device_supports_format(handle, (SoundIoFormat)format); - } - - public bool SupportsSampleRate(int sampleRate) - { - return Natives.soundio_device_supports_sample_rate(handle, sampleRate); - } - - public bool SupportsChannelCount(int channelCount) - { - return Natives.soundio_device_supports_layout(handle, SoundIOChannelLayout.GetDefault(channelCount).Handle); - } - - public int GetNearestSampleRate(int sampleRate) - { - return Natives.soundio_device_nearest_sample_rate(handle, sampleRate); - } - - public SoundIOInStream CreateInStream() - { - return new SoundIOInStream(Natives.soundio_instream_create(handle)); - } - - public SoundIOOutStream CreateOutStream() - { - return new SoundIOOutStream(Natives.soundio_outstream_create(handle)); - } - } -} \ No newline at end of file diff --git a/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIODeviceAim.cs b/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIODeviceAim.cs deleted file mode 100644 index 1e596127b..000000000 --- a/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIODeviceAim.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace SoundIOSharp -{ - public enum SoundIODeviceAim // soundio.h (228, 6) - { - Input, - Output - } -} \ No newline at end of file diff --git a/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIOException.cs b/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIOException.cs deleted file mode 100644 index 537b6cde2..000000000 --- a/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIOException.cs +++ /dev/null @@ -1,10 +0,0 @@ -using System; -using System.Runtime.InteropServices; - -namespace SoundIOSharp -{ - public class SoundIOException : Exception - { - internal SoundIOException(SoundIoError errorCode) : base (Marshal.PtrToStringAnsi(Natives.soundio_strerror((int) errorCode))) { } - } -} \ No newline at end of file diff --git a/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIOFormat.cs b/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIOFormat.cs deleted file mode 100644 index df1b71c6b..000000000 --- a/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIOFormat.cs +++ /dev/null @@ -1,25 +0,0 @@ -namespace SoundIOSharp -{ - public enum SoundIOFormat - { - Invalid, - S8, - U8, - S16LE, - S16BE, - U16LE, - U16BE, - S24LE, - S24BE, - U24LE, - U24BE, - S32LE, - S32BE, - U32LE, - U32BE, - Float32LE, - Float32BE, - Float64LE, - Float64BE - } -} \ No newline at end of file diff --git a/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIOInStream.cs b/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIOInStream.cs deleted file mode 100644 index df97d6536..000000000 --- a/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIOInStream.cs +++ /dev/null @@ -1,293 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Runtime.InteropServices; - -namespace SoundIOSharp -{ - public class SoundIOInStream : IDisposable - { - internal SoundIOInStream(Pointer handle) - { - this.handle = handle; - } - - Pointer handle; - - public void Dispose() - { - Natives.soundio_instream_destroy(handle); - } - - // Equality (based on handle) - - public override bool Equals(object other) - { - var d = other as SoundIOInStream; - - return d != null && (this.handle == d.handle); - } - - public override int GetHashCode() - { - return (int)(IntPtr)handle; - } - - public static bool operator == (SoundIOInStream obj1, SoundIOInStream obj2) - { - return obj1 is null ? obj2 is null : obj1.Equals(obj2); - } - - public static bool operator != (SoundIOInStream obj1, SoundIOInStream obj2) - { - return obj1 is null ? obj2 is object : !obj1.Equals(obj2); - } - - // fields - - public SoundIODevice Device - { - get { return new SoundIODevice(Marshal.ReadIntPtr(handle, device_offset)); } - } - - static readonly int device_offset = (int)Marshal.OffsetOf("device"); - - public SoundIOFormat Format - { - get { return (SoundIOFormat)Marshal.ReadInt32(handle, format_offset); } - set { Marshal.WriteInt32(handle, format_offset, (int) value); } - } - - static readonly int format_offset = (int)Marshal.OffsetOf("format"); - - public int SampleRate - { - get { return Marshal.ReadInt32(handle, sample_rate_offset); } - set { Marshal.WriteInt32(handle, sample_rate_offset, value); } - } - - static readonly int sample_rate_offset = (int)Marshal.OffsetOf("sample_rate"); - - public SoundIOChannelLayout Layout - { - get { return new SoundIOChannelLayout ((IntPtr) handle + layout_offset); } - set - { - unsafe - { - Buffer.MemoryCopy((void*)((IntPtr)handle + layout_offset), (void*)value.Handle, Marshal.SizeOf(), Marshal.SizeOf()); - } - } - } - - static readonly int layout_offset = (int)Marshal.OffsetOf("layout"); - - public double SoftwareLatency - { - get { return MarshalEx.ReadDouble(handle, software_latency_offset); } - set { MarshalEx.WriteDouble(handle, software_latency_offset, value); } - } - - static readonly int software_latency_offset = (int)Marshal.OffsetOf("software_latency"); - - // error_callback - public Action ErrorCallback - { - get { return error_callback; } - set - { - error_callback = value; - error_callback_native = _ => error_callback(); - - var ptr = Marshal.GetFunctionPointerForDelegate(error_callback_native); - - Marshal.WriteIntPtr(handle, error_callback_offset, ptr); - } - } - - static readonly int error_callback_offset = (int)Marshal.OffsetOf("error_callback"); - - Action error_callback; - delegate void error_callback_delegate(IntPtr handle); - error_callback_delegate error_callback_native; - - // read_callback - public Action ReadCallback - { - get { return read_callback; } - set - { - read_callback = value; - read_callback_native = (_, minFrameCount, maxFrameCount) => read_callback(minFrameCount, maxFrameCount); - - var ptr = Marshal.GetFunctionPointerForDelegate(read_callback_native); - - Marshal.WriteIntPtr(handle, read_callback_offset, ptr); - } - } - - static readonly int read_callback_offset = (int)Marshal.OffsetOf("read_callback"); - - Action read_callback; - delegate void read_callback_delegate(IntPtr handle, int min, int max); - read_callback_delegate read_callback_native; - - // overflow_callback - public Action OverflowCallback - { - get { return overflow_callback; } - set - { - overflow_callback = value; - overflow_callback_native = _ => overflow_callback(); - - var ptr = Marshal.GetFunctionPointerForDelegate(overflow_callback_native); - - Marshal.WriteIntPtr(handle, overflow_callback_offset, ptr); - } - } - static readonly int overflow_callback_offset = (int)Marshal.OffsetOf("overflow_callback"); - - Action overflow_callback; - delegate void overflow_callback_delegate(IntPtr handle); - overflow_callback_delegate overflow_callback_native; - - // FIXME: this should be taken care in more centralized/decent manner... we don't want to write - // this kind of code anywhere we need string marshaling. - List allocated_hglobals = new List(); - - public string Name - { - get { return Marshal.PtrToStringAnsi(Marshal.ReadIntPtr(handle, name_offset)); } - set - { - unsafe - { - var existing = Marshal.ReadIntPtr(handle, name_offset); - if (allocated_hglobals.Contains(existing)) - { - allocated_hglobals.Remove(existing); - Marshal.FreeHGlobal(existing); - } - - var ptr = Marshal.StringToHGlobalAnsi(value); - Marshal.WriteIntPtr(handle, name_offset, ptr); - allocated_hglobals.Add(ptr); - } - } - } - - static readonly int name_offset = (int)Marshal.OffsetOf("name"); - - public bool NonTerminalHint - { - get { return Marshal.ReadInt32(handle, non_terminal_hint_offset) != 0; } - } - - static readonly int non_terminal_hint_offset = (int)Marshal.OffsetOf("non_terminal_hint"); - - public int BytesPerFrame - { - get { return Marshal.ReadInt32(handle, bytes_per_frame_offset); } - } - - static readonly int bytes_per_frame_offset = (int)Marshal.OffsetOf("bytes_per_frame"); - - public int BytesPerSample - { - get { return Marshal.ReadInt32(handle, bytes_per_sample_offset); } - } - - static readonly int bytes_per_sample_offset = (int)Marshal.OffsetOf("bytes_per_sample"); - - public string LayoutErrorMessage - { - get - { - var code = (SoundIoError)Marshal.ReadInt32(handle, layout_error_offset); - - return code == SoundIoError.SoundIoErrorNone ? null : Marshal.PtrToStringAnsi(Natives.soundio_strerror((int)code)); - } - } - - static readonly int layout_error_offset = (int)Marshal.OffsetOf("layout_error"); - - // functions - - public void Open() - { - var ret = (SoundIoError)Natives.soundio_instream_open(handle); - if (ret != SoundIoError.SoundIoErrorNone) - { - throw new SoundIOException(ret); - } - } - - public void Start() - { - var ret = (SoundIoError)Natives.soundio_instream_start(handle); - if (ret != SoundIoError.SoundIoErrorNone) - { - throw new SoundIOException(ret); - } - } - - public SoundIOChannelAreas BeginRead(ref int frameCount) - { - IntPtr ptrs = default; - int nativeFrameCount = frameCount; - - unsafe - { - var frameCountPtr = &nativeFrameCount; - var ptrptr = &ptrs; - var ret = (SoundIoError)Natives.soundio_instream_begin_read(handle, (IntPtr)ptrptr, (IntPtr)frameCountPtr); - - frameCount = *frameCountPtr; - - if (ret != SoundIoError.SoundIoErrorNone) - { - throw new SoundIOException(ret); - } - - return new SoundIOChannelAreas(ptrs, Layout.ChannelCount, frameCount); - } - } - - public void EndRead() - { - var ret = (SoundIoError)Natives.soundio_instream_end_read(handle); - if (ret != SoundIoError.SoundIoErrorNone) - { - throw new SoundIOException(ret); - } - } - - public void Pause(bool pause) - { - var ret = (SoundIoError)Natives.soundio_instream_pause(handle, pause); - if (ret != SoundIoError.SoundIoErrorNone) - { - throw new SoundIOException(ret); - } - } - - public double GetLatency() - { - unsafe - { - double* dptr = null; - IntPtr p = new IntPtr(dptr); - - var ret = (SoundIoError)Natives.soundio_instream_get_latency(handle, p); - if (ret != SoundIoError.SoundIoErrorNone) - { - throw new SoundIOException(ret); - } - - dptr = (double*)p; - - return *dptr; - } - } - } -} diff --git a/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIOOutStream.cs b/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIOOutStream.cs deleted file mode 100644 index 432ca42b8..000000000 --- a/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIOOutStream.cs +++ /dev/null @@ -1,331 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Runtime.InteropServices; - -namespace SoundIOSharp -{ - public class SoundIOOutStream : IDisposable - { - internal SoundIOOutStream (Pointer handle) - { - this.handle = handle; - } - - Pointer handle; - - public void Dispose () - { - Natives.soundio_outstream_destroy (handle); - } - // Equality (based on handle) - - public override bool Equals (object other) - { - var d = other as SoundIOOutStream; - - return d != null && (this.handle == d.handle); - } - - public override int GetHashCode () - { - return (int)(IntPtr)handle; - } - - public static bool operator == (SoundIOOutStream obj1, SoundIOOutStream obj2) - { - return obj1 is null ? obj2 is null : obj1.Equals(obj2); - } - - public static bool operator != (SoundIOOutStream obj1, SoundIOOutStream obj2) - { - return obj1 is null ? obj2 is object : !obj1.Equals(obj2); - } - - // fields - - public SoundIODevice Device - { - get { return new SoundIODevice(Marshal.ReadIntPtr(handle, device_offset)); } - } - - static readonly int device_offset = (int)Marshal.OffsetOf("device"); - - public SoundIOFormat Format - { - get { return (SoundIOFormat) Marshal.ReadInt32(handle, format_offset); } - set { Marshal.WriteInt32(handle, format_offset, (int) value); } - } - - static readonly int format_offset = (int)Marshal.OffsetOf("format"); - - public int SampleRate - { - get { return Marshal.ReadInt32(handle, sample_rate_offset); } - set { Marshal.WriteInt32(handle, sample_rate_offset, value); } - } - - static readonly int sample_rate_offset = (int)Marshal.OffsetOf("sample_rate"); - - public SoundIOChannelLayout Layout - { - get { unsafe { return new SoundIOChannelLayout((IntPtr) (void*)((IntPtr)handle + layout_offset)); } } - set - { - unsafe - { - Buffer.MemoryCopy((void*)value.Handle, (void*)((IntPtr)handle + layout_offset), Marshal.SizeOf(), Marshal.SizeOf()); - } - } - } - static readonly int layout_offset = (int)Marshal.OffsetOf("layout"); - - public double SoftwareLatency - { - get { return MarshalEx.ReadDouble (handle, software_latency_offset); } - set { MarshalEx.WriteDouble (handle, software_latency_offset, value); } - } - - static readonly int software_latency_offset = (int)Marshal.OffsetOf("software_latency"); - - public float Volume - { - get { return MarshalEx.ReadFloat(handle, volume_offset); } - set { MarshalEx.WriteFloat(handle, volume_offset, value); } - } - - static readonly int volume_offset = (int)Marshal.OffsetOf("volume"); - - // error_callback - public Action ErrorCallback - { - get { return error_callback; } - set - { - error_callback = value; - if (value == null) - { - error_callback_native = null; - } - else - { - error_callback_native = stream => error_callback(); - } - - var ptr = Marshal.GetFunctionPointerForDelegate(error_callback_native); - Marshal.WriteIntPtr(handle, error_callback_offset, ptr); - } - } - - static readonly int error_callback_offset = (int)Marshal.OffsetOf("error_callback"); - - Action error_callback; - delegate void error_callback_delegate (IntPtr handle); - error_callback_delegate error_callback_native; - - // write_callback - public Action WriteCallback - { - get { return write_callback; } - set - { - write_callback = value; - if (value == null) - { - write_callback_native = null; - } - else - { - write_callback_native = (h, frame_count_min, frame_count_max) => write_callback(frame_count_min, frame_count_max); - } - - var ptr = Marshal.GetFunctionPointerForDelegate (write_callback_native); - Marshal.WriteIntPtr (handle, write_callback_offset, ptr); - } - } - - static readonly int write_callback_offset = (int)Marshal.OffsetOf("write_callback"); - - Action write_callback; - delegate void write_callback_delegate(IntPtr handle, int min, int max); - write_callback_delegate write_callback_native; - - // underflow_callback - public Action UnderflowCallback - { - get { return underflow_callback; } - set - { - underflow_callback = value; - if (value == null) - { - underflow_callback_native = null; - } - else - { - underflow_callback_native = h => underflow_callback(); - } - - var ptr = Marshal.GetFunctionPointerForDelegate (underflow_callback_native); - Marshal.WriteIntPtr (handle, underflow_callback_offset, ptr); - } - } - - static readonly int underflow_callback_offset = (int)Marshal.OffsetOf("underflow_callback"); - - Action underflow_callback; - delegate void underflow_callback_delegate(IntPtr handle); - underflow_callback_delegate underflow_callback_native; - - // FIXME: this should be taken care in more centralized/decent manner... we don't want to write - // this kind of code anywhere we need string marshaling. - List allocated_hglobals = new List(); - - public string Name { - get { return Marshal.PtrToStringAnsi(Marshal.ReadIntPtr(handle, name_offset)); } - set - { - unsafe - { - var existing = Marshal.ReadIntPtr(handle, name_offset); - if (allocated_hglobals.Contains(existing)) - { - allocated_hglobals.Remove(existing); - Marshal.FreeHGlobal(existing); - } - - var ptr = Marshal.StringToHGlobalAnsi(value); - Marshal.WriteIntPtr(handle, name_offset, ptr); - allocated_hglobals.Add(ptr); - } - } - } - - static readonly int name_offset = (int)Marshal.OffsetOf("name"); - - public bool NonTerminalHint - { - get { return Marshal.ReadInt32(handle, non_terminal_hint_offset) != 0; } - } - - static readonly int non_terminal_hint_offset = (int)Marshal.OffsetOf("non_terminal_hint"); - - public int BytesPerFrame - { - get { return Marshal.ReadInt32(handle, bytes_per_frame_offset); } - } - - static readonly int bytes_per_frame_offset = (int)Marshal.OffsetOf("bytes_per_frame"); - - public int BytesPerSample - { - get { return Marshal.ReadInt32(handle, bytes_per_sample_offset); } - } - - static readonly int bytes_per_sample_offset = (int)Marshal.OffsetOf("bytes_per_sample"); - - public string LayoutErrorMessage - { - get - { - var code = (SoundIoError)Marshal.ReadInt32(handle, layout_error_offset); - - return code == SoundIoError.SoundIoErrorNone ? null : Marshal.PtrToStringAnsi(Natives.soundio_strerror((int)code)); - } - } - - static readonly int layout_error_offset = (int)Marshal.OffsetOf ("layout_error"); - - // functions - - public void Open () - { - var ret = (SoundIoError)Natives.soundio_outstream_open(handle); - if (ret != SoundIoError.SoundIoErrorNone) - { - throw new SoundIOException(ret); - } - } - - public void Start () - { - var ret = (SoundIoError)Natives.soundio_outstream_start(handle); - if (ret != SoundIoError.SoundIoErrorNone) - { - throw new SoundIOException(ret); - } - } - - public SoundIOChannelAreas BeginWrite(ref int frameCount) - { - IntPtr ptrs = default; - int nativeFrameCount = frameCount; - - unsafe - { - var frameCountPtr = &nativeFrameCount; - var ptrptr = &ptrs; - var ret = (SoundIoError)Natives.soundio_outstream_begin_write(handle, (IntPtr)ptrptr, (IntPtr)frameCountPtr); - - frameCount = *frameCountPtr; - - if (ret != SoundIoError.SoundIoErrorNone) - { - throw new SoundIOException(ret); - } - - return new SoundIOChannelAreas(ptrs, Layout.ChannelCount, frameCount); - } - } - - public void EndWrite () - { - var ret = (SoundIoError)Natives.soundio_outstream_end_write(handle); - if (ret != SoundIoError.SoundIoErrorNone) - { - throw new SoundIOException(ret); - } - } - - public void ClearBuffer () - { - _ = Natives.soundio_outstream_clear_buffer(handle); - } - - public void Pause (bool pause) - { - var ret = (SoundIoError)Natives.soundio_outstream_pause(handle, pause); - if (ret != SoundIoError.SoundIoErrorNone) - { - throw new SoundIOException(ret); - } - } - - public double GetLatency () - { - unsafe - { - double* dptr = null; - IntPtr p = new IntPtr(dptr); - - var ret = (SoundIoError)Natives.soundio_outstream_get_latency(handle, p); - if (ret != SoundIoError.SoundIoErrorNone) - { - throw new SoundIOException(ret); - } - - dptr = (double*)p; - - return *dptr; - } - } - - public void SetVolume (double volume) - { - var ret = (SoundIoError)Natives.soundio_outstream_set_volume(handle, volume); - if (ret != SoundIoError.SoundIoErrorNone) - { - throw new SoundIOException(ret); - } - } - } -} diff --git a/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIORingBuffer.cs b/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIORingBuffer.cs deleted file mode 100644 index 7530da72c..000000000 --- a/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIORingBuffer.cs +++ /dev/null @@ -1,58 +0,0 @@ -using System; -namespace SoundIOSharp -{ - public class SoundIORingBuffer : IDisposable - { - internal SoundIORingBuffer(IntPtr handle) - { - this.handle = handle; - } - - IntPtr handle; - - public int Capacity - { - get { return Natives.soundio_ring_buffer_capacity(handle); } - } - - public void Clear() - { - Natives.soundio_ring_buffer_clear(handle); - } - - public void Dispose() - { - Natives.soundio_ring_buffer_destroy(handle); - } - - public int FillCount - { - get { return Natives.soundio_ring_buffer_fill_count(handle); } - } - - public int FreeCount - { - get { return Natives.soundio_ring_buffer_free_count(handle); } - } - - public IntPtr ReadPointer - { - get { return Natives.soundio_ring_buffer_read_ptr(handle); } - } - - public IntPtr WritePointer - { - get { return Natives.soundio_ring_buffer_write_ptr(handle); } - } - - public void AdvanceReadPointer(int count) - { - Natives.soundio_ring_buffer_advance_read_ptr(handle, count); - } - - public void AdvanceWritePointer(int count) - { - Natives.soundio_ring_buffer_advance_write_ptr(handle, count); - } - } -} \ No newline at end of file diff --git a/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIOSampleRateRange.cs b/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIOSampleRateRange.cs deleted file mode 100644 index 3cdf75138..000000000 --- a/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIOSampleRateRange.cs +++ /dev/null @@ -1,14 +0,0 @@ -namespace SoundIOSharp -{ - public struct SoundIOSampleRateRange - { - internal SoundIOSampleRateRange(int min, int max) - { - Min = min; - Max = max; - } - - public readonly int Min; - public readonly int Max; - } -} diff --git a/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/libsoundio-interop.cs b/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/libsoundio-interop.cs deleted file mode 100644 index 5377582f3..000000000 --- a/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/libsoundio-interop.cs +++ /dev/null @@ -1,643 +0,0 @@ -// This source file is generated by nclang PInvokeGenerator. -using System; -using System.Runtime.InteropServices; -using delegate0 = SoundIOSharp.Delegates.delegate0; -using delegate1 = SoundIOSharp.Delegates.delegate1; -using delegate2 = SoundIOSharp.Delegates.delegate2; -using delegate3 = SoundIOSharp.Delegates.delegate3; -using delegate4 = SoundIOSharp.Delegates.delegate4; -using delegate5 = SoundIOSharp.Delegates.delegate5; -using delegate6 = SoundIOSharp.Delegates.delegate6; -using delegate7 = SoundIOSharp.Delegates.delegate7; -using delegate8 = SoundIOSharp.Delegates.delegate8; -using delegate9 = SoundIOSharp.Delegates.delegate9; - -namespace SoundIOSharp -{ - enum SoundIoError // soundio.h (72, 6) - { - SoundIoErrorNone = 0, - SoundIoErrorNoMem = 1, - SoundIoErrorInitAudioBackend = 2, - SoundIoErrorSystemResources = 3, - SoundIoErrorOpeningDevice = 4, - SoundIoErrorNoSuchDevice = 5, - SoundIoErrorInvalid = 6, - SoundIoErrorBackendUnavailable = 7, - SoundIoErrorStreaming = 8, - SoundIoErrorIncompatibleDevice = 9, - SoundIoErrorNoSuchClient = 10, - SoundIoErrorIncompatibleBackend = 11, - SoundIoErrorBackendDisconnected = 12, - SoundIoErrorInterrupted = 13, - SoundIoErrorUnderflow = 14, - SoundIoErrorEncodingString = 15, - } - - enum SoundIoChannelId // soundio.h (106, 6) - { - SoundIoChannelIdInvalid = 0, - SoundIoChannelIdFrontLeft = 1, - SoundIoChannelIdFrontRight = 2, - SoundIoChannelIdFrontCenter = 3, - SoundIoChannelIdLfe = 4, - SoundIoChannelIdBackLeft = 5, - SoundIoChannelIdBackRight = 6, - SoundIoChannelIdFrontLeftCenter = 7, - SoundIoChannelIdFrontRightCenter = 8, - SoundIoChannelIdBackCenter = 9, - SoundIoChannelIdSideLeft = 10, - SoundIoChannelIdSideRight = 11, - SoundIoChannelIdTopCenter = 12, - SoundIoChannelIdTopFrontLeft = 13, - SoundIoChannelIdTopFrontCenter = 14, - SoundIoChannelIdTopFrontRight = 15, - SoundIoChannelIdTopBackLeft = 16, - SoundIoChannelIdTopBackCenter = 17, - SoundIoChannelIdTopBackRight = 18, - SoundIoChannelIdBackLeftCenter = 19, - SoundIoChannelIdBackRightCenter = 20, - SoundIoChannelIdFrontLeftWide = 21, - SoundIoChannelIdFrontRightWide = 22, - SoundIoChannelIdFrontLeftHigh = 23, - SoundIoChannelIdFrontCenterHigh = 24, - SoundIoChannelIdFrontRightHigh = 25, - SoundIoChannelIdTopFrontLeftCenter = 26, - SoundIoChannelIdTopFrontRightCenter = 27, - SoundIoChannelIdTopSideLeft = 28, - SoundIoChannelIdTopSideRight = 29, - SoundIoChannelIdLeftLfe = 30, - SoundIoChannelIdRightLfe = 31, - SoundIoChannelIdLfe2 = 32, - SoundIoChannelIdBottomCenter = 33, - SoundIoChannelIdBottomLeftCenter = 34, - SoundIoChannelIdBottomRightCenter = 35, - SoundIoChannelIdMsMid = 36, - SoundIoChannelIdMsSide = 37, - SoundIoChannelIdAmbisonicW = 38, - SoundIoChannelIdAmbisonicX = 39, - SoundIoChannelIdAmbisonicY = 40, - SoundIoChannelIdAmbisonicZ = 41, - SoundIoChannelIdXyX = 42, - SoundIoChannelIdXyY = 43, - SoundIoChannelIdHeadphonesLeft = 44, - SoundIoChannelIdHeadphonesRight = 45, - SoundIoChannelIdClickTrack = 46, - SoundIoChannelIdForeignLanguage = 47, - SoundIoChannelIdHearingImpaired = 48, - SoundIoChannelIdNarration = 49, - SoundIoChannelIdHaptic = 50, - SoundIoChannelIdDialogCentricMix = 51, - SoundIoChannelIdAux = 52, - SoundIoChannelIdAux0 = 53, - SoundIoChannelIdAux1 = 54, - SoundIoChannelIdAux2 = 55, - SoundIoChannelIdAux3 = 56, - SoundIoChannelIdAux4 = 57, - SoundIoChannelIdAux5 = 58, - SoundIoChannelIdAux6 = 59, - SoundIoChannelIdAux7 = 60, - SoundIoChannelIdAux8 = 61, - SoundIoChannelIdAux9 = 62, - SoundIoChannelIdAux10 = 63, - SoundIoChannelIdAux11 = 64, - SoundIoChannelIdAux12 = 65, - SoundIoChannelIdAux13 = 66, - SoundIoChannelIdAux14 = 67, - SoundIoChannelIdAux15 = 68, - } - - enum SoundIoChannelLayoutId // soundio.h (189, 6) - { - SoundIoChannelLayoutIdMono = 0, - SoundIoChannelLayoutIdStereo = 1, - SoundIoChannelLayoutId2Point1 = 2, - SoundIoChannelLayoutId3Point0 = 3, - SoundIoChannelLayoutId3Point0Back = 4, - SoundIoChannelLayoutId3Point1 = 5, - SoundIoChannelLayoutId4Point0 = 6, - SoundIoChannelLayoutIdQuad = 7, - SoundIoChannelLayoutIdQuadSide = 8, - SoundIoChannelLayoutId4Point1 = 9, - SoundIoChannelLayoutId5Point0Back = 10, - SoundIoChannelLayoutId5Point0Side = 11, - SoundIoChannelLayoutId5Point1 = 12, - SoundIoChannelLayoutId5Point1Back = 13, - SoundIoChannelLayoutId6Point0Side = 14, - SoundIoChannelLayoutId6Point0Front = 15, - SoundIoChannelLayoutIdHexagonal = 16, - SoundIoChannelLayoutId6Point1 = 17, - SoundIoChannelLayoutId6Point1Back = 18, - SoundIoChannelLayoutId6Point1Front = 19, - SoundIoChannelLayoutId7Point0 = 20, - SoundIoChannelLayoutId7Point0Front = 21, - SoundIoChannelLayoutId7Point1 = 22, - SoundIoChannelLayoutId7Point1Wide = 23, - SoundIoChannelLayoutId7Point1WideBack = 24, - SoundIoChannelLayoutIdOctagonal = 25, - } - - enum SoundIoBackend // soundio.h (218, 6) - { - SoundIoBackendNone = 0, - SoundIoBackendJack = 1, - SoundIoBackendPulseAudio = 2, - SoundIoBackendAlsa = 3, - SoundIoBackendCoreAudio = 4, - SoundIoBackendWasapi = 5, - SoundIoBackendDummy = 6, - } - - enum SoundIoDeviceAim // soundio.h (228, 6) - { - SoundIoDeviceAimInput = 0, - SoundIoDeviceAimOutput = 1, - } - - enum SoundIoFormat // soundio.h (235, 6) - { - SoundIoFormatInvalid = 0, - SoundIoFormatS8 = 1, - SoundIoFormatU8 = 2, - SoundIoFormatS16LE = 3, - SoundIoFormatS16BE = 4, - SoundIoFormatU16LE = 5, - SoundIoFormatU16BE = 6, - SoundIoFormatS24LE = 7, - SoundIoFormatS24BE = 8, - SoundIoFormatU24LE = 9, - SoundIoFormatU24BE = 10, - SoundIoFormatS32LE = 11, - SoundIoFormatS32BE = 12, - SoundIoFormatU32LE = 13, - SoundIoFormatU32BE = 14, - SoundIoFormatFloat32LE = 15, - SoundIoFormatFloat32BE = 16, - SoundIoFormatFloat64LE = 17, - SoundIoFormatFloat64BE = 18, - } - - [StructLayout(LayoutKind.Sequential)] - struct SoundIoChannelLayout // soundio.h (306, 8) - { - [CTypeDetails("Pointer")] public System.IntPtr @name; - public int @channel_count; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 24)] - [CTypeDetails("ConstArrayOf")] public SoundIoChannelId[] @channels; - } - - [StructLayout(LayoutKind.Sequential)] - struct SoundIoSampleRateRange // soundio.h (313, 8) - { - public int @min; - public int @max; - } - - [StructLayout(LayoutKind.Sequential)] - struct SoundIoChannelArea // soundio.h (319, 8) - { - [CTypeDetails("Pointer")] public System.IntPtr @ptr; - public int @step; - } - - [StructLayout(LayoutKind.Sequential)] - struct SoundIo // soundio.h (328, 8) - { - [CTypeDetails("Pointer")] public System.IntPtr @userdata; - [CTypeDetails("Pointer")] public delegate0 @on_devices_change; - [CTypeDetails("Pointer")] public delegate1 @on_backend_disconnect; - [CTypeDetails("Pointer")] public Delegates.delegate0 @on_events_signal; - public SoundIoBackend @current_backend; - [CTypeDetails("Pointer")] public System.IntPtr @app_name; - [CTypeDetails("Pointer")] public delegate2 @emit_rtprio_warning; - [CTypeDetails("Pointer")] public delegate3 @jack_info_callback; - [CTypeDetails("Pointer")] public Delegates.delegate3 @jack_error_callback; - } - - [StructLayout(LayoutKind.Sequential)] - struct SoundIoDevice // soundio.h (387, 8) - { - [CTypeDetails("Pointer")] public System.IntPtr @soundio; - [CTypeDetails("Pointer")] public System.IntPtr @id; - [CTypeDetails("Pointer")] public System.IntPtr @name; - public SoundIoDeviceAim @aim; - [CTypeDetails("Pointer")] public System.IntPtr @layouts; - public int @layout_count; - public SoundIoChannelLayout @current_layout; - [CTypeDetails("Pointer")] public System.IntPtr @formats; - public int @format_count; - public SoundIoFormat @current_format; - [CTypeDetails("Pointer")] public System.IntPtr @sample_rates; - public int @sample_rate_count; - public int @sample_rate_current; - public double @software_latency_min; - public double @software_latency_max; - public double @software_latency_current; - public bool @is_raw; - public int @ref_count; - public int @probe_error; - } - - [StructLayout(LayoutKind.Sequential)] - struct SoundIoOutStream // soundio.h (497, 8) - { - [CTypeDetails("Pointer")] public System.IntPtr @device; - public SoundIoFormat @format; - public int @sample_rate; - public SoundIoChannelLayout @layout; - public double @software_latency; - public float @volume; - [CTypeDetails("Pointer")] public System.IntPtr @userdata; - [CTypeDetails("Pointer")] public delegate4 @write_callback; - [CTypeDetails("Pointer")] public delegate5 @underflow_callback; - [CTypeDetails("Pointer")] public delegate6 @error_callback; - [CTypeDetails("Pointer")] public System.IntPtr @name; - public bool @non_terminal_hint; - public int @bytes_per_frame; - public int @bytes_per_sample; - public int @layout_error; - } - - [StructLayout(LayoutKind.Sequential)] - struct SoundIoInStream // soundio.h (600, 8) - { - [CTypeDetails("Pointer")] public System.IntPtr @device; - public SoundIoFormat @format; - public int @sample_rate; - public SoundIoChannelLayout @layout; - public double @software_latency; - [CTypeDetails("Pointer")] public System.IntPtr @userdata; - [CTypeDetails("Pointer")] public delegate7 @read_callback; - [CTypeDetails("Pointer")] public delegate8 @overflow_callback; - [CTypeDetails("Pointer")] public delegate9 @error_callback; - [CTypeDetails("Pointer")] public System.IntPtr @name; - public bool @non_terminal_hint; - public int @bytes_per_frame; - public int @bytes_per_sample; - public int @layout_error; - } - - [StructLayout(LayoutKind.Sequential)] - struct SoundIoRingBuffer // soundio.h (1170, 8) - { - } - - partial class Natives - { - const string LibraryName = "libsoundio"; - // function soundio_version_string - soundio.h (682, 28) - [DllImport(LibraryName)] - internal static extern System.IntPtr soundio_version_string(); - - // function soundio_version_major - soundio.h (684, 20) - [DllImport(LibraryName)] - internal static extern int soundio_version_major(); - - // function soundio_version_minor - soundio.h (686, 20) - [DllImport(LibraryName)] - internal static extern int soundio_version_minor(); - - // function soundio_version_patch - soundio.h (688, 20) - [DllImport(LibraryName)] - internal static extern int soundio_version_patch(); - - // function soundio_create - soundio.h (694, 32) - [DllImport(LibraryName)] - internal static extern System.IntPtr soundio_create(); - - // function soundio_destroy - soundio.h (695, 21) - [DllImport(LibraryName)] - internal static extern void soundio_destroy([CTypeDetails("Pointer")]System.IntPtr @soundio); - - // function soundio_connect - soundio.h (705, 20) - [DllImport(LibraryName)] - internal static extern int soundio_connect([CTypeDetails("Pointer")]System.IntPtr @soundio); - - // function soundio_connect_backend - soundio.h (717, 20) - [DllImport(LibraryName)] - internal static extern int soundio_connect_backend([CTypeDetails("Pointer")]System.IntPtr @soundio, SoundIoBackend @backend); - - // function soundio_disconnect - soundio.h (718, 21) - [DllImport(LibraryName)] - internal static extern void soundio_disconnect([CTypeDetails("Pointer")]System.IntPtr @soundio); - - // function soundio_strerror - soundio.h (721, 28) - [DllImport(LibraryName)] - internal static extern System.IntPtr soundio_strerror(int @error); - - // function soundio_backend_name - soundio.h (723, 28) - [DllImport(LibraryName)] - internal static extern System.IntPtr soundio_backend_name(SoundIoBackend @backend); - - // function soundio_backend_count - soundio.h (726, 20) - [DllImport(LibraryName)] - internal static extern int soundio_backend_count([CTypeDetails("Pointer")]System.IntPtr @soundio); - - // function soundio_get_backend - soundio.h (729, 36) - [DllImport(LibraryName)] - internal static extern SoundIoBackend soundio_get_backend([CTypeDetails("Pointer")]System.IntPtr @soundio, int @index); - - // function soundio_have_backend - soundio.h (732, 21) - [DllImport(LibraryName)] - internal static extern bool soundio_have_backend(SoundIoBackend @backend); - - // function soundio_flush_events - soundio.h (756, 21) - [DllImport(LibraryName)] - internal static extern void soundio_flush_events([CTypeDetails("Pointer")]System.IntPtr @soundio); - - // function soundio_wait_events - soundio.h (760, 21) - [DllImport(LibraryName)] - internal static extern void soundio_wait_events([CTypeDetails("Pointer")]System.IntPtr @soundio); - - // function soundio_wakeup - soundio.h (763, 21) - [DllImport(LibraryName)] - internal static extern void soundio_wakeup([CTypeDetails("Pointer")]System.IntPtr @soundio); - - // function soundio_force_device_scan - soundio.h (780, 21) - [DllImport(LibraryName)] - internal static extern void soundio_force_device_scan([CTypeDetails("Pointer")]System.IntPtr @soundio); - - // function soundio_channel_layout_equal - soundio.h (787, 21) - [DllImport(LibraryName)] - internal static extern bool soundio_channel_layout_equal([CTypeDetails("Pointer")]System.IntPtr @a, [CTypeDetails("Pointer")]System.IntPtr @b); - - // function soundio_get_channel_name - soundio.h (791, 28) - [DllImport(LibraryName)] - internal static extern System.IntPtr soundio_get_channel_name(SoundIoChannelId @id); - - // function soundio_parse_channel_id - soundio.h (795, 38) - [DllImport(LibraryName)] - internal static extern SoundIoChannelId soundio_parse_channel_id([CTypeDetails("Pointer")]System.IntPtr @str, int @str_len); - - // function soundio_channel_layout_builtin_count - soundio.h (798, 20) - [DllImport(LibraryName)] - internal static extern int soundio_channel_layout_builtin_count(); - - // function soundio_channel_layout_get_builtin - soundio.h (803, 51) - [DllImport(LibraryName)] - internal static extern System.IntPtr soundio_channel_layout_get_builtin(int @index); - - // function soundio_channel_layout_get_default - soundio.h (806, 51) - [DllImport(LibraryName)] - internal static extern System.IntPtr soundio_channel_layout_get_default(int @channel_count); - - // function soundio_channel_layout_find_channel - soundio.h (809, 20) - [DllImport(LibraryName)] - internal static extern int soundio_channel_layout_find_channel([CTypeDetails("Pointer")]System.IntPtr @layout, SoundIoChannelId @channel); - - // function soundio_channel_layout_detect_builtin - soundio.h (814, 21) - [DllImport(LibraryName)] - internal static extern bool soundio_channel_layout_detect_builtin([CTypeDetails("Pointer")]System.IntPtr @layout); - - // function soundio_best_matching_channel_layout - soundio.h (819, 51) - [DllImport(LibraryName)] - internal static extern System.IntPtr soundio_best_matching_channel_layout([CTypeDetails("Pointer")]System.IntPtr @preferred_layouts, int @preferred_layout_count, [CTypeDetails("Pointer")]System.IntPtr @available_layouts, int @available_layout_count); - - // function soundio_sort_channel_layouts - soundio.h (824, 21) - [DllImport(LibraryName)] - internal static extern void soundio_sort_channel_layouts([CTypeDetails("Pointer")]System.IntPtr @layouts, int @layout_count); - - // function soundio_get_bytes_per_sample - soundio.h (830, 20) - [DllImport(LibraryName)] - internal static extern int soundio_get_bytes_per_sample(SoundIoFormat @format); - - // function soundio_get_bytes_per_frame - soundio.h (833, 19) - [DllImport(LibraryName)] - internal static extern int soundio_get_bytes_per_frame(SoundIoFormat @format, int @channel_count); - - // function soundio_get_bytes_per_second - soundio.h (838, 19) - [DllImport(LibraryName)] - internal static extern int soundio_get_bytes_per_second(SoundIoFormat @format, int @channel_count, int @sample_rate); - - // function soundio_format_string - soundio.h (845, 29) - [DllImport(LibraryName)] - internal static extern System.IntPtr soundio_format_string(SoundIoFormat @format); - - // function soundio_input_device_count - soundio.h (861, 20) - [DllImport(LibraryName)] - internal static extern int soundio_input_device_count([CTypeDetails("Pointer")]System.IntPtr @soundio); - - // function soundio_output_device_count - soundio.h (864, 20) - [DllImport(LibraryName)] - internal static extern int soundio_output_device_count([CTypeDetails("Pointer")]System.IntPtr @soundio); - - // function soundio_get_input_device - soundio.h (870, 38) - [DllImport(LibraryName)] - internal static extern System.IntPtr soundio_get_input_device([CTypeDetails("Pointer")]System.IntPtr @soundio, int @index); - - // function soundio_get_output_device - soundio.h (875, 38) - [DllImport(LibraryName)] - internal static extern System.IntPtr soundio_get_output_device([CTypeDetails("Pointer")]System.IntPtr @soundio, int @index); - - // function soundio_default_input_device_index - soundio.h (880, 20) - [DllImport(LibraryName)] - internal static extern int soundio_default_input_device_index([CTypeDetails("Pointer")]System.IntPtr @soundio); - - // function soundio_default_output_device_index - soundio.h (885, 20) - [DllImport(LibraryName)] - internal static extern int soundio_default_output_device_index([CTypeDetails("Pointer")]System.IntPtr @soundio); - - // function soundio_device_ref - soundio.h (888, 21) - [DllImport(LibraryName)] - internal static extern void soundio_device_ref([CTypeDetails("Pointer")]System.IntPtr @device); - - // function soundio_device_unref - soundio.h (891, 21) - [DllImport(LibraryName)] - internal static extern void soundio_device_unref([CTypeDetails("Pointer")]System.IntPtr @device); - - // function soundio_device_equal - soundio.h (895, 21) - [DllImport(LibraryName)] - internal static extern bool soundio_device_equal([CTypeDetails("Pointer")]System.IntPtr @a, [CTypeDetails("Pointer")]System.IntPtr @b); - - // function soundio_device_sort_channel_layouts - soundio.h (900, 21) - [DllImport(LibraryName)] - internal static extern void soundio_device_sort_channel_layouts([CTypeDetails("Pointer")]System.IntPtr @device); - - // function soundio_device_supports_format - soundio.h (904, 21) - [DllImport(LibraryName)] - internal static extern bool soundio_device_supports_format([CTypeDetails("Pointer")]System.IntPtr @device, SoundIoFormat @format); - - // function soundio_device_supports_layout - soundio.h (909, 21) - [DllImport(LibraryName)] - internal static extern bool soundio_device_supports_layout([CTypeDetails("Pointer")]System.IntPtr @device, [CTypeDetails("Pointer")]System.IntPtr @layout); - - // function soundio_device_supports_sample_rate - soundio.h (914, 21) - [DllImport(LibraryName)] - internal static extern bool soundio_device_supports_sample_rate([CTypeDetails("Pointer")]System.IntPtr @device, int @sample_rate); - - // function soundio_device_nearest_sample_rate - soundio.h (919, 20) - [DllImport(LibraryName)] - internal static extern int soundio_device_nearest_sample_rate([CTypeDetails("Pointer")]System.IntPtr @device, int @sample_rate); - - // function soundio_outstream_create - soundio.h (929, 41) - [DllImport(LibraryName)] - internal static extern System.IntPtr soundio_outstream_create([CTypeDetails("Pointer")]System.IntPtr @device); - - // function soundio_outstream_destroy - soundio.h (931, 21) - [DllImport(LibraryName)] - internal static extern void soundio_outstream_destroy([CTypeDetails("Pointer")]System.IntPtr @outstream); - - // function soundio_outstream_open - soundio.h (954, 20) - [DllImport(LibraryName)] - internal static extern int soundio_outstream_open([CTypeDetails("Pointer")]System.IntPtr @outstream); - - // function soundio_outstream_start - soundio.h (965, 20) - [DllImport(LibraryName)] - internal static extern int soundio_outstream_start([CTypeDetails("Pointer")]System.IntPtr @outstream); - - // function soundio_outstream_begin_write - soundio.h (997, 20) - [DllImport(LibraryName)] - internal static extern int soundio_outstream_begin_write([CTypeDetails("Pointer")]System.IntPtr @outstream, [CTypeDetails("Pointer")]System.IntPtr @areas, [CTypeDetails("Pointer")]System.IntPtr @frame_count); - - // function soundio_outstream_end_write - soundio.h (1009, 20) - [DllImport(LibraryName)] - internal static extern int soundio_outstream_end_write([CTypeDetails("Pointer")]System.IntPtr @outstream); - - // function soundio_outstream_clear_buffer - soundio.h (1024, 20) - [DllImport(LibraryName)] - internal static extern int soundio_outstream_clear_buffer([CTypeDetails("Pointer")]System.IntPtr @outstream); - - // function soundio_outstream_pause - soundio.h (1045, 20) - [DllImport(LibraryName)] - internal static extern int soundio_outstream_pause([CTypeDetails("Pointer")]System.IntPtr @outstream, bool @pause); - - // function soundio_outstream_get_latency - soundio.h (1058, 20) - [DllImport(LibraryName)] - internal static extern int soundio_outstream_get_latency([CTypeDetails("Pointer")]System.IntPtr @outstream, [CTypeDetails("Pointer")]System.IntPtr @out_latency); - - // function soundio_outstream_set_volume - soundio.h (1061, 20) - [DllImport(LibraryName)] - internal static extern int soundio_outstream_set_volume([CTypeDetails("Pointer")]System.IntPtr @outstream, double @volume); - - // function soundio_instream_create - soundio.h (1071, 40) - [DllImport(LibraryName)] - internal static extern System.IntPtr soundio_instream_create([CTypeDetails("Pointer")]System.IntPtr @device); - - // function soundio_instream_destroy - soundio.h (1073, 21) - [DllImport(LibraryName)] - internal static extern void soundio_instream_destroy([CTypeDetails("Pointer")]System.IntPtr @instream); - - // function soundio_instream_open - soundio.h (1093, 20) - [DllImport(LibraryName)] - internal static extern int soundio_instream_open([CTypeDetails("Pointer")]System.IntPtr @instream); - - // function soundio_instream_start - soundio.h (1102, 20) - [DllImport(LibraryName)] - internal static extern int soundio_instream_start([CTypeDetails("Pointer")]System.IntPtr @instream); - - // function soundio_instream_begin_read - soundio.h (1133, 20) - [DllImport(LibraryName)] - internal static extern int soundio_instream_begin_read([CTypeDetails("Pointer")]System.IntPtr @instream, [CTypeDetails("Pointer")]System.IntPtr @areas, [CTypeDetails("Pointer")]System.IntPtr @frame_count); - - // function soundio_instream_end_read - soundio.h (1143, 20) - [DllImport(LibraryName)] - internal static extern int soundio_instream_end_read([CTypeDetails("Pointer")]System.IntPtr @instream); - - // function soundio_instream_pause - soundio.h (1156, 20) - [DllImport(LibraryName)] - internal static extern int soundio_instream_pause([CTypeDetails("Pointer")]System.IntPtr @instream, bool @pause); - - // function soundio_instream_get_latency - soundio.h (1166, 20) - [DllImport(LibraryName)] - internal static extern int soundio_instream_get_latency([CTypeDetails("Pointer")]System.IntPtr @instream, [CTypeDetails("Pointer")]System.IntPtr @out_latency); - - // function soundio_ring_buffer_create - soundio.h (1181, 42) - [DllImport(LibraryName)] - internal static extern System.IntPtr soundio_ring_buffer_create([CTypeDetails("Pointer")]System.IntPtr @soundio, int @requested_capacity); - - // function soundio_ring_buffer_destroy - soundio.h (1182, 21) - [DllImport(LibraryName)] - internal static extern void soundio_ring_buffer_destroy([CTypeDetails("Pointer")]System.IntPtr @ring_buffer); - - // function soundio_ring_buffer_capacity - soundio.h (1186, 20) - [DllImport(LibraryName)] - internal static extern int soundio_ring_buffer_capacity([CTypeDetails("Pointer")]System.IntPtr @ring_buffer); - - // function soundio_ring_buffer_write_ptr - soundio.h (1189, 22) - [DllImport(LibraryName)] - internal static extern System.IntPtr soundio_ring_buffer_write_ptr([CTypeDetails("Pointer")]System.IntPtr @ring_buffer); - - // function soundio_ring_buffer_advance_write_ptr - soundio.h (1191, 21) - [DllImport(LibraryName)] - internal static extern void soundio_ring_buffer_advance_write_ptr([CTypeDetails("Pointer")]System.IntPtr @ring_buffer, int @count); - - // function soundio_ring_buffer_read_ptr - soundio.h (1194, 22) - [DllImport(LibraryName)] - internal static extern System.IntPtr soundio_ring_buffer_read_ptr([CTypeDetails("Pointer")]System.IntPtr @ring_buffer); - - // function soundio_ring_buffer_advance_read_ptr - soundio.h (1196, 21) - [DllImport(LibraryName)] - internal static extern void soundio_ring_buffer_advance_read_ptr([CTypeDetails("Pointer")]System.IntPtr @ring_buffer, int @count); - - // function soundio_ring_buffer_fill_count - soundio.h (1199, 20) - [DllImport(LibraryName)] - internal static extern int soundio_ring_buffer_fill_count([CTypeDetails("Pointer")]System.IntPtr @ring_buffer); - - // function soundio_ring_buffer_free_count - soundio.h (1202, 20) - [DllImport(LibraryName)] - internal static extern int soundio_ring_buffer_free_count([CTypeDetails("Pointer")]System.IntPtr @ring_buffer); - - // function soundio_ring_buffer_clear - soundio.h (1205, 21) - [DllImport(LibraryName)] - internal static extern void soundio_ring_buffer_clear([CTypeDetails("Pointer")]System.IntPtr @ring_buffer); - - } - - class Delegates - { - public delegate void delegate0(System.IntPtr p0); - public delegate void delegate1(System.IntPtr p0, int p1); - public delegate void delegate2(); - public delegate void delegate3(System.IntPtr p0); - public delegate void delegate4(System.IntPtr p0, int p1, int p2); - public delegate void delegate5(System.IntPtr p0); - public delegate void delegate6(System.IntPtr p0, int p1); - public delegate void delegate7(System.IntPtr p0, int p1, int p2); - public delegate void delegate8(System.IntPtr p0); - public delegate void delegate9(System.IntPtr p0, int p1); - } - - public struct Pointer - { - public IntPtr Handle; - public static implicit operator IntPtr(Pointer value) { return value.Handle; } - public static implicit operator Pointer(IntPtr value) { return new Pointer(value); } - - public Pointer(IntPtr handle) - { - Handle = handle; - } - - public override bool Equals(object obj) - { - return obj is Pointer && this == (Pointer)obj; - } - - public override int GetHashCode() - { - return (int)Handle; - } - - public static bool operator ==(Pointer p1, Pointer p2) - { - return p1.Handle == p2.Handle; - } - - public static bool operator !=(Pointer p1, Pointer p2) - { - return p1.Handle != p2.Handle; - } - } - public struct ArrayOf { } - public struct ConstArrayOf { } - public class CTypeDetailsAttribute : Attribute - { - public CTypeDetailsAttribute(string value) - { - Value = value; - } - - public string Value { get; set; } - } - -} diff --git a/Ryujinx.Audio.Backends.SoundIo/SoundIoHardwareDeviceDriver.cs b/Ryujinx.Audio.Backends.SoundIo/SoundIoHardwareDeviceDriver.cs deleted file mode 100644 index 02a9a2287..000000000 --- a/Ryujinx.Audio.Backends.SoundIo/SoundIoHardwareDeviceDriver.cs +++ /dev/null @@ -1,255 +0,0 @@ -using Ryujinx.Audio.Common; -using Ryujinx.Audio.Integration; -using Ryujinx.Memory; -using SoundIOSharp; -using System; -using System.Collections.Concurrent; -using System.Threading; - -using static Ryujinx.Audio.Integration.IHardwareDeviceDriver; - -namespace Ryujinx.Audio.Backends.SoundIo -{ - public class SoundIoHardwareDeviceDriver : IHardwareDeviceDriver - { - private readonly SoundIO _audioContext; - private readonly SoundIODevice _audioDevice; - private readonly ManualResetEvent _updateRequiredEvent; - private readonly ManualResetEvent _pauseEvent; - private readonly ConcurrentDictionary _sessions; - private int _disposeState; - - public SoundIoHardwareDeviceDriver() - { - _audioContext = new SoundIO(); - _updateRequiredEvent = new ManualResetEvent(false); - _pauseEvent = new ManualResetEvent(true); - _sessions = new ConcurrentDictionary(); - - _audioContext.Connect(); - _audioContext.FlushEvents(); - - _audioDevice = FindNonRawDefaultAudioDevice(_audioContext, true); - } - - public static bool IsSupported => IsSupportedInternal(); - - private static bool IsSupportedInternal() - { - SoundIO context = null; - SoundIODevice device = null; - SoundIOOutStream stream = null; - - bool backendDisconnected = false; - - try - { - context = new SoundIO(); - - context.OnBackendDisconnect = (i) => - { - backendDisconnected = true; - }; - - context.Connect(); - context.FlushEvents(); - - if (backendDisconnected) - { - return false; - } - - if (context.OutputDeviceCount == 0) - { - return false; - } - - device = FindNonRawDefaultAudioDevice(context); - - if (device == null || backendDisconnected) - { - return false; - } - - stream = device.CreateOutStream(); - - if (stream == null || backendDisconnected) - { - return false; - } - - return true; - } - catch - { - return false; - } - finally - { - if (stream != null) - { - stream.Dispose(); - } - - if (context != null) - { - context.Dispose(); - } - } - } - - private static SoundIODevice FindNonRawDefaultAudioDevice(SoundIO audioContext, bool fallback = false) - { - SoundIODevice defaultAudioDevice = audioContext.GetOutputDevice(audioContext.DefaultOutputDeviceIndex); - - if (!defaultAudioDevice.IsRaw) - { - return defaultAudioDevice; - } - - for (int i = 0; i < audioContext.BackendCount; i++) - { - SoundIODevice audioDevice = audioContext.GetOutputDevice(i); - - if (audioDevice.Id == defaultAudioDevice.Id && !audioDevice.IsRaw) - { - return audioDevice; - } - } - - return fallback ? defaultAudioDevice : null; - } - - public ManualResetEvent GetUpdateRequiredEvent() - { - return _updateRequiredEvent; - } - - public ManualResetEvent GetPauseEvent() - { - return _pauseEvent; - } - - public IHardwareDeviceSession OpenDeviceSession(Direction direction, IVirtualMemoryManager memoryManager, SampleFormat sampleFormat, uint sampleRate, uint channelCount, float volume) - { - if (channelCount == 0) - { - channelCount = 2; - } - - if (sampleRate == 0) - { - sampleRate = Constants.TargetSampleRate; - } - - volume = Math.Clamp(volume, 0, 1); - - if (direction != Direction.Output) - { - throw new NotImplementedException("Input direction is currently not implemented on SoundIO backend!"); - } - - SoundIoHardwareDeviceSession session = new SoundIoHardwareDeviceSession(this, memoryManager, sampleFormat, sampleRate, channelCount, volume); - - _sessions.TryAdd(session, 0); - - return session; - } - - internal bool Unregister(SoundIoHardwareDeviceSession session) - { - return _sessions.TryRemove(session, out _); - } - - public static SoundIOFormat GetSoundIoFormat(SampleFormat format) - { - return format switch - { - SampleFormat.PcmInt8 => SoundIOFormat.S8, - SampleFormat.PcmInt16 => SoundIOFormat.S16LE, - SampleFormat.PcmInt24 => SoundIOFormat.S24LE, - SampleFormat.PcmInt32 => SoundIOFormat.S32LE, - SampleFormat.PcmFloat => SoundIOFormat.Float32LE, - _ => throw new ArgumentException ($"Unsupported sample format {format}"), - }; - } - - internal SoundIOOutStream OpenStream(SampleFormat requestedSampleFormat, uint requestedSampleRate, uint requestedChannelCount) - { - SoundIOFormat driverSampleFormat = GetSoundIoFormat(requestedSampleFormat); - - if (!_audioDevice.SupportsSampleRate((int)requestedSampleRate)) - { - throw new ArgumentException($"This sound device does not support a sample rate of {requestedSampleRate}Hz"); - } - - if (!_audioDevice.SupportsFormat(driverSampleFormat)) - { - throw new ArgumentException($"This sound device does not support {requestedSampleFormat}"); - } - - if (!_audioDevice.SupportsChannelCount((int)requestedChannelCount)) - { - throw new ArgumentException($"This sound device does not support channel count {requestedChannelCount}"); - } - - SoundIOOutStream result = _audioDevice.CreateOutStream(); - - result.Name = "Ryujinx"; - result.Layout = SoundIOChannelLayout.GetDefault((int)requestedChannelCount); - result.Format = driverSampleFormat; - result.SampleRate = (int)requestedSampleRate; - - return result; - } - - internal void FlushContextEvents() - { - _audioContext.FlushEvents(); - } - - public void Dispose() - { - if (Interlocked.CompareExchange(ref _disposeState, 1, 0) == 0) - { - Dispose(true); - } - } - - protected virtual void Dispose(bool disposing) - { - if (disposing) - { - foreach (SoundIoHardwareDeviceSession session in _sessions.Keys) - { - session.Dispose(); - } - - _audioContext.Disconnect(); - _audioContext.Dispose(); - _pauseEvent.Dispose(); - } - } - - public bool SupportsSampleRate(uint sampleRate) - { - return _audioDevice.SupportsSampleRate((int)sampleRate); - } - - public bool SupportsSampleFormat(SampleFormat sampleFormat) - { - return _audioDevice.SupportsFormat(GetSoundIoFormat(sampleFormat)); - } - - public bool SupportsChannelCount(uint channelCount) - { - return _audioDevice.SupportsChannelCount((int)channelCount); - } - - public bool SupportsDirection(Direction direction) - { - // TODO: add direction input when supported. - return direction == Direction.Output; - } - } -} diff --git a/Ryujinx.Audio/Backends/CompatLayer/CompatLayerHardwareDeviceDriver.cs b/Ryujinx.Audio/Backends/CompatLayer/CompatLayerHardwareDeviceDriver.cs deleted file mode 100644 index b6f45a3e5..000000000 --- a/Ryujinx.Audio/Backends/CompatLayer/CompatLayerHardwareDeviceDriver.cs +++ /dev/null @@ -1,136 +0,0 @@ -using Ryujinx.Audio.Backends.Common; -using Ryujinx.Audio.Backends.Dummy; -using Ryujinx.Audio.Common; -using Ryujinx.Audio.Integration; -using Ryujinx.Common.Logging; -using Ryujinx.Memory; -using System; -using System.Threading; - -using static Ryujinx.Audio.Integration.IHardwareDeviceDriver; - -namespace Ryujinx.Audio.Backends.CompatLayer -{ - public class CompatLayerHardwareDeviceDriver : IHardwareDeviceDriver - { - private IHardwareDeviceDriver _realDriver; - - public CompatLayerHardwareDeviceDriver(IHardwareDeviceDriver realDevice) - { - _realDriver = realDevice; - } - - public void Dispose() - { - _realDriver.Dispose(); - } - - public ManualResetEvent GetUpdateRequiredEvent() - { - return _realDriver.GetUpdateRequiredEvent(); - } - - public ManualResetEvent GetPauseEvent() - { - return _realDriver.GetPauseEvent(); - } - - private uint SelectHardwareChannelCount(uint targetChannelCount) - { - if (_realDriver.SupportsChannelCount(targetChannelCount)) - { - return targetChannelCount; - } - - return targetChannelCount switch - { - 6 => SelectHardwareChannelCount(2), - 2 => SelectHardwareChannelCount(1), - 1 => throw new ArgumentException("No valid channel configuration found!"), - _ => throw new ArgumentException($"Invalid targetChannelCount {targetChannelCount}") - }; - } - - public IHardwareDeviceSession OpenDeviceSession(Direction direction, IVirtualMemoryManager memoryManager, SampleFormat sampleFormat, uint sampleRate, uint channelCount, float volume) - { - if (channelCount == 0) - { - channelCount = 2; - } - - if (sampleRate == 0) - { - sampleRate = Constants.TargetSampleRate; - } - - volume = Math.Clamp(volume, 0, 1); - - if (!_realDriver.SupportsDirection(direction)) - { - if (direction == Direction.Input) - { - Logger.Warning?.Print(LogClass.Audio, "The selected audio backend doesn't support audio input, fallback to dummy..."); - - return new DummyHardwareDeviceSessionInput(this, memoryManager, sampleFormat, sampleRate, channelCount); - } - - throw new NotImplementedException(); - } - - uint hardwareChannelCount = SelectHardwareChannelCount(channelCount); - - IHardwareDeviceSession realSession = _realDriver.OpenDeviceSession(direction, memoryManager, sampleFormat, sampleRate, hardwareChannelCount, volume); - - if (hardwareChannelCount == channelCount) - { - return realSession; - } - - if (direction == Direction.Input) - { - Logger.Warning?.Print(LogClass.Audio, $"The selected audio backend doesn't support the requested audio input configuration, fallback to dummy..."); - - // TODO: We currently don't support audio input upsampling/downsampling, implement this. - realSession.Dispose(); - - return new DummyHardwareDeviceSessionInput(this, memoryManager, sampleFormat, sampleRate, channelCount); - } - - // It must be a HardwareDeviceSessionOutputBase. - if (realSession is not HardwareDeviceSessionOutputBase realSessionOutputBase) - { - throw new InvalidOperationException($"Real driver session class type isn't based on {typeof(HardwareDeviceSessionOutputBase).Name}."); - } - - // If we need to do post processing before sending to the hardware device, wrap around it. - return new CompatLayerHardwareDeviceSession(realSessionOutputBase, channelCount); - } - - public bool SupportsChannelCount(uint channelCount) - { - return channelCount == 1 || channelCount == 2 || channelCount == 6; - } - - public bool SupportsSampleFormat(SampleFormat sampleFormat) - { - // TODO: More formats. - return sampleFormat == SampleFormat.PcmInt16; - } - - public bool SupportsSampleRate(uint sampleRate) - { - // TODO: More sample rates. - return sampleRate == Constants.TargetSampleRate; - } - - public IHardwareDeviceDriver GetRealDeviceDriver() - { - return _realDriver; - } - - public bool SupportsDirection(Direction direction) - { - return direction == Direction.Input || direction == Direction.Output; - } - } -} \ No newline at end of file diff --git a/Ryujinx.Audio/Backends/CompatLayer/CompatLayerHardwareDeviceSession.cs b/Ryujinx.Audio/Backends/CompatLayer/CompatLayerHardwareDeviceSession.cs deleted file mode 100644 index ff3b0988c..000000000 --- a/Ryujinx.Audio/Backends/CompatLayer/CompatLayerHardwareDeviceSession.cs +++ /dev/null @@ -1,123 +0,0 @@ -using Ryujinx.Audio.Backends.Common; -using Ryujinx.Audio.Common; -using System; -using System.Runtime.InteropServices; - -namespace Ryujinx.Audio.Backends.CompatLayer -{ - class CompatLayerHardwareDeviceSession : HardwareDeviceSessionOutputBase - { - private HardwareDeviceSessionOutputBase _realSession; - private uint _userChannelCount; - - public CompatLayerHardwareDeviceSession(HardwareDeviceSessionOutputBase realSession, uint userChannelCount) : base(realSession.MemoryManager, realSession.RequestedSampleFormat, realSession.RequestedSampleRate, userChannelCount) - { - _realSession = realSession; - _userChannelCount = userChannelCount; - } - - public override void Dispose() - { - _realSession.Dispose(); - } - - public override ulong GetPlayedSampleCount() - { - return _realSession.GetPlayedSampleCount(); - } - - public override float GetVolume() - { - return _realSession.GetVolume(); - } - - public override void PrepareToClose() - { - _realSession.PrepareToClose(); - } - - public override void QueueBuffer(AudioBuffer buffer) - { - _realSession.QueueBuffer(buffer); - } - - public override bool RegisterBuffer(AudioBuffer buffer, byte[] samples) - { - if (RequestedSampleFormat != SampleFormat.PcmInt16) - { - throw new NotImplementedException("Downmixing formats other than PCM16 is not supported."); - } - - if (samples == null) - { - return false; - } - - short[] downmixedBufferPCM16; - - ReadOnlySpan samplesPCM16 = MemoryMarshal.Cast(samples); - - if (_userChannelCount == 6) - { - downmixedBufferPCM16 = Downmixing.DownMixSurroundToStereo(samplesPCM16); - - if (_realSession.RequestedChannelCount == 1) - { - downmixedBufferPCM16 = Downmixing.DownMixStereoToMono(downmixedBufferPCM16); - } - } - else if (_userChannelCount == 2 && _realSession.RequestedChannelCount == 1) - { - downmixedBufferPCM16 = Downmixing.DownMixStereoToMono(samplesPCM16); - } - else - { - throw new NotImplementedException($"Downmixing from {_userChannelCount} to {_realSession.RequestedChannelCount} not implemented."); - } - - byte[] downmixedBuffer = MemoryMarshal.Cast(downmixedBufferPCM16).ToArray(); - - AudioBuffer fakeBuffer = new AudioBuffer - { - BufferTag = buffer.BufferTag, - DataPointer = buffer.DataPointer, - DataSize = (ulong)downmixedBuffer.Length - }; - - bool result = _realSession.RegisterBuffer(fakeBuffer, downmixedBuffer); - - if (result) - { - buffer.Data = fakeBuffer.Data; - buffer.DataSize = fakeBuffer.DataSize; - } - - return result; - } - - public override void SetVolume(float volume) - { - _realSession.SetVolume(volume); - } - - public override void Start() - { - _realSession.Start(); - } - - public override void Stop() - { - _realSession.Stop(); - } - - public override void UnregisterBuffer(AudioBuffer buffer) - { - _realSession.UnregisterBuffer(buffer); - } - - public override bool WasBufferFullyConsumed(AudioBuffer buffer) - { - return _realSession.WasBufferFullyConsumed(buffer); - } - } -} \ No newline at end of file diff --git a/Ryujinx.Audio/Constants.cs b/Ryujinx.Audio/Constants.cs deleted file mode 100644 index 7d2ffa57b..000000000 --- a/Ryujinx.Audio/Constants.cs +++ /dev/null @@ -1,175 +0,0 @@ -namespace Ryujinx.Audio -{ - /// - /// Define constants used by the audio system. - /// - public static class Constants - { - /// - /// The default device output name. - /// - public const string DefaultDeviceOutputName = "DeviceOut"; - - /// - /// The default device input name. - /// - public const string DefaultDeviceInputName = "BuiltInHeadset"; - - /// - /// The maximum number of channels supported. (6 channels for 5.1 surround) - /// - public const int ChannelCountMax = 6; - - /// - /// The maximum number of channels supported per voice. - /// - public const int VoiceChannelCountMax = ChannelCountMax; - - /// - /// The maximum count of mix buffer supported per operations (volumes, mix effect, ...) - /// - public const int MixBufferCountMax = 24; - - /// - /// The maximum count of wavebuffer per voice. - /// - public const int VoiceWaveBufferCount = 4; - - /// - /// The maximum count of biquad filter per voice. - /// - public const int VoiceBiquadFilterCount = 2; - - /// - /// The lowest priority that a voice can have. - /// - public const int VoiceLowestPriority = 0xFF; - - /// - /// The highest priority that a voice can have. - /// - /// Voices with the highest priority will not be dropped if a voice drop needs to occur. - public const int VoiceHighestPriority = 0; - - /// - /// Maximum that can be returned by . - /// - public const int MaxErrorInfos = 10; - - /// - /// Default alignment for buffers. - /// - public const int BufferAlignment = 0x40; - - /// - /// Alignment required for the work buffer. - /// - public const int WorkBufferAlignment = 0x1000; - - /// - /// Alignment required for every performance metrics frame. - /// - public const int PerformanceMetricsPerFramesSizeAlignment = 0x100; - - /// - /// The id of the final mix. - /// - public const int FinalMixId = 0; - - /// - /// The id defining an unused mix id. - /// - public const int UnusedMixId = int.MaxValue; - - /// - /// The id defining an unused splitter id as a signed integer. - /// - public const int UnusedSplitterIdInt = -1; - - /// - /// The id defining an unused splitter id. - /// - public const uint UnusedSplitterId = uint.MaxValue; - - /// - /// The id of invalid/unused node id. - /// - public const int InvalidNodeId = -268435456; - - /// - /// The indice considered invalid for processing order. - /// - public const int InvalidProcessingOrder = -1; - - /// - /// The maximum number of audio renderer sessions allowed to be created system wide. - /// - public const int AudioRendererSessionCountMax = 2; - - /// - /// The maximum number of audio output sessions allowed to be created system wide. - /// - public const int AudioOutSessionCountMax = 12; - - /// - /// The maximum number of audio input sessions allowed to be created system wide. - /// - public const int AudioInSessionCountMax = 4; - - /// - /// Maximum buffers supported by one audio device session. - /// - public const int AudioDeviceBufferCountMax = 32; - - /// - /// The target sample rate of the audio renderer. (48kHz) - /// - public const uint TargetSampleRate = 48000; - - /// - /// The target sample size of the audio renderer. (PCM16) - /// - public const int TargetSampleSize = sizeof(ushort); - - /// - /// The target sample count per audio renderer update. - /// - public const int TargetSampleCount = 240; - - /// - /// The size of an upsampler entry to process upsampling to . - /// - public const int UpSampleEntrySize = TargetSampleCount * VoiceChannelCountMax; - - /// - /// The target audio latency computed from and . - /// - public const int AudioProcessorMaxUpdateTimeTarget = 1000000000 / ((int)TargetSampleRate / TargetSampleCount); // 5.00 ms - - /// - /// The maximum update time of the DSP on original hardware. - /// - public const int AudioProcessorMaxUpdateTime = 5760000; // 5.76 ms - - /// - /// The maximum update time per audio renderer session. - /// - public const int AudioProcessorMaxUpdateTimePerSessions = AudioProcessorMaxUpdateTime / AudioRendererSessionCountMax; - - /// - /// Guest timer frequency used for system ticks. - /// - public const int TargetTimerFrequency = 19200000; - - /// - /// The default coefficients used for standard 5.1 surround to stereo downmixing. - /// - public static float[] DefaultSurroundToStereoCoefficients = new float[4] - { - 1.0f, - 0.707f, - 0.251f, - 0.707f, - }; - } -} \ No newline at end of file diff --git a/Ryujinx.Audio/Renderer/Common/PlayState.cs b/Ryujinx.Audio/Renderer/Common/PlayState.cs deleted file mode 100644 index 4a6929e03..000000000 --- a/Ryujinx.Audio/Renderer/Common/PlayState.cs +++ /dev/null @@ -1,23 +0,0 @@ -namespace Ryujinx.Audio.Renderer.Common -{ - /// - /// Common play state. - /// - public enum PlayState : byte - { - /// - /// The user request the voice to be started. - /// - Start, - - /// - /// The user request the voice to be stopped. - /// - Stop, - - /// - /// The user request the voice to be paused. - /// - Pause - } -} \ No newline at end of file diff --git a/Ryujinx.Audio/Renderer/Common/WaveBuffer.cs b/Ryujinx.Audio/Renderer/Common/WaveBuffer.cs deleted file mode 100644 index 0d00e8384..000000000 --- a/Ryujinx.Audio/Renderer/Common/WaveBuffer.cs +++ /dev/null @@ -1,82 +0,0 @@ -using System.Runtime.InteropServices; - -using DspAddr = System.UInt64; - -namespace Ryujinx.Audio.Renderer.Common -{ - /// - /// A wavebuffer used for data source commands. - /// - [StructLayout(LayoutKind.Sequential, Pack = 1)] - public struct WaveBuffer - { - /// - /// The DSP address of the sample data of the wavebuffer. - /// - public DspAddr Buffer; - - /// - /// The DSP address of the context of the wavebuffer. - /// - /// Only used by . - public DspAddr Context; - - /// - /// The size of the sample buffer data. - /// - public uint BufferSize; - - /// - /// The size of the context buffer. - /// - public uint ContextSize; - - /// - /// First sample to play on the wavebuffer. - /// - public uint StartSampleOffset; - - /// - /// Last sample to play on the wavebuffer. - /// - public uint EndSampleOffset; - - /// - /// First sample to play when looping the wavebuffer. - /// - /// - /// If or is equal to zero,, it will default to and . - /// - public uint LoopStartSampleOffset; - - /// - /// Last sample to play when looping the wavebuffer. - /// - /// - /// If or is equal to zero, it will default to and . - /// - public uint LoopEndSampleOffset; - - /// - /// The max loop count. - /// - public int LoopCount; - - /// - /// Set to true if the wavebuffer is looping. - /// - [MarshalAs(UnmanagedType.I1)] - public bool Looping; - - /// - /// Set to true if the wavebuffer is the end of stream. - /// - [MarshalAs(UnmanagedType.I1)] - public bool IsEndOfStream; - - /// - /// Padding/Reserved. - /// - private ushort _padding; - } -} \ No newline at end of file diff --git a/Ryujinx.Audio/Renderer/Dsp/Command/CommandType.cs b/Ryujinx.Audio/Renderer/Dsp/Command/CommandType.cs deleted file mode 100644 index dfe7f8862..000000000 --- a/Ryujinx.Audio/Renderer/Dsp/Command/CommandType.cs +++ /dev/null @@ -1,36 +0,0 @@ -namespace Ryujinx.Audio.Renderer.Dsp.Command -{ - public enum CommandType : byte - { - Invalid, - PcmInt16DataSourceVersion1, - PcmInt16DataSourceVersion2, - PcmFloatDataSourceVersion1, - PcmFloatDataSourceVersion2, - AdpcmDataSourceVersion1, - AdpcmDataSourceVersion2, - Volume, - VolumeRamp, - BiquadFilter, - Mix, - MixRamp, - MixRampGrouped, - DepopPrepare, - DepopForMixBuffers, - Delay, - Upsample, - DownMixSurroundToStereo, - AuxiliaryBuffer, - DeviceSink, - CircularBufferSink, - Reverb, - Reverb3d, - Performance, - ClearMixBuffer, - CopyMixBuffer, - LimiterVersion1, - LimiterVersion2, - GroupedBiquadFilter, - CaptureBuffer - } -} \ No newline at end of file diff --git a/Ryujinx.Audio/Renderer/Dsp/FloatingPointHelper.cs b/Ryujinx.Audio/Renderer/Dsp/FloatingPointHelper.cs deleted file mode 100644 index 226def46a..000000000 --- a/Ryujinx.Audio/Renderer/Dsp/FloatingPointHelper.cs +++ /dev/null @@ -1,67 +0,0 @@ -using System; -using System.Runtime.CompilerServices; - -namespace Ryujinx.Audio.Renderer.Dsp -{ - public static class FloatingPointHelper - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static float MultiplyRoundDown(float a, float b) - { - return RoundDown(a * b); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static float RoundDown(float a) - { - return MathF.Round(a, 0); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static float RoundUp(float a) - { - return MathF.Round(a); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static float MultiplyRoundUp(float a, float b) - { - return RoundUp(a * b); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static float Pow10(float x) - { - // NOTE: Nintendo implementation uses Q15 and a LUT for this, we don't. - // As such, we support the same ranges as Nintendo to avoid unexpected behaviours. - if (x >= 0.0f) - { - return 1.0f; - } - else if (x <= -5.3f) - { - return 0.0f; - } - - return MathF.Pow(10, x); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static float DegreesToRadians(float degrees) - { - return degrees * MathF.PI / 180.0f; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static float Cos(float value) - { - return MathF.Cos(DegreesToRadians(value)); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static float Sin(float value) - { - return MathF.Sin(DegreesToRadians(value)); - } - } -} \ No newline at end of file diff --git a/Ryujinx.Audio/Renderer/Dsp/PcmHelper.cs b/Ryujinx.Audio/Renderer/Dsp/PcmHelper.cs deleted file mode 100644 index 1eec3e415..000000000 --- a/Ryujinx.Audio/Renderer/Dsp/PcmHelper.cs +++ /dev/null @@ -1,78 +0,0 @@ -using System; -using System.Runtime.CompilerServices; - -namespace Ryujinx.Audio.Renderer.Dsp -{ - public static class PcmHelper - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int GetCountToDecode(int startSampleOffset, int endSampleOffset, int offset, int count) - { - return Math.Min(count, endSampleOffset - startSampleOffset - offset); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ulong GetBufferOffset(int startSampleOffset, int offset, int channelCount) where T : unmanaged - { - return (ulong)(Unsafe.SizeOf() * channelCount * (startSampleOffset + offset)); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int GetBufferSize(int startSampleOffset, int endSampleOffset, int offset, int count) where T : unmanaged - { - return GetCountToDecode(startSampleOffset, endSampleOffset, offset, count) * Unsafe.SizeOf(); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int Decode(Span output, ReadOnlySpan input, int startSampleOffset, int endSampleOffset, int channelIndex, int channelCount) - { - if (input.IsEmpty || endSampleOffset < startSampleOffset) - { - return 0; - } - - int decodedCount = input.Length / channelCount; - - for (int i = 0; i < decodedCount; i++) - { - output[i] = input[i * channelCount + channelIndex]; - } - - return decodedCount; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int Decode(Span output, ReadOnlySpan input, int startSampleOffset, int endSampleOffset, int channelIndex, int channelCount) - { - if (input.IsEmpty || endSampleOffset < startSampleOffset) - { - return 0; - } - - int decodedCount = input.Length / channelCount; - - for (int i = 0; i < decodedCount; i++) - { - output[i] = (short)(input[i * channelCount + channelIndex] * short.MaxValue); - } - - return decodedCount; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static short Saturate(float value) - { - if (value > short.MaxValue) - { - return short.MaxValue; - } - - if (value < short.MinValue) - { - return short.MinValue; - } - - return (short)value; - } - } -} \ No newline at end of file diff --git a/Ryujinx.Audio/Renderer/Dsp/State/LimiterState.cs b/Ryujinx.Audio/Renderer/Dsp/State/LimiterState.cs deleted file mode 100644 index 92ed13fff..000000000 --- a/Ryujinx.Audio/Renderer/Dsp/State/LimiterState.cs +++ /dev/null @@ -1,30 +0,0 @@ -using Ryujinx.Audio.Renderer.Parameter.Effect; -using System; - -namespace Ryujinx.Audio.Renderer.Dsp.State -{ - public class LimiterState - { - public float[] DectectorAverage; - public float[] CompressionGain; - public float[] DelayedSampleBuffer; - public int[] DelayedSampleBufferPosition; - - public LimiterState(ref LimiterParameter parameter, ulong workBuffer) - { - DectectorAverage = new float[parameter.ChannelCount]; - CompressionGain = new float[parameter.ChannelCount]; - DelayedSampleBuffer = new float[parameter.ChannelCount * parameter.DelayBufferSampleCountMax]; - DelayedSampleBufferPosition = new int[parameter.ChannelCount]; - - DectectorAverage.AsSpan().Fill(0.0f); - CompressionGain.AsSpan().Fill(1.0f); - DelayedSampleBufferPosition.AsSpan().Fill(0); - DelayedSampleBuffer.AsSpan().Fill(0.0f); - - UpdateParameter(ref parameter); - } - - public void UpdateParameter(ref LimiterParameter parameter) { } - } -} \ No newline at end of file diff --git a/Ryujinx.Audio/Renderer/Server/AudioRendererManager.cs b/Ryujinx.Audio/Renderer/Server/AudioRendererManager.cs deleted file mode 100644 index 4de0ad166..000000000 --- a/Ryujinx.Audio/Renderer/Server/AudioRendererManager.cs +++ /dev/null @@ -1,405 +0,0 @@ -using Ryujinx.Audio.Integration; -using Ryujinx.Audio.Renderer.Dsp; -using Ryujinx.Audio.Renderer.Parameter; -using Ryujinx.Common.Logging; -using Ryujinx.Cpu; -using Ryujinx.Memory; -using System; -using System.Diagnostics; -using System.Linq; -using System.Threading; - -namespace Ryujinx.Audio.Renderer.Server -{ - /// - /// The audio renderer manager. - /// - public class AudioRendererManager : IDisposable - { - /// - /// Lock used for session allocation. - /// - private object _sessionLock = new object(); - - /// - /// Lock used to control the running state. - /// - private object _audioProcessorLock = new object(); - - /// - /// The session ids allocation table. - /// - private int[] _sessionIds; - - /// - /// The events linked to each session. - /// - private IWritableEvent[] _sessionsSystemEvent; - - /// - /// The sessions instances. - /// - private AudioRenderSystem[] _sessions; - - /// - /// The count of active sessions. - /// - private int _activeSessionCount; - - /// - /// The worker thread used to run . - /// - private Thread _workerThread; - - /// - /// Indicate if the worker thread and are running. - /// - private bool _isRunning; - - /// - /// The audio device driver to create audio outputs. - /// - private IHardwareDeviceDriver _deviceDriver; - - /// - /// Tick source used to measure elapsed time. - /// - public ITickSource TickSource { get; } - - /// - /// The instance associated to this manager. - /// - public AudioProcessor Processor { get; } - - /// - /// The dispose state. - /// - private int _disposeState; - - /// - /// Create a new . - /// - /// Tick source used to measure elapsed time. - public AudioRendererManager(ITickSource tickSource) - { - Processor = new AudioProcessor(); - TickSource = tickSource; - _sessionIds = new int[Constants.AudioRendererSessionCountMax]; - _sessions = new AudioRenderSystem[Constants.AudioRendererSessionCountMax]; - _activeSessionCount = 0; - - for (int i = 0; i < _sessionIds.Length; i++) - { - _sessionIds[i] = i; - } - } - - /// - /// Initialize the . - /// - /// The events associated to each session. - /// The device driver to use to create audio outputs. - public void Initialize(IWritableEvent[] sessionSystemEvents, IHardwareDeviceDriver deviceDriver) - { - _sessionsSystemEvent = sessionSystemEvents; - _deviceDriver = deviceDriver; - } - - /// - /// Get the work buffer size required by a session. - /// - /// The user configuration - /// The work buffer size required by a session. - public static ulong GetWorkBufferSize(ref AudioRendererConfiguration parameter) - { - return AudioRenderSystem.GetWorkBufferSize(ref parameter); - } - - /// - /// Acquire a new session id. - /// - /// A new session id. - private int AcquireSessionId() - { - lock (_sessionLock) - { - int index = _activeSessionCount; - - Debug.Assert(index < _sessionIds.Length); - - int sessionId = _sessionIds[index]; - - _sessionIds[index] = -1; - - _activeSessionCount++; - - Logger.Info?.Print(LogClass.AudioRenderer, $"Registered new renderer ({sessionId})"); - - return sessionId; - } - } - - /// - /// Release a given . - /// - /// The session id to release. - private void ReleaseSessionId(int sessionId) - { - lock (_sessionLock) - { - Debug.Assert(_activeSessionCount > 0); - - int newIndex = --_activeSessionCount; - - _sessionIds[newIndex] = sessionId; - } - - Logger.Info?.Print(LogClass.AudioRenderer, $"Unregistered renderer ({sessionId})"); - } - - /// - /// Check if there is any audio renderer active. - /// - /// Returns true if there is any audio renderer active. - private bool HasAnyActiveRendererLocked() - { - foreach (AudioRenderSystem renderer in _sessions) - { - if (renderer != null) - { - return true; - } - } - - return false; - } - - /// - /// Start the and worker thread. - /// - private void StartLocked(float volume) - { - _isRunning = true; - - // TODO: virtual device mapping (IAudioDevice) - Processor.Start(_deviceDriver, volume); - - _workerThread = new Thread(SendCommands) - { - Name = "AudioRendererManager.Worker" - }; - - _workerThread.Start(); - } - - /// - /// Stop the and worker thread. - /// - private void StopLocked() - { - _isRunning = false; - - _workerThread.Join(); - Processor.Stop(); - - Logger.Info?.Print(LogClass.AudioRenderer, "Stopped audio renderer"); - } - - /// - /// Stop sending commands to the without stopping the worker thread. - /// - public void StopSendingCommands() - { - lock (_sessionLock) - { - foreach (AudioRenderSystem renderer in _sessions) - { - renderer?.Disable(); - } - } - - lock (_audioProcessorLock) - { - if (_isRunning) - { - StopLocked(); - } - } - } - - /// - /// Worker main function. This is used to dispatch audio renderer commands to the . - /// - private void SendCommands() - { - Logger.Info?.Print(LogClass.AudioRenderer, "Starting audio renderer"); - Processor.Wait(); - - while (_isRunning) - { - lock (_sessionLock) - { - foreach (AudioRenderSystem renderer in _sessions) - { - renderer?.SendCommands(); - } - } - - Processor.Signal(); - Processor.Wait(); - } - } - - /// - /// Register a new . - /// - /// The to register. - private void Register(AudioRenderSystem renderer, float volume) - { - lock (_sessionLock) - { - _sessions[renderer.GetSessionId()] = renderer; - } - - lock (_audioProcessorLock) - { - if (!_isRunning) - { - StartLocked(volume); - } - } - } - - /// - /// Unregister a new . - /// - /// The to unregister. - internal void Unregister(AudioRenderSystem renderer) - { - lock (_sessionLock) - { - int sessionId = renderer.GetSessionId(); - - _sessions[renderer.GetSessionId()] = null; - - ReleaseSessionId(sessionId); - } - - lock (_audioProcessorLock) - { - if (_isRunning && !HasAnyActiveRendererLocked()) - { - StopLocked(); - } - } - } - - /// - /// Open a new - /// - /// The new - /// The memory manager that will be used for all guest memory operations. - /// The user configuration - /// The applet resource user id of the application. - /// The guest work buffer address. - /// The guest work buffer size. - /// The process handle of the application. - /// A reporting an error or a success. - public ResultCode OpenAudioRenderer( - out AudioRenderSystem renderer, - IVirtualMemoryManager memoryManager, - ref AudioRendererConfiguration parameter, - ulong appletResourceUserId, - ulong workBufferAddress, - ulong workBufferSize, - uint processHandle, - float volume) - { - int sessionId = AcquireSessionId(); - - AudioRenderSystem audioRenderer = new AudioRenderSystem(this, _sessionsSystemEvent[sessionId]); - - // TODO: Eventually, we should try to use the guest supplied work buffer instead of allocating - // our own. However, it was causing problems on some applications that would unmap the memory - // before the audio renderer was fully disposed. - Memory workBufferMemory = GC.AllocateArray((int)workBufferSize, pinned: true); - - ResultCode result = audioRenderer.Initialize( - ref parameter, - processHandle, - workBufferMemory, - workBufferAddress, - workBufferSize, - sessionId, - appletResourceUserId, - memoryManager); - - if (result == ResultCode.Success) - { - renderer = audioRenderer; - - Register(renderer, volume); - } - else - { - ReleaseSessionId(sessionId); - - renderer = null; - } - - return result; - } - - public float GetVolume() - { - if (Processor != null) - { - return Processor.GetVolume(); - } - - return 0f; - } - - public void SetVolume(float volume) - { - Processor?.SetVolume(volume); - } - - public void Dispose() - { - if (Interlocked.CompareExchange(ref _disposeState, 1, 0) == 0) - { - Dispose(true); - } - } - - protected virtual void Dispose(bool disposing) - { - if (disposing) - { - // Clone the sessions array to dispose them outside the lock. - AudioRenderSystem[] sessions; - - lock (_sessionLock) - { - sessions = _sessions.ToArray(); - } - - foreach (AudioRenderSystem renderer in sessions) - { - renderer?.Dispose(); - } - - lock (_audioProcessorLock) - { - if (_isRunning) - { - StopLocked(); - } - } - - Processor.Dispose(); - } - } - } -} \ No newline at end of file diff --git a/Ryujinx.Audio/Renderer/Server/CommandProcessingTimeEstimatorVersion2.cs b/Ryujinx.Audio/Renderer/Server/CommandProcessingTimeEstimatorVersion2.cs deleted file mode 100644 index 15800c993..000000000 --- a/Ryujinx.Audio/Renderer/Server/CommandProcessingTimeEstimatorVersion2.cs +++ /dev/null @@ -1,547 +0,0 @@ -using Ryujinx.Audio.Renderer.Dsp.Command; -using System; -using System.Diagnostics; - -namespace Ryujinx.Audio.Renderer.Server -{ - /// - /// version 2. (added with REV5) - /// - public class CommandProcessingTimeEstimatorVersion2 : ICommandProcessingTimeEstimator - { - private uint _sampleCount; - private uint _bufferCount; - - public CommandProcessingTimeEstimatorVersion2(uint sampleCount, uint bufferCount) - { - _sampleCount = sampleCount; - _bufferCount = bufferCount; - } - - public uint Estimate(PerformanceCommand command) - { - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - - if (_sampleCount == 160) - { - return (uint)489.35f; - } - - return (uint)491.18f; - } - - public uint Estimate(ClearMixBufferCommand command) - { - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - - float costPerBuffer = 668.8f; - float baseCost = 193.2f; - - if (_sampleCount == 160) - { - costPerBuffer = 260.4f; - baseCost = 139.65f; - } - - return (uint)(baseCost + costPerBuffer * _bufferCount); - } - - public uint Estimate(BiquadFilterCommand command) - { - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - - if (_sampleCount == 160) - { - return (uint)4813.2f; - } - - return (uint)6915.4f; - } - - public uint Estimate(MixRampGroupedCommand command) - { - const float costPerSample = 7.245f; - - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - - int volumeCount = 0; - - for (int i = 0; i < command.MixBufferCount; i++) - { - if (command.Volume0[i] != 0.0f || command.Volume1[i] != 0.0f) - { - volumeCount++; - } - } - - return (uint)(_sampleCount * costPerSample * volumeCount); - } - - public uint Estimate(MixRampCommand command) - { - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - - if (_sampleCount == 160) - { - return (uint)1859.0f; - } - - return (uint)2286.1f; - } - - public uint Estimate(DepopPrepareCommand command) - { - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - - if (_sampleCount == 160) - { - return (uint)306.62f; - } - - return (uint)293.22f; - } - - public uint Estimate(VolumeRampCommand command) - { - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - - if (_sampleCount == 160) - { - return (uint)1403.9f; - } - - return (uint)1884.3f; - } - - public uint Estimate(PcmInt16DataSourceCommandVersion1 command) - { - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - - float costPerSample = 1195.5f; - float baseCost = 7797.0f; - - if (_sampleCount == 160) - { - costPerSample = 749.27f; - baseCost = 6138.9f; - } - - return (uint)(baseCost + (costPerSample * (((command.SampleRate / 200.0f) / _sampleCount) * (command.Pitch * 0.000030518f)))); - } - - public uint Estimate(AdpcmDataSourceCommandVersion1 command) - { - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - - float costPerSample = 3564.1f; - float baseCost = 6225.5f; - - if (_sampleCount == 160) - { - costPerSample = 2125.6f; - baseCost = 9039.5f; - } - - return (uint)(baseCost + (costPerSample * (((command.SampleRate / 200.0f) / _sampleCount) * (command.Pitch * 0.000030518f)))); - } - - public uint Estimate(DepopForMixBuffersCommand command) - { - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - - if (_sampleCount == 160) - { - return (uint)762.96f; - } - - return (uint)726.96f; - } - - public uint Estimate(CopyMixBufferCommand command) - { - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - - if (_sampleCount == 160) - { - return (uint)836.32f; - } - - return (uint)1000.9f; - } - - public uint Estimate(MixCommand command) - { - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - - if (_sampleCount == 160) - { - return (uint)1342.2f; - } - - return (uint)1833.2f; - } - - public uint Estimate(DelayCommand command) - { - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - - if (_sampleCount == 160) - { - if (command.Enabled) - { - switch (command.Parameter.ChannelCount) - { - case 1: - return (uint)41636.0f; - case 2: - return (uint)97861.0f; - case 4: - return (uint)192520.0f; - case 6: - return (uint)301760.0f; - default: - throw new NotImplementedException($"{command.Parameter.ChannelCount}"); - } - } - else - { - switch (command.Parameter.ChannelCount) - { - case 1: - return (uint)578.53f; - case 2: - return (uint)663.06f; - case 4: - return (uint)703.98f; - case 6: - return (uint)760.03f; - default: - throw new NotImplementedException($"{command.Parameter.ChannelCount}"); - } - } - - } - - if (command.Enabled) - { - switch (command.Parameter.ChannelCount) - { - case 1: - return (uint)8770.3f; - case 2: - return (uint)25741.0f; - case 4: - return (uint)47551.0f; - case 6: - return (uint)81629.0f; - default: - throw new NotImplementedException($"{command.Parameter.ChannelCount}"); - } - } - else - { - switch (command.Parameter.ChannelCount) - { - case 1: - return (uint)521.28f; - case 2: - return (uint)585.4f; - case 4: - return (uint)629.88f; - case 6: - return (uint)713.57f; - default: - throw new NotImplementedException($"{command.Parameter.ChannelCount}"); - } - } - } - - public uint Estimate(ReverbCommand command) - { - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - - if (_sampleCount == 160) - { - if (command.Enabled) - { - switch (command.Parameter.ChannelCount) - { - case 1: - return (uint)97192.0f; - case 2: - return (uint)103280.0f; - case 4: - return (uint)109580.0f; - case 6: - return (uint)115070.0f; - default: - throw new NotImplementedException($"{command.Parameter.ChannelCount}"); - } - } - else - { - switch (command.Parameter.ChannelCount) - { - case 1: - return (uint)492.01f; - case 2: - return (uint)554.46f; - case 4: - return (uint)595.86f; - case 6: - return (uint)656.62f; - default: - throw new NotImplementedException($"{command.Parameter.ChannelCount}"); - } - } - - } - - if (command.Enabled) - { - switch (command.Parameter.ChannelCount) - { - case 1: - return (uint)136460.0f; - case 2: - return (uint)145750.0f; - case 4: - return (uint)154800.0f; - case 6: - return (uint)161970.0f; - default: - throw new NotImplementedException($"{command.Parameter.ChannelCount}"); - } - } - else - { - switch (command.Parameter.ChannelCount) - { - case 1: - return (uint)495.79f; - case 2: - return (uint)527.16f; - case 4: - return (uint)598.75f; - case 6: - return (uint)666.03f; - default: - throw new NotImplementedException($"{command.Parameter.ChannelCount}"); - } - } - } - - public uint Estimate(Reverb3dCommand command) - { - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - - if (_sampleCount == 160) - { - if (command.Enabled) - { - switch (command.Parameter.ChannelCount) - { - case 1: - return (uint)138840.0f; - case 2: - return (uint)135430.0f; - case 4: - return (uint)199180.0f; - case 6: - return (uint)247350.0f; - default: - throw new NotImplementedException($"{command.Parameter.ChannelCount}"); - } - } - else - { - switch (command.Parameter.ChannelCount) - { - case 1: - return (uint)718.7f; - case 2: - return (uint)751.3f; - case 4: - return (uint)797.46f; - case 6: - return (uint)867.43f; - default: - throw new NotImplementedException($"{command.Parameter.ChannelCount}"); - } - } - } - - if (command.Enabled) - { - switch (command.Parameter.ChannelCount) - { - case 1: - return (uint)199950.0f; - case 2: - return (uint)195200.0f; - case 4: - return (uint)290580.0f; - case 6: - return (uint)363490.0f; - default: - throw new NotImplementedException($"{command.Parameter.ChannelCount}"); - } - } - else - { - switch (command.Parameter.ChannelCount) - { - case 1: - return (uint)534.24f; - case 2: - return (uint)570.87f; - case 4: - return (uint)660.93f; - case 6: - return (uint)694.6f; - default: - throw new NotImplementedException($"{command.Parameter.ChannelCount}"); - } - } - } - - public uint Estimate(AuxiliaryBufferCommand command) - { - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - - if (_sampleCount == 160) - { - if (command.Enabled) - { - return (uint)7177.9f; - } - - return (uint)489.16f; - } - - if (command.Enabled) - { - return (uint)9499.8f; - } - - return (uint)485.56f; - } - - public uint Estimate(VolumeCommand command) - { - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - - if (_sampleCount == 160) - { - return (uint)1280.3f; - } - - return (uint)1737.8f; - } - - public uint Estimate(CircularBufferSinkCommand command) - { - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - - float costPerBuffer = 1726.0f; - float baseCost = 1369.7f; - - if (_sampleCount == 160) - { - costPerBuffer = 853.63f; - baseCost = 1284.5f; - } - - return (uint)(baseCost + costPerBuffer * command.InputCount); - } - - public uint Estimate(DownMixSurroundToStereoCommand command) - { - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - - if (_sampleCount == 160) - { - return (uint)10009.0f; - } - - return (uint)14577.0f; - } - - public uint Estimate(UpsampleCommand command) - { - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - - if (_sampleCount == 160) - { - return (uint)292000.0f; - } - - return (uint)0.0f; - } - - public uint Estimate(DeviceSinkCommand command) - { - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - Debug.Assert(command.InputCount == 2 || command.InputCount == 6); - - if (command.InputCount == 2) - { - if (_sampleCount == 160) - { - return (uint)9261.5f; - } - - return (uint)9336.1f; - } - - if (_sampleCount == 160) - { - return (uint)9111.8f; - } - - return (uint)9566.7f; - } - - public uint Estimate(PcmFloatDataSourceCommandVersion1 command) - { - // NOTE: This was added between REV7 and REV8 and for some reasons the estimator v2 was changed... - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - - float costPerSample = 3490.9f; - float baseCost = 10091.0f; - - if (_sampleCount == 160) - { - costPerSample = 2310.4f; - baseCost = 7845.3f; - } - - return (uint)(baseCost + (costPerSample * (((command.SampleRate / 200.0f) / _sampleCount) * (command.Pitch * 0.000030518f)))); - } - - public uint Estimate(DataSourceVersion2Command command) - { - return 0; - } - - public uint Estimate(LimiterCommandVersion1 command) - { - return 0; - } - - public uint Estimate(LimiterCommandVersion2 command) - { - return 0; - } - - public uint Estimate(GroupedBiquadFilterCommand command) - { - return 0; - } - - public uint Estimate(CaptureBufferCommand command) - { - return 0; - } - } -} \ No newline at end of file diff --git a/Ryujinx.Audio/Renderer/Server/CommandProcessingTimeEstimatorVersion3.cs b/Ryujinx.Audio/Renderer/Server/CommandProcessingTimeEstimatorVersion3.cs deleted file mode 100644 index 6c6e2828c..000000000 --- a/Ryujinx.Audio/Renderer/Server/CommandProcessingTimeEstimatorVersion3.cs +++ /dev/null @@ -1,751 +0,0 @@ -using Ryujinx.Audio.Common; -using Ryujinx.Audio.Renderer.Dsp.Command; -using Ryujinx.Audio.Renderer.Parameter.Effect; -using System; -using System.Diagnostics; -using static Ryujinx.Audio.Renderer.Parameter.VoiceInParameter; - -namespace Ryujinx.Audio.Renderer.Server -{ - /// - /// version 3. (added with REV8) - /// - public class CommandProcessingTimeEstimatorVersion3 : ICommandProcessingTimeEstimator - { - protected uint _sampleCount; - protected uint _bufferCount; - - public CommandProcessingTimeEstimatorVersion3(uint sampleCount, uint bufferCount) - { - _sampleCount = sampleCount; - _bufferCount = bufferCount; - } - - public uint Estimate(PerformanceCommand command) - { - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - - if (_sampleCount == 160) - { - return (uint)498.17f; - } - - return (uint)489.42f; - } - - public uint Estimate(ClearMixBufferCommand command) - { - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - - float costPerBuffer = 440.68f; - float baseCost = 0; - - if (_sampleCount == 160) - { - costPerBuffer = 266.65f; - } - - return (uint)(baseCost + costPerBuffer * _bufferCount); - } - - public uint Estimate(BiquadFilterCommand command) - { - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - - if (_sampleCount == 160) - { - return (uint)4173.2f; - } - - return (uint)5585.1f; - } - - public uint Estimate(MixRampGroupedCommand command) - { - float costPerSample = 6.4434f; - - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - - if (_sampleCount == 160) - { - costPerSample = 6.708f; - } - - int volumeCount = 0; - - for (int i = 0; i < command.MixBufferCount; i++) - { - if (command.Volume0[i] != 0.0f || command.Volume1[i] != 0.0f) - { - volumeCount++; - } - } - - return (uint)(_sampleCount * costPerSample * volumeCount); - } - - public uint Estimate(MixRampCommand command) - { - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - - if (_sampleCount == 160) - { - return (uint)1968.7f; - } - - return (uint)2459.4f; - } - - public uint Estimate(DepopPrepareCommand command) - { - return 0; - } - - public uint Estimate(VolumeRampCommand command) - { - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - - if (_sampleCount == 160) - { - return (uint)1425.3f; - } - - return (uint)1700.0f; - } - - public uint Estimate(PcmInt16DataSourceCommandVersion1 command) - { - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - - float costPerSample = 710.143f; - float baseCost = 7853.286f; - - if (_sampleCount == 160) - { - costPerSample = 427.52f; - baseCost = 6329.442f; - } - - return (uint)(baseCost + (costPerSample * (((command.SampleRate / 200.0f) / _sampleCount) * (command.Pitch * 0.000030518f)))); - } - - public uint Estimate(AdpcmDataSourceCommandVersion1 command) - { - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - - float costPerSample = 3564.1f; - float baseCost = 9736.702f; - - if (_sampleCount == 160) - { - costPerSample = 2125.6f; - baseCost = 7913.808f; - } - - return (uint)(baseCost + (costPerSample * (((command.SampleRate / 200.0f) / _sampleCount) * (command.Pitch * 0.000030518f)))); - } - - public uint Estimate(DepopForMixBuffersCommand command) - { - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - - if (_sampleCount == 160) - { - return (uint)739.64f; - } - - return (uint)910.97f; - } - - public uint Estimate(CopyMixBufferCommand command) - { - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - - if (_sampleCount == 160) - { - return (uint)842.59f; - } - - return (uint)986.72f; - } - - public uint Estimate(MixCommand command) - { - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - - if (_sampleCount == 160) - { - return (uint)1402.8f; - } - - return (uint)1853.2f; - } - - public virtual uint Estimate(DelayCommand command) - { - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - - if (_sampleCount == 160) - { - if (command.Enabled) - { - switch (command.Parameter.ChannelCount) - { - case 1: - return (uint)8929.04f; - case 2: - return (uint)25500.75f; - case 4: - return (uint)47759.62f; - case 6: - return (uint)82203.07f; - default: - throw new NotImplementedException($"{command.Parameter.ChannelCount}"); - } - } - else - { - switch (command.Parameter.ChannelCount) - { - case 1: - return (uint)1295.20f; - case 2: - return (uint)1213.60f; - case 4: - return (uint)942.03f; - case 6: - return (uint)1001.55f; - default: - throw new NotImplementedException($"{command.Parameter.ChannelCount}"); - } - } - } - - if (command.Enabled) - { - switch (command.Parameter.ChannelCount) - { - case 1: - return (uint)11941.05f; - case 2: - return (uint)37197.37f; - case 4: - return (uint)69749.84f; - case 6: - return (uint)120042.40f; - default: - throw new NotImplementedException($"{command.Parameter.ChannelCount}"); - } - } - else - { - switch (command.Parameter.ChannelCount) - { - case 1: - return (uint)997.67f; - case 2: - return (uint)977.63f; - case 4: - return (uint)792.30f; - case 6: - return (uint)875.43f; - default: - throw new NotImplementedException($"{command.Parameter.ChannelCount}"); - } - } - } - - public virtual uint Estimate(ReverbCommand command) - { - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - - if (_sampleCount == 160) - { - if (command.Enabled) - { - switch (command.Parameter.ChannelCount) - { - case 1: - return (uint)81475.05f; - case 2: - return (uint)84975.0f; - case 4: - return (uint)91625.15f; - case 6: - return (uint)95332.27f; - default: - throw new NotImplementedException($"{command.Parameter.ChannelCount}"); - } - } - else - { - switch (command.Parameter.ChannelCount) - { - case 1: - return (uint)536.30f; - case 2: - return (uint)588.70f; - case 4: - return (uint)643.70f; - case 6: - return (uint)706.0f; - default: - throw new NotImplementedException($"{command.Parameter.ChannelCount}"); - } - } - } - - if (command.Enabled) - { - switch (command.Parameter.ChannelCount) - { - case 1: - return (uint)120174.47f; - case 2: - return (uint)25262.22f; - case 4: - return (uint)135751.23f; - case 6: - return (uint)141129.23f; - default: - throw new NotImplementedException($"{command.Parameter.ChannelCount}"); - } - } - else - { - switch (command.Parameter.ChannelCount) - { - case 1: - return (uint)617.64f; - case 2: - return (uint)659.54f; - case 4: - return (uint)711.43f; - case 6: - return (uint)778.07f; - default: - throw new NotImplementedException($"{command.Parameter.ChannelCount}"); - } - } - } - - public virtual uint Estimate(Reverb3dCommand command) - { - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - - if (_sampleCount == 160) - { - if (command.Enabled) - { - switch (command.Parameter.ChannelCount) - { - case 1: - return (uint)116754.0f; - case 2: - return (uint)125912.05f; - case 4: - return (uint)146336.03f; - case 6: - return (uint)165812.66f; - default: - throw new NotImplementedException($"{command.Parameter.ChannelCount}"); - } - } - else - { - switch (command.Parameter.ChannelCount) - { - case 1: - return (uint)734.0f; - case 2: - return (uint)766.62f; - case 4: - return (uint)797.46f; - case 6: - return (uint)867.43f; - default: - throw new NotImplementedException($"{command.Parameter.ChannelCount}"); - } - } - } - - if (command.Enabled) - { - switch (command.Parameter.ChannelCount) - { - case 1: - return (uint)170292.34f; - case 2: - return (uint)183875.63f; - case 4: - return (uint)214696.19f; - case 6: - return (uint)243846.77f; - default: - throw new NotImplementedException($"{command.Parameter.ChannelCount}"); - } - } - else - { - switch (command.Parameter.ChannelCount) - { - case 1: - return (uint)508.47f; - case 2: - return (uint)582.45f; - case 4: - return (uint)626.42f; - case 6: - return (uint)682.47f; - default: - throw new NotImplementedException($"{command.Parameter.ChannelCount}"); - } - } - } - - public uint Estimate(AuxiliaryBufferCommand command) - { - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - - if (_sampleCount == 160) - { - if (command.Enabled) - { - return (uint)7182.14f; - } - - return (uint)472.11f; - } - - if (command.Enabled) - { - return (uint)9435.96f; - } - - return (uint)462.62f; - } - - public uint Estimate(VolumeCommand command) - { - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - - if (_sampleCount == 160) - { - return (uint)1311.1f; - } - - return (uint)1713.6f; - } - - public uint Estimate(CircularBufferSinkCommand command) - { - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - - float costPerBuffer = 770.26f; - float baseCost = 0f; - - if (_sampleCount == 160) - { - costPerBuffer = 531.07f; - } - - return (uint)(baseCost + costPerBuffer * command.InputCount); - } - - public uint Estimate(DownMixSurroundToStereoCommand command) - { - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - - if (_sampleCount == 160) - { - return (uint)9949.7f; - } - - return (uint)14679.0f; - } - - public uint Estimate(UpsampleCommand command) - { - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - - if (_sampleCount == 160) - { - return (uint)312990.0f; - } - - return (uint)0.0f; - } - - public uint Estimate(DeviceSinkCommand command) - { - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - Debug.Assert(command.InputCount == 2 || command.InputCount == 6); - - if (command.InputCount == 2) - { - if (_sampleCount == 160) - { - return (uint)8980.0f; - } - - return (uint)9221.9f; - } - - if (_sampleCount == 160) - { - return (uint)9177.9f; - } - - return (uint)9725.9f; - } - - public uint Estimate(PcmFloatDataSourceCommandVersion1 command) - { - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - - float costPerSample = 3490.9f; - float baseCost = 10090.9f; - - if (_sampleCount == 160) - { - costPerSample = 2310.4f; - baseCost = 7845.25f; - } - - return (uint)(baseCost + (costPerSample * (((command.SampleRate / 200.0f) / _sampleCount) * (command.Pitch * 0.000030518f)))); - } - - public uint Estimate(DataSourceVersion2Command command) - { - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - - (float baseCost, float costPerSample) = GetCostByFormat(_sampleCount, command.SampleFormat, command.SrcQuality); - - return (uint)(baseCost + (costPerSample * (((command.SampleRate / 200.0f) / _sampleCount) * (command.Pitch * 0.000030518f) - 1.0f))); - } - - private static (float, float) GetCostByFormat(uint sampleCount, SampleFormat format, SampleRateConversionQuality quality) - { - Debug.Assert(sampleCount == 160 || sampleCount == 240); - - switch (format) - { - case SampleFormat.PcmInt16: - switch (quality) - { - case SampleRateConversionQuality.Default: - if (sampleCount == 160) - { - return (6329.44f, 427.52f); - } - - return (7853.28f, 710.14f); - case SampleRateConversionQuality.High: - if (sampleCount == 160) - { - return (8049.42f, 371.88f); - } - - return (10138.84f, 610.49f); - case SampleRateConversionQuality.Low: - if (sampleCount == 160) - { - return (5062.66f, 423.43f); - } - - return (5810.96f, 676.72f); - default: - throw new NotImplementedException($"{format} {quality}"); - } - case SampleFormat.PcmFloat: - switch (quality) - { - case SampleRateConversionQuality.Default: - if (sampleCount == 160) - { - return (7845.25f, 2310.4f); - } - - return (10090.9f, 3490.9f); - case SampleRateConversionQuality.High: - if (sampleCount == 160) - { - return (9446.36f, 2308.91f); - } - - return (12520.85f, 3480.61f); - case SampleRateConversionQuality.Low: - if (sampleCount == 160) - { - return (9446.36f, 2308.91f); - } - - return (12520.85f, 3480.61f); - default: - throw new NotImplementedException($"{format} {quality}"); - } - case SampleFormat.Adpcm: - switch (quality) - { - case SampleRateConversionQuality.Default: - if (sampleCount == 160) - { - return (7913.81f, 1827.66f); - } - - return (9736.70f, 2756.37f); - case SampleRateConversionQuality.High: - if (sampleCount == 160) - { - return (9607.81f, 1829.29f); - } - - return (12154.38f, 2731.31f); - case SampleRateConversionQuality.Low: - if (sampleCount == 160) - { - return (6517.48f, 1824.61f); - } - - return (7929.44f, 2732.15f); - default: - throw new NotImplementedException($"{format} {quality}"); - } - default: - throw new NotImplementedException($"{format}"); - } - } - - private uint EstimateLimiterCommandCommon(LimiterParameter parameter, bool enabled) - { - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - - if (_sampleCount == 160) - { - if (enabled) - { - switch (parameter.ChannelCount) - { - case 1: - return (uint)21392.0f; - case 2: - return (uint)26829.0f; - case 4: - return (uint)32405.0f; - case 6: - return (uint)52219.0f; - default: - throw new NotImplementedException($"{parameter.ChannelCount}"); - } - } - else - { - switch (parameter.ChannelCount) - { - case 1: - return (uint)897.0f; - case 2: - return (uint)931.55f; - case 4: - return (uint)975.39f; - case 6: - return (uint)1016.8f; - default: - throw new NotImplementedException($"{parameter.ChannelCount}"); - } - } - } - - if (enabled) - { - switch (parameter.ChannelCount) - { - case 1: - return (uint)30556.0f; - case 2: - return (uint)39011.0f; - case 4: - return (uint)48270.0f; - case 6: - return (uint)76712.0f; - default: - throw new NotImplementedException($"{parameter.ChannelCount}"); - } - } - else - { - switch (parameter.ChannelCount) - { - case 1: - return (uint)874.43f; - case 2: - return (uint)921.55f; - case 4: - return (uint)945.26f; - case 6: - return (uint)992.26f; - default: - throw new NotImplementedException($"{parameter.ChannelCount}"); - } - } - } - - public uint Estimate(LimiterCommandVersion1 command) - { - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - - return EstimateLimiterCommandCommon(command.Parameter, command.IsEffectEnabled); - } - - public uint Estimate(LimiterCommandVersion2 command) - { - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - - if (!command.Parameter.StatisticsEnabled || !command.IsEffectEnabled) - { - return EstimateLimiterCommandCommon(command.Parameter, command.IsEffectEnabled); - } - - if (_sampleCount == 160) - { - switch (command.Parameter.ChannelCount) - { - case 1: - return (uint)23309.0f; - case 2: - return (uint)29954.0f; - case 4: - return (uint)35807.0f; - case 6: - return (uint)58340.0f; - default: - throw new NotImplementedException($"{command.Parameter.ChannelCount}"); - } - } - - switch (command.Parameter.ChannelCount) - { - case 1: - return (uint)33526.0f; - case 2: - return (uint)43549.0f; - case 4: - return (uint)52190.0f; - case 6: - return (uint)85527.0f; - default: - throw new NotImplementedException($"{command.Parameter.ChannelCount}"); - } - } - - public virtual uint Estimate(GroupedBiquadFilterCommand command) - { - return 0; - } - - public virtual uint Estimate(CaptureBufferCommand command) - { - return 0; - } - } -} \ No newline at end of file diff --git a/Ryujinx.Audio/Renderer/Server/CommandProcessingTimeEstimatorVersion5.cs b/Ryujinx.Audio/Renderer/Server/CommandProcessingTimeEstimatorVersion5.cs deleted file mode 100644 index 961d92aa6..000000000 --- a/Ryujinx.Audio/Renderer/Server/CommandProcessingTimeEstimatorVersion5.cs +++ /dev/null @@ -1,236 +0,0 @@ -using Ryujinx.Audio.Renderer.Dsp.Command; -using System; -using System.Diagnostics; - -namespace Ryujinx.Audio.Renderer.Server -{ - /// - /// version 5. (added with REV11) - /// - public class CommandProcessingTimeEstimatorVersion5 : CommandProcessingTimeEstimatorVersion4 - { - public CommandProcessingTimeEstimatorVersion5(uint sampleCount, uint bufferCount) : base(sampleCount, bufferCount) { } - - public override uint Estimate(DelayCommand command) - { - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - - if (_sampleCount == 160) - { - if (command.Enabled) - { - switch (command.Parameter.ChannelCount) - { - case 1: - return 8929; - case 2: - return 25501; - case 4: - return 47760; - case 6: - return 82203; - default: - throw new NotImplementedException($"{command.Parameter.ChannelCount}"); - } - } - else - { - switch (command.Parameter.ChannelCount) - { - case 1: - return (uint)1295.20f; - case 2: - return (uint)1213.60f; - case 4: - return (uint)942.03f; - case 6: - return (uint)1001.6f; - default: - throw new NotImplementedException($"{command.Parameter.ChannelCount}"); - } - } - } - - if (command.Enabled) - { - switch (command.Parameter.ChannelCount) - { - case 1: - return 11941; - case 2: - return 37197; - case 4: - return 69750; - case 6: - return 12004; - default: - throw new NotImplementedException($"{command.Parameter.ChannelCount}"); - } - } - else - { - switch (command.Parameter.ChannelCount) - { - case 1: - return (uint)997.67f; - case 2: - return (uint)977.63f; - case 4: - return (uint)792.31f; - case 6: - return (uint)875.43f; - default: - throw new NotImplementedException($"{command.Parameter.ChannelCount}"); - } - } - } - - public override uint Estimate(ReverbCommand command) - { - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - - if (_sampleCount == 160) - { - if (command.Enabled) - { - switch (command.Parameter.ChannelCount) - { - case 1: - return 81475; - case 2: - return 84975; - case 4: - return 91625; - case 6: - return 95332; - default: - throw new NotImplementedException($"{command.Parameter.ChannelCount}"); - } - } - else - { - switch (command.Parameter.ChannelCount) - { - case 1: - return (uint)536.30f; - case 2: - return (uint)588.80f; - case 4: - return (uint)643.70f; - case 6: - return (uint)706.0f; - default: - throw new NotImplementedException($"{command.Parameter.ChannelCount}"); - } - } - } - - if (command.Enabled) - { - switch (command.Parameter.ChannelCount) - { - case 1: - return 120170; - case 2: - return 125260; - case 4: - return 135750; - case 6: - return 141130; - default: - throw new NotImplementedException($"{command.Parameter.ChannelCount}"); - } - } - else - { - switch (command.Parameter.ChannelCount) - { - case 1: - return (uint)617.64f; - case 2: - return (uint)659.54f; - case 4: - return (uint)711.44f; - case 6: - return (uint)778.07f; - default: - throw new NotImplementedException($"{command.Parameter.ChannelCount}"); - } - } - } - - public override uint Estimate(Reverb3dCommand command) - { - Debug.Assert(_sampleCount == 160 || _sampleCount == 240); - - if (_sampleCount == 160) - { - if (command.Enabled) - { - switch (command.Parameter.ChannelCount) - { - case 1: - return 116750; - case 2: - return 125910; - case 4: - return 146340; - case 6: - return 165810; - default: - throw new NotImplementedException($"{command.Parameter.ChannelCount}"); - } - } - else - { - switch (command.Parameter.ChannelCount) - { - case 1: - return 735; - case 2: - return (uint)766.62f; - case 4: - return (uint)834.07f; - case 6: - return (uint)875.44f; - default: - throw new NotImplementedException($"{command.Parameter.ChannelCount}"); - } - } - } - - if (command.Enabled) - { - switch (command.Parameter.ChannelCount) - { - case 1: - return 170290; - case 2: - return 183880; - case 4: - return 214700; - case 6: - return 243850; - default: - throw new NotImplementedException($"{command.Parameter.ChannelCount}"); - } - } - else - { - switch (command.Parameter.ChannelCount) - { - case 1: - return (uint)508.47f; - case 2: - return (uint)582.45f; - case 4: - return (uint)626.42f; - case 6: - return (uint)682.47f; - default: - throw new NotImplementedException($"{command.Parameter.ChannelCount}"); - } - } - } - } -} \ No newline at end of file diff --git a/Ryujinx.Audio/Renderer/Server/StateUpdater.cs b/Ryujinx.Audio/Renderer/Server/StateUpdater.cs deleted file mode 100644 index 0c2cfa7ea..000000000 --- a/Ryujinx.Audio/Renderer/Server/StateUpdater.cs +++ /dev/null @@ -1,632 +0,0 @@ -using Ryujinx.Audio.Renderer.Common; -using Ryujinx.Audio.Renderer.Parameter; -using Ryujinx.Audio.Renderer.Parameter.Performance; -using Ryujinx.Audio.Renderer.Server.Effect; -using Ryujinx.Audio.Renderer.Server.MemoryPool; -using Ryujinx.Audio.Renderer.Server.Mix; -using Ryujinx.Audio.Renderer.Server.Performance; -using Ryujinx.Audio.Renderer.Server.Sink; -using Ryujinx.Audio.Renderer.Server.Splitter; -using Ryujinx.Audio.Renderer.Server.Voice; -using Ryujinx.Audio.Renderer.Utils; -using Ryujinx.Common.Logging; -using System; -using System.Diagnostics; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -using static Ryujinx.Audio.Renderer.Common.BehaviourParameter; - -namespace Ryujinx.Audio.Renderer.Server -{ - public class StateUpdater - { - private readonly ReadOnlyMemory _inputOrigin; - private ReadOnlyMemory _outputOrigin; - private ReadOnlyMemory _input; - - private Memory _output; - private uint _processHandle; - private BehaviourContext _behaviourContext; - - private UpdateDataHeader _inputHeader; - private Memory _outputHeader; - - private ref UpdateDataHeader OutputHeader => ref _outputHeader.Span[0]; - - public StateUpdater(ReadOnlyMemory input, Memory output, uint processHandle, BehaviourContext behaviourContext) - { - _input = input; - _inputOrigin = _input; - _output = output; - _outputOrigin = _output; - _processHandle = processHandle; - _behaviourContext = behaviourContext; - - _inputHeader = SpanIOHelper.Read(ref _input); - - _outputHeader = SpanMemoryManager.Cast(_output.Slice(0, Unsafe.SizeOf())); - OutputHeader.Initialize(_behaviourContext.UserRevision); - _output = _output.Slice(Unsafe.SizeOf()); - } - - public ResultCode UpdateBehaviourContext() - { - BehaviourParameter parameter = SpanIOHelper.Read(ref _input); - - if (!BehaviourContext.CheckValidRevision(parameter.UserRevision) || parameter.UserRevision != _behaviourContext.UserRevision) - { - return ResultCode.InvalidUpdateInfo; - } - - _behaviourContext.ClearError(); - _behaviourContext.UpdateFlags(parameter.Flags); - - if (_inputHeader.BehaviourSize != Unsafe.SizeOf()) - { - return ResultCode.InvalidUpdateInfo; - } - - return ResultCode.Success; - } - - public ResultCode UpdateMemoryPools(Span memoryPools) - { - PoolMapper mapper = new PoolMapper(_processHandle, _behaviourContext.IsMemoryPoolForceMappingEnabled()); - - if (memoryPools.Length * Unsafe.SizeOf() != _inputHeader.MemoryPoolsSize) - { - return ResultCode.InvalidUpdateInfo; - } - - foreach (ref MemoryPoolState memoryPool in memoryPools) - { - MemoryPoolInParameter parameter = SpanIOHelper.Read(ref _input); - - ref MemoryPoolOutStatus outStatus = ref SpanIOHelper.GetWriteRef(ref _output)[0]; - - PoolMapper.UpdateResult updateResult = mapper.Update(ref memoryPool, ref parameter, ref outStatus); - - if (updateResult != PoolMapper.UpdateResult.Success && - updateResult != PoolMapper.UpdateResult.MapError && - updateResult != PoolMapper.UpdateResult.UnmapError) - { - if (updateResult != PoolMapper.UpdateResult.InvalidParameter) - { - throw new InvalidOperationException($"{updateResult}"); - } - - return ResultCode.InvalidUpdateInfo; - } - } - - OutputHeader.MemoryPoolsSize = (uint)(Unsafe.SizeOf() * memoryPools.Length); - OutputHeader.TotalSize += OutputHeader.MemoryPoolsSize; - - return ResultCode.Success; - } - - public ResultCode UpdateVoiceChannelResources(VoiceContext context) - { - if (context.GetCount() * Unsafe.SizeOf() != _inputHeader.VoiceResourcesSize) - { - return ResultCode.InvalidUpdateInfo; - } - - for (int i = 0; i < context.GetCount(); i++) - { - VoiceChannelResourceInParameter parameter = SpanIOHelper.Read(ref _input); - - ref VoiceChannelResource resource = ref context.GetChannelResource(i); - - resource.Id = parameter.Id; - parameter.Mix.AsSpan().CopyTo(resource.Mix.AsSpan()); - resource.IsUsed = parameter.IsUsed; - } - - return ResultCode.Success; - } - - public ResultCode UpdateVoices(VoiceContext context, Memory memoryPools) - { - if (context.GetCount() * Unsafe.SizeOf() != _inputHeader.VoicesSize) - { - return ResultCode.InvalidUpdateInfo; - } - - int initialOutputSize = _output.Length; - - ReadOnlySpan parameters = MemoryMarshal.Cast(_input.Slice(0, (int)_inputHeader.VoicesSize).Span); - - _input = _input.Slice((int)_inputHeader.VoicesSize); - - PoolMapper mapper = new PoolMapper(_processHandle, memoryPools, _behaviourContext.IsMemoryPoolForceMappingEnabled()); - - // First make everything not in use. - for (int i = 0; i < context.GetCount(); i++) - { - ref VoiceState state = ref context.GetState(i); - - state.InUse = false; - } - - // Start processing - for (int i = 0; i < context.GetCount(); i++) - { - VoiceInParameter parameter = parameters[i]; - - Memory[] voiceUpdateStates = new Memory[Constants.VoiceChannelCountMax]; - - ref VoiceOutStatus outStatus = ref SpanIOHelper.GetWriteRef(ref _output)[0]; - - if (parameter.InUse) - { - ref VoiceState currentVoiceState = ref context.GetState(i); - - for (int channelResourceIndex = 0; channelResourceIndex < parameter.ChannelCount; channelResourceIndex++) - { - int channelId = parameter.ChannelResourceIds[channelResourceIndex]; - - Debug.Assert(channelId >= 0 && channelId < context.GetCount()); - - voiceUpdateStates[channelResourceIndex] = context.GetUpdateStateForCpu(channelId); - } - - if (parameter.IsNew) - { - currentVoiceState.Initialize(); - } - - currentVoiceState.UpdateParameters(out ErrorInfo updateParameterError, ref parameter, ref mapper, ref _behaviourContext); - - if (updateParameterError.ErrorCode != ResultCode.Success) - { - _behaviourContext.AppendError(ref updateParameterError); - } - - currentVoiceState.UpdateWaveBuffers(out ErrorInfo[] waveBufferUpdateErrorInfos, ref parameter, voiceUpdateStates, ref mapper, ref _behaviourContext); - - foreach (ref ErrorInfo errorInfo in waveBufferUpdateErrorInfos.AsSpan()) - { - if (errorInfo.ErrorCode != ResultCode.Success) - { - _behaviourContext.AppendError(ref errorInfo); - } - } - - currentVoiceState.WriteOutStatus(ref outStatus, ref parameter, voiceUpdateStates); - } - } - - int currentOutputSize = _output.Length; - - OutputHeader.VoicesSize = (uint)(Unsafe.SizeOf() * context.GetCount()); - OutputHeader.TotalSize += OutputHeader.VoicesSize; - - Debug.Assert((initialOutputSize - currentOutputSize) == OutputHeader.VoicesSize); - - return ResultCode.Success; - } - - private static void ResetEffect(ref BaseEffect effect, ref T parameter, PoolMapper mapper) where T : unmanaged, IEffectInParameter - { - effect.ForceUnmapBuffers(mapper); - - switch (parameter.Type) - { - case EffectType.Invalid: - effect = new BaseEffect(); - break; - case EffectType.BufferMix: - effect = new BufferMixEffect(); - break; - case EffectType.AuxiliaryBuffer: - effect = new AuxiliaryBufferEffect(); - break; - case EffectType.Delay: - effect = new DelayEffect(); - break; - case EffectType.Reverb: - effect = new ReverbEffect(); - break; - case EffectType.Reverb3d: - effect = new Reverb3dEffect(); - break; - case EffectType.BiquadFilter: - effect = new BiquadFilterEffect(); - break; - case EffectType.Limiter: - effect = new LimiterEffect(); - break; - case EffectType.CaptureBuffer: - effect = new CaptureBufferEffect(); - break; - default: - throw new NotImplementedException($"EffectType {parameter.Type} not implemented!"); - } - } - - public ResultCode UpdateEffects(EffectContext context, bool isAudioRendererActive, Memory memoryPools) - { - if (_behaviourContext.IsEffectInfoVersion2Supported()) - { - return UpdateEffectsVersion2(context, isAudioRendererActive, memoryPools); - } - else - { - return UpdateEffectsVersion1(context, isAudioRendererActive, memoryPools); - } - } - - public ResultCode UpdateEffectsVersion2(EffectContext context, bool isAudioRendererActive, Memory memoryPools) - { - if (context.GetCount() * Unsafe.SizeOf() != _inputHeader.EffectsSize) - { - return ResultCode.InvalidUpdateInfo; - } - - int initialOutputSize = _output.Length; - - ReadOnlySpan parameters = MemoryMarshal.Cast(_input.Slice(0, (int)_inputHeader.EffectsSize).Span); - - _input = _input.Slice((int)_inputHeader.EffectsSize); - - PoolMapper mapper = new PoolMapper(_processHandle, memoryPools, _behaviourContext.IsMemoryPoolForceMappingEnabled()); - - for (int i = 0; i < context.GetCount(); i++) - { - EffectInParameterVersion2 parameter = parameters[i]; - - ref EffectOutStatusVersion2 outStatus = ref SpanIOHelper.GetWriteRef(ref _output)[0]; - - ref BaseEffect effect = ref context.GetEffect(i); - - if (!effect.IsTypeValid(ref parameter)) - { - ResetEffect(ref effect, ref parameter, mapper); - } - - effect.Update(out ErrorInfo updateErrorInfo, ref parameter, mapper); - - if (updateErrorInfo.ErrorCode != ResultCode.Success) - { - _behaviourContext.AppendError(ref updateErrorInfo); - } - - effect.StoreStatus(ref outStatus, isAudioRendererActive); - - if (parameter.IsNew) - { - effect.InitializeResultState(ref context.GetDspState(i)); - effect.InitializeResultState(ref context.GetState(i)); - } - - effect.UpdateResultState(ref outStatus.ResultState, ref context.GetState(i)); - } - - int currentOutputSize = _output.Length; - - OutputHeader.EffectsSize = (uint)(Unsafe.SizeOf() * context.GetCount()); - OutputHeader.TotalSize += OutputHeader.EffectsSize; - - Debug.Assert((initialOutputSize - currentOutputSize) == OutputHeader.EffectsSize); - - return ResultCode.Success; - } - - public ResultCode UpdateEffectsVersion1(EffectContext context, bool isAudioRendererActive, Memory memoryPools) - { - if (context.GetCount() * Unsafe.SizeOf() != _inputHeader.EffectsSize) - { - return ResultCode.InvalidUpdateInfo; - } - - int initialOutputSize = _output.Length; - - ReadOnlySpan parameters = MemoryMarshal.Cast(_input.Slice(0, (int)_inputHeader.EffectsSize).Span); - - _input = _input.Slice((int)_inputHeader.EffectsSize); - - PoolMapper mapper = new PoolMapper(_processHandle, memoryPools, _behaviourContext.IsMemoryPoolForceMappingEnabled()); - - for (int i = 0; i < context.GetCount(); i++) - { - EffectInParameterVersion1 parameter = parameters[i]; - - ref EffectOutStatusVersion1 outStatus = ref SpanIOHelper.GetWriteRef(ref _output)[0]; - - ref BaseEffect effect = ref context.GetEffect(i); - - if (!effect.IsTypeValid(ref parameter)) - { - ResetEffect(ref effect, ref parameter, mapper); - } - - effect.Update(out ErrorInfo updateErrorInfo, ref parameter, mapper); - - if (updateErrorInfo.ErrorCode != ResultCode.Success) - { - _behaviourContext.AppendError(ref updateErrorInfo); - } - - effect.StoreStatus(ref outStatus, isAudioRendererActive); - } - - int currentOutputSize = _output.Length; - - OutputHeader.EffectsSize = (uint)(Unsafe.SizeOf() * context.GetCount()); - OutputHeader.TotalSize += OutputHeader.EffectsSize; - - Debug.Assert((initialOutputSize - currentOutputSize) == OutputHeader.EffectsSize); - - return ResultCode.Success; - } - - public ResultCode UpdateSplitter(SplitterContext context) - { - if (context.Update(_input.Span, out int consumedSize)) - { - _input = _input.Slice(consumedSize); - - return ResultCode.Success; - } - else - { - return ResultCode.InvalidUpdateInfo; - } - } - - private bool CheckMixParametersValidity(MixContext mixContext, uint mixBufferCount, uint inputMixCount, ReadOnlySpan parameters) - { - uint maxMixStateCount = mixContext.GetCount(); - uint totalRequiredMixBufferCount = 0; - - for (int i = 0; i < inputMixCount; i++) - { - if (parameters[i].IsUsed) - { - if (parameters[i].DestinationMixId != Constants.UnusedMixId && - parameters[i].DestinationMixId > maxMixStateCount && - parameters[i].MixId != Constants.FinalMixId) - { - return true; - } - - totalRequiredMixBufferCount += parameters[i].BufferCount; - } - } - - return totalRequiredMixBufferCount > mixBufferCount; - } - - public ResultCode UpdateMixes(MixContext mixContext, uint mixBufferCount, EffectContext effectContext, SplitterContext splitterContext) - { - uint mixCount; - uint inputMixSize; - uint inputSize = 0; - - if (_behaviourContext.IsMixInParameterDirtyOnlyUpdateSupported()) - { - MixInParameterDirtyOnlyUpdate parameter = MemoryMarshal.Cast(_input.Span)[0]; - - mixCount = parameter.MixCount; - - inputSize += (uint)Unsafe.SizeOf(); - } - else - { - mixCount = mixContext.GetCount(); - } - - inputMixSize = mixCount * (uint)Unsafe.SizeOf(); - - inputSize += inputMixSize; - - if (inputSize != _inputHeader.MixesSize) - { - return ResultCode.InvalidUpdateInfo; - } - - if (_behaviourContext.IsMixInParameterDirtyOnlyUpdateSupported()) - { - _input = _input.Slice(Unsafe.SizeOf()); - } - - ReadOnlySpan parameters = MemoryMarshal.Cast(_input.Span.Slice(0, (int)inputMixSize)); - - _input = _input.Slice((int)inputMixSize); - - if (CheckMixParametersValidity(mixContext, mixBufferCount, mixCount, parameters)) - { - return ResultCode.InvalidUpdateInfo; - } - - bool isMixContextDirty = false; - - for (int i = 0; i < parameters.Length; i++) - { - MixParameter parameter = parameters[i]; - - int mixId = i; - - if (_behaviourContext.IsMixInParameterDirtyOnlyUpdateSupported()) - { - mixId = parameter.MixId; - } - - ref MixState mix = ref mixContext.GetState(mixId); - - if (parameter.IsUsed != mix.IsUsed) - { - mix.IsUsed = parameter.IsUsed; - - if (parameter.IsUsed) - { - mix.ClearEffectProcessingOrder(); - } - - isMixContextDirty = true; - } - - if (mix.IsUsed) - { - isMixContextDirty |= mix.Update(mixContext.EdgeMatrix, ref parameter, effectContext, splitterContext, _behaviourContext); - } - } - - if (isMixContextDirty) - { - if (_behaviourContext.IsSplitterSupported() && splitterContext.UsingSplitter()) - { - if (!mixContext.Sort(splitterContext)) - { - return ResultCode.InvalidMixSorting; - } - } - else - { - mixContext.Sort(); - } - } - - return ResultCode.Success; - } - - private static void ResetSink(ref BaseSink sink, ref SinkInParameter parameter) - { - sink.CleanUp(); - - switch (parameter.Type) - { - case SinkType.Invalid: - sink = new BaseSink(); - break; - case SinkType.CircularBuffer: - sink = new CircularBufferSink(); - break; - case SinkType.Device: - sink = new DeviceSink(); - break; - default: - throw new NotImplementedException($"SinkType {parameter.Type} not implemented!"); - } - } - - public ResultCode UpdateSinks(SinkContext context, Memory memoryPools) - { - PoolMapper mapper = new PoolMapper(_processHandle, memoryPools, _behaviourContext.IsMemoryPoolForceMappingEnabled()); - - if (context.GetCount() * Unsafe.SizeOf() != _inputHeader.SinksSize) - { - return ResultCode.InvalidUpdateInfo; - } - - int initialOutputSize = _output.Length; - - ReadOnlySpan parameters = MemoryMarshal.Cast(_input.Slice(0, (int)_inputHeader.SinksSize).Span); - - _input = _input.Slice((int)_inputHeader.SinksSize); - - for (int i = 0; i < context.GetCount(); i++) - { - SinkInParameter parameter = parameters[i]; - ref SinkOutStatus outStatus = ref SpanIOHelper.GetWriteRef(ref _output)[0]; - ref BaseSink sink = ref context.GetSink(i); - - if (!sink.IsTypeValid(ref parameter)) - { - ResetSink(ref sink, ref parameter); - } - - sink.Update(out ErrorInfo updateErrorInfo, ref parameter, ref outStatus, mapper); - - if (updateErrorInfo.ErrorCode != ResultCode.Success) - { - _behaviourContext.AppendError(ref updateErrorInfo); - } - } - - int currentOutputSize = _output.Length; - - OutputHeader.SinksSize = (uint)(Unsafe.SizeOf() * context.GetCount()); - OutputHeader.TotalSize += OutputHeader.SinksSize; - - Debug.Assert((initialOutputSize - currentOutputSize) == OutputHeader.SinksSize); - - return ResultCode.Success; - } - - public ResultCode UpdatePerformanceBuffer(PerformanceManager manager, Span performanceOutput) - { - if (Unsafe.SizeOf() != _inputHeader.PerformanceBufferSize) - { - return ResultCode.InvalidUpdateInfo; - } - - PerformanceInParameter parameter = SpanIOHelper.Read(ref _input); - - ref PerformanceOutStatus outStatus = ref SpanIOHelper.GetWriteRef(ref _output)[0]; - - if (manager != null) - { - outStatus.HistorySize = manager.CopyHistories(performanceOutput); - - manager.SetTargetNodeId(parameter.TargetNodeId); - } - else - { - outStatus.HistorySize = 0; - } - - OutputHeader.PerformanceBufferSize = (uint)Unsafe.SizeOf(); - OutputHeader.TotalSize += OutputHeader.PerformanceBufferSize; - - return ResultCode.Success; - } - - public ResultCode UpdateErrorInfo() - { - ref BehaviourErrorInfoOutStatus outStatus = ref SpanIOHelper.GetWriteRef(ref _output)[0]; - - _behaviourContext.CopyErrorInfo(outStatus.ErrorInfos.AsSpan(), out outStatus.ErrorInfosCount); - - OutputHeader.BehaviourSize = (uint)Unsafe.SizeOf(); - OutputHeader.TotalSize += OutputHeader.BehaviourSize; - - return ResultCode.Success; - } - - public ResultCode UpdateRendererInfo(ulong elapsedFrameCount) - { - ref RendererInfoOutStatus outStatus = ref SpanIOHelper.GetWriteRef(ref _output)[0]; - - outStatus.ElapsedFrameCount = elapsedFrameCount; - - OutputHeader.RenderInfoSize = (uint)Unsafe.SizeOf(); - OutputHeader.TotalSize += OutputHeader.RenderInfoSize; - - return ResultCode.Success; - } - - public ResultCode CheckConsumedSize() - { - int consumedInputSize = _inputOrigin.Length - _input.Length; - int consumedOutputSize = _outputOrigin.Length - _output.Length; - - if (consumedInputSize != _inputHeader.TotalSize) - { - Logger.Error?.Print(LogClass.AudioRenderer, $"Consumed input size mismatch (got {consumedInputSize} expected {_inputHeader.TotalSize})"); - - return ResultCode.InvalidUpdateInfo; - } - - if (consumedOutputSize != OutputHeader.TotalSize) - { - Logger.Error?.Print(LogClass.AudioRenderer, $"Consumed output size mismatch (got {consumedOutputSize} expected {OutputHeader.TotalSize})"); - - return ResultCode.InvalidUpdateInfo; - } - - return ResultCode.Success; - } - } -} \ No newline at end of file diff --git a/Ryujinx.Audio/Renderer/Server/Types/PlayState.cs b/Ryujinx.Audio/Renderer/Server/Types/PlayState.cs deleted file mode 100644 index 25cc34a8f..000000000 --- a/Ryujinx.Audio/Renderer/Server/Types/PlayState.cs +++ /dev/null @@ -1,39 +0,0 @@ -namespace Ryujinx.Audio.Renderer.Server.Types -{ - /// - /// The internal play state of a - /// - public enum PlayState - { - /// - /// The voice has been started and is playing. - /// - Started, - - /// - /// The voice has been stopped. - /// - /// - /// This cannot be directly set by user. - /// See for correct usage. - /// - Stopped, - - /// - /// The user asked the voice to be stopped. - /// - /// - /// This is changed to the state after command generation. - /// - /// - Stopping, - - /// - /// The voice has been paused by user request. - /// - /// - /// The user can resume to the state. - /// - Paused - } -} \ No newline at end of file diff --git a/Ryujinx.Audio/Renderer/Server/Voice/WaveBuffer.cs b/Ryujinx.Audio/Renderer/Server/Voice/WaveBuffer.cs deleted file mode 100644 index 4bf7dd280..000000000 --- a/Ryujinx.Audio/Renderer/Server/Voice/WaveBuffer.cs +++ /dev/null @@ -1,104 +0,0 @@ -using Ryujinx.Audio.Renderer.Server.MemoryPool; -using System.Runtime.InteropServices; - -namespace Ryujinx.Audio.Renderer.Server.Voice -{ - /// - /// A wavebuffer used for server update. - /// - [StructLayout(LayoutKind.Sequential, Size = 0x58, Pack = 1)] - public struct WaveBuffer - { - /// - /// The of the sample data of the wavebuffer. - /// - public AddressInfo BufferAddressInfo; - - /// - /// The of the context of the wavebuffer. - /// - /// Only used by . - public AddressInfo ContextAddressInfo; - - - /// - /// First sample to play of the wavebuffer. - /// - public uint StartSampleOffset; - - /// - /// Last sample to play of the wavebuffer. - /// - public uint EndSampleOffset; - - /// - /// Set to true if the wavebuffer is looping. - /// - [MarshalAs(UnmanagedType.I1)] - public bool ShouldLoop; - - /// - /// Set to true if the wavebuffer is the end of stream. - /// - [MarshalAs(UnmanagedType.I1)] - public bool IsEndOfStream; - - /// - /// Set to true if the wavebuffer wasn't sent to the . - /// - [MarshalAs(UnmanagedType.I1)] - public bool IsSendToAudioProcessor; - - /// - /// First sample to play when looping the wavebuffer. - /// - public uint LoopStartSampleOffset; - - /// - /// Last sample to play when looping the wavebuffer. - /// - public uint LoopEndSampleOffset; - - /// - /// The max loop count. - /// - public int LoopCount; - - /// - /// Create a new for use by the . - /// - /// The target version of the wavebuffer. - /// A new for use by the . - public Common.WaveBuffer ToCommon(int version) - { - Common.WaveBuffer waveBuffer = new Common.WaveBuffer(); - - waveBuffer.Buffer = BufferAddressInfo.GetReference(true); - waveBuffer.BufferSize = (uint)BufferAddressInfo.Size; - - if (ContextAddressInfo.CpuAddress != 0) - { - waveBuffer.Context = ContextAddressInfo.GetReference(true); - waveBuffer.ContextSize = (uint)ContextAddressInfo.Size; - } - - waveBuffer.StartSampleOffset = StartSampleOffset; - waveBuffer.EndSampleOffset = EndSampleOffset; - waveBuffer.Looping = ShouldLoop; - waveBuffer.IsEndOfStream = IsEndOfStream; - - if (version == 2) - { - waveBuffer.LoopCount = LoopCount; - waveBuffer.LoopStartSampleOffset = LoopStartSampleOffset; - waveBuffer.LoopEndSampleOffset = LoopEndSampleOffset; - } - else - { - waveBuffer.LoopCount = -1; - } - - return waveBuffer; - } - } -} \ No newline at end of file diff --git a/Ryujinx.Audio/ResultCode.cs b/Ryujinx.Audio/ResultCode.cs deleted file mode 100644 index 8e0bfcb0c..000000000 --- a/Ryujinx.Audio/ResultCode.cs +++ /dev/null @@ -1,21 +0,0 @@ -namespace Ryujinx.Audio -{ - public enum ResultCode - { - ModuleId = 153, - ErrorCodeShift = 9, - - Success = 0, - - DeviceNotFound = (1 << ErrorCodeShift) | ModuleId, - OperationFailed = (2 << ErrorCodeShift) | ModuleId, - UnsupportedSampleRate = (3 << ErrorCodeShift) | ModuleId, - WorkBufferTooSmall = (4 << ErrorCodeShift) | ModuleId, - BufferRingFull = (8 << ErrorCodeShift) | ModuleId, - UnsupportedChannelConfiguration = (10 << ErrorCodeShift) | ModuleId, - InvalidUpdateInfo = (41 << ErrorCodeShift) | ModuleId, - InvalidAddressInfo = (42 << ErrorCodeShift) | ModuleId, - InvalidMixSorting = (43 << ErrorCodeShift) | ModuleId, - UnsupportedOperation = (513 << ErrorCodeShift) | ModuleId, - } -} \ No newline at end of file diff --git a/Ryujinx.Ava/App.axaml b/Ryujinx.Ava/App.axaml deleted file mode 100644 index eb9ffd865..000000000 --- a/Ryujinx.Ava/App.axaml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - \ No newline at end of file diff --git a/Ryujinx.Ava/App.axaml.cs b/Ryujinx.Ava/App.axaml.cs deleted file mode 100644 index 180c74b43..000000000 --- a/Ryujinx.Ava/App.axaml.cs +++ /dev/null @@ -1,151 +0,0 @@ -using Avalonia; -using Avalonia.Controls.ApplicationLifetimes; -using Avalonia.Markup.Xaml; -using Avalonia.Styling; -using Avalonia.Threading; -using FluentAvalonia.Styling; -using Ryujinx.Ava.Common.Locale; -using Ryujinx.Ava.Ui.Controls; -using Ryujinx.Ava.Ui.Windows; -using Ryujinx.Common; -using Ryujinx.Common.Logging; -using Ryujinx.Ui.Common.Configuration; -using System; -using System.Diagnostics; -using System.IO; - -namespace Ryujinx.Ava -{ - public class App : Application - { - public override void Initialize() - { - AvaloniaXamlLoader.Load(this); - } - - public override void OnFrameworkInitializationCompleted() - { - if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) - { - desktop.MainWindow = new MainWindow(); - } - - base.OnFrameworkInitializationCompleted(); - - if (Program.PreviewerDetached) - { - ApplyConfiguredTheme(); - - ConfigurationState.Instance.Ui.BaseStyle.Event += ThemeChanged_Event; - ConfigurationState.Instance.Ui.CustomThemePath.Event += ThemeChanged_Event; - ConfigurationState.Instance.Ui.EnableCustomTheme.Event += CustomThemeChanged_Event; - } - } - - private void CustomThemeChanged_Event(object sender, ReactiveEventArgs e) - { - ApplyConfiguredTheme(); - } - - private void ShowRestartDialog() - { -#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed - Dispatcher.UIThread.InvokeAsync(async () => - { - if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) - { - var result = await ContentDialogHelper.CreateConfirmationDialog( - LocaleManager.Instance["DialogThemeRestartMessage"], - LocaleManager.Instance["DialogThemeRestartSubMessage"], - LocaleManager.Instance["InputDialogYes"], - LocaleManager.Instance["InputDialogNo"], - LocaleManager.Instance["DialogRestartRequiredMessage"]); - - if (result == UserResult.Yes) - { - var path = Process.GetCurrentProcess().MainModule.FileName; - var info = new ProcessStartInfo() { FileName = path, UseShellExecute = false }; - var proc = Process.Start(info); - desktop.Shutdown(); - Environment.Exit(0); - } - } - }); -#pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed - } - - private void ThemeChanged_Event(object sender, ReactiveEventArgs e) - { - ApplyConfiguredTheme(); - } - - private void ApplyConfiguredTheme() - { - try - { - string baseStyle = ConfigurationState.Instance.Ui.BaseStyle; - string themePath = ConfigurationState.Instance.Ui.CustomThemePath; - bool enableCustomTheme = ConfigurationState.Instance.Ui.EnableCustomTheme; - - const string BaseStyleUrl = "avares://Ryujinx.Ava/Assets/Styles/Base{0}.xaml"; - - if (string.IsNullOrWhiteSpace(baseStyle)) - { - ConfigurationState.Instance.Ui.BaseStyle.Value = "Dark"; - - baseStyle = ConfigurationState.Instance.Ui.BaseStyle; - } - - var theme = AvaloniaLocator.Current.GetService(); - - theme.RequestedTheme = baseStyle; - - var currentStyles = this.Styles; - - // Remove all styles except the base style. - if (currentStyles.Count > 1) - { - currentStyles.RemoveRange(1, currentStyles.Count - 1); - } - - IStyle newStyles = null; - - // Load requested style, and fallback to Dark theme if loading failed. - try - { - newStyles = (Styles)AvaloniaXamlLoader.Load(new Uri(string.Format(BaseStyleUrl, baseStyle), UriKind.Absolute)); - } - catch (XamlLoadException) - { - newStyles = (Styles)AvaloniaXamlLoader.Load(new Uri(string.Format(BaseStyleUrl, "Dark"), UriKind.Absolute)); - } - - currentStyles.Add(newStyles); - - if (enableCustomTheme) - { - if (!string.IsNullOrWhiteSpace(themePath)) - { - try - { - var themeContent = File.ReadAllText(themePath); - var customStyle = AvaloniaRuntimeXamlLoader.Parse(themeContent); - - currentStyles.Add(customStyle); - } - catch (Exception ex) - { - Logger.Error?.Print(LogClass.Application, $"Failed to Apply Custom Theme. Error: {ex.Message}"); - } - } - } - } - catch (Exception) - { - Logger.Warning?.Print(LogClass.Application, "Failed to Apply Theme. A restart is needed to apply the selected theme"); - - ShowRestartDialog(); - } - } - } -} \ No newline at end of file diff --git a/Ryujinx.Ava/AppHost.cs b/Ryujinx.Ava/AppHost.cs deleted file mode 100644 index 320efeb5e..000000000 --- a/Ryujinx.Ava/AppHost.cs +++ /dev/null @@ -1,1075 +0,0 @@ -using ARMeilleure.Translation; -using ARMeilleure.Translation.PTC; -using Avalonia.Input; -using Avalonia.Threading; -using LibHac.Tools.FsSystem; -using Ryujinx.Audio.Backends.Dummy; -using Ryujinx.Audio.Backends.OpenAL; -using Ryujinx.Audio.Backends.SDL2; -using Ryujinx.Audio.Backends.SoundIo; -using Ryujinx.Audio.Integration; -using Ryujinx.Ava.Common; -using Ryujinx.Ava.Common.Locale; -using Ryujinx.Ava.Input; -using Ryujinx.Ava.Ui.Controls; -using Ryujinx.Ava.Ui.Models; -using Ryujinx.Ava.Ui.Windows; -using Ryujinx.Common; -using Ryujinx.Common.Configuration; -using Ryujinx.Common.Logging; -using Ryujinx.Common.System; -using Ryujinx.Graphics.GAL; -using Ryujinx.Graphics.GAL.Multithreading; -using Ryujinx.Graphics.Gpu; -using Ryujinx.Graphics.OpenGL; -using Ryujinx.Graphics.Vulkan; -using Ryujinx.HLE.FileSystem; -using Ryujinx.HLE.HOS; -using Ryujinx.HLE.HOS.Services.Account.Acc; -using Ryujinx.HLE.HOS.SystemState; -using Ryujinx.Input; -using Ryujinx.Input.HLE; -using Ryujinx.Ui.Common; -using Ryujinx.Ui.Common.Configuration; -using Ryujinx.Ui.Common.Helper; -using SixLabors.ImageSharp; -using SixLabors.ImageSharp.Formats.Png; -using SixLabors.ImageSharp.PixelFormats; -using SixLabors.ImageSharp.Processing; -using SPB.Graphics.Vulkan; -using System; -using System.Diagnostics; -using System.IO; -using System.Threading; -using System.Threading.Tasks; - -using InputManager = Ryujinx.Input.HLE.InputManager; -using Key = Ryujinx.Input.Key; -using MouseButton = Ryujinx.Input.MouseButton; -using Size = Avalonia.Size; -using Switch = Ryujinx.HLE.Switch; -using WindowState = Avalonia.Controls.WindowState; - -namespace Ryujinx.Ava -{ - internal class AppHost - { - private const int CursorHideIdleTime = 8; // Hide Cursor seconds - private const float MaxResolutionScale = 4.0f; // Max resolution hotkeys can scale to before wrapping. - private const int TargetFps = 60; - - private static readonly Cursor InvisibleCursor = new Cursor(StandardCursorType.None); - - private readonly long _ticksPerFrame; - private readonly Stopwatch _chrono; - private readonly AccountManager _accountManager; - private readonly UserChannelPersistence _userChannelPersistence; - private readonly InputManager _inputManager; - private readonly MainWindow _parent; - private readonly IKeyboard _keyboardInterface; - private readonly GraphicsDebugLevel _glLogLevel; - - private bool _hideCursorOnIdle; - private bool _isStopped; - private bool _isActive; - private long _lastCursorMoveTime; - private long _ticks = 0; - - private KeyboardHotkeyState _prevHotkeyState; - - private IRenderer _renderer; - private readonly Thread _renderingThread; - - private bool _isMouseInRenderer; - private bool _renderingStarted; - private bool _dialogShown; - - private WindowsMultimediaTimerResolution _windowsMultimediaTimerResolution; - - private readonly CancellationTokenSource _gpuCancellationTokenSource; - - public event EventHandler AppExit; - public event EventHandler StatusUpdatedEvent; - - public RendererHost Renderer { get; } - public VirtualFileSystem VirtualFileSystem { get; } - public ContentManager ContentManager { get; } - public Switch Device { get; set; } - public NpadManager NpadManager { get; } - public TouchScreenManager TouchScreenManager { get; } - - public int Width { get; private set; } - public int Height { get; private set; } - public string ApplicationPath { get; private set; } - - private bool _isFirmwareTitle; - - public bool ScreenshotRequested { get; set; } - - private object _lockObject = new(); - - public AppHost( - RendererHost renderer, - InputManager inputManager, - string applicationPath, - VirtualFileSystem virtualFileSystem, - ContentManager contentManager, - AccountManager accountManager, - UserChannelPersistence userChannelPersistence, - MainWindow parent) - { - _parent = parent; - _inputManager = inputManager; - _accountManager = accountManager; - _userChannelPersistence = userChannelPersistence; - _renderingThread = new Thread(RenderLoop) { Name = "GUI.RenderThread" }; - _hideCursorOnIdle = ConfigurationState.Instance.HideCursorOnIdle; - _lastCursorMoveTime = Stopwatch.GetTimestamp(); - _glLogLevel = ConfigurationState.Instance.Logger.GraphicsDebugLevel; - _inputManager.SetMouseDriver(new AvaloniaMouseDriver(_parent, renderer)); - _keyboardInterface = (IKeyboard)_inputManager.KeyboardDriver.GetGamepad("0"); - - NpadManager = _inputManager.CreateNpadManager(); - TouchScreenManager = _inputManager.CreateTouchScreenManager(); - Renderer = renderer; - ApplicationPath = applicationPath; - VirtualFileSystem = virtualFileSystem; - ContentManager = contentManager; - - _chrono = new Stopwatch(); - _ticksPerFrame = Stopwatch.Frequency / TargetFps; - - if (ApplicationPath.StartsWith("@SystemContent")) - { - ApplicationPath = _parent.VirtualFileSystem.SwitchPathToSystemPath(ApplicationPath); - - _isFirmwareTitle = true; - } - - ConfigurationState.Instance.HideCursorOnIdle.Event += HideCursorState_Changed; - - _parent.PointerLeave += Parent_PointerLeft; - _parent.PointerMoved += Parent_PointerMoved; - - ConfigurationState.Instance.System.IgnoreMissingServices.Event += UpdateIgnoreMissingServicesState; - ConfigurationState.Instance.Graphics.AspectRatio.Event += UpdateAspectRatioState; - ConfigurationState.Instance.System.EnableDockedMode.Event += UpdateDockedModeState; - ConfigurationState.Instance.System.AudioVolume.Event += UpdateAudioVolumeState; - - _gpuCancellationTokenSource = new CancellationTokenSource(); - } - - private void Parent_PointerMoved(object sender, PointerEventArgs e) - { - _lastCursorMoveTime = Stopwatch.GetTimestamp(); - var p = e.GetCurrentPoint(_parent).Position; - var r = _parent.InputHitTest(p); - _isMouseInRenderer = r == Renderer; - } - - private void Parent_PointerLeft(object sender, PointerEventArgs e) - { - _isMouseInRenderer = false; - _parent.Cursor = Cursor.Default; - } - - private void SetRendererWindowSize(Size size) - { - if (_renderer != null) - { - double scale = _parent.PlatformImpl.RenderScaling; - _renderer.Window?.SetSize((int)(size.Width * scale), (int)(size.Height * scale)); - } - } - - private unsafe void Renderer_ScreenCaptured(object sender, ScreenCaptureImageInfo e) - { - if (e.Data.Length > 0 && e.Height > 0 && e.Width > 0) - { - Task.Run(() => - { - lock (_lockObject) - { - var currentTime = DateTime.Now; - string filename = $"ryujinx_capture_{currentTime.Year}-{currentTime.Month:D2}-{currentTime.Day:D2}_{currentTime.Hour:D2}-{currentTime.Minute:D2}-{currentTime.Second:D2}.png"; - string directory = AppDataManager.Mode switch - { - AppDataManager.LaunchMode.Portable => Path.Combine(AppDataManager.BaseDirPath, "screenshots"), - _ => Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyPictures), "Ryujinx") - }; - - string path = Path.Combine(directory, filename); - - try - { - Directory.CreateDirectory(directory); - } - catch (Exception ex) - { - Logger.Error?.Print(LogClass.Application, $"Failed to create directory at path {directory}. Error : {ex.GetType().Name}", "Screenshot"); - - return; - } - - Image image = e.IsBgra ? Image.LoadPixelData(e.Data, e.Width, e.Height) - : Image.LoadPixelData(e.Data, e.Width, e.Height); - - if (e.FlipX) - { - image.Mutate(x => x.Flip(FlipMode.Horizontal)); - } - - if (e.FlipY) - { - image.Mutate(x => x.Flip(FlipMode.Vertical)); - } - - image.SaveAsPng(path, new PngEncoder() - { - ColorType = PngColorType.Rgb - }); - - image.Dispose(); - - Logger.Notice.Print(LogClass.Application, $"Screenshot saved to {path}", "Screenshot"); - } - }); - } - else - { - Logger.Error?.Print(LogClass.Application, $"Screenshot is empty. Size : {e.Data.Length} bytes. Resolution : {e.Width}x{e.Height}", "Screenshot"); - } - } - - public void Start() - { - if (OperatingSystem.IsWindows()) - { - _windowsMultimediaTimerResolution = new WindowsMultimediaTimerResolution(1); - } - - DisplaySleep.Prevent(); - - NpadManager.Initialize(Device, ConfigurationState.Instance.Hid.InputConfig, ConfigurationState.Instance.Hid.EnableKeyboard, ConfigurationState.Instance.Hid.EnableMouse); - TouchScreenManager.Initialize(Device); - - _parent.ViewModel.IsGameRunning = true; - - string titleNameSection = string.IsNullOrWhiteSpace(Device.Application.TitleName) - ? string.Empty - : $" - {Device.Application.TitleName}"; - - string titleVersionSection = string.IsNullOrWhiteSpace(Device.Application.DisplayVersion) - ? string.Empty - : $" v{Device.Application.DisplayVersion}"; - - string titleIdSection = string.IsNullOrWhiteSpace(Device.Application.TitleIdText) - ? string.Empty - : $" ({Device.Application.TitleIdText.ToUpper()})"; - - string titleArchSection = Device.Application.TitleIs64Bit - ? " (64-bit)" - : " (32-bit)"; - - Dispatcher.UIThread.InvokeAsync(() => - { - _parent.Title = $"Ryujinx {Program.Version}{titleNameSection}{titleVersionSection}{titleIdSection}{titleArchSection}"; - }); - - _parent.ViewModel.HandleShaderProgress(Device); - - Renderer.SizeChanged += Window_SizeChanged; - - _isActive = true; - - _renderingThread.Start(); - - _parent.ViewModel.Volume = ConfigurationState.Instance.System.AudioVolume.Value; - - MainLoop(); - - Exit(); - } - - private void UpdateIgnoreMissingServicesState(object sender, ReactiveEventArgs args) - { - if (Device != null) - { - Device.Configuration.IgnoreMissingServices = args.NewValue; - } - } - - private void UpdateAspectRatioState(object sender, ReactiveEventArgs args) - { - if (Device != null) - { - Device.Configuration.AspectRatio = args.NewValue; - } - } - - private void UpdateDockedModeState(object sender, ReactiveEventArgs e) - { - Device?.System.ChangeDockedModeState(e.NewValue); - } - - private void UpdateAudioVolumeState(object sender, ReactiveEventArgs e) - { - Device?.SetVolume(e.NewValue); - Dispatcher.UIThread.Post(() => - { - var value = e.NewValue; - _parent.ViewModel.Volume = e.NewValue; - }); - } - - public void Stop() - { - _isActive = false; - } - - private void Exit() - { - (_keyboardInterface as AvaloniaKeyboard)?.Clear(); - - if (_isStopped) - { - return; - } - - _isStopped = true; - _isActive = false; - } - - public void DisposeContext() - { - Dispose(); - - _isActive = false; - - _renderingThread.Join(); - - DisplaySleep.Restore(); - - Ptc.Close(); - PtcProfiler.Stop(); - NpadManager.Dispose(); - TouchScreenManager.Dispose(); - Device.Dispose(); - - DisposeGpu(); - - AppExit?.Invoke(this, EventArgs.Empty); - } - - private void Dispose() - { - if (Device.Application != null) - { - _parent.UpdateGameMetadata(Device.Application.TitleIdText); - } - - ConfigurationState.Instance.System.IgnoreMissingServices.Event -= UpdateIgnoreMissingServicesState; - ConfigurationState.Instance.Graphics.AspectRatio.Event -= UpdateAspectRatioState; - ConfigurationState.Instance.System.EnableDockedMode.Event -= UpdateDockedModeState; - ConfigurationState.Instance.System.AudioVolume.Event -= UpdateAudioVolumeState; - - _gpuCancellationTokenSource.Cancel(); - _gpuCancellationTokenSource.Dispose(); - - _chrono.Stop(); - } - - public void DisposeGpu() - { - if (OperatingSystem.IsWindows()) - { - _windowsMultimediaTimerResolution?.Dispose(); - _windowsMultimediaTimerResolution = null; - } - - Renderer?.MakeCurrent(); - - Device.DisposeGpu(); - - Renderer?.MakeCurrent(null); - } - - private void HideCursorState_Changed(object sender, ReactiveEventArgs state) - { - Dispatcher.UIThread.InvokeAsync(delegate - { - _hideCursorOnIdle = state.NewValue; - - if (_hideCursorOnIdle) - { - _lastCursorMoveTime = Stopwatch.GetTimestamp(); - } - else - { - _parent.Cursor = Cursor.Default; - } - }); - } - - public async Task LoadGuestApplication() - { - InitializeSwitchInstance(); - - MainWindow.UpdateGraphicsConfig(); - - SystemVersion firmwareVersion = ContentManager.GetCurrentFirmwareVersion(); - - if (!SetupValidator.CanStartApplication(ContentManager, ApplicationPath, out UserError userError)) - { - if (SetupValidator.CanFixStartApplication(ContentManager, ApplicationPath, userError, out firmwareVersion)) - { - if (userError == UserError.NoFirmware) - { - string message = string.Format(LocaleManager.Instance["DialogFirmwareInstallEmbeddedMessage"], - firmwareVersion.VersionString); - - UserResult result = await ContentDialogHelper.CreateConfirmationDialog( - LocaleManager.Instance["DialogFirmwareNoFirmwareInstalledMessage"], message, - LocaleManager.Instance["InputDialogYes"], LocaleManager.Instance["InputDialogNo"], ""); - - if (result != UserResult.Yes) - { - Dispatcher.UIThread.Post(async () => await - UserErrorDialog.ShowUserErrorDialog(userError, _parent)); - Device.Dispose(); - - return false; - } - } - - if (!SetupValidator.TryFixStartApplication(ContentManager, ApplicationPath, userError, out _)) - { - Dispatcher.UIThread.Post(async () => await - UserErrorDialog.ShowUserErrorDialog(userError, _parent)); - Device.Dispose(); - - return false; - } - - // Tell the user that we installed a firmware for them. - if (userError == UserError.NoFirmware) - { - firmwareVersion = ContentManager.GetCurrentFirmwareVersion(); - - _parent.RefreshFirmwareStatus(); - - string message = string.Format(LocaleManager.Instance["DialogFirmwareInstallEmbeddedSuccessMessage"], firmwareVersion.VersionString); - - await ContentDialogHelper.CreateInfoDialog( - string.Format(LocaleManager.Instance["DialogFirmwareInstalledMessage"], firmwareVersion.VersionString), - message, - LocaleManager.Instance["InputDialogOk"], - "", - LocaleManager.Instance["RyujinxInfo"]); - } - } - else - { - Dispatcher.UIThread.Post(async () => await - UserErrorDialog.ShowUserErrorDialog(userError, _parent)); - - Device.Dispose(); - - return false; - } - } - - Logger.Notice.Print(LogClass.Application, $"Using Firmware Version: {firmwareVersion?.VersionString}"); - - if (_isFirmwareTitle) - { - Logger.Info?.Print(LogClass.Application, "Loading as Firmware Title (NCA)."); - - Device.LoadNca(ApplicationPath); - } - else if (Directory.Exists(ApplicationPath)) - { - string[] romFsFiles = Directory.GetFiles(ApplicationPath, "*.istorage"); - - if (romFsFiles.Length == 0) - { - romFsFiles = Directory.GetFiles(ApplicationPath, "*.romfs"); - } - - if (romFsFiles.Length > 0) - { - Logger.Info?.Print(LogClass.Application, "Loading as cart with RomFS."); - - Device.LoadCart(ApplicationPath, romFsFiles[0]); - } - else - { - Logger.Info?.Print(LogClass.Application, "Loading as cart WITHOUT RomFS."); - - Device.LoadCart(ApplicationPath); - } - } - else if (File.Exists(ApplicationPath)) - { - switch (System.IO.Path.GetExtension(ApplicationPath).ToLowerInvariant()) - { - case ".xci": - { - Logger.Info?.Print(LogClass.Application, "Loading as XCI."); - - Device.LoadXci(ApplicationPath); - - break; - } - case ".nca": - { - Logger.Info?.Print(LogClass.Application, "Loading as NCA."); - - Device.LoadNca(ApplicationPath); - - break; - } - case ".nsp": - case ".pfs0": - { - Logger.Info?.Print(LogClass.Application, "Loading as NSP."); - - Device.LoadNsp(ApplicationPath); - - break; - } - default: - { - Logger.Info?.Print(LogClass.Application, "Loading as homebrew."); - - try - { - Device.LoadProgram(ApplicationPath); - } - catch (ArgumentOutOfRangeException) - { - Logger.Error?.Print(LogClass.Application, "The specified file is not supported by Ryujinx."); - - Dispose(); - - return false; - } - - break; - } - } - } - else - { - Logger.Warning?.Print(LogClass.Application, "Please specify a valid XCI/NCA/NSP/PFS0/NRO file."); - - Dispose(); - - return false; - } - - DiscordIntegrationModule.SwitchToPlayingState(Device.Application.TitleIdText, Device.Application.TitleName); - - _parent.ApplicationLibrary.LoadAndSaveMetaData(Device.Application.TitleIdText, appMetadata => - { - appMetadata.LastPlayed = DateTime.UtcNow.ToString(); - }); - - return true; - } - - internal void Resume() - { - Device?.System.TogglePauseEmulation(false); - _parent.ViewModel.IsPaused = false; - } - - internal void Pause() - { - Device?.System.TogglePauseEmulation(true); - _parent.ViewModel.IsPaused = true; - } - - private void InitializeSwitchInstance() - { - VirtualFileSystem.ReloadKeySet(); - - IRenderer renderer; - - if (Renderer.IsVulkan) - { - string preferredGpu = ConfigurationState.Instance.Graphics.PreferredGpu.Value; - - renderer = new VulkanRenderer(Renderer.CreateVulkanSurface, VulkanHelper.GetRequiredInstanceExtensions, preferredGpu); - } - else - { - renderer = new OpenGLRenderer(); - } - - IHardwareDeviceDriver deviceDriver = new DummyHardwareDeviceDriver(); - - BackendThreading threadingMode = ConfigurationState.Instance.Graphics.BackendThreading; - - var isGALthreaded = threadingMode == BackendThreading.On || (threadingMode == BackendThreading.Auto && renderer.PreferThreading); - - if (isGALthreaded) - { - renderer = new ThreadedRenderer(renderer); - } - - Logger.Info?.PrintMsg(LogClass.Gpu, $"Backend Threading ({threadingMode}): {isGALthreaded}"); - - if (ConfigurationState.Instance.System.AudioBackend.Value == AudioBackend.SDL2) - { - if (SDL2HardwareDeviceDriver.IsSupported) - { - deviceDriver = new SDL2HardwareDeviceDriver(); - } - else - { - Logger.Warning?.Print(LogClass.Audio, "SDL2 is not supported, trying to fall back to OpenAL."); - - if (OpenALHardwareDeviceDriver.IsSupported) - { - Logger.Warning?.Print(LogClass.Audio, "Found OpenAL, changing configuration."); - - ConfigurationState.Instance.System.AudioBackend.Value = AudioBackend.OpenAl; - MainWindow.SaveConfig(); - - deviceDriver = new OpenALHardwareDeviceDriver(); - } - else - { - Logger.Warning?.Print(LogClass.Audio, "OpenAL is not supported, trying to fall back to SoundIO."); - - if (SoundIoHardwareDeviceDriver.IsSupported) - { - Logger.Warning?.Print(LogClass.Audio, "Found SoundIO, changing configuration."); - - ConfigurationState.Instance.System.AudioBackend.Value = AudioBackend.SoundIo; - MainWindow.SaveConfig(); - - deviceDriver = new SoundIoHardwareDeviceDriver(); - } - else - { - Logger.Warning?.Print(LogClass.Audio, "SoundIO is not supported, falling back to dummy audio out."); - } - } - } - } - else if (ConfigurationState.Instance.System.AudioBackend.Value == AudioBackend.SoundIo) - { - if (SoundIoHardwareDeviceDriver.IsSupported) - { - deviceDriver = new SoundIoHardwareDeviceDriver(); - } - else - { - Logger.Warning?.Print(LogClass.Audio, "SoundIO is not supported, trying to fall back to SDL2."); - - if (SDL2HardwareDeviceDriver.IsSupported) - { - Logger.Warning?.Print(LogClass.Audio, "Found SDL2, changing configuration."); - - ConfigurationState.Instance.System.AudioBackend.Value = AudioBackend.SDL2; - MainWindow.SaveConfig(); - - deviceDriver = new SDL2HardwareDeviceDriver(); - } - else - { - Logger.Warning?.Print(LogClass.Audio, "SDL2 is not supported, trying to fall back to OpenAL."); - - if (OpenALHardwareDeviceDriver.IsSupported) - { - Logger.Warning?.Print(LogClass.Audio, "Found OpenAL, changing configuration."); - - ConfigurationState.Instance.System.AudioBackend.Value = AudioBackend.OpenAl; - MainWindow.SaveConfig(); - - deviceDriver = new OpenALHardwareDeviceDriver(); - } - else - { - Logger.Warning?.Print(LogClass.Audio, "OpenAL is not supported, falling back to dummy audio out."); - } - } - } - } - else if (ConfigurationState.Instance.System.AudioBackend.Value == AudioBackend.OpenAl) - { - if (OpenALHardwareDeviceDriver.IsSupported) - { - deviceDriver = new OpenALHardwareDeviceDriver(); - } - else - { - Logger.Warning?.Print(LogClass.Audio, "OpenAL is not supported, trying to fall back to SDL2."); - - if (SDL2HardwareDeviceDriver.IsSupported) - { - Logger.Warning?.Print(LogClass.Audio, "Found SDL2, changing configuration."); - - ConfigurationState.Instance.System.AudioBackend.Value = AudioBackend.SDL2; - MainWindow.SaveConfig(); - - deviceDriver = new SDL2HardwareDeviceDriver(); - } - else - { - Logger.Warning?.Print(LogClass.Audio, "SDL2 is not supported, trying to fall back to SoundIO."); - - if (SoundIoHardwareDeviceDriver.IsSupported) - { - Logger.Warning?.Print(LogClass.Audio, "Found SoundIO, changing configuration."); - - ConfigurationState.Instance.System.AudioBackend.Value = AudioBackend.SoundIo; - MainWindow.SaveConfig(); - - deviceDriver = new SoundIoHardwareDeviceDriver(); - } - else - { - Logger.Warning?.Print(LogClass.Audio, "SoundIO is not supported, falling back to dummy audio out."); - } - } - } - } - - var memoryConfiguration = ConfigurationState.Instance.System.ExpandRam.Value ? HLE.MemoryConfiguration.MemoryConfiguration6GB : HLE.MemoryConfiguration.MemoryConfiguration4GB; - - IntegrityCheckLevel fsIntegrityCheckLevel = ConfigurationState.Instance.System.EnableFsIntegrityChecks ? IntegrityCheckLevel.ErrorOnInvalid : IntegrityCheckLevel.None; - - HLE.HLEConfiguration configuration = new HLE.HLEConfiguration(VirtualFileSystem, - _parent.LibHacHorizonManager, - ContentManager, - _accountManager, - _userChannelPersistence, - renderer, - deviceDriver, - memoryConfiguration, - _parent.UiHandler, - (SystemLanguage)ConfigurationState.Instance.System.Language.Value, - (RegionCode)ConfigurationState.Instance.System.Region.Value, - ConfigurationState.Instance.Graphics.EnableVsync, - ConfigurationState.Instance.System.EnableDockedMode, - ConfigurationState.Instance.System.EnablePtc, - ConfigurationState.Instance.System.EnableInternetAccess, - fsIntegrityCheckLevel, - ConfigurationState.Instance.System.FsGlobalAccessLogMode, - ConfigurationState.Instance.System.SystemTimeOffset, - ConfigurationState.Instance.System.TimeZone, - ConfigurationState.Instance.System.MemoryManagerMode, - ConfigurationState.Instance.System.IgnoreMissingServices, - ConfigurationState.Instance.Graphics.AspectRatio, - ConfigurationState.Instance.System.AudioVolume); - - Device = new Switch(configuration); - } - - private void Window_SizeChanged(object sender, Size e) - { - Width = (int)e.Width; - Height = (int)e.Height; - SetRendererWindowSize(e); - } - - private void MainLoop() - { - while (_isActive) - { - UpdateFrame(); - - // Polling becomes expensive if it's not slept - Thread.Sleep(1); - } - } - - private unsafe void RenderLoop() - { - Dispatcher.UIThread.InvokeAsync(() => - { - if (_parent.ViewModel.StartGamesInFullscreen) - { - _parent.WindowState = WindowState.FullScreen; - } - - if (_parent.WindowState == WindowState.FullScreen) - { - _parent.ViewModel.ShowMenuAndStatusBar = false; - } - }); - - IRenderer renderer = Device.Gpu.Renderer; - - if (renderer is ThreadedRenderer tr) - { - renderer = tr.BaseRenderer; - } - - _renderer = renderer; - - _renderer.ScreenCaptured += Renderer_ScreenCaptured; - - (_renderer as OpenGLRenderer)?.InitializeBackgroundContext(SPBOpenGLContext.CreateBackgroundContext(Renderer.GetContext())); - - Renderer.MakeCurrent(); - - Device.Gpu.Renderer.Initialize(_glLogLevel); - - Width = (int)Renderer.Bounds.Width; - Height = (int)Renderer.Bounds.Height; - - _renderer.Window.SetSize((int)(Width * _parent.PlatformImpl.RenderScaling), (int)(Height * _parent.PlatformImpl.RenderScaling)); - - _chrono.Start(); - - Device.Gpu.Renderer.RunLoop(() => - { - Device.Gpu.SetGpuThread(); - Device.Gpu.InitializeShaderCache(_gpuCancellationTokenSource.Token); - Translator.IsReadyForTranslation.Set(); - - while (_isActive) - { - _ticks += _chrono.ElapsedTicks; - - _chrono.Restart(); - - if (Device.WaitFifo()) - { - Device.Statistics.RecordFifoStart(); - Device.ProcessFrame(); - Device.Statistics.RecordFifoEnd(); - } - - while (Device.ConsumeFrameAvailable()) - { - if (!_renderingStarted) - { - _renderingStarted = true; - _parent.SwitchToGameControl(); - } - - Device.PresentFrame(() => Renderer?.SwapBuffers()); - } - - if (_ticks >= _ticksPerFrame) - { - UpdateStatus(); - } - } - }); - - Renderer?.MakeCurrent(null); - } - - public void UpdateStatus() - { - // Run a status update only when a frame is to be drawn. This prevents from updating the ui and wasting a render when no frame is queued - string dockedMode = ConfigurationState.Instance.System.EnableDockedMode ? LocaleManager.Instance["Docked"] : LocaleManager.Instance["Handheld"]; - float scale = GraphicsConfig.ResScale; - - if (scale != 1) - { - dockedMode += $" ({scale}x)"; - } - - StatusUpdatedEvent?.Invoke(this, new StatusUpdatedEventArgs( - Device.EnableDeviceVsync, - LocaleManager.Instance["VolumeShort"] + $": {(int)(Device.GetVolume() * 100)}%", - Renderer.IsVulkan ? "Vulkan" : "OpenGL", - dockedMode, - ConfigurationState.Instance.Graphics.AspectRatio.Value.ToText(), - LocaleManager.Instance["Game"] + $": {Device.Statistics.GetGameFrameRate():00.00} FPS ({Device.Statistics.GetGameFrameTime():00.00} ms)", - $"FIFO: {Device.Statistics.GetFifoPercent():00.00} %", - $"GPU: {_renderer.GetHardwareInfo().GpuVendor}")); - } - - public async Task ShowExitPrompt() - { - bool shouldExit = !ConfigurationState.Instance.ShowConfirmExit; - - if (!shouldExit) - { - if (_dialogShown) - { - return; - } - - _dialogShown = true; - shouldExit = await ContentDialogHelper.CreateStopEmulationDialog(); - - _dialogShown = false; - } - - if (shouldExit) - { - Stop(); - } - } - - private void HandleScreenState() - { - if (ConfigurationState.Instance.Hid.EnableMouse) - { - Dispatcher.UIThread.Post(() => - { - _parent.Cursor = _isMouseInRenderer ? InvisibleCursor : Cursor.Default; - }); - } - else - { - if (_hideCursorOnIdle) - { - long cursorMoveDelta = Stopwatch.GetTimestamp() - _lastCursorMoveTime; - - Dispatcher.UIThread.Post(() => - { - _parent.Cursor = cursorMoveDelta >= CursorHideIdleTime * Stopwatch.Frequency ? InvisibleCursor : Cursor.Default; - }); - } - } - } - - private bool UpdateFrame() - { - if (!_isActive) - { - return false; - } - - if (_parent.IsActive) - { - Dispatcher.UIThread.Post(() => - { - HandleScreenState(); - - if (_keyboardInterface.GetKeyboardStateSnapshot().IsPressed(Key.Delete) && _parent.WindowState != WindowState.FullScreen) - { - Ptc.Continue(); - } - }); - } - - NpadManager.Update(ConfigurationState.Instance.Graphics.AspectRatio.Value.ToFloat()); - - if (_parent.IsActive) - { - KeyboardHotkeyState currentHotkeyState = GetHotkeyState(); - - if (currentHotkeyState != _prevHotkeyState) - { - switch (currentHotkeyState) - { - case KeyboardHotkeyState.ToggleVSync: - Device.EnableDeviceVsync = !Device.EnableDeviceVsync; - - break; - case KeyboardHotkeyState.Screenshot: - ScreenshotRequested = true; - break; - case KeyboardHotkeyState.ShowUi: - _parent.ViewModel.ShowMenuAndStatusBar = true; - break; - case KeyboardHotkeyState.Pause: - if (_parent.ViewModel.IsPaused) - { - Resume(); - } - else - { - Pause(); - } - break; - case KeyboardHotkeyState.ToggleMute: - if (Device.IsAudioMuted()) - { - Device.SetVolume(ConfigurationState.Instance.System.AudioVolume); - } - else - { - Device.SetVolume(0); - } - - _parent.ViewModel.Volume = Device.GetVolume(); - break; - case KeyboardHotkeyState.ResScaleUp: - GraphicsConfig.ResScale = GraphicsConfig.ResScale % MaxResolutionScale + 1; - break; - case KeyboardHotkeyState.ResScaleDown: - GraphicsConfig.ResScale = - (MaxResolutionScale + GraphicsConfig.ResScale - 2) % MaxResolutionScale + 1; - break; - case KeyboardHotkeyState.None: - (_keyboardInterface as AvaloniaKeyboard).Clear(); - break; - } - } - - _prevHotkeyState = currentHotkeyState; - - if (ScreenshotRequested) - { - ScreenshotRequested = false; - _renderer.Screenshot(); - } - } - - // Touchscreen - bool hasTouch = false; - - if (_parent.IsActive && !ConfigurationState.Instance.Hid.EnableMouse) - { - hasTouch = TouchScreenManager.Update(true, (_inputManager.MouseDriver as AvaloniaMouseDriver).IsButtonPressed(MouseButton.Button1), ConfigurationState.Instance.Graphics.AspectRatio.Value.ToFloat()); - } - - if (!hasTouch) - { - Device.Hid.Touchscreen.Update(); - } - - Device.Hid.DebugPad.Update(); - - return true; - } - - private KeyboardHotkeyState GetHotkeyState() - { - KeyboardHotkeyState state = KeyboardHotkeyState.None; - - if (_keyboardInterface.IsPressed((Key)ConfigurationState.Instance.Hid.Hotkeys.Value.ToggleVsync)) - { - state = KeyboardHotkeyState.ToggleVSync; - } - else if (_keyboardInterface.IsPressed((Key)ConfigurationState.Instance.Hid.Hotkeys.Value.Screenshot)) - { - state = KeyboardHotkeyState.Screenshot; - } - else if (_keyboardInterface.IsPressed((Key)ConfigurationState.Instance.Hid.Hotkeys.Value.ShowUi)) - { - state = KeyboardHotkeyState.ShowUi; - } - else if (_keyboardInterface.IsPressed((Key)ConfigurationState.Instance.Hid.Hotkeys.Value.Pause)) - { - state = KeyboardHotkeyState.Pause; - } - else if (_keyboardInterface.IsPressed((Key)ConfigurationState.Instance.Hid.Hotkeys.Value.ToggleMute)) - { - state = KeyboardHotkeyState.ToggleMute; - } - else if (_keyboardInterface.IsPressed((Key)ConfigurationState.Instance.Hid.Hotkeys.Value.ResScaleUp)) - { - state = KeyboardHotkeyState.ResScaleUp; - } - else if (_keyboardInterface.IsPressed((Key)ConfigurationState.Instance.Hid.Hotkeys.Value.ResScaleDown)) - { - state = KeyboardHotkeyState.ResScaleDown; - } - - return state; - } - } -} \ No newline at end of file diff --git a/Ryujinx.Ava/Assets/Locales/fr_FR.json b/Ryujinx.Ava/Assets/Locales/fr_FR.json deleted file mode 100644 index 2cd5cfd2f..000000000 --- a/Ryujinx.Ava/Assets/Locales/fr_FR.json +++ /dev/null @@ -1,272 +0,0 @@ -{ - "MenuBarFile": "_Fichier", - "MenuBarFileOpenFromFile": "_Charger un jeu depuis un fichier", - "MenuBarFileOpenUnpacked": "Charger un jeu _extrait", - "MenuBarFileOpenEmuFolder": "Ouvrir le dossier Ryujinx", - "MenuBarFileOpenLogsFolder": "Ouvrir le dossier de Logs", - "MenuBarFileExit": "_Quitter", - "MenuBarOptions": "Options", - "MenuBarOptionsToggleFullscreen": "Basculer en plein écran", - "MenuBarOptionsStartGamesInFullscreen": "Démarrer le jeu en plein écran", - "MenuBarOptionsStopEmulation": "Arrêter l'émulation", - "MenuBarOptionsSettings": "_Paramètres", - "MenuBarOptionsManageUserProfiles": "_Gêrer les profils d'utilisateurs", - "MenuBarActions": "_Actions", - "MenuBarOptionsSimulateWakeUpMessage": "Simuler une sortie de veille", - "MenuBarActionsScanAmiibo": "Scanner un Amiibo", - "MenuBarTools": "_Outils", - "MenuBarToolsInstallFirmware": "Installer un firmware", - "MenuBarFileToolsInstallFirmwareFromFile": "Installer un firmware depuis un fichier XCI ou ZIP", - "MenuBarFileToolsInstallFirmwareFromDirectory": "Installer un firmware depuis un dossier", - "MenuBarHelp": "Aide", - "MenuBarHelpCheckForUpdates": "Vérifier les mises à jour", - "MenuBarHelpAbout": "Á propos", - "MenuSearch": "Rechercher...", - "GameListHeaderFavorite": "Favoris", - "GameListHeaderIcon": "Icône", - "GameListHeaderApplication": "Application", - "GameListHeaderDeveloper": "Développeur", - "GameListHeaderVersion": "Version", - "GameListHeaderTimePlayed": "Temps de jeu", - "GameListHeaderLastPlayed": "Dernière partie", - "GameListHeaderFileExtension": "Extension du Fichier", - "GameListHeaderFileSize": "Taille du Fichier", - "GameListHeaderPath": "Chemin", - "GameListContextMenuOpenUserSaveDirectory": "Ouvrir le dossier de sauvegarde utilisateur", - "GameListContextMenuOpenUserSaveDirectoryToolTip": "Ouvre le dossier contenant la sauvegarde utilisateur du jeu", - "GameListContextMenuOpenUserDeviceDirectory": "Ouvrir le dossier de sauvegarde console", - "GameListContextMenuOpenUserDeviceDirectoryToolTip": "Ouvre le dossier contenant la sauvegarde console du jeu", - "GameListContextMenuOpenUserBcatDirectory": "Ouvrir le dossier de sauvegarde BCAT", - "GameListContextMenuOpenUserBcatDirectoryToolTip": "Ouvre le dossier contenant la sauvegarde BCAT du jeu", - "GameListContextMenuManageTitleUpdates": "Gérer les mises à jour", - "GameListContextMenuManageTitleUpdatesToolTip": "Ouvre la fenêtre de gestion des mises à jour", - "GameListContextMenuManageDlc": "Gérer les DLC", - "GameListContextMenuManageDlcToolTip": "Ouvre la fenêtre de gestion des DLC", - "GameListContextMenuOpenModsDirectory": "Ouvrir le dossier des Mods", - "GameListContextMenuOpenModsDirectoryToolTip": "Ouvre le dossier contenant les mods du jeu", - "GameListContextMenuCacheManagement": "Gestion des caches", - "GameListContextMenuCacheManagementPurgePptc": "Purger le PPTC", - "GameListContextMenuCacheManagementPurgePptcToolTip": "Supprime le PPTC du jeu", - "GameListContextMenuCacheManagementPurgeShaderCache": "Purger le cache des Shaders", - "GameListContextMenuCacheManagementPurgeShaderCacheToolTip": "Supprime le cache des shaders du jeu", - "GameListContextMenuCacheManagementOpenPptcDirectory": "Ouvrir le dossier du PPTC", - "GameListContextMenuCacheManagementOpenPptcDirectoryToolTip": "Ouvre le dossier contenant le PPTC du jeu", - "GameListContextMenuCacheManagementOpenShaderCacheDirectory": "Ouvrir le dossier du cache des shaders", - "GameListContextMenuCacheManagementOpenShaderCacheDirectoryToolTip": "Ouvre le dossier contenant le cache des shaders du jeu", - "GameListContextMenuExtractData": "Extraire les données", - "GameListContextMenuExtractDataExeFS": "ExeFS", - "GameListContextMenuExtractDataExeFSToolTip": "Extrait la section ExeFS du jeu (mise à jour incluse)", - "GameListContextMenuExtractDataRomFS": "RomFS", - "GameListContextMenuExtractDataRomFSToolTip": "Extrait la section RomFS du jeu (mise à jour incluse)", - "GameListContextMenuExtractDataLogo": "Logo", - "GameListContextMenuExtractDataLogoToolTip": "Extrait la section Logo du jeu (mise à jour incluse)", - "StatusBarGamesLoaded": "{0}/{1} Jeux chargés", - "StatusBarSystemVersion": "Version du Firmware: {0}", - "Settings": "Paramètres", - "SettingsTabGeneral": "Général", - "SettingsTabGeneralGeneral": "Général", - "SettingsTabGeneralEnableDiscordRichPresence": "Active Discord Rich Presence", - "SettingsTabGeneralCheckUpdatesOnLaunch": "Vérifier les mises à jour au démarrage", - "SettingsTabGeneralShowConfirmExitDialog": "Afficher le message de \"Confirmation de fermeture\"", - "SettingsTabGeneralHideCursorOnIdle": "Masquer le curseur si inactif", - "SettingsTabGeneralGameDirectories": "Dossiers de Jeux", - "SettingsTabGeneralAdd": "Ajouter", - "SettingsTabGeneralRemove": "Supprimer", - "SettingsTabSystem": "Système", - "SettingsTabSystemCore": "Core", - "SettingsTabSystemSystemRegion": "Région du système:", - "SettingsTabSystemSystemRegionJapan": "Japon", - "SettingsTabSystemSystemRegionUSA": "USA", - "SettingsTabSystemSystemRegionEurope": "Europe", - "SettingsTabSystemSystemRegionAustralia": "Australie", - "SettingsTabSystemSystemRegionChina": "Chine", - "SettingsTabSystemSystemRegionKorea": "Corée", - "SettingsTabSystemSystemRegionTaiwan": "Taïwan", - "SettingsTabSystemSystemLanguage": "Langue du système:", - "SettingsTabSystemSystemLanguageJapanese": "Japonais", - "SettingsTabSystemSystemLanguageAmericanEnglish": "Américain", - "SettingsTabSystemSystemLanguageFrench": "Français", - "SettingsTabSystemSystemLanguageGerman": "Allemand", - "SettingsTabSystemSystemLanguageItalian": "Italien", - "SettingsTabSystemSystemLanguageSpanish": "Espagnol", - "SettingsTabSystemSystemLanguageChinese": "Chinois", - "SettingsTabSystemSystemLanguageKorean": "Coréen", - "SettingsTabSystemSystemLanguageDutch": "Néerlandais", - "SettingsTabSystemSystemLanguagePortuguese": "Portugais", - "SettingsTabSystemSystemLanguageRussian": "Russe", - "SettingsTabSystemSystemLanguageTaiwanese": "Taïwanais", - "SettingsTabSystemSystemLanguageBritishEnglish": "Anglais", - "SettingsTabSystemSystemLanguageCanadianFrench": "Canadien", - "SettingsTabSystemSystemLanguageLatinAmericanSpanish": "Espagnol latino-américain", - "SettingsTabSystemSystemLanguageSimplifiedChinese": "Chinois simplifié", - "SettingsTabSystemSystemLanguageTraditionalChinese": "Chinois traditionnel", - "SettingsTabSystemSystemTimeZone": "Fuseau horaire du système:", - "SettingsTabSystemSystemTime": "Heure du système:", - "SettingsTabSystemEnableVsync": "Activer la VSync", - "SettingsTabSystemEnablePptc": "Activer le PPTC (Profiled Persistent Translation Cache)", - "SettingsTabSystemEnableFsIntegrityChecks": "Activer la vérification de l'intégrité du système de fichiers", - "SettingsTabSystemAudioBackend": "Bibliothèque Audio:", - "SettingsTabSystemAudioBackendDummy": "Dummy", - "SettingsTabSystemAudioBackendOpenAL": "OpenAL", - "SettingsTabSystemAudioBackendSoundIO": "SoundIO", - "SettingsTabSystemAudioBackendSDL2": "SDL2", - "SettingsTabSystemHacks": "Hacks", - "SettingsTabSystemHacksNote": " (Cela peut causer des instabilitées)", - "SettingsTabSystemExpandDramSize": "Augmenter la taille de la DRAM à 6GB", - "SettingsTabSystemIgnoreMissingServices": "Ignorer les services manquant", - "SettingsTabGraphics": "Graphique", - "SettingsTabGraphicsAPI": "API Graphique", - "SettingsTabGraphicsEnableShaderCache": "Activer le cache des shaders", - "SettingsTabGraphicsAnisotropicFiltering": "Filtrage anisotrope:", - "SettingsTabGraphicsAnisotropicFilteringAuto": "Auto", - "SettingsTabGraphicsAnisotropicFiltering2x": "2x", - "SettingsTabGraphicsAnisotropicFiltering4x": "4x", - "SettingsTabGraphicsAnisotropicFiltering8x": "8x", - "SettingsTabGraphicsAnisotropicFiltering16x": "16x", - "SettingsTabGraphicsResolutionScale": "Échelle de résolution:", - "SettingsTabGraphicsResolutionScaleCustom": "Customisée (Non recommandée)", - "SettingsTabGraphicsResolutionScaleNative": "Native (720p/1080p)", - "SettingsTabGraphicsResolutionScale2x": "2x (1440p/2160p)", - "SettingsTabGraphicsResolutionScale3x": "3x (2160p/3240p)", - "SettingsTabGraphicsResolutionScale4x": "4x (2880p/4320p)", - "SettingsTabGraphicsAspectRatio": "Format:", - "SettingsTabGraphicsAspectRatio4x3": "4:3", - "SettingsTabGraphicsAspectRatio16x9": "16:9", - "SettingsTabGraphicsAspectRatio16x10": "16:10", - "SettingsTabGraphicsAspectRatio21x9": "21:9", - "SettingsTabGraphicsAspectRatio32x9": "32:9", - "SettingsTabGraphicsAspectRatioStretch": "Écran étiré", - "SettingsTabGraphicsDeveloperOptions": "Options développeur", - "SettingsTabGraphicsShaderDumpPath": "Chemin du dossier de dump des shaders:", - "SettingsTabGraphicsFeatures": "Fonctionnalités & Améliorations", - "SettingsTabLogging": "Journaux", - "SettingsTabLoggingLogging": "Journaux", - "SettingsTabLoggingEnableLoggingToFile": "Activer la sauvegarde des journaux vers un fichier", - "SettingsTabLoggingEnableStubLogs": "Activer les journaux stub", - "SettingsTabLoggingEnableInfoLogs": "Activer les journaux d'informations", - "SettingsTabLoggingEnableWarningLogs": "Activer les journaux d'avertissements", - "SettingsTabLoggingEnableErrorLogs": "Activer les journaux d'erreurs", - "SettingsTabLoggingEnableGuestLogs": "Activer les journaux du programme simulé", - "SettingsTabLoggingEnableFsAccessLogs": "Activer les journaux des accès au système de fichiers", - "SettingsTabLoggingFsGlobalAccessLogMode": "Niveau des journaux des accès au système de fichiers:", - "SettingsTabLoggingDeveloperOptions": "Options développeur (ATTENTION: Cela peut réduire les performances)", - "SettingsTabLoggingOpenglLogLevel": "Niveau des journaux OpenGL:", - "SettingsTabLoggingOpenglLogLevelNone": "Aucun", - "SettingsTabLoggingOpenglLogLevelError": "Erreur", - "SettingsTabLoggingOpenglLogLevelPerformance": "Ralentissements", - "SettingsTabLoggingOpenglLogLevelAll": "Tout", - "SettingsTabLoggingEnableDebugLogs": "Activer les journaux de debug", - "SettingsTabInput": "Contrôles", - "SettingsTabInputEnableDockedMode": "Active le mode station d'accueil", - "SettingsTabInputDirectKeyboardAccess": "Accès direct au clavier", - "SettingsButtonSave": "Enregistrer", - "SettingsButtonClose": "Fermer", - "SettingsButtonApply": "Appliquer", - "ControllerSettingsPlayer": "Joueur", - "ControllerSettingsPlayer1": "Joueur 1", - "ControllerSettingsPlayer2": "Joueur 2", - "ControllerSettingsPlayer3": "Joueur 3", - "ControllerSettingsPlayer4": "Joueur 4", - "ControllerSettingsPlayer5": "Joueur 5", - "ControllerSettingsPlayer6": "Joueur 6", - "ControllerSettingsPlayer7": "Joueur 7", - "ControllerSettingsPlayer8": "Joueur 8", - "ControllerSettingsHandheld": "Portable", - "ControllerSettingsInputDevice": "Périphériques", - "ControllerSettingsRefresh": "Actualiser", - "ControllerSettingsDeviceDisabled": "Désactivé", - "ControllerSettingsControllerType": "Type de Controleur", - "ControllerSettingsControllerTypeHandheld": "Portable", - "ControllerSettingsControllerTypeProController": "Pro Controller", - "ControllerSettingsControllerTypeJoyConPair": "JoyCon Joints", - "ControllerSettingsControllerTypeJoyConLeft": "JoyCon Gauche", - "ControllerSettingsControllerTypeJoyConRight": "JoyCon Droite", - "ControllerSettingsProfile": "Profil", - "ControllerSettingsProfileDefault": "Défaut", - "ControllerSettingsLoad": "Charger", - "ControllerSettingsAdd": "Ajouter", - "ControllerSettingsRemove": "Supprimer", - "ControllerSettingsButtons": "Boutons", - "ControllerSettingsButtonA": "A", - "ControllerSettingsButtonB": "B", - "ControllerSettingsButtonX": "X", - "ControllerSettingsButtonY": "Y", - "ControllerSettingsButtonPlus": "+", - "ControllerSettingsButtonMinus": "-", - "ControllerSettingsDPad": "Croix Directionnelle", - "ControllerSettingsDPadUp": "Haut", - "ControllerSettingsDPadDown": "Bas", - "ControllerSettingsDPadLeft": "Gauche", - "ControllerSettingsDPadRight": "Droite", - "ControllerSettingsLStick": "Joystick Gauche", - "ControllerSettingsLStickButton": "Bouton", - "ControllerSettingsLStickUp": "Haut", - "ControllerSettingsLStickDown": "Bas", - "ControllerSettingsLStickLeft": "Gauche", - "ControllerSettingsLStickRight": "Droite", - "ControllerSettingsLStickStick": "Joystick", - "ControllerSettingsLStickInvertXAxis": "Inverser l'axe X", - "ControllerSettingsLStickInvertYAxis": "Inverser l'axe Y", - "ControllerSettingsLStickDeadzone": "Zone morte:", - "ControllerSettingsRStick": "Joystick Droit", - "ControllerSettingsRStickButton": "Bouton", - "ControllerSettingsRStickUp": "Haut", - "ControllerSettingsRStickDown": "Bas", - "ControllerSettingsRStickLeft": "Gauche", - "ControllerSettingsRStickRight": "Droite", - "ControllerSettingsRStickStick": "Joystick", - "ControllerSettingsRStickInvertXAxis": "Inverser l'axe X", - "ControllerSettingsRStickInvertYAxis": "Inverser l'axe Y", - "ControllerSettingsRStickDeadzone": "Zone morte:", - "ControllerSettingsTriggers": "Gachettes", - "ControllerSettingsTriggersLeft": "Gachettes Gauche", - "ControllerSettingsTriggersRight": "Gachettes Droite", - "ControllerSettingsTriggersButtonsLeft": "Boutons Gachettes Gauche", - "ControllerSettingsTriggersButtonsRight": "Boutons Gachettes Droite", - "ControllerSettingsTriggerL": "L", - "ControllerSettingsTriggerR": "R", - "ControllerSettingsTriggerZL": "ZL", - "ControllerSettingsTriggerZR": "ZR", - "ControllerSettingsLeftSL": "SL", - "ControllerSettingsLeftSR": "SR", - "ControllerSettingsRightSL": "SL", - "ControllerSettingsRightSR": "SR", - "ControllerSettingsExtraButtonsLeft": "Boutons Gauche", - "ControllerSettingsExtraButtonsRight": "Boutons Droite", - "ControllerSettingsMisc": "Divers", - "ControllerSettingsTriggerThreshold": "Seuil de gachettes:", - "ControllerSettingsMotion": "Mouvements", - "ControllerSettingsConfigureGeneral": "Configurer", - "ControllerSettingsMotionUseCemuhookCompatibleMotion": "Utiliser un capteur de mouvements CemuHook", - "ControllerSettingsMotionControllerSlot": "Contrôleur ID:", - "ControllerSettingsMotionMirrorInput": "Inverser les contrôles", - "ControllerSettingsMotionRightJoyConSlot": "JoyCon Droit ID:", - "ControllerSettingsMotionServerHost": "Addresse du Server:", - "ControllerSettingsMotionGyroSensitivity": "Sensibilitée du gyroscope:", - "ControllerSettingsMotionGyroDeadzone": "Zone morte du gyroscope:", - "ControllerSettingsSave": "Enregistrer", - "ControllerSettingsClose": "Fermer", - "UserProfilesSelectedUserProfile": "Choisir un profil utilisateur:", - "UserProfilesSaveProfileName": "Enregistrer le nom du profil", - "UserProfilesChangeProfileImage": "Changer l'image du profil", - "UserProfilesAvailableUserProfiles": "Profils utilisateurs disponible:", - "UserProfilesAddNewProfile": "Ajouter un nouveau profil", - "UserProfilesDeleteSelectedProfile": "Supprimer le profil sélectionné", - "UserProfilesClose": "Fermer", - "ProfileImageSelectionTitle": "Sélection de l'image du profil", - "ProfileImageSelectionHeader": "Choisir l'image du profil", - "ProfileImageSelectionNote": "Vous pouvez importer une image de profil personnalisée ou sélectionner un avatar à partir du firmware", - "ProfileImageSelectionImportImage": "Importer une image", - "ProfileImageSelectionSelectAvatar": "Choisir un avatar du firmware", - "InputDialogTitle": "Fenêtre d'entrée de texte", - "InputDialogOk": "OK", - "InputDialogCancel": "Annuler", - "InputDialogAddNewProfileTitle": "Choisir un nom de profil", - "InputDialogAddNewProfileHeader": "Merci d'entrer un nom de profil", - "InputDialogAddNewProfileSubtext": "(Longueur max.: {0})", - "AvatarChoose": "Choisir", - "AvatarSetBackgroundColor": "Choisir une couleur de fond", - "AvatarClose": "Fermer", - "ControllerMotionTitle": "Motion Control Settings", - "ControllerRumbleTitle": "Rumble Settings" -} diff --git a/Ryujinx.Ava/Assets/Locales/it_IT.json b/Ryujinx.Ava/Assets/Locales/it_IT.json deleted file mode 100644 index 3e403094a..000000000 --- a/Ryujinx.Ava/Assets/Locales/it_IT.json +++ /dev/null @@ -1,560 +0,0 @@ -{ - "MenuBarFileOpenApplet": "Apri applet", - "MenuBarFileOpenAppletOpenMiiAppletToolTip": "Apri l'editor Mii in modalità standalone", - "SettingsTabInputDirectMouseAccess": "Accesso diretto al mouse", - "SettingsTabSystemMemoryManagerMode": "Modalità di gestione della memoria:", - "SettingsTabSystemMemoryManagerModeSoftware": "Software", - "SettingsTabSystemMemoryManagerModeHost": "Host (veloce)", - "SettingsTabSystemMemoryManagerModeHostUnchecked": "Host Unchecked (più veloce, non sicura)", - "MenuBarFile": "_File", - "MenuBarFileOpenFromFile": "_Carica applicazione da un file", - "MenuBarFileOpenUnpacked": "Carica _gioco estratto", - "MenuBarFileOpenEmuFolder": "Apri cartella di Ryujinx", - "MenuBarFileOpenLogsFolder": "Apri cartella dei logs", - "MenuBarFileExit": "_Esci", - "MenuBarOptions": "Opzioni", - "MenuBarOptionsToggleFullscreen": "Schermo intero", - "MenuBarOptionsStartGamesInFullscreen": "Avvia i giochi a schermo intero", - "MenuBarOptionsStopEmulation": "Ferma emulazione", - "MenuBarOptionsSettings": "_Impostazioni", - "MenuBarOptionsManageUserProfiles": "_Gestisci i profili utente", - "MenuBarActions": "_Azioni", - "MenuBarOptionsSimulateWakeUpMessage": "Simula messaggio Wake-up", - "MenuBarActionsScanAmiibo": "Scansiona un Amiibo", - "MenuBarTools": "_Strumenti", - "MenuBarToolsInstallFirmware": "Installa firmware", - "MenuBarFileToolsInstallFirmwareFromFile": "Installa un firmware da file XCI o ZIP", - "MenuBarFileToolsInstallFirmwareFromDirectory": "Installa un firmare da una cartella", - "MenuBarHelp": "Aiuto", - "MenuBarHelpCheckForUpdates": "Controlla aggiornamenti", - "MenuBarHelpAbout": "Informazioni", - "MenuSearch": "Cerca...", - "GameListHeaderFavorite": "Pref", - "GameListHeaderIcon": "Icona", - "GameListHeaderApplication": "Nome", - "GameListHeaderDeveloper": "Sviluppatore", - "GameListHeaderVersion": "Versione", - "GameListHeaderTimePlayed": "Tempo di gioco", - "GameListHeaderLastPlayed": "Giocato l'ultima volta", - "GameListHeaderFileExtension": "Estensione", - "GameListHeaderFileSize": "Dimensione file", - "GameListHeaderPath": "Percorso", - "GameListContextMenuOpenUserSaveDirectory": "Apri la cartella salvataggi dell'utente", - "GameListContextMenuOpenUserSaveDirectoryToolTip": "Apre la cartella che contiene i salvataggi di gioco dell'utente", - "GameListContextMenuOpenUserDeviceDirectory": "Apri la cartella dispositivo dell'utente", - "GameListContextMenuOpenUserDeviceDirectoryToolTip": "Apre la cartella che contiene i salvataggi di gioco del dispositivo", - "GameListContextMenuOpenUserBcatDirectory": "Apri la cartella BCAT dell'utente", - "GameListContextMenuOpenUserBcatDirectoryToolTip": "Apre la cartella che contiene i salvataggi BCAT dell'applicazione", - "GameListContextMenuManageTitleUpdates": "Gestisci aggiornamenti del gioco", - "GameListContextMenuManageTitleUpdatesToolTip": "Apre la finestra di gestione aggiornamenti del gioco", - "GameListContextMenuManageDlc": "Gestici DLC", - "GameListContextMenuManageDlcToolTip": "Apre la finestra di gestione DLC", - "GameListContextMenuOpenModsDirectory": "Apri cartella delle mods", - "GameListContextMenuOpenModsDirectoryToolTip": "Apre la cartella che contiene le mods dell'applicazione", - "GameListContextMenuCacheManagement": "Gestione della cache", - "GameListContextMenuCacheManagementPurgePptc": "Pulisci PPTC cache", - "GameListContextMenuCacheManagementPurgePptcToolTip": "Elimina la PPTC cache dell'applicazione", - "GameListContextMenuCacheManagementPurgeShaderCache": "Pulisci shader cache", - "GameListContextMenuCacheManagementPurgeShaderCacheToolTip": "Elimina la shader cache dell'applicazione", - "GameListContextMenuCacheManagementOpenPptcDirectory": "Apri cartella PPTC", - "GameListContextMenuCacheManagementOpenPptcDirectoryToolTip": "Apre la cartella che contiene la PPTC cache dell'applicazione", - "GameListContextMenuCacheManagementOpenShaderCacheDirectory": "Apri cartella shader cache", - "GameListContextMenuCacheManagementOpenShaderCacheDirectoryToolTip": "Apre la cartella che contiene la shader cache dell'applicazione", - "GameListContextMenuExtractData": "Estrai dati", - "GameListContextMenuExtractDataExeFS": "ExeFS", - "GameListContextMenuExtractDataExeFSToolTip": "Estrae la sezione ExeFS dall'attuale configurazione dell'applicazione (includendo aggiornamenti)", - "GameListContextMenuExtractDataRomFS": "RomFS", - "GameListContextMenuExtractDataRomFSToolTip": "Estrae la sezione RomFS dall'attuale configurazione dell'applicazione (includendo aggiornamenti)", - "GameListContextMenuExtractDataLogo": "Logo", - "GameListContextMenuExtractDataLogoToolTip": "Estrae la sezione Logo dall'attuale configurazione dell'applicazione (includendo aggiornamenti)", - "StatusBarGamesLoaded": "{0}/{1} Giochi caricati", - "StatusBarSystemVersion": "Versione di sistema: {0}", - "Settings": "Impostazioni", - "SettingsTabGeneral": "Interfaccia utente", - "SettingsTabGeneralGeneral": "Generali", - "SettingsTabGeneralEnableDiscordRichPresence": "Attiva Discord Rich Presence", - "SettingsTabGeneralCheckUpdatesOnLaunch": "Controlla aggiornamenti all'avvio", - "SettingsTabGeneralShowConfirmExitDialog": "Mostra dialogo \"Conferma Uscita\"", - "SettingsTabGeneralHideCursorOnIdle": "Nascondi cursore inattivo", - "SettingsTabGeneralGameDirectories": "Cartelle dei giochi", - "SettingsTabGeneralAdd": "Aggiungi", - "SettingsTabGeneralRemove": "Rimuovi", - "SettingsTabSystem": "Sistema", - "SettingsTabSystemCore": "Core", - "SettingsTabSystemSystemRegion": "Regione di sistema:", - "SettingsTabSystemSystemRegionJapan": "Giappone", - "SettingsTabSystemSystemRegionUSA": "Stati Uniti d'America", - "SettingsTabSystemSystemRegionEurope": "Europa", - "SettingsTabSystemSystemRegionAustralia": "Australia", - "SettingsTabSystemSystemRegionChina": "Cina", - "SettingsTabSystemSystemRegionKorea": "Corea", - "SettingsTabSystemSystemRegionTaiwan": "Taiwan", - "SettingsTabSystemSystemLanguage": "Lingua di sistema:", - "SettingsTabSystemSystemLanguageJapanese": "Giapponese", - "SettingsTabSystemSystemLanguageAmericanEnglish": "Inglese americano", - "SettingsTabSystemSystemLanguageFrench": "Francese", - "SettingsTabSystemSystemLanguageGerman": "Tedesco", - "SettingsTabSystemSystemLanguageItalian": "Italiano", - "SettingsTabSystemSystemLanguageSpanish": "Spagnolo", - "SettingsTabSystemSystemLanguageChinese": "Cinese", - "SettingsTabSystemSystemLanguageKorean": "Coreano", - "SettingsTabSystemSystemLanguageDutch": "Olandese", - "SettingsTabSystemSystemLanguagePortuguese": "Portoghese", - "SettingsTabSystemSystemLanguageRussian": "Russo", - "SettingsTabSystemSystemLanguageTaiwanese": "Taiwanese", - "SettingsTabSystemSystemLanguageBritishEnglish": "Inglese britannico", - "SettingsTabSystemSystemLanguageCanadianFrench": "Francese canadese", - "SettingsTabSystemSystemLanguageLatinAmericanSpanish": "Spagnolo latino americano", - "SettingsTabSystemSystemLanguageSimplifiedChinese": "Cinese semplificato", - "SettingsTabSystemSystemLanguageTraditionalChinese": "Cinese tradizionale", - "SettingsTabSystemSystemTimeZone": "Fuso orario di sistema:", - "SettingsTabSystemSystemTime": "Data e ora di sistema:", - "SettingsTabSystemEnableVsync": "Attiva VSync", - "SettingsTabSystemEnablePptc": "Attiva PPTC (Profiled Persistent Translation Cache)", - "SettingsTabSystemEnableFsIntegrityChecks": "Attiva controlli d'integrità FS", - "SettingsTabSystemAudioBackend": "Backend audio:", - "SettingsTabSystemAudioBackendDummy": "Dummy", - "SettingsTabSystemAudioBackendOpenAL": "OpenAL", - "SettingsTabSystemAudioBackendSoundIO": "SoundIO", - "SettingsTabSystemAudioBackendSDL2": "SDL2", - "SettingsTabSystemHacks": "Hacks", - "SettingsTabSystemHacksNote": " (Possono causare instabilità)", - "SettingsTabSystemExpandDramSize": "Espandi dimensione DRAM a 6GB", - "SettingsTabSystemIgnoreMissingServices": "Ignora servizi mancanti", - "SettingsTabGraphics": "Grafica", - "SettingsTabGraphicsAPI": "API Grafiche", - "SettingsTabGraphicsEnableShaderCache": "Attiva Shader Cache", - "SettingsTabGraphicsAnisotropicFiltering": "Filtro anisotropico:", - "SettingsTabGraphicsAnisotropicFilteringAuto": "Auto", - "SettingsTabGraphicsAnisotropicFiltering2x": "2x", - "SettingsTabGraphicsAnisotropicFiltering4x": "4x", - "SettingsTabGraphicsAnisotropicFiltering8x": "8x", - "SettingsTabGraphicsAnisotropicFiltering16x": "16x", - "SettingsTabGraphicsResolutionScale": "Scala della risoluzione:", - "SettingsTabGraphicsResolutionScaleCustom": "Personalizzata (Non raccomandata)", - "SettingsTabGraphicsResolutionScaleNative": "Nativa (720p/1080p)", - "SettingsTabGraphicsResolutionScale2x": "2x (1440p/2160p)", - "SettingsTabGraphicsResolutionScale3x": "3x (2160p/3240p)", - "SettingsTabGraphicsResolutionScale4x": "4x (2880p/4320p)", - "SettingsTabGraphicsAspectRatio": "Rapporto d'aspetto:", - "SettingsTabGraphicsAspectRatio4x3": "4:3", - "SettingsTabGraphicsAspectRatio16x9": "16:9", - "SettingsTabGraphicsAspectRatio16x10": "16:10", - "SettingsTabGraphicsAspectRatio21x9": "21:9", - "SettingsTabGraphicsAspectRatio32x9": "32:9", - "SettingsTabGraphicsAspectRatioStretch": "Adatta alla finestra", - "SettingsTabGraphicsDeveloperOptions": "Opzioni da sviluppatore", - "SettingsTabGraphicsShaderDumpPath": "Percorso di dump degli shaders:", - "SettingsTabLogging": "Log", - "SettingsTabLoggingLogging": "Log", - "SettingsTabLoggingEnableLoggingToFile": "Salva i log su file", - "SettingsTabLoggingEnableStubLogs": "Attiva Stub Logs", - "SettingsTabLoggingEnableInfoLogs": "Attiva Info Logs", - "SettingsTabLoggingEnableWarningLogs": "Attiva Warning Logs", - "SettingsTabLoggingEnableErrorLogs": "Attiva Error Logs", - "SettingsTabLoggingEnableTraceLogs": "Attiva Trace Logs", - "SettingsTabLoggingEnableGuestLogs": "Attiva Guest Logs", - "SettingsTabLoggingEnableFsAccessLogs": "Attiva Fs Access Logs", - "SettingsTabLoggingFsGlobalAccessLogMode": "Modalità di log accesso globale Fs:", - "SettingsTabLoggingDeveloperOptions": "Opzioni da sviluppatore (AVVISO: Ridurrà le prestazioni)", - "SettingsTabLoggingOpenglLogLevel": "Livello di log OpenGL:", - "SettingsTabLoggingOpenglLogLevelNone": "Nessuno", - "SettingsTabLoggingOpenglLogLevelError": "Errore", - "SettingsTabLoggingOpenglLogLevelPerformance": "Rallentamenti", - "SettingsTabLoggingOpenglLogLevelAll": "Tutto", - "SettingsTabLoggingEnableDebugLogs": "Attiva logs di debug", - "SettingsTabInput": "Input", - "SettingsTabInputEnableDockedMode": "Attiva modalità TV", - "SettingsTabInputDirectKeyboardAccess": "Accesso diretto alla tastiera", - "SettingsButtonSave": "Salva", - "SettingsButtonClose": "Chiudi", - "SettingsButtonApply": "Applica", - "ControllerSettingsPlayer": "Giocatore", - "ControllerSettingsPlayer1": "Giocatore 1", - "ControllerSettingsPlayer2": "Giocatore 2", - "ControllerSettingsPlayer3": "Giocatore 3", - "ControllerSettingsPlayer4": "Giocatore 4", - "ControllerSettingsPlayer5": "Giocatore 5", - "ControllerSettingsPlayer6": "Giocatore 6", - "ControllerSettingsPlayer7": "Giocatore 7", - "ControllerSettingsPlayer8": "Giocatore 8", - "ControllerSettingsHandheld": "Portatile", - "ControllerSettingsInputDevice": "Dispositivo di input", - "ControllerSettingsRefresh": "Ricarica", - "ControllerSettingsDeviceDisabled": "Disabilitato", - "ControllerSettingsControllerType": "Tipo di controller", - "ControllerSettingsControllerTypeHandheld": "Portatile", - "ControllerSettingsControllerTypeProController": "Pro Controller", - "ControllerSettingsControllerTypeJoyConPair": "Coppia di JoyCon", - "ControllerSettingsControllerTypeJoyConLeft": "JoyCon sinistro", - "ControllerSettingsControllerTypeJoyConRight": "JoyCon destro", - "ControllerSettingsProfile": "Profilo", - "ControllerSettingsProfileDefault": "Predefinito", - "ControllerSettingsLoad": "Carica", - "ControllerSettingsAdd": "Aggiungi", - "ControllerSettingsRemove": "Rimuovi", - "ControllerSettingsButtons": "Pulsanti", - "ControllerSettingsButtonA": "A", - "ControllerSettingsButtonB": "B", - "ControllerSettingsButtonX": "X", - "ControllerSettingsButtonY": "Y", - "ControllerSettingsButtonPlus": "+", - "ControllerSettingsButtonMinus": "-", - "ControllerSettingsDPad": "Croce direzionale", - "ControllerSettingsDPadUp": "Su", - "ControllerSettingsDPadDown": "Giù", - "ControllerSettingsDPadLeft": "Sinistra", - "ControllerSettingsDPadRight": "Destra", - "ControllerSettingsLStick": "Stick sinistro", - "ControllerSettingsLStickButton": "Pulsante", - "ControllerSettingsLStickUp": "Su", - "ControllerSettingsLStickDown": "Giù", - "ControllerSettingsLStickLeft": "Sinistra", - "ControllerSettingsLStickRight": "Destra", - "ControllerSettingsLStickStick": "Stick", - "ControllerSettingsLStickInvertXAxis": "Inverti stick X", - "ControllerSettingsLStickInvertYAxis": "Inverti stick Y", - "ControllerSettingsLStickDeadzone": "Zona morta:", - "ControllerSettingsRStick": "Stick destro", - "ControllerSettingsRStickButton": "Pulsante", - "ControllerSettingsRStickUp": "Su", - "ControllerSettingsRStickDown": "Giù", - "ControllerSettingsRStickLeft": "Sinistra", - "ControllerSettingsRStickRight": "Destra", - "ControllerSettingsRStickStick": "Stick", - "ControllerSettingsRStickInvertXAxis": "Inverti stick X", - "ControllerSettingsRStickInvertYAxis": "Inverti stick Y", - "ControllerSettingsRStickDeadzone": "Zona morta:", - "ControllerSettingsTriggersLeft": "Grilletto sinistro", - "ControllerSettingsTriggersRight": "Grilletto destro", - "ControllerSettingsTriggersButtonsLeft": "Pulsante dorsale sinistro", - "ControllerSettingsTriggersButtonsRight": "Pulsante dorsale destro", - "ControllerSettingsTriggers": "Grilletti", - "ControllerSettingsTriggerL": "L", - "ControllerSettingsTriggerR": "R", - "ControllerSettingsTriggerZL": "ZL", - "ControllerSettingsTriggerZR": "ZR", - "ControllerSettingsLeftSL": "SL", - "ControllerSettingsLeftSR": "SR", - "ControllerSettingsRightSL": "SL", - "ControllerSettingsRightSR": "SR", - "ControllerSettingsExtraButtonsLeft": "Tasto sinitro", - "ControllerSettingsExtraButtonsRight": "Tasto destro", - "ControllerSettingsMisc": "Miscellanee", - "ControllerSettingsTriggerThreshold": "Sensibilità dei grilletti:", - "ControllerSettingsMotion": "Movimento", - "ControllerSettingsMotionUseCemuhookCompatibleMotion": "Usa sensore compatibile con CemuHook", - "ControllerSettingsMotionControllerSlot": "Slot del controller:", - "ControllerSettingsMotionMirrorInput": "Input specchiato", - "ControllerSettingsMotionRightJoyConSlot": "Slot JoyCon destro:", - "ControllerSettingsMotionServerHost": "Server:", - "ControllerSettingsMotionGyroSensitivity": "Sensibilità del giroscopio:", - "ControllerSettingsMotionGyroDeadzone": "Zona morta del giroscopio:", - "ControllerSettingsSave": "Salva", - "ControllerSettingsClose": "Chiudi", - "UserProfilesSelectedUserProfile": "Profilo utente selezionato:", - "UserProfilesSaveProfileName": "Salva nome del profilo", - "UserProfilesChangeProfileImage": "Cambia immagine profilo", - "UserProfilesAvailableUserProfiles": "Profili utente disponibili:", - "UserProfilesAddNewProfile": "Aggiungi nuovo profilo", - "UserProfilesDeleteSelectedProfile": "Elimina il profilo selezionato", - "UserProfilesClose": "Chiudi", - "ProfileImageSelectionTitle": "Selezione dell'immagine profilo", - "ProfileImageSelectionHeader": "Scegli un'immagine profilo", - "ProfileImageSelectionNote": "Puoi importare un'immagine profilo personalizzata o selezionare un avatar dal firmware di sistema", - "ProfileImageSelectionImportImage": "Importa file immagine", - "ProfileImageSelectionSelectAvatar": "Seleziona avatar dal firmware", - "InputDialogTitle": "Input Dialog", - "InputDialogOk": "OK", - "InputDialogCancel": "Annulla", - "InputDialogAddNewProfileTitle": "Scegli il nome profilo", - "InputDialogAddNewProfileHeader": "Digita un nome profilo", - "InputDialogAddNewProfileSubtext": "(Lunghezza massima: {0})", - "AvatarChoose": "Scegli", - "AvatarSetBackgroundColor": "Imposta colore di sfondo", - "AvatarClose": "Chiudi", - "ControllerSettingsLoadProfileToolTip": "Carica profilo", - "ControllerSettingsAddProfileToolTip": "Aggiungi profilo", - "ControllerSettingsRemoveProfileToolTip": "Rimuovi profilo", - "ControllerSettingsSaveProfileToolTip": "Salva profilo", - "MenuBarFileToolsTakeScreenshot": "Fai uno screenshot", - "MenuBarFileToolsHideUi": "Nascondi Ui", - "GameListContextMenuToggleFavorite": "Preferito", - "GameListContextMenuToggleFavoriteToolTip": "Segna il gioco come preferito", - "SettingsTabGeneralTheme": "Tema", - "SettingsTabGeneralThemeCustomTheme": "Percorso del tema personalizzato", - "SettingsTabGeneralThemeBaseStyle": "Modalità", - "SettingsTabGeneralThemeBaseStyleDark": "Scura", - "SettingsTabGeneralThemeBaseStyleLight": "Chiara", - "SettingsTabGeneralThemeEnableCustomTheme": "Attiva tema personalizzato", - "ButtonBrowse": "Sfoglia", - "ControllerSettingsConfigureGeneral": "Configura", - "ControllerSettingsRumble": "Vibrazione", - "ControllerSettingsRumbleStrongMultiplier": "Moltiplicatore vibrazione forte", - "ControllerSettingsRumbleWeakMultiplier": "Moltiplicatore vibrazione debole", - "DialogMessageSaveNotAvailableMessage": "Non ci sono dati di salvataggio per {0} [{1:x16}]", - "DialogMessageSaveNotAvailableCreateSaveMessage": "Vuoi creare dei dat di salvataggio per questo gioco?", - "DialogConfirmationTitle": "Ryujinx - Conferma", - "DialogUpdaterTitle": "Ryujinx - Updater", - "DialogErrorTitle": "Ryujinx - Errore", - "DialogWarningTitle": "Ryujinx - Avviso", - "DialogExitTitle": "Ryujinx - Uscita", - "DialogErrorMessage": "Ryujinx ha riscontrato un problema", - "DialogExitMessage": "Sei sicuro di voler chiudere Ryujinx?", - "DialogExitSubMessage": "Tutti i dati non salvati andranno persi!", - "DialogMessageCreateSaveErrorMessage": "C'è stato un errore durante la creazione dei dati di salvataggio: {0}", - "DialogMessageFindSaveErrorMessage": "C'è stato un errore durante la ricerca dei dati di salvataggio: {0}", - "FolderDialogExtractTitle": "Scegli una cartella in cui estrarre", - "DialogNcaExtractionMessage": "Estrazione della sezione {0} da {1}...", - "DialogNcaExtractionTitle": "Ryujinx - Estrattore sezione NCA", - "DialogNcaExtractionMainNcaNotFoundErrorMessage": "L'estrazione è fallita. L'NCA principale non era presente nel file selezionato.", - "DialogNcaExtractionCheckLogErrorMessage": "L'estrazione è fallita. Leggi il log per più informazioni.", - "DialogNcaExtractionSuccessMessage": "Estrazione completata con successo.", - "DialogUpdaterConvertFailedMessage": "La conversione dell'attuale versione di Ryujinx è fallita.", - "DialogUpdaterCancelUpdateMessage": "Annullando l'aggiornamento!", - "DialogUpdaterAlreadyOnLatestVersionMessage": "Stai già usando la versione più recente di Ryujinx!", - "DialogUpdaterFailedToGetVersionMessage": "Si è verificato un errore nel tentativo di ottenere informazioni da Github Release. Questo può verificarsi se una nuova release è in compilazione su GitHub Actions. Riprova tra qualche minuto.", - "DialogUpdaterConvertFailedGithubMessage": "La conversione della versione di Ryujinx ricevuta da Github Release è fallita.", - "DialogUpdaterDownloadingMessage": "Download dell'aggiornamento...", - "DialogUpdaterExtractionMessage": "Estrazione dell'aggiornamento...", - "DialogUpdaterRenamingMessage": "Rinominazione dell'aggiornamento...", - "DialogUpdaterAddingFilesMessage": "Aggiunta nuovo aggiornamento...", - "DialogUpdaterCompleteMessage": "Aggiornamento completato!", - "DialogUpdaterRestartMessage": "Vuoi riavviare Ryujinx adesso?", - "DialogUpdaterArchNotSupportedMessage": "Non stai usando un'architettura di sistema supportata!", - "DialogUpdaterArchNotSupportedSubMessage": "(Solo sistemi x64 sono supportati!)", - "DialogUpdaterNoInternetMessage": "Non sei connesso ad Internet!", - "DialogUpdaterNoInternetSubMessage": "Verifica di avere una connessione ad Internet funzionante!", - "DialogUpdaterDirtyBuildMessage": "Non puoi aggiornare una Dirty build di Ryujinx!", - "DialogUpdaterDirtyBuildSubMessage": "Scarica Ryujinx da https://ryujinx.org/ se stai cercando una versione supportata.", - "DialogRestartRequiredMessage": "Riavvio richiesto", - "DialogThemeRestartMessage": "Il tema è stato salvato. E' richiesto un riavvio per applicare un tema.", - "DialogThemeRestartSubMessage": "Vuoi riavviare?", - "DialogFirmwareInstallEmbeddedMessage": "Vuoi installare il firmware incorporato in questo gioco? (Firmware {0})", - "DialogFirmwareInstallEmbeddedSuccessMessage": "Non è stato trovato alcun firmware installato, ma Ryujinx è riuscito di installare il firmware {0} dal gioco fornito.\nL'emulatore si avvierà adesso.", - "DialogFirmwareNoFirmwareInstalledMessage": "Nessun firmware installato", - "DialogFirmwareInstalledMessage": "Il firmware {0} è stato installato", - "DialogOpenSettingsWindowLabel": "Apri finestra delle impostazioni", - "DialogControllerAppletTitle": "Applet del controller", - "DialogMessageDialogErrorExceptionMessage": "Errore nella visualizzazione del Message Dialog: {0}", - "DialogSoftwareKeyboardErrorExceptionMessage": "Errore nella visualizzazione della tastiera software: {0}", - "DialogErrorAppletErrorExceptionMessage": "Errore nella visualizzazione dell'ErrorApplet Dialog: {0}", - "DialogUserErrorDialogMessage": "{0}: {1}", - "DialogUserErrorDialogInfoMessage": "\nPer più informazioni su come risolvere questo errore, segui la nostra guida all'installazione.", - "DialogUserErrorDialogTitle": "Errore di Ryujinx ({0})", - "DialogAmiiboApiTitle": "Amiibo API", - "DialogAmiiboApiFailFetchMessage": "Si è verificato un errore durante il recupero delle informazioni dall'API.", - "DialogAmiiboApiConnectErrorMessage": "Impossibile connettersi al server Amiibo API. Il servizio potrebbe essere fuori uso o potresti dover verificare che la tua connessione internet sia online.", - "DialogProfileInvalidProfileErrorMessage": "Il profilo {0} è incompatibile con l'attuale sistema di configurazione input.", - "DialogProfileDefaultProfileOverwriteErrorMessage": "Il profilo predefinito non può essere sovrascritto", - "DialogProfileDeleteProfileTitle": "Eliminazione profilo", - "DialogProfileDeleteProfileMessage": "Quest'azione è irreversibile, sei sicuro di voler continuare?", - "DialogWarning": "Avviso", - "DialogPPTCDeletionMessage": "Stai per eliminare la PPTC cache per :\n\n{0}\n\nSei sicuro di voler proseguire?", - "DialogPPTCDeletionErrorMessage": "Errore nell'eliminazione della PPTC cache a {0}: {1}", - "DialogShaderDeletionMessage": "Stai per eliminare la Shader cache per :\n\n{0}\n\nSei sicuro di voler proseguire?", - "DialogShaderDeletionErrorMessage": "Errore nell'eliminazione della Shader cache a {0}: {1}", - "DialogRyujinxErrorMessage": "Ryujinx ha incontrato un errore", - "DialogInvalidTitleIdErrorMessage": "Errore UI: Il gioco selezionato non ha un title ID valido", - "DialogFirmwareInstallerFirmwareNotFoundErrorMessage": "Un firmware di sistema valido non è stato trovato in {0}.", - "DialogFirmwareInstallerFirmwareInstallTitle": "Installa firmware {0}", - "DialogFirmwareInstallerFirmwareInstallMessage": "La versione di sistema {0} sarà installata.", - "DialogFirmwareInstallerFirmwareInstallSubMessage": "\n\nQuesta sostituirà l'attuale versione di sistema {0}.", - "DialogFirmwareInstallerFirmwareInstallConfirmMessage": "\n\nVuoi continuare?", - "DialogFirmwareInstallerFirmwareInstallWaitMessage": "Installazione del firmware...", - "DialogFirmwareInstallerFirmwareInstallSuccessMessage": "La versione di sistema {0} è stata installata.", - "DialogUserProfileDeletionWarningMessage": "Non ci sarebbero altri profili da aprire se il profilo selezionato viene cancellato", - "DialogUserProfileDeletionConfirmMessage": "Vuoi eliminare il profilo selezionato?", - "DialogControllerSettingsModifiedConfirmMessage": "Le attuali impostazioni del controller sono state aggiornate.", - "DialogControllerSettingsModifiedConfirmSubMessage": "Vuoi salvare?", - "DialogDlcLoadNcaErrorMessage": "{0}. File errato: {1}", - "DialogDlcNoDlcErrorMessage": "Il file specificato non contiene un DLC per il titolo selezionato!", - "DialogPerformanceCheckLoggingEnabledMessage": "Hai abilitato il trace logging, che è progettato per essere usato solo dagli sviluppatori.", - "DialogPerformanceCheckLoggingEnabledConfirmMessage": "Per prestazioni ottimali, si raccomanda di disabilitare il trace logging. Vuoi disabilitare il debug logging adesso?", - "DialogPerformanceCheckShaderDumpEnabledMessage": "Hai abilitato lo shader dumping, che è progettato per essere usato solo dagli sviluppatori.", - "DialogPerformanceCheckShaderDumpEnabledConfirmMessage": "Per prestazioni ottimali, si raccomanda di disabilitare lo shader dumping. Vuoi disabilitare lo shader dumping adesso?", - "DialogLoadAppGameAlreadyLoadedMessage": "Un gioco è già stato caricato", - "DialogLoadAppGameAlreadyLoadedSubMessage": "Ferma l'emulazione o chiudi l'emulatore prima di avviare un altro gioco.", - "DialogUpdateAddUpdateErrorMessage": "Il file specificato non contiene un aggiornamento per il titolo selezionato!", - "DialogSettingsBackendThreadingWarningTitle": "Avviso - Backend Threading", - "DialogSettingsBackendThreadingWarningMessage": "Ryujinx deve essere riavviato dopo aver cambiato questa opzione per applicarla completamente. A seconda della tua piattaforma, potrebbe essere necessario disabilitare manualmente il multithreading del driver quando usi quello di Ryujinx.", - "SettingsTabGraphicsFeaturesOptions": "Funzionalità", - "SettingsTabGraphicsBackendMultithreading": "Graphics Backend Multithreading", - "CommonAuto": "Auto", - "CommonOff": "Spento", - "CommonOn": "Acceso", - "InputDialogYes": "Si", - "InputDialogNo": "No", - "DialogProfileInvalidProfileNameErrorMessage": "Il nome del file contiene caratteri non validi. Riprova.", - "MenuBarOptionsPauseEmulation": "Pausa", - "MenuBarOptionsResumeEmulation": "Riprendi", - "AboutUrlTooltipMessage": "Clicca per aprire il sito web di Ryujinx nel tuo browser predefinito.", - "AboutDisclaimerMessage": "Ryujinx non è affiliato con Nintendo™,\no i suoi partner, in alcun modo.", - "AboutAmiiboDisclaimerMessage": "AmiiboAPI (www.amiiboapi.com) è usata\nnella nostra emulazione Amiibo.", - "AboutPatreonUrlTooltipMessage": "Clicca per aprire la pagina Patreon di Ryujinx nel tuo browser predefinito.", - "AboutGithubUrlTooltipMessage": "Clicca per aprire la pagina GitHub di Ryujinx nel tuo browser predefinito.", - "AboutDiscordUrlTooltipMessage": "Clicca per aprire un invito al server Discord di Ryujinx nel tuo browser predefinito.", - "AboutTwitterUrlTooltipMessage": "Clicca per aprire la pagina Twitter di Ryujinx nel tuo browser predefinito.", - "AboutRyujinxAboutTitle": "Informazioni:", - "AboutRyujinxAboutContent": "Ryujinx è un emulatore per la Nintendo Switch™.\nPer favore supportaci su Patreon.\nRicevi tutte le ultime notizie sul nostro Twitter o su Discord.\nGli sviluppatori interessati a contribuire possono trovare più informazioni sul nostro GitHub o Discord.", - "AboutRyujinxMaintainersTitle": "Mantenuto da:", - "AboutRyujinxMaintainersContentTooltipMessage": "Clicca per aprire la pagina dei Contributors nel tuo browser predefinito.", - "AboutRyujinxSupprtersTitle": "Supportato su Patreon da:", - "AmiiboSeriesLabel": "Serie Amiibo", - "AmiiboCharacterLabel": "Personaggio", - "AmiiboScanButtonLabel": "Scannerizza", - "AmiiboOptionsShowAllLabel": "Mostra tutti gli amiibo", - "AmiiboOptionsUsRandomTagLabel": "Hack: Usa un tag uuid casuale", - "DlcManagerTableHeadingEnabledLabel": "Abilitato", - "DlcManagerTableHeadingTitleIdLabel": "Title ID", - "DlcManagerTableHeadingContainerPathLabel": "Percorso del contenitore", - "DlcManagerTableHeadingFullPathLabel": "Percorso completo", - "DlcManagerRemoveAllButton": "Rimuovi tutti", - "MenuBarOptionsChangeLanguage": "Cambia lingua", - "CommonSort": "Ordina", - "CommonShowNames": "Mostra nomi", - "CommonFavorite": "Preferito", - "OrderAscending": "Crescente", - "OrderDescending": "Decrescente", - "SettingsTabGraphicsFeatures": "Funzionalità & Miglioramenti", - "ErrorWindowTitle": "Finestra errore", - "ToggleDiscordTooltip": "Attiva o disattiva Discord Rich Presence", - "AddGameDirBoxTooltip": "Inserisci la directory di un gioco per aggiungerlo alla lista", - "AddGameDirTooltip": "Aggiungi la directory di un gioco alla lista", - "RemoveGameDirTooltip": "Rimuovi la directory di gioco selezionata", - "CustomThemeCheckTooltip": "Attiva o disattiva temi personalizzati nella GUI", - "CustomThemePathTooltip": "Percorso al tema GUI personalizzato", - "CustomThemeBrowseTooltip": "Sfoglia per cercare un tema GUI personalizzato", - "DockModeToggleTooltip": "Attiva o disabilta modalità TV", - "DirectKeyboardTooltip": "Attiva o disattiva \"il supporto all'accesso diretto alla tastiera (HID)\" (Fornisce l'accesso ai giochi alla tua tastiera come dispositivo di immissione del testo)", - "DirectMouseTooltip": "Attiva o disattiva \"il supporto all'accesso diretto al mouse (HID)\" (Fornisce l'accesso ai giochi al tuo mouse come dispositivo di puntamento)", - "RegionTooltip": "Cambia regione di sistema", - "LanguageTooltip": "Cambia lingua di sistema", - "TimezoneTooltip": "Cambia fuso orario di sistema", - "TimeTooltip": "Cambia data e ora di sistema", - "VSyncToggleTooltip": "Attiva o disattiva sincronizzazione verticale", - "PptcToggleTooltip": "Attiva o disattiva PPTC", - "FsIntegrityToggleTooltip": "Attiva controlli d'integrità sui file dei contenuti di gioco", - "AudioBackendTooltip": "Cambia backend audio", - "MemoryManagerTooltip": "Cambia il modo in cui la memoria guest è mappata e vi si accede. Influisce notevolmente sulle prestazioni della CPU emulata.", - "MemoryManagerSoftwareTooltip": "Usa una software page table per la traduzione degli indirizzi. Massima precisione ma prestazioni più lente.", - "MemoryManagerHostTooltip": "Mappa direttamente la memoria nello spazio degli indirizzi dell'host. Compilazione ed esecuzione JIT molto più veloce.", - "MemoryManagerUnsafeTooltip": "Mappa direttamente la memoria, ma non maschera l'indirizzo all'interno dello spazio degli indirizzi guest prima dell'accesso. Più veloce, ma a costo della sicurezza. L'applicazione guest può accedere alla memoria da qualsiasi punto di Ryujinx, quindi esegui solo programmi di cui ti fidi con questa modalità.", - "DRamTooltip": "Espande l'ammontare di memoria sul sistema emulato da 4GB A 6GB", - "IgnoreMissingServicesTooltip": "Attiva o disattiva l'opzione di ignorare i servizi mancanti", - "GraphicsBackendThreadingTooltip": "Attiva il Graphics Backend Multithreading", - "GalThreadingTooltip": "Esegue i comandi del backend grafico su un secondo thread. Permette il multithreading runtime della compilazione degli shader, riduce lo stuttering e migliora le prestazioni sui driver senza supporto multithreading proprio. Varia leggermente le prestazioni di picco sui driver con multithreading. Ryujinx potrebbe aver bisogno di essere riavviato per disabilitare correttamente il multithreading integrato nel driver, o potrebbe essere necessario farlo manualmente per ottenere le migliori prestazioni.", - "ShaderCacheToggleTooltip": "Attiva o disattiva la Shader Cache", - "ResolutionScaleTooltip": "Scala della risoluzione applicata ai render targets applicabili", - "ResolutionScaleEntryTooltip": "Scala della risoluzione in virgola mobile, come 1,5. Le scale non integrali hanno maggiori probabilità di causare problemi o crash.", - "AnisotropyTooltip": "Livello del filtro anisotropico (imposta su Auto per usare il valore richiesto dal gioco)", - "AspectRatioTooltip": "Rapporto d'aspetto applicato alla finestra del renderer.", - "ShaderDumpPathTooltip": "Percorso di dump Graphics Shaders", - "FileLogTooltip": "Attiva o disattiva il logging su file", - "StubLogTooltip": "Attiva messaggi stub log", - "InfoLogTooltip": "Attiva messaggi info log", - "WarnLogTooltip": "Attiva messaggi warning log", - "ErrorLogTooltip": "Attiva messaggi error log", - "TraceLogTooltip": "Attiva messaggi trace log", - "GuestLogTooltip": "Attiva messaggi guest log", - "FileAccessLogTooltip": "Attiva messaggi file access log", - "FSAccessLogModeTooltip": "Attiva output FS access log alla console. Le modalità possibili sono 0-3", - "DeveloperOptionTooltip": "Usa con attenzione", - "OpenGlLogLevel": "Richiede livelli di log appropriati abilitati", - "DebugLogTooltip": "Attiva messaggi debug log", - "LoadApplicationFileTooltip": "Apri un file explorer per scegliere un file compatibile Switch da caricare", - "LoadApplicationFolderTooltip": "Apri un file explorer per scegliere un file compatibile Switch, applicazione sfusa da caricare", - "OpenRyujinxFolderTooltip": "Apri la cartella del filesystem di Ryujinx", - "OpenRyujinxLogsTooltip": "Apre la cartella dove vengono scritti i log", - "ExitTooltip": "Esci da Ryujinx", - "OpenSettingsTooltip": "Apri finestra delle impostazioni", - "OpenProfileManagerTooltip": "Apri la finestra di gestione dei profili utente", - "StopEmulationTooltip": "Ferma l'emulazione del gioco attuale e torna alla selezione dei giochi", - "CheckUpdatesTooltip": "Controlla la presenza di aggiornamenti di Ryujinx", - "OpenAboutTooltip": "Apri finestra delle informazioni", - "GridSize": "Dimensione griglia", - "GridSizeTooltip": "Cambia la dimensione dei riquardi della griglia", - "SettingsTabSystemSystemLanguageBrazilianPortuguese": "Portoghese Brasiliano", - "AboutRyujinxContributorsButtonHeader": "Vedi tutti i Contributors", - "SettingsTabSystemAudioVolume": "Volume: ", - "AudioVolumeTooltip": "Cambia volume audio", - "SettingsTabSystemEnableInternetAccess": "Attiva Guest Internet Access", - "EnableInternetAccessTooltip": "Attiva il guest Internet access. Se abilitato, l'applicazione si comporterà come se la console Switch emulata fosse collegata a Internet. Si noti che in alcuni casi, le applicazioni possono comunque accedere a Internet anche con questa opzione disabilitata", - "GameListContextMenuManageCheatToolTip": "Gestisci Cheats", - "GameListContextMenuManageCheat": "Gestisci Cheats", - "ControllerSettingsStickRange": "Raggio:", - "DialogStopEmulationTitle": "Ryujinx - Ferma emulazione", - "DialogStopEmulationMessage": "Sei sicuro di voler fermare l'emulazione?", - "SettingsTabCpu": "CPU", - "SettingsTabAudio": "Audio", - "SettingsTabNetwork": "Rete", - "SettingsTabNetworkConnection": "Connessione di rete", - "SettingsTabCpuCache": "Cache CPU", - "SettingsTabCpuMemory": "Memoria CPU", - "DialogUpdaterFlatpakNotSupportedMessage": "Per favore aggiorna Ryujinx via FlatHub.", - "UpdaterDisabledWarningTitle": "Updater disabilitato!", - "GameListContextMenuOpenSdModsDirectory": "Apri cartella delle mods Atmosphere", - "GameListContextMenuOpenSdModsDirectoryToolTip": "Apre la cartella aternativa di atmosphere che contiene le mods dell'applicazione", - "ControllerSettingsRotate90": "Ruota in senso orario di 90°", - "IconSize": "Dimensioni icona", - "IconSizeTooltip": "Cambia le dimensioni dell'icona di un gioco", - "MenuBarOptionsShowConsole": "Mostra console", - "ShaderCachePurgeError" : "Errore nella pulizia della shader cache a {0}: {1}", - "UserErrorNoKeys": "Chiavi non trovate", - "UserErrorNoFirmware": "Firmware non trovato", - "UserErrorFirmwareParsingFailed": "Errori di analisi del firmware", - "UserErrorApplicationNotFound": "Applicazione non trovata", - "UserErrorUnknown": "Errore sconosciuto", - "UserErrorUndefined": "Errore non definito", - "UserErrorNoKeysDescription": "Ryujinx non è riuscito a trovare il file 'prod.keys'", - "UserErrorNoFirmwareDescription": "Ryujinx non è riuscito a trovare alcun firmware installato", - "UserErrorFirmwareParsingFailedDescription": "Ryujinx non è riuscito ad analizzare il firmware. Questo di solito è causato da chiavi non aggiornate.", - "UserErrorApplicationNotFoundDescription": "Ryujinx non è riuscito a trovare un'applicazione valida al percorso specificato.", - "UserErrorUnknownDescription": "Si è verificato un errore sconosciuto!", - "UserErrorUndefinedDescription": "Si è verificato un errore sconosciuto! Non dovrebbe succedere, per favore contatta uno sviluppatore!", - "OpenSetupGuideMessage": "Apri la guida all'installazione", - "NoUpdate": "Nessun aggiornamento", - "TitleUpdateVersionLabel": "Versione {0} - {1}", - "RyujinxInfo": "Ryujinx - Info", - "RyujinxConfirm": "Ryujinx - Conferma", - "FileDialogAllTypes": "Tutti i tipi", - "Never": "Mai", - "SwkbdMinCharacters": "Non può avere meno di {0} caratteri", - "SwkbdMinRangeCharacters": "Può avere da {0} a {1} caratteri", - "SoftwareKeyboard": "Tastiera software", - "DialogControllerAppletMessagePlayerRange": "L'applicazione richiede {0} giocatori con:\n\nTIPI: {1}\n\nGIOCATORI: {2}\n\n{3}Apri le impostazioni e riconfigura l'input adesso o premi Chiudi.", - "DialogControllerAppletMessage": "L'applicazione richiede esattamente {0} giocatori con:\n\nTIPI: {1}\n\nGIOCATORI: {2}\n\n{3}Apri le impostazioni e riconfigura l'input adesso o premi Chiudi.", - "DialogControllerAppletDockModeSet": "Modalità TV attivata. Neanche portatile è valida.\n\n", - "UpdaterRenaming": "Rinominazione dei vecchi files...", - "UpdaterRenameFailed": "L'updater non è riuscito a rinominare il file: {0}", - "UpdaterAddingFiles": "Aggiunta nuovi files...", - "UpdaterExtracting": "Estrazione aggiornamento...", - "UpdaterDownloading": "Download aggiornamento...", - "Game": "Gioco", - "Docked": "TV", - "Handheld": "Portatile", - "ConnectionError": "Errore di connessione.", - "AboutPageDeveloperListMore": "{0} e altri ancora...", - "ApiError": "Errore dell'API.", - "LoadingHeading": "Caricamento di {0}", - "CompilingPPTC": "Compilazione PTC", - "CompilingShaders": "Compilazione Shaders", - "AllKeyboards": "Tutte le tastiere", - "OpenFileDialogTitle": "Seleziona un file supportato da aprire", - "OpenFolderDialogTitle": "Seleziona una cartella con un gioco estratto", - "AllSupportedFormats": "Tutti i formati supportati", - "RyujinxUpdater": "Ryujinx Updater", - "SettingsTabHotkeys": "Tasti di scelta rapida", - "SettingsTabHotkeysHotkeys": "Tasti di scelta rapida", - "SettingsTabHotkeysToggleVsyncHotkey": "VSync:", - "SettingsTabHotkeysScreenshotHotkey": "Screenshot:", - "SettingsTabHotkeysShowUiHotkey": "Mostra UI:", - "SettingsTabHotkeysPauseHotkey": "Metti in pausa:", - "SettingsTabHotkeysToggleMuteHotkey": "Muta:", - "ControllerMotionTitle": "Impostazioni dei sensori di movimento", - "ControllerRumbleTitle": "Impostazioni di vibrazione", - "SettingsSelectThemeFileDialogTitle" : "Seleziona file del tema", - "SettingsXamlThemeFile" : "File del tema xaml", - "SettingsTabHotkeysResScaleUpHotkey": "Aumentare la risoluzione:", - "SettingsTabHotkeysResScaleDownHotkey": "Diminuire la risoluzione:" -} diff --git a/Ryujinx.Ava/Assets/Locales/ko_KR.json b/Ryujinx.Ava/Assets/Locales/ko_KR.json deleted file mode 100644 index 34253314f..000000000 --- a/Ryujinx.Ava/Assets/Locales/ko_KR.json +++ /dev/null @@ -1,494 +0,0 @@ -{ - "MenuBarFileOpenApplet": "애플릿 열기", - "MenuBarFileOpenAppletOpenMiiAppletToolTip": "독립 실행형 모드에서 Mii 편집기 애플릿 열기", - "SettingsTabInputDirectMouseAccess": "직접 마우스 액세스", - "SettingsTabSystemMemoryManagerMode": "메모리 관리자 모드 :", - "SettingsTabSystemMemoryManagerModeSoftware": "소프트웨어", - "SettingsTabSystemMemoryManagerModeHost": "호스트 (빠른)", - "SettingsTabSystemMemoryManagerModeHostUnchecked": "호스트가 확인되지 않음 (가장 빠르고 안전하지 않은)", - "MenuBarFile": "_파일", - "MenuBarFileOpenFromFile": "_서류철음에서 애플리케이션 로드", - "MenuBarFileOpenUnpacked": "_압축을 푼 게임 로드", - "MenuBarFileOpenEmuFolder": "Ryujinx 폴더 열기", - "MenuBarFileOpenLogsFolder": "로그 폴더 열기", - "MenuBarFileExit": "_그만두", - "MenuBarOptions": "옵션", - "MenuBarOptionsToggleFullscreen": "전체 화면 전환", - "MenuBarOptionsStartGamesInFullscreen": "전체 화면 모드에서 게임 열기", - "MenuBarOptionsStopEmulation": "에뮬레이션 중지", - "MenuBarOptionsSettings": "_조절", - "MenuBarOptionsManageUserProfiles": "사용자 프로필 _관리", - "MenuBarActions": "_행위", - "MenuBarOptionsSimulateWakeUpMessage": "깨우기 명령어 시뮬레이션", - "MenuBarActionsScanAmiibo": "Amiibo 스캔", - "MenuBarTools": "_도구", - "MenuBarToolsInstallFirmware": "펌웨어 설치", - "MenuBarFileToolsInstallFirmwareFromFile": "XCI 또는 ZIP에서 펌웨어 설치", - "MenuBarFileToolsInstallFirmwareFromDirectory": "디렉토리에서 펌웨어 설치", - "MenuBarHelp": "돕다", - "MenuBarHelpCheckForUpdates": "업데이트 확인", - "MenuBarHelpAbout": "통지", - "MenuSearch": "찾다···", - "GameListHeaderFavorite": "즐겨찾기", - "GameListHeaderIcon": "상", - "GameListHeaderApplication": "이름", - "GameListHeaderDeveloper": "개발자", - "GameListHeaderVersion": "버전", - "GameListHeaderTimePlayed": "플레이 시간", - "GameListHeaderLastPlayed": "해본 마지막", - "GameListHeaderFileExtension": "파일 확장자", - "GameListHeaderFileSize": "파일 크기", - "GameListHeaderPath": "파일 경로", - "GameListContextMenuOpenUserSaveDirectory": "사용자 저장 폴더 열기", - "GameListContextMenuOpenUserSaveDirectoryToolTip": "응용 프로그램의 사용자 저장이 포함된 폴더를 엽니다", - "GameListContextMenuOpenUserDeviceDirectory": "사용자 장치 폴더 열기", - "GameListContextMenuOpenUserDeviceDirectoryToolTip": "응용 프로그램의 장치 저장이 포함된 폴더를 엽니다", - "GameListContextMenuOpenUserBcatDirectory": "사용자의 BCAT 폴더 열기", - "GameListContextMenuOpenUserBcatDirectoryToolTip": "응용 프로그램의 BCAT 저장이 포함된 폴더를 엽니다", - "GameListContextMenuManageTitleUpdates": "타이틀 업데이트 관리s", - "GameListContextMenuManageTitleUpdatesToolTip": "타이틀 업데이트 관리 창 열기", - "GameListContextMenuManageDlc": "DLC 관리", - "GameListContextMenuManageDlcToolTip": "DLC 관리 창 열기", - "GameListContextMenuOpenModsDirectory": "모드 디렉토리 열기", - "GameListContextMenuOpenModsDirectoryToolTip": "응용 프로그램의 모드가들 포함된 디렉터리를 엽니다", - "GameListContextMenuCacheManagement": "캐시 관리", - "GameListContextMenuCacheManagementPurgePptc": "PPTC 캐시 제거", - "GameListContextMenuCacheManagementPurgePptcToolTip": "응용 프로그램 PPTC 캐시 삭제", - "GameListContextMenuCacheManagementPurgeShaderCache": "셰이더 캐시 제거", - "GameListContextMenuCacheManagementPurgeShaderCacheToolTip": "애플리케이션 셰이더 캐시를 삭제합니다.", - "GameListContextMenuCacheManagementOpenPptcDirectory": "PPTC 디렉토리 열기", - "GameListContextMenuCacheManagementOpenPptcDirectoryToolTip": "응용 프로그램 PPTC 캐시가 포함된 디렉터리를 엽니다", - "GameListContextMenuCacheManagementOpenShaderCacheDirectory": "셰이더 캐시 디렉토리 열기", - "GameListContextMenuCacheManagementOpenShaderCacheDirectoryToolTip": "응용 프로그램 셰이더 캐시가 포함된 디렉터리를 엽니다", - "GameListContextMenuExtractData": "데이터 추출", - "GameListContextMenuExtractDataExeFS": "ExeFS", - "GameListContextMenuExtractDataExeFSToolTip": "애플리케이션의 현재 구성에서 ExeFS 추출 (업데이트 포함)", - "GameListContextMenuExtractDataRomFS": "RomFS", - "GameListContextMenuExtractDataRomFSToolTip": "애플리케이션의 현재 구성에서 RomFS 추출 (업데이트 포함)", - "GameListContextMenuExtractDataLogo": "Logo", - "GameListContextMenuExtractDataLogoToolTip": "애플리케이션의 현재 구성에서 로고 섹션 추출 (업데이트 포함)", - "StatusBarGamesLoaded": "로드된 {0}/{1}개의 게임", - "StatusBarSystemVersion": "시스템 버전 : {0}", - "Settings": "조절", - "SettingsTabGeneral": "사용자 인터페이스", - "SettingsTabGeneralGeneral": "일반", - "SettingsTabGeneralEnableDiscordRichPresence": "Discord Rich Presence 활성화", - "SettingsTabGeneralCheckUpdatesOnLaunch": "열 때 업데이트 확인", - "SettingsTabGeneralShowConfirmExitDialog": "\"종료 확인\" 대화 상자 표시", - "SettingsTabGeneralHideCursorOnIdle": "유휴 상태에서 커서 숨기기", - "SettingsTabGeneralGameDirectories": "게임 디렉토리들", - "SettingsTabGeneralAdd": "추가하다", - "SettingsTabGeneralRemove": "제거하다", - "SettingsTabSystem": "체계", - "SettingsTabSystemCore": "핵심", - "SettingsTabSystemSystemRegion": "시스템 영역 :", - "SettingsTabSystemSystemRegionJapan": "일본", - "SettingsTabSystemSystemRegionUSA": "미국", - "SettingsTabSystemSystemRegionEurope": "유럽", - "SettingsTabSystemSystemRegionAustralia": "호주", - "SettingsTabSystemSystemRegionChina": "중국", - "SettingsTabSystemSystemRegionKorea": "한국", - "SettingsTabSystemSystemRegionTaiwan": "대만", - "SettingsTabSystemSystemLanguage": "시스템 언어 :", - "SettingsTabSystemSystemLanguageJapanese": "일본어", - "SettingsTabSystemSystemLanguageAmericanEnglish": "영어(미국)", - "SettingsTabSystemSystemLanguageFrench": "프랑스어", - "SettingsTabSystemSystemLanguageGerman": "독일어", - "SettingsTabSystemSystemLanguageItalian": "이탈리아어", - "SettingsTabSystemSystemLanguageSpanish": "스페인어", - "SettingsTabSystemSystemLanguageChinese": "중국어", - "SettingsTabSystemSystemLanguageKorean": "한국어", - "SettingsTabSystemSystemLanguageDutch": "네덜란드 어", - "SettingsTabSystemSystemLanguagePortuguese": "포르투갈어", - "SettingsTabSystemSystemLanguageRussian": "러시아어", - "SettingsTabSystemSystemLanguageTaiwanese": "대만어", - "SettingsTabSystemSystemLanguageBritishEnglish": "영어(영국)", - "SettingsTabSystemSystemLanguageCanadianFrench": "프랑스어(캐나다)", - "SettingsTabSystemSystemLanguageLatinAmericanSpanish": "스페인어(라틴 아메리카)", - "SettingsTabSystemSystemLanguageSimplifiedChinese": "중국어 간체", - "SettingsTabSystemSystemLanguageTraditionalChinese": "중국어 번체", - "SettingsTabSystemSystemTimeZone": "시스템 시간대 :", - "SettingsTabSystemSystemTime": "시스템 시간 :", - "SettingsTabSystemEnableVsync": "수직 동기화 사용", - "SettingsTabSystemEnablePptc": "PPTC(Profiled Persistent Translation Cache) 활성화", - "SettingsTabSystemEnableFsIntegrityChecks": "FS 무결성 검사 활성화", - "SettingsTabSystemAudioBackend": "오디오 백엔드 :", - "SettingsTabSystemAudioBackendDummy": "Dummy", - "SettingsTabSystemAudioBackendOpenAL": "OpenAL", - "SettingsTabSystemAudioBackendSoundIO": "SoundIO", - "SettingsTabSystemAudioBackendSDL2": "SDL2", - "SettingsTabSystemHacks": "해킹", - "SettingsTabSystemHacksNote": " (불안정을 일으킬 수 있음)", - "SettingsTabSystemExpandDramSize": "DRAM 크기를 6GB로 확장", - "SettingsTabSystemIgnoreMissingServices": "누락된 서비스 무시", - "SettingsTabGraphics": "제도법", - "SettingsTabGraphicsAPI": "그래픽 API", - "SettingsTabGraphicsEnableShaderCache": "셰이더 캐시 활성화", - "SettingsTabGraphicsAnisotropicFiltering": "이방성 필터링 :", - "SettingsTabGraphicsAnisotropicFilteringAuto": "자동적 인", - "SettingsTabGraphicsAnisotropicFiltering2x": "2x", - "SettingsTabGraphicsAnisotropicFiltering4x": "4x", - "SettingsTabGraphicsAnisotropicFiltering8x": "8x", - "SettingsTabGraphicsAnisotropicFiltering16x": "16x", - "SettingsTabGraphicsResolutionScale": "해상도 스케일 :", - "SettingsTabGraphicsResolutionScaleCustom": "사용자 지정(권장하지 않음)", - "SettingsTabGraphicsResolutionScaleNative": "기본 (720p/1080p)", - "SettingsTabGraphicsResolutionScale2x": "2x (1440p/2160p)", - "SettingsTabGraphicsResolutionScale3x": "3x (2160p/3240p)", - "SettingsTabGraphicsResolutionScale4x": "4x (2880p/4320p)", - "SettingsTabGraphicsAspectRatio": "종횡비 :", - "SettingsTabGraphicsAspectRatio4x3": "4:3", - "SettingsTabGraphicsAspectRatio16x9": "16:9", - "SettingsTabGraphicsAspectRatio16x10": "16:10", - "SettingsTabGraphicsAspectRatio21x9": "21:9", - "SettingsTabGraphicsAspectRatio32x9": "32:9", - "SettingsTabGraphicsAspectRatioStretch": "창에 맞게 늘리기", - "SettingsTabGraphicsDeveloperOptions": "개발자 옵션", - "SettingsTabGraphicsShaderDumpPath": "그래픽 쉐이더 덤프 경로 :", - "SettingsTabLogging": "로깅", - "SettingsTabLoggingLogging": "로깅", - "SettingsTabLoggingEnableLoggingToFile": "파일에 로깅 활성화", - "SettingsTabLoggingEnableStubLogs": "스텁 로그 켜기 ", - "SettingsTabLoggingEnableInfoLogs": "정보 로그 켜기", - "SettingsTabLoggingEnableWarningLogs": "경고 로그 켜기", - "SettingsTabLoggingEnableErrorLogs": "오류 로그 켜기", - "SettingsTabLoggingEnableGuestLogs": "게스트 로그 켜기", - "SettingsTabLoggingEnableFsAccessLogs": "Fs 액세스 로그 켜기", - "SettingsTabLoggingFsGlobalAccessLogMode": "Fs 전역 액세스 로그 모드 :", - "SettingsTabLoggingDeveloperOptions": "개발자 옵션 (경고 : 성능이 저하됩니다.)", - "SettingsTabLoggingOpenglLogLevel": "OpenGL 로그 수준 :", - "SettingsTabLoggingOpenglLogLevelNone": "없음", - "SettingsTabLoggingOpenglLogLevelError": "오류", - "SettingsTabLoggingOpenglLogLevelPerformance": "감속", - "SettingsTabLoggingOpenglLogLevelAll": "모두", - "SettingsTabLoggingEnableDebugLogs": "디버그 로그 사용", - "SettingsTabInput": "입력", - "SettingsTabInputEnableDockedMode": "도킹 모드 활성화", - "SettingsTabInputDirectKeyboardAccess": "직접 키보드 액세스", - "SettingsButtonSave": "구하다", - "SettingsButtonClose": "출구", - "SettingsButtonApply": "적용하다", - "ControllerSettingsPlayer": "플레이어", - "ControllerSettingsPlayer1": "플레이어 1", - "ControllerSettingsPlayer2": "플레이어 2", - "ControllerSettingsPlayer3": "플레이어 3", - "ControllerSettingsPlayer4": "플레이어 4", - "ControllerSettingsPlayer5": "플레이어 5", - "ControllerSettingsPlayer6": "플레이어 6", - "ControllerSettingsPlayer7": "플레이어 7", - "ControllerSettingsPlayer8": "플레이어 8", - "ControllerSettingsHandheld": "휴대용", - "ControllerSettingsInputDevice": "입력 장치", - "ControllerSettingsRefresh": "새로 고치다", - "ControllerSettingsDeviceDisabled": "장애가있는", - "ControllerSettingsControllerType": "컨트롤러 유형", - "ControllerSettingsControllerTypeHandheld": "휴대용", - "ControllerSettingsControllerTypeProController": "Pro Controller", - "ControllerSettingsControllerTypeJoyConPair": "JoyCon 페어", - "ControllerSettingsControllerTypeJoyConLeft": "JoyCon 왼쪽", - "ControllerSettingsControllerTypeJoyConRight": "JoyCon 오른쪽", - "ControllerSettingsProfile": "프로필", - "ControllerSettingsProfileDefault": "기본", - "ControllerSettingsLoad": "짐", - "ControllerSettingsAdd": "추가하다", - "ControllerSettingsRemove": "제거하다", - "ControllerSettingsButtons": "버튼", - "ControllerSettingsButtonA": "A", - "ControllerSettingsButtonB": "B", - "ControllerSettingsButtonX": "X", - "ControllerSettingsButtonY": "Y", - "ControllerSettingsButtonPlus": "+", - "ControllerSettingsButtonMinus": "-", - "ControllerSettingsDPad": "Directional Pad", - "ControllerSettingsDPadUp": "위로", - "ControllerSettingsDPadDown": "아래에", - "ControllerSettingsDPadLeft": "왼쪽", - "ControllerSettingsDPadRight": "오른쪽", - "ControllerSettingsLStick": "왼쪽 스틱", - "ControllerSettingsLStickButton": "단추", - "ControllerSettingsLStickUp": "위로", - "ControllerSettingsLStickDown": "아래에", - "ControllerSettingsLStickLeft": "왼쪽", - "ControllerSettingsLStickRight": "오른쪽", - "ControllerSettingsLStickStick": "막대", - "ControllerSettingsLStickInvertXAxis": "스틱 X축 반전", - "ControllerSettingsLStickInvertYAxis": "스틱 Y축 반전", - "ControllerSettingsLStickDeadzone": "데드 존 :", - "ControllerSettingsRStick": "오른쪽 스틱", - "ControllerSettingsRStickButton": "단추", - "ControllerSettingsRStickUp": "위로", - "ControllerSettingsRStickDown": "아래에", - "ControllerSettingsRStickLeft": "왼쪽", - "ControllerSettingsRStickRight": "오른쪽", - "ControllerSettingsRStickStick": "Stick", - "ControllerSettingsRStickInvertXAxis": "스틱 X축 반전", - "ControllerSettingsRStickInvertYAxis": "스틱 Y축 반전", - "ControllerSettingsRStickDeadzone": "데드 존 :", - "ControllerSettingsTriggersLeft": "왼쪽 트리거", - "ControllerSettingsTriggersRight": "오른쪽 트리거", - "ControllerSettingsTriggersButtonsLeft": "트리거 버튼 왼쪽", - "ControllerSettingsTriggersButtonsRight": "트리거 버튼 오른쪽", - "ControllerSettingsTriggers": "방아쇠", - "ControllerSettingsTriggerL": "L", - "ControllerSettingsTriggerR": "R", - "ControllerSettingsTriggerZL": "ZL", - "ControllerSettingsTriggerZR": "ZR", - "ControllerSettingsLeftSL": "SL", - "ControllerSettingsLeftSR": "SR", - "ControllerSettingsRightSL": "SL", - "ControllerSettingsRightSR": "SR", - "ControllerSettingsExtraButtonsLeft": "왼쪽 버튼", - "ControllerSettingsExtraButtonsRight": "버튼 오른쪽", - "ControllerSettingsMisc": "여러 가지 잡다한", - "ControllerSettingsTriggerThreshold": "트리거 임계값 :", - "ControllerSettingsMotion": "운동", - "ControllerSettingsMotionUseCemuhookCompatibleMotion": "CemuHook 호환 모션 사용", - "ControllerSettingsMotionControllerSlot": "컨트롤러 슬롯 :", - "ControllerSettingsMotionMirrorInput": "미러 입력", - "ControllerSettingsMotionRightJoyConSlot": "오른쪽 JoyCon 슬롯 :", - "ControllerSettingsMotionServerHost": "서버 호스트 :", - "ControllerSettingsMotionGyroSensitivity": "자이로 감도 :", - "ControllerSettingsMotionGyroDeadzone": "자이로 데드존 :", - "ControllerSettingsSave": "구하다", - "ControllerSettingsClose": "출구", - "UserProfilesSelectedUserProfile": "선택한 사용자 프로필 :", - "UserProfilesSaveProfileName": "프로필 이름 저장", - "UserProfilesChangeProfileImage": "프로필 이미지 변경", - "UserProfilesAvailableUserProfiles": "사용 가능한 사용자 프로필 :", - "UserProfilesAddNewProfile": "새 프로필 추가", - "UserProfilesDeleteSelectedProfile": "선택한 프로필 삭제", - "UserProfilesClose": "출구", - "ProfileImageSelectionTitle": "프로필 이미지 선택", - "ProfileImageSelectionHeader": "이미지 선택", - "ProfileImageSelectionNote": "사용자 정의 프로필 이미지를 사용하거나 시스템 펌웨어에서 하나를 선택할 수 있습니다", - "ProfileImageSelectionImportImage": "이미지 파일 가져오기", - "ProfileImageSelectionSelectAvatar": "펌웨어 아바타 선택", - "InputDialogTitle": "입력 대화 상자", - "InputDialogOk": "확인", - "InputDialogCancel": "취소", - "InputDialogAddNewProfileTitle": "프로필 이름 선택", - "InputDialogAddNewProfileHeader": "프로필 이름을 입력하세요", - "InputDialogAddNewProfileSubtext": "최대 길이 : {0})", - "AvatarChoose": "선택하다", - "AvatarSetBackgroundColor": "배경색 설정", - "AvatarClose": "출구", - "ControllerSettingsLoadProfileToolTip": "프로필 로드", - "ControllerSettingsAddProfileToolTip": "프로필 추가", - "ControllerSettingsRemoveProfileToolTip": "프로필 제거", - "ControllerSettingsSaveProfileToolTip": "프로필 저장", - "MenuBarFileToolsTakeScreenshot": "스크린 샷을 찍다", - "MenuBarFileToolsHideUi": "사용자 인터페이스 숨기기", - "GameListContextMenuToggleFavorite": "즐겨찾기 설정", - "GameListContextMenuToggleFavoriteToolTip": "이 게임이 즐겨찾기인지 여부를 전환합니다", - "SettingsTabGeneralTheme": "테마", - "SettingsTabGeneralThemeCustomTheme": "사용자 정의 테마 경로", - "SettingsTabGeneralThemeBaseStyle": "기본 스타일", - "SettingsTabGeneralThemeBaseStyleDark": "어두운", - "SettingsTabGeneralThemeBaseStyleLight": "빛", - "SettingsTabGeneralThemeEnableCustomTheme": "사용자 정의 테마 활성화", - "ButtonBrowse": "검색", - "ControllerSettingsConfigureGeneral": "션 구성", - "ControllerSettingsRumble": "하인 좌석", - "ControllerSettingsRumbleStrongMultiplier": "강력한 럼블 배율기", - "ControllerSettingsRumbleWeakMultiplier": "약한 럼블 승수", - "DialogMessageSaveNotAvailableMessage": "에 대한 세이브 데이터가 없습니다 {0} [{1:x16}]", - "DialogMessageSaveNotAvailableCreateSaveMessage": "이 게임의 세이브 데이터를 생성하시겠습니까?", - "DialogConfirmationTitle": "Ryujinx - 확인", - "DialogUpdaterTitle": "Ryujinx - 업데이터", - "DialogErrorTitle": "Ryujinx - 오류", - "DialogWarningTitle": "Ryujinx - 경고", - "DialogExitTitle": "Ryujinx - 출구", - "DialogErrorMessage": "Ryujinx에 오류가 발생했습니다", - "DialogExitMessage": "Ryujinx를 종료하시겠습니까?", - "DialogExitSubMessage": "저장하지 않은 모든 데이터는 손실됩니다!", - "DialogMessageCreateSaveErrorMessage": "지정된 세이브 데이터를 작성하는 중에 오류가 발생했습니다 : {0}", - "DialogMessageFindSaveErrorMessage": "지정된 저장 데이터를 찾는 중에 오류가 발생했습니다 : {0}", - "FolderDialogExtractTitle": "추출할 폴더 선택", - "DialogNcaExtractionMessage": "{1}에서 섹션 {0} 추출···", - "DialogNcaExtractionTitle": "Ryujinx - NCA 섹션 추출기", - "DialogNcaExtractionMainNcaNotFoundErrorMessage": "추출 실패. 선택한 파일에 기본 NCA가 없습니다.", - "DialogNcaExtractionCheckLogErrorMessage": "추출 실패. 자세한 내용은 로그 파일을 읽으십시오.", - "DialogNcaExtractionSuccessMessage": "추출이 성공적으로 완료되었습니다.", - "DialogUpdaterConvertFailedMessage": "현재 Ryujinx 버전을 변환하지 못했습니다.", - "DialogUpdaterCancelUpdateMessage": "업데이트 취소 중!", - "DialogUpdaterAlreadyOnLatestVersionMessage": "이미 최신 버전의 Ryujinx를 사용하고 있습니다!", - "DialogUpdaterFailedToGetVersionMessage": "Github 릴리스에서 릴리스 정보를 가져오는 중에 오류가 발생했습니다. 이는 GitHub Actions에서 새 릴리스를 컴파일하는 경우 발생할 수 있습니다. 몇 분 후에 다시 시도하십시오.", - "DialogUpdaterConvertFailedGithubMessage": "Github Release에서 받은 Ryujinx 버전을 변환하지 못했습니다.", - "DialogUpdaterDownloadingMessage": "업데이트 다운로드 중···", - "DialogUpdaterExtractionMessage": "업데이트 추출···", - "DialogUpdaterRenamingMessage": "업데이트 이름 바꾸기···", - "DialogUpdaterAddingFilesMessage": "새 업데이트 추가···", - "DialogUpdaterCompleteMessage": "업데이트 완료!", - "DialogUpdaterRestartMessage": "지금 Ryujinx를 다시 시작하시겠습니까?", - "DialogUpdaterArchNotSupportedMessage": "지원되는 시스템 아키텍처를 실행하고 있지 않습니다!", - "DialogUpdaterArchNotSupportedSubMessage": "(x86 시스템만 지원됩니다!)", - "DialogUpdaterNoInternetMessage": "인터넷에 연결되어 있지 않습니다!", - "DialogUpdaterNoInternetSubMessage": "인터넷 연결이 작동하는지 확인하십시오!", - "DialogUpdaterDirtyBuildMessage": "Ryujinx의 더러운 빌드는 업데이트할 수 없습니다!", - "DialogUpdaterDirtyBuildSubMessage": "지원되는 버전을 찾고 있다면 https://ryujinx.org/에서 Ryujinx를 다운로드하십시오.", - "DialogRestartRequiredMessage": "재시작 필요", - "DialogThemeRestartMessage": "테마가 저장되었습니다. 테마를 적용하려면 다시 시작해야 합니다.", - "DialogThemeRestartSubMessage": "다시 시작하시겠습니까?", - "DialogFirmwareInstallEmbeddedMessage": "이 게임에 내장된 펌웨어를 설치하시겠습니까? (펌웨어 {0})", - "DialogFirmwareInstallEmbeddedSuccessMessage": "설치된 펌웨어를 찾을 수 없지만 Ryujinx는 제공된 게임에서 펌웨어 {0} 설치할 수 있었습니다.\n이제 에뮬레이터가 시작됩니다.", - "DialogFirmwareNoFirmwareInstalledMessage": "펌웨어가 설치되지 않았습니다", - "DialogFirmwareInstalledMessage": "펌웨어 {0} 설치되었습니다.", - "DialogOpenSettingsWindowLabel": "설정 창 열기", - "DialogControllerAppletTitle": "컨트롤러 애플릿", - "DialogMessageDialogErrorExceptionMessage": "메시지 대화 상자를 표시하는 동안 오류가 발생했습니다 : {0}", - "DialogSoftwareKeyboardErrorExceptionMessage": "소프트웨어 키보드를 표시하는 동안 오류가 발생했습니다 : {0}", - "DialogErrorAppletErrorExceptionMessage": "ErrorApplet 대화 상자를 표시하는 동안 오류가 발생했습니다 : {0}", - "DialogUserErrorDialogMessage": "{0}: {1}", - "DialogUserErrorDialogInfoMessage": "\n이 오류를 수정하는 방법에 대한 자세한 내용은 설정 가이드를 따르십시오", - "DialogUserErrorDialogTitle": "Ryuijnx의 오류 ({0})", - "DialogAmiiboApiTitle": "Amiibo API", - "DialogAmiiboApiFailFetchMessage": "API에서 정보를 가져오는 동안 오류가 발생했습니다.", - "DialogAmiiboApiConnectErrorMessage": "Amiibo API 서버에 연결할 수 없습니다. 서비스가 다운되었거나 인터넷 연결이 오프라인인지 확인해야 할 수 있습니다.", - "DialogProfileInvalidProfileErrorMessage": "프로필 AAA는 현재 입력 구성 시스템과 호환되지 않습니다.", - "DialogProfileDefaultProfileOverwriteErrorMessage": "기본 프로필을 덮어쓸 수 없습니다", - "DialogProfileDeleteProfileTitle": "프로필 삭제", - "DialogProfileDeleteProfileMessage": "이 작업은 되돌릴 수 없습니다. 계속하시겠습니까?", - "DialogWarning": "경고", - "DialogPPTCDeletionMessage": "{0}에\n\n 대한 PPTC 캐시를 삭제하려고 합니다.\n\n계속하시겠습니까?", - "DialogPPTCDeletionErrorMessage": "{0} : {1}에서 PPTC 캐시를 제거하는 동안 오류가 발생했습니다.", - "DialogShaderDeletionMessage": "{0}에\n\n 대한 셰이더 캐시를 삭제하려고 합니다.\n\n계속하시겠습니까?", - "DialogShaderDeletionErrorMessage": "{0} : {1}에서 셰이더 캐시를 제거하는 동안 오류가 발생했습니다.", - "DialogRyujinxErrorMessage": "Ryujinx에 오류가 발생했습니다", - "DialogInvalidTitleIdErrorMessage": "UI 오류 : 선택한 게임에 유효한 제목 ID가 없습니다", - "DialogFirmwareInstallerFirmwareNotFoundErrorMessage": "{0}에서 유효한 시스템 펌웨어를 찾을 수 없습니다.", - "DialogFirmwareInstallerFirmwareInstallTitle": "펌웨어 {0} 설치", - "DialogFirmwareInstallerFirmwareInstallMessage": "시스템 버전 {0}가 설치되려고 합니다", - "DialogFirmwareInstallerFirmwareInstallSubMessage": "\n\n이것은 현재 설치된 버전 {0}를 대체합니다.", - "DialogFirmwareInstallerFirmwareInstallConfirmMessage": "\n\n계속하시겠습니까?", - "DialogFirmwareInstallerFirmwareInstallWaitMessage": "펌웨어 설치···", - "DialogFirmwareInstallerFirmwareInstallSuccessMessage": "시스템 버전 {0}가 성공적으로 설치되었습니다.", - "DialogUserProfileDeletionWarningMessage": "선택한 프로필이 삭제되면 사용 가능한 다른 프로필이 없습니다", - "DialogUserProfileDeletionConfirmMessage": "선택한 프로필을 삭제하시겠습니까", - "DialogControllerSettingsModifiedConfirmMessage": "현재 컨트롤러 설정이 업데이트되었습니다.", - "DialogControllerSettingsModifiedConfirmSubMessage": "저장하시겠습니까?", - "DialogDlcLoadNcaErrorMessage": "{0}. 오류 파일 : {1}", - "DialogDlcNoDlcErrorMessage": "지정한 파일에 선택한 타이틀의 DLC가 없습니다!", - "DialogPerformanceCheckLoggingEnabledMessage": "개발자 전용으로 설계된 디버그 로깅을 활성화했습니다.", - "DialogPerformanceCheckLoggingEnabledConfirmMessage": "최적의 성능을 위해 디버그 로깅을 비활성화하는 것이 좋습니다. 지금 디버그 로깅을 비활성화하시겠습니까?", - "DialogPerformanceCheckShaderDumpEnabledMessage": "Y개발자만 사용하도록 설계된 셰이더 덤핑이 활성화되어 있습니다.", - "DialogPerformanceCheckShaderDumpEnabledConfirmMessage": "최적의 성능을 위해 셰이더 덤핑을 비활성화하는 것이 좋습니다. 지금 셰이더 덤핑을 비활성화하시겠습니까?", - "DialogLoadAppGameAlreadyLoadedMessage": "다른 게임이 이미 로드되었습니다", - "DialogLoadAppGameAlreadyLoadedSubMessage": "다른 게임을 시작하기 전에 에뮬레이션을 중지하거나 에뮬레이터를 닫으십시오.", - "DialogUpdateAddUpdateErrorMessage": "파일에 선택한 제목에 대한 업데이트가 포함되어 있지 않습니다!", - "DialogSettingsBackendThreadingWarningTitle": "경고 - 백엔드 스레딩", - "DialogSettingsBackendThreadingWarningMessage": "변경 사항을 완전히 적용하려면 이 옵션을 변경한 후 Ryujinx를 다시 시작해야 합니다. 플랫폼에 따라 Ryujinx를 사용할 때 드라이버 자체의 멀티스레딩을 수동으로 비활성화해야 할 수도 있습니다.", - "SettingsTabGraphicsFeaturesOptions": "특징", - "SettingsTabGraphicsBackendMultithreading": "그래픽 백엔드 멀티스레딩 :", - "CommonAuto": "자동적 인", - "CommonOff": "끄다", - "CommonOn": "켜짐", - "InputDialogYes": "네", - "InputDialogNo": "아니", - "DialogProfileInvalidProfileNameErrorMessage": "파일 이름에 잘못된 기호가 있습니다. 다시 시도하십시오.", - "MenuBarOptionsPauseEmulation": "정지시키다", - "MenuBarOptionsResumeEmulation": "재개하다", - "AboutUrlTooltipMessage": "기본 브라우저에서 Ryujinx 웹사이트를 열려면 클릭하십시오.", - "AboutDisclaimerMessage": "Ryujinx는 Nintendo™와 제휴하지 않으며,\n어떤 식으로든 또는 그 파트너.", - "AboutAmiiboDisclaimerMessage": "AmiiboAPI(www.amiiboapi.com) 사용\nAmiibo 에뮬레이션에서.", - "AboutPatreonUrlTooltipMessage": "기본 브라우저에서 Ryujinx Patreon 페이지를 열려면 클릭하세요.", - "AboutGithubUrlTooltipMessage": "클릭하여 기본 브라우저에서 Ryujinx GitHub 페이지를 엽니다.", - "AboutDiscordUrlTooltipMessage": "기본 브라우저에서 Ryujinx Discord 서버 초대를 열려면 클릭하세요.", - "AboutTwitterUrlTooltipMessage": "클릭하여 기본 브라우저에서 Ryujinx Twitter 페이지를 엽니다.", - "AboutRyujinxAboutTitle": "에 대한 :", - "AboutRyujinxAboutContent": "Ryujinx는 Nintendo Switch™용 에뮬레이터입니다.\nPatreon에서 지원해 주세요.\n모든 최신 뉴스는 Twitter 또는 Discord에서 확인하세요.\n기고에 관심이 있는 개발자는 GitHub 또는 Discord에서 자세한 내용을 확인할 수 있습니다.", - "AboutRyujinxMaintainersTitle": "유지 관리 :", - "AboutRyujinxMaintainersContentTooltipMessage": "기본 브라우저에서 기여자 페이지를 열려면 클릭하십시오.", - "AboutRyujinxSupprtersTitle": "Patreon에서 지원 :", - "AmiiboSeriesLabel": "Amiibo 시리즈", - "AmiiboCharacterLabel": "성격", - "AmiiboScanButtonLabel": "스캔", - "AmiiboOptionsShowAllLabel": "모든 Amiibo 표시", - "AmiiboOptionsUsRandomTagLabel": "해킹: 임의의 태그 UUID 사용", - "DlcManagerTableHeadingEnabledLabel": "활성화됨", - "DlcManagerTableHeadingTitleIdLabel": "제목 ID", - "DlcManagerTableHeadingContainerPathLabel": "컨테이너 경로", - "DlcManagerTableHeadingFullPathLabel": "전체 경로", - "DlcManagerRemoveAllButton": "모두 제거", - "MenuBarOptionsChangeLanguage": "언어 변경", - "CommonSort": "정렬", - "CommonShowNames": "이름 표시", - "CommonFavorite": "가장 좋아하는", - "OrderAscending": "오름차순", - "OrderDescending": "내림차순", - "SettingsTabGraphicsFeatures": "특징ㆍ개선 사항", - "ErrorWindowTitle": "오류 창", - "ToggleDiscordTooltip": "Discord Rich Presence 활성화 또는 비활성화", - "AddGameDirBoxTooltip": "게임 디렉토리를 입력하여 목록에 추가하세요", - "AddGameDirTooltip": "목록에 게임 디렉토리 추가", - "RemoveGameDirTooltip": "선택한 게임 디렉토리 제거", - "CustomThemeCheckTooltip": "GUI에서 사용자 정의 테마 활성화 또는 비활성화", - "CustomThemePathTooltip": "사용자 지정 GUI 테마 경로", - "CustomThemeBrowseTooltip": "사용자 정의 GUI 테마 찾기", - "DockModeToggleTooltip": "도킹 모드 활성화 또는 비활성화", - "DirectKeyboardTooltip": "\"직접 키보드 액세스(HID) 지원\" 활성화 또는 비활성화(텍스트 입력 장치로 키보드에 대한 게임 액세스 제공)", - "DirectMouseTooltip": "\"직접 마우스 액세스(HID) 지원\" 활성화 또는 비활성화(포인팅 장치로 마우스에 대한 게임 액세스 제공)", - "RegionTooltip": "시스템 지역 변경", - "LanguageTooltip": "시스템 언어 변경", - "TimezoneTooltip": "시스템 시간대 변경", - "TimeTooltip": "시스템 시간 변경", - "VSyncToggleTooltip": "수직 동기화 활성화 또는 비활성화", - "PptcToggleTooltip": "PPTC 활성화 또는 비활성화", - "FsIntegrityToggleTooltip": "게임 콘텐츠 파일에 대한 무결성 검사 활성화", - "AudioBackendTooltip": "오디오 백엔드 변경", - "MemoryManagerTooltip": "게스트 메모리가 매핑되고 액세스되는 방식을 변경합니다. 에뮬레이트된 CPU 성능에 큰 영향을 줍니다.", - "MemoryManagerSoftwareTooltip": "주소 변환을 위해 소프트웨어 페이지 테이블을 사용하십시오. 정확도는 가장 높지만 성능은 가장 느립니다.", - "MemoryManagerHostTooltip": "호스트 주소 공간에서 메모리를 직접 매핑합니다. 훨씬 더 빠른 JIT 컴파일 및 실행.", - "MemoryManagerUnsafeTooltip": "메모리를 직접 매핑하지만 액세스하기 전에 게스트 주소 공간 내의 주소를 마스킹하지 마십시오. 더 빠르지만 안전을 희생해야 합니다. 게스트 응용 프로그램은 Ryujinx의 어디에서나 메모리에 액세스할 수 있으므로 이 모드로 신뢰할 수 있는 프로그램만 실행하십시오.", - "DRamTooltip": "에뮬레이트된 시스템의 메모리 양을 4GB에서 6GB로 확장", - "IgnoreMissingServicesTooltip": "누락된 서비스 무시 옵션 활성화 또는 비활성화", - "GraphicsBackendThreadingTooltip": "그래픽 백엔드 멀티스레딩 활성화", - "GalThreadingTooltip": "두 번째 스레드에서 그래픽 백엔드 명령을 실행합니다. 셰이더 컴파일의 런타임 멀티스레딩을 허용하고, 말더듬을 줄이고, 자체 멀티스레딩 지원 없이 드라이버의 성능을 개선합니다. 멀티스레딩이 있는 드라이버에서 약간 다른 최대 성능. 드라이버 내장 멀티스레딩을 올바르게 비활성화하려면 Ryujinx를 다시 시작해야 할 수도 있고 최상의 성능을 얻으려면 수동으로 수행해야 할 수도 있습니다.", - "ShaderCacheToggleTooltip": "셰이더 캐시 활성화 또는 비활성화", - "ResolutionScaleTooltip": "적용 가능한 렌더 타겟에 적용된 해상도 배율", - "ResolutionScaleEntryTooltip": "1.5와 같은 부동 소수점 해상도 스케일. 비적분 스케일은 문제나 충돌을 일으킬 가능성이 더 큽니다.", - "AnisotropyTooltip": "이방성 필터링 수준(게임에서 요청한 값을 사용하려면 자동으로 설정)", - "AspectRatioTooltip": "렌더러 창에 적용된 종횡비.", - "ShaderDumpPathTooltip": "그래픽 셰이더 덤프 경로", - "FileLogTooltip": "디스크의 파일에 대한 로깅 활성화 또는 비활성화", - "StubLogTooltip": "스텁 로그 메시지 인쇄 활성화", - "InfoLogTooltip": "정보 로그 메시지 인쇄 활성화", - "WarnLogTooltip": "경고 로그 메시지 인쇄 활성화", - "ErrorLogTooltip": "오류 로그 메시지 인쇄 활성화", - "GuestLogTooltip": "게스트 로그 메시지 인쇄 활성화", - "FileAccessLogTooltip": "파일 액세스 로그 메시지 인쇄 활성화", - "FSAccessLogModeTooltip": "콘솔에 대한 FS 액세스 로그 출력을 활성화합니다. 가능한 모드는 0-3입니다", - "DeveloperOptionTooltip": "주의해서 사용", - "OpenGlLogLevel": "적절한 로그 수준이 활성화되어 있어야 합니다", - "DebugLogTooltip": "디버그 로그 메시지 인쇄 활성화", - "LoadApplicationFileTooltip": "로드할 Switch 호환 파일을 선택하려면 파일 선택기를 엽니다.", - "LoadApplicationFolderTooltip": "파일 선택기를 열어 로드할 Switch 호환 가능하고 압축을 푼 응용 프로그램을 선택합니다", - "OpenRyujinxFolderTooltip": "Ryujinx 파일 시스템 폴더 열기", - "OpenRyujinxLogsTooltip": "로그가 기록되는 폴더를 엽니다.", - "ExitTooltip": "Ryujinx 종료", - "OpenSettingsTooltip": "설정 창 열기", - "OpenProfileManagerTooltip": "사용자 프로필 관리자 창 열기", - "StopEmulationTooltip": "현재 게임의 에뮬레이션을 중지하고 게임 선택으로 돌아가기", - "CheckUpdatesTooltip": "Ryujinx 업데이트 확인", - "OpenAboutTooltip": "정보 창 열기", - "GridSize": "그리드 크기", - "GridSizeTooltip": "그리드 항목의 크기 변경", - "SettingsTabSystemSystemLanguageBrazilianPortuguese": "포르투갈어(브라질)", - "AboutRyujinxContributorsButtonHeader": "모든 기여자 보기", - "SettingsTabSystemAudioVolume": "용량 : ", - "AudioVolumeTooltip": "오디오 볼륨 변경", - "SettingsTabSystemEnableInternetAccess": "게스트 인터넷 액세스 활성화s", - "EnableInternetAccessTooltip": "게스트 인터넷 액세스를 활성화합니다. 활성화된 경우 응용 프로그램은 에뮬레이트된 스위치 콘솔이 인터넷에 연결된 것처럼 작동합니다. 경우에 따라 이 옵션이 비활성화된 경우에도 응용 프로그램이 인터넷에 계속 액세스할 수 있습니다", - "GameListContextMenuManageCheatToolTip" : "치트 관리", - "GameListContextMenuManageCheat" : "치트 관리", - "ControllerSettingsStickRange" : "범위:", - "DialogStopEmulationTitle" : "Ryujinx - 에뮬레이션 중지", - "DialogStopEmulationMessage": "에뮬레이션을 중지하시겠습니까?", - "SettingsTabCpu": "CPU", - "SettingsTabAudio": "오디오", - "SettingsTabNetwork": "회로망", - "SettingsTabNetworkConnection" : "네트워크 연결", - "SettingsTabCpuCache" : "CPU 캐시", - "SettingsTabCpuMemory" : "CPU 메모리", - "ControllerMotionTitle": "Motion Control Settings", - "ControllerRumbleTitle": "Rumble Settings" -} diff --git a/Ryujinx.Ava/Assets/Styles/BaseDark.xaml b/Ryujinx.Ava/Assets/Styles/BaseDark.xaml deleted file mode 100644 index 074b16612..000000000 --- a/Ryujinx.Ava/Assets/Styles/BaseDark.xaml +++ /dev/null @@ -1,59 +0,0 @@ - - - - - - - - - - - - - - - - - - - -