1use std::fmt;
34
35use rucc_base::float::Format;
36use rucc_base::{Idx, Interner, Symbol};
37use rucc_diag::Span;
38use rucc_target::{Slot, TargetInfo, Triple};
39
40use crate::attrs::{AttrSet, Attrs, FpContract};
41use crate::func::Func;
42use crate::inst::{
43 Abi, AsmInfo, Block, BlockCall, CallInfo, Imm, Inst, InstData, MemInfo, Meta, MetaNode, Param,
44 Signature, SwitchInfo, VaInfo, Value,
45};
46use crate::module::{
47 Alias, AliasKind, DataLayout, Datum, Global, Linkage, Module, Reloc, TlsModel, Visibility,
48};
49use crate::{
50 Extra, ExtraKind, FORMAT_VERSION, Flags, FloatPred, IntPred, MemOrder, Opcode, RmwOp, Type,
51};
52
53#[derive(Clone, Debug, PartialEq, Eq)]
59pub struct ParseError {
60 pub line: u32,
62 pub message: String,
64}
65
66impl fmt::Display for ParseError {
67 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
68 write!(f, "line {}: {}", self.line, self.message)
69 }
70}
71
72impl std::error::Error for ParseError {}
73
74pub fn parse(text: &str, names: &mut Interner) -> Result<Module, ParseError> {
83 Parser::new(text, names).module()
84}
85
86struct Parser<'a, 'n> {
88 text: &'a str,
89 pos: usize,
90 line: u32,
91 names: &'n mut Interner,
92 meta_used: Option<(u32, u32)>,
95}
96
97struct PendingBlock<'a> {
99 params: Vec<(u32, Type)>,
100 insts: Vec<PendingInst<'a>>,
101}
102
103struct PendingInst<'a> {
105 opcode: Opcode,
106 flags: Flags,
107 results: Vec<u32>,
108 written: Vec<Type>,
110 args: Vec<u32>,
111 extra: PendingExtra<'a>,
112 line: u32,
113}
114
115struct PendingCall {
117 block: u32,
118 args: Vec<u32>,
119}
120
121enum PendingExtra<'a> {
123 None,
124 Imm(&'a str),
126 Symbol(Symbol),
127 IntPred(IntPred),
128 FloatPred(FloatPred),
129 Mem(MemInfo),
130 VaObject(MemInfo, Vec<Slot>),
133 Rmw(RmwOp, MemInfo),
134 Order(MemOrder),
135 Targets(Vec<PendingCall>),
136 Call {
137 callee: Option<Symbol>,
138 signature: Signature,
139 abis: Vec<Abi>,
142 },
143 Switch {
144 targets: Vec<PendingCall>,
145 cases: Vec<&'a str>,
146 },
147 Asm {
148 template: Symbol,
149 constraints: Symbol,
150 clobbers: Symbol,
151 targets: Vec<PendingCall>,
152 },
153}
154
155impl<'a, 'n> Parser<'a, 'n> {
156 fn new(text: &'a str, names: &'n mut Interner) -> Self {
157 Parser { text, pos: 0, line: 1, names, meta_used: None }
158 }
159
160 fn module(mut self) -> Result<Module, ParseError> {
163 let name = self.header_name()?;
164 self.expect("; format ")?;
165 let version = self.u32()?;
166 if version != FORMAT_VERSION {
167 return self.fail(format!(
168 "this build reads format {FORMAT_VERSION} and the text says format {version}"
169 ));
170 }
171 self.end_of_line()?;
172
173 self.expect("target triple = ")?;
174 let triple = self.quoted_str()?;
175 let Ok(triple) = triple.parse::<Triple>() else {
176 return self.fail(format!("`{triple}` is not a target triple"));
177 };
178 self.end_of_line()?;
179
180 self.expect("target datalayout = ")?;
181 let layout = self.quoted_str()?;
182 let Some(datalayout) = DataLayout::parse(&layout) else {
183 return self.fail(format!("`{layout}` is not a data layout"));
184 };
185 self.end_of_line()?;
186
187 let name = self.names.intern(&name);
188 let mut module = Module::new(name, &TargetInfo::new(triple));
189 module.datalayout = datalayout;
190
191 loop {
192 self.skip_blank_lines();
193 if self.at_end() {
194 break;
195 }
196 match self.peek_word() {
197 "global" => self.global(&mut module)?,
198 "alias" | "ifunc" => self.alias(&mut module)?,
199 "func" => self.func(&mut module)?,
200 _ if self.at("!") => self.meta(&mut module)?,
201 other => return self.fail(format!("`{other}` does not start anything")),
202 }
203 }
204
205 if let Some((used, line)) = self.meta_used {
206 let count = module.counts().metadata as u32;
207 if used >= count {
208 self.line = line;
209 return self.fail(format!("!{used} is used and never defined"));
210 }
211 }
212 Ok(module)
213 }
214
215 fn header_name(&mut self) -> Result<String, ParseError> {
217 self.expect("; ModuleID = '")?;
218 let start = self.pos;
219 let Some(end) = self.text[start..].find('\'') else {
220 return self.fail("the module name is not closed");
221 };
222 let name = self.text[start..start + end].to_string();
223 self.pos = start + end + 1;
224 self.end_of_line()?;
225 Ok(name)
226 }
227
228 fn global(&mut self, module: &mut Module) -> Result<(), ParseError> {
231 self.expect("global")?;
232 let name = self.symbol()?;
233 self.expect(":")?;
234
235 let mut global = Global::new(name, 0, 1);
236 if self.eat_word("bytes") {
237 global.size = self.u64()?;
238 if self.eat("=") {
239 self.expect("{")?;
240 let mut data = Vec::new();
241 if !self.eat("}") {
245 loop {
246 data.push(self.datum(module)?);
247 if !self.eat(",") {
248 break;
249 }
250 }
251 self.expect("}")?;
252 }
253 global.init = Some(module.push_data(&data));
254 }
255 } else {
256 let ty = self.ty()?;
257 self.expect("=")?;
258 let text = self.imm_text()?;
259 let value = self.imm(text, ty)?;
260 let datum = Datum::Scalar { ty, value: module.add_imm(value) };
261 global.size = datum.size(module);
262 global.init = Some(module.push_data(&[datum]));
263 }
264
265 while self.eat(",") {
266 match self.word() {
267 "align" => global.align = self.u32()?,
268 "linkage" => {
269 global.linkage = self.parenthesised(Linkage::from_name, "a linkage")?
270 }
271 "visibility" => {
272 global.visibility =
273 self.parenthesised(Visibility::from_name, "a visibility")?;
274 }
275 "tls" => {
276 global.tls =
277 Some(self.parenthesised(TlsModel::from_name, "a thread-local model")?);
278 }
279 "constant" => global.constant = true,
280 "section" => global.section = Some(self.symbol_from_string()?),
281 other => return self.fail(format!("a global has no `{other}`")),
282 }
283 }
284 self.end_of_line()?;
285 module.add_global(global);
286 Ok(())
287 }
288
289 fn datum(&mut self, module: &mut Module) -> Result<Datum, ParseError> {
291 match self.peek_word() {
292 "zero" => {
293 self.expect("zero")?;
294 Ok(Datum::Zero(self.u64()?))
295 }
296 "bytes" => {
297 self.expect("bytes")?;
298 let bytes = self.string()?;
299 Ok(Datum::Bytes(module.push_bytes(&bytes)))
300 }
301 "addr" => {
302 self.expect("addr")?;
303 self.expect(".")?;
304 let size = self.u32()?;
305 let symbol = self.symbol()?;
306 let addend = if self.eat("+") {
307 self.i64()?
308 } else if self.eat("-") {
309 let amount = self.i64()?;
310 match amount.checked_neg() {
311 Some(negated) => negated,
312 None => return self.fail("that offset has no negative"),
313 }
314 } else {
315 0
316 };
317 Ok(Datum::Addr(module.add_reloc(Reloc { symbol, addend, size })))
318 }
319 _ => {
320 let ty = self.ty()?;
321 let text = self.imm_text()?;
322 let value = self.imm(text, ty)?;
323 Ok(Datum::Scalar { ty, value: module.add_imm(value) })
324 }
325 }
326 }
327
328 fn alias(&mut self, module: &mut Module) -> Result<(), ParseError> {
329 let word = self.word();
330 let Some(kind) = AliasKind::from_name(word) else {
331 return self.fail(format!("`{word}` is not a kind of alias"));
332 };
333 let name = self.symbol()?;
334 self.expect("=")?;
335 let target = self.symbol()?;
336 let mut alias = Alias::new(name, target);
337 alias.kind = kind;
338 while self.eat(",") {
339 match self.word() {
340 "linkage" => alias.linkage = self.parenthesised(Linkage::from_name, "a linkage")?,
341 "visibility" => {
342 alias.visibility = self.parenthesised(Visibility::from_name, "a visibility")?;
343 }
344 other => return self.fail(format!("an alias has no `{other}`")),
345 }
346 }
347 self.end_of_line()?;
348 module.add_alias(alias);
349 Ok(())
350 }
351
352 fn meta(&mut self, module: &mut Module) -> Result<(), ParseError> {
353 let index = self.meta_ref()?;
354 let expected = module.counts().metadata as u32;
355 if index.raw() != expected {
356 return self.fail(format!("metadata is numbered in order and !{expected} comes next"));
357 }
358 self.expect("=")?;
359 self.expect("tbaa")?;
360 let name = self.symbol_from_string()?;
361 let mut node = MetaNode { name, parent: None, offset: 0 };
362 while self.eat(",") {
363 match self.word() {
364 "parent" => node.parent = Some(self.meta_ref()?),
365 "offset" => node.offset = self.u64()?,
366 other => return self.fail(format!("a metadata node has no `{other}`")),
367 }
368 }
369 if node.parent.is_some_and(|parent| parent.raw() >= index.raw()) {
370 return self.fail("a metadata node's parent comes before it");
371 }
372 self.end_of_line()?;
373 module.add_meta(node);
374 Ok(())
375 }
376
377 fn func(&mut self, module: &mut Module) -> Result<(), ParseError> {
380 self.expect("func")?;
381 let name = self.symbol()?;
382 let signature = self.signature()?;
383 let mut func = Func::new(name, signature);
384 while self.eat(",") {
385 match self.word() {
386 "linkage" => func.linkage = self.parenthesised(Linkage::from_name, "a linkage")?,
387 "visibility" => {
388 func.visibility = self.parenthesised(Visibility::from_name, "a visibility")?;
389 }
390 "attrs" => func.attrs = self.attrs()?,
391 "section" => func.section = Some(self.symbol_from_string()?),
392 other => return self.fail(format!("a function has no `{other}`")),
393 }
394 }
395 if self.eat(";") {
396 self.end_of_line()?;
397 module.add_func(func);
398 return Ok(());
399 }
400 self.expect("{")?;
401 self.end_of_line()?;
402 let blocks = self.body()?;
403 self.build(&mut func, &blocks)?;
404 module.add_func(func);
405 Ok(())
406 }
407
408 fn signature(&mut self) -> Result<Signature, ParseError> {
410 self.expect("(")?;
411 let mut signature = Signature::new();
412 if !self.eat(")") {
413 loop {
414 if self.eat("...") {
415 signature.variadic = true;
416 break;
417 }
418 signature.params.push(self.param()?);
419 if !self.eat(",") {
420 break;
421 }
422 }
423 self.expect(")")?;
424 }
425 if self.eat("->") {
426 if self.eat("(") {
427 loop {
428 signature.returns.push(self.param()?);
429 if !self.eat(",") {
430 break;
431 }
432 }
433 self.expect(")")?;
434 } else {
435 signature.returns.push(self.param()?);
436 }
437 }
438 Ok(signature)
439 }
440
441 fn param(&mut self) -> Result<Param, ParseError> {
443 let ty = self.ty()?;
444 let abi = self.abi()?;
445 Ok(Param { ty, abi })
446 }
447
448 fn abi(&mut self) -> Result<Abi, ParseError> {
450 let abi = match self.peek_word() {
451 "sext" => {
452 self.word();
453 Abi::Sext
454 }
455 "zext" => {
456 self.word();
457 Abi::Zext
458 }
459 word @ ("byval" | "sret") => {
460 let indirect = word == "byval";
461 self.word();
462 self.expect("(")?;
463 let size = self.u64()?;
464 self.expect(",")?;
465 self.expect("align")?;
466 let align = self.u32()?;
467 self.expect(")")?;
468 if indirect { Abi::ByVal { size, align } } else { Abi::Sret { size, align } }
469 }
470 _ => Abi::Plain,
471 };
472 Ok(abi)
473 }
474
475 fn attrs(&mut self) -> Result<Attrs, ParseError> {
476 self.expect("(")?;
477 let mut attrs = Attrs::NONE;
478 loop {
479 let word = self.word();
480 if self.eat("=") {
481 let value = self.word();
482 match word {
483 "fp_contract" => match FpContract::from_name(value) {
484 Some(contract) => attrs.fp_contract = contract,
485 None => return self.fail(format!("`{value}` is not a contraction")),
486 },
487 other => return self.fail(format!("`{other}` takes no value")),
488 }
489 } else {
490 match AttrSet::from_name(word) {
491 Some(attr) => attrs.set |= attr,
492 None => return self.fail(format!("`{word}` is not an attribute")),
493 }
494 }
495 if !self.eat(",") {
496 break;
497 }
498 }
499 self.expect(")")?;
500 Ok(attrs)
501 }
502
503 fn body(&mut self) -> Result<Vec<PendingBlock<'a>>, ParseError> {
505 let mut blocks: Vec<PendingBlock<'a>> = Vec::new();
506 loop {
507 self.skip_blank_lines();
508 if self.eat("}") {
509 self.end_of_line()?;
510 return Ok(blocks);
511 }
512 if self.at_end() {
513 return self.fail("the function is not closed");
514 }
515 if self.peek_word().starts_with("block") {
516 let number = self.block_ref()?;
517 if number as usize != blocks.len() {
518 return self.fail(format!(
519 "blocks are numbered in order and block{} comes next",
520 blocks.len()
521 ));
522 }
523 let mut params = Vec::new();
524 if self.eat("(") {
525 loop {
526 let value = self.value_ref()?;
527 self.expect(":")?;
528 params.push((value, self.ty()?));
529 if !self.eat(",") {
530 break;
531 }
532 }
533 self.expect(")")?;
534 }
535 self.expect(":")?;
536 self.end_of_line()?;
537 blocks.push(PendingBlock { params, insts: Vec::new() });
538 continue;
539 }
540 let inst = self.inst()?;
541 match blocks.last_mut() {
542 Some(block) => block.insts.push(inst),
543 None => return self.fail("an instruction before any block"),
544 }
545 }
546 }
547
548 fn inst(&mut self) -> Result<PendingInst<'a>, ParseError> {
550 let line = self.line;
551 let mut results = Vec::new();
552 if self.peek_is("%") {
553 results = self.value_list()?;
554 self.expect("=")?;
555 }
556
557 let word = self.word();
558 let Some(opcode) = Opcode::from_name(word) else {
559 return self.fail(format!("`{word}` is not an opcode"));
560 };
561 let (written, flags) = self.suffixes()?;
562
563 let mut args = Vec::new();
564 let extra = match opcode.extra_kind() {
565 ExtraKind::None => {
566 args = self.value_list()?;
567 PendingExtra::None
568 }
569 ExtraKind::Imm => PendingExtra::Imm(self.imm_text()?),
570 ExtraKind::Symbol => {
571 let symbol = self.symbol()?;
572 if self.eat("(") {
573 args = self.value_list()?;
574 self.expect(")")?;
575 }
576 PendingExtra::Symbol(symbol)
577 }
578 ExtraKind::IntPred => {
579 let word = self.word();
580 let Some(pred) = IntPred::from_name(word) else {
581 return self.fail(format!("`{word}` is not an integer comparison"));
582 };
583 args = self.value_list()?;
584 PendingExtra::IntPred(pred)
585 }
586 ExtraKind::FloatPred => {
587 let word = self.word();
588 let Some(pred) = FloatPred::from_name(word) else {
589 return self.fail(format!("`{word}` is not a floating point comparison"));
590 };
591 args = self.value_list()?;
592 PendingExtra::FloatPred(pred)
593 }
594 ExtraKind::Mem => {
595 if matches!(opcode, Opcode::Store | Opcode::AtomicStore) {
596 let value = self.value_ref()?;
598 self.expect("->")?;
599 args = vec![value, self.value_ref()?];
600 } else {
601 args = self.value_list()?;
602 }
603 PendingExtra::Mem(self.mem()?)
604 }
605 ExtraKind::VaObject => {
606 args = self.value_list()?;
607 let (info, slots) = self.va()?;
608 PendingExtra::VaObject(info, slots)
609 }
610 ExtraKind::Rmw => {
611 let word = self.word();
612 let Some(op) = RmwOp::from_name(word) else {
613 return self.fail(format!("`{word}` is not a read-modify-write"));
614 };
615 args = self.value_list()?;
616 PendingExtra::Rmw(op, self.mem()?)
617 }
618 ExtraKind::Order => {
619 let word = self.word();
620 let Some(order) = MemOrder::from_name(word) else {
621 return self.fail(format!("`{word}` is not an ordering"));
622 };
623 PendingExtra::Order(order)
624 }
625 ExtraKind::Targets => {
626 args = self.value_list()?;
627 if !args.is_empty() {
628 self.expect(",")?;
629 }
630 let mut targets = Vec::new();
631 loop {
632 targets.push(self.block_call()?);
633 if !self.eat(",") {
634 break;
635 }
636 }
637 PendingExtra::Targets(targets)
638 }
639 ExtraKind::Call => {
640 let callee = if self.peek_is("@") {
641 Some(self.symbol()?)
642 } else {
643 args.push(self.value_ref()?);
644 None
645 };
646 self.expect("(")?;
647 let (values, abis) = self.call_args()?;
648 args.extend(values);
649 self.expect(")")?;
650 self.expect(":")?;
651 PendingExtra::Call { callee, signature: self.signature()?, abis }
652 }
653 ExtraKind::Switch => {
654 args = self.value_list()?;
655 let mut targets = Vec::new();
656 let mut cases = Vec::new();
657 if self.eat(",") {
658 targets.push(self.block_call()?);
659 self.expect(",")?;
660 self.expect("[")?;
661 if !self.eat("]") {
662 loop {
663 cases.push(self.imm_text()?);
664 self.expect("=>")?;
665 targets.push(self.block_call()?);
666 if !self.eat(",") {
667 break;
668 }
669 }
670 self.expect("]")?;
671 }
672 }
673 PendingExtra::Switch { targets, cases }
674 }
675 ExtraKind::Asm => {
676 let template = self.symbol_from_string()?;
677 self.expect(",")?;
678 let constraints = self.symbol_from_string()?;
679 self.expect(",")?;
680 let clobbers = self.symbol_from_string()?;
681 self.expect("(")?;
682 args = self.value_list()?;
683 self.expect(")")?;
684 let mut targets = Vec::new();
685 if self.eat(",") {
686 self.expect("labels")?;
687 self.expect("[")?;
688 loop {
689 targets.push(self.block_call()?);
690 if !self.eat(",") {
691 break;
692 }
693 }
694 self.expect("]")?;
695 }
696 PendingExtra::Asm { template, constraints, clobbers, targets }
697 }
698 };
699 self.end_of_line()?;
700 Ok(PendingInst { opcode, flags, results, written, args, extra, line })
701 }
702
703 fn suffixes(&mut self) -> Result<(Vec<Type>, Flags), ParseError> {
705 let mut written = Vec::new();
706 let mut flags = Flags::NONE;
707 while self.at(".") {
708 self.pos += 1;
709 if self.at("(") {
710 self.pos += 1;
711 loop {
712 written.push(self.ty()?);
713 if !self.eat(",") {
714 break;
715 }
716 }
717 self.expect(")")?;
718 continue;
719 }
720 let word = self.glued_word();
721 if let Some(flag) = Flags::from_name(word) {
722 flags |= flag;
723 } else if let Some(ty) = Type::parse(word) {
724 written.push(ty);
725 } else {
726 return self.fail(format!("`{word}` is neither a type nor a flag"));
727 }
728 }
729 Ok((written, flags))
730 }
731
732 fn mem(&mut self) -> Result<MemInfo, ParseError> {
734 let mut info = MemInfo { size: 0, align: 1, order: MemOrder::NotAtomic, tbaa: None };
735 while self.eat(",") {
736 let word = self.word();
737 if !self.mem_field(&mut info, word)? {
738 return self.fail(format!("an access has no `{word}`"));
739 }
740 }
741 Ok(info)
742 }
743
744 fn mem_field(&mut self, info: &mut MemInfo, word: &str) -> Result<bool, ParseError> {
746 match word {
747 "size" => info.size = self.u64()?,
748 "align" => info.align = self.u32()?,
749 "tbaa" => info.tbaa = Some(self.meta_ref()?),
750 _ => match MemOrder::from_name(word) {
751 Some(order) => info.order = order,
752 None => return Ok(false),
753 },
754 }
755 Ok(true)
756 }
757
758 fn va(&mut self) -> Result<(MemInfo, Vec<Slot>), ParseError> {
761 let mut info = MemInfo { size: 0, align: 1, order: MemOrder::NotAtomic, tbaa: None };
762 let mut slots = Vec::new();
763 while self.eat(",") {
764 let word = self.word();
765 if word == "in" {
766 self.expect("(")?;
767 loop {
768 slots.push(self.slot()?);
769 if !self.eat(",") {
770 break;
771 }
772 }
773 self.expect(")")?;
774 } else if !self.mem_field(&mut info, word)? {
775 return self
776 .fail(format!("an object off a variable argument list has no `{word}`"));
777 }
778 }
779 Ok((info, slots))
780 }
781
782 fn slot(&mut self) -> Result<Slot, ParseError> {
784 let word = self.word();
785 let slot = match word {
786 "int" => {
787 let size = self.u32()?;
788 self.expect("at")?;
789 Slot::Integer { offset: self.u64()?, size }
790 }
791 "float" => {
792 let name = self.word();
793 let Some(format) = Format::from_name(name) else {
794 return self.fail(format!("`{name}` is not a floating point format"));
795 };
796 self.expect("at")?;
797 Slot::Float { offset: self.u64()?, format }
798 }
799 _ => return self.fail(format!("`{word}` is not how a slot is written")),
800 };
801 Ok(slot)
802 }
803
804 fn block_call(&mut self) -> Result<PendingCall, ParseError> {
806 let block = self.block_ref()?;
807 let mut args = Vec::new();
808 if self.eat("(") {
809 args = self.value_list()?;
810 self.expect(")")?;
811 }
812 Ok(PendingCall { block, args })
813 }
814
815 fn build(&mut self, func: &mut Func, blocks: &[PendingBlock<'a>]) -> Result<(), ParseError> {
819 let count = self.check_numbering(blocks)?;
820 let types = self.value_types(blocks, count)?;
821
822 let mut next = 0;
823 for pending in blocks {
824 let block = func.create_block();
825 for &(number, ty) in &pending.params {
826 if number != next {
827 self.line = self.line_of(blocks, number);
828 return self
829 .fail(format!("values are numbered in order and %{next} comes next"));
830 }
831 func.append_param(block, ty);
832 next += 1;
833 }
834 for inst in &pending.insts {
835 if inst.results.first().is_some_and(|&first| first != next) {
836 self.line = inst.line;
837 return self
838 .fail(format!("values are numbered in order and %{next} comes next"));
839 }
840 let built = self.build_inst(func, inst, &types)?;
841 func.append_inst(block, built);
842 next += inst.results.len() as u32;
843 }
844 }
845 Ok(())
846 }
847
848 fn check_numbering(&mut self, blocks: &[PendingBlock<'a>]) -> Result<u32, ParseError> {
852 let mut count = 0;
853 for pending in blocks {
854 count += pending.params.len();
855 for inst in &pending.insts {
856 count += inst.results.len();
857 }
858 }
859 let count = count as u32;
860 let total = blocks.len() as u32;
861 for pending in blocks {
862 for inst in &pending.insts {
863 self.line = inst.line;
864 for &arg in &inst.args {
865 if arg >= count {
866 return self.fail(format!("%{arg} is used and never defined"));
867 }
868 }
869 for call in inst_calls(inst) {
870 if call.block >= total {
871 return self.fail(format!("block{} is used and never defined", call.block));
872 }
873 for &arg in &call.args {
874 if arg >= count {
875 return self.fail(format!("%{arg} is used and never defined"));
876 }
877 }
878 }
879 }
880 }
881 Ok(count)
882 }
883
884 fn value_types(
891 &mut self,
892 blocks: &[PendingBlock<'a>],
893 count: u32,
894 ) -> Result<Vec<Option<Type>>, ParseError> {
895 let mut types = vec![None; count as usize];
896 for pending in blocks {
897 for &(number, ty) in &pending.params {
898 types[number as usize] = Some(ty);
899 }
900 }
901 loop {
902 let mut progress = false;
903 for pending in blocks {
904 for inst in &pending.insts {
905 let Some(&first) = inst.results.first() else { continue };
906 if types[first as usize].is_some() {
907 continue;
908 }
909 let Some(resolved) = result_types(inst, &types) else { continue };
910 if resolved.len() != inst.results.len() {
911 self.line = inst.line;
912 return self.fail(format!(
913 "{} produces {} values and the text names {}",
914 inst.opcode.name(),
915 resolved.len(),
916 inst.results.len()
917 ));
918 }
919 for (&number, ty) in inst.results.iter().zip(resolved) {
920 types[number as usize] = Some(ty);
921 }
922 progress = true;
923 }
924 }
925 if !progress {
926 break;
927 }
928 }
929 for pending in blocks {
930 for inst in &pending.insts {
931 if inst.results.first().is_some_and(|&first| types[first as usize].is_none()) {
932 self.line = inst.line;
933 return self.fail(format!(
934 "nothing in the text says what {} produces",
935 inst.opcode.name()
936 ));
937 }
938 }
939 }
940 Ok(types)
941 }
942
943 fn build_inst(
944 &mut self,
945 func: &mut Func,
946 pending: &PendingInst<'a>,
947 types: &[Option<Type>],
948 ) -> Result<Inst, ParseError> {
949 let results: Vec<Type> = pending
950 .results
951 .iter()
952 .map(|&number| types[number as usize].unwrap_or(Type::VOID))
953 .collect();
954 let args: Vec<Value> =
955 pending.args.iter().map(|&number| Value::from_usize(number as usize)).collect();
956 let arg_list = func.push_values(&args);
957
958 let extra = match &pending.extra {
959 PendingExtra::None => Extra::None,
960 PendingExtra::Imm(text) => {
961 let ty = results.first().copied().unwrap_or(Type::VOID);
962 self.line = pending.line;
963 let imm = self.imm(text, ty)?;
964 Extra::Imm(func.add_imm(imm))
965 }
966 PendingExtra::Symbol(symbol) => Extra::Symbol(*symbol),
967 PendingExtra::IntPred(pred) => Extra::IntPred(*pred),
968 PendingExtra::FloatPred(pred) => Extra::FloatPred(*pred),
969 PendingExtra::Mem(info) => Extra::Mem(func.add_mem(*info)),
970 PendingExtra::VaObject(info, slots) => {
971 let mem = func.add_mem(*info);
972 let slots = func.push_slots(slots);
973 Extra::VaObject(func.add_va_object(VaInfo { mem, slots }))
974 }
975 PendingExtra::Rmw(op, info) => Extra::Rmw(*op, func.add_mem(*info)),
976 PendingExtra::Order(order) => Extra::Order(*order),
977 PendingExtra::Targets(targets) => {
978 let calls = build_calls(func, targets);
979 Extra::Targets(func.push_block_calls(&calls))
980 }
981 PendingExtra::Call { callee, signature, abis } => {
982 let named = signature.params.len();
983 if abis.iter().take(named).any(|&abi| abi != Abi::Plain) {
984 self.line = pending.line;
985 return self.fail(
986 "the signature is what says how an argument it names travels".to_string(),
987 );
988 }
989 let varargs = match abis.get(named.min(abis.len())..) {
990 Some(rest) if rest.iter().any(|&abi| abi != Abi::Plain) => rest,
991 _ => &[],
992 };
993 let varargs = func.push_abis(varargs);
994 let sig = func.add_signature(signature.clone());
995 Extra::Call(func.add_call(CallInfo { callee: *callee, signature: sig, varargs }))
996 }
997 PendingExtra::Switch { targets, cases } => {
998 let ty = pending
999 .args
1000 .first()
1001 .and_then(|&number| types[number as usize])
1002 .unwrap_or(Type::VOID);
1003 self.line = pending.line;
1004 let mut imms = Vec::with_capacity(cases.len());
1005 for case in cases {
1006 imms.push(self.imm(case, ty)?);
1007 }
1008 let calls = build_calls(func, targets);
1009 let targets = func.push_block_calls(&calls);
1010 let cases = func.push_imms(&imms);
1011 Extra::Switch(func.add_switch(SwitchInfo { targets, cases }))
1012 }
1013 PendingExtra::Asm { template, constraints, clobbers, targets } => {
1014 let calls = build_calls(func, targets);
1015 let targets = func.push_block_calls(&calls);
1016 Extra::Asm(func.add_asm(AsmInfo {
1017 template: *template,
1018 constraints: *constraints,
1019 clobbers: *clobbers,
1020 targets,
1021 }))
1022 }
1023 };
1024
1025 let data = InstData {
1026 opcode: pending.opcode,
1027 flags: pending.flags,
1028 args: arg_list,
1029 extra,
1030 ..InstData::new(pending.opcode)
1031 };
1032 Ok(func.create_inst(data, &results, Span::DUMMY))
1033 }
1034
1035 fn line_of(&self, blocks: &[PendingBlock<'a>], number: u32) -> u32 {
1037 for pending in blocks {
1038 for inst in &pending.insts {
1039 if inst.results.contains(&number) {
1040 return inst.line;
1041 }
1042 }
1043 }
1044 self.line
1045 }
1046
1047 fn imm(&mut self, text: &str, ty: Type) -> Result<Imm, ParseError> {
1051 let scalar = if ty.is_vector() { ty.lane() } else { ty };
1052 if scalar.is_int() {
1053 match parse_i128(text) {
1054 Some(value) => Ok(Imm::int(value, scalar)),
1055 None => self.fail(format!("`{text}` is not an {scalar}")),
1056 }
1057 } else {
1058 match text.strip_prefix("0x").and_then(|rest| u128::from_str_radix(rest, 16).ok()) {
1059 Some(bits) => Ok(Imm::from_bits(bits)),
1060 None => self.fail(format!("`{text}` is not the bits of a {scalar}")),
1061 }
1062 }
1063 }
1064
1065 fn imm_text(&mut self) -> Result<&'a str, ParseError> {
1067 self.spaces();
1068 let start = self.pos;
1069 if self.at("-") {
1070 self.pos += 1;
1071 }
1072 while self.peek().is_some_and(|byte| byte.is_ascii_alphanumeric()) {
1073 self.pos += 1;
1074 }
1075 if self.pos == start {
1076 return self.fail("a constant was expected");
1077 }
1078 Ok(&self.text[start..self.pos])
1079 }
1080
1081 fn ty(&mut self) -> Result<Type, ParseError> {
1082 let word = self.word();
1083 match Type::parse(word) {
1084 Some(ty) => Ok(ty),
1085 None => self.fail(format!("`{word}` is not a type")),
1086 }
1087 }
1088
1089 fn value_ref(&mut self) -> Result<u32, ParseError> {
1091 self.expect("%")?;
1092 self.u32()
1093 }
1094
1095 fn value_list(&mut self) -> Result<Vec<u32>, ParseError> {
1097 let mut values = Vec::new();
1098 if !self.peek_is("%") {
1099 return Ok(values);
1100 }
1101 loop {
1102 values.push(self.value_ref()?);
1103 let save = self.pos;
1104 if !self.eat(",") {
1105 return Ok(values);
1106 }
1107 if !self.peek_is("%") {
1108 self.pos = save;
1109 return Ok(values);
1110 }
1111 }
1112 }
1113
1114 fn call_args(&mut self) -> Result<(Vec<u32>, Vec<Abi>), ParseError> {
1117 let mut values = Vec::new();
1118 let mut abis = Vec::new();
1119 if !self.peek_is("%") {
1120 return Ok((values, abis));
1121 }
1122 loop {
1123 values.push(self.value_ref()?);
1124 abis.push(self.abi()?);
1125 let save = self.pos;
1126 if !self.eat(",") {
1127 return Ok((values, abis));
1128 }
1129 if !self.peek_is("%") {
1130 self.pos = save;
1131 return Ok((values, abis));
1132 }
1133 }
1134 }
1135
1136 fn block_ref(&mut self) -> Result<u32, ParseError> {
1138 let word = self.word();
1139 match word.strip_prefix("block").and_then(parse_u32) {
1140 Some(number) => Ok(number),
1141 None => self.fail(format!("`{word}` is not a block")),
1142 }
1143 }
1144
1145 fn meta_ref(&mut self) -> Result<Meta, ParseError> {
1147 self.expect("!")?;
1148 let index = self.u32()?;
1149 let seen = self.meta_used.is_none_or(|(used, _)| index > used);
1150 if seen {
1151 self.meta_used = Some((index, self.line));
1152 }
1153 Ok(Idx::from_usize(index as usize))
1154 }
1155
1156 fn symbol(&mut self) -> Result<Symbol, ParseError> {
1158 self.expect("@")?;
1159 let start = self.pos;
1160 while self.peek().is_some_and(is_name_byte) {
1161 self.pos += 1;
1162 }
1163 if self.pos == start {
1164 return self.fail("a name was expected");
1165 }
1166 let name = &self.text[start..self.pos];
1167 Ok(self.names.intern(name))
1168 }
1169
1170 fn symbol_from_string(&mut self) -> Result<Symbol, ParseError> {
1172 let text = self.quoted_str()?;
1173 Ok(self.names.intern(&text))
1174 }
1175
1176 fn quoted_str(&mut self) -> Result<String, ParseError> {
1178 let bytes = self.string()?;
1179 match String::from_utf8(bytes) {
1180 Ok(text) => Ok(text),
1181 Err(_) => self.fail("that string is not text"),
1182 }
1183 }
1184
1185 fn string(&mut self) -> Result<Vec<u8>, ParseError> {
1187 self.expect("\"")?;
1188 let mut bytes = Vec::new();
1189 loop {
1190 let Some(byte) = self.peek() else {
1191 return self.fail("that string is not closed");
1192 };
1193 self.pos += 1;
1194 match byte {
1195 b'"' => return Ok(bytes),
1196 b'\n' => return self.fail("that string is not closed"),
1197 b'\\' => {
1198 let escape = match self.peek() {
1199 Some(b'"') => b'"',
1200 Some(b'\\') => b'\\',
1201 _ => {
1202 let hex = self.text.get(self.pos..self.pos + 2);
1203 match hex.and_then(|hex| u8::from_str_radix(hex, 16).ok()) {
1204 Some(byte) => {
1205 self.pos += 2;
1206 bytes.push(byte);
1207 continue;
1208 }
1209 None => return self.fail("that is not an escape"),
1210 }
1211 }
1212 };
1213 self.pos += 1;
1214 bytes.push(escape);
1215 }
1216 _ => bytes.push(byte),
1217 }
1218 }
1219 }
1220
1221 fn u32(&mut self) -> Result<u32, ParseError> {
1222 let word = self.word();
1223 match parse_u32(word) {
1224 Some(number) => Ok(number),
1225 None => self.fail(format!("`{word}` is not a number")),
1226 }
1227 }
1228
1229 fn u64(&mut self) -> Result<u64, ParseError> {
1230 let word = self.word();
1231 match parse_u64(word) {
1232 Some(number) => Ok(number),
1233 None => self.fail(format!("`{word}` is not a number")),
1234 }
1235 }
1236
1237 fn i64(&mut self) -> Result<i64, ParseError> {
1238 let word = self.word();
1239 match parse_u64(word).and_then(|number| i64::try_from(number).ok()) {
1240 Some(number) => Ok(number),
1241 None => self.fail(format!("`{word}` is not an offset")),
1242 }
1243 }
1244
1245 fn parenthesised<T>(
1247 &mut self,
1248 from_name: impl Fn(&str) -> Option<T>,
1249 what: &str,
1250 ) -> Result<T, ParseError> {
1251 self.expect("(")?;
1252 let word = self.word();
1253 let Some(value) = from_name(word) else {
1254 return self.fail(format!("`{word}` is not {what}"));
1255 };
1256 self.expect(")")?;
1257 Ok(value)
1258 }
1259
1260 fn fail<T>(&self, message: impl Into<String>) -> Result<T, ParseError> {
1263 Err(ParseError { line: self.line, message: message.into() })
1264 }
1265
1266 fn peek(&self) -> Option<u8> {
1267 self.text.as_bytes().get(self.pos).copied()
1268 }
1269
1270 fn at(&self, text: &str) -> bool {
1271 self.text[self.pos..].starts_with(text)
1272 }
1273
1274 fn at_end(&self) -> bool {
1275 self.pos >= self.text.len()
1276 }
1277
1278 fn peek_is(&self, text: &str) -> bool {
1280 self.text[self.pos..].trim_start_matches([' ', '\t']).starts_with(text)
1281 }
1282
1283 fn spaces(&mut self) {
1284 while matches!(self.peek(), Some(b' ' | b'\t')) {
1285 self.pos += 1;
1286 }
1287 }
1288
1289 fn eat(&mut self, text: &str) -> bool {
1290 self.spaces();
1291 if self.at(text) {
1292 self.pos += text.len();
1293 return true;
1294 }
1295 false
1296 }
1297
1298 fn expect(&mut self, text: &str) -> Result<(), ParseError> {
1299 if self.eat(text) {
1300 return Ok(());
1301 }
1302 self.fail(format!("`{text}` was expected"))
1303 }
1304
1305 fn word(&mut self) -> &'a str {
1307 self.spaces();
1308 self.glued_word()
1309 }
1310
1311 fn glued_word(&mut self) -> &'a str {
1313 let start = self.pos;
1314 while self.peek().is_some_and(|byte| byte.is_ascii_alphanumeric() || byte == b'_') {
1315 self.pos += 1;
1316 }
1317 &self.text[start..self.pos]
1318 }
1319
1320 fn peek_word(&self) -> &'a str {
1322 let rest = self.text[self.pos..].trim_start_matches([' ', '\t']);
1323 let end =
1324 rest.find(|c: char| !(c.is_ascii_alphanumeric() || c == '_')).unwrap_or(rest.len());
1325 &rest[..end]
1326 }
1327
1328 fn eat_word(&mut self, word: &str) -> bool {
1330 if self.peek_word() == word {
1331 self.word();
1332 return true;
1333 }
1334 false
1335 }
1336
1337 fn end_of_line(&mut self) -> Result<(), ParseError> {
1338 self.spaces();
1339 if self.at_end() {
1340 return Ok(());
1341 }
1342 if self.at("\n") {
1343 self.pos += 1;
1344 self.line += 1;
1345 return Ok(());
1346 }
1347 let rest = &self.text[self.pos..];
1348 let end = rest.find('\n').unwrap_or(rest.len());
1349 self.fail(format!("`{}` is left over at the end of the line", &rest[..end]))
1350 }
1351
1352 fn skip_blank_lines(&mut self) {
1353 loop {
1354 let save = self.pos;
1355 self.spaces();
1356 if self.at("\n") {
1357 self.pos += 1;
1358 self.line += 1;
1359 } else {
1360 self.pos = save;
1361 return;
1362 }
1363 }
1364 }
1365}
1366
1367fn inst_calls<'p>(inst: &'p PendingInst<'_>) -> &'p [PendingCall] {
1369 match &inst.extra {
1370 PendingExtra::Targets(targets)
1371 | PendingExtra::Switch { targets, .. }
1372 | PendingExtra::Asm { targets, .. } => targets,
1373 _ => &[],
1374 }
1375}
1376
1377fn build_calls(func: &mut Func, targets: &[PendingCall]) -> Vec<BlockCall> {
1379 targets
1380 .iter()
1381 .map(|call| {
1382 let args: Vec<Value> =
1383 call.args.iter().map(|&number| Value::from_usize(number as usize)).collect();
1384 BlockCall {
1385 block: Block::from_usize(call.block as usize),
1386 args: func.push_values(&args),
1387 }
1388 })
1389 .collect()
1390}
1391
1392fn result_types(inst: &PendingInst<'_>, types: &[Option<Type>]) -> Option<Vec<Type>> {
1397 if inst.results.is_empty() {
1398 return Some(Vec::new());
1399 }
1400 if !inst.written.is_empty() {
1401 return Some(inst.written.clone());
1402 }
1403 match inst.opcode {
1404 Opcode::GlobalAddr | Opcode::BlockAddr | Opcode::Alloca => Some(vec![Type::PTR]),
1405 Opcode::ICmp | Opcode::FCmp => {
1406 let ty = arg_type(inst, types)?;
1407 Some(vec![ty.with_lane(Type::I1)])
1408 }
1409 Opcode::Call | Opcode::CallIndirect | Opcode::TailCall => match &inst.extra {
1410 PendingExtra::Call { signature, .. } => Some(signature.return_types().collect()),
1411 _ => None,
1412 },
1413 _ => Some(vec![arg_type(inst, types)?]),
1414 }
1415}
1416
1417fn arg_type(inst: &PendingInst<'_>, types: &[Option<Type>]) -> Option<Type> {
1419 let &first = inst.args.first()?;
1420 *types.get(first as usize)?
1421}
1422
1423fn parse_u64(text: &str) -> Option<u64> {
1425 if text.is_empty() || (text.starts_with('0') && text.len() > 1) {
1426 return None;
1427 }
1428 if !text.bytes().all(|byte| byte.is_ascii_digit()) {
1429 return None;
1430 }
1431 text.parse().ok()
1432}
1433
1434fn parse_u32(text: &str) -> Option<u32> {
1435 parse_u64(text).and_then(|number| u32::try_from(number).ok())
1436}
1437
1438fn parse_i128(text: &str) -> Option<i128> {
1440 let (negative, digits) = match text.strip_prefix('-') {
1441 Some(rest) => (true, rest),
1442 None => (false, text),
1443 };
1444 if digits.is_empty() || (digits.starts_with('0') && digits.len() > 1) {
1445 return None;
1446 }
1447 if negative && digits == "0" {
1448 return None;
1449 }
1450 if !digits.bytes().all(|byte| byte.is_ascii_digit()) {
1451 return None;
1452 }
1453 let magnitude: u128 = digits.parse().ok()?;
1454 if negative {
1455 (magnitude <= 1 << 127).then(|| (magnitude as i128).wrapping_neg())
1458 } else {
1459 i128::try_from(magnitude).ok()
1460 }
1461}
1462
1463fn is_name_byte(byte: u8) -> bool {
1471 byte.is_ascii_alphanumeric() || matches!(byte, b'_' | b'.' | b'$') || byte >= 0x80
1472}
1473
1474#[cfg(test)]
1475mod tests {
1476 use rucc_base::Interner;
1477
1478 use super::*;
1479 use crate::fixtures::{EXAMPLE, SYMBOLS, ZOO};
1480 use crate::print;
1481
1482 fn round_trip(text: &str) -> String {
1484 let mut names = Interner::new();
1485 let module = match parse(text, &mut names) {
1486 Ok(module) => module,
1487 Err(error) => panic!("{error}"),
1488 };
1489 print(&module, &names)
1490 }
1491
1492 fn error(text: &str) -> String {
1493 let mut names = Interner::new();
1494 match parse(text, &mut names) {
1495 Ok(_) => panic!("that was expected to be turned down"),
1496 Err(error) => error.to_string(),
1497 }
1498 }
1499
1500 const HEADER: &str = "\
1501; ModuleID = 'example.c'
1502; format 0
1503target triple = \"x86_64-unknown-linux-gnu\"
1504target datalayout = \"e-p:64:64-i64:64-f80:128-S128\"
1505";
1506
1507 #[test]
1508 fn the_example_in_the_spec_comes_back_byte_for_byte() {
1509 assert_eq!(round_trip(EXAMPLE), EXAMPLE);
1510 }
1511
1512 #[test]
1513 fn one_of_almost_everything_comes_back_byte_for_byte() {
1514 assert_eq!(round_trip(ZOO), ZOO);
1515 }
1516
1517 #[test]
1518 fn the_shapes_a_symbol_comes_in_come_back_byte_for_byte() {
1519 assert_eq!(round_trip(SYMBOLS), SYMBOLS);
1520 }
1521
1522 #[test]
1523 fn a_name_that_is_not_ascii_comes_back_byte_for_byte() {
1524 let text = format!("{HEADER}\nglobal @été : i32 = 1, align 4, linkage(external)\n");
1528 assert_eq!(round_trip(&text), text);
1529 }
1530
1531 #[test]
1532 fn a_value_defined_after_it_is_used() {
1533 let text = format!(
1537 "{HEADER}
1538func @late() -> i64, linkage(external) {{
1539block0:
1540 jump block2
1541
1542block1(%0: i64):
1543 %1 = add %2, %0
1544 return %1
1545
1546block2:
1547 %2 = iconst.i64 7
1548 jump block1(%2)
1549}}
1550"
1551 );
1552 assert_eq!(round_trip(&text), text);
1553 }
1554
1555 #[test]
1556 fn what_the_abi_asks_of_a_parameter_comes_back_byte_for_byte() {
1557 let text = format!(
1560 "{HEADER}
1561func @f(ptr sret(24, align 8), ptr byval(16, align 8), i8 zext), linkage(external) {{
1562block0(%0: ptr, %1: ptr, %2: i8):
1563 return
1564}}
1565
1566func @g(i8 sext) -> i8 sext, linkage(external);
1567"
1568 );
1569 assert_eq!(round_trip(&text), text);
1570 }
1571
1572 #[test]
1573 fn a_word_that_is_not_an_attribute_is_not_read_as_one() {
1574 let text = format!(
1575 "{HEADER}
1576func @f(ptr inreg), linkage(external);
1577"
1578 );
1579 assert_eq!(error(&text), "line 6: `)` was expected");
1580 }
1581
1582 #[test]
1583 fn an_empty_module_is_its_header() {
1584 assert_eq!(round_trip(HEADER), HEADER);
1585 }
1586
1587 #[test]
1588 fn the_format_version_is_checked_before_anything_else() {
1589 let text = "; ModuleID = 'a.c'\n; format 99\n";
1590 assert_eq!(error(text), "line 2: this build reads format 0 and the text says format 99");
1591 }
1592
1593 #[test]
1594 fn an_opcode_nobody_has_is_reported_with_its_line() {
1595 let text = format!(
1596 "{HEADER}
1597func @f(), linkage(external) {{
1598block0:
1599 getelementptr %0
1600}}
1601"
1602 );
1603 assert_eq!(error(&text), "line 8: `getelementptr` is not an opcode");
1604 }
1605
1606 #[test]
1609 fn a_slot_written_as_something_that_is_not_one_is_reported() {
1610 let text = format!(
1611 "{HEADER}
1612func @f(ptr) -> ptr, linkage(external) {{
1613block0(%0: ptr):
1614 %1 = va_object %0, size 16, align 8, in(short 8 at 0)
1615 return %1
1616}}
1617"
1618 );
1619 assert_eq!(error(&text), "line 8: `short` is not how a slot is written");
1620 }
1621
1622 #[test]
1623 fn an_abi_on_an_argument_the_signature_names_is_turned_down() {
1624 let text = format!(
1627 "{HEADER}
1628func @f(ptr), linkage(external) {{
1629block0(%0: ptr):
1630 call @p(%0 byval(8, align 8)) : (ptr, ...)
1631 return
1632}}
1633"
1634 );
1635 assert_eq!(
1636 error(&text),
1637 "line 8: the signature is what says how an argument it names travels"
1638 );
1639 }
1640
1641 #[test]
1642 fn a_value_nothing_defines_is_reported() {
1643 let text = format!(
1644 "{HEADER}
1645func @f(i32) -> i32, linkage(external) {{
1646block0(%0: i32):
1647 %1 = add %0, %9
1648 return %1
1649}}
1650"
1651 );
1652 assert_eq!(error(&text), "line 8: %9 is used and never defined");
1653 }
1654
1655 #[test]
1656 fn a_block_nothing_defines_is_reported() {
1657 let text = format!(
1658 "{HEADER}
1659func @f(), linkage(external) {{
1660block0:
1661 jump block7
1662}}
1663"
1664 );
1665 assert_eq!(error(&text), "line 8: block7 is used and never defined");
1666 }
1667
1668 #[test]
1669 fn values_have_to_be_numbered_in_print_order() {
1670 let text = format!(
1671 "{HEADER}
1672func @f() -> i32, linkage(external) {{
1673block0:
1674 %1 = iconst.i32 0
1675 %0 = iconst.i32 1
1676 return %1
1677}}
1678"
1679 );
1680 assert_eq!(error(&text), "line 8: values are numbered in order and %0 comes next");
1681 }
1682
1683 #[test]
1684 fn blocks_have_to_be_numbered_in_print_order() {
1685 let text = format!(
1686 "{HEADER}
1687func @f(), linkage(external) {{
1688block1:
1689 return
1690}}
1691"
1692 );
1693 assert_eq!(error(&text), "line 7: blocks are numbered in order and block0 comes next");
1694 }
1695
1696 #[test]
1697 fn metadata_nobody_defines_is_reported() {
1698 let text = format!(
1699 "{HEADER}
1700func @f(ptr), linkage(external) {{
1701block0(%0: ptr):
1702 %1 = load.i32 %0, align 4, tbaa !3
1703 return
1704}}
1705"
1706 );
1707 assert_eq!(error(&text), "line 8: !3 is used and never defined");
1708 }
1709
1710 #[test]
1711 fn a_type_nothing_says_is_reported_rather_than_guessed() {
1712 let text = format!(
1713 "{HEADER}
1714func @f(), linkage(external) {{
1715block0:
1716 %0 = add
1717 return
1718}}
1719"
1720 );
1721 assert_eq!(error(&text), "line 8: nothing in the text says what add produces");
1722 }
1723
1724 #[test]
1725 fn a_line_with_something_left_on_it_is_turned_down() {
1726 let text = format!(
1727 "{HEADER}
1728global @x : i32 = 0, align 4, linkage(internal) and then some
1729"
1730 );
1731 assert_eq!(error(&text), "line 6: `and then some` is left over at the end of the line");
1732 }
1733
1734 #[test]
1735 fn a_constant_that_is_not_one_is_turned_down() {
1736 let text = format!(
1737 "{HEADER}
1738global @x : i32 = 007, align 4, linkage(internal)
1739"
1740 );
1741 assert_eq!(error(&text), "line 6: `007` is not an i32");
1742 }
1743
1744 #[test]
1745 fn a_number_is_read_the_way_the_printer_writes_it() {
1746 assert_eq!(parse_i128("-1"), Some(-1));
1747 assert_eq!(parse_i128("0"), Some(0));
1748 assert_eq!(parse_i128("-0"), None);
1749 assert_eq!(parse_i128("+1"), None);
1750 assert_eq!(parse_i128("01"), None);
1751 assert_eq!(parse_i128(""), None);
1752 assert_eq!(parse_i128("170141183460469231731687303715884105728"), None);
1753 assert_eq!(parse_i128("-170141183460469231731687303715884105728"), Some(i128::MIN));
1754 }
1755
1756 #[test]
1757 fn every_opcode_says_which_payload_it_carries() {
1758 for opcode in Opcode::all() {
1761 let kind = opcode.extra_kind();
1762 let expected = match opcode {
1763 Opcode::IConst | Opcode::FConst | Opcode::Splat => ExtraKind::Imm,
1764 Opcode::GlobalAddr | Opcode::TargetIntrinsic => ExtraKind::Symbol,
1765 Opcode::ICmp => ExtraKind::IntPred,
1766 Opcode::FCmp => ExtraKind::FloatPred,
1767 Opcode::Fence => ExtraKind::Order,
1768 Opcode::AtomicRmw => ExtraKind::Rmw,
1769 Opcode::Switch => ExtraKind::Switch,
1770 Opcode::InlineAsm => ExtraKind::Asm,
1771 Opcode::Jump | Opcode::BrIf | Opcode::BlockAddr | Opcode::IndirectBr => {
1772 ExtraKind::Targets
1773 }
1774 Opcode::Call | Opcode::CallIndirect | Opcode::TailCall => ExtraKind::Call,
1775 Opcode::Alloca
1776 | Opcode::Load
1777 | Opcode::Store
1778 | Opcode::Memcpy
1779 | Opcode::Memmove
1780 | Opcode::Memset
1781 | Opcode::AtomicLoad
1782 | Opcode::AtomicStore
1783 | Opcode::Cmpxchg => ExtraKind::Mem,
1784 Opcode::VaObject => ExtraKind::VaObject,
1785 _ => ExtraKind::None,
1786 };
1787 assert_eq!(kind, expected, "{}", opcode.name());
1788 }
1789 }
1790}