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;
|
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)
|
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;
|
Node operation = node.Value;
|
||||||
|
|
||||||
Operand dest = operation.Dest;
|
foreach (Operand dest in Destinations(operation))
|
||||||
|
|
||||||
if (dest != null && dest.Kind == OperandKind.LocalVariable && visited.Add(dest))
|
|
||||||
{
|
{
|
||||||
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 (Node node in block.Operations)
|
||||||
{
|
{
|
||||||
foreach (Operand source in Operands(node))
|
foreach (Operand source in Sources(node))
|
||||||
{
|
{
|
||||||
int id = GetOperandId(source);
|
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;
|
operationPos -= InstructionGap;
|
||||||
|
|
||||||
Operand dest = node.Dest;
|
foreach (Operand dest in Destinations(node))
|
||||||
|
|
||||||
if (dest != null && IsLocalOrRegister(dest.Kind))
|
|
||||||
{
|
{
|
||||||
LiveInterval interval = _intervals[GetOperandId(dest)];
|
LiveInterval interval = _intervals[GetOperandId(dest)];
|
||||||
|
|
||||||
|
@ -904,7 +908,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
|
||||||
interval.AddUsePosition(operationPos + 1);
|
interval.AddUsePosition(operationPos + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (Operand source in Operands(node))
|
foreach (Operand source in Sources(node))
|
||||||
{
|
{
|
||||||
LiveInterval interval = _intervals[GetOperandId(source)];
|
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++)
|
for (int index = 0; index < node.SourcesCount; index++)
|
||||||
{
|
{
|
||||||
|
|
|
@ -700,6 +700,10 @@ namespace ARMeilleure.CodeGen.X86
|
||||||
|
|
||||||
if (dest.Type.IsInteger())
|
if (dest.Type.IsInteger())
|
||||||
{
|
{
|
||||||
|
divisor = operation.GetSource(2);
|
||||||
|
|
||||||
|
EnsureSameType(dest, divisor);
|
||||||
|
|
||||||
if (divisor.Type == OperandType.I32)
|
if (divisor.Type == OperandType.I32)
|
||||||
{
|
{
|
||||||
context.Assembler.Cdq();
|
context.Assembler.Cdq();
|
||||||
|
@ -723,7 +727,7 @@ namespace ARMeilleure.CodeGen.X86
|
||||||
|
|
||||||
private static void GenerateDivideUI(CodeGenContext context, Operation operation)
|
private static void GenerateDivideUI(CodeGenContext context, Operation operation)
|
||||||
{
|
{
|
||||||
Operand divisor = operation.GetSource(1);
|
Operand divisor = operation.GetSource(2);
|
||||||
|
|
||||||
Operand rdx = Register(X86Register.Rdx);
|
Operand rdx = Register(X86Register.Rdx);
|
||||||
|
|
||||||
|
|
|
@ -79,7 +79,7 @@ namespace ARMeilleure.CodeGen.X86
|
||||||
{
|
{
|
||||||
HandleLoadArgumentWindowsAbi(cctx, node, preservedArgs, operation);
|
HandleLoadArgumentWindowsAbi(cctx, node, preservedArgs, operation);
|
||||||
}
|
}
|
||||||
else
|
else /* if (callConv == CallConvName.SystemV) */
|
||||||
{
|
{
|
||||||
HandleLoadArgumentSystemVAbi(cctx, node, preservedArgs, operation);
|
HandleLoadArgumentSystemVAbi(cctx, node, preservedArgs, operation);
|
||||||
}
|
}
|
||||||
|
@ -209,28 +209,26 @@ namespace ARMeilleure.CodeGen.X86
|
||||||
// - The expected value should be in RDX:RAX.
|
// - The expected value should be in RDX:RAX.
|
||||||
// - The new value to be written should be in RCX:RBX.
|
// - The new value to be written should be in RCX:RBX.
|
||||||
// - The value at the memory location is loaded to RDX:RAX.
|
// - 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, lr, source, Const(0)));
|
||||||
nodes.AddBefore(node, new Operation(Instruction.VectorExtract, hr, source, Const(1)));
|
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 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);
|
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.VectorCreateScalar, dest, rax));
|
||||||
node = nodes.AddAfter(node, new Operation(Instruction.VectorInsert, dest, dest, rdx, Const(1)));
|
node = nodes.AddAfter(node, new Operation(Instruction.VectorInsert, dest, dest, rdx, Const(1)));
|
||||||
|
|
||||||
operation.SetSource(1, Undef());
|
operation.SetDestinations(new Operand[] { rdx, rax });
|
||||||
operation.SetSource(2, Undef());
|
|
||||||
|
|
||||||
operation.Dest = null;
|
operation.SetSources(new Operand[] { operation.GetSource(0), rdx, rax, rcx, rbx });
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -245,25 +243,24 @@ namespace ARMeilleure.CodeGen.X86
|
||||||
|
|
||||||
Operand eax = Gpr(X86Register.Rax, OperandType.I32);
|
Operand eax = Gpr(X86Register.Rax, OperandType.I32);
|
||||||
Operand ebx = Gpr(X86Register.Rbx, 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);
|
Operand edx = Gpr(X86Register.Rdx, OperandType.I32);
|
||||||
|
|
||||||
// Value 0x01 = Version, family and feature information.
|
// Value 0x01 = Version, family and feature information.
|
||||||
nodes.AddBefore(node, new Operation(Instruction.Copy, eax, Const(1)));
|
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.
|
// Copy results to the destination register.
|
||||||
// The values are split into 2 32-bits registers, we merge them
|
// The values are split into 2 32-bits registers, we merge them
|
||||||
// into a single 64-bits register.
|
// 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.ZeroExtend32, dest, edx));
|
||||||
node = nodes.AddAfter(node, new Operation(Instruction.ShiftLeft, dest, dest, Const(32)));
|
node = nodes.AddAfter(node, new Operation(Instruction.ShiftLeft, dest, dest, Const(32)));
|
||||||
node = nodes.AddAfter(node, new Operation(Instruction.BitwiseOr, dest, dest, rcx));
|
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;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -280,14 +277,15 @@ namespace ARMeilleure.CodeGen.X86
|
||||||
Operand rax = Gpr(X86Register.Rax, src1.Type);
|
Operand rax = Gpr(X86Register.Rax, src1.Type);
|
||||||
Operand rdx = Gpr(X86Register.Rdx, src1.Type);
|
Operand rdx = Gpr(X86Register.Rdx, src1.Type);
|
||||||
|
|
||||||
nodes.AddBefore(node, new Operation(Instruction.Copy, rax, src1));
|
nodes.AddBefore(node, new Operation(Instruction.Copy, rax, src1));
|
||||||
|
|
||||||
operation.SetSource(0, rax);
|
|
||||||
|
|
||||||
nodes.AddBefore(node, new Operation(Instruction.Clobber, rdx));
|
nodes.AddBefore(node, new Operation(Instruction.Clobber, rdx));
|
||||||
|
|
||||||
node = nodes.AddAfter(node, new Operation(Instruction.Copy, dest, rax));
|
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;
|
operation.Dest = rax;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
@ -328,7 +326,7 @@ namespace ARMeilleure.CodeGen.X86
|
||||||
|
|
||||||
node = nodes.AddAfter(node, new Operation(Instruction.Copy, dest, rdx));
|
node = nodes.AddAfter(node, new Operation(Instruction.Copy, dest, rdx));
|
||||||
|
|
||||||
operation.Dest = rdx;
|
operation.SetDestinations(new Operand[] { rdx, rax });
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -571,11 +569,13 @@ namespace ARMeilleure.CodeGen.X86
|
||||||
return offset;
|
return offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Operand arg0Reg = null;
|
||||||
|
|
||||||
if (dest != null && dest.Type == OperandType.V128)
|
if (dest != null && dest.Type == OperandType.V128)
|
||||||
{
|
{
|
||||||
int stackOffset = AllocateOnStack(dest.Type.GetSizeInBytes());
|
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));
|
Operation allocOp = new Operation(Instruction.StackAlloc, arg0Reg, Const(stackOffset));
|
||||||
|
|
||||||
|
@ -584,6 +584,24 @@ namespace ARMeilleure.CodeGen.X86
|
||||||
retArgs = 1;
|
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++)
|
for (int index = 1; index < operation.SourcesCount; index++)
|
||||||
{
|
{
|
||||||
Operand source = operation.GetSource(index);
|
Operand source = operation.GetSource(index);
|
||||||
|
@ -602,35 +620,29 @@ namespace ARMeilleure.CodeGen.X86
|
||||||
|
|
||||||
HandleConstantCopy(nodes.AddBefore(node, storeOp), storeOp);
|
HandleConstantCopy(nodes.AddBefore(node, storeOp), storeOp);
|
||||||
|
|
||||||
operation.SetSource(index, stackAddr);
|
sources[retArgs + index] = stackAddr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle arguments passed on registers.
|
// 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++)
|
for (int index = 0; index < argsCount; index++)
|
||||||
{
|
{
|
||||||
Operand source = operation.GetSource(index + 1);
|
Operand source = operation.GetSource(index + 1);
|
||||||
|
|
||||||
RegisterType regType = source.Type.ToRegisterType();
|
if (source.Type == OperandType.V128)
|
||||||
|
{
|
||||||
|
source = sources[1 + retArgs + index];
|
||||||
|
}
|
||||||
|
|
||||||
Operand argReg;
|
Operand argReg;
|
||||||
|
|
||||||
int argIndex = index + retArgs;
|
int argIndex = index + retArgs;
|
||||||
|
|
||||||
if (regType == RegisterType.Integer)
|
if (source.Type.IsInteger())
|
||||||
{
|
{
|
||||||
argReg = Gpr(CallingConvention.GetIntArgumentRegister(argIndex), source.Type);
|
argReg = Gpr(CallingConvention.GetIntArgumentRegister(argIndex), source.Type);
|
||||||
}
|
}
|
||||||
else /* if (regType == RegisterType.Vector) */
|
else
|
||||||
{
|
{
|
||||||
argReg = Xmm(CallingConvention.GetVecArgumentRegister(argIndex), source.Type);
|
argReg = Xmm(CallingConvention.GetVecArgumentRegister(argIndex), source.Type);
|
||||||
}
|
}
|
||||||
|
@ -639,7 +651,7 @@ namespace ARMeilleure.CodeGen.X86
|
||||||
|
|
||||||
HandleConstantCopy(nodes.AddBefore(node, copyOp), copyOp);
|
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)
|
// 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);
|
Operation spillOp = new Operation(Instruction.SpillArg, null, offset, source);
|
||||||
|
|
||||||
HandleConstantCopy(nodes.AddBefore(node, spillOp), spillOp);
|
HandleConstantCopy(nodes.AddBefore(node, spillOp), spillOp);
|
||||||
|
|
||||||
operation.SetSource(index + 1, new Operand(OperandKind.Undefined));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dest != null)
|
if (dest != null)
|
||||||
|
@ -663,8 +673,6 @@ namespace ARMeilleure.CodeGen.X86
|
||||||
{
|
{
|
||||||
Operand retValueAddr = Local(OperandType.I64);
|
Operand retValueAddr = Local(OperandType.I64);
|
||||||
|
|
||||||
Operand arg0Reg = Gpr(CallingConvention.GetIntArgumentRegister(0), OperandType.I64);
|
|
||||||
|
|
||||||
Operation copyOp = new Operation(Instruction.Copy, retValueAddr, arg0Reg);
|
Operation copyOp = new Operation(Instruction.Copy, retValueAddr, arg0Reg);
|
||||||
|
|
||||||
nodes.AddBefore(node, copyOp);
|
nodes.AddBefore(node, copyOp);
|
||||||
|
@ -677,9 +685,7 @@ namespace ARMeilleure.CodeGen.X86
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
RegisterType regType = dest.Type.ToRegisterType();
|
Operand retReg = dest.Type.IsInteger()
|
||||||
|
|
||||||
Operand retReg = regType == RegisterType.Integer
|
|
||||||
? Gpr(CallingConvention.GetIntReturnRegister(), dest.Type)
|
? Gpr(CallingConvention.GetIntReturnRegister(), dest.Type)
|
||||||
: Xmm(CallingConvention.GetVecReturnRegister(), dest.Type);
|
: Xmm(CallingConvention.GetVecReturnRegister(), dest.Type);
|
||||||
|
|
||||||
|
@ -691,6 +697,8 @@ namespace ARMeilleure.CodeGen.X86
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
operation.SetSources(sources);
|
||||||
|
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -700,7 +708,10 @@ namespace ARMeilleure.CodeGen.X86
|
||||||
|
|
||||||
LinkedList<Node> nodes = node.List;
|
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 argsCount = operation.SourcesCount - 1;
|
||||||
|
|
||||||
int intMax = CallingConvention.GetIntArgumentsOnRegsCount();
|
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, argReg, source, Const(0)));
|
||||||
nodes.AddBefore(node, new Operation(Instruction.VectorExtract, argReg2, source, Const(1)));
|
nodes.AddBefore(node, new Operation(Instruction.VectorExtract, argReg2, source, Const(1)));
|
||||||
|
|
||||||
operation.SetSource(index + 1, Undef());
|
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -754,7 +763,7 @@ namespace ARMeilleure.CodeGen.X86
|
||||||
|
|
||||||
HandleConstantCopy(nodes.AddBefore(node, copyOp), copyOp);
|
HandleConstantCopy(nodes.AddBefore(node, copyOp), copyOp);
|
||||||
|
|
||||||
operation.SetSource(index + 1, argReg);
|
sources.Add(argReg);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -765,8 +774,6 @@ namespace ARMeilleure.CodeGen.X86
|
||||||
HandleConstantCopy(nodes.AddBefore(node, spillOp), spillOp);
|
HandleConstantCopy(nodes.AddBefore(node, spillOp), spillOp);
|
||||||
|
|
||||||
stackOffset += source.Type.GetSizeInBytes();
|
stackOffset += source.Type.GetSizeInBytes();
|
||||||
|
|
||||||
operation.SetSource(index + 1, Undef());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -784,9 +791,7 @@ namespace ARMeilleure.CodeGen.X86
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
RegisterType regType = dest.Type.ToRegisterType();
|
Operand retReg = dest.Type.IsInteger()
|
||||||
|
|
||||||
Operand retReg = regType == RegisterType.Integer
|
|
||||||
? Gpr(CallingConvention.GetIntReturnRegister(), dest.Type)
|
? Gpr(CallingConvention.GetIntReturnRegister(), dest.Type)
|
||||||
: Xmm(CallingConvention.GetVecReturnRegister(), dest.Type);
|
: Xmm(CallingConvention.GetVecReturnRegister(), dest.Type);
|
||||||
|
|
||||||
|
@ -798,6 +803,8 @@ namespace ARMeilleure.CodeGen.X86
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
operation.SetSources(sources.ToArray());
|
||||||
|
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -76,21 +76,4 @@ namespace ARMeilleure.IntermediateRepresentation
|
||||||
SpillArg,
|
SpillArg,
|
||||||
StoreToContext
|
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
|
class Node
|
||||||
{
|
{
|
||||||
private Operand _dest;
|
|
||||||
|
|
||||||
private LinkedListNode<Node> _asgUseNode;
|
|
||||||
|
|
||||||
public Operand Dest
|
public Operand Dest
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
return _dest;
|
return _destinations.Length != 0 ? GetDestination(0) : null;
|
||||||
}
|
}
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
if (_dest != null && _dest.Kind == OperandKind.LocalVariable)
|
if (value != null)
|
||||||
{
|
{
|
||||||
_dest.Assignments.Remove(_asgUseNode);
|
SetDestinations(new Operand[] { value });
|
||||||
}
|
}
|
||||||
|
else
|
||||||
if (value != null && value.Kind == OperandKind.LocalVariable)
|
|
||||||
{
|
{
|
||||||
_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)
|
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)
|
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 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;
|
Inst = inst;
|
||||||
Dest = dest;
|
|
||||||
|
|
||||||
//The array may be modified externally, so we store a copy.
|
for (int index = 0; index < sources.Length; index++)
|
||||||
Sources = (Operand[])sources.Clone();
|
|
||||||
|
|
||||||
for (int index = 0; index < Sources.Length; index++)
|
|
||||||
{
|
{
|
||||||
Operand source = Sources[index];
|
SetSource(index, sources[index]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (source.Kind == OperandKind.LocalVariable)
|
public Operation(
|
||||||
{
|
Instruction inst,
|
||||||
SrcUseNodes[index] = source.Uses.AddLast(this);
|
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;
|
Inst = Instruction.Copy;
|
||||||
|
|
||||||
for (int index = 0; index < Sources.Length; index++)
|
SetSources(new Operand[] { source });
|
||||||
{
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -4,13 +4,9 @@ namespace ARMeilleure.IntermediateRepresentation
|
||||||
{
|
{
|
||||||
private BasicBlock[] _blocks;
|
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];
|
_blocks = new BasicBlock[predecessorsCount];
|
||||||
|
|
||||||
Dest = dest;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public BasicBlock GetBlock(int index)
|
public BasicBlock GetBlock(int index)
|
||||||
|
|
|
@ -3,6 +3,7 @@ using ARMeilleure.Instructions;
|
||||||
using ARMeilleure.IntermediateRepresentation;
|
using ARMeilleure.IntermediateRepresentation;
|
||||||
using ARMeilleure.Memory;
|
using ARMeilleure.Memory;
|
||||||
using ARMeilleure.State;
|
using ARMeilleure.State;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
using static ARMeilleure.IntermediateRepresentation.OperandHelper;
|
using static ARMeilleure.IntermediateRepresentation.OperandHelper;
|
||||||
|
|
||||||
|
@ -10,6 +11,8 @@ namespace ARMeilleure.Translation
|
||||||
{
|
{
|
||||||
class ArmEmitterContext : EmitterContext
|
class ArmEmitterContext : EmitterContext
|
||||||
{
|
{
|
||||||
|
private Dictionary<ulong, Operand> _labels;
|
||||||
|
|
||||||
private OpCode _optOpLastCompare;
|
private OpCode _optOpLastCompare;
|
||||||
private OpCode _optOpLastFlagSet;
|
private OpCode _optOpLastFlagSet;
|
||||||
|
|
||||||
|
@ -42,6 +45,20 @@ namespace ARMeilleure.Translation
|
||||||
{
|
{
|
||||||
Memory = memory;
|
Memory = memory;
|
||||||
Mode = mode;
|
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)
|
public void MarkComparison(Operand n, Operand m)
|
||||||
|
|
|
@ -10,8 +10,6 @@ namespace ARMeilleure.Translation
|
||||||
{
|
{
|
||||||
class EmitterContext
|
class EmitterContext
|
||||||
{
|
{
|
||||||
private Dictionary<ulong, Operand> _labels;
|
|
||||||
|
|
||||||
private Dictionary<Operand, BasicBlock> _irLabels;
|
private Dictionary<Operand, BasicBlock> _irLabels;
|
||||||
|
|
||||||
private LinkedList<BasicBlock> _irBlocks;
|
private LinkedList<BasicBlock> _irBlocks;
|
||||||
|
@ -22,8 +20,6 @@ namespace ARMeilleure.Translation
|
||||||
|
|
||||||
public EmitterContext()
|
public EmitterContext()
|
||||||
{
|
{
|
||||||
_labels = new Dictionary<ulong, Operand>();
|
|
||||||
|
|
||||||
_irLabels = new Dictionary<Operand, BasicBlock>();
|
_irLabels = new Dictionary<Operand, BasicBlock>();
|
||||||
|
|
||||||
_irBlocks = new LinkedList<BasicBlock>();
|
_irBlocks = new LinkedList<BasicBlock>();
|
||||||
|
@ -94,37 +90,34 @@ namespace ARMeilleure.Translation
|
||||||
return Call(Const(ptr.ToInt64()), returnType, callArgs);
|
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)
|
private static OperandType GetOperandType(Type type)
|
||||||
{
|
{
|
||||||
switch (Type.GetTypeCode(type))
|
if (_typeCodeToOperandTypeMap.TryGetValue(Type.GetTypeCode(type), out OperandType ot))
|
||||||
{
|
{
|
||||||
case TypeCode.Boolean:
|
return ot;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
else if (type == typeof(V128))
|
||||||
if (type == typeof(V128))
|
|
||||||
{
|
{
|
||||||
return OperandType.V128;
|
return OperandType.V128;
|
||||||
}
|
}
|
||||||
|
else if (type == typeof(void))
|
||||||
if (type == typeof(void))
|
|
||||||
{
|
{
|
||||||
return OperandType.None;
|
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()
|
private void NewNextBlock()
|
||||||
{
|
{
|
||||||
BasicBlock block = new BasicBlock(_irBlocks.Count);
|
BasicBlock block = new BasicBlock(_irBlocks.Count);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue