//! The LLVM IR generator context tests.

use crate::optimizer::settings::Settings as OptimizerSettings;
use crate::polkavm::context::attribute::Attribute;
use crate::polkavm::context::Context;
use crate::PolkaVMTarget;

/// Initializes the LLVM compiler backend.
fn initialize_llvm() {
    crate::initialize_llvm(PolkaVMTarget::PVM, "resolc", Default::default());
}

#[test]
pub fn check_attribute_null_pointer_is_invalid() {
    initialize_llvm();

    let llvm = inkwell::context::Context::create();
    let mut context = Context::new_dummy(&llvm, OptimizerSettings::cycles());

    let function = context
        .add_function(
            "test",
            context
                .word_type()
                .fn_type(&[context.word_type().into()], false),
            1,
            Some(inkwell::module::Linkage::External),
            None,
            false,
        )
        .expect("Failed to add function");
    assert!(!function
        .borrow()
        .declaration()
        .value
        .attributes(inkwell::attributes::AttributeLoc::Function)
        .contains(&llvm.create_enum_attribute(Attribute::NullPointerIsValid as u32, 0)));
}

#[test]
pub fn check_attribute_optimize_for_size_mode_3() {
    initialize_llvm();

    let llvm = inkwell::context::Context::create();
    let mut context = Context::new_dummy(&llvm, OptimizerSettings::cycles());

    let function = context
        .add_function(
            "test",
            context
                .word_type()
                .fn_type(&[context.word_type().into()], false),
            1,
            Some(inkwell::module::Linkage::External),
            None,
            false,
        )
        .expect("Failed to add function");
    assert!(!function
        .borrow()
        .declaration()
        .value
        .attributes(inkwell::attributes::AttributeLoc::Function)
        .contains(&llvm.create_enum_attribute(Attribute::OptimizeForSize as u32, 0)));
}

#[test]
pub fn check_attribute_optimize_for_size_mode_z() {
    initialize_llvm();

    let llvm = inkwell::context::Context::create();
    let mut context = Context::new_dummy(&llvm, OptimizerSettings::size());

    let function = context
        .add_function(
            "test",
            context
                .word_type()
                .fn_type(&[context.word_type().into()], false),
            1,
            Some(inkwell::module::Linkage::External),
            None,
            false,
        )
        .expect("Failed to add function");
    assert!(function
        .borrow()
        .declaration()
        .value
        .attributes(inkwell::attributes::AttributeLoc::Function)
        .contains(&llvm.create_enum_attribute(Attribute::OptimizeForSize as u32, 0)));
}

#[test]
pub fn check_attribute_min_size_mode_3() {
    initialize_llvm();

    let llvm = inkwell::context::Context::create();
    let mut context = Context::new_dummy(&llvm, OptimizerSettings::cycles());

    let function = context
        .add_function(
            "test",
            context
                .word_type()
                .fn_type(&[context.word_type().into()], false),
            1,
            Some(inkwell::module::Linkage::External),
            None,
            false,
        )
        .expect("Failed to add function");
    assert!(!function
        .borrow()
        .declaration()
        .value
        .attributes(inkwell::attributes::AttributeLoc::Function)
        .contains(&llvm.create_enum_attribute(Attribute::MinSize as u32, 0)));
}

#[test]
pub fn check_attribute_min_size_mode_z() {
    initialize_llvm();

    let llvm = inkwell::context::Context::create();
    let mut context = Context::new_dummy(&llvm, OptimizerSettings::size());

    let function = context
        .add_function(
            "test",
            context
                .word_type()
                .fn_type(&[context.word_type().into()], false),
            1,
            Some(inkwell::module::Linkage::External),
            None,
            false,
        )
        .expect("Failed to add function");
    assert!(function
        .borrow()
        .declaration()
        .value
        .attributes(inkwell::attributes::AttributeLoc::Function)
        .contains(&llvm.create_enum_attribute(Attribute::MinSize as u32, 0)));
}
