1pub use cubecl_runtime::kernel::*;
5
6use alloc::string::{String, ToString};
7use core::{
8 fmt::Display,
9 sync::atomic::{AtomicI8, Ordering},
10};
11
12use cubecl_common::format::format_str;
13use cubecl_environment::backtrace::BackTrace;
14
15use crate::{
16 compiler::{CompilationError, Compiler},
17 config::{CubeClRuntimeConfig, RuntimeConfig, compilation::CompilationLogLevel},
18 id::KernelId,
19 server::CubeDim,
20};
21
22pub struct CompiledKernel<C: Compiler> {
24 pub entrypoint_name: String,
34
35 pub debug_name: Option<&'static str>,
53
54 pub source: String,
56 pub repr: Option<C::Representation>,
58 pub cube_dim: CubeDim,
60 pub io: Option<alloc::vec::Vec<BufferIOAttr>>,
66 pub debug_info: Option<DebugInformation>,
68}
69
70#[derive(new)]
72pub struct DebugInformation {
73 pub lang_tag: &'static str,
75 pub id: KernelId,
77}
78
79impl<C: Compiler> CompiledKernel<C> {
80 pub fn compile(
83 kernel: &dyn CubeKernel,
84 definition: KernelDefinition,
85 compiler: &mut C,
86 compilation_options: &C::CompilationOptions,
87 ) -> Result<Self, CompilationError> {
88 let entrypoint_name = definition.settings.kernel_name.clone();
89 let cube_dim = definition.settings.cube_dim.into();
90
91 if let Some(precompiled) = kernel.source() {
96 if precompiled.lang != compiler.lang_tag() {
97 return Err(CompilationError::Generic {
98 reason: alloc::format!(
99 "kernel `{}` carries {} source, but this compiler expects {}",
100 kernel.name(),
101 precompiled.lang,
102 compiler.lang_tag()
103 ),
104 backtrace: BackTrace::capture(),
105 });
106 }
107 return Ok(CompiledKernel {
108 entrypoint_name: precompiled.entrypoint_name,
109 debug_name: Some(kernel.name()),
110 source: precompiled.source,
111 io: None,
112 repr: None,
113 cube_dim,
114 debug_info: None,
115 });
116 }
117
118 let lower_level_ir = compiler.compile(definition, compilation_options)?;
119
120 Ok(CompiledKernel {
121 entrypoint_name,
122 debug_name: Some(kernel.name()),
123 source: lower_level_ir.to_string(),
124 io: C::buffer_io(&lower_level_ir),
125 repr: Some(lower_level_ir),
126 cube_dim,
127 debug_info: None,
128 })
129 }
130}
131
132static COMPILATION_LEVEL: AtomicI8 = AtomicI8::new(-1);
133
134fn compilation_level() -> u8 {
135 let compilation_level = COMPILATION_LEVEL.load(Ordering::Relaxed);
136 if compilation_level == -1 {
137 let val = match CubeClRuntimeConfig::get().compilation.logger.level {
138 CompilationLogLevel::Full => 2,
139 CompilationLogLevel::Disabled => 0,
140 CompilationLogLevel::Basic => 1,
141 };
142
143 COMPILATION_LEVEL.store(val, Ordering::Relaxed);
144 val as u8
145 } else {
146 compilation_level as u8
147 }
148}
149
150impl<C: Compiler> Display for CompiledKernel<C> {
151 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
152 match compilation_level() {
153 2 => self.format_full(f),
154 _ => self.format_basic(f),
155 }
156 }
157}
158
159impl<C: Compiler> CompiledKernel<C> {
160 fn format_basic(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
161 f.write_str("[Compiling kernel]")?;
162 if let Some(name) = self.debug_name {
163 if name.len() <= 32 {
164 f.write_fmt(format_args!(" {name}"))?;
165 } else {
166 f.write_fmt(format_args!(" {}", name.split('<').next().unwrap_or("")))?;
167 }
168 }
169
170 Ok(())
171 }
172
173 fn format_full(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
174 f.write_str("[START_KERNEL_COMPILATION]")?;
175
176 if let Some(name) = self.debug_name {
177 if name.len() <= 32 {
178 f.write_fmt(format_args!("\nname: {name}"))?;
179 } else {
180 let name = format_str(name, &[('<', '>')], false);
181 f.write_fmt(format_args!("\nname: {name}"))?;
182 }
183 }
184
185 if let Some(info) = &self.debug_info {
186 f.write_fmt(format_args!("\nid: {:#?}", info.id))?;
187 }
188
189 f.write_fmt(format_args!(
190 "
191source:
192```{}
193{}
194```
195[END_KERNEL_COMPILATION]
196",
197 self.debug_info
198 .as_ref()
199 .map(|info| info.lang_tag)
200 .unwrap_or(""),
201 self.source
202 ))
203 }
204}