//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); }
/// <summary> /// PASS 1: Analyze Branches /// </summary> private void AnalyzeBranches() { _skipPc = new HashSet <uint>(); _analyzedPc = new HashSet <uint>(); var branchesToAnalyze = new Queue <uint>(); _labels[_entryPc] = AstLabel.CreateLabel("EntryPoint"); var endPc = _instructionReader.EndPc; _pc = _entryPc; _minPc = uint.MaxValue; _maxPc = uint.MinValue; branchesToAnalyze.Enqueue(_entryPc); while (true) { HandleNewBranch: var endOfBranchFound = false; if (branchesToAnalyze.Count == 0) { break; } for (_pc = branchesToAnalyze.Dequeue(); _pc <= endPc; _pc += 4) { // If already analyzed, stop scanning this branch. if (_analyzedPc.Contains(_pc)) { break; } _analyzedPc.Add(_pc); //Console.WriteLine("%08X".Sprintf(PC)); if (_analyzedPc.Count > MaxNumberOfInstructions) { throw new InvalidDataException( $"Code sequence too long: >= {MaxNumberOfInstructions} at 0x{_entryPc:X8}"); } UpdateMinMax(_pc); //Console.WriteLine(" PC:{0:X}", PC); var instruction = _instructionReader[_pc]; var branchInfo = DynarecBranchAnalyzer.GetBranchInfo(instruction); var disassemblerInfo = _mipsDisassembler.Disassemble(_pc, instruction); LogInstruction(_pc, instruction); // Break if (disassemblerInfo.InstructionInfo.Name == "break") { break; } // Branch instruction. //else if (BranchInfo.HasFlag(DynarecBranchAnalyzer.JumpFlags.JumpAlways)) else if (branchInfo.HasFlag(DynarecBranchAnalyzer.JumpFlags.JumpInstruction)) { //Console.WriteLine("Instruction"); var jumpAddress = instruction.GetJumpAddress(_memory, _pc); // Located a jump-always instruction with a delayed slot. Process next instruction too. if (branchInfo.HasFlag(DynarecBranchAnalyzer.JumpFlags.AndLink)) { // Just a function call. Continue analyzing. } else { if (PspMemory.IsAddressValid(jumpAddress)) { if (!_labelsJump.ContainsKey(jumpAddress)) { if (AddressInsideFunction(jumpAddress)) { //Console.WriteLine("JumpAddress: {0:X8}", JumpAddress); _labelsJump[jumpAddress] = AstLabel.CreateLabel($"Jump_0x{jumpAddress:X8}"); branchesToAnalyze.Enqueue(jumpAddress); } } } endOfBranchFound = true; continue; } } else if (branchInfo.HasFlag(DynarecBranchAnalyzer.JumpFlags.BranchOrJumpInstruction)) { var branchAddress = instruction.GetBranchAddress(_pc); if (!_labels.ContainsKey(branchAddress)) { //Console.WriteLine("BranchAddress: {0:X8}", BranchAddress); UpdateMinMax(branchAddress); _labels[branchAddress] = AstLabel.CreateLabel($"Label_0x{branchAddress:X8}"); branchesToAnalyze.Enqueue(branchAddress); } } else if (branchInfo.HasFlag(DynarecBranchAnalyzer.JumpFlags.SyscallInstruction)) { // On this special Syscall if (instruction.Code == SyscallInfo.NativeCallSyscallCode) { //PC += 4; goto HandleNewBranch; } } // Jump-Always found. And we have also processed the delayed branch slot. End the branch. if (endOfBranchFound) { endOfBranchFound = false; goto HandleNewBranch; } } } //Console.WriteLine("FunctionSegment({0:X8}-{1:X8})", MinPC, MaxPC); foreach (var labelAddress in _labelsJump.Keys.ToArray()) { if (!AddressInsideFunction(labelAddress)) { _labelsJump.Remove(labelAddress); } } _cpuEmitter.BranchCount = _labels.Count; }