Skip to main content

ptx_parser/type/
function.rs

1use super::common::{Instruction, Label};
2use super::variable::{ParameterDirective, VariableDirective};
3use crate::Spanned;
4use crate::parser::Span;
5use crate::r#type::{AttributeDirective, DataType, FunctionSymbol, VariableSymbol};
6use serde::Serialize;
7
8/// Alias directive relating one function symbol to another.
9///
10/// Syntax:
11/// .alias fAlias, fAliasee;
12///
13/// Example:
14/// .alias foo, bar;
15#[derive(Debug, Clone, PartialEq, Spanned, Serialize)]
16pub struct AliasFunctionDirective {
17    pub alias: FunctionSymbol,
18    pub target: FunctionSymbol,
19    pub span: Span,
20}
21
22/// A PTX kernel declared with the `.entry` directive.
23#[derive(Debug, Clone, PartialEq, Spanned, Serialize)]
24pub struct FuncFunctionDirective {
25    /// Example:
26    /// .func .attribute(.unified(0xAB, 0xCD)) bar() { ... }
27    pub attributes: Vec<AttributeDirective>,
28    /// Optional return param.
29    ///
30    /// Example:
31    /// .func (.param .u32 rval) bar(.param .u32 N, .param .align 4 .b8 numbers[]) { ... }
32    pub return_param: Option<ParameterDirective>,
33    /// Function name.
34    pub name: FunctionSymbol,
35    /// Function parameters.
36    ///
37    /// Example:
38    /// .func (.param .u32 rval) bar(.param .u32 N, .param .align 4 .b8 numbers[])
39    pub params: Vec<ParameterDirective>,
40    /// Optional directives.
41    ///
42    /// Example:
43    /// .func foo (.reg .b32 N, .reg .f64 dbl) .noreturn { ... }
44    pub directives: Vec<FuncFunctionHeaderDirective>,
45    /// Pre-body declarations (.reg, .local, .shared, .param) that appear between
46    /// the function header and the body. These are allowed by PTX but must appear
47    /// before the opening brace.
48    ///
49    /// Example:
50    /// .func foo()
51    ///     .reg .b32 %r0;
52    ///     .local .b8 stack[16];
53    /// { ... }
54    pub pre_body_declarations: Vec<StatementDirective>,
55    /// Optional function body. Without body represents a function prototype.
56    pub body: Option<FunctionBody>,
57    pub span: Span,
58}
59
60/// A PTX device function declared with the `.func` directive.
61#[derive(Debug, Clone, PartialEq, Spanned, Serialize)]
62pub struct EntryFunctionDirective {
63    /// Name of the entry function.
64    pub name: FunctionSymbol,
65    /// Function parameters.
66    pub params: Vec<ParameterDirective>,
67    /// Optional directives.
68    pub directives: Vec<EntryFunctionHeaderDirective>,
69    /// Optional function body. Without body represents a function prototype.
70    pub body: Option<FunctionBody>,
71    pub span: Span,
72}
73
74/// Directive tokens that may decorate a PTX function header.
75#[derive(Debug, Clone, PartialEq, Spanned, Serialize)]
76pub enum FuncFunctionHeaderDirective {
77    /// Syntax:
78    /// .noreturn
79    ///
80    /// Example:
81    /// .func foo .noreturn { ... }
82    NoReturn { span: Span },
83    /// Syntax:
84    /// .pragma list-of-strings ;
85    ///
86    /// Example:
87    ///.entry foo .pragma "nounroll"; { ... } // disable unrolling for current kernel
88    Pragma { args: Vec<String>, span: Span },
89    /// Syntax:
90    /// .abi_preserve N
91    ///
92    /// Example:
93    /// .entry foo .abi_preserve 8 { ... }
94    AbiPreserve { value: u32, span: Span },
95    /// Syntax:
96    /// .abi_preserve_control N
97    ///
98    /// Example:
99    /// .entry foo .abi_preserve_control 16 { ... }
100    AbiPreserveControl { value: u32, span: Span },
101}
102
103/// Directive tokens that may decorate a PTX function header.
104#[derive(Debug, Clone, PartialEq, Spanned, Serialize)]
105pub enum EntryFunctionHeaderDirective {
106    /// Syntax:
107    /// .maxnreg n
108    ///
109    /// Example:
110    /// .entry foo .maxnreg 16 { ... }  // max regs per thread = 16
111    MaxNReg { value: u32, span: Span },
112    /// Syntax:
113    /// .maxntid nx
114    /// .maxntid nx, ny
115    /// .maxntid nx, ny, nz
116    ///
117    /// Example:
118    /// .entry foo .maxntid 256       { ... }  // max threads = 256
119    /// .entry bar .maxntid 16,16,4   { ... }  // max threads = 1024
120    MaxNTid { dim: FunctionDim, span: Span },
121    /// Syntax:
122    /// .reqntid nx
123    /// .reqntid nx, ny
124    /// .reqntid nx, ny, nz
125    ///
126    /// Example:
127    /// .entry foo .reqntid 256       { ... }  // num threads = 256
128    /// .entry bar .reqntid 16,16,4   { ... }  // num threads = 1024
129    ReqNTid { dim: FunctionDim, span: Span },
130    /// Syntax:
131    /// .minnctapersm ncta
132    ///
133    /// Example:
134    /// .entry foo .maxntid 256 .minnctapersm 4 { ... }
135    MinNCtaPerSm { value: u32, span: Span },
136    /// Syntax:
137    /// .maxnctapersm ncta
138    ///
139    /// Example:
140    /// .entry foo .maxntid 256 .maxnctapersm 4 { ... }
141    MaxNCtaPerSm { value: u32, span: Span },
142    /// Syntax:
143    /// .pragma list-of-strings ;
144    ///
145    /// Example:
146    ///.entry foo .pragma "nounroll"; { ... } // disable unrolling for current kernel
147    Pragma { args: Vec<String>, span: Span },
148    /// Syntax:
149    /// .reqnctapercluster nx
150    /// .reqnctapercluster nx, ny
151    /// .reqnctapercluster nx, ny, nz
152    ///
153    /// Example:
154    /// .entry foo .reqnctapercluster 2         { . . . }
155    /// .entry bar .reqnctapercluster 2, 2, 1   { . . . }
156    /// .entry ker .reqnctapercluster 3, 2      { . . . }
157    ReqNctaPerCluster { dim: FunctionDim, span: Span },
158    /// Syntax:
159    /// .explicitcluster
160    ///
161    /// Example:
162    /// .entry foo .explicitcluster         { . . . }
163    ExplicitCluster { span: Span },
164    /// Syntax:
165    /// .maxclusterrank n
166    ///
167    /// Example:
168    /// .entry foo ..maxclusterrank 8         { . . . }
169    MaxClusterRank { value: u32, span: Span },
170    /// Syntax:
171    ///.blocksareclusters
172    ///
173    /// Example:
174    /// .entry foo .reqntid 32, 32, 1 .reqnctapercluster 32, 32, 1 .blocksareclusters { ... } // only allowed when with .reqnctapercluster and .reqntid
175    BlocksAreClusters { span: Span },
176}
177
178/// Statements contained within a PTX function body.
179#[derive(Debug, Clone, Default, PartialEq, Spanned, Serialize)]
180pub struct FunctionBody {
181    pub statements: Vec<FunctionStatement>,
182    pub span: Span,
183}
184
185/// Nested statement block enclosed in braces.
186/// Executable items that appear within a function body.
187#[derive(Debug, Clone, PartialEq, Spanned, Serialize)]
188pub enum FunctionStatement {
189    Label {
190        label: Label,
191        span: Span,
192    },
193    Directive {
194        directive: StatementDirective,
195        span: Span,
196    },
197    Instruction {
198        instruction: Instruction,
199        span: Span,
200    },
201    Block {
202        statements: Vec<FunctionStatement>,
203        span: Span,
204    },
205}
206
207/// Directive that declares a register variable inside a function body.
208///
209/// Syntax:
210/// `.reg {.v2|.v4} .ty name<range>`
211#[derive(Debug, Clone, PartialEq, Spanned, Serialize)]
212pub struct RegisterDirective {
213    /// Optional vector width applied to every declared register symbol.
214    pub vector: Option<RegisterVectorWidth>,
215    pub ty: DataType,
216    pub registers: Vec<RegisterTarget>,
217    pub span: Span,
218}
219
220/// Vector width attached to a PTX register declaration.
221///
222/// This is declaration syntax rather than an instruction modifier. Each
223/// declared symbol owns components addressed with suffixes such as `.x`.
224#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
225pub enum RegisterVectorWidth {
226    V2,
227    V4,
228}
229
230#[derive(Debug, Clone, PartialEq, Spanned, Serialize)]
231pub struct RegisterTarget {
232    pub name: VariableSymbol,
233    pub range: Option<u32>,
234    pub span: Span,
235}
236
237/// Directive that applies to individual statements.
238#[derive(Debug, Clone, PartialEq, Spanned, Serialize)]
239pub enum StatementDirective {
240    Loc {
241        directive: LocationDirective,
242        span: Span,
243    },
244    Pragma {
245        directive: PragmaDirective,
246        span: Span,
247    },
248    Section {
249        directive: SectionDirective,
250        span: Span,
251    },
252    Reg {
253        directive: RegisterDirective,
254        span: Span,
255    },
256    Local {
257        directive: VariableDirective,
258        span: Span,
259    },
260    Param {
261        directive: VariableDirective,
262        span: Span,
263    },
264    Shared {
265        directive: VariableDirective,
266        span: Span,
267    },
268    Dwarf {
269        directive: DwarfDirective,
270        span: Span,
271    },
272    BranchTargets {
273        directive: BranchTargetsDirective,
274        span: Span,
275    },
276    CallTargets {
277        directive: CallTargetsDirective,
278        span: Span,
279    },
280    CallPrototype {
281        directive: CallPrototypeDirective,
282        span: Span,
283    },
284}
285
286/// Raw dwarf directive emitted by the compiler (e.g. `@@dwarf`).
287///
288/// Syntax:
289/// ```text
290/// @@DWARF dwarf-string
291///
292/// dwarf-string may have one of the
293/// .byte   byte-list   // comma-separated hexadecimal byte values
294/// .4byte  int32-list  // comma-separated hexadecimal integers in range [0..2^32-1]
295/// .quad   int64-list  // comma-separated hexadecimal integers in range [0..2^64-1]
296/// .4byte  label
297/// .quad   label
298/// ```
299#[derive(Debug, Clone, PartialEq, Spanned, Serialize)]
300pub struct DwarfDirective {
301    pub kind: DwarfDirectiveKind,
302    pub span: Span,
303}
304
305#[derive(Debug, Clone, PartialEq, Serialize)]
306pub enum DwarfDirectiveKind {
307    ByteValues(Vec<u8>),
308    FourByteValues(Vec<u32>),
309    QuadValues(Vec<u64>),
310    FourByteLabel(Label),
311    QuadLabel(Label),
312}
313
314/// Structured representation of a `.section` directive inside a function body.
315///
316/// Syntax:
317/// ```text
318/// .section section_name { dwarf-lines }
319///
320/// dwarf-lines have the following formats:
321///   .b8    byte-list       // integers in [-128..255]
322///   .b16   int16-list      // integers in [-2^15..2^16-1]
323///   .b32   int32-list      // integers in [-2^31..2^32-1]
324///   label:                 // define label inside the debug section
325///   .b64   int64-list      // integers in [-2^63..2^64-1]
326///   .b32   label
327///   .b64   label
328///   .b32   label+imm       // label plus constant integer byte offset (32-bit)
329///   .b64   label+imm       // label plus constant integer byte offset (64-bit)
330///   .b32   label1-label2   // difference between labels in same section (32-bit)
331///   .b64   label3-label4   // difference between labels in same section (64-bit)
332/// ```
333///
334/// Example:
335/// ```text
336///     .section .debug_str {
337///    info_string0:
338///     .b8 95  // _
339///     .b8 90  // z
340///     .b8 51  // 3
341///     .b8 102 // f
342///     .b8 111 // o
343///     .b8 111 // o
344///     .b8 118 // v
345///     .b8 0
346///    info_string1:
347///     .b8 95  // _
348///     .b8 90  // z
349///     .b8 51  // 3
350///     .b8 98  // b
351///     .b8 97  // a
352///     .b8 114 // r
353///     .b8 118 // v
354///     .b8 0
355///     .b8 95  // _
356///     .b8 90  // z
357///     .b8 51  // 3
358///     .b8 99  // c
359///     .b8 97  // a
360///     .b8 114 // r
361///     .b8 118 // v
362///     .b8 0
363///    }
364/// ```
365#[derive(Debug, Clone, PartialEq, Spanned, Serialize)]
366pub struct SectionDirective {
367    pub name: String,
368    pub entries: Vec<SectionEntry>,
369    pub span: Span,
370}
371
372#[derive(Debug, Clone, PartialEq, Serialize)]
373pub enum SectionEntry {
374    Label { label: Label, span: Span },
375    Directive(StatementSectionDirectiveLine),
376}
377
378#[derive(Debug, Clone, PartialEq, Spanned, Serialize)]
379pub enum StatementSectionDirectiveLine {
380    B8 { values: Vec<i16>, span: Span },
381    B16 { values: Vec<i32>, span: Span },
382    B32Immediate { values: Vec<i64>, span: Span },
383    B64Immediate { values: Vec<i128>, span: Span },
384    B32Label { labels: Label, span: Span },
385    B64Label { labels: Label, span: Span },
386    B32LabelPlusImm { entries: (Label, i32), span: Span },
387    B64LabelPlusImm { entries: (Label, i64), span: Span },
388    B32LabelDiff { entries: (Label, Label), span: Span },
389    B64LabelDiff { entries: (Label, Label), span: Span },
390}
391
392/// Structured representation of a `.loc` directive inside a PTX function.
393///
394/// Syntax:
395///     .loc file_index line_number column_position
396///     .loc file_index line_number column_position, function_name label {+ immediate}, inlined_at file_index2 line_number2 column_position2
397#[derive(Debug, Clone, PartialEq, Spanned, Serialize)]
398pub struct LocationDirective {
399    pub file_index: u32,
400    pub line: u32,
401    pub column: u32,
402    /// Optional metadata for an inlined function. PTX requires
403    /// `function_name` and `inlined_at` to occur together.
404    pub function: Option<LocationFunctionInfo>,
405    pub span: Span,
406}
407
408/// Debug-string reference and call site attached to an inlined `.loc`.
409#[derive(Debug, Clone, PartialEq, Spanned, Serialize)]
410pub struct LocationFunctionInfo {
411    /// Label in the `.debug_str` section that names the inlined function.
412    pub label: Label,
413    /// Optional byte offset from `label`.
414    pub label_offset: Option<i64>,
415    pub inlined_at: LocationInlinedAt,
416    pub span: Span,
417}
418
419/// Source position from which the current `.loc` position was inlined.
420#[derive(Debug, Clone, PartialEq, Spanned, Serialize)]
421pub struct LocationInlinedAt {
422    pub file_index: u32,
423    pub line: u32,
424    pub column: u32,
425    pub span: Span,
426}
427
428/// Structured representation of a `.pragma` directive.
429///
430/// Syntax:
431///     .pragma "nounroll";
432///     .pragma "used_bytes_mask mask";
433///     .pragma "enable_smem_spilling";
434///     .pragma "frequency n";
435#[derive(Debug, Clone, PartialEq, Spanned, Serialize)]
436pub struct PragmaDirective {
437    pub kind: PragmaDirectiveKind,
438    pub span: Span,
439}
440
441#[derive(Debug, Clone, PartialEq, Serialize)]
442pub enum PragmaDirectiveKind {
443    Nounroll,
444    UsedBytesMask { mask: String },
445    EnableSmemSpilling,
446    Frequency { value: u32 },
447    Raw(String),
448}
449
450/// Structured representation of a `.branchtargets` directive.
451///
452/// Syntax:
453///    .branchtargets label1, label2, label3, ...;
454#[derive(Debug, Clone, PartialEq, Spanned, Serialize)]
455pub struct BranchTargetsDirective {
456    pub labels: Vec<Label>,
457    pub span: Span,
458}
459
460/// Structured representation of a `.calltargets` directive.
461///
462/// Syntax:
463///     .calltargets func1, func2, func3, ...;
464#[derive(Debug, Clone, PartialEq, Spanned, Serialize)]
465pub struct CallTargetsDirective {
466    pub targets: Vec<FunctionSymbol>,
467    pub span: Span,
468}
469
470/// Structured representation of a `.callprototype` directive.
471///
472/// Syntax:
473///     // no input or return parameters
474///     label: .callprototype _ .noreturn {.abi_preserve N} {.abi_preserve_control N};
475///     // input params, no return params
476///     label: .callprototype _ (param-list) .noreturn {.abi_preserve N} {.abi_preserve_control N};
477///     // no input params, // return params
478///     label: .callprototype (ret-param) _ {.abi_preserve N} {.abi_preserve_control N};
479///     // input, return parameters
480///     label: .callprototype (ret-param) _ (param-list) {.abi_preserve N} {.abi_preserve_control N};
481#[derive(Debug, Clone, PartialEq, Spanned, Serialize)]
482pub struct CallPrototypeDirective {
483    pub return_param: Option<ParameterDirective>,
484    pub params: Vec<ParameterDirective>,
485    pub noreturn: bool,
486    pub abi_preserve: Option<u32>,
487    pub abi_preserve_control: Option<u32>,
488    pub span: Span,
489}
490
491/// Dimension triplet used by several function header directives.
492#[derive(Debug, Clone, PartialEq, Spanned, Serialize)]
493pub enum FunctionDim {
494    X { x: u32, span: Span },
495    XY { x: u32, y: u32, span: Span },
496    XYZ { x: u32, y: u32, z: u32, span: Span },
497}