Skip to main content

llvm_bitcode/
reader.rs

1//! Bitcode reader: parses the LRIR binary format and reconstructs a `(Context, Module)`.
2
3use crate::error::BitcodeError;
4use llvm_ir::value::Argument;
5use llvm_ir::{
6    ArgId, BasicBlock, BlockId, ConstId, ConstantData, Context, FastMathFlags, FloatKind,
7    FloatPredicate, Function, GlobalId, InstrId, InstrKind, Instruction, IntArithFlags,
8    IntPredicate, Linkage, Module, TailCallKind, TypeData, TypeId, ValueRef,
9};
10
11/// Magic bytes for the LRIR format.
12const MAGIC: &[u8; 4] = b"LRIR";
13
14/// Parse a LRIR binary blob and reconstruct `(Context, Module)`.
15pub fn read_bitcode(bytes: &[u8]) -> Result<(Context, Module), BitcodeError> {
16    let mut r = Reader::new(bytes);
17
18    // ── header ────────────────────────────────────────────────────────────
19    let magic = r.read_bytes(4)?;
20    if magic != MAGIC {
21        return Err(BitcodeError::InvalidMagic);
22    }
23    let version = r.u32()?;
24    if version != 1 {
25        return Err(BitcodeError::ParseError(format!(
26            "unsupported version {}",
27            version
28        )));
29    }
30
31    // ── type table ────────────────────────────────────────────────────────
32    let mut ctx = Context::new();
33    let type_count = r.u32()? as usize;
34    // We'll collect the types as raw TypeData first; the Context will
35    // intern them in order.  We need a mapping from serialized TypeId → interned TypeId.
36    let mut type_id_map: Vec<TypeId> = Vec::with_capacity(type_count);
37
38    for _ in 0..type_count {
39        let td = decode_type(&mut r, &type_id_map)?;
40        // Intern the type and record the mapping.
41        let interned = intern_type(&mut ctx, td);
42        type_id_map.push(interned);
43    }
44
45    // ── constant table ─────────────────────────────────────────────────────
46    let const_count = r.u32()? as usize;
47    let mut const_id_map: Vec<ConstId> = Vec::with_capacity(const_count);
48
49    for _ in 0..const_count {
50        let cd = decode_const(&mut r, &type_id_map, &const_id_map)?;
51        let cid = ctx.push_const(cd);
52        const_id_map.push(cid);
53    }
54
55    // ── module header ──────────────────────────────────────────────────────
56    let module_name = r.string()?;
57    let mut module = Module::new(module_name);
58
59    // ── functions ──────────────────────────────────────────────────────────
60    let func_count = r.u32()? as usize;
61    for _ in 0..func_count {
62        let func = decode_function(&mut r, &type_id_map, &const_id_map)?;
63        module.add_function(func);
64    }
65
66    Ok((ctx, module))
67}
68
69// ── type decoding ──────────────────────────────────────────────────────────
70
71mod type_tag {
72    /// Public API for `VOID`.
73    pub const VOID: u8 = 0;
74    /// Public API for `INTEGER`.
75    pub const INTEGER: u8 = 1;
76    /// Public API for `FLOAT`.
77    pub const FLOAT: u8 = 2;
78    /// Public API for `POINTER`.
79    pub const POINTER: u8 = 3;
80    /// Public API for `ARRAY`.
81    pub const ARRAY: u8 = 4;
82    /// Public API for `VECTOR`.
83    pub const VECTOR: u8 = 5;
84    /// Public API for `STRUCT`.
85    pub const STRUCT: u8 = 6;
86    /// Public API for `FUNCTION`.
87    pub const FUNCTION: u8 = 7;
88    /// Public API for `LABEL`.
89    pub const LABEL: u8 = 8;
90    /// Public API for `METADATA`.
91    pub const METADATA: u8 = 9;
92}
93
94mod float_tag {
95    /// Public API for `HALF`.
96    pub const HALF: u8 = 0;
97    /// Public API for `BFLOAT`.
98    pub const BFLOAT: u8 = 1;
99    /// Public API for `SINGLE`.
100    pub const SINGLE: u8 = 2;
101    /// Public API for `DOUBLE`.
102    pub const DOUBLE: u8 = 3;
103    /// Public API for `FP128`.
104    pub const FP128: u8 = 4;
105    /// Public API for `X86FP80`.
106    pub const X86FP80: u8 = 5;
107}
108
109/// Decode a TypeData from the stream, resolving type IDs via `type_id_map`.
110fn decode_type(r: &mut Reader, type_id_map: &[TypeId]) -> Result<TypeData, BitcodeError> {
111    let tag = r.u8()?;
112    match tag {
113        type_tag::VOID => Ok(TypeData::Void),
114        type_tag::INTEGER => {
115            let bits = r.u32()?;
116            Ok(TypeData::Integer(bits))
117        }
118        type_tag::FLOAT => {
119            let ftag = r.u8()?;
120            let kind = match ftag {
121                float_tag::HALF => FloatKind::Half,
122                float_tag::BFLOAT => FloatKind::BFloat,
123                float_tag::SINGLE => FloatKind::Single,
124                float_tag::DOUBLE => FloatKind::Double,
125                float_tag::FP128 => FloatKind::Fp128,
126                float_tag::X86FP80 => FloatKind::X86Fp80,
127                _ => return Err(BitcodeError::InvalidType),
128            };
129            Ok(TypeData::Float(kind))
130        }
131        type_tag::POINTER => Ok(TypeData::Pointer),
132        type_tag::ARRAY => {
133            let elem_raw = r.u32()? as usize;
134            let len = r.u64()?;
135            let element = map_type_id(type_id_map, elem_raw)?;
136            Ok(TypeData::Array { element, len })
137        }
138        type_tag::VECTOR => {
139            let elem_raw = r.u32()? as usize;
140            let len = r.u32()?;
141            let scalable = r.u8()? != 0;
142            let element = map_type_id(type_id_map, elem_raw)?;
143            Ok(TypeData::Vector {
144                element,
145                len,
146                scalable,
147            })
148        }
149        type_tag::STRUCT => {
150            let name = r.opt_string()?;
151            let packed = r.u8()? != 0;
152            let field_count = r.u32()? as usize;
153            let mut fields = Vec::with_capacity(field_count);
154            for _ in 0..field_count {
155                let fid_raw = r.u32()? as usize;
156                fields.push(map_type_id(type_id_map, fid_raw)?);
157            }
158            Ok(TypeData::Struct(llvm_ir::StructType {
159                name,
160                fields,
161                packed,
162            }))
163        }
164        type_tag::FUNCTION => {
165            let ret_raw = r.u32()? as usize;
166            let variadic = r.u8()? != 0;
167            let param_count = r.u32()? as usize;
168            let mut params = Vec::with_capacity(param_count);
169            for _ in 0..param_count {
170                let pid_raw = r.u32()? as usize;
171                params.push(map_type_id(type_id_map, pid_raw)?);
172            }
173            let ret = map_type_id(type_id_map, ret_raw)?;
174            Ok(TypeData::Function(llvm_ir::FunctionType {
175                ret,
176                params,
177                variadic,
178            }))
179        }
180        type_tag::LABEL => Ok(TypeData::Label),
181        type_tag::METADATA => Ok(TypeData::Metadata),
182        _ => Err(BitcodeError::InvalidType),
183    }
184}
185
186fn map_type_id(type_id_map: &[TypeId], raw: usize) -> Result<TypeId, BitcodeError> {
187    type_id_map.get(raw).copied().ok_or_else(|| {
188        BitcodeError::ParseError(format!(
189            "type id {} out of range (table size {})",
190            raw,
191            type_id_map.len()
192        ))
193    })
194}
195
196fn map_const_id(const_id_map: &[ConstId], raw: usize) -> Result<ConstId, BitcodeError> {
197    const_id_map
198        .get(raw)
199        .copied()
200        .ok_or_else(|| BitcodeError::ParseError(format!("const id {} out of range", raw)))
201}
202
203/// Intern a TypeData into the Context and return the TypeId.
204fn intern_type(ctx: &mut Context, td: TypeData) -> TypeId {
205    match td {
206        TypeData::Void => ctx.void_ty,
207        TypeData::Integer(b) => ctx.mk_int(b),
208        TypeData::Float(k) => ctx.mk_float(k),
209        TypeData::Pointer => ctx.mk_ptr(),
210        TypeData::Label => ctx.mk_label(),
211        TypeData::Metadata => ctx.mk_metadata(),
212        TypeData::Array { element, len } => ctx.mk_array(element, len),
213        TypeData::Vector {
214            element,
215            len,
216            scalable,
217        } => ctx.mk_vector(element, len, scalable),
218        TypeData::Struct(st) => {
219            if let Some(ref name) = st.name {
220                let id = ctx.mk_struct_named(name.clone());
221                ctx.define_struct_body(id, st.fields, st.packed);
222                id
223            } else {
224                ctx.mk_struct_anon(st.fields, st.packed)
225            }
226        }
227        TypeData::Function(ft) => ctx.mk_fn_type(ft.ret, ft.params, ft.variadic),
228    }
229}
230
231// ── constant decoding ─────────────────────────────────────────────────────
232
233mod const_tag {
234    /// Public API for `INT`.
235    pub const INT: u8 = 0;
236    /// Public API for `INT_WIDE`.
237    pub const INT_WIDE: u8 = 1;
238    /// Public API for `FLOAT`.
239    pub const FLOAT: u8 = 2;
240    /// Public API for `NULL`.
241    pub const NULL: u8 = 3;
242    /// Public API for `UNDEF`.
243    pub const UNDEF: u8 = 4;
244    /// Public API for `POISON`.
245    pub const POISON: u8 = 5;
246    /// Public API for `ZERO_INIT`.
247    pub const ZERO_INIT: u8 = 6;
248    /// Public API for `ARRAY`.
249    pub const ARRAY: u8 = 7;
250    /// Public API for `STRUCT`.
251    pub const STRUCT: u8 = 8;
252    /// Public API for `VECTOR`.
253    pub const VECTOR: u8 = 9;
254    /// Public API for `GLOBAL_REF`.
255    pub const GLOBAL_REF: u8 = 10;
256}
257
258fn decode_const(
259    r: &mut Reader,
260    type_id_map: &[TypeId],
261    const_id_map: &[ConstId],
262) -> Result<ConstantData, BitcodeError> {
263    let tag = r.u8()?;
264    match tag {
265        const_tag::INT => {
266            let ty = map_type_id(type_id_map, r.u32()? as usize)?;
267            let val = r.u64()?;
268            Ok(ConstantData::Int { ty, val })
269        }
270        const_tag::INT_WIDE => {
271            let ty = map_type_id(type_id_map, r.u32()? as usize)?;
272            let word_count = r.u32()? as usize;
273            let mut words = Vec::with_capacity(word_count);
274            for _ in 0..word_count {
275                words.push(r.u64()?);
276            }
277            Ok(ConstantData::IntWide { ty, words })
278        }
279        const_tag::FLOAT => {
280            let ty = map_type_id(type_id_map, r.u32()? as usize)?;
281            let bits = r.u64()?;
282            Ok(ConstantData::Float { ty, bits })
283        }
284        const_tag::NULL => {
285            let ty = map_type_id(type_id_map, r.u32()? as usize)?;
286            Ok(ConstantData::Null(ty))
287        }
288        const_tag::UNDEF => {
289            let ty = map_type_id(type_id_map, r.u32()? as usize)?;
290            Ok(ConstantData::Undef(ty))
291        }
292        const_tag::POISON => {
293            let ty = map_type_id(type_id_map, r.u32()? as usize)?;
294            Ok(ConstantData::Poison(ty))
295        }
296        const_tag::ZERO_INIT => {
297            let ty = map_type_id(type_id_map, r.u32()? as usize)?;
298            Ok(ConstantData::ZeroInitializer(ty))
299        }
300        const_tag::ARRAY => {
301            let ty = map_type_id(type_id_map, r.u32()? as usize)?;
302            let n = r.u32()? as usize;
303            let mut elems = Vec::with_capacity(n);
304            for _ in 0..n {
305                elems.push(map_const_id(const_id_map, r.u32()? as usize)?);
306            }
307            Ok(ConstantData::Array {
308                ty,
309                elements: elems,
310            })
311        }
312        const_tag::STRUCT => {
313            let ty = map_type_id(type_id_map, r.u32()? as usize)?;
314            let n = r.u32()? as usize;
315            let mut fields = Vec::with_capacity(n);
316            for _ in 0..n {
317                fields.push(map_const_id(const_id_map, r.u32()? as usize)?);
318            }
319            Ok(ConstantData::Struct { ty, fields })
320        }
321        const_tag::VECTOR => {
322            let ty = map_type_id(type_id_map, r.u32()? as usize)?;
323            let n = r.u32()? as usize;
324            let mut elems = Vec::with_capacity(n);
325            for _ in 0..n {
326                elems.push(map_const_id(const_id_map, r.u32()? as usize)?);
327            }
328            Ok(ConstantData::Vector {
329                ty,
330                elements: elems,
331            })
332        }
333        const_tag::GLOBAL_REF => {
334            let ty = map_type_id(type_id_map, r.u32()? as usize)?;
335            let id_raw = r.u32()?;
336            let name = r.string()?;
337            Ok(ConstantData::GlobalRef {
338                ty,
339                id: GlobalId(id_raw),
340                name,
341            })
342        }
343        other => Err(BitcodeError::UnsupportedRecord(other as u32)),
344    }
345}
346
347// ── function decoding ─────────────────────────────────────────────────────
348
349mod linkage_tag {
350    /// Public API for `PRIVATE`.
351    pub const PRIVATE: u8 = 0;
352    /// Public API for `INTERNAL`.
353    pub const INTERNAL: u8 = 1;
354    /// Public API for `EXTERNAL`.
355    pub const EXTERNAL: u8 = 2;
356    /// Public API for `WEAK`.
357    pub const WEAK: u8 = 3;
358    /// Public API for `WEAK_ODR`.
359    pub const WEAK_ODR: u8 = 4;
360    /// Public API for `LINK_ONCE`.
361    pub const LINK_ONCE: u8 = 5;
362    /// Public API for `LINK_ONCE_ODR`.
363    pub const LINK_ONCE_ODR: u8 = 6;
364    /// Public API for `COMMON`.
365    pub const COMMON: u8 = 7;
366    /// Public API for `AVAILABLE_EXTERNALLY`.
367    pub const AVAILABLE_EXTERNALLY: u8 = 8;
368}
369
370fn decode_linkage(tag: u8) -> Result<Linkage, BitcodeError> {
371    match tag {
372        linkage_tag::PRIVATE => Ok(Linkage::Private),
373        linkage_tag::INTERNAL => Ok(Linkage::Internal),
374        linkage_tag::EXTERNAL => Ok(Linkage::External),
375        linkage_tag::WEAK => Ok(Linkage::Weak),
376        linkage_tag::WEAK_ODR => Ok(Linkage::WeakOdr),
377        linkage_tag::LINK_ONCE => Ok(Linkage::LinkOnce),
378        linkage_tag::LINK_ONCE_ODR => Ok(Linkage::LinkOnceOdr),
379        linkage_tag::COMMON => Ok(Linkage::Common),
380        linkage_tag::AVAILABLE_EXTERNALLY => Ok(Linkage::AvailableExternally),
381        other => Err(BitcodeError::UnsupportedRecord(other as u32)),
382    }
383}
384
385fn decode_function(
386    r: &mut Reader,
387    type_id_map: &[TypeId],
388    const_id_map: &[ConstId],
389) -> Result<Function, BitcodeError> {
390    let name = r.string()?;
391    let ty_raw = r.u32()? as usize;
392    let ty = map_type_id(type_id_map, ty_raw)?;
393    let linkage = decode_linkage(r.u8()?)?;
394    let is_declaration = r.u8()? != 0;
395
396    // Arguments.
397    let arg_count = r.u32()? as usize;
398    let mut args = Vec::with_capacity(arg_count);
399    for _ in 0..arg_count {
400        let aname = r.string()?;
401        let aty_raw = r.u32()? as usize;
402        let aty = map_type_id(type_id_map, aty_raw)?;
403        let index = r.u32()?;
404        args.push(Argument {
405            name: aname,
406            ty: aty,
407            index,
408        });
409    }
410
411    let mut func = if is_declaration {
412        Function::new_declaration(name, ty, args, linkage)
413    } else {
414        Function::new(name, ty, args, linkage)
415    };
416    func.is_declaration = is_declaration;
417
418    // Read flat instruction pool first (needed for block body references).
419    let block_count = r.u32()? as usize;
420    // Save block records for later (after we read the instruction pool).
421    let mut block_records: Vec<(String, Vec<u32>, u32)> = Vec::with_capacity(block_count);
422    for _ in 0..block_count {
423        let bname = r.string()?;
424        let body_count = r.u32()? as usize;
425        let mut body = Vec::with_capacity(body_count);
426        for _ in 0..body_count {
427            body.push(r.u32()?);
428        }
429        let term = r.u32()?;
430        block_records.push((bname, body, term));
431    }
432
433    // Flat instruction pool.
434    let instr_count = r.u32()? as usize;
435    for _ in 0..instr_count {
436        let instr = decode_instr(r, type_id_map, const_id_map)?;
437        func.alloc_instr(instr);
438    }
439
440    // Reconstruct basic blocks.
441    for (bname, body_ids, term_raw) in block_records {
442        let mut bb = BasicBlock::new(bname);
443        for id in body_ids {
444            bb.body.push(InstrId(id));
445        }
446        bb.terminator = if term_raw == 0xFFFF_FFFF {
447            None
448        } else {
449            Some(InstrId(term_raw))
450        };
451        func.blocks.push(bb);
452    }
453
454    Ok(func)
455}
456
457// ── instruction decoding ──────────────────────────────────────────────────
458
459mod instr_tag {
460    /// Public API for `ADD`.
461    pub const ADD: u32 = 0;
462    /// Public API for `SUB`.
463    pub const SUB: u32 = 1;
464    /// Public API for `MUL`.
465    pub const MUL: u32 = 2;
466    /// Public API for `UDIV`.
467    pub const UDIV: u32 = 3;
468    /// Public API for `SDIV`.
469    pub const SDIV: u32 = 4;
470    /// Public API for `UREM`.
471    pub const UREM: u32 = 5;
472    /// Public API for `SREM`.
473    pub const SREM: u32 = 6;
474    /// Public API for `AND`.
475    pub const AND: u32 = 10;
476    /// Public API for `OR`.
477    pub const OR: u32 = 11;
478    /// Public API for `XOR`.
479    pub const XOR: u32 = 12;
480    /// Public API for `SHL`.
481    pub const SHL: u32 = 13;
482    /// Public API for `LSHR`.
483    pub const LSHR: u32 = 14;
484    /// Public API for `ASHR`.
485    pub const ASHR: u32 = 15;
486    /// Public API for `FADD`.
487    pub const FADD: u32 = 20;
488    /// Public API for `FSUB`.
489    pub const FSUB: u32 = 21;
490    /// Public API for `FMUL`.
491    pub const FMUL: u32 = 22;
492    /// Public API for `FDIV`.
493    pub const FDIV: u32 = 23;
494    /// Public API for `FREM`.
495    pub const FREM: u32 = 24;
496    /// Public API for `FNEG`.
497    pub const FNEG: u32 = 25;
498    /// Public API for `ICMP`.
499    pub const ICMP: u32 = 30;
500    /// Public API for `FCMP`.
501    pub const FCMP: u32 = 31;
502    /// Public API for `ALLOCA`.
503    pub const ALLOCA: u32 = 40;
504    /// Public API for `LOAD`.
505    pub const LOAD: u32 = 41;
506    /// Public API for `STORE`.
507    pub const STORE: u32 = 42;
508    /// Public API for `GEP`.
509    pub const GEP: u32 = 43;
510    /// Public API for `TRUNC`.
511    pub const TRUNC: u32 = 50;
512    /// Public API for `ZEXT`.
513    pub const ZEXT: u32 = 51;
514    /// Public API for `SEXT`.
515    pub const SEXT: u32 = 52;
516    /// Public API for `FPTRUNC`.
517    pub const FPTRUNC: u32 = 53;
518    /// Public API for `FPEXT`.
519    pub const FPEXT: u32 = 54;
520    /// Public API for `FPTOUI`.
521    pub const FPTOUI: u32 = 55;
522    /// Public API for `FPTOSI`.
523    pub const FPTOSI: u32 = 56;
524    /// Public API for `UITOFP`.
525    pub const UITOFP: u32 = 57;
526    /// Public API for `SITOFP`.
527    pub const SITOFP: u32 = 58;
528    /// Public API for `PTRTOINT`.
529    pub const PTRTOINT: u32 = 59;
530    /// Public API for `INTTOPTR`.
531    pub const INTTOPTR: u32 = 60;
532    /// Public API for `BITCAST`.
533    pub const BITCAST: u32 = 61;
534    /// Public API for `ADDRSPACECAST`.
535    pub const ADDRSPACECAST: u32 = 62;
536    /// Public API for `FREEZE`.
537    pub const FREEZE: u32 = 63;
538    /// Public API for `SELECT`.
539    pub const SELECT: u32 = 70;
540    /// Public API for `PHI`.
541    pub const PHI: u32 = 71;
542    /// Public API for `EXTRACTVALUE`.
543    pub const EXTRACTVALUE: u32 = 72;
544    /// Public API for `INSERTVALUE`.
545    pub const INSERTVALUE: u32 = 73;
546    /// Public API for `EXTRACTELEM`.
547    pub const EXTRACTELEM: u32 = 74;
548    /// Public API for `INSERTELEM`.
549    pub const INSERTELEM: u32 = 75;
550    /// Public API for `SHUFFLEVEC`.
551    pub const SHUFFLEVEC: u32 = 76;
552    /// Public API for `CALL`.
553    pub const CALL: u32 = 80;
554    /// Public API for `RET`.
555    pub const RET: u32 = 90;
556    /// Public API for `BR`.
557    pub const BR: u32 = 91;
558    /// Public API for `CONDBR`.
559    pub const CONDBR: u32 = 92;
560    /// Public API for `SWITCH`.
561    pub const SWITCH: u32 = 93;
562    /// Public API for `UNREACHABLE`.
563    pub const UNREACHABLE: u32 = 94;
564}
565
566fn decode_vref(r: &mut Reader) -> Result<ValueRef, BitcodeError> {
567    let tag = r.u8()?;
568    let id = r.u32()?;
569    match tag {
570        0 => Ok(ValueRef::Instruction(InstrId(id))),
571        1 => Ok(ValueRef::Argument(ArgId(id))),
572        2 => Ok(ValueRef::Constant(ConstId(id))),
573        3 => Ok(ValueRef::Global(GlobalId(id))),
574        other => Err(BitcodeError::UnsupportedRecord(other as u32)),
575    }
576}
577
578fn decode_opt_vref(r: &mut Reader) -> Result<Option<ValueRef>, BitcodeError> {
579    let present = r.u8()?;
580    if present != 0 {
581        Ok(Some(decode_vref(r)?))
582    } else {
583        Ok(None)
584    }
585}
586
587fn decode_opt_u32(r: &mut Reader) -> Result<Option<u32>, BitcodeError> {
588    let present = r.u8()?;
589    if present != 0 {
590        Ok(Some(r.u32()?))
591    } else {
592        Ok(None)
593    }
594}
595
596fn decode_int_pred(tag: u8) -> Result<IntPredicate, BitcodeError> {
597    match tag {
598        0 => Ok(IntPredicate::Eq),
599        1 => Ok(IntPredicate::Ne),
600        2 => Ok(IntPredicate::Ugt),
601        3 => Ok(IntPredicate::Uge),
602        4 => Ok(IntPredicate::Ult),
603        5 => Ok(IntPredicate::Ule),
604        6 => Ok(IntPredicate::Sgt),
605        7 => Ok(IntPredicate::Sge),
606        8 => Ok(IntPredicate::Slt),
607        9 => Ok(IntPredicate::Sle),
608        other => Err(BitcodeError::UnsupportedRecord(other as u32)),
609    }
610}
611
612fn decode_float_pred(tag: u8) -> Result<FloatPredicate, BitcodeError> {
613    match tag {
614        0 => Ok(FloatPredicate::False),
615        1 => Ok(FloatPredicate::Oeq),
616        2 => Ok(FloatPredicate::Ogt),
617        3 => Ok(FloatPredicate::Oge),
618        4 => Ok(FloatPredicate::Olt),
619        5 => Ok(FloatPredicate::Ole),
620        6 => Ok(FloatPredicate::One),
621        7 => Ok(FloatPredicate::Ord),
622        8 => Ok(FloatPredicate::Uno),
623        9 => Ok(FloatPredicate::Ueq),
624        10 => Ok(FloatPredicate::Ugt),
625        11 => Ok(FloatPredicate::Uge),
626        12 => Ok(FloatPredicate::Ult),
627        13 => Ok(FloatPredicate::Ule),
628        14 => Ok(FloatPredicate::Une),
629        15 => Ok(FloatPredicate::True),
630        other => Err(BitcodeError::UnsupportedRecord(other as u32)),
631    }
632}
633
634fn decode_instr(
635    r: &mut Reader,
636    type_id_map: &[TypeId],
637    _const_id_map: &[ConstId],
638) -> Result<Instruction, BitcodeError> {
639    // Name: 0-length = None.
640    let name = r.opt_string()?;
641    let ty_raw = r.u32()? as usize;
642    let ty = map_type_id(type_id_map, ty_raw)?;
643    let tag = r.u32()?;
644
645    let kind = match tag {
646        instr_tag::ADD => {
647            let nuw = r.u8()? != 0;
648            let nsw = r.u8()? != 0;
649            let flags = IntArithFlags { nuw, nsw };
650            InstrKind::Add {
651                flags,
652                lhs: decode_vref(r)?,
653                rhs: decode_vref(r)?,
654            }
655        }
656        instr_tag::SUB => {
657            let nuw = r.u8()? != 0;
658            let nsw = r.u8()? != 0;
659            let flags = IntArithFlags { nuw, nsw };
660            InstrKind::Sub {
661                flags,
662                lhs: decode_vref(r)?,
663                rhs: decode_vref(r)?,
664            }
665        }
666        instr_tag::MUL => {
667            let nuw = r.u8()? != 0;
668            let nsw = r.u8()? != 0;
669            let flags = IntArithFlags { nuw, nsw };
670            InstrKind::Mul {
671                flags,
672                lhs: decode_vref(r)?,
673                rhs: decode_vref(r)?,
674            }
675        }
676        instr_tag::UDIV => {
677            let exact = r.u8()? != 0;
678            InstrKind::UDiv {
679                exact,
680                lhs: decode_vref(r)?,
681                rhs: decode_vref(r)?,
682            }
683        }
684        instr_tag::SDIV => {
685            let exact = r.u8()? != 0;
686            InstrKind::SDiv {
687                exact,
688                lhs: decode_vref(r)?,
689                rhs: decode_vref(r)?,
690            }
691        }
692        instr_tag::UREM => InstrKind::URem {
693            lhs: decode_vref(r)?,
694            rhs: decode_vref(r)?,
695        },
696        instr_tag::SREM => InstrKind::SRem {
697            lhs: decode_vref(r)?,
698            rhs: decode_vref(r)?,
699        },
700        instr_tag::AND => InstrKind::And {
701            lhs: decode_vref(r)?,
702            rhs: decode_vref(r)?,
703        },
704        instr_tag::OR => InstrKind::Or {
705            lhs: decode_vref(r)?,
706            rhs: decode_vref(r)?,
707        },
708        instr_tag::XOR => InstrKind::Xor {
709            lhs: decode_vref(r)?,
710            rhs: decode_vref(r)?,
711        },
712        instr_tag::SHL => {
713            let nuw = r.u8()? != 0;
714            let nsw = r.u8()? != 0;
715            let flags = IntArithFlags { nuw, nsw };
716            InstrKind::Shl {
717                flags,
718                lhs: decode_vref(r)?,
719                rhs: decode_vref(r)?,
720            }
721        }
722        instr_tag::LSHR => {
723            let exact = r.u8()? != 0;
724            InstrKind::LShr {
725                exact,
726                lhs: decode_vref(r)?,
727                rhs: decode_vref(r)?,
728            }
729        }
730        instr_tag::ASHR => {
731            let exact = r.u8()? != 0;
732            InstrKind::AShr {
733                exact,
734                lhs: decode_vref(r)?,
735                rhs: decode_vref(r)?,
736            }
737        }
738        instr_tag::FADD => InstrKind::FAdd {
739            flags: FastMathFlags::default(),
740            lhs: decode_vref(r)?,
741            rhs: decode_vref(r)?,
742        },
743        instr_tag::FSUB => InstrKind::FSub {
744            flags: FastMathFlags::default(),
745            lhs: decode_vref(r)?,
746            rhs: decode_vref(r)?,
747        },
748        instr_tag::FMUL => InstrKind::FMul {
749            flags: FastMathFlags::default(),
750            lhs: decode_vref(r)?,
751            rhs: decode_vref(r)?,
752        },
753        instr_tag::FDIV => InstrKind::FDiv {
754            flags: FastMathFlags::default(),
755            lhs: decode_vref(r)?,
756            rhs: decode_vref(r)?,
757        },
758        instr_tag::FREM => InstrKind::FRem {
759            flags: FastMathFlags::default(),
760            lhs: decode_vref(r)?,
761            rhs: decode_vref(r)?,
762        },
763        instr_tag::FNEG => InstrKind::FNeg {
764            flags: FastMathFlags::default(),
765            operand: decode_vref(r)?,
766        },
767        instr_tag::ICMP => {
768            let pred = decode_int_pred(r.u8()?)?;
769            InstrKind::ICmp {
770                pred,
771                lhs: decode_vref(r)?,
772                rhs: decode_vref(r)?,
773            }
774        }
775        instr_tag::FCMP => {
776            let pred = decode_float_pred(r.u8()?)?;
777            InstrKind::FCmp {
778                flags: FastMathFlags::default(),
779                pred,
780                lhs: decode_vref(r)?,
781                rhs: decode_vref(r)?,
782            }
783        }
784        instr_tag::ALLOCA => {
785            let alloc_ty = map_type_id(type_id_map, r.u32()? as usize)?;
786            let num_elements = decode_opt_vref(r)?;
787            let align = decode_opt_u32(r)?;
788            InstrKind::Alloca {
789                alloc_ty,
790                num_elements,
791                align,
792            }
793        }
794        instr_tag::LOAD => {
795            let lty = map_type_id(type_id_map, r.u32()? as usize)?;
796            let ptr = decode_vref(r)?;
797            let align = decode_opt_u32(r)?;
798            let volatile = r.u8()? != 0;
799            InstrKind::Load {
800                ty: lty,
801                ptr,
802                align,
803                volatile,
804            }
805        }
806        instr_tag::STORE => {
807            let val = decode_vref(r)?;
808            let ptr = decode_vref(r)?;
809            let align = decode_opt_u32(r)?;
810            let volatile = r.u8()? != 0;
811            InstrKind::Store {
812                val,
813                ptr,
814                align,
815                volatile,
816            }
817        }
818        instr_tag::GEP => {
819            let inbounds = r.u8()? != 0;
820            let base_ty = map_type_id(type_id_map, r.u32()? as usize)?;
821            let ptr = decode_vref(r)?;
822            let idx_count = r.u32()? as usize;
823            let mut indices = Vec::with_capacity(idx_count);
824            for _ in 0..idx_count {
825                indices.push(decode_vref(r)?);
826            }
827            InstrKind::GetElementPtr {
828                inbounds,
829                base_ty,
830                ptr,
831                indices,
832            }
833        }
834        instr_tag::TRUNC => {
835            let val = decode_vref(r)?;
836            let to = map_type_id(type_id_map, r.u32()? as usize)?;
837            InstrKind::Trunc { val, to }
838        }
839        instr_tag::ZEXT => {
840            let val = decode_vref(r)?;
841            let to = map_type_id(type_id_map, r.u32()? as usize)?;
842            InstrKind::ZExt { val, to }
843        }
844        instr_tag::SEXT => {
845            let val = decode_vref(r)?;
846            let to = map_type_id(type_id_map, r.u32()? as usize)?;
847            InstrKind::SExt { val, to }
848        }
849        instr_tag::FPTRUNC => {
850            let val = decode_vref(r)?;
851            let to = map_type_id(type_id_map, r.u32()? as usize)?;
852            InstrKind::FPTrunc { val, to }
853        }
854        instr_tag::FPEXT => {
855            let val = decode_vref(r)?;
856            let to = map_type_id(type_id_map, r.u32()? as usize)?;
857            InstrKind::FPExt { val, to }
858        }
859        instr_tag::FPTOUI => {
860            let val = decode_vref(r)?;
861            let to = map_type_id(type_id_map, r.u32()? as usize)?;
862            InstrKind::FPToUI { val, to }
863        }
864        instr_tag::FPTOSI => {
865            let val = decode_vref(r)?;
866            let to = map_type_id(type_id_map, r.u32()? as usize)?;
867            InstrKind::FPToSI { val, to }
868        }
869        instr_tag::UITOFP => {
870            let val = decode_vref(r)?;
871            let to = map_type_id(type_id_map, r.u32()? as usize)?;
872            InstrKind::UIToFP { val, to }
873        }
874        instr_tag::SITOFP => {
875            let val = decode_vref(r)?;
876            let to = map_type_id(type_id_map, r.u32()? as usize)?;
877            InstrKind::SIToFP { val, to }
878        }
879        instr_tag::PTRTOINT => {
880            let val = decode_vref(r)?;
881            let to = map_type_id(type_id_map, r.u32()? as usize)?;
882            InstrKind::PtrToInt { val, to }
883        }
884        instr_tag::INTTOPTR => {
885            let val = decode_vref(r)?;
886            let to = map_type_id(type_id_map, r.u32()? as usize)?;
887            InstrKind::IntToPtr { val, to }
888        }
889        instr_tag::BITCAST => {
890            let val = decode_vref(r)?;
891            let to = map_type_id(type_id_map, r.u32()? as usize)?;
892            InstrKind::BitCast { val, to }
893        }
894        instr_tag::ADDRSPACECAST => {
895            let val = decode_vref(r)?;
896            let to = map_type_id(type_id_map, r.u32()? as usize)?;
897            InstrKind::AddrSpaceCast { val, to }
898        }
899        instr_tag::FREEZE => InstrKind::Freeze {
900            val: decode_vref(r)?,
901        },
902        instr_tag::SELECT => InstrKind::Select {
903            cond: decode_vref(r)?,
904            then_val: decode_vref(r)?,
905            else_val: decode_vref(r)?,
906        },
907        instr_tag::PHI => {
908            let phi_ty = map_type_id(type_id_map, r.u32()? as usize)?;
909            let in_count = r.u32()? as usize;
910            let mut incoming = Vec::with_capacity(in_count);
911            for _ in 0..in_count {
912                let vr = decode_vref(r)?;
913                let bid = BlockId(r.u32()?);
914                incoming.push((vr, bid));
915            }
916            InstrKind::Phi {
917                ty: phi_ty,
918                incoming,
919            }
920        }
921        instr_tag::EXTRACTVALUE => {
922            let agg = decode_vref(r)?;
923            let idx_count = r.u32()? as usize;
924            let mut indices = Vec::with_capacity(idx_count);
925            for _ in 0..idx_count {
926                indices.push(r.u32()?);
927            }
928            InstrKind::ExtractValue {
929                aggregate: agg,
930                indices,
931            }
932        }
933        instr_tag::INSERTVALUE => {
934            let agg = decode_vref(r)?;
935            let val = decode_vref(r)?;
936            let idx_count = r.u32()? as usize;
937            let mut indices = Vec::with_capacity(idx_count);
938            for _ in 0..idx_count {
939                indices.push(r.u32()?);
940            }
941            InstrKind::InsertValue {
942                aggregate: agg,
943                val,
944                indices,
945            }
946        }
947        instr_tag::EXTRACTELEM => InstrKind::ExtractElement {
948            vec: decode_vref(r)?,
949            idx: decode_vref(r)?,
950        },
951        instr_tag::INSERTELEM => InstrKind::InsertElement {
952            vec: decode_vref(r)?,
953            val: decode_vref(r)?,
954            idx: decode_vref(r)?,
955        },
956        instr_tag::SHUFFLEVEC => {
957            let v1 = decode_vref(r)?;
958            let v2 = decode_vref(r)?;
959            let n = r.u32()? as usize;
960            let mut mask = Vec::with_capacity(n);
961            for _ in 0..n {
962                mask.push(r.i32()?);
963            }
964            InstrKind::ShuffleVector { v1, v2, mask }
965        }
966        instr_tag::CALL => {
967            let tail_tag = r.u8()?;
968            let tail = match tail_tag {
969                0 => TailCallKind::None,
970                1 => TailCallKind::Tail,
971                2 => TailCallKind::MustTail,
972                _ => TailCallKind::NoTail,
973            };
974            let callee_ty = map_type_id(type_id_map, r.u32()? as usize)?;
975            let callee = decode_vref(r)?;
976            let arg_count = r.u32()? as usize;
977            let mut args = Vec::with_capacity(arg_count);
978            for _ in 0..arg_count {
979                args.push(decode_vref(r)?);
980            }
981            InstrKind::Call {
982                tail,
983                callee_ty,
984                callee,
985                args,
986            }
987        }
988        instr_tag::RET => InstrKind::Ret {
989            val: decode_opt_vref(r)?,
990        },
991        instr_tag::BR => InstrKind::Br {
992            dest: BlockId(r.u32()?),
993        },
994        instr_tag::CONDBR => {
995            let cond = decode_vref(r)?;
996            let then_dest = BlockId(r.u32()?);
997            let else_dest = BlockId(r.u32()?);
998            InstrKind::CondBr {
999                cond,
1000                then_dest,
1001                else_dest,
1002            }
1003        }
1004        instr_tag::SWITCH => {
1005            let val = decode_vref(r)?;
1006            let default = BlockId(r.u32()?);
1007            let case_count = r.u32()? as usize;
1008            let mut cases = Vec::with_capacity(case_count);
1009            for _ in 0..case_count {
1010                let cv = decode_vref(r)?;
1011                let bd = BlockId(r.u32()?);
1012                cases.push((cv, bd));
1013            }
1014            InstrKind::Switch {
1015                val,
1016                default,
1017                cases,
1018            }
1019        }
1020        instr_tag::UNREACHABLE => InstrKind::Unreachable,
1021        other => return Err(BitcodeError::UnsupportedRecord(other)),
1022    };
1023
1024    Ok(Instruction::new(name, ty, kind))
1025}
1026
1027// ── reader helper ─────────────────────────────────────────────────────────
1028
1029struct Reader<'a> {
1030    data: &'a [u8],
1031    pos: usize,
1032}
1033
1034impl<'a> Reader<'a> {
1035    fn new(data: &'a [u8]) -> Self {
1036        Reader { data, pos: 0 }
1037    }
1038
1039    fn read_bytes(&mut self, n: usize) -> Result<&[u8], BitcodeError> {
1040        if self.pos + n > self.data.len() {
1041            return Err(BitcodeError::TruncatedInput);
1042        }
1043        let slice = &self.data[self.pos..self.pos + n];
1044        self.pos += n;
1045        Ok(slice)
1046    }
1047
1048    fn u8(&mut self) -> Result<u8, BitcodeError> {
1049        let b = self.read_bytes(1)?;
1050        Ok(b[0])
1051    }
1052
1053    fn u32(&mut self) -> Result<u32, BitcodeError> {
1054        let b = self.read_bytes(4)?;
1055        Ok(u32::from_le_bytes([b[0], b[1], b[2], b[3]]))
1056    }
1057
1058    fn i32(&mut self) -> Result<i32, BitcodeError> {
1059        let b = self.read_bytes(4)?;
1060        Ok(i32::from_le_bytes([b[0], b[1], b[2], b[3]]))
1061    }
1062
1063    fn u64(&mut self) -> Result<u64, BitcodeError> {
1064        let b = self.read_bytes(8)?;
1065        Ok(u64::from_le_bytes([
1066            b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7],
1067        ]))
1068    }
1069
1070    /// Read a length-prefixed string (u32 len + UTF-8 bytes).
1071    /// Returns `None` if len == 0.
1072    fn opt_string(&mut self) -> Result<Option<String>, BitcodeError> {
1073        let len = self.u32()? as usize;
1074        if len == 0 {
1075            return Ok(None);
1076        }
1077        let bytes = self.read_bytes(len)?;
1078        String::from_utf8(bytes.to_vec())
1079            .map(Some)
1080            .map_err(|e| BitcodeError::ParseError(format!("invalid UTF-8: {}", e)))
1081    }
1082
1083    /// Read a length-prefixed string.  Returns an empty `String` if len == 0.
1084    fn string(&mut self) -> Result<String, BitcodeError> {
1085        let len = self.u32()? as usize;
1086        if len == 0 {
1087            return Ok(String::new());
1088        }
1089        let bytes = self.read_bytes(len)?;
1090        String::from_utf8(bytes.to_vec())
1091            .map_err(|e| BitcodeError::ParseError(format!("invalid UTF-8: {}", e)))
1092    }
1093}