1use crate::bitstream::{Block, Record};
9use crate::{Result, error};
10
11const MODULE: u64 = 8;
12const PARAMATTR: u64 = 9;
13const PARAMATTR_GROUP: u64 = 10;
14const CONSTANTS: u64 = 11;
15const FUNCTION: u64 = 12;
16const VALUE_SYMTAB: u64 = 14;
17const METADATA: u64 = 15;
18const METADATA_ATTACHMENT: u64 = 16;
19const TYPES: u64 = 17;
20const USELIST: u64 = 18;
21const BLOCKINFO: u64 = 0;
22
23const MAX_VALUES: usize = 1 << 22;
25const MAX_TYPES: usize = 1 << 16;
26
27pub type TypeId = usize;
29pub type ValueId = usize;
31pub type MetadataId = usize;
33
34#[derive(Clone, Debug, PartialEq, Eq)]
36pub enum Type {
37 Void,
39 Label,
41 Metadata,
43 Half,
45 Float,
47 Double,
49 Integer(u32),
51 Pointer(TypeId, u32),
54 Array(u64, TypeId),
56 Vector(u64, TypeId),
58 Struct {
60 name: Option<String>,
62 elements: Vec<TypeId>,
64 },
65 Opaque(Option<String>),
67 Function {
69 vararg: bool,
71 ret: TypeId,
73 params: Vec<TypeId>,
75 },
76}
77
78#[derive(Clone, Debug, PartialEq)]
80pub enum Constant {
81 Null,
83 Undef,
85 Integer(i64),
87 Float(u64),
89 Aggregate(Vec<ValueId>),
91 Data(Vec<u64>),
93 String(Vec<u8>),
95 Gep {
97 base: ValueId,
99 indices: Vec<ValueId>,
101 },
102 Cast {
104 op: CastOp,
106 value: ValueId,
108 },
109 Binary {
111 op: BinaryOp,
113 lhs: ValueId,
115 rhs: ValueId,
117 },
118}
119
120#[derive(Clone, Debug, PartialEq)]
122pub enum Value {
123 Function {
125 ty: TypeId,
127 declaration: bool,
129 attributes: Option<usize>,
131 },
132 Global {
134 ty: TypeId,
136 value_ty: TypeId,
138 init: Option<ValueId>,
140 constant: bool,
142 address_space: u32,
144 },
145 Constant(Constant),
147 Local,
149}
150
151#[derive(Clone, Debug, PartialEq)]
153pub enum Metadata {
154 String(Vec<u8>),
156 Value {
158 ty: TypeId,
160 value: ValueId,
162 },
163 Node(Vec<Option<MetadataId>>),
165}
166
167#[derive(Clone, Copy, Debug, PartialEq, Eq)]
169pub enum BinaryOp {
170 Add,
172 Sub,
174 Mul,
176 UDiv,
178 SDiv,
180 URem,
182 SRem,
184 Shl,
186 LShr,
188 AShr,
190 And,
192 Or,
194 Xor,
196}
197#[derive(Clone, Copy, Debug, PartialEq, Eq)]
199pub enum CastOp {
200 Trunc,
202 ZExt,
204 SExt,
206 FpToUi,
208 FpToSi,
210 UiToFp,
212 SiToFp,
214 FpTrunc,
216 FpExt,
218 PtrToInt,
220 IntToPtr,
222 BitCast,
224}
225
226#[derive(Clone, Debug, PartialEq)]
228pub enum Op {
229 Binary {
231 op: BinaryOp,
233 lhs: ValueId,
235 rhs: ValueId,
237 },
238 Cast {
240 op: CastOp,
242 value: ValueId,
244 },
245 Compare {
247 predicate: u64,
249 lhs: ValueId,
251 rhs: ValueId,
253 },
254 Select {
256 condition: ValueId,
258 then: ValueId,
260 otherwise: ValueId,
262 },
263 ExtractValue {
265 aggregate: ValueId,
267 indices: Vec<u64>,
269 },
270 InsertValue {
272 aggregate: ValueId,
274 value: ValueId,
276 indices: Vec<u64>,
278 },
279 ExtractElement {
281 vector: ValueId,
283 index: ValueId,
285 },
286 InsertElement {
288 vector: ValueId,
290 value: ValueId,
292 index: ValueId,
294 },
295 ShuffleVector {
297 first: ValueId,
299 second: ValueId,
301 mask: ValueId,
303 },
304 Call {
306 function: ValueId,
308 args: Vec<ValueId>,
310 },
311 Phi {
313 incoming: Vec<(ValueId, usize)>,
315 },
316 Return(Option<ValueId>),
318 Branch {
320 target: usize,
322 },
323 CondBranch {
325 condition: ValueId,
327 then: usize,
329 otherwise: usize,
331 },
332 Switch {
334 value: ValueId,
336 default: usize,
338 cases: Vec<(ValueId, usize)>,
340 },
341 Unreachable,
343 Alloca {
345 ty: TypeId,
347 },
348 Load {
350 pointer: ValueId,
352 },
353 Store {
355 pointer: ValueId,
357 value: ValueId,
359 },
360 Gep {
362 base: ValueId,
364 indices: Vec<ValueId>,
366 },
367 AtomicRmw {
370 pointer: ValueId,
372 value: ValueId,
374 op: u64,
376 },
377 CmpXchg {
379 pointer: ValueId,
381 compare: ValueId,
383 value: ValueId,
385 },
386 Fence,
388}
389
390impl Op {
391 pub fn operands(&self) -> Vec<ValueId> {
393 match self {
394 Op::Binary { lhs, rhs, .. } | Op::Compare { lhs, rhs, .. } => vec![*lhs, *rhs],
395 Op::Cast { value, .. } => vec![*value],
396 Op::Select {
397 condition,
398 then,
399 otherwise,
400 } => vec![*condition, *then, *otherwise],
401 Op::ExtractValue { aggregate, .. } => vec![*aggregate],
402 Op::InsertValue { aggregate, value, .. } => vec![*aggregate, *value],
403 Op::ExtractElement { vector, index } => vec![*vector, *index],
404 Op::InsertElement { vector, value, index } => vec![*vector, *value, *index],
405 Op::ShuffleVector { first, second, mask } => vec![*first, *second, *mask],
406 Op::Call { args, .. } => args.clone(),
407 Op::Phi { incoming } => incoming.iter().map(|(v, _)| *v).collect(),
408 Op::Return(value) => value.iter().copied().collect(),
409 Op::CondBranch { condition, .. } => vec![*condition],
410 Op::Switch { value, cases, .. } => std::iter::once(*value)
411 .chain(cases.iter().map(|(c, _)| *c))
412 .collect(),
413 Op::Load { pointer } => vec![*pointer],
414 Op::Store { pointer, value } | Op::AtomicRmw { pointer, value, .. } => vec![*pointer, *value],
415 Op::Gep { base, indices } => std::iter::once(*base).chain(indices.iter().copied()).collect(),
416 Op::CmpXchg {
417 pointer,
418 compare,
419 value,
420 } => vec![*pointer, *compare, *value],
421 Op::Branch { .. } | Op::Unreachable | Op::Alloca { .. } | Op::Fence => Vec::new(),
422 }
423 }
424
425 pub fn blocks(&self) -> Vec<usize> {
427 match self {
428 Op::Branch { target } => vec![*target],
429 Op::CondBranch { then, otherwise, .. } => vec![*then, *otherwise],
430 Op::Switch { default, cases, .. } => std::iter::once(*default)
431 .chain(cases.iter().map(|(_, b)| *b))
432 .collect(),
433 Op::Phi { incoming } => incoming.iter().map(|(_, b)| *b).collect(),
434 _ => Vec::new(),
435 }
436 }
437}
438
439#[derive(Clone, Debug, PartialEq)]
441pub struct Instruction {
442 pub op: Op,
444 pub result: Option<(ValueId, TypeId)>,
446 pub block: usize,
448 pub at: usize,
450 pub precise: bool,
456 pub attachments: Vec<Attachment>,
458}
459
460#[derive(Clone, Copy, Debug, PartialEq, Eq)]
464pub struct Attachment {
465 pub kind: u64,
467 pub node: MetadataId,
469}
470
471#[derive(Clone, Debug, PartialEq, Eq)]
473pub enum Attribute {
474 Enum(u64),
476 Integer(u64, u64),
478 String(String, String),
480}
481
482#[derive(Clone, Debug, PartialEq, Eq)]
484pub struct AttributeGroup {
485 pub id: u64,
487 pub slot: u64,
489 pub attributes: Vec<Attribute>,
491}
492
493pub const FUNCTION_SLOT: u64 = 0xFFFF_FFFF;
495
496pub fn attribute_name(kind: u64) -> Option<&'static str> {
500 Some(match kind {
501 9 => "noalias",
502 11 => "nocapture",
503 12 => "noduplicate",
504 17 => "noreturn",
505 18 => "nounwind",
506 20 => "readnone",
507 21 => "readonly",
508 39 => "nonnull",
509 _ => return None,
510 })
511}
512
513#[derive(Clone, Debug, PartialEq)]
515pub struct Function {
516 pub value: ValueId,
518 pub blocks: usize,
520 pub instructions: Vec<Instruction>,
522 pub first: ValueId,
525 pub locals: Vec<Value>,
527 pub local_types: Vec<TypeId>,
529 pub attachments: Vec<Attachment>,
531}
532
533#[derive(Clone, Debug, Default, PartialEq)]
535pub struct Module {
536 pub types: Vec<Type>,
538 pub values: Vec<Value>,
541 pub value_types: Vec<TypeId>,
543 pub names: Vec<(ValueId, String)>,
545 pub metadata: Vec<Metadata>,
547 pub metadata_at: Vec<usize>,
549 pub named_metadata: Vec<(String, Vec<MetadataId>)>,
551 pub named_metadata_at: Vec<usize>,
553 pub at: usize,
555 pub functions: Vec<Function>,
557 pub precise_kind: Option<u64>,
559 pub kinds: Vec<(u64, String)>,
561 pub attribute_groups: Vec<AttributeGroup>,
563 pub attribute_lists: Vec<Vec<u64>>,
566}
567
568fn op(r: &Record, i: usize) -> Result<u64> {
569 r.operands
570 .get(i)
571 .copied()
572 .ok_or_else(|| error(r.at, format!("record {} lacks operand {i}", r.code)))
573}
574fn text(ops: &[u64], at: usize) -> Result<Vec<u8>> {
575 ops.iter()
576 .map(|&c| u8::try_from(c).map_err(|_| error(at, "character above 255")))
577 .collect()
578}
579fn c_string(r: &Record, from: usize) -> Result<(String, usize)> {
581 let rest = r.operands.get(from..).unwrap_or_default();
582 let n = rest
583 .iter()
584 .position(|&c| c == 0)
585 .ok_or_else(|| error(r.at, "an attribute string without its terminator"))?;
586 let bytes = text(rest.get(..n).unwrap_or_default(), r.at)?;
587 Ok((
588 String::from_utf8_lossy(&bytes).into_owned(),
589 from.saturating_add(n).saturating_add(1),
590 ))
591}
592fn utf8(bytes: Vec<u8>, at: usize) -> Result<String> {
593 String::from_utf8(bytes).map_err(|_| error(at, "name is not UTF-8"))
594}
595fn signed_vbr(v: u64) -> i64 {
596 if v & 1 == 0 {
597 i64::try_from(v >> 1).unwrap_or(i64::MAX)
598 } else if v == 1 {
599 i64::MIN
600 } else {
601 i64::try_from(v >> 1).map_or(i64::MIN, i64::wrapping_neg)
602 }
603}
604
605impl Module {
606 fn ty(&self, id: u64, at: usize) -> Result<TypeId> {
607 let id = usize::try_from(id).map_err(|_| error(at, "type id"))?;
608 if id < self.types.len() {
609 Ok(id)
610 } else {
611 Err(error(at, format!("type {id} undefined")))
612 }
613 }
614 fn type_at(&self, id: TypeId, at: usize) -> Result<&Type> {
616 self.types
617 .get(id)
618 .ok_or_else(|| error(at, format!("type {id} of {} types", self.types.len())))
619 }
620 fn intern(&mut self, ty: Type) -> TypeId {
622 match self.types.iter().position(|x| *x == ty) {
623 Some(p) => p,
624 None => {
625 self.types.push(ty);
626 self.types.len().saturating_sub(1)
627 }
628 }
629 }
630 pub fn name(&self, value: ValueId) -> Option<&str> {
632 self.names
633 .iter()
634 .find(|(v, _)| *v == value)
635 .map(|(_, n)| n.as_str())
636 }
637 fn push(&mut self, value: Value, ty: TypeId, at: usize) -> Result<ValueId> {
638 if self.values.len() >= MAX_VALUES {
639 return Err(error(at, "too many values"));
640 }
641 self.values.push(value);
642 self.value_types.push(ty);
643 Ok(self.values.len().saturating_sub(1))
644 }
645
646 fn read_types(&mut self, block: &Block) -> Result<()> {
647 let mut struct_name: Option<String> = None;
648 for r in block.records() {
649 if self.types.len() >= MAX_TYPES {
650 return Err(error(r.at, "too many types"));
651 }
652 let t = match r.code {
653 1 => continue, 2 => Type::Void,
655 3 => Type::Float,
656 4 => Type::Double,
657 5 => Type::Label,
658 6 => Type::Opaque(struct_name.take()),
659 7 => Type::Integer(
660 u32::try_from(op(r, 0)?)
661 .ok()
662 .filter(|w| (1..=64).contains(w))
663 .ok_or_else(|| error(r.at, "integer width"))?,
664 ),
665 8 => Type::Pointer(
666 self.ty(op(r, 0)?, r.at)?,
667 u32::try_from(op(r, 1)?).map_err(|_| error(r.at, "pointer address space"))?,
668 ),
669 10 => Type::Half,
670 11 => Type::Array(op(r, 0)?, self.ty(op(r, 1)?, r.at)?),
671 12 => Type::Vector(op(r, 0)?, self.ty(op(r, 1)?, r.at)?),
672 16 => Type::Metadata,
673 18 | 20 => Type::Struct {
674 name: if r.code == 20 { struct_name.take() } else { None },
675 elements: r
676 .operands
677 .get(1..)
678 .unwrap_or_default()
679 .iter()
680 .map(|&t| self.ty(t, r.at))
681 .collect::<Result<_>>()?,
682 },
683 19 => {
684 struct_name = Some(utf8(text(&r.operands, r.at)?, r.at)?);
685 continue;
686 }
687 21 => Type::Function {
688 vararg: op(r, 0)? != 0,
689 ret: self.ty(op(r, 1)?, r.at)?,
690 params: r
691 .operands
692 .get(2..)
693 .unwrap_or_default()
694 .iter()
695 .map(|&t| self.ty(t, r.at))
696 .collect::<Result<_>>()?,
697 },
698 other => return Err(error(r.at, format!("type record {other}"))),
699 };
700 self.types.push(t);
701 }
702 Ok(())
703 }
704
705 fn read_constants(&mut self, block: &Block) -> Result<()> {
707 let mut ty: Option<TypeId> = None;
708 for r in block.records() {
709 let id = |v: u64| usize::try_from(v).map_err(|_| error(r.at, "value id"));
710 if r.code == 1 {
711 ty = Some(self.ty(op(r, 0)?, r.at)?);
712 continue;
713 }
714 let t = ty.ok_or_else(|| error(r.at, "constant before SETTYPE"))?;
715 let c = match r.code {
716 2 => Constant::Null,
717 3 => Constant::Undef,
718 4 => Constant::Integer(signed_vbr(op(r, 0)?)),
719 6 => Constant::Float(op(r, 0)?),
720 7 => Constant::Aggregate(
721 r.operands
722 .iter()
723 .map(|&v| usize::try_from(v).map_err(|_| error(r.at, "value id")))
724 .collect::<Result<_>>()?,
725 ),
726 8 | 9 => Constant::String(text(&r.operands, r.at)?),
727 22 => Constant::Data(r.operands.clone()),
728 12 | 20 => {
730 let ops = r
731 .operands
732 .get(usize::from(r.operands.len() % 2 == 1)..)
733 .unwrap_or_default();
734 let (pairs, rest) = ops.as_chunks::<2>();
735 let ([_, base], true) = (
736 pairs.first().unwrap_or(&[0, 0]),
737 rest.is_empty() && !pairs.is_empty(),
738 ) else {
739 return Err(error(r.at, "constant getelementptr operands"));
740 };
741 Constant::Gep {
742 base: id(*base)?,
743 indices: pairs
744 .iter()
745 .skip(1)
746 .map(|[_, index]| id(*index))
747 .collect::<Result<_>>()?,
748 }
749 }
750 10 => Constant::Binary {
752 op: binary(op(r, 0)?, r.at)?,
753 lhs: id(op(r, 1)?)?,
754 rhs: id(op(r, 2)?)?,
755 },
756 11 => Constant::Cast {
758 op: cast(op(r, 0)?, r.at)?,
759 value: id(op(r, 2)?)?,
760 },
761 other => {
762 return Err(error(
763 r.at,
764 format!("constant record {other} (constant expressions are not supported)"),
765 ));
766 }
767 };
768 self.push(Value::Constant(c), t, r.at)?;
769 }
770 Ok(())
771 }
772
773 fn read_metadata(&mut self, block: &Block) -> Result<()> {
774 let mut name: Option<String> = None;
775 let md = |v: u64, at: usize| usize::try_from(v).map_err(|_| error(at, "metadata id"));
776 for r in block.records() {
777 match r.code {
778 1 => {
779 self.metadata.push(Metadata::String(text(&r.operands, r.at)?));
780 self.metadata_at.push(r.at);
781 }
782 2 => {
783 self.metadata.push(Metadata::Value {
784 ty: self.ty(op(r, 0)?, r.at)?,
785 value: md(op(r, 1)?, r.at)?,
786 });
787 self.metadata_at.push(r.at);
788 }
789 3 | 5 => {
790 self.metadata.push(Metadata::Node(
791 r.operands
792 .iter()
793 .map(|&v| {
794 if v == 0 {
795 Ok(None)
796 } else {
797 md(v.saturating_sub(1), r.at).map(Some)
798 }
799 })
800 .collect::<Result<_>>()?,
801 ));
802 self.metadata_at.push(r.at);
803 }
804 4 => name = Some(utf8(text(&r.operands, r.at)?, r.at)?),
805 10 => {
806 let n = name
807 .take()
808 .ok_or_else(|| error(r.at, "named node without a name"))?;
809 let nodes = r.operands.iter().map(|&v| md(v, r.at)).collect::<Result<_>>()?;
810 self.named_metadata.push((n, nodes));
811 self.named_metadata_at.push(r.at);
812 }
813 6 => {
814 let id = op(r, 0)?;
816 let bytes = text(r.operands.get(1..).unwrap_or_default(), r.at)?;
817 if bytes == b"dx.precise" {
818 self.precise_kind = Some(id);
819 }
820 self.kinds
821 .push((id, String::from_utf8_lossy(&bytes).into_owned()));
822 }
823 other => return Err(error(r.at, format!("metadata record {other}"))),
824 }
825 }
826 Ok(())
827 }
828
829 fn read_attribute_groups(&mut self, block: &Block) -> Result<()> {
832 for r in block.records().filter(|r| r.code == 3) {
833 let mut attributes = Vec::new();
834 let mut i = 2;
835 while i < r.operands.len() {
836 match op(r, i)? {
837 0 => {
838 attributes.push(Attribute::Enum(op(r, i.saturating_add(1))?));
839 i = i.saturating_add(2);
840 }
841 1 => {
842 attributes.push(Attribute::Integer(
843 op(r, i.saturating_add(1))?,
844 op(r, i.saturating_add(2))?,
845 ));
846 i = i.saturating_add(3);
847 }
848 form @ (3 | 4) => {
849 let (key, next) = c_string(r, i.saturating_add(1))?;
850 let (value, next) = if form == 4 {
851 c_string(r, next)?
852 } else {
853 (String::new(), next)
854 };
855 attributes.push(Attribute::String(key, value));
856 i = next;
857 }
858 other => return Err(error(r.at, format!("attribute encoding {other}"))),
859 }
860 }
861 self.attribute_groups.push(AttributeGroup {
862 id: op(r, 0)?,
863 slot: op(r, 1)?,
864 attributes,
865 });
866 }
867 Ok(())
868 }
869
870 fn read_attribute_lists(&mut self, block: &Block) {
872 for r in block.records().filter(|r| r.code == 2) {
873 self.attribute_lists.push(r.operands.clone());
874 }
875 }
876
877 pub fn kind_name(&self, kind: u64) -> Option<&str> {
879 self.kinds
880 .iter()
881 .find(|(k, _)| *k == kind)
882 .map(|(_, n)| n.as_str())
883 }
884
885 pub fn attachment(&self, attachments: &[Attachment], name: &str) -> Option<MetadataId> {
887 attachments
888 .iter()
889 .find(|a| self.kind_name(a.kind) == Some(name))
890 .map(|a| a.node)
891 }
892
893 pub fn function_attributes(&self, function: ValueId) -> Vec<&Attribute> {
896 let Some(Value::Function {
897 attributes: Some(list),
898 ..
899 }) = self.values.get(function)
900 else {
901 return Vec::new();
902 };
903 let Some(groups) = self.attribute_lists.get(*list) else {
904 return Vec::new();
905 };
906 groups
907 .iter()
908 .filter_map(|id| {
909 self.attribute_groups
910 .iter()
911 .find(|g| g.id == *id && g.slot == FUNCTION_SLOT)
912 })
913 .flat_map(|g| g.attributes.iter())
914 .collect()
915 }
916
917 pub fn string_attribute(&self, function: ValueId, key: &str) -> Option<&str> {
919 self.function_attributes(function)
920 .into_iter()
921 .find_map(|a| match a {
922 Attribute::String(k, v) if k == key => Some(v.as_str()),
923 _ => None,
924 })
925 }
926
927 fn read_symbols(&mut self, block: &Block, base: usize) -> Result<()> {
928 for r in block.records() {
929 match r.code {
930 1 | 3 => {
931 let value = usize::try_from(op(r, 0)?).map_err(|_| error(r.at, "value id"))?;
932 let skip = if r.code == 3 { 2 } else { 1 };
933 let n = utf8(text(r.operands.get(skip..).unwrap_or_default(), r.at)?, r.at)?;
934 let id = base.checked_add(value).ok_or_else(|| error(r.at, "value id"))?;
935 self.names.push((id, n));
936 }
937 2 => {} other => return Err(error(r.at, format!("symbol record {other}"))),
939 }
940 }
941 Ok(())
942 }
943}
944
945struct Body<'m> {
947 m: &'m mut Module,
948 block: usize,
949 blocks: usize,
950}
951impl Body<'_> {
952 fn next(&self) -> usize {
953 self.m.values.len()
954 }
955 fn value_type(&self, r: &Record, i: &mut usize) -> Result<(ValueId, TypeId)> {
958 let id = self.absolute(op(r, *i)?, r.at)?;
959 *i = i.saturating_add(1);
960 if id < self.next() {
961 let t = self
962 .m
963 .value_types
964 .get(id)
965 .copied()
966 .ok_or_else(|| error(r.at, format!("value {id} has no type")))?;
967 Ok((id, t))
968 } else {
969 let t = self.m.ty(op(r, *i)?, r.at)?;
970 *i = i.saturating_add(1);
971 Ok((id, t))
972 }
973 }
974 fn value(&self, r: &Record, i: &mut usize) -> Result<ValueId> {
976 let id = self.absolute(op(r, *i)?, r.at)?;
977 *i = i.saturating_add(1);
978 Ok(id)
979 }
980 fn absolute(&self, relative: u64, at: usize) -> Result<ValueId> {
983 let relative = u32::try_from(relative)
984 .map_err(|_| error(at, format!("relative value id {relative} wider than 32 bits")))?;
985 let next = u32::try_from(self.next()).map_err(|_| error(at, "too many values"))?;
986 Ok(next.wrapping_sub(relative) as usize)
987 }
988 fn pointer_to(&mut self, t: TypeId) -> TypeId {
990 self.m.intern(Type::Pointer(t, 0))
991 }
992 fn constant_index(&self, v: ValueId) -> Option<usize> {
994 match self.m.values.get(v) {
995 Some(Value::Constant(Constant::Integer(i))) => usize::try_from(*i).ok(),
996 Some(Value::Constant(Constant::Null)) => Some(0),
997 _ => None,
998 }
999 }
1000 fn result(&mut self, ty: TypeId, at: usize) -> Result<Option<(ValueId, TypeId)>> {
1001 if *self.m.type_at(ty, at)? == Type::Void {
1002 return Ok(None);
1003 }
1004 Ok(Some((self.m.push(Value::Local, ty, at)?, ty)))
1005 }
1006}
1007
1008fn binary(code: u64, at: usize) -> Result<BinaryOp> {
1009 Ok(match code {
1010 0 => BinaryOp::Add,
1011 1 => BinaryOp::Sub,
1012 2 => BinaryOp::Mul,
1013 3 => BinaryOp::UDiv,
1014 4 => BinaryOp::SDiv,
1015 5 => BinaryOp::URem,
1016 6 => BinaryOp::SRem,
1017 7 => BinaryOp::Shl,
1018 8 => BinaryOp::LShr,
1019 9 => BinaryOp::AShr,
1020 10 => BinaryOp::And,
1021 11 => BinaryOp::Or,
1022 12 => BinaryOp::Xor,
1023 other => return Err(error(at, format!("binary opcode {other}"))),
1024 })
1025}
1026fn cast(code: u64, at: usize) -> Result<CastOp> {
1027 Ok(match code {
1028 0 => CastOp::Trunc,
1029 1 => CastOp::ZExt,
1030 2 => CastOp::SExt,
1031 3 => CastOp::FpToUi,
1032 4 => CastOp::FpToSi,
1033 5 => CastOp::UiToFp,
1034 6 => CastOp::SiToFp,
1035 7 => CastOp::FpTrunc,
1036 8 => CastOp::FpExt,
1037 9 => CastOp::PtrToInt,
1038 10 => CastOp::IntToPtr,
1039 11 => CastOp::BitCast,
1040 other => return Err(error(at, format!("cast opcode {other}"))),
1041 })
1042}
1043fn refused(code: u64) -> &'static str {
1045 match code {
1046 4 | 30 => "getelementptr (old form)",
1047 13 => "invoke",
1048 41 => "load (atomic)",
1049 23 => "va_arg",
1050 24 | 42 | 45 => "store (atomic)",
1051 31 => "indirectbr",
1052 37 => "cmpxchg (old form)",
1053 59 => "atomicrmw (new form)",
1054 39 => "resume",
1055 40 | 47 => "landingpad",
1056 _ => "unknown instruction record",
1057 }
1058}
1059
1060fn read_attachments(
1064 precise: Option<u64>,
1065 block: &Block,
1066 instructions: &mut [Instruction],
1067 function: &mut Vec<Attachment>,
1068) -> Result<()> {
1069 for r in block.records().filter(|r| r.code == 11) {
1070 let per_instruction = r.operands.len() % 2 == 1;
1071 let mut attachments = Vec::new();
1072 let (pairs, _) = r
1073 .operands
1074 .get(usize::from(per_instruction)..)
1075 .unwrap_or_default()
1076 .as_chunks::<2>();
1077 for &[kind, node] in pairs {
1078 attachments.push(Attachment {
1079 kind,
1080 node: usize::try_from(node).map_err(|_| error(r.at, "attachment node"))?,
1081 });
1082 }
1083 if !per_instruction {
1084 function.extend(attachments);
1085 continue;
1086 }
1087 let at = usize::try_from(op(r, 0)?).map_err(|_| error(r.at, "attachment instruction"))?;
1088 let instruction = instructions.get_mut(at).ok_or_else(|| {
1089 error(
1090 r.at,
1091 format!("an attachment names instruction {at} of a shorter body"),
1092 )
1093 })?;
1094 if precise.is_some_and(|kind| attachments.iter().any(|a| a.kind == kind)) {
1095 instruction.precise = true;
1096 }
1097 instruction.attachments.extend(attachments);
1098 }
1099 Ok(())
1100}
1101
1102impl Module {
1103 fn read_function(&mut self, block: &Block, value: ValueId) -> Result<Function> {
1104 let fty = match self.value_types.get(value).and_then(|&t| self.types.get(t)) {
1105 Some(Type::Pointer(t, _)) => *t,
1106 _ => return Err(error(block.at, "function value is not a function pointer")),
1107 };
1108 let params = match self.type_at(fty, block.at)? {
1109 Type::Function { params, .. } => params.clone(),
1110 _ => return Err(error(block.at, "function type")),
1111 };
1112 let base = self.values.len();
1113 for p in params {
1114 self.push(Value::Local, p, block.at)?;
1115 }
1116 let mut body = Body {
1117 m: self,
1118 block: 0,
1119 blocks: 0,
1120 };
1121 let mut instructions = Vec::new();
1122 let mut function_attachments = Vec::new();
1123 for e in &block.elements {
1124 let r = match e {
1125 crate::bitstream::Element::Block(b) => {
1126 match b.id {
1127 CONSTANTS => body.m.read_constants(b)?,
1128 VALUE_SYMTAB => body.m.read_symbols(b, 0)?,
1129 METADATA_ATTACHMENT => read_attachments(
1130 body.m.precise_kind,
1131 b,
1132 &mut instructions,
1133 &mut function_attachments,
1134 )?,
1135 METADATA | USELIST => {}
1136 other => return Err(error(b.at, format!("block {other} in a function"))),
1137 }
1138 continue;
1139 }
1140 crate::bitstream::Element::Record(r) => r,
1141 };
1142 let mut i = 0;
1143 let (op, ty): (Op, Option<TypeId>) = match r.code {
1144 1 => {
1145 body.blocks = usize::try_from(op(r, 0)?)
1146 .ok()
1147 .filter(|&n| n > 0 && n <= 1 << 16)
1148 .ok_or_else(|| error(r.at, "basic block count"))?;
1149 continue;
1150 }
1151 33 | 35 => continue, 2 => {
1153 let (lhs, t) = body.value_type(r, &mut i)?;
1154 let rhs = body.value(r, &mut i)?;
1155 let o = binary(op(r, i)?, r.at)?;
1156 (Op::Binary { op: o, lhs, rhs }, Some(t))
1157 }
1158 3 => {
1159 let value = body.value(r, &mut i)?;
1160 let to = body.m.ty(op(r, i)?, r.at)?;
1161 let o = cast(op(r, i.saturating_add(1))?, r.at)?;
1162 (Op::Cast { op: o, value }, Some(to))
1163 }
1164 9 | 28 => {
1165 let (lhs, t) = body.value_type(r, &mut i)?;
1166 let rhs = body.value(r, &mut i)?;
1167 let predicate = op(r, i)?;
1168 let bool_ty = match body.m.type_at(t, r.at)? {
1169 Type::Vector(..) => {
1170 return Err(error(r.at, "vector comparison"));
1171 }
1172 _ => body
1173 .m
1174 .types
1175 .iter()
1176 .position(|x| *x == Type::Integer(1))
1177 .ok_or_else(|| error(r.at, "no i1 type for a comparison"))?,
1178 };
1179 (Op::Compare { predicate, lhs, rhs }, Some(bool_ty))
1180 }
1181 29 => {
1182 let (then, t) = body.value_type(r, &mut i)?;
1183 let otherwise = body.value(r, &mut i)?;
1184 let condition = body.value(r, &mut i)?;
1185 (
1186 Op::Select {
1187 condition,
1188 then,
1189 otherwise,
1190 },
1191 Some(t),
1192 )
1193 }
1194 26 => {
1195 let (aggregate, mut t) = body.value_type(r, &mut i)?;
1196 let indices = r.operands.get(i..).unwrap_or_default().to_vec();
1197 for &k in &indices {
1198 t = match body.m.type_at(t, r.at)? {
1199 Type::Struct { elements, .. } => *usize::try_from(k)
1200 .ok()
1201 .and_then(|k| elements.get(k))
1202 .ok_or_else(|| error(r.at, "extractvalue index"))?,
1203 Type::Array(n, e) if k < *n => *e,
1204 _ => return Err(error(r.at, "extractvalue index")),
1205 };
1206 }
1207 (Op::ExtractValue { aggregate, indices }, Some(t))
1208 }
1209 6 => {
1210 let (vector, t) = body.value_type(r, &mut i)?;
1211 let (index, _) = body.value_type(r, &mut i)?;
1212 let Type::Vector(_, element) = *body.m.type_at(t, r.at)? else {
1213 return Err(error(r.at, "extractelement of something that is not a vector"));
1214 };
1215 (Op::ExtractElement { vector, index }, Some(element))
1216 }
1217 7 => {
1218 let (vector, t) = body.value_type(r, &mut i)?;
1219 let value = body.value(r, &mut i)?;
1220 let (index, _) = body.value_type(r, &mut i)?;
1221 (Op::InsertElement { vector, value, index }, Some(t))
1222 }
1223 8 => {
1224 let (first, t) = body.value_type(r, &mut i)?;
1225 let second = body.value(r, &mut i)?;
1226 let (mask, mask_ty) = body.value_type(r, &mut i)?;
1227 let (Type::Vector(_, element), Type::Vector(lanes, _)) = (
1228 body.m.type_at(t, r.at)?.clone(),
1229 body.m.type_at(mask_ty, r.at)?.clone(),
1230 ) else {
1231 return Err(error(r.at, "shufflevector of something that is not a vector"));
1232 };
1233 let result = body
1234 .m
1235 .types
1236 .iter()
1237 .position(|x| *x == Type::Vector(lanes, element))
1238 .ok_or_else(|| error(r.at, "no type for the shuffled vector"))?;
1239 (Op::ShuffleVector { first, second, mask }, Some(result))
1240 }
1241 27 => {
1242 let (aggregate, t) = body.value_type(r, &mut i)?;
1243 let value = body.value(r, &mut i)?;
1244 let indices = r.operands.get(i..).unwrap_or_default().to_vec();
1245 (
1246 Op::InsertValue {
1247 aggregate,
1248 value,
1249 indices,
1250 },
1251 Some(t),
1252 )
1253 }
1254 34 => {
1255 i = 1; let cc = op(r, i)?;
1257 i = i.saturating_add(1);
1258 if cc & (1 << 17) != 0 {
1259 i = i.saturating_add(1); }
1261 let explicit = if cc & (1 << 15) != 0 {
1262 let t = body.m.ty(op(r, i)?, r.at)?;
1263 i = i.saturating_add(1);
1264 Some(t)
1265 } else {
1266 None
1267 };
1268 let (function, callee_ty) = body.value_type(r, &mut i)?;
1269 let fty = match (explicit, body.m.type_at(callee_ty, r.at)?) {
1270 (Some(t), _) => t,
1271 (None, Type::Pointer(t, _)) => *t,
1272 _ => return Err(error(r.at, "callee is not a function pointer")),
1273 };
1274 let (ret, params, vararg) = match body.m.type_at(fty, r.at)? {
1275 Type::Function { ret, params, vararg } => (*ret, params.clone(), *vararg),
1276 _ => return Err(error(r.at, "call through a non-function type")),
1277 };
1278 if vararg {
1279 return Err(error(r.at, "vararg call"));
1280 }
1281 let mut args = Vec::with_capacity(params.len());
1282 for p in ¶ms {
1283 let a = body.value(r, &mut i)?;
1285 if a < body.next() && body.m.value_types.get(a) != Some(p) {
1286 return Err(error(r.at, "call argument type"));
1287 }
1288 args.push(a);
1289 }
1290 if i != r.operands.len() {
1291 return Err(error(r.at, "call operands left over"));
1292 }
1293 (Op::Call { function, args }, Some(ret))
1294 }
1295 16 => {
1296 let t = body.m.ty(op(r, 0)?, r.at)?;
1297 let pairs = r.operands.get(1..).unwrap_or_default();
1298 if pairs.is_empty() || pairs.len() % 2 != 0 {
1299 return Err(error(r.at, "phi operands"));
1300 }
1301 let next = i64::try_from(body.next()).map_err(|_| error(r.at, "too many values"))?;
1302 let mut incoming = Vec::with_capacity(pairs.len() / 2);
1303 for pair in pairs.as_chunks::<2>().0 {
1304 let id = next
1306 .checked_sub(signed_vbr(pair[0]))
1307 .and_then(|v| usize::try_from(v).ok())
1308 .ok_or_else(|| error(r.at, "phi value"))?;
1309 let block = usize::try_from(pair[1])
1310 .ok()
1311 .filter(|&b| b < body.blocks)
1312 .ok_or_else(|| error(r.at, "phi block"))?;
1313 incoming.push((id, block));
1314 }
1315 (Op::Phi { incoming }, Some(t))
1316 }
1317 10 => {
1318 if r.operands.is_empty() {
1319 (Op::Return(None), None)
1320 } else {
1321 (Op::Return(Some(body.value(r, &mut i)?)), None)
1322 }
1323 }
1324 11 => {
1325 let target = |v: u64| -> Result<usize> {
1326 usize::try_from(v)
1327 .ok()
1328 .filter(|&b| b < body.blocks)
1329 .ok_or_else(|| error(r.at, "branch target"))
1330 };
1331 if r.operands.len() == 1 {
1332 (
1333 Op::Branch {
1334 target: target(op(r, 0)?)?,
1335 },
1336 None,
1337 )
1338 } else {
1339 let then = target(op(r, 0)?)?;
1340 let otherwise = target(op(r, 1)?)?;
1341 i = 2;
1342 let condition = body.value(r, &mut i)?;
1343 (
1344 Op::CondBranch {
1345 condition,
1346 then,
1347 otherwise,
1348 },
1349 None,
1350 )
1351 }
1352 }
1353 12 => {
1354 let block = |v: u64| -> Result<usize> {
1356 usize::try_from(v)
1357 .ok()
1358 .filter(|&b| b < body.blocks)
1359 .ok_or_else(|| error(r.at, "switch target"))
1360 };
1361 i = 1;
1362 let value = body.value(r, &mut i)?;
1363 let default = block(op(r, i)?)?;
1364 let pairs = r.operands.get(i.saturating_add(1)..).unwrap_or_default();
1365 if pairs.len() % 2 != 0 {
1366 return Err(error(r.at, "switch cases"));
1367 }
1368 let cases = pairs
1369 .as_chunks::<2>()
1370 .0
1371 .iter()
1372 .map(|p| {
1373 Ok((
1374 usize::try_from(p[0]).map_err(|_| error(r.at, "case value"))?,
1375 block(p[1])?,
1376 ))
1377 })
1378 .collect::<Result<Vec<_>>>()?;
1379 (
1380 Op::Switch {
1381 value,
1382 default,
1383 cases,
1384 },
1385 None,
1386 )
1387 }
1388 15 => (Op::Unreachable, None),
1389 19 => {
1390 let ty = body.m.ty(op(r, 0)?, r.at)?;
1392 (Op::Alloca { ty }, Some(body.pointer_to(ty)))
1393 }
1394 20 => {
1395 let (pointer, pt) = body.value_type(r, &mut i)?;
1396 let _ = pt;
1397 let ty = body.m.ty(op(r, i)?, r.at)?;
1398 (Op::Load { pointer }, Some(ty))
1399 }
1400 44 => {
1401 let (pointer, _) = body.value_type(r, &mut i)?;
1402 let (value, _) = body.value_type(r, &mut i)?;
1403 (Op::Store { pointer, value }, None)
1404 }
1405 38 => {
1407 let (pointer, _) = body.value_type(r, &mut i)?;
1408 let value = body.value(r, &mut i)?;
1409 let op = op(r, i)?;
1410 let ty = body.m.value_types.get(value).copied();
1411 let ty = match ty {
1412 Some(t) if value < body.next() => t,
1413 _ => return Err(error(r.at, "an atomicrmw of a value defined later")),
1414 };
1415 (Op::AtomicRmw { pointer, value, op }, Some(ty))
1416 }
1417 46 => {
1420 let (pointer, _) = body.value_type(r, &mut i)?;
1421 let (compare, ty) = body.value_type(r, &mut i)?;
1422 let value = body.value(r, &mut i)?;
1423 let flag = body
1424 .m
1425 .types
1426 .iter()
1427 .position(|t| *t == Type::Integer(1))
1428 .ok_or_else(|| error(r.at, "a cmpxchg without a boolean type"))?;
1429 let pair = Type::Struct {
1430 name: None,
1431 elements: vec![ty, flag],
1432 };
1433 let result = body.m.intern(pair);
1434 (
1435 Op::CmpXchg {
1436 pointer,
1437 compare,
1438 value,
1439 },
1440 Some(result),
1441 )
1442 }
1443 36 => (Op::Fence, None),
1444 43 => {
1445 i = 2;
1447 let source = body.m.ty(op(r, 1)?, r.at)?;
1448 let (base, _) = body.value_type(r, &mut i)?;
1449 let mut indices = Vec::new();
1450 while i < r.operands.len() {
1451 indices.push(body.value_type(r, &mut i)?.0);
1452 }
1453 let mut t = source;
1456 for &index in indices.iter().skip(1) {
1457 t = match body.m.type_at(t, r.at)?.clone() {
1458 Type::Array(_, e) | Type::Vector(_, e) => e,
1459 Type::Struct { elements, .. } => {
1460 let k = match body.constant_index(index) {
1461 Some(k) => k,
1462 None => {
1463 return Err(error(r.at, "a structure index that is not constant"));
1464 }
1465 };
1466 *elements
1467 .get(k)
1468 .ok_or_else(|| error(r.at, "getelementptr structure index"))?
1469 }
1470 _ => return Err(error(r.at, "getelementptr into a scalar")),
1471 };
1472 }
1473 (Op::Gep { base, indices }, Some(body.pointer_to(t)))
1474 }
1475 other => {
1476 return Err(error(
1477 r.at,
1478 format!("instruction {} (record {other}) is not supported", refused(other)),
1479 ));
1480 }
1481 };
1482 let result = match ty {
1483 Some(t) => body.result(t, r.at)?,
1484 None => None,
1485 };
1486 let terminator = matches!(
1487 op,
1488 Op::Return(_)
1489 | Op::Branch { .. }
1490 | Op::CondBranch { .. }
1491 | Op::Switch { .. }
1492 | Op::Unreachable
1493 );
1494 instructions.push(Instruction {
1495 op,
1496 result,
1497 block: body.block,
1498 at: r.at,
1499 precise: false,
1500 attachments: Vec::new(),
1501 });
1502 if terminator {
1503 body.block = body.block.saturating_add(1);
1504 }
1505 }
1506 if body.block != body.blocks {
1507 return Err(error(block.at, "basic blocks without terminators"));
1508 }
1509 let end = body.next();
1510 let blocks = body.blocks;
1511 for inst in &instructions {
1514 if inst.block >= blocks {
1515 return Err(error(inst.at, "an instruction after the last terminator"));
1516 }
1517 if let Some(v) = inst.op.operands().into_iter().find(|v| *v >= end) {
1518 return Err(error(inst.at, format!("value {v} of {end} values")));
1519 }
1520 if let Some(b) = inst.op.blocks().into_iter().find(|b| *b >= blocks) {
1521 return Err(error(inst.at, format!("basic block {b} of {blocks}")));
1522 }
1523 if let Op::Call { function, args } = &inst.op {
1524 if *function >= end {
1525 return Err(error(inst.at, format!("callee {function} of {end} values")));
1526 }
1527 if let Some(Value::Function { ty, .. }) = self.values.get(*function)
1528 && let Some(Type::Function {
1529 vararg: false,
1530 params,
1531 ..
1532 }) = self.types.get(*ty)
1533 && params.len() != args.len()
1534 {
1535 return Err(error(
1536 inst.at,
1537 format!(
1538 "a call of {} arguments to a function of {} parameters",
1539 args.len(),
1540 params.len()
1541 ),
1542 ));
1543 }
1544 }
1545 }
1546 let locals = self.values.split_off(base);
1547 let local_types = self.value_types.split_off(base);
1548 Ok(Function {
1549 value,
1550 blocks,
1551 instructions,
1552 first: base,
1553 locals,
1554 local_types,
1555 attachments: function_attachments,
1556 })
1557 }
1558
1559 pub fn read(top: &[Block]) -> Result<Self> {
1561 let module = match top {
1562 [m] if m.id == MODULE => m,
1563 _ => return Err(error(0, "bitcode is not one module block")),
1564 };
1565 let mut m = Module {
1566 at: module.at,
1567 ..Module::default()
1568 };
1569 let mut bodies: Vec<ValueId> = Vec::new();
1570 let mut version = None;
1571 for e in &module.elements {
1572 match e {
1573 crate::bitstream::Element::Record(r) => match r.code {
1574 1 => version = Some(op(r, 0)?),
1575 2..=6 | 11 | 13 | 16 => {} 7 => {
1577 let t = m.ty(op(r, 0)?, r.at)?;
1580 let flags = op(r, 1)?;
1581 let address_space =
1582 u32::try_from(flags >> 2).map_err(|_| error(r.at, "address space"))?;
1583 let (ty, value_ty) = if flags & 2 != 0 {
1584 let pointer = m.intern(Type::Pointer(t, address_space));
1585 (pointer, t)
1586 } else {
1587 match m.type_at(t, r.at)? {
1588 Type::Pointer(inner, _) => (t, *inner),
1589 _ => return Err(error(r.at, "a global whose type is not a pointer")),
1590 }
1591 };
1592 let init = match op(r, 2)? {
1593 0 => None,
1594 n => Some(
1595 usize::try_from(n.saturating_sub(1))
1596 .map_err(|_| error(r.at, "initial value id"))?,
1597 ),
1598 };
1599 m.push(
1600 Value::Global {
1601 ty,
1602 value_ty,
1603 init,
1604 constant: flags & 1 != 0,
1605 address_space,
1606 },
1607 ty,
1608 r.at,
1609 )?;
1610 }
1611 8 => {
1612 let t = m.ty(op(r, 0)?, r.at)?;
1614 let pointer = m.intern(Type::Pointer(t, 0));
1615 let declaration = op(r, 2)? != 0;
1616 let attributes = r
1618 .operands
1619 .get(4)
1620 .and_then(|&n| usize::try_from(n).ok())
1621 .and_then(|n| n.checked_sub(1));
1622 let v = m.push(
1623 Value::Function {
1624 ty: t,
1625 declaration,
1626 attributes,
1627 },
1628 pointer,
1629 r.at,
1630 )?;
1631 if !declaration {
1632 bodies.push(v);
1633 }
1634 }
1635 other => return Err(error(r.at, format!("module record {other}"))),
1636 },
1637 crate::bitstream::Element::Block(b) => match b.id {
1638 BLOCKINFO | USELIST => {}
1639 PARAMATTR_GROUP => m.read_attribute_groups(b)?,
1640 PARAMATTR => m.read_attribute_lists(b),
1641 TYPES => m.read_types(b)?,
1642 CONSTANTS => m.read_constants(b)?,
1643 METADATA => m.read_metadata(b)?,
1644 VALUE_SYMTAB => m.read_symbols(b, 0)?,
1645 FUNCTION => {
1646 if version != Some(1) {
1647 return Err(error(b.at, "only relative value ids (module version 1)"));
1648 }
1649 if bodies.is_empty() {
1651 return Err(error(b.at, "function body without a definition"));
1652 }
1653 let value = bodies.remove(0);
1654 let f = m.read_function(b, value)?;
1656 m.functions.push(f);
1657 }
1658 other => return Err(error(b.at, format!("module block {other}"))),
1659 },
1660 }
1661 }
1662 if !bodies.is_empty() {
1663 return Err(error(module.at, "a defined function has no body"));
1664 }
1665 Ok(m)
1666 }
1667}