Skip to content

Commit

Permalink
bintr: Keep execute segment referenced during compilation
Browse files Browse the repository at this point in the history
  • Loading branch information
fwsGonzo committed Jul 4, 2024
1 parent 7e5d677 commit a17f6b3
Show file tree
Hide file tree
Showing 4 changed files with 37 additions and 27 deletions.
6 changes: 3 additions & 3 deletions lib/libriscv/cpu.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ namespace riscv

// Binary translation functions
int load_translation(const MachineOptions<W>&, std::string* filename, DecodedExecuteSegment<W>&) const;
void try_translate(const MachineOptions<W>&, const std::string&, DecodedExecuteSegment<W>&, address_t pc, address_t endpc) const;
void try_translate(const MachineOptions<W>&, const std::string&, std::shared_ptr<DecodedExecuteSegment<W>>&, address_t pc, address_t endpc) const;

void reset();
void reset_stack_pointer() noexcept;
Expand Down Expand Up @@ -182,8 +182,8 @@ namespace riscv

#ifdef RISCV_BINARY_TRANSLATION
std::vector<TransMapping<W>> emit(std::string& code, const TransInfo<W>&) const;
void activate_dylib(const MachineOptions<W>&, DecodedExecuteSegment<W>&, void*, bool, bool) const RISCV_INTERNAL;
bool initialize_translated_segment(DecodedExecuteSegment<W>&, void*, bool) const RISCV_INTERNAL;
static void activate_dylib(const MachineOptions<W>&, DecodedExecuteSegment<W>&, void*, void*, bool, bool) RISCV_INTERNAL;
static bool initialize_translated_segment(DecodedExecuteSegment<W>&, void*, void*, bool) RISCV_INTERNAL;
#endif
static_assert((W == 4 || W == 8 || W == 16), "Must be either 32-bit, 64-bit or 128-bit ISA");
};
Expand Down
9 changes: 5 additions & 4 deletions lib/libriscv/decoder_cache.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -267,8 +267,9 @@ namespace riscv
template <int W> RISCV_INTERNAL
void Memory<W>::generate_decoder_cache(
[[maybe_unused]] const MachineOptions<W>& options,
DecodedExecuteSegment<W>& exec)
std::shared_ptr<DecodedExecuteSegment<W>>& shared_segment)
{
auto& exec = *shared_segment;
if (exec.exec_end() < exec.exec_begin())
throw MachineException(INVALID_PROGRAM, "Execute segment was invalid");

Expand Down Expand Up @@ -320,7 +321,7 @@ namespace riscv
if (must_translate)
{
machine().cpu.try_translate(
options, bintr_filename, exec, addr, addr + len);
options, bintr_filename, shared_segment, addr, addr + len);
}
} // W != 16
#endif
Expand Down Expand Up @@ -504,7 +505,7 @@ namespace riscv
// Store the hash in the decoder cache
free_slot->set_crc32c_hash(hash);

this->generate_decoder_cache(options, *free_slot);
this->generate_decoder_cache(options, free_slot);

// Share the execute segment
shared_execute_segments<W>.get_segment(hash).unlocked_set(free_slot);
Expand All @@ -515,7 +516,7 @@ namespace riscv
// Store the hash in the decoder cache
free_slot->set_crc32c_hash(hash);

this->generate_decoder_cache(options, *free_slot);
this->generate_decoder_cache(options, free_slot);
}

return *free_slot;
Expand Down
2 changes: 1 addition & 1 deletion lib/libriscv/memory.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,7 @@ namespace riscv
void binary_loader(const MachineOptions<W>&);
void binary_load_ph(const MachineOptions<W>&, const typename Elf::ProgramHeader*, address_t vaddr);
void serialize_execute_segment(const MachineOptions<W>&, const typename Elf::ProgramHeader*, address_t vaddr);
void generate_decoder_cache(const MachineOptions<W>&, DecodedExecuteSegment<W>&);
void generate_decoder_cache(const MachineOptions<W>&, std::shared_ptr<DecodedExecuteSegment<W>>&);
// Machine copy-on-write fork
void machine_loader(const Machine<W>&, const MachineOptions<W>&);

Expand Down
47 changes: 28 additions & 19 deletions lib/libriscv/tr_translate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ namespace riscv
template <int W>
using binary_translation_init_func = void (*)(const CallbackTable<W>&, void*);
template <int W>
static CallbackTable<W> create_bintr_callback_table(const CPU<W>& cpu);
static CallbackTable<W> create_bintr_callback_table(DecodedExecuteSegment<W>&);

// Translations that are embeddable in the binary will be added as a source
// file directly in the project, which allows it to run global constructors.
Expand Down Expand Up @@ -220,7 +220,7 @@ int CPU<W>::load_translation(const MachineOptions<W>& options,
if (options.verbose_loader) {
printf("Found embedded translation for hash %08X\n", checksum);
}
*translation.api_table = create_bintr_callback_table(*this);
*translation.api_table = create_bintr_callback_table(exec);
exec.create_mappings(translation.nmappings);
for (unsigned i = 0; i < translation.nmappings; i++) {
const auto& mapping = translation.mappings[i];
Expand Down Expand Up @@ -307,7 +307,8 @@ int CPU<W>::load_translation(const MachineOptions<W>& options,
return 1;
}

this->activate_dylib(options, exec, dylib, false, false);
void* arena = machine().memory.memory_arena_ptr_ref();
this->activate_dylib(options, exec, dylib, arena, false, false);

if (options.translate_timing) {
TIME_POINT(t10);
Expand Down Expand Up @@ -345,7 +346,7 @@ static bool is_stopping_instruction(rv32i_instruction instr) {
template <int W>
void CPU<W>::try_translate(const MachineOptions<W>& options,
const std::string& filename,
DecodedExecuteSegment<W>& exec, address_t basepc, address_t endbasepc) const
std::shared_ptr<DecodedExecuteSegment<W>>& shared_segment, address_t basepc, address_t endbasepc) const
{
// Run with VERBOSE=1 to see command and output
const bool verbose = options.verbose_loader;
Expand All @@ -355,6 +356,8 @@ void CPU<W>::try_translate(const MachineOptions<W>& options,
if (!options.translate_invoke_compiler)
return;

auto& exec = *shared_segment;

address_t gp = 0;
TIME_POINT(t0);
if constexpr (SCAN_FOR_GP) {
Expand Down Expand Up @@ -593,11 +596,14 @@ VISIBLE const struct Mapping mappings[] = {

const auto defines = create_defines_for(machine(), options);
const bool live_patch = options.translate_background_callback != nullptr;
void* arena = machine().memory.memory_arena_ptr_ref();

// Compilation step
std::function<void()> compilation_step =
[this, options, defines = std::move(defines), code = std::move(code), footer = std::move(footer), filename, exec = &exec, live_patch] () mutable
[this, options, defines = std::move(defines), code = std::move(code), footer = std::move(footer), filename, arena, live_patch, shared_segment = shared_segment]
{
void* dylib = nullptr;
auto* exec = shared_segment.get();
// Final shared library loadable code w/footer
const std::string shared_library_code = code + footer;

Expand Down Expand Up @@ -647,12 +653,12 @@ VISIBLE const struct Mapping mappings[] = {
}

if (!exec->is_binary_translated()) {
this->activate_dylib(options, *exec, dylib, libtcc_enabled, live_patch);
this->activate_dylib(options, *exec, dylib, arena, libtcc_enabled, live_patch);
}

if constexpr (!libtcc_enabled) {
if (!options.translation_cache) {
// Delete the program if the shared ELF is unwanted
// Delete the shared object if it is unwanted
unlink(filename.c_str());
}
}
Expand Down Expand Up @@ -714,11 +720,11 @@ VISIBLE const struct Mapping mappings[] = {
}

template <int W>
void CPU<W>::activate_dylib(const MachineOptions<W>& options, DecodedExecuteSegment<W>& exec, void* dylib, bool is_libtcc, bool live_patch) const
void CPU<W>::activate_dylib(const MachineOptions<W>& options, DecodedExecuteSegment<W>& exec, void* dylib, void* arena, bool is_libtcc, bool live_patch)
{
TIME_POINT(t11);

if (!initialize_translated_segment(exec, dylib, is_libtcc))
if (!initialize_translated_segment(exec, dylib, arena, is_libtcc))
{
if constexpr (!libtcc_enabled) {
// only warn when translation is not already disabled
Expand Down Expand Up @@ -791,6 +797,9 @@ void CPU<W>::activate_dylib(const MachineOptions<W>& options, DecodedExecuteSegm
auto d = *dd;
d.set_bytecode(RV32I_BC_FUNCBLOCK);
d.idxend = 0; // 0(+1) instructions to next block
#ifdef RISCV_EXT_C
d.icount = 0; // 0 + 1 - 0 == 1 instruction
#endif
d.instr = instr.whole;
dd->atomic_overwrite(d);
addr_patch += instr.length();
Expand Down Expand Up @@ -843,7 +852,7 @@ void CPU<W>::activate_dylib(const MachineOptions<W>& options, DecodedExecuteSegm
}

template <int W>
CallbackTable<W> create_bintr_callback_table(const CPU<W>& cpu)
CallbackTable<W> create_bintr_callback_table(DecodedExecuteSegment<W>&)
{
return CallbackTable<W>{
.mem_read = [] (CPU<W>& cpu, address_type<W> addr, unsigned size) -> address_type<W> {
Expand Down Expand Up @@ -911,7 +920,7 @@ CallbackTable<W> create_bintr_callback_table(const CPU<W>& cpu)
(void)cpu; (void)addr; (void)vd;
#endif
},
.syscalls = cpu.machine().syscall_handlers.data(),
.syscalls = Machine<W>::syscall_handlers.data(),
.system_call = [] (CPU<W>& cpu, int sysno) -> int {
try {
const auto current_pc = cpu.registers().pc;
Expand Down Expand Up @@ -1039,7 +1048,7 @@ CallbackTable<W> create_bintr_callback_table(const CPU<W>& cpu)
}

template <int W>
bool CPU<W>::initialize_translated_segment(DecodedExecuteSegment<W>&, void* dylib, bool is_libtcc) const
bool CPU<W>::initialize_translated_segment(DecodedExecuteSegment<W>& exec, void* dylib, void* arena, bool is_libtcc)
{
// NOTE: At some point this must be able to duplicate the dylib
// in order to be able to share execute segments across machines.
Expand All @@ -1051,7 +1060,7 @@ bool CPU<W>::initialize_translated_segment(DecodedExecuteSegment<W>&, void* dyli

// Map the API callback table
auto func = (binary_translation_init_func<W>) ptr;
func(create_bintr_callback_table<W>(*this), machine().memory.memory_arena_ptr_ref());
func(create_bintr_callback_table<W>(exec), arena);

return true;
}
Expand All @@ -1066,17 +1075,17 @@ std::string MachineOptions<W>::translation_filename(const std::string& prefix, u
}

#ifdef RISCV_32I
template void CPU<4>::try_translate(const MachineOptions<4>&, const std::string&, DecodedExecuteSegment<4>&, address_t, address_t) const;
template void CPU<4>::try_translate(const MachineOptions<4>&, const std::string&, std::shared_ptr<DecodedExecuteSegment<4>>&, address_t, address_t) const;
template int CPU<4>::load_translation(const MachineOptions<4>&, std::string*, DecodedExecuteSegment<4>&) const;
template bool CPU<4>::initialize_translated_segment(DecodedExecuteSegment<4>&, void* dylib, bool) const;
template void CPU<4>::activate_dylib(const MachineOptions<4>&, DecodedExecuteSegment<4>&, void*, bool, bool) const;
template bool CPU<4>::initialize_translated_segment(DecodedExecuteSegment<4>&, void* dylib, void*, bool);
template void CPU<4>::activate_dylib(const MachineOptions<4>&, DecodedExecuteSegment<4>&, void*, void*, bool, bool);
template std::string MachineOptions<4>::translation_filename(const std::string&, uint32_t, const std::string&);
#endif
#ifdef RISCV_64I
template void CPU<8>::try_translate(const MachineOptions<8>&, const std::string&, DecodedExecuteSegment<8>&, address_t, address_t) const;
template void CPU<8>::try_translate(const MachineOptions<8>&, const std::string&, std::shared_ptr<DecodedExecuteSegment<8>>&, address_t, address_t) const;
template int CPU<8>::load_translation(const MachineOptions<8>&, std::string*, DecodedExecuteSegment<8>&) const;
template bool CPU<8>::initialize_translated_segment(DecodedExecuteSegment<8>&, void* dylib, bool) const;
template void CPU<8>::activate_dylib(const MachineOptions<8>&, DecodedExecuteSegment<8>&, void*, bool, bool) const;
template bool CPU<8>::initialize_translated_segment(DecodedExecuteSegment<8>&, void* dylib, void*, bool);
template void CPU<8>::activate_dylib(const MachineOptions<8>&, DecodedExecuteSegment<8>&, void*, void*, bool, bool);
template std::string MachineOptions<8>::translation_filename(const std::string&, uint32_t, const std::string&);
#endif

Expand Down

0 comments on commit a17f6b3

Please sign in to comment.