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 ¶ms {
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, §ions)?;
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, §ions)?,
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}