Exemple #1
0
        private Result OnFetchCall()
        {
            var call  = _node.As <CallNode>();
            var cdecl = call.FunctionDeclaration;

            var target = call.Target;
            var args   = call.Arguments;
            var rets   = call.Return;

            _functionNode.FunctionFlags |= FunctionNodeFlags.IsCaller;
            _functionNode.MergeCallStackSize(cdecl.ArgumentsStackSize);

            int i;
            var argCount        = cdecl.ArgumentCount;
            var sArgCount       = 0;
            var gpAllocableMask = _variableContext.GaRegs[RegisterClass.Gp] & ~call.UsedArgs.Get(RegisterClass.Gp);

            VariableData       vd;
            VariableAttributes va;

            _variableContext.Begin();
            // Function-call operand.
            if (target.IsVariable())
            {
                vd = _compiler.GetVariableData(target.Id);
                va = _variableContext.Merge(vd, 0, 0);

                va.Flags |= VariableFlags.RReg | VariableFlags.RCall;
                if (va.InRegs == 0)
                {
                    va.AllocableRegs |= gpAllocableMask;
                }
            }
            else if (target.IsMemory())
            {
                var m = target.As <Memory>();

                if (m.Base.IsVariableId() && m.IsBaseIndexType())
                {
                    vd = _compiler.GetVariableData(m.Base);
                    if (!vd.IsStack)
                    {
                        va = _variableContext.Merge(vd, 0, 0);
                        if (m.MemoryType == MemoryType.BaseIndex)
                        {
                            va.Flags |= VariableFlags.RReg | VariableFlags.RCall;
                            if (va.InRegs == 0)
                            {
                                va.AllocableRegs |= gpAllocableMask;
                            }
                        }
                        else
                        {
                            va.Flags |= VariableFlags.RMem | VariableFlags.RCall;
                        }
                    }
                }

                if (m.Index.IsVariableId())
                {
                    // Restrict allocation to all registers except ESP/RSP/R12.
                    vd = _compiler.GetVariableData(m.Index);
                    va = _variableContext.Merge(vd, 0, 0);

                    va.Flags |= VariableFlags.RReg | VariableFlags.RCall;
                    if ((va.InRegs & ~_indexMask) == 0)
                    {
                        va.AllocableRegs |= (int)(gpAllocableMask & _indexMask);
                    }
                }
            }

            // Function-call arguments.
            for (i = 0; i < argCount; i++)
            {
                var op = args[i];
                if (!op.IsVariable())
                {
                    continue;
                }

                vd = _compiler.GetVariableData(op.Id);
                var arg = cdecl.GetArgument(i);

                if (arg.RegisterIndex != RegisterIndex.Invalid)
                {
                    va = _variableContext.Merge(vd, 0, 0);

                    var argType  = arg.VariableType;
                    var argClass = argType.GetRegisterClass();

                    if (vd.Info.RegisterClass == argClass)
                    {
                        va.InRegs |= Utils.Mask(arg.RegisterIndex);
                        va.Flags  |= VariableFlags.RReg | VariableFlags.RFunc;
                    }
                    else
                    {
                        va.Flags |= VariableFlags.RConv | VariableFlags.RFunc;
                    }
                }
                // If this is a stack-based argument we insert HLCallArg instead of
                // using VarAttr. It improves the code, because the argument can be
                // moved onto stack as soon as it is ready and the register used by
                // the variable can be reused for something else. It is also much
                // easier to handle argument conversions, because there will be at
                // most only one node per conversion.
                else
                {
                    InsertCallArgument(call, vd, arg, i, ref _sArgDatas, ref sArgCount);
                }
            }

            // Function-call return(s).
            for (i = 0; i < 2; i++)
            {
                var op = rets[i];
                if (!op.IsVariable())
                {
                    continue;
                }

                var ret = cdecl.GetReturn(i);
                if (ret.RegisterIndex == RegisterIndex.Invalid)
                {
                    continue;
                }
                var retType  = ret.VariableType;
                var retClass = retType.GetRegisterClass();

                vd = _compiler.GetVariableData(op.Id);
                va = _variableContext.Merge(vd, 0, 0);

                if (vd.Info.RegisterClass == retClass)
                {
                    va.OutRegIndex = ret.RegisterIndex;
                    va.Flags      |= VariableFlags.WReg | VariableFlags.WFunc;
                }
                else
                {
                    va.Flags |= VariableFlags.WConv | VariableFlags.WFunc;
                }
            }

            // Init clobbered.
            _variableContext.ClobberedRegs.Set(RegisterClass.Gp, (int)(Utils.Bits(Cpu.Info.RegisterCount.Gp) & ~cdecl.Preserved.Get(RegisterClass.Gp)));
            _variableContext.ClobberedRegs.Set(RegisterClass.Mm, (int)(Utils.Bits(Cpu.Info.RegisterCount.Mm) & ~cdecl.Preserved.Get(RegisterClass.Mm)));
            _variableContext.ClobberedRegs.Set(RegisterClass.K, (int)(Utils.Bits(Cpu.Info.RegisterCount.K) & ~cdecl.Preserved.Get(RegisterClass.K)));
            _variableContext.ClobberedRegs.Set(RegisterClass.Xyz, (int)(Utils.Bits(Cpu.Info.RegisterCount.Xyz) & ~cdecl.Preserved.Get(RegisterClass.Xyz)));

            _variableContext.End(_node);

            return(Result.Break);
        }