mirror of
				https://github.com/N64Recomp/N64Recomp.git
				synced 2025-10-30 08:02:11 +00:00 
			
		
		
		
	Added single-file mode and absolute symbol options (for patch recompilation)
This commit is contained in:
		
							parent
							
								
									d249363fe5
								
							
						
					
					
						commit
						be275c198a
					
				
					 7 changed files with 184 additions and 90 deletions
				
			
		|  | @ -46,7 +46,10 @@ namespace RecompPort { | |||
| 
 | ||||
|     struct Config { | ||||
|         int32_t entrypoint; | ||||
|         bool has_entrypoint; | ||||
|         bool uses_mips3_float_mode; | ||||
|         bool single_file_output; | ||||
|         bool use_absolute_symbols; | ||||
|         std::filesystem::path elf_path; | ||||
|         std::filesystem::path output_func_path; | ||||
|         std::filesystem::path relocatable_sections_path; | ||||
|  | @ -154,7 +157,7 @@ namespace RecompPort { | |||
|     }; | ||||
| 
 | ||||
|     bool analyze_function(const Context& context, const Function& function, const std::vector<rabbitizer::InstructionCpu>& instructions, FunctionStats& stats); | ||||
|     bool recompile_function(const Context& context, const Config& config, const Function& func, const std::filesystem::path& output_path, std::span<std::vector<uint32_t>> static_funcs); | ||||
|     bool recompile_function(const Context& context, const Config& config, const Function& func, std::ofstream& output_file, std::span<std::vector<uint32_t>> static_funcs, bool write_header); | ||||
| } | ||||
| 
 | ||||
| #endif | ||||
|  |  | |||
|  | @ -22,8 +22,10 @@ | |||
|     <ClCompile Include="rabbitizer\cplusplus\src\analysis\LoPairingInfo.cpp" /> | ||||
|     <ClCompile Include="rabbitizer\cplusplus\src\analysis\RegistersTracker.cpp" /> | ||||
|     <ClCompile Include="rabbitizer\cplusplus\src\instructions\InstrId.cpp" /> | ||||
|     <ClCompile Include="rabbitizer\cplusplus\src\instructions\InstrIdType.cpp" /> | ||||
|     <ClCompile Include="rabbitizer\cplusplus\src\instructions\InstructionBase.cpp" /> | ||||
|     <ClCompile Include="rabbitizer\cplusplus\src\instructions\InstructionCpu.cpp" /> | ||||
|     <ClCompile Include="rabbitizer\cplusplus\src\instructions\InstructionR3000GTE.cpp" /> | ||||
|     <ClCompile Include="rabbitizer\cplusplus\src\instructions\InstructionR5900.cpp" /> | ||||
|     <ClCompile Include="rabbitizer\cplusplus\src\instructions\InstructionRsp.cpp" /> | ||||
|     <ClCompile Include="rabbitizer\src\analysis\RabbitizerLoPairingInfo.c" /> | ||||
|  | @ -35,8 +37,12 @@ | |||
|     <ClCompile Include="rabbitizer\src\instructions\RabbitizerInstrCategory.c" /> | ||||
|     <ClCompile Include="rabbitizer\src\instructions\RabbitizerInstrDescriptor.c" /> | ||||
|     <ClCompile Include="rabbitizer\src\instructions\RabbitizerInstrId.c" /> | ||||
|     <ClCompile Include="rabbitizer\src\instructions\RabbitizerInstrIdType.c" /> | ||||
|     <ClCompile Include="rabbitizer\src\instructions\RabbitizerInstrSuffix.c" /> | ||||
|     <ClCompile Include="rabbitizer\src\instructions\RabbitizerInstructionCpu\RabbitizerInstructionCpu_OperandType.c" /> | ||||
|     <ClCompile Include="rabbitizer\src\instructions\RabbitizerInstructionR3000GTE\RabbitizerInstructionR3000GTE.c" /> | ||||
|     <ClCompile Include="rabbitizer\src\instructions\RabbitizerInstructionR3000GTE\RabbitizerInstructionR3000GTE_OperandType.c" /> | ||||
|     <ClCompile Include="rabbitizer\src\instructions\RabbitizerInstructionR3000GTE\RabbitizerInstructionR3000GTE_ProcessUniqueId.c" /> | ||||
|     <ClCompile Include="rabbitizer\src\instructions\RabbitizerInstructionR5900\RabbitizerInstructionR5900.c" /> | ||||
|     <ClCompile Include="rabbitizer\src\instructions\RabbitizerInstructionR5900\RabbitizerInstructionR5900_OperandType.c" /> | ||||
|     <ClCompile Include="rabbitizer\src\instructions\RabbitizerInstructionR5900\RabbitizerInstructionR5900_ProcessUniqueId.c" /> | ||||
|  | @ -46,8 +52,10 @@ | |||
|     <ClCompile Include="rabbitizer\src\instructions\RabbitizerInstruction\RabbitizerInstruction.c" /> | ||||
|     <ClCompile Include="rabbitizer\src\instructions\RabbitizerInstruction\RabbitizerInstruction_Disassemble.c" /> | ||||
|     <ClCompile Include="rabbitizer\src\instructions\RabbitizerInstruction\RabbitizerInstruction_Examination.c" /> | ||||
|     <ClCompile Include="rabbitizer\src\instructions\RabbitizerInstruction\RabbitizerInstruction_Operand.c" /> | ||||
|     <ClCompile Include="rabbitizer\src\instructions\RabbitizerInstruction\RabbitizerInstruction_ProcessUniqueId.c" /> | ||||
|     <ClCompile Include="rabbitizer\src\instructions\RabbitizerRegister.c" /> | ||||
|     <ClCompile Include="rabbitizer\src\instructions\RabbitizerRegisterDescriptor.c" /> | ||||
|   </ItemGroup> | ||||
|   <ItemGroup> | ||||
|     <ClInclude Include="rabbitizer\cplusplus\include\analysis\LoPairingInfo.hpp" /> | ||||
|  | @ -158,7 +166,7 @@ | |||
|       <GenerateDebugInformation>true</GenerateDebugInformation> | ||||
|     </Link> | ||||
|     <ClCompile> | ||||
|       <AdditionalIncludeDirectories>$(ProjectDir)rabbitizer\include;$(ProjectDir)rabbitizer\cplusplus\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> | ||||
|       <AdditionalIncludeDirectories>$(ProjectDir)rabbitizer\include;$(ProjectDir)rabbitizer\cplusplus\include;$(ProjectDir)rabbitizer\tables</AdditionalIncludeDirectories> | ||||
|       <LanguageStandard>stdcpp17</LanguageStandard> | ||||
|     </ClCompile> | ||||
|   </ItemDefinitionGroup> | ||||
|  | @ -171,7 +179,7 @@ | |||
|       <GenerateDebugInformation>true</GenerateDebugInformation> | ||||
|     </Link> | ||||
|     <ClCompile> | ||||
|       <AdditionalIncludeDirectories>$(ProjectDir)rabbitizer\include;$(ProjectDir)rabbitizer\cplusplus\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> | ||||
|       <AdditionalIncludeDirectories>$(ProjectDir)rabbitizer\include;$(ProjectDir)rabbitizer\cplusplus\include;$(ProjectDir)rabbitizer\tables</AdditionalIncludeDirectories> | ||||
|       <LanguageStandard>stdcpp17</LanguageStandard> | ||||
|     </ClCompile> | ||||
|   </ItemDefinitionGroup> | ||||
|  | @ -182,7 +190,7 @@ | |||
|       <GenerateDebugInformation>true</GenerateDebugInformation> | ||||
|     </Link> | ||||
|     <ClCompile> | ||||
|       <AdditionalIncludeDirectories>$(ProjectDir)rabbitizer\include;$(ProjectDir)rabbitizer\cplusplus\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> | ||||
|       <AdditionalIncludeDirectories>$(ProjectDir)rabbitizer\include;$(ProjectDir)rabbitizer\cplusplus\include;$(ProjectDir)rabbitizer\tables</AdditionalIncludeDirectories> | ||||
|       <LanguageStandard>stdcpp17</LanguageStandard> | ||||
|     </ClCompile> | ||||
|   </ItemDefinitionGroup> | ||||
|  | @ -195,7 +203,7 @@ | |||
|       <GenerateDebugInformation>true</GenerateDebugInformation> | ||||
|     </Link> | ||||
|     <ClCompile> | ||||
|       <AdditionalIncludeDirectories>$(ProjectDir)rabbitizer\include;$(ProjectDir)rabbitizer\cplusplus\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> | ||||
|       <AdditionalIncludeDirectories>$(ProjectDir)rabbitizer\include;$(ProjectDir)rabbitizer\cplusplus\include;$(ProjectDir)rabbitizer\tables</AdditionalIncludeDirectories> | ||||
|       <LanguageStandard>stdcpp17</LanguageStandard> | ||||
|     </ClCompile> | ||||
|   </ItemDefinitionGroup> | ||||
|  |  | |||
|  | @ -102,6 +102,30 @@ | |||
|     <ClCompile Include="rabbitizer\cplusplus\src\analysis\RegistersTracker.cpp"> | ||||
|       <Filter>Source Files</Filter> | ||||
|     </ClCompile> | ||||
|     <ClCompile Include="rabbitizer\src\instructions\RabbitizerInstrIdType.c"> | ||||
|       <Filter>Source Files</Filter> | ||||
|     </ClCompile> | ||||
|     <ClCompile Include="rabbitizer\src\instructions\RabbitizerRegisterDescriptor.c"> | ||||
|       <Filter>Source Files</Filter> | ||||
|     </ClCompile> | ||||
|     <ClCompile Include="rabbitizer\src\instructions\RabbitizerInstructionR3000GTE\RabbitizerInstructionR3000GTE.c"> | ||||
|       <Filter>Source Files</Filter> | ||||
|     </ClCompile> | ||||
|     <ClCompile Include="rabbitizer\src\instructions\RabbitizerInstructionR3000GTE\RabbitizerInstructionR3000GTE_OperandType.c"> | ||||
|       <Filter>Source Files</Filter> | ||||
|     </ClCompile> | ||||
|     <ClCompile Include="rabbitizer\src\instructions\RabbitizerInstructionR3000GTE\RabbitizerInstructionR3000GTE_ProcessUniqueId.c"> | ||||
|       <Filter>Source Files</Filter> | ||||
|     </ClCompile> | ||||
|     <ClCompile Include="rabbitizer\src\instructions\RabbitizerInstruction\RabbitizerInstruction_Operand.c"> | ||||
|       <Filter>Source Files</Filter> | ||||
|     </ClCompile> | ||||
|     <ClCompile Include="rabbitizer\cplusplus\src\instructions\InstrIdType.cpp"> | ||||
|       <Filter>Source Files</Filter> | ||||
|     </ClCompile> | ||||
|     <ClCompile Include="rabbitizer\cplusplus\src\instructions\InstructionR3000GTE.cpp"> | ||||
|       <Filter>Source Files</Filter> | ||||
|     </ClCompile> | ||||
|   </ItemGroup> | ||||
|   <ItemGroup> | ||||
|     <ClInclude Include="rabbitizer\include\instructions\RabbitizerAccessType.h"> | ||||
|  |  | |||
|  | @ -1 +1 @@ | |||
| Subproject commit b9a39f6ec0a3ff6690ef2925e6275cf6578602cc | ||||
| Subproject commit e0d8003047938e2ec3697eaf8d61a84d11d17b43 | ||||
|  | @ -211,12 +211,20 @@ RecompPort::Config::Config(const char* path) { | |||
| 		// Input section (required)
 | ||||
| 		const toml::value& input_data = toml::find<toml::value>(config_data, "input"); | ||||
| 
 | ||||
| 		if (input_data.contains("entrypoint")) { | ||||
| 			entrypoint = toml::find<int32_t>(input_data, "entrypoint"); | ||||
| 			has_entrypoint = true; | ||||
| 		} | ||||
| 		else { | ||||
| 			has_entrypoint = false; | ||||
| 		} | ||||
| 		elf_path                  = concat_if_not_empty(basedir, toml::find<std::string>(input_data, "elf_path")); | ||||
| 		output_func_path          = concat_if_not_empty(basedir, toml::find<std::string>(input_data, "output_func_path")); | ||||
| 		relocatable_sections_path = concat_if_not_empty(basedir, toml::find_or<std::string>(input_data, "relocatable_sections_path", "")); | ||||
| 		uses_mips3_float_mode     = toml::find_or<bool>(input_data, "uses_mips3_float_mode", false); | ||||
| 		bss_section_suffix        = toml::find_or<std::string>(input_data, "bss_section_suffix", ".bss"); | ||||
| 		single_file_output        = toml::find_or<bool>(input_data, "single_file_output", false); | ||||
| 		use_absolute_symbols      = toml::find_or<bool>(input_data, "use_absolute_symbols", false); | ||||
| 
 | ||||
| 		// Patches section (optional)
 | ||||
| 		const toml::value& patches_data = toml::find_or<toml::value>(config_data, "patches", toml::value{}); | ||||
|  |  | |||
							
								
								
									
										135
									
								
								src/main.cpp
									
										
									
									
									
								
							
							
						
						
									
										135
									
								
								src/main.cpp
									
										
									
									
									
								
							|  | @ -573,7 +573,7 @@ std::unordered_set<std::string> renamed_funcs{ | |||
|     "__assert", | ||||
| }; | ||||
| 
 | ||||
| bool read_symbols(RecompPort::Context& context, const ELFIO::elfio& elf_file, ELFIO::section* symtab_section, uint32_t entrypoint) { | ||||
| bool read_symbols(RecompPort::Context& context, const ELFIO::elfio& elf_file, ELFIO::section* symtab_section, uint32_t entrypoint, bool has_entrypoint, bool use_absolute_symbols) { | ||||
|     bool found_entrypoint_func = false; | ||||
|     ELFIO::symbol_section_accessor symbols{ elf_file, symtab_section }; | ||||
|     fmt::print("Num symbols: {}\n", symbols.get_symbols_num()); | ||||
|  | @ -593,12 +593,28 @@ bool read_symbols(RecompPort::Context& context, const ELFIO::elfio& elf_file, EL | |||
|         symbols.get_symbol(sym_index, name, value, size, bind, type, | ||||
|             section_index, other); | ||||
| 
 | ||||
|         if (section_index == ELFIO::SHN_ABS && use_absolute_symbols) { | ||||
|             uint32_t vram = static_cast<uint32_t>(value); | ||||
|             context.functions_by_vram[vram].push_back(context.functions.size()); | ||||
| 
 | ||||
|             context.functions.emplace_back( | ||||
|                 vram, | ||||
|                 0, | ||||
|                 std::vector<uint32_t>{}, | ||||
|                 std::move(name), | ||||
|                 0, | ||||
|                 true, | ||||
|                 reimplemented | ||||
|             ); | ||||
|             continue; | ||||
|         } | ||||
| 
 | ||||
|         if (section_index >= context.sections.size()) { | ||||
|             continue; | ||||
|         } | ||||
|          | ||||
|         // Check if this symbol is the entrypoint
 | ||||
|         if (value == entrypoint && type == ELFIO::STT_FUNC) { | ||||
|         if (has_entrypoint && value == entrypoint && type == ELFIO::STT_FUNC) { | ||||
|             if (found_entrypoint_func) { | ||||
|                 fmt::print(stderr, "Ambiguous entrypoint: {}\n", name); | ||||
|                 return false; | ||||
|  | @ -996,6 +1012,59 @@ bool read_list_file(const std::filesystem::path& filename, std::vector<std::stri | |||
|     return true; | ||||
| } | ||||
| 
 | ||||
| bool compare_files(const std::filesystem::path& file1_path, const std::filesystem::path& file2_path) { | ||||
|     static std::vector<char> file1_buf(65536); | ||||
|     static std::vector<char> file2_buf(65536); | ||||
| 
 | ||||
|     std::ifstream file1(file1_path, std::ifstream::ate | std::ifstream::binary); //open file at the end
 | ||||
|     std::ifstream file2(file2_path, std::ifstream::ate | std::ifstream::binary); //open file at the end
 | ||||
|     const std::ifstream::pos_type fileSize = file1.tellg(); | ||||
| 
 | ||||
|     file1.rdbuf()->pubsetbuf(file1_buf.data(), file1_buf.size()); | ||||
|     file2.rdbuf()->pubsetbuf(file2_buf.data(), file2_buf.size()); | ||||
| 
 | ||||
|     if (fileSize != file2.tellg()) { | ||||
|         return false; //different file size
 | ||||
|     } | ||||
| 
 | ||||
|     file1.seekg(0); //rewind
 | ||||
|     file2.seekg(0); //rewind
 | ||||
| 
 | ||||
|     std::istreambuf_iterator<char> begin1(file1); | ||||
|     std::istreambuf_iterator<char> begin2(file2); | ||||
| 
 | ||||
|     return std::equal(begin1, std::istreambuf_iterator<char>(), begin2); //Second argument is end-of-range iterator
 | ||||
| } | ||||
| 
 | ||||
| bool recompile_single_function(const RecompPort::Context& context, const RecompPort::Config& config, const RecompPort::Function& func, const std::filesystem::path& output_path, std::span<std::vector<uint32_t>> static_funcs_out) { | ||||
|     // Open the temporary output file
 | ||||
|     std::filesystem::path temp_path = output_path; | ||||
|     temp_path.replace_extension(".tmp"); | ||||
|     std::ofstream output_file{ temp_path }; | ||||
|     if (!output_file.good()) { | ||||
|         fmt::print(stderr, "Failed to open file for writing: {}\n", temp_path.string() ); | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     if (!RecompPort::recompile_function(context, config, func, output_file, static_funcs_out, true)) { | ||||
|         return false; | ||||
|     } | ||||
|      | ||||
|     output_file.close(); | ||||
| 
 | ||||
|     // If a file of the target name exists and it's identical to the output file, delete the output file.
 | ||||
|     // This prevents updating the existing file so that it doesn't need to be rebuilt.
 | ||||
|     if (std::filesystem::exists(output_path) && compare_files(output_path, temp_path)) { | ||||
|         std::filesystem::remove(temp_path); | ||||
|     } | ||||
|     // Otherwise, rename the new file to the target path.
 | ||||
|     else { | ||||
|         std::filesystem::rename(temp_path, output_path); | ||||
|     } | ||||
| 
 | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| int main(int argc, char** argv) { | ||||
|     auto exit_failure = [] (const std::string& error_str) { | ||||
|         fmt::vprint(stderr, error_str, fmt::make_format_args()); | ||||
|  | @ -1069,9 +1138,9 @@ int main(int argc, char** argv) { | |||
|     } | ||||
| 
 | ||||
|     // Read all of the symbols in the elf and look for the entrypoint function
 | ||||
|     bool found_entrypoint_func = read_symbols(context, elf_file, symtab_section, config.entrypoint); | ||||
|     bool found_entrypoint_func = read_symbols(context, elf_file, symtab_section, config.entrypoint, config.has_entrypoint, config.use_absolute_symbols); | ||||
| 
 | ||||
|     if (!found_entrypoint_func) { | ||||
|     if (config.has_entrypoint && !found_entrypoint_func) { | ||||
|         exit_failure("Could not find entrypoint function\n"); | ||||
|     } | ||||
| 
 | ||||
|  | @ -1079,17 +1148,8 @@ int main(int argc, char** argv) { | |||
| 
 | ||||
|     std::filesystem::create_directories(config.output_func_path); | ||||
| 
 | ||||
|     std::ofstream lookup_file{ config.output_func_path / "lookup.cpp" }; | ||||
|     std::ofstream func_header_file{ config.output_func_path / "funcs.h" }; | ||||
| 
 | ||||
|     fmt::print(lookup_file, | ||||
|         //"#include <utility>\n"
 | ||||
|         "#include \"recomp.h\"\n" | ||||
|         //"#include \"funcs.h\"\n"
 | ||||
|         "\n" | ||||
|         //"std::pair<uint32_t, recomp_func_t*> funcs[] {{\n"
 | ||||
|     ); | ||||
| 
 | ||||
|     fmt::print(func_header_file, | ||||
|         "#include \"recomp.h\"\n" | ||||
|         "\n" | ||||
|  | @ -1152,6 +1212,13 @@ int main(int argc, char** argv) { | |||
|         func.words[instruction_index] = byteswap(patch.value); | ||||
|     } | ||||
| 
 | ||||
|     std::ofstream single_output_file; | ||||
|     bool header_written = false; | ||||
| 
 | ||||
|     if (config.single_file_output) { | ||||
|         single_output_file.open(config.output_func_path / config.elf_path.stem().replace_extension(".c")); | ||||
|     } | ||||
| 
 | ||||
|     //#pragma omp parallel for
 | ||||
|     for (size_t i = 0; i < context.functions.size(); i++) { | ||||
|         const auto& func = context.functions[i]; | ||||
|  | @ -1159,18 +1226,21 @@ int main(int argc, char** argv) { | |||
|         if (!func.ignored && func.words.size() != 0) { | ||||
|             fmt::print(func_header_file, | ||||
|                 "void {}(uint8_t* rdram, recomp_context* ctx);\n", func.name); | ||||
|             //fmt::print(lookup_file,
 | ||||
|             //    "    {{ 0x{:08X}u, {} }},\n", func.vram, func.name);
 | ||||
|             if (RecompPort::recompile_function(context, config, func, config.output_func_path / (func.name + ".c"), static_funcs_by_section) == false) { | ||||
|                 //lookup_file.clear();
 | ||||
|             bool result; | ||||
|             if (config.single_file_output) { | ||||
|                 result = RecompPort::recompile_function(context, config, func, single_output_file, static_funcs_by_section, !header_written); | ||||
|                 header_written = true; | ||||
|             } | ||||
|             else { | ||||
|                 result = recompile_single_function(context, config, func, config.output_func_path / (func.name + ".c"), static_funcs_by_section); | ||||
|             } | ||||
|             if (result == false) { | ||||
|                 fmt::print(stderr, "Error recompiling {}\n", func.name); | ||||
|                 std::exit(EXIT_FAILURE); | ||||
|             } | ||||
|         } else if (func.reimplemented) { | ||||
|             fmt::print(func_header_file, | ||||
|                        "void {}(uint8_t* rdram, recomp_context* ctx);\n", func.name); | ||||
|             //fmt::print(lookup_file,
 | ||||
|             //           "    {{ 0x{:08X}u, {} }},\n", func.vram, func.name);
 | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|  | @ -1228,20 +1298,32 @@ int main(int argc, char** argv) { | |||
| 
 | ||||
|             fmt::print(func_header_file, | ||||
|                        "void {}(uint8_t* rdram, recomp_context* ctx);\n", func.name); | ||||
|             //fmt::print(lookup_file,
 | ||||
|             //           "    {{ 0x{:08X}u, {} }},\n", func.vram, func.name);
 | ||||
|             if (RecompPort::recompile_function(context, config, func, config.output_func_path / (func.name + ".c"), static_funcs_by_section) == false) { | ||||
|                 //lookup_file.clear();
 | ||||
| 
 | ||||
|             bool result; | ||||
|             if (config.single_file_output) { | ||||
|                 result = RecompPort::recompile_function(context, config, func, single_output_file, static_funcs_by_section, !header_written); | ||||
|                 header_written = true; | ||||
|             } | ||||
|             else { | ||||
|                 result = recompile_single_function(context, config, func, config.output_func_path / (func.name + ".c"), static_funcs_by_section); | ||||
|             } | ||||
| 
 | ||||
|             if (result == false) { | ||||
|                 fmt::print(stderr, "Error recompiling {}\n", func.name); | ||||
|                 std::exit(EXIT_FAILURE); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     if (config.has_entrypoint) { | ||||
|         std::ofstream lookup_file{ config.output_func_path / "lookup.cpp" }; | ||||
|          | ||||
|         fmt::print(lookup_file, | ||||
|             "#include \"recomp.h\"\n" | ||||
|             "\n" | ||||
|         ); | ||||
| 
 | ||||
|         fmt::print(lookup_file, | ||||
|         //"}};\n"
 | ||||
|         //"extern const size_t num_funcs = sizeof(funcs) / sizeof(funcs[0]);\n"
 | ||||
|         //"\n"
 | ||||
|             "gpr get_entrypoint_address() {{ return (gpr)(int32_t)0x{:08X}u; }}\n" | ||||
|             "\n" | ||||
|             "const char* get_rom_name() {{ return \"{}\"; }}\n" | ||||
|  | @ -1249,6 +1331,7 @@ int main(int argc, char** argv) { | |||
|             static_cast<uint32_t>(config.entrypoint), | ||||
|             config.elf_path.filename().replace_extension(".z64").string() | ||||
|         ); | ||||
|     } | ||||
| 
 | ||||
|     fmt::print(func_header_file, | ||||
|         "\n" | ||||
|  |  | |||
|  | @ -191,6 +191,7 @@ bool process_instruction(const RecompPort::Context& context, const RecompPort::C | |||
|         } | ||||
|         needs_link_branch = true; | ||||
|         print_unconditional_branch("{}(rdram, ctx)", jal_target_name); | ||||
|         return true; | ||||
|     }; | ||||
| 
 | ||||
|     if (indent) { | ||||
|  | @ -674,6 +675,7 @@ bool process_instruction(const RecompPort::Context& context, const RecompPort::C | |||
|         break; | ||||
| 
 | ||||
|     // Cop1 compares
 | ||||
|     // TODO allow NaN in ordered and unordered float comparisons, default to a compare result of 1 for ordered and 0 for unordered if a NaN is present
 | ||||
|     case InstrId::cpu_c_lt_s: | ||||
|         print_line("CHECK_FR(ctx, {})", fs); | ||||
|         print_line("CHECK_FR(ctx, {})", ft); | ||||
|  | @ -701,6 +703,12 @@ bool process_instruction(const RecompPort::Context& context, const RecompPort::C | |||
|         //print_line("*(volatile int*)0 = 0;");
 | ||||
|         print_line("c1cs = ctx->f{}.fl <= ctx->f{}.fl", fs, ft); | ||||
|         break; | ||||
|     case InstrId::cpu_c_ule_s: | ||||
|         print_line("CHECK_FR(ctx, {})", fs); | ||||
|         print_line("CHECK_FR(ctx, {})", ft); | ||||
|         //print_line("*(volatile int*)0 = 0;");
 | ||||
|         print_line("c1cs = ctx->f{}.fl <= ctx->f{}.fl", fs, ft); | ||||
|         break; | ||||
|     case InstrId::cpu_c_le_d: | ||||
|         print_line("CHECK_FR(ctx, {})", fs); | ||||
|         print_line("CHECK_FR(ctx, {})", ft); | ||||
|  | @ -947,47 +955,19 @@ bool process_instruction(const RecompPort::Context& context, const RecompPort::C | |||
|     return true; | ||||
| } | ||||
| 
 | ||||
| bool compare_files(const std::filesystem::path& file1_path, const std::filesystem::path& file2_path) { | ||||
|     static std::vector<char> file1_buf(65536); | ||||
|     static std::vector<char> file2_buf(65536); | ||||
| 
 | ||||
|     std::ifstream file1(file1_path, std::ifstream::ate | std::ifstream::binary); //open file at the end
 | ||||
|     std::ifstream file2(file2_path, std::ifstream::ate | std::ifstream::binary); //open file at the end
 | ||||
|     const std::ifstream::pos_type fileSize = file1.tellg(); | ||||
| 
 | ||||
|     file1.rdbuf()->pubsetbuf(file1_buf.data(), file1_buf.size()); | ||||
|     file2.rdbuf()->pubsetbuf(file2_buf.data(), file2_buf.size()); | ||||
| 
 | ||||
|     if (fileSize != file2.tellg()) { | ||||
|         return false; //different file size
 | ||||
|     } | ||||
| 
 | ||||
|     file1.seekg(0); //rewind
 | ||||
|     file2.seekg(0); //rewind
 | ||||
| 
 | ||||
|     std::istreambuf_iterator<char> begin1(file1); | ||||
|     std::istreambuf_iterator<char> begin2(file2); | ||||
| 
 | ||||
|     return std::equal(begin1, std::istreambuf_iterator<char>(), begin2); //Second argument is end-of-range iterator
 | ||||
| } | ||||
| 
 | ||||
| bool RecompPort::recompile_function(const RecompPort::Context& context, const RecompPort::Config& config, const RecompPort::Function& func, const std::filesystem::path& output_path, std::span<std::vector<uint32_t>> static_funcs_out) { | ||||
| bool RecompPort::recompile_function(const RecompPort::Context& context, const RecompPort::Config& config, const RecompPort::Function& func, std::ofstream& output_file, std::span<std::vector<uint32_t>> static_funcs_out, bool write_header) { | ||||
|     //fmt::print("Recompiling {}\n", func.name);
 | ||||
|     std::vector<rabbitizer::InstructionCpu> instructions; | ||||
| 
 | ||||
|     // Open the output file and write the file header
 | ||||
|     std::filesystem::path temp_path = output_path; | ||||
|     temp_path.replace_extension(".tmp"); | ||||
|     std::ofstream output_file{ temp_path }; | ||||
|     if (!output_file.good()) { | ||||
|         fmt::print(stderr, "Failed to open file for writing: {}\n", temp_path.string() ); | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     if (write_header) { | ||||
|         // Write the file header
 | ||||
|         fmt::print(output_file, | ||||
|             "#include \"recomp.h\"\n" | ||||
|             "#include \"disable_warnings.h\"\n" | ||||
|         "\n" | ||||
|             "\n"); | ||||
|     } | ||||
| 
 | ||||
|     fmt::print(output_file, | ||||
|         "void {}(uint8_t* rdram, recomp_context* ctx) {{\n" | ||||
|         // these variables shouldn't need to be preserved across function boundaries, so make them local for more efficient output
 | ||||
|         "    uint64_t hi = 0, lo = 0, result = 0;\n" | ||||
|  | @ -1070,7 +1050,7 @@ bool RecompPort::recompile_function(const RecompPort::Context& context, const Re | |||
| 
 | ||||
|             // Process the current instruction and check for errors
 | ||||
|             if (process_instruction(context, config, func, stats, skipped_insns, instr_index, instructions, output_file, false, needs_link_branch, num_link_branches, reloc_index, needs_link_branch, is_branch_likely, static_funcs_out) == false) { | ||||
|                 fmt::print(stderr, "Error in recompilation, clearing {}\n", output_path.string()); | ||||
|                 fmt::print(stderr, "Error in recompiling {}, clearing output file\n", func.name); | ||||
|                 output_file.clear(); | ||||
|                 return false; | ||||
|             } | ||||
|  | @ -1093,17 +1073,5 @@ bool RecompPort::recompile_function(const RecompPort::Context& context, const Re | |||
|     // Terminate the function
 | ||||
|     fmt::print(output_file, ";}}\n"); | ||||
|      | ||||
|     output_file.close(); | ||||
| 
 | ||||
|     // If a file of the target name exists and it's identical to the output file, delete the output file.
 | ||||
|     // This prevents updating the existing file so that it doesn't need to be rebuilt.
 | ||||
|     if (std::filesystem::exists(output_path) && compare_files(output_path, temp_path)) { | ||||
|         std::filesystem::remove(temp_path); | ||||
|     } | ||||
|     // Otherwise, rename the new file to the target path.
 | ||||
|     else { | ||||
|         std::filesystem::rename(temp_path, output_path); | ||||
|     } | ||||
| 
 | ||||
|     return true; | ||||
| } | ||||
|  |  | |||
		Loading…
	
	Add table
		
		Reference in a new issue
	
	 Mr-Wiseguy
						Mr-Wiseguy