teeny_cuda/compiler/
mod.rs1use std::ffi::{c_char, c_void};
18use std::ptr;
19
20use teeny_core::device::program::Kernel;
21
22use crate::compiler::options::Options;
23use crate::cuda;
24use crate::device::program::CudaProgram;
25use crate::errors::{Error, Result};
26
27pub mod aot;
29pub mod graph;
31pub mod options;
33pub mod target;
35
36pub struct PtxCompiler {
38 compiler: cuda::nvPTXCompilerHandle,
39}
40
41impl PtxCompiler {
42 pub fn try_new(ptx: &[u8]) -> Result<Self> {
47 let mut compiler = cuda::nvPTXCompilerHandle::default();
48 let result = unsafe {
49 cuda::nvPTXCompilerCreate(&mut compiler, ptx.len(), ptx.as_ptr().cast::<c_char>())
50 };
51
52 if result != cuda::nvPTXCompileResult_NVPTXCOMPILE_SUCCESS {
53 return Err(Error::NvptxCompileError {
54 code: result,
55 log: String::new(),
56 }
57 .into());
58 }
59 Ok(PtxCompiler { compiler })
60 }
61
62 pub fn compile(&mut self, options: &Options) -> Result<Vec<u8>> {
64 let compile_options = options.to_compile_options();
65 let num_options = compile_options.len() as i32;
66 eprintln!("[nvPTX] compile options: {compile_options:?}");
67
68 let cstrs: Vec<std::ffi::CString> = compile_options
70 .iter()
71 .map(|s| std::ffi::CString::new(s.as_str()).map_err(|e| Error::CStringError(e).into()))
72 .collect::<Result<Vec<std::ffi::CString>>>()?;
73 let cptrs: Vec<*const c_char> = cstrs.iter().map(|cs| cs.as_ptr()).collect();
74
75 let result =
76 unsafe { cuda::nvPTXCompilerCompile(self.compiler, num_options, cptrs.as_ptr()) };
77
78 if result != cuda::nvPTXCompileResult_NVPTXCOMPILE_SUCCESS {
79 let log = self.error_log();
81 return Err(Error::NvptxCompileError { code: result, log }.into());
82 }
83
84 let mut binary_size = 0usize;
85 let result =
86 unsafe { cuda::nvPTXCompilerGetCompiledProgramSize(self.compiler, &mut binary_size) };
87 if result != cuda::nvPTXCompileResult_NVPTXCOMPILE_SUCCESS {
88 return Err(Error::NvptxCompileError {
89 code: result,
90 log: String::new(),
91 }
92 .into());
93 }
94
95 let mut binary = vec![0u8; binary_size];
96 let result = unsafe {
97 cuda::nvPTXCompilerGetCompiledProgram(
98 self.compiler,
99 binary.as_mut_ptr().cast::<c_void>(),
100 )
101 };
102 if result != cuda::nvPTXCompileResult_NVPTXCOMPILE_SUCCESS {
103 return Err(Error::NvptxCompileError {
104 code: result,
105 log: String::new(),
106 }
107 .into());
108 }
109
110 Ok(binary)
111 }
112
113 fn error_log(&self) -> String {
114 let mut log_size = 0usize;
115 let result = unsafe { cuda::nvPTXCompilerGetErrorLogSize(self.compiler, &mut log_size) };
116 if result != cuda::nvPTXCompileResult_NVPTXCOMPILE_SUCCESS || log_size == 0 {
117 return String::new();
118 }
119 let mut buf = vec![0u8; log_size];
120 let result = unsafe {
121 cuda::nvPTXCompilerGetErrorLog(self.compiler, buf.as_mut_ptr().cast::<c_char>())
122 };
123 if result != cuda::nvPTXCompileResult_NVPTXCOMPILE_SUCCESS {
124 return String::new();
125 }
126 String::from_utf8_lossy(&buf)
127 .trim_end_matches('\0')
128 .to_string()
129 }
130
131 pub fn compile_program<K: Kernel>(
135 &mut self,
136 options: &Options,
137 ) -> Result<CudaProgram<'static, K>> {
138 let cubin = self.compile(options)?;
139 CudaProgram::try_new(&cubin, options.entry.as_str())
140 }
141}
142
143impl Drop for PtxCompiler {
144 fn drop(&mut self) {
145 let result = unsafe { cuda::nvPTXCompilerDestroy(ptr::addr_of_mut!(self.compiler)) };
146 if result != cuda::nvPTXCompileResult_NVPTXCOMPILE_SUCCESS {
147 eprintln!("Failed to destroy NVPTX compiler: {}", result);
148 }
149 }
150}