Support multiple destination operands
This commit is contained in:
parent
ceb5c055a0
commit
36be15fe6c
9 changed files with 244 additions and 188 deletions
|
@ -695,19 +695,24 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
|
|||
{
|
||||
Node operation = GetOperationNode(usePosition).Value;
|
||||
|
||||
for (int srcIndex = 0; srcIndex < operation.SourcesCount; srcIndex++)
|
||||
for (int index = 0; index < operation.SourcesCount; index++)
|
||||
{
|
||||
Operand source = operation.GetSource(srcIndex);
|
||||
Operand source = operation.GetSource(index);
|
||||
|
||||
if (source == current.Local)
|
||||
{
|
||||
operation.SetSource(srcIndex, register);
|
||||
operation.SetSource(index, register);
|
||||
}
|
||||
}
|
||||
|
||||
if (operation.Dest == current.Local)
|
||||
for (int index = 0; index < operation.DestinationsCount; index++)
|
||||
{
|
||||
operation.Dest = register;
|
||||
Operand dest = operation.GetDestination(index);
|
||||
|
||||
if (dest == current.Local)
|
||||
{
|
||||
operation.SetDestination(index, register);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -753,13 +758,14 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
|
|||
|
||||
Node operation = node.Value;
|
||||
|
||||
Operand dest = operation.Dest;
|
||||
|
||||
if (dest != null && dest.Kind == OperandKind.LocalVariable && visited.Add(dest))
|
||||
foreach (Operand dest in Destinations(operation))
|
||||
{
|
||||
dest.NumberLocal(_intervals.Count);
|
||||
if (dest.Kind == OperandKind.LocalVariable && visited.Add(dest))
|
||||
{
|
||||
dest.NumberLocal(_intervals.Count);
|
||||
|
||||
_intervals.Add(new LiveInterval(dest));
|
||||
_intervals.Add(new LiveInterval(dest));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -794,7 +800,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
|
|||
|
||||
foreach (Node node in block.Operations)
|
||||
{
|
||||
foreach (Operand source in Operands(node))
|
||||
foreach (Operand source in Sources(node))
|
||||
{
|
||||
int id = GetOperandId(source);
|
||||
|
||||
|
@ -804,9 +810,9 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
|
|||
}
|
||||
}
|
||||
|
||||
if (node.Dest != null && IsLocalOrRegister(node.Dest.Kind))
|
||||
foreach (Operand dest in Destinations(node))
|
||||
{
|
||||
liveKill.Set(GetOperandId(node.Dest));
|
||||
liveKill.Set(GetOperandId(dest));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -894,9 +900,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
|
|||
{
|
||||
operationPos -= InstructionGap;
|
||||
|
||||
Operand dest = node.Dest;
|
||||
|
||||
if (dest != null && IsLocalOrRegister(dest.Kind))
|
||||
foreach (Operand dest in Destinations(node))
|
||||
{
|
||||
LiveInterval interval = _intervals[GetOperandId(dest)];
|
||||
|
||||
|
@ -904,7 +908,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
|
|||
interval.AddUsePosition(operationPos + 1);
|
||||
}
|
||||
|
||||
foreach (Operand source in Operands(node))
|
||||
foreach (Operand source in Sources(node))
|
||||
{
|
||||
LiveInterval interval = _intervals[GetOperandId(source)];
|
||||
|
||||
|
@ -983,7 +987,15 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
|
|||
}
|
||||
}
|
||||
|
||||
private static IEnumerable<Operand> Operands(Node node)
|
||||
private static IEnumerable<Operand> Destinations(Node node)
|
||||
{
|
||||
for (int index = 0; index < node.DestinationsCount; index++)
|
||||
{
|
||||
yield return node.GetDestination(index);
|
||||
}
|
||||
}
|
||||
|
||||
private static IEnumerable<Operand> Sources(Node node)
|
||||
{
|
||||
for (int index = 0; index < node.SourcesCount; index++)
|
||||
{
|
||||
|
|
|
@ -700,6 +700,10 @@ namespace ARMeilleure.CodeGen.X86
|
|||
|
||||
if (dest.Type.IsInteger())
|
||||
{
|
||||
divisor = operation.GetSource(2);
|
||||
|
||||
EnsureSameType(dest, divisor);
|
||||
|
||||
if (divisor.Type == OperandType.I32)
|
||||
{
|
||||
context.Assembler.Cdq();
|
||||
|
@ -723,7 +727,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||
|
||||
private static void GenerateDivideUI(CodeGenContext context, Operation operation)
|
||||
{
|
||||
Operand divisor = operation.GetSource(1);
|
||||
Operand divisor = operation.GetSource(2);
|
||||
|
||||
Operand rdx = Register(X86Register.Rdx);
|
||||
|
||||
|
|
|
@ -79,7 +79,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||
{
|
||||
HandleLoadArgumentWindowsAbi(cctx, node, preservedArgs, operation);
|
||||
}
|
||||
else
|
||||
else /* if (callConv == CallConvName.SystemV) */
|
||||
{
|
||||
HandleLoadArgumentSystemVAbi(cctx, node, preservedArgs, operation);
|
||||
}
|
||||
|
@ -209,28 +209,26 @@ namespace ARMeilleure.CodeGen.X86
|
|||
// - The expected value should be in RDX:RAX.
|
||||
// - The new value to be written should be in RCX:RBX.
|
||||
// - The value at the memory location is loaded to RDX:RAX.
|
||||
void SplitOperand(Operand source, X86Register lowReg, X86Register highReg)
|
||||
void SplitOperand(Operand source, Operand lr, Operand hr)
|
||||
{
|
||||
Operand lr = Gpr(lowReg, OperandType.I64);
|
||||
Operand hr = Gpr(highReg, OperandType.I64);
|
||||
|
||||
nodes.AddBefore(node, new Operation(Instruction.VectorExtract, lr, source, Const(0)));
|
||||
nodes.AddBefore(node, new Operation(Instruction.VectorExtract, hr, source, Const(1)));
|
||||
}
|
||||
|
||||
SplitOperand(operation.GetSource(1), X86Register.Rax, X86Register.Rdx);
|
||||
SplitOperand(operation.GetSource(2), X86Register.Rbx, X86Register.Rcx);
|
||||
|
||||
Operand rax = Gpr(X86Register.Rax, OperandType.I64);
|
||||
Operand rbx = Gpr(X86Register.Rbx, OperandType.I64);
|
||||
Operand rcx = Gpr(X86Register.Rcx, OperandType.I64);
|
||||
Operand rdx = Gpr(X86Register.Rdx, OperandType.I64);
|
||||
|
||||
SplitOperand(operation.GetSource(1), rax, rdx);
|
||||
SplitOperand(operation.GetSource(2), rbx, rcx);
|
||||
|
||||
node = nodes.AddAfter(node, new Operation(Instruction.VectorCreateScalar, dest, rax));
|
||||
node = nodes.AddAfter(node, new Operation(Instruction.VectorInsert, dest, dest, rdx, Const(1)));
|
||||
|
||||
operation.SetSource(1, Undef());
|
||||
operation.SetSource(2, Undef());
|
||||
operation.SetDestinations(new Operand[] { rdx, rax });
|
||||
|
||||
operation.Dest = null;
|
||||
operation.SetSources(new Operand[] { operation.GetSource(0), rdx, rax, rcx, rbx });
|
||||
|
||||
break;
|
||||
}
|
||||
|
@ -245,25 +243,24 @@ namespace ARMeilleure.CodeGen.X86
|
|||
|
||||
Operand eax = Gpr(X86Register.Rax, OperandType.I32);
|
||||
Operand ebx = Gpr(X86Register.Rbx, OperandType.I32);
|
||||
Operand rcx = Gpr(X86Register.Rcx, OperandType.I64);
|
||||
Operand ecx = Gpr(X86Register.Rcx, OperandType.I32);
|
||||
Operand edx = Gpr(X86Register.Rdx, OperandType.I32);
|
||||
|
||||
// Value 0x01 = Version, family and feature information.
|
||||
nodes.AddBefore(node, new Operation(Instruction.Copy, eax, Const(1)));
|
||||
|
||||
// We don't care about those two, but their values are overwritten,
|
||||
// so we need to take that into account.
|
||||
node = nodes.AddAfter(node, new Operation(Instruction.Clobber, eax));
|
||||
node = nodes.AddAfter(node, new Operation(Instruction.Clobber, ebx));
|
||||
|
||||
// Copy results to the destination register.
|
||||
// The values are split into 2 32-bits registers, we merge them
|
||||
// into a single 64-bits register.
|
||||
Operand rcx = Gpr(X86Register.Rcx, OperandType.I64);
|
||||
|
||||
node = nodes.AddAfter(node, new Operation(Instruction.ZeroExtend32, dest, edx));
|
||||
node = nodes.AddAfter(node, new Operation(Instruction.ShiftLeft, dest, dest, Const(32)));
|
||||
node = nodes.AddAfter(node, new Operation(Instruction.BitwiseOr, dest, dest, rcx));
|
||||
|
||||
operation.Dest = null;
|
||||
operation.SetDestinations(new Operand[] { eax, ebx, ecx, edx });
|
||||
|
||||
operation.SetSources(new Operand[] { eax });
|
||||
|
||||
break;
|
||||
}
|
||||
|
@ -280,14 +277,15 @@ namespace ARMeilleure.CodeGen.X86
|
|||
Operand rax = Gpr(X86Register.Rax, src1.Type);
|
||||
Operand rdx = Gpr(X86Register.Rdx, src1.Type);
|
||||
|
||||
nodes.AddBefore(node, new Operation(Instruction.Copy, rax, src1));
|
||||
|
||||
operation.SetSource(0, rax);
|
||||
|
||||
nodes.AddBefore(node, new Operation(Instruction.Copy, rax, src1));
|
||||
nodes.AddBefore(node, new Operation(Instruction.Clobber, rdx));
|
||||
|
||||
node = nodes.AddAfter(node, new Operation(Instruction.Copy, dest, rax));
|
||||
|
||||
operation.SetDestinations(new Operand[] { rdx, rax });
|
||||
|
||||
operation.SetSources(new Operand[] { rdx, rax, operation.GetSource(1) });
|
||||
|
||||
operation.Dest = rax;
|
||||
|
||||
break;
|
||||
|
@ -328,7 +326,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||
|
||||
node = nodes.AddAfter(node, new Operation(Instruction.Copy, dest, rdx));
|
||||
|
||||
operation.Dest = rdx;
|
||||
operation.SetDestinations(new Operand[] { rdx, rax });
|
||||
|
||||
break;
|
||||
}
|
||||
|
@ -571,11 +569,13 @@ namespace ARMeilleure.CodeGen.X86
|
|||
return offset;
|
||||
}
|
||||
|
||||
Operand arg0Reg = null;
|
||||
|
||||
if (dest != null && dest.Type == OperandType.V128)
|
||||
{
|
||||
int stackOffset = AllocateOnStack(dest.Type.GetSizeInBytes());
|
||||
|
||||
Operand arg0Reg = Gpr(CallingConvention.GetIntArgumentRegister(0), OperandType.I64);
|
||||
arg0Reg = Gpr(CallingConvention.GetIntArgumentRegister(0), OperandType.I64);
|
||||
|
||||
Operation allocOp = new Operation(Instruction.StackAlloc, arg0Reg, Const(stackOffset));
|
||||
|
||||
|
@ -584,6 +584,24 @@ namespace ARMeilleure.CodeGen.X86
|
|||
retArgs = 1;
|
||||
}
|
||||
|
||||
int argsCount = operation.SourcesCount - 1;
|
||||
|
||||
int maxArgs = CallingConvention.GetArgumentsOnRegsCount() - retArgs;
|
||||
|
||||
if (argsCount > maxArgs)
|
||||
{
|
||||
argsCount = maxArgs;
|
||||
}
|
||||
|
||||
Operand[] sources = new Operand[1 + retArgs + argsCount];
|
||||
|
||||
sources[0] = operation.GetSource(0);
|
||||
|
||||
if (arg0Reg != null)
|
||||
{
|
||||
sources[1] = arg0Reg;
|
||||
}
|
||||
|
||||
for (int index = 1; index < operation.SourcesCount; index++)
|
||||
{
|
||||
Operand source = operation.GetSource(index);
|
||||
|
@ -602,35 +620,29 @@ namespace ARMeilleure.CodeGen.X86
|
|||
|
||||
HandleConstantCopy(nodes.AddBefore(node, storeOp), storeOp);
|
||||
|
||||
operation.SetSource(index, stackAddr);
|
||||
sources[retArgs + index] = stackAddr;
|
||||
}
|
||||
}
|
||||
|
||||
// Handle arguments passed on registers.
|
||||
int argsCount = operation.SourcesCount - 1;
|
||||
|
||||
int maxArgs = CallingConvention.GetArgumentsOnRegsCount() - retArgs;
|
||||
|
||||
if (argsCount > maxArgs)
|
||||
{
|
||||
argsCount = maxArgs;
|
||||
}
|
||||
|
||||
for (int index = 0; index < argsCount; index++)
|
||||
{
|
||||
Operand source = operation.GetSource(index + 1);
|
||||
|
||||
RegisterType regType = source.Type.ToRegisterType();
|
||||
if (source.Type == OperandType.V128)
|
||||
{
|
||||
source = sources[1 + retArgs + index];
|
||||
}
|
||||
|
||||
Operand argReg;
|
||||
|
||||
int argIndex = index + retArgs;
|
||||
|
||||
if (regType == RegisterType.Integer)
|
||||
if (source.Type.IsInteger())
|
||||
{
|
||||
argReg = Gpr(CallingConvention.GetIntArgumentRegister(argIndex), source.Type);
|
||||
}
|
||||
else /* if (regType == RegisterType.Vector) */
|
||||
else
|
||||
{
|
||||
argReg = Xmm(CallingConvention.GetVecArgumentRegister(argIndex), source.Type);
|
||||
}
|
||||
|
@ -639,7 +651,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||
|
||||
HandleConstantCopy(nodes.AddBefore(node, copyOp), copyOp);
|
||||
|
||||
operation.SetSource(index + 1, argReg);
|
||||
sources[1 + retArgs + index] = argReg;
|
||||
}
|
||||
|
||||
// The remaining arguments (those that are not passed on registers)
|
||||
|
@ -653,8 +665,6 @@ namespace ARMeilleure.CodeGen.X86
|
|||
Operation spillOp = new Operation(Instruction.SpillArg, null, offset, source);
|
||||
|
||||
HandleConstantCopy(nodes.AddBefore(node, spillOp), spillOp);
|
||||
|
||||
operation.SetSource(index + 1, new Operand(OperandKind.Undefined));
|
||||
}
|
||||
|
||||
if (dest != null)
|
||||
|
@ -663,8 +673,6 @@ namespace ARMeilleure.CodeGen.X86
|
|||
{
|
||||
Operand retValueAddr = Local(OperandType.I64);
|
||||
|
||||
Operand arg0Reg = Gpr(CallingConvention.GetIntArgumentRegister(0), OperandType.I64);
|
||||
|
||||
Operation copyOp = new Operation(Instruction.Copy, retValueAddr, arg0Reg);
|
||||
|
||||
nodes.AddBefore(node, copyOp);
|
||||
|
@ -677,9 +685,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||
}
|
||||
else
|
||||
{
|
||||
RegisterType regType = dest.Type.ToRegisterType();
|
||||
|
||||
Operand retReg = regType == RegisterType.Integer
|
||||
Operand retReg = dest.Type.IsInteger()
|
||||
? Gpr(CallingConvention.GetIntReturnRegister(), dest.Type)
|
||||
: Xmm(CallingConvention.GetVecReturnRegister(), dest.Type);
|
||||
|
||||
|
@ -691,6 +697,8 @@ namespace ARMeilleure.CodeGen.X86
|
|||
}
|
||||
}
|
||||
|
||||
operation.SetSources(sources);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
|
@ -700,7 +708,10 @@ namespace ARMeilleure.CodeGen.X86
|
|||
|
||||
LinkedList<Node> nodes = node.List;
|
||||
|
||||
// Handle arguments passed on registers.
|
||||
List<Operand> sources = new List<Operand>();
|
||||
|
||||
sources.Add(operation.GetSource(0));
|
||||
|
||||
int argsCount = operation.SourcesCount - 1;
|
||||
|
||||
int intMax = CallingConvention.GetIntArgumentsOnRegsCount();
|
||||
|
@ -739,8 +750,6 @@ namespace ARMeilleure.CodeGen.X86
|
|||
nodes.AddBefore(node, new Operation(Instruction.VectorExtract, argReg, source, Const(0)));
|
||||
nodes.AddBefore(node, new Operation(Instruction.VectorExtract, argReg2, source, Const(1)));
|
||||
|
||||
operation.SetSource(index + 1, Undef());
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -754,7 +763,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||
|
||||
HandleConstantCopy(nodes.AddBefore(node, copyOp), copyOp);
|
||||
|
||||
operation.SetSource(index + 1, argReg);
|
||||
sources.Add(argReg);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -765,8 +774,6 @@ namespace ARMeilleure.CodeGen.X86
|
|||
HandleConstantCopy(nodes.AddBefore(node, spillOp), spillOp);
|
||||
|
||||
stackOffset += source.Type.GetSizeInBytes();
|
||||
|
||||
operation.SetSource(index + 1, Undef());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -784,9 +791,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||
}
|
||||
else
|
||||
{
|
||||
RegisterType regType = dest.Type.ToRegisterType();
|
||||
|
||||
Operand retReg = regType == RegisterType.Integer
|
||||
Operand retReg = dest.Type.IsInteger()
|
||||
? Gpr(CallingConvention.GetIntReturnRegister(), dest.Type)
|
||||
: Xmm(CallingConvention.GetVecReturnRegister(), dest.Type);
|
||||
|
||||
|
@ -798,6 +803,8 @@ namespace ARMeilleure.CodeGen.X86
|
|||
}
|
||||
}
|
||||
|
||||
operation.SetSources(sources.ToArray());
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
|
|
|
@ -76,21 +76,4 @@ namespace ARMeilleure.IntermediateRepresentation
|
|||
SpillArg,
|
||||
StoreToContext
|
||||
}
|
||||
|
||||
static class InstructionExtensions
|
||||
{
|
||||
public static bool IsShift(this Instruction inst)
|
||||
{
|
||||
switch (inst)
|
||||
{
|
||||
case Instruction.RotateRight:
|
||||
case Instruction.ShiftLeft:
|
||||
case Instruction.ShiftRightSI:
|
||||
case Instruction.ShiftRightUI:
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,63 +4,129 @@ namespace ARMeilleure.IntermediateRepresentation
|
|||
{
|
||||
class Node
|
||||
{
|
||||
private Operand _dest;
|
||||
|
||||
private LinkedListNode<Node> _asgUseNode;
|
||||
|
||||
public Operand Dest
|
||||
{
|
||||
get
|
||||
{
|
||||
return _dest;
|
||||
return _destinations.Length != 0 ? GetDestination(0) : null;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (_dest != null && _dest.Kind == OperandKind.LocalVariable)
|
||||
if (value != null)
|
||||
{
|
||||
_dest.Assignments.Remove(_asgUseNode);
|
||||
SetDestinations(new Operand[] { value });
|
||||
}
|
||||
|
||||
if (value != null && value.Kind == OperandKind.LocalVariable)
|
||||
else
|
||||
{
|
||||
_asgUseNode = value.Assignments.AddLast(this);
|
||||
SetDestinations(new Operand[0]);
|
||||
}
|
||||
|
||||
_dest = value;
|
||||
}
|
||||
}
|
||||
|
||||
protected Operand[] Sources;
|
||||
private Operand[] _destinations;
|
||||
private Operand[] _sources;
|
||||
|
||||
public int SourcesCount => Sources.Length;
|
||||
private LinkedListNode<Node>[] _asgUseNodes;
|
||||
private LinkedListNode<Node>[] _srcUseNodes;
|
||||
|
||||
protected LinkedListNode<Node>[] SrcUseNodes;
|
||||
public int DestinationsCount => _destinations.Length;
|
||||
public int SourcesCount => _sources.Length;
|
||||
|
||||
public Node(int sourcesCount)
|
||||
public Node(Operand destination, int sourcesCount)
|
||||
{
|
||||
SrcUseNodes = new LinkedListNode<Node>[sourcesCount];
|
||||
Dest = destination;
|
||||
|
||||
_sources = new Operand[sourcesCount];
|
||||
|
||||
_srcUseNodes = new LinkedListNode<Node>[sourcesCount];
|
||||
}
|
||||
|
||||
public Node(Operand[] destinations, int sourcesCount)
|
||||
{
|
||||
SetDestinations(destinations);
|
||||
|
||||
_sources = new Operand[sourcesCount];
|
||||
|
||||
_srcUseNodes = new LinkedListNode<Node>[sourcesCount];
|
||||
}
|
||||
|
||||
public Operand GetDestination(int index)
|
||||
{
|
||||
return _destinations[index];
|
||||
}
|
||||
|
||||
public Operand GetSource(int index)
|
||||
{
|
||||
return Sources[index];
|
||||
return _sources[index];
|
||||
}
|
||||
|
||||
public void SetDestination(int index, Operand destination)
|
||||
{
|
||||
Set(_destinations, _asgUseNodes, index, destination);
|
||||
}
|
||||
|
||||
public void SetSource(int index, Operand source)
|
||||
{
|
||||
Operand oldSrc = Sources[index];
|
||||
Set(_sources, _srcUseNodes, index, source);
|
||||
}
|
||||
|
||||
if (oldSrc != null && oldSrc.Kind == OperandKind.LocalVariable)
|
||||
private void Set(Operand[] ops, LinkedListNode<Node>[] uses, int index, Operand newOp)
|
||||
{
|
||||
Operand oldOp = ops[index];
|
||||
|
||||
if (oldOp != null && oldOp.Kind == OperandKind.LocalVariable)
|
||||
{
|
||||
oldSrc.Uses.Remove(SrcUseNodes[index]);
|
||||
oldOp.Uses.Remove(uses[index]);
|
||||
}
|
||||
|
||||
if (source != null && source.Kind == OperandKind.LocalVariable)
|
||||
if (newOp != null && newOp.Kind == OperandKind.LocalVariable)
|
||||
{
|
||||
SrcUseNodes[index] = source.Uses.AddLast(this);
|
||||
uses[index] = newOp.Uses.AddLast(this);
|
||||
}
|
||||
|
||||
Sources[index] = source;
|
||||
ops[index] = newOp;
|
||||
}
|
||||
|
||||
public void SetDestinations(Operand[] destinations)
|
||||
{
|
||||
Set(ref _destinations, ref _asgUseNodes, destinations);
|
||||
}
|
||||
|
||||
public void SetSources(Operand[] sources)
|
||||
{
|
||||
Set(ref _sources, ref _srcUseNodes, sources);
|
||||
}
|
||||
|
||||
private void Set(ref Operand[] ops, ref LinkedListNode<Node>[] uses, Operand[] newOps)
|
||||
{
|
||||
if (ops != null)
|
||||
{
|
||||
for (int index = 0; index < ops.Length; index++)
|
||||
{
|
||||
Operand oldOp = ops[index];
|
||||
|
||||
if (oldOp != null && oldOp.Kind == OperandKind.LocalVariable)
|
||||
{
|
||||
oldOp.Uses.Remove(uses[index]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ops = new Operand[newOps.Length];
|
||||
|
||||
uses = new LinkedListNode<Node>[newOps.Length];
|
||||
|
||||
for (int index = 0; index < newOps.Length; index++)
|
||||
{
|
||||
Operand newOp = newOps[index];
|
||||
|
||||
ops[index] = newOp;
|
||||
|
||||
if (newOp.Kind == OperandKind.LocalVariable)
|
||||
{
|
||||
uses[index] = newOp.Uses.AddLast(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -6,22 +6,29 @@ namespace ARMeilleure.IntermediateRepresentation
|
|||
{
|
||||
public Instruction Inst { get; private set; }
|
||||
|
||||
public Operation(Instruction inst, Operand dest, params Operand[] sources) : base(sources.Length)
|
||||
public Operation(
|
||||
Instruction inst,
|
||||
Operand destination,
|
||||
params Operand[] sources) : base(destination, sources.Length)
|
||||
{
|
||||
Inst = inst;
|
||||
Dest = dest;
|
||||
|
||||
//The array may be modified externally, so we store a copy.
|
||||
Sources = (Operand[])sources.Clone();
|
||||
|
||||
for (int index = 0; index < Sources.Length; index++)
|
||||
for (int index = 0; index < sources.Length; index++)
|
||||
{
|
||||
Operand source = Sources[index];
|
||||
SetSource(index, sources[index]);
|
||||
}
|
||||
}
|
||||
|
||||
if (source.Kind == OperandKind.LocalVariable)
|
||||
{
|
||||
SrcUseNodes[index] = source.Uses.AddLast(this);
|
||||
}
|
||||
public Operation(
|
||||
Instruction inst,
|
||||
Operand[] destinations,
|
||||
Operand[] sources) : base(destinations, sources.Length)
|
||||
{
|
||||
Inst = inst;
|
||||
|
||||
for (int index = 0; index < sources.Length; index++)
|
||||
{
|
||||
SetSource(index, sources[index]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -29,24 +36,7 @@ namespace ARMeilleure.IntermediateRepresentation
|
|||
{
|
||||
Inst = Instruction.Copy;
|
||||
|
||||
for (int index = 0; index < Sources.Length; index++)
|
||||
{
|
||||
if (Sources[index].Kind != OperandKind.LocalVariable)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
Sources[index].Uses.Remove(SrcUseNodes[index]);
|
||||
}
|
||||
|
||||
Sources = new Operand[] { source };
|
||||
|
||||
SrcUseNodes = new LinkedListNode<Node>[1];
|
||||
|
||||
if (source.Kind == OperandKind.LocalVariable)
|
||||
{
|
||||
SrcUseNodes[0] = source.Uses.AddLast(this);
|
||||
}
|
||||
SetSources(new Operand[] { source });
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,13 +4,9 @@ namespace ARMeilleure.IntermediateRepresentation
|
|||
{
|
||||
private BasicBlock[] _blocks;
|
||||
|
||||
public PhiNode(Operand dest, int predecessorsCount) : base(predecessorsCount)
|
||||
public PhiNode(Operand destination, int predecessorsCount) : base(destination, predecessorsCount)
|
||||
{
|
||||
Sources = new Operand[predecessorsCount];
|
||||
|
||||
_blocks = new BasicBlock[predecessorsCount];
|
||||
|
||||
Dest = dest;
|
||||
}
|
||||
|
||||
public BasicBlock GetBlock(int index)
|
||||
|
|
|
@ -3,6 +3,7 @@ using ARMeilleure.Instructions;
|
|||
using ARMeilleure.IntermediateRepresentation;
|
||||
using ARMeilleure.Memory;
|
||||
using ARMeilleure.State;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using static ARMeilleure.IntermediateRepresentation.OperandHelper;
|
||||
|
||||
|
@ -10,6 +11,8 @@ namespace ARMeilleure.Translation
|
|||
{
|
||||
class ArmEmitterContext : EmitterContext
|
||||
{
|
||||
private Dictionary<ulong, Operand> _labels;
|
||||
|
||||
private OpCode _optOpLastCompare;
|
||||
private OpCode _optOpLastFlagSet;
|
||||
|
||||
|
@ -42,6 +45,20 @@ namespace ARMeilleure.Translation
|
|||
{
|
||||
Memory = memory;
|
||||
Mode = mode;
|
||||
|
||||
_labels = new Dictionary<ulong, Operand>();
|
||||
}
|
||||
|
||||
public Operand GetLabel(ulong address)
|
||||
{
|
||||
if (!_labels.TryGetValue(address, out Operand label))
|
||||
{
|
||||
label = Label();
|
||||
|
||||
_labels.Add(address, label);
|
||||
}
|
||||
|
||||
return label;
|
||||
}
|
||||
|
||||
public void MarkComparison(Operand n, Operand m)
|
||||
|
|
|
@ -10,8 +10,6 @@ namespace ARMeilleure.Translation
|
|||
{
|
||||
class EmitterContext
|
||||
{
|
||||
private Dictionary<ulong, Operand> _labels;
|
||||
|
||||
private Dictionary<Operand, BasicBlock> _irLabels;
|
||||
|
||||
private LinkedList<BasicBlock> _irBlocks;
|
||||
|
@ -22,8 +20,6 @@ namespace ARMeilleure.Translation
|
|||
|
||||
public EmitterContext()
|
||||
{
|
||||
_labels = new Dictionary<ulong, Operand>();
|
||||
|
||||
_irLabels = new Dictionary<Operand, BasicBlock>();
|
||||
|
||||
_irBlocks = new LinkedList<BasicBlock>();
|
||||
|
@ -94,37 +90,34 @@ namespace ARMeilleure.Translation
|
|||
return Call(Const(ptr.ToInt64()), returnType, callArgs);
|
||||
}
|
||||
|
||||
private static Dictionary<TypeCode, OperandType> _typeCodeToOperandTypeMap =
|
||||
new Dictionary<TypeCode, OperandType>()
|
||||
{
|
||||
{ TypeCode.Boolean, OperandType.I32 },
|
||||
{ TypeCode.Byte, OperandType.I32 },
|
||||
{ TypeCode.Char, OperandType.I32 },
|
||||
{ TypeCode.Double, OperandType.FP64 },
|
||||
{ TypeCode.Int16, OperandType.I32 },
|
||||
{ TypeCode.Int32, OperandType.I32 },
|
||||
{ TypeCode.Int64, OperandType.I64 },
|
||||
{ TypeCode.SByte, OperandType.I32 },
|
||||
{ TypeCode.Single, OperandType.FP32 },
|
||||
{ TypeCode.UInt16, OperandType.I32 },
|
||||
{ TypeCode.UInt32, OperandType.I32 },
|
||||
{ TypeCode.UInt64, OperandType.I64 }
|
||||
};
|
||||
|
||||
private static OperandType GetOperandType(Type type)
|
||||
{
|
||||
switch (Type.GetTypeCode(type))
|
||||
if (_typeCodeToOperandTypeMap.TryGetValue(Type.GetTypeCode(type), out OperandType ot))
|
||||
{
|
||||
case TypeCode.Boolean:
|
||||
case TypeCode.Char:
|
||||
case TypeCode.Byte:
|
||||
case TypeCode.SByte:
|
||||
case TypeCode.UInt16:
|
||||
case TypeCode.Int16:
|
||||
case TypeCode.UInt32:
|
||||
case TypeCode.Int32:
|
||||
return OperandType.I32;
|
||||
|
||||
case TypeCode.UInt64:
|
||||
case TypeCode.Int64:
|
||||
return OperandType.I64;
|
||||
|
||||
case TypeCode.Single:
|
||||
return OperandType.FP32;
|
||||
|
||||
case TypeCode.Double:
|
||||
return OperandType.FP64;
|
||||
return ot;
|
||||
}
|
||||
|
||||
if (type == typeof(V128))
|
||||
else if (type == typeof(V128))
|
||||
{
|
||||
return OperandType.V128;
|
||||
}
|
||||
|
||||
if (type == typeof(void))
|
||||
else if (type == typeof(void))
|
||||
{
|
||||
return OperandType.None;
|
||||
}
|
||||
|
@ -527,18 +520,6 @@ namespace ARMeilleure.Translation
|
|||
}
|
||||
}
|
||||
|
||||
public Operand GetLabel(ulong address)
|
||||
{
|
||||
if (!_labels.TryGetValue(address, out Operand label))
|
||||
{
|
||||
label = Label();
|
||||
|
||||
_labels.Add(address, label);
|
||||
}
|
||||
|
||||
return label;
|
||||
}
|
||||
|
||||
private void NewNextBlock()
|
||||
{
|
||||
BasicBlock block = new BasicBlock(_irBlocks.Count);
|
||||
|
|
Loading…
Add table
Reference in a new issue