public void StackAllocatorTest() { StackAllocator allocator = new StackAllocator(1000); Assert.AreSame(allocator, Allocator.GetAllocatorByID(allocator.ID)); Assert.IsTrue(Allocator.IsCached(allocator)); int *p = allocator.Allocate <int>(4); for (int i = 0; i < 4; i++) { p[i] = i + 1; } Assert.AreEqual(1, p[0]); Assert.AreEqual(2, p[1]); Assert.AreEqual(3, p[2]); Assert.AreEqual(4, p[3]); p = allocator.Reallocate(p, 6); Assert.AreEqual(1, p[0]); Assert.AreEqual(2, p[1]); Assert.AreEqual(3, p[2]); Assert.AreEqual(4, p[3]); Assert.AreEqual(0, p[4]); Assert.AreEqual(0, p[5]); allocator.Free(p); allocator.Dispose(); Assert.IsFalse(Allocator.IsCached(allocator)); }
public AllocationContext(StackAllocator stackAlloc, RegisterMasks masks, int intervalsCount) { StackAlloc = stackAlloc; Masks = masks; Active = new BitMap(Allocators.Default, intervalsCount); Inactive = new BitMap(Allocators.Default, intervalsCount); PopulateFreePositions(RegisterType.Integer, out _intFreePositions, out _intFreePositionsCount); PopulateFreePositions(RegisterType.Vector, out _vecFreePositions, out _vecFreePositionsCount); void PopulateFreePositions(RegisterType type, out int[] positions, out int count) { positions = new int[RegistersCount]; count = BitOperations.PopCount((uint)masks.GetAvailableRegisters(type)); int mask = masks.GetAvailableRegisters(type); for (int i = 0; i < positions.Length; i++) { if ((mask & (1 << i)) != 0) { positions[i] = int.MaxValue; } } } }
public AllocationContext(StackAllocator stackAlloc, RegisterMasks masks, int intervalsCount) { StackAlloc = stackAlloc; Masks = masks; Active = new BitMap(intervalsCount); Inactive = new BitMap(intervalsCount); }
public AllocationContext(StackAllocator stackAlloc, RegisterMasks masks, int intervalsCount) { StackAlloc = stackAlloc; Masks = masks; BitMapPool.PrepareBitMapPool(); Active = BitMapPool.Allocate(intervalsCount); Inactive = BitMapPool.Allocate(intervalsCount); }
public void Setup() { int AllocatorSize = Bytes * 2; var defaultAlloc = Allocator.Default; if (defaultAlloc == null) { throw new Exception("Null default allocator"); } heapAllocator = DefaultHeapAllocator.Instance; localAllocator = DefaultLocalAllocator.Instance; cAllocator = DefaultCppAllocator.Instance; arenaAllocator = new ArenaAllocator(AllocatorSize); stackAllocator = new StackAllocator(AllocatorSize); fixedPoolAllocator = new FixedMemoryPoolAllocator(10, AllocatorSize); poolAllocator = new MemoryPoolAllocator(AllocatorSize); }
private static Node HandleCallWindowsAbi(IntrusiveList <Node> nodes, StackAllocator stackAlloc, Node node, Operation operation) { Operand dest = operation.Destination; // Handle struct arguments. int retArgs = 0; int stackAllocOffset = 0; int AllocateOnStack(int size) { // We assume that the stack allocator is initially empty (TotalSize = 0). // Taking that into account, we can reuse the space allocated for other // calls by keeping track of our own allocated size (stackAllocOffset). // If the space allocated is not big enough, then we just expand it. int offset = stackAllocOffset; if (stackAllocOffset + size > stackAlloc.TotalSize) { stackAlloc.Allocate((stackAllocOffset + size) - stackAlloc.TotalSize); } stackAllocOffset += size; return(offset); } Operand arg0Reg = null; if (dest != null && dest.Type == OperandType.V128) { int stackOffset = AllocateOnStack(dest.Type.GetSizeInBytes()); arg0Reg = Gpr(CallingConvention.GetIntArgumentRegister(0), OperandType.I64); Operation allocOp = new Operation(Instruction.StackAlloc, arg0Reg, Const(stackOffset)); nodes.AddBefore(node, allocOp); 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); if (source.Type == OperandType.V128) { Operand stackAddr = Local(OperandType.I64); int stackOffset = AllocateOnStack(source.Type.GetSizeInBytes()); nodes.AddBefore(node, new Operation(Instruction.StackAlloc, stackAddr, Const(stackOffset))); Operation storeOp = new Operation(Instruction.Store, null, stackAddr, source); HandleConstantCopy(nodes, nodes.AddBefore(node, storeOp), storeOp); operation.SetSource(index, stackAddr); } } // Handle arguments passed on registers. for (int index = 0; index < argsCount; index++) { Operand source = operation.GetSource(index + 1); Operand argReg; int argIndex = index + retArgs; if (source.Type.IsInteger()) { argReg = Gpr(CallingConvention.GetIntArgumentRegister(argIndex), source.Type); } else { argReg = Xmm(CallingConvention.GetVecArgumentRegister(argIndex), source.Type); } Operation copyOp = new Operation(Instruction.Copy, argReg, source); HandleConstantCopy(nodes, nodes.AddBefore(node, copyOp), copyOp); sources[1 + retArgs + index] = argReg; } // The remaining arguments (those that are not passed on registers) // should be passed on the stack, we write them to the stack with "SpillArg". for (int index = argsCount; index < operation.SourcesCount - 1; index++) { Operand source = operation.GetSource(index + 1); Operand offset = new Operand((index + retArgs) * 8); Operation spillOp = new Operation(Instruction.SpillArg, null, offset, source); HandleConstantCopy(nodes, nodes.AddBefore(node, spillOp), spillOp); } if (dest != null) { if (dest.Type == OperandType.V128) { Operand retValueAddr = Local(OperandType.I64); nodes.AddBefore(node, new Operation(Instruction.Copy, retValueAddr, arg0Reg)); Operation loadOp = new Operation(Instruction.Load, dest, retValueAddr); node = nodes.AddAfter(node, loadOp); operation.Destination = null; } else { Operand retReg = dest.Type.IsInteger() ? Gpr(CallingConvention.GetIntReturnRegister(), dest.Type) : Xmm(CallingConvention.GetVecReturnRegister(), dest.Type); Operation copyOp = new Operation(Instruction.Copy, dest, retReg); node = nodes.AddAfter(node, copyOp); operation.Destination = retReg; } } operation.SetSources(sources); return(node); }
public static void RunPass(CompilerContext cctx, StackAllocator stackAlloc, out int maxCallArgs) { maxCallArgs = -1; CallConvName callConv = CallingConvention.GetCurrentCallConv(); Operand[] preservedArgs = new Operand[CallingConvention.GetArgumentsOnRegsCount()]; for (BasicBlock block = cctx.Cfg.Blocks.First; block != null; block = block.ListNext) { Node nextNode; for (Node node = block.Operations.First; node != null; node = nextNode) { nextNode = node.ListNext; if (!(node is Operation operation)) { continue; } HandleConstantCopy(block.Operations, node, operation); HandleSameDestSrc1Copy(block.Operations, node, operation); HandleFixedRegisterCopy(block.Operations, node, operation); switch (operation.Instruction) { case Instruction.Call: // Get the maximum number of arguments used on a call. // On windows, when a struct is returned from the call, // we also need to pass the pointer where the struct // should be written on the first argument. int argsCount = operation.SourcesCount - 1; if (operation.Destination != null && operation.Destination.Type == OperandType.V128) { argsCount++; } if (maxCallArgs < argsCount) { maxCallArgs = argsCount; } // Copy values to registers expected by the function // being called, as mandated by the ABI. if (callConv == CallConvName.Windows) { node = HandleCallWindowsAbi(block.Operations, stackAlloc, node, operation); } else /* if (callConv == CallConvName.SystemV) */ { node = HandleCallSystemVAbi(block.Operations, node, operation); } break; case Instruction.ConvertToFPUI: HandleConvertToFPUI(block.Operations, node, operation); break; case Instruction.LoadArgument: if (callConv == CallConvName.Windows) { HandleLoadArgumentWindowsAbi(cctx, block.Operations, node, preservedArgs, operation); } else /* if (callConv == CallConvName.SystemV) */ { HandleLoadArgumentSystemVAbi(cctx, block.Operations, node, preservedArgs, operation); } break; case Instruction.Negate: if (!operation.GetSource(0).Type.IsInteger()) { node = HandleNegate(block.Operations, node, operation); } break; case Instruction.Return: if (callConv == CallConvName.Windows) { HandleReturnWindowsAbi(cctx, block.Operations, node, preservedArgs, operation); } else /* if (callConv == CallConvName.SystemV) */ { HandleReturnSystemVAbi(block.Operations, node, operation); } break; case Instruction.VectorInsert8: if (!HardwareCapabilities.SupportsSse41) { node = HandleVectorInsert8(block.Operations, node, operation); } break; } } } }
public static void Run(Module module) { var functions = module.GetFunctionEnumerator(); while (functions.MoveNext()) { Block block = functions.Current.Code; StackAllocator stack = new StackAllocator(block); block.stack = stack; // Parameters var function = functions.Current.Type as FunctionType; for (int i = 0; i < function.Params.Count; i++) { stack.ReserveSpace(function.Params[i]); } // Return address stack.ReserveSpace(new BuiltInType("void *").Size); // Saved registers stack.ReserveSpace(new BuiltInType("void *").Size * 3); stack.ReserveSpace(0); var statements = from Statement s in block where s is FunctionCall select s; foreach (FunctionCall call in statements) { int index = block.Statements.IndexOf(call); block.Statements.Remove(call); List <Statement> newStatements = null; switch (block.Function.CallingConvention) { case FunctionType.CallConvention.CalleeSave: newStatements = FormatCallCalleeSave(block, call); break; case FunctionType.CallConvention.CallerSave: newStatements = FormatCallCallerSave(block, call); break; } block.Statements.InsertRange(index, newStatements); } Label endLabel = new Label("__function_cleanup"); var returns = from Statement s in block where s is Return select s; foreach (Return curReturn in returns) { int index = block.Statements.IndexOf(curReturn); block.Statements.Remove(curReturn); var newStatements = new List <Statement>(); var assignment = block.Statements[index - 1]; Datum returnVal = curReturn.ReturnReg; if (assignment is Assignment) { block.Statements.Remove(assignment); index--; returnVal = ((Assignment)assignment).RValue; } newStatements.Add(new ReturnMove(returnVal)); newStatements.Add(new Goto(endLabel)); block.Statements.InsertRange(index, newStatements); } block.Statements.Add(endLabel); var funcType = functions.Current.Type as FunctionType; var newFuncType = new StrippedFunctionType(funcType); functions.Current.Type = newFuncType; } }
public void Setup() { stackAllocator = new StackAllocator(1000_000); }
public AllocationContext(StackAllocator stackAlloc, in RegisterMasks masks, int intervalsCount)