codegen.cpp 17.2 KB
Newer Older
1
#include <memory>
2 3
#include "./helper.h"

4 5
#include "megbrain/comp_node_env.h"
#include "megbrain/gopt/inference.h"
6
#include "megbrain/jit/executor_opr.h"
7
#include "megbrain/opr/basic_arith.h"
8
#include "megbrain/opr/basic_arith_wrapper.h"
9
#include "megbrain/opr/tensor_manip.h"
10
#include "megbrain/test/helper.h"
11
#include "megdnn/dtype.h"
12 13 14 15 16 17 18 19 20 21 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

#if MGB_JIT
using namespace mgb;
using namespace jit;

#define FOREACH_CASE(cb) cb(simple) cb(grad)

namespace {
#define def_tag(x) \
    struct x {};
FOREACH_CASE(def_tag)
#undef def_tag

#define t(n) n,
using test_types = ::testing::Types<FOREACH_CASE(t) void>;
#undef t

template <typename tag>
void run(Backend backend, CompNode cn);

template <>
void run<simple>(Backend backend, CompNode cn) {
    set_backend(backend);
    auto graph = ComputingGraph::make();
    HostTensorGenerator<> gen;
    auto host_x0 = gen({23, 42}, cn), host_x1 = gen({23, 1}, cn),
         host_x2 = gen({1, 42}, cn);

    auto a = opr::Host2DeviceCopy::make(*graph, host_x0),
         b = opr::Host2DeviceCopy::make(*graph, host_x1),
         c = opr::Host2DeviceCopy::make(*graph, host_x2);

    a = opr::TypeCvt::make(a, dtype::Float16{});

    auto y = a + b * c;
    y = opr::TypeCvt::make(y, dtype::Float16{});
    y = opr::TypeCvt::make((y + y.make_scalar_dt(1.f)), dtype::Float32{});

    VarNodeArray inputs{a.node(), b.node(), c.node()}, outputs{y.node()};
M
Megvii Engine Team 已提交
51
    auto ig_gen = std::make_unique<InternalGraphGenerator>(y.node()->owner_opr());
52 53 54 55 56 57 58 59 60 61 62

    for (auto i : get_rev_topo_order(y)) {
        if (!i->same_type<opr::Host2DeviceCopy>()) {
            ig_gen->add_opr(i);
        }
    }

    auto igraph = ig_gen->generate();
    auto y_jit = JITExecutor::make(igraph, ig_gen->orig_inps());

    HostTensorND host_y, host_y_jit;
M
Megvii Engine Team 已提交
63 64
    auto func = graph->compile(
            {make_callback_copy(y, host_y), make_callback_copy(y_jit, host_y_jit)});
65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86
    func->execute();

    MGB_ASSERT_TENSOR_NEAR(host_y, host_y_jit, 5e-3);
};

template <>
void run<grad>(Backend backend, CompNode cn) {
    set_backend(backend);
    auto graph = ComputingGraph::make();
    HostTensorGenerator<> gen;
    auto host_x0 = gen({23, 42}, cn), host_x1 = gen({23, 1}, cn),
         host_x2 = gen({1, 42}, cn);

    auto a = opr::Host2DeviceCopy::make(*graph, host_x0),
         b = opr::Host2DeviceCopy::make(*graph, host_x1),
         c = opr::Host2DeviceCopy::make(*graph, host_x2);

    a = opr::TypeCvt::make(a, dtype::Float16{});

    auto y = opr::floor_div(a, opr::abs(b) + 0.1f) * opr::sin(c);

    VarNodeArray inputs{a.node(), b.node(), c.node()}, outputs{y.node()};
M
Megvii Engine Team 已提交
87
    auto ig_gen = std::make_unique<InternalGraphGenerator>(y.node()->owner_opr());
88 89 90 91 92 93 94 95 96 97 98

    for (auto i : get_rev_topo_order(y)) {
        if (!i->same_type<opr::Host2DeviceCopy>()) {
            ig_gen->add_opr(i);
        }
    }

    auto igraph = ig_gen->generate();
    auto y_jit = JITExecutor::make(igraph, ig_gen->orig_inps());

    HostTensorND host_y, host_y_jit;
M
Megvii Engine Team 已提交
99 100
    auto func = graph->compile(
            {make_callback_copy(y, host_y), make_callback_copy(y_jit, host_y_jit)});
101 102 103 104
    func->execute();

    MGB_ASSERT_TENSOR_EQ(host_y, host_y_jit);

M
Megvii Engine Team 已提交
105
    auto grad = [loss = opr::reduce_sum(y_jit, y_jit.make_scalar(1))](SymbolVar x) {
106 107 108 109 110 111 112 113 114
        return cg::grad(loss, x, false, false).node();
    };
    ASSERT_EQ(nullptr, grad(a));
    ASSERT_EQ(nullptr, grad(b));
    ASSERT_NE(nullptr, grad(c));
};

template <>
void run<void>(Backend, CompNode) {}
115 116 117 118 119 120 121

#if MGB_JIT_MLIR
void run_mlir(CompNode cn) {
    set_backend(Backend::MLIR);
    auto graph = ComputingGraph::make();
    HostTensorGenerator<dtype::Float32> gen;

122 123
    auto host_x0 = gen({23, 42}, cn), host_x1 = gen({23, 1}, cn),
         host_x2 = gen({23, 42}, cn);
124 125 126 127 128

    auto a = opr::Host2DeviceCopy::make(*graph, host_x0),
         b = opr::Host2DeviceCopy::make(*graph, host_x1),
         c = opr::Host2DeviceCopy::make(*graph, host_x2);

129
    auto y = a + b * c + 0.3f;
130

M
Megvii Engine Team 已提交
131
    auto ig_gen = std::make_unique<InternalGraphGenerator>(y.node()->owner_opr());
132 133 134 135 136 137 138 139 140 141 142

    for (auto i : get_rev_topo_order(y)) {
        if (!i->same_type<opr::Host2DeviceCopy>()) {
            ig_gen->add_opr(i);
        }
    }

    auto igraph = ig_gen->generate();
    auto y_jit = JITExecutor::make(igraph, ig_gen->orig_inps());

    HostTensorND host_y, host_y_jit;
M
Megvii Engine Team 已提交
143 144
    auto func = graph->compile(
            {make_callback_copy(y, host_y), make_callback_copy(y_jit, host_y_jit)});
145 146 147 148
    func->execute();

    MGB_ASSERT_TENSOR_EQ(host_y, host_y_jit);
}
149

150 151 152 153 154 155 156 157 158 159 160 161 162
void run_mlir_broadcast(CompNode cn) {
    set_backend(Backend::MLIR);
    auto graph = ComputingGraph::make();
    HostTensorGenerator<dtype::Float32> gen;

    auto host_x0 = gen({10, 20, 5, 6}, cn), host_x1 = gen({1, 20, 1, 1}, cn),
         host_x2 = gen({10, 1, 5, 1}, cn), host_x3 = gen({10, 1, 1, 1}, cn);

    auto a = opr::Host2DeviceCopy::make(*graph, host_x0),
         b = opr::Host2DeviceCopy::make(*graph, host_x1),
         c = opr::Host2DeviceCopy::make(*graph, host_x2),
         d = opr::Host2DeviceCopy::make(*graph, host_x3);

M
Megvii Engine Team 已提交
163 164
    auto y = opr::Elemwise::make({a, b, c}, opr::Elemwise::Mode::FUSE_MUL_ADD3) +
             opr::Elemwise::make({d}, opr::Elemwise::Mode::ABS) - 0.3f;
165

M
Megvii Engine Team 已提交
166
    auto ig_gen = std::make_unique<InternalGraphGenerator>(y.node()->owner_opr());
167 168 169 170 171 172 173 174 175 176 177

    for (auto i : get_rev_topo_order(y)) {
        if (!i->same_type<opr::Host2DeviceCopy>()) {
            ig_gen->add_opr(i);
        }
    }

    auto igraph = ig_gen->generate();
    auto y_jit = JITExecutor::make(igraph, ig_gen->orig_inps());

    HostTensorND host_y, host_y_jit;
M
Megvii Engine Team 已提交
178 179
    auto func = graph->compile(
            {make_callback_copy(y, host_y), make_callback_copy(y_jit, host_y_jit)});
180 181 182 183 184
    func->execute();

    MGB_ASSERT_TENSOR_EQ(host_y, host_y_jit);
}

185 186 187 188 189 190 191 192 193
void run_mlir_different_shape(CompNode cn) {
    set_backend(Backend::MLIR);
    auto graph = ComputingGraph::make();
    HostTensorGenerator<dtype::Float32> gen;

    auto run = [&](TensorShape tshp) {
        auto host_x = gen(tshp, cn);
        auto x = opr::Host2DeviceCopy::make(*graph, host_x);
        auto y = x * 2;
M
Megvii Engine Team 已提交
194
        auto ig_gen = std::make_unique<InternalGraphGenerator>(y.node()->owner_opr());
195 196 197 198 199 200 201 202 203 204 205

        for (auto i : get_rev_topo_order(y)) {
            if (!i->same_type<opr::Host2DeviceCopy>()) {
                ig_gen->add_opr(i);
            }
        }

        auto igraph = ig_gen->generate();
        auto y_jit = JITExecutor::make(igraph, ig_gen->orig_inps());

        HostTensorND host_y, host_y_jit;
M
Megvii Engine Team 已提交
206 207
        auto func = graph->compile(
                {make_callback_copy(y, host_y), make_callback_copy(y_jit, host_y_jit)});
208 209 210 211 212 213 214 215 216 217 218
        func->execute();

        MGB_ASSERT_TENSOR_EQ(host_y, host_y_jit);
    };

    run({23, 42});
    run({16, 31});
    run({32, 56});
    run({10});
}

219 220 221 222 223 224 225 226 227 228 229 230 231 232
struct MlirTestOpt {
    float low;
    float high;
    float maxerr;
};

struct MlirTestOpt get_mode_opt(opr::Elemwise::Mode mode) {
    struct MlirTestOpt opt = {0, 1, 1e-6};
    if (mode == opr::Elemwise::Mode::ABS) {
        opt.low = -10;
        opt.high = 10;
    } else if (mode == opr::Elemwise::Mode::LOG) {
        opt.low = 0.1;
        opt.high = 4;
M
Megvii Engine Team 已提交
233
    } else if (mode == opr::Elemwise::Mode::ERF or mode == opr::Elemwise::Mode::ERFC) {
234 235 236 237 238 239 240 241 242 243 244 245 246 247
        opt.low = -5;
        opt.high = 5;
    } else if (mode == opr::Elemwise::Mode::ERFINV) {
        opt.low = -0.999;
        opt.high = 0.999;
        opt.maxerr = 1e-4;
    } else if (mode == opr::Elemwise::Mode::ERFCINV) {
        opt.low = 0.001;
        opt.high = 1.999;
        opt.maxerr = 1e-4;
    }
    return opt;
}

248 249 250 251
template <typename tag, int arity>
void run_mlir_mode(CompNode cn) {
    set_backend(Backend::MLIR);
    auto graph = ComputingGraph::make();
252
    auto opt = get_mode_opt(tag::mode);
M
Megvii Engine Team 已提交
253 254
    HostTensorGenerator<dtype::Float32, RandomDistribution::UNIFORM> gen(
            opt.low, opt.high);
255 256 257 258

    SmallVector<std::shared_ptr<HostTensorND>> hosts;
    VarNodeArray input_vars;
    for (int i = 0; i < arity; i++) {
259
        hosts.push_back(gen({2323, 4242}, cn));
M
Megvii Engine Team 已提交
260
        input_vars.push_back(opr::Host2DeviceCopy::make(*graph, hosts[i]).node());
261 262 263 264
    }

    auto y = opr::Elemwise::make(input_vars, tag::mode);

M
Megvii Engine Team 已提交
265
    auto ig_gen = std::make_unique<InternalGraphGenerator>(y.node()->owner_opr());
266 267 268 269 270 271 272 273 274 275 276

    for (auto i : get_rev_topo_order(y)) {
        if (!i->template same_type<opr::Host2DeviceCopy>()) {
            ig_gen->add_opr(i);
        }
    }

    auto igraph = ig_gen->generate();
    auto y_jit = JITExecutor::make(igraph, ig_gen->orig_inps());

    HostTensorND host_y, host_y_jit;
M
Megvii Engine Team 已提交
277 278
    auto func = graph->compile(
            {make_callback_copy(y, host_y), make_callback_copy(y_jit, host_y_jit)});
279 280
    func->execute();

281
    MGB_ASSERT_TENSOR_NEAR(host_y, host_y_jit, opt.maxerr);
282
}
283
#endif
284 285
}  // anonymous namespace

286 287
/* ===================== TestJITHalideCodeGenCude ===================== */

288 289 290 291 292 293 294 295 296 297
#if MGB_JIT_HALIDE
template <typename tag>
class TestJITHalideCodeGenCuda : public ::testing::Test {};
TYPED_TEST_CASE(TestJITHalideCodeGenCuda, test_types);
TYPED_TEST(TestJITHalideCodeGenCuda, run) {
    REQUIRE_GPU(1);
    run<TypeParam>(Backend::HALIDE, CompNode::load("gpu0"));
}
#endif

298 299
/* ===================== TestJITNvrtcCodeGen ===================== */

300 301 302 303 304 305 306 307
template <typename tag>
class TestJITNvrtcCodeGen : public ::testing::Test {};
TYPED_TEST_CASE(TestJITNvrtcCodeGen, test_types);
TYPED_TEST(TestJITNvrtcCodeGen, run) {
    REQUIRE_GPU(1);
    run<TypeParam>(Backend::NVRTC, CompNode::load("gpu0"));
}

308 309
/* ===================== TestJITMlirCodeGen ===================== */

310 311 312 313
#if MGB_JIT_MLIR
TEST(TestJITMlirCodeGen, Basic) {
    auto cn = CompNode::load("cpu0");
    run_mlir(cn);
314
    run_mlir_broadcast(cn);
315
    run_mlir_different_shape(cn);
316 317 318 319 320 321
}

TEST(TestJITMlirCodeGen, BasicGPU) {
    REQUIRE_GPU(1);
    auto cn = CompNode::load("gpu0");
    run_mlir(cn);
322
    run_mlir_broadcast(cn);
323
    run_mlir_different_shape(cn);
324 325
}

326
/* ===================== TestJITMlirUnaryElemwise ===================== */
327 328 329 330
#define FOREACH_UNARY_MODE(cb)                                                       \
    cb(RELU) cb(ABS) cb(NEGATE) cb(ACOS) cb(ASIN) cb(CEIL) cb(EXP) cb(FLOOR) cb(LOG) \
            cb(LOG1P) cb(SIN) cb(COS) cb(TANH) cb(FAST_TANH) cb(H_SWISH) cb(SIGMOID) \
                    cb(EXPM1) cb(ROUND) cb(ERF) cb(ERFINV) cb(ERFC) cb(ERFCINV)
331

332 333 334 335 336 337 338 339 340 341 342
template <typename tag>
class TestJITMlirUnaryElemwise : public ::testing::Test {};

#define def_tag(x)                                                          \
    struct x {                                                              \
        static constexpr opr::Elemwise::Mode mode = opr::Elemwise::Mode::x; \
    };
FOREACH_UNARY_MODE(def_tag)
#undef def_tag

#define t(n) n,
M
Megvii Engine Team 已提交
343
using mlir_elemwise_unary_types = ::testing::Types<FOREACH_UNARY_MODE(t) ABS>;
344 345 346
#undef t
TYPED_TEST_CASE(TestJITMlirUnaryElemwise, mlir_elemwise_unary_types);

347 348 349 350 351
#define SKIP_MODE(_mode)                                 \
    if (TypeParam::mode == opr::Elemwise::Mode::_mode) { \
        printf("skip\n");                                \
        return;                                          \
    }
352 353 354 355 356 357 358 359 360

TYPED_TEST(TestJITMlirUnaryElemwise, run) {
    auto cn = CompNode::load("cpu0");

    SKIP_MODE(ROUND);

    run_mlir_mode<TypeParam, 1>(cn);
}

361 362 363 364
TYPED_TEST(TestJITMlirUnaryElemwise, runGpu) {
    REQUIRE_GPU(1);
    auto cn = CompNode::load("gpu0");

365
    SKIP_MODE(ROUND);
366 367 368 369

    run_mlir_mode<TypeParam, 1>(cn);
}

370
/* ===================== TestJITMlirBinaryElemwise ===================== */
371 372 373 374 375 376
#define FOREACH_BINARY_MODE(cb)                                                        \
    cb(ADD) cb(FLOOR_DIV) cb(MUL) cb(MAX) cb(MIN) cb(MOD) cb(SUB) cb(TRUE_DIV) cb(POW) \
            cb(ABS_GRAD) cb(SIGMOID_GRAD) cb(SWITCH_GT0) cb(TANH_GRAD) cb(LT) cb(LEQ)  \
                    cb(EQ) cb(FUSE_ADD_RELU) cb(LOG_SUM_EXP) cb(FUSE_ADD_TANH)         \
                            cb(FAST_TANH_GRAD) cb(FUSE_ADD_SIGMOID) cb(H_SWISH_GRAD)   \
                                    cb(FUSE_ADD_H_SWISH) cb(ATAN2)
377

378 379 380 381 382 383 384 385 386 387 388
template <typename tag>
class TestJITMlirBinaryElemwise : public ::testing::Test {};

#define def_tag(x)                                                          \
    struct x {                                                              \
        static constexpr opr::Elemwise::Mode mode = opr::Elemwise::Mode::x; \
    };
FOREACH_BINARY_MODE(def_tag)
#undef def_tag

#define t(n) n,
M
Megvii Engine Team 已提交
389
using mlir_elemwise_binary_types = ::testing::Types<FOREACH_BINARY_MODE(t) ADD>;
390 391 392 393 394 395 396
#undef t
TYPED_TEST_CASE(TestJITMlirBinaryElemwise, mlir_elemwise_binary_types);
TYPED_TEST(TestJITMlirBinaryElemwise, run) {
    auto cn = CompNode::load("cpu0");
    run_mlir_mode<TypeParam, 2>(cn);
}

397 398 399
TYPED_TEST(TestJITMlirBinaryElemwise, runGpu) {
    REQUIRE_GPU(1);
    auto cn = CompNode::load("gpu0");
400 401 402

    SKIP_MODE(MOD);

403 404 405
    run_mlir_mode<TypeParam, 2>(cn);
}

406
/* ===================== TestJITMlirTenaryElemwise ===================== */
407
#define FOREACH_TERNARY_MODE(cb) cb(COND_LEQ_MOV) cb(COND_LT_MOV) cb(FUSE_MUL_ADD3)
408

409 410 411 412 413 414 415 416 417 418 419
template <typename tag>
class TestJITMlirTernaryElemwise : public ::testing::Test {};

#define def_tag(x)                                                          \
    struct x {                                                              \
        static constexpr opr::Elemwise::Mode mode = opr::Elemwise::Mode::x; \
    };
FOREACH_TERNARY_MODE(def_tag)
#undef def_tag

#define t(n) n,
420 421
using mlir_elemwise_ternary_types =
        ::testing::Types<FOREACH_TERNARY_MODE(t) COND_LEQ_MOV>;
422 423 424 425 426 427 428
#undef t
TYPED_TEST_CASE(TestJITMlirTernaryElemwise, mlir_elemwise_ternary_types);
TYPED_TEST(TestJITMlirTernaryElemwise, run) {
    auto cn = CompNode::load("cpu0");
    run_mlir_mode<TypeParam, 3>(cn);
}

429 430 431 432 433 434 435 436
TYPED_TEST(TestJITMlirTernaryElemwise, runGpu) {
    REQUIRE_GPU(1);
    auto cn = CompNode::load("gpu0");
    run_mlir_mode<TypeParam, 3>(cn);
}

#undef SKIP_MODE

437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460
/* ===================== TestJITMlirTypeCvt ===================== */

template <typename itype, typename otype>
void run_typecvt(CompNode cn) {
    set_backend(Backend::MLIR);
    auto graph = ComputingGraph::make();
    HostTensorGenerator<itype, RandomDistribution::UNIFORM> gen(-10, 10);

    auto host_x = gen({23, 42}, cn);
    auto x = opr::Host2DeviceCopy::make(*graph, host_x);
    auto y = opr::TypeCvt::make(x, otype());

    auto ig_gen = std::make_unique<InternalGraphGenerator>(y.node()->owner_opr());

    for (auto i : get_rev_topo_order(y)) {
        if (!i->template same_type<opr::Host2DeviceCopy>()) {
            ig_gen->add_opr(i);
        }
    }

    auto igraph = ig_gen->generate();
    auto y_jit = JITExecutor::make(igraph, ig_gen->orig_inps());

    HostTensorND host_y, host_y_jit;
461 462
    auto func = graph->compile(
            {make_callback_copy(y, host_y), make_callback_copy(y_jit, host_y_jit)});
463 464 465 466 467
    func->execute();

    MGB_ASSERT_TENSOR_EQ(host_y, host_y_jit);
};

468 469
#define add_typecvt_gtest(itype, otype)                                  \
    TEST(TestJITMlirTypeCvt, itype##_to_##otype) {                       \
470
        run_typecvt<dtype::itype, dtype::otype>(CompNode::load("cpu0")); \
471 472 473
    }                                                                    \
    TEST(TestJITMlirTypeCvt, itype##_to_##otype##_GPU) {                 \
        REQUIRE_GPU(1);                                                  \
474 475 476 477 478
        run_typecvt<dtype::itype, dtype::otype>(CompNode::load("gpu0")); \
    }

#if !MEGDNN_DISABLE_FLOAT16

479
    // TODO: the support for f16 and bf16 is currently not complete in mlir
480

481 482 483 484
    // FPExtOp
    // add_typecvt_gtest(Float16, Float32);
    // add_typecvt_gtest(BFloat16, Float32);
    // add_typecvt_gtest(Float16, BFloat16);
485

486 487 488 489
    // FPTruncOp
    // add_typecvt_gtest(Float32, Float16);
    // add_typecvt_gtest(Float32, BFloat16);
    // add_typecvt_gtest(Float16, BFloat16);
490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510

#endif

// FPToSIOp
add_typecvt_gtest(Float32, Int8);
add_typecvt_gtest(Float32, Int16);
add_typecvt_gtest(Float32, Int32);

// FPToUIOp
add_typecvt_gtest(Float32, Uint8);

// SIToFPOp
add_typecvt_gtest(Int8, Float32);
add_typecvt_gtest(Int16, Float32);
add_typecvt_gtest(Int32, Float32);

// UIToFPOp
add_typecvt_gtest(Uint8, Float32);

#undef add_typecvt_gtest

511 512
/* ===================== TestJITMlirDimshuffle ===================== */

513
void run_dimshuffle(CompNode cn, TensorShape ishape, const std::vector<int>& pattern) {
514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533
    set_backend(Backend::MLIR);
    auto graph = ComputingGraph::make();
    HostTensorGenerator<> gen;

    auto host_x = gen(ishape, cn);
    auto x = opr::Host2DeviceCopy::make(*graph, host_x);
    auto y = opr::Dimshuffle::make(x, pattern);

    auto ig_gen = std::make_unique<InternalGraphGenerator>(y.node()->owner_opr());

    for (auto i : get_rev_topo_order(y)) {
        if (!i->template same_type<opr::Host2DeviceCopy>()) {
            ig_gen->add_opr(i);
        }
    }

    auto igraph = ig_gen->generate();
    auto y_jit = JITExecutor::make(igraph, ig_gen->orig_inps());

    HostTensorND host_y, host_y_jit;
534 535
    auto func = graph->compile(
            {make_callback_copy(y, host_y), make_callback_copy(y_jit, host_y_jit)});
536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554
    func->execute();

    MGB_ASSERT_TENSOR_EQ(host_y, host_y_jit);
}

void run_dimshuffle_cases(CompNode cn) {
    run_dimshuffle(cn, {3, 4, 5}, {2, 0, 1});
    run_dimshuffle(cn, {3, 4, 5}, {1, -1, 0, 2});
}

TEST(TestJITMlirDimshuffle, Basic) {
    run_dimshuffle_cases(CompNode::load("cpu0"));
}

TEST(TestJITMlirDimshuffle, BasicGPU) {
    REQUIRE_GPU(1);
    run_dimshuffle_cases(CompNode::load("gpu0"));
}

555
#endif  // MGB_JIT_MLIR
556

557 558 559
#endif  // MGB_JIT

// vim: syntax=cpp.doxygen foldmethod=marker foldmarker=f{{{,f}}}