use crate::Cycles;
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum Provenance {
Gcc,
Chosen,
Derived,
Awaiting,
}
impl Provenance {
#[must_use]
pub const fn as_str(self) -> &'static str {
match self {
Self::Gcc => "adopted from gcc",
Self::Chosen => "chosen, not measured",
Self::Derived => "derived from another constant here",
Self::Awaiting => "placeholder, awaiting measurement",
}
}
#[must_use]
pub const fn is_evidence(self) -> bool {
matches!(self, Self::Gcc)
}
}
impl std::fmt::Display for Provenance {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(self.as_str())
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Constant {
pub name: &'static str,
pub value: i64,
pub unit: &'static str,
pub document: &'static str,
pub gcc: &'static str,
pub provenance: Provenance,
}
pub const BRANCH_COST_FOR_SIZE: Cycles = Cycles::insns(2);
pub const BRANCH_COST_PREDICTABLE: Cycles = Cycles::ZERO;
pub const PREDICTABLE_BRANCH_PERCENT: u32 = 2;
pub const IF_CONVERSION_BUDGET_PREDICTABLE: u32 = 20;
pub const IF_CONVERSION_BUDGET_UNPREDICTABLE: u32 = 40;
pub const IF_CONVERSION_BLOCK_LIMIT: u32 = 10;
pub const LICM_PRESSURE_MARGIN: u32 = 2;
pub const BLOCK_COPY_MOVES_FOR_SPEED: u32 = 8;
pub const BLOCK_COPY_MOVES_FOR_SIZE: u32 = 4;
pub const REASSOC_WIDTH_UNTUNED: u32 = 1;
pub const INLINE_FREQUENCY_CLAMP: u32 = 100;
pub const INLINE_GROWTH_SQUARING_BOUND: u32 = 256;
pub const ALIGN_FREQUENCY_FRACTION: u32 = 100;
pub const LOOP_ALIGN_MIN_ITERATIONS: u32 = 4;
pub const SCHEDULER_READY_LIST_BOUND: usize = 100;
pub const JUMP_TABLE_MIN_TARGETS: u32 = 8;
pub const ALLOCATOR_DEGRADATION_PERCENT: u32 = 10;
pub const ALL: &[Constant] = &[
Constant {
name: "BRANCH_COST_FOR_SIZE",
value: 2,
unit: "operations",
document: "40.5",
gcc: "BRANCH_COST when optimize_size",
provenance: Provenance::Gcc,
},
Constant {
name: "BRANCH_COST_PREDICTABLE",
value: 0,
unit: "operations",
document: "40.5",
gcc: "BRANCH_COST for a predictable branch",
provenance: Provenance::Gcc,
},
Constant {
name: "PREDICTABLE_BRANCH_PERCENT",
value: 2,
unit: "percent",
document: "40.5",
gcc: "PROB_VERY_LIKELY",
provenance: Provenance::Gcc,
},
Constant {
name: "IF_CONVERSION_BUDGET_PREDICTABLE",
value: 20,
unit: "instructions",
document: "40.5",
gcc: "",
provenance: Provenance::Chosen,
},
Constant {
name: "IF_CONVERSION_BUDGET_UNPREDICTABLE",
value: 40,
unit: "instructions",
document: "40.5",
gcc: "",
provenance: Provenance::Chosen,
},
Constant {
name: "IF_CONVERSION_BLOCK_LIMIT",
value: 10,
unit: "instructions",
document: "40.5",
gcc: "param_max_rtl_if_conversion_insns",
provenance: Provenance::Gcc,
},
Constant {
name: "LICM_PRESSURE_MARGIN",
value: 2,
unit: "registers per class",
document: "40.6",
gcc: "",
provenance: Provenance::Chosen,
},
Constant {
name: "BLOCK_COPY_MOVES_FOR_SPEED",
value: 8,
unit: "moves",
document: "40.7",
gcc: "MOVE_RATIO",
provenance: Provenance::Gcc,
},
Constant {
name: "BLOCK_COPY_MOVES_FOR_SIZE",
value: 4,
unit: "moves",
document: "40.7",
gcc: "MOVE_RATIO when optimize_size",
provenance: Provenance::Gcc,
},
Constant {
name: "REASSOC_WIDTH_UNTUNED",
value: 1,
unit: "operations in parallel",
document: "40.8",
gcc: "TARGET_SCHED_REASSOCIATION_WIDTH default",
provenance: Provenance::Gcc,
},
Constant {
name: "INLINE_FREQUENCY_CLAMP",
value: 100,
unit: "times the entry frequency",
document: "40.11",
gcc: "",
provenance: Provenance::Chosen,
},
Constant {
name: "INLINE_GROWTH_SQUARING_BOUND",
value: 256,
unit: "instructions of growth",
document: "40.11",
gcc: "overall_growth in edge_badness",
provenance: Provenance::Gcc,
},
Constant {
name: "ALIGN_FREQUENCY_FRACTION",
value: 100,
unit: "one part in",
document: "38.5",
gcc: "",
provenance: Provenance::Chosen,
},
Constant {
name: "LOOP_ALIGN_MIN_ITERATIONS",
value: 4,
unit: "iterations",
document: "38.5",
gcc: "param_align_loop_iterations",
provenance: Provenance::Gcc,
},
Constant {
name: "SCHEDULER_READY_LIST_BOUND",
value: 100,
unit: "instructions",
document: "38.8",
gcc: "param_max_sched_ready_insns",
provenance: Provenance::Gcc,
},
Constant {
name: "JUMP_TABLE_MIN_TARGETS",
value: 8,
unit: "case targets",
document: "40.10",
gcc: "param_case_values_threshold",
provenance: Provenance::Awaiting,
},
Constant {
name: "ALLOCATOR_DEGRADATION_PERCENT",
value: 10,
unit: "percent",
document: "39.4",
gcc: "",
provenance: Provenance::Awaiting,
},
];
#[cfg(test)]
mod tests {
use super::{
ALL, BLOCK_COPY_MOVES_FOR_SIZE, BLOCK_COPY_MOVES_FOR_SPEED, BRANCH_COST_FOR_SIZE,
BRANCH_COST_PREDICTABLE, IF_CONVERSION_BUDGET_PREDICTABLE,
IF_CONVERSION_BUDGET_UNPREDICTABLE, Provenance,
};
use crate::Cycles;
#[test]
fn the_table_matches_the_constants_it_describes() {
let by_name = |name: &str| ALL.iter().find(|c| c.name == name).expect(name).value;
assert_eq!(by_name("BRANCH_COST_FOR_SIZE") * 100, BRANCH_COST_FOR_SIZE.raw());
assert_eq!(by_name("BRANCH_COST_PREDICTABLE") * 100, BRANCH_COST_PREDICTABLE.raw());
assert_eq!(by_name("BLOCK_COPY_MOVES_FOR_SPEED"), i64::from(BLOCK_COPY_MOVES_FOR_SPEED));
assert_eq!(by_name("BLOCK_COPY_MOVES_FOR_SIZE"), i64::from(BLOCK_COPY_MOVES_FOR_SIZE));
}
#[test]
fn every_constant_names_the_document_that_argued_for_it() {
for constant in ALL {
assert!(
constant.document.starts_with(|c: char| c.is_ascii_digit()),
"{} cites {:?}, which is not a section number",
constant.name,
constant.document
);
assert!(!constant.unit.is_empty(), "{} does not say what it counts", constant.name);
}
}
#[test]
fn a_constant_with_no_gcc_parameter_does_not_claim_to_be_adopted_from_gcc() {
for constant in ALL {
if constant.provenance == Provenance::Gcc {
assert!(
!constant.gcc.is_empty(),
"{} says it came from gcc without saying from where",
constant.name
);
}
}
}
#[test]
fn the_two_unmeasured_constants_are_marked_and_not_dressed_up() {
let waiting: Vec<&str> =
ALL.iter().filter(|c| c.provenance == Provenance::Awaiting).map(|c| c.name).collect();
assert_eq!(waiting, ["JUMP_TABLE_MIN_TARGETS", "ALLOCATOR_DEGRADATION_PERCENT"]);
}
#[test]
fn an_unpredictable_branch_gets_a_larger_budget_than_a_predictable_one() {
const {
assert!(IF_CONVERSION_BUDGET_UNPREDICTABLE > IF_CONVERSION_BUDGET_PREDICTABLE);
}
assert_eq!(BRANCH_COST_PREDICTABLE, Cycles::ZERO);
assert!(BRANCH_COST_FOR_SIZE > BRANCH_COST_PREDICTABLE);
}
#[test]
fn every_name_in_the_table_is_distinct() {
let mut names: Vec<&str> = ALL.iter().map(|c| c.name).collect();
names.sort_unstable();
let before = names.len();
names.dedup();
assert_eq!(names.len(), before);
}
}