diff --git a/src/binary_translation/InstructionBlock.cpp b/src/binary_translation/InstructionBlock.cpp index 3fec2169f..b097162ca 100644 --- a/src/binary_translation/InstructionBlock.cpp +++ b/src/binary_translation/InstructionBlock.cpp @@ -28,6 +28,8 @@ void InstructionBlock::GenerateCode() auto ir_builder = Module()->IrBuilder(); ir_builder->SetInsertPoint(entry_basic_block); + module->GenerateIncInstructionCount(); + instruction->GenerateCode(this); } diff --git a/src/binary_translation/ModuleGen.cpp b/src/binary_translation/ModuleGen.cpp index 51d32237e..1b5eca0d0 100644 --- a/src/binary_translation/ModuleGen.cpp +++ b/src/binary_translation/ModuleGen.cpp @@ -46,6 +46,15 @@ void ModuleGen::Run() GenerateBlockAddressArray(); } +void ModuleGen::GenerateIncInstructionCount() +{ + auto load = ir_builder->CreateLoad(instruction_count); + auto inc = ir_builder->CreateAdd(load, ir_builder->getInt32(1)); + auto store = ir_builder->CreateStore(inc, instruction_count); + tbaa->TagInstructionCount(load); + tbaa->TagInstructionCount(store); +} + void ModuleGen::BranchReadPC() { if (verify) @@ -111,6 +120,9 @@ void ModuleGen::GenerateGlobals() // bool Verify - contains the value of verify for citra usage new GlobalVariable(*module, ir_builder->getInt1Ty(), true, GlobalValue::ExternalLinkage, ir_builder->getInt1(verify), "Verify"); + + instruction_count = new GlobalVariable(*Module(), ir_builder->getInt32Ty(), false, GlobalValue::ExternalLinkage, + ir_builder->getInt32(0), "InstructionCount"); } void ModuleGen::GenerateBlockAddressArray() diff --git a/src/binary_translation/ModuleGen.h b/src/binary_translation/ModuleGen.h index ef08bf964..016bf1e8d 100644 --- a/src/binary_translation/ModuleGen.h +++ b/src/binary_translation/ModuleGen.h @@ -27,6 +27,7 @@ public: void Run(); + void GenerateIncInstructionCount(); // Generate code to read pc and run all following instructions, used in cases of indirect branch void BranchReadPC(); // Generate code to write to pc and run all following instructions, used in cases of direct branch @@ -80,6 +81,11 @@ private: */ llvm::ArrayType *block_address_array_type; llvm::GlobalVariable *block_address_array; + /* + * i32 InstructionCount; + * The count of instructions executed + */ + llvm::GlobalVariable *instruction_count; /* * i8 *GetBlockAddress(u32 pc) * Returns the address of the block for the instruction at pc diff --git a/src/binary_translation/TBAA.cpp b/src/binary_translation/TBAA.cpp index b177e99cf..ed638a337 100644 --- a/src/binary_translation/TBAA.cpp +++ b/src/binary_translation/TBAA.cpp @@ -20,6 +20,7 @@ void TBAA::GenerateTags() register_nodes[i] = md_builder.createTBAAScalarTypeNode(ss.str(), tbaa_root); } const_node = md_builder.createTBAAScalarTypeNode("Readonly", tbaa_root); + instruction_count_node = md_builder.createTBAAScalarTypeNode("InstructionCount", tbaa_root); } void TBAA::TagRegister(Instruction* instruction, Register reg) @@ -30,4 +31,9 @@ void TBAA::TagRegister(Instruction* instruction, Register reg) void TBAA::TagConst(Instruction* instruction) { instruction->setMetadata(LLVMContext::MD_tbaa, const_node); +} + +void TBAA::TagInstructionCount(llvm::Instruction* instruction) +{ + instruction->setMetadata(LLVMContext::MD_tbaa, instruction_count_node); } \ No newline at end of file diff --git a/src/binary_translation/TBAA.h b/src/binary_translation/TBAA.h index 0a4e2c766..71798e034 100644 --- a/src/binary_translation/TBAA.h +++ b/src/binary_translation/TBAA.h @@ -21,9 +21,11 @@ public: void TagRegister(llvm::Instruction *instruction, Register reg); void TagConst(llvm::Instruction *instruction); + void TagInstructionCount(llvm::Instruction *instruction); private: llvm::MDNode *register_nodes[RegisterCount]; // Tag for everything that is never written. // Since it is never written, one tag works llvm::MDNode *const_node; + llvm::MDNode *instruction_count_node; }; \ No newline at end of file diff --git a/src/core/arm/dyncom/arm_dyncom_interpreter.cpp b/src/core/arm/dyncom/arm_dyncom_interpreter.cpp index a9b87b7a3..2a630ce13 100644 --- a/src/core/arm/dyncom/arm_dyncom_interpreter.cpp +++ b/src/core/arm/dyncom/arm_dyncom_interpreter.cpp @@ -3985,7 +3985,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { #if ENABLE_BINARY_TRANSLATION - BinaryTranslationLoader::Run(); + num_instrs = BinaryTranslationLoader::Run(num_instrs); #endif if (cpu->TFlag) diff --git a/src/core/binary_translation/BinaryTranslationLoader.cpp b/src/core/binary_translation/BinaryTranslationLoader.cpp index 0d047d34c..e90002984 100644 --- a/src/core/binary_translation/BinaryTranslationLoader.cpp +++ b/src/core/binary_translation/BinaryTranslationLoader.cpp @@ -19,6 +19,7 @@ std::unique_ptr g_loaded_object_info; void(*g_run_function)(); bool(*g_can_run_function)(); +uint32_t *g_instruction_count; // Used by the verifier struct SavedState @@ -117,7 +118,16 @@ void BinaryTranslationLoader::Load(FileUtil::IOFile& file) g_run_function = static_cast(g_dyld->getSymbolAddress("Run")); g_can_run_function = static_cast(g_dyld->getSymbolAddress("CanRun")); - g_verify = *static_cast(g_dyld->getSymbolAddress("Verify")); + auto verify_ptr = static_cast(g_dyld->getSymbolAddress("Verify")); + g_instruction_count = static_cast(g_dyld->getSymbolAddress("InstructionCount")); + + if (!g_run_function || !g_can_run_function || !verify_ptr || !g_instruction_count) + { + LOG_WARNING(Loader, "Cannot load optimized file, missing critical function"); + return; + } + + g_verify = *verify_ptr; g_enabled = true; } @@ -145,18 +155,19 @@ bool BinaryTranslationLoader::CanRun(bool specific_address) return true; } -void BinaryTranslationLoader::Run() +uint32_t BinaryTranslationLoader::Run(uint32_t instruction_count) { // No need to check the PC, Run does it anyway - if (!CanRun(false)) return; + if (!CanRun(false)) return instruction_count; // If verify is enabled, it will run opcodes - if (g_verify) return; + if (g_verify) return instruction_count; - RunInternal(); + return RunInternal(instruction_count); } -void BinaryTranslationLoader::RunInternal() +uint32_t BinaryTranslationLoader::RunInternal(uint32_t instruction_count) { + *g_instruction_count = instruction_count; g_run_function(); g_state->TFlag = g_state->Reg[15] & 1; @@ -164,6 +175,8 @@ void BinaryTranslationLoader::RunInternal() g_state->Reg[15] &= 0xfffffffe; else g_state->Reg[15] &= 0xfffffffc; + + return *g_instruction_count; } void Swap(void *a, void *b, size_t size) @@ -198,7 +211,7 @@ void BinaryTranslationLoader::VerifyCallback() g_state_copy.SwapWith(*g_state); // Run the opcode - RunInternal(); + RunInternal(0); // Test auto current_as_saved_state = SavedState(*g_state); diff --git a/src/core/binary_translation/BinaryTranslationLoader.h b/src/core/binary_translation/BinaryTranslationLoader.h index dafb3ace8..58b570095 100644 --- a/src/core/binary_translation/BinaryTranslationLoader.h +++ b/src/core/binary_translation/BinaryTranslationLoader.h @@ -13,8 +13,9 @@ public: // If specific_address, checks the specific PC too static bool CanRun(bool specific_address); // Runs the state provided at SetCpuState. - static void Run(); + // Returns instruction_count + number of instructions executed + static uint32_t Run(uint32_t instruction_count); // Link between Run and VerifyCallback - static void RunInternal(); + static uint32_t RunInternal(uint32_t instruction_count); static void VerifyCallback(); }; \ No newline at end of file