use cubecl_core::ir::amd::GfxArch;
use cubecl_core::prelude::KernelDefinition;
use cubecl_cpp::shared::CompilationOptions;
use cubecl_cpp::{ComputeKernel, shared::CppCompiler, target::Hip};
use cubecl_server::compiler::{CompilationError, Compiler};
use cubecl_server::kernel::BufferIOAttr;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum HipBackend {
Cpp,
Llvm,
}
impl Default for HipBackend {
fn default() -> Self {
if cfg!(feature = "cpp") {
HipBackend::Cpp
} else {
HipBackend::Llvm
}
}
}
#[derive(Clone, Debug)]
pub enum HipCompiler {
Cpp(CppCompiler<Hip>),
Llvm(cubecl_llvm::PlironCompiler),
}
impl HipCompiler {
pub fn new(backend: HipBackend) -> Self {
match backend {
HipBackend::Cpp => HipCompiler::Cpp(CppCompiler::default()),
HipBackend::Llvm => HipCompiler::Llvm(cubecl_llvm::PlironCompiler {
target: cubecl_llvm::LlvmTarget::AmdGpu,
}),
}
}
}
impl Default for HipCompiler {
fn default() -> Self {
Self::new(HipBackend::default())
}
}
#[derive(Debug, Default, Clone)]
pub struct HipCompilationOptions {
pub cpp: CompilationOptions,
pub arch: Option<GfxArch>,
}
pub enum HipRepresentation {
Cpp(ComputeKernel),
Llvm(cubecl_llvm::AmdGpuModule),
}
impl core::fmt::Debug for HipRepresentation {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
HipRepresentation::Cpp(_) => f.write_str("HipRepresentation::Cpp"),
HipRepresentation::Llvm(module) => f
.debug_tuple("HipRepresentation::Llvm")
.field(module)
.finish(),
}
}
}
impl HipRepresentation {
pub fn shared_memory_size(&self) -> usize {
match self {
HipRepresentation::Cpp(kernel) => kernel.shared_memory_size,
HipRepresentation::Llvm(module) => module.shared_memory_size,
}
}
}
impl core::fmt::Display for HipRepresentation {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
HipRepresentation::Cpp(kernel) => write!(f, "{kernel}"),
HipRepresentation::Llvm(module) => write!(f, "{}", module.ir),
}
}
}
impl Compiler for HipCompiler {
type Representation = HipRepresentation;
type CompilationOptions = HipCompilationOptions;
fn buffer_io(repr: &Self::Representation) -> Option<Vec<BufferIOAttr>> {
match repr {
HipRepresentation::Cpp(kernel) => <CppCompiler<Hip> as Compiler>::buffer_io(kernel),
HipRepresentation::Llvm(module) => Some(module.io.clone()),
}
}
fn compile(
&mut self,
kernel: KernelDefinition,
options: &Self::CompilationOptions,
) -> Result<Self::Representation, CompilationError> {
match self {
HipCompiler::Cpp(compiler) => Ok(HipRepresentation::Cpp(
compiler.compile(kernel, &options.cpp)?,
)),
HipCompiler::Llvm(compiler) => {
let pliron_options = cubecl_llvm::PlironOptions {
grid_constants: false,
arch: options.arch.clone(),
..Default::default()
};
match compiler.compile(kernel, &pliron_options)? {
cubecl_llvm::PlironArtifact::AmdGpuCode(module) => {
Ok(HipRepresentation::Llvm(module))
}
_ => unreachable!("the HIP runtime always configures LlvmTarget::AmdGpu"),
}
}
}
}
fn extension(&self) -> &'static str {
match self {
HipCompiler::Cpp(compiler) => compiler.extension(),
HipCompiler::Llvm(_) => "ll",
}
}
fn lang_tag(&self) -> &'static str {
match self {
HipCompiler::Cpp(compiler) => compiler.lang_tag(),
HipCompiler::Llvm(compiler) => compiler.lang_tag(),
}
}
}