Refactoring around the old IRAdapter, now renamed to PreAllocator

This commit is contained in:
gdkchan 2019-05-28 22:28:24 -03:00
parent c25bc79316
commit 8e6ee56200
13 changed files with 559 additions and 541 deletions

View file

@ -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);

View file

@ -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);

View file

@ -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> _node;
public IRModContext(BasicBlock block, LinkedListNode<Node> 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> 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<Node> 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;
}
}
}

View file

@ -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> _node;
public IRModContext(BasicBlock block, LinkedListNode<Node> 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> 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> 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> 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> 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> 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> 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;
}
}
}

View file

@ -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();

View file

@ -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)

View file

@ -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));

View file

@ -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);

View file

@ -7,7 +7,6 @@ namespace ARMeilleure.IntermediateRepresentation
LocalVariable,
Memory,
Register,
RegisterNoRename,
Undefined
}
}

View file

@ -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))

View file

@ -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<Register, Operand> _map;
private long[] _phiMasks;
private BitMap _phiMasks;
public DefMap()
{
_map = new Dictionary<Register, Operand>();
_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<BasicBlock> 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);
}
}
}

View file

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

View file

@ -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)
{