Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 9 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -109,15 +109,22 @@ if(DOLRECOMP_ENABLE_LLVM)
target_link_libraries(dr_llvm PRIVATE
"${DOLRECOMP_LLVM_SHARED_IMPORT}")
else()
# AArch64 alongside the host target so an x86-64 build can emit
# for the Pi. Linking it costs binary size on a build machine and
# nothing at runtime; without it a cross target fails at
# lookupTarget with "No available targets are compatible", which
# reads like a bad triple rather than a missing component.
llvm_map_components_to_libnames(DOLRECOMP_LLVM_LIBS
Core Support Analysis Passes Target MC native nativecodegen)
Core Support Analysis Passes Target MC native nativecodegen
AArch64CodeGen AArch64AsmParser AArch64Desc AArch64Info)
target_link_libraries(dr_llvm PRIVATE ${DOLRECOMP_LLVM_LIBS})
endif()
elseif(TARGET LLVM)
target_link_libraries(dr_llvm PRIVATE LLVM)
else()
llvm_map_components_to_libnames(DOLRECOMP_LLVM_LIBS
Core Support Analysis Passes Target MC native nativecodegen)
Core Support Analysis Passes Target MC native nativecodegen
AArch64CodeGen AArch64AsmParser AArch64Desc AArch64Info)
target_link_libraries(dr_llvm PRIVATE ${DOLRECOMP_LLVM_LIBS})
endif()
endif()
Expand Down
19 changes: 17 additions & 2 deletions src/backend/llvm/llvm_backend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,15 @@ extern "C" bool dolllvm_emit_object(const DolIRModule *source,
llvm::InitializeNativeTarget();
llvm::InitializeNativeTargetAsmPrinter();
llvm::InitializeNativeTargetAsmParser();
// AArch64 as well, so an x86-64 build machine can emit objects for an
// AArch64 host. Relaxing the triple guard alone is not enough: a target
// that was never registered is simply absent from the registry, and
// lookupTarget reports it as an unsupported triple.
LLVMInitializeAArch64Target();
LLVMInitializeAArch64TargetInfo();
LLVMInitializeAArch64TargetMC();
LLVMInitializeAArch64AsmPrinter();
LLVMInitializeAArch64AsmParser();
return true;
}();
(void)initialized;
Expand All @@ -247,11 +256,17 @@ extern "C" bool dolllvm_emit_object(const DolIRModule *source,
std::string tripleName =
resolveTriple(options ? options->target_triple : nullptr);
const llvm::Triple triple(tripleName);
if (triple.getArch() != llvm::Triple::x86_64 ||
// AArch64 is accepted alongside x86-64. Nothing in the function emitter or
// in the memory/runtime lowering is x86-specific -- there is no inline asm
// and functions are emitted with CallingConv::C -- so the IR is
// target-neutral and LLVM codegens AArch64 objects directly.
const bool arch_supported = triple.getArch() == llvm::Triple::x86_64 ||
triple.getArch() == llvm::Triple::aarch64;
if (!arch_supported ||
(!triple.isOSLinux() && !triple.isOSWindows())) {
fprintf(
diagnostics,
"dolllvm: supported production targets are x86-64 Linux and Windows\n");
"dolllvm: supported production targets are x86-64 and AArch64 Linux, and x86-64 Windows\n");
return false;
}

Expand Down
27 changes: 27 additions & 0 deletions tests/test_llvm_backend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,33 @@ int main(int argc, char** argv) {
std::istreambuf_iterator<char>());
CHECK(irText.find("define hidden void @func_80001000") !=
std::string::npos);

// The same module emitted for AArch64, which is a cross-compile on every
// host this suite currently runs on. Accepting the triple is not enough on
// its own: if the AArch64 target is not registered, lookupTarget cannot see
// it and reports it as an unsupported triple, so emission fails here rather
// than producing a wrong object.
const std::string aarch64Path = std::string(argv[1]) + ".aarch64.o";
DolLLVMOptions aarch64Options = options;
aarch64Options.emit_ir = 0;
aarch64Options.ir_path = nullptr;
aarch64Options.target_triple = "aarch64-unknown-linux-gnu";
CHECK(dolllvm_emit_object(&module, aarch64Path.c_str(), &aarch64Options,
stderr));
FILE* aarch64Object = std::fopen(aarch64Path.c_str(), "rb");
CHECK(aarch64Object != nullptr);
unsigned char header[20]{};
const bool headerRead =
std::fread(header, 1, sizeof(header), aarch64Object) == sizeof(header);
std::fclose(aarch64Object);
CHECK(headerRead);
// An explicit triple selects the object format too, so this is ELF even on
// a Windows host. e_machine sits at offset 18 and is EM_AARCH64 (183).
CHECK(header[0] == 0x7f && header[1] == 'E' && header[2] == 'L' &&
header[3] == 'F');
CHECK(header[4] == 2); // ELFCLASS64
CHECK(header[5] == 1); // ELFDATA2LSB
CHECK(header[18] == 0xB7 && header[19] == 0x00);
dolir_module_free(&module);
return 0;
}
Loading