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