llvm_mapper/block/
mod.rs

1//! Functionality for mapping individual blocks.
2
3pub mod attributes;
4pub mod identification;
5pub mod module;
6pub mod strtab;
7pub mod symtab;
8pub mod type_table;
9
10use std::convert::TryFrom;
11
12use llvm_support::bitcodes::{IrBlockId, ReservedBlockId};
13use thiserror::Error;
14
15pub use self::attributes::*;
16pub use self::identification::*;
17pub use self::module::*;
18pub use self::strtab::*;
19pub use self::symtab::*;
20pub use self::type_table::*;
21use crate::map::{MapError, PartialCtxMappable, PartialMapCtx};
22use crate::unroll::UnrolledBlock;
23
24/// Potential errors when mapping a single bitstream block.
25#[non_exhaustive]
26#[derive(Debug, Error)]
27pub enum BlockMapError {
28    /// We couldn't map the identification block.
29    #[error("error while mapping identification block")]
30    Identification(#[from] IdentificationError),
31
32    /// We couldn't map the module block.
33    #[error("error while mapping module")]
34    Module(#[from] ModuleError),
35
36    /// We couldn't map the string table.
37    #[error("error while mapping string table")]
38    Strtab(#[from] StrtabError),
39
40    /// We couldn't map the symbol table.
41    #[error("error while mapping symbol table")]
42    Symtab(#[from] SymtabError),
43}
44
45/// A holistic model of all possible block IDs, spanning reserved, IR, and unknown IDs.
46#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
47pub enum BlockId {
48    /// A block ID that's been reserved by LLVM. Reserved IDs are internal, and cannot be mapped here.
49    Reserved(ReservedBlockId),
50    /// A block ID used by LLVM IR.
51    Ir(IrBlockId),
52    /// An unknown block ID. Unknown IDs cannot be mapped.
53    Unknown(u64),
54}
55
56impl From<u64> for BlockId {
57    fn from(value: u64) -> Self {
58        // Try to turn `value` into each of our known kinds of block IDs, in order
59        // of precedence.
60        ReservedBlockId::try_from(value).map_or_else(
61            |_| IrBlockId::try_from(value).map_or_else(|_| BlockId::Unknown(value), BlockId::Ir),
62            BlockId::Reserved,
63        )
64    }
65}
66
67/// A trait implemented by all blocks that correspond to IR models, allowing them
68/// to be mapped into their corresponding model.
69pub(crate) trait IrBlock: Sized {
70    type Error;
71
72    /// The `IrBlockId` that corresponds to this IR model.
73    const BLOCK_ID: IrBlockId;
74
75    /// Attempt to map the given block to the implementing type, returning an error if mapping fails.
76    ///
77    /// This is an interior trait that shouldn't be used directly.
78    fn try_map_inner(block: &UnrolledBlock, ctx: &mut PartialMapCtx) -> Result<Self, Self::Error>;
79}
80
81impl<T: IrBlock> PartialCtxMappable<UnrolledBlock> for T
82where
83    T::Error: From<MapError>,
84{
85    type Error = T::Error;
86
87    fn try_map(block: &UnrolledBlock, ctx: &mut PartialMapCtx) -> Result<Self, Self::Error> {
88        if block.id != BlockId::Ir(T::BLOCK_ID) {
89            return Err(MapError::BadBlockMap(format!(
90                "can't map {:?} into {:?}",
91                block.id,
92                Identification::BLOCK_ID
93            ))
94            .into());
95        }
96
97        IrBlock::try_map_inner(block, ctx)
98    }
99}
100
101#[cfg(test)]
102mod tests {
103    use super::*;
104
105    #[test]
106    fn test_blockid_from_u64() {
107        assert_eq!(
108            BlockId::from(0),
109            BlockId::Reserved(ReservedBlockId::BlockInfo)
110        );
111        assert_eq!(
112            BlockId::from(7),
113            BlockId::Reserved(ReservedBlockId::Reserved7)
114        );
115        assert_eq!(BlockId::from(8), BlockId::Ir(IrBlockId::Module));
116        assert_eq!(BlockId::from(2384629342), BlockId::Unknown(2384629342));
117    }
118}