Unverified Commit 91c9ebbc authored by Paul Fultz II's avatar Paul Fultz II Committed by GitHub
Browse files

Add option to compile with hiprtc (#892)

* Add hiprtc compile option
* Add cross compile test
* Update error reporting
* Add tests for errors and warnings
* Fix tidy warning
* Add comment to ifdefs
* Skip null character at end of log
* Assert there is null at the end
parent a8d86615
...@@ -49,12 +49,13 @@ inline std::string make_source_context(const std::string& file, int line, const ...@@ -49,12 +49,13 @@ inline std::string make_source_context(const std::string& file, int line, const
return file + ":" + std::to_string(line) + ": " + fname; return file + ":" + std::to_string(line) + ": " + fname;
} }
// NOLINTNEXTLINE
#define MIGRAPHX_MAKE_SOURCE_CTX() migraphx::make_source_context(__FILE__, __LINE__, __func__)
/** /**
* @brief Throw an exception with context information * @brief Throw an exception with context information
*/ */
#define MIGRAPHX_THROW(...) \ #define MIGRAPHX_THROW(...) throw migraphx::make_exception(MIGRAPHX_MAKE_SOURCE_CTX(), __VA_ARGS__)
throw migraphx::make_exception(migraphx::make_source_context(__FILE__, __LINE__, __func__), \
__VA_ARGS__)
} // namespace MIGRAPHX_INLINE_NS } // namespace MIGRAPHX_INLINE_NS
} // namespace migraphx } // namespace migraphx
......
...@@ -284,6 +284,10 @@ if(MIGRAPHX_ENABLE_MLIR) ...@@ -284,6 +284,10 @@ if(MIGRAPHX_ENABLE_MLIR)
target_link_libraries(migraphx_gpu PUBLIC ${LIBMLIRMIOPEN}) target_link_libraries(migraphx_gpu PUBLIC ${LIBMLIRMIOPEN})
endif() endif()
set(MIGRAPHX_USE_HIPRTC OFF CACHE BOOL "")
if(MIGRAPHX_USE_HIPRTC)
target_compile_definitions(migraphx_gpu PRIVATE -DMIGRAPHX_USE_HIPRTC=1)
else()
# Get flags needed to compile hip # Get flags needed to compile hip
include(TargetFlags) include(TargetFlags)
target_flags(HIP_COMPILER_FLAGS hip::device) target_flags(HIP_COMPILER_FLAGS hip::device)
...@@ -296,7 +300,9 @@ target_compile_definitions(migraphx_gpu PRIVATE ...@@ -296,7 +300,9 @@ target_compile_definitions(migraphx_gpu PRIVATE
"-DMIGRAPHX_HIP_COMPILER_FLAGS=${HIP_COMPILER_FLAGS}" "-DMIGRAPHX_HIP_COMPILER_FLAGS=${HIP_COMPILER_FLAGS}"
"-DMIGRAPHX_OFFLOADBUNDLER_BIN=${MIGRAPHX_OFFLOADBUNDLER_BIN}" "-DMIGRAPHX_OFFLOADBUNDLER_BIN=${MIGRAPHX_OFFLOADBUNDLER_BIN}"
"-DMIGRAPHX_EXTRACT_KERNEL=${MIGRAPHX_EXTRACT_KERNEL}" "-DMIGRAPHX_EXTRACT_KERNEL=${MIGRAPHX_EXTRACT_KERNEL}"
"-DMIGRAPHX_USE_HIPRTC=0"
) )
endif()
# Check miopen find mode api # Check miopen find mode api
include(CheckLibraryExists) include(CheckLibraryExists)
......
#include <migraphx/gpu/compile_hip.hpp> #include <migraphx/gpu/compile_hip.hpp>
#include <migraphx/errors.hpp> #include <migraphx/errors.hpp>
#include <migraphx/stringutils.hpp> #include <migraphx/stringutils.hpp>
#include <migraphx/compile_src.hpp>
#include <migraphx/process.hpp>
#include <migraphx/env.hpp> #include <migraphx/env.hpp>
#include <cassert> #include <cassert>
#include <iostream>
#if MIGRAPHX_USE_HIPRTC
#include <hip/hiprtc.h>
#include <migraphx/manage_ptr.hpp>
#include <migraphx/env.hpp>
#else
#include <migraphx/compile_src.hpp>
#include <migraphx/process.hpp>
#endif
namespace migraphx { namespace migraphx {
inline namespace MIGRAPHX_INLINE_NS { inline namespace MIGRAPHX_INLINE_NS {
namespace gpu { namespace gpu {
MIGRAPHX_DECLARE_ENV_VAR(MIGRAPHX_GPU_DEBUG);
MIGRAPHX_DECLARE_ENV_VAR(MIGRAPHX_GPU_OPTIMIZE);
#if MIGRAPHX_USE_HIPRTC
MIGRAPHX_DECLARE_ENV_VAR(MIGRAPHX_TRACE_HIPRTC)
std::string hiprtc_error(hiprtcResult err, const std::string& msg)
{
return "hiprtc: " + (hiprtcGetErrorString(err) + (": " + msg));
}
void hiprtc_check_error(hiprtcResult err, const std::string& msg, const std::string& ctx)
{
if(err != HIPRTC_SUCCESS)
throw make_exception(ctx, hiprtc_error(err, msg));
}
#define MIGRAPHX_HIPRTC(...) \
hiprtc_check_error(__VA_ARGS__, #__VA_ARGS__, MIGRAPHX_MAKE_SOURCE_CTX())
#define MIGRAPHX_HIPRTC_THROW(error, msg) MIGRAPHX_THROW(hiprtc_error(error, msg))
// Workaround hiprtc's broken API
void hiprtc_program_destroy(hiprtcProgram prog) { hiprtcDestroyProgram(&prog); }
using hiprtc_program_ptr = MIGRAPHX_MANAGE_PTR(hiprtcProgram, hiprtc_program_destroy);
template <class... Ts>
hiprtc_program_ptr hiprtc_program_create(Ts... xs)
{
hiprtcProgram prog = nullptr;
auto result = hiprtcCreateProgram(&prog, xs...);
hiprtc_program_ptr p{prog};
if(result != HIPRTC_SUCCESS)
MIGRAPHX_HIPRTC_THROW(result, "Create program failed.");
return p;
}
struct hiprtc_program
{
struct string_array
{
std::vector<std::string> strings{};
std::vector<const char*> c_strs{};
string_array() {}
string_array(const string_array&) = delete;
std::size_t size() const { return strings.size(); }
const char** data() { return c_strs.data(); }
void push_back(std::string s)
{
strings.push_back(std::move(s));
c_strs.push_back(strings.back().c_str());
}
};
hiprtc_program_ptr prog = nullptr;
string_array headers{};
string_array include_names{};
std::string cpp_src = "";
std::string cpp_name = "";
hiprtc_program(const std::vector<src_file>& srcs)
{
for(auto&& src : srcs)
{
std::string content{src.content.first, src.content.second};
std::string path = src.path.string();
if(src.path.extension().string() == ".cpp")
{
cpp_src = std::move(content);
cpp_name = std::move(path);
}
else
{
headers.push_back(std::move(content));
include_names.push_back(std::move(path));
}
}
prog = hiprtc_program_create(cpp_src.c_str(),
cpp_name.c_str(),
headers.size(),
headers.data(),
include_names.data());
}
void compile(const std::vector<std::string>& options)
{
if(enabled(MIGRAPHX_TRACE_HIPRTC{}))
std::cout << "hiprtc " << join_strings(options, " ") << " " << cpp_name << std::endl;
std::vector<const char*> c_options;
std::transform(options.begin(),
options.end(),
std::back_inserter(c_options),
[](const std::string& s) { return s.c_str(); });
auto result = hiprtcCompileProgram(prog.get(), c_options.size(), c_options.data());
std::cerr << log() << std::endl;
if(result != HIPRTC_SUCCESS)
MIGRAPHX_HIPRTC_THROW(result, "Compilation failed.");
}
std::string log()
{
std::size_t n = 0;
MIGRAPHX_HIPRTC(hiprtcGetProgramLogSize(prog.get(), &n));
if(n < 2)
return {};
std::vector<char> buffer(n);
MIGRAPHX_HIPRTC(hiprtcGetProgramLog(prog.get(), buffer.data()));
assert(buffer.back() == 0);
return {buffer.begin(), buffer.end() - 1};
}
std::vector<char> get_code_obj()
{
std::size_t n = 0;
MIGRAPHX_HIPRTC(hiprtcGetCodeSize(prog.get(), &n));
std::vector<char> buffer(n);
MIGRAPHX_HIPRTC(hiprtcGetCode(prog.get(), buffer.data()));
return buffer;
}
};
std::vector<std::vector<char>>
compile_hip_src(const std::vector<src_file>& srcs, std::string params, const std::string& arch)
{
hiprtc_program prog(srcs);
auto options = split_string(params, ' ');
if(enabled(MIGRAPHX_GPU_DEBUG{}))
options.push_back("-DMIGRAPHX_DEBUG");
if(std::none_of(options.begin(), options.end(), [](const std::string& s) {
return starts_with(s, "--std=") or starts_with(s, "-std=");
}))
options.push_back("-std=c++17");
options.push_back("-fno-gpu-rdc");
options.push_back(" -O" + string_value_of(MIGRAPHX_GPU_OPTIMIZE{}, "3"));
options.push_back("-Wno-cuda-compat");
options.push_back("--cuda-gpu-arch=" + arch);
prog.compile(options);
return {prog.get_code_obj()};
}
#else // MIGRAPHX_USE_HIPRTC
bool is_hcc_compiler() bool is_hcc_compiler()
{ {
static const auto result = ends_with(MIGRAPHX_STRINGIZE(MIGRAPHX_HIP_COMPILER), "hcc"); static const auto result = ends_with(MIGRAPHX_STRINGIZE(MIGRAPHX_HIP_COMPILER), "hcc");
...@@ -22,9 +177,6 @@ bool is_hip_clang_compiler() ...@@ -22,9 +177,6 @@ bool is_hip_clang_compiler()
return result; return result;
} }
MIGRAPHX_DECLARE_ENV_VAR(MIGRAPHX_GPU_DEBUG);
MIGRAPHX_DECLARE_ENV_VAR(MIGRAPHX_GPU_OPTIMIZE);
std::vector<std::vector<char>> std::vector<std::vector<char>>
compile_hip_src(const std::vector<src_file>& srcs, std::string params, const std::string& arch) compile_hip_src(const std::vector<src_file>& srcs, std::string params, const std::string& arch)
{ {
...@@ -78,6 +230,8 @@ compile_hip_src(const std::vector<src_file>& srcs, std::string params, const std ...@@ -78,6 +230,8 @@ compile_hip_src(const std::vector<src_file>& srcs, std::string params, const std
return {compiler.compile(srcs)}; return {compiler.compile(srcs)};
} }
#endif // MIGRAPHX_USE_HIPRTC
} // namespace gpu } // namespace gpu
} // namespace MIGRAPHX_INLINE_NS } // namespace MIGRAPHX_INLINE_NS
} // namespace migraphx } // namespace migraphx
...@@ -88,7 +88,6 @@ operation compile_hip_code_object(const std::string& content, hip_compile_option ...@@ -88,7 +88,6 @@ operation compile_hip_code_object(const std::string& content, hip_compile_option
std::make_pair(args_hpp.data(), args_hpp.data() + args_hpp.size())}); std::make_pair(args_hpp.data(), args_hpp.data() + args_hpp.size())});
options.params += " -DMIGRAPHX_NGLOBAL=" + std::to_string(options.global); options.params += " -DMIGRAPHX_NGLOBAL=" + std::to_string(options.global);
options.params += " -DMIGRAPHX_NLOCAL=" + std::to_string(options.local); options.params += " -DMIGRAPHX_NLOCAL=" + std::to_string(options.local);
options.params += " -I.";
auto cos = compile_hip_src(srcs, std::move(options.params), get_device_name()); auto cos = compile_hip_src(srcs, std::move(options.params), get_device_name());
if(cos.size() != 1) if(cos.size() != 1)
MIGRAPHX_THROW("No code object"); MIGRAPHX_THROW("No code object");
......
...@@ -70,6 +70,43 @@ int main() {} ...@@ -70,6 +70,43 @@ int main() {}
)__migraphx__"; )__migraphx__";
// NOLINTNEXTLINE
const std::string check_define = R"__migraphx__(
#ifndef __DEFINE__
#error __DEFINE__ was not defined
#endif
int main() {}
)__migraphx__";
// NOLINTNEXTLINE
const std::string unused_param = R"__migraphx__(
extern "C" {
__global__ void kernel(void* x, void* y)
{}
}
int main() {}
)__migraphx__";
// NOLINTNEXTLINE
const std::string incorrect_program = R"__migraphx__(
extern "C" {
__global__ void kernel(void* x)
{
x += y;
}
}
int main() {}
)__migraphx__";
migraphx::src_file make_src_file(const std::string& name, const std::string& content) migraphx::src_file make_src_file(const std::string& name, const std::string& content)
{ {
return {name, std::make_pair(content.data(), content.data() + content.size())}; return {name, std::make_pair(content.data(), content.data() + content.size())};
...@@ -92,6 +129,41 @@ TEST_CASE(simple_compile_hip) ...@@ -92,6 +129,41 @@ TEST_CASE(simple_compile_hip)
EXPECT(migraphx::all_of(data, [](auto x) { return x == 2; })); EXPECT(migraphx::all_of(data, [](auto x) { return x == 2; }));
} }
auto check_target(const std::string& arch)
{
auto define = "__" + arch + "__";
auto content = migraphx::replace_string(check_define, "__DEFINE__", define);
return migraphx::gpu::compile_hip_src({make_src_file("main.cpp", content)}, "", arch);
}
TEST_CASE(compile_target)
{
EXPECT(not check_target("gfx900").empty());
EXPECT(not check_target("gfx906").empty());
}
TEST_CASE(compile_errors)
{
EXPECT(test::throws([&] {
migraphx::gpu::compile_hip_src(
{make_src_file("main.cpp", incorrect_program)}, "", migraphx::gpu::get_device_name());
}));
}
TEST_CASE(compile_warnings)
{
auto compile = [](const std::string& params) {
return migraphx::gpu::compile_hip_src(
{make_src_file("main.cpp", unused_param)}, params, migraphx::gpu::get_device_name());
};
EXPECT(not compile("").empty());
EXPECT(not compile("-Wunused-parameter -Wno-error").empty());
EXPECT(not compile("-Wno-unused-parameter -Werror").empty());
EXPECT(test::throws([&] { compile("-Werror=unused-parameter"); }));
EXPECT(test::throws([&] { compile("-Wunused-parameter -Werror"); }));
}
TEST_CASE(code_object_hip) TEST_CASE(code_object_hip)
{ {
auto binaries = migraphx::gpu::compile_hip_src( auto binaries = migraphx::gpu::compile_hip_src(
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment