Compare commits

..

11 Commits

Author SHA1 Message Date
05a41b31bc Misc: Support space in path on macOS distribution (#4462)
* .

* Apply suggestions from code review

Co-authored-by: TSRBerry <20988865+TSRBerry@users.noreply.github.com>

* wildcard(*) needs to be outside of quotes(") for cp to work

---------

Co-authored-by: TSRBerry <20988865+TSRBerry@users.noreply.github.com>
2023-03-12 17:21:21 +01:00
eed17f963e Increase access permissions for Ava timezones (#4538) 2023-03-12 17:20:09 +01:00
c09c0c002d [Flatpak] Beautify multiline strings again & Add full git commit hash (#4535)
* Don't destroy multiline strings

* Use full git commit hash
2023-03-12 10:42:33 +01:00
d56d335c0b misc: Some dependencies cleanup (#4507)
* Remove dependencies on libraries provided by .NET standard library

* Use System.IO.Hashing instead of Crc32.NET
2023-03-12 03:24:11 +01:00
23c844b2aa Misc performance tweaks (#4509)
* use Array.Empty() where instead of allocating new zero-length arrays

* structure for loops in a way that the JIT will elide array/Span bounds checking

* avoiding function calls in for loop condition tests

* avoid LINQ in a hot path

* conform with code style

* fix mistake in GetNextWaitingObject()

* fix GetNextWaitingObject() possibility of returning null if all list items have TimePoint == long.MaxValue

* make GetNextWaitingObject() behave FIFO behavior for multiple items with the same TimePoint
2023-03-11 17:05:48 -03:00
81691b9e37 gha(release): Attempt to fix flathub pusher 2023-03-11 20:11:09 +01:00
2dc422bc14 gha(release): Hopefully fixes it 2023-03-11 19:16:08 +01:00
a80fa5e33f gha(release): Makes environment variables global 2023-03-11 19:09:48 +01:00
954e995321 Attempt to fix syntax error of previous merge 2023-03-11 19:06:42 +01:00
dad9ab6bb6 [Flatpak] Add release github workflow (#4529)
* Add flatpak release workflow

Co-authored-by: Mary <mary@mary.zone>

* infra: Update required SDK version to 7.0.200

---------

Co-authored-by: Mary <mary@mary.zone>
2023-03-11 19:04:13 +01:00
f0562b9c75 CPU: Avoid argument value copies on the JIT (#4484)
* Minor refactoring of the pre-allocator

* Avoid LoadArgument copies

* PPTC version bump
2023-03-08 23:25:35 +01:00
33 changed files with 1067 additions and 821 deletions

171
.github/workflows/flatpak.yml vendored Normal file
View 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

View File

@ -13,23 +13,22 @@ on:
concurrency: release
env:
POWERSHELL_TELEMETRY_OPTOUT: 1
DOTNET_CLI_TELEMETRY_OPTOUT: 1
RYUJINX_BASE_VERSION: "1.1"
RYUJINX_TARGET_RELEASE_CHANNEL_NAME: "master"
RYUJINX_TARGET_RELEASE_CHANNEL_OWNER: "Ryujinx"
RYUJINX_TARGET_RELEASE_CHANNEL_REPO: "release-channel-master"
jobs:
release:
runs-on: windows-latest
env:
POWERSHELL_TELEMETRY_OPTOUT: 1
DOTNET_CLI_TELEMETRY_OPTOUT: 1
RYUJINX_BASE_VERSION: "1.1"
RYUJINX_TARGET_RELEASE_CHANNEL_NAME: "master"
RYUJINX_TARGET_RELEASE_CHANNEL_OWNER: "Ryujinx"
RYUJINX_TARGET_RELEASE_CHANNEL_REPO: "release-channel-master"
steps:
- uses: actions/checkout@v3
- uses: actions/setup-dotnet@v3
with:
dotnet-version: 7.0.x
global-json-file: global.json
- name: Get version info
id: version_info
run: |
@ -112,3 +111,10 @@ jobs:
owner: ${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}
repo: ${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }}
token: ${{ secrets.RELEASE_TOKEN }}
flatpak_release:
uses: ./.github/workflows/flatpak.yml
needs: release
with:
ryujinx_version: "1.1.${{ github.run_number }}"
secrets: inherit

View File

@ -265,7 +265,7 @@ namespace ARMeilleure.CodeGen.Arm64
}
else
{
relocInfo = new RelocInfo(new RelocEntry[0]);
relocInfo = new RelocInfo(Array.Empty<RelocEntry>());
}
return (code, relocInfo);

View File

@ -9,7 +9,7 @@ using static ARMeilleure.IntermediateRepresentation.Operation.Factory;
namespace ARMeilleure.CodeGen.Arm64
{
class PreAllocator
static class PreAllocator
{
private class ConstantDict
{
@ -54,8 +54,8 @@ namespace ARMeilleure.CodeGen.Arm64
continue;
}
HandleConstantRegCopy(constants, block.Operations, node);
HandleDestructiveRegCopy(block.Operations, node);
InsertConstantRegCopies(constants, block.Operations, node);
InsertDestructiveRegCopies(block.Operations, node);
switch (node.Instruction)
{
@ -78,28 +78,28 @@ namespace ARMeilleure.CodeGen.Arm64
// Copy values to registers expected by the function
// being called, as mandated by the ABI.
HandleCall(constants, block.Operations, node);
InsertCallCopies(constants, block.Operations, node);
break;
case Instruction.CompareAndSwap:
case Instruction.CompareAndSwap16:
case Instruction.CompareAndSwap8:
nextNode = HandleCompareAndSwap(block.Operations, node);
nextNode = GenerateCompareAndSwap(block.Operations, node);
break;
case Instruction.LoadArgument:
nextNode = HandleLoadArgument(cctx, ref buffer, block.Operations, preservedArgs, node);
nextNode = InsertLoadArgumentCopy(cctx, ref buffer, block.Operations, preservedArgs, node);
break;
case Instruction.Return:
HandleReturn(block.Operations, node);
InsertReturnCopy(block.Operations, node);
break;
case Instruction.Tailcall:
HandleTailcall(constants, block.Operations, stackAlloc, node, node);
InsertTailcallCopies(constants, block.Operations, stackAlloc, node, node);
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))
{
@ -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)
{
@ -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;
@ -319,7 +319,7 @@ namespace ARMeilleure.CodeGen.Arm64
Operation copyOp = Operation(Instruction.Copy, argReg, source);
HandleConstantRegCopy(constants, nodes, nodes.AddBefore(node, copyOp));
InsertConstantRegCopies(constants, nodes, nodes.AddBefore(node, copyOp));
sources.Add(argReg);
}
@ -329,7 +329,7 @@ namespace ARMeilleure.CodeGen.Arm64
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();
}
@ -364,7 +364,7 @@ namespace ARMeilleure.CodeGen.Arm64
operation.SetSources(sources.ToArray());
}
private static void HandleTailcall(
private static void InsertTailcallCopies(
ConstantDict constants,
IntrusiveList<Operation> nodes,
StackAllocator stackAlloc,
@ -420,7 +420,7 @@ namespace ARMeilleure.CodeGen.Arm64
Operation copyOp = Operation(Instruction.Copy, argReg, source);
HandleConstantRegCopy(constants, nodes, nodes.AddBefore(node, copyOp));
InsertConstantRegCopies(constants, nodes, nodes.AddBefore(node, copyOp));
sources.Add(argReg);
}
@ -444,7 +444,7 @@ namespace ARMeilleure.CodeGen.Arm64
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);
@ -508,7 +508,7 @@ namespace ARMeilleure.CodeGen.Arm64
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)
{
@ -537,7 +537,7 @@ namespace ARMeilleure.CodeGen.Arm64
}
}
private static Operation HandleLoadArgument(
private static Operation InsertLoadArgumentCopy(
CompilerContext cctx,
ref Span<Operation> buffer,
IntrusiveList<Operation> nodes,
@ -629,7 +629,7 @@ namespace ARMeilleure.CodeGen.Arm64
if (dest.AssignmentsCount == 1)
{
// 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;
}
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(
ConstantDict constants,
IntrusiveList<Operation> nodes,

View 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));
}
}
}
}
}
}
}

View File

@ -433,16 +433,11 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
private static int GetHighestValueIndex(Span<int> span)
{
int highest = span[0];
if (highest == int.MaxValue)
{
return 0;
}
int highest = int.MinValue;
int selected = 0;
for (int index = 1; index < span.Length; index++)
for (int index = 0; index < span.Length; index++)
{
int current = span[index];

View File

@ -2,19 +2,20 @@ using ARMeilleure.CodeGen.RegisterAllocators;
using ARMeilleure.IntermediateRepresentation;
using ARMeilleure.Translation;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
using static ARMeilleure.IntermediateRepresentation.Operation.Factory;
namespace ARMeilleure.CodeGen.X86
{
static class PreAllocator
class PreAllocator
{
public static void RunPass(CompilerContext cctx, StackAllocator stackAlloc, out int maxCallArgs)
{
maxCallArgs = -1;
Span<Operation> buffer = default;
CallConvName callConv = CallingConvention.GetCurrentCallConv();
Operand[] preservedArgs = new Operand[CallingConvention.GetArgumentsOnRegsCount()];
@ -32,9 +33,9 @@ namespace ARMeilleure.CodeGen.X86
continue;
}
HandleConstantRegCopy(block.Operations, node);
HandleDestructiveRegCopy(block.Operations, node);
HandleConstrainedRegCopy(block.Operations, node);
InsertConstantRegCopies(block.Operations, node);
InsertDestructiveRegCopies(block.Operations, node);
InsertConstrainedRegCopies(block.Operations, node);
switch (node.Instruction)
{
@ -59,62 +60,62 @@ namespace ARMeilleure.CodeGen.X86
// being called, as mandated by the ABI.
if (callConv == CallConvName.Windows)
{
HandleCallWindowsAbi(block.Operations, stackAlloc, node);
PreAllocatorWindows.InsertCallCopies(block.Operations, stackAlloc, node);
}
else /* if (callConv == CallConvName.SystemV) */
{
HandleCallSystemVAbi(block.Operations, node);
PreAllocatorSystemV.InsertCallCopies(block.Operations, node);
}
break;
case Instruction.ConvertToFPUI:
HandleConvertToFPUI(block.Operations, node);
GenerateConvertToFPUI(block.Operations, node);
break;
case Instruction.LoadArgument:
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) */
{
nextNode = HandleLoadArgumentSystemVAbi(cctx, block.Operations, preservedArgs, node);
nextNode = PreAllocatorSystemV.InsertLoadArgumentCopy(cctx, ref buffer, block.Operations, preservedArgs, node);
}
break;
case Instruction.Negate:
if (!node.GetSource(0).Type.IsInteger())
{
HandleNegate(block.Operations, node);
GenerateNegate(block.Operations, node);
}
break;
case Instruction.Return:
if (callConv == CallConvName.Windows)
{
HandleReturnWindowsAbi(cctx, block.Operations, preservedArgs, node);
PreAllocatorWindows.InsertReturnCopy(cctx, block.Operations, preservedArgs, node);
}
else /* if (callConv == CallConvName.SystemV) */
{
HandleReturnSystemVAbi(block.Operations, node);
PreAllocatorSystemV.InsertReturnCopy(block.Operations, node);
}
break;
case Instruction.Tailcall:
if (callConv == CallConvName.Windows)
{
HandleTailcallWindowsAbi(block.Operations, stackAlloc, node);
PreAllocatorWindows.InsertTailcallCopies(block.Operations, stackAlloc, node);
}
else
{
HandleTailcallSystemVAbi(block.Operations, stackAlloc, node);
PreAllocatorSystemV.InsertTailcallCopies(block.Operations, stackAlloc, node);
}
break;
case Instruction.VectorInsert8:
if (!HardwareCapabilities.SupportsSse41)
{
HandleVectorInsert8(block.Operations, node);
GenerateVectorInsert8(block.Operations, node);
}
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))
{
@ -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;
@ -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)
{
@ -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.
// We need to turn them into signed integer to FP conversions, and
@ -501,7 +502,7 @@ namespace ARMeilleure.CodeGen.X86
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
// 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);
}
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.
Operand dest = node.Destination;
@ -579,620 +580,7 @@ namespace ARMeilleure.CodeGen.X86
Delete(nodes, currentNode);
}
private static void HandleCallWindowsAbi(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);
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)
protected static Operand AddXmmCopy(IntrusiveList<Operation> nodes, Operation node, Operand source)
{
Operand temp = Local(source.Type);
Operand intConst = AddCopy(nodes, node, GetIntConst(source));
@ -1204,7 +592,7 @@ namespace ARMeilleure.CodeGen.X86
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);
@ -1229,7 +617,7 @@ namespace ARMeilleure.CodeGen.X86
return value;
}
private static void Delete(IntrusiveList<Operation> nodes, Operation node)
protected static void Delete(IntrusiveList<Operation> nodes, Operation node)
{
node.Destination = default;
@ -1241,12 +629,12 @@ namespace ARMeilleure.CodeGen.X86
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);
}
private static Operand Xmm(X86Register register, OperandType type)
protected static Operand Xmm(X86Register register, OperandType type)
{
return Register((int)register, RegisterType.Vector, type);
}

View 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);
}
}
}
}

View 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>());
}
}
}

View File

@ -17,7 +17,7 @@ namespace ARMeilleure.Decoders
{
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);
}
@ -29,7 +29,7 @@ namespace ARMeilleure.Decoders
{
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);
}

View File

@ -1301,7 +1301,7 @@ namespace ARMeilleure.Decoders
{
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>();
}
@ -1311,7 +1311,7 @@ namespace ARMeilleure.Decoders
int mask = ToFastLookupIndex(inst.Mask);
int value = ToFastLookupIndex(inst.Value);
for (int index = 0; index < FastLookupSize; index++)
for (int index = 0; index < temp.Length; index++)
{
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();
}

View File

@ -29,7 +29,7 @@ namespace ARMeilleure.Translation.PTC
private const string OuterHeaderMagicString = "PTCohd\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 BackupDir = "1";

View File

@ -12,7 +12,6 @@
<PackageVersion Include="Avalonia.Svg.Skia" Version="0.10.18" />
<PackageVersion Include="CommandLineParser" Version="2.9.1" />
<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="DynamicData" Version="7.12.11" />
<PackageVersion Include="FluentAvaloniaUI" Version="1.4.5" />
@ -45,10 +44,8 @@
<PackageVersion Include="SPB" Version="0.0.4-build28" />
<PackageVersion Include="System.Drawing.Common" Version="7.0.0" />
<PackageVersion Include="System.IdentityModel.Tokens.Jwt" Version="6.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.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="XamlNameReferenceGenerator" Version="1.5.1" />
</ItemGroup>

View File

@ -400,7 +400,9 @@ namespace Ryujinx.Audio.Common
{
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)
{

View File

@ -13,7 +13,7 @@
</PropertyGroup>
<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>
<PropertyGroup Condition="'$(RuntimeIdentifier)' != ''">

View File

@ -236,7 +236,7 @@ namespace Ryujinx.Ava.UI.ViewModels
public DateTimeOffset DateOffset { 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 ObservableCollection<ComboBoxItem> AvailableGpus { get; set; }

View File

@ -125,7 +125,7 @@ namespace Ryujinx.Ava.UI.Windows
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)

View File

@ -17,7 +17,7 @@ namespace Ryujinx.Graphics.Vulkan.Queries
_counterQueues = new CounterQueue[count];
for (int index = 0; index < count; index++)
for (int index = 0; index < _counterQueues.Length; index++)
{
CounterType type = (CounterType)index;
_counterQueues[index] = new CounterQueue(gd, device, pipeline, type);

View File

@ -29,9 +29,6 @@
<PackageReference Include="Silk.NET.Vulkan" />
<PackageReference Include="Silk.NET.Vulkan.Extensions.EXT" />
<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>

View File

@ -29,7 +29,7 @@ namespace Ryujinx.Graphics.Vulkan
uint structSize = 0;
for (int i = 0; i < count; ++i)
for (int i = 0; i < Map.Length; ++i)
{
var typeSize = SizeOf(description[i].Type);
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
public SpecDescription(SpecializationMapEntry[] map)
{
int count = map.Length;
Map = map;
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);
}

View File

@ -60,10 +60,9 @@ namespace Ryujinx.Graphics.Vulkan
private void RecreateSwapchain()
{
var oldSwapchain = _swapchain;
int imageCount = _swapchainImageViews.Length;
_vsyncModeChanged = false;
for (int i = 0; i < imageCount; i++)
for (int i = 0; i < _swapchainImageViews.Length; i++)
{
_swapchainImageViews[i].Dispose();
}
@ -147,7 +146,7 @@ namespace Ryujinx.Graphics.Vulkan
_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);
}

View File

@ -49,12 +49,12 @@ namespace Ryujinx.HLE.HOS.Ipc
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)
{
return new IpcHandleDesc(new int[0], handles);
return new IpcHandleDesc(Array.Empty<int>(), handles);
}
public byte[] GetBytes()

View File

@ -1,3 +1,4 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
@ -132,7 +133,7 @@ namespace Ryujinx.HLE.HOS.Ipc
word0 |= (ReceiveBuff.Count & 0xf) << 24;
word0 |= (ExchangeBuff.Count & 0xf) << 28;
byte[] handleData = new byte[0];
byte[] handleData = Array.Empty<byte>();
if (HandleDesc != null)
{
@ -202,7 +203,7 @@ namespace Ryujinx.HLE.HOS.Ipc
word0 |= (ReceiveBuff.Count & 0xf) << 24;
word0 |= (ExchangeBuff.Count & 0xf) << 28;
byte[] handleData = new byte[0];
byte[] handleData = Array.Empty<byte>();
if (HandleDesc != null)
{

View File

@ -1,7 +1,6 @@
using Ryujinx.Common;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
namespace Ryujinx.HLE.HOS.Kernel.Common
@ -86,7 +85,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Common
{
Interlocked.Exchange(ref _enforceWakeupFromSpinWait, 0);
next = _waitingObjects.OrderBy(x => x.TimePoint).FirstOrDefault();
next = GetNextWaitingObject();
}
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)
{
time /= 1000000;

View File

@ -233,7 +233,7 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
// If the location name is too long, error out.
if (locationName.Length > 0x24)
{
outLocationNameArray = new string[0];
outLocationNameArray = Array.Empty<string>();
return ResultCode.LocationNameTooLong;
}

View File

@ -27,7 +27,9 @@ namespace Ryujinx.Input.SDL2
SDL2Driver.Instance.OnJoystickDisconnected += HandleJoyStickDisconnected;
// 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));
}

View File

@ -1,5 +1,4 @@
using Force.Crc32;
using Ryujinx.Common;
using Ryujinx.Common;
using Ryujinx.Common.Configuration.Hid;
using Ryujinx.Common.Configuration.Hid.Controller;
using Ryujinx.Common.Configuration.Hid.Controller.Motion;
@ -9,6 +8,7 @@ using Ryujinx.Input.Motion.CemuHook.Protocol;
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Hashing;
using System.Net;
using System.Net.Sockets;
using System.Numerics;
@ -401,10 +401,10 @@ namespace Ryujinx.Input.Motion.CemuHook
writer.Seek(6, SeekOrigin.Begin);
writer.Write(header.Length);
header.Crc32 = Crc32Algorithm.Compute(stream.ToArray());
Crc32.Hash(stream.ToArray(), header.Crc32.AsSpan());
writer.Seek(8, SeekOrigin.Begin);
writer.Write(header.Crc32);
writer.Write(header.Crc32.AsSpan());
byte[] data = stream.ToArray();
@ -440,10 +440,10 @@ namespace Ryujinx.Input.Motion.CemuHook
writer.Seek(6, SeekOrigin.Begin);
writer.Write(header.Length);
header.Crc32 = Crc32Algorithm.Compute(stream.ToArray());
Crc32.Hash(stream.ToArray(), header.Crc32.AsSpan());
writer.Seek(8, SeekOrigin.Begin);
writer.Write(header.Crc32);
writer.Write(header.Crc32.AsSpan());
byte[] data = stream.ToArray();
@ -458,8 +458,7 @@ namespace Ryujinx.Input.Motion.CemuHook
Id = (uint)clientId,
MagicString = Magic,
Version = Version,
Length = 0,
Crc32 = 0
Length = 0
};
return header;

View File

@ -1,14 +1,15 @@
using System.Runtime.InteropServices;
using Ryujinx.Common.Memory;
using System.Runtime.InteropServices;
namespace Ryujinx.Input.Motion.CemuHook.Protocol
{
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct Header
{
public uint MagicString;
public uint MagicString;
public ushort Version;
public ushort Length;
public uint Crc32;
public uint Id;
public Array4<byte> Crc32;
public uint Id;
}
}

View File

@ -6,7 +6,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Crc32.NET" />
<PackageReference Include="System.IO.Hashing" />
</ItemGroup>
<ItemGroup>

View File

@ -78,7 +78,7 @@ namespace Ryujinx.Memory.Tests
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)

View File

@ -6,31 +6,31 @@ PUBLISH_DIRECTORY=$1
OUTPUT_DIRECTORY=$2
ENTITLEMENTS_FILE_PATH=$3
APP_BUNDLE_DIRECTORY=$OUTPUT_DIRECTORY/Ryujinx.app
APP_BUNDLE_DIRECTORY="$OUTPUT_DIRECTORY/Ryujinx.app"
rm -rf $APP_BUNDLE_DIRECTORY
mkdir -p $APP_BUNDLE_DIRECTORY/Contents
mkdir $APP_BUNDLE_DIRECTORY/Contents/Frameworks
mkdir $APP_BUNDLE_DIRECTORY/Contents/MacOS
mkdir $APP_BUNDLE_DIRECTORY/Contents/Resources
rm -rf "$APP_BUNDLE_DIRECTORY"
mkdir -p "$APP_BUNDLE_DIRECTORY/Contents"
mkdir "$APP_BUNDLE_DIRECTORY/Contents/Frameworks"
mkdir "$APP_BUNDLE_DIRECTORY/Contents/MacOS"
mkdir "$APP_BUNDLE_DIRECTORY/Contents/Resources"
# Copy executables first
cp $PUBLISH_DIRECTORY/Ryujinx.Ava $APP_BUNDLE_DIRECTORY/Contents/MacOS/Ryujinx
chmod u+x $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"
# Then all libraries
cp $PUBLISH_DIRECTORY/*.dylib $APP_BUNDLE_DIRECTORY/Contents/Frameworks
cp "$PUBLISH_DIRECTORY"/*.dylib "$APP_BUNDLE_DIRECTORY/Contents/Frameworks"
# Then resources
cp Info.plist $APP_BUNDLE_DIRECTORY/Contents
cp Ryujinx.icns $APP_BUNDLE_DIRECTORY/Contents/Resources/Ryujinx.icns
cp updater.sh $APP_BUNDLE_DIRECTORY/Contents/Resources/updater.sh
cp -r $PUBLISH_DIRECTORY/THIRDPARTY.md $APP_BUNDLE_DIRECTORY/Contents/Resources
cp Info.plist "$APP_BUNDLE_DIRECTORY/Contents"
cp Ryujinx.icns "$APP_BUNDLE_DIRECTORY/Contents/Resources/Ryujinx.icns"
cp updater.sh "$APP_BUNDLE_DIRECTORY/Contents/Resources/updater.sh"
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
python3 bundle_fix_up.py $APP_BUNDLE_DIRECTORY MacOS/Ryujinx
python3 bundle_fix_up.py "$APP_BUNDLE_DIRECTORY" MacOS/Ryujinx
# Now sign it
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.
# 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"
rcodesign sign --entitlements-xml-path $ENTITLEMENTS_FILE_PATH $APP_BUNDLE_DIRECTORY
rcodesign sign --entitlements-xml-path "$ENTITLEMENTS_FILE_PATH" "$APP_BUNDLE_DIRECTORY"
else
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

View File

@ -7,54 +7,54 @@ if [ "$#" -ne 6 ]; then
exit 1
fi
mkdir -p $1
mkdir -p $2
mkdir -p $3
mkdir -p "$1"
mkdir -p "$2"
mkdir -p "$3"
BASE_DIR=$(readlink -f $1)
TEMP_DIRECTORY=$(readlink -f $2)
OUTPUT_DIRECTORY=$(readlink -f $3)
ENTITLEMENTS_FILE_PATH=$(readlink -f $4)
BASE_DIR=$(readlink -f "$1")
TEMP_DIRECTORY=$(readlink -f "$2")
OUTPUT_DIRECTORY=$(readlink -f "$3")
ENTITLEMENTS_FILE_PATH=$(readlink -f "$4")
VERSION=$5
SOURCE_REVISION_ID=$6
RELEASE_TAR_FILE_NAME=Ryujinx-$VERSION-macos_universal.app.tar
ARM64_APP_BUNDLE=$TEMP_DIRECTORY/output_arm64/Ryujinx.app
X64_APP_BUNDLE=$TEMP_DIRECTORY/output_x64/Ryujinx.app
UNIVERSAL_APP_BUNDLE=$OUTPUT_DIRECTORY/Ryujinx.app
ARM64_APP_BUNDLE="$TEMP_DIRECTORY/output_arm64/Ryujinx.app"
X64_APP_BUNDLE="$TEMP_DIRECTORY/output_x64/Ryujinx.app"
UNIVERSAL_APP_BUNDLE="$OUTPUT_DIRECTORY/Ryujinx.app"
EXECUTABLE_SUB_PATH=Contents/MacOS/Ryujinx
rm -rf $TEMP_DIRECTORY
mkdir -p $TEMP_DIRECTORY
rm -rf "$TEMP_DIRECTORY"
mkdir -p "$TEMP_DIRECTORY"
DOTNET_COMMON_ARGS="-p:DebugType=embedded -p:Version=$VERSION -p:SourceRevisionId=$SOURCE_REVISION_ID --self-contained true"
dotnet restore
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-x64 -o $TEMP_DIRECTORY/publish_x64 $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
# 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
# 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
./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
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_arm64" "$TEMP_DIRECTORY/output_arm64" "$ENTITLEMENTS_FILE_PATH"
popd
rm -rf $UNIVERSAL_APP_BUNDLE
mkdir -p $OUTPUT_DIRECTORY
rm -rf "$UNIVERSAL_APP_BUNDLE"
mkdir -p "$OUTPUT_DIRECTORY"
# Let's copy one of the two different app bundle and remove the executable
cp -R $ARM64_APP_BUNDLE $UNIVERSAL_APP_BUNDLE
rm $UNIVERSAL_APP_BUNDLE/$EXECUTABLE_SUB_PATH
cp -R "$ARM64_APP_BUNDLE" "$UNIVERSAL_APP_BUNDLE"
rm "$UNIVERSAL_APP_BUNDLE/$EXECUTABLE_SUB_PATH"
# 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)" ];
then
@ -69,12 +69,12 @@ else
fi
# 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
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
rm $UNIVERSAL_APP_BUNDLE/Contents/Info.plist.bck
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"
rm "$UNIVERSAL_APP_BUNDLE/Contents/Info.plist.bck"
# Now sign it
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.
# 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"
rcodesign sign --entitlements-xml-path $ENTITLEMENTS_FILE_PATH $UNIVERSAL_APP_BUNDLE
rcodesign sign --entitlements-xml-path "$ENTITLEMENTS_FILE_PATH" "$UNIVERSAL_APP_BUNDLE"
else
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
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
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
rm $RELEASE_TAR_FILE_NAME
popd

View File

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