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