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])); } }
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); } }
//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); } }