Compare commits
7 Commits
Author | SHA1 | Date | |
---|---|---|---|
23c844b2aa | |||
81691b9e37 | |||
2dc422bc14 | |||
a80fa5e33f | |||
954e995321 | |||
dad9ab6bb6 | |||
f0562b9c75 |
161
.github/workflows/flatpak.yml
vendored
Normal file
161
.github/workflows/flatpak.yml
vendored
Normal file
@ -0,0 +1,161 @@
|
|||||||
|
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_short_hash=$(git rev-parse --short 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_short_hash }}
|
||||||
|
shell: python
|
||||||
|
run: |
|
||||||
|
import hashlib
|
||||||
|
import hmac
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
import yaml
|
||||||
|
from datetime import datetime
|
||||||
|
from lxml import etree
|
||||||
|
|
||||||
|
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";
|
||||||
|
@ -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)
|
||||||
{
|
{
|
||||||
|
@ -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,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));
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
|
@ -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