Esempio n. 1
0
 private void TryPutLabelAt(uint pc, AstNodeStmContainer nodes)
 {
     if (_labels.ContainsKey(pc))
     {
         nodes.AddStatement(EmitInstructionCountIncrement(false));
         nodes.AddStatement(_ast.Label(_labels[pc]));
     }
     if (_labelsJump.ContainsKey(pc))
     {
         nodes.AddStatement(_ast.Label(_labelsJump[pc]));
     }
 }
Esempio n. 2
0
        protected virtual AstNode _Optimize(AstNodeStmContainer container)
        {
            if (container.Nodes.Count == 1)
            {
                return(container.Nodes[0]);
            }

            var newContainer = new AstNodeStmContainer(container.Inline);

            foreach (var node in container.Nodes)
            {
                if (node == null)
                {
                    continue;
                }

                if (node is AstNodeStmContainer)
                {
                    foreach (var node2 in (node as AstNodeStmContainer).Nodes)
                    {
                        if (!(node2 is AstNodeStmEmpty))
                        {
                            newContainer.AddStatement(node2);
                        }
                    }
                }
                else
                {
                    if (!(node is AstNodeStmEmpty))
                    {
                        newContainer.AddStatement(node);
                    }
                }
            }

            var rebuild = false;

            for (var n = 0; n < newContainer.Nodes.Count - 1; n++)
            {
                var currentNode = newContainer.Nodes[n];
                var nextNode    = newContainer.Nodes[n + 1];
                if (!(currentNode is AstNodeStmGotoAlways) || !(nextNode is AstNodeStmLabel))
                {
                    continue;
                }
                if ((currentNode as AstNodeStmGotoAlways).AstLabel != (nextNode as AstNodeStmLabel).AstLabel)
                {
                    continue;
                }
                newContainer.Nodes[n] = null;
                //NewContainer.Nodes[n + 1] = null;
                rebuild = true;
            }

            if (rebuild)
            {
                return(new AstNodeStmContainer(container.Inline,
                                               newContainer.Nodes.Where(node => node != null).ToArray()));
            }
            else
            {
                return(newContainer);
            }
        }
Esempio n. 3
0
            //static int DummyTempCounter = 0;

            /// <summary>
            /// PASS 2: Generate code and put labels;
            /// </summary>
            private AstNodeStmContainer GenerateCode()
            {
                foreach (var label in _labels.ToArray())
                {
                    if (!(label.Key >= _minPc && label.Key <= _maxPc))
                    {
                        _labels.Remove(label.Key);
                    }
                }
                //AnalyzedPC

                _instructionsEmitedSinceLastWaypoint = 0;

                //Debug.WriteLine("PASS2: MinPC:{0:X}, MaxPC:{1:X}", MinPC, MaxPC);

                // Jumps to the entry point.
                var nodes = new AstNodeStmContainer();

                if (!_labels.ContainsKey(_entryPc))
                {
                    throw new KeyNotFoundException($"Can't find key {_entryPc:X} in list [{_labels.Select(it => $"{it.Key:X}").JoinToString(",")}]");
                }
                nodes.AddStatement(_ast.GotoAlways(_labels[_entryPc]));

                for (_pc = _minPc; _pc <= _maxPc;)
                {
                    if (!_analyzedPc.Contains(_pc))
                    {
                        _pc += 4;
                        continue;
                    }
                    uint        currentInstructionPc = _pc;
                    Instruction currentInstruction   = _instructionReader[_pc];
                    _instructionsProcessed++;

                    var branchInfo = DynarecBranchAnalyzer.GetBranchInfo(currentInstruction.Value);

                    // Delayed branch instruction.
                    if ((branchInfo & DynarecBranchAnalyzer.JumpFlags.BranchOrJumpInstruction) != 0)
                    {
                        _instructionsEmitedSinceLastWaypoint += 2;
                        nodes.AddStatement(EmitInstructionCountIncrement(true));

                        var branchAddress = currentInstruction.GetBranchAddress(_pc);

                        if (branchInfo.HasFlag(DynarecBranchAnalyzer.JumpFlags.JumpInstruction))
                        {
                            TryPutLabelAt(_pc, nodes);

                            var delayedBranchInstruction = _GetAstCpuInstructionAT(_pc + 4); // Delayed
                            var jumpInstruction          = _GetAstCpuInstructionAT(_pc + 0); // Jump

#if !DISABLE_JUMP_GOTO
                            var jumpInstruction2 = _cpuEmitter.LoadAt(_pc + 0);
                            var jumpDisasm       = _mipsDisassembler.Disassemble(_pc + 0, jumpInstruction2);
                            var jumpJumpPc       = jumpDisasm.Instruction.GetJumpAddress(_memory, jumpDisasm.InstructionPc);

                            // An internal jump.
                            if (
                                jumpDisasm.InstructionInfo.Name == "j" &&
                                _labelsJump.ContainsKey(jumpJumpPc)
                                )
                            {
                                jumpInstruction = new AstNodeStmPspInstruction(jumpDisasm,
                                                                               _ast.GotoAlways(_labelsJump[jumpJumpPc]));

                                //Console.WriteLine(
                                //	"{0}: {1} : Function({2:X8}-{3:X8})",
                                //	DummyTempCounter,
                                //	GeneratorCSharpPsp.GenerateString<GeneratorCSharpPsp>(AstOptimizerPsp.GlobalOptimize(CpuProcessor, JumpInstruction)),
                                //	MinPC, MaxPC
                                //);

                                //DummyTempCounter++;
                            }
                            else if (jumpDisasm.InstructionInfo.Name == "j" || jumpDisasm.InstructionInfo.Name == "jal")
                            {
                                CallingPCs.Add(jumpJumpPc);
                            }
#endif

                            // Put delayed instruction first.
                            nodes.AddStatement(delayedBranchInstruction);
                            // A jump outside the current function.
                            nodes.AddStatement(jumpInstruction);

                            _pc += 8;
                        }
                        else
                        {
                            // Branch instruction.
                            nodes.AddStatement(EmitCpuInstruction());

                            //if ((BranchInfo & CpuBranchAnalyzer.Flags.Likely) != 0)
                            if (branchInfo.HasFlag(DynarecBranchAnalyzer.JumpFlags.Likely))
                            {
                                //Console.WriteLine("Likely");
                                // Delayed instruction.
                                nodes.AddStatement(_cpuEmitter._branch_likely(EmitCpuInstruction()));
                            }
                            else
                            {
                                //Console.WriteLine("Not Likely");
                                // Delayed instruction.
                                nodes.AddStatement(EmitCpuInstruction());
                            }

                            if (currentInstructionPc + 4 != branchAddress)
                            {
                                if (_labels.ContainsKey(branchAddress))
                                {
                                    nodes.AddStatement(_cpuEmitter._branch_post(_labels[branchAddress], branchAddress));
                                }
                                // Code not reached.
                                else
                                {
                                    throw new InvalidOperationException("!Labels.ContainsKey(BranchAddress)");
                                }
                            }
                            else
                            {
                                throw new InvalidOperationException("Invalid branch!");
                            }
                        }
                    }
                    // Normal instruction.
                    else
                    {
                        // Syscall instruction.
                        if ((branchInfo & DynarecBranchAnalyzer.JumpFlags.SyscallInstruction) != 0)
                        {
                            nodes.AddStatement(StorePc());
                        }
                        nodes.AddStatement(EmitCpuInstruction());
                        if ((branchInfo & DynarecBranchAnalyzer.JumpFlags.SyscallInstruction) != 0)
                        {
                            // On this special Syscall
                            if (currentInstruction.Code == SyscallInfo.NativeCallSyscallCode)
                            {
                                //PC += 4;
                                break;
                            }
                        }
                    }
                }

                //MipsMethodEmiter.GenerateIL(Nodes);
                ShowInstructionStats();

                //if (BreakPoint) IsDebuggerPresentDebugBreak();

                return(nodes);
            }
        private AstNodeStmContainer CreateDelegateForMethodInfoPriv(MethodInfo MethodInfo,
                                                                    HlePspFunctionAttribute HlePspFunctionAttribute, out List <ParamInfo> OutParamInfoList)
        {
            var RegisterReader = new AstRegisterReader(MethodInfo, Memory);

            OutParamInfoList = RegisterReader.ParamInfoList;

            //var SafeILGenerator = MipsMethodEmiter.SafeILGenerator;

            var AstNodes = new AstNodeStmContainer();

            AstNodes.AddStatement(ast.Comment("HleModuleHost.CreateDelegateForMethodInfo(" + MethodInfo + ", " +
                                              HlePspFunctionAttribute + ")"));

            AstNodeExprCall AstMethodCall;

            {
                //var ModuleObject = this.Cast(this.GetType(), this.FieldAccess(this.Argument<CpuThreadState>(0, "CpuThreadState"), "ModuleObject"));
                //SafeILGenerator.LoadArgument0CpuThreadState();
                //SafeILGenerator.LoadField(typeof(CpuThreadState).GetField("ModuleObject"));
                //SafeILGenerator.CastClass(this.GetType());

                var AstParameters = new List <AstNodeExpr>();

                foreach (var ParameterInfo in MethodInfo.GetParameters())
                {
                    var ParameterType = ParameterInfo.ParameterType;

                    var HleInvalidAsNullAttribute           = ParameterInfo.GetCustomAttribute <HleInvalidAsNullAttribute>();
                    var HleInvalidAsInvalidPointerAttribute =
                        ParameterInfo.GetCustomAttribute <HleInvalidAsInvalidPointerAttribute>();
                    InvalidAddressAsEnum InvalidAddressAsEnum = InvalidAddressAsEnum.Exception;
                    if (HleInvalidAsNullAttribute != null)
                    {
                        InvalidAddressAsEnum = InvalidAddressAsEnum.Null;
                    }
                    if (HleInvalidAsInvalidPointerAttribute != null)
                    {
                        InvalidAddressAsEnum = InvalidAddressAsEnum.InvalidAddress;
                    }

                    // The CpuThreadState
                    if (ParameterType == typeof(CpuThreadState))
                    {
                        AstParameters.Add(ast.CpuThreadStateExpr);
                    }
                    // A stringz
                    else if (ParameterType == typeof(string))
                    {
                        AstParameters.Add(
                            ast.CallStatic(
                                (Func <CpuThreadState, uint, string>)HleModuleHost.StringFromAddress,
                                ast.CpuThreadStateExpr,
                                RegisterReader.Read <uint>(ParameterInfo)
                                )
                            );
                    }
                    // A pointer or ref/out
                    else if (ParameterType.IsPointer || ParameterType.IsByRef)
                    {
                        AstParameters.Add(
                            ast.Cast(
                                ParameterType,
                                ast.MemoryGetPointer(
                                    CpuProcessor.Memory,
                                    RegisterReader.Read <uint>(ParameterInfo),
                                    safe: true,
                                    errorDescription: "Invalid Pointer for Argument '" + ParameterType.Name + " " +
                                    ParameterInfo.Name + "'",
                                    invalidAddress: InvalidAddressAsEnum
                                    )
                                )
                            );
                    }
                    // A long type
                    else if (ParameterType == typeof(long) || ParameterType == typeof(ulong))
                    {
                        AstParameters.Add(RegisterReader.Read(ParameterInfo));
                    }
                    // A float register.
                    else if (ParameterType == typeof(float))
                    {
                        AstParameters.Add(RegisterReader.Read(ParameterInfo));
                    }
                    // PspPointer
                    else if (ParameterType == typeof(PspPointer))
                    {
                        AstParameters.Add(ast.CallStatic(
                                              typeof(PspPointer).GetMethod("op_Implicit", new[] { typeof(uint) }),
                                              RegisterReader.Read <uint>(ParameterInfo)
                                              ));
                    }
                    // A class
                    else if (ParameterType.IsClass)
                    {
                        if (!ParameterType.Implements(typeof(IHleUidPoolClass)))
                        {
                            throw (new InvalidCastException(
                                       $"Can't use a class '{ParameterType}' not implementing IHleUidPoolClass as parameter"));
                        }

                        AstParameters.Add(ast.Cast(ParameterType, ast.CallStatic(
                                                       (Func <CpuThreadState, Type, int, bool, object>)GetObjectFromPoolHelper,
                                                       ast.CpuThreadStateExpr,
                                                       ast.Immediate(ParameterType),
                                                       RegisterReader.Read <int>(ParameterInfo),
                                                       (InvalidAddressAsEnum == InvalidAddressAsEnum.Null)
                                                       )));
                    }
                    // An integer register
                    else
                    {
                        AstParameters.Add(ast.Cast(ParameterType,
                                                   RegisterReader.Read((ParameterType == typeof(uint)) ? typeof(uint) : typeof(int),
                                                                       ParameterInfo)));
                    }
                }

                AstMethodCall = ast.CallInstance(
                    ThisILInstanceHolder.GetAstFieldAccess(),
                    MethodInfo,
                    AstParameters.ToArray()
                    );
            }

            if (AstMethodCall.Type == typeof(void))
            {
                AstNodes.AddStatement(ast.Statement(AstMethodCall));
            }
            else if (AstMethodCall.Type == typeof(long))
            {
                AstNodes.AddStatement(ast.Assign(ast.GPR_l(2), ast.Cast <long>(AstMethodCall)));
            }
            else if (AstMethodCall.Type == typeof(float))
            {
                AstNodes.AddStatement(ast.Assign(ast.Fpr(0), ast.Cast <float>(AstMethodCall)));
            }
            else if (AstMethodCall.Type.IsClass)
            {
                if (!AstMethodCall.Type.Implements(typeof(IHleUidPoolClass)))
                {
                    throw (new InvalidCastException(
                               $"Can't use a class '{AstMethodCall.Type}' not implementing IHleUidPoolClass as return value"));
                }
                AstNodes.AddStatement(ast.Assign(
                                          ast.Gpr(2),
                                          ast.CallStatic(
                                              (Func <CpuThreadState, Type, IHleUidPoolClass, uint>)GetOrAllocIndexFromPoolHelper,
                                              ast.CpuThreadStateExpr,
                                              ast.Immediate(AstMethodCall.Type),
                                              ast.Cast <IHleUidPoolClass>(AstMethodCall)
                                              )
                                          ));
            }
            else
            {
                AstNodes.AddStatement(ast.Assign(ast.Gpr(2), ast.Cast <uint>(AstMethodCall)));
            }

            return(AstNodes);
        }
        protected virtual AstNode _Optimize(AstNodeStmContainer Container)
        {
            if (Container.Nodes.Count == 1)
            {
                return(Container.Nodes[0]);
            }

            var NewContainer = new AstNodeStmContainer(Container.Inline);

            foreach (var Node in Container.Nodes)
            {
                if (Node == null)
                {
                    continue;
                }

                if (Node is AstNodeStmContainer)
                {
                    foreach (var Node2 in (Node as AstNodeStmContainer).Nodes)
                    {
                        if (!(Node2 is AstNodeStmEmpty))
                        {
                            NewContainer.AddStatement(Node2);
                        }
                    }
                }
                else
                {
                    if (!(Node is AstNodeStmEmpty))
                    {
                        NewContainer.AddStatement(Node);
                    }
                }
            }

            bool Rebuild = false;

            for (int n = 0; n < NewContainer.Nodes.Count - 1; n++)
            {
                var CurrentNode = NewContainer.Nodes[n];
                var NextNode    = NewContainer.Nodes[n + 1];
                if ((CurrentNode is AstNodeStmGotoAlways) && (NextNode is AstNodeStmLabel))
                {
                    if ((CurrentNode as AstNodeStmGotoAlways).AstLabel == (NextNode as AstNodeStmLabel).AstLabel)
                    {
                        NewContainer.Nodes[n] = null;
                        //NewContainer.Nodes[n + 1] = null;
                        Rebuild = true;
                    }
                }
            }

            if (Rebuild)
            {
                return(new AstNodeStmContainer(Container.Inline, NewContainer.Nodes.Where(Node => Node != null).ToArray()));
            }
            else
            {
                return(NewContainer);
            }
        }