llvm-ir 0.8.2

LLVM IR in natural Rust data structures
Documentation
#![cfg(feature="llvm-12-or-greater")]

//! These tests simply ensure that we can parse all of the `.bc` files in LLVM 12's `test/Bitcode` directory without crashing.
//! We only include the `.bc` files which are new or have changed since LLVM 11 (older ones are covered in other llvm_*_tests.rs).
//! Human-readable `.ll` versions of these files can be found in the LLVM repo at `test/Bitcode` at the git tag `llvmorg-12.0.0`.

use llvm_ir::Module;
use std::path::Path;

macro_rules! llvm_test {
    ($path:expr, $func:ident) => {
        #[test]
        #[allow(non_snake_case)]
        fn $func() {
            let _ = env_logger::builder().is_test(true).try_init(); // capture log messages with test harness
            let path = Path::new($path);
            let _ = Module::from_bc_path(&path).expect("Failed to parse module");
        }
    };
}

llvm_test!("tests/llvm_bc/aarch64-bf16-upgrade.ll.bc", aarch64_bf16_upgrade);
llvm_test!("tests/llvm_bc/arm-bf16-upgrade.ll.bc", arm_bf16_upgrade);
llvm_test!("tests/llvm_bc/compatibility-as-of-llvm-12.bc", compatibility_llvm_12);
llvm_test!("tests/llvm_bc/upgrade-ptr-annotation.ll.bc", upgrade_ptr_annotation);
llvm_test!("tests/llvm_bc/upgrade-var-annotation.ll.bc", upgrade_var_annotation);

// also ensure that the new-to-llvm-12 `Constant::Poison` was parsed correctly

use llvm_ir::{instruction, Constant, Name, Operand, Type, instruction::UnaryOp, types::FPType};
use std::convert::TryInto;

#[test]
fn constant_poison() {
    let _ = env_logger::builder().is_test(true).try_init(); // capture log messages with test harness
    let path = Path::new("tests/llvm_bc/compatibility-as-of-llvm-12.bc");
    let module = Module::from_bc_path(&path).expect("Failed to parse module");

    let const_struct = module.global_vars.iter().find(|gvar| gvar.name == Name::from("const.struct")).expect("Couldn't find @const.struct");
    let initializer = const_struct.initializer.as_ref().expect("@const.struct should have an initializer");
    match initializer.as_ref() {
        Constant::Struct { values, .. } => match &values[2].as_ref() {
            Constant::Poison(ty) => match ty.as_ref() {
                Type::IntegerType { bits: 64 } => {}  // pass
                ty => panic!("Poison of wrong type: expected i64, got {}", ty),
            }
            c => panic!("Expected constant poison, got {}", c),
        }
        c => panic!("Expected a constant struct, got {}", c),
    }

    let conversions = module.get_func_by_name("instructions.conversions").expect("Couldn't find function @instructions.conversions");
    let bb = &conversions.basic_blocks[0];
    let fptrunc: instruction::FPTrunc = bb.instrs[7].clone().try_into().unwrap();
    match fptrunc.get_operand() {
        Operand::ConstantOperand(c) => match c.as_ref() {
            Constant::Poison(ty) => match ty.as_ref() {
                Type::FPType(FPType::Single) => {}  // pass
                ty => panic!("Poison of wrong type: expected float, got {}", ty),
            }
            c => panic!("Expected constant poison, got {}", c),
        }
        o => panic!("Expected constant operand, got {}", o),
    }
}