Compare commits

...

20 Commits

Author SHA1 Message Date
GreemDev
0e26e35ec0 language feature: field keyword & partial properties for observable properties in main & settings window view models 2025-09-12 14:10:52 -05:00
GreemDev
a5a13271d5 language feature: field keyword & partial properties for observable properties in the UI
partial properties are from C# 13 but weren't usable for these properties
2025-09-12 13:58:01 -05:00
GreemDev
de49d1779e chore: converted BufferHandle ToInt32 extension to an implicit int operator on BufferHandle directly. 2025-09-12 13:13:47 -05:00
GreemDev
9cd1e9be68 chore: Split SoftFloat into multiple partial class parts 2025-09-12 13:13:47 -05:00
GreemDev
9def11f7d2 chore: Split SoftFallback into multiple partial class parts 2025-09-12 13:13:47 -05:00
GreemDev
2fa5905f1e some more extension members 2025-09-12 13:13:47 -05:00
GreemDev
04427f3a1a language feature: Extension Members: More converted 2025-09-12 13:13:47 -05:00
GreemDev
e152dbe254 use extension members for StorageProviderExtensions 2025-09-12 13:13:46 -05:00
GreemDev
bda52e97ad language feature: Extension Members: HLE <-> UI enum converters 2025-09-12 13:13:46 -05:00
GreemDev
4a64b23ca3 Parse UI enum directly 2025-09-12 13:13:46 -05:00
GreemDev
5fcf70be77 language feature: Extension Members: Misc enum extensions methods converted to properties 2025-09-12 13:13:46 -05:00
GreemDev
7a115764e8 language feature: Extension Members: Ryujinx.Graphics.GAL.Format 2025-09-12 13:13:44 -05:00
GreemDev
e78bc68dc5 language feature: Extension Members: OperandType 2025-09-12 13:11:45 -05:00
GreemDev
34a36fb3ff language feature: Extension Members: HLE 2025-09-12 13:11:45 -05:00
GreemDev
ef86ae59cb language feature: Extension Members: Graphics related, enums 2025-09-12 13:11:45 -05:00
GreemDev
df29d51250 language feature: Extension Members: CPU-related, enums 2025-09-12 13:11:42 -05:00
GreemDev
aaa0bd98ec Add .NET Runtime version in About window under Ryujinx version. 2025-09-12 13:10:28 -05:00
GreemDev
bbf30a107c feature: Initial .NET 10 Support
Works as of .NET 10.0.0-preview.3.25171.5
2025-09-12 13:10:27 -05:00
Coxxs
df40a69872 Fix headless mode (ryubing/ryujinx!146)
See merge request ryubing/ryujinx!146
2025-09-10 11:43:50 -05:00
LotP
b000f91dad Memory changes 2.2.1 (ryubing/ryujinx!144)
See merge request ryubing/ryujinx!144
2025-09-06 13:51:08 -05:00
171 changed files with 6045 additions and 6406 deletions

View File

@@ -1,6 +1,6 @@
<Project>
<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
<LangVersion>latest</LangVersion>
<TargetFramework>net10.0</TargetFramework>
<LangVersion>preview</LangVersion>
</PropertyGroup>
</Project>

View File

@@ -85,6 +85,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
.github\workflows\build.yml = .github\workflows\build.yml
.github\workflows\canary.yml = .github\workflows\canary.yml
Directory.Packages.props = Directory.Packages.props
Directory.Build.props = Directory.Build.props
.github\workflows\release.yml = .github\workflows\release.yml
nuget.config = nuget.config
EndProjectSection

View File

@@ -1,6 +1,6 @@
{
"sdk": {
"version": "9.0.100",
"version": "10.0.100",
"rollForward": "latestFeature"
}
}

View File

@@ -25,9 +25,9 @@ namespace ARMeilleure.CodeGen.Arm64
static class ComparisonArm64Extensions
{
public static ArmCondition ToArmCondition(this Comparison comp)
extension(Comparison comparison)
{
return comp switch
public ArmCondition Arm => comparison switch
{
#pragma warning disable IDE0055 // Disable formatting
Comparison.Equal => ArmCondition.Eq,
@@ -42,7 +42,7 @@ namespace ARMeilleure.CodeGen.Arm64
Comparison.LessUI => ArmCondition.LtUn,
#pragma warning restore IDE0055
_ => throw new ArgumentException(null, nameof(comp)),
_ => throw new ArgumentException(null, nameof(comparison))
};
}
}

View File

@@ -181,10 +181,10 @@ namespace ARMeilleure.CodeGen.Arm64
public void Fmov(Operand rd, Operand rn, bool topHalf)
{
Debug.Assert(rd.Type.IsInteger() != rn.Type.IsInteger());
Debug.Assert(rd.Type.IsInteger != rn.Type.IsInteger);
Debug.Assert(rd.Type == OperandType.I64 || rn.Type == OperandType.I64 || !topHalf);
uint opcode = rd.Type.IsInteger() ? 0b110u : 0b111u;
uint opcode = rd.Type.IsInteger ? 0b110u : 0b111u;
uint rmode = topHalf ? 1u << 19 : 0u;
uint ftype = rd.Type == OperandType.FP64 || rn.Type == OperandType.FP64 ? 1u << 22 : 0u;
@@ -411,7 +411,7 @@ namespace ARMeilleure.CodeGen.Arm64
public void Mov(Operand rd, Operand rn)
{
if (rd.Type.IsInteger())
if (rd.Type.IsInteger)
{
Orr(rd, Factory.Register(ZrRegister, RegisterType.Integer, rd.Type), rn);
}
@@ -973,7 +973,7 @@ namespace ARMeilleure.CodeGen.Arm64
uint instruction;
int scale;
if (type.IsInteger())
if (type.IsInteger)
{
instruction = intInst;
@@ -1009,7 +1009,7 @@ namespace ARMeilleure.CodeGen.Arm64
{
uint instruction;
if (type.IsInteger())
if (type.IsInteger)
{
instruction = intInst;

View File

@@ -250,7 +250,7 @@ namespace ARMeilleure.CodeGen.Arm64
// ValidateBinOp(dest, src1, src2);
if (dest.Type.IsInteger())
if (dest.Type.IsInteger)
{
context.Assembler.Add(dest, src1, src2);
}
@@ -268,7 +268,7 @@ namespace ARMeilleure.CodeGen.Arm64
ValidateBinOp(dest, src1, src2);
Debug.Assert(dest.Type.IsInteger());
Debug.Assert(dest.Type.IsInteger);
context.Assembler.And(dest, src1, src2);
}
@@ -281,7 +281,7 @@ namespace ARMeilleure.CodeGen.Arm64
ValidateBinOp(dest, src1, src2);
if (dest.Type.IsInteger())
if (dest.Type.IsInteger)
{
context.Assembler.Eor(dest, src1, src2);
}
@@ -298,7 +298,7 @@ namespace ARMeilleure.CodeGen.Arm64
ValidateUnOp(dest, source);
Debug.Assert(dest.Type.IsInteger());
Debug.Assert(dest.Type.IsInteger);
context.Assembler.Mvn(dest, source);
}
@@ -311,7 +311,7 @@ namespace ARMeilleure.CodeGen.Arm64
ValidateBinOp(dest, src1, src2);
Debug.Assert(dest.Type.IsInteger());
Debug.Assert(dest.Type.IsInteger);
context.Assembler.Orr(dest, src1, src2);
}
@@ -322,7 +322,7 @@ namespace ARMeilleure.CodeGen.Arm64
Debug.Assert(comp.Kind == OperandKind.Constant);
ArmCondition cond = ((Comparison)comp.AsInt32()).ToArmCondition();
ArmCondition cond = ((Comparison)comp.AsInt32()).Arm;
GenerateCompareCommon(context, operation);
@@ -336,7 +336,7 @@ namespace ARMeilleure.CodeGen.Arm64
ValidateUnOp(dest, source);
Debug.Assert(dest.Type.IsInteger());
Debug.Assert(dest.Type.IsInteger);
context.Assembler.Rev(dest, source);
}
@@ -354,7 +354,7 @@ namespace ARMeilleure.CodeGen.Arm64
Debug.Assert(dest.Type == OperandType.I32);
Debug.Assert(comp.Kind == OperandKind.Constant);
ArmCondition cond = ((Comparison)comp.AsInt32()).ToArmCondition();
ArmCondition cond = ((Comparison)comp.AsInt32()).Arm;
GenerateCompareCommon(context, operation);
@@ -428,7 +428,7 @@ namespace ARMeilleure.CodeGen.Arm64
EnsureSameType(src1, src2);
Debug.Assert(src1.Type.IsInteger());
Debug.Assert(src1.Type.IsInteger);
context.Assembler.Cmp(src1, src2);
}
@@ -442,7 +442,7 @@ namespace ARMeilleure.CodeGen.Arm64
EnsureSameType(dest, src2, src3);
Debug.Assert(dest.Type.IsInteger());
Debug.Assert(dest.Type.IsInteger);
Debug.Assert(src1.Type == OperandType.I32);
context.Assembler.Cmp(src1, Const(src1.Type, 0));
@@ -468,7 +468,7 @@ namespace ARMeilleure.CodeGen.Arm64
Debug.Assert(dest.Type != source.Type);
Debug.Assert(source.Type != OperandType.V128);
if (source.Type.IsInteger())
if (source.Type.IsInteger)
{
context.Assembler.ScvtfScalar(dest, source);
}
@@ -485,7 +485,7 @@ namespace ARMeilleure.CodeGen.Arm64
Debug.Assert(dest.Type is OperandType.FP32 or OperandType.FP64);
Debug.Assert(dest.Type != source.Type);
Debug.Assert(source.Type.IsInteger());
Debug.Assert(source.Type.IsInteger);
context.Assembler.UcvtfScalar(dest, source);
}
@@ -497,7 +497,7 @@ namespace ARMeilleure.CodeGen.Arm64
EnsureSameType(dest, source);
Debug.Assert(dest.Type.IsInteger() || source.Kind != OperandKind.Constant);
Debug.Assert(dest.Type.IsInteger || source.Kind != OperandKind.Constant);
// Moves to the same register are useless.
if (dest.Kind == source.Kind && dest.Value == source.Value)
@@ -529,7 +529,7 @@ namespace ARMeilleure.CodeGen.Arm64
EnsureSameType(dest, source);
Debug.Assert(dest.Type.IsInteger());
Debug.Assert(dest.Type.IsInteger);
context.Assembler.Clz(dest, source);
}
@@ -542,7 +542,7 @@ namespace ARMeilleure.CodeGen.Arm64
ValidateBinOp(dest, dividend, divisor);
if (dest.Type.IsInteger())
if (dest.Type.IsInteger)
{
context.Assembler.Sdiv(dest, dividend, divisor);
}
@@ -576,7 +576,7 @@ namespace ARMeilleure.CodeGen.Arm64
Operand value = operation.Destination;
Operand address = operation.GetSource(0);
Debug.Assert(value.Type.IsInteger());
Debug.Assert(value.Type.IsInteger);
context.Assembler.LdrhRiUn(value, address, 0);
}
@@ -586,7 +586,7 @@ namespace ARMeilleure.CodeGen.Arm64
Operand value = operation.Destination;
Operand address = operation.GetSource(0);
Debug.Assert(value.Type.IsInteger());
Debug.Assert(value.Type.IsInteger);
context.Assembler.LdrbRiUn(value, address, 0);
}
@@ -604,7 +604,7 @@ namespace ARMeilleure.CodeGen.Arm64
EnsureSameType(dest, src1, src2);
if (dest.Type.IsInteger())
if (dest.Type.IsInteger)
{
context.Assembler.Mul(dest, src1, src2);
}
@@ -647,7 +647,7 @@ namespace ARMeilleure.CodeGen.Arm64
ValidateUnOp(dest, source);
if (dest.Type.IsInteger())
if (dest.Type.IsInteger)
{
context.Assembler.Neg(dest, source);
}
@@ -732,7 +732,7 @@ namespace ARMeilleure.CodeGen.Arm64
Operand dest = operation.Destination;
Operand source = operation.GetSource(0);
Debug.Assert(dest.Type.IsInteger() && source.Type.IsInteger());
Debug.Assert(dest.Type.IsInteger && source.Type.IsInteger);
context.Assembler.Sxth(dest, source);
}
@@ -742,7 +742,7 @@ namespace ARMeilleure.CodeGen.Arm64
Operand dest = operation.Destination;
Operand source = operation.GetSource(0);
Debug.Assert(dest.Type.IsInteger() && source.Type.IsInteger());
Debug.Assert(dest.Type.IsInteger && source.Type.IsInteger);
context.Assembler.Sxtw(dest, source);
}
@@ -752,7 +752,7 @@ namespace ARMeilleure.CodeGen.Arm64
Operand dest = operation.Destination;
Operand source = operation.GetSource(0);
Debug.Assert(dest.Type.IsInteger() && source.Type.IsInteger());
Debug.Assert(dest.Type.IsInteger && source.Type.IsInteger);
context.Assembler.Sxtb(dest, source);
}
@@ -823,7 +823,7 @@ namespace ARMeilleure.CodeGen.Arm64
Operand value = operation.GetSource(1);
Operand address = operation.GetSource(0);
Debug.Assert(value.Type.IsInteger());
Debug.Assert(value.Type.IsInteger);
context.Assembler.StrhRiUn(value, address, 0);
}
@@ -833,7 +833,7 @@ namespace ARMeilleure.CodeGen.Arm64
Operand value = operation.GetSource(1);
Operand address = operation.GetSource(0);
Debug.Assert(value.Type.IsInteger());
Debug.Assert(value.Type.IsInteger);
context.Assembler.StrbRiUn(value, address, 0);
}
@@ -858,7 +858,7 @@ namespace ARMeilleure.CodeGen.Arm64
// ValidateBinOp(dest, src1, src2);
if (dest.Type.IsInteger())
if (dest.Type.IsInteger)
{
context.Assembler.Sub(dest, src1, src2);
}
@@ -882,7 +882,7 @@ namespace ARMeilleure.CodeGen.Arm64
if (dest != default)
{
Debug.Assert(!dest.Type.IsInteger() && source.Type.IsInteger());
Debug.Assert(!dest.Type.IsInteger && source.Type.IsInteger);
OperandType destType = source.Type == OperandType.I64 ? OperandType.FP64 : OperandType.FP32;
@@ -901,9 +901,9 @@ namespace ARMeilleure.CodeGen.Arm64
byte index = src2.AsByte();
Debug.Assert(index < OperandType.V128.GetSizeInBytes() / dest.Type.GetSizeInBytes());
Debug.Assert(index < OperandType.V128.ByteSize / dest.Type.ByteSize);
if (dest.Type.IsInteger())
if (dest.Type.IsInteger)
{
context.Assembler.Umov(dest, src1, index, dest.Type == OperandType.I64 ? 3 : 2);
}
@@ -959,7 +959,7 @@ namespace ARMeilleure.CodeGen.Arm64
byte index = src3.AsByte();
if (src2.Type.IsInteger())
if (src2.Type.IsInteger)
{
context.Assembler.Ins(dest, src2, index, src2.Type == OperandType.I64 ? 3 : 2);
}
@@ -1007,7 +1007,7 @@ namespace ARMeilleure.CodeGen.Arm64
{
Operand dest = operation.Destination;
Debug.Assert(!dest.Type.IsInteger());
Debug.Assert(!dest.Type.IsInteger);
context.Assembler.CmeqVector(dest, dest, dest, 2);
}
@@ -1016,7 +1016,7 @@ namespace ARMeilleure.CodeGen.Arm64
{
Operand dest = operation.Destination;
Debug.Assert(!dest.Type.IsInteger());
Debug.Assert(!dest.Type.IsInteger);
context.Assembler.EorVector(dest, dest, dest);
}
@@ -1046,7 +1046,7 @@ namespace ARMeilleure.CodeGen.Arm64
Operand dest = operation.Destination;
Operand source = operation.GetSource(0);
Debug.Assert(dest.Type.IsInteger() && source.Type.IsInteger());
Debug.Assert(dest.Type.IsInteger && source.Type.IsInteger);
context.Assembler.Uxth(dest, source);
}
@@ -1056,7 +1056,7 @@ namespace ARMeilleure.CodeGen.Arm64
Operand dest = operation.Destination;
Operand source = operation.GetSource(0);
Debug.Assert(dest.Type.IsInteger() && source.Type.IsInteger());
Debug.Assert(dest.Type.IsInteger && source.Type.IsInteger);
// We can eliminate the move if source is already 32-bit and the registers are the same.
if (dest.Value == source.Value && source.Type == OperandType.I32)
@@ -1072,7 +1072,7 @@ namespace ARMeilleure.CodeGen.Arm64
Operand dest = operation.Destination;
Operand source = operation.GetSource(0);
Debug.Assert(dest.Type.IsInteger() && source.Type.IsInteger());
Debug.Assert(dest.Type.IsInteger && source.Type.IsInteger);
context.Assembler.Uxtb(dest, source);
}
@@ -1169,7 +1169,7 @@ namespace ARMeilleure.CodeGen.Arm64
context.Assembler.StrRiPre(Register(reg, type), Register(SpRegister), -calleeSaveRegionSize);
}
offset += type.GetSizeInBytes();
offset += type.ByteSize;
}
while (mask != 0)
@@ -1195,7 +1195,7 @@ namespace ARMeilleure.CodeGen.Arm64
context.Assembler.StpRiPre(Register(reg, type), Register(reg2, type), Register(SpRegister), -calleeSaveRegionSize);
}
offset += type.GetSizeInBytes() * 2;
offset += type.ByteSize * 2;
}
}
@@ -1273,7 +1273,7 @@ namespace ARMeilleure.CodeGen.Arm64
mask &= ~(1 << reg2);
offset -= type.GetSizeInBytes() * 2;
offset -= type.ByteSize * 2;
if (offset != 0)
{
@@ -1286,7 +1286,7 @@ namespace ARMeilleure.CodeGen.Arm64
}
else
{
offset -= type.GetSizeInBytes();
offset -= type.ByteSize;
if (offset != 0)
{
@@ -1435,12 +1435,12 @@ namespace ARMeilleure.CodeGen.Arm64
OperandType valueType = GetMemOpValueType(currentOp);
if (valueType != GetMemOpValueType(nextOp) || op1Offset + valueType.GetSizeInBytes() != op2Offset)
if (valueType != GetMemOpValueType(nextOp) || op1Offset + valueType.ByteSize != op2Offset)
{
return false;
}
if (!CodeGenCommon.ConstFitsOnSImm7(op1Offset, valueType.GetSizeInBytesLog2()))
if (!CodeGenCommon.ConstFitsOnSImm7(op1Offset, valueType.ByteSizeLog2))
{
return false;
}
@@ -1549,7 +1549,7 @@ namespace ARMeilleure.CodeGen.Arm64
// EnsureSameReg (dest, src1);
EnsureSameType(dest, src1);
Debug.Assert(dest.Type.IsInteger() && src2.Type == OperandType.I32);
Debug.Assert(dest.Type.IsInteger && src2.Type == OperandType.I32);
}
private static void EnsureSameReg(Operand op1, Operand op2)

View File

@@ -462,7 +462,7 @@ namespace ARMeilleure.CodeGen.Arm64
{
instruction |= (sz << 22);
if (rd.Type.IsInteger())
if (rd.Type.IsInteger)
{
context.Assembler.WriteInstructionAuto(instruction, rd, rn);
}
@@ -490,7 +490,7 @@ namespace ARMeilleure.CodeGen.Arm64
instruction |= (sz << 22);
instruction |= (64 - fBits) << 10;
if (rd.Type.IsInteger())
if (rd.Type.IsInteger)
{
Debug.Assert(rd.Type != OperandType.I32 || fBits <= 32);

View File

@@ -112,7 +112,7 @@ namespace ARMeilleure.CodeGen.Arm64
if (src1.Kind == OperandKind.Constant)
{
if (!src1.Type.IsInteger())
if (!src1.Type.IsInteger)
{
// Handle non-integer types (FP32, FP64 and V128).
// For instructions without an immediate operand, we do the following:
@@ -161,7 +161,7 @@ namespace ARMeilleure.CodeGen.Arm64
if (src2.Kind == OperandKind.Constant)
{
if (!src2.Type.IsInteger())
if (!src2.Type.IsInteger)
{
src2 = AddFloatConstantCopy(constants, nodes, node, src2);
@@ -191,7 +191,7 @@ namespace ARMeilleure.CodeGen.Arm64
if (src.Kind == OperandKind.Constant)
{
if (!src.Type.IsInteger())
if (!src.Type.IsInteger)
{
src = AddFloatConstantCopy(constants, nodes, node, src);
@@ -282,7 +282,7 @@ namespace ARMeilleure.CodeGen.Arm64
bool passOnReg;
if (source.Type.IsInteger())
if (source.Type.IsInteger)
{
passOnReg = intCount < intMax;
}
@@ -309,7 +309,7 @@ namespace ARMeilleure.CodeGen.Arm64
if (passOnReg)
{
Operand argReg = source.Type.IsInteger()
Operand argReg = source.Type.IsInteger
? Gpr(CallingConvention.GetIntArgumentRegister(intCount++), source.Type)
: Xmm(CallingConvention.GetVecArgumentRegister(vecCount++), source.Type);
@@ -327,7 +327,7 @@ namespace ARMeilleure.CodeGen.Arm64
InsertConstantRegCopies(constants, nodes, nodes.AddBefore(node, spillOp));
stackOffset += source.Type.GetSizeInBytes();
stackOffset += source.Type.ByteSize;
}
}
@@ -345,7 +345,7 @@ namespace ARMeilleure.CodeGen.Arm64
}
else
{
Operand retReg = dest.Type.IsInteger()
Operand retReg = dest.Type.IsInteger
? Gpr(CallingConvention.GetIntReturnRegister(), dest.Type)
: Xmm(CallingConvention.GetVecReturnRegister(), dest.Type);
@@ -385,7 +385,7 @@ namespace ARMeilleure.CodeGen.Arm64
bool passOnReg;
if (source.Type.IsInteger())
if (source.Type.IsInteger)
{
passOnReg = intCount + 1 < intMax;
}
@@ -408,7 +408,7 @@ namespace ARMeilleure.CodeGen.Arm64
if (passOnReg)
{
Operand argReg = source.Type.IsInteger()
Operand argReg = source.Type.IsInteger
? Gpr(CallingConvention.GetIntArgumentRegister(intCount++), source.Type)
: Xmm(CallingConvention.GetVecArgumentRegister(vecCount++), source.Type);
@@ -521,7 +521,7 @@ namespace ARMeilleure.CodeGen.Arm64
}
else
{
Operand retReg = source.Type.IsInteger()
Operand retReg = source.Type.IsInteger
? Gpr(CallingConvention.GetIntReturnRegister(), source.Type)
: Xmm(CallingConvention.GetVecReturnRegister(), source.Type);
@@ -551,7 +551,7 @@ namespace ARMeilleure.CodeGen.Arm64
{
OperandType argType = cctx.FuncArgTypes[cIndex];
if (argType.IsInteger())
if (argType.IsInteger)
{
intCount++;
}
@@ -567,7 +567,7 @@ namespace ARMeilleure.CodeGen.Arm64
bool passOnReg;
if (source.Type.IsInteger())
if (source.Type.IsInteger)
{
passOnReg = intCount < CallingConvention.GetArgumentsOnRegsCount();
}
@@ -606,7 +606,7 @@ namespace ARMeilleure.CodeGen.Arm64
{
Operand pArg = Local(dest.Type);
Operand argReg = dest.Type.IsInteger()
Operand argReg = dest.Type.IsInteger
? Gpr(CallingConvention.GetIntArgumentRegister(intCount), dest.Type)
: Xmm(CallingConvention.GetVecArgumentRegister(vecCount), dest.Type);

View File

@@ -51,7 +51,7 @@ namespace ARMeilleure.CodeGen.Optimizations
if (trueSucc == block.ListNext)
{
Comparison comp = (Comparison)branchOp.GetSource(2).AsInt32();
Comparison compInv = comp.Invert();
Comparison compInv = comp.Inverse;
branchOp.SetSource(2, Const((int)compInv));

View File

@@ -161,7 +161,7 @@ namespace ARMeilleure.CodeGen.Optimizations
}
else if (otherCompType == Comparison.Equal)
{
propCompType = compType.Invert();
propCompType = compType.Inverse;
}
else
{

View File

@@ -105,7 +105,7 @@ namespace ARMeilleure.CodeGen.Optimizations
Operand x = operation.GetSource(0);
Operand y = operation.GetSource(1);
if (x == y && x.Type.IsInteger())
if (x == y && x.Type.IsInteger)
{
operation.TurnIntoCopy(Const(x.Type, 0));
}
@@ -161,7 +161,7 @@ namespace ARMeilleure.CodeGen.Optimizations
private static bool IsConstEqual(Operand operand, ulong comparand)
{
if (operand.Kind != OperandKind.Constant || !operand.Type.IsInteger())
if (operand.Kind != OperandKind.Constant || !operand.Type.IsInteger)
{
return false;
}

View File

@@ -98,7 +98,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
{
OperandType type = types[copyDest];
type = type.IsInteger() ? OperandType.I64 : OperandType.V128;
type = type.IsInteger ? OperandType.I64 : OperandType.V128;
EmitXorSwap(sequence, GetRegister(copyDest, type), GetRegister(copySource, type));

View File

@@ -178,7 +178,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
}
else if (dest.Kind == OperandKind.Register)
{
if (dest.Type.IsInteger())
if (dest.Type.IsInteger)
{
intFixedRegisters |= 1 << dest.GetRegister().Index;
}
@@ -236,7 +236,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
{
Register reg = info.Register.GetRegister();
if (local.Type.IsInteger())
if (local.Type.IsInteger)
{
intLocalFreeRegisters |= 1 << reg.Index;
}
@@ -254,7 +254,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
if (temp == default || info.Sequence != sequence)
{
temp = local.Type.IsInteger()
temp = local.Type.IsInteger
? GetSpillTemp(local, intSpillTempRegisters, ref intLocalUse)
: GetSpillTemp(local, vecSpillTempRegisters, ref vecLocalUse);
@@ -335,7 +335,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
if (info.UsesAllocated == 0)
{
int mask = dest.Type.IsInteger()
int mask = dest.Type.IsInteger
? intLocalFreeRegisters
: vecLocalFreeRegisters;
@@ -343,9 +343,9 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
{
int selectedReg = BitOperations.TrailingZeroCount(mask);
info.Register = Register(selectedReg, info.Type.ToRegisterType(), info.Type);
info.Register = Register(selectedReg, info.Type.Register, info.Type);
if (dest.Type.IsInteger())
if (dest.Type.IsInteger)
{
intLocalFreeRegisters &= ~(1 << selectedReg);
intUsedRegisters |= 1 << selectedReg;
@@ -359,7 +359,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
else
{
info.Register = default;
info.SpillOffset = Const(stackAlloc.Allocate(dest.Type.GetSizeInBytes()));
info.SpillOffset = Const(stackAlloc.Allocate(dest.Type.ByteSize));
}
}
@@ -377,7 +377,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
if (temp == default || info.Sequence != sequence)
{
temp = dest.Type.IsInteger()
temp = dest.Type.IsInteger
? GetSpillTemp(dest, intSpillTempRegisters, ref intLocalAsg)
: GetSpillTemp(dest, vecSpillTempRegisters, ref vecLocalAsg);
@@ -443,7 +443,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
useMask |= 1 << selectedReg;
return Register(selectedReg, local.Type.ToRegisterType(), local.Type);
return Register(selectedReg, local.Type.Register, local.Type);
}
private static int UsesCount(Operand local)

View File

@@ -208,7 +208,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
private bool TryAllocateRegWithoutSpill(AllocationContext context, LiveInterval current, int cIndex, int registersCount)
{
RegisterType regType = current.Local.Type.ToRegisterType();
RegisterType regType = current.Local.Type.Register;
Span<int> freePositions = stackalloc int[registersCount];
@@ -318,7 +318,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
private void AllocateRegWithSpill(AllocationContext context, LiveInterval current, int cIndex, int registersCount)
{
RegisterType regType = current.Local.Type.ToRegisterType();
RegisterType regType = current.Local.Type.Register;
Span<int> usePositions = stackalloc int[registersCount];
Span<int> blockedPositions = stackalloc int[registersCount];

View File

@@ -10,7 +10,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
public int Allocate(OperandType type)
{
return Allocate(type.GetSizeInBytes());
return Allocate(type.ByteSize);
}
public int Allocate(int sizeInBytes)

View File

@@ -385,7 +385,7 @@ namespace ARMeilleure.CodeGen.X86
{
ref readonly InstructionInfo info = ref _instTable[(int)X86Instruction.Movd];
if (source.Type.IsInteger() || source.Kind == OperandKind.Memory)
if (source.Type.IsInteger || source.Kind == OperandKind.Memory)
{
WriteOpCode(dest, default, source, OperandType.None, info.Flags, info.OpRRM, rrm: true);
}
@@ -416,11 +416,11 @@ namespace ARMeilleure.CodeGen.X86
InstructionFlags flags = info.Flags | InstructionFlags.RexW;
if (source.Type.IsInteger() || source.Kind == OperandKind.Memory)
if (source.Type.IsInteger || source.Kind == OperandKind.Memory)
{
WriteOpCode(dest, default, source, OperandType.None, flags, info.OpRRM, rrm: true);
}
else if (dest.Type.IsInteger() || dest.Kind == OperandKind.Memory)
else if (dest.Type.IsInteger || dest.Kind == OperandKind.Memory)
{
WriteOpCode(dest, default, source, OperandType.None, flags, info.OpRMR);
}

View File

@@ -289,7 +289,7 @@ namespace ARMeilleure.CodeGen.X86
EnsureSameType(dest, source);
Debug.Assert(dest.Type.IsInteger());
Debug.Assert(dest.Type.IsInteger);
context.Assembler.Popcnt(dest, source, dest.Type);
@@ -303,7 +303,7 @@ namespace ARMeilleure.CodeGen.X86
EnsureSameType(dest, source);
Debug.Assert(!dest.Type.IsInteger());
Debug.Assert(!dest.Type.IsInteger);
context.Assembler.WriteInstruction(info.Inst, dest, source);
@@ -315,7 +315,7 @@ namespace ARMeilleure.CodeGen.X86
Operand dest = operation.Destination;
Operand source = operation.GetSource(0);
Debug.Assert(dest.Type.IsInteger() && !source.Type.IsInteger());
Debug.Assert(dest.Type.IsInteger && !source.Type.IsInteger);
if (operation.Intrinsic == Intrinsic.X86Cvtsi2si)
{
@@ -349,8 +349,8 @@ namespace ARMeilleure.CodeGen.X86
EnsureSameReg(dest, src1);
}
Debug.Assert(!dest.Type.IsInteger());
Debug.Assert(!src2.Type.IsInteger() || src2.Kind == OperandKind.Constant);
Debug.Assert(!dest.Type.IsInteger);
Debug.Assert(!src2.Type.IsInteger || src2.Kind == OperandKind.Constant);
context.Assembler.WriteInstruction(info.Inst, dest, src1, src2);
@@ -370,7 +370,7 @@ namespace ARMeilleure.CodeGen.X86
EnsureSameReg(dest, src1);
}
Debug.Assert(!dest.Type.IsInteger() && src2.Type.IsInteger());
Debug.Assert(!dest.Type.IsInteger && src2.Type.IsInteger);
context.Assembler.WriteInstruction(info.Inst, dest, src1, src2, src2.Type);
@@ -385,7 +385,7 @@ namespace ARMeilleure.CodeGen.X86
EnsureSameReg(dest, src1);
Debug.Assert(dest.Type.IsInteger() && src1.Type.IsInteger() && src2.Type.IsInteger());
Debug.Assert(dest.Type.IsInteger && src1.Type.IsInteger && src2.Type.IsInteger);
context.Assembler.WriteInstruction(info.Inst, dest, src2, dest.Type);
@@ -405,7 +405,7 @@ namespace ARMeilleure.CodeGen.X86
EnsureSameReg(dest, src1);
}
Debug.Assert(!dest.Type.IsInteger() && src2.Kind == OperandKind.Constant);
Debug.Assert(!dest.Type.IsInteger && src2.Kind == OperandKind.Constant);
context.Assembler.WriteInstruction(info.Inst, dest, src1, src2.AsByte());
@@ -421,7 +421,7 @@ namespace ARMeilleure.CodeGen.X86
EnsureSameType(dest, src1, src2, src3);
Debug.Assert(!dest.Type.IsInteger());
Debug.Assert(!dest.Type.IsInteger);
if (info.Inst == X86Instruction.Blendvpd && HardwareCapabilities.SupportsVexEncoding)
{
@@ -461,7 +461,7 @@ namespace ARMeilleure.CodeGen.X86
EnsureSameReg(dest, src1);
}
Debug.Assert(!dest.Type.IsInteger() && src3.Kind == OperandKind.Constant);
Debug.Assert(!dest.Type.IsInteger && src3.Kind == OperandKind.Constant);
context.Assembler.WriteInstruction(info.Inst, dest, src1, src2, src3.AsByte());
@@ -512,7 +512,7 @@ namespace ARMeilleure.CodeGen.X86
Operand src1 = operation.GetSource(0);
Operand src2 = operation.GetSource(1);
if (dest.Type.IsInteger())
if (dest.Type.IsInteger)
{
// If Destination and Source 1 Operands are the same, perform a standard add as there are no benefits to using LEA.
if (dest.Kind == src1.Kind && dest.Value == src1.Value)
@@ -567,7 +567,7 @@ namespace ARMeilleure.CodeGen.X86
ValidateBinOp(dest, src1, src2);
Debug.Assert(dest.Type.IsInteger());
Debug.Assert(dest.Type.IsInteger);
// Note: GenerateCompareCommon makes the assumption that BitwiseAnd will emit only a single `and`
// instruction.
@@ -582,7 +582,7 @@ namespace ARMeilleure.CodeGen.X86
ValidateBinOp(dest, src1, src2);
if (dest.Type.IsInteger())
if (dest.Type.IsInteger)
{
context.Assembler.Xor(dest, src2, dest.Type);
}
@@ -599,7 +599,7 @@ namespace ARMeilleure.CodeGen.X86
ValidateUnOp(dest, source);
Debug.Assert(dest.Type.IsInteger());
Debug.Assert(dest.Type.IsInteger);
context.Assembler.Not(dest);
}
@@ -612,7 +612,7 @@ namespace ARMeilleure.CodeGen.X86
ValidateBinOp(dest, src1, src2);
Debug.Assert(dest.Type.IsInteger());
Debug.Assert(dest.Type.IsInteger);
context.Assembler.Or(dest, src2, dest.Type);
}
@@ -623,7 +623,7 @@ namespace ARMeilleure.CodeGen.X86
Debug.Assert(comp.Kind == OperandKind.Constant);
X86Condition cond = ((Comparison)comp.AsInt32()).ToX86Condition();
X86Condition cond = ((Comparison)comp.AsInt32()).X86;
GenerateCompareCommon(context, operation);
@@ -637,7 +637,7 @@ namespace ARMeilleure.CodeGen.X86
ValidateUnOp(dest, source);
Debug.Assert(dest.Type.IsInteger());
Debug.Assert(dest.Type.IsInteger);
context.Assembler.Bswap(dest);
}
@@ -661,7 +661,7 @@ namespace ARMeilleure.CodeGen.X86
Debug.Assert(dest.Type == OperandType.I32);
Debug.Assert(comp.Kind == OperandKind.Constant);
X86Condition cond = ((Comparison)comp.AsInt32()).ToX86Condition();
X86Condition cond = ((Comparison)comp.AsInt32()).X86;
GenerateCompareCommon(context, operation);
@@ -676,7 +676,7 @@ namespace ARMeilleure.CodeGen.X86
EnsureSameType(src1, src2);
Debug.Assert(src1.Type.IsInteger());
Debug.Assert(src1.Type.IsInteger);
if (src2.Kind == OperandKind.Constant && src2.Value == 0)
{
@@ -766,7 +766,7 @@ namespace ARMeilleure.CodeGen.X86
EnsureSameReg(dest, src3);
EnsureSameType(dest, src2, src3);
Debug.Assert(dest.Type.IsInteger());
Debug.Assert(dest.Type.IsInteger);
Debug.Assert(src1.Type == OperandType.I32);
context.Assembler.Test(src1, src1, src1.Type);
@@ -792,9 +792,9 @@ namespace ARMeilleure.CodeGen.X86
if (dest.Type == OperandType.FP32)
{
Debug.Assert(source.Type.IsInteger() || source.Type == OperandType.FP64);
Debug.Assert(source.Type.IsInteger || source.Type == OperandType.FP64);
if (source.Type.IsInteger())
if (source.Type.IsInteger)
{
context.Assembler.Xorps(dest, dest, dest);
context.Assembler.Cvtsi2ss(dest, dest, source, source.Type);
@@ -808,9 +808,9 @@ namespace ARMeilleure.CodeGen.X86
}
else /* if (dest.Type == OperandType.FP64) */
{
Debug.Assert(source.Type.IsInteger() || source.Type == OperandType.FP32);
Debug.Assert(source.Type.IsInteger || source.Type == OperandType.FP32);
if (source.Type.IsInteger())
if (source.Type.IsInteger)
{
context.Assembler.Xorps(dest, dest, dest);
context.Assembler.Cvtsi2sd(dest, dest, source, source.Type);
@@ -831,7 +831,7 @@ namespace ARMeilleure.CodeGen.X86
EnsureSameType(dest, source);
Debug.Assert(dest.Type.IsInteger() || source.Kind != OperandKind.Constant);
Debug.Assert(dest.Type.IsInteger || source.Kind != OperandKind.Constant);
// Moves to the same register are useless.
if (dest.Kind == source.Kind && dest.Value == source.Value)
@@ -845,7 +845,7 @@ namespace ARMeilleure.CodeGen.X86
// Assemble "mov reg, 0" as "xor reg, reg" as the later is more efficient.
context.Assembler.Xor(dest, dest, OperandType.I32);
}
else if (dest.Type.IsInteger())
else if (dest.Type.IsInteger)
{
context.Assembler.Mov(dest, source, dest.Type);
}
@@ -862,7 +862,7 @@ namespace ARMeilleure.CodeGen.X86
EnsureSameType(dest, source);
Debug.Assert(dest.Type.IsInteger());
Debug.Assert(dest.Type.IsInteger);
context.Assembler.Bsr(dest, source, dest.Type);
@@ -894,12 +894,12 @@ namespace ARMeilleure.CodeGen.X86
Operand dividend = operation.GetSource(0);
Operand divisor = operation.GetSource(1);
if (!dest.Type.IsInteger())
if (!dest.Type.IsInteger)
{
ValidateBinOp(dest, dividend, divisor);
}
if (dest.Type.IsInteger())
if (dest.Type.IsInteger)
{
divisor = operation.GetSource(2);
@@ -932,7 +932,7 @@ namespace ARMeilleure.CodeGen.X86
Operand rdx = Register(X86Register.Rdx);
Debug.Assert(divisor.Type.IsInteger());
Debug.Assert(divisor.Type.IsInteger);
context.Assembler.Xor(rdx, rdx, OperandType.I32);
context.Assembler.Div(divisor);
@@ -967,7 +967,7 @@ namespace ARMeilleure.CodeGen.X86
Operand value = operation.Destination;
Operand address = Memory(operation.GetSource(0), value.Type);
Debug.Assert(value.Type.IsInteger());
Debug.Assert(value.Type.IsInteger);
context.Assembler.Movzx16(value, address, value.Type);
}
@@ -977,7 +977,7 @@ namespace ARMeilleure.CodeGen.X86
Operand value = operation.Destination;
Operand address = Memory(operation.GetSource(0), value.Type);
Debug.Assert(value.Type.IsInteger());
Debug.Assert(value.Type.IsInteger);
context.Assembler.Movzx8(value, address, value.Type);
}
@@ -1000,7 +1000,7 @@ namespace ARMeilleure.CodeGen.X86
EnsureSameType(dest, src1, src2);
if (dest.Type.IsInteger())
if (dest.Type.IsInteger)
{
if (src2.Kind == OperandKind.Constant)
{
@@ -1046,7 +1046,7 @@ namespace ARMeilleure.CodeGen.X86
ValidateUnOp(dest, source);
Debug.Assert(dest.Type.IsInteger());
Debug.Assert(dest.Type.IsInteger);
context.Assembler.Neg(dest);
}
@@ -1107,7 +1107,7 @@ namespace ARMeilleure.CodeGen.X86
Operand dest = operation.Destination;
Operand source = operation.GetSource(0);
Debug.Assert(dest.Type.IsInteger() && source.Type.IsInteger());
Debug.Assert(dest.Type.IsInteger && source.Type.IsInteger);
context.Assembler.Movsx16(dest, source, dest.Type);
}
@@ -1117,7 +1117,7 @@ namespace ARMeilleure.CodeGen.X86
Operand dest = operation.Destination;
Operand source = operation.GetSource(0);
Debug.Assert(dest.Type.IsInteger() && source.Type.IsInteger());
Debug.Assert(dest.Type.IsInteger && source.Type.IsInteger);
context.Assembler.Movsx32(dest, source, dest.Type);
}
@@ -1127,7 +1127,7 @@ namespace ARMeilleure.CodeGen.X86
Operand dest = operation.Destination;
Operand source = operation.GetSource(0);
Debug.Assert(dest.Type.IsInteger() && source.Type.IsInteger());
Debug.Assert(dest.Type.IsInteger && source.Type.IsInteger);
context.Assembler.Movsx8(dest, source, dest.Type);
}
@@ -1187,7 +1187,7 @@ namespace ARMeilleure.CodeGen.X86
Operand value = operation.GetSource(1);
Operand address = Memory(operation.GetSource(0), value.Type);
Debug.Assert(value.Type.IsInteger());
Debug.Assert(value.Type.IsInteger);
context.Assembler.Mov16(address, value);
}
@@ -1197,7 +1197,7 @@ namespace ARMeilleure.CodeGen.X86
Operand value = operation.GetSource(1);
Operand address = Memory(operation.GetSource(0), value.Type);
Debug.Assert(value.Type.IsInteger());
Debug.Assert(value.Type.IsInteger);
context.Assembler.Mov8(address, value);
}
@@ -1210,7 +1210,7 @@ namespace ARMeilleure.CodeGen.X86
ValidateBinOp(dest, src1, src2);
if (dest.Type.IsInteger())
if (dest.Type.IsInteger)
{
context.Assembler.Sub(dest, src2, dest.Type);
}
@@ -1236,7 +1236,7 @@ namespace ARMeilleure.CodeGen.X86
Operand dest = operation.Destination;
Operand source = operation.GetSource(0);
Debug.Assert(!dest.Type.IsInteger() && source.Type.IsInteger());
Debug.Assert(!dest.Type.IsInteger && source.Type.IsInteger);
if (source.Type == OperandType.I32)
{
@@ -1259,7 +1259,7 @@ namespace ARMeilleure.CodeGen.X86
byte index = src2.AsByte();
Debug.Assert(index < OperandType.V128.GetSizeInBytes() / dest.Type.GetSizeInBytes());
Debug.Assert(index < OperandType.V128.ByteSize / dest.Type.ByteSize);
if (dest.Type == OperandType.I32)
{
@@ -1541,7 +1541,7 @@ namespace ARMeilleure.CodeGen.X86
{
Operand dest = operation.Destination;
Debug.Assert(!dest.Type.IsInteger());
Debug.Assert(!dest.Type.IsInteger);
context.Assembler.Pcmpeqw(dest, dest, dest);
}
@@ -1550,7 +1550,7 @@ namespace ARMeilleure.CodeGen.X86
{
Operand dest = operation.Destination;
Debug.Assert(!dest.Type.IsInteger());
Debug.Assert(!dest.Type.IsInteger);
context.Assembler.Xorps(dest, dest, dest);
}
@@ -1580,7 +1580,7 @@ namespace ARMeilleure.CodeGen.X86
Operand dest = operation.Destination;
Operand source = operation.GetSource(0);
Debug.Assert(dest.Type.IsInteger() && source.Type.IsInteger());
Debug.Assert(dest.Type.IsInteger && source.Type.IsInteger);
context.Assembler.Movzx16(dest, source, OperandType.I32);
}
@@ -1590,7 +1590,7 @@ namespace ARMeilleure.CodeGen.X86
Operand dest = operation.Destination;
Operand source = operation.GetSource(0);
Debug.Assert(dest.Type.IsInteger() && source.Type.IsInteger());
Debug.Assert(dest.Type.IsInteger && source.Type.IsInteger);
// We can eliminate the move if source is already 32-bit and the registers are the same.
if (dest.Value == source.Value && source.Type == OperandType.I32)
@@ -1606,7 +1606,7 @@ namespace ARMeilleure.CodeGen.X86
Operand dest = operation.Destination;
Operand source = operation.GetSource(0);
Debug.Assert(dest.Type.IsInteger() && source.Type.IsInteger());
Debug.Assert(dest.Type.IsInteger && source.Type.IsInteger);
context.Assembler.Movzx8(dest, source, OperandType.I32);
}
@@ -1713,12 +1713,12 @@ namespace ARMeilleure.CodeGen.X86
EnsureSameReg(dest, src1);
EnsureSameType(dest, src1);
Debug.Assert(dest.Type.IsInteger() && src2.Type == OperandType.I32);
Debug.Assert(dest.Type.IsInteger && src2.Type == OperandType.I32);
}
private static void EnsureSameReg(Operand op1, Operand op2)
{
if (!op1.Type.IsInteger() && HardwareCapabilities.SupportsVexEncoding)
if (!op1.Type.IsInteger && HardwareCapabilities.SupportsVexEncoding)
{
return;
}

View File

@@ -86,7 +86,7 @@ namespace ARMeilleure.CodeGen.X86
break;
case Instruction.Negate:
if (!node.GetSource(0).Type.IsInteger())
if (!node.GetSource(0).Type.IsInteger)
{
GenerateNegate(block.Operations, node);
}
@@ -159,7 +159,7 @@ namespace ARMeilleure.CodeGen.X86
if (src1.Kind == OperandKind.Constant)
{
if (!src1.Type.IsInteger())
if (!src1.Type.IsInteger)
{
// Handle non-integer types (FP32, FP64 and V128).
// For instructions without an immediate operand, we do the following:
@@ -208,7 +208,7 @@ namespace ARMeilleure.CodeGen.X86
if (src2.Kind == OperandKind.Constant)
{
if (!src2.Type.IsInteger())
if (!src2.Type.IsInteger)
{
src2 = AddXmmCopy(nodes, node, src2);
@@ -298,7 +298,7 @@ namespace ARMeilleure.CodeGen.X86
// - The dividend is always in RDX:RAX.
// - The result is always in RAX.
// - Additionally it also writes the remainder in RDX.
if (dest.Type.IsInteger())
if (dest.Type.IsInteger)
{
Operand src1 = node.GetSource(0);
@@ -466,7 +466,7 @@ namespace ARMeilleure.CodeGen.X86
Operand dest = node.Destination;
Operand source = node.GetSource(0);
Debug.Assert(source.Type.IsInteger(), $"Invalid source type \"{source.Type}\".");
Debug.Assert(source.Type.IsInteger, $"Invalid source type \"{source.Type}\".");
Operation currentNode = node;
@@ -654,10 +654,10 @@ namespace ARMeilleure.CodeGen.X86
switch (operation.Instruction)
{
case Instruction.Add:
return !HardwareCapabilities.SupportsVexEncoding && !operation.Destination.Type.IsInteger();
return !HardwareCapabilities.SupportsVexEncoding && !operation.Destination.Type.IsInteger;
case Instruction.Multiply:
case Instruction.Subtract:
return !HardwareCapabilities.SupportsVexEncoding || operation.Destination.Type.IsInteger();
return !HardwareCapabilities.SupportsVexEncoding || operation.Destination.Type.IsInteger;
case Instruction.BitwiseAnd:
case Instruction.BitwiseExclusiveOr:
@@ -672,7 +672,7 @@ namespace ARMeilleure.CodeGen.X86
return true;
case Instruction.Divide:
return !HardwareCapabilities.SupportsVexEncoding && !operation.Destination.Type.IsInteger();
return !HardwareCapabilities.SupportsVexEncoding && !operation.Destination.Type.IsInteger;
case Instruction.VectorInsert:
case Instruction.VectorInsert16:

View File

@@ -35,7 +35,7 @@ namespace ARMeilleure.CodeGen.X86
bool passOnReg;
if (source.Type.IsInteger())
if (source.Type.IsInteger)
{
passOnReg = intCount < intMax;
}
@@ -62,7 +62,7 @@ namespace ARMeilleure.CodeGen.X86
if (passOnReg)
{
Operand argReg = source.Type.IsInteger()
Operand argReg = source.Type.IsInteger
? Gpr(CallingConvention.GetIntArgumentRegister(intCount++), source.Type)
: Xmm(CallingConvention.GetVecArgumentRegister(vecCount++), source.Type);
@@ -80,7 +80,7 @@ namespace ARMeilleure.CodeGen.X86
InsertConstantRegCopies(nodes, nodes.AddBefore(node, spillOp));
stackOffset += source.Type.GetSizeInBytes();
stackOffset += source.Type.ByteSize;
}
}
@@ -102,7 +102,7 @@ namespace ARMeilleure.CodeGen.X86
}
else
{
Operand retReg = dest.Type.IsInteger()
Operand retReg = dest.Type.IsInteger
? Gpr(CallingConvention.GetIntReturnRegister(), dest.Type)
: Xmm(CallingConvention.GetVecReturnRegister(), dest.Type);
@@ -137,7 +137,7 @@ namespace ARMeilleure.CodeGen.X86
bool passOnReg;
if (source.Type.IsInteger())
if (source.Type.IsInteger)
{
passOnReg = intCount + 1 < intMax;
}
@@ -160,7 +160,7 @@ namespace ARMeilleure.CodeGen.X86
if (passOnReg)
{
Operand argReg = source.Type.IsInteger()
Operand argReg = source.Type.IsInteger
? Gpr(CallingConvention.GetIntArgumentRegister(intCount++), source.Type)
: Xmm(CallingConvention.GetVecArgumentRegister(vecCount++), source.Type);
@@ -210,7 +210,7 @@ namespace ARMeilleure.CodeGen.X86
{
OperandType argType = cctx.FuncArgTypes[cIndex];
if (argType.IsInteger())
if (argType.IsInteger)
{
intCount++;
}
@@ -226,7 +226,7 @@ namespace ARMeilleure.CodeGen.X86
bool passOnReg;
if (source.Type.IsInteger())
if (source.Type.IsInteger)
{
passOnReg = intCount < CallingConvention.GetIntArgumentsOnRegsCount();
}
@@ -265,7 +265,7 @@ namespace ARMeilleure.CodeGen.X86
{
Operand pArg = Local(dest.Type);
Operand argReg = dest.Type.IsInteger()
Operand argReg = dest.Type.IsInteger
? Gpr(CallingConvention.GetIntArgumentRegister(intCount), dest.Type)
: Xmm(CallingConvention.GetVecArgumentRegister(vecCount), dest.Type);
@@ -320,7 +320,7 @@ namespace ARMeilleure.CodeGen.X86
}
else
{
Operand retReg = source.Type.IsInteger()
Operand retReg = source.Type.IsInteger
? Gpr(CallingConvention.GetIntReturnRegister(), source.Type)
: Xmm(CallingConvention.GetVecReturnRegister(), source.Type);

View File

@@ -40,7 +40,7 @@ namespace ARMeilleure.CodeGen.X86
if (dest != default && dest.Type == OperandType.V128)
{
int stackOffset = AllocateOnStack(dest.Type.GetSizeInBytes());
int stackOffset = AllocateOnStack(dest.Type.ByteSize);
arg0Reg = Gpr(CallingConvention.GetIntArgumentRegister(0), OperandType.I64);
@@ -76,7 +76,7 @@ namespace ARMeilleure.CodeGen.X86
{
Operand stackAddr = Local(OperandType.I64);
int stackOffset = AllocateOnStack(source.Type.GetSizeInBytes());
int stackOffset = AllocateOnStack(source.Type.ByteSize);
nodes.AddBefore(node, Operation(Instruction.StackAlloc, stackAddr, Const(stackOffset)));
@@ -96,7 +96,7 @@ namespace ARMeilleure.CodeGen.X86
int argIndex = index + retArgs;
if (source.Type.IsInteger())
if (source.Type.IsInteger)
{
argReg = Gpr(CallingConvention.GetIntArgumentRegister(argIndex), source.Type);
}
@@ -140,7 +140,7 @@ namespace ARMeilleure.CodeGen.X86
}
else
{
Operand retReg = dest.Type.IsInteger()
Operand retReg = dest.Type.IsInteger
? Gpr(CallingConvention.GetIntReturnRegister(), dest.Type)
: Xmm(CallingConvention.GetVecReturnRegister(), dest.Type);
@@ -171,7 +171,7 @@ namespace ARMeilleure.CodeGen.X86
for (int index = 0; index < argsCount; index++)
{
Operand source = node.GetSource(1 + index);
Operand argReg = source.Type.IsInteger()
Operand argReg = source.Type.IsInteger
? Gpr(CallingConvention.GetIntArgumentRegister(index), source.Type)
: Xmm(CallingConvention.GetVecArgumentRegister(index), source.Type);
@@ -219,7 +219,7 @@ namespace ARMeilleure.CodeGen.X86
{
Operand argReg, pArg;
if (dest.Type.IsInteger())
if (dest.Type.IsInteger)
{
argReg = Gpr(CallingConvention.GetIntArgumentRegister(index), dest.Type);
pArg = Local(dest.Type);
@@ -283,7 +283,7 @@ namespace ARMeilleure.CodeGen.X86
Operand source = node.GetSource(0);
Operand retReg;
if (source.Type.IsInteger())
if (source.Type.IsInteger)
{
retReg = Gpr(CallingConvention.GetIntReturnRegister(), source.Type);
}

View File

@@ -25,9 +25,9 @@ namespace ARMeilleure.CodeGen.X86
static class ComparisonX86Extensions
{
public static X86Condition ToX86Condition(this Comparison comp)
extension(Comparison comparison)
{
return comp switch
public X86Condition X86 => comparison switch
{
#pragma warning disable IDE0055 // Disable formatting
Comparison.Equal => X86Condition.Equal,
@@ -42,7 +42,7 @@ namespace ARMeilleure.CodeGen.X86
Comparison.LessUI => X86Condition.Below,
#pragma warning restore IDE0055
_ => throw new ArgumentException(null, nameof(comp)),
_ => throw new ArgumentException(null, nameof(comparison))
};
}
}

View File

@@ -22,11 +22,11 @@ namespace ARMeilleure.Decoders
static class ConditionExtensions
{
public static Condition Invert(this Condition cond)
extension(Condition condition)
{
// Bit 0 of all conditions is basically a negation bit, so
// inverting this bit has the effect of inverting the condition.
return (Condition)((int)cond ^ 1);
public Condition Inverse => (Condition)((int)condition ^ 1);
}
}
}

View File

@@ -16,7 +16,7 @@ namespace ARMeilleure.Instructions
public static Operand EmitCrc32(ArmEmitterContext context, Operand crc, Operand value, int size, bool castagnoli)
{
Debug.Assert(crc.Type.IsInteger() && value.Type.IsInteger());
Debug.Assert(crc.Type.IsInteger && value.Type.IsInteger);
Debug.Assert(size is >= 0 and < 4);
Debug.Assert((size < 3) || (value.Type == OperandType.I64));

View File

@@ -157,7 +157,7 @@ namespace ARMeilleure.Instructions
context.Copy(temp, value);
if (!context.Memory.Type.IsHostMappedOrTracked())
if (!context.Memory.Type.IsHostMappedOrTracked)
{
context.Branch(lblEnd);
@@ -198,7 +198,7 @@ namespace ARMeilleure.Instructions
SetInt(context, rt, value);
if (!context.Memory.Type.IsHostMappedOrTracked())
if (!context.Memory.Type.IsHostMappedOrTracked)
{
context.Branch(lblEnd);
@@ -265,7 +265,7 @@ namespace ARMeilleure.Instructions
context.Copy(GetVec(rt), value);
if (!context.Memory.Type.IsHostMappedOrTracked())
if (!context.Memory.Type.IsHostMappedOrTracked)
{
context.Branch(lblEnd);
@@ -312,7 +312,7 @@ namespace ARMeilleure.Instructions
break;
}
if (!context.Memory.Type.IsHostMappedOrTracked())
if (!context.Memory.Type.IsHostMappedOrTracked)
{
context.Branch(lblEnd);
@@ -385,7 +385,7 @@ namespace ARMeilleure.Instructions
break;
}
if (!context.Memory.Type.IsHostMappedOrTracked())
if (!context.Memory.Type.IsHostMappedOrTracked)
{
context.Branch(lblEnd);
@@ -399,11 +399,11 @@ namespace ARMeilleure.Instructions
public static Operand EmitPtPointerLoad(ArmEmitterContext context, Operand address, Operand lblSlowPath, bool write, int size)
{
if (context.Memory.Type.IsHostMapped())
if (context.Memory.Type.IsHostMapped)
{
return EmitHostMappedPointer(context, address);
}
else if (context.Memory.Type.IsHostTracked())
else if (context.Memory.Type.IsHostTracked)
{
if (address.Type == OperandType.I32)
{

View File

@@ -1,692 +0,0 @@
using ARMeilleure.State;
using System;
using System.Runtime.InteropServices;
namespace ARMeilleure.Instructions
{
static class SoftFallback
{
#region "ShrImm64"
[UnmanagedCallersOnly]
public static long SignedShrImm64(long value, long roundConst, int shift)
{
if (roundConst == 0L)
{
if (shift <= 63)
{
return value >> shift;
}
else /* if (shift == 64) */
{
if (value < 0L)
{
return -1L;
}
else /* if (value >= 0L) */
{
return 0L;
}
}
}
else /* if (roundConst == 1L << (shift - 1)) */
{
if (shift <= 63)
{
long add = value + roundConst;
if ((~value & (value ^ add)) < 0L)
{
return (long)((ulong)add >> shift);
}
else
{
return add >> shift;
}
}
else /* if (shift == 64) */
{
return 0L;
}
}
}
[UnmanagedCallersOnly]
public static ulong UnsignedShrImm64(ulong value, long roundConst, int shift)
{
if (roundConst == 0L)
{
if (shift <= 63)
{
return value >> shift;
}
else /* if (shift == 64) */
{
return 0UL;
}
}
else /* if (roundConst == 1L << (shift - 1)) */
{
ulong add = value + (ulong)roundConst;
if ((add < value) && (add < (ulong)roundConst))
{
if (shift <= 63)
{
return (add >> shift) | (0x8000000000000000UL >> (shift - 1));
}
else /* if (shift == 64) */
{
return 1UL;
}
}
else
{
if (shift <= 63)
{
return add >> shift;
}
else /* if (shift == 64) */
{
return 0UL;
}
}
}
}
#endregion
#region "Saturation"
[UnmanagedCallersOnly]
public static int SatF32ToS32(float value)
{
if (float.IsNaN(value))
{
return 0;
}
return value >= int.MaxValue ? int.MaxValue :
value <= int.MinValue ? int.MinValue : (int)value;
}
[UnmanagedCallersOnly]
public static long SatF32ToS64(float value)
{
if (float.IsNaN(value))
{
return 0;
}
return value >= long.MaxValue ? long.MaxValue :
value <= long.MinValue ? long.MinValue : (long)value;
}
[UnmanagedCallersOnly]
public static uint SatF32ToU32(float value)
{
if (float.IsNaN(value))
{
return 0;
}
return value >= uint.MaxValue ? uint.MaxValue :
value <= uint.MinValue ? uint.MinValue : (uint)value;
}
[UnmanagedCallersOnly]
public static ulong SatF32ToU64(float value)
{
if (float.IsNaN(value))
{
return 0;
}
return value >= ulong.MaxValue ? ulong.MaxValue :
value <= ulong.MinValue ? ulong.MinValue : (ulong)value;
}
[UnmanagedCallersOnly]
public static int SatF64ToS32(double value)
{
if (double.IsNaN(value))
{
return 0;
}
return value >= int.MaxValue ? int.MaxValue :
value <= int.MinValue ? int.MinValue : (int)value;
}
[UnmanagedCallersOnly]
public static long SatF64ToS64(double value)
{
if (double.IsNaN(value))
{
return 0;
}
return value >= long.MaxValue ? long.MaxValue :
value <= long.MinValue ? long.MinValue : (long)value;
}
[UnmanagedCallersOnly]
public static uint SatF64ToU32(double value)
{
if (double.IsNaN(value))
{
return 0;
}
return value >= uint.MaxValue ? uint.MaxValue :
value <= uint.MinValue ? uint.MinValue : (uint)value;
}
[UnmanagedCallersOnly]
public static ulong SatF64ToU64(double value)
{
if (double.IsNaN(value))
{
return 0;
}
return value >= ulong.MaxValue ? ulong.MaxValue :
value <= ulong.MinValue ? ulong.MinValue : (ulong)value;
}
#endregion
#region "Count"
[UnmanagedCallersOnly]
public static ulong CountLeadingSigns(ulong value, int size) // size is 8, 16, 32 or 64 (SIMD&FP or Base Inst.).
{
value ^= value >> 1;
int highBit = size - 2;
for (int bit = highBit; bit >= 0; bit--)
{
if (((int)(value >> bit) & 0b1) != 0)
{
return (ulong)(highBit - bit);
}
}
return (ulong)(size - 1);
}
private static ReadOnlySpan<byte> ClzNibbleTbl => [4, 3, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0];
[UnmanagedCallersOnly]
public static ulong CountLeadingZeros(ulong value, int size) // size is 8, 16, 32 or 64 (SIMD&FP or Base Inst.).
{
if (value == 0ul)
{
return (ulong)size;
}
int nibbleIdx = size;
int preCount, count = 0;
do
{
nibbleIdx -= 4;
preCount = ClzNibbleTbl[(int)(value >> nibbleIdx) & 0b1111];
count += preCount;
}
while (preCount == 4);
return (ulong)count;
}
#endregion
#region "Table"
[UnmanagedCallersOnly]
public static V128 Tbl1(V128 vector, int bytes, V128 tb0)
{
return TblOrTbx(default, vector, bytes, tb0);
}
[UnmanagedCallersOnly]
public static V128 Tbl2(V128 vector, int bytes, V128 tb0, V128 tb1)
{
return TblOrTbx(default, vector, bytes, tb0, tb1);
}
[UnmanagedCallersOnly]
public static V128 Tbl3(V128 vector, int bytes, V128 tb0, V128 tb1, V128 tb2)
{
return TblOrTbx(default, vector, bytes, tb0, tb1, tb2);
}
[UnmanagedCallersOnly]
public static V128 Tbl4(V128 vector, int bytes, V128 tb0, V128 tb1, V128 tb2, V128 tb3)
{
return TblOrTbx(default, vector, bytes, tb0, tb1, tb2, tb3);
}
[UnmanagedCallersOnly]
public static V128 Tbx1(V128 dest, V128 vector, int bytes, V128 tb0)
{
return TblOrTbx(dest, vector, bytes, tb0);
}
[UnmanagedCallersOnly]
public static V128 Tbx2(V128 dest, V128 vector, int bytes, V128 tb0, V128 tb1)
{
return TblOrTbx(dest, vector, bytes, tb0, tb1);
}
[UnmanagedCallersOnly]
public static V128 Tbx3(V128 dest, V128 vector, int bytes, V128 tb0, V128 tb1, V128 tb2)
{
return TblOrTbx(dest, vector, bytes, tb0, tb1, tb2);
}
[UnmanagedCallersOnly]
public static V128 Tbx4(V128 dest, V128 vector, int bytes, V128 tb0, V128 tb1, V128 tb2, V128 tb3)
{
return TblOrTbx(dest, vector, bytes, tb0, tb1, tb2, tb3);
}
private static V128 TblOrTbx(V128 dest, V128 vector, int bytes, params ReadOnlySpan<V128> tb)
{
byte[] res = new byte[16];
if (dest != default)
{
Buffer.BlockCopy(dest.ToArray(), 0, res, 0, bytes);
}
byte[] table = new byte[tb.Length * 16];
for (byte index = 0; index < tb.Length; index++)
{
Buffer.BlockCopy(tb[index].ToArray(), 0, table, index * 16, 16);
}
byte[] v = vector.ToArray();
for (byte index = 0; index < bytes; index++)
{
byte tblIndex = v[index];
if (tblIndex < table.Length)
{
res[index] = table[tblIndex];
}
}
return new V128(res);
}
#endregion
#region "Crc32"
private const uint Crc32RevPoly = 0xedb88320;
private const uint Crc32cRevPoly = 0x82f63b78;
[UnmanagedCallersOnly]
public static uint Crc32b(uint crc, byte value) => Crc32(crc, Crc32RevPoly, value);
[UnmanagedCallersOnly]
public static uint Crc32h(uint crc, ushort value) => Crc32h(crc, Crc32RevPoly, value);
[UnmanagedCallersOnly]
public static uint Crc32w(uint crc, uint value) => Crc32w(crc, Crc32RevPoly, value);
[UnmanagedCallersOnly]
public static uint Crc32x(uint crc, ulong value) => Crc32x(crc, Crc32RevPoly, value);
[UnmanagedCallersOnly]
public static uint Crc32cb(uint crc, byte value) => Crc32(crc, Crc32cRevPoly, value);
[UnmanagedCallersOnly]
public static uint Crc32ch(uint crc, ushort value) => Crc32h(crc, Crc32cRevPoly, value);
[UnmanagedCallersOnly]
public static uint Crc32cw(uint crc, uint value) => Crc32w(crc, Crc32cRevPoly, value);
[UnmanagedCallersOnly]
public static uint Crc32cx(uint crc, ulong value) => Crc32x(crc, Crc32cRevPoly, value);
private static uint Crc32h(uint crc, uint poly, ushort val)
{
crc = Crc32(crc, poly, (byte)(val >> 0));
crc = Crc32(crc, poly, (byte)(val >> 8));
return crc;
}
private static uint Crc32w(uint crc, uint poly, uint val)
{
crc = Crc32(crc, poly, (byte)(val >> 0));
crc = Crc32(crc, poly, (byte)(val >> 8));
crc = Crc32(crc, poly, (byte)(val >> 16));
crc = Crc32(crc, poly, (byte)(val >> 24));
return crc;
}
private static uint Crc32x(uint crc, uint poly, ulong val)
{
crc = Crc32(crc, poly, (byte)(val >> 0));
crc = Crc32(crc, poly, (byte)(val >> 8));
crc = Crc32(crc, poly, (byte)(val >> 16));
crc = Crc32(crc, poly, (byte)(val >> 24));
crc = Crc32(crc, poly, (byte)(val >> 32));
crc = Crc32(crc, poly, (byte)(val >> 40));
crc = Crc32(crc, poly, (byte)(val >> 48));
crc = Crc32(crc, poly, (byte)(val >> 56));
return crc;
}
private static uint Crc32(uint crc, uint poly, byte val)
{
crc ^= val;
for (int bit = 7; bit >= 0; bit--)
{
uint mask = (uint)(-(int)(crc & 1));
crc = (crc >> 1) ^ (poly & mask);
}
return crc;
}
#endregion
#region "Aes"
[UnmanagedCallersOnly]
public static V128 Decrypt(V128 value, V128 roundKey)
{
return CryptoHelper.AesInvSubBytes(CryptoHelper.AesInvShiftRows(value ^ roundKey));
}
[UnmanagedCallersOnly]
public static V128 Encrypt(V128 value, V128 roundKey)
{
return CryptoHelper.AesSubBytes(CryptoHelper.AesShiftRows(value ^ roundKey));
}
[UnmanagedCallersOnly]
public static V128 InverseMixColumns(V128 value)
{
return CryptoHelper.AesInvMixColumns(value);
}
[UnmanagedCallersOnly]
public static V128 MixColumns(V128 value)
{
return CryptoHelper.AesMixColumns(value);
}
#endregion
#region "Sha1"
[UnmanagedCallersOnly]
public static V128 HashChoose(V128 hash_abcd, uint hash_e, V128 wk)
{
for (int e = 0; e <= 3; e++)
{
uint t = ShaChoose(hash_abcd.Extract<uint>(1),
hash_abcd.Extract<uint>(2),
hash_abcd.Extract<uint>(3));
hash_e += Rol(hash_abcd.Extract<uint>(0), 5) + t + wk.Extract<uint>(e);
t = Rol(hash_abcd.Extract<uint>(1), 30);
hash_abcd.Insert(1, t);
Rol32_160(ref hash_e, ref hash_abcd);
}
return hash_abcd;
}
[UnmanagedCallersOnly]
public static uint FixedRotate(uint hash_e)
{
return hash_e.Rol(30);
}
[UnmanagedCallersOnly]
public static V128 HashMajority(V128 hash_abcd, uint hash_e, V128 wk)
{
for (int e = 0; e <= 3; e++)
{
uint t = ShaMajority(hash_abcd.Extract<uint>(1),
hash_abcd.Extract<uint>(2),
hash_abcd.Extract<uint>(3));
hash_e += Rol(hash_abcd.Extract<uint>(0), 5) + t + wk.Extract<uint>(e);
t = Rol(hash_abcd.Extract<uint>(1), 30);
hash_abcd.Insert(1, t);
Rol32_160(ref hash_e, ref hash_abcd);
}
return hash_abcd;
}
[UnmanagedCallersOnly]
public static V128 HashParity(V128 hash_abcd, uint hash_e, V128 wk)
{
for (int e = 0; e <= 3; e++)
{
uint t = ShaParity(hash_abcd.Extract<uint>(1),
hash_abcd.Extract<uint>(2),
hash_abcd.Extract<uint>(3));
hash_e += Rol(hash_abcd.Extract<uint>(0), 5) + t + wk.Extract<uint>(e);
t = Rol(hash_abcd.Extract<uint>(1), 30);
hash_abcd.Insert(1, t);
Rol32_160(ref hash_e, ref hash_abcd);
}
return hash_abcd;
}
[UnmanagedCallersOnly]
public static V128 Sha1SchedulePart1(V128 w0_3, V128 w4_7, V128 w8_11)
{
ulong t2 = w4_7.Extract<ulong>(0);
ulong t1 = w0_3.Extract<ulong>(1);
V128 result = new(t1, t2);
return result ^ (w0_3 ^ w8_11);
}
[UnmanagedCallersOnly]
public static V128 Sha1SchedulePart2(V128 tw0_3, V128 w12_15)
{
V128 t = tw0_3 ^ (w12_15 >> 32);
uint tE0 = t.Extract<uint>(0);
uint tE1 = t.Extract<uint>(1);
uint tE2 = t.Extract<uint>(2);
uint tE3 = t.Extract<uint>(3);
return new V128(tE0.Rol(1), tE1.Rol(1), tE2.Rol(1), tE3.Rol(1) ^ tE0.Rol(2));
}
private static void Rol32_160(ref uint y, ref V128 x)
{
uint xE3 = x.Extract<uint>(3);
x <<= 32;
x.Insert(0, y);
y = xE3;
}
private static uint ShaChoose(uint x, uint y, uint z)
{
return ((y ^ z) & x) ^ z;
}
private static uint ShaMajority(uint x, uint y, uint z)
{
return (x & y) | ((x | y) & z);
}
private static uint ShaParity(uint x, uint y, uint z)
{
return x ^ y ^ z;
}
private static uint Rol(this uint value, int count)
{
return (value << count) | (value >> (32 - count));
}
#endregion
#region "Sha256"
[UnmanagedCallersOnly]
public static V128 HashLower(V128 hash_abcd, V128 hash_efgh, V128 wk)
{
return Sha256Hash(hash_abcd, hash_efgh, wk, part1: true);
}
[UnmanagedCallersOnly]
public static V128 HashUpper(V128 hash_abcd, V128 hash_efgh, V128 wk)
{
return Sha256Hash(hash_abcd, hash_efgh, wk, part1: false);
}
[UnmanagedCallersOnly]
public static V128 Sha256SchedulePart1(V128 w0_3, V128 w4_7)
{
V128 result = new();
for (int e = 0; e <= 3; e++)
{
uint elt = (e <= 2 ? w0_3 : w4_7).Extract<uint>(e <= 2 ? e + 1 : 0);
elt = elt.Ror(7) ^ elt.Ror(18) ^ elt.Lsr(3);
elt += w0_3.Extract<uint>(e);
result.Insert(e, elt);
}
return result;
}
[UnmanagedCallersOnly]
public static V128 Sha256SchedulePart2(V128 w0_3, V128 w8_11, V128 w12_15)
{
V128 result = new();
ulong t1 = w12_15.Extract<ulong>(1);
for (int e = 0; e <= 1; e++)
{
uint elt = t1.ULongPart(e);
elt = elt.Ror(17) ^ elt.Ror(19) ^ elt.Lsr(10);
elt += w0_3.Extract<uint>(e) + w8_11.Extract<uint>(e + 1);
result.Insert(e, elt);
}
t1 = result.Extract<ulong>(0);
for (int e = 2; e <= 3; e++)
{
uint elt = t1.ULongPart(e - 2);
elt = elt.Ror(17) ^ elt.Ror(19) ^ elt.Lsr(10);
elt += w0_3.Extract<uint>(e) + (e == 2 ? w8_11 : w12_15).Extract<uint>(e == 2 ? 3 : 0);
result.Insert(e, elt);
}
return result;
}
private static V128 Sha256Hash(V128 x, V128 y, V128 w, bool part1)
{
for (int e = 0; e <= 3; e++)
{
uint chs = ShaChoose(y.Extract<uint>(0),
y.Extract<uint>(1),
y.Extract<uint>(2));
uint maj = ShaMajority(x.Extract<uint>(0),
x.Extract<uint>(1),
x.Extract<uint>(2));
uint t1 = y.Extract<uint>(3) + ShaHashSigma1(y.Extract<uint>(0)) + chs + w.Extract<uint>(e);
uint t2 = t1 + x.Extract<uint>(3);
x.Insert(3, t2);
t2 = t1 + ShaHashSigma0(x.Extract<uint>(0)) + maj;
y.Insert(3, t2);
Rol32_256(ref y, ref x);
}
return part1 ? x : y;
}
private static void Rol32_256(ref V128 y, ref V128 x)
{
uint yE3 = y.Extract<uint>(3);
uint xE3 = x.Extract<uint>(3);
y <<= 32;
x <<= 32;
y.Insert(0, xE3);
x.Insert(0, yE3);
}
private static uint ShaHashSigma0(uint x)
{
return x.Ror(2) ^ x.Ror(13) ^ x.Ror(22);
}
private static uint ShaHashSigma1(uint x)
{
return x.Ror(6) ^ x.Ror(11) ^ x.Ror(25);
}
private static uint Ror(this uint value, int count)
{
return (value >> count) | (value << (32 - count));
}
private static uint Lsr(this uint value, int count)
{
return value >> count;
}
private static uint ULongPart(this ulong value, int part)
{
return part == 0
? (uint)(value & 0xFFFFFFFFUL)
: (uint)(value >> 32);
}
#endregion
[UnmanagedCallersOnly]
public static V128 PolynomialMult64_128(ulong op1, ulong op2)
{
V128 result = V128.Zero;
V128 op2_128 = new(op2, 0);
for (int i = 0; i < 64; i++)
{
if (((op1 >> i) & 1) == 1)
{
result ^= op2_128 << i;
}
}
return result;
}
}
}

View File

@@ -0,0 +1,32 @@
using ARMeilleure.State;
using System.Runtime.InteropServices;
namespace ARMeilleure.Instructions
{
static partial class SoftFallback
{
[UnmanagedCallersOnly]
public static V128 Decrypt(V128 value, V128 roundKey)
{
return CryptoHelper.AesInvSubBytes(CryptoHelper.AesInvShiftRows(value ^ roundKey));
}
[UnmanagedCallersOnly]
public static V128 Encrypt(V128 value, V128 roundKey)
{
return CryptoHelper.AesSubBytes(CryptoHelper.AesShiftRows(value ^ roundKey));
}
[UnmanagedCallersOnly]
public static V128 InverseMixColumns(V128 value)
{
return CryptoHelper.AesInvMixColumns(value);
}
[UnmanagedCallersOnly]
public static V128 MixColumns(V128 value)
{
return CryptoHelper.AesMixColumns(value);
}
}
}

View File

@@ -0,0 +1,50 @@
using System;
using System.Runtime.InteropServices;
namespace ARMeilleure.Instructions
{
static partial class SoftFallback
{
[UnmanagedCallersOnly]
public static ulong CountLeadingSigns(ulong value, int size) // size is 8, 16, 32 or 64 (SIMD&FP or Base Inst.).
{
value ^= value >> 1;
int highBit = size - 2;
for (int bit = highBit; bit >= 0; bit--)
{
if (((int)(value >> bit) & 0b1) != 0)
{
return (ulong)(highBit - bit);
}
}
return (ulong)(size - 1);
}
private static ReadOnlySpan<byte> ClzNibbleTbl => [4, 3, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0];
[UnmanagedCallersOnly]
public static ulong CountLeadingZeros(ulong value, int size) // size is 8, 16, 32 or 64 (SIMD&FP or Base Inst.).
{
if (value == 0ul)
{
return (ulong)size;
}
int nibbleIdx = size;
int preCount, count = 0;
do
{
nibbleIdx -= 4;
preCount = ClzNibbleTbl[(int)(value >> nibbleIdx) & 0b1111];
count += preCount;
}
while (preCount == 4);
return (ulong)count;
}
}
}

View File

@@ -0,0 +1,74 @@
using System.Runtime.InteropServices;
namespace ARMeilleure.Instructions
{
static partial class SoftFallback
{
private const uint Crc32RevPoly = 0xedb88320;
private const uint Crc32cRevPoly = 0x82f63b78;
[UnmanagedCallersOnly]
public static uint Crc32b(uint crc, byte value) => Crc32(crc, Crc32RevPoly, value);
[UnmanagedCallersOnly]
public static uint Crc32h(uint crc, ushort value) => Crc32h(crc, Crc32RevPoly, value);
[UnmanagedCallersOnly]
public static uint Crc32w(uint crc, uint value) => Crc32w(crc, Crc32RevPoly, value);
[UnmanagedCallersOnly]
public static uint Crc32x(uint crc, ulong value) => Crc32x(crc, Crc32RevPoly, value);
[UnmanagedCallersOnly]
public static uint Crc32cb(uint crc, byte value) => Crc32(crc, Crc32cRevPoly, value);
[UnmanagedCallersOnly]
public static uint Crc32ch(uint crc, ushort value) => Crc32h(crc, Crc32cRevPoly, value);
[UnmanagedCallersOnly]
public static uint Crc32cw(uint crc, uint value) => Crc32w(crc, Crc32cRevPoly, value);
[UnmanagedCallersOnly]
public static uint Crc32cx(uint crc, ulong value) => Crc32x(crc, Crc32cRevPoly, value);
private static uint Crc32h(uint crc, uint poly, ushort val)
{
crc = Crc32(crc, poly, (byte)(val >> 0));
crc = Crc32(crc, poly, (byte)(val >> 8));
return crc;
}
private static uint Crc32w(uint crc, uint poly, uint val)
{
crc = Crc32(crc, poly, (byte)(val >> 0));
crc = Crc32(crc, poly, (byte)(val >> 8));
crc = Crc32(crc, poly, (byte)(val >> 16));
crc = Crc32(crc, poly, (byte)(val >> 24));
return crc;
}
private static uint Crc32x(uint crc, uint poly, ulong val)
{
crc = Crc32(crc, poly, (byte)(val >> 0));
crc = Crc32(crc, poly, (byte)(val >> 8));
crc = Crc32(crc, poly, (byte)(val >> 16));
crc = Crc32(crc, poly, (byte)(val >> 24));
crc = Crc32(crc, poly, (byte)(val >> 32));
crc = Crc32(crc, poly, (byte)(val >> 40));
crc = Crc32(crc, poly, (byte)(val >> 48));
crc = Crc32(crc, poly, (byte)(val >> 56));
return crc;
}
private static uint Crc32(uint crc, uint poly, byte val)
{
crc ^= val;
for (int bit = 7; bit >= 0; bit--)
{
uint mask = (uint)(-(int)(crc & 1));
crc = (crc >> 1) ^ (poly & mask);
}
return crc;
}
}
}

View File

@@ -0,0 +1,103 @@
using System.Runtime.InteropServices;
namespace ARMeilleure.Instructions
{
static partial class SoftFallback
{
[UnmanagedCallersOnly]
public static int SatF32ToS32(float value)
{
if (float.IsNaN(value))
{
return 0;
}
return value >= int.MaxValue ? int.MaxValue :
value <= int.MinValue ? int.MinValue : (int)value;
}
[UnmanagedCallersOnly]
public static long SatF32ToS64(float value)
{
if (float.IsNaN(value))
{
return 0;
}
return value >= long.MaxValue ? long.MaxValue :
value <= long.MinValue ? long.MinValue : (long)value;
}
[UnmanagedCallersOnly]
public static uint SatF32ToU32(float value)
{
if (float.IsNaN(value))
{
return 0;
}
return value >= uint.MaxValue ? uint.MaxValue :
value <= uint.MinValue ? uint.MinValue : (uint)value;
}
[UnmanagedCallersOnly]
public static ulong SatF32ToU64(float value)
{
if (float.IsNaN(value))
{
return 0;
}
return value >= ulong.MaxValue ? ulong.MaxValue :
value <= ulong.MinValue ? ulong.MinValue : (ulong)value;
}
[UnmanagedCallersOnly]
public static int SatF64ToS32(double value)
{
if (double.IsNaN(value))
{
return 0;
}
return value >= int.MaxValue ? int.MaxValue :
value <= int.MinValue ? int.MinValue : (int)value;
}
[UnmanagedCallersOnly]
public static long SatF64ToS64(double value)
{
if (double.IsNaN(value))
{
return 0;
}
return value >= long.MaxValue ? long.MaxValue :
value <= long.MinValue ? long.MinValue : (long)value;
}
[UnmanagedCallersOnly]
public static uint SatF64ToU32(double value)
{
if (double.IsNaN(value))
{
return 0;
}
return value >= uint.MaxValue ? uint.MaxValue :
value <= uint.MinValue ? uint.MinValue : (uint)value;
}
[UnmanagedCallersOnly]
public static ulong SatF64ToU64(double value)
{
if (double.IsNaN(value))
{
return 0;
}
return value >= ulong.MaxValue ? ulong.MaxValue :
value <= ulong.MinValue ? ulong.MinValue : (ulong)value;
}
}
}

View File

@@ -0,0 +1,131 @@
using ARMeilleure.State;
using System.Runtime.InteropServices;
namespace ARMeilleure.Instructions
{
static partial class SoftFallback
{
[UnmanagedCallersOnly]
public static V128 HashChoose(V128 hash_abcd, uint hash_e, V128 wk)
{
for (int e = 0; e <= 3; e++)
{
uint t = ShaChoose(hash_abcd.Extract<uint>(1),
hash_abcd.Extract<uint>(2),
hash_abcd.Extract<uint>(3));
hash_e += Rol(hash_abcd.Extract<uint>(0), 5) + t + wk.Extract<uint>(e);
t = Rol(hash_abcd.Extract<uint>(1), 30);
hash_abcd.Insert(1, t);
Rol32_160(ref hash_e, ref hash_abcd);
}
return hash_abcd;
}
[UnmanagedCallersOnly]
public static uint FixedRotate(uint hash_e)
{
return hash_e.Rol(30);
}
[UnmanagedCallersOnly]
public static V128 HashMajority(V128 hash_abcd, uint hash_e, V128 wk)
{
for (int e = 0; e <= 3; e++)
{
uint t = ShaMajority(hash_abcd.Extract<uint>(1),
hash_abcd.Extract<uint>(2),
hash_abcd.Extract<uint>(3));
hash_e += Rol(hash_abcd.Extract<uint>(0), 5) + t + wk.Extract<uint>(e);
t = Rol(hash_abcd.Extract<uint>(1), 30);
hash_abcd.Insert(1, t);
Rol32_160(ref hash_e, ref hash_abcd);
}
return hash_abcd;
}
[UnmanagedCallersOnly]
public static V128 HashParity(V128 hash_abcd, uint hash_e, V128 wk)
{
for (int e = 0; e <= 3; e++)
{
uint t = ShaParity(hash_abcd.Extract<uint>(1),
hash_abcd.Extract<uint>(2),
hash_abcd.Extract<uint>(3));
hash_e += Rol(hash_abcd.Extract<uint>(0), 5) + t + wk.Extract<uint>(e);
t = Rol(hash_abcd.Extract<uint>(1), 30);
hash_abcd.Insert(1, t);
Rol32_160(ref hash_e, ref hash_abcd);
}
return hash_abcd;
}
[UnmanagedCallersOnly]
public static V128 Sha1SchedulePart1(V128 w0_3, V128 w4_7, V128 w8_11)
{
ulong t2 = w4_7.Extract<ulong>(0);
ulong t1 = w0_3.Extract<ulong>(1);
V128 result = new(t1, t2);
return result ^ (w0_3 ^ w8_11);
}
[UnmanagedCallersOnly]
public static V128 Sha1SchedulePart2(V128 tw0_3, V128 w12_15)
{
V128 t = tw0_3 ^ (w12_15 >> 32);
uint tE0 = t.Extract<uint>(0);
uint tE1 = t.Extract<uint>(1);
uint tE2 = t.Extract<uint>(2);
uint tE3 = t.Extract<uint>(3);
return new V128(tE0.Rol(1), tE1.Rol(1), tE2.Rol(1), tE3.Rol(1) ^ tE0.Rol(2));
}
private static void Rol32_160(ref uint y, ref V128 x)
{
uint xE3 = x.Extract<uint>(3);
x <<= 32;
x.Insert(0, y);
y = xE3;
}
private static uint ShaChoose(uint x, uint y, uint z)
{
return ((y ^ z) & x) ^ z;
}
private static uint ShaMajority(uint x, uint y, uint z)
{
return (x & y) | ((x | y) & z);
}
private static uint ShaParity(uint x, uint y, uint z)
{
return x ^ y ^ z;
}
private static uint Rol(this uint value, int count)
{
return (value << count) | (value >> (32 - count));
}
}
}

View File

@@ -0,0 +1,140 @@
using ARMeilleure.State;
using System.Runtime.InteropServices;
namespace ARMeilleure.Instructions
{
static partial class SoftFallback
{
[UnmanagedCallersOnly]
public static V128 HashLower(V128 hash_abcd, V128 hash_efgh, V128 wk)
{
return Sha256Hash(hash_abcd, hash_efgh, wk, part1: true);
}
[UnmanagedCallersOnly]
public static V128 HashUpper(V128 hash_abcd, V128 hash_efgh, V128 wk)
{
return Sha256Hash(hash_abcd, hash_efgh, wk, part1: false);
}
[UnmanagedCallersOnly]
public static V128 Sha256SchedulePart1(V128 w0_3, V128 w4_7)
{
V128 result = new();
for (int e = 0; e <= 3; e++)
{
uint elt = (e <= 2 ? w0_3 : w4_7).Extract<uint>(e <= 2 ? e + 1 : 0);
elt = elt.Ror(7) ^ elt.Ror(18) ^ elt.Lsr(3);
elt += w0_3.Extract<uint>(e);
result.Insert(e, elt);
}
return result;
}
[UnmanagedCallersOnly]
public static V128 Sha256SchedulePart2(V128 w0_3, V128 w8_11, V128 w12_15)
{
V128 result = new();
ulong t1 = w12_15.Extract<ulong>(1);
for (int e = 0; e <= 1; e++)
{
uint elt = t1.ULongPart(e);
elt = elt.Ror(17) ^ elt.Ror(19) ^ elt.Lsr(10);
elt += w0_3.Extract<uint>(e) + w8_11.Extract<uint>(e + 1);
result.Insert(e, elt);
}
t1 = result.Extract<ulong>(0);
for (int e = 2; e <= 3; e++)
{
uint elt = t1.ULongPart(e - 2);
elt = elt.Ror(17) ^ elt.Ror(19) ^ elt.Lsr(10);
elt += w0_3.Extract<uint>(e) + (e == 2 ? w8_11 : w12_15).Extract<uint>(e == 2 ? 3 : 0);
result.Insert(e, elt);
}
return result;
}
private static V128 Sha256Hash(V128 x, V128 y, V128 w, bool part1)
{
for (int e = 0; e <= 3; e++)
{
uint chs = ShaChoose(y.Extract<uint>(0),
y.Extract<uint>(1),
y.Extract<uint>(2));
uint maj = ShaMajority(x.Extract<uint>(0),
x.Extract<uint>(1),
x.Extract<uint>(2));
uint t1 = y.Extract<uint>(3) + ShaHashSigma1(y.Extract<uint>(0)) + chs + w.Extract<uint>(e);
uint t2 = t1 + x.Extract<uint>(3);
x.Insert(3, t2);
t2 = t1 + ShaHashSigma0(x.Extract<uint>(0)) + maj;
y.Insert(3, t2);
Rol32_256(ref y, ref x);
}
return part1 ? x : y;
}
private static void Rol32_256(ref V128 y, ref V128 x)
{
uint yE3 = y.Extract<uint>(3);
uint xE3 = x.Extract<uint>(3);
y <<= 32;
x <<= 32;
y.Insert(0, xE3);
x.Insert(0, yE3);
}
private static uint ShaHashSigma0(uint x)
{
return x.Ror(2) ^ x.Ror(13) ^ x.Ror(22);
}
private static uint ShaHashSigma1(uint x)
{
return x.Ror(6) ^ x.Ror(11) ^ x.Ror(25);
}
private static uint Ror(this uint value, int count)
{
return (value >> count) | (value << (32 - count));
}
private static uint Lsr(this uint value, int count)
{
return value >> count;
}
private static uint ULongPart(this ulong value, int part)
{
return part == 0
? (uint)(value & 0xFFFFFFFFUL)
: (uint)(value >> 32);
}
}
}

View File

@@ -0,0 +1,93 @@
using System.Runtime.InteropServices;
namespace ARMeilleure.Instructions
{
static partial class SoftFallback
{
[UnmanagedCallersOnly]
public static long SignedShrImm64(long value, long roundConst, int shift)
{
if (roundConst == 0L)
{
if (shift <= 63)
{
return value >> shift;
}
else /* if (shift == 64) */
{
if (value < 0L)
{
return -1L;
}
else /* if (value >= 0L) */
{
return 0L;
}
}
}
else /* if (roundConst == 1L << (shift - 1)) */
{
if (shift <= 63)
{
long add = value + roundConst;
if ((~value & (value ^ add)) < 0L)
{
return (long)((ulong)add >> shift);
}
else
{
return add >> shift;
}
}
else /* if (shift == 64) */
{
return 0L;
}
}
}
[UnmanagedCallersOnly]
public static ulong UnsignedShrImm64(ulong value, long roundConst, int shift)
{
if (roundConst == 0L)
{
if (shift <= 63)
{
return value >> shift;
}
else /* if (shift == 64) */
{
return 0UL;
}
}
else /* if (roundConst == 1L << (shift - 1)) */
{
ulong add = value + (ulong)roundConst;
if ((add < value) && (add < (ulong)roundConst))
{
if (shift <= 63)
{
return (add >> shift) | (0x8000000000000000UL >> (shift - 1));
}
else /* if (shift == 64) */
{
return 1UL;
}
}
else
{
if (shift <= 63)
{
return add >> shift;
}
else /* if (shift == 64) */
{
return 0UL;
}
}
}
}
}
}

View File

@@ -0,0 +1,88 @@
using ARMeilleure.State;
using System;
using System.Runtime.InteropServices;
namespace ARMeilleure.Instructions
{
static partial class SoftFallback
{
[UnmanagedCallersOnly]
public static V128 Tbl1(V128 vector, int bytes, V128 tb0)
{
return TblOrTbx(default, vector, bytes, tb0);
}
[UnmanagedCallersOnly]
public static V128 Tbl2(V128 vector, int bytes, V128 tb0, V128 tb1)
{
return TblOrTbx(default, vector, bytes, tb0, tb1);
}
[UnmanagedCallersOnly]
public static V128 Tbl3(V128 vector, int bytes, V128 tb0, V128 tb1, V128 tb2)
{
return TblOrTbx(default, vector, bytes, tb0, tb1, tb2);
}
[UnmanagedCallersOnly]
public static V128 Tbl4(V128 vector, int bytes, V128 tb0, V128 tb1, V128 tb2, V128 tb3)
{
return TblOrTbx(default, vector, bytes, tb0, tb1, tb2, tb3);
}
[UnmanagedCallersOnly]
public static V128 Tbx1(V128 dest, V128 vector, int bytes, V128 tb0)
{
return TblOrTbx(dest, vector, bytes, tb0);
}
[UnmanagedCallersOnly]
public static V128 Tbx2(V128 dest, V128 vector, int bytes, V128 tb0, V128 tb1)
{
return TblOrTbx(dest, vector, bytes, tb0, tb1);
}
[UnmanagedCallersOnly]
public static V128 Tbx3(V128 dest, V128 vector, int bytes, V128 tb0, V128 tb1, V128 tb2)
{
return TblOrTbx(dest, vector, bytes, tb0, tb1, tb2);
}
[UnmanagedCallersOnly]
public static V128 Tbx4(V128 dest, V128 vector, int bytes, V128 tb0, V128 tb1, V128 tb2, V128 tb3)
{
return TblOrTbx(dest, vector, bytes, tb0, tb1, tb2, tb3);
}
private static V128 TblOrTbx(V128 dest, V128 vector, int bytes, params ReadOnlySpan<V128> tb)
{
byte[] res = new byte[16];
if (dest != default)
{
Buffer.BlockCopy(dest.ToArray(), 0, res, 0, bytes);
}
byte[] table = new byte[tb.Length * 16];
for (byte index = 0; index < tb.Length; index++)
{
Buffer.BlockCopy(tb[index].ToArray(), 0, table, index * 16, 16);
}
byte[] v = vector.ToArray();
for (byte index = 0; index < bytes; index++)
{
byte tblIndex = v[index];
if (tblIndex < table.Length)
{
res[index] = table[tblIndex];
}
}
return new V128(res);
}
}
}

View File

@@ -0,0 +1,26 @@
using ARMeilleure.State;
using System.Runtime.InteropServices;
namespace ARMeilleure.Instructions
{
static partial class SoftFallback
{
[UnmanagedCallersOnly]
public static V128 PolynomialMult64_128(ulong op1, ulong op2)
{
V128 result = V128.Zero;
V128 op2_128 = new(op2, 0);
for (int i = 0; i < 64; i++)
{
if (((op1 >> i) & 1) == 1)
{
result ^= op2_128 << i;
}
}
return result;
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,111 @@
using ARMeilleure.State;
using System;
using System.Diagnostics;
namespace ARMeilleure.Instructions
{
static class SoftFloat
{
static SoftFloat()
{
RecipEstimateTable = BuildRecipEstimateTable();
RecipSqrtEstimateTable = BuildRecipSqrtEstimateTable();
}
public static readonly byte[] RecipEstimateTable;
public static readonly byte[] RecipSqrtEstimateTable;
private static byte[] BuildRecipEstimateTable()
{
byte[] tbl = new byte[256];
for (int idx = 0; idx < 256; idx++)
{
uint src = (uint)idx + 256u;
Debug.Assert(src is >= 256u and < 512u);
src = (src << 1) + 1u;
uint aux = (1u << 19) / src;
uint dst = (aux + 1u) >> 1;
Debug.Assert(dst is >= 256u and < 512u);
tbl[idx] = (byte)(dst - 256u);
}
return tbl;
}
private static byte[] BuildRecipSqrtEstimateTable()
{
byte[] tbl = new byte[384];
for (int idx = 0; idx < 384; idx++)
{
uint src = (uint)idx + 128u;
Debug.Assert(src is >= 128u and < 512u);
if (src < 256u)
{
src = (src << 1) + 1u;
}
else
{
src = (src >> 1) << 1;
src = (src + 1u) << 1;
}
uint aux = 512u;
while (src * (aux + 1u) * (aux + 1u) < (1u << 28))
{
aux++;
}
uint dst = (aux + 1u) >> 1;
Debug.Assert(dst is >= 256u and < 512u);
tbl[idx] = (byte)(dst - 256u);
}
return tbl;
}
public static void FPProcessException(FPException exc, ExecutionContext context)
{
FPProcessException(exc, context, context.Fpcr);
}
public static void FPProcessException(FPException exc, ExecutionContext context, FPCR fpcr)
{
int enable = (int)exc + 8;
if ((fpcr & (FPCR)(1 << enable)) != 0)
{
throw new NotImplementedException("Floating-point trap handling.");
}
else
{
context.Fpsr |= (FPSR)(1 << (int)exc);
}
}
extension(FPCR fpcr)
{
public FPRoundingMode RoundingMode
{
get
{
const int RModeShift = 22;
return (FPRoundingMode)(((uint)fpcr >> RModeShift) & 3u);
}
}
}
}
}

View File

@@ -0,0 +1,212 @@
using ARMeilleure.State;
using System;
namespace ARMeilleure.Instructions
{
static class SoftFloat16
{
public static ushort FPDefaultNaN()
{
return (ushort)0x7E00u;
}
public static ushort FPInfinity(bool sign)
{
return sign ? (ushort)0xFC00u : (ushort)0x7C00u;
}
public static ushort FPZero(bool sign)
{
return sign ? (ushort)0x8000u : (ushort)0x0000u;
}
public static ushort FPMaxNormal(bool sign)
{
return sign ? (ushort)0xFBFFu : (ushort)0x7BFFu;
}
public static double FPUnpackCv(
this ushort valueBits,
out FPType type,
out bool sign,
ExecutionContext context)
{
sign = (~(uint)valueBits & 0x8000u) == 0u;
uint exp16 = ((uint)valueBits & 0x7C00u) >> 10;
uint frac16 = (uint)valueBits & 0x03FFu;
double real;
if (exp16 == 0u)
{
if (frac16 == 0u)
{
type = FPType.Zero;
real = 0d;
}
else
{
type = FPType.Nonzero; // Subnormal.
real = Math.Pow(2d, -14) * ((double)frac16 * Math.Pow(2d, -10));
}
}
else if (exp16 == 0x1Fu && (context.Fpcr & FPCR.Ahp) == 0)
{
if (frac16 == 0u)
{
type = FPType.Infinity;
real = Math.Pow(2d, 1000);
}
else
{
type = (~frac16 & 0x0200u) == 0u ? FPType.QNaN : FPType.SNaN;
real = 0d;
}
}
else
{
type = FPType.Nonzero; // Normal.
real = Math.Pow(2d, (int)exp16 - 15) * (1d + (double)frac16 * Math.Pow(2d, -10));
}
return sign ? -real : real;
}
public static ushort FPRoundCv(double real, ExecutionContext context)
{
const int MinimumExp = -14;
const int E = 5;
const int F = 10;
bool sign;
double mantissa;
if (real < 0d)
{
sign = true;
mantissa = -real;
}
else
{
sign = false;
mantissa = real;
}
int exponent = 0;
while (mantissa < 1d)
{
mantissa *= 2d;
exponent--;
}
while (mantissa >= 2d)
{
mantissa /= 2d;
exponent++;
}
uint biasedExp = (uint)Math.Max(exponent - MinimumExp + 1, 0);
if (biasedExp == 0u)
{
mantissa /= Math.Pow(2d, MinimumExp - exponent);
}
uint intMant = (uint)Math.Floor(mantissa * Math.Pow(2d, F));
double error = mantissa * Math.Pow(2d, F) - (double)intMant;
if (biasedExp == 0u && (error != 0d || (context.Fpcr & FPCR.Ufe) != 0))
{
SoftFloat.FPProcessException(FPException.Underflow, context);
}
bool overflowToInf;
bool roundUp;
switch (context.Fpcr.RoundingMode)
{
case FPRoundingMode.ToNearest:
roundUp = (error > 0.5d || (error == 0.5d && (intMant & 1u) == 1u));
overflowToInf = true;
break;
case FPRoundingMode.TowardsPlusInfinity:
roundUp = (error != 0d && !sign);
overflowToInf = !sign;
break;
case FPRoundingMode.TowardsMinusInfinity:
roundUp = (error != 0d && sign);
overflowToInf = sign;
break;
case FPRoundingMode.TowardsZero:
roundUp = false;
overflowToInf = false;
break;
default:
throw new ArgumentException($"Invalid rounding mode \"{context.Fpcr.RoundingMode}\".");
}
if (roundUp)
{
intMant++;
if (intMant == 1u << F)
{
biasedExp = 1u;
}
if (intMant == 1u << (F + 1))
{
biasedExp++;
intMant >>= 1;
}
}
ushort resultBits;
if ((context.Fpcr & FPCR.Ahp) == 0)
{
if (biasedExp >= (1u << E) - 1u)
{
resultBits = overflowToInf ? FPInfinity(sign) : FPMaxNormal(sign);
SoftFloat.FPProcessException(FPException.Overflow, context);
error = 1d;
}
else
{
resultBits = (ushort)((sign ? 1u : 0u) << 15 | (biasedExp & 0x1Fu) << 10 | (intMant & 0x03FFu));
}
}
else
{
if (biasedExp >= 1u << E)
{
resultBits = (ushort)((sign ? 1u : 0u) << 15 | 0x7FFFu);
SoftFloat.FPProcessException(FPException.InvalidOp, context);
error = 0d;
}
else
{
resultBits = (ushort)((sign ? 1u : 0u) << 15 | (biasedExp & 0x1Fu) << 10 | (intMant & 0x03FFu));
}
}
if (error != 0d)
{
SoftFloat.FPProcessException(FPException.Inexact, context);
}
return resultBits;
}
}
}

View File

@@ -0,0 +1,182 @@
using ARMeilleure.State;
using System;
using System.Runtime.InteropServices;
namespace ARMeilleure.Instructions
{
static class SoftFloat16_32
{
[UnmanagedCallersOnly]
public static float FPConvert(ushort valueBits)
{
ExecutionContext context = NativeInterface.GetContext();
double real = valueBits.FPUnpackCv(out FPType type, out bool sign, context);
float result;
if (type is FPType.SNaN or FPType.QNaN)
{
if ((context.Fpcr & FPCR.Dn) != 0)
{
result = SoftFloat32.FPDefaultNaN();
}
else
{
result = FPConvertNaN(valueBits);
}
if (type == FPType.SNaN)
{
SoftFloat.FPProcessException(FPException.InvalidOp, context);
}
}
else if (type == FPType.Infinity)
{
result = SoftFloat32.FPInfinity(sign);
}
else if (type == FPType.Zero)
{
result = SoftFloat32.FPZero(sign);
}
else
{
result = FPRoundCv(real, context);
}
return result;
}
private static float FPRoundCv(double real, ExecutionContext context)
{
const int MinimumExp = -126;
const int E = 8;
const int F = 23;
bool sign;
double mantissa;
if (real < 0d)
{
sign = true;
mantissa = -real;
}
else
{
sign = false;
mantissa = real;
}
int exponent = 0;
while (mantissa < 1d)
{
mantissa *= 2d;
exponent--;
}
while (mantissa >= 2d)
{
mantissa /= 2d;
exponent++;
}
if ((context.Fpcr & FPCR.Fz) != 0 && exponent < MinimumExp)
{
context.Fpsr |= FPSR.Ufc;
return SoftFloat32.FPZero(sign);
}
uint biasedExp = (uint)Math.Max(exponent - MinimumExp + 1, 0);
if (biasedExp == 0u)
{
mantissa /= Math.Pow(2d, MinimumExp - exponent);
}
uint intMant = (uint)Math.Floor(mantissa * Math.Pow(2d, F));
double error = mantissa * Math.Pow(2d, F) - (double)intMant;
if (biasedExp == 0u && (error != 0d || (context.Fpcr & FPCR.Ufe) != 0))
{
SoftFloat.FPProcessException(FPException.Underflow, context);
}
bool overflowToInf;
bool roundUp;
switch (context.Fpcr.RoundingMode)
{
case FPRoundingMode.ToNearest:
roundUp = (error > 0.5d || (error == 0.5d && (intMant & 1u) == 1u));
overflowToInf = true;
break;
case FPRoundingMode.TowardsPlusInfinity:
roundUp = (error != 0d && !sign);
overflowToInf = !sign;
break;
case FPRoundingMode.TowardsMinusInfinity:
roundUp = (error != 0d && sign);
overflowToInf = sign;
break;
case FPRoundingMode.TowardsZero:
roundUp = false;
overflowToInf = false;
break;
default:
throw new ArgumentException($"Invalid rounding mode \"{context.Fpcr.RoundingMode}\".");
}
if (roundUp)
{
intMant++;
if (intMant == 1u << F)
{
biasedExp = 1u;
}
if (intMant == 1u << (F + 1))
{
biasedExp++;
intMant >>= 1;
}
}
float result;
if (biasedExp >= (1u << E) - 1u)
{
result = overflowToInf ? SoftFloat32.FPInfinity(sign) : SoftFloat32.FPMaxNormal(sign);
SoftFloat.FPProcessException(FPException.Overflow, context);
error = 1d;
}
else
{
result = BitConverter.Int32BitsToSingle(
(int)((sign ? 1u : 0u) << 31 | (biasedExp & 0xFFu) << 23 | (intMant & 0x007FFFFFu)));
}
if (error != 0d)
{
SoftFloat.FPProcessException(FPException.Inexact, context);
}
return result;
}
private static float FPConvertNaN(ushort valueBits)
{
return BitConverter.Int32BitsToSingle(
(int)(((uint)valueBits & 0x8000u) << 16 | 0x7FC00000u | ((uint)valueBits & 0x01FFu) << 13));
}
}
}

View File

@@ -0,0 +1,182 @@
using ARMeilleure.State;
using System;
using System.Runtime.InteropServices;
namespace ARMeilleure.Instructions
{
static class SoftFloat16_64
{
[UnmanagedCallersOnly]
public static double FPConvert(ushort valueBits)
{
ExecutionContext context = NativeInterface.GetContext();
double real = valueBits.FPUnpackCv(out FPType type, out bool sign, context);
double result;
if (type is FPType.SNaN or FPType.QNaN)
{
if ((context.Fpcr & FPCR.Dn) != 0)
{
result = SoftFloat64.FPDefaultNaN();
}
else
{
result = FPConvertNaN(valueBits);
}
if (type == FPType.SNaN)
{
SoftFloat.FPProcessException(FPException.InvalidOp, context);
}
}
else if (type == FPType.Infinity)
{
result = SoftFloat64.FPInfinity(sign);
}
else if (type == FPType.Zero)
{
result = SoftFloat64.FPZero(sign);
}
else
{
result = FPRoundCv(real, context);
}
return result;
}
private static double FPRoundCv(double real, ExecutionContext context)
{
const int MinimumExp = -1022;
const int E = 11;
const int F = 52;
bool sign;
double mantissa;
if (real < 0d)
{
sign = true;
mantissa = -real;
}
else
{
sign = false;
mantissa = real;
}
int exponent = 0;
while (mantissa < 1d)
{
mantissa *= 2d;
exponent--;
}
while (mantissa >= 2d)
{
mantissa /= 2d;
exponent++;
}
if ((context.Fpcr & FPCR.Fz) != 0 && exponent < MinimumExp)
{
context.Fpsr |= FPSR.Ufc;
return SoftFloat64.FPZero(sign);
}
uint biasedExp = (uint)Math.Max(exponent - MinimumExp + 1, 0);
if (biasedExp == 0u)
{
mantissa /= Math.Pow(2d, MinimumExp - exponent);
}
ulong intMant = (ulong)Math.Floor(mantissa * Math.Pow(2d, F));
double error = mantissa * Math.Pow(2d, F) - (double)intMant;
if (biasedExp == 0u && (error != 0d || (context.Fpcr & FPCR.Ufe) != 0))
{
SoftFloat.FPProcessException(FPException.Underflow, context);
}
bool overflowToInf;
bool roundUp;
switch (context.Fpcr.RoundingMode)
{
case FPRoundingMode.ToNearest:
roundUp = (error > 0.5d || (error == 0.5d && (intMant & 1u) == 1u));
overflowToInf = true;
break;
case FPRoundingMode.TowardsPlusInfinity:
roundUp = (error != 0d && !sign);
overflowToInf = !sign;
break;
case FPRoundingMode.TowardsMinusInfinity:
roundUp = (error != 0d && sign);
overflowToInf = sign;
break;
case FPRoundingMode.TowardsZero:
roundUp = false;
overflowToInf = false;
break;
default:
throw new ArgumentException($"Invalid rounding mode \"{context.Fpcr.RoundingMode}\".");
}
if (roundUp)
{
intMant++;
if (intMant == 1ul << F)
{
biasedExp = 1u;
}
if (intMant == 1ul << (F + 1))
{
biasedExp++;
intMant >>= 1;
}
}
double result;
if (biasedExp >= (1u << E) - 1u)
{
result = overflowToInf ? SoftFloat64.FPInfinity(sign) : SoftFloat64.FPMaxNormal(sign);
SoftFloat.FPProcessException(FPException.Overflow, context);
error = 1d;
}
else
{
result = BitConverter.Int64BitsToDouble(
(long)((sign ? 1ul : 0ul) << 63 | (biasedExp & 0x7FFul) << 52 | (intMant & 0x000FFFFFFFFFFFFFul)));
}
if (error != 0d)
{
SoftFloat.FPProcessException(FPException.Inexact, context);
}
return result;
}
private static double FPConvertNaN(ushort valueBits)
{
return BitConverter.Int64BitsToDouble(
(long)(((ulong)valueBits & 0x8000ul) << 48 | 0x7FF8000000000000ul | ((ulong)valueBits & 0x01FFul) << 42));
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,126 @@
using ARMeilleure.State;
using System;
using System.Runtime.InteropServices;
namespace ARMeilleure.Instructions
{
static class SoftFloat32_16
{
[UnmanagedCallersOnly]
public static ushort FPConvert(float value)
{
ExecutionContext context = NativeInterface.GetContext();
double real = value.FPUnpackCv(out FPType type, out bool sign, out uint valueBits, context);
bool altHp = (context.Fpcr & FPCR.Ahp) != 0;
ushort resultBits;
if (type is FPType.SNaN or FPType.QNaN)
{
if (altHp)
{
resultBits = SoftFloat16.FPZero(sign);
}
else if ((context.Fpcr & FPCR.Dn) != 0)
{
resultBits = SoftFloat16.FPDefaultNaN();
}
else
{
resultBits = FPConvertNaN(valueBits);
}
if (type == FPType.SNaN || altHp)
{
SoftFloat.FPProcessException(FPException.InvalidOp, context);
}
}
else if (type == FPType.Infinity)
{
if (altHp)
{
resultBits = (ushort)((sign ? 1u : 0u) << 15 | 0x7FFFu);
SoftFloat.FPProcessException(FPException.InvalidOp, context);
}
else
{
resultBits = SoftFloat16.FPInfinity(sign);
}
}
else if (type == FPType.Zero)
{
resultBits = SoftFloat16.FPZero(sign);
}
else
{
resultBits = SoftFloat16.FPRoundCv(real, context);
}
return resultBits;
}
private static double FPUnpackCv(
this float value,
out FPType type,
out bool sign,
out uint valueBits,
ExecutionContext context)
{
valueBits = (uint)BitConverter.SingleToInt32Bits(value);
sign = (~valueBits & 0x80000000u) == 0u;
uint exp32 = (valueBits & 0x7F800000u) >> 23;
uint frac32 = valueBits & 0x007FFFFFu;
double real;
if (exp32 == 0u)
{
if (frac32 == 0u || (context.Fpcr & FPCR.Fz) != 0)
{
type = FPType.Zero;
real = 0d;
if (frac32 != 0u)
{
SoftFloat.FPProcessException(FPException.InputDenorm, context);
}
}
else
{
type = FPType.Nonzero; // Subnormal.
real = Math.Pow(2d, -126) * ((double)frac32 * Math.Pow(2d, -23));
}
}
else if (exp32 == 0xFFu)
{
if (frac32 == 0u)
{
type = FPType.Infinity;
real = Math.Pow(2d, 1000);
}
else
{
type = (~frac32 & 0x00400000u) == 0u ? FPType.QNaN : FPType.SNaN;
real = 0d;
}
}
else
{
type = FPType.Nonzero; // Normal.
real = Math.Pow(2d, (int)exp32 - 127) * (1d + (double)frac32 * Math.Pow(2d, -23));
}
return sign ? -real : real;
}
private static ushort FPConvertNaN(uint valueBits)
{
return (ushort)((valueBits & 0x80000000u) >> 16 | 0x7E00u | (valueBits & 0x003FE000u) >> 13);
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,127 @@
using ARMeilleure.State;
using System;
using System.Runtime.InteropServices;
namespace ARMeilleure.Instructions
{
static class SoftFloat64_16
{
[UnmanagedCallersOnly]
public static ushort FPConvert(double value)
{
ExecutionContext context = NativeInterface.GetContext();
double real = value.FPUnpackCv(out FPType type, out bool sign, out ulong valueBits, context);
bool altHp = (context.Fpcr & FPCR.Ahp) != 0;
ushort resultBits;
if (type is FPType.SNaN or FPType.QNaN)
{
if (altHp)
{
resultBits = SoftFloat16.FPZero(sign);
}
else if ((context.Fpcr & FPCR.Dn) != 0)
{
resultBits = SoftFloat16.FPDefaultNaN();
}
else
{
resultBits = FPConvertNaN(valueBits);
}
if (type == FPType.SNaN || altHp)
{
SoftFloat.FPProcessException(FPException.InvalidOp, context);
}
}
else if (type == FPType.Infinity)
{
if (altHp)
{
resultBits = (ushort)((sign ? 1u : 0u) << 15 | 0x7FFFu);
SoftFloat.FPProcessException(FPException.InvalidOp, context);
}
else
{
resultBits = SoftFloat16.FPInfinity(sign);
}
}
else if (type == FPType.Zero)
{
resultBits = SoftFloat16.FPZero(sign);
}
else
{
resultBits = SoftFloat16.FPRoundCv(real, context);
}
return resultBits;
}
private static double FPUnpackCv(
this double value,
out FPType type,
out bool sign,
out ulong valueBits,
ExecutionContext context)
{
valueBits = (ulong)BitConverter.DoubleToInt64Bits(value);
sign = (~valueBits & 0x8000000000000000ul) == 0u;
ulong exp64 = (valueBits & 0x7FF0000000000000ul) >> 52;
ulong frac64 = valueBits & 0x000FFFFFFFFFFFFFul;
double real;
if (exp64 == 0u)
{
if (frac64 == 0u || (context.Fpcr & FPCR.Fz) != 0)
{
type = FPType.Zero;
real = 0d;
if (frac64 != 0u)
{
SoftFloat.FPProcessException(FPException.InputDenorm, context);
}
}
else
{
type = FPType.Nonzero; // Subnormal.
real = Math.Pow(2d, -1022) * ((double)frac64 * Math.Pow(2d, -52));
}
}
else if (exp64 == 0x7FFul)
{
if (frac64 == 0u)
{
type = FPType.Infinity;
real = Math.Pow(2d, 1000000);
}
else
{
type = (~frac64 & 0x0008000000000000ul) == 0u ? FPType.QNaN : FPType.SNaN;
real = 0d;
}
}
else
{
type = FPType.Nonzero; // Normal.
real = Math.Pow(2d, (int)exp64 - 1023) * (1d + (double)frac64 * Math.Pow(2d, -52));
}
return sign ? -real : real;
}
private static ushort FPConvertNaN(ulong valueBits)
{
return (ushort)((valueBits & 0x8000000000000000ul) >> 48 | 0x7E00u |
(valueBits & 0x0007FC0000000000ul) >> 42);
}
}
}

View File

@@ -16,9 +16,9 @@ namespace ARMeilleure.IntermediateRepresentation
static class ComparisonExtensions
{
public static Comparison Invert(this Comparison comp)
extension(Comparison comparison)
{
return (Comparison)((int)comp ^ 1);
public Comparison Inverse => (Comparison)((int)comparison ^ 1);
}
}
}

View File

@@ -14,48 +14,38 @@ namespace ARMeilleure.IntermediateRepresentation
static class OperandTypeExtensions
{
public static bool IsInteger(this OperandType type)
extension(OperandType type)
{
return type is OperandType.I32 or
OperandType.I64;
}
public bool IsInteger => type is OperandType.I32 or OperandType.I64;
public static RegisterType ToRegisterType(this OperandType type)
{
return type switch
public RegisterType Register => type switch
{
OperandType.FP32 => RegisterType.Vector,
OperandType.FP64 => RegisterType.Vector,
OperandType.I32 => RegisterType.Integer,
OperandType.I64 => RegisterType.Integer,
OperandType.V128 => RegisterType.Vector,
_ => throw new InvalidOperationException($"Invalid operand type \"{type}\"."),
_ => throw new InvalidOperationException($"Invalid operand type \"{type}\".")
};
}
public static int GetSizeInBytes(this OperandType type)
{
return type switch
public int ByteSize => type switch
{
OperandType.FP32 => 4,
OperandType.FP64 => 8,
OperandType.I32 => 4,
OperandType.I64 => 8,
OperandType.V128 => 16,
_ => throw new InvalidOperationException($"Invalid operand type \"{type}\"."),
_ => throw new InvalidOperationException($"Invalid operand type \"{type}\".")
};
}
public static int GetSizeInBytesLog2(this OperandType type)
{
return type switch
public int ByteSizeLog2 => type switch
{
OperandType.FP32 => 2,
OperandType.FP64 => 3,
OperandType.I32 => 2,
OperandType.I64 => 3,
OperandType.V128 => 4,
_ => throw new InvalidOperationException($"Invalid operand type \"{type}\"."),
_ => throw new InvalidOperationException($"Invalid operand type \"{type}\".")
};
}
}

View File

@@ -45,19 +45,12 @@ namespace ARMeilleure.Memory
public static class MemoryManagerTypeExtensions
{
public static bool IsHostMapped(this MemoryManagerType type)
extension(MemoryManagerType type)
{
return type is MemoryManagerType.HostMapped or MemoryManagerType.HostMappedUnsafe;
}
public bool IsHostMapped => type is MemoryManagerType.HostMapped or MemoryManagerType.HostMappedUnsafe;
public bool IsHostTracked => type is MemoryManagerType.HostTracked or MemoryManagerType.HostTrackedUnsafe;
public static bool IsHostTracked(this MemoryManagerType type)
{
return type is MemoryManagerType.HostTracked or MemoryManagerType.HostTrackedUnsafe;
}
public static bool IsHostMappedOrTracked(this MemoryManagerType type)
{
return type.IsHostMapped() || type.IsHostTracked();
public bool IsHostMappedOrTracked => type.IsHostMapped || type.IsHostTracked;
}
}
}

View File

@@ -412,7 +412,7 @@ namespace ARMeilleure.Translation
{
context.SyncQcFlag();
if (block.Branch != null && !block.Branch.Exit && block.Branch.Address <= block.Address)
if (block.Branch is { Exit: false } && block.Branch.Address <= block.Address)
{
EmitSynchronization(context);
}
@@ -429,14 +429,14 @@ namespace ARMeilleure.Translation
{
lblPredicateSkip = Label();
InstEmitFlowHelper.EmitCondBranch(context, lblPredicateSkip, context.CurrentIfThenBlockCond.Invert());
InstEmitFlowHelper.EmitCondBranch(context, lblPredicateSkip, context.CurrentIfThenBlockCond.Inverse);
}
if (opCode is OpCode32 op && op.Cond < Condition.Al)
if (opCode is OpCode32 { Cond: < Condition.Al } op)
{
lblPredicateSkip = Label();
InstEmitFlowHelper.EmitCondBranch(context, lblPredicateSkip, op.Cond.Invert());
InstEmitFlowHelper.EmitCondBranch(context, lblPredicateSkip, op.Cond.Inverse);
}
if (opCode.Instruction.Emitter != null)

View File

@@ -58,16 +58,16 @@ namespace Ryujinx.Audio.Backends.CompatLayer
switch (realSampleFormat)
{
case SampleFormat.PcmInt8:
PcmHelper.ConvertSampleToPcm8(MemoryMarshal.Cast<byte, sbyte>(convertedSamples), samples);
PcmHelper.ConvertSampleToPcm8(MemoryMarshal.Cast<byte, sbyte>(new Span<byte>(convertedSamples)), samples);
break;
case SampleFormat.PcmInt24:
PcmHelper.ConvertSampleToPcm24(convertedSamples, samples);
break;
case SampleFormat.PcmInt32:
PcmHelper.ConvertSampleToPcm32(MemoryMarshal.Cast<byte, int>(convertedSamples), samples);
PcmHelper.ConvertSampleToPcm32(MemoryMarshal.Cast<byte, int>(new Span<byte>(convertedSamples)), samples);
break;
case SampleFormat.PcmFloat:
PcmHelper.ConvertSampleToPcmFloat(MemoryMarshal.Cast<byte, float>(convertedSamples), samples);
PcmHelper.ConvertSampleToPcmFloat(MemoryMarshal.Cast<byte, float>(new Span<byte>(convertedSamples)), samples);
break;
default:
throw new NotImplementedException($"Sample format conversion from {_userSampleFormat} to {realSampleFormat} not implemented.");

View File

@@ -27,7 +27,7 @@ namespace Ryujinx.Audio.Integration
public void AppendBuffer(ReadOnlySpan<short> data, uint channelCount)
{
data.CopyTo(MemoryMarshal.Cast<byte, short>(_buffer));
data.CopyTo(MemoryMarshal.Cast<byte, short>(new Span<byte>(_buffer)));
_session.QueueBuffer(new AudioBuffer
{

View File

@@ -17,7 +17,7 @@ namespace Ryujinx.Cpu.Jit
_functionTable = AddressTable<ulong>.CreateForArm(for64Bit, memory.Type);
_translator = new Translator(new JitMemoryAllocator(forJit: true), memory, _functionTable);
if (memory.Type.IsHostMappedOrTracked())
if (memory.Type.IsHostMappedOrTracked)
{
NativeSignalHandler.InitializeSignalHandler();
}

View File

@@ -26,7 +26,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm32
return;
}
if (_operand.Type.IsInteger())
if (_operand.Type.IsInteger)
{
_registerAllocator.FreeTempGprRegister(_operand.AsInt32());
}

View File

@@ -381,7 +381,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64
if (currentCond != ArmCondition.Al)
{
instructionPointer = context.CodeWriter.InstructionPointer;
context.Arm64Assembler.B(currentCond.Invert(), 0);
context.Arm64Assembler.B(currentCond.Inverse, 0);
}
}
}

View File

@@ -104,7 +104,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64
if (invert)
{
conditions[i++] = ((ArmCondition)firstCond).Invert();
conditions[i++] = ((ArmCondition)firstCond).Inverse;
}
else
{

View File

@@ -1129,7 +1129,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64
// We don't need to mask the address for the safe mode, since it is already naturally limited to 32-bit
// and can never reach out of the guest address space.
if (mmType.IsHostTracked())
if (mmType.IsHostTracked)
{
int tempRegister = regAlloc.AllocateTempGprRegister();
@@ -1141,7 +1141,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64
regAlloc.FreeTempGprRegister(tempRegister);
}
else if (mmType.IsHostMapped())
else if (mmType.IsHostMapped)
{
asm.Add(destination64, basePointer, guestAddress);
}

View File

@@ -132,7 +132,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm64
InstName lastInstructionName = Instructions[^1].Name;
return lastInstructionName.IsCall() || lastInstructionName.IsException();
return lastInstructionName.IsCall || lastInstructionName.IsException;
}
}
}

View File

@@ -1042,126 +1042,39 @@ namespace Ryujinx.Cpu.LightningJit.Arm64
static class InstNameExtensions
{
public static bool IsCall(this InstName name)
extension(InstName name)
{
return name is InstName.Bl or InstName.Blr;
}
public bool IsCall => name is InstName.Bl or InstName.Blr;
public static bool IsControlFlowOrException(this InstName name)
{
switch (name)
public bool IsControlFlowOrException => name is
InstName.BUncond or InstName.BCond or InstName.Bl or InstName.Blr or InstName.Br or InstName.Brk
or InstName.Cbnz or InstName.Cbz or InstName.Ret or InstName.Tbnz or InstName.Tbz or InstName.Svc
or InstName.UdfPermUndef;
public bool IsException => name is InstName.Brk or InstName.Svc or InstName.UdfPermUndef;
public bool IsSystem => name switch
{
case InstName.BUncond:
case InstName.BCond:
case InstName.Bl:
case InstName.Blr:
case InstName.Br:
case InstName.Brk:
case InstName.Cbnz:
case InstName.Cbz:
case InstName.Ret:
case InstName.Tbnz:
case InstName.Tbz:
case InstName.Svc:
case InstName.UdfPermUndef:
return true;
}
InstName.Mrs or InstName.MsrImm or InstName.MsrReg => true,
_ => name.IsException
};
return false;
}
public bool IsSystemOrCall => name.IsCall || name is
InstName.Svc or InstName.Mrs or InstName.MsrImm or InstName.MsrReg
or InstName.Sysl;
public static bool IsException(this InstName name)
{
switch (name)
{
case InstName.Brk:
case InstName.Svc:
case InstName.UdfPermUndef:
return true;
}
public bool IsPrivileged => name is
InstName.Dcps1 or InstName.Dcps2 or InstName.Dcps3 or InstName.Drps or InstName.Eret or InstName.Ereta
or InstName.Hvc or InstName.MsrImm or InstName.Smc;
return false;
}
public bool IsPartialRegisterUpdateMemory => name is
InstName.Ld1AdvsimdSnglAsNoPostIndex or InstName.Ld1AdvsimdSnglAsPostIndex
or InstName.Ld2AdvsimdSnglAsNoPostIndex or InstName.Ld2AdvsimdSnglAsPostIndex
or InstName.Ld3AdvsimdSnglAsNoPostIndex or InstName.Ld3AdvsimdSnglAsPostIndex
or InstName.Ld4AdvsimdSnglAsNoPostIndex or InstName.Ld4AdvsimdSnglAsPostIndex;
public static bool IsSystem(this InstName name)
{
switch (name)
{
case InstName.Mrs:
case InstName.MsrImm:
case InstName.MsrReg:
return true;
}
return name.IsException();
}
public static bool IsSystemOrCall(this InstName name)
{
switch (name)
{
case InstName.Bl:
case InstName.Blr:
case InstName.Svc:
case InstName.Mrs:
case InstName.MsrImm:
case InstName.MsrReg:
case InstName.Sysl:
return true;
}
return false;
}
public static bool IsPrivileged(this InstName name)
{
switch (name)
{
case InstName.Dcps1:
case InstName.Dcps2:
case InstName.Dcps3:
case InstName.Drps:
case InstName.Eret:
case InstName.Ereta:
case InstName.Hvc:
case InstName.MsrImm:
case InstName.Smc:
return true;
}
return false;
}
public static bool IsPartialRegisterUpdateMemory(this InstName name)
{
switch (name)
{
case InstName.Ld1AdvsimdSnglAsNoPostIndex:
case InstName.Ld1AdvsimdSnglAsPostIndex:
case InstName.Ld2AdvsimdSnglAsNoPostIndex:
case InstName.Ld2AdvsimdSnglAsPostIndex:
case InstName.Ld3AdvsimdSnglAsNoPostIndex:
case InstName.Ld3AdvsimdSnglAsPostIndex:
case InstName.Ld4AdvsimdSnglAsNoPostIndex:
case InstName.Ld4AdvsimdSnglAsPostIndex:
return true;
}
return false;
}
public static bool IsPrefetchMemory(this InstName name)
{
switch (name)
{
case InstName.PrfmImm:
case InstName.PrfmLit:
case InstName.PrfmReg:
case InstName.Prfum:
return true;
}
return false;
public bool IsPrefetchMemory => name is
InstName.PrfmImm or InstName.PrfmLit or InstName.PrfmReg or InstName.Prfum;
}
}
}

View File

@@ -150,7 +150,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm64
public static int CalculateMaxTemps(MemoryManagerType mmType)
{
return mmType.IsHostMapped() ? 1 : 2;
return mmType.IsHostMapped ? 1 : 2;
}
public static int CalculateMaxTempsInclFixed(MemoryManagerType mmType)

View File

@@ -247,7 +247,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm64
}
}
if (!flags.HasFlag(InstFlags.ReadRt) || name.IsPartialRegisterUpdateMemory())
if (!flags.HasFlag(InstFlags.ReadRt) || name.IsPartialRegisterUpdateMemory)
{
if (flags.HasFlag(InstFlags.Rt))
{
@@ -281,7 +281,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm64
gprMask |= MaskFromIndex(ExtractRd(flags, encoding));
}
if (!flags.HasFlag(InstFlags.ReadRt) || name.IsPartialRegisterUpdateMemory())
if (!flags.HasFlag(InstFlags.ReadRt) || name.IsPartialRegisterUpdateMemory)
{
if (flags.HasFlag(InstFlags.Rt))
{

View File

@@ -364,7 +364,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm64.Target.Arm64
{
InstEmitMemory.RewriteSysInstruction(memoryManager.AddressSpaceBits, memoryManager.Type, writer, regAlloc, encoding);
}
else if (instInfo.Name.IsSystem())
else if (instInfo.Name.IsSystem)
{
bool needsContextStoreLoad = InstEmitSystem.NeedsContextStoreLoad(instInfo.Name);
@@ -405,7 +405,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm64.Target.Arm64
lastInstructionEncoding = RegisterUtils.RemapRegisters(regAlloc, lastInstructionFlags, lastInstructionEncoding);
if (lastInstructionName.IsCall())
if (lastInstructionName.IsCall)
{
context.StoreToContextBeforeCall(blockIndex, pc + 4UL);

View File

@@ -257,7 +257,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm64.Target.Arm64
(name, flags, AddressForm addressForm) = InstTable.GetInstNameAndFlags(encoding, cpuPreset.Version, cpuPreset.Features);
if (name.IsPrivileged() || (name == InstName.Sys && IsPrivilegedSys(encoding)))
if (name.IsPrivileged || (name == InstName.Sys && IsPrivilegedSys(encoding)))
{
name = InstName.UdfPermUndef;
flags = InstFlags.None;
@@ -267,7 +267,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm64.Target.Arm64
(uint instGprReadMask, uint instFpSimdReadMask) = RegisterUtils.PopulateReadMasks(name, flags, encoding);
(uint instGprWriteMask, uint instFpSimdWriteMask) = RegisterUtils.PopulateWriteMasks(name, flags, encoding);
if (name.IsCall())
if (name.IsCall)
{
instGprWriteMask |= 1u << RegisterUtils.LrIndex;
}
@@ -310,12 +310,12 @@ namespace Ryujinx.Cpu.LightningJit.Arm64.Target.Arm64
fpSimdUseMask |= instFpSimdReadMask | instFpSimdWriteMask;
pStateUseMask |= instPStateReadMask | instPStateWriteMask;
if (name.IsSystemOrCall() && !hasHostCall)
if (name.IsSystemOrCall && !hasHostCall)
{
hasHostCall = name.IsCall() || InstEmitSystem.NeedsCall(encoding);
hasHostCall = name.IsCall || InstEmitSystem.NeedsCall(encoding);
}
isControlFlow = name.IsControlFlowOrException();
isControlFlow = name.IsControlFlowOrException;
RegisterUse registerUse = new(
instGprReadMask,
@@ -339,7 +339,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm64.Target.Arm64
useMask = new(gprUseMask, fpSimdUseMask, pStateUseMask);
return new(startAddress, address, insts, !isTruncated && !name.IsException(), isTruncated, isLoopEnd);
return new(startAddress, address, insts, !isTruncated && !name.IsException, isTruncated, isLoopEnd);
}
private static bool IsPrivilegedSys(uint encoding)

View File

@@ -55,7 +55,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm64.Target.Arm64
ulong pc,
uint encoding)
{
if (name.IsPrefetchMemory() && mmType == MemoryManagerType.HostTrackedUnsafe)
if (name.IsPrefetchMemory && mmType == MemoryManagerType.HostTrackedUnsafe)
{
// Prefetch to invalid addresses do not cause faults, so for memory manager
// types where we need to access the page table before doing the prefetch,
@@ -544,7 +544,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm64.Target.Arm64
{
Operand basePointer = new(regAlloc.FixedPageTableRegister, RegisterType.Integer, OperandType.I64);
if (mmType.IsHostTracked())
if (mmType.IsHostTracked)
{
int tempRegister = regAlloc.AllocateTempGprRegister();
@@ -562,7 +562,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm64.Target.Arm64
regAlloc.FreeTempGprRegister(tempRegister);
}
else if (mmType.IsHostMapped())
else if (mmType.IsHostMapped)
{
if (mmType == MemoryManagerType.HostMapped)
{

View File

@@ -22,9 +22,9 @@ namespace Ryujinx.Cpu.LightningJit.CodeGen.Arm64
static class ArmConditionExtensions
{
public static ArmCondition Invert(this ArmCondition condition)
extension(ArmCondition condition)
{
return (ArmCondition)((int)condition ^ 1);
public ArmCondition Inverse => (ArmCondition)((int)condition ^ 1);
}
}
}

View File

@@ -673,7 +673,7 @@ namespace Ryujinx.Cpu.LightningJit.CodeGen.Arm64
public readonly void Mov(Operand rd, Operand rn)
{
Debug.Assert(rd.Type.IsInteger());
Debug.Assert(rd.Type.IsInteger);
Orr(rd, new Operand(ZrRegister, RegisterType.Integer, rd.Type), rn);
}
@@ -4544,7 +4544,7 @@ namespace Ryujinx.Cpu.LightningJit.CodeGen.Arm64
uint instruction;
int scale;
if (type.IsInteger())
if (type.IsInteger)
{
instruction = intInst;
@@ -4580,7 +4580,7 @@ namespace Ryujinx.Cpu.LightningJit.CodeGen.Arm64
{
uint instruction;
if (type.IsInteger())
if (type.IsInteger)
{
instruction = intInst;
@@ -4610,7 +4610,7 @@ namespace Ryujinx.Cpu.LightningJit.CodeGen.Arm64
{
uint instruction;
if (type.IsInteger())
if (type.IsInteger)
{
instruction = intInst;

View File

@@ -34,7 +34,7 @@ namespace Ryujinx.Cpu.LightningJit.CodeGen.Arm64
int gprCalleeSavedRegsCount = BitOperations.PopCount(_gprMask);
int fpSimdCalleeSavedRegsCount = BitOperations.PopCount(_fpSimdMask);
return (_hasCall ? 16 : 0) + Align16(gprCalleeSavedRegsCount * 8 + fpSimdCalleeSavedRegsCount * _fpSimdType.GetSizeInBytes());
return (_hasCall ? 16 : 0) + Align16(gprCalleeSavedRegsCount * 8 + fpSimdCalleeSavedRegsCount * _fpSimdType.ByteSize);
}
public void WritePrologue(ref Assembler asm)
@@ -46,7 +46,7 @@ namespace Ryujinx.Cpu.LightningJit.CodeGen.Arm64
int fpSimdCalleeSavedRegsCount = BitOperations.PopCount(fpSimdMask);
int reservedStackSize = Align16(_reservedStackSize);
int calleeSaveRegionSize = Align16(gprCalleeSavedRegsCount * 8 + fpSimdCalleeSavedRegsCount * _fpSimdType.GetSizeInBytes()) + reservedStackSize;
int calleeSaveRegionSize = Align16(gprCalleeSavedRegsCount * 8 + fpSimdCalleeSavedRegsCount * _fpSimdType.ByteSize) + reservedStackSize;
int offset = 0;
WritePrologueCalleeSavesPreIndexed(ref asm, ref gprMask, ref offset, calleeSaveRegionSize, OperandType.I64);
@@ -103,7 +103,7 @@ namespace Ryujinx.Cpu.LightningJit.CodeGen.Arm64
asm.StrRiUn(Register(reg, type), Register(Assembler.SpRegister), 0);
}
offset += type.GetSizeInBytes();
offset += type.ByteSize;
}
while (mask != 0)
@@ -130,7 +130,7 @@ namespace Ryujinx.Cpu.LightningJit.CodeGen.Arm64
asm.StpRiUn(Register(reg, type), Register(reg2, type), Register(Assembler.SpRegister), 0);
}
offset += type.GetSizeInBytes() * 2;
offset += type.ByteSize * 2;
}
}
@@ -144,7 +144,7 @@ namespace Ryujinx.Cpu.LightningJit.CodeGen.Arm64
bool misalignedVector = _fpSimdType == OperandType.V128 && (gprCalleeSavedRegsCount & 1) != 0;
int offset = gprCalleeSavedRegsCount * 8 + fpSimdCalleeSavedRegsCount * _fpSimdType.GetSizeInBytes();
int offset = gprCalleeSavedRegsCount * 8 + fpSimdCalleeSavedRegsCount * _fpSimdType.ByteSize;
if (misalignedVector)
{
@@ -197,7 +197,7 @@ namespace Ryujinx.Cpu.LightningJit.CodeGen.Arm64
mask &= ~(1u << reg2);
offset -= type.GetSizeInBytes() * 2;
offset -= type.ByteSize * 2;
if (offset != 0)
{
@@ -215,7 +215,7 @@ namespace Ryujinx.Cpu.LightningJit.CodeGen.Arm64
}
else
{
offset -= type.GetSizeInBytes();
offset -= type.ByteSize;
if (offset != 0)
{

View File

@@ -14,14 +14,11 @@ namespace Ryujinx.Cpu.LightningJit.CodeGen
static class OperandTypeExtensions
{
public static bool IsInteger(this OperandType type)
extension(OperandType type)
{
return type is OperandType.I32 or OperandType.I64;
}
public bool IsInteger => type is OperandType.I32 or OperandType.I64;
public static int GetSizeInBytes(this OperandType type)
{
return type switch
public int ByteSize => type switch
{
OperandType.FP32 => 4,
OperandType.FP64 => 8,

View File

@@ -48,7 +48,7 @@ namespace Ryujinx.Cpu.LightningJit
FunctionTable.Fill = (ulong)Stubs.SlowDispatchStub;
if (memory.Type.IsHostMappedOrTracked())
if (memory.Type.IsHostMappedOrTracked)
{
NativeSignalHandler.InitializeSignalHandler();
}

View File

@@ -41,22 +41,12 @@ namespace Ryujinx.Graphics.GAL
public static class BlendFactorExtensions
{
public static bool IsDualSource(this BlendFactor factor)
extension(BlendFactor factor)
{
switch (factor)
{
case BlendFactor.Src1Color:
case BlendFactor.Src1ColorGl:
case BlendFactor.Src1Alpha:
case BlendFactor.Src1AlphaGl:
case BlendFactor.OneMinusSrc1Color:
case BlendFactor.OneMinusSrc1ColorGl:
case BlendFactor.OneMinusSrc1Alpha:
case BlendFactor.OneMinusSrc1AlphaGl:
return true;
default:
return false;
}
public bool IsDualSource => factor is
BlendFactor.Src1Color or BlendFactor.Src1ColorGl or BlendFactor.Src1Alpha or BlendFactor.Src1AlphaGl
or BlendFactor.OneMinusSrc1Color or BlendFactor.OneMinusSrc1ColorGl or BlendFactor.OneMinusSrc1Alpha
or BlendFactor.OneMinusSrc1AlphaGl;
}
}
}

View File

@@ -1,3 +1,4 @@
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace Ryujinx.Graphics.GAL
@@ -10,5 +11,7 @@ namespace Ryujinx.Graphics.GAL
public static BufferHandle Null => new(0);
private BufferHandle(ulong value) => _value = value;
public static implicit operator int(BufferHandle handle) => (int)Unsafe.As<BufferHandle, ulong>(ref handle);
}
}

View File

@@ -158,589 +158,191 @@ namespace Ryujinx.Graphics.GAL
/// </summary>
public const int MaxBufferFormatScalarSize = 4;
/// <summary>
/// Gets the byte size for a single component of this format, or its packed size.
/// </summary>
/// <param name="format">Texture format</param>
/// <returns>Byte size for a single component, or packed size</returns>
public static int GetScalarSize(this Format format)
extension(Format fmt)
{
switch (format)
/// <summary>
/// Gets the byte size for a single component of this format, or its packed size.
/// </summary>
public int ScalarSize => fmt switch
{
case Format.R8Unorm:
case Format.R8Snorm:
case Format.R8Uint:
case Format.R8Sint:
case Format.R8G8Unorm:
case Format.R8G8Snorm:
case Format.R8G8Uint:
case Format.R8G8Sint:
case Format.R8G8B8Unorm:
case Format.R8G8B8Snorm:
case Format.R8G8B8Uint:
case Format.R8G8B8Sint:
case Format.R8G8B8A8Unorm:
case Format.R8G8B8A8Snorm:
case Format.R8G8B8A8Uint:
case Format.R8G8B8A8Sint:
case Format.R8G8B8A8Srgb:
case Format.R4G4Unorm:
case Format.R8Uscaled:
case Format.R8Sscaled:
case Format.R8G8Uscaled:
case Format.R8G8Sscaled:
case Format.R8G8B8Uscaled:
case Format.R8G8B8Sscaled:
case Format.R8G8B8A8Uscaled:
case Format.R8G8B8A8Sscaled:
case Format.B8G8R8A8Unorm:
case Format.B8G8R8A8Srgb:
return 1;
Format.R8Unorm or Format.R8Snorm or Format.R8Uint or Format.R8Sint or Format.R8G8Unorm
or Format.R8G8Snorm or Format.R8G8Uint or Format.R8G8Sint or Format.R8G8B8Unorm
or Format.R8G8B8Snorm or Format.R8G8B8Uint or Format.R8G8B8Sint or Format.R8G8B8A8Unorm
or Format.R8G8B8A8Snorm or Format.R8G8B8A8Uint or Format.R8G8B8A8Sint or Format.R8G8B8A8Srgb
or Format.R4G4Unorm or Format.R8Uscaled or Format.R8Sscaled or Format.R8G8Uscaled
or Format.R8G8Sscaled or Format.R8G8B8Uscaled or Format.R8G8B8Sscaled or Format.R8G8B8A8Uscaled
or Format.R8G8B8A8Sscaled or Format.B8G8R8A8Unorm or Format.B8G8R8A8Srgb => 1,
Format.R16Float or Format.R16Unorm or Format.R16Snorm or Format.R16Uint or Format.R16Sint
or Format.R16G16Float or Format.R16G16Unorm or Format.R16G16Snorm or Format.R16G16Uint
or Format.R16G16Sint or Format.R16G16B16Float or Format.R16G16B16Unorm or Format.R16G16B16Snorm
or Format.R16G16B16Uint or Format.R16G16B16Sint or Format.R16G16B16A16Float
or Format.R16G16B16A16Unorm or Format.R16G16B16A16Snorm or Format.R16G16B16A16Uint
or Format.R16G16B16A16Sint or Format.R4G4B4A4Unorm or Format.R5G5B5X1Unorm or Format.R5G5B5A1Unorm
or Format.R5G6B5Unorm or Format.R16Uscaled or Format.R16Sscaled or Format.R16G16Uscaled
or Format.R16G16Sscaled or Format.R16G16B16Uscaled or Format.R16G16B16Sscaled
or Format.R16G16B16A16Uscaled or Format.R16G16B16A16Sscaled or Format.B5G6R5Unorm
or Format.B5G5R5A1Unorm or Format.A1B5G5R5Unorm => 2,
Format.R32Float or Format.R32Uint or Format.R32Sint or Format.R32G32Float or Format.R32G32Uint
or Format.R32G32Sint or Format.R32G32B32Float or Format.R32G32B32Uint or Format.R32G32B32Sint
or Format.R32G32B32A32Float or Format.R32G32B32A32Uint or Format.R32G32B32A32Sint
or Format.R10G10B10A2Unorm or Format.R10G10B10A2Uint or Format.R11G11B10Float
or Format.R9G9B9E5Float or Format.R32Uscaled or Format.R32Sscaled or Format.R32G32Uscaled
or Format.R32G32Sscaled or Format.R32G32B32Uscaled or Format.R32G32B32Sscaled
or Format.R32G32B32A32Uscaled or Format.R32G32B32A32Sscaled or Format.R10G10B10A2Snorm
or Format.R10G10B10A2Sint or Format.R10G10B10A2Uscaled or Format.R10G10B10A2Sscaled
or Format.B10G10R10A2Unorm => 4,
Format.S8Uint => 1,
Format.D16Unorm => 2,
Format.S8UintD24Unorm or Format.X8UintD24Unorm or Format.D32Float or Format.D24UnormS8Uint => 4,
Format.D32FloatS8Uint => 8,
Format.Bc1RgbaUnorm or Format.Bc1RgbaSrgb => 8,
Format.Bc2Unorm or Format.Bc3Unorm or Format.Bc2Srgb or Format.Bc3Srgb or Format.Bc4Unorm
or Format.Bc4Snorm or Format.Bc5Unorm or Format.Bc5Snorm or Format.Bc7Unorm or Format.Bc7Srgb
or Format.Bc6HSfloat or Format.Bc6HUfloat => 16,
Format.Etc2RgbUnorm or Format.Etc2RgbPtaUnorm or Format.Etc2RgbSrgb or Format.Etc2RgbPtaSrgb => 8,
Format.Etc2RgbaUnorm or Format.Etc2RgbaSrgb => 16,
Format.Astc4x4Unorm or Format.Astc5x4Unorm or Format.Astc5x5Unorm or Format.Astc6x5Unorm
or Format.Astc6x6Unorm or Format.Astc8x5Unorm or Format.Astc8x6Unorm or Format.Astc8x8Unorm
or Format.Astc10x5Unorm or Format.Astc10x6Unorm or Format.Astc10x8Unorm or Format.Astc10x10Unorm
or Format.Astc12x10Unorm or Format.Astc12x12Unorm or Format.Astc4x4Srgb or Format.Astc5x4Srgb
or Format.Astc5x5Srgb or Format.Astc6x5Srgb or Format.Astc6x6Srgb or Format.Astc8x5Srgb
or Format.Astc8x6Srgb or Format.Astc8x8Srgb or Format.Astc10x5Srgb or Format.Astc10x6Srgb
or Format.Astc10x8Srgb or Format.Astc10x10Srgb or Format.Astc12x10Srgb
or Format.Astc12x12Srgb => 16,
_ => 1
};
case Format.R16Float:
case Format.R16Unorm:
case Format.R16Snorm:
case Format.R16Uint:
case Format.R16Sint:
case Format.R16G16Float:
case Format.R16G16Unorm:
case Format.R16G16Snorm:
case Format.R16G16Uint:
case Format.R16G16Sint:
case Format.R16G16B16Float:
case Format.R16G16B16Unorm:
case Format.R16G16B16Snorm:
case Format.R16G16B16Uint:
case Format.R16G16B16Sint:
case Format.R16G16B16A16Float:
case Format.R16G16B16A16Unorm:
case Format.R16G16B16A16Snorm:
case Format.R16G16B16A16Uint:
case Format.R16G16B16A16Sint:
case Format.R4G4B4A4Unorm:
case Format.R5G5B5X1Unorm:
case Format.R5G5B5A1Unorm:
case Format.R5G6B5Unorm:
case Format.R16Uscaled:
case Format.R16Sscaled:
case Format.R16G16Uscaled:
case Format.R16G16Sscaled:
case Format.R16G16B16Uscaled:
case Format.R16G16B16Sscaled:
case Format.R16G16B16A16Uscaled:
case Format.R16G16B16A16Sscaled:
case Format.B5G6R5Unorm:
case Format.B5G5R5A1Unorm:
case Format.A1B5G5R5Unorm:
return 2;
/// <summary>
/// Checks if the texture format is a depth or depth-stencil format.
/// </summary>
public bool HasDepth => fmt is
Format.D16Unorm or Format.D24UnormS8Uint or Format.S8UintD24Unorm or Format.X8UintD24Unorm
or Format.D32Float or Format.D32FloatS8Uint;
case Format.R32Float:
case Format.R32Uint:
case Format.R32Sint:
case Format.R32G32Float:
case Format.R32G32Uint:
case Format.R32G32Sint:
case Format.R32G32B32Float:
case Format.R32G32B32Uint:
case Format.R32G32B32Sint:
case Format.R32G32B32A32Float:
case Format.R32G32B32A32Uint:
case Format.R32G32B32A32Sint:
case Format.R10G10B10A2Unorm:
case Format.R10G10B10A2Uint:
case Format.R11G11B10Float:
case Format.R9G9B9E5Float:
case Format.R32Uscaled:
case Format.R32Sscaled:
case Format.R32G32Uscaled:
case Format.R32G32Sscaled:
case Format.R32G32B32Uscaled:
case Format.R32G32B32Sscaled:
case Format.R32G32B32A32Uscaled:
case Format.R32G32B32A32Sscaled:
case Format.R10G10B10A2Snorm:
case Format.R10G10B10A2Sint:
case Format.R10G10B10A2Uscaled:
case Format.R10G10B10A2Sscaled:
case Format.B10G10R10A2Unorm:
return 4;
/// <summary>
/// Checks if the texture format is a stencil or depth-stencil format.
/// </summary>
public bool HasStencil => fmt is
Format.D24UnormS8Uint or Format.S8UintD24Unorm or Format.D32FloatS8Uint or Format.S8Uint;
case Format.S8Uint:
return 1;
case Format.D16Unorm:
return 2;
case Format.S8UintD24Unorm:
case Format.X8UintD24Unorm:
case Format.D32Float:
case Format.D24UnormS8Uint:
return 4;
case Format.D32FloatS8Uint:
return 8;
/// <summary>
/// Checks if the texture format is valid to use as image format.
/// </summary>
public bool IsImageCompatible => fmt is
Format.R8Unorm or Format.R8Snorm or Format.R8Uint or Format.R8Sint or Format.R16Float or Format.R16Unorm
or Format.R16Snorm or Format.R16Uint or Format.R16Sint or Format.R32Float or Format.R32Uint
or Format.R32Sint or Format.R8G8Unorm or Format.R8G8Snorm or Format.R8G8Uint or Format.R8G8Sint
or Format.R16G16Float or Format.R16G16Unorm or Format.R16G16Snorm or Format.R16G16Uint
or Format.R16G16Sint or Format.R32G32Float or Format.R32G32Uint or Format.R32G32Sint
or Format.R8G8B8A8Unorm or Format.R8G8B8A8Snorm or Format.R8G8B8A8Uint or Format.R8G8B8A8Sint
or Format.R16G16B16A16Float or Format.R16G16B16A16Unorm or Format.R16G16B16A16Snorm
or Format.R16G16B16A16Uint or Format.R16G16B16A16Sint or Format.R32G32B32A32Float
or Format.R32G32B32A32Uint or Format.R32G32B32A32Sint or Format.R10G10B10A2Unorm
or Format.R10G10B10A2Uint or Format.R11G11B10Float or Format.B8G8R8A8Unorm;
case Format.Bc1RgbaUnorm:
case Format.Bc1RgbaSrgb:
return 8;
/// <summary>
/// Checks if the texture format is valid to use as render target color format.
/// </summary>
public bool IsRtColorCompatible => fmt is
Format.R32G32B32A32Float or Format.R32G32B32A32Sint or Format.R32G32B32A32Uint
or Format.R16G16B16A16Unorm or Format.R16G16B16A16Snorm or Format.R16G16B16A16Sint
or Format.R16G16B16A16Uint or Format.R16G16B16A16Float or Format.R32G32Float or Format.R32G32Sint
or Format.R32G32Uint or Format.B8G8R8A8Unorm or Format.B8G8R8A8Srgb or Format.B10G10R10A2Unorm
or Format.R10G10B10A2Unorm or Format.R10G10B10A2Uint or Format.R8G8B8A8Unorm or Format.R8G8B8A8Srgb
or Format.R8G8B8A8Snorm or Format.R8G8B8A8Sint or Format.R8G8B8A8Uint or Format.R16G16Unorm
or Format.R16G16Snorm or Format.R16G16Sint or Format.R16G16Uint or Format.R16G16Float
or Format.R11G11B10Float or Format.R32Sint or Format.R32Uint or Format.R32Float
or Format.B5G6R5Unorm or Format.B5G5R5A1Unorm or Format.R8G8Unorm or Format.R8G8Snorm
or Format.R8G8Sint or Format.R8G8Uint or Format.R16Unorm or Format.R16Snorm or Format.R16Sint
or Format.R16Uint or Format.R16Float or Format.R8Unorm or Format.R8Snorm or Format.R8Sint
or Format.R8Uint;
case Format.Bc2Unorm:
case Format.Bc3Unorm:
case Format.Bc2Srgb:
case Format.Bc3Srgb:
case Format.Bc4Unorm:
case Format.Bc4Snorm:
case Format.Bc5Unorm:
case Format.Bc5Snorm:
case Format.Bc7Unorm:
case Format.Bc7Srgb:
case Format.Bc6HSfloat:
case Format.Bc6HUfloat:
return 16;
/// <summary>
/// Checks if the texture format is 16 bit packed.
/// </summary>
public bool Is16BitPacked => fmt is
Format.B5G6R5Unorm or Format.B5G5R5A1Unorm or Format.R5G5B5X1Unorm or Format.R5G5B5A1Unorm
or Format.R5G6B5Unorm or Format.R4G4B4A4Unorm;
case Format.Etc2RgbUnorm:
case Format.Etc2RgbPtaUnorm:
case Format.Etc2RgbSrgb:
case Format.Etc2RgbPtaSrgb:
return 8;
/// <summary>
/// Checks if the texture format is an ETC2 format.
/// </summary>
public bool IsEtc2 => fmt is
Format.Etc2RgbaSrgb or Format.Etc2RgbaUnorm or Format.Etc2RgbPtaSrgb
or Format.Etc2RgbPtaUnorm or Format.Etc2RgbSrgb or Format.Etc2RgbUnorm;
case Format.Etc2RgbaUnorm:
case Format.Etc2RgbaSrgb:
return 16;
/// <summary>
/// Checks if the texture format is a BGR format.
/// </summary>
public bool IsBgr => fmt is
Format.B5G6R5Unorm or Format.B5G5R5A1Unorm or Format.B8G8R8A8Unorm or Format.B8G8R8A8Srgb
or Format.B10G10R10A2Unorm;
case Format.Astc4x4Unorm:
case Format.Astc5x4Unorm:
case Format.Astc5x5Unorm:
case Format.Astc6x5Unorm:
case Format.Astc6x6Unorm:
case Format.Astc8x5Unorm:
case Format.Astc8x6Unorm:
case Format.Astc8x8Unorm:
case Format.Astc10x5Unorm:
case Format.Astc10x6Unorm:
case Format.Astc10x8Unorm:
case Format.Astc10x10Unorm:
case Format.Astc12x10Unorm:
case Format.Astc12x12Unorm:
case Format.Astc4x4Srgb:
case Format.Astc5x4Srgb:
case Format.Astc5x5Srgb:
case Format.Astc6x5Srgb:
case Format.Astc6x6Srgb:
case Format.Astc8x5Srgb:
case Format.Astc8x6Srgb:
case Format.Astc8x8Srgb:
case Format.Astc10x5Srgb:
case Format.Astc10x6Srgb:
case Format.Astc10x8Srgb:
case Format.Astc10x10Srgb:
case Format.Astc12x10Srgb:
case Format.Astc12x12Srgb:
return 16;
}
/// <summary>
/// Checks if the texture format is a depth, stencil or depth-stencil format.
/// </summary>
public bool IsDepthOrStencil => fmt is
Format.D16Unorm or Format.D24UnormS8Uint or Format.S8UintD24Unorm or Format.X8UintD24Unorm
or Format.D32Float or Format.D32FloatS8Uint or Format.S8Uint;
return 1;
}
/// <summary>
/// Checks if the texture format is a float or sRGB color format.
/// </summary>
/// <remarks>
/// Does not include normalized, compressed or depth formats.
/// Float and sRGB formats do not participate in logical operations.
/// </remarks>
public bool IsFloatOrSrgb => fmt is
Format.R8G8B8A8Srgb or Format.B8G8R8A8Srgb or Format.R16Float or Format.R16G16Float
or Format.R16G16B16Float or Format.R16G16B16A16Float or Format.R32Float or Format.R32G32Float
or Format.R32G32B32Float or Format.R32G32B32A32Float or Format.R11G11B10Float
or Format.R9G9B9E5Float;
/// <summary>
/// Checks if the texture format is a depth or depth-stencil format.
/// </summary>
/// <param name="format">Texture format</param>
/// <returns>True if the format is a depth or depth-stencil format, false otherwise</returns>
public static bool HasDepth(this Format format)
{
switch (format)
{
case Format.D16Unorm:
case Format.D24UnormS8Uint:
case Format.S8UintD24Unorm:
case Format.X8UintD24Unorm:
case Format.D32Float:
case Format.D32FloatS8Uint:
return true;
}
/// <summary>
/// Checks if the texture format is an ASTC Unorm format.
/// </summary>
public bool IsAstcUnorm => fmt is
Format.Astc4x4Unorm or Format.Astc5x4Unorm or Format.Astc5x5Unorm or Format.Astc6x5Unorm
or Format.Astc6x6Unorm or Format.Astc8x5Unorm or Format.Astc8x6Unorm or Format.Astc8x8Unorm
or Format.Astc10x5Unorm or Format.Astc10x6Unorm or Format.Astc10x8Unorm or Format.Astc10x10Unorm
or Format.Astc12x10Unorm or Format.Astc12x12Unorm;
return false;
}
/// <summary>
/// Checks if the texture format is an ASTC SRGB format.
/// </summary>
public bool IsAstcSrgb => fmt is
Format.Astc4x4Srgb or Format.Astc5x4Srgb or Format.Astc5x5Srgb or Format.Astc6x5Srgb
or Format.Astc6x6Srgb or Format.Astc8x5Srgb or Format.Astc8x6Srgb or Format.Astc8x8Srgb
or Format.Astc10x5Srgb or Format.Astc10x6Srgb or Format.Astc10x8Srgb or Format.Astc10x10Srgb
or Format.Astc12x10Srgb or Format.Astc12x12Srgb;
/// <summary>
/// Checks if the texture format is a stencil or depth-stencil format.
/// </summary>
/// <param name="format">Texture format</param>
/// <returns>True if the format is a stencil or depth-stencil format, false otherwise</returns>
public static bool HasStencil(this Format format)
{
switch (format)
{
case Format.D24UnormS8Uint:
case Format.S8UintD24Unorm:
case Format.D32FloatS8Uint:
case Format.S8Uint:
return true;
}
/// <summary>
/// Checks if the texture format is an ASTC format.
/// </summary>
public bool IsAstc => fmt.IsAstcUnorm || fmt.IsAstcSrgb;
return false;
}
/// <summary>
/// Checks if the texture format is an unsigned integer color format.
/// </summary>
public bool IsUnsignedInt => fmt is
Format.R8Uint or Format.R16Uint or Format.R32Uint or Format.R8G8Uint or Format.R16G16Uint
or Format.R32G32Uint or Format.R8G8B8Uint or Format.R16G16B16Uint or Format.R32G32B32Uint
or Format.R8G8B8A8Uint or Format.R16G16B16A16Uint or Format.R32G32B32A32Uint
or Format.R10G10B10A2Uint;
/// <summary>
/// Checks if the texture format is valid to use as image format.
/// </summary>
/// <param name="format">Texture format</param>
/// <returns>True if the texture can be used as image, false otherwise</returns>
public static bool IsImageCompatible(this Format format)
{
switch (format)
{
case Format.R8Unorm:
case Format.R8Snorm:
case Format.R8Uint:
case Format.R8Sint:
case Format.R16Float:
case Format.R16Unorm:
case Format.R16Snorm:
case Format.R16Uint:
case Format.R16Sint:
case Format.R32Float:
case Format.R32Uint:
case Format.R32Sint:
case Format.R8G8Unorm:
case Format.R8G8Snorm:
case Format.R8G8Uint:
case Format.R8G8Sint:
case Format.R16G16Float:
case Format.R16G16Unorm:
case Format.R16G16Snorm:
case Format.R16G16Uint:
case Format.R16G16Sint:
case Format.R32G32Float:
case Format.R32G32Uint:
case Format.R32G32Sint:
case Format.R8G8B8A8Unorm:
case Format.R8G8B8A8Snorm:
case Format.R8G8B8A8Uint:
case Format.R8G8B8A8Sint:
case Format.R16G16B16A16Float:
case Format.R16G16B16A16Unorm:
case Format.R16G16B16A16Snorm:
case Format.R16G16B16A16Uint:
case Format.R16G16B16A16Sint:
case Format.R32G32B32A32Float:
case Format.R32G32B32A32Uint:
case Format.R32G32B32A32Sint:
case Format.R10G10B10A2Unorm:
case Format.R10G10B10A2Uint:
case Format.R11G11B10Float:
case Format.B8G8R8A8Unorm:
return true;
}
/// <summary>
/// Checks if the texture format is a signed integer color format.
/// </summary>
public bool IsSignedInt => fmt is
Format.R8Sint or Format.R16Sint or Format.R32Sint or Format.R8G8Sint or Format.R16G16Sint
or Format.R32G32Sint or Format.R8G8B8Sint or Format.R16G16B16Sint or Format.R32G32B32Sint
or Format.R8G8B8A8Sint or Format.R16G16B16A16Sint or Format.R32G32B32A32Sint
or Format.R10G10B10A2Sint;
return false;
}
/// <summary>
/// Checks if the texture format is valid to use as render target color format.
/// </summary>
/// <param name="format">Texture format</param>
/// <returns>True if the texture can be used as render target, false otherwise</returns>
public static bool IsRtColorCompatible(this Format format)
{
switch (format)
{
case Format.R32G32B32A32Float:
case Format.R32G32B32A32Sint:
case Format.R32G32B32A32Uint:
case Format.R16G16B16A16Unorm:
case Format.R16G16B16A16Snorm:
case Format.R16G16B16A16Sint:
case Format.R16G16B16A16Uint:
case Format.R16G16B16A16Float:
case Format.R32G32Float:
case Format.R32G32Sint:
case Format.R32G32Uint:
case Format.B8G8R8A8Unorm:
case Format.B8G8R8A8Srgb:
case Format.B10G10R10A2Unorm:
case Format.R10G10B10A2Unorm:
case Format.R10G10B10A2Uint:
case Format.R8G8B8A8Unorm:
case Format.R8G8B8A8Srgb:
case Format.R8G8B8A8Snorm:
case Format.R8G8B8A8Sint:
case Format.R8G8B8A8Uint:
case Format.R16G16Unorm:
case Format.R16G16Snorm:
case Format.R16G16Sint:
case Format.R16G16Uint:
case Format.R16G16Float:
case Format.R11G11B10Float:
case Format.R32Sint:
case Format.R32Uint:
case Format.R32Float:
case Format.B5G6R5Unorm:
case Format.B5G5R5A1Unorm:
case Format.R8G8Unorm:
case Format.R8G8Snorm:
case Format.R8G8Sint:
case Format.R8G8Uint:
case Format.R16Unorm:
case Format.R16Snorm:
case Format.R16Sint:
case Format.R16Uint:
case Format.R16Float:
case Format.R8Unorm:
case Format.R8Snorm:
case Format.R8Sint:
case Format.R8Uint:
return true;
}
return false;
}
/// <summary>
/// Checks if the texture format is 16 bit packed.
/// </summary>
/// <param name="format">Texture format</param>
/// <returns>True if the texture format is 16 bit packed, false otherwise</returns>
public static bool Is16BitPacked(this Format format)
{
switch (format)
{
case Format.B5G6R5Unorm:
case Format.B5G5R5A1Unorm:
case Format.R5G5B5X1Unorm:
case Format.R5G5B5A1Unorm:
case Format.R5G6B5Unorm:
case Format.R4G4B4A4Unorm:
return true;
}
return false;
}
/// <summary>
/// Checks if the texture format is an ASTC format.
/// </summary>
/// <param name="format">Texture format</param>
/// <returns>True if the texture format is an ASTC format, false otherwise</returns>
public static bool IsAstc(this Format format)
{
return format.IsAstcUnorm() || format.IsAstcSrgb();
}
/// <summary>
/// Checks if the texture format is an ASTC Unorm format.
/// </summary>
/// <param name="format">Texture format</param>
/// <returns>True if the texture format is an ASTC Unorm format, false otherwise</returns>
public static bool IsAstcUnorm(this Format format)
{
switch (format)
{
case Format.Astc4x4Unorm:
case Format.Astc5x4Unorm:
case Format.Astc5x5Unorm:
case Format.Astc6x5Unorm:
case Format.Astc6x6Unorm:
case Format.Astc8x5Unorm:
case Format.Astc8x6Unorm:
case Format.Astc8x8Unorm:
case Format.Astc10x5Unorm:
case Format.Astc10x6Unorm:
case Format.Astc10x8Unorm:
case Format.Astc10x10Unorm:
case Format.Astc12x10Unorm:
case Format.Astc12x12Unorm:
return true;
}
return false;
}
/// <summary>
/// Checks if the texture format is an ASTC SRGB format.
/// </summary>
/// <param name="format">Texture format</param>
/// <returns>True if the texture format is an ASTC SRGB format, false otherwise</returns>
public static bool IsAstcSrgb(this Format format)
{
switch (format)
{
case Format.Astc4x4Srgb:
case Format.Astc5x4Srgb:
case Format.Astc5x5Srgb:
case Format.Astc6x5Srgb:
case Format.Astc6x6Srgb:
case Format.Astc8x5Srgb:
case Format.Astc8x6Srgb:
case Format.Astc8x8Srgb:
case Format.Astc10x5Srgb:
case Format.Astc10x6Srgb:
case Format.Astc10x8Srgb:
case Format.Astc10x10Srgb:
case Format.Astc12x10Srgb:
case Format.Astc12x12Srgb:
return true;
}
return false;
}
/// <summary>
/// Checks if the texture format is an ETC2 format.
/// </summary>
/// <param name="format">Texture format</param>
/// <returns>True if the texture format is an ETC2 format, false otherwise</returns>
public static bool IsEtc2(this Format format)
{
switch (format)
{
case Format.Etc2RgbaSrgb:
case Format.Etc2RgbaUnorm:
case Format.Etc2RgbPtaSrgb:
case Format.Etc2RgbPtaUnorm:
case Format.Etc2RgbSrgb:
case Format.Etc2RgbUnorm:
return true;
}
return false;
}
/// <summary>
/// Checks if the texture format is a BGR format.
/// </summary>
/// <param name="format">Texture format</param>
/// <returns>True if the texture format is a BGR format, false otherwise</returns>
public static bool IsBgr(this Format format)
{
switch (format)
{
case Format.B5G6R5Unorm:
case Format.B5G5R5A1Unorm:
case Format.B8G8R8A8Unorm:
case Format.B8G8R8A8Srgb:
case Format.B10G10R10A2Unorm:
return true;
}
return false;
}
/// <summary>
/// Checks if the texture format is a depth, stencil or depth-stencil format.
/// </summary>
/// <param name="format">Texture format</param>
/// <returns>True if the format is a depth, stencil or depth-stencil format, false otherwise</returns>
public static bool IsDepthOrStencil(this Format format)
{
switch (format)
{
case Format.D16Unorm:
case Format.D24UnormS8Uint:
case Format.S8UintD24Unorm:
case Format.X8UintD24Unorm:
case Format.D32Float:
case Format.D32FloatS8Uint:
case Format.S8Uint:
return true;
}
return false;
}
/// <summary>
/// Checks if the texture format is an unsigned integer color format.
/// </summary>
/// <param name="format">Texture format</param>
/// <returns>True if the texture format is an unsigned integer color format, false otherwise</returns>
public static bool IsUint(this Format format)
{
switch (format)
{
case Format.R8Uint:
case Format.R16Uint:
case Format.R32Uint:
case Format.R8G8Uint:
case Format.R16G16Uint:
case Format.R32G32Uint:
case Format.R8G8B8Uint:
case Format.R16G16B16Uint:
case Format.R32G32B32Uint:
case Format.R8G8B8A8Uint:
case Format.R16G16B16A16Uint:
case Format.R32G32B32A32Uint:
case Format.R10G10B10A2Uint:
return true;
}
return false;
}
/// <summary>
/// Checks if the texture format is a signed integer color format.
/// </summary>
/// <param name="format">Texture format</param>
/// <returns>True if the texture format is a signed integer color format, false otherwise</returns>
public static bool IsSint(this Format format)
{
switch (format)
{
case Format.R8Sint:
case Format.R16Sint:
case Format.R32Sint:
case Format.R8G8Sint:
case Format.R16G16Sint:
case Format.R32G32Sint:
case Format.R8G8B8Sint:
case Format.R16G16B16Sint:
case Format.R32G32B32Sint:
case Format.R8G8B8A8Sint:
case Format.R16G16B16A16Sint:
case Format.R32G32B32A32Sint:
case Format.R10G10B10A2Sint:
return true;
}
return false;
}
/// <summary>
/// Checks if the texture format is an integer color format.
/// </summary>
/// <param name="format">Texture format</param>
/// <returns>True if the texture format is an integer color format, false otherwise</returns>
public static bool IsInteger(this Format format)
{
return format.IsUint() || format.IsSint();
}
/// <summary>
/// Checks if the texture format is a float or sRGB color format.
/// </summary>
/// <remarks>
/// Does not include normalized, compressed or depth formats.
/// Float and sRGB formats do not participate in logical operations.
/// </remarks>
/// <param name="format">Texture format</param>
/// <returns>True if the format is a float or sRGB color format, false otherwise</returns>
public static bool IsFloatOrSrgb(this Format format)
{
switch (format)
{
case Format.R8G8B8A8Srgb:
case Format.B8G8R8A8Srgb:
case Format.R16Float:
case Format.R16G16Float:
case Format.R16G16B16Float:
case Format.R16G16B16A16Float:
case Format.R32Float:
case Format.R32G32Float:
case Format.R32G32B32Float:
case Format.R32G32B32A32Float:
case Format.R11G11B10Float:
case Format.R9G9B9E5Float:
return true;
}
return false;
/// <summary>
/// Checks if the texture format is an integer color format.
/// </summary>
public bool IsInt => fmt.IsUnsignedInt || fmt.IsSignedInt;
}
}
}

View File

@@ -16,19 +16,18 @@ namespace Ryujinx.Graphics.GAL
public static class TargetExtensions
{
public static bool IsMultisample(this Target target)
extension(Target target)
{
return target is Target.Texture2DMultisample or Target.Texture2DMultisampleArray;
}
public bool IsMultisample => target is Target.Texture2DMultisample or Target.Texture2DMultisampleArray;
public static bool HasDepthOrLayers(this Target target)
{
return target is Target.Texture3D or
Target.Texture1DArray or
Target.Texture2DArray or
Target.Texture2DMultisampleArray or
Target.Cubemap or
Target.CubemapArray;
public bool HasDepthOrLayers =>
target is
Target.Texture3D or
Target.Texture1DArray or
Target.Texture2DArray or
Target.Texture2DMultisampleArray or
Target.Cubemap or
Target.CubemapArray;
}
}
}

View File

@@ -171,7 +171,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.InlineToMemory
{
MemoryManager memoryManager = _channel.MemoryManager;
Span<byte> data = MemoryMarshal.Cast<int, byte>(_buffer)[.._size];
Span<byte> data = MemoryMarshal.Cast<int, byte>(new Span<int>(_buffer))[.._size];
if (_isLinear && _lineCount == 1)
{

View File

@@ -176,7 +176,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed.ComputeDraw
ulong vbSize = GetVertexBufferSize(address, endAddress.Pack(), vbStride, _indexed, instanced, _firstVertex, _count);
ulong attributeOffset = (ulong)vertexAttrib.UnpackOffset();
int componentSize = format.GetScalarSize();
int componentSize = format.ScalarSize;
address += attributeOffset;

View File

@@ -849,8 +849,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
FormatInfo dsFormat = _state.State.RtDepthStencilState.Format.Convert();
bool hasDepth = dsFormat.Format.HasDepth();
bool hasStencil = dsFormat.Format.HasStencil();
bool hasDepth = dsFormat.Format.HasDepth;
bool hasStencil = dsFormat.Format.HasStencil;
if (hasStencil && (!clearStencil || (clearAffectedByStencilMask && _state.State.StencilTestState.FrontMask != 0xff)))
{

View File

@@ -298,7 +298,9 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
{
Format format = colorState.Format.Convert().Format;
AttributeType type = format.IsInteger() ? (format.IsSint() ? AttributeType.Sint : AttributeType.Uint) : AttributeType.Float;
AttributeType type = format.IsInt
? (format.IsSignedInt ? AttributeType.Sint : AttributeType.Uint)
: AttributeType.Float;
if (type != fragmentOutputTypesSpan[index])
{

View File

@@ -534,7 +534,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
if (!_context.Capabilities.SupportsBgraFormat)
{
_context.SupportBufferUpdater.SetRenderTargetIsBgra(index, color.Format.IsBgr());
_context.SupportBufferUpdater.SetRenderTargetIsBgra(index, color.Format.IsBgr);
}
}
}
@@ -1317,10 +1317,10 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
FilterBlendFactor(blend.AlphaDstFactor, index));
if (enable &&
(blend.ColorSrcFactor.IsDualSource() ||
blend.ColorDstFactor.IsDualSource() ||
blend.AlphaSrcFactor.IsDualSource() ||
blend.AlphaDstFactor.IsDualSource()))
(blend.ColorSrcFactor.IsDualSource ||
blend.ColorDstFactor.IsDualSource ||
blend.AlphaSrcFactor.IsDualSource ||
blend.AlphaDstFactor.IsDualSource))
{
dualSourceBlendEnabled = true;
}
@@ -1345,10 +1345,10 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
FilterBlendFactor(blend.AlphaDstFactor, 0));
if (enable &&
(blend.ColorSrcFactor.IsDualSource() ||
blend.ColorDstFactor.IsDualSource() ||
blend.AlphaSrcFactor.IsDualSource() ||
blend.AlphaDstFactor.IsDualSource()))
(blend.ColorSrcFactor.IsDualSource ||
blend.ColorDstFactor.IsDualSource ||
blend.AlphaSrcFactor.IsDualSource ||
blend.AlphaDstFactor.IsDualSource))
{
dualSourceBlendEnabled = true;
}

View File

@@ -333,7 +333,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Twod
// as copies between depth and color formats are not allowed.
// For depth blit, the destination texture format should always match exactly.
if (srcTexture.Format.IsDepthOrStencil())
if (srcTexture.Format.IsDepthOrStencil)
{
dstCopyTextureFormat = srcTexture.Info.FormatInfo;
}

View File

@@ -661,7 +661,7 @@ namespace Ryujinx.Graphics.Gpu.Image
bool found = _textureFormats.TryGetValue((TextureFormat)encoded, out format);
if (found && isPacked && !format.Format.IsDepthOrStencil())
if (found && isPacked && !format.Format.IsDepthOrStencil)
{
// If the packed flag is set, then the components of the pixel are tightly packed into the
// GPU registers on the shader.

View File

@@ -643,7 +643,7 @@ namespace Ryujinx.Graphics.Gpu.Image
// The decompression is slow, so we want to avoid it as much as possible.
// This does a byte-by-byte check and skips the update if the data is equal in this case.
// This improves the speed on applications that overwrites ASTC data without changing anything.
if (Info.FormatInfo.Format.IsAstc() && !_context.Capabilities.SupportsAstcCompression)
if (Info.FormatInfo.Format.IsAstc && !_context.Capabilities.SupportsAstcCompression)
{
if (_updateCount < ByteComparisonSwitchThreshold)
{
@@ -792,7 +792,7 @@ namespace Ryujinx.Graphics.Gpu.Image
// Handle compressed cases not supported by the host:
// - ASTC is usually not supported on desktop cards.
// - BC4/BC5 is not supported on 3D textures.
if (!_context.Capabilities.SupportsAstcCompression && Format.IsAstc())
if (!_context.Capabilities.SupportsAstcCompression && Format.IsAstc)
{
using (result)
{
@@ -823,7 +823,7 @@ namespace Ryujinx.Graphics.Gpu.Image
return decoded;
}
}
else if (!_context.Capabilities.SupportsEtc2Compression && Format.IsEtc2())
else if (!_context.Capabilities.SupportsEtc2Compression && Format.IsEtc2)
{
switch (Format)
{
@@ -924,7 +924,7 @@ namespace Ryujinx.Graphics.Gpu.Image
}
}
}
else if (!_context.Capabilities.Supports5BitComponentFormat && Format.Is16BitPacked())
else if (!_context.Capabilities.Supports5BitComponentFormat && Format.Is16BitPacked)
{
switch (Format)
{
@@ -1251,7 +1251,7 @@ namespace Ryujinx.Graphics.Gpu.Image
{
result = TextureCompatibility.PropagateViewCompatibility(result, TextureCompatibility.ViewTargetCompatible(Info, info, ref caps));
bool bothMs = Info.Target.IsMultisample() && info.Target.IsMultisample();
bool bothMs = Info.Target.IsMultisample && info.Target.IsMultisample;
if (bothMs && (Info.SamplesInX != info.SamplesInX || Info.SamplesInY != info.SamplesInY))
{
result = TextureViewCompatibility.Incompatible;

View File

@@ -180,7 +180,7 @@ namespace Ryujinx.Graphics.Gpu.Image
int widthAlignment = (info.IsLinear ? Constants.StrideAlignment : Constants.GobAlignment) / info.FormatInfo.BytesPerPixel;
if (!(info.FormatInfo.Format.IsDepthOrStencil() || info.FormatInfo.Components == 1))
if (!(info.FormatInfo.Format.IsDepthOrStencil || info.FormatInfo.Components == 1))
{
// Discount square textures that aren't depth-stencil like. (excludes game textures, cubemap faces, most 3D texture LUT, texture atlas)
// Detect if the texture is possibly square. Widths may be aligned, so to remove the uncertainty we align both the width and height.

View File

@@ -75,13 +75,14 @@ namespace Ryujinx.Graphics.Gpu.Image
if (!caps.SupportsAstcCompression)
{
if (info.FormatInfo.Format.IsAstcUnorm())
if (info.FormatInfo.Format.IsAstcUnorm)
{
return GraphicsConfig.EnableTextureRecompression
? new FormatInfo(Format.Bc7Unorm, 4, 4, 16, 4)
: new FormatInfo(Format.R8G8B8A8Unorm, 1, 1, 4, 4);
}
else if (info.FormatInfo.Format.IsAstcSrgb())
if (info.FormatInfo.Format.IsAstcSrgb)
{
return GraphicsConfig.EnableTextureRecompression
? new FormatInfo(Format.Bc7Srgb, 4, 4, 16, 4)
@@ -151,9 +152,9 @@ namespace Ryujinx.Graphics.Gpu.Image
return new FormatInfo(Format.R8G8B8A8Unorm, 1, 1, 4, 4);
}
}
else if (!caps.Supports5BitComponentFormat && info.FormatInfo.Format.Is16BitPacked())
else if (!caps.Supports5BitComponentFormat && info.FormatInfo.Format.Is16BitPacked)
{
return new FormatInfo(info.FormatInfo.Format.IsBgr() ? Format.B8G8R8A8Unorm : Format.R8G8B8A8Unorm, 1, 1, 4, 4);
return new FormatInfo(info.FormatInfo.Format.IsBgr ? Format.B8G8R8A8Unorm : Format.R8G8B8A8Unorm, 1, 1, 4, 4);
}
return info.FormatInfo;
@@ -388,7 +389,7 @@ namespace Ryujinx.Graphics.Gpu.Image
return stride == rhs.Stride ? TextureViewCompatibility.CopyOnly : TextureViewCompatibility.LayoutIncompatible;
}
else if (lhs.Target.IsMultisample() != rhs.Target.IsMultisample() && alignedWidthMatches && lhsAlignedSize.Height == rhsAlignedSize.Height)
else if (lhs.Target.IsMultisample != rhs.Target.IsMultisample && alignedWidthMatches && lhsAlignedSize.Height == rhsAlignedSize.Height)
{
// Copy between multisample and non-multisample textures with mismatching size is allowed,
// as long aligned size matches.
@@ -644,7 +645,7 @@ namespace Ryujinx.Graphics.Gpu.Image
FormatInfo lhsFormat = lhs.FormatInfo;
FormatInfo rhsFormat = rhs.FormatInfo;
if (lhsFormat.Format.IsDepthOrStencil() || rhsFormat.Format.IsDepthOrStencil())
if (lhsFormat.Format.IsDepthOrStencil || rhsFormat.Format.IsDepthOrStencil)
{
bool forSampler = flags.HasFlag(TextureSearchFlags.ForSampler);
bool depthAlias = flags.HasFlag(TextureSearchFlags.DepthAlias);

View File

@@ -139,7 +139,7 @@ namespace Ryujinx.Graphics.Gpu.Image
_allOffsets = size.AllOffsets;
_sliceSizes = size.SliceSizes;
if (Storage.Target.HasDepthOrLayers() && Storage.Info.GetSlices() > GranularLayerThreshold)
if (Storage.Target.HasDepthOrLayers && Storage.Info.GetSlices() > GranularLayerThreshold)
{
_hasLayerViews = true;
_hasMipViews = true;

View File

@@ -649,7 +649,7 @@ namespace Ryujinx.Graphics.Gpu.Image
swizzleB,
swizzleA);
if (formatInfo.Format.IsDepthOrStencil())
if (formatInfo.Format.IsDepthOrStencil)
{
swizzleR = SwizzleComponent.Red;
swizzleG = SwizzleComponent.Red;

View File

@@ -487,10 +487,12 @@ namespace Ryujinx.Graphics.Gpu.Memory
/// <param name="stage">The type of usage that created the buffer</param>
private void CreateBufferAligned(ulong address, ulong size, BufferStage stage)
{
Buffer newBuffer = null;
_buffers.Lock.EnterWriteLock();
Span<RangeItem<Buffer>> overlaps = _buffers.FindOverlapsAsSpan(address, size);
if (overlaps.Length > 0)
if (overlaps.Length != 0)
{
// The buffer already exists. We can just return the existing buffer
// if the buffer we need is fully contained inside the overlapping buffer.
@@ -531,35 +533,42 @@ namespace Ryujinx.Graphics.Gpu.Memory
address = Math.Min(address, overlaps[0].Address);
endAddress = Math.Max(endAddress, overlaps[^1].EndAddress);
RangeItem<Buffer>[] overlapsArray = overlaps.ToArray();
for (int i = 0; i < overlaps.Length; i++)
{
anySparseCompatible |= overlaps[i].Value.SparseCompatible;
}
RangeItem<Buffer>[] overlapsArray = overlaps.ToArray();
_buffers.RemoveRange(overlaps[0], overlaps[^1]);
_buffers.Lock.ExitWriteLock();
ulong newSize = endAddress - address;
Buffer newBuffer = CreateBufferAligned(address, newSize, stage, anySparseCompatible, overlapsArray);
_buffers.Lock.EnterWriteLock();
_buffers.Add(newBuffer);
newBuffer = CreateBufferAligned(address, newSize, stage, anySparseCompatible, overlapsArray);
}
else
{
_buffers.Lock.ExitWriteLock();
}
}
else
{
// No overlap, just create a new buffer.
Buffer buffer = new(_context, _physicalMemory, address, size, stage, sparseCompatible: false, []);
_buffers.Lock.ExitWriteLock();
_buffers.Add(buffer);
// No overlap, just create a new buffer.
newBuffer = new(_context, _physicalMemory, address, size, stage, sparseCompatible: false, []);
}
_buffers.Lock.ExitWriteLock();
if (newBuffer is not null)
{
_buffers.Lock.EnterWriteLock();
_buffers.Add(newBuffer);
_buffers.Lock.ExitWriteLock();
}
}
/// <summary>
@@ -574,11 +583,12 @@ namespace Ryujinx.Graphics.Gpu.Memory
private void CreateBufferAligned(ulong address, ulong size, BufferStage stage, ulong alignment)
{
bool sparseAligned = alignment >= SparseBufferAlignmentSize;
Buffer newBuffer = null;
_buffers.Lock.EnterWriteLock();
Span<RangeItem<Buffer>> overlaps = _buffers.FindOverlapsAsSpan(address, size);
if (overlaps.Length > 0)
if (overlaps.Length != 0)
{
// If the buffer already exists, make sure if covers the entire range,
// and make sure it is properly aligned, otherwise sparse mapping may fail.
@@ -595,19 +605,20 @@ namespace Ryujinx.Graphics.Gpu.Memory
// overlaps more buffers, so try again after each extension
// and ensure we cover all overlaps.
RangeItem<Buffer> oldFirst;
endAddress = Math.Max(endAddress, overlaps[^1].EndAddress);
int oldOverlapCount;
do
{
address = Math.Min(address, overlaps[0].Address);
endAddress = Math.Max(endAddress, overlaps[^1].EndAddress);
address &= ~(alignment - 1);
oldFirst = overlaps[0];
oldOverlapCount = overlaps.Length;
overlaps = _buffers.FindOverlapsAsSpan(address, endAddress - address);
}
while (oldFirst != overlaps[0]);
while (oldOverlapCount != overlaps.Length);
ulong newSize = endAddress - address;
@@ -617,22 +628,29 @@ namespace Ryujinx.Graphics.Gpu.Memory
_buffers.Lock.ExitWriteLock();
Buffer newBuffer = CreateBufferAligned(address, newSize, stage, sparseAligned, overlapsArray);
_buffers.Lock.EnterWriteLock();
_buffers.Add(newBuffer);
newBuffer = CreateBufferAligned(address, newSize, stage, sparseAligned, overlapsArray);
}
else
{
_buffers.Lock.ExitWriteLock();
}
}
else
{
// No overlap, just create a new buffer.
Buffer buffer = new(_context, _physicalMemory, address, size, stage, sparseAligned, []);
_buffers.Lock.ExitWriteLock();
_buffers.Add(buffer);
// No overlap, just create a new buffer.
newBuffer = new(_context, _physicalMemory, address, size, stage, sparseAligned, []);
}
_buffers.Lock.ExitWriteLock();
if (newBuffer is not null)
{
_buffers.Lock.EnterWriteLock();
_buffers.Add(newBuffer);
_buffers.Lock.ExitWriteLock();
}
}
/// <summary>
@@ -879,7 +897,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
{
MemoryRange subRange = range.GetSubRange(i);
Buffer subBuffer = _buffers.FindOverlapFast(subRange.Address, subRange.Size).Value;
Buffer subBuffer = _buffers.FindOverlap(subRange.Address, subRange.Size).Value;
subBuffer.SynchronizeMemory(subRange.Address, subRange.Size);
@@ -977,7 +995,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
{
if (size != 0)
{
Buffer buffer = _buffers.FindOverlapFast(address, size).Value;
Buffer buffer = _buffers.FindOverlap(address, size).Value;
if (copyBackVirtual)
{

View File

@@ -473,6 +473,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
ranges._migrationTarget = this;
Lock.EnterWriteLock();
foreach (BufferModifiedRange range in inheritRanges)
{
Add(range);

View File

@@ -8,7 +8,7 @@ namespace Ryujinx.Graphics.OpenGL
{
public static void Clear(BufferHandle destination, int offset, int size, uint value)
{
GL.BindBuffer(BufferTarget.CopyWriteBuffer, destination.ToInt32());
GL.BindBuffer(BufferTarget.CopyWriteBuffer, destination);
unsafe
{
@@ -58,8 +58,8 @@ namespace Ryujinx.Graphics.OpenGL
public static void Copy(BufferHandle source, BufferHandle destination, int srcOffset, int dstOffset, int size)
{
GL.BindBuffer(BufferTarget.CopyReadBuffer, source.ToInt32());
GL.BindBuffer(BufferTarget.CopyWriteBuffer, destination.ToInt32());
GL.BindBuffer(BufferTarget.CopyReadBuffer, source);
GL.BindBuffer(BufferTarget.CopyWriteBuffer, destination);
GL.CopyBufferSubData(
BufferTarget.CopyReadBuffer,
@@ -86,7 +86,7 @@ namespace Ryujinx.Graphics.OpenGL
{
nint target = renderer.PersistentBuffers.Default.GetHostArray(size);
GL.BindBuffer(BufferTarget.CopyReadBuffer, buffer.ToInt32());
GL.BindBuffer(BufferTarget.CopyReadBuffer, buffer);
GL.GetBufferSubData(BufferTarget.CopyReadBuffer, (nint)offset, size, target);
@@ -96,13 +96,13 @@ namespace Ryujinx.Graphics.OpenGL
public static void Resize(BufferHandle handle, int size)
{
GL.BindBuffer(BufferTarget.CopyWriteBuffer, handle.ToInt32());
GL.BindBuffer(BufferTarget.CopyWriteBuffer, handle);
GL.BufferData(BufferTarget.CopyWriteBuffer, size, nint.Zero, BufferUsageHint.StreamCopy);
}
public static void SetData(BufferHandle buffer, int offset, ReadOnlySpan<byte> data)
{
GL.BindBuffer(BufferTarget.CopyWriteBuffer, buffer.ToInt32());
GL.BindBuffer(BufferTarget.CopyWriteBuffer, buffer);
unsafe
{
@@ -115,7 +115,7 @@ namespace Ryujinx.Graphics.OpenGL
public static void Delete(BufferHandle buffer)
{
GL.DeleteBuffer(buffer.ToInt32());
GL.DeleteBuffer(buffer);
}
}
}

View File

@@ -1,4 +1,3 @@
using Ryujinx.Graphics.GAL;
using System.Diagnostics;
using System.Runtime.CompilerServices;
@@ -14,10 +13,5 @@ namespace Ryujinx.Graphics.OpenGL
return Unsafe.As<ulong, T>(ref handle64);
}
public static int ToInt32(this BufferHandle handle)
{
return (int)Unsafe.As<BufferHandle, ulong>(ref handle);
}
}
}

View File

@@ -139,7 +139,7 @@ namespace Ryujinx.Graphics.OpenGL.Image
start = sizeAligned;
}
Span<uint> outSpan = MemoryMarshal.Cast<byte, uint>(output);
Span<uint> outSpan = MemoryMarshal.Cast<byte, uint>(new Span<byte>(output));
ReadOnlySpan<uint> dataSpan = MemoryMarshal.Cast<byte, uint>(data);
for (int i = start / sizeof(uint); i < dataSpan.Length; i++)
{

View File

@@ -97,7 +97,7 @@ namespace Ryujinx.Graphics.OpenGL.Image
SizedInternalFormat format = (SizedInternalFormat)FormatTable.GetFormatInfo(Info.Format).PixelInternalFormat;
GL.TexBufferRange(TextureBufferTarget.TextureBuffer, format, _buffer.ToInt32(), (nint)buffer.Offset, buffer.Size);
GL.TexBufferRange(TextureBufferTarget.TextureBuffer, format, _buffer, (nint)buffer.Offset, buffer.Size);
}
public void Dispose()

View File

@@ -53,7 +53,7 @@ namespace Ryujinx.Graphics.OpenGL.Image
int layers,
int levels)
{
TextureView srcConverted = src.Format.IsBgr() != dst.Format.IsBgr() ? BgraSwap(src) : src;
TextureView srcConverted = src.Format.IsBgr != dst.Format.IsBgr ? BgraSwap(src) : src;
(int oldDrawFramebufferHandle, int oldReadFramebufferHandle) = ((Pipeline)_renderer.Pipeline).GetBoundFramebuffers();
@@ -87,7 +87,7 @@ namespace Ryujinx.Graphics.OpenGL.Image
ClearBufferMask mask = GetMask(src.Format);
if ((mask & (ClearBufferMask.DepthBufferBit | ClearBufferMask.StencilBufferBit)) != 0 || src.Format.IsInteger())
if ((mask & (ClearBufferMask.DepthBufferBit | ClearBufferMask.StencilBufferBit)) != 0 || src.Format.IsInt)
{
linearFilter = false;
}

View File

@@ -84,7 +84,7 @@ namespace Ryujinx.Graphics.OpenGL.Image
swizzleRgba[2] = temp2;
swizzleRgba[3] = temp;
}
else if (Info.Format.IsBgr())
else if (Info.Format.IsBgr)
{
// Swap B <-> R for BGRA formats, as OpenGL has no support for them
// and we need to manually swap the components on read/write on the GPU.
@@ -116,13 +116,13 @@ namespace Ryujinx.Graphics.OpenGL.Image
{
TextureView destinationView = (TextureView)destination;
bool srcIsMultisample = Target.IsMultisample();
bool dstIsMultisample = destinationView.Target.IsMultisample();
bool srcIsMultisample = Target.IsMultisample;
bool dstIsMultisample = destinationView.Target.IsMultisample;
if (dstIsMultisample != srcIsMultisample && Info.Format.IsDepthOrStencil())
if (dstIsMultisample != srcIsMultisample && Info.Format.IsDepthOrStencil)
{
int layers = Math.Min(Info.GetLayers(), destinationView.Info.GetLayers() - firstLayer);
CopyWithBlitForDepthMS(destinationView, 0, firstLayer, layers);
CopyWithBlitForDepthMultisample(destinationView, 0, firstLayer, layers);
}
else if (!dstIsMultisample && srcIsMultisample)
{
@@ -140,7 +140,7 @@ namespace Ryujinx.Graphics.OpenGL.Image
int levels = Math.Min(Info.Levels, destinationView.Info.Levels - firstLevel);
_renderer.TextureCopyIncompatible.CopyIncompatibleFormats(this, destinationView, 0, firstLayer, 0, firstLevel, layers, levels);
}
else if (destinationView.Format.IsDepthOrStencil() != Format.IsDepthOrStencil())
else if (destinationView.Format.IsDepthOrStencil != Format.IsDepthOrStencil)
{
int layers = Math.Min(Info.GetLayers(), destinationView.Info.GetLayers() - firstLayer);
int levels = Math.Min(Info.Levels, destinationView.Info.Levels - firstLevel);
@@ -172,12 +172,12 @@ namespace Ryujinx.Graphics.OpenGL.Image
{
TextureView destinationView = (TextureView)destination;
bool srcIsMultisample = Target.IsMultisample();
bool dstIsMultisample = destinationView.Target.IsMultisample();
bool srcIsMultisample = Target.IsMultisample;
bool dstIsMultisample = destinationView.Target.IsMultisample;
if (dstIsMultisample != srcIsMultisample && Info.Format.IsDepthOrStencil())
if (dstIsMultisample != srcIsMultisample && Info.Format.IsDepthOrStencil)
{
CopyWithBlitForDepthMS(destinationView, srcLayer, dstLayer, 1);
CopyWithBlitForDepthMultisample(destinationView, srcLayer, dstLayer, 1);
}
else if (!dstIsMultisample && srcIsMultisample)
{
@@ -191,7 +191,7 @@ namespace Ryujinx.Graphics.OpenGL.Image
{
_renderer.TextureCopyIncompatible.CopyIncompatibleFormats(this, destinationView, srcLayer, dstLayer, srcLevel, dstLevel, 1, 1);
}
else if (destinationView.Format.IsDepthOrStencil() != Format.IsDepthOrStencil())
else if (destinationView.Format.IsDepthOrStencil != Format.IsDepthOrStencil)
{
int minWidth = Math.Min(Width, destinationView.Width);
int minHeight = Math.Min(Height, destinationView.Height);
@@ -204,7 +204,7 @@ namespace Ryujinx.Graphics.OpenGL.Image
}
}
private void CopyWithBlitForDepthMS(TextureView destinationView, int srcLayer, int dstLayer, int layers)
private void CopyWithBlitForDepthMultisample(TextureView destinationView, int srcLayer, int dstLayer, int layers)
{
// This is currently used for multisample <-> non-multisample copies.
// We can't do that with compute because it's not possible to write depth textures on compute.
@@ -216,9 +216,9 @@ namespace Ryujinx.Graphics.OpenGL.Image
Extents2D srcRegion = new(0, 0, Width, Height);
Extents2D dstRegion = new(0, 0, destinationView.Width, destinationView.Height);
if (destinationView.Target.IsMultisample())
if (destinationView.Target.IsMultisample)
{
TextureView intermmediate = _renderer.TextureCopy.IntermediatePool.GetOrCreateWithAtLeast(
TextureView intermediate = _renderer.TextureCopy.IntermediatePool.GetOrCreateWithAtLeast(
Info.Target,
Info.BlockWidth,
Info.BlockHeight,
@@ -230,8 +230,8 @@ namespace Ryujinx.Graphics.OpenGL.Image
1,
1);
_renderer.TextureCopy.Copy(this, intermmediate, srcRegion, dstRegion, false);
_renderer.TextureCopy.Copy(intermmediate, destinationView, dstRegion, dstRegion, false, srcLayer, dstLayer, 0, 0, layers, 1);
_renderer.TextureCopy.Copy(this, intermediate, srcRegion, dstRegion, false);
_renderer.TextureCopy.Copy(intermediate, destinationView, dstRegion, dstRegion, false, srcLayer, dstLayer, 0, 0, layers, 1);
}
else
{
@@ -242,7 +242,7 @@ namespace Ryujinx.Graphics.OpenGL.Image
_ => Target,
};
TextureView intermmediate = _renderer.TextureCopy.IntermediatePool.GetOrCreateWithAtLeast(
TextureView intermediate = _renderer.TextureCopy.IntermediatePool.GetOrCreateWithAtLeast(
target,
Info.BlockWidth,
Info.BlockHeight,
@@ -254,8 +254,8 @@ namespace Ryujinx.Graphics.OpenGL.Image
1,
1);
_renderer.TextureCopy.Copy(this, intermmediate, srcRegion, srcRegion, false);
_renderer.TextureCopy.Copy(intermmediate, destinationView, srcRegion, dstRegion, false, srcLayer, dstLayer, 0, 0, layers, 1);
_renderer.TextureCopy.Copy(this, intermediate, srcRegion, srcRegion, false);
_renderer.TextureCopy.Copy(intermediate, destinationView, srcRegion, dstRegion, false, srcLayer, dstLayer, 0, 0, layers, 1);
}
}
@@ -305,14 +305,12 @@ namespace Ryujinx.Graphics.OpenGL.Image
{
return PinnedSpan<byte>.UnsafeFromSpan(_renderer.PersistentBuffers.Default.GetTextureData(this, size, layer, level));
}
else
{
nint target = _renderer.PersistentBuffers.Default.GetHostArray(size);
int offset = WriteTo2D(target, layer, level);
nint target = _renderer.PersistentBuffers.Default.GetHostArray(size);
return new PinnedSpan<byte>((byte*)target.ToPointer() + offset, size);
}
int offset = WriteTo2D(target, layer, level);
return new PinnedSpan<byte>((byte*)target.ToPointer() + offset, size);
}
public void CopyTo(BufferRange range, int layer, int level, int stride)
@@ -322,7 +320,7 @@ namespace Ryujinx.Graphics.OpenGL.Image
throw new NotSupportedException("Stride conversion for texture copy to buffer not supported.");
}
GL.BindBuffer(BufferTarget.PixelPackBuffer, range.Handle.ToInt32());
GL.BindBuffer(BufferTarget.PixelPackBuffer, range.Handle);
FormatInfo format = FormatTable.GetFormatInfo(Info.Format);
if (format.PixelFormat == PixelFormat.DepthStencil)

View File

@@ -26,7 +26,7 @@ namespace Ryujinx.Graphics.OpenGL
public void Map(BufferHandle handle, int size)
{
GL.BindBuffer(BufferTarget.CopyWriteBuffer, handle.ToInt32());
GL.BindBuffer(BufferTarget.CopyWriteBuffer, handle);
nint ptr = GL.MapBufferRange(BufferTarget.CopyWriteBuffer, nint.Zero, size, BufferAccessMask.MapReadBit | BufferAccessMask.MapPersistentBit);
_maps[handle] = ptr;
@@ -36,7 +36,7 @@ namespace Ryujinx.Graphics.OpenGL
{
if (_maps.ContainsKey(handle))
{
GL.BindBuffer(BufferTarget.CopyWriteBuffer, handle.ToInt32());
GL.BindBuffer(BufferTarget.CopyWriteBuffer, handle);
GL.UnmapBuffer(BufferTarget.CopyWriteBuffer);
_maps.Remove(handle);
@@ -140,7 +140,7 @@ namespace Ryujinx.Graphics.OpenGL
{
EnsureBuffer(size);
GL.BindBuffer(BufferTarget.CopyReadBuffer, buffer.ToInt32());
GL.BindBuffer(BufferTarget.CopyReadBuffer, buffer);
GL.BindBuffer(BufferTarget.CopyWriteBuffer, _copyBufferHandle);
GL.CopyBufferSubData(BufferTarget.CopyReadBuffer, BufferTarget.CopyWriteBuffer, (nint)offset, nint.Zero, size);

View File

@@ -587,7 +587,7 @@ namespace Ryujinx.Graphics.OpenGL
_vertexArray.SetRangeOfIndexBuffer();
GL.BindBuffer((BufferTarget)All.DrawIndirectBuffer, indirectBuffer.Handle.ToInt32());
GL.BindBuffer((BufferTarget)All.DrawIndirectBuffer, indirectBuffer.Handle);
GL.DrawElementsIndirect(_primitiveType, _elementsType, (nint)indirectBuffer.Offset);
@@ -608,8 +608,8 @@ namespace Ryujinx.Graphics.OpenGL
_vertexArray.SetRangeOfIndexBuffer();
GL.BindBuffer((BufferTarget)All.DrawIndirectBuffer, indirectBuffer.Handle.ToInt32());
GL.BindBuffer((BufferTarget)All.ParameterBuffer, parameterBuffer.Handle.ToInt32());
GL.BindBuffer((BufferTarget)All.DrawIndirectBuffer, indirectBuffer.Handle);
GL.BindBuffer((BufferTarget)All.ParameterBuffer, parameterBuffer.Handle);
GL.MultiDrawElementsIndirectCount(
_primitiveType,
@@ -634,7 +634,7 @@ namespace Ryujinx.Graphics.OpenGL
PreDrawVbUnbounded();
GL.BindBuffer((BufferTarget)All.DrawIndirectBuffer, indirectBuffer.Handle.ToInt32());
GL.BindBuffer((BufferTarget)All.DrawIndirectBuffer, indirectBuffer.Handle);
GL.DrawArraysIndirect(_primitiveType, (nint)indirectBuffer.Offset);
@@ -651,8 +651,8 @@ namespace Ryujinx.Graphics.OpenGL
PreDrawVbUnbounded();
GL.BindBuffer((BufferTarget)All.DrawIndirectBuffer, indirectBuffer.Handle.ToInt32());
GL.BindBuffer((BufferTarget)All.ParameterBuffer, parameterBuffer.Handle.ToInt32());
GL.BindBuffer((BufferTarget)All.DrawIndirectBuffer, indirectBuffer.Handle);
GL.BindBuffer((BufferTarget)All.ParameterBuffer, parameterBuffer.Handle);
GL.MultiDrawArraysIndirectCount(
_primitiveType,
@@ -812,10 +812,10 @@ namespace Ryujinx.Graphics.OpenGL
EnsureFramebuffer();
_framebuffer.SetDualSourceBlend(
blend.ColorSrcFactor.IsDualSource() ||
blend.ColorDstFactor.IsDualSource() ||
blend.AlphaSrcFactor.IsDualSource() ||
blend.AlphaDstFactor.IsDualSource());
blend.ColorSrcFactor.IsDualSource ||
blend.ColorDstFactor.IsDualSource ||
blend.AlphaSrcFactor.IsDualSource ||
blend.AlphaDstFactor.IsDualSource);
if (_blendConstant != blend.BlendConstant)
{
@@ -1178,7 +1178,7 @@ namespace Ryujinx.Graphics.OpenGL
if (color != null)
{
int isBgra = color.Format.IsBgr() ? 1 : 0;
int isBgra = color.Format.IsBgr ? 1 : 0;
if (_fpIsBgra[index].X != isBgra)
{
@@ -1349,7 +1349,7 @@ namespace Ryujinx.Graphics.OpenGL
Buffer.Resize(_tfbs[i], buffer.Size);
Buffer.Copy(buffer.Handle, _tfbs[i], buffer.Offset, 0, buffer.Size);
GL.BindBufferBase(BufferRangeTarget.TransformFeedbackBuffer, i, _tfbs[i].ToInt32());
GL.BindBufferBase(BufferRangeTarget.TransformFeedbackBuffer, i, _tfbs[i]);
}
if (_tfEnabled)
@@ -1454,7 +1454,7 @@ namespace Ryujinx.Graphics.OpenGL
continue;
}
GL.BindBufferRange(target, assignment.Binding, buffer.Handle.ToInt32(), (nint)buffer.Offset, buffer.Size);
GL.BindBufferRange(target, assignment.Binding, buffer.Handle, (nint)buffer.Offset, buffer.Size);
}
}

View File

@@ -56,7 +56,7 @@ namespace Ryujinx.Graphics.OpenGL
minVertexCount = vertexCount;
}
GL.BindVertexBuffer(bindingIndex, vb.Buffer.Handle.ToInt32(), (nint)vb.Buffer.Offset, vb.Stride);
GL.BindVertexBuffer(bindingIndex, vb.Buffer.Handle, (nint)vb.Buffer.Offset, vb.Stride);
GL.VertexBindingDivisor(bindingIndex, vb.Divisor);
_vertexBuffersInUse |= 1u << bindingIndex;
}
@@ -134,19 +134,19 @@ namespace Ryujinx.Graphics.OpenGL
public void SetIndexBuffer(BufferRange range)
{
_indexBuffer = range;
GL.BindBuffer(BufferTarget.ElementArrayBuffer, range.Handle.ToInt32());
GL.BindBuffer(BufferTarget.ElementArrayBuffer, range.Handle);
}
public void SetRangeOfIndexBuffer()
{
Buffer.Resize(_tempIndexBuffer, _indexBuffer.Size);
Buffer.Copy(_indexBuffer.Handle, _tempIndexBuffer, _indexBuffer.Offset, 0, _indexBuffer.Size);
GL.BindBuffer(BufferTarget.ElementArrayBuffer, _tempIndexBuffer.ToInt32());
GL.BindBuffer(BufferTarget.ElementArrayBuffer, _tempIndexBuffer);
}
public void RestoreIndexBuffer()
{
GL.BindBuffer(BufferTarget.ElementArrayBuffer, _indexBuffer.Handle.ToInt32());
GL.BindBuffer(BufferTarget.ElementArrayBuffer, _indexBuffer.Handle);
}
public void PreDraw(int vertexCount)
@@ -188,7 +188,7 @@ namespace Ryujinx.Graphics.OpenGL
Buffer.Copy(vb.Buffer.Handle, tempVertexBuffer, vb.Buffer.Offset, currentTempVbOffset, vb.Buffer.Size);
Buffer.Clear(tempVertexBuffer, currentTempVbOffset + vb.Buffer.Size, requiredSize - vb.Buffer.Size, 0);
GL.BindVertexBuffer(vbIndex, tempVertexBuffer.ToInt32(), (nint)currentTempVbOffset, vb.Stride);
GL.BindVertexBuffer(vbIndex, tempVertexBuffer, (nint)currentTempVbOffset, vb.Stride);
currentTempVbOffset += requiredSize;
_vertexBuffersLimited |= 1u << vbIndex;
@@ -234,7 +234,7 @@ namespace Ryujinx.Graphics.OpenGL
ref VertexBufferDescriptor vb = ref _vertexBuffers[vbIndex];
GL.BindVertexBuffer(vbIndex, vb.Buffer.Handle.ToInt32(), (nint)vb.Buffer.Offset, vb.Stride);
GL.BindVertexBuffer(vbIndex, vb.Buffer.Handle, (nint)vb.Buffer.Offset, vb.Stride);
buffersLimited &= ~(1u << vbIndex);
}

View File

@@ -70,7 +70,7 @@ namespace Ryujinx.Graphics.OpenGL
GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, drawFramebuffer);
GL.BindFramebuffer(FramebufferTarget.ReadFramebuffer, readFramebuffer);
TextureView viewConverted = view.Format.IsBgr() ? _renderer.TextureCopy.BgraSwap(view) : view;
TextureView viewConverted = view.Format.IsBgr ? _renderer.TextureCopy.BgraSwap(view) : view;
UpdateEffect();
@@ -80,7 +80,7 @@ namespace Ryujinx.Graphics.OpenGL
viewConverted = _antiAliasing.Run(viewConverted, _width, _height);
if (viewConverted.Format.IsBgr())
if (viewConverted.Format.IsBgr)
{
TextureView swappedView = _renderer.TextureCopy.BgraSwap(viewConverted);
@@ -152,14 +152,14 @@ namespace Ryujinx.Graphics.OpenGL
if (ScreenCaptureRequested)
{
CaptureFrame(srcX0, srcY0, srcX1, srcY1, view.Format.IsBgr(), crop.FlipX, crop.FlipY);
CaptureFrame(srcX0, srcY0, srcX1, srcY1, view.Format.IsBgr, crop.FlipX, crop.FlipY);
ScreenCaptureRequested = false;
}
if (_scalingFilter != null)
{
if (viewConverted.Format.IsBgr() && !_isBgra)
if (viewConverted.Format.IsBgr && !_isBgra)
{
RecreateUpscalingTexture(true);
}

View File

@@ -20,20 +20,18 @@ namespace Ryujinx.Graphics.Shader
static class AttributeTypeExtensions
{
public static AggregateType ToAggregateType(this AttributeType type)
extension(AttributeType type)
{
return (type & ~AttributeType.AnyPacked) switch
public AggregateType Aggregate =>
(type & ~AttributeType.AnyPacked) switch
{
AttributeType.Float => AggregateType.FP32,
AttributeType.Sint => AggregateType.S32,
AttributeType.Uint => AggregateType.U32,
_ => throw new ArgumentException($"Invalid attribute type \"{type}\"."),
};
}
public static AggregateType ToAggregateType(this AttributeType type, bool supportsScaledFormats)
{
return (type & ~AttributeType.AnyPacked) switch
public AggregateType AsAggregate(bool supportsScaledFormats) => (type & ~AttributeType.AnyPacked) switch
{
AttributeType.Float => AggregateType.FP32,
AttributeType.Sint => AggregateType.S32,

View File

@@ -83,7 +83,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
{
if (context.Definitions.Stage == ShaderStage.Geometry)
{
string inPrimitive = context.Definitions.InputTopology.ToGlslString();
string inPrimitive = context.Definitions.InputTopology.GlslString;
context.AppendLine($"layout (invocations = {context.Definitions.ThreadsPerInputPrimitive}, {inPrimitive}) in;");
@@ -98,7 +98,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
}
else
{
string outPrimitive = context.Definitions.OutputTopology.ToGlslString();
string outPrimitive = context.Definitions.OutputTopology.GlslString;
int maxOutputVertices = context.Definitions.MaxOutputVertices;
context.AppendLine($"layout ({outPrimitive}, max_vertices = {maxOutputVertices}) out;");
@@ -123,8 +123,8 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
tessCw = !tessCw;
}
string patchType = context.Definitions.TessPatchType.ToGlsl();
string spacing = context.Definitions.TessSpacing.ToGlsl();
string patchType = context.Definitions.TessPatchType.Glsl;
string spacing = context.Definitions.TessSpacing.Glsl;
string windingOrder = tessCw ? "cw" : "ccw";
context.AppendLine($"layout ({patchType}, {spacing}, {windingOrder}) in;");
@@ -351,7 +351,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
arrayDecl = "[]";
}
string samplerTypeName = definition.Separate ? definition.Type.ToGlslTextureType() : definition.Type.ToGlslSamplerType();
string samplerTypeName = definition.Separate ? definition.Type.GlslTextureTypeName : definition.Type.GlslSamplerTypeName;
string layout = string.Empty;
@@ -379,7 +379,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
arrayDecl = "[]";
}
string imageTypeName = definition.Type.ToGlslImageType(definition.Format.GetComponentType());
string imageTypeName = definition.Type.GetGlslImageTypeName(definition.Format.GetComponentType());
if (definition.Flags.HasFlag(TextureUsageFlags.ImageCoherent))
{

View File

@@ -54,7 +54,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
texCallBuilder.Append('(');
texCallBuilder.Append(imageName);
int coordsCount = texOp.Type.GetDimensions();
int coordsCount = texOp.Type.Dimensions;
int pCount = coordsCount + (isArray ? 1 : 0);
@@ -162,7 +162,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
{
AstTextureOperation texOp = (AstTextureOperation)operation;
int coordsCount = texOp.Type.GetDimensions();
int coordsCount = texOp.Type.Dimensions;
int coordsIndex = 0;
string samplerName = GetSamplerName(context, texOp, ref coordsIndex);
@@ -264,7 +264,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
texCall += "(" + samplerName;
int coordsCount = texOp.Type.GetDimensions();
int coordsCount = texOp.Type.Dimensions;
int pCount = coordsCount;
@@ -658,7 +658,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
samplerName = $"{samplerName}[{GetSourceExpr(context, texOp.GetSource(srcIndex++), AggregateType.S32)}]";
}
name = $"{texOp.Type.ToGlslSamplerType()}({name}, {samplerName})";
name = $"{texOp.Type.GlslSamplerTypeName}({name}, {samplerName})";
}
return name;

View File

@@ -385,12 +385,12 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
private static void DeclarePerVertexBlock(CodeGenContext context)
{
if (context.Definitions.Stage.IsVtg())
if (context.Definitions.Stage.IsVtg)
{
if (context.Definitions.Stage != ShaderStage.Vertex)
{
SpvInstruction perVertexInputStructType = CreatePerVertexStructType(context);
int arraySize = context.Definitions.Stage == ShaderStage.Geometry ? context.Definitions.InputTopology.ToInputVertices() : 32;
int arraySize = context.Definitions.Stage == ShaderStage.Geometry ? context.Definitions.InputTopology.InputVertexCount : 32;
SpvInstruction perVertexInputArrayType = context.TypeArray(perVertexInputStructType, context.Constant(context.TypeU32(), arraySize));
SpvInstruction perVertexInputPointerType = context.TypePointer(StorageClass.Input, perVertexInputArrayType);
SpvInstruction perVertexInputVariable = context.Variable(perVertexInputPointerType, StorageClass.Input);
@@ -537,7 +537,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
if (!isPerPatch && IoMap.IsPerVertex(ioVariable, context.Definitions.Stage, isOutput))
{
int arraySize = context.Definitions.Stage == ShaderStage.Geometry ? context.Definitions.InputTopology.ToInputVertices() : 32;
int arraySize = context.Definitions.Stage == ShaderStage.Geometry ? context.Definitions.InputTopology.InputVertexCount : 32;
spvType = context.TypeArray(spvType, context.Constant(context.TypeU32(), arraySize));
if (context.Definitions.GpPassthrough && context.HostCapabilities.SupportsGeometryShaderPassthrough)

View File

@@ -615,7 +615,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
image = context.AccessChain(imagePointerType, image, textureIndex);
}
int coordsCount = texOp.Type.GetDimensions();
int coordsCount = texOp.Type.Dimensions;
int pCount = coordsCount + (isArray ? 1 : 0);
@@ -693,7 +693,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
image = context.Load(declaration.ImageType, image);
int coordsCount = texOp.Type.GetDimensions();
int coordsCount = texOp.Type.Dimensions;
int pCount = coordsCount + (isArray ? 1 : 0);
@@ -750,7 +750,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
image = context.Load(declaration.ImageType, image);
int coordsCount = texOp.Type.GetDimensions();
int coordsCount = texOp.Type.Dimensions;
int pCount = coordsCount + (isArray ? 1 : 0);
@@ -840,7 +840,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
SamplerDeclaration declaration = context.Samplers[texOp.GetTextureSetAndBinding()];
SpvInstruction image = GenerateSampledImageLoad(context, texOp, declaration, ref srcIndex);
int pCount = texOp.Type.GetDimensions();
int pCount = texOp.Type.Dimensions;
SpvInstruction pCoords;
@@ -1164,7 +1164,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
SamplerDeclaration declaration = context.Samplers[texOp.GetTextureSetAndBinding()];
SpvInstruction image = GenerateSampledImageLoad(context, texOp, declaration, ref srcIndex);
int coordsCount = texOp.Type.GetDimensions();
int coordsCount = texOp.Type.Dimensions;
int pCount = coordsCount;
@@ -1463,7 +1463,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
SamplerType type = context.SamplersTypes[texOp.GetTextureSetAndBinding()];
bool hasLod = !type.HasFlag(SamplerType.Multisample) && type != SamplerType.TextureBuffer;
int dimensions = (type & SamplerType.Mask) == SamplerType.TextureCube ? 2 : type.GetDimensions();
int dimensions = (type & SamplerType.Mask) == SamplerType.TextureCube ? 2 : type.Dimensions;
if (type.HasFlag(SamplerType.Array))
{
@@ -1486,7 +1486,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
if (dimensions != 1)
{
result = context.CompositeExtract(context.TypeS32(), result, (SpvLiteralInteger)texOp.Index);
result = context.CompositeExtract(context.TypeS32(), result, texOp.Index);
}
return new OperationResult(AggregateType.S32, result);

View File

@@ -457,7 +457,7 @@ namespace Ryujinx.Graphics.Shader.Decoders
case AttributeConsts.ClipDistance5:
case AttributeConsts.ClipDistance6:
case AttributeConsts.ClipDistance7:
if (definitions.Stage.IsVtg())
if (definitions.Stage.IsVtg)
{
context.SetClipDistanceWritten((attr - AttributeConsts.ClipDistance0) / 4);
}

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