use std::collections::{BTreeMap, BTreeSet, BinaryHeap, HashMap, HashSet, VecDeque};
use std::fmt;
use std::sync::atomic::{AtomicBool, AtomicU64, Ordering};
use std::sync::{Arc, Mutex};
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub enum DeepOptLevel {
O0,
O1,
O2,
O3,
Os,
Oz,
}
impl fmt::Display for DeepOptLevel {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
DeepOptLevel::O0 => write!(f, "O0"),
DeepOptLevel::O1 => write!(f, "O1"),
DeepOptLevel::O2 => write!(f, "O2"),
DeepOptLevel::O3 => write!(f, "O3"),
DeepOptLevel::Os => write!(f, "Os"),
DeepOptLevel::Oz => write!(f, "Oz"),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum DeepPassResult {
Unchanged,
Changed,
Invalid,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct DeepPassId(pub u64);
impl DeepPassId {
pub const fn new(id: u64) -> Self {
DeepPassId(id)
}
}
impl fmt::Display for DeepPassId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Pass(0x{:04X})", self.0)
}
}
#[derive(Debug, Clone)]
pub struct DeepPassDependency {
pub requires: Vec<DeepPassId>,
pub invalidates: Vec<DeepPassId>,
pub preserves: Vec<DeepPassId>,
}
#[derive(Debug, Clone)]
pub struct DeepPass {
pub id: DeepPassId,
pub name: &'static str,
pub description: &'static str,
pub min_opt_level: DeepOptLevel,
pub dependencies: DeepPassDependency,
pub enabled: bool,
pub x86_tuning_weight: u8,
}
#[derive(Debug, Clone, Default)]
pub struct DeepPassStats {
pub run_count: u64,
pub changed_count: u64,
pub total_time_ns: u64,
pub items_processed: u64,
}
#[derive(Debug)]
pub struct X86IRPassesDeep {
pub passes: Vec<DeepPass>,
pub stats: BTreeMap<DeepPassId, DeepPassStats>,
pub opt_level: DeepOptLevel,
pub microarch_tuning: X86MicroArchTuning,
pub debug_mode: bool,
pub total_pipeline_time_ns: u64,
}
#[derive(Debug, Clone)]
pub struct X86MicroArchTuning {
pub arch_name: &'static str,
pub l1d_size: u32,
pub l2_size: u32,
pub l3_size: u32,
pub prefetch_distance: u8,
pub unroll_threshold: u32,
pub preferred_vector_width: u16,
pub has_gather_scatter: bool,
pub has_smt: bool,
}
impl Default for X86MicroArchTuning {
fn default() -> Self {
X86MicroArchTuning {
arch_name: "x86-64-v3",
l1d_size: 32768,
l2_size: 262144,
l3_size: 8388608,
prefetch_distance: 16,
unroll_threshold: 150,
preferred_vector_width: 256,
has_gather_scatter: true,
has_smt: true,
}
}
}
impl X86MicroArchTuning {
pub fn skylake_client() -> Self {
X86MicroArchTuning {
arch_name: "skylake",
l1d_size: 32768,
l2_size: 262144,
l3_size: 8388608,
prefetch_distance: 32,
unroll_threshold: 200,
preferred_vector_width: 256,
has_gather_scatter: true,
has_smt: true,
}
}
pub fn alder_lake_p() -> Self {
X86MicroArchTuning {
arch_name: "alderlake-p",
l1d_size: 49152,
l2_size: 1310720,
l3_size: 31457280,
prefetch_distance: 64,
unroll_threshold: 250,
preferred_vector_width: 512,
has_gather_scatter: true,
has_smt: true,
}
}
pub fn zen4() -> Self {
X86MicroArchTuning {
arch_name: "zen4",
l1d_size: 32768,
l2_size: 1048576,
l3_size: 33554432,
prefetch_distance: 28,
unroll_threshold: 180,
preferred_vector_width: 256,
has_gather_scatter: true,
has_smt: true,
}
}
pub fn zen5() -> Self {
X86MicroArchTuning {
arch_name: "zen5",
l1d_size: 49152,
l2_size: 1048576,
l3_size: 33554432,
prefetch_distance: 32,
unroll_threshold: 220,
preferred_vector_width: 512,
has_gather_scatter: true,
has_smt: true,
}
}
pub fn granite_rapids() -> Self {
X86MicroArchTuning {
arch_name: "graniterapids",
l1d_size: 49152,
l2_size: 2097152,
l3_size: 503316480,
prefetch_distance: 72,
unroll_threshold: 300,
preferred_vector_width: 512,
has_gather_scatter: true,
has_smt: false,
}
}
}
pub mod deep_pass_ids {
use super::DeepPassId;
pub const CONSTANT_MERGE: DeepPassId = DeepPassId::new(0x1001);
pub const GLOBAL_MERGE: DeepPassId = DeepPassId::new(0x1002);
pub const MERGE_FUNCTIONS: DeepPassId = DeepPassId::new(0x1003);
pub const PARTIAL_INLINING: DeepPassId = DeepPassId::new(0x1004);
pub const FUNCTION_SPECIALIZATION: DeepPassId = DeepPassId::new(0x1005);
pub const HOT_COLD_SPLITTING: DeepPassId = DeepPassId::new(0x1006);
pub const IR_OUTLINER: DeepPassId = DeepPassId::new(0x1007);
pub const LOOP_EXTRACTOR: DeepPassId = DeepPassId::new(0x1008);
pub const LOOP_SIMPLIFY_CFG: DeepPassId = DeepPassId::new(0x2001);
pub const LOOP_STRENGTH_REDUCE: DeepPassId = DeepPassId::new(0x2002);
pub const LOOP_DATA_PREFETCH: DeepPassId = DeepPassId::new(0x2003);
pub const LOOP_LOAD_ELIM: DeepPassId = DeepPassId::new(0x2004);
pub const LOOP_REROLL: DeepPassId = DeepPassId::new(0x2005);
pub const LOOP_INTERCHANGE: DeepPassId = DeepPassId::new(0x2006);
pub const LOOP_UNSWITCH: DeepPassId = DeepPassId::new(0x2007);
pub const SIMPLE_LOOP_UNSWITCH: DeepPassId = DeepPassId::new(0x2008);
pub const NARY_REASSOCIATE: DeepPassId = DeepPassId::new(0x2009);
pub const LOAD_STORE_VECTORIZER: DeepPassId = DeepPassId::new(0x200A);
pub const VECTOR_COMBINE: DeepPassId = DeepPassId::new(0x3001);
pub const LOWER_MATRIX_INTRINSICS: DeepPassId = DeepPassId::new(0x3002);
pub const EXPAND_REDUCTIONS: DeepPassId = DeepPassId::new(0x3003);
pub const LOWER_WIDENABLE_CONDITION: DeepPassId = DeepPassId::new(0x4001);
pub const MAKE_GUARDS_EXPLICIT: DeepPassId = DeepPassId::new(0x4002);
pub const IRCE_CORE: DeepPassId = DeepPassId::new(0x4003);
pub const REWRITE_STATEPOINTS: DeepPassId = DeepPassId::new(0x4004);
pub const EXPAND_MEMCMP: DeepPassId = DeepPassId::new(0x4005);
pub const LOWER_INVOKE: DeepPassId = DeepPassId::new(0x4006);
pub const LOWER_SWITCH: DeepPassId = DeepPassId::new(0x4007);
pub const LOWER_CONSTANT_INTRINSICS: DeepPassId = DeepPassId::new(0x4008);
pub const LOWER_EXPECT_INTRINSIC: DeepPassId = DeepPassId::new(0x4009);
pub const ENTRY_EXIT_INSTRUMENTER: DeepPassId = DeepPassId::new(0x400A);
pub const INJECT_TLI_MAPPINGS: DeepPassId = DeepPassId::new(0x400B);
}
#[derive(Debug)]
pub struct ConstantMergePass {
pub min_merge_size: usize,
pub max_uses_threshold: usize,
pub constants_merged: usize,
pub bytes_saved: usize,
}
impl ConstantMergePass {
pub fn new() -> Self {
ConstantMergePass {
min_merge_size: 8,
max_uses_threshold: 1,
constants_merged: 0,
bytes_saved: 0,
}
}
pub fn run(&mut self) -> DeepPassResult {
self.constants_merged = 0;
self.bytes_saved = 0;
DeepPassResult::Changed
}
}
#[derive(Debug)]
pub struct GlobalMergePass {
pub max_global_size: usize,
pub globals_merged: usize,
}
impl GlobalMergePass {
pub fn new() -> Self {
GlobalMergePass {
max_global_size: 32,
globals_merged: 0,
}
}
pub fn run(&mut self) -> DeepPassResult {
self.globals_merged = 0;
DeepPassResult::Changed
}
}
#[derive(Debug)]
pub struct MergeFunctionsPass {
pub min_function_size: usize,
function_hashes: HashMap<u64, Vec<usize>>,
pub functions_merged: usize,
}
impl MergeFunctionsPass {
pub fn new() -> Self {
MergeFunctionsPass {
min_function_size: 5,
function_hashes: HashMap::new(),
functions_merged: 0,
}
}
pub fn run(&mut self) -> DeepPassResult {
self.function_hashes.clear();
self.functions_merged = 0;
DeepPassResult::Unchanged
}
pub fn hash_function(&self, _func_id: usize) -> u64 {
0
}
}
#[derive(Debug)]
pub struct PartialInliningPass {
pub threshold: u32,
pub functions_partially_inlined: usize,
}
impl PartialInliningPass {
pub fn new() -> Self {
PartialInliningPass {
threshold: 100,
functions_partially_inlined: 0,
}
}
pub fn run(&mut self) -> DeepPassResult {
self.functions_partially_inlined = 0;
DeepPassResult::Unchanged
}
}
#[derive(Debug)]
pub struct FunctionSpecializationPass {
pub min_const_args: usize,
pub max_specializations: usize,
pub functions_specialized: usize,
}
impl FunctionSpecializationPass {
pub fn new() -> Self {
FunctionSpecializationPass {
min_const_args: 1,
max_specializations: 8,
functions_specialized: 0,
}
}
pub fn run(&mut self) -> DeepPassResult {
self.functions_specialized = 0;
DeepPassResult::Unchanged
}
}
#[derive(Debug)]
pub struct HotColdSplittingPass {
pub cold_threshold: u64,
pub functions_split: usize,
pub cold_blocks_outlined: usize,
}
impl HotColdSplittingPass {
pub fn new() -> Self {
HotColdSplittingPass {
cold_threshold: 0,
functions_split: 0,
cold_blocks_outlined: 0,
}
}
pub fn run(&mut self) -> DeepPassResult {
self.functions_split = 0;
self.cold_blocks_outlined = 0;
DeepPassResult::Unchanged
}
}
#[derive(Debug)]
pub struct IROutlinerPass {
pub min_sequence_length: usize,
pub min_occurrences: usize,
pub sequences_outlined: usize,
pub instructions_saved: usize,
}
impl IROutlinerPass {
pub fn new() -> Self {
IROutlinerPass {
min_sequence_length: 3,
min_occurrences: 2,
sequences_outlined: 0,
instructions_saved: 0,
}
}
pub fn run(&mut self) -> DeepPassResult {
self.sequences_outlined = 0;
self.instructions_saved = 0;
DeepPassResult::Unchanged
}
}
#[derive(Debug)]
pub struct LoopExtractorPass {
pub min_loop_size: usize,
pub loops_extracted: usize,
}
impl LoopExtractorPass {
pub fn new() -> Self {
LoopExtractorPass {
min_loop_size: 50,
loops_extracted: 0,
}
}
pub fn run(&mut self) -> DeepPassResult {
self.loops_extracted = 0;
DeepPassResult::Unchanged
}
}
#[derive(Debug)]
pub struct LoopSimplifyCFGPass {
pub loops_simplified: usize,
pub unreachable_blocks_removed: usize,
}
impl LoopSimplifyCFGPass {
pub fn new() -> Self {
LoopSimplifyCFGPass {
loops_simplified: 0,
unreachable_blocks_removed: 0,
}
}
pub fn run(&mut self) -> DeepPassResult {
self.loops_simplified = 0;
self.unreachable_blocks_removed = 0;
DeepPassResult::Unchanged
}
}
#[derive(Debug)]
pub struct LoopStrengthReducePass {
pub use_post_inc: bool,
pub ivs_replaced: usize,
pub instructions_eliminated: usize,
}
impl LoopStrengthReducePass {
pub fn new() -> Self {
LoopStrengthReducePass {
use_post_inc: true,
ivs_replaced: 0,
instructions_eliminated: 0,
}
}
pub fn run(&mut self) -> DeepPassResult {
self.ivs_replaced = 0;
self.instructions_eliminated = 0;
DeepPassResult::Unchanged
}
}
#[derive(Debug)]
pub struct LoopDataPrefetchPass {
pub prefetch_distance: u8,
pub min_stride: i64,
pub prefetches_inserted: usize,
}
impl LoopDataPrefetchPass {
pub fn new(prefetch_distance: u8) -> Self {
LoopDataPrefetchPass {
prefetch_distance,
min_stride: 1,
prefetches_inserted: 0,
}
}
pub fn run(&mut self) -> DeepPassResult {
self.prefetches_inserted = 0;
DeepPassResult::Unchanged
}
}
#[derive(Debug)]
pub struct LoopLoadElimPass {
pub forward_stores: bool,
pub loads_eliminated: usize,
pub stores_forwarded: usize,
}
impl LoopLoadElimPass {
pub fn new() -> Self {
LoopLoadElimPass {
forward_stores: true,
loads_eliminated: 0,
stores_forwarded: 0,
}
}
pub fn run(&mut self) -> DeepPassResult {
self.loads_eliminated = 0;
self.stores_forwarded = 0;
DeepPassResult::Unchanged
}
}
#[derive(Debug)]
pub struct LoopRerollPass {
pub max_unroll_factor: u8,
pub loops_rerolled: usize,
}
impl LoopRerollPass {
pub fn new() -> Self {
LoopRerollPass {
max_unroll_factor: 4,
loops_rerolled: 0,
}
}
pub fn run(&mut self) -> DeepPassResult {
self.loops_rerolled = 0;
DeepPassResult::Unchanged
}
}
#[derive(Debug)]
pub struct LoopInterchangePass {
pub min_loop_depth: usize,
pub loops_interchanged: usize,
}
impl LoopInterchangePass {
pub fn new() -> Self {
LoopInterchangePass {
min_loop_depth: 2,
loops_interchanged: 0,
}
}
pub fn run(&mut self) -> DeepPassResult {
self.loops_interchanged = 0;
DeepPassResult::Unchanged
}
}
#[derive(Debug)]
pub struct LoopUnswitchPass {
pub trivial: bool,
pub loops_unswitched: usize,
pub branches_eliminated: usize,
}
impl LoopUnswitchPass {
pub fn new(trivial: bool) -> Self {
LoopUnswitchPass {
trivial,
loops_unswitched: 0,
branches_eliminated: 0,
}
}
pub fn run(&mut self) -> DeepPassResult {
self.loops_unswitched = 0;
self.branches_eliminated = 0;
DeepPassResult::Unchanged
}
}
#[derive(Debug)]
pub struct SimpleLoopUnswitchPass {
pub loops_unswitched: usize,
}
impl SimpleLoopUnswitchPass {
pub fn new() -> Self {
SimpleLoopUnswitchPass {
loops_unswitched: 0,
}
}
pub fn run(&mut self) -> DeepPassResult {
self.loops_unswitched = 0;
DeepPassResult::Unchanged
}
}
#[derive(Debug)]
pub struct NaryReassociatePass {
pub expressions_reassociated: usize,
pub cse_exposed: usize,
}
impl NaryReassociatePass {
pub fn new() -> Self {
NaryReassociatePass {
expressions_reassociated: 0,
cse_exposed: 0,
}
}
pub fn run(&mut self) -> DeepPassResult {
self.expressions_reassociated = 0;
self.cse_exposed = 0;
DeepPassResult::Unchanged
}
}
#[derive(Debug)]
pub struct LoadStoreVectorizerPass {
pub max_vector_width: u16,
pub loads_merged: usize,
pub stores_merged: usize,
}
impl LoadStoreVectorizerPass {
pub fn new(max_vector_width: u16) -> Self {
LoadStoreVectorizerPass {
max_vector_width,
loads_merged: 0,
stores_merged: 0,
}
}
pub fn run(&mut self) -> DeepPassResult {
self.loads_merged = 0;
self.stores_merged = 0;
DeepPassResult::Unchanged
}
}
#[derive(Debug)]
pub struct VectorCombinePass {
pub ops_combined: usize,
pub shuffles_simplified: usize,
}
impl VectorCombinePass {
pub fn new() -> Self {
VectorCombinePass {
ops_combined: 0,
shuffles_simplified: 0,
}
}
pub fn run(&mut self) -> DeepPassResult {
self.ops_combined = 0;
self.shuffles_simplified = 0;
DeepPassResult::Unchanged
}
}
#[derive(Debug)]
pub struct LowerMatrixIntrinsicsPass {
pub intrinsics_lowered: usize,
}
impl LowerMatrixIntrinsicsPass {
pub fn new() -> Self {
LowerMatrixIntrinsicsPass {
intrinsics_lowered: 0,
}
}
pub fn run(&mut self) -> DeepPassResult {
self.intrinsics_lowered = 0;
DeepPassResult::Unchanged
}
}
#[derive(Debug)]
pub struct ExpandReductionsPass {
pub reductions_expanded: usize,
}
impl ExpandReductionsPass {
pub fn new() -> Self {
ExpandReductionsPass {
reductions_expanded: 0,
}
}
pub fn run(&mut self) -> DeepPassResult {
self.reductions_expanded = 0;
DeepPassResult::Unchanged
}
}
#[derive(Debug)]
pub struct LowerWidenableConditionPass {
pub conditions_lowered: usize,
}
impl LowerWidenableConditionPass {
pub fn new() -> Self {
LowerWidenableConditionPass {
conditions_lowered: 0,
}
}
pub fn run(&mut self) -> DeepPassResult {
self.conditions_lowered = 0;
DeepPassResult::Unchanged
}
}
#[derive(Debug)]
pub struct MakeGuardsExplicitPass {
pub guards_explicit: usize,
}
impl MakeGuardsExplicitPass {
pub fn new() -> Self {
MakeGuardsExplicitPass { guards_explicit: 0 }
}
pub fn run(&mut self) -> DeepPassResult {
self.guards_explicit = 0;
DeepPassResult::Unchanged
}
}
#[derive(Debug)]
pub struct IrceCorePass {
pub checks_eliminated: usize,
pub loops_affected: usize,
}
impl IrceCorePass {
pub fn new() -> Self {
IrceCorePass {
checks_eliminated: 0,
loops_affected: 0,
}
}
pub fn run(&mut self) -> DeepPassResult {
self.checks_eliminated = 0;
self.loops_affected = 0;
DeepPassResult::Unchanged
}
}
#[derive(Debug)]
pub struct RewriteStatepointsForGCPass {
pub statepoints_rewritten: usize,
}
impl RewriteStatepointsForGCPass {
pub fn new() -> Self {
RewriteStatepointsForGCPass {
statepoints_rewritten: 0,
}
}
pub fn run(&mut self) -> DeepPassResult {
self.statepoints_rewritten = 0;
DeepPassResult::Unchanged
}
}
#[derive(Debug)]
pub struct ExpandMemCmpPass {
pub max_expand_size: usize,
pub expansions: usize,
}
impl ExpandMemCmpPass {
pub fn new() -> Self {
ExpandMemCmpPass {
max_expand_size: 64,
expansions: 0,
}
}
pub fn run(&mut self) -> DeepPassResult {
self.expansions = 0;
DeepPassResult::Unchanged
}
}
#[derive(Debug)]
pub struct LowerInvokePass {
pub invokes_lowered: usize,
}
impl LowerInvokePass {
pub fn new() -> Self {
LowerInvokePass { invokes_lowered: 0 }
}
pub fn run(&mut self) -> DeepPassResult {
self.invokes_lowered = 0;
DeepPassResult::Unchanged
}
}
#[derive(Debug)]
pub struct LowerSwitchPass {
pub jump_table_threshold: usize,
pub switches_lowered: usize,
pub jump_tables_generated: usize,
}
impl LowerSwitchPass {
pub fn new() -> Self {
LowerSwitchPass {
jump_table_threshold: 4,
switches_lowered: 0,
jump_tables_generated: 0,
}
}
pub fn run(&mut self) -> DeepPassResult {
self.switches_lowered = 0;
self.jump_tables_generated = 0;
DeepPassResult::Unchanged
}
}
#[derive(Debug)]
pub struct LowerConstantIntrinsicsPass {
pub intrinsics_lowered: usize,
}
impl LowerConstantIntrinsicsPass {
pub fn new() -> Self {
LowerConstantIntrinsicsPass {
intrinsics_lowered: 0,
}
}
pub fn run(&mut self) -> DeepPassResult {
self.intrinsics_lowered = 0;
DeepPassResult::Unchanged
}
}
#[derive(Debug)]
pub struct LowerExpectIntrinsicPass {
pub expects_lowered: usize,
}
impl LowerExpectIntrinsicPass {
pub fn new() -> Self {
LowerExpectIntrinsicPass { expects_lowered: 0 }
}
pub fn run(&mut self) -> DeepPassResult {
self.expects_lowered = 0;
DeepPassResult::Unchanged
}
}
#[derive(Debug)]
pub struct EntryExitInstrumenterPass {
pub functions_instrumented: usize,
pub instrument_entry: bool,
pub instrument_exit: bool,
}
impl EntryExitInstrumenterPass {
pub fn new() -> Self {
EntryExitInstrumenterPass {
functions_instrumented: 0,
instrument_entry: true,
instrument_exit: true,
}
}
pub fn run(&mut self) -> DeepPassResult {
self.functions_instrumented = 0;
DeepPassResult::Unchanged
}
}
#[derive(Debug)]
pub struct InjectTLIMappingsPass {
pub mappings_injected: usize,
pub tli_name: String,
}
impl InjectTLIMappingsPass {
pub fn new(tli_name: &str) -> Self {
InjectTLIMappingsPass {
mappings_injected: 0,
tli_name: tli_name.to_string(),
}
}
pub fn run(&mut self) -> DeepPassResult {
self.mappings_injected = 0;
DeepPassResult::Unchanged
}
}
impl X86IRPassesDeep {
pub fn new(opt_level: DeepOptLevel, tuning: X86MicroArchTuning) -> Self {
let mut pm = X86IRPassesDeep {
passes: Vec::new(),
stats: BTreeMap::new(),
opt_level,
microarch_tuning: tuning,
debug_mode: false,
total_pipeline_time_ns: 0,
};
pm.register_all_passes();
pm
}
pub fn with_default_tuning(opt_level: DeepOptLevel) -> Self {
Self::new(opt_level, X86MicroArchTuning::default())
}
fn register_all_passes(&mut self) {
let tuning_weight = |base: u8| -> u8 {
base
};
self.add_pass(DeepPass {
id: deep_pass_ids::LOWER_EXPECT_INTRINSIC,
name: "LowerExpectIntrinsic",
description: "Lowers llvm.expect to branch-weight metadata",
min_opt_level: DeepOptLevel::O1,
dependencies: DeepPassDependency {
requires: vec![],
invalidates: vec![],
preserves: vec![],
},
enabled: true,
x86_tuning_weight: tuning_weight(5),
});
self.add_pass(DeepPass {
id: deep_pass_ids::LOWER_CONSTANT_INTRINSICS,
name: "LowerConstantIntrinsics",
description: "Lowers llvm.is.constant and related intrinsics",
min_opt_level: DeepOptLevel::O1,
dependencies: DeepPassDependency {
requires: vec![],
invalidates: vec![],
preserves: vec![],
},
enabled: true,
x86_tuning_weight: tuning_weight(5),
});
self.add_pass(DeepPass {
id: deep_pass_ids::LOWER_WIDENABLE_CONDITION,
name: "LowerWidenableCondition",
description: "Lowers llvm.widenable.condition to 'true'",
min_opt_level: DeepOptLevel::O1,
dependencies: DeepPassDependency {
requires: vec![],
invalidates: vec![],
preserves: vec![],
},
enabled: true,
x86_tuning_weight: tuning_weight(5),
});
self.add_pass(DeepPass {
id: deep_pass_ids::MAKE_GUARDS_EXPLICIT,
name: "MakeGuardsExplicit",
description: "Transforms implicit guards into explicit llvm.experimental.guard calls",
min_opt_level: DeepOptLevel::O1,
dependencies: DeepPassDependency {
requires: vec![],
invalidates: vec![],
preserves: vec![],
},
enabled: true,
x86_tuning_weight: tuning_weight(3),
});
self.add_pass(DeepPass {
id: deep_pass_ids::CONSTANT_MERGE,
name: "ConstantMerge",
description: "Merges duplicate global constants to reduce code size",
min_opt_level: DeepOptLevel::O1,
dependencies: DeepPassDependency {
requires: vec![],
invalidates: vec![],
preserves: vec![],
},
enabled: true,
x86_tuning_weight: tuning_weight(15),
});
self.add_pass(DeepPass {
id: deep_pass_ids::GLOBAL_MERGE,
name: "GlobalMerge",
description: "Merges small adjacent global variables into a combined struct",
min_opt_level: DeepOptLevel::O2,
dependencies: DeepPassDependency {
requires: vec![deep_pass_ids::CONSTANT_MERGE],
invalidates: vec![],
preserves: vec![],
},
enabled: true,
x86_tuning_weight: tuning_weight(20),
});
self.add_pass(DeepPass {
id: deep_pass_ids::MERGE_FUNCTIONS,
name: "MergeFunctions",
description: "Merges functions with identical bodies (thunk generation)",
min_opt_level: DeepOptLevel::Os,
dependencies: DeepPassDependency {
requires: vec![],
invalidates: vec![
deep_pass_ids::FUNCTION_SPECIALIZATION,
deep_pass_ids::PARTIAL_INLINING,
],
preserves: vec![],
},
enabled: true,
x86_tuning_weight: tuning_weight(25),
});
self.add_pass(DeepPass {
id: deep_pass_ids::FUNCTION_SPECIALIZATION,
name: "FunctionSpecialization",
description: "Clones functions with constant arguments for better optimization",
min_opt_level: DeepOptLevel::O3,
dependencies: DeepPassDependency {
requires: vec![],
invalidates: vec![deep_pass_ids::MERGE_FUNCTIONS],
preserves: vec![],
},
enabled: true,
x86_tuning_weight: tuning_weight(30),
});
self.add_pass(DeepPass {
id: deep_pass_ids::PARTIAL_INLINING,
name: "PartialInlining",
description: "Outlines cold code so hot path can be inlined",
min_opt_level: DeepOptLevel::O3,
dependencies: DeepPassDependency {
requires: vec![deep_pass_ids::HOT_COLD_SPLITTING],
invalidates: vec![],
preserves: vec![],
},
enabled: true,
x86_tuning_weight: tuning_weight(35),
});
self.add_pass(DeepPass {
id: deep_pass_ids::HOT_COLD_SPLITTING,
name: "HotColdSplitting",
description: "Splits hot and cold basic blocks in functions",
min_opt_level: DeepOptLevel::O3,
dependencies: DeepPassDependency {
requires: vec![],
invalidates: vec![],
preserves: vec![],
},
enabled: true,
x86_tuning_weight: tuning_weight(28),
});
self.add_pass(DeepPass {
id: deep_pass_ids::IR_OUTLINER,
name: "IROutliner",
description: "Outlines repeated instruction sequences to reduce code size",
min_opt_level: DeepOptLevel::Os,
dependencies: DeepPassDependency {
requires: vec![],
invalidates: vec![],
preserves: vec![],
},
enabled: true,
x86_tuning_weight: tuning_weight(22),
});
self.add_pass(DeepPass {
id: deep_pass_ids::LOOP_EXTRACTOR,
name: "LoopExtractor",
description: "Extracts loops into separate functions (for testing or code size)",
min_opt_level: DeepOptLevel::O0,
dependencies: DeepPassDependency {
requires: vec![],
invalidates: vec![],
preserves: vec![],
},
enabled: false, x86_tuning_weight: tuning_weight(0),
});
self.add_pass(DeepPass {
id: deep_pass_ids::LOOP_SIMPLIFY_CFG,
name: "LoopSimplifyCFG",
description: "Simplifies loop control flow (constant branches, dead blocks)",
min_opt_level: DeepOptLevel::O1,
dependencies: DeepPassDependency {
requires: vec![],
invalidates: vec![],
preserves: vec![],
},
enabled: true,
x86_tuning_weight: tuning_weight(40),
});
self.add_pass(DeepPass {
id: deep_pass_ids::LOOP_STRENGTH_REDUCE,
name: "LoopStrengthReduce",
description: "Strength-reduces induction variables using x86 addressing modes",
min_opt_level: DeepOptLevel::O2,
dependencies: DeepPassDependency {
requires: vec![deep_pass_ids::LOOP_SIMPLIFY_CFG],
invalidates: vec![],
preserves: vec![],
},
enabled: true,
x86_tuning_weight: tuning_weight(50),
});
self.add_pass(DeepPass {
id: deep_pass_ids::LOOP_DATA_PREFETCH,
name: "LoopDataPrefetch",
description: "Inserts prefetch instructions for strided array accesses",
min_opt_level: DeepOptLevel::O3,
dependencies: DeepPassDependency {
requires: vec![deep_pass_ids::LOOP_STRENGTH_REDUCE],
invalidates: vec![],
preserves: vec![],
},
enabled: true,
x86_tuning_weight: tuning_weight(45),
});
self.add_pass(DeepPass {
id: deep_pass_ids::LOOP_LOAD_ELIM,
name: "LoopLoadElim",
description: "Eliminates redundant loads across loop iterations",
min_opt_level: DeepOptLevel::O2,
dependencies: DeepPassDependency {
requires: vec![],
invalidates: vec![],
preserves: vec![],
},
enabled: true,
x86_tuning_weight: tuning_weight(38),
});
self.add_pass(DeepPass {
id: deep_pass_ids::LOOP_REROLL,
name: "LoopReroll",
description: "Rerolls unrolled loops for code size savings",
min_opt_level: DeepOptLevel::Os,
dependencies: DeepPassDependency {
requires: vec![],
invalidates: vec![],
preserves: vec![],
},
enabled: true,
x86_tuning_weight: tuning_weight(15),
});
self.add_pass(DeepPass {
id: deep_pass_ids::LOOP_INTERCHANGE,
name: "LoopInterchange",
description: "Swaps nested loop order for cache locality",
min_opt_level: DeepOptLevel::O3,
dependencies: DeepPassDependency {
requires: vec![deep_pass_ids::LOOP_SIMPLIFY_CFG],
invalidates: vec![],
preserves: vec![],
},
enabled: true,
x86_tuning_weight: tuning_weight(42),
});
self.add_pass(DeepPass {
id: deep_pass_ids::LOOP_UNSWITCH,
name: "LoopUnswitch",
description: "Hoists loop-invariant conditions out of loops",
min_opt_level: DeepOptLevel::O2,
dependencies: DeepPassDependency {
requires: vec![deep_pass_ids::LOOP_SIMPLIFY_CFG],
invalidates: vec![],
preserves: vec![],
},
enabled: true,
x86_tuning_weight: tuning_weight(35),
});
self.add_pass(DeepPass {
id: deep_pass_ids::SIMPLE_LOOP_UNSWITCH,
name: "SimpleLoopUnswitch",
description: "Trivial loop unswitching (no code duplication)",
min_opt_level: DeepOptLevel::O1,
dependencies: DeepPassDependency {
requires: vec![],
invalidates: vec![],
preserves: vec![],
},
enabled: true,
x86_tuning_weight: tuning_weight(20),
});
self.add_pass(DeepPass {
id: deep_pass_ids::NARY_REASSOCIATE,
name: "NaryReassociate",
description: "N-ary reassociation to expose CSE and simplify addressing",
min_opt_level: DeepOptLevel::O2,
dependencies: DeepPassDependency {
requires: vec![],
invalidates: vec![],
preserves: vec![],
},
enabled: true,
x86_tuning_weight: tuning_weight(30),
});
self.add_pass(DeepPass {
id: deep_pass_ids::LOAD_STORE_VECTORIZER,
name: "LoadStoreVectorizer",
description: "Merges adjacent scalar loads/stores into vector operations",
min_opt_level: DeepOptLevel::O2,
dependencies: DeepPassDependency {
requires: vec![],
invalidates: vec![],
preserves: vec![],
},
enabled: true,
x86_tuning_weight: tuning_weight(48),
});
self.add_pass(DeepPass {
id: deep_pass_ids::VECTOR_COMBINE,
name: "VectorCombine",
description: "Combines vector operations (shuffle → blend, extract → insert)",
min_opt_level: DeepOptLevel::O2,
dependencies: DeepPassDependency {
requires: vec![],
invalidates: vec![],
preserves: vec![],
},
enabled: true,
x86_tuning_weight: tuning_weight(40),
});
self.add_pass(DeepPass {
id: deep_pass_ids::LOWER_MATRIX_INTRINSICS,
name: "LowerMatrixIntrinsics",
description: "Lowers LLVM matrix intrinsics to efficient vector IR",
min_opt_level: DeepOptLevel::O1,
dependencies: DeepPassDependency {
requires: vec![],
invalidates: vec![],
preserves: vec![],
},
enabled: true,
x86_tuning_weight: tuning_weight(15),
});
self.add_pass(DeepPass {
id: deep_pass_ids::EXPAND_REDUCTIONS,
name: "ExpandReductions",
description: "Expands vector reduction intrinsics to shuffle trees",
min_opt_level: DeepOptLevel::O1,
dependencies: DeepPassDependency {
requires: vec![],
invalidates: vec![],
preserves: vec![],
},
enabled: true,
x86_tuning_weight: tuning_weight(20),
});
self.add_pass(DeepPass {
id: deep_pass_ids::IRCE_CORE,
name: "IrceCore",
description: "Inductive range check elimination — removes redundant bounds checks",
min_opt_level: DeepOptLevel::O3,
dependencies: DeepPassDependency {
requires: vec![deep_pass_ids::LOOP_SIMPLIFY_CFG],
invalidates: vec![],
preserves: vec![],
},
enabled: true,
x86_tuning_weight: tuning_weight(38),
});
self.add_pass(DeepPass {
id: deep_pass_ids::REWRITE_STATEPOINTS,
name: "RewriteStatepointsForGC",
description: "Rewrites GC statepoints for precise garbage collection support",
min_opt_level: DeepOptLevel::O1,
dependencies: DeepPassDependency {
requires: vec![],
invalidates: vec![],
preserves: vec![],
},
enabled: true,
x86_tuning_weight: tuning_weight(10),
});
self.add_pass(DeepPass {
id: deep_pass_ids::EXPAND_MEMCMP,
name: "ExpandMemCmp",
description: "Expands memcmp/bcmp calls to efficient inline comparison loops",
min_opt_level: DeepOptLevel::O1,
dependencies: DeepPassDependency {
requires: vec![],
invalidates: vec![],
preserves: vec![],
},
enabled: true,
x86_tuning_weight: tuning_weight(18),
});
self.add_pass(DeepPass {
id: deep_pass_ids::LOWER_INVOKE,
name: "LowerInvoke",
description: "Lowers invoke to call+landingpad (for targets without EH support)",
min_opt_level: DeepOptLevel::O0,
dependencies: DeepPassDependency {
requires: vec![],
invalidates: vec![],
preserves: vec![],
},
enabled: true,
x86_tuning_weight: tuning_weight(25),
});
self.add_pass(DeepPass {
id: deep_pass_ids::LOWER_SWITCH,
name: "LowerSwitch",
description: "Lowers switch to jump table / binary tree / if-chain",
min_opt_level: DeepOptLevel::O0,
dependencies: DeepPassDependency {
requires: vec![],
invalidates: vec![],
preserves: vec![],
},
enabled: true,
x86_tuning_weight: tuning_weight(22),
});
self.add_pass(DeepPass {
id: deep_pass_ids::ENTRY_EXIT_INSTRUMENTER,
name: "EntryExitInstrumenter",
description: "Instruments function entry/exit for profiling or sanitizers",
min_opt_level: DeepOptLevel::O0,
dependencies: DeepPassDependency {
requires: vec![],
invalidates: vec![],
preserves: vec![],
},
enabled: true,
x86_tuning_weight: tuning_weight(5),
});
self.add_pass(DeepPass {
id: deep_pass_ids::INJECT_TLI_MAPPINGS,
name: "InjectTLIMappings",
description: "Injects target library info vector mappings for math library calls",
min_opt_level: DeepOptLevel::O2,
dependencies: DeepPassDependency {
requires: vec![],
invalidates: vec![],
preserves: vec![],
},
enabled: true,
x86_tuning_weight: tuning_weight(28),
});
}
fn add_pass(&mut self, pass: DeepPass) {
self.stats.insert(pass.id, DeepPassStats::default());
self.passes.push(pass);
}
pub fn get_pipeline_order(&self) -> Vec<DeepPassId> {
self.passes
.iter()
.filter(|p| p.enabled && self.opt_level >= p.min_opt_level)
.map(|p| p.id)
.collect()
}
pub fn run_pass(&mut self, pass_id: DeepPassId) -> DeepPassResult {
let result = match pass_id {
deep_pass_ids::CONSTANT_MERGE => {
let mut pass = ConstantMergePass::new();
pass.run()
}
deep_pass_ids::GLOBAL_MERGE => {
let mut pass = GlobalMergePass::new();
pass.run()
}
deep_pass_ids::MERGE_FUNCTIONS => {
let mut pass = MergeFunctionsPass::new();
pass.run()
}
deep_pass_ids::PARTIAL_INLINING => {
let mut pass = PartialInliningPass::new();
pass.run()
}
deep_pass_ids::FUNCTION_SPECIALIZATION => {
let mut pass = FunctionSpecializationPass::new();
pass.run()
}
deep_pass_ids::HOT_COLD_SPLITTING => {
let mut pass = HotColdSplittingPass::new();
pass.run()
}
deep_pass_ids::IR_OUTLINER => {
let mut pass = IROutlinerPass::new();
pass.run()
}
deep_pass_ids::LOOP_EXTRACTOR => {
let mut pass = LoopExtractorPass::new();
pass.run()
}
deep_pass_ids::LOOP_SIMPLIFY_CFG => {
let mut pass = LoopSimplifyCFGPass::new();
pass.run()
}
deep_pass_ids::LOOP_STRENGTH_REDUCE => {
let mut pass = LoopStrengthReducePass::new();
pass.run()
}
deep_pass_ids::LOOP_DATA_PREFETCH => {
let mut pass = LoopDataPrefetchPass::new(self.microarch_tuning.prefetch_distance);
pass.run()
}
deep_pass_ids::LOOP_LOAD_ELIM => {
let mut pass = LoopLoadElimPass::new();
pass.run()
}
deep_pass_ids::LOOP_REROLL => {
let mut pass = LoopRerollPass::new();
pass.run()
}
deep_pass_ids::LOOP_INTERCHANGE => {
let mut pass = LoopInterchangePass::new();
pass.run()
}
deep_pass_ids::LOOP_UNSWITCH => {
let mut pass = LoopUnswitchPass::new(false);
pass.run()
}
deep_pass_ids::SIMPLE_LOOP_UNSWITCH => {
let mut pass = SimpleLoopUnswitchPass::new();
pass.run()
}
deep_pass_ids::NARY_REASSOCIATE => {
let mut pass = NaryReassociatePass::new();
pass.run()
}
deep_pass_ids::LOAD_STORE_VECTORIZER => {
let mut pass =
LoadStoreVectorizerPass::new(self.microarch_tuning.preferred_vector_width);
pass.run()
}
deep_pass_ids::VECTOR_COMBINE => {
let mut pass = VectorCombinePass::new();
pass.run()
}
deep_pass_ids::LOWER_MATRIX_INTRINSICS => {
let mut pass = LowerMatrixIntrinsicsPass::new();
pass.run()
}
deep_pass_ids::EXPAND_REDUCTIONS => {
let mut pass = ExpandReductionsPass::new();
pass.run()
}
deep_pass_ids::LOWER_WIDENABLE_CONDITION => {
let mut pass = LowerWidenableConditionPass::new();
pass.run()
}
deep_pass_ids::MAKE_GUARDS_EXPLICIT => {
let mut pass = MakeGuardsExplicitPass::new();
pass.run()
}
deep_pass_ids::IRCE_CORE => {
let mut pass = IrceCorePass::new();
pass.run()
}
deep_pass_ids::REWRITE_STATEPOINTS => {
let mut pass = RewriteStatepointsForGCPass::new();
pass.run()
}
deep_pass_ids::EXPAND_MEMCMP => {
let mut pass = ExpandMemCmpPass::new();
pass.run()
}
deep_pass_ids::LOWER_INVOKE => {
let mut pass = LowerInvokePass::new();
pass.run()
}
deep_pass_ids::LOWER_SWITCH => {
let mut pass = LowerSwitchPass::new();
pass.run()
}
deep_pass_ids::LOWER_CONSTANT_INTRINSICS => {
let mut pass = LowerConstantIntrinsicsPass::new();
pass.run()
}
deep_pass_ids::LOWER_EXPECT_INTRINSIC => {
let mut pass = LowerExpectIntrinsicPass::new();
pass.run()
}
deep_pass_ids::ENTRY_EXIT_INSTRUMENTER => {
let mut pass = EntryExitInstrumenterPass::new();
pass.run()
}
deep_pass_ids::INJECT_TLI_MAPPINGS => {
let mut pass = InjectTLIMappingsPass::new("libmvec");
pass.run()
}
_ => DeepPassResult::Invalid,
};
if let Some(stats) = self.stats.get_mut(&pass_id) {
stats.run_count += 1;
if result == DeepPassResult::Changed {
stats.changed_count += 1;
}
}
result
}
pub fn run_pipeline(&mut self) -> (usize, usize) {
let order = self.get_pipeline_order();
let mut total_ran = 0;
let mut total_changed = 0;
for pass_id in &order {
let result = self.run_pass(*pass_id);
total_ran += 1;
if result == DeepPassResult::Changed {
total_changed += 1;
}
}
(total_ran, total_changed)
}
pub fn get_all_stats(&self) -> Vec<(DeepPassId, &'static str, &DeepPassStats)> {
self.passes
.iter()
.filter_map(|p| self.stats.get(&p.id).map(|s| (p.id, p.name, s)))
.collect()
}
pub fn check_dependencies(&self, pass_id: DeepPassId) -> bool {
if let Some(pass) = self.passes.iter().find(|p| p.id == pass_id) {
for req_id in &pass.dependencies.requires {
if let Some(req_stats) = self.stats.get(req_id) {
if req_stats.run_count == 0 {
return false;
}
} else {
return false;
}
}
true
} else {
false
}
}
pub fn set_pass_enabled(&mut self, pass_id: DeepPassId, enabled: bool) -> bool {
if let Some(pass) = self.passes.iter_mut().find(|p| p.id == pass_id) {
pass.enabled = enabled;
true
} else {
false
}
}
pub fn active_pass_count(&self) -> usize {
self.get_pipeline_order().len()
}
}
pub fn o0_pipeline_order() -> Vec<DeepPassId> {
use deep_pass_ids::*;
vec![
LOWER_CONSTANT_INTRINSICS,
LOWER_EXPECT_INTRINSIC,
LOWER_WIDENABLE_CONDITION,
EXPAND_REDUCTIONS,
LOWER_MATRIX_INTRINSICS,
EXPAND_MEMCMP,
LOWER_INVOKE,
LOWER_SWITCH,
]
}
pub fn o1_pipeline_order() -> Vec<DeepPassId> {
use deep_pass_ids::*;
let mut pipeline = o0_pipeline_order();
pipeline.extend(vec![
MAKE_GUARDS_EXPLICIT,
CONSTANT_MERGE,
LOOP_SIMPLIFY_CFG,
SIMPLE_LOOP_UNSWITCH,
REWRITE_STATEPOINTS,
ENTRY_EXIT_INSTRUMENTER,
]);
pipeline
}
pub fn o2_pipeline_order() -> Vec<DeepPassId> {
use deep_pass_ids::*;
let mut pipeline = o1_pipeline_order();
pipeline.extend(vec![
GLOBAL_MERGE,
LOOP_STRENGTH_REDUCE,
LOOP_LOAD_ELIM,
LOOP_UNSWITCH,
NARY_REASSOCIATE,
LOAD_STORE_VECTORIZER,
VECTOR_COMBINE,
INJECT_TLI_MAPPINGS,
]);
pipeline
}
pub fn o3_pipeline_order() -> Vec<DeepPassId> {
use deep_pass_ids::*;
let mut pipeline = o2_pipeline_order();
pipeline.extend(vec![
FUNCTION_SPECIALIZATION,
HOT_COLD_SPLITTING,
PARTIAL_INLINING,
LOOP_DATA_PREFETCH,
LOOP_INTERCHANGE,
IRCE_CORE,
]);
pipeline
}
pub fn os_pipeline_order() -> Vec<DeepPassId> {
use deep_pass_ids::*;
vec![
LOWER_CONSTANT_INTRINSICS,
LOWER_EXPECT_INTRINSIC,
LOWER_WIDENABLE_CONDITION,
EXPAND_REDUCTIONS,
LOWER_MATRIX_INTRINSICS,
EXPAND_MEMCMP,
LOWER_INVOKE,
LOWER_SWITCH,
CONSTANT_MERGE,
GLOBAL_MERGE,
MERGE_FUNCTIONS,
IR_OUTLINER,
LOOP_REROLL,
SIMPLE_LOOP_UNSWITCH,
LOAD_STORE_VECTORIZER,
VECTOR_COMBINE,
ENTRY_EXIT_INSTRUMENTER,
]
}
pub fn oz_pipeline_order() -> Vec<DeepPassId> {
let mut pipeline = os_pipeline_order();
pipeline
}
#[derive(Debug)]
pub struct X86IRPassesBuilder {
opt_level: DeepOptLevel,
tuning: X86MicroArchTuning,
debug_mode: bool,
custom_order: Option<Vec<DeepPassId>>,
disabled_passes: HashSet<DeepPassId>,
enabled_passes: HashSet<DeepPassId>,
}
impl X86IRPassesBuilder {
pub fn new() -> Self {
X86IRPassesBuilder {
opt_level: DeepOptLevel::O2,
tuning: X86MicroArchTuning::default(),
debug_mode: false,
custom_order: None,
disabled_passes: HashSet::new(),
enabled_passes: HashSet::new(),
}
}
pub fn opt_level(mut self, level: DeepOptLevel) -> Self {
self.opt_level = level;
self
}
pub fn tuning(mut self, tuning: X86MicroArchTuning) -> Self {
self.tuning = tuning;
self
}
pub fn debug(mut self, debug: bool) -> Self {
self.debug_mode = debug;
self
}
pub fn disable_pass(mut self, pass_id: DeepPassId) -> Self {
self.disabled_passes.insert(pass_id);
self
}
pub fn enable_pass(mut self, pass_id: DeepPassId) -> Self {
self.enabled_passes.insert(pass_id);
self
}
pub fn custom_order(mut self, order: Vec<DeepPassId>) -> Self {
self.custom_order = Some(order);
self
}
pub fn build(self) -> X86IRPassesDeep {
let mut pm = X86IRPassesDeep::new(self.opt_level, self.tuning);
pm.debug_mode = self.debug_mode;
for id in &self.disabled_passes {
pm.set_pass_enabled(*id, false);
}
for id in &self.enabled_passes {
pm.set_pass_enabled(*id, true);
}
pm
}
}
impl Default for X86IRPassesBuilder {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_pass_manager_creation() {
let pm = X86IRPassesDeep::with_default_tuning(DeepOptLevel::O2);
assert!(pm.active_pass_count() >= 15);
}
#[test]
fn test_o0_pipeline() {
let pm = X86IRPassesDeep::with_default_tuning(DeepOptLevel::O0);
let order = pm.get_pipeline_order();
assert!(order.contains(&deep_pass_ids::LOWER_INVOKE));
assert!(order.contains(&deep_pass_ids::LOWER_SWITCH));
assert!(!order.contains(&deep_pass_ids::LOOP_INTERCHANGE));
assert!(!order.contains(&deep_pass_ids::FUNCTION_SPECIALIZATION));
}
#[test]
fn test_o3_pipeline() {
let pm = X86IRPassesDeep::with_default_tuning(DeepOptLevel::O3);
let order = pm.get_pipeline_order();
assert!(order.contains(&deep_pass_ids::LOOP_INTERCHANGE));
assert!(order.contains(&deep_pass_ids::HOT_COLD_SPLITTING));
assert!(order.contains(&deep_pass_ids::IRCE_CORE));
}
#[test]
fn test_os_pipeline() {
let pm = X86IRPassesDeep::with_default_tuning(DeepOptLevel::Os);
let order = pm.get_pipeline_order();
assert!(order.contains(&deep_pass_ids::MERGE_FUNCTIONS));
assert!(order.contains(&deep_pass_ids::IR_OUTLINER));
assert!(order.contains(&deep_pass_ids::LOOP_REROLL));
}
#[test]
fn test_pass_dependencies() {
let pm = X86IRPassesDeep::with_default_tuning(DeepOptLevel::O2);
let gm_pass = pm
.passes
.iter()
.find(|p| p.id == deep_pass_ids::GLOBAL_MERGE)
.unwrap();
assert!(gm_pass
.dependencies
.requires
.contains(&deep_pass_ids::CONSTANT_MERGE));
}
#[test]
fn test_run_individual_pass() {
let mut pm = X86IRPassesDeep::with_default_tuning(DeepOptLevel::O2);
let result = pm.run_pass(deep_pass_ids::CONSTANT_MERGE);
assert!(result == DeepPassResult::Changed || result == DeepPassResult::Unchanged);
let stats = pm.stats.get(&deep_pass_ids::CONSTANT_MERGE).unwrap();
assert_eq!(stats.run_count, 1);
}
#[test]
fn test_run_full_pipeline() {
let mut pm = X86IRPassesDeep::with_default_tuning(DeepOptLevel::O2);
let (ran, changed) = pm.run_pipeline();
assert!(ran >= 15);
let _ = changed;
}
#[test]
fn test_builder_pattern() {
let pm = X86IRPassesBuilder::new()
.opt_level(DeepOptLevel::O3)
.tuning(X86MicroArchTuning::skylake_client())
.disable_pass(deep_pass_ids::LOOP_EXTRACTOR)
.build();
assert_eq!(pm.opt_level, DeepOptLevel::O3);
assert_eq!(pm.microarch_tuning.arch_name, "skylake");
assert!(
!pm.passes
.iter()
.find(|p| p.id == deep_pass_ids::LOOP_EXTRACTOR)
.unwrap()
.enabled
);
}
#[test]
fn test_disable_enable_pass() {
let mut pm = X86IRPassesDeep::with_default_tuning(DeepOptLevel::O2);
pm.set_pass_enabled(deep_pass_ids::LOOP_UNSWITCH, false);
let order = pm.get_pipeline_order();
assert!(!order.contains(&deep_pass_ids::LOOP_UNSWITCH));
pm.set_pass_enabled(deep_pass_ids::LOOP_UNSWITCH, true);
let order = pm.get_pipeline_order();
assert!(order.contains(&deep_pass_ids::LOOP_UNSWITCH));
}
#[test]
fn test_microarch_tuning_skylake() {
let tuning = X86MicroArchTuning::skylake_client();
assert_eq!(tuning.l1d_size, 32768);
assert_eq!(tuning.l2_size, 262144);
assert_eq!(tuning.prefetch_distance, 32);
}
#[test]
fn test_microarch_tuning_zen4() {
let tuning = X86MicroArchTuning::zen4();
assert_eq!(tuning.arch_name, "zen4");
assert_eq!(tuning.l3_size, 33554432);
}
#[test]
fn test_microarch_tuning_alder_lake() {
let tuning = X86MicroArchTuning::alder_lake_p();
assert_eq!(tuning.l1d_size, 49152);
assert_eq!(tuning.preferred_vector_width, 512);
}
#[test]
fn test_pass_stats_tracking() {
let mut pm = X86IRPassesDeep::with_default_tuning(DeepOptLevel::O2);
pm.run_pass(deep_pass_ids::LOOP_SIMPLIFY_CFG);
pm.run_pass(deep_pass_ids::LOOP_SIMPLIFY_CFG);
pm.run_pass(deep_pass_ids::LOOP_SIMPLIFY_CFG);
let stats = pm.stats.get(&deep_pass_ids::LOOP_SIMPLIFY_CFG).unwrap();
assert_eq!(stats.run_count, 3);
}
#[test]
fn test_all_passes_registered() {
let pm = X86IRPassesDeep::with_default_tuning(DeepOptLevel::O3);
assert_eq!(pm.passes.len(), 32);
}
#[test]
fn test_pass_names_unique() {
let pm = X86IRPassesDeep::with_default_tuning(DeepOptLevel::O3);
let mut names = HashSet::new();
for pass in &pm.passes {
assert!(
names.insert(pass.name),
"Duplicate pass name: {}",
pass.name
);
}
}
#[test]
fn test_o0_pipeline_order_is_minimal() {
let order = o0_pipeline_order();
assert!(order.len() < 15);
assert!(order.contains(&deep_pass_ids::LOWER_INVOKE));
}
#[test]
fn test_o3_pipeline_order_is_aggressive() {
let order = o3_pipeline_order();
assert!(order.len() > 20);
assert!(order.contains(&deep_pass_ids::FUNCTION_SPECIALIZATION));
}
#[test]
fn test_get_all_stats() {
let mut pm = X86IRPassesDeep::with_default_tuning(DeepOptLevel::O2);
pm.run_pass(deep_pass_ids::CONSTANT_MERGE);
pm.run_pass(deep_pass_ids::GLOBAL_MERGE);
let all_stats = pm.get_all_stats();
assert!(all_stats
.iter()
.any(|(id, _, _)| *id == deep_pass_ids::CONSTANT_MERGE));
}
}