Initial support for the System-V ABI
This commit is contained in:
parent
40b8a2a750
commit
ceb5c055a0
12 changed files with 452 additions and 81 deletions
8
ARMeilleure/CodeGen/X86/CallConvName.cs
Normal file
8
ARMeilleure/CodeGen/X86/CallConvName.cs
Normal file
|
@ -0,0 +1,8 @@
|
|||
namespace ARMeilleure.CodeGen.X86
|
||||
{
|
||||
enum CallConvName
|
||||
{
|
||||
SystemV,
|
||||
Windows
|
||||
}
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace ARMeilleure.CodeGen.X86
|
||||
{
|
||||
|
@ -18,23 +19,45 @@ namespace ARMeilleure.CodeGen.X86
|
|||
|
||||
public static int GetIntCallerSavedRegisters()
|
||||
{
|
||||
return (1 << (int)X86Register.Rax) |
|
||||
(1 << (int)X86Register.Rdx) |
|
||||
(1 << (int)X86Register.Rcx) |
|
||||
(1 << (int)X86Register.R8) |
|
||||
(1 << (int)X86Register.R9) |
|
||||
(1 << (int)X86Register.R10) |
|
||||
(1 << (int)X86Register.R11);
|
||||
if (GetCurrentCallConv() == CallConvName.Windows)
|
||||
{
|
||||
return (1 << (int)X86Register.Rax) |
|
||||
(1 << (int)X86Register.Rcx) |
|
||||
(1 << (int)X86Register.Rdx) |
|
||||
(1 << (int)X86Register.R8) |
|
||||
(1 << (int)X86Register.R9) |
|
||||
(1 << (int)X86Register.R10) |
|
||||
(1 << (int)X86Register.R11);
|
||||
}
|
||||
else /* if (GetCurrentCallConv() == CallConvName.SystemV) */
|
||||
{
|
||||
return (1 << (int)X86Register.Rax) |
|
||||
(1 << (int)X86Register.Rcx) |
|
||||
(1 << (int)X86Register.Rdx) |
|
||||
(1 << (int)X86Register.Rsi) |
|
||||
(1 << (int)X86Register.Rdi) |
|
||||
(1 << (int)X86Register.R8) |
|
||||
(1 << (int)X86Register.R9) |
|
||||
(1 << (int)X86Register.R10) |
|
||||
(1 << (int)X86Register.R11);
|
||||
}
|
||||
}
|
||||
|
||||
public static int GetVecCallerSavedRegisters()
|
||||
{
|
||||
return (1 << (int)X86Register.Xmm0) |
|
||||
(1 << (int)X86Register.Xmm1) |
|
||||
(1 << (int)X86Register.Xmm2) |
|
||||
(1 << (int)X86Register.Xmm3) |
|
||||
(1 << (int)X86Register.Xmm4) |
|
||||
(1 << (int)X86Register.Xmm5);
|
||||
if (GetCurrentCallConv() == CallConvName.Windows)
|
||||
{
|
||||
return (1 << (int)X86Register.Xmm0) |
|
||||
(1 << (int)X86Register.Xmm1) |
|
||||
(1 << (int)X86Register.Xmm2) |
|
||||
(1 << (int)X86Register.Xmm3) |
|
||||
(1 << (int)X86Register.Xmm4) |
|
||||
(1 << (int)X86Register.Xmm5);
|
||||
}
|
||||
else /* if (GetCurrentCallConv() == CallConvName.SystemV) */
|
||||
{
|
||||
return RegistersMask;
|
||||
}
|
||||
}
|
||||
|
||||
public static int GetIntCalleeSavedRegisters()
|
||||
|
@ -52,14 +75,39 @@ namespace ARMeilleure.CodeGen.X86
|
|||
return 4;
|
||||
}
|
||||
|
||||
public static int GetIntArgumentsOnRegsCount()
|
||||
{
|
||||
return 6;
|
||||
}
|
||||
|
||||
public static int GetVecArgumentsOnRegsCount()
|
||||
{
|
||||
return 8;
|
||||
}
|
||||
|
||||
public static X86Register GetIntArgumentRegister(int index)
|
||||
{
|
||||
switch (index)
|
||||
if (GetCurrentCallConv() == CallConvName.Windows)
|
||||
{
|
||||
case 0: return X86Register.Rcx;
|
||||
case 1: return X86Register.Rdx;
|
||||
case 2: return X86Register.R8;
|
||||
case 3: return X86Register.R9;
|
||||
switch (index)
|
||||
{
|
||||
case 0: return X86Register.Rcx;
|
||||
case 1: return X86Register.Rdx;
|
||||
case 2: return X86Register.R8;
|
||||
case 3: return X86Register.R9;
|
||||
}
|
||||
}
|
||||
else /* if (GetCurrentCallConv() == CallConvName.SystemV) */
|
||||
{
|
||||
switch (index)
|
||||
{
|
||||
case 0: return X86Register.Rdi;
|
||||
case 1: return X86Register.Rsi;
|
||||
case 2: return X86Register.Rdx;
|
||||
case 3: return X86Register.Rcx;
|
||||
case 4: return X86Register.R8;
|
||||
case 5: return X86Register.R9;
|
||||
}
|
||||
}
|
||||
|
||||
throw new ArgumentOutOfRangeException(nameof(index));
|
||||
|
@ -67,12 +115,20 @@ namespace ARMeilleure.CodeGen.X86
|
|||
|
||||
public static X86Register GetVecArgumentRegister(int index)
|
||||
{
|
||||
switch (index)
|
||||
int count;
|
||||
|
||||
if (GetCurrentCallConv() == CallConvName.Windows)
|
||||
{
|
||||
case 0: return X86Register.Xmm0;
|
||||
case 1: return X86Register.Xmm1;
|
||||
case 2: return X86Register.Xmm2;
|
||||
case 3: return X86Register.Xmm3;
|
||||
count = 4;
|
||||
}
|
||||
else /* if (GetCurrentCallConv() == CallConvName.SystemV) */
|
||||
{
|
||||
count = 8;
|
||||
}
|
||||
|
||||
if ((uint)index < count)
|
||||
{
|
||||
return X86Register.Xmm0 + index;
|
||||
}
|
||||
|
||||
throw new ArgumentOutOfRangeException(nameof(index));
|
||||
|
@ -83,9 +139,21 @@ namespace ARMeilleure.CodeGen.X86
|
|||
return X86Register.Rax;
|
||||
}
|
||||
|
||||
public static X86Register GetIntReturnRegisterHigh()
|
||||
{
|
||||
return X86Register.Rdx;
|
||||
}
|
||||
|
||||
public static X86Register GetVecReturnRegister()
|
||||
{
|
||||
return X86Register.Xmm0;
|
||||
}
|
||||
|
||||
public static CallConvName GetCurrentCallConv()
|
||||
{
|
||||
return RuntimeInformation.IsOSPlatform(OSPlatform.Windows)
|
||||
? CallConvName.Windows
|
||||
: CallConvName.SystemV;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -116,7 +116,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||
|
||||
int frameSize = calleeSaveRegionSize + allocResult.SpillRegionSize;
|
||||
|
||||
int callArgsAndFrameSize = frameSize + argsCount * 8;
|
||||
int callArgsAndFrameSize = frameSize + argsCount * 16; //FIXME * 16 => calc
|
||||
|
||||
//Ensure that the Stack Pointer will be aligned to 16 bytes.
|
||||
callArgsAndFrameSize = (callArgsAndFrameSize + 0xf) & ~0xf;
|
||||
|
|
|
@ -117,7 +117,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||
|
||||
Logger.StartPass(PassName.RegisterAllocation);
|
||||
|
||||
FastLinearScan regAlloc = new FastLinearScan();
|
||||
LinearScan regAlloc = new LinearScan();
|
||||
|
||||
RegisterMasks regMasks = new RegisterMasks(
|
||||
CallingConvention.GetIntAvailableRegisters(),
|
||||
|
@ -1607,7 +1607,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||
size = (size + pageMask) & ~pageMask;
|
||||
|
||||
Operand rsp = Register(X86Register.Rsp);
|
||||
Operand temp = Register(CallingConvention.GetIntReturnRegister());
|
||||
Operand temp = Register(CallingConvention.GetIntReturnRegister());
|
||||
|
||||
for (int offset = PageSize; offset < size; offset += PageSize)
|
||||
{
|
||||
|
|
|
@ -38,7 +38,9 @@ namespace ARMeilleure.CodeGen.X86
|
|||
|
||||
ControlFlowGraph cfg = context.GetControlFlowGraph();
|
||||
|
||||
GetFeatureInfo getFeatureInfo = Compiler.Compile<GetFeatureInfo>(cfg, OperandType.I64);
|
||||
OperandType[] argTypes = new OperandType[0];
|
||||
|
||||
GetFeatureInfo getFeatureInfo = Compiler.Compile<GetFeatureInfo>(cfg, argTypes, OperandType.I64);
|
||||
|
||||
_featureInfo = getFeatureInfo();
|
||||
}
|
||||
|
|
|
@ -16,6 +16,8 @@ namespace ARMeilleure.CodeGen.X86
|
|||
{
|
||||
maxCallArgs = -1;
|
||||
|
||||
CallConvName callConv = CallingConvention.GetCurrentCallConv();
|
||||
|
||||
Operand[] preservedArgs = new Operand[CallingConvention.GetArgumentsOnRegsCount()];
|
||||
|
||||
foreach (BasicBlock block in cctx.Cfg.Blocks)
|
||||
|
@ -58,7 +60,14 @@ namespace ARMeilleure.CodeGen.X86
|
|||
|
||||
// Copy values to registers expected by the function
|
||||
// being called, as mandated by the ABI.
|
||||
node = HandleCallWindowsAbi(stackAlloc, node, operation);
|
||||
if (callConv == CallConvName.Windows)
|
||||
{
|
||||
node = HandleCallWindowsAbi(stackAlloc, node, operation);
|
||||
}
|
||||
else /* if (callConv == CallConvName.SystemV) */
|
||||
{
|
||||
node = HandleCallSystemVAbi(node, operation);
|
||||
}
|
||||
break;
|
||||
|
||||
case Instruction.ConvertToFPUI:
|
||||
|
@ -66,7 +75,14 @@ namespace ARMeilleure.CodeGen.X86
|
|||
break;
|
||||
|
||||
case Instruction.LoadArgument:
|
||||
HandleLoadArgumentWindowsAbi(cctx, node, preservedArgs, operation);
|
||||
if (callConv == CallConvName.Windows)
|
||||
{
|
||||
HandleLoadArgumentWindowsAbi(cctx, node, preservedArgs, operation);
|
||||
}
|
||||
else
|
||||
{
|
||||
HandleLoadArgumentSystemVAbi(cctx, node, preservedArgs, operation);
|
||||
}
|
||||
break;
|
||||
|
||||
case Instruction.Negate:
|
||||
|
@ -77,7 +93,14 @@ namespace ARMeilleure.CodeGen.X86
|
|||
break;
|
||||
|
||||
case Instruction.Return:
|
||||
HandleReturnWindowsAbi(cctx, node, preservedArgs, operation);
|
||||
if (callConv == CallConvName.Windows)
|
||||
{
|
||||
HandleReturnWindowsAbi(cctx, node, preservedArgs, operation);
|
||||
}
|
||||
else /* if (callConv == CallConvName.SystemV) */
|
||||
{
|
||||
HandleReturnSystemVAbi(node, operation);
|
||||
}
|
||||
break;
|
||||
|
||||
case Instruction.VectorInsert8:
|
||||
|
@ -612,9 +635,9 @@ namespace ARMeilleure.CodeGen.X86
|
|||
argReg = Xmm(CallingConvention.GetVecArgumentRegister(argIndex), source.Type);
|
||||
}
|
||||
|
||||
Operation srcCopyOp = new Operation(Instruction.Copy, argReg, source);
|
||||
Operation copyOp = new Operation(Instruction.Copy, argReg, source);
|
||||
|
||||
HandleConstantCopy(nodes.AddBefore(node, srcCopyOp), srcCopyOp);
|
||||
HandleConstantCopy(nodes.AddBefore(node, copyOp), copyOp);
|
||||
|
||||
operation.SetSource(index + 1, argReg);
|
||||
}
|
||||
|
@ -656,20 +679,120 @@ namespace ARMeilleure.CodeGen.X86
|
|||
{
|
||||
RegisterType regType = dest.Type.ToRegisterType();
|
||||
|
||||
Operand retReg;
|
||||
Operand retReg = regType == RegisterType.Integer
|
||||
? Gpr(CallingConvention.GetIntReturnRegister(), dest.Type)
|
||||
: Xmm(CallingConvention.GetVecReturnRegister(), dest.Type);
|
||||
|
||||
if (regType == RegisterType.Integer)
|
||||
{
|
||||
retReg = Gpr(CallingConvention.GetIntReturnRegister(), dest.Type);
|
||||
}
|
||||
else /* if (regType == RegisterType.Vector) */
|
||||
{
|
||||
retReg = Xmm(CallingConvention.GetVecReturnRegister(), dest.Type);
|
||||
}
|
||||
Operation copyOp = new Operation(Instruction.Copy, dest, retReg);
|
||||
|
||||
Operation destCopyOp = new Operation(Instruction.Copy, dest, retReg);
|
||||
node = nodes.AddAfter(node, copyOp);
|
||||
|
||||
node = nodes.AddAfter(node, destCopyOp);
|
||||
operation.Dest = retReg;
|
||||
}
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
private static LLNode HandleCallSystemVAbi(LLNode node, Operation operation)
|
||||
{
|
||||
Operand dest = operation.Dest;
|
||||
|
||||
LinkedList<Node> nodes = node.List;
|
||||
|
||||
// Handle arguments passed on registers.
|
||||
int argsCount = operation.SourcesCount - 1;
|
||||
|
||||
int intMax = CallingConvention.GetIntArgumentsOnRegsCount();
|
||||
int vecMax = CallingConvention.GetVecArgumentsOnRegsCount();
|
||||
|
||||
int intCount = 0;
|
||||
int vecCount = 0;
|
||||
|
||||
int stackOffset = 0;
|
||||
|
||||
for (int index = 0; index < argsCount; index++)
|
||||
{
|
||||
Operand source = operation.GetSource(index + 1);
|
||||
|
||||
bool passOnReg;
|
||||
|
||||
if (source.Type.IsInteger())
|
||||
{
|
||||
passOnReg = intCount < intMax;
|
||||
}
|
||||
else if (source.Type == OperandType.V128)
|
||||
{
|
||||
passOnReg = intCount + 1 < intMax;
|
||||
}
|
||||
else
|
||||
{
|
||||
passOnReg = vecCount < vecMax;
|
||||
}
|
||||
|
||||
if (source.Type == OperandType.V128 && passOnReg)
|
||||
{
|
||||
// V128 is a struct, we pass each half on a GPR if possible.
|
||||
Operand argReg = Gpr(CallingConvention.GetIntArgumentRegister(intCount++), OperandType.I64);
|
||||
Operand argReg2 = Gpr(CallingConvention.GetIntArgumentRegister(intCount++), OperandType.I64);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if (passOnReg)
|
||||
{
|
||||
Operand argReg = source.Type.IsInteger()
|
||||
? Gpr(CallingConvention.GetIntArgumentRegister(intCount++), source.Type)
|
||||
: Xmm(CallingConvention.GetVecArgumentRegister(vecCount++), source.Type);
|
||||
|
||||
Operation copyOp = new Operation(Instruction.Copy, argReg, source);
|
||||
|
||||
HandleConstantCopy(nodes.AddBefore(node, copyOp), copyOp);
|
||||
|
||||
operation.SetSource(index + 1, argReg);
|
||||
}
|
||||
else
|
||||
{
|
||||
Operand offset = new Operand(stackOffset);
|
||||
|
||||
Operation spillOp = new Operation(Instruction.SpillArg, null, offset, source);
|
||||
|
||||
HandleConstantCopy(nodes.AddBefore(node, spillOp), spillOp);
|
||||
|
||||
stackOffset += source.Type.GetSizeInBytes();
|
||||
|
||||
operation.SetSource(index + 1, Undef());
|
||||
}
|
||||
}
|
||||
|
||||
if (dest != null)
|
||||
{
|
||||
if (dest.Type == OperandType.V128)
|
||||
{
|
||||
Operand retLReg = Gpr(CallingConvention.GetIntReturnRegister(), OperandType.I64);
|
||||
Operand retHReg = Gpr(CallingConvention.GetIntReturnRegisterHigh(), OperandType.I64);
|
||||
|
||||
node = nodes.AddAfter(node, new Operation(Instruction.VectorCreateScalar, dest, retLReg));
|
||||
node = nodes.AddAfter(node, new Operation(Instruction.VectorInsert, dest, dest, retHReg, Const(1)));
|
||||
|
||||
operation.Dest = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
RegisterType regType = dest.Type.ToRegisterType();
|
||||
|
||||
Operand retReg = regType == RegisterType.Integer
|
||||
? Gpr(CallingConvention.GetIntReturnRegister(), dest.Type)
|
||||
: Xmm(CallingConvention.GetVecReturnRegister(), dest.Type);
|
||||
|
||||
Operation copyOp = new Operation(Instruction.Copy, dest, retReg);
|
||||
|
||||
node = nodes.AddAfter(node, copyOp);
|
||||
|
||||
operation.Dest = retReg;
|
||||
}
|
||||
|
@ -698,44 +821,144 @@ namespace ARMeilleure.CodeGen.X86
|
|||
|
||||
if (preservedArgs[index] == null)
|
||||
{
|
||||
Operand preservedArg;
|
||||
|
||||
Operand argReg;
|
||||
Operand argReg, pArg;
|
||||
|
||||
if (dest.Type.IsInteger())
|
||||
{
|
||||
argReg = Gpr(CallingConvention.GetIntArgumentRegister(index), dest.Type);
|
||||
|
||||
preservedArg = Local(dest.Type);
|
||||
pArg = Local(dest.Type);
|
||||
}
|
||||
else if (dest.Type == OperandType.V128)
|
||||
{
|
||||
argReg = Gpr(CallingConvention.GetIntArgumentRegister(index), OperandType.I64);
|
||||
|
||||
preservedArg = Local(OperandType.I64);
|
||||
pArg = Local(OperandType.I64);
|
||||
}
|
||||
else /* if (regType == RegisterType.Vector) */
|
||||
else
|
||||
{
|
||||
argReg = Xmm(CallingConvention.GetVecArgumentRegister(index), dest.Type);
|
||||
|
||||
preservedArg = Local(dest.Type);
|
||||
pArg = Local(dest.Type);
|
||||
}
|
||||
|
||||
Operation copyOp = new Operation(Instruction.Copy, preservedArg, argReg);
|
||||
Operation copyOp = new Operation(Instruction.Copy, pArg, argReg);
|
||||
|
||||
cctx.Cfg.Entry.Operations.AddFirst(copyOp);
|
||||
|
||||
preservedArgs[index] = preservedArg;
|
||||
preservedArgs[index] = pArg;
|
||||
}
|
||||
|
||||
Operation loadArgOp = new Operation(dest.Type == OperandType.V128
|
||||
Operation argCopyOp = new Operation(dest.Type == OperandType.V128
|
||||
? Instruction.Load
|
||||
: Instruction.Copy, dest, preservedArgs[index]);
|
||||
|
||||
node.List.AddBefore(node, loadArgOp);
|
||||
node.List.AddBefore(node, argCopyOp);
|
||||
|
||||
Delete(node, operation);
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: Pass on stack.
|
||||
}
|
||||
}
|
||||
|
||||
private static void HandleLoadArgumentSystemVAbi(
|
||||
CompilerContext cctx,
|
||||
LLNode node,
|
||||
Operand[] preservedArgs,
|
||||
Operation operation)
|
||||
{
|
||||
Operand source = operation.GetSource(0);
|
||||
|
||||
Debug.Assert(source.Kind == OperandKind.Constant, "Non-constant LoadArgument source kind.");
|
||||
|
||||
int index = source.AsInt32();
|
||||
|
||||
int intCount = 0;
|
||||
int vecCount = 0;
|
||||
|
||||
for (int cIndex = 0; cIndex < index; cIndex++)
|
||||
{
|
||||
OperandType argType = cctx.FuncArgTypes[cIndex];
|
||||
|
||||
if (argType.IsInteger())
|
||||
{
|
||||
intCount++;
|
||||
}
|
||||
else if (argType == OperandType.V128)
|
||||
{
|
||||
intCount += 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
vecCount++;
|
||||
}
|
||||
}
|
||||
|
||||
bool passOnReg;
|
||||
|
||||
if (source.Type.IsInteger())
|
||||
{
|
||||
passOnReg = intCount < CallingConvention.GetIntArgumentsOnRegsCount();
|
||||
}
|
||||
else if (source.Type == OperandType.V128)
|
||||
{
|
||||
passOnReg = intCount + 1 < CallingConvention.GetIntArgumentsOnRegsCount();
|
||||
}
|
||||
else
|
||||
{
|
||||
passOnReg = vecCount < CallingConvention.GetVecArgumentsOnRegsCount();
|
||||
}
|
||||
|
||||
if (passOnReg)
|
||||
{
|
||||
Operand dest = operation.Dest;
|
||||
|
||||
if (preservedArgs[index] == null)
|
||||
{
|
||||
if (dest.Type == OperandType.V128)
|
||||
{
|
||||
// V128 is a struct, we pass each half on a GPR if possible.
|
||||
Operand pArg = Local(OperandType.V128);
|
||||
|
||||
Operand argLReg = Gpr(CallingConvention.GetIntArgumentRegister(intCount), OperandType.I64);
|
||||
Operand argHReg = Gpr(CallingConvention.GetIntArgumentRegister(intCount + 1), OperandType.I64);
|
||||
|
||||
Operation copyL = new Operation(Instruction.VectorCreateScalar, pArg, argLReg);
|
||||
Operation copyH = new Operation(Instruction.VectorInsert, pArg, pArg, argHReg, Const(1));
|
||||
|
||||
cctx.Cfg.Entry.Operations.AddFirst(copyH);
|
||||
cctx.Cfg.Entry.Operations.AddFirst(copyL);
|
||||
|
||||
preservedArgs[index] = pArg;
|
||||
}
|
||||
else
|
||||
{
|
||||
Operand pArg = Local(dest.Type);
|
||||
|
||||
Operand argReg = dest.Type.IsInteger()
|
||||
? Gpr(CallingConvention.GetIntArgumentRegister(intCount), dest.Type)
|
||||
: Xmm(CallingConvention.GetVecArgumentRegister(vecCount), dest.Type);
|
||||
|
||||
Operation copyOp = new Operation(Instruction.Copy, pArg, argReg);
|
||||
|
||||
cctx.Cfg.Entry.Operations.AddFirst(copyOp);
|
||||
|
||||
preservedArgs[index] = pArg;
|
||||
}
|
||||
}
|
||||
|
||||
Operation argCopyOp = new Operation(Instruction.Copy, dest, preservedArgs[index]);
|
||||
|
||||
node.List.AddBefore(node, argCopyOp);
|
||||
|
||||
Delete(node, operation);
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: Pass on stack.
|
||||
}
|
||||
}
|
||||
|
||||
private static void HandleReturnWindowsAbi(
|
||||
|
@ -774,7 +997,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||
|
||||
retReg = preservedArgs[0];
|
||||
}
|
||||
else /* if (regType == RegisterType.Vector) */
|
||||
else
|
||||
{
|
||||
retReg = Xmm(CallingConvention.GetVecReturnRegister(), source.Type);
|
||||
}
|
||||
|
@ -793,6 +1016,35 @@ namespace ARMeilleure.CodeGen.X86
|
|||
}
|
||||
}
|
||||
|
||||
private static void HandleReturnSystemVAbi(LLNode node, Operation operation)
|
||||
{
|
||||
if (operation.SourcesCount == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Operand source = operation.GetSource(0);
|
||||
|
||||
if (source.Type == OperandType.V128)
|
||||
{
|
||||
Operand retLReg = Gpr(CallingConvention.GetIntReturnRegister(), OperandType.I64);
|
||||
Operand retHReg = Gpr(CallingConvention.GetIntReturnRegisterHigh(), OperandType.I64);
|
||||
|
||||
node.List.AddBefore(node, new Operation(Instruction.VectorExtract, retLReg, source, Const(0)));
|
||||
node.List.AddBefore(node, new Operation(Instruction.VectorExtract, retHReg, source, Const(1)));
|
||||
}
|
||||
else
|
||||
{
|
||||
Operand retReg = source.Type.IsInteger()
|
||||
? Gpr(CallingConvention.GetIntReturnRegister(), source.Type)
|
||||
: Xmm(CallingConvention.GetVecReturnRegister(), source.Type);
|
||||
|
||||
Operation retCopyOp = new Operation(Instruction.Copy, retReg, source);
|
||||
|
||||
node.List.AddBefore(node, retCopyOp);
|
||||
}
|
||||
}
|
||||
|
||||
private static Operand AddXmmCopy(LLNode node, Operand source)
|
||||
{
|
||||
Operand temp = Local(source.Type);
|
||||
|
|
|
@ -59,7 +59,14 @@ namespace ARMeilleure.Memory
|
|||
|
||||
ControlFlowGraph cfg = context.GetControlFlowGraph();
|
||||
|
||||
_compareExchange128 = Compiler.Compile<CompareExchange128>(cfg, OperandType.V128);
|
||||
OperandType[] argTypes = new OperandType[]
|
||||
{
|
||||
OperandType.I64,
|
||||
OperandType.V128,
|
||||
OperandType.V128
|
||||
};
|
||||
|
||||
_compareExchange128 = Compiler.Compile<CompareExchange128>(cfg, argTypes, OperandType.V128);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,9 +9,12 @@ namespace ARMeilleure.Translation
|
|||
{
|
||||
static class Compiler
|
||||
{
|
||||
public static T Compile<T>(ControlFlowGraph cfg, OperandType funcReturnType)
|
||||
public static T Compile<T>(
|
||||
ControlFlowGraph cfg,
|
||||
OperandType[] funcArgTypes,
|
||||
OperandType funcReturnType)
|
||||
{
|
||||
CompilerContext cctx = GetCompilerContext(cfg, funcReturnType);
|
||||
CompilerContext cctx = GetCompilerContext(cfg, funcArgTypes, funcReturnType);
|
||||
|
||||
CompiledFunction func = CodeGenerator.Generate(cctx);
|
||||
|
||||
|
@ -20,7 +23,10 @@ namespace ARMeilleure.Translation
|
|||
return Marshal.GetDelegateForFunctionPointer<T>(codePtr);
|
||||
}
|
||||
|
||||
private static CompilerContext GetCompilerContext(ControlFlowGraph cfg, OperandType funcReturnType)
|
||||
private static CompilerContext GetCompilerContext(
|
||||
ControlFlowGraph cfg,
|
||||
OperandType[] funcArgTypes,
|
||||
OperandType funcReturnType)
|
||||
{
|
||||
Logger.StartPass(PassName.Dominance);
|
||||
|
||||
|
@ -35,7 +41,7 @@ namespace ARMeilleure.Translation
|
|||
|
||||
Logger.EndPass(PassName.SsaConstruction, cfg);
|
||||
|
||||
return new CompilerContext(cfg, funcReturnType);
|
||||
return new CompilerContext(cfg, funcArgTypes, funcReturnType);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -6,11 +6,16 @@ namespace ARMeilleure.Translation
|
|||
{
|
||||
public ControlFlowGraph Cfg { get; }
|
||||
|
||||
public OperandType FuncReturnType { get; }
|
||||
public OperandType[] FuncArgTypes { get; }
|
||||
public OperandType FuncReturnType { get; }
|
||||
|
||||
public CompilerContext(ControlFlowGraph cfg, OperandType funcReturnType)
|
||||
public CompilerContext(
|
||||
ControlFlowGraph cfg,
|
||||
OperandType[] funcArgTypes,
|
||||
OperandType funcReturnType)
|
||||
{
|
||||
Cfg = cfg;
|
||||
FuncArgTypes = funcArgTypes;
|
||||
FuncReturnType = funcReturnType;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ using ARMeilleure.CodeGen;
|
|||
using ARMeilleure.Memory;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
|
||||
namespace ARMeilleure.Translation
|
||||
|
@ -25,10 +26,13 @@ namespace ARMeilleure.Translation
|
|||
{
|
||||
_basePointer = MemoryManagement.Allocate(CacheSize);
|
||||
|
||||
JitUnwindWindows.InstallFunctionTableHandler(_basePointer, CacheSize);
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||||
{
|
||||
JitUnwindWindows.InstallFunctionTableHandler(_basePointer, CacheSize);
|
||||
|
||||
//The first page is used for the table based SEH structs.
|
||||
_offset = PageSize;
|
||||
// The first page is used for the table based SEH structs.
|
||||
_offset = PageSize;
|
||||
}
|
||||
|
||||
_cacheEntries = new List<JitCacheEntry>();
|
||||
}
|
||||
|
@ -41,26 +45,44 @@ namespace ARMeilleure.Translation
|
|||
|
||||
IntPtr funcPtr = _basePointer + funcOffset;
|
||||
|
||||
unsafe
|
||||
{
|
||||
fixed (byte* codePtr = code)
|
||||
{
|
||||
byte* dest = (byte*)funcPtr;
|
||||
Marshal.Copy(code, 0, funcPtr, code.Length);
|
||||
|
||||
long size = (long)code.Length;
|
||||
|
||||
Buffer.MemoryCopy(codePtr, dest, size, size);
|
||||
}
|
||||
}
|
||||
|
||||
//TODO: W^X.
|
||||
MemoryManagement.Reprotect(funcPtr, (ulong)code.Length, MemoryProtection.ReadWriteExecute);
|
||||
ReprotectRange(funcOffset, code.Length);
|
||||
|
||||
Add(new JitCacheEntry(funcOffset, code.Length, func.UnwindInfo));
|
||||
|
||||
return funcPtr;
|
||||
}
|
||||
|
||||
private static void ReprotectRange(int offset, int size)
|
||||
{
|
||||
// Map pages that are already full as RX.
|
||||
// Map pages that are not full yet as RWX.
|
||||
// On unix, the address and size must be page aligned.
|
||||
int endOffs = offset + size;
|
||||
|
||||
int pageStart = offset & ~PageMask;
|
||||
int pageEnd = endOffs & ~PageMask;
|
||||
|
||||
int fullPagesSize = pageEnd - pageStart;
|
||||
|
||||
if (fullPagesSize != 0)
|
||||
{
|
||||
IntPtr funcPtr = _basePointer + pageStart;
|
||||
|
||||
MemoryManagement.Reprotect(funcPtr, (ulong)fullPagesSize, MemoryProtection.ReadAndExecute);
|
||||
}
|
||||
|
||||
int remaining = endOffs - pageEnd;
|
||||
|
||||
if (remaining != 0)
|
||||
{
|
||||
IntPtr funcPtr = _basePointer + pageEnd;
|
||||
|
||||
MemoryManagement.Reprotect(funcPtr, (ulong)remaining, MemoryProtection.ReadWriteExecute);
|
||||
}
|
||||
}
|
||||
|
||||
private static int Allocate(int codeSize)
|
||||
{
|
||||
codeSize = checked(codeSize + (CodeAlignment - 1)) & ~(CodeAlignment - 1);
|
||||
|
@ -79,7 +101,7 @@ namespace ARMeilleure.Translation
|
|||
|
||||
private static void Add(JitCacheEntry entry)
|
||||
{
|
||||
//TODO: Use concurrent collection.
|
||||
// TODO: Use concurrent collection.
|
||||
lock (_cacheEntries)
|
||||
{
|
||||
_cacheEntries.Add(entry);
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
using ARMeilleure.IntermediateRepresentation;
|
||||
using ARMeilleure.Memory;
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
|
|
|
@ -93,7 +93,9 @@ namespace ARMeilleure.Translation
|
|||
|
||||
Logger.EndPass(PassName.RegisterUsage);
|
||||
|
||||
GuestFunction func = Compiler.Compile<GuestFunction>(cfg, OperandType.I64);
|
||||
OperandType[] argTypes = new OperandType[] { OperandType.I64 };
|
||||
|
||||
GuestFunction func = Compiler.Compile<GuestFunction>(cfg, argTypes, OperandType.I64);
|
||||
|
||||
return new TranslatedFunction(func);
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue