From 8e6ee56200b350e974a851dd20a6611a7c1681e1 Mon Sep 17 00:00:00 2001 From: gdkchan Date: Tue, 28 May 2019 22:28:24 -0300 Subject: [PATCH] Refactoring around the old IRAdapter, now renamed to PreAllocator --- .../CodeGen/RegisterAllocators/LinearScan.cs | 2 +- ARMeilleure/CodeGen/X86/CodeGenerator.cs | 43 +- ARMeilleure/CodeGen/X86/IRAdapter.cs | 419 ------------------ ARMeilleure/CodeGen/X86/PreAllocator.cs | 417 +++++++++++++++++ ARMeilleure/Diagnostics/IRDumper.cs | 3 +- ARMeilleure/Instructions/InstEmitAlu.cs | 4 +- ARMeilleure/Instructions/InstEmitAluHelper.cs | 18 +- .../IntermediateRepresentation/Operand.cs | 12 +- .../IntermediateRepresentation/OperandKind.cs | 1 - ARMeilleure/Translation/RegisterUsage.cs | 57 ++- ARMeilleure/Translation/Ssa.cs | 110 ++--- ARMeilleure/Translation/Translator.cs | 6 +- Ryujinx.Tests/Cpu/CpuTest.cs | 8 +- 13 files changed, 559 insertions(+), 541 deletions(-) delete mode 100644 ARMeilleure/CodeGen/X86/IRAdapter.cs create mode 100644 ARMeilleure/CodeGen/X86/PreAllocator.cs diff --git a/ARMeilleure/CodeGen/RegisterAllocators/LinearScan.cs b/ARMeilleure/CodeGen/RegisterAllocators/LinearScan.cs index aabfc62e14..0077c994f6 100644 --- a/ARMeilleure/CodeGen/RegisterAllocators/LinearScan.cs +++ b/ARMeilleure/CodeGen/RegisterAllocators/LinearScan.cs @@ -70,7 +70,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators } } - public RAReport Allocate(ControlFlowGraph cfg, RegisterMasks regMasks) + public RAReport RunPass(ControlFlowGraph cfg, RegisterMasks regMasks) { PhiFunctions.Remove(cfg); diff --git a/ARMeilleure/CodeGen/X86/CodeGenerator.cs b/ARMeilleure/CodeGen/X86/CodeGenerator.cs index 95f5f84ca9..d4a0b6d715 100644 --- a/ARMeilleure/CodeGen/X86/CodeGenerator.cs +++ b/ARMeilleure/CodeGen/X86/CodeGenerator.cs @@ -1,6 +1,7 @@ using ARMeilleure.CodeGen.RegisterAllocators; using ARMeilleure.Common; using ARMeilleure.IntermediateRepresentation; +using ARMeilleure.Memory; using ARMeilleure.State; using ARMeilleure.Translation; using System; @@ -39,6 +40,7 @@ namespace ARMeilleure.CodeGen.X86 Add(Instruction.Divide, GenerateDivide); Add(Instruction.Fill, GenerateFill); Add(Instruction.Load, GenerateLoad); + Add(Instruction.LoadFromContext, GenerateLoadFromContext); Add(Instruction.LoadSx16, GenerateLoadSx16); Add(Instruction.LoadSx32, GenerateLoadSx32); Add(Instruction.LoadSx8, GenerateLoadSx8); @@ -58,6 +60,7 @@ namespace ARMeilleure.CodeGen.X86 Add(Instruction.Store, GenerateStore); Add(Instruction.Store16, GenerateStore16); Add(Instruction.Store8, GenerateStore8); + Add(Instruction.StoreToContext, GenerateStoreToContext); Add(Instruction.Subtract, GenerateSubtract); } @@ -66,9 +69,9 @@ namespace ARMeilleure.CodeGen.X86 _instTable[(int)inst] = func; } - public static byte[] Generate(ControlFlowGraph cfg) + public static byte[] Generate(ControlFlowGraph cfg, MemoryManager memory) { - //IRAdapter.Adapt(cfg); + PreAllocator.RunPass(cfg, memory); LinearScan regAlloc = new LinearScan(); @@ -76,7 +79,7 @@ namespace ARMeilleure.CodeGen.X86 CallingConvention.GetIntAvailableRegisters(), CallingConvention.GetIntCalleeSavedRegisters()); - RAReport raReport = regAlloc.Allocate(cfg, regMasks); + RAReport raReport = regAlloc.RunPass(cfg, regMasks); using (MemoryStream stream = new MemoryStream()) { @@ -303,6 +306,23 @@ namespace ARMeilleure.CodeGen.X86 context.Assembler.Mov(operation.Dest, operation.GetSource(0)); } + private static void GenerateLoadFromContext(CodeGenContext context, Operation operation) + { + Operand dest = operation.Dest; + Operand offset = operation.GetSource(0); + + if (offset.Kind != OperandKind.Constant) + { + throw new InvalidOperationException("LoadFromContext has non-constant context offset."); + } + + Operand rbp = Register(X86Register.Rbp); + + X86MemoryOperand memOp = new X86MemoryOperand(dest.Type, rbp, null, Scale.x1, offset.AsInt32()); + + context.Assembler.Mov(dest, memOp); + } + private static void GenerateLoadSx16(CodeGenContext context, Operation operation) { context.Assembler.Movsx16(operation.Dest, operation.GetSource(0)); @@ -433,6 +453,23 @@ namespace ARMeilleure.CodeGen.X86 context.Assembler.Mov8(operation.GetSource(0), operation.GetSource(1)); } + private static void GenerateStoreToContext(CodeGenContext context, Operation operation) + { + Operand offset = operation.GetSource(0); + Operand source = operation.GetSource(1); + + if (offset.Kind != OperandKind.Constant) + { + throw new InvalidOperationException("StoreToContext has non-constant context offset."); + } + + Operand rbp = Register(X86Register.Rbp); + + X86MemoryOperand memOp = new X86MemoryOperand(source.Type, rbp, null, Scale.x1, offset.AsInt32()); + + context.Assembler.Mov(memOp, source); + } + private static void GenerateSubtract(CodeGenContext context, Operation operation) { ValidateDestSrc1(operation); diff --git a/ARMeilleure/CodeGen/X86/IRAdapter.cs b/ARMeilleure/CodeGen/X86/IRAdapter.cs deleted file mode 100644 index aeda316eeb..0000000000 --- a/ARMeilleure/CodeGen/X86/IRAdapter.cs +++ /dev/null @@ -1,419 +0,0 @@ -using ARMeilleure.CodeGen.Optimizations; -using ARMeilleure.IntermediateRepresentation; -using ARMeilleure.Memory; -using ARMeilleure.State; -using ARMeilleure.Translation; -using System.Collections.Generic; - -using static ARMeilleure.IntermediateRepresentation.OperandHelper; - -namespace ARMeilleure.CodeGen.X86 -{ - static class IRAdapter - { - private class IRModContext - { - private BasicBlock _block; - private LinkedListNode _node; - - public IRModContext(BasicBlock block, LinkedListNode node) - { - _block = block; - _node = node.Previous; - } - - public Operand Append(Instruction inst, Operand src1, Operand src2) - { - Operand destSrc = AppendCopy(src1); - - Operation operation = new Operation(inst, destSrc, destSrc, src2); - - if (src2 is X86MemoryOperand memOp) - { - AddMemoryOperandUse(memOp, operation); - } - - Append(operation); - - return destSrc; - } - - public Operand AppendCopy(Operand src) - { - Operation operation = new Operation(Instruction.Copy, Local(OperandType.I64), src); - - if (src is X86MemoryOperand memOp) - { - AddMemoryOperandUse(memOp, operation); - } - - Append(operation); - - return operation.Dest; - } - - private void Append(Operation operation) - { - if (_node != null) - { - _node = _block.Operations.AddAfter(_node, operation); - } - else - { - _node = _block.Operations.AddFirst(operation); - } - } - } - - public static void Adapt(ControlFlowGraph cfg, MemoryManager memory) - { - Optimizer.Optimize(cfg); - - foreach (BasicBlock block in cfg.Blocks) - { - for (LinkedListNode node = block.Operations.First; node != null; node = node.Next) - { - if (!(node.Value is Operation operation)) - { - continue; - } - - void Clobber(X86Register register) - { - Operand reg = Gpr(register, OperandType.I32); - - Operation copyOp = new Operation(Instruction.Copy, reg, reg); - - block.Operations.AddBefore(node, copyOp); - } - - Operand AddCopy(Operand source) - { - Operand temp = Local(source.Type); - - Operation copyOp = new Operation(Instruction.Copy, temp, source); - - block.Operations.AddBefore(node, copyOp); - - return temp; - } - - Instruction inst = operation.Inst; - - if (inst.IsMemory()) - { - IRModContext context = new IRModContext(block, node); - - Operand va = operation.GetSource(0); - - OperandType valueType = inst == Instruction.Store || - inst == Instruction.Store16 || - inst == Instruction.Store8 ? operation.GetSource(1).Type : operation.Dest.Type; - - X86MemoryOperand hostAddr = GuestToHostAddress(context, memory, valueType, va); - - operation.SetSource(0, hostAddr); - - AddMemoryOperandUse(hostAddr, operation); - } - - if (IsRMOnly(inst)) - { - Operand src = operation.GetSource(0); - - if (src.Kind == OperandKind.Constant) - { - src = AddCopy(src); - - operation.SetSource(0, src); - } - } - - if (operation.Dest == null || operation.SourcesCount == 0) - { - continue; - } - - Operand dest = operation.Dest; - Operand src1 = operation.GetSource(0); - - bool isBinary = operation.SourcesCount == 2; - - bool isRMOnly = IsRMOnly(inst); - - if (operation.Inst != Instruction.Copy) - { - if ((src1.Kind == OperandKind.Constant && isBinary) || isRMOnly || IsLongConst(dest.Type, src1)) - { - if (IsComutative(inst)) - { - Operand src2 = operation.GetSource(1); - Operand temp = src1; - - src1 = src2; - src2 = temp; - - operation.SetSource(0, src1); - operation.SetSource(1, src2); - } - - if (src1.Kind == OperandKind.Constant) - { - src1 = AddCopy(src1); - - operation.SetSource(0, src1); - } - } - } - - if (isBinary) - { - Operand src2 = operation.GetSource(1); - - //Comparison instructions uses CMOVcc, which does not zero the - //upper bits of the register (since it's R8), we need to ensure it - //is zero by zeroing it beforehand. - if (inst.IsComparison()) - { - Operation copyOp = new Operation(Instruction.Copy, dest, Const(0)); - - block.Operations.AddBefore(node, copyOp); - } - - //64-bits immediates are only supported by the MOV instruction. - if (isRMOnly || IsLongConst(dest.Type, src2)) - { - src2 = AddCopy(src2); - - operation.SetSource(1, src2); - } - - //Handle the many restrictions of the division instructions: - //- The dividend is always in RDX:RAX. - //- The result is always in RAX. - //- Additionally it also writes the remainder in RDX. - if (inst == Instruction.Divide || inst == Instruction.DivideUI) - { - Operand rax = Gpr(X86Register.Rax, src1.Type); - Operand rdx = Gpr(X86Register.Rdx, src1.Type); - - Operation srcCopyOp = new Operation(Instruction.Copy, rax, src1); - - block.Operations.AddBefore(node, srcCopyOp); - - src1 = rax; - - operation.SetSource(0, src1); - - Clobber(X86Register.Rdx); - - Operation destCopyOp = new Operation(Instruction.Copy, dest, rax); - - block.Operations.AddAfter(node, destCopyOp); - - dest = rax; - - operation.Dest = dest; - } - - //The only allowed shift register is CL. - if (inst.IsShift() && src2.Kind == OperandKind.LocalVariable) - { - Operand rcx = Gpr(X86Register.Rcx, OperandType.I32); - - Operation copyOp = new Operation(Instruction.Copy, rcx, src2); - - block.Operations.AddBefore(node, copyOp); - - src2 = rcx; - - operation.SetSource(1, src2); - } - } - - //The multiply instruction (that maps to IMUL) is somewhat special, it has - //a three operand form where the second source is a immediate value. - bool threeOperandForm = inst == Instruction.Multiply && operation.GetSource(1).Kind == OperandKind.Constant; - - if (IsSameOperandDestSrc1(inst) && src1.Kind == OperandKind.LocalVariable && !threeOperandForm) - { - Operation copyOp = new Operation(Instruction.Copy, dest, src1); - - block.Operations.AddBefore(node, copyOp); - - operation.SetSource(0, dest); - - src1 = dest; - } - else if (inst == Instruction.ConditionalSelect) - { - Operand src3 = operation.GetSource(2); - - Operation copyOp = new Operation(Instruction.Copy, dest, src3); - - block.Operations.AddBefore(node, copyOp); - - operation.SetSource(2, dest); - } - - if (inst == Instruction.LoadFromContext || - inst == Instruction.StoreToContext) - { - if (inst == Instruction.LoadFromContext) - { - src1 = GetContextMemoryOperand(src1.GetRegister()); - - operation.Dest = null; - } - else /* if (inst == Instruction.StoreToContext) */ - { - dest = GetContextMemoryOperand(dest.GetRegister()); - - operation.SetSource(0, null); - } - - operation = new Operation(Instruction.Copy, dest, src1); - - LinkedListNode temp = block.Operations.AddBefore(node, operation); - - block.Operations.Remove(node); - - node = temp; - } - } - } - } - - private static bool IsLongConst(OperandType destType, Operand operand) - { - if (operand.Kind != OperandKind.Constant) - { - return false; - } - - if (operand.Type == destType || destType == OperandType.I32) - { - return operand.AsInt32() != operand.AsInt64(); - } - else - { - return operand.Value >> 31 != 0; - } - } - - private static X86MemoryOperand GuestToHostAddress( - IRModContext context, - MemoryManager memory, - OperandType valueType, - Operand va) - { - Operand vaPageOffs = context.Append(Instruction.BitwiseAnd, va, Const((ulong)MemoryManager.PageMask)); - - Operand ptBaseAddr = context.AppendCopy(Const(memory.PageTable.ToInt64())); - - int bit = MemoryManager.PageBits; - - do - { - va = context.Append(Instruction.ShiftRightUI, va, Const(bit)); - - Operand ptOffs = va; - - bit += memory.PtLevelBits; - - if (bit < memory.AddressSpaceBits) - { - ptOffs = context.Append(Instruction.BitwiseAnd, va, Const((ulong)memory.PtLevelMask)); - } - - X86MemoryOperand memOp = new X86MemoryOperand(OperandType.I64, ptBaseAddr, ptOffs, Scale.x8, 0); - - ptBaseAddr = context.AppendCopy(memOp); - } - while (bit < memory.AddressSpaceBits); - - return new X86MemoryOperand(valueType, ptBaseAddr, vaPageOffs, Scale.x1, 0); - } - - private static X86MemoryOperand GetContextMemoryOperand(Register reg) - { - Operand baseReg = Register((int)X86Register.Rbp, RegisterType.Integer, OperandType.I64); - - int offset = NativeContext.GetRegisterOffset(reg); - - return new X86MemoryOperand(OperandType.I64, baseReg, null, Scale.x1, offset); - } - - private static void AddMemoryOperandUse(X86MemoryOperand memOp, Operation operation) - { - memOp.BaseAddress.Uses.AddLast(operation); - - if (memOp.Index != null) - { - memOp.Index.Uses.AddLast(operation); - } - } - - private static Operand Gpr(X86Register register, OperandType type) - { - return Register((int)register, RegisterType.Integer, type); - } - - private static bool IsSameOperandDestSrc1(Instruction inst) - { - switch (inst) - { - case Instruction.Add: - case Instruction.BitwiseAnd: - case Instruction.BitwiseExclusiveOr: - case Instruction.BitwiseNot: - case Instruction.BitwiseOr: - case Instruction.Multiply: - case Instruction.Negate: - case Instruction.RotateRight: - case Instruction.ShiftLeft: - case Instruction.ShiftRightSI: - case Instruction.ShiftRightUI: - case Instruction.Subtract: - return true; - } - - return false; - } - - private static bool IsComutative(Instruction inst) - { - switch (inst) - { - case Instruction.Add: - case Instruction.BitwiseAnd: - case Instruction.BitwiseExclusiveOr: - case Instruction.BitwiseOr: - case Instruction.CompareEqual: - case Instruction.CompareNotEqual: - case Instruction.Multiply: - return true; - } - - return false; - } - - private static bool IsRMOnly(Instruction inst) - { - switch (inst) - { - case Instruction.BranchIfFalse: - case Instruction.BranchIfTrue: - case Instruction.ConditionalSelect: - case Instruction.Divide: - case Instruction.DivideUI: - case Instruction.SignExtend16: - case Instruction.SignExtend32: - case Instruction.SignExtend8: - return true; - } - - return false; - } - } -} \ No newline at end of file diff --git a/ARMeilleure/CodeGen/X86/PreAllocator.cs b/ARMeilleure/CodeGen/X86/PreAllocator.cs new file mode 100644 index 0000000000..521f30b4bb --- /dev/null +++ b/ARMeilleure/CodeGen/X86/PreAllocator.cs @@ -0,0 +1,417 @@ +using ARMeilleure.CodeGen.Optimizations; +using ARMeilleure.IntermediateRepresentation; +using ARMeilleure.Memory; +using ARMeilleure.State; +using ARMeilleure.Translation; +using System.Collections.Generic; + +using static ARMeilleure.IntermediateRepresentation.OperandHelper; + +namespace ARMeilleure.CodeGen.X86 +{ + static class PreAllocator + { + private class IRModContext + { + private BasicBlock _block; + private LinkedListNode _node; + + public IRModContext(BasicBlock block, LinkedListNode node) + { + _block = block; + _node = node.Previous; + } + + public Operand Append(Instruction inst, Operand src1, Operand src2) + { + Operand destSrc = AppendCopy(src1); + + Operation operation = new Operation(inst, destSrc, destSrc, src2); + + if (src2 is X86MemoryOperand memOp) + { + AddMemoryOperandUse(memOp, operation); + } + + Append(operation); + + return destSrc; + } + + public Operand AppendCopy(Operand src) + { + Operation operation = new Operation(Instruction.Copy, Local(OperandType.I64), src); + + if (src is X86MemoryOperand memOp) + { + AddMemoryOperandUse(memOp, operation); + } + + Append(operation); + + return operation.Dest; + } + + private void Append(Operation operation) + { + if (_node != null) + { + _node = _block.Operations.AddAfter(_node, operation); + } + else + { + _node = _block.Operations.AddFirst(operation); + } + } + } + + public static void RunPass(ControlFlowGraph cfg, MemoryManager memory) + { + Optimizer.Optimize(cfg); + + foreach (BasicBlock block in cfg.Blocks) + { + for (LinkedListNode node = block.Operations.First; node != null; node = node.Next) + { + if (!(node.Value is Operation operation)) + { + continue; + } + + Instruction inst = operation.Inst; + + if (inst.IsMemory()) + { + IRModContext context = new IRModContext(block, node); + + Operand va = operation.GetSource(0); + + OperandType valueType = inst == Instruction.Store || + inst == Instruction.Store16 || + inst == Instruction.Store8 ? operation.GetSource(1).Type : operation.Dest.Type; + + X86MemoryOperand hostAddr = GuestToHostAddress(context, memory, valueType, va); + + operation.SetSource(0, hostAddr); + + AddMemoryOperandUse(hostAddr, operation); + } + + AddConstantCopy(node, operation); + + //Comparison instructions uses CMOVcc, which does not zero the + //upper bits of the register (since it's R8), we need to ensure it + //is zero by zeroing it beforehand. + if (inst.IsComparison()) + { + Operation copyOp = new Operation(Instruction.Copy, operation.Dest, Const(0)); + + block.Operations.AddBefore(node, copyOp); + } + + AddFixedRegisterCopy(node, operation); + + AddSameDestSrc1Copy(node, operation); + } + } + } + + private static void AddConstantCopy(LinkedListNode node, Operation operation) + { + if (operation.SourcesCount == 0) + { + return; + } + + Instruction inst = operation.Inst; + + Operand src1 = operation.GetSource(0); + Operand src2; + + if (src1.Kind == OperandKind.Constant && !HasConstSrc1(inst)) + { + if (IsComutative(inst)) + { + src2 = operation.GetSource(1); + + Operand temp = src1; + + src1 = src2; + src2 = temp; + + operation.SetSource(0, src1); + operation.SetSource(1, src2); + } + + if (src1.Kind == OperandKind.Constant) + { + src1 = AddCopy(node, src1); + + operation.SetSource(0, src1); + } + } + + if (operation.SourcesCount < 2) + { + return; + } + + src2 = operation.GetSource(1); + + if (src2.Kind == OperandKind.Constant && (!HasConstSrc2(inst) || IsLongConst(src2))) + { + src2 = AddCopy(node, src2); + + operation.SetSource(1, src2); + } + } + + private static void AddFixedRegisterCopy(LinkedListNode node, Operation operation) + { + if (operation.Dest == null || operation.SourcesCount == 0) + { + return; + } + + Instruction inst = operation.Inst; + + Operand dest = operation.Dest; + Operand src1 = operation.GetSource(0); + + //Handle the many restrictions of the division instructions: + //- The dividend is always in RDX:RAX. + //- The result is always in RAX. + //- Additionally it also writes the remainder in RDX. + if (inst == Instruction.Divide || inst == Instruction.DivideUI) + { + Operand rax = Gpr(X86Register.Rax, src1.Type); + Operand rdx = Gpr(X86Register.Rdx, src1.Type); + + Operation srcCopyOp = new Operation(Instruction.Copy, rax, src1); + + node.List.AddBefore(node, srcCopyOp); + + operation.SetSource(0, rax); + + Clobber(node, X86Register.Rdx); + + Operation destCopyOp = new Operation(Instruction.Copy, dest, rax); + + node.List.AddAfter(node, destCopyOp); + + operation.Dest = rax; + } + + //The only allowed shift register is CL. + if (inst.IsShift() && operation.GetSource(1).Kind == OperandKind.LocalVariable) + { + Operand rcx = Gpr(X86Register.Rcx, OperandType.I32); + + Operation copyOp = new Operation(Instruction.Copy, rcx, operation.GetSource(1)); + + node.List.AddBefore(node, copyOp); + + operation.SetSource(1, rcx); + } + } + + private static void AddSameDestSrc1Copy(LinkedListNode node, Operation operation) + { + if (operation.Dest == null || operation.SourcesCount == 0) + { + return; + } + + Instruction inst = operation.Inst; + + Operand dest = operation.Dest; + Operand src1 = operation.GetSource(0); + + //The multiply instruction (that maps to IMUL) is somewhat special, it has + //a three operand form where the second source is a immediate value. + bool threeOperandForm = inst == Instruction.Multiply && operation.GetSource(1).Kind == OperandKind.Constant; + + if (IsSameOperandDestSrc1(inst) && src1.Kind == OperandKind.LocalVariable && !threeOperandForm) + { + Operation copyOp = new Operation(Instruction.Copy, dest, src1); + + node.List.AddBefore(node, copyOp); + + operation.SetSource(0, dest); + } + else if (inst == Instruction.ConditionalSelect) + { + Operand src3 = operation.GetSource(2); + + Operation copyOp = new Operation(Instruction.Copy, dest, src3); + + node.List.AddBefore(node, copyOp); + + operation.SetSource(2, dest); + } + } + + private static Operand AddCopy(LinkedListNode node, Operand source) + { + Operand temp = Local(source.Type); + + Operation copyOp = new Operation(Instruction.Copy, temp, source); + + node.List.AddBefore(node, copyOp); + + return temp; + } + + private static void Clobber(LinkedListNode node, X86Register register) + { + Operand reg = Gpr(register, OperandType.I32); + + Operation copyOp = new Operation(Instruction.Copy, reg, reg); + + node.List.AddBefore(node, copyOp); + } + + private static bool IsLongConst(Operand operand) + { + long value = operand.Type == OperandType.I32 ? operand.AsInt32() + : operand.AsInt64(); + + return !ConstFitsOnS32(value); + } + + private static bool ConstFitsOnS32(long value) + { + return value == (int)value; + } + + private static X86MemoryOperand GuestToHostAddress( + IRModContext context, + MemoryManager memory, + OperandType valueType, + Operand va) + { + Operand vaPageOffs = context.Append(Instruction.BitwiseAnd, va, Const((ulong)MemoryManager.PageMask)); + + Operand ptBaseAddr = context.AppendCopy(Const(memory.PageTable.ToInt64())); + + int bit = MemoryManager.PageBits; + + do + { + va = context.Append(Instruction.ShiftRightUI, va, Const(bit)); + + Operand ptOffs = va; + + bit += memory.PtLevelBits; + + if (bit < memory.AddressSpaceBits) + { + ptOffs = context.Append(Instruction.BitwiseAnd, va, Const((ulong)memory.PtLevelMask)); + } + + X86MemoryOperand memOp = new X86MemoryOperand(OperandType.I64, ptBaseAddr, ptOffs, Scale.x8, 0); + + ptBaseAddr = context.AppendCopy(memOp); + } + while (bit < memory.AddressSpaceBits); + + return new X86MemoryOperand(valueType, ptBaseAddr, vaPageOffs, Scale.x1, 0); + } + + private static void AddMemoryOperandUse(X86MemoryOperand memOp, Operation operation) + { + memOp.BaseAddress.Uses.AddLast(operation); + + if (memOp.Index != null) + { + memOp.Index.Uses.AddLast(operation); + } + } + + private static Operand Gpr(X86Register register, OperandType type) + { + return Register((int)register, RegisterType.Integer, type); + } + + private static bool IsSameOperandDestSrc1(Instruction inst) + { + switch (inst) + { + case Instruction.Add: + case Instruction.BitwiseAnd: + case Instruction.BitwiseExclusiveOr: + case Instruction.BitwiseNot: + case Instruction.BitwiseOr: + case Instruction.Multiply: + case Instruction.Negate: + case Instruction.RotateRight: + case Instruction.ShiftLeft: + case Instruction.ShiftRightSI: + case Instruction.ShiftRightUI: + case Instruction.Subtract: + return true; + } + + return false; + } + + private static bool HasConstSrc1(Instruction inst) + { + switch (inst) + { + case Instruction.Copy: + case Instruction.LoadFromContext: + case Instruction.StoreToContext: + return true; + } + + return false; + } + + private static bool HasConstSrc2(Instruction inst) + { + switch (inst) + { + case Instruction.Add: + case Instruction.BitwiseAnd: + case Instruction.BitwiseExclusiveOr: + case Instruction.BitwiseOr: + case Instruction.CompareEqual: + case Instruction.CompareGreater: + case Instruction.CompareGreaterOrEqual: + case Instruction.CompareGreaterOrEqualUI: + case Instruction.CompareGreaterUI: + case Instruction.CompareLess: + case Instruction.CompareLessOrEqual: + case Instruction.CompareLessOrEqualUI: + case Instruction.CompareLessUI: + case Instruction.CompareNotEqual: + case Instruction.Multiply: + case Instruction.ShiftLeft: + case Instruction.ShiftRightSI: + case Instruction.ShiftRightUI: + case Instruction.Subtract: + return true; + } + + return false; + } + + private static bool IsComutative(Instruction inst) + { + switch (inst) + { + case Instruction.Add: + case Instruction.BitwiseAnd: + case Instruction.BitwiseExclusiveOr: + case Instruction.BitwiseOr: + case Instruction.CompareEqual: + case Instruction.CompareNotEqual: + case Instruction.Multiply: + return true; + } + + return false; + } + } +} \ No newline at end of file diff --git a/ARMeilleure/Diagnostics/IRDumper.cs b/ARMeilleure/Diagnostics/IRDumper.cs index ac80de0347..d157e20583 100644 --- a/ARMeilleure/Diagnostics/IRDumper.cs +++ b/ARMeilleure/Diagnostics/IRDumper.cs @@ -123,8 +123,7 @@ namespace ARMeilleure.Diagnostics name = localName; } - else if (operand.Kind == OperandKind.Register || - operand.Kind == OperandKind.RegisterNoRename) + else if (operand.Kind == OperandKind.Register) { Register reg = operand.GetRegister(); diff --git a/ARMeilleure/Instructions/InstEmitAlu.cs b/ARMeilleure/Instructions/InstEmitAlu.cs index 8cff7b6021..01d68078d1 100644 --- a/ARMeilleure/Instructions/InstEmitAlu.cs +++ b/ARMeilleure/Instructions/InstEmitAlu.cs @@ -328,8 +328,8 @@ namespace ARMeilleure.Instructions private static void EmitNZFlagsCheck(EmitterContext context, Operand d) { - context.Copy(GetFlag(PState.NFlag), context.ICompareLess (d, Const(0))); - context.Copy(GetFlag(PState.ZFlag), context.ICompareEqual(d, Const(0))); + context.Copy(GetFlag(PState.NFlag), context.ICompareLess (d, Const(d.Type, 0))); + context.Copy(GetFlag(PState.ZFlag), context.ICompareEqual(d, Const(d.Type, 0))); } private static void EmitCVFlagsClear(EmitterContext context) diff --git a/ARMeilleure/Instructions/InstEmitAluHelper.cs b/ARMeilleure/Instructions/InstEmitAluHelper.cs index 3a47462617..723e1a92ec 100644 --- a/ARMeilleure/Instructions/InstEmitAluHelper.cs +++ b/ARMeilleure/Instructions/InstEmitAluHelper.cs @@ -11,28 +11,28 @@ namespace ARMeilleure.Instructions { static class InstEmitAluHelper { - public static void EmitAdcsCCheck(EmitterContext context, Operand n, Operand result) + public static void EmitAdcsCCheck(EmitterContext context, Operand n, Operand d) { //C = (Rd == Rn && CIn) || Rd < Rn Operand cIn = GetFlag(PState.CFlag); - Operand cOut = context.BitwiseAnd(context.ICompareEqual(result, n), cIn); + Operand cOut = context.BitwiseAnd(context.ICompareEqual(d, n), cIn); - cOut = context.BitwiseOr(cOut, context.ICompareLessUI(result, n)); + cOut = context.BitwiseOr(cOut, context.ICompareLessUI(d, n)); context.Copy(GetFlag(PState.CFlag), cOut); } - public static void EmitAddsCCheck(EmitterContext context, Operand n, Operand result) + public static void EmitAddsCCheck(EmitterContext context, Operand n, Operand d) { //C = Rd < Rn - context.Copy(GetFlag(PState.CFlag), context.ICompareLessUI(result, n)); + context.Copy(GetFlag(PState.CFlag), context.ICompareLessUI(d, n)); } - public static void EmitAddsVCheck(EmitterContext context, Operand n, Operand m, Operand result) + public static void EmitAddsVCheck(EmitterContext context, Operand n, Operand m, Operand d) { //V = (Rd ^ Rn) & ~(Rn ^ Rm) < 0 - Operand vOut = context.BitwiseExclusiveOr(result, n); + Operand vOut = context.BitwiseExclusiveOr(d, n); vOut = context.BitwiseAnd(vOut, context.BitwiseNot(context.BitwiseExclusiveOr(n, m))); @@ -63,10 +63,10 @@ namespace ARMeilleure.Instructions EmitterContext context, Operand n, Operand m, - Operand result) + Operand d) { //V = (Rd ^ Rn) & (Rn ^ Rm) < 0 - Operand vOut = context.BitwiseExclusiveOr(result, n); + Operand vOut = context.BitwiseExclusiveOr(d, n); vOut = context.BitwiseAnd(vOut, context.BitwiseExclusiveOr(n, m)); diff --git a/ARMeilleure/IntermediateRepresentation/Operand.cs b/ARMeilleure/IntermediateRepresentation/Operand.cs index f061a63df6..66c1656284 100644 --- a/ARMeilleure/IntermediateRepresentation/Operand.cs +++ b/ARMeilleure/IntermediateRepresentation/Operand.cs @@ -54,17 +54,9 @@ namespace ARMeilleure.IntermediateRepresentation Value = value; } - public Operand(int index, RegisterType regType, OperandType type, bool rename = true) : this() + public Operand(int index, RegisterType regType, OperandType type) : this() { - if (rename) - { - Kind = OperandKind.Register; - } - else - { - Kind = OperandKind.RegisterNoRename; - } - + Kind = OperandKind.Register; Type = type; Value = (ulong)((int)regType << 24 | index); diff --git a/ARMeilleure/IntermediateRepresentation/OperandKind.cs b/ARMeilleure/IntermediateRepresentation/OperandKind.cs index f67f93143e..5761835344 100644 --- a/ARMeilleure/IntermediateRepresentation/OperandKind.cs +++ b/ARMeilleure/IntermediateRepresentation/OperandKind.cs @@ -7,7 +7,6 @@ namespace ARMeilleure.IntermediateRepresentation LocalVariable, Memory, Register, - RegisterNoRename, Undefined } } \ No newline at end of file diff --git a/ARMeilleure/Translation/RegisterUsage.cs b/ARMeilleure/Translation/RegisterUsage.cs index d68354b543..e7e00d33fb 100644 --- a/ARMeilleure/Translation/RegisterUsage.cs +++ b/ARMeilleure/Translation/RegisterUsage.cs @@ -2,6 +2,8 @@ using ARMeilleure.IntermediateRepresentation; using ARMeilleure.State; using System; +using static ARMeilleure.IntermediateRepresentation.OperandHelper; + namespace ARMeilleure.Translation { static class RegisterUsage @@ -238,15 +240,18 @@ namespace ARMeilleure.Translation { long mask = 1L << bit; - if ((inputs & mask) != 0) + if ((inputs & mask) == 0) { - Operand dest = GetRegFromBit(bit, baseType, rename: true); - Operand source = GetRegFromBit(bit, baseType, rename: false); - - Operation operation = new Operation(Instruction.LoadFromContext, dest, source); - - block.Operations.AddFirst(operation); + continue; } + + Operand dest = GetRegFromBit(bit, baseType); + + int offset = NativeContext.GetRegisterOffset(dest.GetRegister()); + + Operation operation = new Operation(Instruction.LoadFromContext, dest, Const(offset)); + + block.Operations.AddFirst(operation); } } @@ -254,8 +259,7 @@ namespace ARMeilleure.Translation { if (Optimizations.AssumeStrictAbiCompliance) { - if (baseType == RegisterType.Integer || - baseType == RegisterType.Flag) + if (baseType == RegisterType.Integer || baseType == RegisterType.Flag) { outputs = ClearCallerSavedIntRegs(outputs); } @@ -269,27 +273,30 @@ namespace ARMeilleure.Translation { long mask = 1L << bit; - if ((outputs & mask) != 0) + if ((outputs & mask) == 0) { - Operand dest = GetRegFromBit(bit, baseType, rename: false); - Operand source = GetRegFromBit(bit, baseType, rename: true); - - Operation operation = new Operation(Instruction.StoreToContext, dest, source); - - block.Append(operation); + continue; } + + Operand source = GetRegFromBit(bit, baseType); + + int offset = NativeContext.GetRegisterOffset(source.GetRegister()); + + Operation operation = new Operation(Instruction.StoreToContext, null, Const(offset), source); + + block.Append(operation); } } - private static Operand GetRegFromBit(int bit, RegisterType baseType, bool rename) + private static Operand GetRegFromBit(int bit, RegisterType baseType) { if (bit < RegsCount) { - return new Operand(bit, baseType, OperandType.I64, rename); + return new Operand(bit, baseType, GetOperandType(baseType)); } else if (baseType == RegisterType.Integer) { - return new Operand(bit & RegsMask, RegisterType.Flag, OperandType.I64, rename); + return new Operand(bit & RegsMask, RegisterType.Flag, OperandType.I32); } else { @@ -297,6 +304,18 @@ namespace ARMeilleure.Translation } } + private static OperandType GetOperandType(RegisterType type) + { + switch (type) + { + case RegisterType.Flag: return OperandType.I32; + case RegisterType.Integer: return OperandType.I64; + case RegisterType.Vector: return OperandType.V128; + } + + throw new ArgumentException($"Invalid register type \"{type}\"."); + } + private static bool HasContextStore(BasicBlock block) { if (!(block.GetLastOp() is Operation operation)) diff --git a/ARMeilleure/Translation/Ssa.cs b/ARMeilleure/Translation/Ssa.cs index 8c1cbd7de8..eee5e2f092 100644 --- a/ARMeilleure/Translation/Ssa.cs +++ b/ARMeilleure/Translation/Ssa.cs @@ -1,3 +1,4 @@ +using ARMeilleure.Common; using ARMeilleure.IntermediateRepresentation; using ARMeilleure.State; using System.Collections.Generic; @@ -12,13 +13,13 @@ namespace ARMeilleure.Translation { private Dictionary _map; - private long[] _phiMasks; + private BitMap _phiMasks; public DefMap() { _map = new Dictionary(); - _phiMasks = new long[(RegisterConsts.TotalCount + 63) / 64]; + _phiMasks = new BitMap(RegisterConsts.TotalCount); } public bool TryAddOperand(Register reg, Operand operand) @@ -33,31 +34,12 @@ namespace ARMeilleure.Translation public bool AddPhi(Register reg) { - int key = GetKeyFromRegister(reg); - - int index = key / 64; - int bit = key & 63; - - long mask = 1L << bit; - - if ((_phiMasks[index] & mask) != 0) - { - return false; - } - - _phiMasks[index] |= mask; - - return true; + return _phiMasks.Set(GetIdFromRegister(reg)); } public bool HasPhi(Register reg) { - int key = GetKeyFromRegister(reg); - - int index = key / 64; - int bit = key & 63; - - return (_phiMasks[index] & (1L << bit)) != 0; + return _phiMasks.IsSet(GetIdFromRegister(reg)); } } @@ -83,7 +65,7 @@ namespace ARMeilleure.Translation { if (operand != null && operand.Kind == OperandKind.Register) { - Operand local = localDefs[GetKeyFromRegister(operand.GetRegister())]; + Operand local = localDefs[GetIdFromRegister(operand.GetRegister())]; if (local != null && local.Type != operand.Type) { @@ -117,7 +99,7 @@ namespace ARMeilleure.Translation { Operand local = Local(dest.Type); - localDefs[GetKeyFromRegister(dest.GetRegister())] = local; + localDefs[GetIdFromRegister(dest.GetRegister())] = local; operation.Dest = local; } @@ -135,7 +117,7 @@ namespace ARMeilleure.Translation continue; } - Register reg = GetRegisterFromKey(index); + Register reg = GetRegisterFromId(index); globalDefs[block.Index].TryAddOperand(reg, local); @@ -165,29 +147,29 @@ namespace ARMeilleure.Translation { if (operand != null && operand.Kind == OperandKind.Register) { - int key = GetKeyFromRegister(operand.GetRegister()); + int key = GetIdFromRegister(operand.GetRegister()); Operand local = localDefs[key]; - if (local != null) + if (local == null) { - if (local.Type != operand.Type) - { - Operand temp = Local(operand.Type); + local = FindDef(globalDefs, block, operand); - Operation castOp = new Operation(Instruction.Copy, temp, local); - - block.Operations.AddBefore(node, castOp); - - local = temp; - } - - return local; + localDefs[key] = local; } - operand = FindDef(globalDefs, block, operand); + if (local.Kind == OperandKind.LocalVariable && local.Type != operand.Type) + { + Operand temp = Local(operand.Type); - localDefs[key] = operand; + Operation castOp = new Operation(Instruction.Copy, temp, local); + + block.Operations.AddBefore(node, castOp); + + local = temp; + } + + operand = local; } return operand; @@ -225,36 +207,32 @@ namespace ARMeilleure.Translation private static Operand FindDefOnPred(DefMap[] globalDefs, BasicBlock current, Operand operand) { - foreach (BasicBlock block in SelfAndImmediateDominators(current)) - { - DefMap defMap = globalDefs[block.Index]; + BasicBlock previous; - if (defMap.TryGetOperand(operand.GetRegister(), out Operand lastDef)) + do + { + DefMap defMap = globalDefs[current.Index]; + + Register reg = operand.GetRegister(); + + if (defMap.TryGetOperand(reg, out Operand lastDef)) { return lastDef; } - if (defMap.HasPhi(operand.GetRegister())) + if (defMap.HasPhi(reg)) { - return InsertPhi(globalDefs, block, operand); + return InsertPhi(globalDefs, current, operand); } + + previous = current; + current = current.ImmediateDominator; } + while (previous != current); return Undef(); } - private static IEnumerable SelfAndImmediateDominators(BasicBlock block) - { - while (block != block.ImmediateDominator) - { - yield return block; - - block = block.ImmediateDominator; - } - - yield return block; - } - private static Operand InsertPhi(DefMap[] globalDefs, BasicBlock block, Operand operand) { //This block has a Phi that has not been materialized yet, but that @@ -302,7 +280,7 @@ namespace ARMeilleure.Translation } } - private static int GetKeyFromRegister(Register reg) + private static int GetIdFromRegister(Register reg) { if (reg.Type == RegisterType.Integer) { @@ -318,19 +296,19 @@ namespace ARMeilleure.Translation } } - private static Register GetRegisterFromKey(int key) + private static Register GetRegisterFromId(int id) { - if (key < RegisterConsts.IntRegsCount) + if (id < RegisterConsts.IntRegsCount) { - return new Register(key, RegisterType.Integer); + return new Register(id, RegisterType.Integer); } - else if (key < RegisterConsts.IntAndVecRegsCount) + else if (id < RegisterConsts.IntAndVecRegsCount) { - return new Register(key - RegisterConsts.IntRegsCount, RegisterType.Vector); + return new Register(id - RegisterConsts.IntRegsCount, RegisterType.Vector); } else /* if (key < RegisterConsts.TotalCount) */ { - return new Register(key - RegisterConsts.IntAndVecRegsCount, RegisterType.Flag); + return new Register(id - RegisterConsts.IntAndVecRegsCount, RegisterType.Flag); } } } diff --git a/ARMeilleure/Translation/Translator.cs b/ARMeilleure/Translation/Translator.cs index 0a4172ea00..35453cadce 100644 --- a/ARMeilleure/Translation/Translator.cs +++ b/ARMeilleure/Translation/Translator.cs @@ -30,8 +30,6 @@ namespace ARMeilleure.Translation TranslatedFunction func = Translate(address, ExecutionMode.Aarch64); address = func.Execute(context); - - break; } while (address != 0); } @@ -58,9 +56,7 @@ namespace ARMeilleure.Translation logger.EndPass(PassName.SsaConstruction, cfg); - IRAdapter.Adapt(cfg, _memory); - - byte[] code = CodeGenerator.Generate(cfg); + byte[] code = CodeGenerator.Generate(cfg, _memory); return _cache.CreateFunction(code); } diff --git a/Ryujinx.Tests/Cpu/CpuTest.cs b/Ryujinx.Tests/Cpu/CpuTest.cs index 934e7b2b29..8fbf1e0e87 100644 --- a/Ryujinx.Tests/Cpu/CpuTest.cs +++ b/Ryujinx.Tests/Cpu/CpuTest.cs @@ -25,6 +25,8 @@ namespace Ryujinx.Tests.Cpu private ExecutionContext _context; + private Translator _translator; + private static bool _unicornAvailable; private UnicornAArch64 _unicornEmu; @@ -52,7 +54,7 @@ namespace Ryujinx.Tests.Cpu _context = new ExecutionContext(); - Translator translator = new Translator(_memory); + _translator = new Translator(_memory); if (_unicornAvailable) { @@ -165,9 +167,7 @@ namespace Ryujinx.Tests.Cpu protected void ExecuteOpcodes() { - Translator translator = new Translator(_memory); - - translator.Execute(_context, _entryPoint); + _translator.Execute(_context, _entryPoint); if (_unicornAvailable) {