use crate::arm::arm_instr_info::ArmOpcode;
use crate::opcode::Opcode;
use std::collections::HashMap;
use super::arm_isel_table::{ImmConstraint, IselOperand, IselPattern, IselStats};
pub struct SME2IselTable {
pub patterns: Vec<IselPattern>,
pub stats: IselStats,
}
pub fn sme2_isel_table() -> Vec<IselPattern> {
let mut table = Vec::new();
table.push(IselPattern {
ir_opcode: Opcode::FAdd,
description: "fmopa za0.s, p/m, p/m, z.s, z.s — SME2 FP outer product add 32-bit",
result_opcode: ArmOpcode::FMOPA,
priority: 100,
num_operands: 4,
imm_constraint: None,
is_two_address: false,
required_feature: Some("sme2"),
cond: None,
});
table.push(IselPattern {
ir_opcode: Opcode::FAdd,
description: "fmopa za0.d, p/m, p/m, z.d, z.d — SME2 FP outer product add 64-bit",
result_opcode: ArmOpcode::FMOPA,
priority: 101,
num_operands: 4,
imm_constraint: None,
is_two_address: false,
required_feature: Some("sme2"),
cond: None,
});
table.push(IselPattern {
ir_opcode: Opcode::FAdd,
description: "fmopa za0.h, p/m, p/m, z.h, z.h — SME2 FP outer product add 16-bit",
result_opcode: ArmOpcode::FMOPA,
priority: 102,
num_operands: 4,
imm_constraint: None,
is_two_address: false,
required_feature: Some("sme2"),
cond: None,
});
table.push(IselPattern {
ir_opcode: Opcode::FAdd,
description: "bfmopa za0.s, p/m, p/m, z.h, z.h — SME2 BF16 outer product add",
result_opcode: ArmOpcode::BFMOPA,
priority: 103,
num_operands: 4,
imm_constraint: None,
is_two_address: false,
required_feature: Some("sme2"),
cond: None,
});
table.push(IselPattern {
ir_opcode: Opcode::Mul,
description: "smopa za0.s, p/m, p/m, z.b, z.b — SME2 signed int outer product add 8→32",
result_opcode: ArmOpcode::SMOPA,
priority: 100,
num_operands: 4,
imm_constraint: None,
is_two_address: false,
required_feature: Some("sme2"),
cond: None,
});
table.push(IselPattern {
ir_opcode: Opcode::Mul,
description: "smopa za0.d, p/m, p/m, z.h, z.h — SME2 signed int outer product add 16→64",
result_opcode: ArmOpcode::SMOPA_WIDE,
priority: 101,
num_operands: 4,
imm_constraint: None,
is_two_address: false,
required_feature: Some("sme2"),
cond: None,
});
table.push(IselPattern {
ir_opcode: Opcode::Mul,
description: "umopa za0.s, p/m, p/m, z.b, z.b — SME2 unsigned int outer product add 8→32",
result_opcode: ArmOpcode::UMOPA_WIDE,
priority: 100,
num_operands: 4,
imm_constraint: None,
is_two_address: false,
required_feature: Some("sme2"),
cond: None,
});
table.push(IselPattern {
ir_opcode: Opcode::Mul,
description: "umopa za0.d, p/m, p/m, z.h, z.h — SME2 unsigned int outer product add 16→64",
result_opcode: ArmOpcode::UMOPA_WIDE,
priority: 101,
num_operands: 4,
imm_constraint: None,
is_two_address: false,
required_feature: Some("sme2"),
cond: None,
});
table.push(IselPattern {
ir_opcode: Opcode::FMul,
description: "fmla za.s[m], p/m, z.s, z.s — SME2 multi-vector FMLA 32-bit",
result_opcode: ArmOpcode::FMLA_MULTI_Z,
priority: 100,
num_operands: 4,
imm_constraint: None,
is_two_address: false,
required_feature: Some("sme2"),
cond: None,
});
table.push(IselPattern {
ir_opcode: Opcode::FMul,
description: "fmla za.d[m], p/m, z.d, z.d — SME2 multi-vector FMLA 64-bit",
result_opcode: ArmOpcode::FMLA_MULTI_Z,
priority: 101,
num_operands: 4,
imm_constraint: None,
is_two_address: false,
required_feature: Some("sme2"),
cond: None,
});
table.push(IselPattern {
ir_opcode: Opcode::FMul,
description: "fmla za.h[m], p/m, z.h, z.h — SME2 multi-vector FMLA 16-bit",
result_opcode: ArmOpcode::FMLA_MULTI_Z,
priority: 102,
num_operands: 4,
imm_constraint: None,
is_two_address: false,
required_feature: Some("sme2"),
cond: None,
});
table.push(IselPattern {
ir_opcode: Opcode::FMul,
description: "fmls za.s[m], p/m, z.s, z.s — SME2 multi-vector FMLS 32-bit",
result_opcode: ArmOpcode::FMLS_MULTI_Z,
priority: 103,
num_operands: 4,
imm_constraint: None,
is_two_address: false,
required_feature: Some("sme2"),
cond: None,
});
table.push(IselPattern {
ir_opcode: Opcode::FMul,
description: "fmls za.d[m], p/m, z.d, z.d — SME2 multi-vector FMLS 64-bit",
result_opcode: ArmOpcode::FMLS_MULTI_Z,
priority: 104,
num_operands: 4,
imm_constraint: None,
is_two_address: false,
required_feature: Some("sme2"),
cond: None,
});
table.push(IselPattern {
ir_opcode: Opcode::FMul,
description: "fmls za.h[m], p/m, z.h, z.h — SME2 multi-vector FMLS 16-bit",
result_opcode: ArmOpcode::FMLS_MULTI_Z,
priority: 105,
num_operands: 4,
imm_constraint: None,
is_two_address: false,
required_feature: Some("sme2"),
cond: None,
});
table.push(IselPattern {
ir_opcode: Opcode::Mul,
description: "smlal za.s[m], p/m, z.b, z.b — SME2 signed MLA long multi-vec 8→32",
result_opcode: ArmOpcode::SMLAL_MULTI_Z,
priority: 100,
num_operands: 4,
imm_constraint: None,
is_two_address: false,
required_feature: Some("sme2"),
cond: None,
});
table.push(IselPattern {
ir_opcode: Opcode::Mul,
description: "smlal za.d[m], p/m, z.h, z.h — SME2 signed MLA long multi-vec 16→64",
result_opcode: ArmOpcode::SMLAL_MULTI_Z,
priority: 101,
num_operands: 4,
imm_constraint: None,
is_two_address: false,
required_feature: Some("sme2"),
cond: None,
});
table.push(IselPattern {
ir_opcode: Opcode::Mul,
description: "umlal za.s[m], p/m, z.b, z.b — SME2 unsigned MLA long multi-vec 8→32",
result_opcode: ArmOpcode::UMLAL_MULTI_Z,
priority: 100,
num_operands: 4,
imm_constraint: None,
is_two_address: false,
required_feature: Some("sme2"),
cond: None,
});
table.push(IselPattern {
ir_opcode: Opcode::Mul,
description: "umlal za.d[m], p/m, z.h, z.h — SME2 unsigned MLA long multi-vec 16→64",
result_opcode: ArmOpcode::UMLAL_MULTI_Z,
priority: 101,
num_operands: 4,
imm_constraint: None,
is_two_address: false,
required_feature: Some("sme2"),
cond: None,
});
table.push(IselPattern {
ir_opcode: Opcode::Mul,
description: "smlsl za.s[m], p/m, z.b, z.b — SME2 signed MLS long multi-vec 8→32",
result_opcode: ArmOpcode::SMLSL_MULTI_Z,
priority: 102,
num_operands: 4,
imm_constraint: None,
is_two_address: false,
required_feature: Some("sme2"),
cond: None,
});
table.push(IselPattern {
ir_opcode: Opcode::Mul,
description: "smlsl za.d[m], p/m, z.h, z.h — SME2 signed MLS long multi-vec 16→64",
result_opcode: ArmOpcode::SMLSL_MULTI_Z,
priority: 103,
num_operands: 4,
imm_constraint: None,
is_two_address: false,
required_feature: Some("sme2"),
cond: None,
});
table.push(IselPattern {
ir_opcode: Opcode::Mul,
description: "umlsl za.s[m], p/m, z.b, z.b — SME2 unsigned MLS long multi-vec 8→32",
result_opcode: ArmOpcode::UMLSL_MULTI_Z,
priority: 104,
num_operands: 4,
imm_constraint: None,
is_two_address: false,
required_feature: Some("sme2"),
cond: None,
});
table.push(IselPattern {
ir_opcode: Opcode::Mul,
description: "umlsl za.d[m], p/m, z.h, z.h — SME2 unsigned MLS long multi-vec 16→64",
result_opcode: ArmOpcode::UMLSL_MULTI_Z,
priority: 105,
num_operands: 4,
imm_constraint: None,
is_two_address: false,
required_feature: Some("sme2"),
cond: None,
});
table.push(IselPattern {
ir_opcode: Opcode::Ret,
description: "zero {} — SME2 zero single tile",
result_opcode: ArmOpcode::ZERO_ZA,
priority: 100,
num_operands: 0,
imm_constraint: None,
is_two_address: false,
required_feature: Some("sme2"),
cond: None,
});
table.push(IselPattern {
ir_opcode: Opcode::Load,
description: "ld1b {z.b, z.b}, p/z, [x0] — SME2 contiguous load 2-reg 8-bit",
result_opcode: ArmOpcode::LD1X2_Z,
priority: 100,
num_operands: 3,
imm_constraint: None,
is_two_address: false,
required_feature: Some("sme2"),
cond: None,
});
table.push(IselPattern {
ir_opcode: Opcode::Load,
description: "ld1h {z.h, z.h}, p/z, [x0] — SME2 contiguous load 2-reg 16-bit",
result_opcode: ArmOpcode::LD1X2_Z,
priority: 101,
num_operands: 3,
imm_constraint: None,
is_two_address: false,
required_feature: Some("sme2"),
cond: None,
});
table.push(IselPattern {
ir_opcode: Opcode::Load,
description: "ld1w {z.s, z.s}, p/z, [x0] — SME2 contiguous load 2-reg 32-bit",
result_opcode: ArmOpcode::LD1X2_Z,
priority: 102,
num_operands: 3,
imm_constraint: None,
is_two_address: false,
required_feature: Some("sme2"),
cond: None,
});
table.push(IselPattern {
ir_opcode: Opcode::Load,
description: "ld1d {z.d, z.d}, p/z, [x0] — SME2 contiguous load 2-reg 64-bit",
result_opcode: ArmOpcode::LD1X2_Z,
priority: 103,
num_operands: 3,
imm_constraint: None,
is_two_address: false,
required_feature: Some("sme2"),
cond: None,
});
table.push(IselPattern {
ir_opcode: Opcode::Load,
description: "ld1b {z.b-z.b}, p/z, [x0] — SME2 contiguous load 4-reg 8-bit",
result_opcode: ArmOpcode::LD1X4_Z,
priority: 104,
num_operands: 5,
imm_constraint: None,
is_two_address: false,
required_feature: Some("sme2"),
cond: None,
});
table.push(IselPattern {
ir_opcode: Opcode::Load,
description: "ld1h {z.h-z.h}, p/z, [x0] — SME2 contiguous load 4-reg 16-bit",
result_opcode: ArmOpcode::LD1X4_Z,
priority: 105,
num_operands: 5,
imm_constraint: None,
is_two_address: false,
required_feature: Some("sme2"),
cond: None,
});
table.push(IselPattern {
ir_opcode: Opcode::Load,
description: "ld1w {z.s-z.s}, p/z, [x0] — SME2 contiguous load 4-reg 32-bit",
result_opcode: ArmOpcode::LD1X4_Z,
priority: 106,
num_operands: 5,
imm_constraint: None,
is_two_address: false,
required_feature: Some("sme2"),
cond: None,
});
table.push(IselPattern {
ir_opcode: Opcode::Load,
description: "ld1d {z.d-z.d}, p/z, [x0] — SME2 contiguous load 4-reg 64-bit",
result_opcode: ArmOpcode::LD1X4_Z,
priority: 107,
num_operands: 5,
imm_constraint: None,
is_two_address: false,
required_feature: Some("sme2"),
cond: None,
});
table.push(IselPattern {
ir_opcode: Opcode::Store,
description: "st1b {z.b, z.b}, p, [x0] — SME2 contiguous store 2-reg 8-bit",
result_opcode: ArmOpcode::ST1X2_Z,
priority: 100,
num_operands: 3,
imm_constraint: None,
is_two_address: false,
required_feature: Some("sme2"),
cond: None,
});
table.push(IselPattern {
ir_opcode: Opcode::Store,
description: "st1h {z.h, z.h}, p, [x0] — SME2 contiguous store 2-reg 16-bit",
result_opcode: ArmOpcode::ST1X2_Z,
priority: 101,
num_operands: 3,
imm_constraint: None,
is_two_address: false,
required_feature: Some("sme2"),
cond: None,
});
table.push(IselPattern {
ir_opcode: Opcode::Store,
description: "st1w {z.s, z.s}, p, [x0] — SME2 contiguous store 2-reg 32-bit",
result_opcode: ArmOpcode::ST1X2_Z,
priority: 102,
num_operands: 3,
imm_constraint: None,
is_two_address: false,
required_feature: Some("sme2"),
cond: None,
});
table.push(IselPattern {
ir_opcode: Opcode::Store,
description: "st1d {z.d, z.d}, p, [x0] — SME2 contiguous store 2-reg 64-bit",
result_opcode: ArmOpcode::ST1X2_Z,
priority: 103,
num_operands: 3,
imm_constraint: None,
is_two_address: false,
required_feature: Some("sme2"),
cond: None,
});
table.push(IselPattern {
ir_opcode: Opcode::Store,
description: "st1b {z.b-z.b}, p, [x0] — SME2 contiguous store 4-reg 8-bit",
result_opcode: ArmOpcode::ST1X4_Z,
priority: 104,
num_operands: 5,
imm_constraint: None,
is_two_address: false,
required_feature: Some("sme2"),
cond: None,
});
table.push(IselPattern {
ir_opcode: Opcode::Store,
description: "st1h {z.h-z.h}, p, [x0] — SME2 contiguous store 4-reg 16-bit",
result_opcode: ArmOpcode::ST1X4_Z,
priority: 105,
num_operands: 5,
imm_constraint: None,
is_two_address: false,
required_feature: Some("sme2"),
cond: None,
});
table.push(IselPattern {
ir_opcode: Opcode::Store,
description: "st1w {z.s-z.s}, p, [x0] — SME2 contiguous store 4-reg 32-bit",
result_opcode: ArmOpcode::ST1X4_Z,
priority: 106,
num_operands: 5,
imm_constraint: None,
is_two_address: false,
required_feature: Some("sme2"),
cond: None,
});
table.push(IselPattern {
ir_opcode: Opcode::Store,
description: "st1d {z.d-z.d}, p, [x0] — SME2 contiguous store 4-reg 64-bit",
result_opcode: ArmOpcode::ST1X4_Z,
priority: 107,
num_operands: 5,
imm_constraint: None,
is_two_address: false,
required_feature: Some("sme2"),
cond: None,
});
table.push(IselPattern {
ir_opcode: Opcode::Load,
description: "ld1b z.b, p/z, [x0, x1] — SME2 strided load 8-bit",
result_opcode: ArmOpcode::LD_STRIDED_Z,
priority: 100,
num_operands: 3,
imm_constraint: None,
is_two_address: false,
required_feature: Some("sme2"),
cond: None,
});
table.push(IselPattern {
ir_opcode: Opcode::Load,
description: "ld1h z.h, p/z, [x0, x1] — SME2 strided load 16-bit",
result_opcode: ArmOpcode::LD_STRIDED_Z,
priority: 101,
num_operands: 3,
imm_constraint: None,
is_two_address: false,
required_feature: Some("sme2"),
cond: None,
});
table.push(IselPattern {
ir_opcode: Opcode::Load,
description: "ld1w z.s, p/z, [x0, x1] — SME2 strided load 32-bit",
result_opcode: ArmOpcode::LD_STRIDED_Z,
priority: 102,
num_operands: 3,
imm_constraint: None,
is_two_address: false,
required_feature: Some("sme2"),
cond: None,
});
table.push(IselPattern {
ir_opcode: Opcode::Load,
description: "ld1d z.d, p/z, [x0, x1] — SME2 strided load 64-bit",
result_opcode: ArmOpcode::LD_STRIDED_Z,
priority: 103,
num_operands: 3,
imm_constraint: None,
is_two_address: false,
required_feature: Some("sme2"),
cond: None,
});
table.push(IselPattern {
ir_opcode: Opcode::Store,
description: "st1b z.b, p, [x0, x1] — SME2 strided store 8-bit",
result_opcode: ArmOpcode::ST_STRIDED_Z,
priority: 100,
num_operands: 3,
imm_constraint: None,
is_two_address: false,
required_feature: Some("sme2"),
cond: None,
});
table.push(IselPattern {
ir_opcode: Opcode::Store,
description: "st1h z.h, p, [x0, x1] — SME2 strided store 16-bit",
result_opcode: ArmOpcode::ST_STRIDED_Z,
priority: 101,
num_operands: 3,
imm_constraint: None,
is_two_address: false,
required_feature: Some("sme2"),
cond: None,
});
table.push(IselPattern {
ir_opcode: Opcode::Store,
description: "st1w z.s, p, [x0, x1] — SME2 strided store 32-bit",
result_opcode: ArmOpcode::ST_STRIDED_Z,
priority: 102,
num_operands: 3,
imm_constraint: None,
is_two_address: false,
required_feature: Some("sme2"),
cond: None,
});
table.push(IselPattern {
ir_opcode: Opcode::Store,
description: "st1d z.d, p, [x0, x1] — SME2 strided store 64-bit",
result_opcode: ArmOpcode::ST_STRIDED_Z,
priority: 103,
num_operands: 3,
imm_constraint: None,
is_two_address: false,
required_feature: Some("sme2"),
cond: None,
});
table.push(IselPattern {
ir_opcode: Opcode::Call,
description: "mova za0.d, p/m, za1.d — SME2 move accumulator tile to tile",
result_opcode: ArmOpcode::MOVA_ZA,
priority: 100,
num_operands: 3,
imm_constraint: None,
is_two_address: false,
required_feature: Some("sme2"),
cond: None,
});
table.push(IselPattern {
ir_opcode: Opcode::Call,
description: "mova za0.s, p/m, za1.s — SME2 move accumulator tile to tile 32-bit",
result_opcode: ArmOpcode::MOVA_ZA,
priority: 101,
num_operands: 3,
imm_constraint: None,
is_two_address: false,
required_feature: Some("sme2"),
cond: None,
});
table.push(IselPattern {
ir_opcode: Opcode::Call,
description: "psel p0, p1, p2.b — SME2 pair select predicate 8-bit",
result_opcode: ArmOpcode::PSEL_Z,
priority: 100,
num_operands: 3,
imm_constraint: None,
is_two_address: false,
required_feature: Some("sme2"),
cond: None,
});
table.push(IselPattern {
ir_opcode: Opcode::Call,
description: "psel p0, p1, p2.h — SME2 pair select predicate 16-bit",
result_opcode: ArmOpcode::PSEL_Z,
priority: 101,
num_operands: 3,
imm_constraint: None,
is_two_address: false,
required_feature: Some("sme2"),
cond: None,
});
table.push(IselPattern {
ir_opcode: Opcode::Call,
description: "psel p0, p1, p2.s — SME2 pair select predicate 32-bit",
result_opcode: ArmOpcode::PSEL_Z,
priority: 102,
num_operands: 3,
imm_constraint: None,
is_two_address: false,
required_feature: Some("sme2"),
cond: None,
});
table.push(IselPattern {
ir_opcode: Opcode::Call,
description: "psel p0, p1, p2.d — SME2 pair select predicate 64-bit",
result_opcode: ArmOpcode::PSEL_Z,
priority: 103,
num_operands: 3,
imm_constraint: None,
is_two_address: false,
required_feature: Some("sme2"),
cond: None,
});
table.push(IselPattern {
ir_opcode: Opcode::Call,
description: "sclamp z.b, z.b, z.b — SME2 signed saturating clamp 8-bit",
result_opcode: ArmOpcode::SCLAMP_Z,
priority: 100,
num_operands: 3,
imm_constraint: None,
is_two_address: false,
required_feature: Some("sme2"),
cond: None,
});
table.push(IselPattern {
ir_opcode: Opcode::Call,
description: "sclamp z.h, z.h, z.h — SME2 signed saturating clamp 16-bit",
result_opcode: ArmOpcode::SCLAMP_Z,
priority: 101,
num_operands: 3,
imm_constraint: None,
is_two_address: false,
required_feature: Some("sme2"),
cond: None,
});
table.push(IselPattern {
ir_opcode: Opcode::Call,
description: "sclamp z.s, z.s, z.s — SME2 signed saturating clamp 32-bit",
result_opcode: ArmOpcode::SCLAMP_Z,
priority: 102,
num_operands: 3,
imm_constraint: None,
is_two_address: false,
required_feature: Some("sme2"),
cond: None,
});
table.push(IselPattern {
ir_opcode: Opcode::Call,
description: "sclamp z.d, z.d, z.d — SME2 signed saturating clamp 64-bit",
result_opcode: ArmOpcode::SCLAMP_Z,
priority: 103,
num_operands: 3,
imm_constraint: None,
is_two_address: false,
required_feature: Some("sme2"),
cond: None,
});
table.push(IselPattern {
ir_opcode: Opcode::Call,
description: "uclamp z.b, z.b, z.b — SME2 unsigned saturating clamp 8-bit",
result_opcode: ArmOpcode::UCLAMP_Z,
priority: 104,
num_operands: 3,
imm_constraint: None,
is_two_address: false,
required_feature: Some("sme2"),
cond: None,
});
table.push(IselPattern {
ir_opcode: Opcode::Call,
description: "uclamp z.h, z.h, z.h — SME2 unsigned saturating clamp 16-bit",
result_opcode: ArmOpcode::UCLAMP_Z,
priority: 105,
num_operands: 3,
imm_constraint: None,
is_two_address: false,
required_feature: Some("sme2"),
cond: None,
});
table.push(IselPattern {
ir_opcode: Opcode::Call,
description: "uclamp z.s, z.s, z.s — SME2 unsigned saturating clamp 32-bit",
result_opcode: ArmOpcode::UCLAMP_Z,
priority: 106,
num_operands: 3,
imm_constraint: None,
is_two_address: false,
required_feature: Some("sme2"),
cond: None,
});
table.push(IselPattern {
ir_opcode: Opcode::Call,
description: "uclamp z.d, z.d, z.d — SME2 unsigned saturating clamp 64-bit",
result_opcode: ArmOpcode::UCLAMP_Z,
priority: 107,
num_operands: 3,
imm_constraint: None,
is_two_address: false,
required_feature: Some("sme2"),
cond: None,
});
table.push(IselPattern {
ir_opcode: Opcode::Call,
description: "luti2 z.b, zt0, z.b — SME2 2-bit table lookup 8-bit",
result_opcode: ArmOpcode::LUTI2_8,
priority: 100,
num_operands: 3,
imm_constraint: None,
is_two_address: false,
required_feature: Some("sme2"),
cond: None,
});
table.push(IselPattern {
ir_opcode: Opcode::Call,
description: "luti2 z.h, zt0, z.h — SME2 2-bit table lookup 16-bit",
result_opcode: ArmOpcode::LUTI2_16,
priority: 101,
num_operands: 3,
imm_constraint: None,
is_two_address: false,
required_feature: Some("sme2"),
cond: None,
});
table.push(IselPattern {
ir_opcode: Opcode::Call,
description: "luti4 z.b, zt0, z.b — SME2 4-bit table lookup 8-bit",
result_opcode: ArmOpcode::LUTI4_8,
priority: 102,
num_operands: 3,
imm_constraint: None,
is_two_address: false,
required_feature: Some("sme2"),
cond: None,
});
table.push(IselPattern {
ir_opcode: Opcode::Call,
description: "luti4 z.h, zt0, z.h — SME2 4-bit table lookup 16-bit",
result_opcode: ArmOpcode::LUTI4_16,
priority: 103,
num_operands: 3,
imm_constraint: None,
is_two_address: false,
required_feature: Some("sme2"),
cond: None,
});
table.push(IselPattern {
ir_opcode: Opcode::Call,
description: "f1cvt z.h, z.b — SME2 FP8→FP16 convert 8→16",
result_opcode: ArmOpcode::F1CVT_Z,
priority: 100,
num_operands: 2,
imm_constraint: None,
is_two_address: false,
required_feature: Some("sme2"),
cond: None,
});
table.push(IselPattern {
ir_opcode: Opcode::Call,
description: "f1cvt z.s, z.b — SME2 FP8→FP32 convert 8→32",
result_opcode: ArmOpcode::F1CVT_Z,
priority: 101,
num_operands: 2,
imm_constraint: None,
is_two_address: false,
required_feature: Some("sme2"),
cond: None,
});
table.push(IselPattern {
ir_opcode: Opcode::Call,
description: "f2cvt z.b, z.h — SME2 FP16→FP8 convert 16→8",
result_opcode: ArmOpcode::F2CVT_Z,
priority: 100,
num_operands: 2,
imm_constraint: None,
is_two_address: false,
required_feature: Some("sme2"),
cond: None,
});
table.push(IselPattern {
ir_opcode: Opcode::Call,
description: "f2cvt z.b, z.s — SME2 FP32→FP8 convert 32→8",
result_opcode: ArmOpcode::F2CVT_Z,
priority: 101,
num_operands: 2,
imm_constraint: None,
is_two_address: false,
required_feature: Some("sme2"),
cond: None,
});
table.push(IselPattern {
ir_opcode: Opcode::Call,
description: "bf1cvt z.b, z.h — SME2 BF16→FP8 convert",
result_opcode: ArmOpcode::BF1CVT_Z,
priority: 100,
num_operands: 2,
imm_constraint: None,
is_two_address: false,
required_feature: Some("sme2"),
cond: None,
});
table.push(IselPattern {
ir_opcode: Opcode::FMul,
description: "fdot za.s[m], z.h, z.h — SME2 FP dot product multi-vec 16→32",
result_opcode: ArmOpcode::FDOT_Z,
priority: 100,
num_operands: 4,
imm_constraint: None,
is_two_address: false,
required_feature: Some("sme2"),
cond: None,
});
table.push(IselPattern {
ir_opcode: Opcode::FMul,
description: "fdot za.d[m], z.s, z.s — SME2 FP dot product multi-vec 32→64",
result_opcode: ArmOpcode::FDOT_Z,
priority: 101,
num_operands: 4,
imm_constraint: None,
is_two_address: false,
required_feature: Some("sme2"),
cond: None,
});
table.push(IselPattern {
ir_opcode: Opcode::Mul,
description: "sdot za.s[m], z.b, z.b — SME2 signed int dot product multi-vec 8→32",
result_opcode: ArmOpcode::SDOT_Z,
priority: 100,
num_operands: 4,
imm_constraint: None,
is_two_address: false,
required_feature: Some("sme2"),
cond: None,
});
table.push(IselPattern {
ir_opcode: Opcode::Mul,
description: "sdot za.d[m], z.h, z.h — SME2 signed int dot product multi-vec 16→64",
result_opcode: ArmOpcode::SDOT_Z,
priority: 101,
num_operands: 4,
imm_constraint: None,
is_two_address: false,
required_feature: Some("sme2"),
cond: None,
});
table.push(IselPattern {
ir_opcode: Opcode::Mul,
description: "udot za.s[m], z.b, z.b — SME2 unsigned int dot product multi-vec 8→32",
result_opcode: ArmOpcode::UDOT_Z,
priority: 100,
num_operands: 4,
imm_constraint: None,
is_two_address: false,
required_feature: Some("sme2"),
cond: None,
});
table.push(IselPattern {
ir_opcode: Opcode::Mul,
description: "udot za.d[m], z.h, z.h — SME2 unsigned int dot product multi-vec 16→64",
result_opcode: ArmOpcode::UDOT_Z,
priority: 101,
num_operands: 4,
imm_constraint: None,
is_two_address: false,
required_feature: Some("sme2"),
cond: None,
});
table
}
pub struct SME2IselEngine {
pub patterns: Vec<IselPattern>,
pub has_sve: bool,
pub has_sme: bool,
pub has_sme2: bool,
pub stats: IselStats,
}
impl SME2IselEngine {
pub fn new(has_sve: bool, has_sme: bool, has_sme2: bool) -> Self {
let mut patterns = sme2_isel_table();
patterns.sort_by_key(|p| p.priority);
Self {
patterns,
has_sve,
has_sme,
has_sme2,
stats: IselStats::new(),
}
}
pub fn lookup(
&mut self,
ir_opcode: Opcode,
_operands: &[IselOperand],
_imm_value: Option<i64>,
) -> Option<(ArmOpcode, &IselPattern)> {
let opcode_id = ir_opcode as u32;
if !self.has_sve || !self.has_sme || !self.has_sme2 {
self.stats.record_miss(opcode_id);
return None;
}
for pattern in &self.patterns {
if pattern.ir_opcode == ir_opcode {
if let Some(feat) = pattern.required_feature {
match feat {
"sme2" if !self.has_sme2 => continue,
"sme" if !self.has_sme => continue,
"sve" if !self.has_sve => continue,
_ => {}
}
}
if let Some(constraint) = &pattern.imm_constraint {
if let Some(val) = _imm_value {
if !super::arm_isel_table::evaluate_imm_constraint(constraint, val, true) {
continue;
}
} else {
continue;
}
}
self.stats.record_match(opcode_id);
return Some((pattern.result_opcode, pattern));
}
}
self.stats.record_miss(opcode_id);
None
}
pub fn patterns_for(&self, ir_opcode: Opcode) -> Vec<&IselPattern> {
self.patterns
.iter()
.filter(|p| p.ir_opcode == ir_opcode)
.collect()
}
pub fn pattern_count(&self) -> usize {
self.patterns.len()
}
pub fn patterns_by_feature(&self) -> HashMap<&str, usize> {
let mut counts: HashMap<&str, usize> = HashMap::new();
for p in &self.patterns {
if let Some(feat) = p.required_feature {
*counts.entry(feat).or_insert(0) += 1;
}
}
counts
}
pub fn is_available(&self) -> bool {
self.has_sve && self.has_sme && self.has_sme2
}
pub fn coverage_report(&self, all_opcodes: &[Opcode]) -> String {
let covered: std::collections::HashSet<_> =
self.patterns.iter().map(|p| p.ir_opcode as u32).collect();
let uncovered: Vec<_> = all_opcodes
.iter()
.filter(|op| !covered.contains(&(**op as u32)))
.collect();
format!(
"SME2 ISel Coverage: {}/{} opcodes covered ({} uncovered: {:?})",
covered.len(),
all_opcodes.len(),
uncovered.len(),
uncovered
)
}
pub fn detailed_stats(&self) -> String {
let mut op_counts: HashMap<u32, usize> = HashMap::new();
for p in &self.patterns {
*op_counts.entry(p.ir_opcode as u32).or_insert(0) += 1;
}
let feat_counts = self.patterns_by_feature();
format!(
"SME2 ISel: {} total patterns, {} unique IR opcodes, features: {:?}, available: {}",
self.patterns.len(),
op_counts.len(),
feat_counts,
self.is_available()
)
}
}
impl Default for SME2IselEngine {
fn default() -> Self {
Self::new(false, false, false)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_sme2_table_not_empty() {
let table = sme2_isel_table();
assert!(!table.is_empty());
assert!(table.len() >= 50, "Expected at least 50 SME2 patterns");
}
#[test]
fn test_sme2_lookup_fmopa() {
let mut engine = SME2IselEngine::new(true, true, true);
let result = engine.lookup(Opcode::FAdd, &[], None);
assert!(result.is_some(), "SME2 should match FMOPA via FAdd");
}
#[test]
fn test_sme2_lookup_outer_product_signed() {
let mut engine = SME2IselEngine::new(true, true, true);
let result = engine.lookup(Opcode::Mul, &[], None);
assert!(result.is_some(), "SME2 should match SMOPA via Mul");
}
#[test]
fn test_sme2_lookup_multi_vector_fmla() {
let mut engine = SME2IselEngine::new(true, true, true);
let result = engine.lookup(Opcode::FMul, &[], None);
assert!(result.is_some(), "SME2 should match FMLA multi-vec via FMul");
}
#[test]
fn test_sme2_lookup_multi_vector_load() {
let mut engine = SME2IselEngine::new(true, true, true);
let result = engine.lookup(Opcode::Load, &[], None);
assert!(result.is_some(), "SME2 should match LD1x2/x4 via Load");
}
#[test]
fn test_sme2_lookup_multi_vector_store() {
let mut engine = SME2IselEngine::new(true, true, true);
let result = engine.lookup(Opcode::Store, &[], None);
assert!(result.is_some(), "SME2 should match ST1x2/x4 via Store");
}
#[test]
fn test_sme2_lookup_psel() {
let mut engine = SME2IselEngine::new(true, true, true);
let result = engine.lookup(Opcode::Call, &[], None);
assert!(result.is_some(), "SME2 should match PSEL/MOVA via Call");
}
#[test]
fn test_sme2_lookup_clamp() {
let mut engine = SME2IselEngine::new(true, true, true);
let result = engine.lookup(Opcode::Call, &[], None);
assert!(result.is_some(), "SME2 should match SCLAMP/UCLAMP");
}
#[test]
fn test_sme2_lookup_luti() {
let mut engine = SME2IselEngine::new(true, true, true);
let result = engine.lookup(Opcode::Call, &[], None);
assert!(result.is_some(), "SME2 should match LUTI2/LUTI4");
}
#[test]
fn test_sme2_lookup_fp8_convert() {
let mut engine = SME2IselEngine::new(true, true, true);
let result = engine.lookup(Opcode::Call, &[], None);
assert!(result.is_some(), "SME2 should match F1CVT/F2CVT/BF1CVT");
}
#[test]
fn test_sme2_lookup_dot_product() {
let mut engine = SME2IselEngine::new(true, true, true);
let result_mul = engine.lookup(Opcode::Mul, &[], None);
assert!(result_mul.is_some(), "SME2 should match SDOT/UDOT");
let mut engine2 = SME2IselEngine::new(true, true, true);
let result_fmul = engine2.lookup(Opcode::FMul, &[], None);
assert!(result_fmul.is_some(), "SME2 should match FDOT");
}
#[test]
fn test_sme2_feature_guard_disabled() {
let mut engine = SME2IselEngine::new(false, false, false);
let result = engine.lookup(Opcode::FAdd, &[], None);
assert!(result.is_none(), "No SME2 patterns without features");
}
#[test]
fn test_sme2_feature_guard_no_sme2() {
let mut engine = SME2IselEngine::new(true, true, false);
let result = engine.lookup(Opcode::FAdd, &[], None);
assert!(result.is_none(), "No SME2 patterns if sme2 feature disabled");
}
#[test]
fn test_sme2_pattern_count() {
let engine = SME2IselEngine::new(true, true, true);
assert!(
engine.pattern_count() >= 50,
"Expected at least 50 patterns, got {}",
engine.pattern_count()
);
}
#[test]
fn test_sme2_is_available() {
let engine = SME2IselEngine::new(true, true, true);
assert!(engine.is_available());
let engine2 = SME2IselEngine::new(true, true, false);
assert!(!engine2.is_available());
}
#[test]
fn test_sme2_patterns_by_feature() {
let engine = SME2IselEngine::new(true, true, true);
let counts = engine.patterns_by_feature();
assert!(counts.contains_key("sme2"), "Should have sme2 patterns");
}
#[test]
fn test_sme2_coverage_report() {
let engine = SME2IselEngine::new(true, true, true);
let all_ops = &[
Opcode::FAdd,
Opcode::FMul,
Opcode::Mul,
Opcode::Load,
Opcode::Store,
Opcode::Call,
Opcode::Ret,
];
let report = engine.coverage_report(all_ops);
assert!(report.contains("SME2 ISel Coverage"));
}
#[test]
fn test_sme2_detailed_stats() {
let engine = SME2IselEngine::new(true, true, true);
let stats = engine.detailed_stats();
assert!(stats.contains("SME2 ISel"));
assert!(stats.contains("patterns"));
}
#[test]
fn test_sme2_lookup_zero() {
let mut engine = SME2IselEngine::new(true, true, true);
let result = engine.lookup(Opcode::Ret, &[], None);
assert!(result.is_some(), "SME2 should match ZERO via Ret");
}
#[test]
fn test_sme2_strided_load() {
let mut engine = SME2IselEngine::new(true, true, true);
let result = engine.lookup(Opcode::Load, &[], None);
assert!(result.is_some(), "SME2 should match strided load");
}
#[test]
fn test_sme2_strided_store() {
let mut engine = SME2IselEngine::new(true, true, true);
let result = engine.lookup(Opcode::Store, &[], None);
assert!(result.is_some(), "SME2 should match strided store");
}
}