Add tracing to custom parsers (#469)
Some checks are pending
ZLUDA / Build (Linux) (push) Waiting to run
ZLUDA / Build (Windows) (push) Waiting to run
ZLUDA / Build AMD GPU unit tests (push) Waiting to run
ZLUDA / Run AMD GPU unit tests (push) Blocked by required conditions

This commit is contained in:
Violet 2025-08-07 11:51:56 -07:00 committed by GitHub
commit ef98c1e0ba
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -396,18 +396,21 @@ pub fn parse_module_checked<'input>(
}
fn module<'a, 'input>(stream: &mut PtxParser<'a, 'input>) -> PResult<ast::Module<'input>> {
(
version,
target,
opt(address_size),
repeat_without_none(directive),
eof,
)
.map(|(version, _, _, directives, _)| ast::Module {
trace(
"module",
(
version,
directives,
})
.parse_next(stream)
target,
opt(address_size),
repeat_without_none(directive),
eof,
)
.map(|(version, _, _, directives, _)| ast::Module {
version,
directives,
}),
)
.parse_next(stream)
}
fn address_size<'a, 'input>(stream: &mut PtxParser<'a, 'input>) -> PResult<()> {
@ -440,18 +443,20 @@ fn shader_model<'a>(stream: &mut &str) -> PResult<(u32, Option<char>)> {
fn directive<'a, 'input>(
stream: &mut PtxParser<'a, 'input>,
) -> PResult<Option<ast::Directive<'input, ast::ParsedOperand<&'input str>>>> {
with_recovery(
alt((
// When adding a new variant here remember to add its first token into recovery parser down below
function.map(|(linking, func)| Some(ast::Directive::Method(linking, func))),
file.map(|_| None),
section.map(|_| None),
(module_variable, Token::Semicolon)
.map(|((linking, var), _)| Some(ast::Directive::Variable(linking, var))),
)),
(
any,
take_till(1.., |(token, _)| match token {
trace(
"directive",
with_recovery(
alt((
// When adding a new variant here remember to add its first token into recovery parser down below
function.map(|(linking, func)| Some(ast::Directive::Method(linking, func))),
file.map(|_| None),
section.map(|_| None),
(module_variable, Token::Semicolon)
.map(|((linking, var), _)| Some(ast::Directive::Variable(linking, var))),
)),
(
any,
take_till(1.., |(token, _)| match token {
// visibility
Token::DotExtern | Token::DotVisible | Token::DotWeak
// methods
@ -462,11 +467,12 @@ fn directive<'a, 'input>(
| Token::DotFile | Token::DotSection => true,
_ => false,
}),
)
.map(|(_, x)| x),
|text| PtxError::UnrecognizedDirective(text.unwrap_or("")),
)
.map(|(_, x)| x),
|text| PtxError::UnrecognizedDirective(text.unwrap_or("")),
.map(Option::flatten),
)
.map(Option::flatten)
.parse_next(stream)
}
@ -483,26 +489,32 @@ fn module_variable<'a, 'input>(
}
fn file<'a, 'input>(stream: &mut PtxParser<'a, 'input>) -> PResult<()> {
(
Token::DotFile,
u32,
Token::String,
opt((Token::Comma, u32, Token::Comma, u32)),
trace(
"file",
(
Token::DotFile,
u32,
Token::String,
opt((Token::Comma, u32, Token::Comma, u32)),
)
.void(),
)
.void()
.parse_next(stream)
.parse_next(stream)
}
fn section<'a, 'input>(stream: &mut PtxParser<'a, 'input>) -> PResult<()> {
(
Token::DotSection.void(),
dot_ident.void(),
Token::LBrace.void(),
repeat::<_, _, (), _, _>(0.., section_dwarf_line),
Token::RBrace.void(),
trace(
"section",
(
Token::DotSection.void(),
dot_ident.void(),
Token::LBrace.void(),
repeat::<_, _, (), _, _>(0.., section_dwarf_line),
Token::RBrace.void(),
)
.void(),
)
.void()
.parse_next(stream)
.parse_next(stream)
}
fn section_dwarf_line<'a, 'input>(stream: &mut PtxParser<'a, 'input>) -> PResult<()> {
@ -535,23 +547,26 @@ fn function<'a, 'input>(
ast::LinkingDirective,
ast::Function<'input, &'input str, ast::Statement<ParsedOperand<&'input str>>>,
)> {
let (linking, function) = (
linking_directives,
method_declaration,
repeat(0.., tuning_directive),
function_body,
let (linking, function) = trace(
"function",
(
linking_directives,
method_declaration,
repeat(0.., tuning_directive),
function_body,
)
.map(|(linking, func_directive, tuning, body)| {
(
linking,
ast::Function {
func_directive,
tuning,
body,
},
)
}),
)
.map(|(linking, func_directive, tuning, body)| {
(
linking,
ast::Function {
func_directive,
tuning,
body,
},
)
})
.parse_next(stream)?;
.parse_next(stream)?;
stream.state.record_function(&function.func_directive);
Ok((linking, function))
}
@ -559,16 +574,19 @@ fn function<'a, 'input>(
fn linking_directives<'a, 'input>(
stream: &mut PtxParser<'a, 'input>,
) -> PResult<ast::LinkingDirective> {
repeat(
0..,
dispatch! { any;
(Token::DotExtern, _) => empty.value(ast::LinkingDirective::EXTERN),
(Token::DotVisible, _) => empty.value(ast::LinkingDirective::VISIBLE),
(Token::DotWeak, _) => empty.value(ast::LinkingDirective::WEAK),
_ => fail
},
trace(
"linking_directives",
repeat(
0..,
dispatch! { any;
(Token::DotExtern, _) => empty.value(ast::LinkingDirective::EXTERN),
(Token::DotVisible, _) => empty.value(ast::LinkingDirective::VISIBLE),
(Token::DotWeak, _) => empty.value(ast::LinkingDirective::WEAK),
_ => fail
},
)
.fold(|| ast::LinkingDirective::NONE, |x, y| x | y),
)
.fold(|| ast::LinkingDirective::NONE, |x, y| x | y)
.parse_next(stream)
}
@ -680,11 +698,11 @@ fn tuple1to3_u32<'a, 'input>(stream: &mut PtxParser<'a, 'input>) -> PResult<(u32
fn function_body<'a, 'input>(
stream: &mut PtxParser<'a, 'input>,
) -> PResult<Option<Vec<ast::Statement<ParsedOperandStr<'input>>>>> {
dispatch! {any;
trace("function_body", dispatch! {any;
(Token::LBrace, _) => terminated(repeat_without_none(statement), Token::RBrace).map(Some),
(Token::Semicolon, _) => empty.map(|_| None),
_ => fail
}
})
.parse_next(stream)
}
@ -745,7 +763,7 @@ fn take_till_inclusive<I: Stream, E: ParserError<I>>(
}
Err(ParserError::from_error_kind(input, ErrorKind::Eof))
}
move |stream: &mut I| {
trace("take_till_inclusive", move |stream: &mut I| {
let mut should_backtrack = false;
let offset = get_offset(stream, &backtrack_token, &end_token, &mut should_backtrack)?;
let result = stream.next_slice(offset);
@ -757,7 +775,7 @@ fn take_till_inclusive<I: Stream, E: ParserError<I>>(
} else {
Ok(result)
}
}
})
}
/*
@ -783,27 +801,30 @@ fn with_recovery<'a, 'input: 'a, T>(
mut recovery: impl Parser<PtxParser<'a, 'input>, &'a [(Token<'input>, logos::Span)], ContextError>,
mut error: impl FnMut(Option<&'input str>) -> PtxError<'input>,
) -> impl Parser<PtxParser<'a, 'input>, Option<T>, ContextError> {
move |stream: &mut PtxParser<'a, 'input>| {
let input_start = stream.input.first().map(|(_, s)| s).cloned();
let stream_start = stream.checkpoint();
match parser.parse_next(stream) {
Ok(value) => Ok(Some(value)),
Err(_) => {
stream.reset(&stream_start);
let tokens = recovery.parse_next(stream)?;
let range = match input_start {
Some(start) => {
Some(&stream.state.text[start.start..tokens.last().unwrap().1.end])
}
// We could handle `(Some(start), None)``, but this whole error recovery is to
// recover from unknown instructions, so we don't care about early end of stream
_ => None,
};
stream.state.errors.push(error(range));
Ok(None)
trace(
"with_recovery",
move |stream: &mut PtxParser<'a, 'input>| {
let input_start = stream.input.first().map(|(_, s)| s).cloned();
let stream_start = stream.checkpoint();
match parser.parse_next(stream) {
Ok(value) => Ok(Some(value)),
Err(_) => {
stream.reset(&stream_start);
let tokens = recovery.parse_next(stream)?;
let range = match input_start {
Some(start) => {
Some(&stream.state.text[start.start..tokens.last().unwrap().1.end])
}
// We could handle `(Some(start), None)``, but this whole error recovery is to
// recover from unknown instructions, so we don't care about early end of stream
_ => None,
};
stream.state.errors.push(error(range));
Ok(None)
}
}
}
}
},
)
}
fn pragma<'a, 'input>(stream: &mut PtxParser<'a, 'input>) -> PResult<()> {
@ -815,207 +836,225 @@ fn pragma<'a, 'input>(stream: &mut PtxParser<'a, 'input>) -> PResult<()> {
fn method_parameter<'a, 'input: 'a>(
state_space: StateSpace,
) -> impl Parser<PtxParser<'a, 'input>, Variable<&'input str>, ContextError> {
move |stream: &mut PtxParser<'a, 'input>| {
let (align, vector, type_, name) = variable_declaration.parse_next(stream)?;
let array_dimensions = if state_space != StateSpace::Reg {
opt(array_dimensions).parse_next(stream)?
} else {
None
};
// TODO: push this check into array_dimensions(...)
if let Some(ref dims) = array_dimensions {
if dims[0] == 0 {
return Err(ErrMode::from_error_kind(stream, ErrorKind::Verify));
trace(
"method_parameter",
move |stream: &mut PtxParser<'a, 'input>| {
let (align, vector, type_, name) = variable_declaration.parse_next(stream)?;
let array_dimensions = if state_space != StateSpace::Reg {
opt(array_dimensions).parse_next(stream)?
} else {
None
};
// TODO: push this check into array_dimensions(...)
if let Some(ref dims) = array_dimensions {
if dims[0] == 0 {
return Err(ErrMode::from_error_kind(stream, ErrorKind::Verify));
}
}
}
Ok(Variable {
align,
v_type: Type::maybe_array(vector, type_, array_dimensions),
state_space,
name,
array_init: Vec::new(),
})
}
Ok(Variable {
align,
v_type: Type::maybe_array(vector, type_, array_dimensions),
state_space,
name,
array_init: Vec::new(),
})
},
)
}
// TODO: split to a separate type
fn variable_declaration<'a, 'input>(
stream: &mut PtxParser<'a, 'input>,
) -> PResult<(Option<u32>, Option<NonZeroU8>, ScalarType, &'input str)> {
(
opt(align.verify(|x| x.count_ones() == 1)),
vector_prefix,
scalar_type,
ident,
trace(
"variable_declaration",
(
opt(align.verify(|x| x.count_ones() == 1)),
vector_prefix,
scalar_type,
ident,
),
)
.parse_next(stream)
.parse_next(stream)
}
fn multi_variable<'a, 'input: 'a>(
extern_: bool,
state_space: StateSpace,
) -> impl Parser<PtxParser<'a, 'input>, MultiVariable<&'input str>, ContextError> {
move |stream: &mut PtxParser<'a, 'input>| {
let ((align, vector, type_, name), count) = (
variable_declaration,
// https://docs.nvidia.com/cuda/parallel-thread-execution/index.html#parameterized-variable-names
opt(delimited(Token::Lt, u32.verify(|x| *x != 0), Token::Gt)),
)
.parse_next(stream)?;
if count.is_some() {
return Ok(MultiVariable {
trace(
"multi_variable",
move |stream: &mut PtxParser<'a, 'input>| {
let ((align, vector, type_, name), count) = (
variable_declaration,
// https://docs.nvidia.com/cuda/parallel-thread-execution/index.html#parameterized-variable-names
opt(delimited(Token::Lt, u32.verify(|x| *x != 0), Token::Gt)),
)
.parse_next(stream)?;
if count.is_some() {
return Ok(MultiVariable {
var: Variable {
align,
v_type: Type::maybe_vector_parsed(vector, type_),
state_space,
name,
array_init: Vec::new(),
},
count,
});
}
let mut array_dimensions = if state_space != StateSpace::Reg {
opt(array_dimensions).parse_next(stream)?
} else {
None
};
let initializer = match state_space {
StateSpace::Global | StateSpace::Const => match array_dimensions {
Some(ref mut dimensions) => {
opt(array_initializer(vector, type_, dimensions)).parse_next(stream)?
}
None => opt(value_initializer(vector, type_)).parse_next(stream)?,
},
_ => None,
};
if let Some(ref dims) = array_dimensions {
if !extern_ && dims[0] == 0 {
return Err(ErrMode::from_error_kind(stream, ErrorKind::Verify));
}
}
Ok(MultiVariable {
var: Variable {
align,
v_type: Type::maybe_vector_parsed(vector, type_),
v_type: Type::maybe_array(vector, type_, array_dimensions),
state_space,
name,
array_init: Vec::new(),
array_init: initializer.unwrap_or(Vec::new()),
},
count,
});
}
let mut array_dimensions = if state_space != StateSpace::Reg {
opt(array_dimensions).parse_next(stream)?
} else {
None
};
let initializer = match state_space {
StateSpace::Global | StateSpace::Const => match array_dimensions {
Some(ref mut dimensions) => {
opt(array_initializer(vector, type_, dimensions)).parse_next(stream)?
}
None => opt(value_initializer(vector, type_)).parse_next(stream)?,
},
_ => None,
};
if let Some(ref dims) = array_dimensions {
if !extern_ && dims[0] == 0 {
return Err(ErrMode::from_error_kind(stream, ErrorKind::Verify));
}
}
Ok(MultiVariable {
var: Variable {
align,
v_type: Type::maybe_array(vector, type_, array_dimensions),
state_space,
name,
array_init: initializer.unwrap_or(Vec::new()),
},
count,
})
}
})
},
)
}
fn array_initializer<'a, 'input: 'a>(
fn array_initializer<'b, 'a: 'b, 'input: 'a>(
vector: Option<NonZeroU8>,
type_: ScalarType,
array_dimensions: &mut Vec<u32>,
) -> impl Parser<PtxParser<'a, 'input>, Vec<u8>, ContextError> + '_ {
move |stream: &mut PtxParser<'a, 'input>| {
Token::Eq.parse_next(stream)?;
let mut result = Vec::new();
// TODO: vector constants and multi dim arrays
if vector.is_some() || array_dimensions[0] == 0 || array_dimensions.len() > 1 {
return Err(ErrMode::from_error_kind(stream, ErrorKind::Verify));
}
delimited(
Token::LBrace,
separated::<_, (), (), _, _, _, _>(
0..=array_dimensions[0] as usize,
single_value_append(&mut result, type_),
Token::Comma,
),
Token::RBrace,
)
.parse_next(stream)?;
// pad with zeros
let result_size = type_.size_of() as usize * array_dimensions[0] as usize;
result.extend(iter::repeat(0u8).take(result_size - result.len()));
Ok(result)
}
array_dimensions: &'b mut Vec<u32>,
) -> impl Parser<PtxParser<'a, 'input>, Vec<u8>, ContextError> + 'b {
trace(
"array_initializer",
move |stream: &mut PtxParser<'a, 'input>| {
Token::Eq.parse_next(stream)?;
let mut result = Vec::new();
// TODO: vector constants and multi dim arrays
if vector.is_some() || array_dimensions[0] == 0 || array_dimensions.len() > 1 {
return Err(ErrMode::from_error_kind(stream, ErrorKind::Verify));
}
delimited(
Token::LBrace,
separated::<_, (), (), _, _, _, _>(
0..=array_dimensions[0] as usize,
single_value_append(&mut result, type_),
Token::Comma,
),
Token::RBrace,
)
.parse_next(stream)?;
// pad with zeros
let result_size = type_.size_of() as usize * array_dimensions[0] as usize;
result.extend(iter::repeat(0u8).take(result_size - result.len()));
Ok(result)
},
)
}
fn value_initializer<'a, 'input: 'a>(
vector: Option<NonZeroU8>,
type_: ScalarType,
) -> impl Parser<PtxParser<'a, 'input>, Vec<u8>, ContextError> {
move |stream: &mut PtxParser<'a, 'input>| {
Token::Eq.parse_next(stream)?;
let mut result = Vec::new();
// TODO: vector constants
if vector.is_some() {
return Err(ErrMode::from_error_kind(stream, ErrorKind::Verify));
}
single_value_append(&mut result, type_).parse_next(stream)?;
Ok(result)
}
trace(
"value_initializer",
move |stream: &mut PtxParser<'a, 'input>| {
Token::Eq.parse_next(stream)?;
let mut result = Vec::new();
// TODO: vector constants
if vector.is_some() {
return Err(ErrMode::from_error_kind(stream, ErrorKind::Verify));
}
single_value_append(&mut result, type_).parse_next(stream)?;
Ok(result)
},
)
}
fn single_value_append<'a, 'input: 'a>(
accumulator: &mut Vec<u8>,
fn single_value_append<'b, 'a: 'b, 'input: 'a>(
accumulator: &'b mut Vec<u8>,
type_: ScalarType,
) -> impl Parser<PtxParser<'a, 'input>, (), ContextError> + '_ {
move |stream: &mut PtxParser<'a, 'input>| {
let value = immediate_value.parse_next(stream)?;
match (type_, value) {
(ScalarType::U8 | ScalarType::B8, ImmediateValue::U64(x)) => {
accumulator.extend_from_slice(&(x as u8).to_le_bytes())
) -> impl Parser<PtxParser<'a, 'input>, (), ContextError> + 'b {
trace(
"single_value_append",
move |stream: &mut PtxParser<'a, 'input>| {
let value = immediate_value.parse_next(stream)?;
match (type_, value) {
(ScalarType::U8 | ScalarType::B8, ImmediateValue::U64(x)) => {
accumulator.extend_from_slice(&(x as u8).to_le_bytes())
}
(ScalarType::U8 | ScalarType::B8, ImmediateValue::S64(x)) => {
accumulator.extend_from_slice(&(x as u8).to_le_bytes())
}
(ScalarType::U16 | ScalarType::B16, ImmediateValue::U64(x)) => {
accumulator.extend_from_slice(&(x as u16).to_le_bytes())
}
(ScalarType::U16 | ScalarType::B16, ImmediateValue::S64(x)) => {
accumulator.extend_from_slice(&(x as u16).to_le_bytes())
}
(ScalarType::U32 | ScalarType::B32, ImmediateValue::U64(x)) => {
accumulator.extend_from_slice(&(x as u32).to_le_bytes())
}
(ScalarType::U32 | ScalarType::B32, ImmediateValue::S64(x)) => {
accumulator.extend_from_slice(&(x as u32).to_le_bytes())
}
(ScalarType::U64 | ScalarType::B64, ImmediateValue::U64(x)) => {
accumulator.extend_from_slice(&(x as u64).to_le_bytes())
}
(ScalarType::U64 | ScalarType::B64, ImmediateValue::S64(x)) => {
accumulator.extend_from_slice(&(x as u64).to_le_bytes())
}
(ScalarType::S8, ImmediateValue::U64(x)) => {
accumulator.extend_from_slice(&(x as i8).to_le_bytes())
}
(ScalarType::S8, ImmediateValue::S64(x)) => {
accumulator.extend_from_slice(&(x as i8).to_le_bytes())
}
(ScalarType::S16, ImmediateValue::U64(x)) => {
accumulator.extend_from_slice(&(x as i16).to_le_bytes())
}
(ScalarType::S16, ImmediateValue::S64(x)) => {
accumulator.extend_from_slice(&(x as i16).to_le_bytes())
}
(ScalarType::S32, ImmediateValue::U64(x)) => {
accumulator.extend_from_slice(&(x as i32).to_le_bytes())
}
(ScalarType::S32, ImmediateValue::S64(x)) => {
accumulator.extend_from_slice(&(x as i32).to_le_bytes())
}
(ScalarType::S64, ImmediateValue::U64(x)) => {
accumulator.extend_from_slice(&(x as i64).to_le_bytes())
}
(ScalarType::S64, ImmediateValue::S64(x)) => {
accumulator.extend_from_slice(&(x as i64).to_le_bytes())
}
(ScalarType::F32, ImmediateValue::F32(x)) => {
accumulator.extend_from_slice(&x.to_le_bytes())
}
(ScalarType::F64, ImmediateValue::F64(x)) => {
accumulator.extend_from_slice(&x.to_le_bytes())
}
_ => return Err(ErrMode::from_error_kind(stream, ErrorKind::Verify)),
}
(ScalarType::U8 | ScalarType::B8, ImmediateValue::S64(x)) => {
accumulator.extend_from_slice(&(x as u8).to_le_bytes())
}
(ScalarType::U16 | ScalarType::B16, ImmediateValue::U64(x)) => {
accumulator.extend_from_slice(&(x as u16).to_le_bytes())
}
(ScalarType::U16 | ScalarType::B16, ImmediateValue::S64(x)) => {
accumulator.extend_from_slice(&(x as u16).to_le_bytes())
}
(ScalarType::U32 | ScalarType::B32, ImmediateValue::U64(x)) => {
accumulator.extend_from_slice(&(x as u32).to_le_bytes())
}
(ScalarType::U32 | ScalarType::B32, ImmediateValue::S64(x)) => {
accumulator.extend_from_slice(&(x as u32).to_le_bytes())
}
(ScalarType::U64 | ScalarType::B64, ImmediateValue::U64(x)) => {
accumulator.extend_from_slice(&(x as u64).to_le_bytes())
}
(ScalarType::U64 | ScalarType::B64, ImmediateValue::S64(x)) => {
accumulator.extend_from_slice(&(x as u64).to_le_bytes())
}
(ScalarType::S8, ImmediateValue::U64(x)) => {
accumulator.extend_from_slice(&(x as i8).to_le_bytes())
}
(ScalarType::S8, ImmediateValue::S64(x)) => {
accumulator.extend_from_slice(&(x as i8).to_le_bytes())
}
(ScalarType::S16, ImmediateValue::U64(x)) => {
accumulator.extend_from_slice(&(x as i16).to_le_bytes())
}
(ScalarType::S16, ImmediateValue::S64(x)) => {
accumulator.extend_from_slice(&(x as i16).to_le_bytes())
}
(ScalarType::S32, ImmediateValue::U64(x)) => {
accumulator.extend_from_slice(&(x as i32).to_le_bytes())
}
(ScalarType::S32, ImmediateValue::S64(x)) => {
accumulator.extend_from_slice(&(x as i32).to_le_bytes())
}
(ScalarType::S64, ImmediateValue::U64(x)) => {
accumulator.extend_from_slice(&(x as i64).to_le_bytes())
}
(ScalarType::S64, ImmediateValue::S64(x)) => {
accumulator.extend_from_slice(&(x as i64).to_le_bytes())
}
(ScalarType::F32, ImmediateValue::F32(x)) => {
accumulator.extend_from_slice(&x.to_le_bytes())
}
(ScalarType::F64, ImmediateValue::F64(x)) => {
accumulator.extend_from_slice(&x.to_le_bytes())
}
_ => return Err(ErrMode::from_error_kind(stream, ErrorKind::Verify)),
}
Ok(())
}
Ok(())
},
)
}
fn array_dimensions<'a, 'input>(stream: &mut PtxParser<'a, 'input>) -> PResult<Vec<u32>> {
@ -1188,20 +1227,26 @@ fn debug_directive<'a, 'input>(stream: &mut PtxParser<'a, 'input>) -> PResult<()
fn block_statement<'a, 'input>(
stream: &mut PtxParser<'a, 'input>,
) -> PResult<ast::Statement<ParsedOperandStr<'input>>> {
delimited(Token::LBrace, repeat_without_none(statement), Token::RBrace)
.map(|s| ast::Statement::Block(s))
.parse_next(stream)
trace(
"block_statement",
delimited(Token::LBrace, repeat_without_none(statement), Token::RBrace)
.map(|s| ast::Statement::Block(s)),
)
.parse_next(stream)
}
fn repeat_without_none<Input: Stream, Output, Error: ParserError<Input>>(
parser: impl Parser<Input, Option<Output>, Error>,
) -> impl Parser<Input, Vec<Output>, Error> {
repeat(0.., parser).fold(Vec::new, |mut acc: Vec<_>, item| {
if let Some(item) = item {
acc.push(item);
}
acc
})
trace(
"repeat_without_none",
repeat(0.., parser).fold(Vec::new, |mut acc: Vec<_>, item| {
if let Some(item) = item {
acc.push(item);
}
acc
}),
)
}
fn ident_literal<
@ -1267,11 +1312,14 @@ impl<Ident> ast::ParsedOperand<Ident> {
}
.parse_next(stream)
}
alt((
ident_operands,
immediate_value.map(ast::ParsedOperand::Imm),
vector_operand.map(ast::ParsedOperand::VecPack),
))
trace(
"operand",
alt((
ident_operands,
immediate_value.map(ast::ParsedOperand::Imm),
vector_operand.map(ast::ParsedOperand::VecPack),
)),
)
.parse_next(stream)
}
}
@ -1445,25 +1493,29 @@ fn bra<'a, 'input>(
fn call<'a, 'input>(
stream: &mut PtxParser<'a, 'input>,
) -> PResult<ast::Instruction<ParsedOperandStr<'input>>> {
let (uni, return_arguments, name, input_arguments) = (
opt(Token::DotUni),
opt((
Token::LParen,
separated(1.., ident, Token::Comma).map(|x: Vec<_>| x),
Token::RParen,
Token::Comma,
)
.map(|(_, arguments, _, _)| arguments)),
ident,
opt((
Token::Comma.void(),
Token::LParen.void(),
separated(1.., ParsedOperand::<&'input str>::parse, Token::Comma).map(|x: Vec<_>| x),
Token::RParen.void(),
)
.map(|(_, _, arguments, _)| arguments)),
let (uni, return_arguments, name, input_arguments) = trace(
"call",
(
opt(Token::DotUni),
opt((
Token::LParen,
separated(1.., ident, Token::Comma).map(|x: Vec<_>| x),
Token::RParen,
Token::Comma,
)
.map(|(_, arguments, _, _)| arguments)),
ident,
opt((
Token::Comma.void(),
Token::LParen.void(),
separated(1.., ParsedOperand::<&'input str>::parse, Token::Comma)
.map(|x: Vec<_>| x),
Token::RParen.void(),
)
.map(|(_, _, arguments, _)| arguments)),
),
)
.parse_next(stream)?;
.parse_next(stream)?;
let uniform = uni.is_some();
let recorded_fn = match stream.state.function_declarations.get(name) {
Some(decl) => decl,
@ -1536,7 +1588,7 @@ where
ParseRequired: Parser<Input, RequiredOutput, Error>,
Error: ParserError<Input>,
{
move |input: &mut Input| -> Result<(Option<OptionalOutput>, RequiredOutput), ErrMode<Error>> {
trace("first_optional", move |input: &mut Input| -> Result<(Option<OptionalOutput>, RequiredOutput), ErrMode<Error>> {
let start = input.checkpoint();
let parsed_optional = match optional.parse_next(input) {
@ -1555,7 +1607,7 @@ where
};
Ok((None, required.parse_next(input)?))
}
})
}
// This macro is responsible for generating parser code for instruction parser.