Merge branch 'master' of https://github.com/Ryujinx/Ryujinx into mmdurrant/texture-tests

This commit is contained in:
Michael Durrant 2023-07-31 13:32:39 -06:00
commit 4ce3f5b29d
2876 changed files with 34266 additions and 34342 deletions

View file

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

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

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

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

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

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

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

View file

@ -1,25 +1,10 @@
name: Build job
on:
workflow_dispatch:
inputs: {}
#push:
# branches: [ master ]
# paths-ignore:
# - '.github/*'
# - '.github/ISSUE_TEMPLATE/**'
# - '*.yml'
# - 'README.md'
pull_request:
branches: [ master ]
paths-ignore:
- '.github/*'
- '.github/ISSUE_TEMPLATE/**'
- '*.yml'
- 'README.md'
workflow_call:
concurrency:
group: pr-checks-${{ github.event.number }}
group: pr-builds-${{ github.event.number }}
cancel-in-progress: true
env:

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

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

View file

@ -1,8 +1,10 @@
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'

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

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

View file

@ -6,9 +6,10 @@ on:
push:
branches: [ master ]
paths-ignore:
- '.github/*'
- '.github/ISSUE_TEMPLATE/**'
- '.github/**'
- '*.yml'
- '*.json'
- '*.config'
- 'README.md'
concurrency: release

View file

@ -20,8 +20,8 @@
<PackageVersion Include="jp2masa.Avalonia.Flexbox" Version="0.2.0" />
<PackageVersion Include="LibHac" Version="0.18.0" />
<PackageVersion Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.4" />
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="4.5.0" />
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.6.1" />
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="4.6.0" />
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.6.3" />
<PackageVersion Include="Microsoft.IO.RecyclableMemoryStream" Version="2.3.2" />
<PackageVersion Include="MsgPack.Cli" Version="1.0.1" />
<PackageVersion Include="NUnit" Version="3.13.3" />
@ -34,7 +34,7 @@
<PackageVersion Include="Ryujinx.Graphics.Nvdec.Dependencies" Version="5.0.1-build13" />
<PackageVersion Include="Ryujinx.Graphics.Vulkan.Dependencies.MoltenVK" Version="1.2.0" />
<PackageVersion Include="Ryujinx.GtkSharp" Version="3.24.24.59-ryujinx" />
<PackageVersion Include="Ryujinx.SDL2-CS" Version="2.26.3-build25" />
<PackageVersion Include="Ryujinx.SDL2-CS" Version="2.28.1-build28" />
<PackageVersion Include="shaderc.net" Version="0.1.0" />
<PackageVersion Include="SharpZipLib" Version="1.4.2" />
<PackageVersion Include="Silk.NET.Vulkan" Version="2.16.0" />
@ -44,9 +44,9 @@
<PackageVersion Include="SixLabors.ImageSharp.Drawing" Version="1.0.0-beta11" />
<PackageVersion Include="SPB" Version="0.0.4-build28" />
<PackageVersion Include="System.Drawing.Common" Version="7.0.0" />
<PackageVersion Include="System.IdentityModel.Tokens.Jwt" Version="6.30.1" />
<PackageVersion Include="System.IdentityModel.Tokens.Jwt" Version="6.31.0" />
<PackageVersion Include="System.IO.Hashing" Version="7.0.0" />
<PackageVersion Include="System.Management" Version="7.0.1" />
<PackageVersion Include="System.Management" Version="7.0.2" />
<PackageVersion Include="UnicornEngine.Unicorn" Version="2.0.2-rc1-fb78016" />
<PackageVersion Include="XamlNameReferenceGenerator" Version="1.6.1" />
</ItemGroup>

View file

@ -39,10 +39,15 @@
<key>CSResourcesFileMapped</key>
<true/>
<key>NSHumanReadableCopyright</key>
<string>Copyright © 2018 - 2022 Ryujinx Team and Contributors.</string>
<string>Copyright © 2018 - 2023 Ryujinx Team and Contributors.</string>
<key>LSApplicationCategoryType</key>
<string>public.app-category.games</string>
<key>LSMinimumSystemVersion</key>
<string>11.0</string>
<key>LSEnvironment</key>
<dict>
<key>COMPlus_DefaultStackSize</key>
<string>200000</string>
</dict>
</dict>
</plist>

View file

@ -35,12 +35,12 @@ EXECUTABLE_SUB_PATH=Contents/MacOS/Ryujinx
rm -rf "$TEMP_DIRECTORY"
mkdir -p "$TEMP_DIRECTORY"
DOTNET_COMMON_ARGS="-p:DebugType=embedded -p:Version=$VERSION -p:SourceRevisionId=$SOURCE_REVISION_ID --self-contained true $EXTRA_ARGS"
DOTNET_COMMON_ARGS=(-p:DebugType=embedded -p:Version="$VERSION" -p:SourceRevisionId="$SOURCE_REVISION_ID" --self-contained true $EXTRA_ARGS)
dotnet restore
dotnet build -c $CONFIGURATION src/Ryujinx.Ava
dotnet publish -c $CONFIGURATION -r osx-arm64 -o "$TEMP_DIRECTORY/publish_arm64" $DOTNET_COMMON_ARGS src/Ryujinx.Ava
dotnet publish -c $CONFIGURATION -r osx-x64 -o "$TEMP_DIRECTORY/publish_x64" $DOTNET_COMMON_ARGS src/Ryujinx.Ava
dotnet build -c "$CONFIGURATION" src/Ryujinx.Ava
dotnet publish -c "$CONFIGURATION" -r osx-arm64 -o "$TEMP_DIRECTORY/publish_arm64" "${DOTNET_COMMON_ARGS[@]}" src/Ryujinx.Ava
dotnet publish -c "$CONFIGURATION" -r osx-x64 -o "$TEMP_DIRECTORY/publish_x64" "${DOTNET_COMMON_ARGS[@]}" src/Ryujinx.Ava
# Get rid of the support library for ARMeilleure for x64 (that's only for arm64)
rm -rf "$TEMP_DIRECTORY/publish_x64/libarmeilleure-jitsupport.dylib"
@ -104,10 +104,10 @@ fi
echo "Creating archive"
pushd "$OUTPUT_DIRECTORY"
tar --exclude "Ryujinx.app/Contents/MacOS/Ryujinx" -cvf $RELEASE_TAR_FILE_NAME Ryujinx.app 1> /dev/null
python3 "$BASE_DIR/distribution/misc/add_tar_exec.py" $RELEASE_TAR_FILE_NAME "Ryujinx.app/Contents/MacOS/Ryujinx" "Ryujinx.app/Contents/MacOS/Ryujinx"
gzip -9 < $RELEASE_TAR_FILE_NAME > $RELEASE_TAR_FILE_NAME.gz
rm $RELEASE_TAR_FILE_NAME
tar --exclude "Ryujinx.app/Contents/MacOS/Ryujinx" -cvf "$RELEASE_TAR_FILE_NAME" Ryujinx.app 1> /dev/null
python3 "$BASE_DIR/distribution/misc/add_tar_exec.py" "$RELEASE_TAR_FILE_NAME" "Ryujinx.app/Contents/MacOS/Ryujinx" "Ryujinx.app/Contents/MacOS/Ryujinx"
gzip -9 < "$RELEASE_TAR_FILE_NAME" > "$RELEASE_TAR_FILE_NAME.gz"
rm "$RELEASE_TAR_FILE_NAME"
popd
echo "Done"

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -93,4 +93,4 @@ namespace ARMeilleure.CodeGen.Arm64
return 0;
}
}
}
}

View file

@ -88,4 +88,4 @@ namespace ARMeilleure.CodeGen.Arm64
return true;
}
}
}
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -35,4 +35,4 @@ namespace ARMeilleure.CodeGen.Linking
return $"({nameof(Position)} = {Position}, {nameof(Symbol)} = {Symbol})";
}
}
}
}

View file

@ -29,4 +29,4 @@ namespace ARMeilleure.CodeGen.Linking
_entries = entries;
}
}
}
}

View file

@ -23,6 +23,6 @@
/// <summary>
/// Refers to a special symbol which is handled by <see cref="Translation.PTC.Ptc.PatchCode"/>.
/// </summary>
Special
Special,
}
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -9,4 +9,4 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
StackAllocator stackAlloc,
RegisterMasks regMasks);
}
}
}

View file

@ -14,7 +14,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
// http://www.christianwimmer.at/Publications/Wimmer04a/Wimmer04a.pdf
class LinearScanAllocator : IRegisterAllocator
{
private const int InstructionGap = 2;
private const int InstructionGap = 2;
private const int InstructionGapMask = InstructionGap - 1;
private HashSet<int> _blockEdges;
@ -33,7 +33,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
public StackAllocator StackAlloc { get; }
public BitMap Active { get; }
public BitMap Active { get; }
public BitMap Inactive { get; }
public int IntUsedRegisters { get; set; }
@ -47,9 +47,9 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
public AllocationContext(StackAllocator stackAlloc, RegisterMasks masks, int intervalsCount)
{
StackAlloc = stackAlloc;
Masks = masks;
Masks = masks;
Active = new BitMap(Allocators.Default, intervalsCount);
Active = new BitMap(Allocators.Default, intervalsCount);
Inactive = new BitMap(Allocators.Default, intervalsCount);
PopulateFreePositions(RegisterType.Integer, out _intFreePositions, out _intFreePositionsCount);
@ -443,7 +443,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
if (highest < current)
{
highest = current;
highest = current;
selected = index;
if (current == int.MaxValue)
@ -485,9 +485,9 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
private void SplitAndSpillOverlappingInterval(
AllocationContext context,
LiveInterval current,
LiveInterval interval,
int registersCount)
LiveInterval current,
LiveInterval interval,
int registersCount)
{
// If there's a next use after the start of the current interval,
// we need to split the spilled interval twice, and re-insert it
@ -530,8 +530,8 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
private void InsertInterval(LiveInterval interval, int registersCount)
{
Debug.Assert(interval.UsesCount != 0, "Trying to insert a interval without uses.");
Debug.Assert(!interval.IsEmpty, "Trying to insert a empty interval.");
Debug.Assert(!interval.IsSpilled, "Trying to insert a spilled interval.");
Debug.Assert(!interval.IsEmpty, "Trying to insert a empty interval.");
Debug.Assert(!interval.IsSpilled, "Trying to insert a spilled interval.");
int startIndex = registersCount * 2;
@ -545,9 +545,9 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
_intervals.Insert(insertIndex, interval);
}
private void Spill(AllocationContext context, LiveInterval interval)
private static void Spill(AllocationContext context, LiveInterval interval)
{
Debug.Assert(!interval.IsFixed, "Trying to spill a fixed interval.");
Debug.Assert(!interval.IsFixed, "Trying to spill a fixed interval.");
Debug.Assert(interval.UsesCount == 0, "Trying to spill a interval with uses.");
// We first check if any of the siblings were spilled, if so we can reuse
@ -561,7 +561,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
private void InsertSplitCopies()
{
Dictionary<int, CopyResolver> copyResolvers = new Dictionary<int, CopyResolver>();
Dictionary<int, CopyResolver> copyResolvers = new();
CopyResolver GetCopyResolver(int position)
{
@ -668,18 +668,15 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
continue;
}
int lEnd = _blockRanges[block.Index].End - 1;
int lEnd = _blockRanges[block.Index].End - 1;
int rStart = _blockRanges[succIndex].Start;
LiveInterval left = interval.GetSplitChild(lEnd);
LiveInterval left = interval.GetSplitChild(lEnd);
LiveInterval right = interval.GetSplitChild(rStart);
if (left != default && right != default && left != right)
{
if (copyResolver == null)
{
copyResolver = new CopyResolver();
}
copyResolver ??= new CopyResolver();
copyResolver.AddSplit(left, right);
}
@ -856,14 +853,14 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
int mapSize = _intervals.Count;
BitMap[] blkLiveGen = new BitMap[cfg.Blocks.Count];
BitMap[] blkLiveGen = new BitMap[cfg.Blocks.Count];
BitMap[] blkLiveKill = new BitMap[cfg.Blocks.Count];
// Compute local live sets.
for (BasicBlock block = cfg.Blocks.First; block != null; block = block.ListNext)
{
BitMap liveGen = new BitMap(Allocators.Default, mapSize);
BitMap liveKill = new BitMap(Allocators.Default, mapSize);
BitMap liveGen = new(Allocators.Default, mapSize);
BitMap liveKill = new(Allocators.Default, mapSize);
for (Operation node = block.Operations.First; node != default; node = node.ListNext)
{
@ -910,17 +907,17 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
}
}
blkLiveGen [block.Index] = liveGen;
blkLiveGen[block.Index] = liveGen;
blkLiveKill[block.Index] = liveKill;
}
// Compute global live sets.
BitMap[] blkLiveIn = new BitMap[cfg.Blocks.Count];
BitMap[] blkLiveIn = new BitMap[cfg.Blocks.Count];
BitMap[] blkLiveOut = new BitMap[cfg.Blocks.Count];
for (int index = 0; index < cfg.Blocks.Count; index++)
{
blkLiveIn [index] = new BitMap(Allocators.Default, mapSize);
blkLiveIn[index] = new BitMap(Allocators.Default, mapSize);
blkLiveOut[index] = new BitMap(Allocators.Default, mapSize);
}
@ -945,9 +942,9 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
BitMap liveIn = blkLiveIn[block.Index];
liveIn.Set (liveOut);
liveIn.Set(liveOut);
liveIn.Clear(blkLiveKill[block.Index]);
liveIn.Set (blkLiveGen [block.Index]);
liveIn.Set(blkLiveGen[block.Index]);
}
}
while (modified);
@ -969,7 +966,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
int instCount = Math.Max(block.Operations.Count, 1);
int blockStart = operationPos - instCount * InstructionGap;
int blockEnd = operationPos;
int blockEnd = operationPos;
_blockRanges[block.Index] = new LiveRange(blockStart, blockEnd);
@ -1061,7 +1058,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
{
int regIndex = BitOperations.TrailingZeroCount(mask);
Register callerSavedReg = new Register(regIndex, regType);
Register callerSavedReg = new(regIndex, regType);
LiveInterval interval = _intervals[GetRegisterId(callerSavedReg)];
@ -1098,4 +1095,4 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
kind == OperandKind.Register;
}
}
}
}

View file

@ -240,8 +240,10 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
public LiveInterval Split(int position)
{
LiveInterval result = new(Local, Parent);
result.End = End;
LiveInterval result = new(Local, Parent)
{
End = End,
};
LiveRange prev = PrevRange;
LiveRange curr = CurrRange;
@ -393,4 +395,4 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
return string.Join(", ", GetRanges());
}
}
}
}

View file

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

View file

@ -71,4 +71,4 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
return $"[{Start}, {End})";
}
}
}
}

View file

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

View file

@ -22,4 +22,4 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
return offset;
}
}
}
}

View file

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

View file

@ -13,4 +13,4 @@ namespace ARMeilleure.CodeGen.Unwinding
PrologSize = prologSize;
}
}
}
}

View file

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

View file

@ -17,4 +17,4 @@ namespace ARMeilleure.CodeGen.Unwinding
StackOffsetOrAllocSize = stackOffsetOrAllocSize;
}
}
}
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -17,7 +17,7 @@ namespace ARMeilleure.CodeGen.X86
static class CodeGenerator
{
private const int RegistersCount = 16;
private const int PageSize = 0x1000;
private const int PageSize = 0x1000;
private const int StackGuardSize = 0x2000;
private static readonly Action<CodeGenContext, Operation>[] _instTable;
@ -26,6 +26,7 @@ namespace ARMeilleure.CodeGen.X86
{
_instTable = new Action<CodeGenContext, Operation>[EnumUtils.GetCount(typeof(Instruction))];
#pragma warning disable IDE0055 // Disable formatting
Add(Instruction.Add, GenerateAdd);
Add(Instruction.BitwiseAnd, GenerateBitwiseAnd);
Add(Instruction.BitwiseExclusiveOr, GenerateBitwiseExclusiveOr);
@ -85,6 +86,7 @@ namespace ARMeilleure.CodeGen.X86
Add(Instruction.ZeroExtend16, GenerateZeroExtend16);
Add(Instruction.ZeroExtend32, GenerateZeroExtend32);
Add(Instruction.ZeroExtend8, GenerateZeroExtend8);
#pragma warning restore IDE0055
static void Add(Instruction inst, Action<CodeGenContext, Operation> func)
{
@ -203,290 +205,290 @@ namespace ARMeilleure.CodeGen.X86
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);
Debug.Assert(offset.Kind == OperandKind.Constant);
Debug.Assert(offset.Type == OperandType.I32);
int offs = offset.AsInt32() + context.CallArgsRegionSize;
Operand rsp = Register(X86Register.Rsp);
Operand memOp = MemoryOp(OperandType.I32, rsp, default, Multiplier.x1, offs);
Debug.Assert(HardwareCapabilities.SupportsSse || HardwareCapabilities.SupportsVexEncoding);
if (operation.Intrinsic == Intrinsic.X86Ldmxcsr)
{
Operand bits = operation.GetSource(1);
Debug.Assert(bits.Type == OperandType.I32);
context.Assembler.Mov(memOp, bits, OperandType.I32);
context.Assembler.Ldmxcsr(memOp);
}
else if (operation.Intrinsic == Intrinsic.X86Stmxcsr)
{
Operand dest = operation.Destination;
Debug.Assert(dest.Type == OperandType.I32);
Operand src1 = operation.GetSource(0);
Operand src2 = operation.GetSource(1);
context.Assembler.Stmxcsr(memOp);
context.Assembler.Mov(dest, memOp, OperandType.I32);
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;
}
break;
}
case IntrinsicType.Mxcsr:
{
Operand offset = operation.GetSource(0);
Debug.Assert(offset.Kind == OperandKind.Constant);
Debug.Assert(offset.Type == OperandType.I32);
int offs = offset.AsInt32() + context.CallArgsRegionSize;
Operand rsp = Register(X86Register.Rsp);
Operand memOp = MemoryOp(OperandType.I32, rsp, default, Multiplier.x1, offs);
Debug.Assert(HardwareCapabilities.SupportsSse || HardwareCapabilities.SupportsVexEncoding);
if (operation.Intrinsic == Intrinsic.X86Ldmxcsr)
{
Operand bits = operation.GetSource(1);
Debug.Assert(bits.Type == OperandType.I32);
context.Assembler.Mov(memOp, bits, OperandType.I32);
context.Assembler.Ldmxcsr(memOp);
}
else if (operation.Intrinsic == Intrinsic.X86Stmxcsr)
{
Operand dest = operation.Destination;
Debug.Assert(dest.Type == OperandType.I32);
context.Assembler.Stmxcsr(memOp);
context.Assembler.Mov(dest, memOp, OperandType.I32);
}
break;
}
case IntrinsicType.PopCount:
{
Operand dest = operation.Destination;
Operand source = operation.GetSource(0);
{
Operand dest = operation.Destination;
Operand source = operation.GetSource(0);
EnsureSameType(dest, source);
EnsureSameType(dest, source);
Debug.Assert(dest.Type.IsInteger());
Debug.Assert(dest.Type.IsInteger());
context.Assembler.Popcnt(dest, source, dest.Type);
context.Assembler.Popcnt(dest, source, dest.Type);
break;
}
break;
}
case IntrinsicType.Unary:
{
Operand dest = operation.Destination;
Operand source = operation.GetSource(0);
{
Operand dest = operation.Destination;
Operand source = operation.GetSource(0);
EnsureSameType(dest, source);
EnsureSameType(dest, source);
Debug.Assert(!dest.Type.IsInteger());
Debug.Assert(!dest.Type.IsInteger());
context.Assembler.WriteInstruction(info.Inst, dest, source);
context.Assembler.WriteInstruction(info.Inst, dest, source);
break;
}
break;
}
case IntrinsicType.UnaryToGpr:
{
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);
}
Operand dest = operation.Destination;
Operand source = operation.GetSource(0);
break;
}
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);
}
Operand dest = operation.Destination;
Operand src1 = operation.GetSource(0);
Operand src2 = operation.GetSource(1);
Debug.Assert(!dest.Type.IsInteger());
Debug.Assert(!src2.Type.IsInteger() || src2.Kind == OperandKind.Constant);
EnsureSameType(dest, src1);
context.Assembler.WriteInstruction(info.Inst, dest, src1, src2);
if (!HardwareCapabilities.SupportsVexEncoding)
{
EnsureSameReg(dest, src1);
}
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);
Debug.Assert(!dest.Type.IsInteger());
Debug.Assert(!src2.Type.IsInteger() || src2.Kind == OperandKind.Constant);
context.Assembler.WriteInstruction(info.Inst, dest, src1, src2);
break;
}
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);
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;
}
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);
{
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(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);
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);
EnsureSameType(dest, src1, src2, src3);
Debug.Assert(dest.Type == OperandType.V128);
Debug.Assert(dest.Value == src1.Value);
Debug.Assert(dest.Value == src1.Value);
context.Assembler.WriteInstruction(info.Inst, dest, src2, src3);
context.Assembler.WriteInstruction(info.Inst, dest, src2, src3);
break;
}
break;
}
}
}
else
@ -592,7 +594,7 @@ namespace ARMeilleure.CodeGen.X86
private static void GenerateBitwiseNot(CodeGenContext context, Operation operation)
{
Operand dest = operation.Destination;
Operand dest = operation.Destination;
Operand source = operation.GetSource(0);
ValidateUnOp(dest, source);
@ -630,7 +632,7 @@ namespace ARMeilleure.CodeGen.X86
private static void GenerateByteSwap(CodeGenContext context, Operation operation)
{
Operand dest = operation.Destination;
Operand dest = operation.Destination;
Operand source = operation.GetSource(0);
ValidateUnOp(dest, source);
@ -761,19 +763,19 @@ namespace ARMeilleure.CodeGen.X86
Operand src2 = operation.GetSource(1);
Operand src3 = operation.GetSource(2);
EnsureSameReg (dest, src3);
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.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 dest = operation.Destination;
Operand source = operation.GetSource(0);
Debug.Assert(dest.Type == OperandType.I32 && source.Type == OperandType.I64);
@ -783,7 +785,7 @@ namespace ARMeilleure.CodeGen.X86
private static void GenerateConvertToFP(CodeGenContext context, Operation operation)
{
Operand dest = operation.Destination;
Operand dest = operation.Destination;
Operand source = operation.GetSource(0);
Debug.Assert(dest.Type == OperandType.FP32 || dest.Type == OperandType.FP64);
@ -794,7 +796,7 @@ namespace ARMeilleure.CodeGen.X86
if (source.Type.IsInteger())
{
context.Assembler.Xorps (dest, dest, dest);
context.Assembler.Xorps(dest, dest, dest);
context.Assembler.Cvtsi2ss(dest, dest, source, source.Type);
}
else /* if (source.Type == OperandType.FP64) */
@ -810,7 +812,7 @@ namespace ARMeilleure.CodeGen.X86
if (source.Type.IsInteger())
{
context.Assembler.Xorps (dest, dest, dest);
context.Assembler.Xorps(dest, dest, dest);
context.Assembler.Cvtsi2sd(dest, dest, source, source.Type);
}
else /* if (source.Type == OperandType.FP32) */
@ -824,7 +826,7 @@ namespace ARMeilleure.CodeGen.X86
private static void GenerateCopy(CodeGenContext context, Operation operation)
{
Operand dest = operation.Destination;
Operand dest = operation.Destination;
Operand source = operation.GetSource(0);
EnsureSameType(dest, source);
@ -837,7 +839,7 @@ namespace ARMeilleure.CodeGen.X86
return;
}
if (dest.Kind == OperandKind.Register &&
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.
@ -855,7 +857,7 @@ namespace ARMeilleure.CodeGen.X86
private static void GenerateCountLeadingZeros(CodeGenContext context, Operation operation)
{
Operand dest = operation.Destination;
Operand dest = operation.Destination;
Operand source = operation.GetSource(0);
EnsureSameType(dest, source);
@ -888,9 +890,9 @@ namespace ARMeilleure.CodeGen.X86
private static void GenerateDivide(CodeGenContext context, Operation operation)
{
Operand dest = operation.Destination;
Operand dest = operation.Destination;
Operand dividend = operation.GetSource(0);
Operand divisor = operation.GetSource(1);
Operand divisor = operation.GetSource(1);
if (!dest.Type.IsInteger())
{
@ -938,7 +940,7 @@ namespace ARMeilleure.CodeGen.X86
private static void GenerateFill(CodeGenContext context, Operation operation)
{
Operand dest = operation.Destination;
Operand dest = operation.Destination;
Operand offset = operation.GetSource(0);
Debug.Assert(offset.Kind == OperandKind.Constant);
@ -954,7 +956,7 @@ namespace ARMeilleure.CodeGen.X86
private static void GenerateLoad(CodeGenContext context, Operation operation)
{
Operand value = operation.Destination;
Operand value = operation.Destination;
Operand address = Memory(operation.GetSource(0), value.Type);
GenerateLoad(context, address, value);
@ -962,7 +964,7 @@ namespace ARMeilleure.CodeGen.X86
private static void GenerateLoad16(CodeGenContext context, Operation operation)
{
Operand value = operation.Destination;
Operand value = operation.Destination;
Operand address = Memory(operation.GetSource(0), value.Type);
Debug.Assert(value.Type.IsInteger());
@ -972,7 +974,7 @@ namespace ARMeilleure.CodeGen.X86
private static void GenerateLoad8(CodeGenContext context, Operation operation)
{
Operand value = operation.Destination;
Operand value = operation.Destination;
Operand address = Memory(operation.GetSource(0), value.Type);
Debug.Assert(value.Type.IsInteger());
@ -1039,7 +1041,7 @@ namespace ARMeilleure.CodeGen.X86
private static void GenerateNegate(CodeGenContext context, Operation operation)
{
Operand dest = operation.Destination;
Operand dest = operation.Destination;
Operand source = operation.GetSource(0);
ValidateUnOp(dest, source);
@ -1102,7 +1104,7 @@ namespace ARMeilleure.CodeGen.X86
private static void GenerateSignExtend16(CodeGenContext context, Operation operation)
{
Operand dest = operation.Destination;
Operand dest = operation.Destination;
Operand source = operation.GetSource(0);
Debug.Assert(dest.Type.IsInteger() && source.Type.IsInteger());
@ -1112,7 +1114,7 @@ namespace ARMeilleure.CodeGen.X86
private static void GenerateSignExtend32(CodeGenContext context, Operation operation)
{
Operand dest = operation.Destination;
Operand dest = operation.Destination;
Operand source = operation.GetSource(0);
Debug.Assert(dest.Type.IsInteger() && source.Type.IsInteger());
@ -1122,7 +1124,7 @@ namespace ARMeilleure.CodeGen.X86
private static void GenerateSignExtend8(CodeGenContext context, Operation operation)
{
Operand dest = operation.Destination;
Operand dest = operation.Destination;
Operand source = operation.GetSource(0);
Debug.Assert(dest.Type.IsInteger() && source.Type.IsInteger());
@ -1158,7 +1160,7 @@ namespace ARMeilleure.CodeGen.X86
private static void GenerateStackAlloc(CodeGenContext context, Operation operation)
{
Operand dest = operation.Destination;
Operand dest = operation.Destination;
Operand offset = operation.GetSource(0);
Debug.Assert(offset.Kind == OperandKind.Constant);
@ -1174,7 +1176,7 @@ namespace ARMeilleure.CodeGen.X86
private static void GenerateStore(CodeGenContext context, Operation operation)
{
Operand value = operation.GetSource(1);
Operand value = operation.GetSource(1);
Operand address = Memory(operation.GetSource(0), value.Type);
GenerateStore(context, address, value);
@ -1182,7 +1184,7 @@ namespace ARMeilleure.CodeGen.X86
private static void GenerateStore16(CodeGenContext context, Operation operation)
{
Operand value = operation.GetSource(1);
Operand value = operation.GetSource(1);
Operand address = Memory(operation.GetSource(0), value.Type);
Debug.Assert(value.Type.IsInteger());
@ -1192,7 +1194,7 @@ namespace ARMeilleure.CodeGen.X86
private static void GenerateStore8(CodeGenContext context, Operation operation)
{
Operand value = operation.GetSource(1);
Operand value = operation.GetSource(1);
Operand address = Memory(operation.GetSource(0), value.Type);
Debug.Assert(value.Type.IsInteger());
@ -1231,7 +1233,7 @@ namespace ARMeilleure.CodeGen.X86
private static void GenerateVectorCreateScalar(CodeGenContext context, Operation operation)
{
Operand dest = operation.Destination;
Operand dest = operation.Destination;
Operand source = operation.GetSource(0);
Debug.Assert(!dest.Type.IsInteger() && source.Type.IsInteger());
@ -1278,7 +1280,7 @@ namespace ARMeilleure.CodeGen.X86
mask1 = BitUtils.RotateRight(mask1, 8 - index * 2, 8);
context.Assembler.Pshufd(src1, src1, (byte)mask0);
context.Assembler.Movd (dest, src1);
context.Assembler.Movd(dest, src1);
context.Assembler.Pshufd(src1, src1, (byte)mask1);
}
}
@ -1294,11 +1296,11 @@ namespace ARMeilleure.CodeGen.X86
}
else
{
const byte mask = 0b01_00_11_10;
const byte Mask = 0b01_00_11_10;
context.Assembler.Pshufd(src1, src1, mask);
context.Assembler.Movq (dest, src1);
context.Assembler.Pshufd(src1, src1, mask);
context.Assembler.Pshufd(src1, src1, Mask);
context.Assembler.Movq(dest, src1);
context.Assembler.Pshufd(src1, src1, Mask);
}
}
else
@ -1308,7 +1310,7 @@ namespace ARMeilleure.CodeGen.X86
(index == 1 && dest.Type == OperandType.FP64))
{
context.Assembler.Movhlps(dest, dest, src1);
context.Assembler.Movq (dest, dest);
context.Assembler.Movq(dest, dest);
}
else
{
@ -1455,11 +1457,11 @@ namespace ARMeilleure.CodeGen.X86
int mask0 = 0b11_10_01_00;
int mask1 = 0b11_10_01_00;
mask0 = BitUtils.RotateRight(mask0, index * 2, 8);
mask0 = BitUtils.RotateRight(mask0, index * 2, 8);
mask1 = BitUtils.RotateRight(mask1, 8 - index * 2, 8);
context.Assembler.Pshufd(src1, src1, (byte)mask0); // Lane to be inserted in position 0.
context.Assembler.Movss (dest, src1, src2); // dest[127:0] = src1[127:32] | src2[31:0]
context.Assembler.Movss(dest, src1, src2); // dest[127:0] = src1[127:32] | src2[31:0]
context.Assembler.Pshufd(dest, dest, (byte)mask1); // Inserted lane in original position.
if (dest.GetRegister() != src1.GetRegister())
@ -1555,7 +1557,7 @@ namespace ARMeilleure.CodeGen.X86
private static void GenerateVectorZeroUpper64(CodeGenContext context, Operation operation)
{
Operand dest = operation.Destination;
Operand dest = operation.Destination;
Operand source = operation.GetSource(0);
Debug.Assert(dest.Type == OperandType.V128 && source.Type == OperandType.V128);
@ -1565,7 +1567,7 @@ namespace ARMeilleure.CodeGen.X86
private static void GenerateVectorZeroUpper96(CodeGenContext context, Operation operation)
{
Operand dest = operation.Destination;
Operand dest = operation.Destination;
Operand source = operation.GetSource(0);
Debug.Assert(dest.Type == OperandType.V128 && source.Type == OperandType.V128);
@ -1575,7 +1577,7 @@ namespace ARMeilleure.CodeGen.X86
private static void GenerateZeroExtend16(CodeGenContext context, Operation operation)
{
Operand dest = operation.Destination;
Operand dest = operation.Destination;
Operand source = operation.GetSource(0);
Debug.Assert(dest.Type.IsInteger() && source.Type.IsInteger());
@ -1585,7 +1587,7 @@ namespace ARMeilleure.CodeGen.X86
private static void GenerateZeroExtend32(CodeGenContext context, Operation operation)
{
Operand dest = operation.Destination;
Operand dest = operation.Destination;
Operand source = operation.GetSource(0);
Debug.Assert(dest.Type.IsInteger() && source.Type.IsInteger());
@ -1601,7 +1603,7 @@ namespace ARMeilleure.CodeGen.X86
private static void GenerateZeroExtend8(CodeGenContext context, Operation operation)
{
Operand dest = operation.Destination;
Operand dest = operation.Destination;
Operand source = operation.GetSource(0);
Debug.Assert(dest.Type.IsInteger() && source.Type.IsInteger());
@ -1613,13 +1615,25 @@ namespace ARMeilleure.CodeGen.X86
{
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;
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;
default:
Debug.Assert(false);
break;
}
}
@ -1627,13 +1641,25 @@ namespace ARMeilleure.CodeGen.X86
{
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;
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;
default:
Debug.Assert(false);
break;
}
}
@ -1670,21 +1696,21 @@ namespace ARMeilleure.CodeGen.X86
[Conditional("DEBUG")]
private static void ValidateUnOp(Operand dest, Operand source)
{
EnsureSameReg (dest, source);
EnsureSameReg(dest, source);
EnsureSameType(dest, source);
}
[Conditional("DEBUG")]
private static void ValidateBinOp(Operand dest, Operand src1, Operand src2)
{
EnsureSameReg (dest, src1);
EnsureSameReg(dest, src1);
EnsureSameType(dest, src1, src2);
}
[Conditional("DEBUG")]
private static void ValidateShift(Operand dest, Operand src1, Operand src2)
{
EnsureSameReg (dest, src1);
EnsureSameReg(dest, src1);
EnsureSameType(dest, src1);
Debug.Assert(dest.Type.IsInteger() && src2.Type == OperandType.I32);
@ -1722,7 +1748,7 @@ namespace ARMeilleure.CodeGen.X86
private static UnwindInfo WritePrologue(CodeGenContext context)
{
List<UnwindPushEntry> pushEntries = new List<UnwindPushEntry>();
List<UnwindPushEntry> pushEntries = new();
Operand rsp = Register(X86Register.Rsp);
@ -1827,11 +1853,11 @@ namespace ARMeilleure.CodeGen.X86
// 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;
const int PageMask = PageSize - 1;
size = (size + pageMask) & ~pageMask;
size = (size + PageMask) & ~PageMask;
Operand rsp = Register(X86Register.Rsp);
Operand rsp = Register(X86Register.Rsp);
Operand temp = Register(CallingConvention.GetIntReturnRegister());
for (int offset = PageSize; offset < size; offset += PageSize)
@ -1862,4 +1888,4 @@ namespace ARMeilleure.CodeGen.X86
return Operand.Factory.Register((int)register, RegisterType.Vector, OperandType.V128);
}
}
}
}

View file

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

View file

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

View file

@ -5,12 +5,13 @@ namespace ARMeilleure.CodeGen.X86
{
static class IntrinsicTable
{
private static IntrinsicInfo[] _intrinTable;
private static readonly IntrinsicInfo[] _intrinTable;
static IntrinsicTable()
{
_intrinTable = new IntrinsicInfo[EnumUtils.GetCount(typeof(Intrinsic))];
#pragma warning disable IDE0055 // Disable formatting
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));
@ -185,6 +186,7 @@ namespace ARMeilleure.CodeGen.X86
Add(Intrinsic.X86Vpternlogd, new IntrinsicInfo(X86Instruction.Vpternlogd, IntrinsicType.TernaryImm));
Add(Intrinsic.X86Xorpd, new IntrinsicInfo(X86Instruction.Xorpd, IntrinsicType.Binary));
Add(Intrinsic.X86Xorps, new IntrinsicInfo(X86Instruction.Xorps, IntrinsicType.Binary));
#pragma warning restore IDE0055
}
private static void Add(Intrinsic intrin, IntrinsicInfo info)
@ -197,4 +199,4 @@ namespace ARMeilleure.CodeGen.X86
return _intrinTable[(int)intrin];
}
}
}
}

View file

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

View file

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

View file

@ -104,11 +104,11 @@ namespace ARMeilleure.CodeGen.X86
case Instruction.Tailcall:
if (callConv == CallConvName.Windows)
{
PreAllocatorWindows.InsertTailcallCopies(block.Operations, stackAlloc, node);
PreAllocatorWindows.InsertTailcallCopies(block.Operations, node);
}
else
{
PreAllocatorSystemV.InsertTailcallCopies(block.Operations, stackAlloc, node);
PreAllocatorSystemV.InsertTailcallCopies(block.Operations, node);
}
break;
@ -177,10 +177,7 @@ namespace ARMeilleure.CodeGen.X86
{
src2 = node.GetSource(1);
Operand temp = src1;
src1 = src2;
src2 = temp;
(src2, src1) = (src1, src2);
node.SetSource(0, src1);
node.SetSource(1, src2);
@ -228,151 +225,151 @@ namespace ARMeilleure.CodeGen.X86
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)
OperandType type = node.GetSource(1).Type;
if (type == OperandType.V128)
{
nodes.AddBefore(node, Operation(Instruction.VectorExtract, lr, source, Const(0)));
nodes.AddBefore(node, Operation(Instruction.VectorExtract, hr, source, Const(1)));
// 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;
}
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 });
break;
}
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())
{
// 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));
nodes.AddBefore(node, Operation(Instruction.Clobber, rdx));
nodes.AddBefore(node, Operation(Instruction.Copy, rax, src1));
nodes.AddAfter(node, Operation(Instruction.Copy, dest, rax));
node.SetSource(0, rax);
node.SetSources(new Operand[] { rdx, rax, node.GetSource(1) });
node.Destination = rax;
nodes.AddAfter(node, Operation(Instruction.Copy, dest, rdx));
node.SetDestinations(new Operand[] { rdx, rax });
break;
}
break;
}
case Instruction.Extended:
{
bool isBlend = node.Intrinsic == Intrinsic.X86Blendvpd ||
node.Intrinsic == Intrinsic.X86Blendvps ||
node.Intrinsic == Intrinsic.X86Pblendvb;
// BLENDVPD, BLENDVPS, PBLENDVB last operand is always implied to be XMM0 when VEX is not supported.
// SHA256RNDS2 always has an implied XMM0 as a last operand.
if ((isBlend && !HardwareCapabilities.SupportsVexEncoding) || node.Intrinsic == Intrinsic.X86Sha256Rnds2)
{
Operand xmm0 = Xmm(X86Register.Xmm0, OperandType.V128);
nodes.AddBefore(node, Operation(Instruction.Copy, xmm0, node.GetSource(2)));
node.SetSource(2, xmm0);
}
break;
}
case Instruction.Multiply64HighSI:
case Instruction.Multiply64HighUI:
{
// Handle the many restrictions of the i64 * i64 = i128 multiply instructions:
// - The multiplicand is always in RAX.
// - The lower 64-bits of the result is always in RAX.
// - The higher 64-bits of the result is always in RDX.
Operand src1 = node.GetSource(0);
Operand rax = Gpr(X86Register.Rax, src1.Type);
Operand rdx = Gpr(X86Register.Rdx, src1.Type);
nodes.AddBefore(node, Operation(Instruction.Copy, rax, src1));
node.SetSource(0, rax);
nodes.AddAfter(node, Operation(Instruction.Copy, dest, rdx));
node.SetDestinations(new Operand[] { rdx, rax });
break;
}
case Instruction.RotateRight:
case Instruction.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);
// 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)));
nodes.AddBefore(node, Operation(Instruction.Copy, rcx, node.GetSource(1)));
node.SetSource(1, rcx);
node.SetSource(1, rcx);
}
break;
}
break;
}
}
}
@ -459,7 +456,7 @@ namespace ARMeilleure.CodeGen.X86
// 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 dest = node.Destination;
Operand source = node.GetSource(0);
Debug.Assert(source.Type.IsInteger(), $"Invalid source type \"{source.Type}\".");
@ -472,8 +469,8 @@ namespace ARMeilleure.CodeGen.X86
// 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));
node = nodes.AddAfter(node, Operation(Instruction.ZeroExtend32, zex, source));
nodes.AddAfter(node, Operation(Instruction.ConvertToFP, dest, zex));
}
else /* if (source.Type == OperandType.I64) */
{
@ -487,15 +484,15 @@ namespace ARMeilleure.CodeGen.X86
// --- 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 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, 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.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));
@ -513,7 +510,7 @@ namespace ARMeilleure.CodeGen.X86
// 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 dest = node.Destination;
Operand source = node.GetSource(0);
Debug.Assert(dest.Type == OperandType.FP32 ||
@ -569,14 +566,14 @@ namespace ARMeilleure.CodeGen.X86
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));
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));
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));
@ -709,16 +706,11 @@ namespace ARMeilleure.CodeGen.X86
private static bool HasConstSrc1(Instruction inst)
{
switch (inst)
return inst switch
{
case Instruction.Copy:
case Instruction.LoadArgument:
case Instruction.Spill:
case Instruction.SpillArg:
return true;
}
return false;
Instruction.Copy or Instruction.LoadArgument or Instruction.Spill or Instruction.SpillArg => true,
_ => false,
};
}
private static bool HasConstSrc2(Instruction inst)
@ -762,15 +754,15 @@ namespace ARMeilleure.CodeGen.X86
case Instruction.BranchIf:
case Instruction.Compare:
{
Operand comp = operation.GetSource(2);
{
Operand comp = operation.GetSource(2);
Debug.Assert(comp.Kind == OperandKind.Constant);
Debug.Assert(comp.Kind == OperandKind.Constant);
var compType = (Comparison)comp.AsInt32();
var compType = (Comparison)comp.AsInt32();
return compType == Comparison.Equal || compType == Comparison.NotEqual;
}
return compType == Comparison.Equal || compType == Comparison.NotEqual;
}
}
return false;
@ -793,4 +785,4 @@ namespace ARMeilleure.CodeGen.X86
return info.Type != IntrinsicType.Crc32;
}
}
}
}

View file

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

View file

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

View file

@ -5,22 +5,22 @@ 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,
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
LessOrEqual = 0xe,
Greater = 0xf,
}
static class ComparisonX86Extensions
@ -29,6 +29,7 @@ namespace ARMeilleure.CodeGen.X86
{
return comp switch
{
#pragma warning disable IDE0055 // Disable formatting
Comparison.Equal => X86Condition.Equal,
Comparison.NotEqual => X86Condition.NotEqual,
Comparison.Greater => X86Condition.Greater,
@ -39,9 +40,10 @@ namespace ARMeilleure.CodeGen.X86
Comparison.Less => X86Condition.Less,
Comparison.GreaterOrEqualUI => X86Condition.AboveOrEqual,
Comparison.LessUI => X86Condition.Below,
#pragma warning restore IDE0055
_ => throw new ArgumentException(null, nameof(comp))
_ => throw new ArgumentException(null, nameof(comp)),
};
}
}
}
}

View file

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

View file

@ -215,7 +215,7 @@ namespace ARMeilleure.CodeGen.X86
1 => Multiplier.x2,
2 => Multiplier.x4,
3 => Multiplier.x8,
_ => Multiplier.x1
_ => Multiplier.x1,
};
baseOp = indexOnSrc2 ? src1 : src2;

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -10,7 +10,7 @@ namespace ARMeilleure.Decoders
Imm8ToFP64Table = BuildImm8ToFP64Table();
}
public static readonly uint[] Imm8ToFP32Table;
public static readonly uint[] Imm8ToFP32Table;
public static readonly ulong[] Imm8ToFP64Table;
private static uint[] BuildImm8ToFP32Table()
@ -40,47 +40,47 @@ namespace ARMeilleure.Decoders
// abcdefgh -> aBbbbbbc defgh000 00000000 00000000 (B = ~b)
private static uint ExpandImm8ToFP32(uint imm)
{
uint MoveBit(uint bits, int from, int to)
static 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, 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)
static 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);
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 int Pos;
public int Shift;
public bool IsUndefined;
public static BitMask Invalid => new BitMask { IsUndefined = true };
public static BitMask Invalid => new() { IsUndefined = true };
}
public static BitMask DecodeBitMask(int opCode, bool immediate)
@ -88,7 +88,7 @@ namespace ARMeilleure.Decoders
int immS = (opCode >> 10) & 0x3f;
int immR = (opCode >> 16) & 0x3f;
int n = (opCode >> 22) & 1;
int n = (opCode >> 22) & 1;
int sf = (opCode >> 31) & 1;
int length = BitUtils.HighestBitSet((~immS & 0x3f) | (n << 6));
@ -115,7 +115,7 @@ namespace ARMeilleure.Decoders
if (r > 0)
{
wMask = BitUtils.RotateRight(wMask, r, size);
wMask = BitUtils.RotateRight(wMask, r, size);
wMask &= BitUtils.FillWithOnes(size);
}
@ -124,8 +124,8 @@ namespace ARMeilleure.Decoders
WMask = BitUtils.Replicate(wMask, size),
TMask = BitUtils.Replicate(tMask, size),
Pos = immS,
Shift = immR
Pos = immS,
Shift = immR,
};
}
@ -164,4 +164,4 @@ namespace ARMeilleure.Decoders
return false;
}
}
}
}

View file

@ -6,4 +6,4 @@
SingleBlock,
SingleInstruction,
}
}
}

View file

@ -14,4 +14,4 @@ namespace ARMeilleure.Decoders
OperandType GetOperandType();
}
}
}

View file

@ -6,4 +6,4 @@ namespace ARMeilleure.Decoders
uint GetPc();
}
}
}

View file

@ -5,4 +5,4 @@ namespace ARMeilleure.Decoders
int Rd { get; }
int Rn { get; }
}
}
}

View file

@ -6,4 +6,4 @@
bool IsRotated { get; }
}
}
}

View file

@ -4,4 +4,4 @@ namespace ARMeilleure.Decoders
{
int Immediate { get; }
}
}
}

View file

@ -7,4 +7,4 @@
ShiftType ShiftType { get; }
}
}
}

View file

@ -7,4 +7,4 @@
ShiftType ShiftType { get; }
}
}
}

View file

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

View file

@ -4,4 +4,4 @@ namespace ARMeilleure.Decoders
{
int Rm { get; }
}
}
}

View file

@ -4,4 +4,4 @@
{
int Id { get; }
}
}
}

View file

@ -4,4 +4,4 @@
{
bool? SetFlags { get; }
}
}
}

View file

@ -13,4 +13,4 @@ namespace ARMeilleure.Decoders
int Immediate { get; }
}
}
}

View file

@ -12,4 +12,4 @@ namespace ARMeilleure.Decoders
int Offset { get; }
}
}
}

View file

@ -4,4 +4,4 @@
{
int Rm { get; }
}
}
}

View file

@ -5,4 +5,4 @@ namespace ARMeilleure.Decoders
int Rm { get; }
ShiftType ShiftType { get; }
}
}
}

View file

@ -7,4 +7,4 @@ namespace ARMeilleure.Decoders
DataOp DataOp { get; }
}
}
}

View file

@ -4,4 +4,4 @@ namespace ARMeilleure.Decoders
{
long Immediate { get; }
}
}
}

View file

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

View file

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

View file

@ -4,4 +4,4 @@ namespace ARMeilleure.Decoders
{
long Immediate { get; }
}
}
}

View file

@ -4,4 +4,4 @@ namespace ARMeilleure.Decoders
{
Condition Cond { get; }
}
}
}

View file

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

View file

@ -4,4 +4,4 @@ namespace ARMeilleure.Decoders
{
int Size { get; }
}
}
}

View file

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

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