inkwell 0.9.0

Inkwell aims to help you pen your own programming languages by safely wrapping llvm-sys.
Documentation
#[llvm_versions(20..)]
use inkwell::OptimizationLevel;
#[llvm_versions(20..)]
use inkwell::context::Context;
#[llvm_versions(20..)]
use inkwell::passes::PassBuilderOptions;
#[llvm_versions(20..)]
use inkwell::targets::{CodeModel, InitializationConfig, RelocMode, Target, TargetMachine};

#[llvm_versions(20..)]
#[test]
fn test_run_passes_on_function() {
    let pass_options = PassBuilderOptions::create();
    pass_options.set_verify_each(true);
    pass_options.set_debug_logging(true);
    pass_options.set_loop_interleaving(true);
    pass_options.set_loop_vectorization(true);
    pass_options.set_loop_slp_vectorization(true);
    pass_options.set_loop_unrolling(true);
    pass_options.set_forget_all_scev_in_loop_unroll(true);
    pass_options.set_licm_mssa_opt_cap(1);
    pass_options.set_licm_mssa_no_acc_for_promotion_cap(10);
    pass_options.set_call_graph_profile(true);
    pass_options.set_merge_functions(true);

    let initialization_config = &InitializationConfig::default();
    Target::initialize_all(initialization_config);
    let context = Context::create();
    let module = context.create_module("my_module");
    let builder = context.create_builder();

    let triple = TargetMachine::get_default_triple();
    let target = Target::from_triple(&triple).unwrap();
    let machine = target
        .create_target_machine(
            &triple,
            "generic",
            "",
            OptimizationLevel::Default,
            RelocMode::Default,
            CodeModel::Default,
        )
        .unwrap();

    let i32_type = context.i32_type();
    let fn_type = i32_type.fn_type(&[], false);

    let function = module.add_function("test_function_passes", fn_type, None);

    let basic_block = context.append_basic_block(function, "entry");
    builder.position_at_end(basic_block);
    let _ = builder.build_return(Some(&i32_type.const_int(3, false)));

    assert!(
        function
            .run_passes("instcombine,reassociate,gvn,simplifycfg", &machine, pass_options)
            .is_ok()
    );
}

#[llvm_versions(20..)]
#[test]
fn test_run_passes_on_function_invalid() {
    let pass_options = PassBuilderOptions::create();

    let initialization_config = &InitializationConfig::default();
    Target::initialize_all(initialization_config);
    let context = Context::create();
    let module = context.create_module("my_module");
    let builder = context.create_builder();

    let triple = TargetMachine::get_default_triple();
    let target = Target::from_triple(&triple).unwrap();
    let machine = target
        .create_target_machine(
            &triple,
            TargetMachine::get_host_cpu_name().to_string().as_str(),
            TargetMachine::get_host_cpu_features().to_string().as_str(),
            OptimizationLevel::Default,
            RelocMode::Default,
            CodeModel::Default,
        )
        .unwrap();

    let i32_type = context.i32_type();
    let fn_type = i32_type.fn_type(&[], false);

    let function = module.add_function("test_function_passes", fn_type, None);

    let basic_block = context.append_basic_block(function, "entry");
    builder.position_at_end(basic_block);
    let _ = builder.build_return(Some(&i32_type.const_int(3, false)));

    let res = function.run_passes("invalid_pass", &machine, pass_options);
    assert!(res.is_err());
    assert_eq!(
        res.unwrap_err().to_str().unwrap(),
        "unknown function pass 'invalid_pass' in pipeline 'invalid_pass'"
    );
}