1use super::types::{AddressSpace, Modifier, Opcode, PtxType, SmTarget};
4
5#[derive(Debug, Clone, Default)]
7pub struct PtxModule {
8 pub version: (u8, u8),
10 pub target: SmTarget,
12 pub address_size: u8,
14 pub globals: Vec<GlobalDecl>,
16 pub kernels: Vec<KernelDef>,
18 pub functions: Vec<FunctionDef>,
20}
21
22#[derive(Debug, Clone)]
24pub struct KernelDef {
25 pub name: String,
27 pub is_entry: bool,
29 pub params: Vec<Param>,
31 pub registers: Vec<RegisterDecl>,
33 pub shared_mem: Vec<SharedMemDecl>,
35 pub body: Vec<Statement>,
37}
38
39#[derive(Debug, Clone)]
41pub struct FunctionDef {
42 pub name: String,
44 pub return_type: Option<PtxType>,
46 pub params: Vec<Param>,
48 pub registers: Vec<RegisterDecl>,
50 pub body: Vec<Statement>,
52}
53
54#[derive(Debug, Clone)]
56pub struct GlobalDecl {
57 pub name: String,
59 pub space: AddressSpace,
61 pub ty: PtxType,
63 pub size: usize,
65 pub init: Option<Vec<u8>>,
67}
68
69#[derive(Debug, Clone)]
71pub struct Param {
72 pub name: String,
74 pub ty: PtxType,
76}
77
78#[derive(Debug, Clone)]
80pub struct RegisterDecl {
81 pub name: String,
83 pub ty: PtxType,
85}
86
87#[derive(Debug, Clone)]
89pub struct SharedMemDecl {
90 pub name: String,
92 pub size: usize,
94 pub ty: PtxType,
96}
97
98#[derive(Debug, Clone)]
100pub enum Statement {
101 Label(String),
103 Instruction(Instruction),
105 Directive(Directive),
107 Comment(String),
109}
110
111#[derive(Debug, Clone)]
113pub struct Instruction {
114 pub opcode: Opcode,
116 pub modifiers: Vec<Modifier>,
118 pub operands: Vec<Operand>,
120 pub predicate: Option<Predicate>,
122 pub location: SourceLocation,
124}
125
126#[derive(Debug, Clone)]
128pub enum Directive {
129 Loc { file: u32, line: u32, column: u32 },
131 Pragma(String),
133 Other(String),
135}
136
137#[derive(Debug, Clone)]
139pub enum Operand {
140 Register(String),
142 Memory(String),
144 Immediate(i64),
146 ImmediateFloat(f64),
148 Label(String),
150 Vector(Vec<Operand>),
152}
153
154impl Operand {
155 pub fn is_register(&self) -> bool {
157 matches!(self, Operand::Register(_))
158 }
159
160 pub fn is_memory(&self) -> bool {
162 matches!(self, Operand::Memory(_))
163 }
164
165 pub fn as_register(&self) -> Option<&str> {
167 match self {
168 Operand::Register(name) => Some(name),
169 _ => None,
170 }
171 }
172}
173
174impl std::fmt::Display for Operand {
175 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
176 match self {
177 Operand::Register(name) => write!(f, "{}", name),
178 Operand::Memory(addr) => write!(f, "{}", addr),
179 Operand::Immediate(val) => write!(f, "{}", val),
180 Operand::ImmediateFloat(val) => write!(f, "{}", val),
181 Operand::Label(name) => write!(f, "{}", name),
182 Operand::Vector(ops) => {
183 write!(f, "{{")?;
184 for (i, op) in ops.iter().enumerate() {
185 if i > 0 {
186 write!(f, ", ")?;
187 }
188 write!(f, "{}", op)?;
189 }
190 write!(f, "}}")
191 }
192 }
193 }
194}
195
196#[derive(Debug, Clone)]
198pub struct Predicate {
199 pub register: String,
201 pub negated: bool,
203}
204
205#[derive(Debug, Clone, Default)]
207pub struct SourceLocation {
208 pub line: usize,
210 pub column: usize,
212 pub file: Option<String>,
214}
215
216impl std::fmt::Display for SourceLocation {
217 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
218 if let Some(file) = &self.file {
219 write!(f, "{}:{}:{}", file, self.line, self.column)
220 } else {
221 write!(f, "{}:{}", self.line, self.column)
222 }
223 }
224}
225
226#[cfg(test)]
227mod tests {
228 use super::*;
229
230 #[test]
231 fn test_operand_display() {
232 assert_eq!(format!("{}", Operand::Register("%r0".into())), "%r0");
233 assert_eq!(format!("{}", Operand::Memory("[%r0]".into())), "[%r0]");
234 assert_eq!(format!("{}", Operand::Immediate(42)), "42");
235 }
236
237 #[test]
238 fn test_source_location_display() {
239 let loc = SourceLocation {
240 line: 10,
241 column: 5,
242 file: Some("test.ptx".into()),
243 };
244 assert_eq!(format!("{}", loc), "test.ptx:10:5");
245
246 let loc = SourceLocation {
247 line: 10,
248 column: 5,
249 file: None,
250 };
251 assert_eq!(format!("{}", loc), "10:5");
252 }
253
254 #[test]
255 fn test_operand_type_checks() {
256 let reg = Operand::Register("%r0".into());
257 assert!(reg.is_register());
258 assert!(!reg.is_memory());
259
260 let mem = Operand::Memory("[%r0]".into());
261 assert!(!mem.is_register());
262 assert!(mem.is_memory());
263 }
264}