Compare commits
11 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
05a41b31bc | ||
|
|
eed17f963e | ||
|
|
c09c0c002d | ||
|
|
d56d335c0b | ||
|
|
23c844b2aa | ||
|
|
81691b9e37 | ||
|
|
2dc422bc14 | ||
|
|
a80fa5e33f | ||
|
|
954e995321 | ||
|
|
dad9ab6bb6 | ||
|
|
f0562b9c75 |
171
.github/workflows/flatpak.yml
vendored
Normal file
171
.github/workflows/flatpak.yml
vendored
Normal file
@@ -0,0 +1,171 @@
|
|||||||
|
name: Flatpak release job
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_call:
|
||||||
|
inputs:
|
||||||
|
ryujinx_version:
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
|
||||||
|
|
||||||
|
concurrency: flatpak-release
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
release:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
env:
|
||||||
|
NUGET_PACKAGES: ${{ github.workspace }}/.nuget/packages
|
||||||
|
GIT_COMMITTER_NAME: "RyujinxBot"
|
||||||
|
GIT_COMMITTER_EMAIL: "61127645+RyujinxBot@users.noreply.github.com"
|
||||||
|
RYUJINX_PROJECT_FILE: "Ryujinx/Ryujinx.csproj"
|
||||||
|
NUGET_SOURCES_DESTDIR: "nuget-sources"
|
||||||
|
RYUJINX_VERSION: "${{ inputs.ryujinx_version }}"
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
path: Ryujinx
|
||||||
|
|
||||||
|
- uses: actions/setup-dotnet@v3
|
||||||
|
with:
|
||||||
|
global-json-file: Ryujinx/global.json
|
||||||
|
|
||||||
|
- name: Get version info
|
||||||
|
id: version_info
|
||||||
|
working-directory: Ryujinx
|
||||||
|
run: |
|
||||||
|
echo "git_hash=$(git rev-parse HEAD)" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
repository: flathub/org.ryujinx.Ryujinx
|
||||||
|
token: ${{ secrets.RYUJINX_BOT_PAT }}
|
||||||
|
submodules: recursive
|
||||||
|
path: flathub
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: python -m pip install PyYAML lxml
|
||||||
|
|
||||||
|
- name: Restore Nuget packages
|
||||||
|
run: dotnet restore Ryujinx/${{ env.RYUJINX_PROJECT_FILE }}
|
||||||
|
|
||||||
|
- name: Generate nuget_sources.json
|
||||||
|
shell: python
|
||||||
|
run: |
|
||||||
|
from pathlib import Path
|
||||||
|
import base64
|
||||||
|
import binascii
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
|
||||||
|
sources = []
|
||||||
|
|
||||||
|
for path in Path(os.environ['NUGET_PACKAGES']).glob('**/*.nupkg.sha512'):
|
||||||
|
name = path.parent.parent.name
|
||||||
|
version = path.parent.name
|
||||||
|
filename = '{}.{}.nupkg'.format(name, version)
|
||||||
|
url = 'https://api.nuget.org/v3-flatcontainer/{}/{}/{}'.format(name, version, filename)
|
||||||
|
|
||||||
|
with path.open() as fp:
|
||||||
|
sha512 = binascii.hexlify(base64.b64decode(fp.read())).decode('ascii')
|
||||||
|
|
||||||
|
sources.append({
|
||||||
|
'type': 'file',
|
||||||
|
'url': url,
|
||||||
|
'sha512': sha512,
|
||||||
|
'dest': os.environ['NUGET_SOURCES_DESTDIR'],
|
||||||
|
'dest-filename': filename,
|
||||||
|
})
|
||||||
|
|
||||||
|
with open('flathub/nuget_sources.json', 'w') as fp:
|
||||||
|
json.dump(sources, fp, indent=4)
|
||||||
|
|
||||||
|
- name: Update flatpak metadata
|
||||||
|
id: metadata
|
||||||
|
env:
|
||||||
|
RYUJINX_GIT_HASH: ${{ steps.version_info.outputs.git_hash }}
|
||||||
|
shell: python
|
||||||
|
run: |
|
||||||
|
import hashlib
|
||||||
|
import hmac
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
import yaml
|
||||||
|
from datetime import datetime
|
||||||
|
from lxml import etree
|
||||||
|
|
||||||
|
|
||||||
|
# Ensure we don't destroy multiline strings
|
||||||
|
def str_presenter(dumper, data):
|
||||||
|
if len(data.splitlines()) > 1:
|
||||||
|
return dumper.represent_scalar("tag:yaml.org,2002:str", data, style="|")
|
||||||
|
return dumper.represent_scalar("tag:yaml.org,2002:str", data)
|
||||||
|
|
||||||
|
|
||||||
|
yaml.representer.SafeRepresenter.add_representer(str, str_presenter)
|
||||||
|
|
||||||
|
yaml_file = "flathub/org.ryujinx.Ryujinx.yml"
|
||||||
|
xml_file = "flathub/org.ryujinx.Ryujinx.appdata.xml"
|
||||||
|
|
||||||
|
with open(yaml_file, "r") as f:
|
||||||
|
data = yaml.safe_load(f)
|
||||||
|
|
||||||
|
for source in data["modules"][0]["sources"]:
|
||||||
|
if type(source) is str:
|
||||||
|
continue
|
||||||
|
if (
|
||||||
|
source["type"] == "git"
|
||||||
|
and source["url"] == "https://github.com/Ryujinx/Ryujinx.git"
|
||||||
|
):
|
||||||
|
source["commit"] = os.environ['RYUJINX_GIT_HASH']
|
||||||
|
|
||||||
|
is_same_version = data["modules"][0]["build-options"]["env"]["RYUJINX_VERSION"] == os.environ['RYUJINX_VERSION']
|
||||||
|
|
||||||
|
with open(os.environ['GITHUB_OUTPUT'], "a") as gh_out:
|
||||||
|
if is_same_version:
|
||||||
|
gh_out.write(f"commit_message=Retry update to {os.environ['RYUJINX_VERSION']}")
|
||||||
|
else:
|
||||||
|
gh_out.write(f"commit_message=Update to {os.environ['RYUJINX_VERSION']}")
|
||||||
|
|
||||||
|
if not is_same_version:
|
||||||
|
data["modules"][0]["build-options"]["env"]["RYUJINX_VERSION"] = os.environ['RYUJINX_VERSION']
|
||||||
|
|
||||||
|
with open(yaml_file, "w") as f:
|
||||||
|
yaml.safe_dump(data, f, sort_keys=False)
|
||||||
|
|
||||||
|
parser = etree.XMLParser(remove_blank_text=True)
|
||||||
|
tree = etree.parse(xml_file, parser)
|
||||||
|
|
||||||
|
root = tree.getroot()
|
||||||
|
|
||||||
|
releases = root.find("releases")
|
||||||
|
|
||||||
|
element = etree.Element("release")
|
||||||
|
element.set("version", os.environ['RYUJINX_VERSION'])
|
||||||
|
element.set("date", datetime.now().date().isoformat())
|
||||||
|
releases.insert(0, element)
|
||||||
|
|
||||||
|
# Ensure 4 spaces
|
||||||
|
etree.indent(root, space=" ")
|
||||||
|
|
||||||
|
with open(xml_file, "wb") as f:
|
||||||
|
f.write(
|
||||||
|
etree.tostring(
|
||||||
|
tree,
|
||||||
|
pretty_print=True,
|
||||||
|
encoding="UTF-8",
|
||||||
|
doctype='<?xml version="1.0" encoding="UTF-8"?>',
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
- name: Push flatpak update
|
||||||
|
working-directory: flathub
|
||||||
|
env:
|
||||||
|
COMMIT_MESSAGE: ${{ steps.metadata.outputs.commit_message }}
|
||||||
|
run: |
|
||||||
|
git config user.name "${{ env.GIT_COMMITTER_NAME }}"
|
||||||
|
git config user.email "${{ env.GIT_COMMITTER_EMAIL }}"
|
||||||
|
git add .
|
||||||
|
git commit -m "$COMMIT_MESSAGE"
|
||||||
|
git push origin master
|
||||||
26
.github/workflows/release.yml
vendored
26
.github/workflows/release.yml
vendored
@@ -13,23 +13,22 @@ on:
|
|||||||
|
|
||||||
concurrency: release
|
concurrency: release
|
||||||
|
|
||||||
|
env:
|
||||||
|
POWERSHELL_TELEMETRY_OPTOUT: 1
|
||||||
|
DOTNET_CLI_TELEMETRY_OPTOUT: 1
|
||||||
|
RYUJINX_BASE_VERSION: "1.1"
|
||||||
|
RYUJINX_TARGET_RELEASE_CHANNEL_NAME: "master"
|
||||||
|
RYUJINX_TARGET_RELEASE_CHANNEL_OWNER: "Ryujinx"
|
||||||
|
RYUJINX_TARGET_RELEASE_CHANNEL_REPO: "release-channel-master"
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
release:
|
release:
|
||||||
runs-on: windows-latest
|
runs-on: windows-latest
|
||||||
|
|
||||||
env:
|
|
||||||
POWERSHELL_TELEMETRY_OPTOUT: 1
|
|
||||||
DOTNET_CLI_TELEMETRY_OPTOUT: 1
|
|
||||||
RYUJINX_BASE_VERSION: "1.1"
|
|
||||||
RYUJINX_TARGET_RELEASE_CHANNEL_NAME: "master"
|
|
||||||
RYUJINX_TARGET_RELEASE_CHANNEL_OWNER: "Ryujinx"
|
|
||||||
RYUJINX_TARGET_RELEASE_CHANNEL_REPO: "release-channel-master"
|
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
- uses: actions/setup-dotnet@v3
|
- uses: actions/setup-dotnet@v3
|
||||||
with:
|
with:
|
||||||
dotnet-version: 7.0.x
|
global-json-file: global.json
|
||||||
- name: Get version info
|
- name: Get version info
|
||||||
id: version_info
|
id: version_info
|
||||||
run: |
|
run: |
|
||||||
@@ -112,3 +111,10 @@ jobs:
|
|||||||
owner: ${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}
|
owner: ${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}
|
||||||
repo: ${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }}
|
repo: ${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }}
|
||||||
token: ${{ secrets.RELEASE_TOKEN }}
|
token: ${{ secrets.RELEASE_TOKEN }}
|
||||||
|
|
||||||
|
flatpak_release:
|
||||||
|
uses: ./.github/workflows/flatpak.yml
|
||||||
|
needs: release
|
||||||
|
with:
|
||||||
|
ryujinx_version: "1.1.${{ github.run_number }}"
|
||||||
|
secrets: inherit
|
||||||
|
|||||||
@@ -265,7 +265,7 @@ namespace ARMeilleure.CodeGen.Arm64
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
relocInfo = new RelocInfo(new RelocEntry[0]);
|
relocInfo = new RelocInfo(Array.Empty<RelocEntry>());
|
||||||
}
|
}
|
||||||
|
|
||||||
return (code, relocInfo);
|
return (code, relocInfo);
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ using static ARMeilleure.IntermediateRepresentation.Operation.Factory;
|
|||||||
|
|
||||||
namespace ARMeilleure.CodeGen.Arm64
|
namespace ARMeilleure.CodeGen.Arm64
|
||||||
{
|
{
|
||||||
class PreAllocator
|
static class PreAllocator
|
||||||
{
|
{
|
||||||
private class ConstantDict
|
private class ConstantDict
|
||||||
{
|
{
|
||||||
@@ -54,8 +54,8 @@ namespace ARMeilleure.CodeGen.Arm64
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
HandleConstantRegCopy(constants, block.Operations, node);
|
InsertConstantRegCopies(constants, block.Operations, node);
|
||||||
HandleDestructiveRegCopy(block.Operations, node);
|
InsertDestructiveRegCopies(block.Operations, node);
|
||||||
|
|
||||||
switch (node.Instruction)
|
switch (node.Instruction)
|
||||||
{
|
{
|
||||||
@@ -78,28 +78,28 @@ namespace ARMeilleure.CodeGen.Arm64
|
|||||||
|
|
||||||
// Copy values to registers expected by the function
|
// Copy values to registers expected by the function
|
||||||
// being called, as mandated by the ABI.
|
// being called, as mandated by the ABI.
|
||||||
HandleCall(constants, block.Operations, node);
|
InsertCallCopies(constants, block.Operations, node);
|
||||||
break;
|
break;
|
||||||
case Instruction.CompareAndSwap:
|
case Instruction.CompareAndSwap:
|
||||||
case Instruction.CompareAndSwap16:
|
case Instruction.CompareAndSwap16:
|
||||||
case Instruction.CompareAndSwap8:
|
case Instruction.CompareAndSwap8:
|
||||||
nextNode = HandleCompareAndSwap(block.Operations, node);
|
nextNode = GenerateCompareAndSwap(block.Operations, node);
|
||||||
break;
|
break;
|
||||||
case Instruction.LoadArgument:
|
case Instruction.LoadArgument:
|
||||||
nextNode = HandleLoadArgument(cctx, ref buffer, block.Operations, preservedArgs, node);
|
nextNode = InsertLoadArgumentCopy(cctx, ref buffer, block.Operations, preservedArgs, node);
|
||||||
break;
|
break;
|
||||||
case Instruction.Return:
|
case Instruction.Return:
|
||||||
HandleReturn(block.Operations, node);
|
InsertReturnCopy(block.Operations, node);
|
||||||
break;
|
break;
|
||||||
case Instruction.Tailcall:
|
case Instruction.Tailcall:
|
||||||
HandleTailcall(constants, block.Operations, stackAlloc, node, node);
|
InsertTailcallCopies(constants, block.Operations, stackAlloc, node, node);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void HandleConstantRegCopy(ConstantDict constants, IntrusiveList<Operation> nodes, Operation node)
|
private static void InsertConstantRegCopies(ConstantDict constants, IntrusiveList<Operation> nodes, Operation node)
|
||||||
{
|
{
|
||||||
if (node.SourcesCount == 0 || IsIntrinsicWithConst(node))
|
if (node.SourcesCount == 0 || IsIntrinsicWithConst(node))
|
||||||
{
|
{
|
||||||
@@ -211,7 +211,7 @@ namespace ARMeilleure.CodeGen.Arm64
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void HandleDestructiveRegCopy(IntrusiveList<Operation> nodes, Operation node)
|
private static void InsertDestructiveRegCopies(IntrusiveList<Operation> nodes, Operation node)
|
||||||
{
|
{
|
||||||
if (node.Destination == default || node.SourcesCount == 0)
|
if (node.Destination == default || node.SourcesCount == 0)
|
||||||
{
|
{
|
||||||
@@ -259,7 +259,7 @@ namespace ARMeilleure.CodeGen.Arm64
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void HandleCall(ConstantDict constants, IntrusiveList<Operation> nodes, Operation node)
|
private static void InsertCallCopies(ConstantDict constants, IntrusiveList<Operation> nodes, Operation node)
|
||||||
{
|
{
|
||||||
Operation operation = node;
|
Operation operation = node;
|
||||||
|
|
||||||
@@ -319,7 +319,7 @@ namespace ARMeilleure.CodeGen.Arm64
|
|||||||
|
|
||||||
Operation copyOp = Operation(Instruction.Copy, argReg, source);
|
Operation copyOp = Operation(Instruction.Copy, argReg, source);
|
||||||
|
|
||||||
HandleConstantRegCopy(constants, nodes, nodes.AddBefore(node, copyOp));
|
InsertConstantRegCopies(constants, nodes, nodes.AddBefore(node, copyOp));
|
||||||
|
|
||||||
sources.Add(argReg);
|
sources.Add(argReg);
|
||||||
}
|
}
|
||||||
@@ -329,7 +329,7 @@ namespace ARMeilleure.CodeGen.Arm64
|
|||||||
|
|
||||||
Operation spillOp = Operation(Instruction.SpillArg, default, offset, source);
|
Operation spillOp = Operation(Instruction.SpillArg, default, offset, source);
|
||||||
|
|
||||||
HandleConstantRegCopy(constants, nodes, nodes.AddBefore(node, spillOp));
|
InsertConstantRegCopies(constants, nodes, nodes.AddBefore(node, spillOp));
|
||||||
|
|
||||||
stackOffset += source.Type.GetSizeInBytes();
|
stackOffset += source.Type.GetSizeInBytes();
|
||||||
}
|
}
|
||||||
@@ -364,7 +364,7 @@ namespace ARMeilleure.CodeGen.Arm64
|
|||||||
operation.SetSources(sources.ToArray());
|
operation.SetSources(sources.ToArray());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void HandleTailcall(
|
private static void InsertTailcallCopies(
|
||||||
ConstantDict constants,
|
ConstantDict constants,
|
||||||
IntrusiveList<Operation> nodes,
|
IntrusiveList<Operation> nodes,
|
||||||
StackAllocator stackAlloc,
|
StackAllocator stackAlloc,
|
||||||
@@ -420,7 +420,7 @@ namespace ARMeilleure.CodeGen.Arm64
|
|||||||
|
|
||||||
Operation copyOp = Operation(Instruction.Copy, argReg, source);
|
Operation copyOp = Operation(Instruction.Copy, argReg, source);
|
||||||
|
|
||||||
HandleConstantRegCopy(constants, nodes, nodes.AddBefore(node, copyOp));
|
InsertConstantRegCopies(constants, nodes, nodes.AddBefore(node, copyOp));
|
||||||
|
|
||||||
sources.Add(argReg);
|
sources.Add(argReg);
|
||||||
}
|
}
|
||||||
@@ -444,7 +444,7 @@ namespace ARMeilleure.CodeGen.Arm64
|
|||||||
operation.SetSources(sources.ToArray());
|
operation.SetSources(sources.ToArray());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Operation HandleCompareAndSwap(IntrusiveList<Operation> nodes, Operation node)
|
private static Operation GenerateCompareAndSwap(IntrusiveList<Operation> nodes, Operation node)
|
||||||
{
|
{
|
||||||
Operand expected = node.GetSource(1);
|
Operand expected = node.GetSource(1);
|
||||||
|
|
||||||
@@ -508,7 +508,7 @@ namespace ARMeilleure.CodeGen.Arm64
|
|||||||
return node.ListNext;
|
return node.ListNext;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void HandleReturn(IntrusiveList<Operation> nodes, Operation node)
|
private static void InsertReturnCopy(IntrusiveList<Operation> nodes, Operation node)
|
||||||
{
|
{
|
||||||
if (node.SourcesCount == 0)
|
if (node.SourcesCount == 0)
|
||||||
{
|
{
|
||||||
@@ -537,7 +537,7 @@ namespace ARMeilleure.CodeGen.Arm64
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Operation HandleLoadArgument(
|
private static Operation InsertLoadArgumentCopy(
|
||||||
CompilerContext cctx,
|
CompilerContext cctx,
|
||||||
ref Span<Operation> buffer,
|
ref Span<Operation> buffer,
|
||||||
IntrusiveList<Operation> nodes,
|
IntrusiveList<Operation> nodes,
|
||||||
@@ -629,7 +629,7 @@ namespace ARMeilleure.CodeGen.Arm64
|
|||||||
if (dest.AssignmentsCount == 1)
|
if (dest.AssignmentsCount == 1)
|
||||||
{
|
{
|
||||||
// Let's propagate the argument if we can to avoid copies.
|
// Let's propagate the argument if we can to avoid copies.
|
||||||
Propagate(ref buffer, dest, preservedArgs[index]);
|
PreAllocatorCommon.Propagate(ref buffer, dest, preservedArgs[index]);
|
||||||
nextNode = node.ListNext;
|
nextNode = node.ListNext;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -648,54 +648,6 @@ namespace ARMeilleure.CodeGen.Arm64
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void Propagate(ref Span<Operation> buffer, Operand dest, Operand value)
|
|
||||||
{
|
|
||||||
ReadOnlySpan<Operation> uses = dest.GetUses(ref buffer);
|
|
||||||
|
|
||||||
foreach (Operation use in uses)
|
|
||||||
{
|
|
||||||
for (int srcIndex = 0; srcIndex < use.SourcesCount; srcIndex++)
|
|
||||||
{
|
|
||||||
Operand useSrc = use.GetSource(srcIndex);
|
|
||||||
|
|
||||||
if (useSrc == dest)
|
|
||||||
{
|
|
||||||
use.SetSource(srcIndex, value);
|
|
||||||
}
|
|
||||||
else if (useSrc.Kind == OperandKind.Memory)
|
|
||||||
{
|
|
||||||
MemoryOperand memoryOp = useSrc.GetMemory();
|
|
||||||
|
|
||||||
Operand baseAddr = memoryOp.BaseAddress;
|
|
||||||
Operand index = memoryOp.Index;
|
|
||||||
bool changed = false;
|
|
||||||
|
|
||||||
if (baseAddr == dest)
|
|
||||||
{
|
|
||||||
baseAddr = value;
|
|
||||||
changed = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (index == dest)
|
|
||||||
{
|
|
||||||
index = value;
|
|
||||||
changed = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (changed)
|
|
||||||
{
|
|
||||||
use.SetSource(srcIndex, MemoryOp(
|
|
||||||
useSrc.Type,
|
|
||||||
baseAddr,
|
|
||||||
index,
|
|
||||||
memoryOp.Scale,
|
|
||||||
memoryOp.Displacement));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Operand AddFloatConstantCopy(
|
private static Operand AddFloatConstantCopy(
|
||||||
ConstantDict constants,
|
ConstantDict constants,
|
||||||
IntrusiveList<Operation> nodes,
|
IntrusiveList<Operation> nodes,
|
||||||
|
|||||||
57
ARMeilleure/CodeGen/PreAllocatorCommon.cs
Normal file
57
ARMeilleure/CodeGen/PreAllocatorCommon.cs
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
using ARMeilleure.IntermediateRepresentation;
|
||||||
|
using System;
|
||||||
|
using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
|
||||||
|
|
||||||
|
namespace ARMeilleure.CodeGen
|
||||||
|
{
|
||||||
|
static class PreAllocatorCommon
|
||||||
|
{
|
||||||
|
public static void Propagate(ref Span<Operation> buffer, Operand dest, Operand value)
|
||||||
|
{
|
||||||
|
ReadOnlySpan<Operation> uses = dest.GetUses(ref buffer);
|
||||||
|
|
||||||
|
foreach (Operation use in uses)
|
||||||
|
{
|
||||||
|
for (int srcIndex = 0; srcIndex < use.SourcesCount; srcIndex++)
|
||||||
|
{
|
||||||
|
Operand useSrc = use.GetSource(srcIndex);
|
||||||
|
|
||||||
|
if (useSrc == dest)
|
||||||
|
{
|
||||||
|
use.SetSource(srcIndex, value);
|
||||||
|
}
|
||||||
|
else if (useSrc.Kind == OperandKind.Memory)
|
||||||
|
{
|
||||||
|
MemoryOperand memoryOp = useSrc.GetMemory();
|
||||||
|
|
||||||
|
Operand baseAddr = memoryOp.BaseAddress;
|
||||||
|
Operand index = memoryOp.Index;
|
||||||
|
bool changed = false;
|
||||||
|
|
||||||
|
if (baseAddr == dest)
|
||||||
|
{
|
||||||
|
baseAddr = value;
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (index == dest)
|
||||||
|
{
|
||||||
|
index = value;
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (changed)
|
||||||
|
{
|
||||||
|
use.SetSource(srcIndex, MemoryOp(
|
||||||
|
useSrc.Type,
|
||||||
|
baseAddr,
|
||||||
|
index,
|
||||||
|
memoryOp.Scale,
|
||||||
|
memoryOp.Displacement));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -433,16 +433,11 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
|
|||||||
|
|
||||||
private static int GetHighestValueIndex(Span<int> span)
|
private static int GetHighestValueIndex(Span<int> span)
|
||||||
{
|
{
|
||||||
int highest = span[0];
|
int highest = int.MinValue;
|
||||||
|
|
||||||
if (highest == int.MaxValue)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int selected = 0;
|
int selected = 0;
|
||||||
|
|
||||||
for (int index = 1; index < span.Length; index++)
|
for (int index = 0; index < span.Length; index++)
|
||||||
{
|
{
|
||||||
int current = span[index];
|
int current = span[index];
|
||||||
|
|
||||||
|
|||||||
@@ -2,19 +2,20 @@ using ARMeilleure.CodeGen.RegisterAllocators;
|
|||||||
using ARMeilleure.IntermediateRepresentation;
|
using ARMeilleure.IntermediateRepresentation;
|
||||||
using ARMeilleure.Translation;
|
using ARMeilleure.Translation;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
|
using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
|
||||||
using static ARMeilleure.IntermediateRepresentation.Operation.Factory;
|
using static ARMeilleure.IntermediateRepresentation.Operation.Factory;
|
||||||
|
|
||||||
namespace ARMeilleure.CodeGen.X86
|
namespace ARMeilleure.CodeGen.X86
|
||||||
{
|
{
|
||||||
static class PreAllocator
|
class PreAllocator
|
||||||
{
|
{
|
||||||
public static void RunPass(CompilerContext cctx, StackAllocator stackAlloc, out int maxCallArgs)
|
public static void RunPass(CompilerContext cctx, StackAllocator stackAlloc, out int maxCallArgs)
|
||||||
{
|
{
|
||||||
maxCallArgs = -1;
|
maxCallArgs = -1;
|
||||||
|
|
||||||
|
Span<Operation> buffer = default;
|
||||||
|
|
||||||
CallConvName callConv = CallingConvention.GetCurrentCallConv();
|
CallConvName callConv = CallingConvention.GetCurrentCallConv();
|
||||||
|
|
||||||
Operand[] preservedArgs = new Operand[CallingConvention.GetArgumentsOnRegsCount()];
|
Operand[] preservedArgs = new Operand[CallingConvention.GetArgumentsOnRegsCount()];
|
||||||
@@ -32,9 +33,9 @@ namespace ARMeilleure.CodeGen.X86
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
HandleConstantRegCopy(block.Operations, node);
|
InsertConstantRegCopies(block.Operations, node);
|
||||||
HandleDestructiveRegCopy(block.Operations, node);
|
InsertDestructiveRegCopies(block.Operations, node);
|
||||||
HandleConstrainedRegCopy(block.Operations, node);
|
InsertConstrainedRegCopies(block.Operations, node);
|
||||||
|
|
||||||
switch (node.Instruction)
|
switch (node.Instruction)
|
||||||
{
|
{
|
||||||
@@ -59,62 +60,62 @@ namespace ARMeilleure.CodeGen.X86
|
|||||||
// being called, as mandated by the ABI.
|
// being called, as mandated by the ABI.
|
||||||
if (callConv == CallConvName.Windows)
|
if (callConv == CallConvName.Windows)
|
||||||
{
|
{
|
||||||
HandleCallWindowsAbi(block.Operations, stackAlloc, node);
|
PreAllocatorWindows.InsertCallCopies(block.Operations, stackAlloc, node);
|
||||||
}
|
}
|
||||||
else /* if (callConv == CallConvName.SystemV) */
|
else /* if (callConv == CallConvName.SystemV) */
|
||||||
{
|
{
|
||||||
HandleCallSystemVAbi(block.Operations, node);
|
PreAllocatorSystemV.InsertCallCopies(block.Operations, node);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Instruction.ConvertToFPUI:
|
case Instruction.ConvertToFPUI:
|
||||||
HandleConvertToFPUI(block.Operations, node);
|
GenerateConvertToFPUI(block.Operations, node);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Instruction.LoadArgument:
|
case Instruction.LoadArgument:
|
||||||
if (callConv == CallConvName.Windows)
|
if (callConv == CallConvName.Windows)
|
||||||
{
|
{
|
||||||
nextNode = HandleLoadArgumentWindowsAbi(cctx, block.Operations, preservedArgs, node);
|
nextNode = PreAllocatorWindows.InsertLoadArgumentCopy(cctx, ref buffer, block.Operations, preservedArgs, node);
|
||||||
}
|
}
|
||||||
else /* if (callConv == CallConvName.SystemV) */
|
else /* if (callConv == CallConvName.SystemV) */
|
||||||
{
|
{
|
||||||
nextNode = HandleLoadArgumentSystemVAbi(cctx, block.Operations, preservedArgs, node);
|
nextNode = PreAllocatorSystemV.InsertLoadArgumentCopy(cctx, ref buffer, block.Operations, preservedArgs, node);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Instruction.Negate:
|
case Instruction.Negate:
|
||||||
if (!node.GetSource(0).Type.IsInteger())
|
if (!node.GetSource(0).Type.IsInteger())
|
||||||
{
|
{
|
||||||
HandleNegate(block.Operations, node);
|
GenerateNegate(block.Operations, node);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Instruction.Return:
|
case Instruction.Return:
|
||||||
if (callConv == CallConvName.Windows)
|
if (callConv == CallConvName.Windows)
|
||||||
{
|
{
|
||||||
HandleReturnWindowsAbi(cctx, block.Operations, preservedArgs, node);
|
PreAllocatorWindows.InsertReturnCopy(cctx, block.Operations, preservedArgs, node);
|
||||||
}
|
}
|
||||||
else /* if (callConv == CallConvName.SystemV) */
|
else /* if (callConv == CallConvName.SystemV) */
|
||||||
{
|
{
|
||||||
HandleReturnSystemVAbi(block.Operations, node);
|
PreAllocatorSystemV.InsertReturnCopy(block.Operations, node);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Instruction.Tailcall:
|
case Instruction.Tailcall:
|
||||||
if (callConv == CallConvName.Windows)
|
if (callConv == CallConvName.Windows)
|
||||||
{
|
{
|
||||||
HandleTailcallWindowsAbi(block.Operations, stackAlloc, node);
|
PreAllocatorWindows.InsertTailcallCopies(block.Operations, stackAlloc, node);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
HandleTailcallSystemVAbi(block.Operations, stackAlloc, node);
|
PreAllocatorSystemV.InsertTailcallCopies(block.Operations, stackAlloc, node);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Instruction.VectorInsert8:
|
case Instruction.VectorInsert8:
|
||||||
if (!HardwareCapabilities.SupportsSse41)
|
if (!HardwareCapabilities.SupportsSse41)
|
||||||
{
|
{
|
||||||
HandleVectorInsert8(block.Operations, node);
|
GenerateVectorInsert8(block.Operations, node);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -131,7 +132,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void HandleConstantRegCopy(IntrusiveList<Operation> nodes, Operation node)
|
protected static void InsertConstantRegCopies(IntrusiveList<Operation> nodes, Operation node)
|
||||||
{
|
{
|
||||||
if (node.SourcesCount == 0 || IsXmmIntrinsic(node))
|
if (node.SourcesCount == 0 || IsXmmIntrinsic(node))
|
||||||
{
|
{
|
||||||
@@ -212,7 +213,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void HandleConstrainedRegCopy(IntrusiveList<Operation> nodes, Operation node)
|
protected static void InsertConstrainedRegCopies(IntrusiveList<Operation> nodes, Operation node)
|
||||||
{
|
{
|
||||||
Operand dest = node.Destination;
|
Operand dest = node.Destination;
|
||||||
|
|
||||||
@@ -369,7 +370,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void HandleDestructiveRegCopy(IntrusiveList<Operation> nodes, Operation node)
|
protected static void InsertDestructiveRegCopies(IntrusiveList<Operation> nodes, Operation node)
|
||||||
{
|
{
|
||||||
if (node.Destination == default || node.SourcesCount == 0)
|
if (node.Destination == default || node.SourcesCount == 0)
|
||||||
{
|
{
|
||||||
@@ -447,7 +448,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void HandleConvertToFPUI(IntrusiveList<Operation> nodes, Operation node)
|
private static void GenerateConvertToFPUI(IntrusiveList<Operation> nodes, Operation node)
|
||||||
{
|
{
|
||||||
// Unsigned integer to FP conversions are not supported on X86.
|
// Unsigned integer to FP conversions are not supported on X86.
|
||||||
// We need to turn them into signed integer to FP conversions, and
|
// We need to turn them into signed integer to FP conversions, and
|
||||||
@@ -501,7 +502,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||||||
Delete(nodes, currentNode);
|
Delete(nodes, currentNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void HandleNegate(IntrusiveList<Operation> nodes, Operation node)
|
private static void GenerateNegate(IntrusiveList<Operation> nodes, Operation node)
|
||||||
{
|
{
|
||||||
// There's no SSE FP negate instruction, so we need to transform that into
|
// There's no SSE FP negate instruction, so we need to transform that into
|
||||||
// a XOR of the value to be negated with a mask with the highest bit set.
|
// a XOR of the value to be negated with a mask with the highest bit set.
|
||||||
@@ -534,7 +535,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||||||
Delete(nodes, currentNode);
|
Delete(nodes, currentNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void HandleVectorInsert8(IntrusiveList<Operation> nodes, Operation node)
|
private static void GenerateVectorInsert8(IntrusiveList<Operation> nodes, Operation node)
|
||||||
{
|
{
|
||||||
// Handle vector insertion, when SSE 4.1 is not supported.
|
// Handle vector insertion, when SSE 4.1 is not supported.
|
||||||
Operand dest = node.Destination;
|
Operand dest = node.Destination;
|
||||||
@@ -579,620 +580,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||||||
Delete(nodes, currentNode);
|
Delete(nodes, currentNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void HandleCallWindowsAbi(IntrusiveList<Operation> nodes, StackAllocator stackAlloc, Operation node)
|
protected static Operand AddXmmCopy(IntrusiveList<Operation> nodes, Operation node, Operand source)
|
||||||
{
|
|
||||||
Operand dest = node.Destination;
|
|
||||||
|
|
||||||
// Handle struct arguments.
|
|
||||||
int retArgs = 0;
|
|
||||||
int stackAllocOffset = 0;
|
|
||||||
|
|
||||||
int AllocateOnStack(int size)
|
|
||||||
{
|
|
||||||
// We assume that the stack allocator is initially empty (TotalSize = 0).
|
|
||||||
// Taking that into account, we can reuse the space allocated for other
|
|
||||||
// calls by keeping track of our own allocated size (stackAllocOffset).
|
|
||||||
// If the space allocated is not big enough, then we just expand it.
|
|
||||||
int offset = stackAllocOffset;
|
|
||||||
|
|
||||||
if (stackAllocOffset + size > stackAlloc.TotalSize)
|
|
||||||
{
|
|
||||||
stackAlloc.Allocate((stackAllocOffset + size) - stackAlloc.TotalSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
stackAllocOffset += size;
|
|
||||||
|
|
||||||
return offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
Operand arg0Reg = default;
|
|
||||||
|
|
||||||
if (dest != default && dest.Type == OperandType.V128)
|
|
||||||
{
|
|
||||||
int stackOffset = AllocateOnStack(dest.Type.GetSizeInBytes());
|
|
||||||
|
|
||||||
arg0Reg = Gpr(CallingConvention.GetIntArgumentRegister(0), OperandType.I64);
|
|
||||||
|
|
||||||
Operation allocOp = Operation(Instruction.StackAlloc, arg0Reg, Const(stackOffset));
|
|
||||||
|
|
||||||
nodes.AddBefore(node, allocOp);
|
|
||||||
|
|
||||||
retArgs = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int argsCount = node.SourcesCount - 1;
|
|
||||||
int maxArgs = CallingConvention.GetArgumentsOnRegsCount() - retArgs;
|
|
||||||
|
|
||||||
if (argsCount > maxArgs)
|
|
||||||
{
|
|
||||||
argsCount = maxArgs;
|
|
||||||
}
|
|
||||||
|
|
||||||
Operand[] sources = new Operand[1 + retArgs + argsCount];
|
|
||||||
|
|
||||||
sources[0] = node.GetSource(0);
|
|
||||||
|
|
||||||
if (arg0Reg != default)
|
|
||||||
{
|
|
||||||
sources[1] = arg0Reg;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int index = 1; index < node.SourcesCount; index++)
|
|
||||||
{
|
|
||||||
Operand source = node.GetSource(index);
|
|
||||||
|
|
||||||
if (source.Type == OperandType.V128)
|
|
||||||
{
|
|
||||||
Operand stackAddr = Local(OperandType.I64);
|
|
||||||
|
|
||||||
int stackOffset = AllocateOnStack(source.Type.GetSizeInBytes());
|
|
||||||
|
|
||||||
nodes.AddBefore(node, Operation(Instruction.StackAlloc, stackAddr, Const(stackOffset)));
|
|
||||||
|
|
||||||
Operation storeOp = Operation(Instruction.Store, default, stackAddr, source);
|
|
||||||
|
|
||||||
HandleConstantRegCopy(nodes, nodes.AddBefore(node, storeOp));
|
|
||||||
|
|
||||||
node.SetSource(index, stackAddr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle arguments passed on registers.
|
|
||||||
for (int index = 0; index < argsCount; index++)
|
|
||||||
{
|
|
||||||
Operand source = node.GetSource(index + 1);
|
|
||||||
Operand argReg;
|
|
||||||
|
|
||||||
int argIndex = index + retArgs;
|
|
||||||
|
|
||||||
if (source.Type.IsInteger())
|
|
||||||
{
|
|
||||||
argReg = Gpr(CallingConvention.GetIntArgumentRegister(argIndex), source.Type);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
argReg = Xmm(CallingConvention.GetVecArgumentRegister(argIndex), source.Type);
|
|
||||||
}
|
|
||||||
|
|
||||||
Operation copyOp = Operation(Instruction.Copy, argReg, source);
|
|
||||||
|
|
||||||
HandleConstantRegCopy(nodes, nodes.AddBefore(node, copyOp));
|
|
||||||
|
|
||||||
sources[1 + retArgs + index] = argReg;
|
|
||||||
}
|
|
||||||
|
|
||||||
// The remaining arguments (those that are not passed on registers)
|
|
||||||
// should be passed on the stack, we write them to the stack with "SpillArg".
|
|
||||||
for (int index = argsCount; index < node.SourcesCount - 1; index++)
|
|
||||||
{
|
|
||||||
Operand source = node.GetSource(index + 1);
|
|
||||||
Operand offset = Const((index + retArgs) * 8);
|
|
||||||
|
|
||||||
Operation spillOp = Operation(Instruction.SpillArg, default, offset, source);
|
|
||||||
|
|
||||||
HandleConstantRegCopy(nodes, nodes.AddBefore(node, spillOp));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dest != default)
|
|
||||||
{
|
|
||||||
if (dest.Type == OperandType.V128)
|
|
||||||
{
|
|
||||||
Operand retValueAddr = Local(OperandType.I64);
|
|
||||||
|
|
||||||
nodes.AddBefore(node, Operation(Instruction.Copy, retValueAddr, arg0Reg));
|
|
||||||
|
|
||||||
Operation loadOp = Operation(Instruction.Load, dest, retValueAddr);
|
|
||||||
|
|
||||||
nodes.AddAfter(node, loadOp);
|
|
||||||
|
|
||||||
node.Destination = default;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Operand retReg = dest.Type.IsInteger()
|
|
||||||
? Gpr(CallingConvention.GetIntReturnRegister(), dest.Type)
|
|
||||||
: Xmm(CallingConvention.GetVecReturnRegister(), dest.Type);
|
|
||||||
|
|
||||||
Operation copyOp = Operation(Instruction.Copy, dest, retReg);
|
|
||||||
|
|
||||||
nodes.AddAfter(node, copyOp);
|
|
||||||
|
|
||||||
node.Destination = retReg;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
node.SetSources(sources);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void HandleCallSystemVAbi(IntrusiveList<Operation> nodes, Operation node)
|
|
||||||
{
|
|
||||||
Operand dest = node.Destination;
|
|
||||||
|
|
||||||
List<Operand> sources = new List<Operand>
|
|
||||||
{
|
|
||||||
node.GetSource(0)
|
|
||||||
};
|
|
||||||
|
|
||||||
int argsCount = node.SourcesCount - 1;
|
|
||||||
|
|
||||||
int intMax = CallingConvention.GetIntArgumentsOnRegsCount();
|
|
||||||
int vecMax = CallingConvention.GetVecArgumentsOnRegsCount();
|
|
||||||
|
|
||||||
int intCount = 0;
|
|
||||||
int vecCount = 0;
|
|
||||||
|
|
||||||
int stackOffset = 0;
|
|
||||||
|
|
||||||
for (int index = 0; index < argsCount; index++)
|
|
||||||
{
|
|
||||||
Operand source = node.GetSource(index + 1);
|
|
||||||
|
|
||||||
bool passOnReg;
|
|
||||||
|
|
||||||
if (source.Type.IsInteger())
|
|
||||||
{
|
|
||||||
passOnReg = intCount < intMax;
|
|
||||||
}
|
|
||||||
else if (source.Type == OperandType.V128)
|
|
||||||
{
|
|
||||||
passOnReg = intCount + 1 < intMax;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
passOnReg = vecCount < vecMax;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (source.Type == OperandType.V128 && passOnReg)
|
|
||||||
{
|
|
||||||
// V128 is a struct, we pass each half on a GPR if possible.
|
|
||||||
Operand argReg = Gpr(CallingConvention.GetIntArgumentRegister(intCount++), OperandType.I64);
|
|
||||||
Operand argReg2 = Gpr(CallingConvention.GetIntArgumentRegister(intCount++), OperandType.I64);
|
|
||||||
|
|
||||||
nodes.AddBefore(node, Operation(Instruction.VectorExtract, argReg, source, Const(0)));
|
|
||||||
nodes.AddBefore(node, Operation(Instruction.VectorExtract, argReg2, source, Const(1)));
|
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (passOnReg)
|
|
||||||
{
|
|
||||||
Operand argReg = source.Type.IsInteger()
|
|
||||||
? Gpr(CallingConvention.GetIntArgumentRegister(intCount++), source.Type)
|
|
||||||
: Xmm(CallingConvention.GetVecArgumentRegister(vecCount++), source.Type);
|
|
||||||
|
|
||||||
Operation copyOp = Operation(Instruction.Copy, argReg, source);
|
|
||||||
|
|
||||||
HandleConstantRegCopy(nodes, nodes.AddBefore(node, copyOp));
|
|
||||||
|
|
||||||
sources.Add(argReg);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Operand offset = Const(stackOffset);
|
|
||||||
|
|
||||||
Operation spillOp = Operation(Instruction.SpillArg, default, offset, source);
|
|
||||||
|
|
||||||
HandleConstantRegCopy(nodes, nodes.AddBefore(node, spillOp));
|
|
||||||
|
|
||||||
stackOffset += source.Type.GetSizeInBytes();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
node.SetSources(sources.ToArray());
|
|
||||||
|
|
||||||
if (dest != default)
|
|
||||||
{
|
|
||||||
if (dest.Type == OperandType.V128)
|
|
||||||
{
|
|
||||||
Operand retLReg = Gpr(CallingConvention.GetIntReturnRegister(), OperandType.I64);
|
|
||||||
Operand retHReg = Gpr(CallingConvention.GetIntReturnRegisterHigh(), OperandType.I64);
|
|
||||||
|
|
||||||
Operation operation = node;
|
|
||||||
|
|
||||||
node = nodes.AddAfter(node, Operation(Instruction.VectorCreateScalar, dest, retLReg));
|
|
||||||
nodes.AddAfter(node, Operation(Instruction.VectorInsert, dest, dest, retHReg, Const(1)));
|
|
||||||
|
|
||||||
operation.Destination = default;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Operand retReg = dest.Type.IsInteger()
|
|
||||||
? Gpr(CallingConvention.GetIntReturnRegister(), dest.Type)
|
|
||||||
: Xmm(CallingConvention.GetVecReturnRegister(), dest.Type);
|
|
||||||
|
|
||||||
Operation copyOp = Operation(Instruction.Copy, dest, retReg);
|
|
||||||
|
|
||||||
nodes.AddAfter(node, copyOp);
|
|
||||||
|
|
||||||
node.Destination = retReg;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void HandleTailcallSystemVAbi(IntrusiveList<Operation> nodes, StackAllocator stackAlloc, Operation node)
|
|
||||||
{
|
|
||||||
List<Operand> sources = new List<Operand>
|
|
||||||
{
|
|
||||||
node.GetSource(0)
|
|
||||||
};
|
|
||||||
|
|
||||||
int argsCount = node.SourcesCount - 1;
|
|
||||||
|
|
||||||
int intMax = CallingConvention.GetIntArgumentsOnRegsCount();
|
|
||||||
int vecMax = CallingConvention.GetVecArgumentsOnRegsCount();
|
|
||||||
|
|
||||||
int intCount = 0;
|
|
||||||
int vecCount = 0;
|
|
||||||
|
|
||||||
// Handle arguments passed on registers.
|
|
||||||
for (int index = 0; index < argsCount; index++)
|
|
||||||
{
|
|
||||||
Operand source = node.GetSource(1 + index);
|
|
||||||
|
|
||||||
bool passOnReg;
|
|
||||||
|
|
||||||
if (source.Type.IsInteger())
|
|
||||||
{
|
|
||||||
passOnReg = intCount + 1 < intMax;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
passOnReg = vecCount < vecMax;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (source.Type == OperandType.V128 && passOnReg)
|
|
||||||
{
|
|
||||||
// V128 is a struct, we pass each half on a GPR if possible.
|
|
||||||
Operand argReg = Gpr(CallingConvention.GetIntArgumentRegister(intCount++), OperandType.I64);
|
|
||||||
Operand argReg2 = Gpr(CallingConvention.GetIntArgumentRegister(intCount++), OperandType.I64);
|
|
||||||
|
|
||||||
nodes.AddBefore(node, Operation(Instruction.VectorExtract, argReg, source, Const(0)));
|
|
||||||
nodes.AddBefore(node, Operation(Instruction.VectorExtract, argReg2, source, Const(1)));
|
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (passOnReg)
|
|
||||||
{
|
|
||||||
Operand argReg = source.Type.IsInteger()
|
|
||||||
? Gpr(CallingConvention.GetIntArgumentRegister(intCount++), source.Type)
|
|
||||||
: Xmm(CallingConvention.GetVecArgumentRegister(vecCount++), source.Type);
|
|
||||||
|
|
||||||
Operation copyOp = Operation(Instruction.Copy, argReg, source);
|
|
||||||
|
|
||||||
HandleConstantRegCopy(nodes, nodes.AddBefore(node, copyOp));
|
|
||||||
|
|
||||||
sources.Add(argReg);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw new NotImplementedException("Spilling is not currently supported for tail calls. (too many arguments)");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// The target address must be on the return registers, since we
|
|
||||||
// don't return anything and it is guaranteed to not be a
|
|
||||||
// callee saved register (which would be trashed on the epilogue).
|
|
||||||
Operand retReg = Gpr(CallingConvention.GetIntReturnRegister(), OperandType.I64);
|
|
||||||
|
|
||||||
Operation addrCopyOp = Operation(Instruction.Copy, retReg, node.GetSource(0));
|
|
||||||
|
|
||||||
nodes.AddBefore(node, addrCopyOp);
|
|
||||||
|
|
||||||
sources[0] = retReg;
|
|
||||||
|
|
||||||
node.SetSources(sources.ToArray());
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void HandleTailcallWindowsAbi(IntrusiveList<Operation> nodes, StackAllocator stackAlloc, Operation node)
|
|
||||||
{
|
|
||||||
int argsCount = node.SourcesCount - 1;
|
|
||||||
int maxArgs = CallingConvention.GetArgumentsOnRegsCount();
|
|
||||||
|
|
||||||
if (argsCount > maxArgs)
|
|
||||||
{
|
|
||||||
throw new NotImplementedException("Spilling is not currently supported for tail calls. (too many arguments)");
|
|
||||||
}
|
|
||||||
|
|
||||||
Operand[] sources = new Operand[1 + argsCount];
|
|
||||||
|
|
||||||
// Handle arguments passed on registers.
|
|
||||||
for (int index = 0; index < argsCount; index++)
|
|
||||||
{
|
|
||||||
Operand source = node.GetSource(1 + index);
|
|
||||||
Operand argReg = source.Type.IsInteger()
|
|
||||||
? Gpr(CallingConvention.GetIntArgumentRegister(index), source.Type)
|
|
||||||
: Xmm(CallingConvention.GetVecArgumentRegister(index), source.Type);
|
|
||||||
|
|
||||||
Operation copyOp = Operation(Instruction.Copy, argReg, source);
|
|
||||||
|
|
||||||
HandleConstantRegCopy(nodes, nodes.AddBefore(node, copyOp));
|
|
||||||
|
|
||||||
sources[1 + index] = argReg;
|
|
||||||
}
|
|
||||||
|
|
||||||
// The target address must be on the return registers, since we
|
|
||||||
// don't return anything and it is guaranteed to not be a
|
|
||||||
// callee saved register (which would be trashed on the epilogue).
|
|
||||||
Operand retReg = Gpr(CallingConvention.GetIntReturnRegister(), OperandType.I64);
|
|
||||||
|
|
||||||
Operation addrCopyOp = Operation(Instruction.Copy, retReg, node.GetSource(0));
|
|
||||||
|
|
||||||
nodes.AddBefore(node, addrCopyOp);
|
|
||||||
|
|
||||||
sources[0] = retReg;
|
|
||||||
|
|
||||||
node.SetSources(sources);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Operation HandleLoadArgumentWindowsAbi(
|
|
||||||
CompilerContext cctx,
|
|
||||||
IntrusiveList<Operation> nodes,
|
|
||||||
Operand[] preservedArgs,
|
|
||||||
Operation node)
|
|
||||||
{
|
|
||||||
Operand source = node.GetSource(0);
|
|
||||||
|
|
||||||
Debug.Assert(source.Kind == OperandKind.Constant, "Non-constant LoadArgument source kind.");
|
|
||||||
|
|
||||||
int retArgs = cctx.FuncReturnType == OperandType.V128 ? 1 : 0;
|
|
||||||
|
|
||||||
int index = source.AsInt32() + retArgs;
|
|
||||||
|
|
||||||
if (index < CallingConvention.GetArgumentsOnRegsCount())
|
|
||||||
{
|
|
||||||
Operand dest = node.Destination;
|
|
||||||
|
|
||||||
if (preservedArgs[index] == default)
|
|
||||||
{
|
|
||||||
Operand argReg, pArg;
|
|
||||||
|
|
||||||
if (dest.Type.IsInteger())
|
|
||||||
{
|
|
||||||
argReg = Gpr(CallingConvention.GetIntArgumentRegister(index), dest.Type);
|
|
||||||
pArg = Local(dest.Type);
|
|
||||||
}
|
|
||||||
else if (dest.Type == OperandType.V128)
|
|
||||||
{
|
|
||||||
argReg = Gpr(CallingConvention.GetIntArgumentRegister(index), OperandType.I64);
|
|
||||||
pArg = Local(OperandType.I64);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
argReg = Xmm(CallingConvention.GetVecArgumentRegister(index), dest.Type);
|
|
||||||
pArg = Local(dest.Type);
|
|
||||||
}
|
|
||||||
|
|
||||||
Operation copyOp = Operation(Instruction.Copy, pArg, argReg);
|
|
||||||
|
|
||||||
cctx.Cfg.Entry.Operations.AddFirst(copyOp);
|
|
||||||
|
|
||||||
preservedArgs[index] = pArg;
|
|
||||||
}
|
|
||||||
|
|
||||||
Operation argCopyOp = Operation(dest.Type == OperandType.V128
|
|
||||||
? Instruction.Load
|
|
||||||
: Instruction.Copy, dest, preservedArgs[index]);
|
|
||||||
|
|
||||||
Operation newNode = nodes.AddBefore(node, argCopyOp);
|
|
||||||
|
|
||||||
Delete(nodes, node);
|
|
||||||
|
|
||||||
return newNode;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// TODO: Pass on stack.
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Operation HandleLoadArgumentSystemVAbi(
|
|
||||||
CompilerContext cctx,
|
|
||||||
IntrusiveList<Operation> nodes,
|
|
||||||
Operand[] preservedArgs,
|
|
||||||
Operation node)
|
|
||||||
{
|
|
||||||
Operand source = node.GetSource(0);
|
|
||||||
|
|
||||||
Debug.Assert(source.Kind == OperandKind.Constant, "Non-constant LoadArgument source kind.");
|
|
||||||
|
|
||||||
int index = source.AsInt32();
|
|
||||||
|
|
||||||
int intCount = 0;
|
|
||||||
int vecCount = 0;
|
|
||||||
|
|
||||||
for (int cIndex = 0; cIndex < index; cIndex++)
|
|
||||||
{
|
|
||||||
OperandType argType = cctx.FuncArgTypes[cIndex];
|
|
||||||
|
|
||||||
if (argType.IsInteger())
|
|
||||||
{
|
|
||||||
intCount++;
|
|
||||||
}
|
|
||||||
else if (argType == OperandType.V128)
|
|
||||||
{
|
|
||||||
intCount += 2;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
vecCount++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool passOnReg;
|
|
||||||
|
|
||||||
if (source.Type.IsInteger())
|
|
||||||
{
|
|
||||||
passOnReg = intCount < CallingConvention.GetIntArgumentsOnRegsCount();
|
|
||||||
}
|
|
||||||
else if (source.Type == OperandType.V128)
|
|
||||||
{
|
|
||||||
passOnReg = intCount + 1 < CallingConvention.GetIntArgumentsOnRegsCount();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
passOnReg = vecCount < CallingConvention.GetVecArgumentsOnRegsCount();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (passOnReg)
|
|
||||||
{
|
|
||||||
Operand dest = node.Destination;
|
|
||||||
|
|
||||||
if (preservedArgs[index] == default)
|
|
||||||
{
|
|
||||||
if (dest.Type == OperandType.V128)
|
|
||||||
{
|
|
||||||
// V128 is a struct, we pass each half on a GPR if possible.
|
|
||||||
Operand pArg = Local(OperandType.V128);
|
|
||||||
|
|
||||||
Operand argLReg = Gpr(CallingConvention.GetIntArgumentRegister(intCount), OperandType.I64);
|
|
||||||
Operand argHReg = Gpr(CallingConvention.GetIntArgumentRegister(intCount + 1), OperandType.I64);
|
|
||||||
|
|
||||||
Operation copyL = Operation(Instruction.VectorCreateScalar, pArg, argLReg);
|
|
||||||
Operation copyH = Operation(Instruction.VectorInsert, pArg, pArg, argHReg, Const(1));
|
|
||||||
|
|
||||||
cctx.Cfg.Entry.Operations.AddFirst(copyH);
|
|
||||||
cctx.Cfg.Entry.Operations.AddFirst(copyL);
|
|
||||||
|
|
||||||
preservedArgs[index] = pArg;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Operand pArg = Local(dest.Type);
|
|
||||||
|
|
||||||
Operand argReg = dest.Type.IsInteger()
|
|
||||||
? Gpr(CallingConvention.GetIntArgumentRegister(intCount), dest.Type)
|
|
||||||
: Xmm(CallingConvention.GetVecArgumentRegister(vecCount), dest.Type);
|
|
||||||
|
|
||||||
Operation copyOp = Operation(Instruction.Copy, pArg, argReg);
|
|
||||||
|
|
||||||
cctx.Cfg.Entry.Operations.AddFirst(copyOp);
|
|
||||||
|
|
||||||
preservedArgs[index] = pArg;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Operation argCopyOp = Operation(Instruction.Copy, dest, preservedArgs[index]);
|
|
||||||
|
|
||||||
Operation newNode = nodes.AddBefore(node, argCopyOp);
|
|
||||||
|
|
||||||
Delete(nodes, node);
|
|
||||||
|
|
||||||
return newNode;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// TODO: Pass on stack.
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void HandleReturnWindowsAbi(
|
|
||||||
CompilerContext cctx,
|
|
||||||
IntrusiveList<Operation> nodes,
|
|
||||||
Operand[] preservedArgs,
|
|
||||||
Operation node)
|
|
||||||
{
|
|
||||||
if (node.SourcesCount == 0)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Operand source = node.GetSource(0);
|
|
||||||
Operand retReg;
|
|
||||||
|
|
||||||
if (source.Type.IsInteger())
|
|
||||||
{
|
|
||||||
retReg = Gpr(CallingConvention.GetIntReturnRegister(), source.Type);
|
|
||||||
}
|
|
||||||
else if (source.Type == OperandType.V128)
|
|
||||||
{
|
|
||||||
if (preservedArgs[0] == default)
|
|
||||||
{
|
|
||||||
Operand preservedArg = Local(OperandType.I64);
|
|
||||||
Operand arg0 = Gpr(CallingConvention.GetIntArgumentRegister(0), OperandType.I64);
|
|
||||||
|
|
||||||
Operation copyOp = Operation(Instruction.Copy, preservedArg, arg0);
|
|
||||||
|
|
||||||
cctx.Cfg.Entry.Operations.AddFirst(copyOp);
|
|
||||||
|
|
||||||
preservedArgs[0] = preservedArg;
|
|
||||||
}
|
|
||||||
|
|
||||||
retReg = preservedArgs[0];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
retReg = Xmm(CallingConvention.GetVecReturnRegister(), source.Type);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (source.Type == OperandType.V128)
|
|
||||||
{
|
|
||||||
Operation retStoreOp = Operation(Instruction.Store, default, retReg, source);
|
|
||||||
|
|
||||||
nodes.AddBefore(node, retStoreOp);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Operation retCopyOp = Operation(Instruction.Copy, retReg, source);
|
|
||||||
|
|
||||||
nodes.AddBefore(node, retCopyOp);
|
|
||||||
}
|
|
||||||
|
|
||||||
node.SetSources(Array.Empty<Operand>());
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void HandleReturnSystemVAbi(IntrusiveList<Operation> nodes, Operation node)
|
|
||||||
{
|
|
||||||
if (node.SourcesCount == 0)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Operand source = node.GetSource(0);
|
|
||||||
|
|
||||||
if (source.Type == OperandType.V128)
|
|
||||||
{
|
|
||||||
Operand retLReg = Gpr(CallingConvention.GetIntReturnRegister(), OperandType.I64);
|
|
||||||
Operand retHReg = Gpr(CallingConvention.GetIntReturnRegisterHigh(), OperandType.I64);
|
|
||||||
|
|
||||||
nodes.AddBefore(node, Operation(Instruction.VectorExtract, retLReg, source, Const(0)));
|
|
||||||
nodes.AddBefore(node, Operation(Instruction.VectorExtract, retHReg, source, Const(1)));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Operand retReg = source.Type.IsInteger()
|
|
||||||
? Gpr(CallingConvention.GetIntReturnRegister(), source.Type)
|
|
||||||
: Xmm(CallingConvention.GetVecReturnRegister(), source.Type);
|
|
||||||
|
|
||||||
Operation retCopyOp = Operation(Instruction.Copy, retReg, source);
|
|
||||||
|
|
||||||
nodes.AddBefore(node, retCopyOp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Operand AddXmmCopy(IntrusiveList<Operation> nodes, Operation node, Operand source)
|
|
||||||
{
|
{
|
||||||
Operand temp = Local(source.Type);
|
Operand temp = Local(source.Type);
|
||||||
Operand intConst = AddCopy(nodes, node, GetIntConst(source));
|
Operand intConst = AddCopy(nodes, node, GetIntConst(source));
|
||||||
@@ -1204,7 +592,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||||||
return temp;
|
return temp;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Operand AddCopy(IntrusiveList<Operation> nodes, Operation node, Operand source)
|
protected static Operand AddCopy(IntrusiveList<Operation> nodes, Operation node, Operand source)
|
||||||
{
|
{
|
||||||
Operand temp = Local(source.Type);
|
Operand temp = Local(source.Type);
|
||||||
|
|
||||||
@@ -1229,7 +617,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void Delete(IntrusiveList<Operation> nodes, Operation node)
|
protected static void Delete(IntrusiveList<Operation> nodes, Operation node)
|
||||||
{
|
{
|
||||||
node.Destination = default;
|
node.Destination = default;
|
||||||
|
|
||||||
@@ -1241,12 +629,12 @@ namespace ARMeilleure.CodeGen.X86
|
|||||||
nodes.Remove(node);
|
nodes.Remove(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Operand Gpr(X86Register register, OperandType type)
|
protected static Operand Gpr(X86Register register, OperandType type)
|
||||||
{
|
{
|
||||||
return Register((int)register, RegisterType.Integer, type);
|
return Register((int)register, RegisterType.Integer, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Operand Xmm(X86Register register, OperandType type)
|
protected static Operand Xmm(X86Register register, OperandType type)
|
||||||
{
|
{
|
||||||
return Register((int)register, RegisterType.Vector, type);
|
return Register((int)register, RegisterType.Vector, type);
|
||||||
}
|
}
|
||||||
|
|||||||
334
ARMeilleure/CodeGen/X86/PreAllocatorSystemV.cs
Normal file
334
ARMeilleure/CodeGen/X86/PreAllocatorSystemV.cs
Normal file
@@ -0,0 +1,334 @@
|
|||||||
|
using ARMeilleure.CodeGen.RegisterAllocators;
|
||||||
|
using ARMeilleure.IntermediateRepresentation;
|
||||||
|
using ARMeilleure.Translation;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
|
||||||
|
using static ARMeilleure.IntermediateRepresentation.Operation.Factory;
|
||||||
|
|
||||||
|
namespace ARMeilleure.CodeGen.X86
|
||||||
|
{
|
||||||
|
class PreAllocatorSystemV : PreAllocator
|
||||||
|
{
|
||||||
|
public static void InsertCallCopies(IntrusiveList<Operation> nodes, Operation node)
|
||||||
|
{
|
||||||
|
Operand dest = node.Destination;
|
||||||
|
|
||||||
|
List<Operand> sources = new List<Operand>
|
||||||
|
{
|
||||||
|
node.GetSource(0)
|
||||||
|
};
|
||||||
|
|
||||||
|
int argsCount = node.SourcesCount - 1;
|
||||||
|
|
||||||
|
int intMax = CallingConvention.GetIntArgumentsOnRegsCount();
|
||||||
|
int vecMax = CallingConvention.GetVecArgumentsOnRegsCount();
|
||||||
|
|
||||||
|
int intCount = 0;
|
||||||
|
int vecCount = 0;
|
||||||
|
|
||||||
|
int stackOffset = 0;
|
||||||
|
|
||||||
|
for (int index = 0; index < argsCount; index++)
|
||||||
|
{
|
||||||
|
Operand source = node.GetSource(index + 1);
|
||||||
|
|
||||||
|
bool passOnReg;
|
||||||
|
|
||||||
|
if (source.Type.IsInteger())
|
||||||
|
{
|
||||||
|
passOnReg = intCount < intMax;
|
||||||
|
}
|
||||||
|
else if (source.Type == OperandType.V128)
|
||||||
|
{
|
||||||
|
passOnReg = intCount + 1 < intMax;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
passOnReg = vecCount < vecMax;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (source.Type == OperandType.V128 && passOnReg)
|
||||||
|
{
|
||||||
|
// V128 is a struct, we pass each half on a GPR if possible.
|
||||||
|
Operand argReg = Gpr(CallingConvention.GetIntArgumentRegister(intCount++), OperandType.I64);
|
||||||
|
Operand argReg2 = Gpr(CallingConvention.GetIntArgumentRegister(intCount++), OperandType.I64);
|
||||||
|
|
||||||
|
nodes.AddBefore(node, Operation(Instruction.VectorExtract, argReg, source, Const(0)));
|
||||||
|
nodes.AddBefore(node, Operation(Instruction.VectorExtract, argReg2, source, Const(1)));
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (passOnReg)
|
||||||
|
{
|
||||||
|
Operand argReg = source.Type.IsInteger()
|
||||||
|
? Gpr(CallingConvention.GetIntArgumentRegister(intCount++), source.Type)
|
||||||
|
: Xmm(CallingConvention.GetVecArgumentRegister(vecCount++), source.Type);
|
||||||
|
|
||||||
|
Operation copyOp = Operation(Instruction.Copy, argReg, source);
|
||||||
|
|
||||||
|
InsertConstantRegCopies(nodes, nodes.AddBefore(node, copyOp));
|
||||||
|
|
||||||
|
sources.Add(argReg);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Operand offset = Const(stackOffset);
|
||||||
|
|
||||||
|
Operation spillOp = Operation(Instruction.SpillArg, default, offset, source);
|
||||||
|
|
||||||
|
InsertConstantRegCopies(nodes, nodes.AddBefore(node, spillOp));
|
||||||
|
|
||||||
|
stackOffset += source.Type.GetSizeInBytes();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
node.SetSources(sources.ToArray());
|
||||||
|
|
||||||
|
if (dest != default)
|
||||||
|
{
|
||||||
|
if (dest.Type == OperandType.V128)
|
||||||
|
{
|
||||||
|
Operand retLReg = Gpr(CallingConvention.GetIntReturnRegister(), OperandType.I64);
|
||||||
|
Operand retHReg = Gpr(CallingConvention.GetIntReturnRegisterHigh(), OperandType.I64);
|
||||||
|
|
||||||
|
Operation operation = node;
|
||||||
|
|
||||||
|
node = nodes.AddAfter(node, Operation(Instruction.VectorCreateScalar, dest, retLReg));
|
||||||
|
nodes.AddAfter(node, Operation(Instruction.VectorInsert, dest, dest, retHReg, Const(1)));
|
||||||
|
|
||||||
|
operation.Destination = default;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Operand retReg = dest.Type.IsInteger()
|
||||||
|
? Gpr(CallingConvention.GetIntReturnRegister(), dest.Type)
|
||||||
|
: Xmm(CallingConvention.GetVecReturnRegister(), dest.Type);
|
||||||
|
|
||||||
|
Operation copyOp = Operation(Instruction.Copy, dest, retReg);
|
||||||
|
|
||||||
|
nodes.AddAfter(node, copyOp);
|
||||||
|
|
||||||
|
node.Destination = retReg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void InsertTailcallCopies(IntrusiveList<Operation> nodes, StackAllocator stackAlloc, Operation node)
|
||||||
|
{
|
||||||
|
List<Operand> sources = new List<Operand>
|
||||||
|
{
|
||||||
|
node.GetSource(0)
|
||||||
|
};
|
||||||
|
|
||||||
|
int argsCount = node.SourcesCount - 1;
|
||||||
|
|
||||||
|
int intMax = CallingConvention.GetIntArgumentsOnRegsCount();
|
||||||
|
int vecMax = CallingConvention.GetVecArgumentsOnRegsCount();
|
||||||
|
|
||||||
|
int intCount = 0;
|
||||||
|
int vecCount = 0;
|
||||||
|
|
||||||
|
// Handle arguments passed on registers.
|
||||||
|
for (int index = 0; index < argsCount; index++)
|
||||||
|
{
|
||||||
|
Operand source = node.GetSource(1 + index);
|
||||||
|
|
||||||
|
bool passOnReg;
|
||||||
|
|
||||||
|
if (source.Type.IsInteger())
|
||||||
|
{
|
||||||
|
passOnReg = intCount + 1 < intMax;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
passOnReg = vecCount < vecMax;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (source.Type == OperandType.V128 && passOnReg)
|
||||||
|
{
|
||||||
|
// V128 is a struct, we pass each half on a GPR if possible.
|
||||||
|
Operand argReg = Gpr(CallingConvention.GetIntArgumentRegister(intCount++), OperandType.I64);
|
||||||
|
Operand argReg2 = Gpr(CallingConvention.GetIntArgumentRegister(intCount++), OperandType.I64);
|
||||||
|
|
||||||
|
nodes.AddBefore(node, Operation(Instruction.VectorExtract, argReg, source, Const(0)));
|
||||||
|
nodes.AddBefore(node, Operation(Instruction.VectorExtract, argReg2, source, Const(1)));
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (passOnReg)
|
||||||
|
{
|
||||||
|
Operand argReg = source.Type.IsInteger()
|
||||||
|
? Gpr(CallingConvention.GetIntArgumentRegister(intCount++), source.Type)
|
||||||
|
: Xmm(CallingConvention.GetVecArgumentRegister(vecCount++), source.Type);
|
||||||
|
|
||||||
|
Operation copyOp = Operation(Instruction.Copy, argReg, source);
|
||||||
|
|
||||||
|
InsertConstantRegCopies(nodes, nodes.AddBefore(node, copyOp));
|
||||||
|
|
||||||
|
sources.Add(argReg);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new NotImplementedException("Spilling is not currently supported for tail calls. (too many arguments)");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The target address must be on the return registers, since we
|
||||||
|
// don't return anything and it is guaranteed to not be a
|
||||||
|
// callee saved register (which would be trashed on the epilogue).
|
||||||
|
Operand retReg = Gpr(CallingConvention.GetIntReturnRegister(), OperandType.I64);
|
||||||
|
|
||||||
|
Operation addrCopyOp = Operation(Instruction.Copy, retReg, node.GetSource(0));
|
||||||
|
|
||||||
|
nodes.AddBefore(node, addrCopyOp);
|
||||||
|
|
||||||
|
sources[0] = retReg;
|
||||||
|
|
||||||
|
node.SetSources(sources.ToArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Operation InsertLoadArgumentCopy(
|
||||||
|
CompilerContext cctx,
|
||||||
|
ref Span<Operation> buffer,
|
||||||
|
IntrusiveList<Operation> nodes,
|
||||||
|
Operand[] preservedArgs,
|
||||||
|
Operation node)
|
||||||
|
{
|
||||||
|
Operand source = node.GetSource(0);
|
||||||
|
|
||||||
|
Debug.Assert(source.Kind == OperandKind.Constant, "Non-constant LoadArgument source kind.");
|
||||||
|
|
||||||
|
int index = source.AsInt32();
|
||||||
|
|
||||||
|
int intCount = 0;
|
||||||
|
int vecCount = 0;
|
||||||
|
|
||||||
|
for (int cIndex = 0; cIndex < index; cIndex++)
|
||||||
|
{
|
||||||
|
OperandType argType = cctx.FuncArgTypes[cIndex];
|
||||||
|
|
||||||
|
if (argType.IsInteger())
|
||||||
|
{
|
||||||
|
intCount++;
|
||||||
|
}
|
||||||
|
else if (argType == OperandType.V128)
|
||||||
|
{
|
||||||
|
intCount += 2;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
vecCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool passOnReg;
|
||||||
|
|
||||||
|
if (source.Type.IsInteger())
|
||||||
|
{
|
||||||
|
passOnReg = intCount < CallingConvention.GetIntArgumentsOnRegsCount();
|
||||||
|
}
|
||||||
|
else if (source.Type == OperandType.V128)
|
||||||
|
{
|
||||||
|
passOnReg = intCount + 1 < CallingConvention.GetIntArgumentsOnRegsCount();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
passOnReg = vecCount < CallingConvention.GetVecArgumentsOnRegsCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (passOnReg)
|
||||||
|
{
|
||||||
|
Operand dest = node.Destination;
|
||||||
|
|
||||||
|
if (preservedArgs[index] == default)
|
||||||
|
{
|
||||||
|
if (dest.Type == OperandType.V128)
|
||||||
|
{
|
||||||
|
// V128 is a struct, we pass each half on a GPR if possible.
|
||||||
|
Operand pArg = Local(OperandType.V128);
|
||||||
|
|
||||||
|
Operand argLReg = Gpr(CallingConvention.GetIntArgumentRegister(intCount), OperandType.I64);
|
||||||
|
Operand argHReg = Gpr(CallingConvention.GetIntArgumentRegister(intCount + 1), OperandType.I64);
|
||||||
|
|
||||||
|
Operation copyL = Operation(Instruction.VectorCreateScalar, pArg, argLReg);
|
||||||
|
Operation copyH = Operation(Instruction.VectorInsert, pArg, pArg, argHReg, Const(1));
|
||||||
|
|
||||||
|
cctx.Cfg.Entry.Operations.AddFirst(copyH);
|
||||||
|
cctx.Cfg.Entry.Operations.AddFirst(copyL);
|
||||||
|
|
||||||
|
preservedArgs[index] = pArg;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Operand pArg = Local(dest.Type);
|
||||||
|
|
||||||
|
Operand argReg = dest.Type.IsInteger()
|
||||||
|
? Gpr(CallingConvention.GetIntArgumentRegister(intCount), dest.Type)
|
||||||
|
: Xmm(CallingConvention.GetVecArgumentRegister(vecCount), dest.Type);
|
||||||
|
|
||||||
|
Operation copyOp = Operation(Instruction.Copy, pArg, argReg);
|
||||||
|
|
||||||
|
cctx.Cfg.Entry.Operations.AddFirst(copyOp);
|
||||||
|
|
||||||
|
preservedArgs[index] = pArg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Operation nextNode;
|
||||||
|
|
||||||
|
if (dest.AssignmentsCount == 1)
|
||||||
|
{
|
||||||
|
// Let's propagate the argument if we can to avoid copies.
|
||||||
|
PreAllocatorCommon.Propagate(ref buffer, dest, preservedArgs[index]);
|
||||||
|
nextNode = node.ListNext;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Operation argCopyOp = Operation(Instruction.Copy, dest, preservedArgs[index]);
|
||||||
|
nextNode = nodes.AddBefore(node, argCopyOp);
|
||||||
|
}
|
||||||
|
|
||||||
|
Delete(nodes, node);
|
||||||
|
return nextNode;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// TODO: Pass on stack.
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void InsertReturnCopy(IntrusiveList<Operation> nodes, Operation node)
|
||||||
|
{
|
||||||
|
if (node.SourcesCount == 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Operand source = node.GetSource(0);
|
||||||
|
|
||||||
|
if (source.Type == OperandType.V128)
|
||||||
|
{
|
||||||
|
Operand retLReg = Gpr(CallingConvention.GetIntReturnRegister(), OperandType.I64);
|
||||||
|
Operand retHReg = Gpr(CallingConvention.GetIntReturnRegisterHigh(), OperandType.I64);
|
||||||
|
|
||||||
|
nodes.AddBefore(node, Operation(Instruction.VectorExtract, retLReg, source, Const(0)));
|
||||||
|
nodes.AddBefore(node, Operation(Instruction.VectorExtract, retHReg, source, Const(1)));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Operand retReg = source.Type.IsInteger()
|
||||||
|
? Gpr(CallingConvention.GetIntReturnRegister(), source.Type)
|
||||||
|
: Xmm(CallingConvention.GetVecReturnRegister(), source.Type);
|
||||||
|
|
||||||
|
Operation retCopyOp = Operation(Instruction.Copy, retReg, source);
|
||||||
|
|
||||||
|
nodes.AddBefore(node, retCopyOp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
327
ARMeilleure/CodeGen/X86/PreAllocatorWindows.cs
Normal file
327
ARMeilleure/CodeGen/X86/PreAllocatorWindows.cs
Normal file
@@ -0,0 +1,327 @@
|
|||||||
|
using ARMeilleure.CodeGen.RegisterAllocators;
|
||||||
|
using ARMeilleure.IntermediateRepresentation;
|
||||||
|
using ARMeilleure.Translation;
|
||||||
|
using System;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
|
||||||
|
using static ARMeilleure.IntermediateRepresentation.Operation.Factory;
|
||||||
|
|
||||||
|
namespace ARMeilleure.CodeGen.X86
|
||||||
|
{
|
||||||
|
class PreAllocatorWindows : PreAllocator
|
||||||
|
{
|
||||||
|
public static void InsertCallCopies(IntrusiveList<Operation> nodes, StackAllocator stackAlloc, Operation node)
|
||||||
|
{
|
||||||
|
Operand dest = node.Destination;
|
||||||
|
|
||||||
|
// Handle struct arguments.
|
||||||
|
int retArgs = 0;
|
||||||
|
int stackAllocOffset = 0;
|
||||||
|
|
||||||
|
int AllocateOnStack(int size)
|
||||||
|
{
|
||||||
|
// We assume that the stack allocator is initially empty (TotalSize = 0).
|
||||||
|
// Taking that into account, we can reuse the space allocated for other
|
||||||
|
// calls by keeping track of our own allocated size (stackAllocOffset).
|
||||||
|
// If the space allocated is not big enough, then we just expand it.
|
||||||
|
int offset = stackAllocOffset;
|
||||||
|
|
||||||
|
if (stackAllocOffset + size > stackAlloc.TotalSize)
|
||||||
|
{
|
||||||
|
stackAlloc.Allocate((stackAllocOffset + size) - stackAlloc.TotalSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
stackAllocOffset += size;
|
||||||
|
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
Operand arg0Reg = default;
|
||||||
|
|
||||||
|
if (dest != default && dest.Type == OperandType.V128)
|
||||||
|
{
|
||||||
|
int stackOffset = AllocateOnStack(dest.Type.GetSizeInBytes());
|
||||||
|
|
||||||
|
arg0Reg = Gpr(CallingConvention.GetIntArgumentRegister(0), OperandType.I64);
|
||||||
|
|
||||||
|
Operation allocOp = Operation(Instruction.StackAlloc, arg0Reg, Const(stackOffset));
|
||||||
|
|
||||||
|
nodes.AddBefore(node, allocOp);
|
||||||
|
|
||||||
|
retArgs = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int argsCount = node.SourcesCount - 1;
|
||||||
|
int maxArgs = CallingConvention.GetArgumentsOnRegsCount() - retArgs;
|
||||||
|
|
||||||
|
if (argsCount > maxArgs)
|
||||||
|
{
|
||||||
|
argsCount = maxArgs;
|
||||||
|
}
|
||||||
|
|
||||||
|
Operand[] sources = new Operand[1 + retArgs + argsCount];
|
||||||
|
|
||||||
|
sources[0] = node.GetSource(0);
|
||||||
|
|
||||||
|
if (arg0Reg != default)
|
||||||
|
{
|
||||||
|
sources[1] = arg0Reg;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int index = 1; index < node.SourcesCount; index++)
|
||||||
|
{
|
||||||
|
Operand source = node.GetSource(index);
|
||||||
|
|
||||||
|
if (source.Type == OperandType.V128)
|
||||||
|
{
|
||||||
|
Operand stackAddr = Local(OperandType.I64);
|
||||||
|
|
||||||
|
int stackOffset = AllocateOnStack(source.Type.GetSizeInBytes());
|
||||||
|
|
||||||
|
nodes.AddBefore(node, Operation(Instruction.StackAlloc, stackAddr, Const(stackOffset)));
|
||||||
|
|
||||||
|
Operation storeOp = Operation(Instruction.Store, default, stackAddr, source);
|
||||||
|
|
||||||
|
InsertConstantRegCopies(nodes, nodes.AddBefore(node, storeOp));
|
||||||
|
|
||||||
|
node.SetSource(index, stackAddr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle arguments passed on registers.
|
||||||
|
for (int index = 0; index < argsCount; index++)
|
||||||
|
{
|
||||||
|
Operand source = node.GetSource(index + 1);
|
||||||
|
Operand argReg;
|
||||||
|
|
||||||
|
int argIndex = index + retArgs;
|
||||||
|
|
||||||
|
if (source.Type.IsInteger())
|
||||||
|
{
|
||||||
|
argReg = Gpr(CallingConvention.GetIntArgumentRegister(argIndex), source.Type);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
argReg = Xmm(CallingConvention.GetVecArgumentRegister(argIndex), source.Type);
|
||||||
|
}
|
||||||
|
|
||||||
|
Operation copyOp = Operation(Instruction.Copy, argReg, source);
|
||||||
|
|
||||||
|
InsertConstantRegCopies(nodes, nodes.AddBefore(node, copyOp));
|
||||||
|
|
||||||
|
sources[1 + retArgs + index] = argReg;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The remaining arguments (those that are not passed on registers)
|
||||||
|
// should be passed on the stack, we write them to the stack with "SpillArg".
|
||||||
|
for (int index = argsCount; index < node.SourcesCount - 1; index++)
|
||||||
|
{
|
||||||
|
Operand source = node.GetSource(index + 1);
|
||||||
|
Operand offset = Const((index + retArgs) * 8);
|
||||||
|
|
||||||
|
Operation spillOp = Operation(Instruction.SpillArg, default, offset, source);
|
||||||
|
|
||||||
|
InsertConstantRegCopies(nodes, nodes.AddBefore(node, spillOp));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dest != default)
|
||||||
|
{
|
||||||
|
if (dest.Type == OperandType.V128)
|
||||||
|
{
|
||||||
|
Operand retValueAddr = Local(OperandType.I64);
|
||||||
|
|
||||||
|
nodes.AddBefore(node, Operation(Instruction.Copy, retValueAddr, arg0Reg));
|
||||||
|
|
||||||
|
Operation loadOp = Operation(Instruction.Load, dest, retValueAddr);
|
||||||
|
|
||||||
|
nodes.AddAfter(node, loadOp);
|
||||||
|
|
||||||
|
node.Destination = default;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Operand retReg = dest.Type.IsInteger()
|
||||||
|
? Gpr(CallingConvention.GetIntReturnRegister(), dest.Type)
|
||||||
|
: Xmm(CallingConvention.GetVecReturnRegister(), dest.Type);
|
||||||
|
|
||||||
|
Operation copyOp = Operation(Instruction.Copy, dest, retReg);
|
||||||
|
|
||||||
|
nodes.AddAfter(node, copyOp);
|
||||||
|
|
||||||
|
node.Destination = retReg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
node.SetSources(sources);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void InsertTailcallCopies(IntrusiveList<Operation> nodes, StackAllocator stackAlloc, Operation node)
|
||||||
|
{
|
||||||
|
int argsCount = node.SourcesCount - 1;
|
||||||
|
int maxArgs = CallingConvention.GetArgumentsOnRegsCount();
|
||||||
|
|
||||||
|
if (argsCount > maxArgs)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException("Spilling is not currently supported for tail calls. (too many arguments)");
|
||||||
|
}
|
||||||
|
|
||||||
|
Operand[] sources = new Operand[1 + argsCount];
|
||||||
|
|
||||||
|
// Handle arguments passed on registers.
|
||||||
|
for (int index = 0; index < argsCount; index++)
|
||||||
|
{
|
||||||
|
Operand source = node.GetSource(1 + index);
|
||||||
|
Operand argReg = source.Type.IsInteger()
|
||||||
|
? Gpr(CallingConvention.GetIntArgumentRegister(index), source.Type)
|
||||||
|
: Xmm(CallingConvention.GetVecArgumentRegister(index), source.Type);
|
||||||
|
|
||||||
|
Operation copyOp = Operation(Instruction.Copy, argReg, source);
|
||||||
|
|
||||||
|
InsertConstantRegCopies(nodes, nodes.AddBefore(node, copyOp));
|
||||||
|
|
||||||
|
sources[1 + index] = argReg;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The target address must be on the return registers, since we
|
||||||
|
// don't return anything and it is guaranteed to not be a
|
||||||
|
// callee saved register (which would be trashed on the epilogue).
|
||||||
|
Operand retReg = Gpr(CallingConvention.GetIntReturnRegister(), OperandType.I64);
|
||||||
|
|
||||||
|
Operation addrCopyOp = Operation(Instruction.Copy, retReg, node.GetSource(0));
|
||||||
|
|
||||||
|
nodes.AddBefore(node, addrCopyOp);
|
||||||
|
|
||||||
|
sources[0] = retReg;
|
||||||
|
|
||||||
|
node.SetSources(sources);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Operation InsertLoadArgumentCopy(
|
||||||
|
CompilerContext cctx,
|
||||||
|
ref Span<Operation> buffer,
|
||||||
|
IntrusiveList<Operation> nodes,
|
||||||
|
Operand[] preservedArgs,
|
||||||
|
Operation node)
|
||||||
|
{
|
||||||
|
Operand source = node.GetSource(0);
|
||||||
|
|
||||||
|
Debug.Assert(source.Kind == OperandKind.Constant, "Non-constant LoadArgument source kind.");
|
||||||
|
|
||||||
|
int retArgs = cctx.FuncReturnType == OperandType.V128 ? 1 : 0;
|
||||||
|
|
||||||
|
int index = source.AsInt32() + retArgs;
|
||||||
|
|
||||||
|
if (index < CallingConvention.GetArgumentsOnRegsCount())
|
||||||
|
{
|
||||||
|
Operand dest = node.Destination;
|
||||||
|
|
||||||
|
if (preservedArgs[index] == default)
|
||||||
|
{
|
||||||
|
Operand argReg, pArg;
|
||||||
|
|
||||||
|
if (dest.Type.IsInteger())
|
||||||
|
{
|
||||||
|
argReg = Gpr(CallingConvention.GetIntArgumentRegister(index), dest.Type);
|
||||||
|
pArg = Local(dest.Type);
|
||||||
|
}
|
||||||
|
else if (dest.Type == OperandType.V128)
|
||||||
|
{
|
||||||
|
argReg = Gpr(CallingConvention.GetIntArgumentRegister(index), OperandType.I64);
|
||||||
|
pArg = Local(OperandType.I64);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
argReg = Xmm(CallingConvention.GetVecArgumentRegister(index), dest.Type);
|
||||||
|
pArg = Local(dest.Type);
|
||||||
|
}
|
||||||
|
|
||||||
|
Operation copyOp = Operation(Instruction.Copy, pArg, argReg);
|
||||||
|
|
||||||
|
cctx.Cfg.Entry.Operations.AddFirst(copyOp);
|
||||||
|
|
||||||
|
preservedArgs[index] = pArg;
|
||||||
|
}
|
||||||
|
|
||||||
|
Operation nextNode;
|
||||||
|
|
||||||
|
if (dest.Type != OperandType.V128 && dest.AssignmentsCount == 1)
|
||||||
|
{
|
||||||
|
// Let's propagate the argument if we can to avoid copies.
|
||||||
|
PreAllocatorCommon.Propagate(ref buffer, dest, preservedArgs[index]);
|
||||||
|
nextNode = node.ListNext;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Operation argCopyOp = Operation(dest.Type == OperandType.V128
|
||||||
|
? Instruction.Load
|
||||||
|
: Instruction.Copy, dest, preservedArgs[index]);
|
||||||
|
|
||||||
|
nextNode = nodes.AddBefore(node, argCopyOp);
|
||||||
|
}
|
||||||
|
|
||||||
|
Delete(nodes, node);
|
||||||
|
return nextNode;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// TODO: Pass on stack.
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void InsertReturnCopy(
|
||||||
|
CompilerContext cctx,
|
||||||
|
IntrusiveList<Operation> nodes,
|
||||||
|
Operand[] preservedArgs,
|
||||||
|
Operation node)
|
||||||
|
{
|
||||||
|
if (node.SourcesCount == 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Operand source = node.GetSource(0);
|
||||||
|
Operand retReg;
|
||||||
|
|
||||||
|
if (source.Type.IsInteger())
|
||||||
|
{
|
||||||
|
retReg = Gpr(CallingConvention.GetIntReturnRegister(), source.Type);
|
||||||
|
}
|
||||||
|
else if (source.Type == OperandType.V128)
|
||||||
|
{
|
||||||
|
if (preservedArgs[0] == default)
|
||||||
|
{
|
||||||
|
Operand preservedArg = Local(OperandType.I64);
|
||||||
|
Operand arg0 = Gpr(CallingConvention.GetIntArgumentRegister(0), OperandType.I64);
|
||||||
|
|
||||||
|
Operation copyOp = Operation(Instruction.Copy, preservedArg, arg0);
|
||||||
|
|
||||||
|
cctx.Cfg.Entry.Operations.AddFirst(copyOp);
|
||||||
|
|
||||||
|
preservedArgs[0] = preservedArg;
|
||||||
|
}
|
||||||
|
|
||||||
|
retReg = preservedArgs[0];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
retReg = Xmm(CallingConvention.GetVecReturnRegister(), source.Type);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (source.Type == OperandType.V128)
|
||||||
|
{
|
||||||
|
Operation retStoreOp = Operation(Instruction.Store, default, retReg, source);
|
||||||
|
|
||||||
|
nodes.AddBefore(node, retStoreOp);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Operation retCopyOp = Operation(Instruction.Copy, retReg, source);
|
||||||
|
|
||||||
|
nodes.AddBefore(node, retCopyOp);
|
||||||
|
}
|
||||||
|
|
||||||
|
node.SetSources(Array.Empty<Operand>());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -17,7 +17,7 @@ namespace ARMeilleure.Decoders
|
|||||||
{
|
{
|
||||||
uint[] tbl = new uint[256];
|
uint[] tbl = new uint[256];
|
||||||
|
|
||||||
for (int idx = 0; idx < 256; idx++)
|
for (int idx = 0; idx < tbl.Length; idx++)
|
||||||
{
|
{
|
||||||
tbl[idx] = ExpandImm8ToFP32((uint)idx);
|
tbl[idx] = ExpandImm8ToFP32((uint)idx);
|
||||||
}
|
}
|
||||||
@@ -29,7 +29,7 @@ namespace ARMeilleure.Decoders
|
|||||||
{
|
{
|
||||||
ulong[] tbl = new ulong[256];
|
ulong[] tbl = new ulong[256];
|
||||||
|
|
||||||
for (int idx = 0; idx < 256; idx++)
|
for (int idx = 0; idx < tbl.Length; idx++)
|
||||||
{
|
{
|
||||||
tbl[idx] = ExpandImm8ToFP64((ulong)idx);
|
tbl[idx] = ExpandImm8ToFP64((ulong)idx);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1301,7 +1301,7 @@ namespace ARMeilleure.Decoders
|
|||||||
{
|
{
|
||||||
List<InstInfo>[] temp = new List<InstInfo>[FastLookupSize];
|
List<InstInfo>[] temp = new List<InstInfo>[FastLookupSize];
|
||||||
|
|
||||||
for (int index = 0; index < FastLookupSize; index++)
|
for (int index = 0; index < temp.Length; index++)
|
||||||
{
|
{
|
||||||
temp[index] = new List<InstInfo>();
|
temp[index] = new List<InstInfo>();
|
||||||
}
|
}
|
||||||
@@ -1311,7 +1311,7 @@ namespace ARMeilleure.Decoders
|
|||||||
int mask = ToFastLookupIndex(inst.Mask);
|
int mask = ToFastLookupIndex(inst.Mask);
|
||||||
int value = ToFastLookupIndex(inst.Value);
|
int value = ToFastLookupIndex(inst.Value);
|
||||||
|
|
||||||
for (int index = 0; index < FastLookupSize; index++)
|
for (int index = 0; index < temp.Length; index++)
|
||||||
{
|
{
|
||||||
if ((index & mask) == value)
|
if ((index & mask) == value)
|
||||||
{
|
{
|
||||||
@@ -1320,7 +1320,7 @@ namespace ARMeilleure.Decoders
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int index = 0; index < FastLookupSize; index++)
|
for (int index = 0; index < temp.Length; index++)
|
||||||
{
|
{
|
||||||
table[index] = temp[index].ToArray();
|
table[index] = temp[index].ToArray();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ namespace ARMeilleure.Translation.PTC
|
|||||||
private const string OuterHeaderMagicString = "PTCohd\0\0";
|
private const string OuterHeaderMagicString = "PTCohd\0\0";
|
||||||
private const string InnerHeaderMagicString = "PTCihd\0\0";
|
private const string InnerHeaderMagicString = "PTCihd\0\0";
|
||||||
|
|
||||||
private const uint InternalVersion = 4328; //! To be incremented manually for each change to the ARMeilleure project.
|
private const uint InternalVersion = 4484; //! To be incremented manually for each change to the ARMeilleure project.
|
||||||
|
|
||||||
private const string ActualDir = "0";
|
private const string ActualDir = "0";
|
||||||
private const string BackupDir = "1";
|
private const string BackupDir = "1";
|
||||||
|
|||||||
@@ -12,7 +12,6 @@
|
|||||||
<PackageVersion Include="Avalonia.Svg.Skia" Version="0.10.18" />
|
<PackageVersion Include="Avalonia.Svg.Skia" Version="0.10.18" />
|
||||||
<PackageVersion Include="CommandLineParser" Version="2.9.1" />
|
<PackageVersion Include="CommandLineParser" Version="2.9.1" />
|
||||||
<PackageVersion Include="Concentus" Version="1.1.7" />
|
<PackageVersion Include="Concentus" Version="1.1.7" />
|
||||||
<PackageVersion Include="Crc32.NET" Version="1.2.0" />
|
|
||||||
<PackageVersion Include="DiscordRichPresence" Version="1.1.3.18" />
|
<PackageVersion Include="DiscordRichPresence" Version="1.1.3.18" />
|
||||||
<PackageVersion Include="DynamicData" Version="7.12.11" />
|
<PackageVersion Include="DynamicData" Version="7.12.11" />
|
||||||
<PackageVersion Include="FluentAvaloniaUI" Version="1.4.5" />
|
<PackageVersion Include="FluentAvaloniaUI" Version="1.4.5" />
|
||||||
@@ -45,10 +44,8 @@
|
|||||||
<PackageVersion Include="SPB" Version="0.0.4-build28" />
|
<PackageVersion Include="SPB" Version="0.0.4-build28" />
|
||||||
<PackageVersion Include="System.Drawing.Common" Version="7.0.0" />
|
<PackageVersion Include="System.Drawing.Common" Version="7.0.0" />
|
||||||
<PackageVersion Include="System.IdentityModel.Tokens.Jwt" Version="6.27.0" />
|
<PackageVersion Include="System.IdentityModel.Tokens.Jwt" Version="6.27.0" />
|
||||||
<PackageVersion Include="System.IO.FileSystem.Primitives" Version="4.3.0" />
|
<PackageVersion Include="System.IO.Hashing" Version="7.0.0" />
|
||||||
<PackageVersion Include="System.Management" Version="7.0.0" />
|
<PackageVersion Include="System.Management" Version="7.0.0" />
|
||||||
<PackageVersion Include="System.Net.NameResolution" Version="4.3.0" />
|
|
||||||
<PackageVersion Include="System.Threading.ThreadPool" Version="4.3.0" />
|
|
||||||
<PackageVersion Include="UnicornEngine.Unicorn" Version="2.0.2-rc1-f7c841d" />
|
<PackageVersion Include="UnicornEngine.Unicorn" Version="2.0.2-rc1-f7c841d" />
|
||||||
<PackageVersion Include="XamlNameReferenceGenerator" Version="1.5.1" />
|
<PackageVersion Include="XamlNameReferenceGenerator" Version="1.5.1" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|||||||
@@ -400,7 +400,9 @@ namespace Ryujinx.Audio.Common
|
|||||||
{
|
{
|
||||||
uint bufferIndex = (_releasedBufferIndex - _bufferReleasedCount) % Constants.AudioDeviceBufferCountMax;
|
uint bufferIndex = (_releasedBufferIndex - _bufferReleasedCount) % Constants.AudioDeviceBufferCountMax;
|
||||||
|
|
||||||
for (int i = 0; i < GetTotalBufferCount(); i++)
|
uint totalBufferCount = GetTotalBufferCount();
|
||||||
|
|
||||||
|
for (int i = 0; i < totalBufferCount; i++)
|
||||||
{
|
{
|
||||||
if (_buffers[bufferIndex].BufferTag == bufferTag)
|
if (_buffers[bufferIndex].BufferTag == bufferTag)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<Target Name="PostBuild" AfterTargets="PostBuildEvent" Condition="$([MSBuild]::IsOSPlatform('OSX'))">
|
<Target Name="PostBuild" AfterTargets="PostBuildEvent" Condition="$([MSBuild]::IsOSPlatform('OSX'))">
|
||||||
<Exec Command="codesign --entitlements $(ProjectDir)..\distribution\macos\entitlements.xml -f --deep -s $(SigningCertificate) $(TargetDir)$(TargetName)" />
|
<Exec Command="codesign --entitlements '$(ProjectDir)..\distribution\macos\entitlements.xml' -f --deep -s $(SigningCertificate) '$(TargetDir)$(TargetName)'" />
|
||||||
</Target>
|
</Target>
|
||||||
|
|
||||||
<PropertyGroup Condition="'$(RuntimeIdentifier)' != ''">
|
<PropertyGroup Condition="'$(RuntimeIdentifier)' != ''">
|
||||||
|
|||||||
@@ -236,7 +236,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
|
|
||||||
public DateTimeOffset DateOffset { get; set; }
|
public DateTimeOffset DateOffset { get; set; }
|
||||||
public TimeSpan TimeOffset { get; set; }
|
public TimeSpan TimeOffset { get; set; }
|
||||||
private AvaloniaList<TimeZone> TimeZones { get; set; }
|
internal AvaloniaList<TimeZone> TimeZones { get; set; }
|
||||||
public AvaloniaList<string> GameDirectories { get; set; }
|
public AvaloniaList<string> GameDirectories { get; set; }
|
||||||
public ObservableCollection<ComboBoxItem> AvailableGpus { get; set; }
|
public ObservableCollection<ComboBoxItem> AvailableGpus { get; set; }
|
||||||
|
|
||||||
|
|||||||
@@ -125,7 +125,7 @@ namespace Ryujinx.Ava.UI.Windows
|
|||||||
|
|
||||||
public static Bgra32[] GetBuffer(Image<Bgra32> image)
|
public static Bgra32[] GetBuffer(Image<Bgra32> image)
|
||||||
{
|
{
|
||||||
return image.TryGetSinglePixelSpan(out var data) ? data.ToArray() : new Bgra32[0];
|
return image.TryGetSinglePixelSpan(out var data) ? data.ToArray() : Array.Empty<Bgra32>();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int GetColorScore(Dictionary<int, int> dominantColorBin, int maxHitCount, PaletteColor color)
|
private static int GetColorScore(Dictionary<int, int> dominantColorBin, int maxHitCount, PaletteColor color)
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ namespace Ryujinx.Graphics.Vulkan.Queries
|
|||||||
|
|
||||||
_counterQueues = new CounterQueue[count];
|
_counterQueues = new CounterQueue[count];
|
||||||
|
|
||||||
for (int index = 0; index < count; index++)
|
for (int index = 0; index < _counterQueues.Length; index++)
|
||||||
{
|
{
|
||||||
CounterType type = (CounterType)index;
|
CounterType type = (CounterType)index;
|
||||||
_counterQueues[index] = new CounterQueue(gd, device, pipeline, type);
|
_counterQueues[index] = new CounterQueue(gd, device, pipeline, type);
|
||||||
|
|||||||
@@ -29,9 +29,6 @@
|
|||||||
<PackageReference Include="Silk.NET.Vulkan" />
|
<PackageReference Include="Silk.NET.Vulkan" />
|
||||||
<PackageReference Include="Silk.NET.Vulkan.Extensions.EXT" />
|
<PackageReference Include="Silk.NET.Vulkan.Extensions.EXT" />
|
||||||
<PackageReference Include="Silk.NET.Vulkan.Extensions.KHR" />
|
<PackageReference Include="Silk.NET.Vulkan.Extensions.KHR" />
|
||||||
<PackageReference Include="System.IO.FileSystem.Primitives" />
|
|
||||||
<PackageReference Include="System.Net.NameResolution" />
|
|
||||||
<PackageReference Include="System.Threading.ThreadPool" />
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
|
|
||||||
uint structSize = 0;
|
uint structSize = 0;
|
||||||
|
|
||||||
for (int i = 0; i < count; ++i)
|
for (int i = 0; i < Map.Length; ++i)
|
||||||
{
|
{
|
||||||
var typeSize = SizeOf(description[i].Type);
|
var typeSize = SizeOf(description[i].Type);
|
||||||
Map[i] = new SpecializationMapEntry(description[i].Id, structSize, typeSize);
|
Map[i] = new SpecializationMapEntry(description[i].Id, structSize, typeSize);
|
||||||
@@ -46,11 +46,10 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
// For advanced mapping with overlapping or staggered fields
|
// For advanced mapping with overlapping or staggered fields
|
||||||
public SpecDescription(SpecializationMapEntry[] map)
|
public SpecDescription(SpecializationMapEntry[] map)
|
||||||
{
|
{
|
||||||
int count = map.Length;
|
|
||||||
Map = map;
|
Map = map;
|
||||||
|
|
||||||
uint structSize = 0;
|
uint structSize = 0;
|
||||||
for (int i = 0; i < count; ++i)
|
for (int i = 0; i < map.Length; ++i)
|
||||||
{
|
{
|
||||||
structSize = Math.Max(structSize, map[i].Offset + (uint)map[i].Size);
|
structSize = Math.Max(structSize, map[i].Offset + (uint)map[i].Size);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -60,10 +60,9 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
private void RecreateSwapchain()
|
private void RecreateSwapchain()
|
||||||
{
|
{
|
||||||
var oldSwapchain = _swapchain;
|
var oldSwapchain = _swapchain;
|
||||||
int imageCount = _swapchainImageViews.Length;
|
|
||||||
_vsyncModeChanged = false;
|
_vsyncModeChanged = false;
|
||||||
|
|
||||||
for (int i = 0; i < imageCount; i++)
|
for (int i = 0; i < _swapchainImageViews.Length; i++)
|
||||||
{
|
{
|
||||||
_swapchainImageViews[i].Dispose();
|
_swapchainImageViews[i].Dispose();
|
||||||
}
|
}
|
||||||
@@ -147,7 +146,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
|
|
||||||
_swapchainImageViews = new Auto<DisposableImageView>[imageCount];
|
_swapchainImageViews = new Auto<DisposableImageView>[imageCount];
|
||||||
|
|
||||||
for (int i = 0; i < imageCount; i++)
|
for (int i = 0; i < _swapchainImageViews.Length; i++)
|
||||||
{
|
{
|
||||||
_swapchainImageViews[i] = CreateSwapchainImageView(_swapchainImages[i], surfaceFormat.Format);
|
_swapchainImageViews[i] = CreateSwapchainImageView(_swapchainImages[i], surfaceFormat.Format);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,12 +49,12 @@ namespace Ryujinx.HLE.HOS.Ipc
|
|||||||
|
|
||||||
public static IpcHandleDesc MakeCopy(params int[] handles)
|
public static IpcHandleDesc MakeCopy(params int[] handles)
|
||||||
{
|
{
|
||||||
return new IpcHandleDesc(handles, new int[0]);
|
return new IpcHandleDesc(handles, Array.Empty<int>());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IpcHandleDesc MakeMove(params int[] handles)
|
public static IpcHandleDesc MakeMove(params int[] handles)
|
||||||
{
|
{
|
||||||
return new IpcHandleDesc(new int[0], handles);
|
return new IpcHandleDesc(Array.Empty<int>(), handles);
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] GetBytes()
|
public byte[] GetBytes()
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
@@ -132,7 +133,7 @@ namespace Ryujinx.HLE.HOS.Ipc
|
|||||||
word0 |= (ReceiveBuff.Count & 0xf) << 24;
|
word0 |= (ReceiveBuff.Count & 0xf) << 24;
|
||||||
word0 |= (ExchangeBuff.Count & 0xf) << 28;
|
word0 |= (ExchangeBuff.Count & 0xf) << 28;
|
||||||
|
|
||||||
byte[] handleData = new byte[0];
|
byte[] handleData = Array.Empty<byte>();
|
||||||
|
|
||||||
if (HandleDesc != null)
|
if (HandleDesc != null)
|
||||||
{
|
{
|
||||||
@@ -202,7 +203,7 @@ namespace Ryujinx.HLE.HOS.Ipc
|
|||||||
word0 |= (ReceiveBuff.Count & 0xf) << 24;
|
word0 |= (ReceiveBuff.Count & 0xf) << 24;
|
||||||
word0 |= (ExchangeBuff.Count & 0xf) << 28;
|
word0 |= (ExchangeBuff.Count & 0xf) << 28;
|
||||||
|
|
||||||
byte[] handleData = new byte[0];
|
byte[] handleData = Array.Empty<byte>();
|
||||||
|
|
||||||
if (HandleDesc != null)
|
if (HandleDesc != null)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
using Ryujinx.Common;
|
using Ryujinx.Common;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
|
||||||
namespace Ryujinx.HLE.HOS.Kernel.Common
|
namespace Ryujinx.HLE.HOS.Kernel.Common
|
||||||
@@ -86,7 +85,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Common
|
|||||||
{
|
{
|
||||||
Interlocked.Exchange(ref _enforceWakeupFromSpinWait, 0);
|
Interlocked.Exchange(ref _enforceWakeupFromSpinWait, 0);
|
||||||
|
|
||||||
next = _waitingObjects.OrderBy(x => x.TimePoint).FirstOrDefault();
|
next = GetNextWaitingObject();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (next != null)
|
if (next != null)
|
||||||
@@ -140,6 +139,26 @@ namespace Ryujinx.HLE.HOS.Kernel.Common
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private WaitingObject GetNextWaitingObject()
|
||||||
|
{
|
||||||
|
WaitingObject selected = null;
|
||||||
|
|
||||||
|
long lowestTimePoint = long.MaxValue;
|
||||||
|
|
||||||
|
for (int index = _waitingObjects.Count - 1; index >= 0; index--)
|
||||||
|
{
|
||||||
|
WaitingObject current = _waitingObjects[index];
|
||||||
|
|
||||||
|
if (current.TimePoint <= lowestTimePoint)
|
||||||
|
{
|
||||||
|
selected = current;
|
||||||
|
lowestTimePoint = current.TimePoint;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return selected;
|
||||||
|
}
|
||||||
|
|
||||||
public static long ConvertNanosecondsToMilliseconds(long time)
|
public static long ConvertNanosecondsToMilliseconds(long time)
|
||||||
{
|
{
|
||||||
time /= 1000000;
|
time /= 1000000;
|
||||||
|
|||||||
@@ -233,7 +233,7 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
|
|||||||
// If the location name is too long, error out.
|
// If the location name is too long, error out.
|
||||||
if (locationName.Length > 0x24)
|
if (locationName.Length > 0x24)
|
||||||
{
|
{
|
||||||
outLocationNameArray = new string[0];
|
outLocationNameArray = Array.Empty<string>();
|
||||||
|
|
||||||
return ResultCode.LocationNameTooLong;
|
return ResultCode.LocationNameTooLong;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,7 +27,9 @@ namespace Ryujinx.Input.SDL2
|
|||||||
SDL2Driver.Instance.OnJoystickDisconnected += HandleJoyStickDisconnected;
|
SDL2Driver.Instance.OnJoystickDisconnected += HandleJoyStickDisconnected;
|
||||||
|
|
||||||
// Add already connected gamepads
|
// Add already connected gamepads
|
||||||
for (int joystickIndex = 0; joystickIndex < SDL_NumJoysticks(); joystickIndex++)
|
int numJoysticks = SDL_NumJoysticks();
|
||||||
|
|
||||||
|
for (int joystickIndex = 0; joystickIndex < numJoysticks; joystickIndex++)
|
||||||
{
|
{
|
||||||
HandleJoyStickConnected(joystickIndex, SDL_JoystickGetDeviceInstanceID(joystickIndex));
|
HandleJoyStickConnected(joystickIndex, SDL_JoystickGetDeviceInstanceID(joystickIndex));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
using Force.Crc32;
|
using Ryujinx.Common;
|
||||||
using Ryujinx.Common;
|
|
||||||
using Ryujinx.Common.Configuration.Hid;
|
using Ryujinx.Common.Configuration.Hid;
|
||||||
using Ryujinx.Common.Configuration.Hid.Controller;
|
using Ryujinx.Common.Configuration.Hid.Controller;
|
||||||
using Ryujinx.Common.Configuration.Hid.Controller.Motion;
|
using Ryujinx.Common.Configuration.Hid.Controller.Motion;
|
||||||
@@ -9,6 +8,7 @@ using Ryujinx.Input.Motion.CemuHook.Protocol;
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.IO.Hashing;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Net.Sockets;
|
using System.Net.Sockets;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
@@ -401,10 +401,10 @@ namespace Ryujinx.Input.Motion.CemuHook
|
|||||||
writer.Seek(6, SeekOrigin.Begin);
|
writer.Seek(6, SeekOrigin.Begin);
|
||||||
writer.Write(header.Length);
|
writer.Write(header.Length);
|
||||||
|
|
||||||
header.Crc32 = Crc32Algorithm.Compute(stream.ToArray());
|
Crc32.Hash(stream.ToArray(), header.Crc32.AsSpan());
|
||||||
|
|
||||||
writer.Seek(8, SeekOrigin.Begin);
|
writer.Seek(8, SeekOrigin.Begin);
|
||||||
writer.Write(header.Crc32);
|
writer.Write(header.Crc32.AsSpan());
|
||||||
|
|
||||||
byte[] data = stream.ToArray();
|
byte[] data = stream.ToArray();
|
||||||
|
|
||||||
@@ -440,10 +440,10 @@ namespace Ryujinx.Input.Motion.CemuHook
|
|||||||
writer.Seek(6, SeekOrigin.Begin);
|
writer.Seek(6, SeekOrigin.Begin);
|
||||||
writer.Write(header.Length);
|
writer.Write(header.Length);
|
||||||
|
|
||||||
header.Crc32 = Crc32Algorithm.Compute(stream.ToArray());
|
Crc32.Hash(stream.ToArray(), header.Crc32.AsSpan());
|
||||||
|
|
||||||
writer.Seek(8, SeekOrigin.Begin);
|
writer.Seek(8, SeekOrigin.Begin);
|
||||||
writer.Write(header.Crc32);
|
writer.Write(header.Crc32.AsSpan());
|
||||||
|
|
||||||
byte[] data = stream.ToArray();
|
byte[] data = stream.ToArray();
|
||||||
|
|
||||||
@@ -458,8 +458,7 @@ namespace Ryujinx.Input.Motion.CemuHook
|
|||||||
Id = (uint)clientId,
|
Id = (uint)clientId,
|
||||||
MagicString = Magic,
|
MagicString = Magic,
|
||||||
Version = Version,
|
Version = Version,
|
||||||
Length = 0,
|
Length = 0
|
||||||
Crc32 = 0
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return header;
|
return header;
|
||||||
|
|||||||
@@ -1,14 +1,15 @@
|
|||||||
using System.Runtime.InteropServices;
|
using Ryujinx.Common.Memory;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace Ryujinx.Input.Motion.CemuHook.Protocol
|
namespace Ryujinx.Input.Motion.CemuHook.Protocol
|
||||||
{
|
{
|
||||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||||
public struct Header
|
public struct Header
|
||||||
{
|
{
|
||||||
public uint MagicString;
|
public uint MagicString;
|
||||||
public ushort Version;
|
public ushort Version;
|
||||||
public ushort Length;
|
public ushort Length;
|
||||||
public uint Crc32;
|
public Array4<byte> Crc32;
|
||||||
public uint Id;
|
public uint Id;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -6,7 +6,7 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Crc32.NET" />
|
<PackageReference Include="System.IO.Hashing" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -78,7 +78,7 @@ namespace Ryujinx.Memory.Tests
|
|||||||
|
|
||||||
IEnumerable<MemoryRange> IVirtualMemoryManager.GetPhysicalRegions(ulong va, ulong size)
|
IEnumerable<MemoryRange> IVirtualMemoryManager.GetPhysicalRegions(ulong va, ulong size)
|
||||||
{
|
{
|
||||||
return NoMappings ? new MemoryRange[0] : new MemoryRange[] { new MemoryRange(va, size) };
|
return NoMappings ? Array.Empty<MemoryRange>() : new MemoryRange[] { new MemoryRange(va, size) };
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool IsMapped(ulong va)
|
public bool IsMapped(ulong va)
|
||||||
|
|||||||
@@ -6,31 +6,31 @@ PUBLISH_DIRECTORY=$1
|
|||||||
OUTPUT_DIRECTORY=$2
|
OUTPUT_DIRECTORY=$2
|
||||||
ENTITLEMENTS_FILE_PATH=$3
|
ENTITLEMENTS_FILE_PATH=$3
|
||||||
|
|
||||||
APP_BUNDLE_DIRECTORY=$OUTPUT_DIRECTORY/Ryujinx.app
|
APP_BUNDLE_DIRECTORY="$OUTPUT_DIRECTORY/Ryujinx.app"
|
||||||
|
|
||||||
rm -rf $APP_BUNDLE_DIRECTORY
|
rm -rf "$APP_BUNDLE_DIRECTORY"
|
||||||
mkdir -p $APP_BUNDLE_DIRECTORY/Contents
|
mkdir -p "$APP_BUNDLE_DIRECTORY/Contents"
|
||||||
mkdir $APP_BUNDLE_DIRECTORY/Contents/Frameworks
|
mkdir "$APP_BUNDLE_DIRECTORY/Contents/Frameworks"
|
||||||
mkdir $APP_BUNDLE_DIRECTORY/Contents/MacOS
|
mkdir "$APP_BUNDLE_DIRECTORY/Contents/MacOS"
|
||||||
mkdir $APP_BUNDLE_DIRECTORY/Contents/Resources
|
mkdir "$APP_BUNDLE_DIRECTORY/Contents/Resources"
|
||||||
|
|
||||||
# Copy executables first
|
# Copy executables first
|
||||||
cp $PUBLISH_DIRECTORY/Ryujinx.Ava $APP_BUNDLE_DIRECTORY/Contents/MacOS/Ryujinx
|
cp "$PUBLISH_DIRECTORY/Ryujinx.Ava" "$APP_BUNDLE_DIRECTORY/Contents/MacOS/Ryujinx"
|
||||||
chmod u+x $APP_BUNDLE_DIRECTORY/Contents/MacOS/Ryujinx
|
chmod u+x "$APP_BUNDLE_DIRECTORY/Contents/MacOS/Ryujinx"
|
||||||
|
|
||||||
# Then all libraries
|
# Then all libraries
|
||||||
cp $PUBLISH_DIRECTORY/*.dylib $APP_BUNDLE_DIRECTORY/Contents/Frameworks
|
cp "$PUBLISH_DIRECTORY"/*.dylib "$APP_BUNDLE_DIRECTORY/Contents/Frameworks"
|
||||||
|
|
||||||
# Then resources
|
# Then resources
|
||||||
cp Info.plist $APP_BUNDLE_DIRECTORY/Contents
|
cp Info.plist "$APP_BUNDLE_DIRECTORY/Contents"
|
||||||
cp Ryujinx.icns $APP_BUNDLE_DIRECTORY/Contents/Resources/Ryujinx.icns
|
cp Ryujinx.icns "$APP_BUNDLE_DIRECTORY/Contents/Resources/Ryujinx.icns"
|
||||||
cp updater.sh $APP_BUNDLE_DIRECTORY/Contents/Resources/updater.sh
|
cp updater.sh "$APP_BUNDLE_DIRECTORY/Contents/Resources/updater.sh"
|
||||||
cp -r $PUBLISH_DIRECTORY/THIRDPARTY.md $APP_BUNDLE_DIRECTORY/Contents/Resources
|
cp -r "$PUBLISH_DIRECTORY/THIRDPARTY.md" "$APP_BUNDLE_DIRECTORY/Contents/Resources"
|
||||||
|
|
||||||
echo -n "APPL????" > $APP_BUNDLE_DIRECTORY/Contents/PkgInfo
|
echo -n "APPL????" > "$APP_BUNDLE_DIRECTORY/Contents/PkgInfo"
|
||||||
|
|
||||||
# Fixup libraries and executable
|
# Fixup libraries and executable
|
||||||
python3 bundle_fix_up.py $APP_BUNDLE_DIRECTORY MacOS/Ryujinx
|
python3 bundle_fix_up.py "$APP_BUNDLE_DIRECTORY" MacOS/Ryujinx
|
||||||
|
|
||||||
# Now sign it
|
# Now sign it
|
||||||
if ! [ -x "$(command -v codesign)" ];
|
if ! [ -x "$(command -v codesign)" ];
|
||||||
@@ -44,9 +44,9 @@ then
|
|||||||
# NOTE: Currently require https://github.com/indygreg/apple-platform-rs/pull/44 to work on other OSes.
|
# NOTE: Currently require https://github.com/indygreg/apple-platform-rs/pull/44 to work on other OSes.
|
||||||
# cargo install --git "https://github.com/marysaka/apple-platform-rs" --branch "fix/adhoc-app-bundle" apple-codesign --bin "rcodesign"
|
# cargo install --git "https://github.com/marysaka/apple-platform-rs" --branch "fix/adhoc-app-bundle" apple-codesign --bin "rcodesign"
|
||||||
echo "Usign rcodesign for ad-hoc signing"
|
echo "Usign rcodesign for ad-hoc signing"
|
||||||
rcodesign sign --entitlements-xml-path $ENTITLEMENTS_FILE_PATH $APP_BUNDLE_DIRECTORY
|
rcodesign sign --entitlements-xml-path "$ENTITLEMENTS_FILE_PATH" "$APP_BUNDLE_DIRECTORY"
|
||||||
else
|
else
|
||||||
echo "Usign codesign for ad-hoc signing"
|
echo "Usign codesign for ad-hoc signing"
|
||||||
codesign --entitlements $ENTITLEMENTS_FILE_PATH -f --deep -s - $APP_BUNDLE_DIRECTORY
|
codesign --entitlements "$ENTITLEMENTS_FILE_PATH" -f --deep -s - "$APP_BUNDLE_DIRECTORY"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|||||||
@@ -7,54 +7,54 @@ if [ "$#" -ne 6 ]; then
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
mkdir -p $1
|
mkdir -p "$1"
|
||||||
mkdir -p $2
|
mkdir -p "$2"
|
||||||
mkdir -p $3
|
mkdir -p "$3"
|
||||||
|
|
||||||
BASE_DIR=$(readlink -f $1)
|
BASE_DIR=$(readlink -f "$1")
|
||||||
TEMP_DIRECTORY=$(readlink -f $2)
|
TEMP_DIRECTORY=$(readlink -f "$2")
|
||||||
OUTPUT_DIRECTORY=$(readlink -f $3)
|
OUTPUT_DIRECTORY=$(readlink -f "$3")
|
||||||
ENTITLEMENTS_FILE_PATH=$(readlink -f $4)
|
ENTITLEMENTS_FILE_PATH=$(readlink -f "$4")
|
||||||
VERSION=$5
|
VERSION=$5
|
||||||
SOURCE_REVISION_ID=$6
|
SOURCE_REVISION_ID=$6
|
||||||
|
|
||||||
RELEASE_TAR_FILE_NAME=Ryujinx-$VERSION-macos_universal.app.tar
|
RELEASE_TAR_FILE_NAME=Ryujinx-$VERSION-macos_universal.app.tar
|
||||||
ARM64_APP_BUNDLE=$TEMP_DIRECTORY/output_arm64/Ryujinx.app
|
ARM64_APP_BUNDLE="$TEMP_DIRECTORY/output_arm64/Ryujinx.app"
|
||||||
X64_APP_BUNDLE=$TEMP_DIRECTORY/output_x64/Ryujinx.app
|
X64_APP_BUNDLE="$TEMP_DIRECTORY/output_x64/Ryujinx.app"
|
||||||
UNIVERSAL_APP_BUNDLE=$OUTPUT_DIRECTORY/Ryujinx.app
|
UNIVERSAL_APP_BUNDLE="$OUTPUT_DIRECTORY/Ryujinx.app"
|
||||||
EXECUTABLE_SUB_PATH=Contents/MacOS/Ryujinx
|
EXECUTABLE_SUB_PATH=Contents/MacOS/Ryujinx
|
||||||
|
|
||||||
rm -rf $TEMP_DIRECTORY
|
rm -rf "$TEMP_DIRECTORY"
|
||||||
mkdir -p $TEMP_DIRECTORY
|
mkdir -p "$TEMP_DIRECTORY"
|
||||||
|
|
||||||
DOTNET_COMMON_ARGS="-p:DebugType=embedded -p:Version=$VERSION -p:SourceRevisionId=$SOURCE_REVISION_ID --self-contained true"
|
DOTNET_COMMON_ARGS="-p:DebugType=embedded -p:Version=$VERSION -p:SourceRevisionId=$SOURCE_REVISION_ID --self-contained true"
|
||||||
|
|
||||||
dotnet restore
|
dotnet restore
|
||||||
dotnet build -c Release Ryujinx.Ava
|
dotnet build -c Release Ryujinx.Ava
|
||||||
dotnet publish -c Release -r osx-arm64 -o $TEMP_DIRECTORY/publish_arm64 $DOTNET_COMMON_ARGS Ryujinx.Ava
|
dotnet publish -c Release -r osx-arm64 -o "$TEMP_DIRECTORY/publish_arm64" $DOTNET_COMMON_ARGS Ryujinx.Ava
|
||||||
dotnet publish -c Release -r osx-x64 -o $TEMP_DIRECTORY/publish_x64 $DOTNET_COMMON_ARGS Ryujinx.Ava
|
dotnet publish -c Release -r osx-x64 -o "$TEMP_DIRECTORY/publish_x64" $DOTNET_COMMON_ARGS Ryujinx.Ava
|
||||||
|
|
||||||
# Get ride of the support library for ARMeilleur for x64 (that's only for arm64)
|
# Get ride of the support library for ARMeilleur for x64 (that's only for arm64)
|
||||||
rm -rf $TEMP_DIRECTORY/publish_x64/libarmeilleure-jitsupport.dylib
|
rm -rf "$TEMP_DIRECTORY/publish_x64/libarmeilleure-jitsupport.dylib"
|
||||||
|
|
||||||
# Get ride of libsoundio from arm64 builds as we don't have a arm64 variant
|
# Get ride of libsoundio from arm64 builds as we don't have a arm64 variant
|
||||||
# TODO: remove this once done
|
# TODO: remove this once done
|
||||||
rm -rf $TEMP_DIRECTORY/publish_arm64/libsoundio.dylib
|
rm -rf "$TEMP_DIRECTORY/publish_arm64/libsoundio.dylib"
|
||||||
|
|
||||||
pushd $BASE_DIR/distribution/macos
|
pushd "$BASE_DIR/distribution/macos"
|
||||||
./create_app_bundle.sh $TEMP_DIRECTORY/publish_x64 $TEMP_DIRECTORY/output_x64 $ENTITLEMENTS_FILE_PATH
|
./create_app_bundle.sh "$TEMP_DIRECTORY/publish_x64" "$TEMP_DIRECTORY/output_x64" "$ENTITLEMENTS_FILE_PATH"
|
||||||
./create_app_bundle.sh $TEMP_DIRECTORY/publish_arm64 $TEMP_DIRECTORY/output_arm64 $ENTITLEMENTS_FILE_PATH
|
./create_app_bundle.sh "$TEMP_DIRECTORY/publish_arm64" "$TEMP_DIRECTORY/output_arm64" "$ENTITLEMENTS_FILE_PATH"
|
||||||
popd
|
popd
|
||||||
|
|
||||||
rm -rf $UNIVERSAL_APP_BUNDLE
|
rm -rf "$UNIVERSAL_APP_BUNDLE"
|
||||||
mkdir -p $OUTPUT_DIRECTORY
|
mkdir -p "$OUTPUT_DIRECTORY"
|
||||||
|
|
||||||
# Let's copy one of the two different app bundle and remove the executable
|
# Let's copy one of the two different app bundle and remove the executable
|
||||||
cp -R $ARM64_APP_BUNDLE $UNIVERSAL_APP_BUNDLE
|
cp -R "$ARM64_APP_BUNDLE" "$UNIVERSAL_APP_BUNDLE"
|
||||||
rm $UNIVERSAL_APP_BUNDLE/$EXECUTABLE_SUB_PATH
|
rm "$UNIVERSAL_APP_BUNDLE/$EXECUTABLE_SUB_PATH"
|
||||||
|
|
||||||
# Make it libraries universal
|
# Make it libraries universal
|
||||||
python3 $BASE_DIR/distribution/macos/construct_universal_dylib.py $ARM64_APP_BUNDLE $X64_APP_BUNDLE $UNIVERSAL_APP_BUNDLE "**/*.dylib"
|
python3 "$BASE_DIR/distribution/macos/construct_universal_dylib.py" "$ARM64_APP_BUNDLE" "$X64_APP_BUNDLE" "$UNIVERSAL_APP_BUNDLE" "**/*.dylib"
|
||||||
|
|
||||||
if ! [ -x "$(command -v lipo)" ];
|
if ! [ -x "$(command -v lipo)" ];
|
||||||
then
|
then
|
||||||
@@ -69,12 +69,12 @@ else
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# Make it the executable universal
|
# Make it the executable universal
|
||||||
$LIPO $ARM64_APP_BUNDLE/$EXECUTABLE_SUB_PATH $X64_APP_BUNDLE/$EXECUTABLE_SUB_PATH -output $UNIVERSAL_APP_BUNDLE/$EXECUTABLE_SUB_PATH -create
|
$LIPO "$ARM64_APP_BUNDLE/$EXECUTABLE_SUB_PATH" "$X64_APP_BUNDLE/$EXECUTABLE_SUB_PATH" -output "$UNIVERSAL_APP_BUNDLE/$EXECUTABLE_SUB_PATH" -create
|
||||||
|
|
||||||
# Patch up the Info.plist to have appropriate version
|
# Patch up the Info.plist to have appropriate version
|
||||||
sed -r -i.bck "s/\%\%RYUJINX_BUILD_VERSION\%\%/$VERSION/g;" $UNIVERSAL_APP_BUNDLE/Contents/Info.plist
|
sed -r -i.bck "s/\%\%RYUJINX_BUILD_VERSION\%\%/$VERSION/g;" "$UNIVERSAL_APP_BUNDLE/Contents/Info.plist"
|
||||||
sed -r -i.bck "s/\%\%RYUJINX_BUILD_GIT_HASH\%\%/$SOURCE_REVISION_ID/g;" $UNIVERSAL_APP_BUNDLE/Contents/Info.plist
|
sed -r -i.bck "s/\%\%RYUJINX_BUILD_GIT_HASH\%\%/$SOURCE_REVISION_ID/g;" "$UNIVERSAL_APP_BUNDLE/Contents/Info.plist"
|
||||||
rm $UNIVERSAL_APP_BUNDLE/Contents/Info.plist.bck
|
rm "$UNIVERSAL_APP_BUNDLE/Contents/Info.plist.bck"
|
||||||
|
|
||||||
# Now sign it
|
# Now sign it
|
||||||
if ! [ -x "$(command -v codesign)" ];
|
if ! [ -x "$(command -v codesign)" ];
|
||||||
@@ -88,16 +88,16 @@ then
|
|||||||
# NOTE: Currently require https://github.com/indygreg/apple-platform-rs/pull/44 to work on other OSes.
|
# NOTE: Currently require https://github.com/indygreg/apple-platform-rs/pull/44 to work on other OSes.
|
||||||
# cargo install --git "https://github.com/marysaka/apple-platform-rs" --branch "fix/adhoc-app-bundle" apple-codesign --bin "rcodesign"
|
# cargo install --git "https://github.com/marysaka/apple-platform-rs" --branch "fix/adhoc-app-bundle" apple-codesign --bin "rcodesign"
|
||||||
echo "Usign rcodesign for ad-hoc signing"
|
echo "Usign rcodesign for ad-hoc signing"
|
||||||
rcodesign sign --entitlements-xml-path $ENTITLEMENTS_FILE_PATH $UNIVERSAL_APP_BUNDLE
|
rcodesign sign --entitlements-xml-path "$ENTITLEMENTS_FILE_PATH" "$UNIVERSAL_APP_BUNDLE"
|
||||||
else
|
else
|
||||||
echo "Usign codesign for ad-hoc signing"
|
echo "Usign codesign for ad-hoc signing"
|
||||||
codesign --entitlements $ENTITLEMENTS_FILE_PATH -f --deep -s - $UNIVERSAL_APP_BUNDLE
|
codesign --entitlements "$ENTITLEMENTS_FILE_PATH" -f --deep -s - "$UNIVERSAL_APP_BUNDLE"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "Creating archive"
|
echo "Creating archive"
|
||||||
pushd $OUTPUT_DIRECTORY
|
pushd "$OUTPUT_DIRECTORY"
|
||||||
tar --exclude "Ryujinx.app/Contents/MacOS/Ryujinx" -cvf $RELEASE_TAR_FILE_NAME Ryujinx.app 1> /dev/null
|
tar --exclude "Ryujinx.app/Contents/MacOS/Ryujinx" -cvf $RELEASE_TAR_FILE_NAME Ryujinx.app 1> /dev/null
|
||||||
python3 $BASE_DIR/distribution/misc/add_tar_exec.py $RELEASE_TAR_FILE_NAME "Ryujinx.app/Contents/MacOS/Ryujinx" "Ryujinx.app/Contents/MacOS/Ryujinx"
|
python3 "$BASE_DIR/distribution/misc/add_tar_exec.py" $RELEASE_TAR_FILE_NAME "Ryujinx.app/Contents/MacOS/Ryujinx" "Ryujinx.app/Contents/MacOS/Ryujinx"
|
||||||
gzip -9 < $RELEASE_TAR_FILE_NAME > $RELEASE_TAR_FILE_NAME.gz
|
gzip -9 < $RELEASE_TAR_FILE_NAME > $RELEASE_TAR_FILE_NAME.gz
|
||||||
rm $RELEASE_TAR_FILE_NAME
|
rm $RELEASE_TAR_FILE_NAME
|
||||||
popd
|
popd
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"sdk": {
|
"sdk": {
|
||||||
"version": "7.0.100",
|
"version": "7.0.200",
|
||||||
"rollForward": "latestFeature"
|
"rollForward": "latestFeature"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user