use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};
use std::fmt;
use super::msp430_instr_info::{Msp430InstrDesc, Msp430InstrInfo, Msp430Opcode, Msp430OperandType};
use super::msp430_register_info::{
Msp430RegClass, Msp430RegisterInfo, MSP430_GPR_BASE, MSP430_GPR_COUNT, MSP430_MAX_REG_ID,
};
use crate::x86::x86_calling_convention::{X86CallFrame, X86CallingConvention};
use crate::x86::x86_frame_lowering::{X86FrameInfo, X86FrameLowering};
use crate::x86::x86_instr_info::{X86InstrDesc, X86InstrInfo, X86Opcode};
use crate::x86::x86_register_info::{X86RegisterInfo, X86_32_REG_COUNT, X86_64_REG_COUNT};
use crate::x86::x86_target_machine::X86TargetMachine;
use crate::x86::X86PeepholeOptimizer;
pub struct MSP430X86Bridge {
pub msp430_instr_info: Msp430InstrInfo,
pub x86_instr_info: X86InstrInfo,
pub msp430_reg_info: Msp430RegisterInfo,
pub x86_reg_info: X86RegisterInfo,
pub shared_isel_patterns: SharedISelPatterns,
pub cross_target_rules: CrossTargetLowering,
pub shared_ra_context: SharedRegisterAllocContext,
pub shared_frame_context: SharedFrameLoweringContext,
pub config: BridgeConfig,
pub stats: BridgeStats,
}
#[derive(Debug, Clone)]
pub struct BridgeConfig {
pub enable_shared_isel: bool,
pub enable_cross_target_opt: bool,
pub enable_shared_ra: bool,
pub enable_shared_frame: bool,
pub max_pattern_depth: usize,
pub opt_transfer_threshold: f64,
pub collect_stats: bool,
pub verbose: bool,
pub target_variant: String,
}
impl Default for BridgeConfig {
fn default() -> Self {
Self {
enable_shared_isel: true,
enable_cross_target_opt: true,
enable_shared_ra: true,
enable_shared_frame: true,
max_pattern_depth: 6,
opt_transfer_threshold: 1.5,
collect_stats: true,
verbose: false,
target_variant: "msp430".into(),
}
}
}
#[derive(Debug, Default, Clone)]
pub struct BridgeStats {
pub shared_isel_matches: u64,
pub cross_target_opts: u64,
pub shared_ra_decisions: u64,
pub shared_frame_ops: u64,
pub pattern_translations: u64,
pub total_time_us: u64,
pub successful_transfers: u64,
pub failed_transfers: u64,
}
impl fmt::Display for BridgeStats {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
writeln!(f, "MSP430 ↔ X86 Bridge Statistics:")?;
writeln!(
f,
" Shared ISel matches: {}",
self.shared_isel_matches
)?;
writeln!(
f,
" Cross-target optimizations: {}",
self.cross_target_opts
)?;
writeln!(
f,
" Shared RA decisions: {}",
self.shared_ra_decisions
)?;
writeln!(f, " Shared frame operations: {}", self.shared_frame_ops)?;
writeln!(
f,
" Pattern translations: {}",
self.pattern_translations
)?;
writeln!(
f,
" Successful transfers: {}",
self.successful_transfers
)?;
writeln!(f, " Failed transfers: {}", self.failed_transfers)?;
write!(f, " Total time (est): {} µs", self.total_time_us)
}
}
impl MSP430X86Bridge {
pub fn new() -> Self {
Self {
msp430_instr_info: Msp430InstrInfo::new(),
x86_instr_info: X86InstrInfo::new(),
msp430_reg_info: Msp430RegisterInfo,
x86_reg_info: X86RegisterInfo,
shared_isel_patterns: SharedISelPatterns::new(),
cross_target_rules: CrossTargetLowering::new(),
shared_ra_context: SharedRegisterAllocContext::new(),
shared_frame_context: SharedFrameLoweringContext::new(),
config: BridgeConfig::default(),
stats: BridgeStats::default(),
}
}
pub fn with_config(config: BridgeConfig) -> Self {
let mut bridge = Self::new();
bridge.config = config;
bridge
}
pub fn initialize(&mut self) {
if self.config.verbose {
self.log("Initializing MSP430 ↔ X86 bridge...");
}
self.shared_isel_patterns.load_patterns();
self.cross_target_rules.load_rules();
self.shared_ra_context.initialize();
self.shared_frame_context.initialize();
if self.config.verbose {
self.log("Bridge initialization complete.");
}
}
pub fn translate_x86_to_msp430(&mut self, x86_opcode: &X86Opcode) -> Option<BridgeInstruction> {
self.stats.pattern_translations += 1;
match x86_opcode {
X86Opcode::ADD => Some(BridgeInstruction::DirectMap(Msp430Opcode::ADD)),
X86Opcode::ADC => Some(BridgeInstruction::DirectMap(Msp430Opcode::ADDC)),
X86Opcode::SUB => Some(BridgeInstruction::DirectMap(Msp430Opcode::SUB)),
X86Opcode::SBB => Some(BridgeInstruction::DirectMap(Msp430Opcode::SUBC)),
X86Opcode::AND => Some(BridgeInstruction::DirectMap(Msp430Opcode::AND)),
X86Opcode::OR => Some(BridgeInstruction::DirectMap(Msp430Opcode::BIS)),
X86Opcode::XOR => Some(BridgeInstruction::DirectMap(Msp430Opcode::XOR)),
X86Opcode::NOT => Some(BridgeInstruction::DirectMap(Msp430Opcode::INV)),
X86Opcode::NEG => Some(BridgeInstruction::Expanded(vec![
Msp430Opcode::INV,
Msp430Opcode::INC,
])),
X86Opcode::INC => Some(BridgeInstruction::DirectMap(Msp430Opcode::ADD)), X86Opcode::DEC => Some(BridgeInstruction::DirectMap(Msp430Opcode::SUB)), X86Opcode::CMP => Some(BridgeInstruction::DirectMap(Msp430Opcode::CMP)),
X86Opcode::TEST => Some(BridgeInstruction::DirectMap(Msp430Opcode::BIT)),
X86Opcode::MOV => Some(BridgeInstruction::DirectMap(Msp430Opcode::MOV)),
X86Opcode::PUSH => Some(BridgeInstruction::DirectMap(Msp430Opcode::PUSH)),
X86Opcode::POP => Some(BridgeInstruction::DirectMap(Msp430Opcode::POP)),
X86Opcode::XCHG => Some(BridgeInstruction::Expanded(vec![
Msp430Opcode::MOV,
Msp430Opcode::MOV,
Msp430Opcode::MOV,
])),
X86Opcode::SHL => Some(BridgeInstruction::DirectMap(Msp430Opcode::RLA)),
X86Opcode::SHR => Some(BridgeInstruction::DirectMap(Msp430Opcode::RRC)), X86Opcode::SAR => Some(BridgeInstruction::DirectMap(Msp430Opcode::RRA)),
X86Opcode::ROL => Some(BridgeInstruction::DirectMap(Msp430Opcode::RLC)),
X86Opcode::ROR => Some(BridgeInstruction::DirectMap(Msp430Opcode::RRC)),
X86Opcode::JMP => Some(BridgeInstruction::DirectMap(Msp430Opcode::JMP)),
X86Opcode::JE => Some(BridgeInstruction::DirectMap(Msp430Opcode::JEQ)),
X86Opcode::JNE => Some(BridgeInstruction::DirectMap(Msp430Opcode::JNE)),
X86Opcode::JB => Some(BridgeInstruction::DirectMap(Msp430Opcode::JC)),
X86Opcode::JAE => Some(BridgeInstruction::DirectMap(Msp430Opcode::JNC)),
X86Opcode::JL => Some(BridgeInstruction::DirectMap(Msp430Opcode::JL)),
X86Opcode::JGE => Some(BridgeInstruction::DirectMap(Msp430Opcode::JGE)),
X86Opcode::JS => Some(BridgeInstruction::DirectMap(Msp430Opcode::JN)),
X86Opcode::CALL => Some(BridgeInstruction::DirectMap(Msp430Opcode::CALL)),
X86Opcode::RET => Some(BridgeInstruction::DirectMap(Msp430Opcode::RET)),
X86Opcode::NOP => Some(BridgeInstruction::DirectMap(Msp430Opcode::NOP)),
_ => {
self.stats.failed_transfers += 1;
None
}
}
}
pub fn translate_msp430_to_x86(
&mut self,
msp430_opcode: &Msp430Opcode,
) -> Option<BridgeInstruction> {
self.stats.pattern_translations += 1;
match msp430_opcode {
Msp430Opcode::MOV => Some(BridgeInstruction::DirectMapX86(X86Opcode::MOV)),
Msp430Opcode::ADD => Some(BridgeInstruction::DirectMapX86(X86Opcode::ADD)),
Msp430Opcode::ADDC => Some(BridgeInstruction::DirectMapX86(X86Opcode::ADC)),
Msp430Opcode::SUBC => Some(BridgeInstruction::DirectMapX86(X86Opcode::SBB)),
Msp430Opcode::SUB => Some(BridgeInstruction::DirectMapX86(X86Opcode::SUB)),
Msp430Opcode::CMP => Some(BridgeInstruction::DirectMapX86(X86Opcode::CMP)),
Msp430Opcode::DADD => Some(BridgeInstruction::ExpandedX86(vec![
X86Opcode::ADD,
X86Opcode::ADC,
])),
Msp430Opcode::BIT => Some(BridgeInstruction::DirectMapX86(X86Opcode::TEST)),
Msp430Opcode::BIC => Some(BridgeInstruction::ExpandedX86(vec![
X86Opcode::NOT,
X86Opcode::AND,
])),
Msp430Opcode::BIS => Some(BridgeInstruction::DirectMapX86(X86Opcode::OR)),
Msp430Opcode::XOR => Some(BridgeInstruction::DirectMapX86(X86Opcode::XOR)),
Msp430Opcode::AND => Some(BridgeInstruction::DirectMapX86(X86Opcode::AND)),
Msp430Opcode::RRC => Some(BridgeInstruction::DirectMapX86(X86Opcode::ROR)),
Msp430Opcode::SWPB => Some(BridgeInstruction::DirectMapX86(X86Opcode::BSWAP)),
Msp430Opcode::RRA => Some(BridgeInstruction::DirectMapX86(X86Opcode::SAR)),
Msp430Opcode::SXT => Some(BridgeInstruction::DirectMapX86(X86Opcode::MOVSX)),
Msp430Opcode::PUSH => Some(BridgeInstruction::DirectMapX86(X86Opcode::PUSH)),
Msp430Opcode::POP => Some(BridgeInstruction::DirectMapX86(X86Opcode::POP)),
Msp430Opcode::CALL => Some(BridgeInstruction::DirectMapX86(X86Opcode::CALL)),
Msp430Opcode::RETI => Some(BridgeInstruction::DirectMapX86(X86Opcode::RET)),
Msp430Opcode::JNE => Some(BridgeInstruction::DirectMapX86(X86Opcode::JNE)),
Msp430Opcode::JEQ => Some(BridgeInstruction::DirectMapX86(X86Opcode::JE)),
Msp430Opcode::JNC => Some(BridgeInstruction::DirectMapX86(X86Opcode::JAE)),
Msp430Opcode::JC => Some(BridgeInstruction::DirectMapX86(X86Opcode::JB)),
Msp430Opcode::JN => Some(BridgeInstruction::DirectMapX86(X86Opcode::JS)),
Msp430Opcode::JGE => Some(BridgeInstruction::DirectMapX86(X86Opcode::JGE)),
Msp430Opcode::JL => Some(BridgeInstruction::DirectMapX86(X86Opcode::JL)),
Msp430Opcode::JMP => Some(BridgeInstruction::DirectMapX86(X86Opcode::JMP)),
Msp430Opcode::CLR => Some(BridgeInstruction::DirectMapX86(X86Opcode::XOR)),
Msp430Opcode::CLRC => Some(BridgeInstruction::ExpandedX86(vec![
X86Opcode::AND,
X86Opcode::NOT,
])),
Msp430Opcode::SETC => Some(BridgeInstruction::DirectMapX86(X86Opcode::OR)),
Msp430Opcode::CLRZ => Some(BridgeInstruction::ExpandedX86(vec![
X86Opcode::AND,
X86Opcode::NOT,
])),
Msp430Opcode::SETZ => Some(BridgeInstruction::DirectMapX86(X86Opcode::OR)),
Msp430Opcode::NOP => Some(BridgeInstruction::DirectMapX86(X86Opcode::NOP)),
Msp430Opcode::BR => Some(BridgeInstruction::DirectMapX86(X86Opcode::JMP)),
Msp430Opcode::RET => Some(BridgeInstruction::DirectMapX86(X86Opcode::RET)),
Msp430Opcode::TST => Some(BridgeInstruction::DirectMapX86(X86Opcode::TEST)),
Msp430Opcode::INV => Some(BridgeInstruction::DirectMapX86(X86Opcode::NOT)),
Msp430Opcode::RLA => Some(BridgeInstruction::DirectMapX86(X86Opcode::SHL)),
Msp430Opcode::RLC => Some(BridgeInstruction::DirectMapX86(X86Opcode::ROL)),
Msp430Opcode::ADC => Some(BridgeInstruction::DirectMapX86(X86Opcode::ADC)),
Msp430Opcode::DADC => Some(BridgeInstruction::ExpandedX86(vec![
X86Opcode::ADC,
X86Opcode::ADC,
])),
_ => {
self.stats.failed_transfers += 1;
None
}
}
}
pub fn match_shared_isel(&mut self, op_name: &str, is_msp430: bool) -> Option<SharedISelMatch> {
if self.config.collect_stats {
self.stats.shared_isel_matches += 1;
}
self.shared_isel_patterns.find(op_name, is_msp430)
}
pub fn apply_cross_target_opt(&mut self, ir_sequence: &[&str]) -> Vec<CrossTargetOptResult> {
self.stats.cross_target_opts += 1;
self.cross_target_rules.apply(ir_sequence)
}
pub fn get_shared_ra_context(&self) -> &SharedRegisterAllocContext {
&self.shared_ra_context
}
pub fn get_shared_ra_context_mut(&mut self) -> &mut SharedRegisterAllocContext {
&mut self.shared_ra_context
}
pub fn get_shared_frame_context(&self) -> &SharedFrameLoweringContext {
&self.shared_frame_context
}
pub fn get_shared_frame_context_mut(&mut self) -> &mut SharedFrameLoweringContext {
&mut self.shared_frame_context
}
pub fn reset_stats(&mut self) {
self.stats = BridgeStats::default();
}
fn log(&self, msg: &str) {
if self.config.verbose {
eprintln!("[MSP430-X86-Bridge] {}", msg);
}
}
}
impl Default for MSP430X86Bridge {
fn default() -> Self {
Self::new()
}
}
impl fmt::Debug for MSP430X86Bridge {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("MSP430X86Bridge")
.field("config", &self.config)
.field("stats", &self.stats)
.finish()
}
}
#[derive(Debug, Clone)]
pub enum BridgeInstruction {
DirectMap(Msp430Opcode),
DirectMapX86(X86Opcode),
Expanded(Vec<Msp430Opcode>),
ExpandedX86(Vec<X86Opcode>),
CompareMapX86 { cmp: X86Opcode, set: X86Opcode },
MemoryExpand(Vec<Msp430Opcode>),
}
pub struct CrossTargetMSP430 {
pub isel_patterns: SharedISelPatterns,
pub lowering_rules: CrossTargetLowering,
pub regalloc_framework: CrossTargetRegisterAlloc,
pub frame_abstractions: CrossTargetFrameLowering,
pub const_materializer: CrossTargetConstMaterializer,
pub branch_analyzer: CrossTargetBranchAnalyzer,
pub features: MSP430FeatureSet,
}
impl CrossTargetMSP430 {
pub fn new() -> Self {
Self {
isel_patterns: SharedISelPatterns::new(),
lowering_rules: CrossTargetLowering::new(),
regalloc_framework: CrossTargetRegisterAlloc::new(),
frame_abstractions: CrossTargetFrameLowering::new(),
const_materializer: CrossTargetConstMaterializer::new(),
branch_analyzer: CrossTargetBranchAnalyzer::new(),
features: MSP430FeatureSet::default(),
}
}
pub fn with_features(features: MSP430FeatureSet) -> Self {
let mut ctx = Self::new();
ctx.features = features;
ctx
}
}
impl Default for CrossTargetMSP430 {
fn default() -> Self {
Self::new()
}
}
pub struct SharedISelPatterns {
patterns: HashMap<String, SharedPattern>,
msp430_variants: HashMap<String, Vec<Msp430Opcode>>,
x86_variants: HashMap<String, Vec<X86Opcode>>,
categories: HashMap<PatternCategory, Vec<String>>,
}
#[derive(Debug, Clone)]
pub struct SharedPattern {
pub name: String,
pub category: PatternCategory,
pub msp430_seq: Vec<Msp430Opcode>,
pub x86_seq: Vec<X86Opcode>,
pub msp430_cost: u32,
pub x86_cost: u32,
pub is_commutative: bool,
pub min_operands: usize,
pub max_operands: usize,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum PatternCategory {
IntegerArithmetic,
IntegerComparison,
Logical,
Shift,
MemoryAccess,
ControlFlow,
BitManipulation,
ByteManipulation,
ConstantMaterialization,
}
impl fmt::Display for PatternCategory {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::IntegerArithmetic => write!(f, "IntegerArithmetic"),
Self::IntegerComparison => write!(f, "IntegerComparison"),
Self::Logical => write!(f, "Logical"),
Self::Shift => write!(f, "Shift"),
Self::MemoryAccess => write!(f, "MemoryAccess"),
Self::ControlFlow => write!(f, "ControlFlow"),
Self::BitManipulation => write!(f, "BitManipulation"),
Self::ByteManipulation => write!(f, "ByteManipulation"),
Self::ConstantMaterialization => write!(f, "ConstantMaterialization"),
}
}
}
impl SharedISelPatterns {
pub fn new() -> Self {
Self {
patterns: HashMap::new(),
msp430_variants: HashMap::new(),
x86_variants: HashMap::new(),
categories: HashMap::new(),
}
}
pub fn load_patterns(&mut self) {
self.load_integer_arithmetic_patterns();
self.load_integer_comparison_patterns();
self.load_logical_patterns();
self.load_shift_patterns();
self.load_memory_access_patterns();
self.load_control_flow_patterns();
self.load_bit_manipulation_patterns();
self.load_byte_manipulation_patterns();
self.load_constant_patterns();
}
fn add_pattern(&mut self, pattern: SharedPattern) {
let name = pattern.name.clone();
let cat = pattern.category;
self.patterns.insert(name, pattern.clone());
self.categories
.entry(cat)
.or_insert_with(Vec::new)
.push(pattern.name);
}
fn load_integer_arithmetic_patterns(&mut self) {
self.add_pattern(SharedPattern {
name: "add_16bit".into(),
category: PatternCategory::IntegerArithmetic,
msp430_seq: vec![Msp430Opcode::ADD],
x86_seq: vec![X86Opcode::ADD],
msp430_cost: 1,
x86_cost: 1,
is_commutative: true,
min_operands: 2,
max_operands: 2,
});
self.add_pattern(SharedPattern {
name: "sub_16bit".into(),
category: PatternCategory::IntegerArithmetic,
msp430_seq: vec![Msp430Opcode::SUB],
x86_seq: vec![X86Opcode::SUB],
msp430_cost: 1,
x86_cost: 1,
is_commutative: false,
min_operands: 2,
max_operands: 2,
});
self.add_pattern(SharedPattern {
name: "add_with_carry".into(),
category: PatternCategory::IntegerArithmetic,
msp430_seq: vec![Msp430Opcode::ADDC],
x86_seq: vec![X86Opcode::ADC],
msp430_cost: 1,
x86_cost: 1,
is_commutative: true,
min_operands: 2,
max_operands: 2,
});
self.add_pattern(SharedPattern {
name: "sub_with_borrow".into(),
category: PatternCategory::IntegerArithmetic,
msp430_seq: vec![Msp430Opcode::SUBC],
x86_seq: vec![X86Opcode::SBB],
msp430_cost: 1,
x86_cost: 1,
is_commutative: false,
min_operands: 2,
max_operands: 2,
});
self.add_pattern(SharedPattern {
name: "decimal_add".into(),
category: PatternCategory::IntegerArithmetic,
msp430_seq: vec![Msp430Opcode::DADD],
x86_seq: vec![X86Opcode::ADD],
msp430_cost: 1,
x86_cost: 2,
is_commutative: true,
min_operands: 2,
max_operands: 2,
});
self.add_pattern(SharedPattern {
name: "negate_16bit".into(),
category: PatternCategory::IntegerArithmetic,
msp430_seq: vec![Msp430Opcode::INV, Msp430Opcode::ADD],
x86_seq: vec![X86Opcode::NEG],
msp430_cost: 2,
x86_cost: 1,
is_commutative: false,
min_operands: 1,
max_operands: 1,
});
self.add_pattern(SharedPattern {
name: "increment".into(),
category: PatternCategory::IntegerArithmetic,
msp430_seq: vec![Msp430Opcode::ADD],
x86_seq: vec![X86Opcode::INC],
msp430_cost: 1,
x86_cost: 1,
is_commutative: false,
min_operands: 1,
max_operands: 1,
});
self.add_pattern(SharedPattern {
name: "decrement".into(),
category: PatternCategory::IntegerArithmetic,
msp430_seq: vec![Msp430Opcode::SUB],
x86_seq: vec![X86Opcode::DEC],
msp430_cost: 1,
x86_cost: 1,
is_commutative: false,
min_operands: 1,
max_operands: 1,
});
self.add_pattern(SharedPattern {
name: "sign_extend_byte".into(),
category: PatternCategory::IntegerArithmetic,
msp430_seq: vec![Msp430Opcode::SXT],
x86_seq: vec![X86Opcode::MOVSX],
msp430_cost: 1,
x86_cost: 1,
is_commutative: false,
min_operands: 1,
max_operands: 1,
});
self.add_pattern(SharedPattern {
name: "multiply_16bit".into(),
category: PatternCategory::IntegerArithmetic,
msp430_seq: vec![
Msp430Opcode::MOV,
Msp430Opcode::MOV,
Msp430Opcode::AND,
Msp430Opcode::ADD,
Msp430Opcode::RLA,
Msp430Opcode::JC,
Msp430Opcode::ADD,
],
x86_seq: vec![X86Opcode::IMUL],
msp430_cost: 60,
x86_cost: 3,
is_commutative: true,
min_operands: 2,
max_operands: 2,
});
self.add_pattern(SharedPattern {
name: "clear_register".into(),
category: PatternCategory::IntegerArithmetic,
msp430_seq: vec![Msp430Opcode::CLR],
x86_seq: vec![X86Opcode::XOR],
msp430_cost: 1,
x86_cost: 1,
is_commutative: false,
min_operands: 1,
max_operands: 1,
});
}
fn load_integer_comparison_patterns(&mut self) {
self.add_pattern(SharedPattern {
name: "compare_16bit".into(),
category: PatternCategory::IntegerComparison,
msp430_seq: vec![Msp430Opcode::CMP],
x86_seq: vec![X86Opcode::CMP],
msp430_cost: 1,
x86_cost: 1,
is_commutative: false,
min_operands: 2,
max_operands: 2,
});
self.add_pattern(SharedPattern {
name: "bit_test".into(),
category: PatternCategory::IntegerComparison,
msp430_seq: vec![Msp430Opcode::BIT],
x86_seq: vec![X86Opcode::TEST],
msp430_cost: 1,
x86_cost: 1,
is_commutative: true,
min_operands: 2,
max_operands: 2,
});
self.add_pattern(SharedPattern {
name: "test_zero".into(),
category: PatternCategory::IntegerComparison,
msp430_seq: vec![Msp430Opcode::TST],
x86_seq: vec![X86Opcode::TEST],
msp430_cost: 1,
x86_cost: 1,
is_commutative: false,
min_operands: 1,
max_operands: 1,
});
self.add_pattern(SharedPattern {
name: "set_if_less_than".into(),
category: PatternCategory::IntegerComparison,
msp430_seq: vec![Msp430Opcode::CMP, Msp430Opcode::JL],
x86_seq: vec![X86Opcode::CMP, X86Opcode::SETL],
msp430_cost: 2,
x86_cost: 2,
is_commutative: false,
min_operands: 2,
max_operands: 2,
});
self.add_pattern(SharedPattern {
name: "set_if_equal".into(),
category: PatternCategory::IntegerComparison,
msp430_seq: vec![Msp430Opcode::CMP, Msp430Opcode::JEQ],
x86_seq: vec![X86Opcode::CMP, X86Opcode::SETE],
msp430_cost: 2,
x86_cost: 2,
is_commutative: true,
min_operands: 2,
max_operands: 2,
});
}
fn load_logical_patterns(&mut self) {
self.add_pattern(SharedPattern {
name: "logical_and".into(),
category: PatternCategory::Logical,
msp430_seq: vec![Msp430Opcode::AND],
x86_seq: vec![X86Opcode::AND],
msp430_cost: 1,
x86_cost: 1,
is_commutative: true,
min_operands: 2,
max_operands: 2,
});
self.add_pattern(SharedPattern {
name: "logical_or".into(),
category: PatternCategory::Logical,
msp430_seq: vec![Msp430Opcode::BIS],
x86_seq: vec![X86Opcode::OR],
msp430_cost: 1,
x86_cost: 1,
is_commutative: true,
min_operands: 2,
max_operands: 2,
});
self.add_pattern(SharedPattern {
name: "logical_xor".into(),
category: PatternCategory::Logical,
msp430_seq: vec![Msp430Opcode::XOR],
x86_seq: vec![X86Opcode::XOR],
msp430_cost: 1,
x86_cost: 1,
is_commutative: true,
min_operands: 2,
max_operands: 2,
});
self.add_pattern(SharedPattern {
name: "logical_not".into(),
category: PatternCategory::Logical,
msp430_seq: vec![Msp430Opcode::INV],
x86_seq: vec![X86Opcode::NOT],
msp430_cost: 1,
x86_cost: 1,
is_commutative: false,
min_operands: 1,
max_operands: 1,
});
self.add_pattern(SharedPattern {
name: "bit_clear".into(),
category: PatternCategory::Logical,
msp430_seq: vec![Msp430Opcode::BIC],
x86_seq: vec![X86Opcode::NOT, X86Opcode::AND],
msp430_cost: 1,
x86_cost: 2,
is_commutative: false,
min_operands: 2,
max_operands: 2,
});
self.add_pattern(SharedPattern {
name: "bit_set".into(),
category: PatternCategory::Logical,
msp430_seq: vec![Msp430Opcode::BIS],
x86_seq: vec![X86Opcode::OR],
msp430_cost: 1,
x86_cost: 1,
is_commutative: true,
min_operands: 2,
max_operands: 2,
});
}
fn load_shift_patterns(&mut self) {
self.add_pattern(SharedPattern {
name: "rotate_right_carry".into(),
category: PatternCategory::Shift,
msp430_seq: vec![Msp430Opcode::RRC],
x86_seq: vec![X86Opcode::RCR],
msp430_cost: 1,
x86_cost: 1,
is_commutative: false,
min_operands: 1,
max_operands: 1,
});
self.add_pattern(SharedPattern {
name: "rotate_left_carry".into(),
category: PatternCategory::Shift,
msp430_seq: vec![Msp430Opcode::RLC],
x86_seq: vec![X86Opcode::RCL],
msp430_cost: 1,
x86_cost: 1,
is_commutative: false,
min_operands: 1,
max_operands: 1,
});
self.add_pattern(SharedPattern {
name: "arithmetic_shift_right".into(),
category: PatternCategory::Shift,
msp430_seq: vec![Msp430Opcode::RRA],
x86_seq: vec![X86Opcode::SAR],
msp430_cost: 1,
x86_cost: 1,
is_commutative: false,
min_operands: 1,
max_operands: 1,
});
self.add_pattern(SharedPattern {
name: "shift_left".into(),
category: PatternCategory::Shift,
msp430_seq: vec![Msp430Opcode::RLA],
x86_seq: vec![X86Opcode::SHL],
msp430_cost: 1,
x86_cost: 1,
is_commutative: false,
min_operands: 1,
max_operands: 1,
});
self.add_pattern(SharedPattern {
name: "multi_shift_left".into(),
category: PatternCategory::Shift,
msp430_seq: vec![Msp430Opcode::RLA, Msp430Opcode::RLA, Msp430Opcode::RLA],
x86_seq: vec![X86Opcode::SHL],
msp430_cost: 3,
x86_cost: 1,
is_commutative: false,
min_operands: 1,
max_operands: 1,
});
}
fn load_memory_access_patterns(&mut self) {
self.add_pattern(SharedPattern {
name: "load_word".into(),
category: PatternCategory::MemoryAccess,
msp430_seq: vec![Msp430Opcode::MOV],
x86_seq: vec![X86Opcode::MOV],
msp430_cost: 1,
x86_cost: 1,
is_commutative: false,
min_operands: 2,
max_operands: 2,
});
self.add_pattern(SharedPattern {
name: "store_word".into(),
category: PatternCategory::MemoryAccess,
msp430_seq: vec![Msp430Opcode::MOV],
x86_seq: vec![X86Opcode::MOV],
msp430_cost: 1,
x86_cost: 1,
is_commutative: false,
min_operands: 2,
max_operands: 2,
});
self.add_pattern(SharedPattern {
name: "push".into(),
category: PatternCategory::MemoryAccess,
msp430_seq: vec![Msp430Opcode::PUSH],
x86_seq: vec![X86Opcode::PUSH],
msp430_cost: 1,
x86_cost: 1,
is_commutative: false,
min_operands: 1,
max_operands: 1,
});
self.add_pattern(SharedPattern {
name: "pop".into(),
category: PatternCategory::MemoryAccess,
msp430_seq: vec![Msp430Opcode::POP],
x86_seq: vec![X86Opcode::POP],
msp430_cost: 1,
x86_cost: 1,
is_commutative: false,
min_operands: 1,
max_operands: 1,
});
self.add_pattern(SharedPattern {
name: "indirect_load".into(),
category: PatternCategory::MemoryAccess,
msp430_seq: vec![Msp430Opcode::MOV],
x86_seq: vec![X86Opcode::MOV],
msp430_cost: 1,
x86_cost: 1,
is_commutative: false,
min_operands: 2,
max_operands: 2,
});
self.add_pattern(SharedPattern {
name: "indexed_load".into(),
category: PatternCategory::MemoryAccess,
msp430_seq: vec![Msp430Opcode::MOV],
x86_seq: vec![X86Opcode::MOV],
msp430_cost: 3,
x86_cost: 2,
is_commutative: false,
min_operands: 2,
max_operands: 2,
});
self.add_pattern(SharedPattern {
name: "byte_swap".into(),
category: PatternCategory::MemoryAccess,
msp430_seq: vec![Msp430Opcode::SWPB],
x86_seq: vec![X86Opcode::MOV, X86Opcode::BSWAP, X86Opcode::SHR],
msp430_cost: 1,
x86_cost: 3,
is_commutative: false,
min_operands: 1,
max_operands: 1,
});
}
fn load_control_flow_patterns(&mut self) {
self.add_pattern(SharedPattern {
name: "unconditional_jump".into(),
category: PatternCategory::ControlFlow,
msp430_seq: vec![Msp430Opcode::JMP],
x86_seq: vec![X86Opcode::JMP],
msp430_cost: 2,
x86_cost: 1,
is_commutative: false,
min_operands: 1,
max_operands: 1,
});
self.add_pattern(SharedPattern {
name: "branch_if_equal".into(),
category: PatternCategory::ControlFlow,
msp430_seq: vec![Msp430Opcode::JEQ],
x86_seq: vec![X86Opcode::JE],
msp430_cost: 2,
x86_cost: 1,
is_commutative: false,
min_operands: 1,
max_operands: 1,
});
self.add_pattern(SharedPattern {
name: "branch_if_not_equal".into(),
category: PatternCategory::ControlFlow,
msp430_seq: vec![Msp430Opcode::JNE],
x86_seq: vec![X86Opcode::JNE],
msp430_cost: 2,
x86_cost: 1,
is_commutative: false,
min_operands: 1,
max_operands: 1,
});
self.add_pattern(SharedPattern {
name: "branch_if_carry".into(),
category: PatternCategory::ControlFlow,
msp430_seq: vec![Msp430Opcode::JC],
x86_seq: vec![X86Opcode::JB],
msp430_cost: 2,
x86_cost: 1,
is_commutative: false,
min_operands: 1,
max_operands: 1,
});
self.add_pattern(SharedPattern {
name: "branch_if_no_carry".into(),
category: PatternCategory::ControlFlow,
msp430_seq: vec![Msp430Opcode::JNC],
x86_seq: vec![X86Opcode::JAE],
msp430_cost: 2,
x86_cost: 1,
is_commutative: false,
min_operands: 1,
max_operands: 1,
});
self.add_pattern(SharedPattern {
name: "branch_if_negative".into(),
category: PatternCategory::ControlFlow,
msp430_seq: vec![Msp430Opcode::JN],
x86_seq: vec![X86Opcode::JS],
msp430_cost: 2,
x86_cost: 1,
is_commutative: false,
min_operands: 1,
max_operands: 1,
});
self.add_pattern(SharedPattern {
name: "branch_if_ge".into(),
category: PatternCategory::ControlFlow,
msp430_seq: vec![Msp430Opcode::JGE],
x86_seq: vec![X86Opcode::JGE],
msp430_cost: 2,
x86_cost: 1,
is_commutative: false,
min_operands: 1,
max_operands: 1,
});
self.add_pattern(SharedPattern {
name: "branch_if_less".into(),
category: PatternCategory::ControlFlow,
msp430_seq: vec![Msp430Opcode::JL],
x86_seq: vec![X86Opcode::JL],
msp430_cost: 2,
x86_cost: 1,
is_commutative: false,
min_operands: 1,
max_operands: 1,
});
self.add_pattern(SharedPattern {
name: "function_call".into(),
category: PatternCategory::ControlFlow,
msp430_seq: vec![Msp430Opcode::CALL],
x86_seq: vec![X86Opcode::CALL],
msp430_cost: 4,
x86_cost: 2,
is_commutative: false,
min_operands: 1,
max_operands: 1,
});
self.add_pattern(SharedPattern {
name: "function_return".into(),
category: PatternCategory::ControlFlow,
msp430_seq: vec![Msp430Opcode::RET],
x86_seq: vec![X86Opcode::RET],
msp430_cost: 3,
x86_cost: 1,
is_commutative: false,
min_operands: 0,
max_operands: 0,
});
self.add_pattern(SharedPattern {
name: "return_from_interrupt".into(),
category: PatternCategory::ControlFlow,
msp430_seq: vec![Msp430Opcode::RETI],
x86_seq: vec![X86Opcode::RET],
msp430_cost: 5,
x86_cost: 1,
is_commutative: false,
min_operands: 0,
max_operands: 0,
});
self.add_pattern(SharedPattern {
name: "nop".into(),
category: PatternCategory::ControlFlow,
msp430_seq: vec![Msp430Opcode::NOP],
x86_seq: vec![X86Opcode::NOP],
msp430_cost: 1,
x86_cost: 1,
is_commutative: false,
min_operands: 0,
max_operands: 0,
});
}
fn load_bit_manipulation_patterns(&mut self) {
self.add_pattern(SharedPattern {
name: "set_carry".into(),
category: PatternCategory::BitManipulation,
msp430_seq: vec![Msp430Opcode::SETC],
x86_seq: vec![X86Opcode::STC],
msp430_cost: 1,
x86_cost: 1,
is_commutative: false,
min_operands: 0,
max_operands: 0,
});
self.add_pattern(SharedPattern {
name: "clear_carry".into(),
category: PatternCategory::BitManipulation,
msp430_seq: vec![Msp430Opcode::CLRC],
x86_seq: vec![X86Opcode::CLC],
msp430_cost: 1,
x86_cost: 1,
is_commutative: false,
min_operands: 0,
max_operands: 0,
});
self.add_pattern(SharedPattern {
name: "set_zero".into(),
category: PatternCategory::BitManipulation,
msp430_seq: vec![Msp430Opcode::SETZ],
x86_seq: vec![X86Opcode::XOR, X86Opcode::CMP],
msp430_cost: 1,
x86_cost: 2,
is_commutative: false,
min_operands: 0,
max_operands: 0,
});
self.add_pattern(SharedPattern {
name: "enable_interrupts".into(),
category: PatternCategory::BitManipulation,
msp430_seq: vec![Msp430Opcode::EINT],
x86_seq: vec![X86Opcode::STI],
msp430_cost: 1,
x86_cost: 1,
is_commutative: false,
min_operands: 0,
max_operands: 0,
});
self.add_pattern(SharedPattern {
name: "disable_interrupts".into(),
category: PatternCategory::BitManipulation,
msp430_seq: vec![Msp430Opcode::DINT],
x86_seq: vec![X86Opcode::CLI],
msp430_cost: 1,
x86_cost: 1,
is_commutative: false,
min_operands: 0,
max_operands: 0,
});
self.add_pattern(SharedPattern {
name: "set_negative".into(),
category: PatternCategory::BitManipulation,
msp430_seq: vec![Msp430Opcode::SETN],
x86_seq: vec![X86Opcode::OR],
msp430_cost: 1,
x86_cost: 1,
is_commutative: false,
min_operands: 0,
max_operands: 0,
});
self.add_pattern(SharedPattern {
name: "clear_negative".into(),
category: PatternCategory::BitManipulation,
msp430_seq: vec![Msp430Opcode::CLRN],
x86_seq: vec![X86Opcode::AND, X86Opcode::NOT],
msp430_cost: 1,
x86_cost: 2,
is_commutative: false,
min_operands: 0,
max_operands: 0,
});
}
fn load_byte_manipulation_patterns(&mut self) {
self.add_pattern(SharedPattern {
name: "swap_bytes_word".into(),
category: PatternCategory::ByteManipulation,
msp430_seq: vec![Msp430Opcode::SWPB],
x86_seq: vec![X86Opcode::ROR],
msp430_cost: 1,
x86_cost: 1,
is_commutative: false,
min_operands: 1,
max_operands: 1,
});
}
fn load_constant_patterns(&mut self) {
self.add_pattern(SharedPattern {
name: "load_constant_zero".into(),
category: PatternCategory::ConstantMaterialization,
msp430_seq: vec![Msp430Opcode::CLR],
x86_seq: vec![X86Opcode::XOR],
msp430_cost: 1,
x86_cost: 1,
is_commutative: false,
min_operands: 1,
max_operands: 1,
});
self.add_pattern(SharedPattern {
name: "load_16bit_immediate".into(),
category: PatternCategory::ConstantMaterialization,
msp430_seq: vec![Msp430Opcode::MOV],
x86_seq: vec![X86Opcode::MOV],
msp430_cost: 2,
x86_cost: 1,
is_commutative: false,
min_operands: 1,
max_operands: 1,
});
self.add_pattern(SharedPattern {
name: "load_20bit_immediate".into(),
category: PatternCategory::ConstantMaterialization,
msp430_seq: vec![Msp430Opcode::MOVA],
x86_seq: vec![X86Opcode::MOV],
msp430_cost: 3,
x86_cost: 1,
is_commutative: false,
min_operands: 1,
max_operands: 1,
});
}
pub fn find(&self, op_name: &str, _is_msp430: bool) -> Option<SharedISelMatch> {
self.patterns.get(op_name).map(|p| SharedISelMatch {
pattern: p.clone(),
msp430_sequence: p.msp430_seq.clone(),
x86_sequence: p.x86_seq.clone(),
estimated_msp430_cost: p.msp430_cost,
estimated_x86_cost: p.x86_cost,
})
}
pub fn list_patterns(&self) -> Vec<&String> {
self.patterns.keys().collect()
}
pub fn list_patterns_by_category(&self, category: PatternCategory) -> Vec<&String> {
self.categories
.get(&category)
.map(|v| v.iter().collect())
.unwrap_or_default()
}
pub fn pattern_count(&self) -> usize {
self.patterns.len()
}
}
impl Default for SharedISelPatterns {
fn default() -> Self {
let mut patterns = Self::new();
patterns.load_patterns();
patterns
}
}
#[derive(Debug, Clone)]
pub struct SharedISelMatch {
pub pattern: SharedPattern,
pub msp430_sequence: Vec<Msp430Opcode>,
pub x86_sequence: Vec<X86Opcode>,
pub estimated_msp430_cost: u32,
pub estimated_x86_cost: u32,
}
pub struct CrossTargetLowering {
rules: Vec<LoweringRule>,
rule_index: HashMap<String, usize>,
}
#[derive(Debug, Clone)]
pub struct LoweringRule {
pub name: String,
pub targets: Vec<EmbeddedTarget>,
pub match_pattern: Vec<String>,
pub replacement: Vec<ReplacementStep>,
pub priority: u32,
pub is_optimization: bool,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum EmbeddedTarget {
MSP430,
MSP430X,
AVR,
ARC,
X86,
X86_64,
All,
}
#[derive(Debug, Clone)]
pub struct ReplacementStep {
pub operation: String,
pub inputs: Vec<usize>,
pub output: String,
pub metadata: HashMap<String, String>,
}
impl CrossTargetLowering {
pub fn new() -> Self {
Self {
rules: Vec::new(),
rule_index: HashMap::new(),
}
}
pub fn load_rules(&mut self) {
self.add_rule(LoweringRule {
name: "combine_mov_mov_to_swpb".into(),
targets: vec![EmbeddedTarget::MSP430, EmbeddedTarget::MSP430X],
match_pattern: vec!["shl".into(), "shr".into(), "or".into()],
replacement: vec![ReplacementStep {
operation: "swpb".into(),
inputs: vec![0],
output: "result".into(),
metadata: HashMap::new(),
}],
priority: 90,
is_optimization: true,
});
self.add_rule(LoweringRule {
name: "lower_16bit_mul_to_shift_add".into(),
targets: vec![EmbeddedTarget::MSP430, EmbeddedTarget::MSP430X],
match_pattern: vec!["mul".into(), "a".into(), "b".into()],
replacement: vec![ReplacementStep {
operation: "msp430_mul_expand".into(),
inputs: vec![1, 2],
output: "result".into(),
metadata: HashMap::new(),
}],
priority: 80,
is_optimization: false,
});
self.add_rule(LoweringRule {
name: "lower_memcpy_to_mov_loop".into(),
targets: vec![EmbeddedTarget::MSP430, EmbeddedTarget::MSP430X],
match_pattern: vec!["memcpy".into(), "dest".into(), "src".into(), "size".into()],
replacement: vec![ReplacementStep {
operation: "memcpy_expand_msp430".into(),
inputs: vec![1, 2, 3],
output: "".into(),
metadata: HashMap::new(),
}],
priority: 70,
is_optimization: false,
});
self.add_rule(LoweringRule {
name: "lower_memset_to_mov_loop".into(),
targets: vec![EmbeddedTarget::MSP430, EmbeddedTarget::MSP430X],
match_pattern: vec![
"memset".into(),
"dest".into(),
"value".into(),
"size".into(),
],
replacement: vec![ReplacementStep {
operation: "memset_expand_msp430".into(),
inputs: vec![1, 2, 3],
output: "".into(),
metadata: HashMap::new(),
}],
priority: 70,
is_optimization: false,
});
self.add_rule(LoweringRule {
name: "use_constant_generator".into(),
targets: vec![EmbeddedTarget::MSP430, EmbeddedTarget::MSP430X],
match_pattern: vec!["mov".into(), "const".into()],
replacement: vec![ReplacementStep {
operation: "mov_cg".into(),
inputs: vec![1],
output: "result".into(),
metadata: {
let mut m = HashMap::new();
m.insert("cg_values".into(), "0,1,2,4,8,-1".into());
m
},
}],
priority: 95,
is_optimization: true,
});
self.add_rule(LoweringRule {
name: "combine_cmp_jcc".into(),
targets: vec![EmbeddedTarget::MSP430, EmbeddedTarget::MSP430X],
match_pattern: vec!["cmp".into(), "jmp".into()],
replacement: vec![ReplacementStep {
operation: "jcc".into(),
inputs: vec![0, 1],
output: "".into(),
metadata: HashMap::new(),
}],
priority: 85,
is_optimization: true,
});
self.add_rule(LoweringRule {
name: "combine_bit_jz".into(),
targets: vec![EmbeddedTarget::MSP430, EmbeddedTarget::MSP430X],
match_pattern: vec!["bit".into(), "jz".into()],
replacement: vec![ReplacementStep {
operation: "bit_branch".into(),
inputs: vec![0, 1],
output: "".into(),
metadata: HashMap::new(),
}],
priority: 85,
is_optimization: true,
});
self.add_rule(LoweringRule {
name: "eliminate_push_pop_pair".into(),
targets: vec![
EmbeddedTarget::MSP430,
EmbeddedTarget::MSP430X,
EmbeddedTarget::X86,
EmbeddedTarget::X86_64,
],
match_pattern: vec!["push".into(), "pop".into()],
replacement: vec![ReplacementStep {
operation: "mov".into(),
inputs: vec![0],
output: "eliminated".into(),
metadata: HashMap::new(),
}],
priority: 90,
is_optimization: true,
});
self.add_rule(LoweringRule {
name: "use_pushm_popm".into(),
targets: vec![EmbeddedTarget::MSP430X],
match_pattern: vec!["push".into(), "push".into(), "push".into()],
replacement: vec![ReplacementStep {
operation: "pushm".into(),
inputs: vec![0, 1, 2],
output: "".into(),
metadata: HashMap::new(),
}],
priority: 92,
is_optimization: true,
});
}
fn add_rule(&mut self, rule: LoweringRule) {
let name = rule.name.clone();
let idx = self.rules.len();
self.rule_index.insert(name, idx);
self.rules.push(rule);
}
pub fn apply(&self, ir_sequence: &[&str]) -> Vec<CrossTargetOptResult> {
let mut results = Vec::new();
for rule in &self.rules {
if let Some(repl) = self.try_match_rule(rule, ir_sequence) {
results.push(CrossTargetOptResult {
rule_name: rule.name.clone(),
matched: true,
replacement: Some(repl),
targets: rule.targets.clone(),
is_optimization: rule.is_optimization,
});
}
}
results
}
fn try_match_rule(&self, rule: &LoweringRule, ir_sequence: &[&str]) -> Option<String> {
if rule.match_pattern.len() > ir_sequence.len() {
return None;
}
for i in 0..=ir_sequence.len() - rule.match_pattern.len() {
let mut matched = true;
for (j, pat) in rule.match_pattern.iter().enumerate() {
if pat != "const" && ir_sequence[i + j] != pat.as_str() {
matched = false;
break;
}
}
if matched {
let desc = rule
.replacement
.iter()
.map(|s| s.operation.clone())
.collect::<Vec<_>>()
.join(", ");
return Some(desc);
}
}
None
}
pub fn get_rule(&self, name: &str) -> Option<&LoweringRule> {
self.rule_index.get(name).map(|&idx| &self.rules[idx])
}
pub fn list_rules(&self) -> Vec<&String> {
self.rules.iter().map(|r| &r.name).collect()
}
pub fn rule_count(&self) -> usize {
self.rules.len()
}
}
impl Default for CrossTargetLowering {
fn default() -> Self {
let mut rules = Self::new();
rules.load_rules();
rules
}
}
#[derive(Debug, Clone)]
pub struct CrossTargetOptResult {
pub rule_name: String,
pub matched: bool,
pub replacement: Option<String>,
pub targets: Vec<EmbeddedTarget>,
pub is_optimization: bool,
}
pub struct SharedRegisterAllocContext {
pub msp430_classes: Vec<SharedRegClass>,
pub x86_classes: Vec<SharedRegClass>,
pub virt_to_phys: HashMap<u32, u32>,
pub reg_pressure: HashMap<u32, u32>,
pub live_intervals: Vec<LiveInterval>,
pub strategy: AllocationStrategy,
pub spill_slots: HashMap<u32, SpillSlotInfo>,
pub allocated: BTreeSet<u32>,
}
#[derive(Debug, Clone)]
pub struct SharedRegClass {
pub id: u32,
pub name: String,
pub registers: Vec<u32>,
pub alignment: u32,
pub size_bits: u32,
pub is_allocatable: bool,
pub copy_cost: u32,
}
#[derive(Debug, Clone)]
pub struct LiveInterval {
pub vreg: u32,
pub start: usize,
pub end: usize,
pub reg_class: u32,
pub spill_weight: f64,
}
#[derive(Debug, Clone)]
pub struct SpillSlotInfo {
pub slot: u32,
pub offset: i32,
pub size: u32,
pub alignment: u32,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum AllocationStrategy {
LinearScan,
Greedy,
Fast,
}
impl AllocationStrategy {
pub fn as_str(&self) -> &str {
match self {
Self::LinearScan => "linear-scan",
Self::Greedy => "greedy",
Self::Fast => "fast",
}
}
}
impl SharedRegisterAllocContext {
pub fn new() -> Self {
Self {
msp430_classes: Vec::new(),
x86_classes: Vec::new(),
virt_to_phys: HashMap::new(),
reg_pressure: HashMap::new(),
live_intervals: Vec::new(),
strategy: AllocationStrategy::Greedy,
spill_slots: HashMap::new(),
allocated: BTreeSet::new(),
}
}
pub fn initialize(&mut self) {
self.msp430_classes.push(SharedRegClass {
id: 0,
name: "GPR16".into(),
registers: vec![8004, 8005, 8006, 8007, 8008, 8009, 8010, 8011, 8012],
alignment: 2,
size_bits: 16,
is_allocatable: true,
copy_cost: 1,
});
self.msp430_classes.push(SharedRegClass {
id: 1,
name: "Special".into(),
registers: vec![8000, 8001, 8002, 8003],
alignment: 2,
size_bits: 16,
is_allocatable: false,
copy_cost: 0,
});
self.msp430_classes.push(SharedRegClass {
id: 2,
name: "CalleeSaved".into(),
registers: vec![8004, 8005, 8006, 8007, 8008, 8009, 8010],
alignment: 2,
size_bits: 16,
is_allocatable: true,
copy_cost: 1,
});
self.msp430_classes.push(SharedRegClass {
id: 3,
name: "CallerSaved".into(),
registers: vec![8011, 8012, 8013, 8014, 8015],
alignment: 2,
size_bits: 16,
is_allocatable: true,
copy_cost: 1,
});
self.x86_classes.push(SharedRegClass {
id: 0,
name: "GPR32".into(),
registers: (0..8).collect(),
alignment: 4,
size_bits: 32,
is_allocatable: true,
copy_cost: 1,
});
self.x86_classes.push(SharedRegClass {
id: 1,
name: "GPR64".into(),
registers: (0..16).collect(),
alignment: 8,
size_bits: 64,
is_allocatable: true,
copy_cost: 1,
});
}
pub fn compute_spill_weight(&self, interval: &LiveInterval) -> f64 {
let length = (interval.end - interval.start) as f64;
if length <= 0.0 {
return 0.0;
}
length.ln() * 2.0
}
pub fn is_register_available(&self, reg: u32) -> bool {
!self.allocated.contains(®)
}
pub fn allocate_register(&mut self, vreg: u32, phys: u32) {
self.virt_to_phys.insert(vreg, phys);
self.allocated.insert(phys);
}
pub fn free_register(&mut self, phys: u32) {
self.allocated.remove(&phys);
self.virt_to_phys.retain(|_, v| *v != phys);
}
pub fn add_spill_slot(&mut self, vreg: u32, size: u32, alignment: u32) -> u32 {
let slot = self.spill_slots.len() as u32;
self.spill_slots.insert(
vreg,
SpillSlotInfo {
slot,
offset: -(slot as i32 + 1) * 2,
size,
alignment,
},
);
slot
}
pub fn get_physical_reg(&self, vreg: u32) -> Option<u32> {
self.virt_to_phys.get(&vreg).copied()
}
pub fn is_spilled(&self, vreg: u32) -> bool {
self.spill_slots.contains_key(&vreg)
}
pub fn get_spill_slot(&self, vreg: u32) -> Option<&SpillSlotInfo> {
self.spill_slots.get(&vreg)
}
pub fn build_msp430_cc_constraints(&self) -> Vec<RegisterConstraint> {
vec![
RegisterConstraint {
reg: 8000,
constraint_type: ConstraintType::Reserved,
reason: "Program Counter (PC)".into(),
},
RegisterConstraint {
reg: 8001,
constraint_type: ConstraintType::FixedAssignment,
reason: "Stack Pointer (SP)".into(),
},
RegisterConstraint {
reg: 8002,
constraint_type: ConstraintType::Reserved,
reason: "Status Register (SR)".into(),
},
RegisterConstraint {
reg: 8003,
constraint_type: ConstraintType::Reserved,
reason: "Constant Generator (CG2)".into(),
},
RegisterConstraint {
reg: 8012,
constraint_type: ConstraintType::FixedAssignment,
reason: "Return value (R12)".into(),
},
RegisterConstraint {
reg: 8013,
constraint_type: ConstraintType::FixedAssignment,
reason: "Second return value (R13)".into(),
},
RegisterConstraint {
reg: 8014,
constraint_type: ConstraintType::FixedAssignment,
reason: "Frame pointer / Link register (R14)".into(),
},
RegisterConstraint {
reg: 8015,
constraint_type: ConstraintType::FixedAssignment,
reason: "Return address / Call register (R15)".into(),
},
]
}
}
impl Default for SharedRegisterAllocContext {
fn default() -> Self {
let mut ctx = Self::new();
ctx.initialize();
ctx
}
}
#[derive(Debug)]
pub struct CrossTargetRegisterAlloc {
pub context: SharedRegisterAllocContext,
pub msp430_constraints: Vec<RegisterConstraint>,
pub x86_constraints: Vec<RegisterConstraint>,
pub aliases: Vec<RegisterAlias>,
}
#[derive(Debug, Clone)]
pub struct RegisterConstraint {
pub reg: u32,
pub constraint_type: ConstraintType,
pub reason: String,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ConstraintType {
Reserved,
FixedAssignment,
CallerSaved,
CalleeSaved,
AlignmentRequired,
}
#[derive(Debug, Clone)]
pub struct RegisterAlias {
pub primary: u32,
pub alias: u32,
pub relation: AliasRelation,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum AliasRelation {
SubRegister,
SuperRegister,
Equivalent,
}
impl CrossTargetRegisterAlloc {
pub fn new() -> Self {
Self {
context: SharedRegisterAllocContext::new(),
msp430_constraints: Vec::new(),
x86_constraints: Vec::new(),
aliases: Vec::new(),
}
}
}
impl Default for CrossTargetRegisterAlloc {
fn default() -> Self {
let mut ra = Self::new();
ra.context.initialize();
ra
}
}
#[derive(Debug)]
pub struct CrossTargetFrameLowering {
pub stack_alignment: u32,
pub red_zone_size: u32,
pub max_call_frame_size: u32,
pub use_frame_pointer: bool,
pub local_area_offset_fixed: bool,
}
impl CrossTargetFrameLowering {
pub fn new() -> Self {
Self {
stack_alignment: 2,
red_zone_size: 0,
max_call_frame_size: 0,
use_frame_pointer: true,
local_area_offset_fixed: false,
}
}
}
impl Default for CrossTargetFrameLowering {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Clone)]
pub struct SharedFrameLoweringContext {
pub frame_size: u32,
pub saved_regs_offset: i32,
pub local_area_offset: i32,
pub callee_saved_slots: Vec<(u32, i32)>,
pub has_frame_pointer: bool,
pub has_calls: bool,
pub stack_alignment: u32,
pub is_msp430x: bool,
}
impl SharedFrameLoweringContext {
pub fn new() -> Self {
Self {
frame_size: 0,
saved_regs_offset: 0,
local_area_offset: 0,
callee_saved_slots: Vec::new(),
has_frame_pointer: false,
has_calls: false,
stack_alignment: 2,
is_msp430x: false,
}
}
pub fn initialize(&mut self) {
self.frame_size = 0;
self.saved_regs_offset = 0;
self.local_area_offset = 0;
self.callee_saved_slots.clear();
self.has_frame_pointer = false;
self.has_calls = false;
}
pub fn add_callee_saved_slot(&mut self, reg: u32, offset: i32) {
self.callee_saved_slots.push((reg, offset));
}
pub fn get_callee_saved_offset(&self, reg: u32) -> Option<i32> {
self.callee_saved_slots
.iter()
.find(|(r, _)| *r == reg)
.map(|(_, o)| *o)
}
pub fn compute_prologue_size(&self) -> u32 {
let mut size = 0u32;
if self.has_frame_pointer {
size += 1;
size += 1;
}
if self.frame_size > 0 {
size += 1;
}
size += self.callee_saved_slots.len() as u32;
size
}
pub fn sort_callee_saved_slots(&mut self) {
self.callee_saved_slots.sort_by_key(|(_, o)| *o);
}
}
impl Default for SharedFrameLoweringContext {
fn default() -> Self {
let mut ctx = Self::new();
ctx.initialize();
ctx
}
}
pub struct CrossTargetConstMaterializer {
pub is_msp430x: bool,
pub max_immediate: i32,
}
impl CrossTargetConstMaterializer {
pub fn new() -> Self {
Self {
is_msp430x: false,
max_immediate: 65535,
}
}
pub fn materialize_msp430(&self, value: i32) -> Vec<Msp430Opcode> {
match value {
0 => vec![Msp430Opcode::CLR],
1 => vec![Msp430Opcode::MOV], 2 => vec![Msp430Opcode::MOV],
4 => vec![Msp430Opcode::MOV],
8 => vec![Msp430Opcode::MOV],
-1 => vec![Msp430Opcode::MOV],
_ if value >= 0 && value <= 65535 => vec![Msp430Opcode::MOV],
_ if self.is_msp430x && value >= 0 && value <= 0xFFFFF => {
vec![Msp430Opcode::MOVA]
}
_ => vec![Msp430Opcode::MOV, Msp430Opcode::MOV],
}
}
pub fn materialize_x86_cost(&self, value: i32) -> u32 {
if value == 0 {
return 1; }
1 }
}
impl Default for CrossTargetConstMaterializer {
fn default() -> Self {
Self::new()
}
}
pub struct CrossTargetBranchAnalyzer {
pub branch_stats: BranchStats,
pub hints: Vec<BranchHint>,
}
#[derive(Debug, Default, Clone)]
pub struct BranchStats {
pub total_branches: u64,
pub conditional_branches: u64,
pub unconditional_branches: u64,
pub backward_branches: u64,
pub forward_branches: u64,
pub avg_branch_distance: f64,
pub indirect_branches: u64,
}
#[derive(Debug, Clone)]
pub struct BranchHint {
pub instr_idx: usize,
pub likely_taken: bool,
pub confidence: f64,
}
impl CrossTargetBranchAnalyzer {
pub fn new() -> Self {
Self {
branch_stats: BranchStats::default(),
hints: Vec::new(),
}
}
pub fn analyze(&mut self, instrs: &[&str]) {
self.branch_stats.total_branches = 0;
self.branch_stats.conditional_branches = 0;
self.branch_stats.unconditional_branches = 0;
self.branch_stats.backward_branches = 0;
self.branch_stats.forward_branches = 0;
self.branch_stats.indirect_branches = 0;
for instr in instrs.iter() {
let lower = instr.to_lowercase();
if lower.starts_with('j') || lower.starts_with('b') || lower.contains("call") {
self.branch_stats.total_branches += 1;
if lower == "jmp" || lower == "br" || lower == "bra" {
self.branch_stats.unconditional_branches += 1;
} else if lower.contains("call") {
self.branch_stats.unconditional_branches += 1;
} else {
self.branch_stats.conditional_branches += 1;
}
}
}
}
pub fn compare(&self, msp430_branches: u64, x86_branches: u64) -> BranchComparison {
let ratio = if x86_branches > 0 {
msp430_branches as f64 / x86_branches as f64
} else {
f64::INFINITY
};
BranchComparison {
msp430_branch_count: msp430_branches,
x86_branch_count: x86_branches,
ratio,
assessment: if ratio < 0.9 {
"MSP430 uses fewer branches".into()
} else if ratio > 1.1 {
"X86 uses fewer branches".into()
} else {
"Similar branch counts".into()
},
}
}
}
#[derive(Debug, Clone)]
pub struct BranchComparison {
pub msp430_branch_count: u64,
pub x86_branch_count: u64,
pub ratio: f64,
pub assessment: String,
}
impl Default for CrossTargetBranchAnalyzer {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Clone, Default)]
pub struct MSP430FeatureSet {
pub enabled: HashSet<String>,
pub disabled: HashSet<String>,
}
impl MSP430FeatureSet {
pub fn new() -> Self {
Self {
enabled: HashSet::new(),
disabled: HashSet::new(),
}
}
pub fn enable(&mut self, feature: &str) {
self.disabled.remove(feature);
self.enabled.insert(feature.to_string());
}
pub fn disable(&mut self, feature: &str) {
self.enabled.remove(feature);
self.disabled.insert(feature.to_string());
}
pub fn has(&self, feature: &str) -> bool {
self.enabled.contains(feature)
}
pub fn is_disabled(&self, feature: &str) -> bool {
self.disabled.contains(feature)
}
pub fn msp430_default() -> Self {
let mut fs = Self::new();
fs.enable("16bit");
fs
}
pub fn msp430x_default() -> Self {
let mut fs = Self::new();
fs.enable("16bit");
fs.enable("20bit");
fs.enable("msp430x");
fs.enable("mova");
fs.enable("pushm");
fs.enable("popm");
fs
}
}
#[derive(Debug, Clone)]
pub struct BridgeMSP430TargetMachine {
pub triple: String,
pub cpu: String,
pub features: String,
pub is_msp430x: bool,
pub data_layout: String,
pub stack_alignment: u32,
pub pointer_size: u32,
pub feature_set: MSP430FeatureSet,
}
pub const MSP430_DATA_LAYOUT: &str = "e-m:e-p:16:16-i32:16:32-a:0:16-n16";
pub const MSP430X_DATA_LAYOUT: &str = "e-m:e-p:20:16-i32:16:32-a:0:16-n16";
impl BridgeMSP430TargetMachine {
pub fn new(triple: &str) -> Self {
let lower = triple.to_lowercase();
let is_msp430x = lower.contains("msp430x") || lower.contains("430x");
let data_layout = if is_msp430x {
MSP430X_DATA_LAYOUT.to_string()
} else {
MSP430_DATA_LAYOUT.to_string()
};
let feature_set = if is_msp430x {
MSP430FeatureSet::msp430x_default()
} else {
MSP430FeatureSet::msp430_default()
};
Self {
triple: triple.to_string(),
cpu: if is_msp430x {
"msp430x".to_string()
} else {
"msp430".to_string()
},
features: if is_msp430x {
"+msp430x,+mova,+20bit".to_string()
} else {
"+16bit".to_string()
},
is_msp430x,
data_layout,
stack_alignment: 2,
pointer_size: if is_msp430x { 4 } else { 2 },
feature_set,
}
}
pub fn new_msp430() -> Self {
Self::new("msp430-unknown-elf")
}
pub fn new_msp430x() -> Self {
Self::new("msp430x-unknown-elf")
}
pub fn get_triple(&self) -> &str {
&self.triple
}
pub fn get_data_layout(&self) -> &str {
&self.data_layout
}
pub fn is_msp430x(&self) -> bool {
self.is_msp430x
}
pub fn describe(&self) -> String {
format!(
"MSP430 Target Machine:\n Triple: {}\n CPU: {}\n Features: {}\n MSP430X: {}\n Data Layout: {}\n Stack Alignment: {}\n Pointer Size: {}",
self.triple,
self.cpu,
self.features,
self.is_msp430x,
self.data_layout,
self.stack_alignment,
self.pointer_size,
)
}
pub fn get_target_name(&self) -> &str {
if self.is_msp430x {
"msp430x"
} else {
"msp430"
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Msp430BridgeReg {
PC,
SP,
SR,
CG2,
R4,
R5,
R6,
R7,
R8,
R9,
R10,
R11,
R12,
R13,
R14,
R15,
}
impl Msp430BridgeReg {
pub fn id(&self) -> u16 {
match self {
Self::PC => MSP430_GPR_BASE,
Self::SP => MSP430_GPR_BASE + 1,
Self::SR => MSP430_GPR_BASE + 2,
Self::CG2 => MSP430_GPR_BASE + 3,
Self::R4 => MSP430_GPR_BASE + 4,
Self::R5 => MSP430_GPR_BASE + 5,
Self::R6 => MSP430_GPR_BASE + 6,
Self::R7 => MSP430_GPR_BASE + 7,
Self::R8 => MSP430_GPR_BASE + 8,
Self::R9 => MSP430_GPR_BASE + 9,
Self::R10 => MSP430_GPR_BASE + 10,
Self::R11 => MSP430_GPR_BASE + 11,
Self::R12 => MSP430_GPR_BASE + 12,
Self::R13 => MSP430_GPR_BASE + 13,
Self::R14 => MSP430_GPR_BASE + 14,
Self::R15 => MSP430_GPR_BASE + 15,
}
}
pub fn abi_name(&self) -> &str {
match self {
Self::PC => "pc",
Self::SP => "sp",
Self::SR => "sr",
Self::CG2 => "cg2",
Self::R4 => "r4",
Self::R5 => "r5",
Self::R6 => "r6",
Self::R7 => "r7",
Self::R8 => "r8",
Self::R9 => "r9",
Self::R10 => "r10",
Self::R11 => "r11",
Self::R12 => "r12",
Self::R13 => "r13",
Self::R14 => "r14",
Self::R15 => "r15",
}
}
pub fn is_special(&self) -> bool {
matches!(self, Self::PC | Self::SP | Self::SR | Self::CG2)
}
pub fn is_callee_saved(&self) -> bool {
matches!(
self,
Self::R4 | Self::R5 | Self::R6 | Self::R7 | Self::R8 | Self::R9 | Self::R10
)
}
pub fn is_caller_saved(&self) -> bool {
matches!(
self,
Self::R11 | Self::R12 | Self::R13 | Self::R14 | Self::R15
)
}
pub fn allocatable_regs() -> Vec<Msp430BridgeReg> {
vec![
Self::R4,
Self::R5,
Self::R6,
Self::R7,
Self::R8,
Self::R9,
Self::R10,
Self::R11,
Self::R12,
Self::R13,
Self::R14,
Self::R15,
]
}
pub fn from_id(id: u16) -> Option<Self> {
match id {
8000 => Some(Self::PC),
8001 => Some(Self::SP),
8002 => Some(Self::SR),
8003 => Some(Self::CG2),
8004 => Some(Self::R4),
8005 => Some(Self::R5),
8006 => Some(Self::R6),
8007 => Some(Self::R7),
8008 => Some(Self::R8),
8009 => Some(Self::R9),
8010 => Some(Self::R10),
8011 => Some(Self::R11),
8012 => Some(Self::R12),
8013 => Some(Self::R13),
8014 => Some(Self::R14),
8015 => Some(Self::R15),
_ => None,
}
}
}
pub struct BridgeMSP430InstrInfo {
pub core: Msp430InstrInfo,
pub single_operand_ops: Vec<Msp430Opcode>,
pub double_operand_ops: Vec<Msp430Opcode>,
pub jump_ops: Vec<Msp430Opcode>,
pub emulated_ops: Vec<Msp430Opcode>,
pub msp430x_ops: Vec<Msp430Opcode>,
pub terminator_ops: Vec<Msp430Opcode>,
pub memory_ops: Vec<Msp430Opcode>,
}
impl BridgeMSP430InstrInfo {
pub fn new() -> Self {
let mut info = Self {
core: Msp430InstrInfo::new(),
single_operand_ops: Vec::new(),
double_operand_ops: Vec::new(),
jump_ops: Vec::new(),
emulated_ops: Vec::new(),
msp430x_ops: Vec::new(),
terminator_ops: Vec::new(),
memory_ops: Vec::new(),
};
info.categorize();
info
}
fn categorize(&mut self) {
self.single_operand_ops = vec![
Msp430Opcode::RRC,
Msp430Opcode::SWPB,
Msp430Opcode::RRA,
Msp430Opcode::SXT,
Msp430Opcode::PUSH,
Msp430Opcode::POP,
Msp430Opcode::CALL,
Msp430Opcode::RETI,
];
self.double_operand_ops = vec![
Msp430Opcode::MOV,
Msp430Opcode::ADD,
Msp430Opcode::ADDC,
Msp430Opcode::SUBC,
Msp430Opcode::SUB,
Msp430Opcode::CMP,
Msp430Opcode::DADD,
Msp430Opcode::BIT,
Msp430Opcode::BIC,
Msp430Opcode::BIS,
Msp430Opcode::XOR,
Msp430Opcode::AND,
];
self.jump_ops = vec![
Msp430Opcode::JNE,
Msp430Opcode::JEQ,
Msp430Opcode::JNC,
Msp430Opcode::JC,
Msp430Opcode::JN,
Msp430Opcode::JGE,
Msp430Opcode::JL,
Msp430Opcode::JMP,
];
self.emulated_ops = vec![
Msp430Opcode::CLR,
Msp430Opcode::CLRC,
Msp430Opcode::SETC,
Msp430Opcode::CLRZ,
Msp430Opcode::SETZ,
Msp430Opcode::CLRN,
Msp430Opcode::SETN,
Msp430Opcode::DINT,
Msp430Opcode::EINT,
Msp430Opcode::NOP,
Msp430Opcode::BR,
Msp430Opcode::RET,
Msp430Opcode::TST,
Msp430Opcode::INV,
Msp430Opcode::RLA,
Msp430Opcode::RLC,
Msp430Opcode::ADC,
Msp430Opcode::DADC,
];
self.msp430x_ops = vec![
Msp430Opcode::MOVA,
Msp430Opcode::CMPA,
Msp430Opcode::ADDA,
Msp430Opcode::SUBA,
Msp430Opcode::BRA,
Msp430Opcode::RETA,
Msp430Opcode::PUSHM,
Msp430Opcode::POPM,
Msp430Opcode::CALLA,
];
self.terminator_ops = vec![
Msp430Opcode::JMP,
Msp430Opcode::BR,
Msp430Opcode::BRA,
Msp430Opcode::CALL,
Msp430Opcode::CALLA,
Msp430Opcode::RET,
Msp430Opcode::RETA,
Msp430Opcode::RETI,
];
self.memory_ops = vec![
Msp430Opcode::MOV,
Msp430Opcode::PUSH,
Msp430Opcode::POP,
Msp430Opcode::PUSHM,
Msp430Opcode::POPM,
];
}
pub fn is_msp430x_opcode(&self, opcode: Msp430Opcode) -> bool {
self.msp430x_ops.contains(&opcode)
}
pub fn get_mnemonic(&self, opcode: Msp430Opcode) -> String {
self.core.get_mnemonic(opcode)
}
pub fn get_branch_ops(&self) -> &[Msp430Opcode] {
&self.jump_ops
}
pub fn instruction_counts(&self) -> InstructionCounts {
InstructionCounts {
single_operand: self.single_operand_ops.len() as u32,
double_operand: self.double_operand_ops.len() as u32,
jumps: self.jump_ops.len() as u32,
emulated: self.emulated_ops.len() as u32,
msp430x: self.msp430x_ops.len() as u32,
}
}
}
#[derive(Debug, Clone)]
pub struct InstructionCounts {
pub single_operand: u32,
pub double_operand: u32,
pub jumps: u32,
pub emulated: u32,
pub msp430x: u32,
}
#[derive(Debug, Clone)]
pub struct MSP430CallingConventionBridge {
pub arg_regs: Vec<u32>,
pub ret_regs: Vec<u32>,
pub callee_saved: Vec<u32>,
pub caller_saved: Vec<u32>,
pub stack_alignment: u32,
pub use_stack_args: bool,
}
impl MSP430CallingConventionBridge {
pub fn new() -> Self {
Self {
arg_regs: vec![
MSP430_GPR_BASE as u32 + 15, MSP430_GPR_BASE as u32 + 14, MSP430_GPR_BASE as u32 + 13, MSP430_GPR_BASE as u32 + 12, ],
ret_regs: vec![
MSP430_GPR_BASE as u32 + 12, MSP430_GPR_BASE as u32 + 13, ],
callee_saved: vec![
MSP430_GPR_BASE as u32 + 4, MSP430_GPR_BASE as u32 + 5, MSP430_GPR_BASE as u32 + 6, MSP430_GPR_BASE as u32 + 7, MSP430_GPR_BASE as u32 + 8, MSP430_GPR_BASE as u32 + 9, MSP430_GPR_BASE as u32 + 10, ],
caller_saved: vec![
MSP430_GPR_BASE as u32 + 11, MSP430_GPR_BASE as u32 + 12, MSP430_GPR_BASE as u32 + 13, MSP430_GPR_BASE as u32 + 14, MSP430_GPR_BASE as u32 + 15, ],
stack_alignment: 2,
use_stack_args: true,
}
}
pub fn get_arg_register(&self, n: usize) -> Option<u32> {
if n < self.arg_regs.len() {
Some(self.arg_regs[self.arg_regs.len() - 1 - n])
} else {
None
}
}
pub fn get_return_register(&self) -> u32 {
self.ret_regs[0]
}
pub fn is_callee_saved(&self, reg: u32) -> bool {
self.callee_saved.contains(®)
}
pub fn compare_with_x86(&self) -> CCComparison {
CCComparison {
msp430_arg_regs: self.arg_regs.len() as u32,
x86_arg_regs: 6, msp430_ret_regs: self.ret_regs.len() as u32,
x86_ret_regs: 2, msp430_callee_saved: self.callee_saved.len() as u32,
x86_callee_saved: 5, msp430_caller_saved: self.caller_saved.len() as u32,
x86_caller_saved: 9,
}
}
}
#[derive(Debug, Clone)]
pub struct CCComparison {
pub msp430_arg_regs: u32,
pub x86_arg_regs: u32,
pub msp430_ret_regs: u32,
pub x86_ret_regs: u32,
pub msp430_callee_saved: u32,
pub x86_callee_saved: u32,
pub msp430_caller_saved: u32,
pub x86_caller_saved: u32,
}
pub struct CodeSizeAnalyzer {
pub msp430_bytes: u64,
pub x86_bytes: u64,
pub msp430_instr_sizes: Vec<(Msp430Opcode, u32)>,
pub x86_instr_sizes: Vec<(X86Opcode, u32)>,
}
impl CodeSizeAnalyzer {
pub fn new() -> Self {
Self {
msp430_bytes: 0,
x86_bytes: 0,
msp430_instr_sizes: Vec::new(),
x86_instr_sizes: Vec::new(),
}
}
pub fn analyze_msp430(&mut self, opcodes: &[Msp430Opcode]) {
for opcode in opcodes {
let size = match opcode {
Msp430Opcode::RRC
| Msp430Opcode::SWPB
| Msp430Opcode::RRA
| Msp430Opcode::SXT
| Msp430Opcode::PUSH
| Msp430Opcode::RETI => 2,
Msp430Opcode::CALL | Msp430Opcode::JMP => 4,
Msp430Opcode::JNE
| Msp430Opcode::JEQ
| Msp430Opcode::JNC
| Msp430Opcode::JC
| Msp430Opcode::JN
| Msp430Opcode::JGE
| Msp430Opcode::JL => 2,
_ => 4,
};
self.msp430_bytes += size as u64;
self.msp430_instr_sizes.push((*opcode, size));
}
}
pub fn analyze_x86(&mut self, opcodes: &[X86Opcode]) {
for opcode in opcodes {
let size = match opcode {
X86Opcode::NOP => 1,
X86Opcode::RET => 1,
X86Opcode::PUSH | X86Opcode::POP => 1,
X86Opcode::INC | X86Opcode::DEC => 1,
X86Opcode::JMP => 2,
X86Opcode::JE
| X86Opcode::JNE
| X86Opcode::JB
| X86Opcode::JAE
| X86Opcode::JL
| X86Opcode::JGE => 2,
X86Opcode::CALL => 5,
_ => 3,
};
self.x86_bytes += size as u64;
self.x86_instr_sizes.push((*opcode, size));
}
}
pub fn compression_ratio(&self) -> f64 {
if self.x86_bytes > 0 {
self.msp430_bytes as f64 / self.x86_bytes as f64
} else {
0.0
}
}
pub fn report(&self) -> String {
format!(
"Code Size: MSP430={} bytes, X86={} bytes, Ratio={:.3} (MSP430/X86)",
self.msp430_bytes,
self.x86_bytes,
self.compression_ratio()
)
}
}
impl Default for CodeSizeAnalyzer {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_bridge_creation() {
let bridge = MSP430X86Bridge::new();
assert_eq!(bridge.config.target_variant, "msp430");
assert!(!bridge.config.verbose);
}
#[test]
fn test_bridge_with_config() {
let config = BridgeConfig {
target_variant: "msp430x".into(),
..BridgeConfig::default()
};
let bridge = MSP430X86Bridge::with_config(config);
assert_eq!(bridge.config.target_variant, "msp430x");
}
#[test]
fn test_translate_x86_to_msp430_add() {
let mut bridge = MSP430X86Bridge::new();
let result = bridge.translate_x86_to_msp430(&X86Opcode::ADD);
assert!(result.is_some());
match result.unwrap() {
BridgeInstruction::DirectMap(op) => assert_eq!(op, Msp430Opcode::ADD),
_ => panic!("Expected DirectMap"),
}
}
#[test]
fn test_translate_x86_to_msp430_sub() {
let mut bridge = MSP430X86Bridge::new();
let result = bridge.translate_x86_to_msp430(&X86Opcode::SUB);
assert!(result.is_some());
match result.unwrap() {
BridgeInstruction::DirectMap(op) => assert_eq!(op, Msp430Opcode::SUB),
_ => panic!("Expected DirectMap"),
}
}
#[test]
fn test_translate_x86_to_msp430_mov() {
let mut bridge = MSP430X86Bridge::new();
let result = bridge.translate_x86_to_msp430(&X86Opcode::MOV);
assert!(result.is_some());
match result.unwrap() {
BridgeInstruction::DirectMap(op) => assert_eq!(op, Msp430Opcode::MOV),
_ => panic!("Expected DirectMap"),
}
}
#[test]
fn test_translate_msp430_to_x86_add() {
let mut bridge = MSP430X86Bridge::new();
let result = bridge.translate_msp430_to_x86(&Msp430Opcode::ADD);
assert!(result.is_some());
match result.unwrap() {
BridgeInstruction::DirectMapX86(op) => assert_eq!(op, X86Opcode::ADD),
_ => panic!("Expected DirectMapX86"),
}
}
#[test]
fn test_translate_msp430_to_x86_bis() {
let mut bridge = MSP430X86Bridge::new();
let result = bridge.translate_msp430_to_x86(&Msp430Opcode::BIS);
assert!(result.is_some());
match result.unwrap() {
BridgeInstruction::DirectMapX86(op) => assert_eq!(op, X86Opcode::OR),
_ => panic!("Expected DirectMapX86"),
}
}
#[test]
fn test_pattern_loading() {
let patterns = SharedISelPatterns::default();
assert!(patterns.pattern_count() > 20);
}
#[test]
fn test_find_pattern() {
let patterns = SharedISelPatterns::default();
let result = patterns.find("add_16bit", true);
assert!(result.is_some());
let m = result.unwrap();
assert_eq!(m.msp430_sequence[0], Msp430Opcode::ADD);
assert_eq!(m.x86_sequence[0], X86Opcode::ADD);
}
#[test]
fn test_lowering_rules() {
let rules = CrossTargetLowering::default();
assert!(rules.rule_count() >= 8);
}
#[test]
fn test_apply_lowering_rule() {
let rules = CrossTargetLowering::default();
let results = rules.apply(&["cmp", "jmp"]);
assert!(!results.is_empty());
let first = &results[0];
assert!(first.matched);
}
#[test]
fn test_ra_context() {
let ctx = SharedRegisterAllocContext::default();
assert_eq!(ctx.msp430_classes.len(), 4);
assert_eq!(ctx.x86_classes.len(), 2);
}
#[test]
fn test_ra_allocate_free() {
let mut ctx = SharedRegisterAllocContext::new();
ctx.initialize();
ctx.allocate_register(100, 8004);
assert!(ctx.is_register_available(8005));
assert!(!ctx.is_register_available(8004));
ctx.free_register(8004);
assert!(ctx.is_register_available(8004));
}
#[test]
fn test_ra_spill_slot() {
let mut ctx = SharedRegisterAllocContext::new();
ctx.initialize();
let slot = ctx.add_spill_slot(100, 2, 2);
assert_eq!(slot, 0);
assert!(ctx.is_spilled(100));
let info = ctx.get_spill_slot(100).unwrap();
assert_eq!(info.size, 2);
}
#[test]
fn test_target_machine_msp430() {
let tm = BridgeMSP430TargetMachine::new_msp430();
assert!(!tm.is_msp430x());
assert_eq!(tm.pointer_size, 2);
assert_eq!(tm.get_target_name(), "msp430");
}
#[test]
fn test_target_machine_msp430x() {
let tm = BridgeMSP430TargetMachine::new_msp430x();
assert!(tm.is_msp430x());
assert_eq!(tm.pointer_size, 4);
assert_eq!(tm.get_target_name(), "msp430x");
}
#[test]
fn test_register_enumeration() {
let regs = Msp430BridgeReg::allocatable_regs();
assert_eq!(regs.len(), 12); assert!(Msp430BridgeReg::PC.is_special());
assert!(Msp430BridgeReg::SP.is_special());
assert!(!Msp430BridgeReg::R5.is_special());
}
#[test]
fn test_register_callee_saved() {
assert!(Msp430BridgeReg::R4.is_callee_saved());
assert!(Msp430BridgeReg::R10.is_callee_saved());
assert!(!Msp430BridgeReg::R12.is_callee_saved());
}
#[test]
fn test_register_from_id() {
assert_eq!(Msp430BridgeReg::from_id(8000), Some(Msp430BridgeReg::PC));
assert_eq!(Msp430BridgeReg::from_id(8015), Some(Msp430BridgeReg::R15));
assert_eq!(Msp430BridgeReg::from_id(9999), None);
}
#[test]
fn test_calling_convention() {
let cc = MSP430CallingConventionBridge::new();
assert_eq!(cc.arg_regs.len(), 4);
assert_eq!(cc.ret_regs.len(), 2);
assert_eq!(cc.callee_saved.len(), 7);
assert_eq!(cc.caller_saved.len(), 5);
assert_eq!(cc.get_return_register(), 8012);
}
#[test]
fn test_calling_convention_args() {
let cc = MSP430CallingConventionBridge::new();
assert_eq!(cc.get_arg_register(0), Some(8015)); assert_eq!(cc.get_arg_register(1), Some(8014)); assert_eq!(cc.get_arg_register(4), None); }
#[test]
fn test_code_size_analyzer() {
let mut analyzer = CodeSizeAnalyzer::new();
analyzer.analyze_msp430(&[Msp430Opcode::MOV, Msp430Opcode::ADD, Msp430Opcode::JMP]);
analyzer.analyze_x86(&[X86Opcode::MOV, X86Opcode::ADD, X86Opcode::JMP]);
assert_eq!(analyzer.msp430_bytes, 12);
assert_eq!(analyzer.x86_bytes, 8);
}
#[test]
fn test_const_materializer() {
let cm = CrossTargetConstMaterializer::new();
assert_eq!(cm.materialize_msp430(0), vec![Msp430Opcode::CLR]);
assert_eq!(cm.materialize_msp430(42), vec![Msp430Opcode::MOV]);
assert_eq!(cm.materialize_x86_cost(0), 1);
assert_eq!(cm.materialize_x86_cost(42), 1);
}
#[test]
fn test_frame_context() {
let mut ctx = SharedFrameLoweringContext::new();
ctx.has_frame_pointer = true;
ctx.frame_size = 8;
ctx.add_callee_saved_slot(8004, -2);
ctx.add_callee_saved_slot(8005, -4);
assert_eq!(ctx.compute_prologue_size(), 6); assert_eq!(ctx.get_callee_saved_offset(8004), Some(-2));
assert_eq!(ctx.get_callee_saved_offset(8005), Some(-4));
}
#[test]
fn test_instr_info_categorization() {
let info = BridgeMSP430InstrInfo::new();
assert_eq!(info.single_operand_ops.len(), 8);
assert_eq!(info.double_operand_ops.len(), 12);
assert_eq!(info.jump_ops.len(), 8);
assert_eq!(info.emulated_ops.len(), 18);
assert_eq!(info.msp430x_ops.len(), 9);
}
}