diff --git a/hipamd/CMakeLists.txt b/hipamd/CMakeLists.txt index e405d06ed6..5c808957ce 100644 --- a/hipamd/CMakeLists.txt +++ b/hipamd/CMakeLists.txt @@ -144,6 +144,13 @@ if (BUILD_HIPIFY_CLANG) add_subdirectory(hipify-clang) endif() +# Build LPL an CA (fat binary generation / fat binary decomposition tools) if +# platform is hcc; do this before the ugly hijacking of the compiler, since no +# HC code is involved. +if (HIP_PLATFORM STREQUAL "hcc") + add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/LPL_CA) +endif () + # Build hip_hcc if platform is hcc if(HIP_PLATFORM STREQUAL "hcc") include_directories(${PROJECT_SOURCE_DIR}/include) @@ -191,7 +198,7 @@ if(HIP_PLATFORM STREQUAL "hcc") src/math_functions.cpp) execute_process(COMMAND ${HCC_HOME}/bin/hcc-config --ldflags OUTPUT_VARIABLE HCC_LD_FLAGS) - set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${HCC_LD_FLAGS} -Wl,-Bsymbolic") + set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${HCC_LD_FLAGS}") #find_package(LLVM HINTS ${HCC_HOME}/compiler/lib/cmake) set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} --amdgpu-target=gfx701 --amdgpu-target=gfx801 --amdgpu-target=gfx802 --amdgpu-target=gfx803 --amdgpu-target=gfx900") if(COMPILE_HIP_ATP_MARKER) diff --git a/hipamd/LPL/CMakeLists.txt b/hipamd/LPL/CMakeLists.txt deleted file mode 100644 index 26e3f6f0de..0000000000 --- a/hipamd/LPL/CMakeLists.txt +++ /dev/null @@ -1,12 +0,0 @@ -add_executable(lpl lpl.cpp) -set_target_properties( - lpl PROPERTIES - CXX_STANDARD 11 - CXX_STANDARD_REQUIRED ON - CXX_EXTENSIONS OFF - RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}) -target_include_directories(lpl PUBLIC ${PROJECT_SOURCE_DIR}/src) -# Install LPL if platform is hcc -if (HIP_PLATFORM STREQUAL "hcc") - install(TARGETS lpl RUNTIME DESTINATION bin) -endif () \ No newline at end of file diff --git a/hipamd/LPL_CA/CMakeLists.txt b/hipamd/LPL_CA/CMakeLists.txt new file mode 100644 index 0000000000..b36d73bbcb --- /dev/null +++ b/hipamd/LPL_CA/CMakeLists.txt @@ -0,0 +1,32 @@ +#-------------------------------------LPL--------------------------------------# +add_executable(lpl lpl.cpp) +set_target_properties( + lpl PROPERTIES + CXX_STANDARD 11 + CXX_STANDARD_REQUIRED ON + CXX_EXTENSIONS OFF + RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}) +target_include_directories(lpl PUBLIC ${PROJECT_SOURCE_DIR}/src) +target_compile_options(lpl PUBLIC -Wall) +target_link_libraries(lpl PUBLIC pthread) + +install(TARGETS lpl RUNTIME DESTINATION bin) +#-------------------------------------LPL--------------------------------------# + +#-------------------------------------CA---------------------------------------# +add_executable(ca ca.cpp ${PROJECT_SOURCE_DIR}/src/code_object_bundle.cpp) +set_target_properties( + ca PROPERTIES + CXX_STANDARD 11 + CXX_STANDARD_REQUIRED ON + CXX_EXTENSIONS OFF + RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}) +target_include_directories(ca SYSTEM PUBLIC ${HSA_PATH}/include) +target_include_directories(ca PUBLIC ${PROJECT_SOURCE_DIR}/src) +find_library( + hsart NAMES libhsa-runtime64.so libhsa-runtime64.so.1 HINTS ${HSA_PATH}/lib) +target_link_libraries(ca PUBLIC ${hsart}) +target_compile_options(ca PUBLIC -Wall) + +install(TARGETS ca RUNTIME DESTINATION bin) +#-------------------------------------CA---------------------------------------# \ No newline at end of file diff --git a/hipamd/LPL_CA/ca.cpp b/hipamd/LPL_CA/ca.cpp new file mode 100644 index 0000000000..485776d427 --- /dev/null +++ b/hipamd/LPL_CA/ca.cpp @@ -0,0 +1,49 @@ +#include "ca.hpp" + +#include +#include +#include +#include +#include +#include + +using namespace clara; +using namespace hip_impl; +using namespace std; + +int main(int argc, char** argv) +{ + try { + bool help = false; + vector inputs; + string targets; + + auto cmd = cmdline_parser(help, inputs, targets); + + const auto r = cmd.parse(Args{argc, argv}); + + if (!r) throw runtime_error{r.errorMessage()}; + + if (help) cout << cmd << endl; + else { + if (inputs.empty()) throw runtime_error{"No inputs specified."}; + + validate_inputs(inputs); + + auto tmp = tokenize_targets(targets); + if (tmp.empty()) { + tmp.assign(amdgpu_targets().cbegin(), amdgpu_targets().cend()); + } + else validate_targets(tmp); + + extract_code_objects(inputs, tmp); + } + } + catch (const exception& ex) { + cerr << ex.what() << endl; + + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} \ No newline at end of file diff --git a/hipamd/LPL_CA/ca.hpp b/hipamd/LPL_CA/ca.hpp new file mode 100644 index 0000000000..8b2a600d6f --- /dev/null +++ b/hipamd/LPL_CA/ca.hpp @@ -0,0 +1,104 @@ +#pragma once + +#include "common.hpp" + +#include "../include/hip/hcc_detail/code_object_bundle.hpp" + +#include "clara/clara.hpp" + +#include +#include +#include +#include +#include +#include + +namespace hip_impl +{ + inline + clara::Parser cmdline_parser( + bool& help, + std::vector& inputs, + std::string& targets) + { + return + clara::Help{help} | + clara::Arg{inputs, "a" + fat_binary_extension() + " etc."}( + "fat binaries which contain the code objects to be extracted; " + "the binary format of the file(s) is documented at: " + "https://reviews.llvm.org/D13909; " + "the code object format is documented at: " + "https://www.llvm.org/docs/AMDGPUUsage.html#code-object.") | + clara::Opt{targets, "gfx803,gfx900 etc."} + ["-t"]["--targets"]( + "targets for which code objects are to be extracted from " + "the fat binary; must be included in the set of processors " + "with ROCm support from " + "https://www.llvm.org/docs/AMDGPUUsage.html#processors."); + } + + inline + std::string make_code_object_file_name( + const std::string& input, const std::string& target) + { + assert(!input.empty() && !target.empty()); + + auto r = input.substr(0, input.find(fat_binary_extension())); + r += '_' + target + code_object_extension(); + + return r; + } + + inline + void extract_code_objects( + const std::vector& inputs, + const std::vector& targets) + { + for (auto&& input : inputs) { + std::ifstream tmp{input}; + std::vector bundle{ + std::istreambuf_iterator{tmp}, + std::istreambuf_iterator{}}; + + Bundled_code_header tmp1{bundle}; + + if (!valid(tmp1)) { + throw std::runtime_error{input + " is not a valid fat binary."}; + } + + for (auto&& target : targets) { + const auto it = std::find_if( + bundles(tmp1).cbegin(), + bundles(tmp1).cend(), + [&](const Bundled_code& x) { + return x.triple.find(target) != std::string::npos; + }); + + if (it == bundles(tmp1).cend()) { + std::cerr << "Warning: " << input + << " does not contain code for the " << target + << " target."; + continue; + } + + std::ofstream out{make_code_object_file_name(input, target)}; + std::copy_n( + it->blob.cbegin(), + it->blob.size(), + std::ostreambuf_iterator{out}); + } + } + } + + inline + void validate_inputs(const std::vector& inputs) + { + const auto it = std::find_if_not( + inputs.cbegin(), inputs.cend(), file_exists); + + if (it != inputs.cend()) { + throw std::runtime_error{ + "Non existent file " + *it + " passed as input."}; + } + } +} \ No newline at end of file diff --git a/hipamd/LPL/clara/clara.hpp b/hipamd/LPL_CA/clara/clara.hpp similarity index 100% rename from hipamd/LPL/clara/clara.hpp rename to hipamd/LPL_CA/clara/clara.hpp diff --git a/hipamd/LPL_CA/common.hpp b/hipamd/LPL_CA/common.hpp new file mode 100644 index 0000000000..a82c1c5a54 --- /dev/null +++ b/hipamd/LPL_CA/common.hpp @@ -0,0 +1,93 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +namespace hip_impl +{ + inline + const std::unordered_set& amdgpu_targets() + { // The evolving list lives at: + // https://www.llvm.org/docs/AMDGPUUsage.html#processors. + static const std::unordered_set r{ + "gfx701", "gfx801", "gfx802", "gfx803", "gfx900"}; + + return r; + } + + inline + const std::string& code_object_extension() + { + static const std::string r{".ffa"}; + + return r; + } + + inline + const std::string& fat_binary_extension() + { + static const std::string r{".adipose"}; + + return r; + } + + inline + bool file_exists(const std::string& path_to) + { + return static_cast(std::ifstream{path_to}); + } + + inline + std::vector tokenize_targets(const std::string& x) + { // TODO: move to regular expressions once we clarify the need to support + // ancient standard library implementations. + if (x.empty()) return {}; + + static constexpr const char valid_characters[] = "gfx0123456789,"; + + if (x.find_first_not_of(valid_characters) != std::string::npos) { + throw std::runtime_error{"Invalid target string: " + x}; + } + + std::vector r; + + auto it = x.cbegin(); + do { + auto it1 = std::find(it, x.cend(), ','); + r.emplace_back(it, it1); + + if (it1 == x.cend()) break; + + it = ++it1; + } while (true); + + return r; + } + + inline + void validate_targets(const std::vector& x) + { + assert(!x.empty()); + + for (auto&& t : x) { + static const std::string digits{"0123456789"}; + static const std::string pre{"gfx"}; + + if (t.find(pre) != 0 || + t.find_first_not_of(digits, pre.size()) != std::string::npos) { + throw std::runtime_error{"Invalid target: " + t}; + } + + if (amdgpu_targets().find(t) == amdgpu_targets().cend()) { + std::cerr << "Warning: target " << t + << " has not been validated yet; it may be invalid." + << std::endl; + } + } + } +} // Namespace hip_impl. \ No newline at end of file diff --git a/hipamd/LPL/lpl.cpp b/hipamd/LPL_CA/lpl.cpp similarity index 100% rename from hipamd/LPL/lpl.cpp rename to hipamd/LPL_CA/lpl.cpp diff --git a/hipamd/LPL/lpl.hpp b/hipamd/LPL_CA/lpl.hpp similarity index 65% rename from hipamd/LPL/lpl.hpp rename to hipamd/LPL_CA/lpl.hpp index f3d0c537b4..e2b157bb1c 100644 --- a/hipamd/LPL/lpl.hpp +++ b/hipamd/LPL_CA/lpl.hpp @@ -1,3 +1,7 @@ +#pragma once + +#include "common.hpp" + #include "clara/clara.hpp" #include "pstreams/pstream.h" #include "../src/elfio/elfio.hpp" @@ -11,29 +15,11 @@ #include #include #include -#include +#include #include namespace hip_impl { - inline - const std::unordered_set& amdgpu_targets() - { // The evolving list lives at: - // https://www.llvm.org/docs/AMDGPUUsage.html#processors. - static const std::unordered_set r{ - "gfx701", "gfx801", "gfx802", "gfx803", "gfx900"}; - - return r; - } - - inline - const std::string& fat_binary_extension() - { - static const std::string r{".adipose"}; - - return r; - } - inline const std::string& kernel_section() { @@ -47,16 +33,20 @@ namespace hip_impl { static constexpr const char self[] = "/proc/self/exe"; - static std::string r(PATH_MAX, '\0'); + static std::string r; static std::once_flag f; std::call_once(f, []() { - decltype(readlink(self, &r.front(), r.size())) read_cnt; - do { - read_cnt = readlink(self, &r.front(), r.size()); - } while (read_cnt == -1); + using N = decltype(readlink(self, &r.front(), r.size())); - r.resize(read_cnt); + constexpr decltype(r.size()) max_path_sz{PATH_MAX}; + N read_cnt; + do { + r.resize(std::max(2 * r.size(), max_path_sz)); + read_cnt = readlink(self, &r.front(), r.size()); + } while (read_cnt == -1 && r.size() < r.max_size()); + + r.resize(std::max(read_cnt, N{0})); }); return r; @@ -155,12 +145,6 @@ namespace hip_impl copy_kernel_section_to_fat_binary(*tmp, output); } - inline - bool file_exists(const std::string& path_to) - { - return static_cast(std::ifstream{path_to}); - } - inline bool hipcc_and_lpl_colocated() { @@ -169,55 +153,6 @@ namespace hip_impl return file_exists(path_to_hipcc()); } - inline - std::vector tokenize_targets(const std::string& x) - { // TODO: move to regular expressions once we clarify the need to support - // ancient standard library implementations. - if (x.empty()) return {}; - - static constexpr const char valid_characters[] = "gfx0123456789,"; - - if (x.find_first_not_of(valid_characters) != std::string::npos) { - throw std::runtime_error{"Invalid target string: " + x}; - } - - std::vector r; - - auto it = x.cbegin(); - do { - auto it1 = std::find(it, x.cend(), ','); - r.emplace_back(it, it1); - - if (it1 == x.cend()) break; - - it = ++it1; - } while (true); - - return r; - } - - inline - void validate_targets(const std::vector& x) - { - assert(!x.empty()); - - for (auto&& t : x) { - static const std::string digits{"0123456789"}; - static const std::string pre{"gfx"}; - - if (t.find(pre) != 0 || - t.find_first_not_of(digits, pre.size()) != std::string::npos) { - throw std::runtime_error{"Invalid target: " + t}; - } - - if (amdgpu_targets().find(t) == amdgpu_targets().cend()) { - std::cerr << "Warning: target " << t - << " has not been validated yet; it may be invalid." - << std::endl; - } - } - } - inline clara::Parser cmdline_parser( bool& help, @@ -239,8 +174,8 @@ namespace hip_impl "inputs for compilation; must contain valid C++ code.") | clara::Opt{targets, "gfx803,gfx900 etc."} ["-t"]["--targets"]( - "targets for AMDGPU lowering; must be one of the processors" - " with ROCm support from " + "targets for AMDGPU lowering; must be included in the set " + "of processors with ROCm support from " "https://www.llvm.org/docs/AMDGPUUsage.html#processors."); } } \ No newline at end of file diff --git a/hipamd/LPL/pstreams/pstream.h b/hipamd/LPL_CA/pstreams/pstream.h similarity index 100% rename from hipamd/LPL/pstreams/pstream.h rename to hipamd/LPL_CA/pstreams/pstream.h