compile_hip.cpp 7.77 KB
Newer Older
Paul Fultz II's avatar
Paul Fultz II committed
1
2
#include <migraphx/gpu/compile_hip.hpp>
#include <migraphx/errors.hpp>
3
#include <migraphx/stringutils.hpp>
Shucai Xiao's avatar
Shucai Xiao committed
4
#include <migraphx/ranges.hpp>
5
#include <migraphx/env.hpp>
Paul Fultz II's avatar
Paul Fultz II committed
6
#include <cassert>
7
8
9
10
11
12
13
14
15
16
#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
Paul Fultz II's avatar
Paul Fultz II committed
17
18
19
20
21

namespace migraphx {
inline namespace MIGRAPHX_INLINE_NS {
namespace gpu {

22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
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;

Shucai Xiao's avatar
Shucai Xiao committed
70
        int size() const { return strings.size(); }
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127

        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()
    {
Shucai Xiao's avatar
Shucai Xiao committed
128
        int n = 0;
129
130
131
132
133
134
135
136
137
138
139
        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()
    {
Shucai Xiao's avatar
Shucai Xiao committed
140
        int n = 0;
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
        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

Paul Fultz II's avatar
Paul Fultz II committed
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
bool is_hcc_compiler()
{
    static const auto result = ends_with(MIGRAPHX_STRINGIZE(MIGRAPHX_HIP_COMPILER), "hcc");
    return result;
}

bool is_hip_clang_compiler()
{
    static const auto result = ends_with(MIGRAPHX_STRINGIZE(MIGRAPHX_HIP_COMPILER), "clang++");
    return result;
}

std::vector<std::vector<char>>
compile_hip_src(const std::vector<src_file>& srcs, std::string params, const std::string& arch)
{
184
    assert(not srcs.empty());
Paul Fultz II's avatar
Paul Fultz II committed
185
186
187
    if(not is_hcc_compiler() and not is_hip_clang_compiler())
        MIGRAPHX_THROW("Unknown hip compiler: " +
                       std::string(MIGRAPHX_STRINGIZE(MIGRAPHX_HIP_COMPILER)));
188

Paul Fultz II's avatar
Paul Fultz II committed
189
190
191
192
193
194
195
196
197
198
199
200
    if(params.find("-std=") == std::string::npos)
        params += " --std=c++17";
    params += " -fno-gpu-rdc";
    params += " -c";
    if(is_hcc_compiler())
    {
        params += " -amdgpu-target=" + arch;
    }
    else if(is_hip_clang_compiler())
    {
        params += " --cuda-gpu-arch=" + arch;
        params += " --cuda-device-only";
201
        params += " -O" + string_value_of(MIGRAPHX_GPU_OPTIMIZE{}, "3") + " ";
Paul Fultz II's avatar
Paul Fultz II committed
202
203
    }

204
205
206
    if(enabled(MIGRAPHX_GPU_DEBUG{}))
        params += " -DMIGRAPHX_DEBUG";

207
    params += " -Wno-unused-command-line-argument -Wno-cuda-compat ";
Paul Fultz II's avatar
Paul Fultz II committed
208
209
    params += MIGRAPHX_STRINGIZE(MIGRAPHX_HIP_COMPILER_FLAGS);

210
211
212
    src_compiler compiler;
    compiler.flags    = params;
    compiler.compiler = MIGRAPHX_STRINGIZE(MIGRAPHX_HIP_COMPILER);
Paul Fultz II's avatar
Paul Fultz II committed
213

214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
    if(is_hcc_compiler())
        compiler.process = [&](const fs::path& obj_path) -> fs::path {
            process{MIGRAPHX_STRINGIZE(MIGRAPHX_EXTRACT_KERNEL) + std::string{" -i "} +
                    obj_path.string()}
                .cwd(obj_path.parent_path());
            for(const auto& entry : fs::directory_iterator{obj_path.parent_path()})
            {
                const auto& hsaco_path = entry.path();
                if(not fs::is_regular_file(hsaco_path))
                    continue;
                if(hsaco_path.extension() != ".hsaco")
                    continue;
                return hsaco_path;
            }
            MIGRAPHX_THROW("Missing hsaco");
        };
Paul Fultz II's avatar
Paul Fultz II committed
230

231
    return {compiler.compile(srcs)};
Paul Fultz II's avatar
Paul Fultz II committed
232
233
}

Shucai Xiao's avatar
Shucai Xiao committed
234
std::string enum_params(int count, std::string param)
Shucai Xiao's avatar
Shucai Xiao committed
235
236
237
238
239
240
{
    std::vector<std::string> items(count);
    transform(range(count), items.begin(), [&](auto i) { return param + std::to_string(i); });
    return join_strings(items, ",");
}

Shucai Xiao's avatar
Shucai Xiao committed
241
int compute_global(int n, int local)
Shucai Xiao's avatar
Shucai Xiao committed
242
{
Shucai Xiao's avatar
Shucai Xiao committed
243
244
    int groups  = (n + local - 1) / local;
    int nglobal = std::min<int>(256, groups) * local;
Shucai Xiao's avatar
Shucai Xiao committed
245
246
247
    return nglobal;
}

248
249
#endif // MIGRAPHX_USE_HIPRTC

Paul Fultz II's avatar
Paul Fultz II committed
250
251
252
} // namespace gpu
} // namespace MIGRAPHX_INLINE_NS
} // namespace migraphx