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));
        }
Example #2
0
            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;
                        }
                    }
                }
            }
Example #3
0
            public AllocationContext(StackAllocator stackAlloc, RegisterMasks masks, int intervalsCount)
            {
                StackAlloc = stackAlloc;
                Masks      = masks;

                Active   = new BitMap(intervalsCount);
                Inactive = new BitMap(intervalsCount);
            }
Example #4
0
            public AllocationContext(StackAllocator stackAlloc, RegisterMasks masks, int intervalsCount)
            {
                StackAlloc = stackAlloc;
                Masks      = masks;

                BitMapPool.PrepareBitMapPool();

                Active   = BitMapPool.Allocate(intervalsCount);
                Inactive = BitMapPool.Allocate(intervalsCount);
            }
Example #5
0
        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);
        }
Example #6
0
        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);
        }
Example #7
0
        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;
            }
        }
Example #9
0
 public void Setup()
 {
     stackAllocator = new StackAllocator(1000_000);
 }
Example #10
0
 public AllocationContext(StackAllocator stackAlloc, in RegisterMasks masks, int intervalsCount)