1 //! Parser for .clif files.
2
3 use crate::error::{Location, ParseError, ParseResult};
4 use crate::isaspec;
5 use crate::lexer::{LexError, Lexer, LocatedError, LocatedToken, Token};
6 use crate::run_command::{Comparison, Invocation, RunCommand};
7 use crate::sourcemap::SourceMap;
8 use crate::testcommand::TestCommand;
9 use crate::testfile::{Comment, Details, Feature, TestFile};
10 use cranelift_codegen::data_value::DataValue;
11 use cranelift_codegen::entity::{EntityRef, PrimaryMap};
12 use cranelift_codegen::ir::entities::{AnyEntity, DynamicType};
13 use cranelift_codegen::ir::immediates::{
14 Ieee16, Ieee32, Ieee64, Ieee128, Imm64, Offset32, Uimm32, Uimm64,
15 };
16 use cranelift_codegen::ir::instructions::{InstructionData, InstructionFormat, VariableArgs};
17 use cranelift_codegen::ir::{self, StackSlotKey, UserExternalNameRef};
18 use cranelift_codegen::ir::{DebugTag, types::*};
19
20 use cranelift_codegen::ir::{
21 AbiParam, ArgumentExtension, ArgumentPurpose, Block, BlockArg, Constant, ConstantData,
22 DynamicStackSlot, DynamicStackSlotData, DynamicTypeData, ExtFuncData, ExternalName, FuncRef,
23 Function, GlobalValue, GlobalValueData, JumpTableData, MemFlags, Opcode, SigRef, Signature,
24 StackSlot, StackSlotData, StackSlotKind, UserFuncName, Value, types,
25 };
26 use cranelift_codegen::isa::{self, CallConv};
27 use cranelift_codegen::packed_option::ReservedValue;
28 use cranelift_codegen::{settings, settings::Configurable, timing};
29 use smallvec::SmallVec;
30 use std::mem;
31 use std::str::FromStr;
32 use std::{u16, u32};
33 use target_lexicon::Triple;
34
35 macro_rules! match_imm {
36 ($signed:ty, $unsigned:ty, $parser:expr, $err_msg:expr) => {{
37 if let Some(Token::Integer(text)) = $parser.token() {
38 $parser.consume();
39 let negative = text.starts_with('-');
40 let positive = text.starts_with('+');
41 let text = if negative || positive {
42 // Strip sign prefix.
43 &text[1..]
44 } else {
45 text
46 };
47
48 // Parse the text value; the lexer gives us raw text that looks like an integer.
49 let value = if text.starts_with("0x") {
50 // Skip underscores.
51 let text = text.replace("_", "");
52 // Parse it in hexadecimal form.
53 <$unsigned>::from_str_radix(&text[2..], 16).map_err(|_| {
54 $parser.error(&format!(
55 "unable to parse '{}' value as a hexadecimal {} immediate",
56 &text[2..],
57 stringify!($unsigned),
58 ))
59 })?
60 } else {
61 // Parse it as a signed type to check for overflow and other issues.
62 text.parse()
63 .map_err(|_| $parser.error("expected decimal immediate"))?
64 };
65
66 // Apply sign if necessary.
67 let signed = if negative {
68 let value = value.wrapping_neg() as $signed;
69 if value > 0 {
70 return Err($parser.error("negative number too small"));
71 }
72 value
73 } else {
74 value as $signed
75 };
76
77 Ok(signed)
78 } else {
79 err!($parser.loc, $err_msg)
80 }
81 }};
82 }
83
84 /// After some quick benchmarks a program should never have more than 100,000 blocks.
85 const MAX_BLOCKS_IN_A_FUNCTION: u32 = 100_000;
86
87 /// Parse the entire `text` into a list of functions.
88 ///
89 /// Any test commands or target declarations are ignored.
parse_functions(text: &str) -> ParseResult<Vec<Function>>90 pub fn parse_functions(text: &str) -> ParseResult<Vec<Function>> {
91 let _tt = timing::parse_text();
92 parse_test(text, ParseOptions::default())
93 .map(|file| file.functions.into_iter().map(|(func, _)| func).collect())
94 }
95
96 /// Options for configuring the parsing of filetests.
97 pub struct ParseOptions<'a> {
98 /// Compiler passes to run on the parsed functions.
99 pub passes: Option<&'a [String]>,
100 /// Target ISA for compiling the parsed functions, e.g. "x86_64 skylake".
101 pub target: Option<&'a str>,
102 /// Default calling convention used when none is specified for a parsed function.
103 pub default_calling_convention: CallConv,
104 /// Default for unwind-info setting (enabled or disabled).
105 pub unwind_info: bool,
106 /// Default for machine_code_cfg_info setting (enabled or disabled).
107 pub machine_code_cfg_info: bool,
108 }
109
110 impl Default for ParseOptions<'_> {
default() -> Self111 fn default() -> Self {
112 Self {
113 passes: None,
114 target: None,
115 default_calling_convention: CallConv::Fast,
116 unwind_info: false,
117 machine_code_cfg_info: false,
118 }
119 }
120 }
121
122 /// Parse the entire `text` as a test case file.
123 ///
124 /// The returned `TestFile` contains direct references to substrings of `text`.
parse_test<'a>(text: &'a str, options: ParseOptions<'a>) -> ParseResult<TestFile<'a>>125 pub fn parse_test<'a>(text: &'a str, options: ParseOptions<'a>) -> ParseResult<TestFile<'a>> {
126 let _tt = timing::parse_text();
127 let mut parser = Parser::new(text);
128
129 // Gather the preamble comments.
130 parser.start_gathering_comments();
131
132 let isa_spec: isaspec::IsaSpec;
133 let commands: Vec<TestCommand<'a>>;
134
135 // Check for specified passes and target, if present throw out test commands/targets specified
136 // in file.
137 match options.passes {
138 Some(pass_vec) => {
139 parser.parse_test_commands();
140 commands = parser.parse_cmdline_passes(pass_vec);
141 parser.parse_target_specs(&options)?;
142 isa_spec = parser.parse_cmdline_target(options.target)?;
143 }
144 None => {
145 commands = parser.parse_test_commands();
146 isa_spec = parser.parse_target_specs(&options)?;
147 }
148 };
149 let features = parser.parse_cranelift_features()?;
150
151 // Decide between using the calling convention passed in the options or using the
152 // host's calling convention--if any tests are to be run on the host we should default to the
153 // host's calling convention.
154 parser = if commands.iter().any(|tc| tc.command == "run") {
155 let host_default_calling_convention = CallConv::triple_default(&Triple::host());
156 parser.with_default_calling_convention(host_default_calling_convention)
157 } else {
158 parser.with_default_calling_convention(options.default_calling_convention)
159 };
160
161 parser.token();
162 parser.claim_gathered_comments(AnyEntity::Function);
163
164 let preamble_comments = parser.take_comments();
165 let functions = parser.parse_function_list()?;
166
167 Ok(TestFile {
168 commands,
169 isa_spec,
170 features,
171 preamble_comments,
172 functions,
173 })
174 }
175
176 /// Parse a CLIF comment `text` as a run command.
177 ///
178 /// Return:
179 /// - `Ok(None)` if the comment is not intended to be a `RunCommand` (i.e. does not start with `run`
180 /// or `print`
181 /// - `Ok(Some(command))` if the comment is intended as a `RunCommand` and can be parsed to one
182 /// - `Err` otherwise.
parse_run_command(text: &str, signature: &Signature) -> ParseResult<Option<RunCommand>>183 pub fn parse_run_command(text: &str, signature: &Signature) -> ParseResult<Option<RunCommand>> {
184 let _tt = timing::parse_text();
185 // We remove leading spaces and semi-colons for convenience here instead of at the call sites
186 // since this function will be attempting to parse a RunCommand from a CLIF comment.
187 let trimmed_text = text.trim_start_matches(|c| c == ' ' || c == ';');
188 let mut parser = Parser::new(trimmed_text);
189 match parser.token() {
190 Some(Token::Identifier("run")) | Some(Token::Identifier("print")) => {
191 parser.parse_run_command(signature).map(|c| Some(c))
192 }
193 Some(_) | None => Ok(None),
194 }
195 }
196
197 pub struct Parser<'a> {
198 lex: Lexer<'a>,
199
200 lex_error: Option<LexError>,
201
202 /// Current lookahead token.
203 lookahead: Option<Token<'a>>,
204
205 /// Location of lookahead.
206 loc: Location,
207
208 /// Are we gathering any comments that we encounter?
209 gathering_comments: bool,
210
211 /// The gathered comments; claim them with `claim_gathered_comments`.
212 gathered_comments: Vec<&'a str>,
213
214 /// Comments collected so far.
215 comments: Vec<Comment<'a>>,
216
217 /// Maps inlined external names to a ref value, so they can be declared before parsing the rest
218 /// of the function later.
219 ///
220 /// This maintains backward compatibility with previous ways for declaring external names.
221 predeclared_external_names: PrimaryMap<UserExternalNameRef, ir::UserExternalName>,
222
223 /// Default calling conventions; used when none is specified.
224 default_calling_convention: CallConv,
225 }
226
227 /// Context for resolving references when parsing a single function.
228 struct Context {
229 function: Function,
230 map: SourceMap,
231
232 /// Aliases to resolve once value definitions are known.
233 aliases: Vec<Value>,
234 }
235
236 impl Context {
new(f: Function) -> Self237 fn new(f: Function) -> Self {
238 Self {
239 function: f,
240 map: SourceMap::new(),
241 aliases: Vec::new(),
242 }
243 }
244
245 // Allocate a new stack slot.
add_ss(&mut self, ss: StackSlot, data: StackSlotData, loc: Location) -> ParseResult<()>246 fn add_ss(&mut self, ss: StackSlot, data: StackSlotData, loc: Location) -> ParseResult<()> {
247 self.map.def_ss(ss, loc)?;
248 while self.function.sized_stack_slots.next_key().index() <= ss.index() {
249 self.function.create_sized_stack_slot(StackSlotData::new(
250 StackSlotKind::ExplicitSlot,
251 0,
252 0,
253 ));
254 }
255 self.function.sized_stack_slots[ss] = data;
256 Ok(())
257 }
258
259 // Resolve a reference to a stack slot.
check_ss(&self, ss: StackSlot, loc: Location) -> ParseResult<()>260 fn check_ss(&self, ss: StackSlot, loc: Location) -> ParseResult<()> {
261 if !self.map.contains_ss(ss) {
262 err!(loc, "undefined stack slot {}", ss)
263 } else {
264 Ok(())
265 }
266 }
267
268 // Allocate a new stack slot.
add_dss( &mut self, ss: DynamicStackSlot, data: DynamicStackSlotData, loc: Location, ) -> ParseResult<()>269 fn add_dss(
270 &mut self,
271 ss: DynamicStackSlot,
272 data: DynamicStackSlotData,
273 loc: Location,
274 ) -> ParseResult<()> {
275 self.map.def_dss(ss, loc)?;
276 while self.function.dynamic_stack_slots.next_key().index() <= ss.index() {
277 self.function
278 .create_dynamic_stack_slot(DynamicStackSlotData::new(
279 StackSlotKind::ExplicitDynamicSlot,
280 data.dyn_ty,
281 ));
282 }
283 self.function.dynamic_stack_slots[ss] = data;
284 Ok(())
285 }
286
287 // Resolve a reference to a dynamic stack slot.
check_dss(&self, dss: DynamicStackSlot, loc: Location) -> ParseResult<()>288 fn check_dss(&self, dss: DynamicStackSlot, loc: Location) -> ParseResult<()> {
289 if !self.map.contains_dss(dss) {
290 err!(loc, "undefined dynamic stack slot {}", dss)
291 } else {
292 Ok(())
293 }
294 }
295
296 // Allocate a new dynamic type.
add_dt(&mut self, dt: DynamicType, data: DynamicTypeData, loc: Location) -> ParseResult<()>297 fn add_dt(&mut self, dt: DynamicType, data: DynamicTypeData, loc: Location) -> ParseResult<()> {
298 self.map.def_dt(dt, loc)?;
299 while self.function.dfg.dynamic_types.next_key().index() <= dt.index() {
300 self.function.dfg.make_dynamic_ty(DynamicTypeData::new(
301 data.base_vector_ty,
302 data.dynamic_scale,
303 ));
304 }
305 self.function.dfg.dynamic_types[dt] = data;
306 Ok(())
307 }
308
309 // Allocate a global value slot.
add_gv(&mut self, gv: GlobalValue, data: GlobalValueData, loc: Location) -> ParseResult<()>310 fn add_gv(&mut self, gv: GlobalValue, data: GlobalValueData, loc: Location) -> ParseResult<()> {
311 self.map.def_gv(gv, loc)?;
312 while self.function.global_values.next_key().index() <= gv.index() {
313 self.function.create_global_value(GlobalValueData::Symbol {
314 name: ExternalName::testcase(""),
315 offset: Imm64::new(0),
316 colocated: false,
317 tls: false,
318 });
319 }
320 self.function.global_values[gv] = data;
321 Ok(())
322 }
323
324 // Resolve a reference to a global value.
check_gv(&self, gv: GlobalValue, loc: Location) -> ParseResult<()>325 fn check_gv(&self, gv: GlobalValue, loc: Location) -> ParseResult<()> {
326 if !self.map.contains_gv(gv) {
327 err!(loc, "undefined global value {}", gv)
328 } else {
329 Ok(())
330 }
331 }
332
333 // Allocate a new signature.
add_sig( &mut self, sig: SigRef, data: Signature, loc: Location, defaultcc: CallConv, ) -> ParseResult<()>334 fn add_sig(
335 &mut self,
336 sig: SigRef,
337 data: Signature,
338 loc: Location,
339 defaultcc: CallConv,
340 ) -> ParseResult<()> {
341 self.map.def_sig(sig, loc)?;
342 while self.function.dfg.signatures.next_key().index() <= sig.index() {
343 self.function.import_signature(Signature::new(defaultcc));
344 }
345 self.function.dfg.signatures[sig] = data;
346 Ok(())
347 }
348
349 // Resolve a reference to a signature.
check_sig(&self, sig: SigRef, loc: Location) -> ParseResult<()>350 fn check_sig(&self, sig: SigRef, loc: Location) -> ParseResult<()> {
351 if !self.map.contains_sig(sig) {
352 err!(loc, "undefined signature {}", sig)
353 } else {
354 Ok(())
355 }
356 }
357
358 // Allocate a new external function.
add_fn(&mut self, fn_: FuncRef, data: ExtFuncData, loc: Location) -> ParseResult<()>359 fn add_fn(&mut self, fn_: FuncRef, data: ExtFuncData, loc: Location) -> ParseResult<()> {
360 self.map.def_fn(fn_, loc)?;
361 while self.function.dfg.ext_funcs.next_key().index() <= fn_.index() {
362 self.function.import_function(ExtFuncData {
363 name: ExternalName::testcase(""),
364 signature: SigRef::reserved_value(),
365 colocated: false,
366 patchable: false,
367 });
368 }
369 self.function.dfg.ext_funcs[fn_] = data;
370 Ok(())
371 }
372
373 // Resolve a reference to a function.
check_fn(&self, fn_: FuncRef, loc: Location) -> ParseResult<()>374 fn check_fn(&self, fn_: FuncRef, loc: Location) -> ParseResult<()> {
375 if !self.map.contains_fn(fn_) {
376 err!(loc, "undefined function {}", fn_)
377 } else {
378 Ok(())
379 }
380 }
381
382 // Allocate a new constant.
add_constant( &mut self, constant: Constant, data: ConstantData, loc: Location, ) -> ParseResult<()>383 fn add_constant(
384 &mut self,
385 constant: Constant,
386 data: ConstantData,
387 loc: Location,
388 ) -> ParseResult<()> {
389 self.map.def_constant(constant, loc)?;
390 self.function.dfg.constants.set(constant, data);
391 Ok(())
392 }
393
394 // Configure the stack limit of the current function.
add_stack_limit(&mut self, limit: GlobalValue, loc: Location) -> ParseResult<()>395 fn add_stack_limit(&mut self, limit: GlobalValue, loc: Location) -> ParseResult<()> {
396 if self.function.stack_limit.is_some() {
397 return err!(loc, "stack limit defined twice");
398 }
399 self.function.stack_limit = Some(limit);
400 Ok(())
401 }
402
403 // Resolve a reference to a constant.
check_constant(&self, c: Constant, loc: Location) -> ParseResult<()>404 fn check_constant(&self, c: Constant, loc: Location) -> ParseResult<()> {
405 if !self.map.contains_constant(c) {
406 err!(loc, "undefined constant {}", c)
407 } else {
408 Ok(())
409 }
410 }
411
412 // Allocate a new block.
add_block(&mut self, block: Block, loc: Location) -> ParseResult<Block>413 fn add_block(&mut self, block: Block, loc: Location) -> ParseResult<Block> {
414 self.map.def_block(block, loc)?;
415 while self.function.dfg.num_blocks() <= block.index() {
416 self.function.dfg.make_block();
417 }
418 self.function.layout.append_block(block);
419 Ok(block)
420 }
421
422 /// Set a block as cold.
set_cold_block(&mut self, block: Block)423 fn set_cold_block(&mut self, block: Block) {
424 self.function.layout.set_cold(block);
425 }
426 }
427
428 impl<'a> Parser<'a> {
429 /// Create a new `Parser` which reads `text`. The referenced text must outlive the parser.
new(text: &'a str) -> Self430 pub fn new(text: &'a str) -> Self {
431 Self {
432 lex: Lexer::new(text),
433 lex_error: None,
434 lookahead: None,
435 loc: Location { line_number: 0 },
436 gathering_comments: false,
437 gathered_comments: Vec::new(),
438 comments: Vec::new(),
439 default_calling_convention: CallConv::Fast,
440 predeclared_external_names: Default::default(),
441 }
442 }
443
444 /// Modify the default calling convention; returns a new parser with the changed calling
445 /// convention.
with_default_calling_convention(self, default_calling_convention: CallConv) -> Self446 pub fn with_default_calling_convention(self, default_calling_convention: CallConv) -> Self {
447 Self {
448 default_calling_convention,
449 ..self
450 }
451 }
452
453 // Consume the current lookahead token and return it.
consume(&mut self) -> Token<'a>454 fn consume(&mut self) -> Token<'a> {
455 self.lookahead.take().expect("No token to consume")
456 }
457
458 // Consume the whole line following the current lookahead token.
459 // Return the text of the line tail.
consume_line(&mut self) -> &'a str460 fn consume_line(&mut self) -> &'a str {
461 let rest = self.lex.rest_of_line();
462 self.consume();
463 rest
464 }
465
466 // Get the current lookahead token, after making sure there is one.
token(&mut self) -> Option<Token<'a>>467 fn token(&mut self) -> Option<Token<'a>> {
468 while self.lookahead.is_none() {
469 match self.lex.next() {
470 Some(Ok(LocatedToken { token, location })) => {
471 match token {
472 Token::Comment(text) => {
473 if self.gathering_comments {
474 self.gathered_comments.push(text);
475 }
476 }
477 _ => self.lookahead = Some(token),
478 }
479 self.loc = location;
480 }
481 Some(Err(LocatedError { error, location })) => {
482 self.lex_error = Some(error);
483 self.loc = location;
484 break;
485 }
486 None => break,
487 }
488 }
489 self.lookahead
490 }
491
492 // Enable gathering of all comments encountered.
start_gathering_comments(&mut self)493 fn start_gathering_comments(&mut self) {
494 debug_assert!(!self.gathering_comments);
495 self.gathering_comments = true;
496 debug_assert!(self.gathered_comments.is_empty());
497 }
498
499 // Claim the comments gathered up to the current position for the
500 // given entity.
claim_gathered_comments<E: Into<AnyEntity>>(&mut self, entity: E)501 fn claim_gathered_comments<E: Into<AnyEntity>>(&mut self, entity: E) {
502 debug_assert!(self.gathering_comments);
503 let entity = entity.into();
504 self.comments.extend(
505 self.gathered_comments
506 .drain(..)
507 .map(|text| Comment { entity, text }),
508 );
509 self.gathering_comments = false;
510 }
511
512 // Get the comments collected so far, clearing out the internal list.
take_comments(&mut self) -> Vec<Comment<'a>>513 fn take_comments(&mut self) -> Vec<Comment<'a>> {
514 debug_assert!(!self.gathering_comments);
515 mem::replace(&mut self.comments, Vec::new())
516 }
517
518 // Match and consume a token without payload.
match_token(&mut self, want: Token<'a>, err_msg: &str) -> ParseResult<Token<'a>>519 fn match_token(&mut self, want: Token<'a>, err_msg: &str) -> ParseResult<Token<'a>> {
520 if self.token() == Some(want) {
521 Ok(self.consume())
522 } else {
523 err!(self.loc, err_msg)
524 }
525 }
526
527 // If the next token is a `want`, consume it, otherwise do nothing.
optional(&mut self, want: Token<'a>) -> bool528 fn optional(&mut self, want: Token<'a>) -> bool {
529 if self.token() == Some(want) {
530 self.consume();
531 true
532 } else {
533 false
534 }
535 }
536
537 // Match and consume a specific identifier string.
538 // Used for pseudo-keywords like "stack_slot" that only appear in certain contexts.
match_identifier(&mut self, want: &'static str, err_msg: &str) -> ParseResult<Token<'a>>539 fn match_identifier(&mut self, want: &'static str, err_msg: &str) -> ParseResult<Token<'a>> {
540 if self.token() == Some(Token::Identifier(want)) {
541 Ok(self.consume())
542 } else {
543 err!(self.loc, err_msg)
544 }
545 }
546
547 // Match and consume a type.
match_type(&mut self, err_msg: &str) -> ParseResult<Type>548 fn match_type(&mut self, err_msg: &str) -> ParseResult<Type> {
549 if let Some(Token::Type(t)) = self.token() {
550 self.consume();
551 Ok(t)
552 } else {
553 err!(self.loc, err_msg)
554 }
555 }
556
557 // Match and consume a stack slot reference.
match_ss(&mut self, err_msg: &str) -> ParseResult<StackSlot>558 fn match_ss(&mut self, err_msg: &str) -> ParseResult<StackSlot> {
559 if let Some(Token::StackSlot(ss)) = self.token() {
560 self.consume();
561 if let Some(ss) = StackSlot::with_number(ss) {
562 return Ok(ss);
563 }
564 }
565 err!(self.loc, err_msg)
566 }
567
568 // Match and consume a dynamic stack slot reference.
match_dss(&mut self, err_msg: &str) -> ParseResult<DynamicStackSlot>569 fn match_dss(&mut self, err_msg: &str) -> ParseResult<DynamicStackSlot> {
570 if let Some(Token::DynamicStackSlot(ss)) = self.token() {
571 self.consume();
572 if let Some(ss) = DynamicStackSlot::with_number(ss) {
573 return Ok(ss);
574 }
575 }
576 err!(self.loc, err_msg)
577 }
578
579 // Match and consume a dynamic type reference.
match_dt(&mut self, err_msg: &str) -> ParseResult<DynamicType>580 fn match_dt(&mut self, err_msg: &str) -> ParseResult<DynamicType> {
581 if let Some(Token::DynamicType(dt)) = self.token() {
582 self.consume();
583 if let Some(dt) = DynamicType::with_number(dt) {
584 return Ok(dt);
585 }
586 }
587 err!(self.loc, err_msg)
588 }
589
590 // Extract Type from DynamicType
concrete_from_dt(&mut self, dt: DynamicType, ctx: &mut Context) -> Option<Type>591 fn concrete_from_dt(&mut self, dt: DynamicType, ctx: &mut Context) -> Option<Type> {
592 ctx.function.get_concrete_dynamic_ty(dt)
593 }
594
595 // Match and consume a global value reference.
match_gv(&mut self, err_msg: &str) -> ParseResult<GlobalValue>596 fn match_gv(&mut self, err_msg: &str) -> ParseResult<GlobalValue> {
597 if let Some(Token::GlobalValue(gv)) = self.token() {
598 self.consume();
599 if let Some(gv) = GlobalValue::with_number(gv) {
600 return Ok(gv);
601 }
602 }
603 err!(self.loc, err_msg)
604 }
605
606 // Match and consume a function reference.
match_fn(&mut self, err_msg: &str) -> ParseResult<FuncRef>607 fn match_fn(&mut self, err_msg: &str) -> ParseResult<FuncRef> {
608 if let Some(Token::FuncRef(fnref)) = self.token() {
609 self.consume();
610 if let Some(fnref) = FuncRef::with_number(fnref) {
611 return Ok(fnref);
612 }
613 }
614 err!(self.loc, err_msg)
615 }
616
617 // Match and consume a signature reference.
match_sig(&mut self, err_msg: &str) -> ParseResult<SigRef>618 fn match_sig(&mut self, err_msg: &str) -> ParseResult<SigRef> {
619 if let Some(Token::SigRef(sigref)) = self.token() {
620 self.consume();
621 if let Some(sigref) = SigRef::with_number(sigref) {
622 return Ok(sigref);
623 }
624 }
625 err!(self.loc, err_msg)
626 }
627
628 // Match and consume a constant reference.
match_constant(&mut self) -> ParseResult<Constant>629 fn match_constant(&mut self) -> ParseResult<Constant> {
630 if let Some(Token::Constant(c)) = self.token() {
631 self.consume();
632 if let Some(c) = Constant::with_number(c) {
633 return Ok(c);
634 }
635 }
636 err!(self.loc, "expected constant number: const«n»")
637 }
638
639 // Match and consume a stack limit token
match_stack_limit(&mut self) -> ParseResult<()>640 fn match_stack_limit(&mut self) -> ParseResult<()> {
641 if let Some(Token::Identifier("stack_limit")) = self.token() {
642 self.consume();
643 return Ok(());
644 }
645 err!(self.loc, "expected identifier: stack_limit")
646 }
647
648 // Match and consume a block reference.
match_block(&mut self, err_msg: &str) -> ParseResult<Block>649 fn match_block(&mut self, err_msg: &str) -> ParseResult<Block> {
650 if let Some(Token::Block(block)) = self.token() {
651 self.consume();
652 Ok(block)
653 } else {
654 err!(self.loc, err_msg)
655 }
656 }
657
658 // Match and consume a value reference.
match_value(&mut self, err_msg: &str) -> ParseResult<Value>659 fn match_value(&mut self, err_msg: &str) -> ParseResult<Value> {
660 if let Some(Token::Value(v)) = self.token() {
661 self.consume();
662 Ok(v)
663 } else {
664 err!(self.loc, err_msg)
665 }
666 }
667
error(&self, message: &str) -> ParseError668 fn error(&self, message: &str) -> ParseError {
669 ParseError {
670 location: self.loc,
671 message: message.to_string(),
672 is_warning: false,
673 }
674 }
675
676 // Match and consume an Imm64 immediate.
match_imm64(&mut self, err_msg: &str) -> ParseResult<Imm64>677 fn match_imm64(&mut self, err_msg: &str) -> ParseResult<Imm64> {
678 if let Some(Token::Integer(text)) = self.token() {
679 self.consume();
680 // Lexer just gives us raw text that looks like an integer.
681 // Parse it as an Imm64 to check for overflow and other issues.
682 text.parse().map_err(|e| self.error(e))
683 } else {
684 err!(self.loc, err_msg)
685 }
686 }
687
688 // Match and consume a hexadeximal immediate
match_hexadecimal_constant(&mut self, err_msg: &str) -> ParseResult<ConstantData>689 fn match_hexadecimal_constant(&mut self, err_msg: &str) -> ParseResult<ConstantData> {
690 if let Some(Token::Integer(text)) = self.token() {
691 self.consume();
692 text.parse().map_err(|e| {
693 self.error(&format!(
694 "expected hexadecimal immediate, failed to parse: {e}"
695 ))
696 })
697 } else {
698 err!(self.loc, err_msg)
699 }
700 }
701
702 // Match and consume either a hexadecimal Uimm128 immediate (e.g. 0x000102...) or its literal
703 // list form (e.g. [0 1 2...]). For convenience, since uimm128 values are stored in the
704 // `ConstantPool`, this returns `ConstantData`.
match_uimm128(&mut self, controlling_type: Type) -> ParseResult<ConstantData>705 fn match_uimm128(&mut self, controlling_type: Type) -> ParseResult<ConstantData> {
706 let expected_size = controlling_type.bytes() as usize;
707 let constant_data = if self.optional(Token::LBracket) {
708 // parse using a list of values, e.g. vconst.i32x4 [0 1 2 3]
709 let uimm128 = self.parse_literals_to_constant_data(controlling_type)?;
710 self.match_token(Token::RBracket, "expected a terminating right bracket")?;
711 uimm128
712 } else {
713 // parse using a hexadecimal value, e.g. 0x000102...
714 let uimm128 =
715 self.match_hexadecimal_constant("expected an immediate hexadecimal operand")?;
716 uimm128.expand_to(expected_size)
717 };
718
719 if constant_data.len() == expected_size {
720 Ok(constant_data)
721 } else {
722 Err(self.error(&format!(
723 "expected parsed constant to have {expected_size} bytes"
724 )))
725 }
726 }
727
728 // Match and consume a Uimm64 immediate.
match_uimm64(&mut self, err_msg: &str) -> ParseResult<Uimm64>729 fn match_uimm64(&mut self, err_msg: &str) -> ParseResult<Uimm64> {
730 if let Some(Token::Integer(text)) = self.token() {
731 self.consume();
732 // Lexer just gives us raw text that looks like an integer.
733 // Parse it as an Uimm64 to check for overflow and other issues.
734 text.parse()
735 .map_err(|_| self.error("expected u64 decimal immediate"))
736 } else {
737 err!(self.loc, err_msg)
738 }
739 }
740
741 // Match and consume a Uimm32 immediate.
match_uimm32(&mut self, err_msg: &str) -> ParseResult<Uimm32>742 fn match_uimm32(&mut self, err_msg: &str) -> ParseResult<Uimm32> {
743 if let Some(Token::Integer(text)) = self.token() {
744 self.consume();
745 // Lexer just gives us raw text that looks like an integer.
746 // Parse it as an Uimm32 to check for overflow and other issues.
747 text.parse().map_err(|e| self.error(e))
748 } else {
749 err!(self.loc, err_msg)
750 }
751 }
752
753 // Match and consume a u8 immediate.
754 // This is used for lane numbers in SIMD vectors.
match_uimm8(&mut self, err_msg: &str) -> ParseResult<u8>755 fn match_uimm8(&mut self, err_msg: &str) -> ParseResult<u8> {
756 if let Some(Token::Integer(text)) = self.token() {
757 self.consume();
758 // Lexer just gives us raw text that looks like an integer.
759 if let Some(num) = text.strip_prefix("0x") {
760 // Parse it as a u8 in hexadecimal form.
761 u8::from_str_radix(num, 16)
762 .map_err(|_| self.error("unable to parse u8 as a hexadecimal immediate"))
763 } else {
764 // Parse it as a u8 to check for overflow and other issues.
765 text.parse()
766 .map_err(|_| self.error("expected u8 decimal immediate"))
767 }
768 } else {
769 err!(self.loc, err_msg)
770 }
771 }
772
773 // Match and consume an i8 immediate.
match_imm8(&mut self, err_msg: &str) -> ParseResult<i8>774 fn match_imm8(&mut self, err_msg: &str) -> ParseResult<i8> {
775 match_imm!(i8, u8, self, err_msg)
776 }
777
778 // Match and consume a signed 16-bit immediate.
match_imm16(&mut self, err_msg: &str) -> ParseResult<i16>779 fn match_imm16(&mut self, err_msg: &str) -> ParseResult<i16> {
780 match_imm!(i16, u16, self, err_msg)
781 }
782
783 // Match and consume an i32 immediate.
784 // This is used for stack argument byte offsets.
match_imm32(&mut self, err_msg: &str) -> ParseResult<i32>785 fn match_imm32(&mut self, err_msg: &str) -> ParseResult<i32> {
786 match_imm!(i32, u32, self, err_msg)
787 }
788
789 // Match and consume an i128 immediate.
match_imm128(&mut self, err_msg: &str) -> ParseResult<i128>790 fn match_imm128(&mut self, err_msg: &str) -> ParseResult<i128> {
791 match_imm!(i128, u128, self, err_msg)
792 }
793
794 // Match and consume an optional offset32 immediate.
795 //
796 // Note that this will match an empty string as an empty offset, and that if an offset is
797 // present, it must contain a sign.
optional_offset32(&mut self) -> ParseResult<Offset32>798 fn optional_offset32(&mut self) -> ParseResult<Offset32> {
799 if let Some(Token::Integer(text)) = self.token() {
800 if text.starts_with('+') || text.starts_with('-') {
801 self.consume();
802 // Lexer just gives us raw text that looks like an integer.
803 // Parse it as an `Offset32` to check for overflow and other issues.
804 return text.parse().map_err(|e| self.error(e));
805 }
806 }
807 // An offset32 operand can be absent.
808 Ok(Offset32::new(0))
809 }
810
811 // Match and consume an optional offset32 immediate.
812 //
813 // Note that this will match an empty string as an empty offset, and that if an offset is
814 // present, it must contain a sign.
optional_offset_imm64(&mut self) -> ParseResult<Imm64>815 fn optional_offset_imm64(&mut self) -> ParseResult<Imm64> {
816 if let Some(Token::Integer(text)) = self.token() {
817 if text.starts_with('+') || text.starts_with('-') {
818 self.consume();
819 // Lexer just gives us raw text that looks like an integer.
820 // Parse it as an `Offset32` to check for overflow and other issues.
821 return text.parse().map_err(|e| self.error(e));
822 }
823 }
824 // If no explicit offset is present, the offset is 0.
825 Ok(Imm64::new(0))
826 }
827
828 // Match and consume an Ieee16 immediate.
match_ieee16(&mut self, err_msg: &str) -> ParseResult<Ieee16>829 fn match_ieee16(&mut self, err_msg: &str) -> ParseResult<Ieee16> {
830 if let Some(Token::Float(text)) = self.token() {
831 self.consume();
832 // Lexer just gives us raw text that looks like a float.
833 // Parse it as an Ieee16 to check for the right number of digits and other issues.
834 text.parse().map_err(|e| self.error(e))
835 } else {
836 err!(self.loc, err_msg)
837 }
838 }
839
840 // Match and consume an Ieee32 immediate.
match_ieee32(&mut self, err_msg: &str) -> ParseResult<Ieee32>841 fn match_ieee32(&mut self, err_msg: &str) -> ParseResult<Ieee32> {
842 if let Some(Token::Float(text)) = self.token() {
843 self.consume();
844 // Lexer just gives us raw text that looks like a float.
845 // Parse it as an Ieee32 to check for the right number of digits and other issues.
846 text.parse().map_err(|e| self.error(e))
847 } else {
848 err!(self.loc, err_msg)
849 }
850 }
851
852 // Match and consume an Ieee64 immediate.
match_ieee64(&mut self, err_msg: &str) -> ParseResult<Ieee64>853 fn match_ieee64(&mut self, err_msg: &str) -> ParseResult<Ieee64> {
854 if let Some(Token::Float(text)) = self.token() {
855 self.consume();
856 // Lexer just gives us raw text that looks like a float.
857 // Parse it as an Ieee64 to check for the right number of digits and other issues.
858 text.parse().map_err(|e| self.error(e))
859 } else {
860 err!(self.loc, err_msg)
861 }
862 }
863
864 // Match and consume an Ieee128 immediate.
match_ieee128(&mut self, err_msg: &str) -> ParseResult<Ieee128>865 fn match_ieee128(&mut self, err_msg: &str) -> ParseResult<Ieee128> {
866 if let Some(Token::Float(text)) = self.token() {
867 self.consume();
868 // Lexer just gives us raw text that looks like a float.
869 // Parse it as an Ieee128 to check for the right number of digits and other issues.
870 text.parse().map_err(|e| self.error(e))
871 } else {
872 err!(self.loc, err_msg)
873 }
874 }
875
876 // Match and consume an enumerated immediate, like one of the condition codes.
match_enum<T: FromStr>(&mut self, err_msg: &str) -> ParseResult<T>877 fn match_enum<T: FromStr>(&mut self, err_msg: &str) -> ParseResult<T> {
878 if let Some(Token::Identifier(text)) = self.token() {
879 self.consume();
880 text.parse().map_err(|_| self.error(err_msg))
881 } else {
882 err!(self.loc, err_msg)
883 }
884 }
885
886 // Match and a consume a possibly empty sequence of memory operation flags.
optional_memflags(&mut self) -> ParseResult<MemFlags>887 fn optional_memflags(&mut self) -> ParseResult<MemFlags> {
888 let mut flags = MemFlags::new();
889 while let Some(Token::Identifier(text)) = self.token() {
890 match flags.set_by_name(text) {
891 Ok(true) => {
892 self.consume();
893 }
894 Ok(false) => break,
895 Err(msg) => return err!(self.loc, msg),
896 }
897 }
898 Ok(flags)
899 }
900
901 // Match and consume an identifier.
match_any_identifier(&mut self, err_msg: &str) -> ParseResult<&'a str>902 fn match_any_identifier(&mut self, err_msg: &str) -> ParseResult<&'a str> {
903 if let Some(Token::Identifier(text)) = self.token() {
904 self.consume();
905 Ok(text)
906 } else {
907 err!(self.loc, err_msg)
908 }
909 }
910
911 /// Parse an optional source location.
912 ///
913 /// Return an optional source location if no real location is present.
optional_srcloc(&mut self) -> ParseResult<ir::SourceLoc>914 fn optional_srcloc(&mut self) -> ParseResult<ir::SourceLoc> {
915 if let Some(Token::SourceLoc(text)) = self.token() {
916 match u32::from_str_radix(text, 16) {
917 Ok(num) => {
918 self.consume();
919 Ok(ir::SourceLoc::new(num))
920 }
921 Err(_) => return err!(self.loc, "invalid source location: {}", text),
922 }
923 } else {
924 Ok(Default::default())
925 }
926 }
927
928 /// Parse an optional list of debug tags.
optional_debug_tags(&mut self) -> ParseResult<Vec<DebugTag>>929 fn optional_debug_tags(&mut self) -> ParseResult<Vec<DebugTag>> {
930 if self.optional(Token::LAngle) {
931 let mut tags = vec![];
932 while !self.optional(Token::RAngle) {
933 match self.token() {
934 Some(Token::Integer(_)) => {
935 let value: u32 = self.match_uimm32("expected a u32 value")?.into();
936 tags.push(DebugTag::User(value));
937 }
938 Some(Token::StackSlot(slot)) => {
939 self.consume();
940 tags.push(DebugTag::StackSlot(StackSlot::from_u32(slot)));
941 }
942 _ => {
943 return err!(
944 self.loc,
945 "expected integer user value or stack slot in debug tags"
946 );
947 }
948 }
949 if !self.optional(Token::Comma) {
950 self.match_token(Token::RAngle, "expected `,` or `>`")?;
951 break;
952 }
953 }
954 Ok(tags)
955 } else {
956 Ok(vec![])
957 }
958 }
959
960 /// Parse a list of literals (i.e. integers, floats, booleans); e.g. `0 1 2 3`, usually as
961 /// part of something like `vconst.i32x4 [0 1 2 3]`.
parse_literals_to_constant_data(&mut self, ty: Type) -> ParseResult<ConstantData>962 fn parse_literals_to_constant_data(&mut self, ty: Type) -> ParseResult<ConstantData> {
963 macro_rules! consume {
964 ( $ty:ident, $match_fn:expr ) => {{
965 assert!($ty.is_vector());
966 let mut data = ConstantData::default();
967 for _ in 0..$ty.lane_count() {
968 data = data.append($match_fn);
969 }
970 data
971 }};
972 }
973
974 if !ty.is_vector() && !ty.is_dynamic_vector() {
975 err!(self.loc, "Expected a controlling vector type, not {}", ty)
976 } else {
977 let constant_data = match ty.lane_type() {
978 I8 => consume!(ty, self.match_imm8("Expected an 8-bit integer")?),
979 I16 => consume!(ty, self.match_imm16("Expected a 16-bit integer")?),
980 I32 => consume!(ty, self.match_imm32("Expected a 32-bit integer")?),
981 I64 => consume!(ty, self.match_imm64("Expected a 64-bit integer")?),
982 F32 => consume!(ty, self.match_ieee32("Expected a 32-bit float")?),
983 F64 => consume!(ty, self.match_ieee64("Expected a 64-bit float")?),
984 _ => return err!(self.loc, "Expected a type of: float, int, bool"),
985 };
986 Ok(constant_data)
987 }
988 }
989
990 /// Parse a list of test command passes specified in command line.
parse_cmdline_passes(&mut self, passes: &'a [String]) -> Vec<TestCommand<'a>>991 pub fn parse_cmdline_passes(&mut self, passes: &'a [String]) -> Vec<TestCommand<'a>> {
992 let mut list = Vec::new();
993 for pass in passes {
994 list.push(TestCommand::new(pass));
995 }
996 list
997 }
998
999 /// Parse a list of test commands.
parse_test_commands(&mut self) -> Vec<TestCommand<'a>>1000 pub fn parse_test_commands(&mut self) -> Vec<TestCommand<'a>> {
1001 let mut list = Vec::new();
1002 while self.token() == Some(Token::Identifier("test")) {
1003 list.push(TestCommand::new(self.consume_line()));
1004 }
1005 list
1006 }
1007
1008 /// Parse a target spec.
1009 ///
1010 /// Accept the target from the command line for pass command.
1011 ///
parse_cmdline_target(&mut self, target_pass: Option<&str>) -> ParseResult<isaspec::IsaSpec>1012 fn parse_cmdline_target(&mut self, target_pass: Option<&str>) -> ParseResult<isaspec::IsaSpec> {
1013 // Were there any `target` commands specified?
1014 let mut specified_target = false;
1015
1016 let mut targets = Vec::new();
1017 let flag_builder = settings::builder();
1018
1019 if let Some(targ) = target_pass {
1020 let loc = self.loc;
1021 let triple = match Triple::from_str(targ) {
1022 Ok(triple) => triple,
1023 Err(err) => return err!(loc, err),
1024 };
1025 let isa_builder = match isa::lookup(triple) {
1026 Err(isa::LookupError::SupportDisabled) => {
1027 return err!(loc, "support disabled target '{}'", targ);
1028 }
1029 Err(isa::LookupError::Unsupported) => {
1030 return warn!(loc, "unsupported target '{}'", targ);
1031 }
1032 Ok(b) => b,
1033 };
1034 specified_target = true;
1035
1036 // Construct a trait object with the aggregate settings.
1037 targets.push(
1038 isa_builder
1039 .finish(settings::Flags::new(flag_builder.clone()))
1040 .map_err(|e| ParseError {
1041 location: loc,
1042 message: format!("invalid ISA flags for '{targ}': {e:?}"),
1043 is_warning: false,
1044 })?,
1045 );
1046 }
1047
1048 if !specified_target {
1049 // No `target` commands.
1050 Ok(isaspec::IsaSpec::None(settings::Flags::new(flag_builder)))
1051 } else {
1052 Ok(isaspec::IsaSpec::Some(targets))
1053 }
1054 }
1055
1056 /// Parse a list of target specs.
1057 ///
1058 /// Accept a mix of `target` and `set` command lines. The `set` commands are cumulative.
1059 ///
parse_target_specs(&mut self, options: &ParseOptions) -> ParseResult<isaspec::IsaSpec>1060 fn parse_target_specs(&mut self, options: &ParseOptions) -> ParseResult<isaspec::IsaSpec> {
1061 // Were there any `target` commands?
1062 let mut seen_target = false;
1063 // Location of last `set` command since the last `target`.
1064 let mut last_set_loc = None;
1065
1066 let mut targets = Vec::new();
1067 let mut flag_builder = settings::builder();
1068
1069 let bool_to_str = |val: bool| {
1070 if val { "true" } else { "false" }
1071 };
1072
1073 // default to enabling cfg info
1074 flag_builder
1075 .set(
1076 "machine_code_cfg_info",
1077 bool_to_str(options.machine_code_cfg_info),
1078 )
1079 .expect("machine_code_cfg_info option should be present");
1080
1081 flag_builder
1082 .set("unwind_info", bool_to_str(options.unwind_info))
1083 .expect("unwind_info option should be present");
1084
1085 while let Some(Token::Identifier(command)) = self.token() {
1086 match command {
1087 "set" => {
1088 last_set_loc = Some(self.loc);
1089 isaspec::parse_options(
1090 self.consume_line().trim().split_whitespace(),
1091 &mut flag_builder,
1092 self.loc,
1093 )
1094 .map_err(|err| ParseError::from(err))?;
1095 }
1096 "target" => {
1097 let loc = self.loc;
1098 // Grab the whole line so the lexer won't go looking for tokens on the
1099 // following lines.
1100 let mut words = self.consume_line().trim().split_whitespace().peekable();
1101 // Look for `target foo`.
1102 let target_name = match words.next() {
1103 Some(w) => w,
1104 None => return err!(loc, "expected target triple"),
1105 };
1106 let triple = match Triple::from_str(target_name) {
1107 Ok(triple) => triple,
1108 Err(err) => return err!(loc, err),
1109 };
1110 let mut isa_builder = match isa::lookup(triple) {
1111 Err(isa::LookupError::SupportDisabled) => {
1112 continue;
1113 }
1114 Err(isa::LookupError::Unsupported) => {
1115 return warn!(loc, "unsupported target '{}'", target_name);
1116 }
1117 Ok(b) => b,
1118 };
1119 last_set_loc = None;
1120 seen_target = true;
1121 // Apply the target-specific settings to `isa_builder`.
1122 isaspec::parse_options(words, &mut isa_builder, self.loc)?;
1123
1124 // Construct a trait object with the aggregate settings.
1125 targets.push(
1126 isa_builder
1127 .finish(settings::Flags::new(flag_builder.clone()))
1128 .map_err(|e| ParseError {
1129 location: loc,
1130 message: format!("invalid ISA flags for '{target_name}': {e:?}"),
1131 is_warning: false,
1132 })?,
1133 );
1134 }
1135 _ => break,
1136 }
1137 }
1138
1139 if !seen_target {
1140 // No `target` commands, but we allow for `set` commands.
1141 Ok(isaspec::IsaSpec::None(settings::Flags::new(flag_builder)))
1142 } else if let Some(loc) = last_set_loc {
1143 err!(
1144 loc,
1145 "dangling 'set' command after ISA specification has no effect."
1146 )
1147 } else {
1148 Ok(isaspec::IsaSpec::Some(targets))
1149 }
1150 }
1151
1152 /// Parse a list of expected features that Cranelift should be compiled with, or without.
parse_cranelift_features(&mut self) -> ParseResult<Vec<Feature<'a>>>1153 pub fn parse_cranelift_features(&mut self) -> ParseResult<Vec<Feature<'a>>> {
1154 let mut list = Vec::new();
1155 while self.token() == Some(Token::Identifier("feature")) {
1156 self.consume();
1157 let has = !self.optional(Token::Bang);
1158 match (self.token(), has) {
1159 (Some(Token::String(flag)), true) => list.push(Feature::With(flag)),
1160 (Some(Token::String(flag)), false) => list.push(Feature::Without(flag)),
1161 (tok, _) => {
1162 return err!(
1163 self.loc,
1164 format!("Expected feature flag string, got {:?}", tok)
1165 );
1166 }
1167 }
1168 self.consume();
1169 }
1170 Ok(list)
1171 }
1172
1173 /// Parse a list of function definitions.
1174 ///
1175 /// This is the top-level parse function matching the whole contents of a file.
parse_function_list(&mut self) -> ParseResult<Vec<(Function, Details<'a>)>>1176 pub fn parse_function_list(&mut self) -> ParseResult<Vec<(Function, Details<'a>)>> {
1177 let mut list = Vec::new();
1178 while self.token().is_some() {
1179 list.push(self.parse_function()?);
1180 }
1181 if let Some(err) = self.lex_error {
1182 return match err {
1183 LexError::InvalidChar => err!(self.loc, "invalid character"),
1184 };
1185 }
1186 Ok(list)
1187 }
1188
1189 // Parse a whole function definition.
1190 //
1191 // function ::= * "function" name signature "{" preamble function-body "}"
1192 //
parse_function(&mut self) -> ParseResult<(Function, Details<'a>)>1193 fn parse_function(&mut self) -> ParseResult<(Function, Details<'a>)> {
1194 // Begin gathering comments.
1195 // Make sure we don't include any comments before the `function` keyword.
1196 self.token();
1197 debug_assert!(self.comments.is_empty());
1198 self.start_gathering_comments();
1199
1200 self.match_identifier("function", "expected 'function'")?;
1201
1202 let location = self.loc;
1203
1204 // function ::= "function" * name signature "{" preamble function-body "}"
1205 let name = self.parse_user_func_name()?;
1206
1207 // function ::= "function" name * signature "{" preamble function-body "}"
1208 let sig = self.parse_signature()?;
1209
1210 let mut ctx = Context::new(Function::with_name_signature(name, sig));
1211
1212 // function ::= "function" name signature * "{" preamble function-body "}"
1213 self.match_token(Token::LBrace, "expected '{' before function body")?;
1214
1215 self.token();
1216 self.claim_gathered_comments(AnyEntity::Function);
1217
1218 // function ::= "function" name signature "{" * preamble function-body "}"
1219 self.parse_preamble(&mut ctx)?;
1220 // function ::= "function" name signature "{" preamble * function-body "}"
1221 self.parse_function_body(&mut ctx)?;
1222 // function ::= "function" name signature "{" preamble function-body * "}"
1223 self.match_token(Token::RBrace, "expected '}' after function body")?;
1224
1225 // Collect any comments following the end of the function, then stop gathering comments.
1226 self.start_gathering_comments();
1227 self.token();
1228 self.claim_gathered_comments(AnyEntity::Function);
1229
1230 // Claim all the declared user-defined function names.
1231 for (user_func_ref, user_external_name) in
1232 std::mem::take(&mut self.predeclared_external_names)
1233 {
1234 let actual_ref = ctx
1235 .function
1236 .declare_imported_user_function(user_external_name);
1237 assert_eq!(user_func_ref, actual_ref);
1238 }
1239
1240 let details = Details {
1241 location,
1242 comments: self.take_comments(),
1243 map: ctx.map,
1244 };
1245
1246 Ok((ctx.function, details))
1247 }
1248
1249 // Parse a user-defined function name
1250 //
1251 // For example, in a function decl, the parser would be in this state:
1252 //
1253 // function ::= "function" * name signature { ... }
1254 //
parse_user_func_name(&mut self) -> ParseResult<UserFuncName>1255 fn parse_user_func_name(&mut self) -> ParseResult<UserFuncName> {
1256 match self.token() {
1257 Some(Token::Name(s)) => {
1258 self.consume();
1259 Ok(UserFuncName::testcase(s))
1260 }
1261 Some(Token::UserRef(namespace)) => {
1262 self.consume();
1263 match self.token() {
1264 Some(Token::Colon) => {
1265 self.consume();
1266 match self.token() {
1267 Some(Token::Integer(index_str)) => {
1268 self.consume();
1269 let index: u32 =
1270 u32::from_str_radix(index_str, 10).map_err(|_| {
1271 self.error("the integer given overflows the u32 type")
1272 })?;
1273 Ok(UserFuncName::user(namespace, index))
1274 }
1275 _ => err!(self.loc, "expected integer"),
1276 }
1277 }
1278 _ => {
1279 err!(self.loc, "expected user function name in the form uX:Y")
1280 }
1281 }
1282 }
1283 _ => err!(self.loc, "expected external name"),
1284 }
1285 }
1286
1287 // Parse an external name.
1288 //
1289 // For example, in a function reference decl, the parser would be in this state:
1290 //
1291 // fn0 = * name signature
1292 //
parse_external_name(&mut self) -> ParseResult<ExternalName>1293 fn parse_external_name(&mut self) -> ParseResult<ExternalName> {
1294 match self.token() {
1295 Some(Token::Name(s)) => {
1296 self.consume();
1297 s.parse()
1298 .map_err(|_| self.error("invalid test case or libcall name"))
1299 }
1300
1301 Some(Token::UserNameRef(name_ref)) => {
1302 self.consume();
1303 Ok(ExternalName::user(UserExternalNameRef::new(
1304 name_ref as usize,
1305 )))
1306 }
1307
1308 Some(Token::UserRef(namespace)) => {
1309 self.consume();
1310 if let Some(Token::Colon) = self.token() {
1311 self.consume();
1312 match self.token() {
1313 Some(Token::Integer(index_str)) => {
1314 let index: u32 = u32::from_str_radix(index_str, 10).map_err(|_| {
1315 self.error("the integer given overflows the u32 type")
1316 })?;
1317 self.consume();
1318
1319 // Deduplicate the reference (O(n), but should be fine for tests),
1320 // to follow `FunctionParameters::declare_imported_user_function`,
1321 // otherwise this will cause ref mismatches when asserted below.
1322 let name_ref = self
1323 .predeclared_external_names
1324 .iter()
1325 .find_map(|(reff, name)| {
1326 if name.index == index && name.namespace == namespace {
1327 Some(reff)
1328 } else {
1329 None
1330 }
1331 })
1332 .unwrap_or_else(|| {
1333 self.predeclared_external_names
1334 .push(ir::UserExternalName { namespace, index })
1335 });
1336
1337 Ok(ExternalName::user(name_ref))
1338 }
1339 _ => err!(self.loc, "expected integer"),
1340 }
1341 } else {
1342 err!(self.loc, "expected colon")
1343 }
1344 }
1345
1346 _ => err!(self.loc, "expected external name"),
1347 }
1348 }
1349
1350 // Parse a function signature.
1351 //
1352 // signature ::= * "(" [paramlist] ")" ["->" retlist] [callconv]
1353 //
parse_signature(&mut self) -> ParseResult<Signature>1354 fn parse_signature(&mut self) -> ParseResult<Signature> {
1355 // Calling convention defaults to `fast`, but can be changed.
1356 let mut sig = Signature::new(self.default_calling_convention);
1357
1358 self.match_token(Token::LPar, "expected function signature: ( args... )")?;
1359 // signature ::= "(" * [abi-param-list] ")" ["->" retlist] [callconv]
1360 if self.token() != Some(Token::RPar) {
1361 sig.params = self.parse_abi_param_list()?;
1362 }
1363 self.match_token(Token::RPar, "expected ')' after function arguments")?;
1364 if self.optional(Token::Arrow) {
1365 sig.returns = self.parse_abi_param_list()?;
1366 }
1367
1368 // The calling convention is optional.
1369 match self.token() {
1370 Some(Token::Identifier(text)) => match text.parse() {
1371 Ok(cc) => {
1372 self.consume();
1373 sig.call_conv = cc;
1374 }
1375 _ => return err!(self.loc, "unknown calling convention: {}", text),
1376 },
1377 _ => {}
1378 }
1379
1380 Ok(sig)
1381 }
1382
1383 // Parse list of function parameter / return value types.
1384 //
1385 // paramlist ::= * param { "," param }
1386 //
parse_abi_param_list(&mut self) -> ParseResult<Vec<AbiParam>>1387 fn parse_abi_param_list(&mut self) -> ParseResult<Vec<AbiParam>> {
1388 let mut list = Vec::new();
1389
1390 // abi-param-list ::= * abi-param { "," abi-param }
1391 list.push(self.parse_abi_param()?);
1392
1393 // abi-param-list ::= abi-param * { "," abi-param }
1394 while self.optional(Token::Comma) {
1395 // abi-param-list ::= abi-param { "," * abi-param }
1396 list.push(self.parse_abi_param()?);
1397 }
1398
1399 Ok(list)
1400 }
1401
1402 // Parse a single argument type with flags.
parse_abi_param(&mut self) -> ParseResult<AbiParam>1403 fn parse_abi_param(&mut self) -> ParseResult<AbiParam> {
1404 // abi-param ::= * type { flag }
1405 let mut arg = AbiParam::new(self.match_type("expected parameter type")?);
1406
1407 // abi-param ::= type * { flag }
1408 while let Some(Token::Identifier(s)) = self.token() {
1409 match s {
1410 "uext" => arg.extension = ArgumentExtension::Uext,
1411 "sext" => arg.extension = ArgumentExtension::Sext,
1412 "sarg" => {
1413 self.consume();
1414 self.match_token(Token::LPar, "expected '(' to begin sarg size")?;
1415 let size = self.match_uimm32("expected byte-size in sarg decl")?;
1416 self.match_token(Token::RPar, "expected ')' to end sarg size")?;
1417 arg.purpose = ArgumentPurpose::StructArgument(size.into());
1418 continue;
1419 }
1420 _ => {
1421 if let Ok(purpose) = s.parse() {
1422 arg.purpose = purpose;
1423 } else {
1424 break;
1425 }
1426 }
1427 }
1428 self.consume();
1429 }
1430
1431 Ok(arg)
1432 }
1433
1434 // Parse the function preamble.
1435 //
1436 // preamble ::= * { preamble-decl }
1437 // preamble-decl ::= * stack-slot-decl
1438 // * function-decl
1439 // * signature-decl
1440 // * jump-table-decl
1441 // * stack-limit-decl
1442 //
1443 // The parsed decls are added to `ctx` rather than returned.
parse_preamble(&mut self, ctx: &mut Context) -> ParseResult<()>1444 fn parse_preamble(&mut self, ctx: &mut Context) -> ParseResult<()> {
1445 loop {
1446 match self.token() {
1447 Some(Token::StackSlot(..)) => {
1448 self.start_gathering_comments();
1449 let loc = self.loc;
1450 self.parse_stack_slot_decl()
1451 .and_then(|(ss, dat)| ctx.add_ss(ss, dat, loc))
1452 }
1453 Some(Token::DynamicStackSlot(..)) => {
1454 self.start_gathering_comments();
1455 let loc = self.loc;
1456 self.parse_dynamic_stack_slot_decl()
1457 .and_then(|(dss, dat)| ctx.add_dss(dss, dat, loc))
1458 }
1459 Some(Token::DynamicType(..)) => {
1460 self.start_gathering_comments();
1461 let loc = self.loc;
1462 self.parse_dynamic_type_decl()
1463 .and_then(|(dt, dat)| ctx.add_dt(dt, dat, loc))
1464 }
1465 Some(Token::GlobalValue(..)) => {
1466 self.start_gathering_comments();
1467 self.parse_global_value_decl()
1468 .and_then(|(gv, dat)| ctx.add_gv(gv, dat, self.loc))
1469 }
1470 Some(Token::SigRef(..)) => {
1471 self.start_gathering_comments();
1472 self.parse_signature_decl().and_then(|(sig, dat)| {
1473 ctx.add_sig(sig, dat, self.loc, self.default_calling_convention)
1474 })
1475 }
1476 Some(Token::FuncRef(..)) => {
1477 self.start_gathering_comments();
1478 self.parse_function_decl(ctx)
1479 .and_then(|(fn_, dat)| ctx.add_fn(fn_, dat, self.loc))
1480 }
1481 Some(Token::Constant(..)) => {
1482 self.start_gathering_comments();
1483 self.parse_constant_decl()
1484 .and_then(|(c, v)| ctx.add_constant(c, v, self.loc))
1485 }
1486 Some(Token::Identifier("stack_limit")) => {
1487 self.start_gathering_comments();
1488 self.parse_stack_limit_decl()
1489 .and_then(|gv| ctx.add_stack_limit(gv, self.loc))
1490 }
1491 // More to come..
1492 _ => return Ok(()),
1493 }?;
1494 }
1495 }
1496
1497 // Parse a stack slot decl.
1498 //
1499 // stack-slot-decl ::= * StackSlot(ss) "=" stack-slot-kind Bytes {"," stack-slot-flag}
1500 // stack-slot-kind ::= "explicit_slot"
1501 // | "spill_slot"
1502 // | "incoming_arg"
1503 // | "outgoing_arg"
1504 // stack-slot-flag ::= "align" "=" Bytes | "key" "=" uimm64
parse_stack_slot_decl(&mut self) -> ParseResult<(StackSlot, StackSlotData)>1505 fn parse_stack_slot_decl(&mut self) -> ParseResult<(StackSlot, StackSlotData)> {
1506 let ss = self.match_ss("expected stack slot number: ss«n»")?;
1507 self.match_token(Token::Equal, "expected '=' in stack slot declaration")?;
1508 let kind = self.match_enum("expected stack slot kind")?;
1509
1510 // stack-slot-decl ::= StackSlot(ss) "=" stack-slot-kind * Bytes {"," stack-slot-flag}
1511 let bytes: i64 = self
1512 .match_imm64("expected byte-size in stack_slot decl")?
1513 .into();
1514 if bytes < 0 {
1515 return err!(self.loc, "negative stack slot size");
1516 }
1517 if bytes > i64::from(u32::MAX) {
1518 return err!(self.loc, "stack slot too large");
1519 }
1520
1521 let mut align = 1;
1522 let mut key = None;
1523
1524 while self.token() == Some(Token::Comma) {
1525 self.consume();
1526 match self.token() {
1527 Some(Token::Identifier("align")) => {
1528 self.consume();
1529 self.match_token(Token::Equal, "expected `=` after flag")?;
1530 let align64: i64 = self
1531 .match_imm64("expected alignment-size after `align` flag")?
1532 .into();
1533 align = u32::try_from(align64)
1534 .map_err(|_| self.error("alignment must be a 32-bit unsigned integer"))?;
1535 }
1536 Some(Token::Identifier("key")) => {
1537 self.consume();
1538 self.match_token(Token::Equal, "expected `=` after flag")?;
1539 let value = self.match_uimm64("expected `u64` value for `key` flag")?;
1540 key = Some(StackSlotKey::new(value.into()));
1541 }
1542 _ => {
1543 return Err(self.error("invalid flag for stack slot"));
1544 }
1545 }
1546 }
1547
1548 if !align.is_power_of_two() {
1549 return err!(self.loc, "stack slot alignment is not a power of two");
1550 }
1551 let align_shift = u8::try_from(align.ilog2()).unwrap(); // Always succeeds: range 0..=31.
1552
1553 let data = match key {
1554 Some(key) => StackSlotData::new_with_key(kind, bytes as u32, align_shift, key),
1555 None => StackSlotData::new(kind, bytes as u32, align_shift),
1556 };
1557
1558 // Collect any trailing comments.
1559 self.token();
1560 self.claim_gathered_comments(ss);
1561
1562 // TBD: stack-slot-decl ::= StackSlot(ss) "=" stack-slot-kind Bytes * {"," stack-slot-flag}
1563 Ok((ss, data))
1564 }
1565
parse_dynamic_stack_slot_decl( &mut self, ) -> ParseResult<(DynamicStackSlot, DynamicStackSlotData)>1566 fn parse_dynamic_stack_slot_decl(
1567 &mut self,
1568 ) -> ParseResult<(DynamicStackSlot, DynamicStackSlotData)> {
1569 let dss = self.match_dss("expected stack slot number: dss«n»")?;
1570 self.match_token(Token::Equal, "expected '=' in stack slot declaration")?;
1571 let kind = self.match_enum("expected stack slot kind")?;
1572 let dt = self.match_dt("expected dynamic type")?;
1573 let data = DynamicStackSlotData::new(kind, dt);
1574 // Collect any trailing comments.
1575 self.token();
1576 self.claim_gathered_comments(dss);
1577
1578 // TBD: stack-slot-decl ::= StackSlot(ss) "=" stack-slot-kind Bytes * {"," stack-slot-flag}
1579 Ok((dss, data))
1580 }
1581
parse_dynamic_type_decl(&mut self) -> ParseResult<(DynamicType, DynamicTypeData)>1582 fn parse_dynamic_type_decl(&mut self) -> ParseResult<(DynamicType, DynamicTypeData)> {
1583 let dt = self.match_dt("expected dynamic type number: dt«n»")?;
1584 self.match_token(Token::Equal, "expected '=' in stack slot declaration")?;
1585 let vector_base_ty = self.match_type("expected base type")?;
1586 assert!(vector_base_ty.is_vector(), "expected vector type");
1587 self.match_token(
1588 Token::Multiply,
1589 "expected '*' followed by a dynamic scale value",
1590 )?;
1591 let dyn_scale = self.match_gv("expected dynamic scale global value")?;
1592 let data = DynamicTypeData::new(vector_base_ty, dyn_scale);
1593 // Collect any trailing comments.
1594 self.token();
1595 self.claim_gathered_comments(dt);
1596 Ok((dt, data))
1597 }
1598
1599 // Parse a global value decl.
1600 //
1601 // global-val-decl ::= * GlobalValue(gv) "=" global-val-desc
1602 // global-val-desc ::= "vmctx"
1603 // | "load" "." type "notrap" "aligned" GlobalValue(base) [offset]
1604 // | "iadd_imm" "(" GlobalValue(base) ")" imm64
1605 // | "symbol" ["colocated"] name + imm64
1606 // | "dyn_scale_target_const" "." type
1607 //
parse_global_value_decl(&mut self) -> ParseResult<(GlobalValue, GlobalValueData)>1608 fn parse_global_value_decl(&mut self) -> ParseResult<(GlobalValue, GlobalValueData)> {
1609 let gv = self.match_gv("expected global value number: gv«n»")?;
1610
1611 self.match_token(Token::Equal, "expected '=' in global value declaration")?;
1612
1613 let data = match self.match_any_identifier("expected global value kind")? {
1614 "vmctx" => GlobalValueData::VMContext,
1615 "load" => {
1616 self.match_token(
1617 Token::Dot,
1618 "expected '.' followed by type in load global value decl",
1619 )?;
1620 let global_type = self.match_type("expected load type")?;
1621 let flags = self.optional_memflags()?;
1622 let base = self.match_gv("expected global value: gv«n»")?;
1623 let offset = self.optional_offset32()?;
1624
1625 if !(flags.notrap() && flags.aligned()) {
1626 return err!(self.loc, "global-value load must be notrap and aligned");
1627 }
1628 GlobalValueData::Load {
1629 base,
1630 offset,
1631 global_type,
1632 flags,
1633 }
1634 }
1635 "iadd_imm" => {
1636 self.match_token(
1637 Token::Dot,
1638 "expected '.' followed by type in iadd_imm global value decl",
1639 )?;
1640 let global_type = self.match_type("expected iadd type")?;
1641 let base = self.match_gv("expected global value: gv«n»")?;
1642 self.match_token(
1643 Token::Comma,
1644 "expected ',' followed by rhs in iadd_imm global value decl",
1645 )?;
1646 let offset = self.match_imm64("expected iadd_imm immediate")?;
1647 GlobalValueData::IAddImm {
1648 base,
1649 offset,
1650 global_type,
1651 }
1652 }
1653 "symbol" => {
1654 let colocated = self.optional(Token::Identifier("colocated"));
1655 let tls = self.optional(Token::Identifier("tls"));
1656 let name = self.parse_external_name()?;
1657 let offset = self.optional_offset_imm64()?;
1658 GlobalValueData::Symbol {
1659 name,
1660 offset,
1661 colocated,
1662 tls,
1663 }
1664 }
1665 "dyn_scale_target_const" => {
1666 self.match_token(
1667 Token::Dot,
1668 "expected '.' followed by type in dynamic scale global value decl",
1669 )?;
1670 let vector_type = self.match_type("expected load type")?;
1671 assert!(vector_type.is_vector(), "Expected vector type");
1672 GlobalValueData::DynScaleTargetConst { vector_type }
1673 }
1674 other => return err!(self.loc, "Unknown global value kind '{}'", other),
1675 };
1676
1677 // Collect any trailing comments.
1678 self.token();
1679 self.claim_gathered_comments(gv);
1680
1681 Ok((gv, data))
1682 }
1683
1684 // Parse a signature decl.
1685 //
1686 // signature-decl ::= SigRef(sigref) "=" signature
1687 //
parse_signature_decl(&mut self) -> ParseResult<(SigRef, Signature)>1688 fn parse_signature_decl(&mut self) -> ParseResult<(SigRef, Signature)> {
1689 let sig = self.match_sig("expected signature number: sig«n»")?;
1690 self.match_token(Token::Equal, "expected '=' in signature decl")?;
1691 let data = self.parse_signature()?;
1692
1693 // Collect any trailing comments.
1694 self.token();
1695 self.claim_gathered_comments(sig);
1696
1697 Ok((sig, data))
1698 }
1699
1700 // Parse a function decl.
1701 //
1702 // Two variants:
1703 //
1704 // function-decl ::= FuncRef(fnref) "=" ["colocated"] ["patchable"] name function-decl-sig
1705 // function-decl-sig ::= SigRef(sig) | signature
1706 //
1707 // The first variant allocates a new signature reference. The second references an existing
1708 // signature which must be declared first.
1709 //
parse_function_decl(&mut self, ctx: &mut Context) -> ParseResult<(FuncRef, ExtFuncData)>1710 fn parse_function_decl(&mut self, ctx: &mut Context) -> ParseResult<(FuncRef, ExtFuncData)> {
1711 let fn_ = self.match_fn("expected function number: fn«n»")?;
1712 self.match_token(Token::Equal, "expected '=' in function decl")?;
1713
1714 let loc = self.loc;
1715
1716 // function-decl ::= FuncRef(fnref) "=" * ["colocated"] ["patchable"] name function-decl-sig
1717 let colocated = self.optional(Token::Identifier("colocated"));
1718 // function-decl ::= FuncRef(fnref) "=" ["colocated"] * ["patchable"] name function-decl-sig
1719 let patchable = self.optional(Token::Identifier("patchable"));
1720
1721 // function-decl ::= FuncRef(fnref) "=" ["colocated"] ["patchable"] * name function-decl-sig
1722 let name = self.parse_external_name()?;
1723
1724 // function-decl ::= FuncRef(fnref) "=" ["colocated"] ["patchable"] name * function-decl-sig
1725 let data = match self.token() {
1726 Some(Token::LPar) => {
1727 // function-decl ::= FuncRef(fnref) "=" ["colocated"] ["patchable"] name * signature
1728 let sig = self.parse_signature()?;
1729 let sigref = ctx.function.import_signature(sig);
1730 ctx.map
1731 .def_entity(sigref.into(), loc)
1732 .expect("duplicate SigRef entities created");
1733 ExtFuncData {
1734 name,
1735 signature: sigref,
1736 colocated,
1737 patchable,
1738 }
1739 }
1740 Some(Token::SigRef(sig_src)) => {
1741 let sig = match SigRef::with_number(sig_src) {
1742 None => {
1743 return err!(self.loc, "attempted to use invalid signature ss{}", sig_src);
1744 }
1745 Some(sig) => sig,
1746 };
1747 ctx.check_sig(sig, self.loc)?;
1748 self.consume();
1749 ExtFuncData {
1750 name,
1751 signature: sig,
1752 colocated,
1753 patchable,
1754 }
1755 }
1756 _ => return err!(self.loc, "expected 'function' or sig«n» in function decl"),
1757 };
1758
1759 // Collect any trailing comments.
1760 self.token();
1761 self.claim_gathered_comments(fn_);
1762
1763 Ok((fn_, data))
1764 }
1765
1766 // Parse a jump table literal.
1767 //
1768 // jump-table-lit ::= "[" block(args) {"," block(args) } "]"
1769 // | "[]"
parse_jump_table( &mut self, ctx: &mut Context, def: ir::BlockCall, ) -> ParseResult<ir::JumpTable>1770 fn parse_jump_table(
1771 &mut self,
1772 ctx: &mut Context,
1773 def: ir::BlockCall,
1774 ) -> ParseResult<ir::JumpTable> {
1775 self.match_token(Token::LBracket, "expected '[' before jump table contents")?;
1776
1777 let mut data = Vec::new();
1778
1779 match self.token() {
1780 Some(Token::Block(dest)) => {
1781 self.consume();
1782 let args = self.parse_opt_block_call_args()?;
1783 data.push(ctx.function.dfg.block_call(dest, &args));
1784
1785 loop {
1786 match self.token() {
1787 Some(Token::Comma) => {
1788 self.consume();
1789 if let Some(Token::Block(dest)) = self.token() {
1790 self.consume();
1791 let args = self.parse_opt_block_call_args()?;
1792 data.push(ctx.function.dfg.block_call(dest, &args));
1793 } else {
1794 return err!(self.loc, "expected jump_table entry");
1795 }
1796 }
1797 Some(Token::RBracket) => break,
1798 _ => return err!(self.loc, "expected ']' after jump table contents"),
1799 }
1800 }
1801 }
1802 Some(Token::RBracket) => (),
1803 _ => return err!(self.loc, "expected jump_table entry"),
1804 }
1805
1806 self.consume();
1807
1808 Ok(ctx
1809 .function
1810 .dfg
1811 .jump_tables
1812 .push(JumpTableData::new(def, &data)))
1813 }
1814
1815 // Parse an exception-table decl.
1816 //
1817 // exception-table ::= * SigRef(sig) "," BlockCall "," "[" (exception-table-entry ( "," exception-table-entry )*)? "]"
1818 // exception-table-entry ::= ExceptionTag(tag) ":" BlockCall
1819 // | "default" ":" BlockCall
1820 // | "context" value
parse_exception_table(&mut self, ctx: &mut Context) -> ParseResult<ir::ExceptionTable>1821 fn parse_exception_table(&mut self, ctx: &mut Context) -> ParseResult<ir::ExceptionTable> {
1822 let sig = self.match_sig("expected signature of called function")?;
1823 self.match_token(Token::Comma, "expected comma after signature argument")?;
1824
1825 let mut handlers = vec![];
1826
1827 let block_num = self.match_block("expected branch destination block")?;
1828 let args = self.parse_opt_block_call_args()?;
1829 let normal_return = ctx.function.dfg.block_call(block_num, &args);
1830
1831 self.match_token(
1832 Token::Comma,
1833 "expected comma after normal-return destination",
1834 )?;
1835
1836 self.match_token(
1837 Token::LBracket,
1838 "expected an open-bracket for exception table list",
1839 )?;
1840 loop {
1841 match self.token() {
1842 Some(Token::RBracket) => {
1843 break;
1844 }
1845 Some(Token::ExceptionTag(tag)) => {
1846 self.consume();
1847 self.match_token(Token::Colon, "expected ':' after exception tag")?;
1848 let tag = ir::ExceptionTag::from_u32(tag);
1849 let block_num = self.match_block("expected branch destination block")?;
1850 let args = self.parse_opt_block_call_args()?;
1851 let block_call = ctx.function.dfg.block_call(block_num, &args);
1852 handlers.push(ir::ExceptionTableItem::Tag(tag, block_call));
1853 }
1854 Some(Token::Identifier("default")) => {
1855 self.consume();
1856 self.match_token(Token::Colon, "expected ':' after 'default'")?;
1857 let block_num = self.match_block("expected branch destination block")?;
1858 let args = self.parse_opt_block_call_args()?;
1859 let block_call = ctx.function.dfg.block_call(block_num, &args);
1860 handlers.push(ir::ExceptionTableItem::Default(block_call));
1861 }
1862 Some(Token::Identifier("context")) => {
1863 self.consume();
1864 let val = self.match_value("expected value for exception-handler context")?;
1865 handlers.push(ir::ExceptionTableItem::Context(val));
1866 }
1867 _ => return err!(self.loc, "invalid token"),
1868 }
1869
1870 if let Some(Token::Comma) = self.token() {
1871 self.consume();
1872 } else {
1873 break;
1874 }
1875 }
1876 self.match_token(Token::RBracket, "expected closing bracket")?;
1877
1878 Ok(ctx
1879 .function
1880 .dfg
1881 .exception_tables
1882 .push(ir::ExceptionTableData::new(sig, normal_return, handlers)))
1883 }
1884
1885 // Parse a constant decl.
1886 //
1887 // constant-decl ::= * Constant(c) "=" ty? "[" literal {"," literal} "]"
parse_constant_decl(&mut self) -> ParseResult<(Constant, ConstantData)>1888 fn parse_constant_decl(&mut self) -> ParseResult<(Constant, ConstantData)> {
1889 let name = self.match_constant()?;
1890 self.match_token(Token::Equal, "expected '=' in constant decl")?;
1891 let data = if let Some(Token::Type(_)) = self.token() {
1892 let ty = self.match_type("expected type of constant")?;
1893 self.match_uimm128(ty)
1894 } else {
1895 self.match_hexadecimal_constant("expected an immediate hexadecimal operand")
1896 }?;
1897
1898 // Collect any trailing comments.
1899 self.token();
1900 self.claim_gathered_comments(name);
1901
1902 Ok((name, data))
1903 }
1904
1905 // Parse a stack limit decl
1906 //
1907 // stack-limit-decl ::= * StackLimit "=" GlobalValue(gv)
parse_stack_limit_decl(&mut self) -> ParseResult<GlobalValue>1908 fn parse_stack_limit_decl(&mut self) -> ParseResult<GlobalValue> {
1909 self.match_stack_limit()?;
1910 self.match_token(Token::Equal, "expected '=' in stack limit decl")?;
1911 let limit = match self.token() {
1912 Some(Token::GlobalValue(base_num)) => match GlobalValue::with_number(base_num) {
1913 Some(gv) => gv,
1914 None => return err!(self.loc, "invalid global value number for stack limit"),
1915 },
1916 _ => return err!(self.loc, "expected global value"),
1917 };
1918 self.consume();
1919
1920 // Collect any trailing comments.
1921 self.token();
1922 self.claim_gathered_comments(AnyEntity::StackLimit);
1923
1924 Ok(limit)
1925 }
1926
1927 // Parse a function body, add contents to `ctx`.
1928 //
1929 // function-body ::= * { extended-basic-block }
1930 //
parse_function_body(&mut self, ctx: &mut Context) -> ParseResult<()>1931 fn parse_function_body(&mut self, ctx: &mut Context) -> ParseResult<()> {
1932 while self.token() != Some(Token::RBrace) {
1933 self.parse_basic_block(ctx)?;
1934 }
1935
1936 // Now that we've seen all defined values in the function, ensure that
1937 // all references refer to a definition.
1938 for block in &ctx.function.layout {
1939 for inst in ctx.function.layout.block_insts(block) {
1940 for value in ctx.function.dfg.inst_values(inst) {
1941 if !ctx.map.contains_value(value) {
1942 return err!(
1943 ctx.map.location(AnyEntity::Inst(inst)).unwrap(),
1944 "undefined operand value {}",
1945 value
1946 );
1947 }
1948 }
1949 }
1950 }
1951
1952 for alias in &ctx.aliases {
1953 if !ctx.function.dfg.set_alias_type_for_parser(*alias) {
1954 let loc = ctx.map.location(AnyEntity::Value(*alias)).unwrap();
1955 return err!(loc, "alias cycle involving {}", alias);
1956 }
1957 }
1958
1959 Ok(())
1960 }
1961
1962 // Parse a basic block, add contents to `ctx`.
1963 //
1964 // extended-basic-block ::= * block-header { instruction }
1965 // block-header ::= Block(block) [block-params] [block-flags] ":"
1966 // block-flags ::= [Cold]
1967 //
parse_basic_block(&mut self, ctx: &mut Context) -> ParseResult<()>1968 fn parse_basic_block(&mut self, ctx: &mut Context) -> ParseResult<()> {
1969 // Collect comments for the next block.
1970 self.start_gathering_comments();
1971
1972 let block_num = self.match_block("expected block header")?;
1973 let block = ctx.add_block(block_num, self.loc)?;
1974
1975 if block_num.as_u32() >= MAX_BLOCKS_IN_A_FUNCTION {
1976 return Err(self.error("too many blocks"));
1977 }
1978
1979 if self.token() == Some(Token::LPar) {
1980 self.parse_block_params(ctx, block)?;
1981 }
1982
1983 if self.optional(Token::Cold) {
1984 ctx.set_cold_block(block);
1985 }
1986
1987 self.match_token(Token::Colon, "expected ':' after block parameters")?;
1988
1989 // Collect any trailing comments.
1990 self.token();
1991 self.claim_gathered_comments(block);
1992
1993 // extended-basic-block ::= block-header * { instruction }
1994 while match self.token() {
1995 Some(Token::Value(_))
1996 | Some(Token::Identifier(_))
1997 | Some(Token::LBracket)
1998 | Some(Token::SourceLoc(_))
1999 | Some(Token::LAngle) => true,
2000 _ => false,
2001 } {
2002 let srcloc = self.optional_srcloc()?;
2003
2004 let debug_tags = self.optional_debug_tags()?;
2005
2006 // We need to parse instruction results here because they are shared
2007 // between the parsing of value aliases and the parsing of instructions.
2008 //
2009 // inst-results ::= Value(v) { "," Value(v) }
2010 let results = self.parse_inst_results()?;
2011
2012 for result in &results {
2013 while ctx.function.dfg.num_values() <= result.index() {
2014 ctx.function.dfg.make_invalid_value_for_parser();
2015 }
2016 }
2017
2018 match self.token() {
2019 Some(Token::Arrow) => {
2020 self.consume();
2021 self.parse_value_alias(&results, ctx)?;
2022 }
2023 Some(Token::Equal) => {
2024 self.consume();
2025 self.parse_instruction(&results, srcloc, debug_tags, ctx, block)?;
2026 }
2027 _ if !results.is_empty() => return err!(self.loc, "expected -> or ="),
2028 _ => self.parse_instruction(&results, srcloc, debug_tags, ctx, block)?,
2029 }
2030 }
2031
2032 Ok(())
2033 }
2034
2035 // Parse parenthesized list of block parameters.
2036 //
2037 // block-params ::= * "(" ( block-param { "," block-param } )? ")"
parse_block_params(&mut self, ctx: &mut Context, block: Block) -> ParseResult<()>2038 fn parse_block_params(&mut self, ctx: &mut Context, block: Block) -> ParseResult<()> {
2039 // block-params ::= * "(" ( block-param { "," block-param } )? ")"
2040 self.match_token(Token::LPar, "expected '(' before block parameters")?;
2041
2042 // block-params ::= "(" * ")"
2043 if self.token() == Some(Token::RPar) {
2044 self.consume();
2045 return Ok(());
2046 }
2047
2048 // block-params ::= "(" * block-param { "," block-param } ")"
2049 self.parse_block_param(ctx, block)?;
2050
2051 // block-params ::= "(" block-param * { "," block-param } ")"
2052 while self.optional(Token::Comma) {
2053 // block-params ::= "(" block-param { "," * block-param } ")"
2054 self.parse_block_param(ctx, block)?;
2055 }
2056
2057 // block-params ::= "(" block-param { "," block-param } * ")"
2058 self.match_token(Token::RPar, "expected ')' after block parameters")?;
2059
2060 Ok(())
2061 }
2062
2063 // Parse a single block parameter declaration, and append it to `block`.
2064 //
2065 // block-param ::= * Value(v) ":" Type(t) arg-loc?
2066 // arg-loc ::= "[" value-location "]"
2067 //
parse_block_param(&mut self, ctx: &mut Context, block: Block) -> ParseResult<()>2068 fn parse_block_param(&mut self, ctx: &mut Context, block: Block) -> ParseResult<()> {
2069 // block-param ::= * Value(v) ":" Type(t) arg-loc?
2070 let v = self.match_value("block argument must be a value")?;
2071 let v_location = self.loc;
2072 self.match_token(Token::Colon, "expected ':' after block argument")?;
2073 // block-param ::= Value(v) ":" * Type(t) arg-loc?
2074 while ctx.function.dfg.num_values() <= v.index() {
2075 ctx.function.dfg.make_invalid_value_for_parser();
2076 }
2077
2078 let t = self.match_type("expected block argument type")?;
2079 // Allocate the block argument.
2080 ctx.function.dfg.append_block_param_for_parser(block, t, v);
2081 ctx.map.def_value(v, v_location)?;
2082
2083 Ok(())
2084 }
2085
2086 // Parse instruction results and return them.
2087 //
2088 // inst-results ::= Value(v) { "," Value(v) }
2089 //
parse_inst_results(&mut self) -> ParseResult<SmallVec<[Value; 1]>>2090 fn parse_inst_results(&mut self) -> ParseResult<SmallVec<[Value; 1]>> {
2091 // Result value numbers.
2092 let mut results = SmallVec::new();
2093
2094 // instruction ::= * [inst-results "="] Opcode(opc) ["." Type] ...
2095 // inst-results ::= * Value(v) { "," Value(v) }
2096 if let Some(Token::Value(v)) = self.token() {
2097 self.consume();
2098
2099 results.push(v);
2100
2101 // inst-results ::= Value(v) * { "," Value(v) }
2102 while self.optional(Token::Comma) {
2103 // inst-results ::= Value(v) { "," * Value(v) }
2104 let v = self.match_value("expected result value")?;
2105 results.push(v);
2106 }
2107 }
2108
2109 Ok(results)
2110 }
2111
2112 // Parse a value alias, and append it to `block`.
2113 //
2114 // value_alias ::= [inst-results] "->" Value(v)
2115 //
parse_value_alias(&mut self, results: &[Value], ctx: &mut Context) -> ParseResult<()>2116 fn parse_value_alias(&mut self, results: &[Value], ctx: &mut Context) -> ParseResult<()> {
2117 if results.len() != 1 {
2118 return err!(self.loc, "wrong number of aliases");
2119 }
2120 let result = results[0];
2121 let dest = self.match_value("expected value alias")?;
2122
2123 // Allow duplicate definitions of aliases, as long as they are identical.
2124 if ctx.map.contains_value(result) {
2125 if let Some(old) = ctx.function.dfg.value_alias_dest_for_serialization(result) {
2126 if old != dest {
2127 return err!(
2128 self.loc,
2129 "value {} is already defined as an alias with destination {}",
2130 result,
2131 old
2132 );
2133 }
2134 } else {
2135 return err!(self.loc, "value {} is already defined");
2136 }
2137 } else {
2138 ctx.map.def_value(result, self.loc)?;
2139 }
2140
2141 if !ctx.map.contains_value(dest) {
2142 return err!(self.loc, "value {} is not yet defined", dest);
2143 }
2144
2145 ctx.function
2146 .dfg
2147 .make_value_alias_for_serialization(dest, result);
2148
2149 ctx.aliases.push(result);
2150 Ok(())
2151 }
2152
2153 // Parse an instruction, append it to `block`.
2154 //
2155 // instruction ::= [inst-results "="] Opcode(opc) ["." Type] ...
2156 //
parse_instruction( &mut self, results: &[Value], srcloc: ir::SourceLoc, debug_tags: Vec<DebugTag>, ctx: &mut Context, block: Block, ) -> ParseResult<()>2157 fn parse_instruction(
2158 &mut self,
2159 results: &[Value],
2160 srcloc: ir::SourceLoc,
2161 debug_tags: Vec<DebugTag>,
2162 ctx: &mut Context,
2163 block: Block,
2164 ) -> ParseResult<()> {
2165 // Define the result values.
2166 for val in results {
2167 ctx.map.def_value(*val, self.loc)?;
2168 }
2169
2170 // Collect comments for the next instruction.
2171 self.start_gathering_comments();
2172
2173 // instruction ::= [inst-results "="] * Opcode(opc) ["." Type] ...
2174 let opcode = if let Some(Token::Identifier(text)) = self.token() {
2175 match text.parse() {
2176 Ok(opc) => opc,
2177 Err(msg) => return err!(self.loc, "{}: '{}'", msg, text),
2178 }
2179 } else {
2180 return err!(self.loc, "expected instruction opcode");
2181 };
2182 let opcode_loc = self.loc;
2183 self.consume();
2184
2185 // Look for a controlling type variable annotation.
2186 // instruction ::= [inst-results "="] Opcode(opc) * ["." Type] ...
2187 let explicit_ctrl_type = if self.optional(Token::Dot) {
2188 if let Some(Token::Type(_t)) = self.token() {
2189 Some(self.match_type("expected type after 'opcode.'")?)
2190 } else {
2191 let dt = self.match_dt("expected dynamic type")?;
2192 self.concrete_from_dt(dt, ctx)
2193 }
2194 } else {
2195 None
2196 };
2197
2198 // instruction ::= [inst-results "="] Opcode(opc) ["." Type] * ...
2199 let inst_data = self.parse_inst_operands(ctx, opcode, explicit_ctrl_type)?;
2200
2201 let ctrl_typevar = self.infer_typevar(ctx, opcode, explicit_ctrl_type, &inst_data)?;
2202 let inst = ctx.function.dfg.make_inst(inst_data);
2203
2204 // Attach stack map, if present.
2205 if self.optional(Token::Comma) {
2206 self.match_token(
2207 Token::Identifier("stack_map"),
2208 "expected `stack_map = [...]`",
2209 )?;
2210 if !opcode.is_call() || opcode.is_return() {
2211 return err!(
2212 self.loc,
2213 "stack map can only be attached to a (non-tail) call"
2214 );
2215 }
2216
2217 self.match_token(Token::Equal, "expected `= [...]`")?;
2218 self.match_token(Token::LBracket, "expected `[...]`")?;
2219 while !self.optional(Token::RBracket) {
2220 let ty = self.match_type("expected `<type> @ <slot> + <offset>`")?;
2221 self.match_token(Token::At, "expected `@ <slot> + <offset>`")?;
2222 let slot = self.match_ss("expected `<slot> + <offset>`")?;
2223 let offset: u32 = match self.token() {
2224 Some(Token::Integer(s)) if s.starts_with('+') => {
2225 self.match_uimm32("expected a u32 offset")?.into()
2226 }
2227 _ => {
2228 self.match_token(Token::Plus, "expected `+ <offset>`")?;
2229 self.match_uimm32("expected a u32 offset")?.into()
2230 }
2231 };
2232 ctx.function
2233 .dfg
2234 .append_user_stack_map_entry(inst, ir::UserStackMapEntry { ty, slot, offset });
2235 if !self.optional(Token::Comma) {
2236 self.match_token(Token::RBracket, "expected `,` or `]`")?;
2237 break;
2238 }
2239 }
2240 }
2241
2242 // We're done parsing the instruction data itself.
2243 //
2244 // We still need to check that the number of result values in
2245 // the source matches the opcode or function call
2246 // signature. We also need to create values with the right
2247 // type for all the instruction results.
2248 let num_results =
2249 ctx.function
2250 .dfg
2251 .make_inst_results_for_parser(inst, ctrl_typevar, results);
2252 ctx.function.layout.append_inst(inst, block);
2253 ctx.map
2254 .def_entity(inst.into(), opcode_loc)
2255 .expect("duplicate inst references created");
2256
2257 if !srcloc.is_default() {
2258 ctx.function.set_srcloc(inst, srcloc);
2259 }
2260 if !debug_tags.is_empty() {
2261 ctx.function.debug_tags.set(inst, debug_tags);
2262 }
2263
2264 if results.len() != num_results {
2265 return err!(
2266 self.loc,
2267 "instruction produces {} result values, {} given",
2268 num_results,
2269 results.len()
2270 );
2271 }
2272
2273 // Collect any trailing comments.
2274 self.token();
2275 self.claim_gathered_comments(inst);
2276
2277 Ok(())
2278 }
2279
2280 // Type inference for polymorphic instructions.
2281 //
2282 // The controlling type variable can be specified explicitly as 'splat.i32x4 v5', or it can be
2283 // inferred from `inst_data.typevar_operand` for some opcodes.
2284 //
2285 // Returns the controlling typevar for a polymorphic opcode, or `INVALID` for a non-polymorphic
2286 // opcode.
infer_typevar( &self, ctx: &Context, opcode: Opcode, explicit_ctrl_type: Option<Type>, inst_data: &InstructionData, ) -> ParseResult<Type>2287 fn infer_typevar(
2288 &self,
2289 ctx: &Context,
2290 opcode: Opcode,
2291 explicit_ctrl_type: Option<Type>,
2292 inst_data: &InstructionData,
2293 ) -> ParseResult<Type> {
2294 let constraints = opcode.constraints();
2295 let ctrl_type = match explicit_ctrl_type {
2296 Some(t) => t,
2297 None => {
2298 if constraints.use_typevar_operand() {
2299 // This is an opcode that supports type inference, AND there was no
2300 // explicit type specified. Look up `ctrl_value` to see if it was defined
2301 // already.
2302 // TBD: If it is defined in another block, the type should have been
2303 // specified explicitly. It is unfortunate that the correctness of IR
2304 // depends on the layout of the blocks.
2305 let ctrl_src_value = inst_data
2306 .typevar_operand(&ctx.function.dfg.value_lists)
2307 .expect("Constraints <-> Format inconsistency");
2308 if !ctx.map.contains_value(ctrl_src_value) {
2309 return err!(
2310 self.loc,
2311 "type variable required for polymorphic opcode, e.g. '{}.{}'; \
2312 can't infer from {} which is not yet defined",
2313 opcode,
2314 constraints.ctrl_typeset().unwrap().example(),
2315 ctrl_src_value
2316 );
2317 }
2318 if !ctx.function.dfg.value_is_valid_for_parser(ctrl_src_value) {
2319 return err!(
2320 self.loc,
2321 "type variable required for polymorphic opcode, e.g. '{}.{}'; \
2322 can't infer from {} which is not yet resolved",
2323 opcode,
2324 constraints.ctrl_typeset().unwrap().example(),
2325 ctrl_src_value
2326 );
2327 }
2328 ctx.function.dfg.value_type(ctrl_src_value)
2329 } else if constraints.is_polymorphic() {
2330 // This opcode does not support type inference, so the explicit type
2331 // variable is required.
2332 return err!(
2333 self.loc,
2334 "type variable required for polymorphic opcode, e.g. '{}.{}'",
2335 opcode,
2336 constraints.ctrl_typeset().unwrap().example()
2337 );
2338 } else {
2339 // This is a non-polymorphic opcode. No typevar needed.
2340 INVALID
2341 }
2342 }
2343 };
2344
2345 // Verify that `ctrl_type` is valid for the controlling type variable. We don't want to
2346 // attempt deriving types from an incorrect basis.
2347 // This is not a complete type check. The verifier does that.
2348 if let Some(typeset) = constraints.ctrl_typeset() {
2349 // This is a polymorphic opcode.
2350 if !typeset.contains(ctrl_type) {
2351 return err!(
2352 self.loc,
2353 "{} is not a valid typevar for {}",
2354 ctrl_type,
2355 opcode
2356 );
2357 }
2358 // Treat it as a syntax error to specify a typevar on a non-polymorphic opcode.
2359 } else if ctrl_type != INVALID {
2360 return err!(self.loc, "{} does not take a typevar", opcode);
2361 }
2362
2363 Ok(ctrl_type)
2364 }
2365
2366 // Parse comma-separated value list into a VariableArgs struct.
2367 //
2368 // value_list ::= [ value { "," value } ]
2369 //
parse_value_list(&mut self) -> ParseResult<VariableArgs>2370 fn parse_value_list(&mut self) -> ParseResult<VariableArgs> {
2371 let mut args = VariableArgs::new();
2372
2373 if let Some(Token::Value(v)) = self.token() {
2374 args.push(v);
2375 self.consume();
2376 } else {
2377 return Ok(args);
2378 }
2379
2380 while self.optional(Token::Comma) {
2381 args.push(self.match_value("expected value in argument list")?);
2382 }
2383
2384 Ok(args)
2385 }
2386
2387 /// Parse an optional list of block-call arguments enclosed in
2388 /// parentheses.
parse_opt_block_call_args(&mut self) -> ParseResult<Vec<BlockArg>>2389 fn parse_opt_block_call_args(&mut self) -> ParseResult<Vec<BlockArg>> {
2390 if !self.optional(Token::LPar) {
2391 return Ok(vec![]);
2392 }
2393
2394 let mut args = vec![];
2395 while self.token() != Some(Token::RPar) {
2396 args.push(self.parse_block_call_arg()?);
2397 if self.token() == Some(Token::Comma) {
2398 self.consume();
2399 } else {
2400 break;
2401 }
2402 }
2403
2404 self.match_token(Token::RPar, "expected ')' after arguments")?;
2405
2406 Ok(args)
2407 }
2408
parse_block_call_arg(&mut self) -> ParseResult<BlockArg>2409 fn parse_block_call_arg(&mut self) -> ParseResult<BlockArg> {
2410 match self.token() {
2411 Some(Token::Value(v)) => {
2412 self.consume();
2413 Ok(BlockArg::Value(v))
2414 }
2415 Some(Token::TryCallRet(i)) => {
2416 self.consume();
2417 Ok(BlockArg::TryCallRet(i))
2418 }
2419 Some(Token::TryCallExn(i)) => {
2420 self.consume();
2421 Ok(BlockArg::TryCallExn(i))
2422 }
2423 tok => Err(self.error(&format!("unexpected token: {tok:?}"))),
2424 }
2425 }
2426
2427 /// Parse a CLIF run command.
2428 ///
2429 /// run-command ::= "run" [":" invocation comparison expected]
2430 /// \ "print" [":" invocation]
parse_run_command(&mut self, sig: &Signature) -> ParseResult<RunCommand>2431 fn parse_run_command(&mut self, sig: &Signature) -> ParseResult<RunCommand> {
2432 // skip semicolon
2433 match self.token() {
2434 Some(Token::Identifier("run")) => {
2435 self.consume();
2436 if self.optional(Token::Colon) {
2437 let invocation = self.parse_run_invocation(sig)?;
2438 let comparison = self.parse_run_comparison()?;
2439 let expected = self.parse_run_returns(sig)?;
2440 Ok(RunCommand::Run(invocation, comparison, expected))
2441 } else if sig.params.is_empty()
2442 && sig.returns.len() == 1
2443 && sig.returns[0].value_type.is_int()
2444 {
2445 // To match the existing run behavior that does not require an explicit
2446 // invocation, we create an invocation from a function like `() -> i*` and
2447 // require the result to be non-zero.
2448 let invocation = Invocation::new("default", vec![]);
2449 let expected = vec![DataValue::I8(0)];
2450 let comparison = Comparison::NotEquals;
2451 Ok(RunCommand::Run(invocation, comparison, expected))
2452 } else {
2453 Err(self.error("unable to parse the run command"))
2454 }
2455 }
2456 Some(Token::Identifier("print")) => {
2457 self.consume();
2458 if self.optional(Token::Colon) {
2459 Ok(RunCommand::Print(self.parse_run_invocation(sig)?))
2460 } else if sig.params.is_empty() {
2461 // To allow printing of functions like `() -> *`, we create a no-arg invocation.
2462 let invocation = Invocation::new("default", vec![]);
2463 Ok(RunCommand::Print(invocation))
2464 } else {
2465 Err(self.error("unable to parse the print command"))
2466 }
2467 }
2468 _ => Err(self.error("expected a 'run:' or 'print:' command")),
2469 }
2470 }
2471
2472 /// Parse the invocation of a CLIF function.
2473 ///
2474 /// This is different from parsing a CLIF `call`; it is used in parsing run commands like
2475 /// `run: %fn(42, 4.2) == false`.
2476 ///
2477 /// invocation ::= name "(" [data-value-list] ")"
parse_run_invocation(&mut self, sig: &Signature) -> ParseResult<Invocation>2478 fn parse_run_invocation(&mut self, sig: &Signature) -> ParseResult<Invocation> {
2479 if let Some(Token::Name(name)) = self.token() {
2480 self.consume();
2481 self.match_token(
2482 Token::LPar,
2483 "expected invocation parentheses, e.g. %fn(...)",
2484 )?;
2485
2486 let arg_types = sig
2487 .params
2488 .iter()
2489 .map(|abi| abi.value_type)
2490 .collect::<Vec<_>>();
2491 let args = self.parse_data_value_list(&arg_types)?;
2492
2493 self.match_token(
2494 Token::RPar,
2495 "expected invocation parentheses, e.g. %fn(...)",
2496 )?;
2497 Ok(Invocation::new(name, args))
2498 } else {
2499 Err(self.error("expected a function name, e.g. %my_fn"))
2500 }
2501 }
2502
2503 /// Parse a comparison operator for run commands.
2504 ///
2505 /// comparison ::= "==" | "!="
parse_run_comparison(&mut self) -> ParseResult<Comparison>2506 fn parse_run_comparison(&mut self) -> ParseResult<Comparison> {
2507 if self.optional(Token::Equal) {
2508 self.match_token(Token::Equal, "expected another =")?;
2509 Ok(Comparison::Equals)
2510 } else if self.optional(Token::Bang) {
2511 self.match_token(Token::Equal, "expected a =")?;
2512 Ok(Comparison::NotEquals)
2513 } else {
2514 Err(self.error("unable to parse a valid comparison operator"))
2515 }
2516 }
2517
2518 /// Parse the expected return values of a run invocation.
2519 ///
2520 /// expected ::= "[" "]"
2521 /// | data-value
2522 /// | "[" data-value-list "]"
parse_run_returns(&mut self, sig: &Signature) -> ParseResult<Vec<DataValue>>2523 fn parse_run_returns(&mut self, sig: &Signature) -> ParseResult<Vec<DataValue>> {
2524 if sig.returns.len() != 1 {
2525 self.match_token(Token::LBracket, "expected a left bracket [")?;
2526 }
2527
2528 let returns = self
2529 .parse_data_value_list(&sig.returns.iter().map(|a| a.value_type).collect::<Vec<_>>())?;
2530
2531 if sig.returns.len() != 1 {
2532 self.match_token(Token::RBracket, "expected a right bracket ]")?;
2533 }
2534 Ok(returns)
2535 }
2536
2537 /// Parse a comma-separated list of data values.
2538 ///
2539 /// data-value-list ::= [data-value {"," data-value-list}]
parse_data_value_list(&mut self, types: &[Type]) -> ParseResult<Vec<DataValue>>2540 fn parse_data_value_list(&mut self, types: &[Type]) -> ParseResult<Vec<DataValue>> {
2541 let mut values = vec![];
2542 for ty in types.iter().take(1) {
2543 values.push(self.parse_data_value(*ty)?);
2544 }
2545 for ty in types.iter().skip(1) {
2546 self.match_token(
2547 Token::Comma,
2548 "expected a comma between invocation arguments",
2549 )?;
2550 values.push(self.parse_data_value(*ty)?);
2551 }
2552 Ok(values)
2553 }
2554
2555 /// Parse a data value; e.g. `42`, `4.2`, `true`.
2556 ///
2557 /// data-value-list ::= [data-value {"," data-value-list}]
parse_data_value(&mut self, ty: Type) -> ParseResult<DataValue>2558 fn parse_data_value(&mut self, ty: Type) -> ParseResult<DataValue> {
2559 let dv = match ty {
2560 I8 => DataValue::from(self.match_imm8("expected a i8")?),
2561 I16 => DataValue::from(self.match_imm16("expected an i16")?),
2562 I32 => DataValue::from(self.match_imm32("expected an i32")?),
2563 I64 => DataValue::from(Into::<i64>::into(self.match_imm64("expected an i64")?)),
2564 I128 => DataValue::from(self.match_imm128("expected an i128")?),
2565 F16 => DataValue::from(self.match_ieee16("expected an f16")?),
2566 F32 => DataValue::from(self.match_ieee32("expected an f32")?),
2567 F64 => DataValue::from(self.match_ieee64("expected an f64")?),
2568 F128 => DataValue::from(self.match_ieee128("expected an f128")?),
2569 _ if (ty.is_vector() || ty.is_dynamic_vector()) => {
2570 let as_vec = self.match_uimm128(ty)?.into_vec();
2571 let slice = as_vec.as_slice();
2572 match slice.len() {
2573 16 => DataValue::V128(slice.try_into().unwrap()),
2574 8 => DataValue::V64(slice.try_into().unwrap()),
2575 4 => DataValue::V32(slice.try_into().unwrap()),
2576 2 => DataValue::V16(slice.try_into().unwrap()),
2577 _ => {
2578 return Err(
2579 self.error("vectors larger than 128 bits are not currently supported")
2580 );
2581 }
2582 }
2583 }
2584 _ => return Err(self.error(&format!("don't know how to parse data values of: {ty}"))),
2585 };
2586 Ok(dv)
2587 }
2588
2589 // Parse the operands following the instruction opcode.
2590 // This depends on the format of the opcode.
parse_inst_operands( &mut self, ctx: &mut Context, opcode: Opcode, explicit_control_type: Option<Type>, ) -> ParseResult<InstructionData>2591 fn parse_inst_operands(
2592 &mut self,
2593 ctx: &mut Context,
2594 opcode: Opcode,
2595 explicit_control_type: Option<Type>,
2596 ) -> ParseResult<InstructionData> {
2597 let idata = match opcode.format() {
2598 InstructionFormat::Unary => InstructionData::Unary {
2599 opcode,
2600 arg: self.match_value("expected SSA value operand")?,
2601 },
2602 InstructionFormat::UnaryImm => {
2603 let msg = |bits| format!("expected immediate {bits}-bit integer operand");
2604 let unsigned = match explicit_control_type {
2605 Some(types::I8) => self.match_imm8(&msg(8))? as u8 as i64,
2606 Some(types::I16) => self.match_imm16(&msg(16))? as u16 as i64,
2607 Some(types::I32) => self.match_imm32(&msg(32))? as u32 as i64,
2608 Some(types::I64) => self.match_imm64(&msg(64))?.bits(),
2609 _ => {
2610 return err!(
2611 self.loc,
2612 "expected one of the following type: i8, i16, i32 or i64"
2613 );
2614 }
2615 };
2616 InstructionData::UnaryImm {
2617 opcode,
2618 imm: Imm64::new(unsigned),
2619 }
2620 }
2621 InstructionFormat::UnaryIeee16 => InstructionData::UnaryIeee16 {
2622 opcode,
2623 imm: self.match_ieee16("expected immediate 16-bit float operand")?,
2624 },
2625 InstructionFormat::UnaryIeee32 => InstructionData::UnaryIeee32 {
2626 opcode,
2627 imm: self.match_ieee32("expected immediate 32-bit float operand")?,
2628 },
2629 InstructionFormat::UnaryIeee64 => InstructionData::UnaryIeee64 {
2630 opcode,
2631 imm: self.match_ieee64("expected immediate 64-bit float operand")?,
2632 },
2633 InstructionFormat::UnaryConst => {
2634 let constant_handle = if let Some(Token::Constant(_)) = self.token() {
2635 // If handed a `const?`, use that.
2636 let c = self.match_constant()?;
2637 ctx.check_constant(c, self.loc)?;
2638 c
2639 } else if opcode == Opcode::F128const {
2640 let ieee128 = self.match_ieee128("expected immediate 128-bit float operand")?;
2641 ctx.function.dfg.constants.insert(ieee128.into())
2642 } else if let Some(controlling_type) = explicit_control_type {
2643 // If an explicit control type is present, we expect a sized value and insert
2644 // it in the constant pool.
2645 let uimm128 = self.match_uimm128(controlling_type)?;
2646 ctx.function.dfg.constants.insert(uimm128)
2647 } else {
2648 return err!(
2649 self.loc,
2650 "Expected either a const entity or a typed value, e.g. inst.i32x4 [...]"
2651 );
2652 };
2653 InstructionData::UnaryConst {
2654 opcode,
2655 constant_handle,
2656 }
2657 }
2658 InstructionFormat::UnaryGlobalValue => {
2659 let gv = self.match_gv("expected global value")?;
2660 ctx.check_gv(gv, self.loc)?;
2661 InstructionData::UnaryGlobalValue {
2662 opcode,
2663 global_value: gv,
2664 }
2665 }
2666 InstructionFormat::Binary => {
2667 let lhs = self.match_value("expected SSA value first operand")?;
2668 self.match_token(Token::Comma, "expected ',' between operands")?;
2669 let rhs = self.match_value("expected SSA value second operand")?;
2670 InstructionData::Binary {
2671 opcode,
2672 args: [lhs, rhs],
2673 }
2674 }
2675 InstructionFormat::BinaryImm8 => {
2676 let arg = self.match_value("expected SSA value first operand")?;
2677 self.match_token(Token::Comma, "expected ',' between operands")?;
2678 let imm = self.match_uimm8("expected unsigned 8-bit immediate")?;
2679 InstructionData::BinaryImm8 { opcode, arg, imm }
2680 }
2681 InstructionFormat::BinaryImm64 => {
2682 let lhs = self.match_value("expected SSA value first operand")?;
2683 self.match_token(Token::Comma, "expected ',' between operands")?;
2684 let rhs = self.match_imm64("expected immediate integer second operand")?;
2685 InstructionData::BinaryImm64 {
2686 opcode,
2687 arg: lhs,
2688 imm: rhs,
2689 }
2690 }
2691 InstructionFormat::Ternary => {
2692 // Names here refer to the `select` instruction.
2693 // This format is also use by `fma`.
2694 let ctrl_arg = self.match_value("expected SSA value control operand")?;
2695 self.match_token(Token::Comma, "expected ',' between operands")?;
2696 let true_arg = self.match_value("expected SSA value true operand")?;
2697 self.match_token(Token::Comma, "expected ',' between operands")?;
2698 let false_arg = self.match_value("expected SSA value false operand")?;
2699 InstructionData::Ternary {
2700 opcode,
2701 args: [ctrl_arg, true_arg, false_arg],
2702 }
2703 }
2704 InstructionFormat::MultiAry => {
2705 let args = self.parse_value_list()?;
2706 InstructionData::MultiAry {
2707 opcode,
2708 args: args.into_value_list(&[], &mut ctx.function.dfg.value_lists),
2709 }
2710 }
2711 InstructionFormat::NullAry => InstructionData::NullAry { opcode },
2712 InstructionFormat::Jump => {
2713 // Parse the destination block number.
2714 let block_num = self.match_block("expected jump destination block")?;
2715 let args = self.parse_opt_block_call_args()?;
2716 let destination = ctx.function.dfg.block_call(block_num, &args);
2717 InstructionData::Jump {
2718 opcode,
2719 destination,
2720 }
2721 }
2722 InstructionFormat::Brif => {
2723 let arg = self.match_value("expected SSA value control operand")?;
2724 self.match_token(Token::Comma, "expected ',' between operands")?;
2725 let block_then = {
2726 let block_num = self.match_block("expected branch then block")?;
2727 let args = self.parse_opt_block_call_args()?;
2728 ctx.function.dfg.block_call(block_num, &args)
2729 };
2730 self.match_token(Token::Comma, "expected ',' between operands")?;
2731 let block_else = {
2732 let block_num = self.match_block("expected branch else block")?;
2733 let args = self.parse_opt_block_call_args()?;
2734 ctx.function.dfg.block_call(block_num, &args)
2735 };
2736 InstructionData::Brif {
2737 opcode,
2738 arg,
2739 blocks: [block_then, block_else],
2740 }
2741 }
2742 InstructionFormat::BranchTable => {
2743 let arg = self.match_value("expected SSA value operand")?;
2744 self.match_token(Token::Comma, "expected ',' between operands")?;
2745 let block_num = self.match_block("expected branch destination block")?;
2746 let args = self.parse_opt_block_call_args()?;
2747 let destination = ctx.function.dfg.block_call(block_num, &args);
2748 self.match_token(Token::Comma, "expected ',' between operands")?;
2749 let table = self.parse_jump_table(ctx, destination)?;
2750 InstructionData::BranchTable { opcode, arg, table }
2751 }
2752 InstructionFormat::TernaryImm8 => {
2753 let lhs = self.match_value("expected SSA value first operand")?;
2754 self.match_token(Token::Comma, "expected ',' between operands")?;
2755 let rhs = self.match_value("expected SSA value last operand")?;
2756 self.match_token(Token::Comma, "expected ',' between operands")?;
2757 let imm = self.match_uimm8("expected 8-bit immediate")?;
2758 InstructionData::TernaryImm8 {
2759 opcode,
2760 imm,
2761 args: [lhs, rhs],
2762 }
2763 }
2764 InstructionFormat::Shuffle => {
2765 let a = self.match_value("expected SSA value first operand")?;
2766 self.match_token(Token::Comma, "expected ',' between operands")?;
2767 let b = self.match_value("expected SSA value second operand")?;
2768 self.match_token(Token::Comma, "expected ',' between operands")?;
2769 let uimm128 = self.match_uimm128(I8X16)?;
2770 let imm = ctx.function.dfg.immediates.push(uimm128);
2771 InstructionData::Shuffle {
2772 opcode,
2773 imm,
2774 args: [a, b],
2775 }
2776 }
2777 InstructionFormat::IntCompare => {
2778 let cond = self.match_enum("expected intcc condition code")?;
2779 let lhs = self.match_value("expected SSA value first operand")?;
2780 self.match_token(Token::Comma, "expected ',' between operands")?;
2781 let rhs = self.match_value("expected SSA value second operand")?;
2782 InstructionData::IntCompare {
2783 opcode,
2784 cond,
2785 args: [lhs, rhs],
2786 }
2787 }
2788 InstructionFormat::IntCompareImm => {
2789 let cond = self.match_enum("expected intcc condition code")?;
2790 let lhs = self.match_value("expected SSA value first operand")?;
2791 self.match_token(Token::Comma, "expected ',' between operands")?;
2792 let rhs = self.match_imm64("expected immediate second operand")?;
2793 InstructionData::IntCompareImm {
2794 opcode,
2795 cond,
2796 arg: lhs,
2797 imm: rhs,
2798 }
2799 }
2800 InstructionFormat::FloatCompare => {
2801 let cond = self.match_enum("expected floatcc condition code")?;
2802 let lhs = self.match_value("expected SSA value first operand")?;
2803 self.match_token(Token::Comma, "expected ',' between operands")?;
2804 let rhs = self.match_value("expected SSA value second operand")?;
2805 InstructionData::FloatCompare {
2806 opcode,
2807 cond,
2808 args: [lhs, rhs],
2809 }
2810 }
2811 InstructionFormat::Call => {
2812 let func_ref = self.match_fn("expected function reference")?;
2813 ctx.check_fn(func_ref, self.loc)?;
2814 self.match_token(Token::LPar, "expected '(' before arguments")?;
2815 let args = self.parse_value_list()?;
2816 self.match_token(Token::RPar, "expected ')' after arguments")?;
2817 InstructionData::Call {
2818 opcode,
2819 func_ref,
2820 args: args.into_value_list(&[], &mut ctx.function.dfg.value_lists),
2821 }
2822 }
2823 InstructionFormat::CallIndirect => {
2824 let sig_ref = self.match_sig("expected signature reference")?;
2825 ctx.check_sig(sig_ref, self.loc)?;
2826 self.match_token(Token::Comma, "expected ',' between operands")?;
2827 let callee = self.match_value("expected SSA value callee operand")?;
2828 self.match_token(Token::LPar, "expected '(' before arguments")?;
2829 let args = self.parse_value_list()?;
2830 self.match_token(Token::RPar, "expected ')' after arguments")?;
2831 InstructionData::CallIndirect {
2832 opcode,
2833 sig_ref,
2834 args: args.into_value_list(&[callee], &mut ctx.function.dfg.value_lists),
2835 }
2836 }
2837 InstructionFormat::TryCall => {
2838 let func_ref = self.match_fn("expected function reference")?;
2839 ctx.check_fn(func_ref, self.loc)?;
2840 self.match_token(Token::LPar, "expected '(' before arguments")?;
2841 let args = self.parse_value_list()?;
2842 self.match_token(Token::RPar, "expected ')' after arguments")?;
2843 self.match_token(Token::Comma, "expected ',' after argument list")?;
2844 let exception = self.parse_exception_table(ctx)?;
2845 InstructionData::TryCall {
2846 opcode,
2847 func_ref,
2848 args: args.into_value_list(&[], &mut ctx.function.dfg.value_lists),
2849 exception,
2850 }
2851 }
2852 InstructionFormat::TryCallIndirect => {
2853 let callee = self.match_value("expected SSA value callee operand")?;
2854 self.match_token(Token::LPar, "expected '(' before arguments")?;
2855 let args = self.parse_value_list()?;
2856 self.match_token(Token::RPar, "expected ')' after arguments")?;
2857 self.match_token(Token::Comma, "expected ',' after argument list")?;
2858 let exception = self.parse_exception_table(ctx)?;
2859 InstructionData::TryCallIndirect {
2860 opcode,
2861 args: args.into_value_list(&[callee], &mut ctx.function.dfg.value_lists),
2862 exception,
2863 }
2864 }
2865 InstructionFormat::FuncAddr => {
2866 let func_ref = self.match_fn("expected function reference")?;
2867 ctx.check_fn(func_ref, self.loc)?;
2868 InstructionData::FuncAddr { opcode, func_ref }
2869 }
2870 InstructionFormat::StackLoad => {
2871 let ss = self.match_ss("expected stack slot number: ss«n»")?;
2872 ctx.check_ss(ss, self.loc)?;
2873 let offset = self.optional_offset32()?;
2874 InstructionData::StackLoad {
2875 opcode,
2876 stack_slot: ss,
2877 offset,
2878 }
2879 }
2880 InstructionFormat::StackStore => {
2881 let arg = self.match_value("expected SSA value operand")?;
2882 self.match_token(Token::Comma, "expected ',' between operands")?;
2883 let ss = self.match_ss("expected stack slot number: ss«n»")?;
2884 ctx.check_ss(ss, self.loc)?;
2885 let offset = self.optional_offset32()?;
2886 InstructionData::StackStore {
2887 opcode,
2888 arg,
2889 stack_slot: ss,
2890 offset,
2891 }
2892 }
2893 InstructionFormat::DynamicStackLoad => {
2894 let dss = self.match_dss("expected dynamic stack slot number: dss«n»")?;
2895 ctx.check_dss(dss, self.loc)?;
2896 InstructionData::DynamicStackLoad {
2897 opcode,
2898 dynamic_stack_slot: dss,
2899 }
2900 }
2901 InstructionFormat::DynamicStackStore => {
2902 let arg = self.match_value("expected SSA value operand")?;
2903 self.match_token(Token::Comma, "expected ',' between operands")?;
2904 let dss = self.match_dss("expected dynamic stack slot number: dss«n»")?;
2905 ctx.check_dss(dss, self.loc)?;
2906 InstructionData::DynamicStackStore {
2907 opcode,
2908 arg,
2909 dynamic_stack_slot: dss,
2910 }
2911 }
2912 InstructionFormat::Load => {
2913 let flags = self.optional_memflags()?;
2914 let addr = self.match_value("expected SSA value address")?;
2915 let offset = self.optional_offset32()?;
2916 InstructionData::Load {
2917 opcode,
2918 flags,
2919 arg: addr,
2920 offset,
2921 }
2922 }
2923 InstructionFormat::Store => {
2924 let flags = self.optional_memflags()?;
2925 let arg = self.match_value("expected SSA value operand")?;
2926 self.match_token(Token::Comma, "expected ',' between operands")?;
2927 let addr = self.match_value("expected SSA value address")?;
2928 let offset = self.optional_offset32()?;
2929 InstructionData::Store {
2930 opcode,
2931 flags,
2932 args: [arg, addr],
2933 offset,
2934 }
2935 }
2936 InstructionFormat::Trap => {
2937 let code = self.match_enum("expected trap code")?;
2938 InstructionData::Trap { opcode, code }
2939 }
2940 InstructionFormat::CondTrap => {
2941 let arg = self.match_value("expected SSA value operand")?;
2942 self.match_token(Token::Comma, "expected ',' between operands")?;
2943 let code = self.match_enum("expected trap code")?;
2944 InstructionData::CondTrap { opcode, arg, code }
2945 }
2946 InstructionFormat::AtomicCas => {
2947 let flags = self.optional_memflags()?;
2948 let addr = self.match_value("expected SSA value address")?;
2949 self.match_token(Token::Comma, "expected ',' between operands")?;
2950 let expected = self.match_value("expected SSA value address")?;
2951 self.match_token(Token::Comma, "expected ',' between operands")?;
2952 let replacement = self.match_value("expected SSA value address")?;
2953 InstructionData::AtomicCas {
2954 opcode,
2955 flags,
2956 args: [addr, expected, replacement],
2957 }
2958 }
2959 InstructionFormat::AtomicRmw => {
2960 let flags = self.optional_memflags()?;
2961 let op = self.match_enum("expected AtomicRmwOp")?;
2962 let addr = self.match_value("expected SSA value address")?;
2963 self.match_token(Token::Comma, "expected ',' between operands")?;
2964 let arg2 = self.match_value("expected SSA value address")?;
2965 InstructionData::AtomicRmw {
2966 opcode,
2967 flags,
2968 op,
2969 args: [addr, arg2],
2970 }
2971 }
2972 InstructionFormat::LoadNoOffset => {
2973 let flags = self.optional_memflags()?;
2974 let addr = self.match_value("expected SSA value address")?;
2975 InstructionData::LoadNoOffset {
2976 opcode,
2977 flags,
2978 arg: addr,
2979 }
2980 }
2981 InstructionFormat::StoreNoOffset => {
2982 let flags = self.optional_memflags()?;
2983 let arg = self.match_value("expected SSA value operand")?;
2984 self.match_token(Token::Comma, "expected ',' between operands")?;
2985 let addr = self.match_value("expected SSA value address")?;
2986 InstructionData::StoreNoOffset {
2987 opcode,
2988 flags,
2989 args: [arg, addr],
2990 }
2991 }
2992 InstructionFormat::IntAddTrap => {
2993 let a = self.match_value("expected SSA value operand")?;
2994 self.match_token(Token::Comma, "expected ',' between operands")?;
2995 let b = self.match_value("expected SSA value operand")?;
2996 self.match_token(Token::Comma, "expected ',' between operands")?;
2997 let code = self.match_enum("expected trap code")?;
2998 InstructionData::IntAddTrap {
2999 opcode,
3000 args: [a, b],
3001 code,
3002 }
3003 }
3004 InstructionFormat::ExceptionHandlerAddress => {
3005 let block = self.match_block("expected block")?;
3006 self.match_token(Token::Comma, "expected ',' between operands")?;
3007 let imm = self.match_imm64("expected immediate handler index")?;
3008 InstructionData::ExceptionHandlerAddress { opcode, block, imm }
3009 }
3010 };
3011 Ok(idata)
3012 }
3013 }
3014
3015 #[cfg(test)]
3016 mod tests {
3017 use super::*;
3018 use crate::isaspec::IsaSpec;
3019
3020 #[test]
argument_type()3021 fn argument_type() {
3022 let mut p = Parser::new("i32 sext");
3023 let arg = p.parse_abi_param().unwrap();
3024 assert_eq!(arg.value_type, types::I32);
3025 assert_eq!(arg.extension, ArgumentExtension::Sext);
3026 assert_eq!(arg.purpose, ArgumentPurpose::Normal);
3027 let ParseError {
3028 location,
3029 message,
3030 is_warning,
3031 } = p.parse_abi_param().unwrap_err();
3032 assert_eq!(location.line_number, 1);
3033 assert_eq!(message, "expected parameter type");
3034 assert!(!is_warning);
3035 }
3036
3037 #[test]
aliases()3038 fn aliases() {
3039 let (func, details) = Parser::new(
3040 "function %qux() system_v {
3041 block0:
3042 v4 = iconst.i8 6
3043 v3 -> v4
3044 v1 = iadd_imm v3, 17
3045 }",
3046 )
3047 .parse_function()
3048 .unwrap();
3049 assert_eq!(func.name.to_string(), "%qux");
3050 let v4 = details.map.lookup_str("v4").unwrap();
3051 assert_eq!(v4.to_string(), "v4");
3052 let v3 = details.map.lookup_str("v3").unwrap();
3053 assert_eq!(v3.to_string(), "v3");
3054 match v3 {
3055 AnyEntity::Value(v3) => {
3056 let aliased_to = func.dfg.resolve_aliases(v3);
3057 assert_eq!(aliased_to.to_string(), "v4");
3058 }
3059 _ => panic!("expected value: {v3}"),
3060 }
3061 }
3062
3063 #[test]
signature()3064 fn signature() {
3065 let sig = Parser::new("()system_v").parse_signature().unwrap();
3066 assert_eq!(sig.params.len(), 0);
3067 assert_eq!(sig.returns.len(), 0);
3068 assert_eq!(sig.call_conv, CallConv::SystemV);
3069
3070 let sig2 =
3071 Parser::new("(i8 uext, f16, f32, f64, f128, i32 sret) -> i32 sext, f64 system_v")
3072 .parse_signature()
3073 .unwrap();
3074 assert_eq!(
3075 sig2.to_string(),
3076 "(i8 uext, f16, f32, f64, f128, i32 sret) -> i32 sext, f64 system_v"
3077 );
3078 assert_eq!(sig2.call_conv, CallConv::SystemV);
3079
3080 // Old-style signature without a calling convention.
3081 assert_eq!(
3082 Parser::new("()").parse_signature().unwrap().to_string(),
3083 "() fast"
3084 );
3085 assert_eq!(
3086 Parser::new("() notacc")
3087 .parse_signature()
3088 .unwrap_err()
3089 .to_string(),
3090 "1: unknown calling convention: notacc"
3091 );
3092
3093 // `void` is not recognized as a type by the lexer. It should not appear in files.
3094 assert_eq!(
3095 Parser::new("() -> void")
3096 .parse_signature()
3097 .unwrap_err()
3098 .to_string(),
3099 "1: expected parameter type"
3100 );
3101 assert_eq!(
3102 Parser::new("i8 -> i8")
3103 .parse_signature()
3104 .unwrap_err()
3105 .to_string(),
3106 "1: expected function signature: ( args... )"
3107 );
3108 assert_eq!(
3109 Parser::new("(i8 -> i8")
3110 .parse_signature()
3111 .unwrap_err()
3112 .to_string(),
3113 "1: expected ')' after function arguments"
3114 );
3115 }
3116
3117 #[test]
stack_slot_decl()3118 fn stack_slot_decl() {
3119 let (func, _) = Parser::new(
3120 "function %foo() system_v {
3121 ss3 = explicit_slot 13
3122 ss1 = explicit_slot 1
3123 }",
3124 )
3125 .parse_function()
3126 .unwrap();
3127 assert_eq!(func.name.to_string(), "%foo");
3128 let mut iter = func.sized_stack_slots.keys();
3129 let _ss0 = iter.next().unwrap();
3130 let ss1 = iter.next().unwrap();
3131 assert_eq!(ss1.to_string(), "ss1");
3132 assert_eq!(
3133 func.sized_stack_slots[ss1].kind,
3134 StackSlotKind::ExplicitSlot
3135 );
3136 assert_eq!(func.sized_stack_slots[ss1].size, 1);
3137 let _ss2 = iter.next().unwrap();
3138 let ss3 = iter.next().unwrap();
3139 assert_eq!(ss3.to_string(), "ss3");
3140 assert_eq!(
3141 func.sized_stack_slots[ss3].kind,
3142 StackSlotKind::ExplicitSlot
3143 );
3144 assert_eq!(func.sized_stack_slots[ss3].size, 13);
3145 assert_eq!(iter.next(), None);
3146
3147 // Catch duplicate definitions.
3148 assert_eq!(
3149 Parser::new(
3150 "function %bar() system_v {
3151 ss1 = explicit_slot 13
3152 ss1 = explicit_slot 1
3153 }",
3154 )
3155 .parse_function()
3156 .unwrap_err()
3157 .to_string(),
3158 "3: duplicate entity: ss1"
3159 );
3160 }
3161
3162 #[test]
block_header()3163 fn block_header() {
3164 let (func, _) = Parser::new(
3165 "function %blocks() system_v {
3166 block0:
3167 block4(v3: i32):
3168 }",
3169 )
3170 .parse_function()
3171 .unwrap();
3172 assert_eq!(func.name.to_string(), "%blocks");
3173
3174 let mut blocks = func.layout.blocks();
3175
3176 let block0 = blocks.next().unwrap();
3177 assert_eq!(func.dfg.block_params(block0), &[]);
3178
3179 let block4 = blocks.next().unwrap();
3180 let block4_args = func.dfg.block_params(block4);
3181 assert_eq!(block4_args.len(), 1);
3182 assert_eq!(func.dfg.value_type(block4_args[0]), types::I32);
3183 }
3184
3185 #[test]
duplicate_block()3186 fn duplicate_block() {
3187 let ParseError {
3188 location,
3189 message,
3190 is_warning,
3191 } = Parser::new(
3192 "function %blocks() system_v {
3193 block0:
3194 block0:
3195 return 2",
3196 )
3197 .parse_function()
3198 .unwrap_err();
3199
3200 assert_eq!(location.line_number, 3);
3201 assert_eq!(message, "duplicate entity: block0");
3202 assert!(!is_warning);
3203 }
3204
3205 #[test]
number_of_blocks()3206 fn number_of_blocks() {
3207 let ParseError {
3208 location,
3209 message,
3210 is_warning,
3211 } = Parser::new(
3212 "function %a() {
3213 block100000:",
3214 )
3215 .parse_function()
3216 .unwrap_err();
3217
3218 assert_eq!(location.line_number, 2);
3219 assert_eq!(message, "too many blocks");
3220 assert!(!is_warning);
3221 }
3222
3223 #[test]
duplicate_ss()3224 fn duplicate_ss() {
3225 let ParseError {
3226 location,
3227 message,
3228 is_warning,
3229 } = Parser::new(
3230 "function %blocks() system_v {
3231 ss0 = explicit_slot 8
3232 ss0 = explicit_slot 8",
3233 )
3234 .parse_function()
3235 .unwrap_err();
3236
3237 assert_eq!(location.line_number, 3);
3238 assert_eq!(message, "duplicate entity: ss0");
3239 assert!(!is_warning);
3240 }
3241
3242 #[test]
duplicate_gv()3243 fn duplicate_gv() {
3244 let ParseError {
3245 location,
3246 message,
3247 is_warning,
3248 } = Parser::new(
3249 "function %blocks() system_v {
3250 gv0 = vmctx
3251 gv0 = vmctx",
3252 )
3253 .parse_function()
3254 .unwrap_err();
3255
3256 assert_eq!(location.line_number, 3);
3257 assert_eq!(message, "duplicate entity: gv0");
3258 assert!(!is_warning);
3259 }
3260
3261 #[test]
duplicate_sig()3262 fn duplicate_sig() {
3263 let ParseError {
3264 location,
3265 message,
3266 is_warning,
3267 } = Parser::new(
3268 "function %blocks() system_v {
3269 sig0 = ()
3270 sig0 = ()",
3271 )
3272 .parse_function()
3273 .unwrap_err();
3274
3275 assert_eq!(location.line_number, 3);
3276 assert_eq!(message, "duplicate entity: sig0");
3277 assert!(!is_warning);
3278 }
3279
3280 #[test]
duplicate_fn()3281 fn duplicate_fn() {
3282 let ParseError {
3283 location,
3284 message,
3285 is_warning,
3286 } = Parser::new(
3287 "function %blocks() system_v {
3288 sig0 = ()
3289 fn0 = %foo sig0
3290 fn0 = %foo sig0",
3291 )
3292 .parse_function()
3293 .unwrap_err();
3294
3295 assert_eq!(location.line_number, 4);
3296 assert_eq!(message, "duplicate entity: fn0");
3297 assert!(!is_warning);
3298 }
3299
3300 #[test]
comments()3301 fn comments() {
3302 let (func, Details { comments, .. }) = Parser::new(
3303 "; before
3304 function %comment() system_v { ; decl
3305 ss10 = explicit_slot 13 ; stackslot.
3306 ; Still stackslot.
3307 block0: ; Basic block
3308 trap user42; Instruction
3309 } ; Trailing.
3310 ; More trailing.",
3311 )
3312 .parse_function()
3313 .unwrap();
3314 assert_eq!(func.name.to_string(), "%comment");
3315 assert_eq!(comments.len(), 7); // no 'before' comment.
3316 assert_eq!(
3317 comments[0],
3318 Comment {
3319 entity: AnyEntity::Function,
3320 text: "; decl",
3321 }
3322 );
3323 assert_eq!(comments[1].entity.to_string(), "ss10");
3324 assert_eq!(comments[2].entity.to_string(), "ss10");
3325 assert_eq!(comments[2].text, "; Still stackslot.");
3326 assert_eq!(comments[3].entity.to_string(), "block0");
3327 assert_eq!(comments[3].text, "; Basic block");
3328
3329 assert_eq!(comments[4].entity.to_string(), "inst0");
3330 assert_eq!(comments[4].text, "; Instruction");
3331
3332 assert_eq!(comments[5].entity, AnyEntity::Function);
3333 assert_eq!(comments[6].entity, AnyEntity::Function);
3334 }
3335
3336 #[test]
test_file()3337 fn test_file() {
3338 let tf = parse_test(
3339 r#"; before
3340 test cfg option=5
3341 test verify
3342 set unwind_info=false
3343 feature "foo"
3344 feature !"bar"
3345 ; still preamble
3346 function %comment() system_v {}"#,
3347 ParseOptions::default(),
3348 )
3349 .unwrap();
3350 assert_eq!(tf.commands.len(), 2);
3351 assert_eq!(tf.commands[0].command, "cfg");
3352 assert_eq!(tf.commands[1].command, "verify");
3353 match tf.isa_spec {
3354 IsaSpec::None(s) => {
3355 assert!(s.enable_verifier());
3356 assert!(!s.unwind_info());
3357 }
3358 _ => panic!("unexpected ISAs"),
3359 }
3360 assert_eq!(tf.features[0], Feature::With(&"foo"));
3361 assert_eq!(tf.features[1], Feature::Without(&"bar"));
3362 assert_eq!(tf.preamble_comments.len(), 2);
3363 assert_eq!(tf.preamble_comments[0].text, "; before");
3364 assert_eq!(tf.preamble_comments[1].text, "; still preamble");
3365 assert_eq!(tf.functions.len(), 1);
3366 assert_eq!(tf.functions[0].0.name.to_string(), "%comment");
3367 }
3368
3369 #[test]
isa_spec()3370 fn isa_spec() {
3371 assert!(
3372 parse_test(
3373 "target
3374 function %foo() system_v {}",
3375 ParseOptions::default()
3376 )
3377 .is_err()
3378 );
3379
3380 assert!(
3381 parse_test(
3382 "target x86_64
3383 set unwind_info=false
3384 function %foo() system_v {}",
3385 ParseOptions::default()
3386 )
3387 .is_err()
3388 );
3389
3390 match parse_test(
3391 "set unwind_info=false
3392 target x86_64
3393 function %foo() system_v {}",
3394 ParseOptions::default(),
3395 )
3396 .unwrap()
3397 .isa_spec
3398 {
3399 IsaSpec::None(_) => panic!("Expected some ISA"),
3400 IsaSpec::Some(v) => {
3401 assert_eq!(v.len(), 1);
3402 assert!(v[0].name() == "x64" || v[0].name() == "x86");
3403 }
3404 }
3405 }
3406
3407 #[test]
user_function_name()3408 fn user_function_name() {
3409 // Valid characters in the name:
3410 let func = Parser::new(
3411 "function u1:2() system_v {
3412 block0:
3413 trap int_divz
3414 }",
3415 )
3416 .parse_function()
3417 .unwrap()
3418 .0;
3419 assert_eq!(func.name.to_string(), "u1:2");
3420
3421 // Invalid characters in the name:
3422 let mut parser = Parser::new(
3423 "function u123:abc() system_v {
3424 block0:
3425 trap stk_ovf
3426 }",
3427 );
3428 assert!(parser.parse_function().is_err());
3429
3430 // Incomplete function names should not be valid:
3431 let mut parser = Parser::new(
3432 "function u() system_v {
3433 block0:
3434 trap int_ovf
3435 }",
3436 );
3437 assert!(parser.parse_function().is_err());
3438
3439 let mut parser = Parser::new(
3440 "function u0() system_v {
3441 block0:
3442 trap int_ovf
3443 }",
3444 );
3445 assert!(parser.parse_function().is_err());
3446
3447 let mut parser = Parser::new(
3448 "function u0:() system_v {
3449 block0:
3450 trap int_ovf
3451 }",
3452 );
3453 assert!(parser.parse_function().is_err());
3454 }
3455
3456 #[test]
change_default_calling_convention()3457 fn change_default_calling_convention() {
3458 let code = "function %test() {
3459 block0:
3460 return
3461 }";
3462
3463 // By default the parser will use the fast calling convention if none is specified.
3464 let mut parser = Parser::new(code);
3465 assert_eq!(
3466 parser.parse_function().unwrap().0.signature.call_conv,
3467 CallConv::Fast
3468 );
3469
3470 // However, we can specify a different calling convention to be the default.
3471 let mut parser = Parser::new(code).with_default_calling_convention(CallConv::PreserveAll);
3472 assert_eq!(
3473 parser.parse_function().unwrap().0.signature.call_conv,
3474 CallConv::PreserveAll
3475 );
3476 }
3477
3478 #[test]
u8_as_hex()3479 fn u8_as_hex() {
3480 fn parse_as_uimm8(text: &str) -> ParseResult<u8> {
3481 Parser::new(text).match_uimm8("unable to parse u8")
3482 }
3483
3484 assert_eq!(parse_as_uimm8("0").unwrap(), 0);
3485 assert_eq!(parse_as_uimm8("0xff").unwrap(), 255);
3486 assert!(parse_as_uimm8("-1").is_err());
3487 assert!(parse_as_uimm8("0xffa").is_err());
3488 }
3489
3490 #[test]
i16_as_hex()3491 fn i16_as_hex() {
3492 fn parse_as_imm16(text: &str) -> ParseResult<i16> {
3493 Parser::new(text).match_imm16("unable to parse i16")
3494 }
3495
3496 assert_eq!(parse_as_imm16("0x8000").unwrap(), -32768);
3497 assert_eq!(parse_as_imm16("0xffff").unwrap(), -1);
3498 assert_eq!(parse_as_imm16("0").unwrap(), 0);
3499 assert_eq!(parse_as_imm16("0x7fff").unwrap(), 32767);
3500 assert_eq!(
3501 parse_as_imm16("-0x0001").unwrap(),
3502 parse_as_imm16("0xffff").unwrap()
3503 );
3504 assert_eq!(
3505 parse_as_imm16("-0x7fff").unwrap(),
3506 parse_as_imm16("0x8001").unwrap()
3507 );
3508 assert!(parse_as_imm16("0xffffa").is_err());
3509 }
3510
3511 #[test]
i32_as_hex()3512 fn i32_as_hex() {
3513 fn parse_as_imm32(text: &str) -> ParseResult<i32> {
3514 Parser::new(text).match_imm32("unable to parse i32")
3515 }
3516
3517 assert_eq!(parse_as_imm32("0x80000000").unwrap(), -2147483648);
3518 assert_eq!(parse_as_imm32("0xffffffff").unwrap(), -1);
3519 assert_eq!(parse_as_imm32("0").unwrap(), 0);
3520 assert_eq!(parse_as_imm32("0x7fffffff").unwrap(), 2147483647);
3521 assert_eq!(
3522 parse_as_imm32("-0x00000001").unwrap(),
3523 parse_as_imm32("0xffffffff").unwrap()
3524 );
3525 assert_eq!(
3526 parse_as_imm32("-0x7fffffff").unwrap(),
3527 parse_as_imm32("0x80000001").unwrap()
3528 );
3529 assert!(parse_as_imm32("0xffffffffa").is_err());
3530 }
3531
3532 #[test]
i64_as_hex()3533 fn i64_as_hex() {
3534 fn parse_as_imm64(text: &str) -> ParseResult<Imm64> {
3535 Parser::new(text).match_imm64("unable to parse Imm64")
3536 }
3537
3538 assert_eq!(
3539 parse_as_imm64("0x8000000000000000").unwrap(),
3540 Imm64::new(-9223372036854775808)
3541 );
3542 assert_eq!(
3543 parse_as_imm64("0xffffffffffffffff").unwrap(),
3544 Imm64::new(-1)
3545 );
3546 assert_eq!(parse_as_imm64("0").unwrap(), Imm64::new(0));
3547 assert_eq!(
3548 parse_as_imm64("0x7fffffffffffffff").unwrap(),
3549 Imm64::new(9223372036854775807)
3550 );
3551 assert_eq!(
3552 parse_as_imm64("-0x0000000000000001").unwrap(),
3553 parse_as_imm64("0xffffffffffffffff").unwrap()
3554 );
3555 assert_eq!(
3556 parse_as_imm64("-0x7fffffffffffffff").unwrap(),
3557 parse_as_imm64("0x8000000000000001").unwrap()
3558 );
3559 assert!(parse_as_imm64("0xffffffffffffffffa").is_err());
3560 }
3561
3562 #[test]
uimm128()3563 fn uimm128() {
3564 macro_rules! parse_as_constant_data {
3565 ($text:expr, $type:expr) => {{ Parser::new($text).parse_literals_to_constant_data($type) }};
3566 }
3567 macro_rules! can_parse_as_constant_data {
3568 ($text:expr, $type:expr) => {{ assert!(parse_as_constant_data!($text, $type).is_ok()) }};
3569 }
3570 macro_rules! cannot_parse_as_constant_data {
3571 ($text:expr, $type:expr) => {{ assert!(parse_as_constant_data!($text, $type).is_err()) }};
3572 }
3573
3574 can_parse_as_constant_data!("1 2 3 4", I32X4);
3575 can_parse_as_constant_data!("1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16", I8X16);
3576 can_parse_as_constant_data!("0x1.1 0x2.2 0x3.3 0x4.4", F32X4);
3577 can_parse_as_constant_data!("0x0 0x1 0x2 0x3", I32X4);
3578 can_parse_as_constant_data!("-1 0 -1 0 -1 0 -1 0", I16X8);
3579 can_parse_as_constant_data!("0 -1", I64X2);
3580 can_parse_as_constant_data!("-1 0", I64X2);
3581 can_parse_as_constant_data!("-1 -1 -1 -1 -1", I32X4); // note that parse_literals_to_constant_data will leave extra tokens unconsumed
3582
3583 cannot_parse_as_constant_data!("1 2 3", I32X4);
3584 cannot_parse_as_constant_data!(" ", F32X4);
3585 }
3586
3587 #[test]
parse_constant_from_booleans()3588 fn parse_constant_from_booleans() {
3589 let c = Parser::new("-1 0 -1 0")
3590 .parse_literals_to_constant_data(I32X4)
3591 .unwrap();
3592 assert_eq!(
3593 c.into_vec(),
3594 [
3595 0xFF, 0xFF, 0xFF, 0xFF, 0, 0, 0, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0, 0, 0, 0
3596 ]
3597 )
3598 }
3599
3600 #[test]
parse_unbounded_constants()3601 fn parse_unbounded_constants() {
3602 // Unlike match_uimm128, match_hexadecimal_constant can parse byte sequences of any size:
3603 assert_eq!(
3604 Parser::new("0x0100")
3605 .match_hexadecimal_constant("err message")
3606 .unwrap(),
3607 vec![0, 1].into()
3608 );
3609
3610 // Only parse hexadecimal constants:
3611 assert!(
3612 Parser::new("228")
3613 .match_hexadecimal_constant("err message")
3614 .is_err()
3615 );
3616 }
3617
3618 #[test]
parse_run_commands()3619 fn parse_run_commands() {
3620 // Helper for creating signatures.
3621 fn sig(ins: &[Type], outs: &[Type]) -> Signature {
3622 let mut sig = Signature::new(CallConv::Fast);
3623 for i in ins {
3624 sig.params.push(AbiParam::new(*i));
3625 }
3626 for o in outs {
3627 sig.returns.push(AbiParam::new(*o));
3628 }
3629 sig
3630 }
3631
3632 // Helper for parsing run commands.
3633 fn parse(text: &str, sig: &Signature) -> ParseResult<RunCommand> {
3634 Parser::new(text).parse_run_command(sig)
3635 }
3636
3637 // Check that we can parse and display the same set of run commands.
3638 fn assert_roundtrip(text: &str, sig: &Signature) {
3639 assert_eq!(parse(text, sig).unwrap().to_string(), text);
3640 }
3641 assert_roundtrip("run: %fn0() == 42", &sig(&[], &[I32]));
3642 assert_roundtrip(
3643 "run: %fn0(8, 16, 32, 64) == 1",
3644 &sig(&[I8, I16, I32, I64], &[I8]),
3645 );
3646 assert_roundtrip(
3647 "run: %my_func(1) == 0x0f0e0d0c0b0a09080706050403020100",
3648 &sig(&[I32], &[I8X16]),
3649 );
3650
3651 // Verify that default invocations are created when not specified.
3652 assert_eq!(
3653 parse("run", &sig(&[], &[I32])).unwrap().to_string(),
3654 "run: %default() != 0"
3655 );
3656 assert_eq!(
3657 parse("print", &sig(&[], &[F32X4, I16X8]))
3658 .unwrap()
3659 .to_string(),
3660 "print: %default()"
3661 );
3662
3663 // Demonstrate some unparsable cases.
3664 assert!(parse("print", &sig(&[I32], &[I32])).is_err());
3665 assert!(parse("print:", &sig(&[], &[])).is_err());
3666 assert!(parse("run: ", &sig(&[], &[])).is_err());
3667 }
3668
3669 #[test]
parse_data_values()3670 fn parse_data_values() {
3671 fn parse(text: &str, ty: Type) -> DataValue {
3672 Parser::new(text).parse_data_value(ty).unwrap()
3673 }
3674
3675 assert_eq!(parse("8", I8).to_string(), "8");
3676 assert_eq!(parse("16", I16).to_string(), "16");
3677 assert_eq!(parse("32", I32).to_string(), "32");
3678 assert_eq!(parse("64", I64).to_string(), "64");
3679 assert_eq!(
3680 parse("0x01234567_01234567_01234567_01234567", I128).to_string(),
3681 "1512366032949150931280199141537564007"
3682 );
3683 assert_eq!(parse("1234567", I128).to_string(), "1234567");
3684 assert_eq!(parse("0x16.1", F16).to_string(), "0x1.610p4");
3685 assert_eq!(parse("0x32.32", F32).to_string(), "0x1.919000p5");
3686 assert_eq!(parse("0x64.64", F64).to_string(), "0x1.9190000000000p6");
3687 assert_eq!(
3688 parse("0x128.128", F128).to_string(),
3689 "0x1.2812800000000000000000000000p8"
3690 );
3691 assert_eq!(
3692 parse("[0 1 2 3]", I32X4).to_string(),
3693 "0x00000003000000020000000100000000"
3694 );
3695 assert_eq!(parse("[1 2]", I32X2).to_string(), "0x0000000200000001");
3696 assert_eq!(parse("[1 2 3 4]", I8X4).to_string(), "0x04030201");
3697 assert_eq!(parse("[1 2]", I8X2).to_string(), "0x0201");
3698 }
3699
3700 #[test]
parse_cold_blocks()3701 fn parse_cold_blocks() {
3702 let code = "function %test() {
3703 block0 cold:
3704 return
3705 block1(v0: i32) cold:
3706 return
3707 block2(v1: i32):
3708 return
3709 }";
3710
3711 let mut parser = Parser::new(code);
3712 let func = parser.parse_function().unwrap().0;
3713 assert_eq!(func.layout.blocks().count(), 3);
3714 assert!(func.layout.is_cold(Block::from_u32(0)));
3715 assert!(func.layout.is_cold(Block::from_u32(1)));
3716 assert!(!func.layout.is_cold(Block::from_u32(2)));
3717 }
3718 }
3719