use std::collections::HashMap;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct ProcResource {
pub id: u32,
pub name: &'static str,
pub num_units: u32,
pub is_pipelined: bool,
pub is_super: bool,
}
#[derive(Debug, Clone)]
pub struct WriteLatency {
pub reg_class: &'static str,
pub latency: u32,
pub is_pipelined: bool,
}
#[derive(Debug, Clone)]
pub struct WriteRes {
pub write_id: u32,
pub resource: u32,
pub cycles: u32,
}
#[derive(Debug, Clone)]
pub struct ReadAdvance {
pub read_id: u32,
pub write_id: u32,
pub advance_cycles: u32,
}
#[derive(Debug, Clone)]
pub struct SchedMachineModel {
pub name: &'static str,
pub issue_width: u32,
pub micro_op_buffer_size: u32,
pub reorder_buffer_size: u32,
pub is_in_order: bool,
pub load_latency: u32,
pub store_latency: u32,
pub mispredict_penalty: u32,
pub description: &'static str,
}
#[derive(Debug, Clone)]
pub struct InstrItinerary {
pub opcode: u32,
pub mnemonic: &'static str,
pub latency: u32,
pub instr_class: InstrClass,
pub resources: Vec<u32>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum InstrClass {
IntALU,
IntMul,
IntDiv,
Branch,
Load,
Store,
FPAddSub,
FPMul,
FPDiv,
FPSqrt,
SIMDIntALU,
SIMDIntMul,
SIMDFP,
SIMDPermute,
SIMDLoadStore,
SIMDComplex,
System,
Move,
NoOp,
}
impl InstrClass {
pub fn typical_latency(&self, model: &SchedMachineModel) -> u32 {
match self {
InstrClass::IntALU | InstrClass::Move | InstrClass::NoOp => 1,
InstrClass::Branch => 1,
InstrClass::Load => model.load_latency,
InstrClass::Store => model.store_latency,
InstrClass::IntMul => 4,
InstrClass::IntDiv => 12,
InstrClass::FPAddSub => 3,
InstrClass::FPMul => 4,
InstrClass::FPDiv => 14,
InstrClass::FPSqrt => 17,
InstrClass::SIMDIntALU => 2,
InstrClass::SIMDIntMul => 4,
InstrClass::SIMDFP => 4,
InstrClass::SIMDPermute => 2,
InstrClass::SIMDLoadStore => 5,
InstrClass::SIMDComplex => 7,
InstrClass::System => 1,
}
}
}
pub mod resources {
use super::ProcResource;
pub const R_NONE: u32 = 0;
pub const R_ALU0: u32 = 1;
pub const R_ALU1: u32 = 2;
pub const R_ALU2: u32 = 3;
pub const R_ALU3: u32 = 4;
pub const R_ALU4: u32 = 5;
pub const R_ALU5: u32 = 6;
pub const R_ALU6: u32 = 7;
pub const R_ALU7: u32 = 8;
pub const R_MUL0: u32 = 9;
pub const R_MUL1: u32 = 10;
pub const R_MUL2: u32 = 11;
pub const R_DIV0: u32 = 12;
pub const R_DIV1: u32 = 13;
pub const R_BR0: u32 = 14;
pub const R_BR1: u32 = 15;
pub const R_LD0: u32 = 16;
pub const R_LD1: u32 = 17;
pub const R_LD2: u32 = 18;
pub const R_LD3: u32 = 19;
pub const R_ST0: u32 = 20;
pub const R_ST1: u32 = 21;
pub const R_ST2: u32 = 22;
pub const R_FP0: u32 = 23;
pub const R_FP1: u32 = 24;
pub const R_FP2: u32 = 25;
pub const R_FP3: u32 = 26;
pub const R_FP4: u32 = 27;
pub const R_FMA0: u32 = 28;
pub const R_FMA1: u32 = 29;
pub const R_FMA2: u32 = 30;
pub const R_FMA3: u32 = 31;
pub const R_SIMD0: u32 = 32;
pub const R_SIMD1: u32 = 33;
pub const R_SIMD2: u32 = 34;
pub const R_SIMD3: u32 = 35;
pub const R_SIMD4: u32 = 36;
pub const R_SIMD5: u32 = 37;
pub const R_STORE_DATA0: u32 = 38;
pub const R_STORE_DATA1: u32 = 39;
pub const R_CRYPTO0: u32 = 40;
pub const R_CRYPTO1: u32 = 41;
pub const R_SVE0: u32 = 42;
pub const R_SVE1: u32 = 43;
pub fn proc_resources() -> Vec<ProcResource> {
vec![
ProcResource {
id: R_NONE,
name: "NoResource",
num_units: 0,
is_pipelined: false,
is_super: false,
},
ProcResource {
id: R_ALU0,
name: "A53_ALU0",
num_units: 2,
is_pipelined: true,
is_super: false,
},
ProcResource {
id: R_ALU1,
name: "A72_ALU2",
num_units: 3,
is_pipelined: true,
is_super: false,
},
ProcResource {
id: R_ALU2,
name: "A76_ALU3",
num_units: 4,
is_pipelined: true,
is_super: false,
},
ProcResource {
id: R_ALU3,
name: "X1_ALU4",
num_units: 5,
is_pipelined: true,
is_super: false,
},
ProcResource {
id: R_ALU4,
name: "X4_ALU5",
num_units: 8,
is_pipelined: true,
is_super: false,
},
ProcResource {
id: R_ALU5,
name: "M1_ALU6",
num_units: 6,
is_pipelined: true,
is_super: false,
},
ProcResource {
id: R_ALU6,
name: "M2_ALU7",
num_units: 7,
is_pipelined: true,
is_super: false,
},
ProcResource {
id: R_ALU7,
name: "M4_ALU8",
num_units: 8,
is_pipelined: true,
is_super: false,
},
ProcResource {
id: R_MUL0,
name: "IntMul0",
num_units: 1,
is_pipelined: true,
is_super: false,
},
ProcResource {
id: R_MUL1,
name: "IntMul1",
num_units: 2,
is_pipelined: true,
is_super: false,
},
ProcResource {
id: R_MUL2,
name: "IntMul2",
num_units: 3,
is_pipelined: true,
is_super: false,
},
ProcResource {
id: R_DIV0,
name: "IntDiv0",
num_units: 1,
is_pipelined: false,
is_super: false,
},
ProcResource {
id: R_DIV1,
name: "IntDiv1",
num_units: 2,
is_pipelined: false,
is_super: false,
},
ProcResource {
id: R_BR0,
name: "Branch0",
num_units: 1,
is_pipelined: true,
is_super: false,
},
ProcResource {
id: R_BR1,
name: "Branch1",
num_units: 2,
is_pipelined: true,
is_super: false,
},
ProcResource {
id: R_LD0,
name: "Load0",
num_units: 1,
is_pipelined: true,
is_super: false,
},
ProcResource {
id: R_LD1,
name: "Load1",
num_units: 2,
is_pipelined: true,
is_super: false,
},
ProcResource {
id: R_LD2,
name: "Load2",
num_units: 3,
is_pipelined: true,
is_super: false,
},
ProcResource {
id: R_LD3,
name: "Load3",
num_units: 4,
is_pipelined: true,
is_super: false,
},
ProcResource {
id: R_ST0,
name: "Store0",
num_units: 1,
is_pipelined: true,
is_super: false,
},
ProcResource {
id: R_ST1,
name: "Store1",
num_units: 2,
is_pipelined: true,
is_super: false,
},
ProcResource {
id: R_ST2,
name: "Store2",
num_units: 3,
is_pipelined: true,
is_super: false,
},
ProcResource {
id: R_FP0,
name: "FPAdd0",
num_units: 1,
is_pipelined: true,
is_super: false,
},
ProcResource {
id: R_FP1,
name: "FPAdd1",
num_units: 2,
is_pipelined: true,
is_super: false,
},
ProcResource {
id: R_FP2,
name: "FPAdd2",
num_units: 3,
is_pipelined: true,
is_super: false,
},
ProcResource {
id: R_FP3,
name: "FPAdd3",
num_units: 4,
is_pipelined: true,
is_super: false,
},
ProcResource {
id: R_FP4,
name: "FPAdd4",
num_units: 4,
is_pipelined: true,
is_super: false,
},
ProcResource {
id: R_FMA0,
name: "FMA0",
num_units: 1,
is_pipelined: true,
is_super: false,
},
ProcResource {
id: R_FMA1,
name: "FMA1",
num_units: 2,
is_pipelined: true,
is_super: false,
},
ProcResource {
id: R_FMA2,
name: "FMA2",
num_units: 3,
is_pipelined: true,
is_super: false,
},
ProcResource {
id: R_FMA3,
name: "FMA3",
num_units: 4,
is_pipelined: true,
is_super: false,
},
ProcResource {
id: R_SIMD0,
name: "SIMDALU0",
num_units: 2,
is_pipelined: true,
is_super: false,
},
ProcResource {
id: R_SIMD1,
name: "SIMDALU1",
num_units: 3,
is_pipelined: true,
is_super: false,
},
ProcResource {
id: R_SIMD2,
name: "SIMDALU2",
num_units: 4,
is_pipelined: true,
is_super: false,
},
ProcResource {
id: R_SIMD3,
name: "SIMDALU3",
num_units: 4,
is_pipelined: true,
is_super: false,
},
ProcResource {
id: R_SIMD4,
name: "SIMDALU4",
num_units: 4,
is_pipelined: true,
is_super: false,
},
ProcResource {
id: R_SIMD5,
name: "SIMDALU5",
num_units: 4,
is_pipelined: true,
is_super: false,
},
ProcResource {
id: R_STORE_DATA0,
name: "StoreData0",
num_units: 1,
is_pipelined: true,
is_super: false,
},
ProcResource {
id: R_STORE_DATA1,
name: "StoreData1",
num_units: 2,
is_pipelined: true,
is_super: false,
},
ProcResource {
id: R_CRYPTO0,
name: "Crypto0",
num_units: 1,
is_pipelined: true,
is_super: false,
},
ProcResource {
id: R_CRYPTO1,
name: "Crypto1",
num_units: 2,
is_pipelined: true,
is_super: false,
},
ProcResource {
id: R_SVE0,
name: "SVE0",
num_units: 2,
is_pipelined: true,
is_super: false,
},
ProcResource {
id: R_SVE1,
name: "SVE1",
num_units: 4,
is_pipelined: true,
is_super: false,
},
]
}
}
pub mod write_ids {
pub const W_NONE: u32 = 0;
pub const W_GPR: u32 = 1;
pub const W_FPR32: u32 = 2;
pub const W_FPR64: u32 = 3;
pub const W_FPR128: u32 = 4;
pub const W_ZPR: u32 = 5;
pub const W_PPR: u32 = 6;
pub const W_CC: u32 = 7;
pub const W_MEM: u32 = 8;
}
pub mod read_ids {
pub const R_NONE: u32 = 0;
pub const R_GPR: u32 = 1;
pub const R_FPR32: u32 = 2;
pub const R_FPR64: u32 = 3;
pub const R_FPR128: u32 = 4;
pub const R_ZPR: u32 = 5;
pub const R_PPR: u32 = 6;
pub const R_CC: u32 = 7;
pub const R_MEM: u32 = 8;
}
pub fn cortex_a53_model() -> SchedMachineModel {
SchedMachineModel {
name: "Cortex-A53",
issue_width: 2,
micro_op_buffer_size: 0,
reorder_buffer_size: 0,
is_in_order: true,
load_latency: 4,
store_latency: 1,
mispredict_penalty: 8,
description: "ARM Cortex-A53 in-order dual-issue pipeline. \
2 integer ALU pipes, 1 FP/SIMD pipe, 1 load/store pipe. \
8-stage pipeline, no out-of-order execution.",
}
}
pub fn cortex_a53_itineraries() -> Vec<InstrItinerary> {
vec![
InstrItinerary {
opcode: 0,
mnemonic: "add",
latency: 1,
instr_class: InstrClass::IntALU,
resources: vec![resources::R_ALU0],
},
InstrItinerary {
opcode: 0,
mnemonic: "sub",
latency: 1,
instr_class: InstrClass::IntALU,
resources: vec![resources::R_ALU0],
},
InstrItinerary {
opcode: 0,
mnemonic: "and",
latency: 1,
instr_class: InstrClass::IntALU,
resources: vec![resources::R_ALU0],
},
InstrItinerary {
opcode: 0,
mnemonic: "orr",
latency: 1,
instr_class: InstrClass::IntALU,
resources: vec![resources::R_ALU0],
},
InstrItinerary {
opcode: 0,
mnemonic: "eor",
latency: 1,
instr_class: InstrClass::IntALU,
resources: vec![resources::R_ALU0],
},
InstrItinerary {
opcode: 0,
mnemonic: "mov",
latency: 1,
instr_class: InstrClass::Move,
resources: vec![resources::R_ALU0],
},
InstrItinerary {
opcode: 0,
mnemonic: "movz",
latency: 1,
instr_class: InstrClass::Move,
resources: vec![resources::R_ALU0],
},
InstrItinerary {
opcode: 0,
mnemonic: "movk",
latency: 1,
instr_class: InstrClass::Move,
resources: vec![resources::R_ALU0],
},
InstrItinerary {
opcode: 0,
mnemonic: "adr",
latency: 1,
instr_class: InstrClass::IntALU,
resources: vec![resources::R_ALU0],
},
InstrItinerary {
opcode: 0,
mnemonic: "adrp",
latency: 1,
instr_class: InstrClass::IntALU,
resources: vec![resources::R_ALU0],
},
InstrItinerary {
opcode: 0,
mnemonic: "cmp",
latency: 1,
instr_class: InstrClass::IntALU,
resources: vec![resources::R_ALU0],
},
InstrItinerary {
opcode: 0,
mnemonic: "csel",
latency: 1,
instr_class: InstrClass::IntALU,
resources: vec![resources::R_ALU0],
},
InstrItinerary {
opcode: 0,
mnemonic: "mul",
latency: 4,
instr_class: InstrClass::IntMul,
resources: vec![resources::R_MUL0],
},
InstrItinerary {
opcode: 0,
mnemonic: "madd",
latency: 4,
instr_class: InstrClass::IntMul,
resources: vec![resources::R_MUL0],
},
InstrItinerary {
opcode: 0,
mnemonic: "msub",
latency: 4,
instr_class: InstrClass::IntMul,
resources: vec![resources::R_MUL0],
},
InstrItinerary {
opcode: 0,
mnemonic: "sdiv",
latency: 12,
instr_class: InstrClass::IntDiv,
resources: vec![resources::R_DIV0],
},
InstrItinerary {
opcode: 0,
mnemonic: "udiv",
latency: 12,
instr_class: InstrClass::IntDiv,
resources: vec![resources::R_DIV0],
},
InstrItinerary {
opcode: 0,
mnemonic: "ldr",
latency: 4,
instr_class: InstrClass::Load,
resources: vec![resources::R_LD0],
},
InstrItinerary {
opcode: 0,
mnemonic: "ldrb",
latency: 4,
instr_class: InstrClass::Load,
resources: vec![resources::R_LD0],
},
InstrItinerary {
opcode: 0,
mnemonic: "ldrh",
latency: 4,
instr_class: InstrClass::Load,
resources: vec![resources::R_LD0],
},
InstrItinerary {
opcode: 0,
mnemonic: "ldp",
latency: 4,
instr_class: InstrClass::Load,
resources: vec![resources::R_LD0],
},
InstrItinerary {
opcode: 0,
mnemonic: "ldur",
latency: 4,
instr_class: InstrClass::Load,
resources: vec![resources::R_LD0],
},
InstrItinerary {
opcode: 0,
mnemonic: "str",
latency: 1,
instr_class: InstrClass::Store,
resources: vec![resources::R_ST0],
},
InstrItinerary {
opcode: 0,
mnemonic: "strb",
latency: 1,
instr_class: InstrClass::Store,
resources: vec![resources::R_ST0],
},
InstrItinerary {
opcode: 0,
mnemonic: "strh",
latency: 1,
instr_class: InstrClass::Store,
resources: vec![resources::R_ST0],
},
InstrItinerary {
opcode: 0,
mnemonic: "stp",
latency: 1,
instr_class: InstrClass::Store,
resources: vec![resources::R_ST0],
},
InstrItinerary {
opcode: 0,
mnemonic: "stur",
latency: 1,
instr_class: InstrClass::Store,
resources: vec![resources::R_ST0],
},
InstrItinerary {
opcode: 0,
mnemonic: "b",
latency: 1,
instr_class: InstrClass::Branch,
resources: vec![resources::R_BR0],
},
InstrItinerary {
opcode: 0,
mnemonic: "bl",
latency: 1,
instr_class: InstrClass::Branch,
resources: vec![resources::R_BR0],
},
InstrItinerary {
opcode: 0,
mnemonic: "br",
latency: 1,
instr_class: InstrClass::Branch,
resources: vec![resources::R_BR0],
},
InstrItinerary {
opcode: 0,
mnemonic: "blr",
latency: 1,
instr_class: InstrClass::Branch,
resources: vec![resources::R_BR0],
},
InstrItinerary {
opcode: 0,
mnemonic: "ret",
latency: 1,
instr_class: InstrClass::Branch,
resources: vec![resources::R_BR0],
},
InstrItinerary {
opcode: 0,
mnemonic: "cbz",
latency: 1,
instr_class: InstrClass::Branch,
resources: vec![resources::R_BR0],
},
InstrItinerary {
opcode: 0,
mnemonic: "cbnz",
latency: 1,
instr_class: InstrClass::Branch,
resources: vec![resources::R_BR0],
},
InstrItinerary {
opcode: 0,
mnemonic: "nop",
latency: 0,
instr_class: InstrClass::NoOp,
resources: vec![],
},
InstrItinerary {
opcode: 0,
mnemonic: "fadd",
latency: 5,
instr_class: InstrClass::FPAddSub,
resources: vec![resources::R_FP0],
},
InstrItinerary {
opcode: 0,
mnemonic: "fsub",
latency: 5,
instr_class: InstrClass::FPAddSub,
resources: vec![resources::R_FP0],
},
InstrItinerary {
opcode: 0,
mnemonic: "fmul",
latency: 5,
instr_class: InstrClass::FPMul,
resources: vec![resources::R_FP0],
},
InstrItinerary {
opcode: 0,
mnemonic: "fdiv",
latency: 17,
instr_class: InstrClass::FPDiv,
resources: vec![resources::R_FP0],
},
InstrItinerary {
opcode: 0,
mnemonic: "fsqrt",
latency: 17,
instr_class: InstrClass::FPSqrt,
resources: vec![resources::R_FP0],
},
InstrItinerary {
opcode: 0,
mnemonic: "fmadd",
latency: 5,
instr_class: InstrClass::SIMDComplex,
resources: vec![resources::R_FP0],
},
InstrItinerary {
opcode: 0,
mnemonic: "fmsub",
latency: 5,
instr_class: InstrClass::SIMDComplex,
resources: vec![resources::R_FP0],
},
InstrItinerary {
opcode: 0,
mnemonic: "add_v",
latency: 2,
instr_class: InstrClass::SIMDIntALU,
resources: vec![resources::R_SIMD0],
},
InstrItinerary {
opcode: 0,
mnemonic: "sub_v",
latency: 2,
instr_class: InstrClass::SIMDIntALU,
resources: vec![resources::R_SIMD0],
},
InstrItinerary {
opcode: 0,
mnemonic: "mul_v",
latency: 5,
instr_class: InstrClass::SIMDIntMul,
resources: vec![resources::R_SIMD0],
},
InstrItinerary {
opcode: 0,
mnemonic: "mla_v",
latency: 5,
instr_class: InstrClass::SIMDIntMul,
resources: vec![resources::R_SIMD0],
},
InstrItinerary {
opcode: 0,
mnemonic: "fadd_v",
latency: 5,
instr_class: InstrClass::SIMDFP,
resources: vec![resources::R_FP0],
},
InstrItinerary {
opcode: 0,
mnemonic: "fsub_v",
latency: 5,
instr_class: InstrClass::SIMDFP,
resources: vec![resources::R_FP0],
},
InstrItinerary {
opcode: 0,
mnemonic: "fmul_v",
latency: 5,
instr_class: InstrClass::SIMDFP,
resources: vec![resources::R_FP0],
},
InstrItinerary {
opcode: 0,
mnemonic: "fdiv_v",
latency: 17,
instr_class: InstrClass::SIMDFP,
resources: vec![resources::R_FP0],
},
]
}
pub fn cortex_a72_model() -> SchedMachineModel {
SchedMachineModel {
name: "Cortex-A72",
issue_width: 3,
micro_op_buffer_size: 128,
reorder_buffer_size: 128,
is_in_order: false,
load_latency: 4,
store_latency: 1,
mispredict_penalty: 15,
description: "ARM Cortex-A72 out-of-order pipeline. \
3-wide decode, 8 execution pipes (2 int ALU, 1 int mul/div, \
2 load, 1 store, 2 FP/SIMD), 128-entry ROB. \
Up to 5 μops/cycle dispatch.",
}
}
pub fn cortex_a72_itineraries() -> Vec<InstrItinerary> {
vec![
InstrItinerary {
opcode: 0,
mnemonic: "add",
latency: 1,
instr_class: InstrClass::IntALU,
resources: vec![resources::R_ALU1],
},
InstrItinerary {
opcode: 0,
mnemonic: "sub",
latency: 1,
instr_class: InstrClass::IntALU,
resources: vec![resources::R_ALU1],
},
InstrItinerary {
opcode: 0,
mnemonic: "and",
latency: 1,
instr_class: InstrClass::IntALU,
resources: vec![resources::R_ALU1],
},
InstrItinerary {
opcode: 0,
mnemonic: "orr",
latency: 1,
instr_class: InstrClass::IntALU,
resources: vec![resources::R_ALU1],
},
InstrItinerary {
opcode: 0,
mnemonic: "mov",
latency: 1,
instr_class: InstrClass::Move,
resources: vec![resources::R_ALU1],
},
InstrItinerary {
opcode: 0,
mnemonic: "mul",
latency: 3,
instr_class: InstrClass::IntMul,
resources: vec![resources::R_MUL1],
},
InstrItinerary {
opcode: 0,
mnemonic: "sdiv",
latency: 12,
instr_class: InstrClass::IntDiv,
resources: vec![resources::R_DIV0],
},
InstrItinerary {
opcode: 0,
mnemonic: "udiv",
latency: 12,
instr_class: InstrClass::IntDiv,
resources: vec![resources::R_DIV0],
},
InstrItinerary {
opcode: 0,
mnemonic: "ldr",
latency: 4,
instr_class: InstrClass::Load,
resources: vec![resources::R_LD1],
},
InstrItinerary {
opcode: 0,
mnemonic: "str",
latency: 1,
instr_class: InstrClass::Store,
resources: vec![resources::R_ST1],
},
InstrItinerary {
opcode: 0,
mnemonic: "b",
latency: 1,
instr_class: InstrClass::Branch,
resources: vec![resources::R_BR1],
},
InstrItinerary {
opcode: 0,
mnemonic: "nop",
latency: 0,
instr_class: InstrClass::NoOp,
resources: vec![],
},
InstrItinerary {
opcode: 0,
mnemonic: "fadd",
latency: 3,
instr_class: InstrClass::FPAddSub,
resources: vec![resources::R_FP1],
},
InstrItinerary {
opcode: 0,
mnemonic: "fmul",
latency: 4,
instr_class: InstrClass::FPMul,
resources: vec![resources::R_FP1],
},
InstrItinerary {
opcode: 0,
mnemonic: "fdiv",
latency: 14,
instr_class: InstrClass::FPDiv,
resources: vec![resources::R_FP1],
},
InstrItinerary {
opcode: 0,
mnemonic: "fsqrt",
latency: 14,
instr_class: InstrClass::FPSqrt,
resources: vec![resources::R_FP1],
},
InstrItinerary {
opcode: 0,
mnemonic: "fmadd",
latency: 4,
instr_class: InstrClass::SIMDComplex,
resources: vec![resources::R_FMA0],
},
InstrItinerary {
opcode: 0,
mnemonic: "add_v",
latency: 2,
instr_class: InstrClass::SIMDIntALU,
resources: vec![resources::R_SIMD1],
},
InstrItinerary {
opcode: 0,
mnemonic: "fadd_v",
latency: 3,
instr_class: InstrClass::SIMDFP,
resources: vec![resources::R_FP1],
},
InstrItinerary {
opcode: 0,
mnemonic: "fmul_v",
latency: 4,
instr_class: InstrClass::SIMDFP,
resources: vec![resources::R_FP1],
},
]
}
pub fn cortex_a76_model() -> SchedMachineModel {
SchedMachineModel {
name: "Cortex-A76",
issue_width: 4,
micro_op_buffer_size: 128,
reorder_buffer_size: 128,
is_in_order: false,
load_latency: 4,
store_latency: 1,
mispredict_penalty: 13,
description: "ARM Cortex-A76 out-of-order pipeline. \
4-wide decode, 8 dispatch pipes (4 int ALU, 2 FP/SIMD, \
2 load/store), 128-entry ROB. \
Up to 8 μops/cycle dispatch.",
}
}
pub fn cortex_a76_itineraries() -> Vec<InstrItinerary> {
vec![
InstrItinerary {
opcode: 0,
mnemonic: "add",
latency: 1,
instr_class: InstrClass::IntALU,
resources: vec![resources::R_ALU2],
},
InstrItinerary {
opcode: 0,
mnemonic: "sub",
latency: 1,
instr_class: InstrClass::IntALU,
resources: vec![resources::R_ALU2],
},
InstrItinerary {
opcode: 0,
mnemonic: "and",
latency: 1,
instr_class: InstrClass::IntALU,
resources: vec![resources::R_ALU2],
},
InstrItinerary {
opcode: 0,
mnemonic: "mov",
latency: 1,
instr_class: InstrClass::Move,
resources: vec![resources::R_ALU2],
},
InstrItinerary {
opcode: 0,
mnemonic: "mul",
latency: 3,
instr_class: InstrClass::IntMul,
resources: vec![resources::R_MUL1],
},
InstrItinerary {
opcode: 0,
mnemonic: "sdiv",
latency: 12,
instr_class: InstrClass::IntDiv,
resources: vec![resources::R_DIV0],
},
InstrItinerary {
opcode: 0,
mnemonic: "udiv",
latency: 12,
instr_class: InstrClass::IntDiv,
resources: vec![resources::R_DIV0],
},
InstrItinerary {
opcode: 0,
mnemonic: "ldr",
latency: 4,
instr_class: InstrClass::Load,
resources: vec![resources::R_LD2],
},
InstrItinerary {
opcode: 0,
mnemonic: "str",
latency: 1,
instr_class: InstrClass::Store,
resources: vec![resources::R_ST1],
},
InstrItinerary {
opcode: 0,
mnemonic: "b",
latency: 1,
instr_class: InstrClass::Branch,
resources: vec![resources::R_BR1],
},
InstrItinerary {
opcode: 0,
mnemonic: "nop",
latency: 0,
instr_class: InstrClass::NoOp,
resources: vec![],
},
InstrItinerary {
opcode: 0,
mnemonic: "fadd",
latency: 3,
instr_class: InstrClass::FPAddSub,
resources: vec![resources::R_FP2],
},
InstrItinerary {
opcode: 0,
mnemonic: "fsub",
latency: 3,
instr_class: InstrClass::FPAddSub,
resources: vec![resources::R_FP2],
},
InstrItinerary {
opcode: 0,
mnemonic: "fmul",
latency: 4,
instr_class: InstrClass::FPMul,
resources: vec![resources::R_FP2],
},
InstrItinerary {
opcode: 0,
mnemonic: "fdiv",
latency: 13,
instr_class: InstrClass::FPDiv,
resources: vec![resources::R_FP2],
},
InstrItinerary {
opcode: 0,
mnemonic: "fsqrt",
latency: 13,
instr_class: InstrClass::FPSqrt,
resources: vec![resources::R_FP2],
},
InstrItinerary {
opcode: 0,
mnemonic: "fmadd",
latency: 4,
instr_class: InstrClass::SIMDComplex,
resources: vec![resources::R_FMA1],
},
InstrItinerary {
opcode: 0,
mnemonic: "add_v",
latency: 2,
instr_class: InstrClass::SIMDIntALU,
resources: vec![resources::R_SIMD2],
},
InstrItinerary {
opcode: 0,
mnemonic: "fadd_v",
latency: 3,
instr_class: InstrClass::SIMDFP,
resources: vec![resources::R_FP2],
},
InstrItinerary {
opcode: 0,
mnemonic: "fmul_v",
latency: 4,
instr_class: InstrClass::SIMDFP,
resources: vec![resources::R_FP2],
},
]
}
pub fn cortex_x1_model() -> SchedMachineModel {
SchedMachineModel {
name: "Cortex-X1",
issue_width: 5,
micro_op_buffer_size: 160,
reorder_buffer_size: 224,
is_in_order: false,
load_latency: 4,
store_latency: 1,
mispredict_penalty: 13,
description: "ARM Cortex-X1 performance pipeline. \
5-wide decode, 8 dispatch pipes (4 int ALU, 2 FP/SIMD, \
2 load/store, 1 branch), 224-entry ROB. \
Up to 8 μops/cycle dispatch, Mop cache.",
}
}
pub fn cortex_x1_itineraries() -> Vec<InstrItinerary> {
vec![
InstrItinerary {
opcode: 0,
mnemonic: "add",
latency: 1,
instr_class: InstrClass::IntALU,
resources: vec![resources::R_ALU3],
},
InstrItinerary {
opcode: 0,
mnemonic: "sub",
latency: 1,
instr_class: InstrClass::IntALU,
resources: vec![resources::R_ALU3],
},
InstrItinerary {
opcode: 0,
mnemonic: "mov",
latency: 1,
instr_class: InstrClass::Move,
resources: vec![resources::R_ALU3],
},
InstrItinerary {
opcode: 0,
mnemonic: "mul",
latency: 3,
instr_class: InstrClass::IntMul,
resources: vec![resources::R_MUL2],
},
InstrItinerary {
opcode: 0,
mnemonic: "sdiv",
latency: 12,
instr_class: InstrClass::IntDiv,
resources: vec![resources::R_DIV1],
},
InstrItinerary {
opcode: 0,
mnemonic: "udiv",
latency: 12,
instr_class: InstrClass::IntDiv,
resources: vec![resources::R_DIV1],
},
InstrItinerary {
opcode: 0,
mnemonic: "ldr",
latency: 4,
instr_class: InstrClass::Load,
resources: vec![resources::R_LD2],
},
InstrItinerary {
opcode: 0,
mnemonic: "str",
latency: 1,
instr_class: InstrClass::Store,
resources: vec![resources::R_ST1],
},
InstrItinerary {
opcode: 0,
mnemonic: "b",
latency: 1,
instr_class: InstrClass::Branch,
resources: vec![resources::R_BR1],
},
InstrItinerary {
opcode: 0,
mnemonic: "nop",
latency: 0,
instr_class: InstrClass::NoOp,
resources: vec![],
},
InstrItinerary {
opcode: 0,
mnemonic: "fadd",
latency: 3,
instr_class: InstrClass::FPAddSub,
resources: vec![resources::R_FP3],
},
InstrItinerary {
opcode: 0,
mnemonic: "fmul",
latency: 3,
instr_class: InstrClass::FPMul,
resources: vec![resources::R_FP3],
},
InstrItinerary {
opcode: 0,
mnemonic: "fdiv",
latency: 12,
instr_class: InstrClass::FPDiv,
resources: vec![resources::R_FP3],
},
InstrItinerary {
opcode: 0,
mnemonic: "fsqrt",
latency: 12,
instr_class: InstrClass::FPSqrt,
resources: vec![resources::R_FP3],
},
InstrItinerary {
opcode: 0,
mnemonic: "fmadd",
latency: 4,
instr_class: InstrClass::SIMDComplex,
resources: vec![resources::R_FMA2],
},
InstrItinerary {
opcode: 0,
mnemonic: "add_v",
latency: 2,
instr_class: InstrClass::SIMDIntALU,
resources: vec![resources::R_SIMD3],
},
InstrItinerary {
opcode: 0,
mnemonic: "fadd_v",
latency: 3,
instr_class: InstrClass::SIMDFP,
resources: vec![resources::R_FP3],
},
]
}
pub fn cortex_x4_model() -> SchedMachineModel {
SchedMachineModel {
name: "Cortex-X4",
issue_width: 8,
micro_op_buffer_size: 192,
reorder_buffer_size: 384,
is_in_order: false,
load_latency: 4,
store_latency: 1,
mispredict_penalty: 11,
description: "ARM Cortex-X4 performance pipeline. \
8-wide decode, 10 dispatch pipes (6 int ALU, 2 FP/SIMD, \
2 load/store, 2 branch), 384-entry ROB. \
Up to 10 μops/cycle dispatch.",
}
}
pub fn cortex_x4_itineraries() -> Vec<InstrItinerary> {
vec![
InstrItinerary {
opcode: 0,
mnemonic: "add",
latency: 1,
instr_class: InstrClass::IntALU,
resources: vec![resources::R_ALU4],
},
InstrItinerary {
opcode: 0,
mnemonic: "sub",
latency: 1,
instr_class: InstrClass::IntALU,
resources: vec![resources::R_ALU4],
},
InstrItinerary {
opcode: 0,
mnemonic: "mov",
latency: 1,
instr_class: InstrClass::Move,
resources: vec![resources::R_ALU4],
},
InstrItinerary {
opcode: 0,
mnemonic: "mul",
latency: 3,
instr_class: InstrClass::IntMul,
resources: vec![resources::R_MUL2],
},
InstrItinerary {
opcode: 0,
mnemonic: "sdiv",
latency: 12,
instr_class: InstrClass::IntDiv,
resources: vec![resources::R_DIV1],
},
InstrItinerary {
opcode: 0,
mnemonic: "ldr",
latency: 4,
instr_class: InstrClass::Load,
resources: vec![resources::R_LD3],
},
InstrItinerary {
opcode: 0,
mnemonic: "str",
latency: 1,
instr_class: InstrClass::Store,
resources: vec![resources::R_ST2],
},
InstrItinerary {
opcode: 0,
mnemonic: "b",
latency: 1,
instr_class: InstrClass::Branch,
resources: vec![resources::R_BR1],
},
InstrItinerary {
opcode: 0,
mnemonic: "nop",
latency: 0,
instr_class: InstrClass::NoOp,
resources: vec![],
},
InstrItinerary {
opcode: 0,
mnemonic: "fadd",
latency: 2,
instr_class: InstrClass::FPAddSub,
resources: vec![resources::R_FP4],
},
InstrItinerary {
opcode: 0,
mnemonic: "fmul",
latency: 3,
instr_class: InstrClass::FPMul,
resources: vec![resources::R_FP4],
},
InstrItinerary {
opcode: 0,
mnemonic: "fdiv",
latency: 10,
instr_class: InstrClass::FPDiv,
resources: vec![resources::R_FP4],
},
InstrItinerary {
opcode: 0,
mnemonic: "fsqrt",
latency: 10,
instr_class: InstrClass::FPSqrt,
resources: vec![resources::R_FP4],
},
InstrItinerary {
opcode: 0,
mnemonic: "fmadd",
latency: 4,
instr_class: InstrClass::SIMDComplex,
resources: vec![resources::R_FMA3],
},
InstrItinerary {
opcode: 0,
mnemonic: "add_v",
latency: 2,
instr_class: InstrClass::SIMDIntALU,
resources: vec![resources::R_SIMD3],
},
InstrItinerary {
opcode: 0,
mnemonic: "fadd_v",
latency: 2,
instr_class: InstrClass::SIMDFP,
resources: vec![resources::R_FP4],
},
]
}
pub fn apple_m1_firestorm_model() -> SchedMachineModel {
SchedMachineModel {
name: "Apple M1 Firestorm",
issue_width: 8,
micro_op_buffer_size: 0,
reorder_buffer_size: 630,
is_in_order: false,
load_latency: 4,
store_latency: 1,
mispredict_penalty: 14,
description: "Apple M1 Firestorm performance core. \
8-wide decode, massive 630-entry ROB, \
6 integer ALU pipes, 4 FP/SIMD pipes, \
3 load/store AGUs, 2 branch units.",
}
}
pub fn apple_m1_itineraries() -> Vec<InstrItinerary> {
vec![
InstrItinerary {
opcode: 0,
mnemonic: "add",
latency: 1,
instr_class: InstrClass::IntALU,
resources: vec![resources::R_ALU5],
},
InstrItinerary {
opcode: 0,
mnemonic: "sub",
latency: 1,
instr_class: InstrClass::IntALU,
resources: vec![resources::R_ALU5],
},
InstrItinerary {
opcode: 0,
mnemonic: "mov",
latency: 1,
instr_class: InstrClass::Move,
resources: vec![resources::R_ALU5],
},
InstrItinerary {
opcode: 0,
mnemonic: "mul",
latency: 3,
instr_class: InstrClass::IntMul,
resources: vec![resources::R_MUL2],
},
InstrItinerary {
opcode: 0,
mnemonic: "ldr",
latency: 4,
instr_class: InstrClass::Load,
resources: vec![resources::R_LD3],
},
InstrItinerary {
opcode: 0,
mnemonic: "str",
latency: 1,
instr_class: InstrClass::Store,
resources: vec![resources::R_ST2],
},
InstrItinerary {
opcode: 0,
mnemonic: "b",
latency: 1,
instr_class: InstrClass::Branch,
resources: vec![resources::R_BR1],
},
InstrItinerary {
opcode: 0,
mnemonic: "nop",
latency: 0,
instr_class: InstrClass::NoOp,
resources: vec![],
},
InstrItinerary {
opcode: 0,
mnemonic: "fadd",
latency: 2,
instr_class: InstrClass::FPAddSub,
resources: vec![resources::R_FP4],
},
InstrItinerary {
opcode: 0,
mnemonic: "fmul",
latency: 3,
instr_class: InstrClass::FPMul,
resources: vec![resources::R_FP4],
},
InstrItinerary {
opcode: 0,
mnemonic: "fmadd",
latency: 3,
instr_class: InstrClass::SIMDComplex,
resources: vec![resources::R_FMA3],
},
InstrItinerary {
opcode: 0,
mnemonic: "fadd_v",
latency: 2,
instr_class: InstrClass::SIMDFP,
resources: vec![resources::R_FP4],
},
InstrItinerary {
opcode: 0,
mnemonic: "add_v",
latency: 2,
instr_class: InstrClass::SIMDIntALU,
resources: vec![resources::R_SIMD4],
},
]
}
pub fn apple_m2_avalanche_model() -> SchedMachineModel {
SchedMachineModel {
name: "Apple M2 Avalanche",
issue_width: 9,
micro_op_buffer_size: 0,
reorder_buffer_size: 672,
is_in_order: false,
load_latency: 4,
store_latency: 1,
mispredict_penalty: 14,
description: "Apple M2 Avalanche performance core. \
9-wide decode, 672-entry ROB, \
6 integer ALU pipes, 4 FP/SIMD pipes, \
3 load/store AGUs, 2 branch units.",
}
}
pub fn apple_m2_itineraries() -> Vec<InstrItinerary> {
vec![
InstrItinerary {
opcode: 0,
mnemonic: "add",
latency: 1,
instr_class: InstrClass::IntALU,
resources: vec![resources::R_ALU6],
},
InstrItinerary {
opcode: 0,
mnemonic: "sub",
latency: 1,
instr_class: InstrClass::IntALU,
resources: vec![resources::R_ALU6],
},
InstrItinerary {
opcode: 0,
mnemonic: "mov",
latency: 1,
instr_class: InstrClass::Move,
resources: vec![resources::R_ALU6],
},
InstrItinerary {
opcode: 0,
mnemonic: "mul",
latency: 3,
instr_class: InstrClass::IntMul,
resources: vec![resources::R_MUL2],
},
InstrItinerary {
opcode: 0,
mnemonic: "ldr",
latency: 4,
instr_class: InstrClass::Load,
resources: vec![resources::R_LD3],
},
InstrItinerary {
opcode: 0,
mnemonic: "str",
latency: 1,
instr_class: InstrClass::Store,
resources: vec![resources::R_ST2],
},
InstrItinerary {
opcode: 0,
mnemonic: "nop",
latency: 0,
instr_class: InstrClass::NoOp,
resources: vec![],
},
InstrItinerary {
opcode: 0,
mnemonic: "fadd",
latency: 2,
instr_class: InstrClass::FPAddSub,
resources: vec![resources::R_FP4],
},
InstrItinerary {
opcode: 0,
mnemonic: "fmul",
latency: 3,
instr_class: InstrClass::FPMul,
resources: vec![resources::R_FP4],
},
InstrItinerary {
opcode: 0,
mnemonic: "fmadd",
latency: 3,
instr_class: InstrClass::SIMDComplex,
resources: vec![resources::R_FMA3],
},
InstrItinerary {
opcode: 0,
mnemonic: "fadd_v",
latency: 2,
instr_class: InstrClass::SIMDFP,
resources: vec![resources::R_FP4],
},
InstrItinerary {
opcode: 0,
mnemonic: "add_v",
latency: 2,
instr_class: InstrClass::SIMDIntALU,
resources: vec![resources::R_SIMD4],
},
]
}
pub fn apple_m4_model() -> SchedMachineModel {
SchedMachineModel {
name: "Apple M4",
issue_width: 10,
micro_op_buffer_size: 0,
reorder_buffer_size: 750,
is_in_order: false,
load_latency: 4,
store_latency: 1,
mispredict_penalty: 13,
description: "Apple M4 performance core. \
10-wide decode, 750+ entry ROB, \
8 integer ALU pipes, 4 FP/SIMD pipes, \
3 load/store AGUs, 2 branch units.",
}
}
pub fn apple_m4_itineraries() -> Vec<InstrItinerary> {
vec![
InstrItinerary {
opcode: 0,
mnemonic: "add",
latency: 1,
instr_class: InstrClass::IntALU,
resources: vec![resources::R_ALU7],
},
InstrItinerary {
opcode: 0,
mnemonic: "sub",
latency: 1,
instr_class: InstrClass::IntALU,
resources: vec![resources::R_ALU7],
},
InstrItinerary {
opcode: 0,
mnemonic: "mov",
latency: 1,
instr_class: InstrClass::Move,
resources: vec![resources::R_ALU7],
},
InstrItinerary {
opcode: 0,
mnemonic: "mul",
latency: 3,
instr_class: InstrClass::IntMul,
resources: vec![resources::R_MUL2],
},
InstrItinerary {
opcode: 0,
mnemonic: "ldr",
latency: 4,
instr_class: InstrClass::Load,
resources: vec![resources::R_LD3],
},
InstrItinerary {
opcode: 0,
mnemonic: "str",
latency: 1,
instr_class: InstrClass::Store,
resources: vec![resources::R_ST2],
},
InstrItinerary {
opcode: 0,
mnemonic: "nop",
latency: 0,
instr_class: InstrClass::NoOp,
resources: vec![],
},
InstrItinerary {
opcode: 0,
mnemonic: "fadd",
latency: 2,
instr_class: InstrClass::FPAddSub,
resources: vec![resources::R_FP4],
},
InstrItinerary {
opcode: 0,
mnemonic: "fmul",
latency: 3,
instr_class: InstrClass::FPMul,
resources: vec![resources::R_FP4],
},
InstrItinerary {
opcode: 0,
mnemonic: "fmadd",
latency: 3,
instr_class: InstrClass::SIMDComplex,
resources: vec![resources::R_FMA3],
},
InstrItinerary {
opcode: 0,
mnemonic: "fadd_v",
latency: 2,
instr_class: InstrClass::SIMDFP,
resources: vec![resources::R_FP4],
},
InstrItinerary {
opcode: 0,
mnemonic: "add_v",
latency: 2,
instr_class: InstrClass::SIMDIntALU,
resources: vec![resources::R_SIMD5],
},
]
}
pub fn neoverse_n2_model() -> SchedMachineModel {
SchedMachineModel {
name: "Neoverse N2",
issue_width: 5,
micro_op_buffer_size: 160,
reorder_buffer_size: 192,
is_in_order: false,
load_latency: 4,
store_latency: 1,
mispredict_penalty: 13,
description: "ARM Neoverse N2 server pipeline. \
5-wide decode, ARMv9.0-A with SVE2 support, \
192-entry ROB, 4 int ALU, 2 FP/SIMD, 2 load/store pipes.",
}
}
pub fn neoverse_n2_itineraries() -> Vec<InstrItinerary> {
vec![
InstrItinerary {
opcode: 0,
mnemonic: "add",
latency: 1,
instr_class: InstrClass::IntALU,
resources: vec![resources::R_ALU3],
},
InstrItinerary {
opcode: 0,
mnemonic: "sub",
latency: 1,
instr_class: InstrClass::IntALU,
resources: vec![resources::R_ALU3],
},
InstrItinerary {
opcode: 0,
mnemonic: "mov",
latency: 1,
instr_class: InstrClass::Move,
resources: vec![resources::R_ALU3],
},
InstrItinerary {
opcode: 0,
mnemonic: "mul",
latency: 3,
instr_class: InstrClass::IntMul,
resources: vec![resources::R_MUL1],
},
InstrItinerary {
opcode: 0,
mnemonic: "ldr",
latency: 4,
instr_class: InstrClass::Load,
resources: vec![resources::R_LD2],
},
InstrItinerary {
opcode: 0,
mnemonic: "str",
latency: 1,
instr_class: InstrClass::Store,
resources: vec![resources::R_ST1],
},
InstrItinerary {
opcode: 0,
mnemonic: "nop",
latency: 0,
instr_class: InstrClass::NoOp,
resources: vec![],
},
InstrItinerary {
opcode: 0,
mnemonic: "fadd",
latency: 3,
instr_class: InstrClass::FPAddSub,
resources: vec![resources::R_FP3],
},
InstrItinerary {
opcode: 0,
mnemonic: "fmul",
latency: 4,
instr_class: InstrClass::FPMul,
resources: vec![resources::R_FP3],
},
InstrItinerary {
opcode: 0,
mnemonic: "fmadd",
latency: 4,
instr_class: InstrClass::SIMDComplex,
resources: vec![resources::R_FMA2],
},
InstrItinerary {
opcode: 0,
mnemonic: "add_z",
latency: 2,
instr_class: InstrClass::SIMDIntALU,
resources: vec![resources::R_SVE0],
},
InstrItinerary {
opcode: 0,
mnemonic: "fadd_z",
latency: 3,
instr_class: InstrClass::SIMDFP,
resources: vec![resources::R_SVE0],
},
InstrItinerary {
opcode: 0,
mnemonic: "fmul_z",
latency: 4,
instr_class: InstrClass::SIMDFP,
resources: vec![resources::R_SVE0],
},
InstrItinerary {
opcode: 0,
mnemonic: "ld1b_z",
latency: 5,
instr_class: InstrClass::SIMDLoadStore,
resources: vec![resources::R_LD2, resources::R_SVE0],
},
InstrItinerary {
opcode: 0,
mnemonic: "st1b_z",
latency: 1,
instr_class: InstrClass::SIMDLoadStore,
resources: vec![resources::R_ST1, resources::R_SVE0],
},
]
}
pub fn neoverse_v2_model() -> SchedMachineModel {
SchedMachineModel {
name: "Neoverse V2",
issue_width: 6,
micro_op_buffer_size: 192,
reorder_buffer_size: 256,
is_in_order: false,
load_latency: 4,
store_latency: 1,
mispredict_penalty: 12,
description: "ARM Neoverse V2 high-performance server pipeline. \
6-wide decode, ARMv9.2-A with SVE2, \
256-entry ROB, 4 int ALU, 2 FP/SIMD, 2 load/store pipes, \
2 SVE units.",
}
}
pub fn neoverse_v2_itineraries() -> Vec<InstrItinerary> {
vec![
InstrItinerary {
opcode: 0,
mnemonic: "add",
latency: 1,
instr_class: InstrClass::IntALU,
resources: vec![resources::R_ALU3],
},
InstrItinerary {
opcode: 0,
mnemonic: "sub",
latency: 1,
instr_class: InstrClass::IntALU,
resources: vec![resources::R_ALU3],
},
InstrItinerary {
opcode: 0,
mnemonic: "mov",
latency: 1,
instr_class: InstrClass::Move,
resources: vec![resources::R_ALU3],
},
InstrItinerary {
opcode: 0,
mnemonic: "mul",
latency: 3,
instr_class: InstrClass::IntMul,
resources: vec![resources::R_MUL2],
},
InstrItinerary {
opcode: 0,
mnemonic: "ldr",
latency: 4,
instr_class: InstrClass::Load,
resources: vec![resources::R_LD3],
},
InstrItinerary {
opcode: 0,
mnemonic: "str",
latency: 1,
instr_class: InstrClass::Store,
resources: vec![resources::R_ST2],
},
InstrItinerary {
opcode: 0,
mnemonic: "nop",
latency: 0,
instr_class: InstrClass::NoOp,
resources: vec![],
},
InstrItinerary {
opcode: 0,
mnemonic: "fadd",
latency: 2,
instr_class: InstrClass::FPAddSub,
resources: vec![resources::R_FP4],
},
InstrItinerary {
opcode: 0,
mnemonic: "fmul",
latency: 3,
instr_class: InstrClass::FPMul,
resources: vec![resources::R_FP4],
},
InstrItinerary {
opcode: 0,
mnemonic: "fmadd",
latency: 4,
instr_class: InstrClass::SIMDComplex,
resources: vec![resources::R_FMA3],
},
InstrItinerary {
opcode: 0,
mnemonic: "add_z",
latency: 2,
instr_class: InstrClass::SIMDIntALU,
resources: vec![resources::R_SVE1],
},
InstrItinerary {
opcode: 0,
mnemonic: "sub_z",
latency: 2,
instr_class: InstrClass::SIMDIntALU,
resources: vec![resources::R_SVE1],
},
InstrItinerary {
opcode: 0,
mnemonic: "mul_z",
latency: 4,
instr_class: InstrClass::SIMDIntMul,
resources: vec![resources::R_SVE1],
},
InstrItinerary {
opcode: 0,
mnemonic: "fadd_z",
latency: 2,
instr_class: InstrClass::SIMDFP,
resources: vec![resources::R_SVE1],
},
InstrItinerary {
opcode: 0,
mnemonic: "fmul_z",
latency: 3,
instr_class: InstrClass::SIMDFP,
resources: vec![resources::R_SVE1],
},
InstrItinerary {
opcode: 0,
mnemonic: "fmad_z",
latency: 4,
instr_class: InstrClass::SIMDComplex,
resources: vec![resources::R_SVE1],
},
InstrItinerary {
opcode: 0,
mnemonic: "ld1b_z",
latency: 5,
instr_class: InstrClass::SIMDLoadStore,
resources: vec![resources::R_LD3, resources::R_SVE1],
},
InstrItinerary {
opcode: 0,
mnemonic: "st1b_z",
latency: 1,
instr_class: InstrClass::SIMDLoadStore,
resources: vec![resources::R_ST2, resources::R_SVE1],
},
InstrItinerary {
opcode: 0,
mnemonic: "aesd",
latency: 2,
instr_class: InstrClass::SIMDComplex,
resources: vec![resources::R_CRYPTO1],
},
InstrItinerary {
opcode: 0,
mnemonic: "aese",
latency: 2,
instr_class: InstrClass::SIMDComplex,
resources: vec![resources::R_CRYPTO1],
},
InstrItinerary {
opcode: 0,
mnemonic: "sha256h",
latency: 2,
instr_class: InstrClass::SIMDComplex,
resources: vec![resources::R_CRYPTO1],
},
]
}
pub struct ArmScheduleModel {
pub models: HashMap<&'static str, SchedMachineModel>,
pub itineraries: HashMap<&'static str, Vec<InstrItinerary>>,
}
impl ArmScheduleModel {
pub fn new() -> Self {
let mut models = HashMap::new();
let mut itineraries: HashMap<&'static str, Vec<InstrItinerary>> = HashMap::new();
models.insert("cortex-a53", cortex_a53_model());
itineraries.insert("cortex-a53", cortex_a53_itineraries());
models.insert("cortex-a72", cortex_a72_model());
itineraries.insert("cortex-a72", cortex_a72_itineraries());
models.insert("cortex-a76", cortex_a76_model());
itineraries.insert("cortex-a76", cortex_a76_itineraries());
models.insert("cortex-x1", cortex_x1_model());
itineraries.insert("cortex-x1", cortex_x1_itineraries());
models.insert("cortex-x4", cortex_x4_model());
itineraries.insert("cortex-x4", cortex_x4_itineraries());
models.insert("apple-m1-firestorm", apple_m1_firestorm_model());
itineraries.insert("apple-m1-firestorm", apple_m1_itineraries());
models.insert("apple-m2-avalanche", apple_m2_avalanche_model());
itineraries.insert("apple-m2-avalanche", apple_m2_itineraries());
models.insert("apple-m4", apple_m4_model());
itineraries.insert("apple-m4", apple_m4_itineraries());
models.insert("neoverse-n2", neoverse_n2_model());
itineraries.insert("neoverse-n2", neoverse_n2_itineraries());
models.insert("neoverse-v2", neoverse_v2_model());
itineraries.insert("neoverse-v2", neoverse_v2_itineraries());
ArmScheduleModel {
models,
itineraries,
}
}
pub fn get_model(&self, cpu: &str) -> Option<&SchedMachineModel> {
self.models.get(cpu)
}
pub fn get_itineraries(&self, cpu: &str) -> Option<&Vec<InstrItinerary>> {
self.itineraries.get(cpu)
}
pub fn lookup_latency(&self, cpu: &str, mnemonic: &str) -> Option<u32> {
self.itineraries.get(cpu).and_then(|itin| {
itin.iter()
.find(|i| i.mnemonic == mnemonic)
.map(|i| i.latency)
})
}
pub fn supported_cpus(&self) -> Vec<&'static str> {
self.models.keys().copied().collect()
}
}
impl Default for ArmScheduleModel {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_cortex_a53_model() {
let m = cortex_a53_model();
assert_eq!(m.issue_width, 2);
assert!(m.is_in_order);
assert_eq!(m.reorder_buffer_size, 0);
assert_eq!(m.load_latency, 4);
assert_eq!(m.mispredict_penalty, 8);
}
#[test]
fn test_cortex_a53_itineraries_count() {
let itins = cortex_a53_itineraries();
assert!(itins.len() > 40);
}
#[test]
fn test_cortex_a72_model() {
let m = cortex_a72_model();
assert_eq!(m.issue_width, 3);
assert!(!m.is_in_order);
assert_eq!(m.reorder_buffer_size, 128);
}
#[test]
fn test_cortex_a76_model() {
let m = cortex_a76_model();
assert_eq!(m.issue_width, 4);
assert_eq!(m.reorder_buffer_size, 128);
}
#[test]
fn test_cortex_x1_model() {
let m = cortex_x1_model();
assert_eq!(m.issue_width, 5);
assert_eq!(m.reorder_buffer_size, 224);
}
#[test]
fn test_cortex_x4_model() {
let m = cortex_x4_model();
assert_eq!(m.issue_width, 8);
assert_eq!(m.reorder_buffer_size, 384);
}
#[test]
fn test_apple_m1_model() {
let m = apple_m1_firestorm_model();
assert_eq!(m.issue_width, 8);
assert_eq!(m.reorder_buffer_size, 630);
}
#[test]
fn test_apple_m2_model() {
let m = apple_m2_avalanche_model();
assert_eq!(m.issue_width, 9);
assert_eq!(m.reorder_buffer_size, 672);
}
#[test]
fn test_apple_m4_model() {
let m = apple_m4_model();
assert_eq!(m.issue_width, 10);
assert!(m.reorder_buffer_size >= 750);
}
#[test]
fn test_neoverse_n2_model() {
let m = neoverse_n2_model();
assert_eq!(m.issue_width, 5);
}
#[test]
fn test_neoverse_v2_model() {
let m = neoverse_v2_model();
assert_eq!(m.issue_width, 6);
}
#[test]
fn test_unified_schedule_model() {
let sm = ArmScheduleModel::new();
assert!(sm.supported_cpus().len() >= 10);
assert!(sm.get_model("cortex-a53").is_some());
assert!(sm.get_model("apple-m4").is_some());
assert!(sm.get_itineraries("cortex-a76").is_some());
}
#[test]
fn test_lookup_latency() {
let sm = ArmScheduleModel::new();
assert_eq!(sm.lookup_latency("cortex-a53", "add"), Some(1));
assert_eq!(sm.lookup_latency("cortex-a53", "fdiv"), Some(17));
assert_eq!(sm.lookup_latency("cortex-a72", "mul"), Some(3));
assert_eq!(sm.lookup_latency("neoverse-v2", "aesd"), Some(2));
}
#[test]
fn test_instr_class_latency() {
let m = cortex_a53_model();
assert_eq!(InstrClass::IntALU.typical_latency(&m), 1);
assert_eq!(InstrClass::Load.typical_latency(&m), 4);
assert_eq!(InstrClass::FPDiv.typical_latency(&m), 14);
}
#[test]
fn test_proc_resources_count() {
let resources = resources::proc_resources();
assert!(resources.len() >= 44);
}
#[test]
fn test_inorder_dual_issue() {
let m = cortex_a53_model();
assert!(m.is_in_order);
assert_eq!(m.issue_width, 2);
assert_eq!(m.reorder_buffer_size, 0);
}
#[test]
fn test_outoforder_characteristics() {
let a72 = cortex_a72_model();
let a76 = cortex_a76_model();
let x1 = cortex_x1_model();
assert!(!a72.is_in_order);
assert!(a72.reorder_buffer_size > 0);
assert!(a76.reorder_buffer_size >= a72.reorder_buffer_size);
assert!(x1.reorder_buffer_size > a76.reorder_buffer_size);
}
#[test]
fn test_apple_models_progression() {
let m1 = apple_m1_firestorm_model();
let m2 = apple_m2_avalanche_model();
let m4 = apple_m4_model();
assert!(m2.issue_width > m1.issue_width);
assert!(m4.issue_width > m2.issue_width);
assert!(m2.reorder_buffer_size > m1.reorder_buffer_size);
assert!(m4.reorder_buffer_size > m2.reorder_buffer_size);
}
#[test]
fn test_neoverse_models() {
let n2 = neoverse_n2_model();
let v2 = neoverse_v2_model();
assert!(v2.issue_width > n2.issue_width);
assert!(v2.reorder_buffer_size > n2.reorder_buffer_size);
}
#[test]
fn test_model_load_store_latency() {
let models = vec![
cortex_a53_model(),
cortex_a72_model(),
cortex_a76_model(),
cortex_x1_model(),
cortex_x4_model(),
apple_m1_firestorm_model(),
apple_m2_avalanche_model(),
apple_m4_model(),
neoverse_n2_model(),
neoverse_v2_model(),
];
for m in &models {
assert!(m.load_latency >= 3 && m.load_latency <= 5);
assert!(m.store_latency == 1);
assert!(m.mispredict_penalty >= 8 && m.mispredict_penalty <= 15);
}
}
#[test]
fn test_instr_class_mapping() {
let m = cortex_a53_model();
assert_eq!(InstrClass::IntALU.typical_latency(&m), 1);
assert_eq!(InstrClass::IntMul.typical_latency(&m), 4);
assert_eq!(InstrClass::IntDiv.typical_latency(&m), 12);
assert_eq!(InstrClass::FPAddSub.typical_latency(&m), 3);
assert_eq!(InstrClass::FPMul.typical_latency(&m), 4);
assert_eq!(InstrClass::FPDiv.typical_latency(&m), 14);
assert_eq!(InstrClass::FPSqrt.typical_latency(&m), 17);
assert_eq!(InstrClass::SIMDIntALU.typical_latency(&m), 2);
assert_eq!(InstrClass::SIMDComplex.typical_latency(&m), 7);
assert_eq!(InstrClass::NoOp.typical_latency(&m), 0);
assert_eq!(InstrClass::Branch.typical_latency(&m), 1);
}
#[test]
fn test_all_models_registered() {
let sm = ArmScheduleModel::new();
let cpus = sm.supported_cpus();
assert!(cpus.contains(&"cortex-a53"));
assert!(cpus.contains(&"cortex-a72"));
assert!(cpus.contains(&"cortex-a76"));
assert!(cpus.contains(&"cortex-x1"));
assert!(cpus.contains(&"cortex-x4"));
assert!(cpus.contains(&"apple-m1-firestorm"));
assert!(cpus.contains(&"apple-m2-avalanche"));
assert!(cpus.contains(&"apple-m4"));
assert!(cpus.contains(&"neoverse-n2"));
assert!(cpus.contains(&"neoverse-v2"));
}
#[test]
fn test_resource_conflicts() {
let resources = resources::proc_resources();
assert_eq!(resources[resources::R_ALU0 as usize].num_units, 2); assert_eq!(resources[resources::R_ALU1 as usize].num_units, 3); assert_eq!(resources[resources::R_ALU2 as usize].num_units, 4); assert_eq!(resources[resources::R_FP0 as usize].num_units, 1);
assert_eq!(resources[resources::R_FP1 as usize].num_units, 2);
assert_eq!(resources[resources::R_LD0 as usize].num_units, 1);
assert_eq!(resources[resources::R_LD2 as usize].num_units, 3);
}
#[test]
fn test_itinerary_latency_consistency() {
for itin in cortex_a53_itineraries() {
match itin.instr_class {
InstrClass::NoOp => assert_eq!(itin.latency, 0, "NOP should have 0 latency"),
InstrClass::IntALU => assert!(itin.latency <= 2, "ALU ops should be 1-2 cycles"),
InstrClass::FPDiv | InstrClass::FPSqrt => {
assert!(itin.latency >= 10, "FP div/sqrt should be slow")
}
_ => {}
}
}
}
#[test]
fn test_cortex_a72_full_coverage() {
let itins = cortex_a72_itineraries();
let mnemonics: Vec<&str> = itins.iter().map(|i| i.mnemonic).collect();
assert!(mnemonics.contains(&"add"));
assert!(mnemonics.contains(&"sub"));
assert!(mnemonics.contains(&"mul"));
assert!(mnemonics.contains(&"ldr"));
assert!(mnemonics.contains(&"str"));
assert!(mnemonics.contains(&"b"));
assert!(mnemonics.contains(&"nop"));
assert!(mnemonics.contains(&"fadd"));
assert!(mnemonics.contains(&"fmul"));
}
#[test]
fn test_simd_integer_ops_present() {
let itins = neoverse_v2_itineraries();
let mnemonics: Vec<&str> = itins.iter().map(|i| i.mnemonic).collect();
assert!(mnemonics.contains(&"add_z"));
assert!(mnemonics.contains(&"fadd_z"));
assert!(mnemonics.contains(&"fmul_z"));
assert!(mnemonics.contains(&"aesd"));
assert!(mnemonics.contains(&"aese"));
}
#[test]
fn test_default_schedule_model() {
let sm = ArmScheduleModel::default();
assert_eq!(sm.supported_cpus().len(), 10);
}
}