//! The LLVM context library. #![allow(clippy::too_many_arguments)] use std::ffi::CString; use std::sync::OnceLock; pub use self::debug_config::ir_type::IRType as DebugConfigIR; pub use self::debug_config::DebugConfig; pub use self::optimizer::settings::size_level::SizeLevel as OptimizerSettingsSizeLevel; pub use self::optimizer::settings::Settings as OptimizerSettings; pub use self::optimizer::Optimizer; pub use self::polkavm::build as polkavm_build; pub use self::polkavm::context::address_space::AddressSpace as PolkaVMAddressSpace; pub use self::polkavm::context::argument::Argument as PolkaVMArgument; pub use self::polkavm::context::attribute::Attribute as PolkaVMAttribute; pub use self::polkavm::context::attribute::MemoryEffect as PolkaVMMemoryEffect; pub use self::polkavm::context::build::Build as PolkaVMBuild; pub use self::polkavm::context::code_type::CodeType as PolkaVMCodeType; pub use self::polkavm::context::debug_info::DebugInfo; pub use self::polkavm::context::function::declaration::Declaration as PolkaVMFunctionDeclaration; pub use self::polkavm::context::function::intrinsics::Intrinsics as PolkaVMIntrinsicFunction; pub use self::polkavm::context::function::llvm_runtime::LLVMRuntime as PolkaVMLLVMRuntime; pub use self::polkavm::context::function::r#return::Return as PolkaVMFunctionReturn; pub use self::polkavm::context::function::runtime::arithmetics::Division as PolkaVMDivisionFunction; pub use self::polkavm::context::function::runtime::arithmetics::Remainder as PolkaVMRemainderFunction; pub use self::polkavm::context::function::runtime::arithmetics::SignedDivision as PolkaVMSignedDivisionFunction; pub use self::polkavm::context::function::runtime::arithmetics::SignedRemainder as PolkaVMSignedRemainderFunction; pub use self::polkavm::context::function::runtime::deploy_code::DeployCode as PolkaVMDeployCodeFunction; pub use self::polkavm::context::function::runtime::entry::Entry as PolkaVMEntryFunction; pub use self::polkavm::context::function::runtime::revive::CallDataLoad as PolkaVMCallDataLoadFunction; pub use self::polkavm::context::function::runtime::revive::CallValue as PolkaVMCallValueFunction; pub use self::polkavm::context::function::runtime::revive::CallValueNonzero as PolkaVMCallValueNonzeroFunction; pub use self::polkavm::context::function::runtime::revive::Caller as PolkaVMCallerFunction; pub use self::polkavm::context::function::runtime::revive::Exit as PolkaVMExitFunction; pub use self::polkavm::context::function::runtime::revive::Revert as PolkaVMRevertFunction; pub use self::polkavm::context::function::runtime::revive::RevertEmpty as PolkaVMRevertEmptyFunction; pub use self::polkavm::context::function::runtime::revive::RevertPanic as PolkaVMRevertPanicFunction; pub use self::polkavm::context::function::runtime::revive::WordToPointer as PolkaVMWordToPointerFunction; pub use self::polkavm::context::function::runtime::runtime_code::RuntimeCode as PolkaVMRuntimeCodeFunction; pub use self::polkavm::context::function::runtime::sbrk::Sbrk as PolkaVMSbrkFunction; pub use self::polkavm::context::function::runtime::FUNCTION_DEPLOY_CODE as PolkaVMFunctionDeployCode; pub use self::polkavm::context::function::runtime::FUNCTION_ENTRY as PolkaVMFunctionEntry; pub use self::polkavm::context::function::runtime::FUNCTION_RUNTIME_CODE as PolkaVMFunctionRuntimeCode; pub use self::polkavm::context::function::yul_data::YulData as PolkaVMFunctionYulData; pub use self::polkavm::context::function::Function as PolkaVMFunction; pub use self::polkavm::context::global::Global as PolkaVMGlobal; pub use self::polkavm::context::pointer::heap::Keccak256OneWord as PolkaVMKeccak256OneWordFunction; pub use self::polkavm::context::pointer::heap::Keccak256TwoWords as PolkaVMKeccak256TwoWordsFunction; pub use self::polkavm::context::pointer::heap::LoadWord as PolkaVMLoadHeapWordFunction; pub use self::polkavm::context::pointer::heap::LoadWordNative as PolkaVMLoadHeapWordNativeFunction; pub use self::polkavm::context::pointer::heap::StoreWord as PolkaVMStoreHeapWordFunction; pub use self::polkavm::context::pointer::heap::StoreWordNative as PolkaVMStoreHeapWordNativeFunction; pub use self::polkavm::context::pointer::storage::LoadTransientWord as PolkaVMLoadTransientStorageWordFunction; pub use self::polkavm::context::pointer::storage::LoadWord as PolkaVMLoadStorageWordFunction; pub use self::polkavm::context::pointer::storage::StoreTransientWord as PolkaVMStoreTransientStorageWordFunction; pub use self::polkavm::context::pointer::storage::StoreWord as PolkaVMStoreStorageWordFunction; pub use self::polkavm::context::pointer::Pointer as PolkaVMPointer; pub use self::polkavm::context::r#loop::Loop as PolkaVMLoop; pub use self::polkavm::context::solidity_data::SolidityData as PolkaVMContextSolidityData; pub use self::polkavm::context::yul_data::YulData as PolkaVMContextYulData; pub use self::polkavm::context::Context as PolkaVMContext; pub use self::polkavm::disassemble as polkavm_disassemble; pub use self::polkavm::evm::arithmetic as polkavm_evm_arithmetic; pub use self::polkavm::evm::bitwise as polkavm_evm_bitwise; pub use self::polkavm::evm::call as polkavm_evm_call; pub use self::polkavm::evm::calldata as polkavm_evm_calldata; pub use self::polkavm::evm::comparison as polkavm_evm_comparison; pub use self::polkavm::evm::context as polkavm_evm_contract_context; pub use self::polkavm::evm::create as polkavm_evm_create; pub use self::polkavm::evm::crypto as polkavm_evm_crypto; pub use self::polkavm::evm::ether_gas as polkavm_evm_ether_gas; pub use self::polkavm::evm::event as polkavm_evm_event; pub use self::polkavm::evm::event::EventLog as PolkaVMEventLogFunction; pub use self::polkavm::evm::ext_code as polkavm_evm_ext_code; pub use self::polkavm::evm::immutable as polkavm_evm_immutable; pub use self::polkavm::evm::immutable::Load as PolkaVMLoadImmutableDataFunction; pub use self::polkavm::evm::immutable::Store as PolkaVMStoreImmutableDataFunction; pub use self::polkavm::evm::math as polkavm_evm_math; pub use self::polkavm::evm::memory as polkavm_evm_memory; pub use self::polkavm::evm::r#return as polkavm_evm_return; pub use self::polkavm::evm::return_data as polkavm_evm_return_data; pub use self::polkavm::evm::storage as polkavm_evm_storage; pub use self::polkavm::hash as polkavm_hash; pub use self::polkavm::link as polkavm_link; pub use self::polkavm::r#const as polkavm_const; pub use self::polkavm::DummyLLVMWritable as PolkaVMDummyLLVMWritable; pub use self::polkavm::WriteLLVM as PolkaVMWriteLLVM; pub use self::target_machine::target::Target as PolkaVMTarget; pub use self::target_machine::TargetMachine as PolkaVMTargetMachine; pub(crate) mod debug_config; pub(crate) mod optimizer; pub(crate) mod polkavm; pub(crate) mod target_machine; static DID_INITIALIZE: OnceLock<()> = OnceLock::new(); /// The global LLVM options applied at [`OptimizerSettingsSizeLevel::Z`] **on the newyork path**. /// /// These trade execution speed for code size: the machine outliner replaces repeated /// instruction sequences with calls, disabling LICM avoids i256 register pressure on the /// PVM target (rv64e) where hoisting causes excessive stack spills, and `ext-tsp-for-size` /// optimizes block layout for size instead of speed. At any other optimization level the /// upstream LLVM defaults apply: paying execution gas for smaller code is only acceptable /// when the user explicitly asked for `-Oz`. /// /// They are applied only for modules produced by the newyork IR generator. Like the /// aggressive code-size pass pipeline in [`crate::optimizer::Optimizer::run`] and the /// `+unaligned-scalar-mem` target feature, these knobs are tuned and validated against /// newyork's outlined code; the stock Yul path keeps the upstream LLVM defaults it was /// validated against (matching `main`). const SIZE_LEVEL_Z_ARGUMENTS: &[&str] = &[ "--disable-licm-promotion", "--disable-machine-licm", "--enable-machine-outliner", "--machine-outliner-reruns=2", "--disable-early-taildup=true", "--apply-ext-tsp-for-size=true", "--attributor-allow-deep-wrappers=true", "--hoist-common-insts=true", ]; /// Initializes the LLVM compiler backend. /// /// This is a no-op if called subsequentially. /// /// `llvm_arguments` are passed as-is to the LLVM CL options parser. /// /// When `use_newyork` is set and the size level is [`OptimizerSettingsSizeLevel::Z`], the /// `SIZE_LEVEL_Z_ARGUMENTS` are prepended. They are gated on the newyork path because they /// are validated against its codegen; the stock Yul path must keep the upstream defaults. /// LLVM parses command line options once per process, so the first caller wins; production /// builds are unaffected because every contract is compiled in its own recursive process /// with its own optimizer settings and IR generator. pub fn initialize_llvm( target: PolkaVMTarget, name: &str, size_level: OptimizerSettingsSizeLevel, use_newyork: bool, llvm_arguments: &[String], ) { let Ok(_) = DID_INITIALIZE.set(()) else { return; // Tests don't go through a recursive process }; let size_arguments = if use_newyork && size_level == OptimizerSettingsSizeLevel::Z { SIZE_LEVEL_Z_ARGUMENTS } else { &[] }; let argv = std::iter::once(name) .chain(size_arguments.iter().copied()) .chain(llvm_arguments.iter().map(String::as_str)) .map(|arg| CString::new(arg.as_bytes()).unwrap()) .collect::>(); let argv: Vec<*const libc::c_char> = argv.iter().map(|arg| arg.as_ptr()).collect(); let overview = CString::new("").unwrap(); unsafe { inkwell::llvm_sys::support::LLVMParseCommandLineOptions( argv.len() as i32, argv.as_ptr(), overview.as_ptr(), ); } inkwell::support::enable_llvm_pretty_stack_trace(); match target { PolkaVMTarget::PVM => inkwell::targets::Target::initialize_riscv(&Default::default()), } }