Skip to main content

dxil_reader/
module.rs

1//! LLVM 3.7 IR as DXIL stores it, read from the bitstream tree: the type table, module values (globals, functions,
2//! constants), metadata, value names and function bodies. Only what DXIL programs use is decoded; any other record in a
3//! function body is refused by name. The blocks of a function body that say nothing a reader of the program's behaviour needs (its metadata and its
4//! use-list order) are the only things skipped. The metadata attached to an instruction or a function is kept as the
5//! pairs the file stores ([`Instruction::attachments`], [`Function::attachments`], with the kind names in
6//! [`Module::kinds`]), `dx.precise` also as [`Instruction::precise`]; the attribute groups and lists are kept as stored
7//! ([`Module::attribute_groups`], [`Module::attribute_lists`]) and each function value names its list.
8use 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
23/// Values a module may hold (globals, constants and function-body values together).
24const MAX_VALUES: usize = 1 << 22;
25const MAX_TYPES: usize = 1 << 16;
26
27/// An index into [`Module::types`].
28pub type TypeId = usize;
29/// An index into the values: the module's [`Module::values`], then a function body's own [`Function::locals`].
30pub type ValueId = usize;
31/// An index into [`Module::metadata`].
32pub type MetadataId = usize;
33
34/// A type of the module's type table.
35#[derive(Clone, Debug, PartialEq, Eq)]
36pub enum Type {
37    /// `void`.
38    Void,
39    /// `label`, the type of a basic block.
40    Label,
41    /// `metadata`.
42    Metadata,
43    /// `half`.
44    Half,
45    /// `float`.
46    Float,
47    /// `double`.
48    Double,
49    /// An integer of this many bits (1 to 64).
50    Integer(u32),
51    /// A pointer to the type, in this LLVM address space (the `TYPE_CODE_POINTER` record's second operand). Pointers to
52    /// one type in two spaces are two types.
53    Pointer(TypeId, u32),
54    /// An array of this many elements of the type.
55    Array(u64, TypeId),
56    /// A vector of this many lanes of the type.
57    Vector(u64, TypeId),
58    /// A structure.
59    Struct {
60        /// Its name, where it has one.
61        name: Option<String>,
62        /// The types of its fields, in order.
63        elements: Vec<TypeId>,
64        /// Its fields are laid out without padding (`<{ ... }>`).
65        packed: bool,
66        /// A literal structure (`TYPE_CODE_STRUCT_ANON`), which is its body: two literal structures of the same fields
67        /// are one type. An identified one (`TYPE_CODE_STRUCT_NAMED`) is a type of its own, named or numbered.
68        literal: bool,
69    },
70    /// A named structure without a body.
71    Opaque(Option<String>),
72    /// A function type.
73    Function {
74        /// Whether it takes a variable argument list.
75        vararg: bool,
76        /// The return type.
77        ret: TypeId,
78        /// The parameter types.
79        params: Vec<TypeId>,
80    },
81}
82
83/// A module-level constant.
84#[derive(Clone, Debug, PartialEq)]
85pub enum Constant {
86    /// The null value of the constant's type (zero).
87    Null,
88    /// An undefined value.
89    Undef,
90    /// An integer's bits, sign-extended from its width.
91    Integer(i64),
92    /// A float's bits (half, float or double by its type).
93    Float(u64),
94    /// An array, structure or vector of other constants (value ids).
95    Aggregate(Vec<ValueId>),
96    /// A constant array or vector of numbers, as stored (the bits of each element).
97    Data(Vec<u64>),
98    /// An array of `i8` given as text: its bytes, with the terminating zero a `CST_CODE_CSTRING` record implies.
99    String(Vec<u8>),
100    /// A constant `getelementptr`: the base (a global) and its indices (module constants).
101    Gep {
102        /// The base global.
103        base: ValueId,
104        /// The index constants.
105        indices: Vec<ValueId>,
106        /// The type the first index steps over: the base's pointee.
107        source: TypeId,
108        /// `inbounds` (`CST_CODE_CE_INBOUNDS_GEP`).
109        inbounds: bool,
110    },
111    /// A constant cast of a module value (to the type of the constant).
112    Cast {
113        /// The cast.
114        op: CastOp,
115        /// The value cast.
116        value: ValueId,
117    },
118    /// A constant binary operation on module values.
119    Binary {
120        /// The operation.
121        op: BinaryOp,
122        /// The left operand.
123        lhs: ValueId,
124        /// The right operand.
125        rhs: ValueId,
126        /// The record's flags, as [`Instruction::flags`].
127        flags: u64,
128    },
129    /// A constant comparison of module values, by its LLVM predicate (as [`Op::Compare`]).
130    Compare {
131        /// The predicate.
132        predicate: u64,
133        /// The left operand.
134        lhs: ValueId,
135        /// The right operand.
136        rhs: ValueId,
137    },
138}
139
140/// How a global value links (LLVM's `LinkageTypes`, decoded from the bitcode's linkage codes).
141#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
142pub enum Linkage {
143    /// Visible to other modules (codes 0, 5, 6 and 15).
144    #[default]
145    External,
146    /// Appended to the same-named array of other modules (2).
147    Appending,
148    /// Local to the module (3).
149    Internal,
150    /// Weak, kept even where unreferenced (16).
151    WeakAny,
152    /// Weak, every definition equivalent (17).
153    WeakOdr,
154    /// Merged with other definitions, dropped where unreferenced (18).
155    LinkOnceAny,
156    /// As `LinkOnceAny`, every definition equivalent (19).
157    LinkOnceOdr,
158    /// A weak reference to an external symbol (7).
159    ExternWeak,
160    /// A tentative definition (8).
161    Common,
162    /// Local to the module and left out of its symbol table (9, 13 and 14).
163    Private,
164    /// Defined elsewhere, given here for optimisation (12).
165    AvailableExternally,
166}
167
168/// What the module states of a function or a global variable beyond its type: how it links, and the other properties
169/// of its `MODULE_CODE_FUNCTION` or `MODULE_CODE_GLOBALVAR` record.
170#[derive(Clone, Debug, Default, PartialEq, Eq)]
171pub struct GlobalProperties {
172    /// How it links.
173    pub linkage: Linkage,
174    /// Its visibility: 0 default, 1 hidden, 2 protected.
175    pub visibility: u8,
176    /// Its DLL storage class: 0 default, 1 `dllimport`, 2 `dllexport`.
177    pub dll_storage: u8,
178    /// Its address is not significant (`unnamed_addr`).
179    pub unnamed_addr: bool,
180    /// The section it is placed in, where the record names one.
181    pub section: Option<String>,
182    /// Its alignment in bytes; 0 where it states none.
183    pub alignment: u64,
184}
185
186/// A value the module numbers.
187#[derive(Clone, Debug, PartialEq)]
188pub enum Value {
189    /// A function, defined or declared.
190    Function {
191        /// Its function type.
192        ty: TypeId,
193        /// Whether it is only declared (it has no body).
194        declaration: bool,
195        /// The attribute list it names (an index into [`Module::attribute_lists`]), where it names one.
196        attributes: Option<usize>,
197        /// Its linkage and the other properties of its record.
198        properties: GlobalProperties,
199        /// Its calling convention (LLVM's `CallingConv::ID`; 0 is C's).
200        calling_conv: u64,
201        /// The garbage collector it names, where it names one.
202        gc: Option<String>,
203    },
204    /// A global variable.
205    Global {
206        /// The global's type: a pointer to `value_ty`.
207        ty: TypeId,
208        /// The type of the value it holds.
209        value_ty: TypeId,
210        /// Its initial value (a module constant), if it has one.
211        init: Option<ValueId>,
212        /// Whether it is a constant (read only).
213        constant: bool,
214        /// LLVM's address space: 0 the default, 3 group shared. No other space occurs in the programs of the games read.
215        address_space: u32,
216        /// Its linkage and the other properties of its record.
217        properties: GlobalProperties,
218        /// Its thread-local model: 0 none, 1 general dynamic, 2 local dynamic, 3 initial exec, 4 local exec.
219        thread_local: u8,
220        /// Its initial value may be set outside the module (`externally_initialized`).
221        externally_initialized: bool,
222    },
223    /// A constant.
224    Constant(Constant),
225    /// A function argument or an instruction's result.
226    Local,
227}
228
229/// A metadata record.
230#[derive(Clone, Debug, PartialEq)]
231pub enum Metadata {
232    /// A metadata string, as stored (not checked to be UTF-8 here).
233    String(Vec<u8>),
234    /// A value as metadata.
235    Value {
236        /// The value's type.
237        ty: TypeId,
238        /// The value.
239        value: ValueId,
240    },
241    /// Operands; `None` is a null operand.
242    Node(Vec<Option<MetadataId>>),
243    /// A node of its own, never merged with a node of the same operands (`METADATA_DISTINCT_NODE`: the loop
244    /// identifiers `llvm.loop` names, whose first operand is the node itself).
245    Distinct(Vec<Option<MetadataId>>),
246}
247
248impl Metadata {
249    /// The operands of a node, distinct or not; `None` for a string or a value.
250    pub fn operands(&self) -> Option<&[Option<MetadataId>]> {
251        match self {
252            Metadata::Node(ops) | Metadata::Distinct(ops) => Some(ops),
253            Metadata::String(_) | Metadata::Value { .. } => None,
254        }
255    }
256}
257
258/// A binary operator code (LLVM's `BinaryOpcodes`).
259#[derive(Clone, Copy, Debug, PartialEq, Eq)]
260pub enum BinaryOp {
261    /// Addition.
262    Add,
263    /// Subtraction.
264    Sub,
265    /// Multiplication.
266    Mul,
267    /// Unsigned division.
268    UDiv,
269    /// Signed division.
270    SDiv,
271    /// Unsigned remainder.
272    URem,
273    /// Signed remainder.
274    SRem,
275    /// Shift left.
276    Shl,
277    /// Logical shift right.
278    LShr,
279    /// Arithmetic shift right.
280    AShr,
281    /// Bitwise and.
282    And,
283    /// Bitwise or.
284    Or,
285    /// Bitwise exclusive or.
286    Xor,
287}
288/// A cast opcode (LLVM's `CastOpcodes`).
289#[derive(Clone, Copy, Debug, PartialEq, Eq)]
290pub enum CastOp {
291    /// Truncate an integer.
292    Trunc,
293    /// Zero-extend an integer.
294    ZExt,
295    /// Sign-extend an integer.
296    SExt,
297    /// Float to unsigned integer.
298    FpToUi,
299    /// Float to signed integer.
300    FpToSi,
301    /// Unsigned integer to float.
302    UiToFp,
303    /// Signed integer to float.
304    SiToFp,
305    /// Truncate a float.
306    FpTrunc,
307    /// Extend a float.
308    FpExt,
309    /// Pointer to integer.
310    PtrToInt,
311    /// Integer to pointer.
312    IntToPtr,
313    /// Reinterpret the bits as another type.
314    BitCast,
315    /// A pointer into another address space.
316    AddrSpaceCast,
317}
318
319/// An instruction, with the value ids (absolute) and block numbers it names.
320#[derive(Clone, Debug, PartialEq)]
321pub enum Op {
322    /// Integer opcodes apply to integers; for floating types Add, Sub, Mul, (S)Div, (S)Rem are the float forms.
323    Binary {
324        /// The operation.
325        op: BinaryOp,
326        /// The left operand.
327        lhs: ValueId,
328        /// The right operand.
329        rhs: ValueId,
330    },
331    /// A conversion.
332    Cast {
333        /// The conversion.
334        op: CastOp,
335        /// The value converted; the instruction's result type is the target.
336        value: ValueId,
337    },
338    /// A comparison by its LLVM predicate (0..15 float, 32..41 integer).
339    Compare {
340        /// The predicate.
341        predicate: u64,
342        /// The left operand.
343        lhs: ValueId,
344        /// The right operand.
345        rhs: ValueId,
346    },
347    /// `select`: one of two values by a condition.
348    Select {
349        /// The condition (an `i1`).
350        condition: ValueId,
351        /// The value when the condition is true.
352        then: ValueId,
353        /// The value when it is false.
354        otherwise: ValueId,
355    },
356    /// A field or element of an aggregate.
357    ExtractValue {
358        /// The aggregate.
359        aggregate: ValueId,
360        /// The indices into it, outermost first.
361        indices: Vec<u64>,
362    },
363    /// An aggregate with one field or element replaced.
364    InsertValue {
365        /// The aggregate.
366        aggregate: ValueId,
367        /// The new field or element.
368        value: ValueId,
369        /// The indices of the replaced one, outermost first.
370        indices: Vec<u64>,
371    },
372    /// One lane of a vector.
373    ExtractElement {
374        /// The vector.
375        vector: ValueId,
376        /// The lane number.
377        index: ValueId,
378    },
379    /// A vector with one lane replaced.
380    InsertElement {
381        /// The vector.
382        vector: ValueId,
383        /// The new lane.
384        value: ValueId,
385        /// The lane number.
386        index: ValueId,
387    },
388    /// The lanes of two vectors the mask (a constant vector of lane numbers) picks.
389    ShuffleVector {
390        /// The first vector.
391        first: ValueId,
392        /// The second vector.
393        second: ValueId,
394        /// The constant vector of lane numbers.
395        mask: ValueId,
396    },
397    /// A call.
398    Call {
399        /// The callee.
400        function: ValueId,
401        /// The arguments, one per parameter.
402        args: Vec<ValueId>,
403        /// The attribute list of the call site (an index into [`Module::attribute_lists`]), where it names one.
404        attributes: Option<usize>,
405        /// The calling convention (0 is C's).
406        calling_conv: u64,
407        /// Whether it is marked a tail call.
408        tail: TailCall,
409    },
410    /// The value from the predecessor block control came from: (value, block) pairs.
411    Phi {
412        /// The (value, predecessor block) pairs.
413        incoming: Vec<(ValueId, usize)>,
414    },
415    /// `ret`, with the value returned where there is one.
416    Return(Option<ValueId>),
417    /// An unconditional branch.
418    Branch {
419        /// The block branched to.
420        target: usize,
421    },
422    /// A conditional branch.
423    CondBranch {
424        /// The condition (an `i1`).
425        condition: ValueId,
426        /// The block when it is true.
427        then: usize,
428        /// The block when it is false.
429        otherwise: usize,
430    },
431    /// A multi-way branch: the value, the default block and the (case constant, block) pairs.
432    Switch {
433        /// The value switched on.
434        value: ValueId,
435        /// The block when no case matches.
436        default: usize,
437        /// The (case constant, block) pairs.
438        cases: Vec<(ValueId, usize)>,
439    },
440    /// `unreachable`.
441    Unreachable,
442    /// A local variable of this type (the result is a pointer to it).
443    Alloca {
444        /// The type of the variable.
445        ty: TypeId,
446        /// The number of variables (an integer value; the compilers write the constant `i32 1`).
447        size: ValueId,
448        /// The alignment in bytes; 0 where the record states none.
449        align: u64,
450        /// The variable is an argument passed in memory (`inalloca`).
451        inalloca: bool,
452    },
453    /// A load.
454    Load {
455        /// The pointer loaded from; the result type is the loaded type.
456        pointer: ValueId,
457        /// The alignment in bytes; 0 where the record states none.
458        align: u64,
459        /// `volatile`.
460        volatile: bool,
461        /// The ordering of an atomic load (`FUNC_CODE_INST_LOADATOMIC`).
462        atomic: Option<Atomic>,
463    },
464    /// A store.
465    Store {
466        /// The pointer stored to.
467        pointer: ValueId,
468        /// The value stored.
469        value: ValueId,
470        /// The alignment in bytes; 0 where the record states none.
471        align: u64,
472        /// `volatile`.
473        volatile: bool,
474        /// The ordering of an atomic store (`FUNC_CODE_INST_STOREATOMIC`).
475        atomic: Option<Atomic>,
476    },
477    /// `getelementptr`: the base pointer and its indices (the first steps over the pointer itself).
478    Gep {
479        /// The base pointer.
480        base: ValueId,
481        /// The indices.
482        indices: Vec<ValueId>,
483        /// The type the first index steps over: the base's pointee, which the record states.
484        source: TypeId,
485        /// `inbounds`.
486        inbounds: bool,
487    },
488    /// `atomicrmw`: the operation (LLVM's code: 0 xchg, 1 add, 2 sub, 3 and, 4 nand, 5 or, 6 xor, 7 max, 8 min, 9 umax,
489    /// 10 umin); the result is the value the pointer held.
490    AtomicRmw {
491        /// The pointer.
492        pointer: ValueId,
493        /// The value operated with.
494        value: ValueId,
495        /// The operation code.
496        op: u64,
497        /// `volatile`.
498        volatile: bool,
499        /// Its ordering.
500        atomic: Atomic,
501    },
502    /// `cmpxchg`: the result is the pair (the value the pointer held, whether it was swapped).
503    CmpXchg {
504        /// The pointer.
505        pointer: ValueId,
506        /// The value compared with.
507        compare: ValueId,
508        /// The new value stored where the comparison holds.
509        value: ValueId,
510        /// `volatile`.
511        volatile: bool,
512        /// `weak`: it may fail even where the comparison holds.
513        weak: bool,
514        /// The ordering where it swaps, and the scope of both.
515        success: Atomic,
516        /// The ordering where it does not.
517        failure: Ordering,
518    },
519    /// `fence`: ordering between invocations, which a lockstep reading does not have.
520    Fence(Atomic),
521}
522
523/// The ordering of an atomic operation (LLVM's `AtomicOrdering`, by its bitcode code 0 to 6).
524#[derive(Clone, Copy, Debug, PartialEq, Eq)]
525pub enum Ordering {
526    /// Not atomic (0).
527    NotAtomic,
528    /// `unordered` (1).
529    Unordered,
530    /// `monotonic` (2).
531    Monotonic,
532    /// `acquire` (3).
533    Acquire,
534    /// `release` (4).
535    Release,
536    /// `acq_rel` (5).
537    AcquireRelease,
538    /// `seq_cst` (6).
539    SequentiallyConsistent,
540}
541
542/// The ordering of an atomic operation and the invocations it orders against.
543#[derive(Clone, Copy, Debug, PartialEq, Eq)]
544pub struct Atomic {
545    /// The ordering.
546    pub ordering: Ordering,
547    /// Only against the invocation itself (`singlethread`); otherwise against all.
548    pub single_thread: bool,
549}
550
551/// Whether a call is marked a tail call.
552#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
553pub enum TailCall {
554    /// Not marked.
555    #[default]
556    None,
557    /// `tail`.
558    Tail,
559    /// `musttail`.
560    MustTail,
561}
562
563impl Op {
564    /// The values the operation reads (a call's arguments, not its callee; a phi's incoming values).
565    pub fn operands(&self) -> Vec<ValueId> {
566        match self {
567            Op::Binary { lhs, rhs, .. } | Op::Compare { lhs, rhs, .. } => vec![*lhs, *rhs],
568            Op::Cast { value, .. } => vec![*value],
569            Op::Select {
570                condition,
571                then,
572                otherwise,
573            } => vec![*condition, *then, *otherwise],
574            Op::ExtractValue { aggregate, .. } => vec![*aggregate],
575            Op::InsertValue { aggregate, value, .. } => vec![*aggregate, *value],
576            Op::ExtractElement { vector, index } => vec![*vector, *index],
577            Op::InsertElement { vector, value, index } => vec![*vector, *value, *index],
578            Op::ShuffleVector { first, second, mask } => vec![*first, *second, *mask],
579            Op::Call { args, .. } => args.clone(),
580            Op::Phi { incoming } => incoming.iter().map(|(v, _)| *v).collect(),
581            Op::Return(value) => value.iter().copied().collect(),
582            Op::CondBranch { condition, .. } => vec![*condition],
583            Op::Switch { value, cases, .. } => std::iter::once(*value)
584                .chain(cases.iter().map(|(c, _)| *c))
585                .collect(),
586            Op::Load { pointer, .. } => vec![*pointer],
587            Op::Store { pointer, value, .. } | Op::AtomicRmw { pointer, value, .. } => vec![*pointer, *value],
588            Op::Gep { base, indices, .. } => std::iter::once(*base).chain(indices.iter().copied()).collect(),
589            Op::CmpXchg {
590                pointer,
591                compare,
592                value,
593                ..
594            } => vec![*pointer, *compare, *value],
595            Op::Alloca { size, .. } => vec![*size],
596            Op::Branch { .. } | Op::Unreachable | Op::Fence(_) => Vec::new(),
597        }
598    }
599
600    /// The basic blocks the operation names (a branch's targets, a phi's predecessors).
601    pub fn blocks(&self) -> Vec<usize> {
602        match self {
603            Op::Branch { target } => vec![*target],
604            Op::CondBranch { then, otherwise, .. } => vec![*then, *otherwise],
605            Op::Switch { default, cases, .. } => std::iter::once(*default)
606                .chain(cases.iter().map(|(_, b)| *b))
607                .collect(),
608            Op::Phi { incoming } => incoming.iter().map(|(_, b)| *b).collect(),
609            _ => Vec::new(),
610        }
611    }
612}
613
614/// An instruction of a function body.
615#[derive(Clone, Debug, PartialEq)]
616pub struct Instruction {
617    /// What it does.
618    pub op: Op,
619    /// The result's value id and type, when the instruction produces one.
620    pub result: Option<(ValueId, TypeId)>,
621    /// The basic block it belongs to.
622    pub block: usize,
623    /// Bit offset of its record.
624    pub at: usize,
625    /// The optimisation flags its record states (0 for none): for an integer `add`, `sub`, `mul` or `shl` bit 0 is
626    /// `nuw` and bit 1 `nsw`; for `udiv`, `sdiv`, `lshr` and `ashr` bit 0 is `exact`; for a float operation or
627    /// comparison they are the fast-math flags (bit 0 `fast`, then `nnan`, `ninf`, `nsz` and `arcp`).
628    pub flags: u64,
629    /// The instruction carries the `dx.precise` attachment, which the compiler writes for HLSL's `precise`: the value
630    /// is not to be fused or reassociated. In skate.'s stock programs it is on calls only: 88,541 `tertiary` (mad),
631    /// 13,005 `loadInput`, 3,546 `unary`, 1,421 `dot3`, 331 `legacyF16ToF32`, 307 `binary`, 213 `dot4` and 105 `dot2`,
632    /// in vertex programs (107,109 instructions in 3,185 of 3,341) and compute programs (360 in 12), in no pixel
633    /// program; none of Elden Ring's has it.
634    pub precise: bool,
635    /// The metadata attached to the instruction, in the order the file stores the pairs (`dx.precise` among them).
636    pub attachments: Vec<Attachment>,
637}
638
639/// A metadata node attached to an instruction or a function: the kind (the id [`Module::kinds`] names) and the node.
640/// In the games' programs the kinds are `dx.controlflow.hints`, `llvm.loop`, `tbaa`, `noalias`, `alias.scope`, `range`
641/// and `dx.precise`.
642#[derive(Clone, Copy, Debug, PartialEq, Eq)]
643pub struct Attachment {
644    /// The metadata kind id (`dx.precise`, `tbaa`, ... by [`Module::kind_name`]).
645    pub kind: u64,
646    /// The attached node, an id into [`Module::metadata`].
647    pub node: MetadataId,
648}
649
650/// An attribute of an attribute group, as the bitcode stores it.
651#[derive(Clone, Debug, PartialEq, Eq)]
652pub enum Attribute {
653    /// A flag attribute, by LLVM's bitcode kind number (see [`attribute_name`]).
654    Enum(u64),
655    /// An attribute with an integer value: its kind number and the value.
656    Integer(u64, u64),
657    /// A string attribute: the key and the value (empty where the attribute has none).
658    String(String, String),
659}
660
661/// A group of attributes, which an attribute list names by its id.
662#[derive(Clone, Debug, PartialEq, Eq)]
663pub struct AttributeGroup {
664    /// The group's id, as the lists name it.
665    pub id: u64,
666    /// The slot the attributes apply to: [`FUNCTION_SLOT`] the function itself, 0 its result, 1 and up its parameters.
667    pub slot: u64,
668    /// The attributes, in the order stored.
669    pub attributes: Vec<Attribute>,
670}
671
672/// The slot of an [`AttributeGroup`] that holds a function's own attributes (`0xFFFFFFFF`).
673pub const FUNCTION_SLOT: u64 = 0xFFFF_FFFF;
674
675/// The name of an LLVM 3.7 enum attribute's bitcode kind number (`nounwind` for 18), for the kinds whose number dxc's own
676/// listing confirms: 9 `noalias`, 11 `nocapture`, 12 `noduplicate`, 17 `noreturn`, 18 `nounwind`, 20 `readnone`, 21
677/// `readonly`, 39 `nonnull`. They are the kinds the games' programs and the test compilations use.
678pub fn attribute_name(kind: u64) -> Option<&'static str> {
679    Some(match kind {
680        9 => "noalias",
681        11 => "nocapture",
682        12 => "noduplicate",
683        17 => "noreturn",
684        18 => "nounwind",
685        20 => "readnone",
686        21 => "readonly",
687        39 => "nonnull",
688        _ => return None,
689    })
690}
691
692/// A function body.
693#[derive(Clone, Debug, PartialEq)]
694pub struct Function {
695    /// The function's module value id.
696    pub value: ValueId,
697    /// The number of basic blocks.
698    pub blocks: usize,
699    /// The instructions of all blocks, in order.
700    pub instructions: Vec<Instruction>,
701    /// The body's own values (arguments, constants, instruction results) and their types; their ids start at
702    /// `first`, after the module's values.
703    pub first: ValueId,
704    /// The values of the body.
705    pub locals: Vec<Value>,
706    /// The types of [`Function::locals`].
707    pub local_types: Vec<TypeId>,
708    /// The metadata attached to the function itself (the attachment records of the body that name no instruction).
709    pub attachments: Vec<Attachment>,
710    /// The body's symbol table: the names of its values (arguments and instruction results, by absolute id).
711    pub names: Vec<(ValueId, String)>,
712    /// The names of its basic blocks that have one.
713    pub block_names: Vec<(usize, String)>,
714    /// The use-list orders of its basic blocks (`USELIST_CODE_BB`): each block and the position its uses take, in the
715    /// order LLVM would otherwise keep them (the most recent first). They are the order of its predecessors.
716    pub block_use_orders: Vec<(usize, Vec<u64>)>,
717}
718
719impl Function {
720    /// The body's name for one of its values, where its symbol table has one.
721    pub fn name(&self, value: ValueId) -> Option<&str> {
722        self.names
723            .iter()
724            .find(|(v, _)| *v == value)
725            .map(|(_, n)| n.as_str())
726    }
727    /// The name of a basic block, where it has one.
728    pub fn block_name(&self, block: usize) -> Option<&str> {
729        self.block_names
730            .iter()
731            .find(|(b, _)| *b == block)
732            .map(|(_, n)| n.as_str())
733    }
734}
735
736/// A module: its types, values, metadata and function bodies.
737#[derive(Clone, Debug, Default, PartialEq)]
738pub struct Module {
739    /// The type table.
740    pub types: Vec<Type>,
741    /// The module's values by id (globals, functions, module constants); a function body's own values continue the
742    /// numbering in its [`Function`].
743    pub values: Vec<Value>,
744    /// Each value's type.
745    pub value_types: Vec<TypeId>,
746    /// The module's symbol table: the names of the module values that have one (a function body's own are in its
747    /// [`Function::names`]).
748    pub names: Vec<(ValueId, String)>,
749    /// The target triple (`dxil-ms-dx`), where the module states one.
750    pub triple: Option<String>,
751    /// The data layout, where the module states one.
752    pub datalayout: Option<String>,
753    /// The module's inline assembly, where it has any.
754    pub asm: Option<String>,
755    /// The metadata records, by [`MetadataId`].
756    pub metadata: Vec<Metadata>,
757    /// The bit of the bitcode each metadata record (by id) starts at, for the locations of reflection errors.
758    pub metadata_at: Vec<usize>,
759    /// The named metadata (`dx.entryPoints`, ...): the name and the records it lists.
760    pub named_metadata: Vec<(String, Vec<MetadataId>)>,
761    /// The bit each named metadata record (by index in `named_metadata`) starts at.
762    pub named_metadata_at: Vec<usize>,
763    /// The bit of the bitcode the module block starts at: where a record the module lacks would be.
764    pub at: usize,
765    /// The function bodies, in the order of their definitions.
766    pub functions: Vec<Function>,
767    /// The id of the module's `dx.precise` metadata kind (the kind [`Instruction::precise`] reads), where it names one.
768    pub precise_kind: Option<u64>,
769    /// The module's metadata kinds: each id and its name, in the order stored.
770    pub kinds: Vec<(u64, String)>,
771    /// The attribute groups, in the order stored.
772    pub attribute_groups: Vec<AttributeGroup>,
773    /// The attribute lists, in the order stored: the ids of the groups each lists. A function value's `attributes` is an
774    /// index into this.
775    pub attribute_lists: Vec<Vec<u64>>,
776}
777
778fn op(r: &Record, i: usize) -> Result<u64> {
779    r.operands
780        .get(i)
781        .copied()
782        .ok_or_else(|| error(r.at, format!("record {} lacks operand {i}", r.code)))
783}
784fn text(ops: &[u64], at: usize) -> Result<Vec<u8>> {
785    ops.iter()
786        .map(|&c| u8::try_from(c).map_err(|_| error(at, "character above 255")))
787        .collect()
788}
789/// The zero-terminated string starting at operand `from` of an attribute record, and the index after its terminator.
790fn c_string(r: &Record, from: usize) -> Result<(String, usize)> {
791    let rest = r.operands.get(from..).unwrap_or_default();
792    let n = rest
793        .iter()
794        .position(|&c| c == 0)
795        .ok_or_else(|| error(r.at, "an attribute string without its terminator"))?;
796    let bytes = text(rest.get(..n).unwrap_or_default(), r.at)?;
797    Ok((
798        String::from_utf8_lossy(&bytes).into_owned(),
799        from.saturating_add(n).saturating_add(1),
800    ))
801}
802fn utf8(bytes: Vec<u8>, at: usize) -> Result<String> {
803    String::from_utf8(bytes).map_err(|_| error(at, "name is not UTF-8"))
804}
805fn signed_vbr(v: u64) -> i64 {
806    if v & 1 == 0 {
807        i64::try_from(v >> 1).unwrap_or(i64::MAX)
808    } else if v == 1 {
809        i64::MIN
810    } else {
811        i64::try_from(v >> 1).map_or(i64::MIN, i64::wrapping_neg)
812    }
813}
814
815impl Module {
816    fn ty(&self, id: u64, at: usize) -> Result<TypeId> {
817        let id = usize::try_from(id).map_err(|_| error(at, "type id"))?;
818        if id < self.types.len() {
819            Ok(id)
820        } else {
821            Err(error(at, format!("type {id} undefined")))
822        }
823    }
824    /// The type `id`, which an earlier record has already checked against the table (an error where it has not).
825    fn type_at(&self, id: TypeId, at: usize) -> Result<&Type> {
826        self.types
827            .get(id)
828            .ok_or_else(|| error(at, format!("type {id} of {} types", self.types.len())))
829    }
830    /// The id of the type `ty`, appended to the table where it is not there yet.
831    fn intern(&mut self, ty: Type) -> TypeId {
832        match self.types.iter().position(|x| *x == ty) {
833            Some(p) => p,
834            None => {
835                self.types.push(ty);
836                self.types.len().saturating_sub(1)
837            }
838        }
839    }
840    /// The module's name for a value, where its symbol table has one.
841    pub fn name(&self, value: ValueId) -> Option<&str> {
842        self.names
843            .iter()
844            .find(|(v, _)| *v == value)
845            .map(|(_, n)| n.as_str())
846    }
847    fn push(&mut self, value: Value, ty: TypeId, at: usize) -> Result<ValueId> {
848        if self.values.len() >= MAX_VALUES {
849            return Err(error(at, "too many values"));
850        }
851        self.values.push(value);
852        self.value_types.push(ty);
853        Ok(self.values.len().saturating_sub(1))
854    }
855
856    fn read_types(&mut self, block: &Block) -> Result<()> {
857        let mut struct_name: Option<String> = None;
858        for r in block.records() {
859            if self.types.len() >= MAX_TYPES {
860                return Err(error(r.at, "too many types"));
861            }
862            let t = match r.code {
863                1 => continue, // NUMENTRY
864                2 => Type::Void,
865                3 => Type::Float,
866                4 => Type::Double,
867                5 => Type::Label,
868                6 => Type::Opaque(struct_name.take()),
869                7 => Type::Integer(
870                    u32::try_from(op(r, 0)?)
871                        .ok()
872                        .filter(|w| (1..=64).contains(w))
873                        .ok_or_else(|| error(r.at, "integer width"))?,
874                ),
875                8 => Type::Pointer(
876                    self.ty(op(r, 0)?, r.at)?,
877                    u32::try_from(op(r, 1)?).map_err(|_| error(r.at, "pointer address space"))?,
878                ),
879                10 => Type::Half,
880                11 => Type::Array(op(r, 0)?, self.ty(op(r, 1)?, r.at)?),
881                12 => Type::Vector(op(r, 0)?, self.ty(op(r, 1)?, r.at)?),
882                16 => Type::Metadata,
883                // STRUCT_ANON and STRUCT_NAMED: [packed, element types...]
884                18 | 20 => Type::Struct {
885                    name: if r.code == 20 { struct_name.take() } else { None },
886                    packed: op(r, 0)? != 0,
887                    literal: r.code == 18,
888                    elements: r
889                        .operands
890                        .get(1..)
891                        .unwrap_or_default()
892                        .iter()
893                        .map(|&t| self.ty(t, r.at))
894                        .collect::<Result<_>>()?,
895                },
896                19 => {
897                    struct_name = Some(utf8(text(&r.operands, r.at)?, r.at)?);
898                    continue;
899                }
900                21 => Type::Function {
901                    vararg: op(r, 0)? != 0,
902                    ret: self.ty(op(r, 1)?, r.at)?,
903                    params: r
904                        .operands
905                        .get(2..)
906                        .unwrap_or_default()
907                        .iter()
908                        .map(|&t| self.ty(t, r.at))
909                        .collect::<Result<_>>()?,
910                },
911                other => return Err(error(r.at, format!("type record {other}"))),
912            };
913            self.types.push(t);
914        }
915        Ok(())
916    }
917
918    /// Read a constants block, appending its values. Value ids inside aggregates are absolute.
919    fn read_constants(&mut self, block: &Block) -> Result<()> {
920        let mut ty: Option<TypeId> = None;
921        for r in block.records() {
922            let id = |v: u64| usize::try_from(v).map_err(|_| error(r.at, "value id"));
923            if r.code == 1 {
924                ty = Some(self.ty(op(r, 0)?, r.at)?);
925                continue;
926            }
927            let t = ty.ok_or_else(|| error(r.at, "constant before SETTYPE"))?;
928            let c = match r.code {
929                2 => Constant::Null,
930                3 => Constant::Undef,
931                4 => Constant::Integer(signed_vbr(op(r, 0)?)),
932                6 => Constant::Float(op(r, 0)?),
933                7 => Constant::Aggregate(
934                    r.operands
935                        .iter()
936                        .map(|&v| usize::try_from(v).map_err(|_| error(r.at, "value id")))
937                        .collect::<Result<_>>()?,
938                ),
939                // STRING and CSTRING, whose terminating zero is not stored
940                8 => Constant::String(text(&r.operands, r.at)?),
941                9 => {
942                    let mut bytes = text(&r.operands, r.at)?;
943                    bytes.push(0);
944                    Constant::String(bytes)
945                }
946                22 => Constant::Data(r.operands.clone()),
947                // CE_GEP and CE_INBOUNDS_GEP: [source type,] then (type, value) pairs, the first the base
948                12 | 20 => {
949                    let explicit = r.operands.len() % 2 == 1;
950                    let ops = r.operands.get(usize::from(explicit)..).unwrap_or_default();
951                    let (pairs, rest) = ops.as_chunks::<2>();
952                    let ([base_ty, base], true) = (
953                        pairs.first().unwrap_or(&[0, 0]),
954                        rest.is_empty() && !pairs.is_empty(),
955                    ) else {
956                        return Err(error(r.at, "constant getelementptr operands"));
957                    };
958                    let source = if explicit {
959                        self.ty(op(r, 0)?, r.at)?
960                    } else {
961                        match self.type_at(self.ty(*base_ty, r.at)?, r.at)? {
962                            Type::Pointer(pointee, _) => *pointee,
963                            _ => {
964                                return Err(error(
965                                    r.at,
966                                    "a constant getelementptr of a value that is not a pointer",
967                                ));
968                            }
969                        }
970                    };
971                    Constant::Gep {
972                        base: id(*base)?,
973                        indices: pairs
974                            .iter()
975                            .skip(1)
976                            .map(|[_, index]| id(*index))
977                            .collect::<Result<_>>()?,
978                        source,
979                        inbounds: r.code == 20,
980                    }
981                }
982                // CE_BINOP: [opcode, lhs, rhs, flags?]
983                10 => Constant::Binary {
984                    op: binary(op(r, 0)?, r.at)?,
985                    lhs: id(op(r, 1)?)?,
986                    rhs: id(op(r, 2)?)?,
987                    flags: r.operands.get(3).copied().unwrap_or(0),
988                },
989                // CE_CMP: [operand type, lhs, rhs, predicate]
990                17 => Constant::Compare {
991                    lhs: id(op(r, 1)?)?,
992                    rhs: id(op(r, 2)?)?,
993                    predicate: op(r, 3)?,
994                },
995                // CE_CAST: [opcode, operand type, operand]
996                11 => Constant::Cast {
997                    op: cast(op(r, 0)?, r.at)?,
998                    value: id(op(r, 2)?)?,
999                },
1000                other => {
1001                    return Err(error(
1002                        r.at,
1003                        format!(
1004                            "constant record {other} ({} is not supported)",
1005                            constant_record(other)
1006                        ),
1007                    ));
1008                }
1009            };
1010            self.push(Value::Constant(c), t, r.at)?;
1011        }
1012        Ok(())
1013    }
1014
1015    fn read_metadata(&mut self, block: &Block) -> Result<()> {
1016        let mut name: Option<String> = None;
1017        let md = |v: u64, at: usize| usize::try_from(v).map_err(|_| error(at, "metadata id"));
1018        for r in block.records() {
1019            match r.code {
1020                1 => {
1021                    self.metadata.push(Metadata::String(text(&r.operands, r.at)?));
1022                    self.metadata_at.push(r.at);
1023                }
1024                2 => {
1025                    self.metadata.push(Metadata::Value {
1026                        ty: self.ty(op(r, 0)?, r.at)?,
1027                        value: md(op(r, 1)?, r.at)?,
1028                    });
1029                    self.metadata_at.push(r.at);
1030                }
1031                // NODE and DISTINCT_NODE: [metadata id + 1, or 0 for null...]
1032                3 | 5 => {
1033                    let ops = r
1034                        .operands
1035                        .iter()
1036                        .map(|&v| {
1037                            if v == 0 {
1038                                Ok(None)
1039                            } else {
1040                                md(v.saturating_sub(1), r.at).map(Some)
1041                            }
1042                        })
1043                        .collect::<Result<_>>()?;
1044                    self.metadata.push(if r.code == 3 {
1045                        Metadata::Node(ops)
1046                    } else {
1047                        Metadata::Distinct(ops)
1048                    });
1049                    self.metadata_at.push(r.at);
1050                }
1051                4 => name = Some(utf8(text(&r.operands, r.at)?, r.at)?),
1052                10 => {
1053                    let n = name
1054                        .take()
1055                        .ok_or_else(|| error(r.at, "named node without a name"))?;
1056                    let nodes = r.operands.iter().map(|&v| md(v, r.at)).collect::<Result<_>>()?;
1057                    self.named_metadata.push((n, nodes));
1058                    self.named_metadata_at.push(r.at);
1059                }
1060                6 => {
1061                    // KIND: [kind id, name]
1062                    let id = op(r, 0)?;
1063                    let bytes = text(r.operands.get(1..).unwrap_or_default(), r.at)?;
1064                    if bytes == b"dx.precise" {
1065                        self.precise_kind = Some(id);
1066                    }
1067                    self.kinds
1068                        .push((id, String::from_utf8_lossy(&bytes).into_owned()));
1069                }
1070                7 | 12..=32 => {
1071                    return Err(error(
1072                        r.at,
1073                        format!(
1074                            "metadata record {other}: debug information is not supported",
1075                            other = r.code
1076                        ),
1077                    ));
1078                }
1079                other => return Err(error(r.at, format!("metadata record {other}"))),
1080            }
1081        }
1082        Ok(())
1083    }
1084
1085    /// The attribute groups: records `[group id, slot, attribute...]`, an attribute being `[0, kind]` (a flag), `[1, kind,
1086    /// value]`, `[3, key..., 0]` or `[4, key..., 0, value..., 0]`.
1087    fn read_attribute_groups(&mut self, block: &Block) -> Result<()> {
1088        for r in block.records().filter(|r| r.code == 3) {
1089            let mut attributes = Vec::new();
1090            let mut i = 2;
1091            while i < r.operands.len() {
1092                match op(r, i)? {
1093                    0 => {
1094                        attributes.push(Attribute::Enum(op(r, i.saturating_add(1))?));
1095                        i = i.saturating_add(2);
1096                    }
1097                    1 => {
1098                        attributes.push(Attribute::Integer(
1099                            op(r, i.saturating_add(1))?,
1100                            op(r, i.saturating_add(2))?,
1101                        ));
1102                        i = i.saturating_add(3);
1103                    }
1104                    form @ (3 | 4) => {
1105                        let (key, next) = c_string(r, i.saturating_add(1))?;
1106                        let (value, next) = if form == 4 {
1107                            c_string(r, next)?
1108                        } else {
1109                            (String::new(), next)
1110                        };
1111                        attributes.push(Attribute::String(key, value));
1112                        i = next;
1113                    }
1114                    other => return Err(error(r.at, format!("attribute encoding {other}"))),
1115                }
1116            }
1117            self.attribute_groups.push(AttributeGroup {
1118                id: op(r, 0)?,
1119                slot: op(r, 1)?,
1120                attributes,
1121            });
1122        }
1123        Ok(())
1124    }
1125
1126    /// The attribute lists: records `[group id...]`.
1127    fn read_attribute_lists(&mut self, block: &Block) {
1128        for r in block.records().filter(|r| r.code == 2) {
1129            self.attribute_lists.push(r.operands.clone());
1130        }
1131    }
1132
1133    /// The name of a metadata kind id, where the module names it.
1134    pub fn kind_name(&self, kind: u64) -> Option<&str> {
1135        self.kinds
1136            .iter()
1137            .find(|(k, _)| *k == kind)
1138            .map(|(_, n)| n.as_str())
1139    }
1140
1141    /// The node of the attachment among `attachments` whose kind is called `name`.
1142    pub fn attachment(&self, attachments: &[Attachment], name: &str) -> Option<MetadataId> {
1143        attachments
1144            .iter()
1145            .find(|a| self.kind_name(a.kind) == Some(name))
1146            .map(|a| a.node)
1147    }
1148
1149    /// The attributes a function value carries on itself (the groups of its list whose slot is [`FUNCTION_SLOT`]); none
1150    /// for a value that is not a function or names no list.
1151    pub fn function_attributes(&self, function: ValueId) -> Vec<&Attribute> {
1152        let Some(Value::Function {
1153            attributes: Some(list),
1154            ..
1155        }) = self.values.get(function)
1156        else {
1157            return Vec::new();
1158        };
1159        let Some(groups) = self.attribute_lists.get(*list) else {
1160            return Vec::new();
1161        };
1162        groups
1163            .iter()
1164            .filter_map(|id| {
1165                self.attribute_groups
1166                    .iter()
1167                    .find(|g| g.id == *id && g.slot == FUNCTION_SLOT)
1168            })
1169            .flat_map(|g| g.attributes.iter())
1170            .collect()
1171    }
1172
1173    /// The value of the string attribute `key` on a function (empty where the attribute has no value), if it carries it.
1174    pub fn string_attribute(&self, function: ValueId, key: &str) -> Option<&str> {
1175        self.function_attributes(function)
1176            .into_iter()
1177            .find_map(|a| match a {
1178                Attribute::String(k, v) if k == key => Some(v.as_str()),
1179                _ => None,
1180            })
1181    }
1182}
1183
1184/// A symbol table's names: of values `[value id, name...]` (`VST_ENTRY`, and `VST_FNENTRY` with an offset before the
1185/// name) and of basic blocks `[block, name...]` (`VST_BBENTRY`).
1186type Symbols = (Vec<(ValueId, String)>, Vec<(usize, String)>);
1187
1188fn read_symbols(block: &Block) -> Result<Symbols> {
1189    let (mut values, mut blocks) = (Vec::new(), Vec::new());
1190    for r in block.records() {
1191        let id = usize::try_from(op(r, 0)?).map_err(|_| error(r.at, "value id"))?;
1192        let skip = if r.code == 3 { 2 } else { 1 };
1193        let name = utf8(text(r.operands.get(skip..).unwrap_or_default(), r.at)?, r.at)?;
1194        match r.code {
1195            1 | 3 => values.push((id, name)),
1196            2 => blocks.push((id, name)),
1197            other => return Err(error(r.at, format!("symbol record {other}"))),
1198        }
1199    }
1200    Ok((values, blocks))
1201}
1202
1203/// Function-body decoding state: relative value numbering (module version 1).
1204struct Body<'m> {
1205    m: &'m mut Module,
1206    block: usize,
1207    blocks: usize,
1208}
1209impl Body<'_> {
1210    fn next(&self) -> usize {
1211        self.m.values.len()
1212    }
1213    /// A relative operand (absolute = next - operand), with its explicit type following when it is a forward
1214    /// reference (a value defined later in the function's layout). Returns the value id and its type, and advances `i`.
1215    fn value_type(&self, r: &Record, i: &mut usize) -> Result<(ValueId, TypeId)> {
1216        let id = self.absolute(op(r, *i)?, r.at)?;
1217        *i = i.saturating_add(1);
1218        if id < self.next() {
1219            let t = self
1220                .m
1221                .value_types
1222                .get(id)
1223                .copied()
1224                .ok_or_else(|| error(r.at, format!("value {id} has no type")))?;
1225            Ok((id, t))
1226        } else {
1227            let t = self.m.ty(op(r, *i)?, r.at)?;
1228            *i = i.saturating_add(1);
1229            Ok((id, t))
1230        }
1231    }
1232    /// A relative operand whose type is known from another operand: a forward reference carries none.
1233    fn value(&self, r: &Record, i: &mut usize) -> Result<ValueId> {
1234        let id = self.absolute(op(r, *i)?, r.at)?;
1235        *i = i.saturating_add(1);
1236        Ok(id)
1237    }
1238    /// The absolute id a relative operand names: the next id minus the operand, in 32 bits as LLVM writes it (a value
1239    /// defined later is a forward reference, which wraps).
1240    fn absolute(&self, relative: u64, at: usize) -> Result<ValueId> {
1241        let relative = u32::try_from(relative)
1242            .map_err(|_| error(at, format!("relative value id {relative} wider than 32 bits")))?;
1243        let next = u32::try_from(self.next()).map_err(|_| error(at, "too many values"))?;
1244        Ok(next.wrapping_sub(relative) as usize)
1245    }
1246    /// The pointer to `t` in address space `space`.
1247    fn pointer_to(&mut self, t: TypeId, space: u32) -> TypeId {
1248        self.m.intern(Type::Pointer(t, space))
1249    }
1250    /// The index a constant integer value stands for, if it is one defined in the module or this function.
1251    fn constant_index(&self, v: ValueId) -> Option<usize> {
1252        match self.m.values.get(v) {
1253            Some(Value::Constant(Constant::Integer(i))) => usize::try_from(*i).ok(),
1254            Some(Value::Constant(Constant::Null)) => Some(0),
1255            _ => None,
1256        }
1257    }
1258    fn result(&mut self, ty: TypeId, at: usize) -> Result<Option<(ValueId, TypeId)>> {
1259        if *self.m.type_at(ty, at)? == Type::Void {
1260            return Ok(None);
1261        }
1262        Ok(Some((self.m.push(Value::Local, ty, at)?, ty)))
1263    }
1264}
1265
1266/// An alignment as records store it: 0 for none, otherwise the log2 of the bytes plus one.
1267fn alignment(stored: u64, at: usize) -> Result<u64> {
1268    match stored {
1269        0 => Ok(0),
1270        n if n <= 30 => Ok(1u64.wrapping_shl(u32::try_from(n).unwrap_or(0).wrapping_sub(1))),
1271        _ => Err(error(at, "alignment")),
1272    }
1273}
1274fn ordering(code: u64, at: usize) -> Result<Ordering> {
1275    Ok(match code {
1276        0 => Ordering::NotAtomic,
1277        1 => Ordering::Unordered,
1278        2 => Ordering::Monotonic,
1279        3 => Ordering::Acquire,
1280        4 => Ordering::Release,
1281        5 => Ordering::AcquireRelease,
1282        6 => Ordering::SequentiallyConsistent,
1283        other => return Err(error(at, format!("atomic ordering {other}"))),
1284    })
1285}
1286/// An ordering and a scope (0 single thread, 1 all).
1287fn atomic(ordering_code: u64, scope: u64, at: usize) -> Result<Atomic> {
1288    Ok(Atomic {
1289        ordering: ordering(ordering_code, at)?,
1290        single_thread: match scope {
1291            0 => true,
1292            1 => false,
1293            other => return Err(error(at, format!("synchronisation scope {other}"))),
1294        },
1295    })
1296}
1297fn binary(code: u64, at: usize) -> Result<BinaryOp> {
1298    Ok(match code {
1299        0 => BinaryOp::Add,
1300        1 => BinaryOp::Sub,
1301        2 => BinaryOp::Mul,
1302        3 => BinaryOp::UDiv,
1303        4 => BinaryOp::SDiv,
1304        5 => BinaryOp::URem,
1305        6 => BinaryOp::SRem,
1306        7 => BinaryOp::Shl,
1307        8 => BinaryOp::LShr,
1308        9 => BinaryOp::AShr,
1309        10 => BinaryOp::And,
1310        11 => BinaryOp::Or,
1311        12 => BinaryOp::Xor,
1312        other => return Err(error(at, format!("binary opcode {other}"))),
1313    })
1314}
1315fn cast(code: u64, at: usize) -> Result<CastOp> {
1316    Ok(match code {
1317        0 => CastOp::Trunc,
1318        1 => CastOp::ZExt,
1319        2 => CastOp::SExt,
1320        3 => CastOp::FpToUi,
1321        4 => CastOp::FpToSi,
1322        5 => CastOp::UiToFp,
1323        6 => CastOp::SiToFp,
1324        7 => CastOp::FpTrunc,
1325        8 => CastOp::FpExt,
1326        9 => CastOp::PtrToInt,
1327        10 => CastOp::IntToPtr,
1328        11 => CastOp::BitCast,
1329        12 => CastOp::AddrSpaceCast,
1330        other => return Err(error(at, format!("cast opcode {other}"))),
1331    })
1332}
1333/// The linkage and other properties of a global variable's or function's record, from the operands at the indices given
1334/// (they differ between the two records). A field past the record's end is its default; a comdat is refused, and so
1335/// is a linkage code that implies one (1, 4, 10 and 11, in a record without the comdat field).
1336#[expect(clippy::too_many_arguments, reason = "the field positions of the two records")]
1337fn global_properties(
1338    r: &Record,
1339    linkage: usize,
1340    alignment_at: usize,
1341    section: usize,
1342    visibility: usize,
1343    unnamed_addr: usize,
1344    dll_storage: usize,
1345    comdat: usize,
1346    sections: &[String],
1347) -> Result<GlobalProperties> {
1348    let raw = op(r, linkage)?;
1349    let decoded = match raw {
1350        0 | 5 | 6 | 15 => Linkage::External,
1351        2 => Linkage::Appending,
1352        3 => Linkage::Internal,
1353        7 => Linkage::ExternWeak,
1354        8 => Linkage::Common,
1355        9 | 13 | 14 => Linkage::Private,
1356        12 => Linkage::AvailableExternally,
1357        1 | 16 => Linkage::WeakAny,
1358        10 | 17 => Linkage::WeakOdr,
1359        4 | 18 => Linkage::LinkOnceAny,
1360        11 | 19 => Linkage::LinkOnceOdr,
1361        _ => Linkage::External,
1362    };
1363    let field = |i: usize| r.operands.get(i).copied();
1364    if field(comdat).map_or(matches!(raw, 1 | 4 | 10 | 11), |c| c != 0) {
1365        return Err(error(r.at, "a global value in a comdat is not supported"));
1366    }
1367    let local = matches!(decoded, Linkage::Internal | Linkage::Private);
1368    Ok(GlobalProperties {
1369        linkage: decoded,
1370        // local linkage has the default visibility, whatever the record says
1371        visibility: match field(visibility).unwrap_or(0) {
1372            _ if local => 0,
1373            v @ 0..=2 => u8::try_from(v).unwrap_or(0),
1374            _ => 0,
1375        },
1376        // a record without the field says it by the old linkage codes 5 (dllimport) and 6 (dllexport)
1377        dll_storage: match field(dll_storage) {
1378            Some(v @ 0..=2) => u8::try_from(v).unwrap_or(0),
1379            Some(_) => 0,
1380            None => match raw {
1381                5 => 1,
1382                6 => 2,
1383                _ => 0,
1384            },
1385        },
1386        unnamed_addr: field(unnamed_addr).is_some_and(|v| v != 0),
1387        section: match op(r, section)? {
1388            0 => None,
1389            n => Some(
1390                usize::try_from(n.saturating_sub(1))
1391                    .ok()
1392                    .and_then(|n| sections.get(n))
1393                    .cloned()
1394                    .ok_or_else(|| error(r.at, "a global value names a section the module lacks"))?,
1395            ),
1396        },
1397        alignment: alignment(op(r, alignment_at)?, r.at)?,
1398    })
1399}
1400
1401/// What a constants record this reader refuses holds.
1402fn constant_record(code: u64) -> &'static str {
1403    match code {
1404        5 => "an integer wider than 64 bits",
1405        13 => "a constant select",
1406        14 => "a constant extractelement",
1407        15 => "a constant insertelement",
1408        16 | 19 => "a constant shufflevector",
1409        18 => "inline assembly (old form)",
1410        21 => "a block address",
1411        23 | 30 => "inline assembly",
1412        _ => "an unknown constant",
1413    }
1414}
1415
1416/// The name of a function-body record code this reader refuses.
1417fn refused(code: u64) -> &'static str {
1418    match code {
1419        4 | 30 => "getelementptr (old form)",
1420        13 => "invoke",
1421        23 => "va_arg",
1422        31 => "indirectbr",
1423        37 => "cmpxchg (old form)",
1424        59 => "atomicrmw (new form)",
1425        39 => "resume",
1426        40 | 47 => "landingpad",
1427        _ => "unknown instruction record",
1428    }
1429}
1430
1431/// Reads a function's attachment block: a record `[instruction, (kind, node)...]` (an odd number of operands) attaches
1432/// the pairs to that instruction, a record of an even number of operands, `(kind, node)...`, to the function itself.
1433/// An instruction given the `dx.precise` kind is also marked [`Instruction::precise`].
1434fn read_attachments(
1435    precise: Option<u64>,
1436    block: &Block,
1437    instructions: &mut [Instruction],
1438    function: &mut Vec<Attachment>,
1439) -> Result<()> {
1440    for r in block.records().filter(|r| r.code == 11) {
1441        let per_instruction = r.operands.len() % 2 == 1;
1442        let mut attachments = Vec::new();
1443        let (pairs, _) = r
1444            .operands
1445            .get(usize::from(per_instruction)..)
1446            .unwrap_or_default()
1447            .as_chunks::<2>();
1448        for &[kind, node] in pairs {
1449            attachments.push(Attachment {
1450                kind,
1451                node: usize::try_from(node).map_err(|_| error(r.at, "attachment node"))?,
1452            });
1453        }
1454        if !per_instruction {
1455            function.extend(attachments);
1456            continue;
1457        }
1458        let at = usize::try_from(op(r, 0)?).map_err(|_| error(r.at, "attachment instruction"))?;
1459        let instruction = instructions.get_mut(at).ok_or_else(|| {
1460            error(
1461                r.at,
1462                format!("an attachment names instruction {at} of a shorter body"),
1463            )
1464        })?;
1465        if precise.is_some_and(|kind| attachments.iter().any(|a| a.kind == kind)) {
1466            instruction.precise = true;
1467        }
1468        instruction.attachments.extend(attachments);
1469    }
1470    Ok(())
1471}
1472
1473impl Module {
1474    fn read_function(&mut self, block: &Block, value: ValueId) -> Result<Function> {
1475        let fty = match self.value_types.get(value).and_then(|&t| self.types.get(t)) {
1476            Some(Type::Pointer(t, _)) => *t,
1477            _ => return Err(error(block.at, "function value is not a function pointer")),
1478        };
1479        let params = match self.type_at(fty, block.at)? {
1480            Type::Function { params, .. } => params.clone(),
1481            _ => return Err(error(block.at, "function type")),
1482        };
1483        let base = self.values.len();
1484        for p in params {
1485            self.push(Value::Local, p, block.at)?;
1486        }
1487        let mut body = Body {
1488            m: self,
1489            block: 0,
1490            blocks: 0,
1491        };
1492        let mut instructions = Vec::new();
1493        let mut function_attachments = Vec::new();
1494        let (mut names, mut block_names, mut block_use_orders) = (Vec::new(), Vec::new(), Vec::new());
1495        for e in &block.elements {
1496            let r = match e {
1497                crate::bitstream::Element::Block(b) => {
1498                    match b.id {
1499                        CONSTANTS => body.m.read_constants(b)?,
1500                        VALUE_SYMTAB => {
1501                            let (values, blocks) = read_symbols(b)?;
1502                            names.extend(values);
1503                            block_names.extend(blocks);
1504                        }
1505                        METADATA_ATTACHMENT => read_attachments(
1506                            body.m.precise_kind,
1507                            b,
1508                            &mut instructions,
1509                            &mut function_attachments,
1510                        )?,
1511                        METADATA => {
1512                            if let Some(r) = b.records().next() {
1513                                return Err(error(
1514                                    r.at,
1515                                    "metadata of a function body (function-local metadata) is not supported",
1516                                ));
1517                            }
1518                        }
1519                        // the use-list orders: of basic blocks [position..., block] (they order its predecessors),
1520                        // and of values [position..., value], which say nothing a listing shows
1521                        USELIST => {
1522                            for r in b.records() {
1523                                let (last, order) = r
1524                                    .operands
1525                                    .split_last()
1526                                    .filter(|(_, order)| order.len() >= 2)
1527                                    .ok_or_else(|| error(r.at, "use-list order"))?;
1528                                match r.code {
1529                                    1 => {}
1530                                    2 => block_use_orders.push((
1531                                        usize::try_from(*last).map_err(|_| error(r.at, "use-list block"))?,
1532                                        order.to_vec(),
1533                                    )),
1534                                    other => return Err(error(r.at, format!("use-list record {other}"))),
1535                                }
1536                            }
1537                        }
1538                        other => return Err(error(b.at, format!("block {other} in a function"))),
1539                    }
1540                    continue;
1541                }
1542                crate::bitstream::Element::Record(r) => r,
1543            };
1544            let mut i = 0;
1545            let mut flags = 0;
1546            let (op, ty): (Op, Option<TypeId>) = match r.code {
1547                1 => {
1548                    body.blocks = usize::try_from(op(r, 0)?)
1549                        .ok()
1550                        .filter(|&n| n > 0 && n <= 1 << 16)
1551                        .ok_or_else(|| error(r.at, "basic block count"))?;
1552                    continue;
1553                }
1554                33 | 35 => {
1555                    return Err(error(r.at, "debug locations are not supported"));
1556                }
1557                // BINOP: [lhs with its type, rhs, opcode, flags?]
1558                2 => {
1559                    let (lhs, t) = body.value_type(r, &mut i)?;
1560                    let rhs = body.value(r, &mut i)?;
1561                    let o = binary(op(r, i)?, r.at)?;
1562                    flags = r.operands.get(i.saturating_add(1)).copied().unwrap_or(0);
1563                    (Op::Binary { op: o, lhs, rhs }, Some(t))
1564                }
1565                // CAST: [value with its type, target type, opcode]
1566                3 => {
1567                    let (value, _) = body.value_type(r, &mut i)?;
1568                    let to = body.m.ty(op(r, i)?, r.at)?;
1569                    let o = cast(op(r, i.saturating_add(1))?, r.at)?;
1570                    (Op::Cast { op: o, value }, Some(to))
1571                }
1572                // CMP and CMP2: [lhs with its type, rhs, predicate, fast-math flags?]
1573                9 | 28 => {
1574                    let (lhs, t) = body.value_type(r, &mut i)?;
1575                    let rhs = body.value(r, &mut i)?;
1576                    let predicate = op(r, i)?;
1577                    flags = r.operands.get(i.saturating_add(1)).copied().unwrap_or(0);
1578                    // i1, or a vector of i1 for vectors
1579                    let lanes = match body.m.type_at(t, r.at)? {
1580                        Type::Vector(n, _) => Some(*n),
1581                        _ => None,
1582                    };
1583                    let flag = body.m.intern(Type::Integer(1));
1584                    let bool_ty = match lanes {
1585                        Some(n) => body.m.intern(Type::Vector(n, flag)),
1586                        None => flag,
1587                    };
1588                    (Op::Compare { predicate, lhs, rhs }, Some(bool_ty))
1589                }
1590                29 => {
1591                    let (then, t) = body.value_type(r, &mut i)?;
1592                    let otherwise = body.value(r, &mut i)?;
1593                    let condition = body.value(r, &mut i)?;
1594                    (
1595                        Op::Select {
1596                            condition,
1597                            then,
1598                            otherwise,
1599                        },
1600                        Some(t),
1601                    )
1602                }
1603                26 => {
1604                    let (aggregate, mut t) = body.value_type(r, &mut i)?;
1605                    let indices = r.operands.get(i..).unwrap_or_default().to_vec();
1606                    for &k in &indices {
1607                        t = match body.m.type_at(t, r.at)? {
1608                            Type::Struct { elements, .. } => *usize::try_from(k)
1609                                .ok()
1610                                .and_then(|k| elements.get(k))
1611                                .ok_or_else(|| error(r.at, "extractvalue index"))?,
1612                            Type::Array(n, e) if k < *n => *e,
1613                            _ => return Err(error(r.at, "extractvalue index")),
1614                        };
1615                    }
1616                    (Op::ExtractValue { aggregate, indices }, Some(t))
1617                }
1618                6 => {
1619                    let (vector, t) = body.value_type(r, &mut i)?;
1620                    let (index, _) = body.value_type(r, &mut i)?;
1621                    let Type::Vector(_, element) = *body.m.type_at(t, r.at)? else {
1622                        return Err(error(r.at, "extractelement of something that is not a vector"));
1623                    };
1624                    (Op::ExtractElement { vector, index }, Some(element))
1625                }
1626                7 => {
1627                    let (vector, t) = body.value_type(r, &mut i)?;
1628                    let value = body.value(r, &mut i)?;
1629                    let (index, _) = body.value_type(r, &mut i)?;
1630                    (Op::InsertElement { vector, value, index }, Some(t))
1631                }
1632                8 => {
1633                    let (first, t) = body.value_type(r, &mut i)?;
1634                    let second = body.value(r, &mut i)?;
1635                    let (mask, mask_ty) = body.value_type(r, &mut i)?;
1636                    let (Type::Vector(_, element), Type::Vector(lanes, _)) = (
1637                        body.m.type_at(t, r.at)?.clone(),
1638                        body.m.type_at(mask_ty, r.at)?.clone(),
1639                    ) else {
1640                        return Err(error(r.at, "shufflevector of something that is not a vector"));
1641                    };
1642                    let result = body
1643                        .m
1644                        .types
1645                        .iter()
1646                        .position(|x| *x == Type::Vector(lanes, element))
1647                        .ok_or_else(|| error(r.at, "no type for the shuffled vector"))?;
1648                    (Op::ShuffleVector { first, second, mask }, Some(result))
1649                }
1650                27 => {
1651                    let (aggregate, t) = body.value_type(r, &mut i)?;
1652                    let value = body.value(r, &mut i)?;
1653                    let indices = r.operands.get(i..).unwrap_or_default().to_vec();
1654                    (
1655                        Op::InsertValue {
1656                            aggregate,
1657                            value,
1658                            indices,
1659                        },
1660                        Some(t),
1661                    )
1662                }
1663                // CALL: [attribute list + 1 or 0, calling convention and flags, function type if explicit, callee with
1664                // its type, arguments]
1665                34 => {
1666                    let attributes = usize::try_from(op(r, 0)?)
1667                        .map_err(|_| error(r.at, "call attribute list"))?
1668                        .checked_sub(1);
1669                    if attributes.is_some_and(|a| a >= body.m.attribute_lists.len()) {
1670                        return Err(error(r.at, "a call names an attribute list the module lacks"));
1671                    }
1672                    i = 1;
1673                    let cc = op(r, i)?;
1674                    i = i.saturating_add(1);
1675                    // bit 0 tail, bit 14 musttail, bit 15 an explicit function type, the convention from bit 1
1676                    let tail = if cc & (1 << 14) != 0 {
1677                        TailCall::MustTail
1678                    } else if cc & 1 != 0 {
1679                        TailCall::Tail
1680                    } else {
1681                        TailCall::None
1682                    };
1683                    let calling_conv = (cc >> 1) & 0x1FFF;
1684                    let explicit = if cc & (1 << 15) != 0 {
1685                        let t = body.m.ty(op(r, i)?, r.at)?;
1686                        i = i.saturating_add(1);
1687                        Some(t)
1688                    } else {
1689                        None
1690                    };
1691                    let (function, callee_ty) = body.value_type(r, &mut i)?;
1692                    let fty = match (explicit, body.m.type_at(callee_ty, r.at)?) {
1693                        (Some(t), _) => t,
1694                        (None, Type::Pointer(t, _)) => *t,
1695                        _ => return Err(error(r.at, "callee is not a function pointer")),
1696                    };
1697                    let (ret, params, vararg) = match body.m.type_at(fty, r.at)? {
1698                        Type::Function { ret, params, vararg } => (*ret, params.clone(), *vararg),
1699                        _ => return Err(error(r.at, "call through a non-function type")),
1700                    };
1701                    if vararg {
1702                        return Err(error(r.at, "vararg call"));
1703                    }
1704                    let mut args = Vec::with_capacity(params.len());
1705                    for p in &params {
1706                        // a fixed parameter carries no type, even for a value defined later in the layout
1707                        let a = body.value(r, &mut i)?;
1708                        if a < body.next() && body.m.value_types.get(a) != Some(p) {
1709                            return Err(error(r.at, "call argument type"));
1710                        }
1711                        args.push(a);
1712                    }
1713                    if i != r.operands.len() {
1714                        return Err(error(r.at, "call operands left over"));
1715                    }
1716                    (
1717                        Op::Call {
1718                            function,
1719                            args,
1720                            attributes,
1721                            calling_conv,
1722                            tail,
1723                        },
1724                        Some(ret),
1725                    )
1726                }
1727                16 => {
1728                    let t = body.m.ty(op(r, 0)?, r.at)?;
1729                    let pairs = r.operands.get(1..).unwrap_or_default();
1730                    if pairs.is_empty() || pairs.len() % 2 != 0 {
1731                        return Err(error(r.at, "phi operands"));
1732                    }
1733                    let next = i64::try_from(body.next()).map_err(|_| error(r.at, "too many values"))?;
1734                    let mut incoming = Vec::with_capacity(pairs.len() / 2);
1735                    for pair in pairs.as_chunks::<2>().0 {
1736                        // Signed and relative to the phi itself; it may name a value defined later.
1737                        let id = next
1738                            .checked_sub(signed_vbr(pair[0]))
1739                            .and_then(|v| usize::try_from(v).ok())
1740                            .ok_or_else(|| error(r.at, "phi value"))?;
1741                        let block = usize::try_from(pair[1])
1742                            .ok()
1743                            .filter(|&b| b < body.blocks)
1744                            .ok_or_else(|| error(r.at, "phi block"))?;
1745                        incoming.push((id, block));
1746                    }
1747                    (Op::Phi { incoming }, Some(t))
1748                }
1749                10 => {
1750                    if r.operands.is_empty() {
1751                        (Op::Return(None), None)
1752                    } else {
1753                        (Op::Return(Some(body.value(r, &mut i)?)), None)
1754                    }
1755                }
1756                11 => {
1757                    let target = |v: u64| -> Result<usize> {
1758                        usize::try_from(v)
1759                            .ok()
1760                            .filter(|&b| b < body.blocks)
1761                            .ok_or_else(|| error(r.at, "branch target"))
1762                    };
1763                    if r.operands.len() == 1 {
1764                        (
1765                            Op::Branch {
1766                                target: target(op(r, 0)?)?,
1767                            },
1768                            None,
1769                        )
1770                    } else {
1771                        let then = target(op(r, 0)?)?;
1772                        let otherwise = target(op(r, 1)?)?;
1773                        i = 2;
1774                        let condition = body.value(r, &mut i)?;
1775                        (
1776                            Op::CondBranch {
1777                                condition,
1778                                then,
1779                                otherwise,
1780                            },
1781                            None,
1782                        )
1783                    }
1784                }
1785                12 => {
1786                    // [type, value, default block, (case constant, block)*]; case constants are absolute ids
1787                    let block = |v: u64| -> Result<usize> {
1788                        usize::try_from(v)
1789                            .ok()
1790                            .filter(|&b| b < body.blocks)
1791                            .ok_or_else(|| error(r.at, "switch target"))
1792                    };
1793                    if op(r, 0)? >> 16 == 0x4B5 {
1794                        return Err(error(r.at, "switch with case ranges is not supported"));
1795                    }
1796                    i = 1;
1797                    let value = body.value(r, &mut i)?;
1798                    let default = block(op(r, i)?)?;
1799                    let pairs = r.operands.get(i.saturating_add(1)..).unwrap_or_default();
1800                    if pairs.len() % 2 != 0 {
1801                        return Err(error(r.at, "switch cases"));
1802                    }
1803                    let cases = pairs
1804                        .as_chunks::<2>()
1805                        .0
1806                        .iter()
1807                        .map(|p| {
1808                            Ok((
1809                                usize::try_from(p[0]).map_err(|_| error(r.at, "case value"))?,
1810                                block(p[1])?,
1811                            ))
1812                        })
1813                        .collect::<Result<Vec<_>>>()?;
1814                    (
1815                        Op::Switch {
1816                            value,
1817                            default,
1818                            cases,
1819                        },
1820                        None,
1821                    )
1822                }
1823                15 => (Op::Unreachable, None),
1824                // ALLOCA: [type, size type, size (an absolute id), alignment with flags: bit 5 inalloca, bit 6 the
1825                // type is the allocated one rather than a pointer to it]
1826                19 => {
1827                    let stated = body.m.ty(op(r, 0)?, r.at)?;
1828                    let packed = op(r, 3)?;
1829                    let ty = if packed & (1 << 6) != 0 {
1830                        stated
1831                    } else {
1832                        match body.m.type_at(stated, r.at)? {
1833                            Type::Pointer(t, _) => *t,
1834                            _ => {
1835                                return Err(error(
1836                                    r.at,
1837                                    "an alloca of the old form whose type is not a pointer",
1838                                ));
1839                            }
1840                        }
1841                    };
1842                    let size = usize::try_from(op(r, 2)?).map_err(|_| error(r.at, "alloca size"))?;
1843                    (
1844                        Op::Alloca {
1845                            ty,
1846                            size,
1847                            align: alignment(packed & !((1 << 5) | (1 << 6)), r.at)?,
1848                            inalloca: packed & (1 << 5) != 0,
1849                        },
1850                        Some(body.pointer_to(ty, 0)),
1851                    )
1852                }
1853                // LOAD: [pointer with its type, loaded type if explicit, alignment, volatile], and LOADATOMIC with the
1854                // ordering and scope after them
1855                20 | 41 => {
1856                    let (pointer, pt) = body.value_type(r, &mut i)?;
1857                    let tail = if r.code == 20 { 2 } else { 4 };
1858                    let ty = if r.operands.len() == i.saturating_add(tail).saturating_add(1) {
1859                        let t = body.m.ty(op(r, i)?, r.at)?;
1860                        i = i.saturating_add(1);
1861                        t
1862                    } else {
1863                        match body.m.type_at(pt, r.at)? {
1864                            Type::Pointer(t, _) => *t,
1865                            _ => return Err(error(r.at, "a load from a value that is not a pointer")),
1866                        }
1867                    };
1868                    if r.operands.len() != i.saturating_add(tail) {
1869                        return Err(error(r.at, "load operands"));
1870                    }
1871                    let atomic = if r.code == 41 {
1872                        Some(atomic(
1873                            op(r, i.saturating_add(2))?,
1874                            op(r, i.saturating_add(3))?,
1875                            r.at,
1876                        )?)
1877                    } else {
1878                        None
1879                    };
1880                    (
1881                        Op::Load {
1882                            pointer,
1883                            align: alignment(op(r, i)?, r.at)?,
1884                            volatile: op(r, i.saturating_add(1))? != 0,
1885                            atomic,
1886                        },
1887                        Some(ty),
1888                    )
1889                }
1890                // STORE: [pointer with its type, value with its type, alignment, volatile], STOREATOMIC with the
1891                // ordering and scope after them; the old forms (24, 42) give the value without a type
1892                24 | 42 | 44 | 45 => {
1893                    let (pointer, _) = body.value_type(r, &mut i)?;
1894                    let value = if matches!(r.code, 44 | 45) {
1895                        body.value_type(r, &mut i)?.0
1896                    } else {
1897                        body.value(r, &mut i)?
1898                    };
1899                    let tail = if matches!(r.code, 24 | 44) { 2 } else { 4 };
1900                    if r.operands.len() != i.saturating_add(tail) {
1901                        return Err(error(r.at, "store operands"));
1902                    }
1903                    let atomic = if matches!(r.code, 42 | 45) {
1904                        Some(atomic(
1905                            op(r, i.saturating_add(2))?,
1906                            op(r, i.saturating_add(3))?,
1907                            r.at,
1908                        )?)
1909                    } else {
1910                        None
1911                    };
1912                    (
1913                        Op::Store {
1914                            pointer,
1915                            value,
1916                            align: alignment(op(r, i)?, r.at)?,
1917                            volatile: op(r, i.saturating_add(1))? != 0,
1918                            atomic,
1919                        },
1920                        None,
1921                    )
1922                }
1923                // ATOMICRMW: [pointer with its type, value, operation, volatile, ordering, scope]
1924                38 => {
1925                    let (pointer, pt) = body.value_type(r, &mut i)?;
1926                    let value = body.value(r, &mut i)?;
1927                    let ty = match body.m.type_at(pt, r.at)? {
1928                        Type::Pointer(t, _) => *t,
1929                        _ => return Err(error(r.at, "an atomicrmw on a value that is not a pointer")),
1930                    };
1931                    (
1932                        Op::AtomicRmw {
1933                            pointer,
1934                            value,
1935                            op: op(r, i)?,
1936                            volatile: op(r, i.saturating_add(1))? != 0,
1937                            atomic: atomic(op(r, i.saturating_add(2))?, op(r, i.saturating_add(3))?, r.at)?,
1938                        },
1939                        Some(ty),
1940                    )
1941                }
1942                // CMPXCHG: [pointer with its type, compare with its type, new value, volatile, success ordering, scope,
1943                // failure ordering, weak]; the result is a structure of the value and a flag
1944                46 => {
1945                    let (pointer, _) = body.value_type(r, &mut i)?;
1946                    let (compare, ty) = body.value_type(r, &mut i)?;
1947                    let value = body.value(r, &mut i)?;
1948                    if r.operands.len() != i.saturating_add(5) {
1949                        return Err(error(
1950                            r.at,
1951                            "cmpxchg without its failure ordering and weak flag (an old form)",
1952                        ));
1953                    }
1954                    let success = atomic(op(r, i.saturating_add(1))?, op(r, i.saturating_add(2))?, r.at)?;
1955                    let failure = ordering(op(r, i.saturating_add(3))?, r.at)?;
1956                    let flag = body.m.intern(Type::Integer(1));
1957                    let pair = Type::Struct {
1958                        name: None,
1959                        elements: vec![ty, flag],
1960                        packed: false,
1961                        literal: true,
1962                    };
1963                    let result = body.m.intern(pair);
1964                    (
1965                        Op::CmpXchg {
1966                            pointer,
1967                            compare,
1968                            value,
1969                            volatile: op(r, i)? != 0,
1970                            weak: op(r, i.saturating_add(4))? != 0,
1971                            success,
1972                            failure,
1973                        },
1974                        Some(result),
1975                    )
1976                }
1977                // FENCE: [ordering, scope]
1978                36 => (Op::Fence(atomic(op(r, 0)?, op(r, 1)?, r.at)?), None),
1979                43 => {
1980                    // [inbounds, source element type, then each operand with its type when a forward reference]
1981                    i = 2;
1982                    let inbounds = op(r, 0)? != 0;
1983                    let source = body.m.ty(op(r, 1)?, r.at)?;
1984                    let (base, base_ty) = body.value_type(r, &mut i)?;
1985                    // the result points into the base's address space
1986                    let space = match body.m.type_at(base_ty, r.at)? {
1987                        Type::Pointer(_, space) => *space,
1988                        _ => return Err(error(r.at, "getelementptr of a value that is not a pointer")),
1989                    };
1990                    let mut indices = Vec::new();
1991                    while i < r.operands.len() {
1992                        indices.push(body.value_type(r, &mut i)?.0);
1993                    }
1994                    // the result points at what the indices reach: the first steps over the pointer, the rest into
1995                    // arrays, vectors and structures
1996                    let mut t = source;
1997                    for &index in indices.iter().skip(1) {
1998                        t = match body.m.type_at(t, r.at)?.clone() {
1999                            Type::Array(_, e) | Type::Vector(_, e) => e,
2000                            Type::Struct { elements, .. } => {
2001                                let k = match body.constant_index(index) {
2002                                    Some(k) => k,
2003                                    None => {
2004                                        return Err(error(r.at, "a structure index that is not constant"));
2005                                    }
2006                                };
2007                                *elements
2008                                    .get(k)
2009                                    .ok_or_else(|| error(r.at, "getelementptr structure index"))?
2010                            }
2011                            _ => return Err(error(r.at, "getelementptr into a scalar")),
2012                        };
2013                    }
2014                    (
2015                        Op::Gep {
2016                            base,
2017                            indices,
2018                            source,
2019                            inbounds,
2020                        },
2021                        Some(body.pointer_to(t, space)),
2022                    )
2023                }
2024                other => {
2025                    return Err(error(
2026                        r.at,
2027                        format!("instruction {} (record {other}) is not supported", refused(other)),
2028                    ));
2029                }
2030            };
2031            let result = match ty {
2032                Some(t) => body.result(t, r.at)?,
2033                None => None,
2034            };
2035            let terminator = matches!(
2036                op,
2037                Op::Return(_)
2038                    | Op::Branch { .. }
2039                    | Op::CondBranch { .. }
2040                    | Op::Switch { .. }
2041                    | Op::Unreachable
2042            );
2043            instructions.push(Instruction {
2044                op,
2045                result,
2046                block: body.block,
2047                at: r.at,
2048                flags,
2049                precise: false,
2050                attachments: Vec::new(),
2051            });
2052            if terminator {
2053                body.block = body.block.saturating_add(1);
2054            }
2055        }
2056        if body.block != body.blocks {
2057            return Err(error(block.at, "basic blocks without terminators"));
2058        }
2059        let end = body.next();
2060        let blocks = body.blocks;
2061        // everything an instruction names is something the function has: a value (an earlier one, or a later one a phi
2062        // or a loop reads), a basic block, and a callee taking the arguments it is given
2063        for inst in &instructions {
2064            if inst.block >= blocks {
2065                return Err(error(inst.at, "an instruction after the last terminator"));
2066            }
2067            if let Some(v) = inst.op.operands().into_iter().find(|v| *v >= end) {
2068                return Err(error(inst.at, format!("value {v} of {end} values")));
2069            }
2070            if let Some(b) = inst.op.blocks().into_iter().find(|b| *b >= blocks) {
2071                return Err(error(inst.at, format!("basic block {b} of {blocks}")));
2072            }
2073            if let Op::Call { function, args, .. } = &inst.op {
2074                if *function >= end {
2075                    return Err(error(inst.at, format!("callee {function} of {end} values")));
2076                }
2077                if let Some(Value::Function { ty, .. }) = self.values.get(*function)
2078                    && let Some(Type::Function {
2079                        vararg: false,
2080                        params,
2081                        ..
2082                    }) = self.types.get(*ty)
2083                    && params.len() != args.len()
2084                {
2085                    return Err(error(
2086                        inst.at,
2087                        format!(
2088                            "a call of {} arguments to a function of {} parameters",
2089                            args.len(),
2090                            params.len()
2091                        ),
2092                    ));
2093                }
2094            }
2095        }
2096        let locals = self.values.split_off(base);
2097        let local_types = self.value_types.split_off(base);
2098        Ok(Function {
2099            value,
2100            blocks,
2101            instructions,
2102            first: base,
2103            locals,
2104            local_types,
2105            attachments: function_attachments,
2106            names,
2107            block_names,
2108            block_use_orders,
2109        })
2110    }
2111
2112    /// Read a module from the bitcode's top-level blocks.
2113    pub fn read(top: &[Block]) -> Result<Self> {
2114        let module = match top {
2115            [m] if m.id == MODULE => m,
2116            _ => return Err(error(0, "bitcode is not one module block")),
2117        };
2118        let mut m = Module {
2119            at: module.at,
2120            ..Module::default()
2121        };
2122        let mut bodies: Vec<ValueId> = Vec::new();
2123        let mut version = None;
2124        let (mut sections, mut gcs) = (Vec::new(), Vec::new());
2125        for e in &module.elements {
2126            match e {
2127                crate::bitstream::Element::Record(r) => match r.code {
2128                    1 => version = Some(op(r, 0)?),
2129                    2 => m.triple = Some(utf8(text(&r.operands, r.at)?, r.at)?),
2130                    3 => m.datalayout = Some(utf8(text(&r.operands, r.at)?, r.at)?),
2131                    4 => m.asm = Some(utf8(text(&r.operands, r.at)?, r.at)?),
2132                    5 => sections.push(utf8(text(&r.operands, r.at)?, r.at)?),
2133                    11 => gcs.push(utf8(text(&r.operands, r.at)?, r.at)?),
2134                    6 | 13 | 16 => {} // deplib, the symbol table's offset, source file
2135                    7 => {
2136                        // GLOBALVAR: [type, flags (bit 0 constant, bit 1 explicit type, from bit 2 the address space),
2137                        // initial value + 1 or 0, linkage, alignment, section, visibility, thread local, unnamed_addr,
2138                        // externally initialized, DLL storage, comdat]
2139                        let t = m.ty(op(r, 0)?, r.at)?;
2140                        let flags = op(r, 1)?;
2141                        let (ty, value_ty, address_space) = if flags & 2 != 0 {
2142                            let space =
2143                                u32::try_from(flags >> 2).map_err(|_| error(r.at, "address space"))?;
2144                            (m.intern(Type::Pointer(t, space)), t, space)
2145                        } else {
2146                            match m.type_at(t, r.at)? {
2147                                Type::Pointer(inner, space) => (t, *inner, *space),
2148                                _ => return Err(error(r.at, "a global whose type is not a pointer")),
2149                            }
2150                        };
2151                        let init = match op(r, 2)? {
2152                            0 => None,
2153                            n => Some(
2154                                usize::try_from(n.saturating_sub(1))
2155                                    .map_err(|_| error(r.at, "initial value id"))?,
2156                            ),
2157                        };
2158                        let properties = global_properties(r, 3, 4, 5, 6, 8, 10, 11, &sections)?;
2159                        m.push(
2160                            Value::Global {
2161                                ty,
2162                                value_ty,
2163                                init,
2164                                constant: flags & 1 != 0,
2165                                address_space,
2166                                properties,
2167                                thread_local: u8::try_from(r.operands.get(7).copied().unwrap_or(0))
2168                                    .ok()
2169                                    .filter(|&t| t <= 4)
2170                                    .ok_or_else(|| error(r.at, "thread-local model"))?,
2171                                externally_initialized: r.operands.get(9).is_some_and(|&v| v != 0),
2172                            },
2173                            ty,
2174                            r.at,
2175                        )?;
2176                    }
2177                    8 => {
2178                        // FUNCTION: [function type, calling convention, declaration, linkage, attribute list + 1 or 0,
2179                        // alignment, section, visibility, gc, unnamed_addr, prologue, DLL storage, comdat, prefix,
2180                        // personality]
2181                        let t = m.ty(op(r, 0)?, r.at)?;
2182                        let pointer = m.intern(Type::Pointer(t, 0));
2183                        let declaration = op(r, 2)? != 0;
2184                        // the attribute list is named by its 1-based index (0 for none)
2185                        let attributes = r
2186                            .operands
2187                            .get(4)
2188                            .and_then(|&n| usize::try_from(n).ok())
2189                            .and_then(|n| n.checked_sub(1));
2190                        for (field, what) in [
2191                            (10, "prologue data"),
2192                            (13, "prefix data"),
2193                            (14, "a personality function"),
2194                        ] {
2195                            if r.operands.get(field).is_some_and(|&v| v != 0) {
2196                                return Err(error(r.at, format!("a function with {what} is not supported")));
2197                            }
2198                        }
2199                        let gc = match r.operands.get(8).copied().unwrap_or(0) {
2200                            0 => None,
2201                            n => Some(
2202                                usize::try_from(n.saturating_sub(1))
2203                                    .ok()
2204                                    .and_then(|n| gcs.get(n))
2205                                    .cloned()
2206                                    .ok_or_else(|| {
2207                                        error(r.at, "a function names a garbage collector the module lacks")
2208                                    })?,
2209                            ),
2210                        };
2211                        let v = m.push(
2212                            Value::Function {
2213                                ty: t,
2214                                declaration,
2215                                attributes,
2216                                properties: global_properties(r, 3, 5, 6, 7, 9, 11, 12, &sections)?,
2217                                calling_conv: op(r, 1)?,
2218                                gc,
2219                            },
2220                            pointer,
2221                            r.at,
2222                        )?;
2223                        if !declaration {
2224                            bodies.push(v);
2225                        }
2226                    }
2227                    other => return Err(error(r.at, format!("module record {other}"))),
2228                },
2229                crate::bitstream::Element::Block(b) => match b.id {
2230                    BLOCKINFO | USELIST => {}
2231                    PARAMATTR_GROUP => m.read_attribute_groups(b)?,
2232                    PARAMATTR => m.read_attribute_lists(b),
2233                    TYPES => m.read_types(b)?,
2234                    CONSTANTS => m.read_constants(b)?,
2235                    METADATA => m.read_metadata(b)?,
2236                    VALUE_SYMTAB => {
2237                        let (values, blocks) = read_symbols(b)?;
2238                        if let Some((_, name)) = blocks.first() {
2239                            return Err(error(
2240                                b.at,
2241                                format!("a basic block name ({name}) in the module's symbol table"),
2242                            ));
2243                        }
2244                        m.names.extend(values);
2245                    }
2246                    FUNCTION => {
2247                        if version != Some(1) {
2248                            return Err(error(b.at, "only relative value ids (module version 1)"));
2249                        }
2250                        // Bodies are stored in the order of their definitions (a hull program has two).
2251                        if bodies.is_empty() {
2252                            return Err(error(b.at, "function body without a definition"));
2253                        }
2254                        let value = bodies.remove(0);
2255                        // A body's values are its own; the next body numbers from the module's values again.
2256                        let f = m.read_function(b, value)?;
2257                        m.functions.push(f);
2258                    }
2259                    other => return Err(error(b.at, format!("module block {other}"))),
2260                },
2261            }
2262        }
2263        if !bodies.is_empty() {
2264            return Err(error(module.at, "a defined function has no body"));
2265        }
2266        Ok(m)
2267    }
2268}