Refactoring around the old IRAdapter, now renamed to PreAllocator
This commit is contained in:
parent
c25bc79316
commit
8e6ee56200
13 changed files with 559 additions and 541 deletions
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
417
ARMeilleure/CodeGen/X86/PreAllocator.cs
Normal file
417
ARMeilleure/CodeGen/X86/PreAllocator.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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));
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -7,7 +7,6 @@ namespace ARMeilleure.IntermediateRepresentation
|
|||
LocalVariable,
|
||||
Memory,
|
||||
Register,
|
||||
RegisterNoRename,
|
||||
Undefined
|
||||
}
|
||||
}
|
|
@ -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))
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
Loading…
Add table
Reference in a new issue