Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ test_categories:
- "rocke_wgrad_streamk_host"
- "rocke_wmma_fmha_decode_host"
- "rocke_future_intrinsic_lowering"
- "rocke_ir_types"
- "rocke_opcode_values"
- "rocke_tiled_attention_2d_reentrancy"
- "rocke_unified_attention_scalar_lower_to_llvm"
- "rocke_python_import_smoke"
Expand Down Expand Up @@ -64,6 +66,8 @@ test_categories:
- "rocke_wgrad_streamk_host"
- "rocke_wmma_fmha_decode_host"
- "rocke_future_intrinsic_lowering"
- "rocke_ir_types"
- "rocke_opcode_values"
- "rocke_tiled_attention_2d_reentrancy"
- "rocke_unified_attention_scalar_lower_to_llvm"
- "rocke_python_import_smoke"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ extern "C" {
#include "rocke/instance_tf32_mma_probe.h"
#include "rocke/ir.h"
#include "rocke/ir_serialize.h"
#include "rocke/lower_hip.h"
#include "rocke/lower_llvm.h"
#include "rocke/rocke_build_id.h"
#include "rocke/verify.h"
Expand Down Expand Up @@ -3974,17 +3975,40 @@ static std::string rocke_engine_flavor_list()
return out;
}

std::string lower_serialized_ir(const std::string& ir_text,
const std::string& arch,
const std::string& flavor)
/* Parse serialized ck.dsl.ir/v1 text into a kernel owned by `b`, which the
* caller has zero-initialised and frees. `entry` names the binding in the
* error messages. Throws std::runtime_error on any failure. */
static const rocke_kernel_def_t*
parse_serialized_ir(const std::string& ir_text, const char* entry, rocke_ir_builder_t* b)
{
const std::string prefix = std::string("rocke_engine.") + entry + ": ";
if(ir_text.empty())
{
throw std::runtime_error("rocke_engine.lower_serialized_ir: empty IR input");
throw std::runtime_error(prefix + "empty IR input");
}
if(rocke_ir_builder_init(b, entry) != ROCKE_OK)
{
throw std::runtime_error(prefix + "builder init failed (OOM)");
}
rocke_kernel_def_t* kernel = nullptr;
const rocke_status_t st = rocke_ir_parse(ir_text.c_str(), b, &kernel);
if(st != ROCKE_OK || !kernel)
{
const char* m = rocke_ir_builder_error(b);
throw std::runtime_error(prefix + "parse failed (status " + std::to_string((int)st)
+ "): " + ((m && *m) ? m : "unknown parse error"));
}
return kernel;
}

std::string lower_serialized_ir(const std::string& ir_text,
const std::string& arch,
const std::string& flavor)
{
/* No empty-string fallback to gfx950: the target is required on both
* engines or on neither. The core resolver's NULL check does not cover
* this -- an empty std::string is not NULL by the time it gets there. */
* this -- an empty std::string is not NULL by the time it gets there.
* An empty IR text is refused by parse_serialized_ir. */
if(arch.empty())
{
throw std::runtime_error("rocke_engine.lower_serialized_ir: lowering requires an "
Expand Down Expand Up @@ -4013,30 +4037,16 @@ std::string lower_serialized_ir(const std::string& ir_text,
rocke_ir_builder_t b = {};
std::unique_ptr<rocke_ir_builder_t, decltype(&rocke_ir_builder_free)> builder(
&b, rocke_ir_builder_free);
const auto init_status = rocke_ir_builder_init(&b, "lower_serialized_ir");
if(init_status != ROCKE_OK)
{
throw std::runtime_error("rocke_engine.lower_serialized_ir: builder init failed (OOM)");
}

rocke_kernel_def_t* kernel = nullptr;
rocke_status_t st = rocke_ir_parse(ir_text.c_str(), &b, &kernel);
if(st != ROCKE_OK || !kernel)
{
const char* m = rocke_ir_builder_error(&b);
std::string msg = std::string("rocke_engine.lower_serialized_ir: parse failed (status ")
+ std::to_string((int)st)
+ "): " + ((m && *m) ? m : "unknown parse error");
throw std::runtime_error(msg);
}
const rocke_kernel_def_t* kernel = parse_serialized_ir(ir_text, "lower_serialized_ir", &b);

if(fl == ROCKE_LLVM_FLAVOR_AUTO)
fl = resolve_python_llvm_flavor();

char* out_ll = nullptr;
char err[ROCKE_ERR_MSG_CAP];
err[0] = '\0';
st = rocke_lower_kernel_to_llvm_ex(kernel, fl, a, &out_ll, err, sizeof(err));
const rocke_status_t st
= rocke_lower_kernel_to_llvm_ex(kernel, fl, a, &out_ll, err, sizeof(err));
std::unique_ptr<char, decltype(&std::free)> text(out_ll, std::free);
if(st != ROCKE_OK || !out_ll)
{
Expand All @@ -4049,6 +4059,46 @@ std::string lower_serialized_ir(const std::string& ir_text,
return std::string(text.get());
}

/* lower_serialized_ir_hip(ir_text, arch): the HIP-source twin of
* lower_serialized_ir -- parse, then rocke_lower_kernel_to_hip with its
* defaults (prologue included, launch bounds from the kernel). Lets a test
* compare the C++ HIP lowering of a Python-built kernel, and its refusals,
* with rocke.core.lower_hip.lower_kernel_to_hip. */
std::string lower_serialized_ir_hip(const std::string& ir_text, const std::string& arch)
{
/* The target is required, as for lower_serialized_ir. */
if(arch.empty())
{
throw std::runtime_error("rocke_engine.lower_serialized_ir_hip: lowering requires an "
"explicit gfx target; pass arch=... (there is no default)");
}
const char* a = arch.c_str();
rocke_ir_builder_t b = {};
std::unique_ptr<rocke_ir_builder_t, decltype(&rocke_ir_builder_free)> builder(
&b, rocke_ir_builder_free);
const rocke_kernel_def_t* kernel = parse_serialized_ir(ir_text, "lower_serialized_ir_hip", &b);

rocke_strbuf_t text;
if(rocke_strbuf_init(&text, 0) != 0)
{
throw std::runtime_error("rocke_engine.lower_serialized_ir_hip: output allocation failed");
}
std::unique_ptr<rocke_strbuf_t, decltype(&rocke_strbuf_free)> owned_text(&text,
rocke_strbuf_free);
rocke_lower_hip_opts_t opts = {};
opts.arch = a;
const rocke_status_t st = rocke_lower_kernel_to_hip(&b, kernel, &opts, &text);
if(st != ROCKE_OK)
{
const char* m = rocke_ir_builder_error(&b);
throw std::runtime_error(std::string("rocke_engine.lower_serialized_ir_hip: lower failed "
"for arch '")
+ a + "' (status " + std::to_string((int)st)
+ "): " + ((m && *m) ? m : "unknown lowering error"));
}
return std::string(rocke_strbuf_cstr(&text));
}

} // namespace

PYBIND11_MODULE(rocke_engine, m)
Expand Down Expand Up @@ -4108,6 +4158,14 @@ PYBIND11_MODULE(rocke_engine, m)
"the Python lowerer for the same serialized IR. flavor='' resolves "
"the LLVM flavor automatically; a name from llvm_flavors() pins it.");

m.def("lower_serialized_ir_hip",
&lower_serialized_ir_hip,
py::arg("ir_text"),
py::arg("arch"), /* required: no default target */
"Parse serialized ck.dsl.ir/v1 text and lower it to HIP source via the "
"C++ engine; the twin of rocke.core.lower_hip.lower_kernel_to_hip with "
"its default options.");

/* Exposes the engine's flavor ladder so a test can assert it still equals
* rocke.core.lower_llvm.LLVM_FLAVORS. Without a way to read the C++ list
* back, the two enumerations can drift into a flavor that lowers on one
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2228,8 +2228,8 @@ static const rocke_mma_op_t k_mma_gfx1151[] = {
&lm_wmma_16x16x16_b,
&lm_wmma_16x16x16_c},
{"wmma",
"iu8",
"iu8",
"i8",
"i8",
"i32",
16,
16,
Expand All @@ -2243,8 +2243,8 @@ static const rocke_mma_op_t k_mma_gfx1151[] = {
&lm_wmma_iu8_b,
&lm_wmma_iu8_c},
{"wmma",
"iu4",
"iu4",
"i4",
"i4",
"i32",
16,
16,
Expand Down Expand Up @@ -2326,8 +2326,8 @@ static const rocke_mma_op_t k_mma_gfx11_generic[] = {
&lm_wmma_16x16x16_b,
&lm_wmma_16x16x16_c},
{"wmma",
"iu8",
"iu8",
"i8",
"i8",
"i32",
16,
16,
Expand All @@ -2341,8 +2341,8 @@ static const rocke_mma_op_t k_mma_gfx11_generic[] = {
&lm_wmma_iu8_b,
&lm_wmma_iu8_c},
{"wmma",
"iu4",
"iu4",
"i4",
"i4",
"i32",
16,
16,
Expand Down
100 changes: 77 additions & 23 deletions dnn-providers/hip-kernel-provider/rocke/platform/cpp/core/dtypes.cpp
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
// Copyright (c) Advanced Micro Devices, Inc., or its affiliates.
// SPDX-License-Identifier: MIT
/* Target-independent dtype names. Mirrors rocke.core.dtypes:
* normalize_dtype -> rocke_normalize_dtype.
* No architecture, IR builder, or lowering dependencies.
* normalize_dtype -> rocke_normalize_dtype, dtype_info -> rocke_dtype_info
* (NULL on a miss) and rocke_require_dtype_info (raises).
* No architecture, IR builder, or lowering dependencies; the engine exception
* types (rocke/error.hpp) carry the raising lookup's refusal.
*/
#include "rocke/dtypes.h"

#include <string.h>

#include "rocke/dtypes_internal.h"
#include "rocke/error.hpp"

/* =========================================================================
* target-independent dtype normalization
* =========================================================================
Expand All @@ -26,17 +31,45 @@ typedef struct rocke_dtype_alias
/* Byte-for-byte the _DTYPE_ALIASES map (insertion order is irrelevant: lookup is
* by exact lowercased key). */
static const rocke_dtype_alias_t k_dtype_aliases[] = {
{"f16", "fp16"}, {"half", "fp16"}, {"fp16", "fp16"},
{"bf16", "bf16"}, {"bfloat16", "bf16"}, {"f32", "fp32"},
{"float", "fp32"}, {"fp32", "fp32"}, {"tf32", "tf32"},
{"xf32", "tf32"}, {"f64", "fp64"}, {"double", "fp64"},
{"fp64", "fp64"}, {"iu8", "iu8"}, {"iu4", "iu4"},
{"i8", "i8"}, {"int8", "i8"}, {"i4", "i4"},
{"int4", "i4"}, {"i32", ROCKE_DTYPE_I32}, {"int32", ROCKE_DTYPE_I32},
{"fp8", "fp8e4m3"}, {"fp8e4m3", "fp8e4m3"}, {"e4m3", "fp8e4m3"},
{"bf8", "bf8e5m2"}, {"bf8e5m2", "bf8e5m2"}, {"fp6", "fp6e2m3"},
{"fp6e2m3", "fp6e2m3"}, {"bf6", "fp6e3m2"}, {"fp6e3m2", "fp6e3m2"},
{"fp4", "fp4e2m1"}, {"fp4e2m1", "fp4e2m1"},
{"f16", "fp16"},
{"half", "fp16"},
{"fp16", "fp16"},
{"bf16", "bf16"},
{"bfloat16", "bf16"},
{"f32", "fp32"},
{"float", "fp32"},
{"fp32", "fp32"},
{"tf32", "tf32"},
{"xf32", "tf32"},
{"f64", "fp64"},
{"double", "fp64"},
{"fp64", "fp64"},
{"fp8", "fp8e4m3"},
{"fp8e4m3", "fp8e4m3"},
{"e4m3", "fp8e4m3"},
{"bf8", "bf8e5m2"},
{"bf8e5m2", "bf8e5m2"},
{"fp6", "fp6e2m3"},
{"fp6e2m3", "fp6e2m3"},
{"bf6", "fp6e3m2"},
{"fp6e3m2", "fp6e3m2"},
{"fp4", "fp4e2m1"},
{"fp4e2m1", "fp4e2m1"},
/* Integers. RDNA integer WMMA instructions call their 8- and 4-bit operands
* "iu8"/"iu4" in the instruction name only; their operand dtypes are i8 / i4,
* because signedness is an instruction operand, not a property of the data.
* "i32" is the integer accumulator. */
{"i8", "i8"},
{"int8", "i8"},
{"i4", "i4"},
{"int4", "i4"},
{"i32", ROCKE_DTYPE_I32},
{"int32", ROCKE_DTYPE_I32},
/* Unsigned integers (logical types; no unsigned arithmetic yet). */
{"u8", "u8"},
{"uint8", "u8"},
{"u4", "u4"},
{"uint4", "u4"},
};
#define K_NUM_DTYPE_ALIASES ((int)(sizeof(k_dtype_aliases) / sizeof(k_dtype_aliases[0])))

Expand Down Expand Up @@ -124,16 +157,29 @@ const char* rocke_normalize_dtype(const char* name, char* lowered, size_t cap)
}

static const rocke_dtype_info_t k_dtype_info[] = {
{"fp64", ROCKE_DTYPE_FLOAT, 64}, {"fp32", ROCKE_DTYPE_FLOAT, 32},
{"tf32", ROCKE_DTYPE_FLOAT, 32}, {"fp16", ROCKE_DTYPE_FLOAT, 16},
{"bf16", ROCKE_DTYPE_FLOAT, 16}, {"fp8e4m3", ROCKE_DTYPE_FLOAT, 8},
{"bf8e5m2", ROCKE_DTYPE_FLOAT, 8}, {"fp6e2m3", ROCKE_DTYPE_FLOAT, 6},
{"fp6e3m2", ROCKE_DTYPE_FLOAT, 6}, {"fp4e2m1", ROCKE_DTYPE_FLOAT, 4},
{"e8m0", ROCKE_DTYPE_FLOAT, 8}, {"e5m3", ROCKE_DTYPE_FLOAT, 8},
{"i4", ROCKE_DTYPE_INTEGER, 4}, {"iu4", ROCKE_DTYPE_INTEGER, 4},
{"i8", ROCKE_DTYPE_INTEGER, 8}, {"iu8", ROCKE_DTYPE_INTEGER, 8},
{"i16", ROCKE_DTYPE_INTEGER, 16}, {"i32", ROCKE_DTYPE_INTEGER, 32},
{"i64", ROCKE_DTYPE_INTEGER, 64}, {"i1", ROCKE_DTYPE_PREDICATE, 1},
/* Floating point, grouped as in _DTYPE_INFO. */
{"fp64", ROCKE_DTYPE_FLOAT, 64},
{"fp32", ROCKE_DTYPE_FLOAT, 32},
{"tf32", ROCKE_DTYPE_FLOAT, 32},
{"fp16", ROCKE_DTYPE_FLOAT, 16},
{"bf16", ROCKE_DTYPE_FLOAT, 16},
{"fp8e4m3", ROCKE_DTYPE_FLOAT, 8},
{"bf8e5m2", ROCKE_DTYPE_FLOAT, 8},
{"fp6e2m3", ROCKE_DTYPE_FLOAT, 6},
{"fp6e3m2", ROCKE_DTYPE_FLOAT, 6},
{"fp4e2m1", ROCKE_DTYPE_FLOAT, 4},
{"e8m0", ROCKE_DTYPE_FLOAT, 8},
{"e5m3", ROCKE_DTYPE_FLOAT, 8},
/* Integers. */
{"i4", ROCKE_DTYPE_INTEGER, 4},
{"i8", ROCKE_DTYPE_INTEGER, 8},
{"u4", ROCKE_DTYPE_INTEGER, 4},
{"u8", ROCKE_DTYPE_INTEGER, 8},
{"i16", ROCKE_DTYPE_INTEGER, 16},
{"i32", ROCKE_DTYPE_INTEGER, 32},
{"i64", ROCKE_DTYPE_INTEGER, 64},
/* Predicates. */
{"i1", ROCKE_DTYPE_PREDICATE, 1},
};

const rocke_dtype_info_t* rocke_dtype_info(const char* name)
Expand All @@ -147,3 +193,11 @@ const rocke_dtype_info_t* rocke_dtype_info(const char* name)
return &info;
return NULL;
}

const rocke_dtype_info_t* rocke_require_dtype_info(const char* name)
{
const rocke_dtype_info_t* info = rocke_dtype_info(name);
if(!info)
throw ckc::ValueError(ckc::format_error("unknown dtype '%s'", name ? name : "(null)"));
return info;
}
Loading
Loading