#![doc(html_root_url = "https://docs.rs/rucc-cost/0.8.0")]
pub mod cost;
pub mod cycles;
pub mod heuristics;
pub mod table;
pub mod tune;
pub mod x86_64;
pub use cost::{Complexity, Cost};
pub use cycles::{Bytes, Cycles};
pub use table::{AddrMode, Builder, CostTable, Width};
pub use tune::{TuneFlag, Tuning};
use rucc_target::Arch;
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum Goal {
Speed,
Size,
}
impl Goal {
#[must_use]
pub const fn for_size(size: bool) -> Self {
if size { Self::Size } else { Self::Speed }
}
#[must_use]
pub const fn as_str(self) -> &'static str {
match self {
Self::Speed => "speed",
Self::Size => "size",
}
}
}
impl std::fmt::Display for Goal {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(self.as_str())
}
}
pub trait TargetCosts: Send + Sync {
fn table(&self, goal: Goal) -> &CostTable;
fn tune(&self, flag: TuneFlag) -> bool;
fn name(&self) -> &'static str;
fn branch_cost(&self, goal: Goal, predictable: bool) -> Cycles {
if goal == Goal::Speed && predictable {
return heuristics::BRANCH_COST_PREDICTABLE;
}
self.table(goal).branch_cost
}
}
#[must_use]
pub fn for_arch(arch: Arch) -> Option<&'static dyn TargetCosts> {
match arch {
Arch::X86_64 => Some(x86_64::COSTS),
_ => None,
}
}
#[cfg(test)]
mod tests {
use super::{Goal, TuneFlag, for_arch};
use rucc_target::Arch;
#[test]
fn the_only_backend_has_costs() {
let costs = for_arch(Arch::X86_64).expect("x86-64 is the back end rucc has");
assert_eq!(costs.name(), "x86-64");
assert!(!costs.table(Goal::Speed).add.is_infinite());
}
#[test]
fn a_target_with_no_back_end_has_no_costs_rather_than_made_up_ones() {
assert!(for_arch(Arch::Aarch64).is_none());
}
#[test]
fn a_tuning_flag_does_not_depend_on_the_goal() {
let costs = for_arch(Arch::X86_64).unwrap();
for flag in TuneFlag::ALL {
let _: bool = costs.tune(flag);
}
}
}