compile_hip.cpp 12.2 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2015-2022 Advanced Micro Devices, Inc. All rights reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
Paul Fultz II's avatar
Paul Fultz II committed
24
25
#include <migraphx/gpu/compile_hip.hpp>
#include <migraphx/errors.hpp>
26
#include <migraphx/stringutils.hpp>
Shucai Xiao's avatar
Shucai Xiao committed
27
#include <migraphx/ranges.hpp>
28
#include <migraphx/env.hpp>
Paul Fultz II's avatar
Paul Fultz II committed
29
#include <cassert>
30
#include <iostream>
31
#include <deque>
32

Umang Yadav's avatar
Umang Yadav committed
33
#ifdef MIGRAPHX_USE_HIPRTC
34
35
#include <hip/hiprtc.h>
#include <migraphx/manage_ptr.hpp>
36
37
38
39
40
41
42
#include <migraphx/value.hpp>
#include <migraphx/tmp_dir.hpp>
#include <migraphx/dynamic_loader.hpp>
#include <migraphx/process.hpp>
#include <migraphx/msgpack.hpp>
#include <migraphx/serialize.hpp>
#include <migraphx/file_buffer.hpp>
43
44
45
46
#else
#include <migraphx/compile_src.hpp>
#include <migraphx/process.hpp>
#endif
Paul Fultz II's avatar
Paul Fultz II committed
47
48
49
50
51

namespace migraphx {
inline namespace MIGRAPHX_INLINE_NS {
namespace gpu {

52
MIGRAPHX_DECLARE_ENV_VAR(MIGRAPHX_GPU_DEBUG);
53
MIGRAPHX_DECLARE_ENV_VAR(MIGRAPHX_GPU_DEBUG_SYM);
54
MIGRAPHX_DECLARE_ENV_VAR(MIGRAPHX_GPU_OPTIMIZE);
55
MIGRAPHX_DECLARE_ENV_VAR(MIGRAPHX_GPU_DUMP_ASM);
56
MIGRAPHX_DECLARE_ENV_VAR(MIGRAPHX_GPU_DUMP_SRC);
57

Umang Yadav's avatar
Umang Yadav committed
58
#ifdef MIGRAPHX_USE_HIPRTC
59
60
61
62
63
64
65
66
67
68
69
70

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));
}

71
// NOLINTNEXTLINE
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
#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
    {
96
        std::deque<std::string> strings{};
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
        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 = "";

119
120
121
122
123
124
    hiprtc_program(const std::string& src, const std::string& name = "main.cpp")
        : cpp_src(src), cpp_name(name)
    {
        create_program();
    }

125
    hiprtc_program(std::vector<hiprtc_src_file> srcs)
126
127
128
    {
        for(auto&& src : srcs)
        {
129
            if(ends_with(src.path, ".cpp"))
130
            {
131
132
                cpp_src  = std::move(src.content);
                cpp_name = std::move(src.path);
133
134
135
            }
            else
            {
136
137
                headers.push_back(std::move(src.content));
                include_names.push_back(std::move(src.path));
138
139
            }
        }
140
141
142
143
144
145
146
147
        create_program();
    }

    void create_program()
    {
        assert(not cpp_src.empty());
        assert(not cpp_name.empty());
        assert(headers.size() == include_names.size());
148
149
150
151
152
153
154
        prog = hiprtc_program_create(cpp_src.c_str(),
                                     cpp_name.c_str(),
                                     headers.size(),
                                     headers.data(),
                                     include_names.data());
    }

155
    void compile(const std::vector<std::string>& options, bool quiet = false) const
156
157
158
159
160
161
162
163
    {
        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(); });
Umang Yadav's avatar
Umang Yadav committed
164
165
        auto result   = hiprtcCompileProgram(prog.get(), c_options.size(), c_options.data());
        auto prog_log = log();
166
        if(not prog_log.empty() and not quiet)
Umang Yadav's avatar
Umang Yadav committed
167
168
169
        {
            std::cerr << prog_log << std::endl;
        }
170
171
172
173
        if(result != HIPRTC_SUCCESS)
            MIGRAPHX_HIPRTC_THROW(result, "Compilation failed.");
    }

Umang Yadav's avatar
Umang Yadav committed
174
    std::string log() const
175
176
177
    {
        std::size_t n = 0;
        MIGRAPHX_HIPRTC(hiprtcGetProgramLogSize(prog.get(), &n));
Umang Yadav's avatar
Umang Yadav committed
178
        if(n == 0)
179
            return {};
Umang Yadav's avatar
Umang Yadav committed
180
        std::string buffer(n, '\0');
181
        MIGRAPHX_HIPRTC(hiprtcGetProgramLog(prog.get(), buffer.data()));
Umang Yadav's avatar
Umang Yadav committed
182
183
        assert(buffer.back() != 0);
        return buffer;
184
185
    }

Umang Yadav's avatar
Umang Yadav committed
186
    std::vector<char> get_code_obj() const
187
188
189
190
191
192
193
194
195
    {
        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;
    }
};

196
197
198
std::vector<std::vector<char>> compile_hip_src_with_hiprtc(std::vector<hiprtc_src_file> srcs,
                                                           std::string params,
                                                           const std::string& arch)
199
{
200
    hiprtc_program prog(std::move(srcs));
201
    auto options = split_string(params, ' ');
Umang Yadav's avatar
Umang Yadav committed
202
203
204
205
206
207
208
    options.push_back("-DMIGRAPHX_USE_HIPRTC=1");
    // remove following three compilation flags for HIPRTC once fixes from hipRTC are available in
    if(enabled(MIGRAPHX_ENABLE_HIPRTC_WORKAROUNDS{}))
    {
        options.push_back("-DMIGRAPHX_HAS_DPP=0");
        options.push_back("-DMIGRAPHX_ENABLE_HIPRTC_WORKAROUNDS=1");
        options.push_back("-Wno-reserved-identifier");
209
        options.push_back("-Wno-unused-parameter");
Umang Yadav's avatar
Umang Yadav committed
210
211
212
        options.push_back("-Wno-gnu-line-marker");
        options.push_back("-Wno-old-style-cast");
    }
213
214
215
216
217
218
219
    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");
Umang Yadav's avatar
Umang Yadav committed
220
    options.push_back("-O" + string_value_of(MIGRAPHX_GPU_OPTIMIZE{}, "3"));
221
    options.push_back("-Wno-cuda-compat");
Umang Yadav's avatar
Umang Yadav committed
222
    options.push_back("--offload-arch=" + arch);
223
224
225
226
    prog.compile(options);
    return {prog.get_code_obj()};
}

227
228
229
230
231
232
233
234
235
236
237
238
239
240
bool hip_has_flags(const std::vector<std::string>& flags)
{
    hiprtc_program prog{" "};
    try
    {
        prog.compile(flags, true);
        return true;
    }
    catch(...)
    {
        return false;
    }
}

241
242
243
244
std::vector<std::vector<char>>
compile_hip_src(const std::vector<src_file>& srcs, std::string params, const std::string& arch)
{
    std::vector<hiprtc_src_file> hsrcs{srcs.begin(), srcs.end()};
245
246
247
248
249
250
    if(enabled(MIGRAPHX_GPU_DUMP_SRC{}))
    {
        for(const auto& src : srcs)
        {
            if(src.path.extension() != ".cpp")
                continue;
251
            std::cout << std::string(src.content) << std::endl;
252
253
        }
    }
254
255
256
257
    auto fname = fs::path{"migraphx-hiprtc-driver"};
#ifdef _WIN32
    fname.replace_extension(".exe");
#endif
258
    auto p      = dynamic_loader::path(&compile_hip_src_with_hiprtc);
259
260
261
262
263
264
265
266
    auto driver = p.parent_path() / fname;

    bool found = fs::exists(driver);
    if(not found)
    {
        driver = p.parent_path().parent_path() / "bin" / fname;
        found  = fs::exists(driver);
    }
267

268
    if(found)
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
    {
        value v;
        v["srcs"]   = to_value(hsrcs);
        v["params"] = to_value(params);
        v["arch"]   = to_value(arch);

        tmp_dir td{};
        auto out = td.path / "output";

        process(driver.string() + " " + out.string()).write([&](auto writer) {
            to_msgpack(v, writer);
        });
        if(fs::exists(out))
            return {read_buffer(out.string())};
    }
    return compile_hip_src_with_hiprtc(std::move(hsrcs), std::move(params), arch);
}

287
288
#else // MIGRAPHX_USE_HIPRTC

289
290
291
292
293
294
295
std::vector<std::vector<char>> compile_hip_src_with_hiprtc(std::vector<hiprtc_src_file>, // NOLINT
                                                           std::string,                  // NOLINT
                                                           const std::string&)
{
    MIGRAPHX_THROW("Not using hiprtc");
}

Paul Fultz II's avatar
Paul Fultz II committed
296
297
bool is_hip_clang_compiler()
{
298
    static const auto result = fs::path{MIGRAPHX_HIP_COMPILER}.stem() == "clang++";
Paul Fultz II's avatar
Paul Fultz II committed
299
300
301
    return result;
}

302
303
#ifdef MIGRAPHX_HIP_COMPILER_LAUNCHER

304
305
bool has_compiler_launcher()
{
306
    static const auto result = fs::exists(MIGRAPHX_HIP_COMPILER_LAUNCHER);
307
308
309
    return result;
}

310
311
#endif

312
313
314
315
316
317
318
src_compiler assemble(src_compiler compiler)
{
    compiler.out_ext = ".S";
    compiler.flags   = replace_string(compiler.flags, " -c", " -S");
    return compiler;
}

Paul Fultz II's avatar
Paul Fultz II committed
319
320
321
std::vector<std::vector<char>>
compile_hip_src(const std::vector<src_file>& srcs, std::string params, const std::string& arch)
{
322
    assert(not srcs.empty());
Umang Yadav's avatar
Umang Yadav committed
323
    if(not is_hip_clang_compiler())
324
        MIGRAPHX_THROW("Unknown hip compiler: " MIGRAPHX_HIP_COMPILER);
325

Paul Fultz II's avatar
Paul Fultz II committed
326
327
328
    if(params.find("-std=") == std::string::npos)
        params += " --std=c++17";
    params += " -fno-gpu-rdc";
329
330
    if(enabled(MIGRAPHX_GPU_DEBUG_SYM{}))
        params += " -g";
Paul Fultz II's avatar
Paul Fultz II committed
331
    params += " -c";
Umang Yadav's avatar
Umang Yadav committed
332
333
334
    params += " --offload-arch=" + arch;
    params += " --cuda-device-only";
    params += " -O" + string_value_of(MIGRAPHX_GPU_OPTIMIZE{}, "3") + " ";
Paul Fultz II's avatar
Paul Fultz II committed
335

336
337
338
    if(enabled(MIGRAPHX_GPU_DEBUG{}))
        params += " -DMIGRAPHX_DEBUG";

339
    params += " -Wno-unused-command-line-argument -Wno-cuda-compat ";
340
    params += MIGRAPHX_HIP_COMPILER_FLAGS;
Paul Fultz II's avatar
Paul Fultz II committed
341

342
343
    src_compiler compiler;
    compiler.flags    = params;
344
    compiler.compiler = MIGRAPHX_HIP_COMPILER;
345
346
#ifdef MIGRAPHX_HIP_COMPILER_LAUNCHER
    if(has_compiler_launcher())
347
        compiler.launcher = MIGRAPHX_HIP_COMPILER_LAUNCHER;
348
#endif
349
350
351
352
353
354
    if(enabled(MIGRAPHX_GPU_DUMP_SRC{}))
    {
        for(const auto& src : srcs)
        {
            if(src.path.extension() != ".cpp")
                continue;
355
            std::cout << std::string(src.content) << std::endl;
356
357
358
        }
    }

359
360
361
362
363
364
    if(enabled(MIGRAPHX_GPU_DUMP_ASM{}))
    {

        std::cout << assemble(compiler).compile(srcs).data() << std::endl;
    }

365
    return {compiler.compile(srcs)};
Paul Fultz II's avatar
Paul Fultz II committed
366
367
}

368
369
370
bool hip_has_flags(const std::vector<std::string>& flags)
{
    src_compiler compiler;
371
    compiler.compiler = MIGRAPHX_HIP_COMPILER;
372
373
374
375
    compiler.flags =
        join_strings(flags, " ") + " -x hip -c --offload-arch=gfx900 --cuda-device-only";

    std::string src;
376
    src_file input{"main.cpp", src};
377
378
379
380
381
382
383
384
385
386
387
388

    try
    {
        compiler.compile({input});
        return true;
    }
    catch(...)
    {
        return false;
    }
}

Umang Yadav's avatar
Umang Yadav committed
389
390
#endif // MIGRAPHX_USE_HIPRTC

Shucai Xiao's avatar
Shucai Xiao committed
391
392
393
394
395
396
397
std::string enum_params(std::size_t count, std::string param)
{
    std::vector<std::string> items(count);
    transform(range(count), items.begin(), [&](auto i) { return param + std::to_string(i); });
    return join_strings(items, ",");
}

Paul Fultz II's avatar
Paul Fultz II committed
398
399
400
} // namespace gpu
} // namespace MIGRAPHX_INLINE_NS
} // namespace migraphx