use std::collections::HashMap;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum ArcRegister {
R0,
R1,
R2,
R3,
R4,
R5,
R6,
R7,
R8,
R9,
R10,
R11,
R12,
R13,
R14,
R15,
R16,
R17,
R18,
R19,
R20,
R21,
R22,
R23,
R24,
R25,
R26,
R27,
R28,
R29,
R30,
R31,
Status32,
Blink,
LpCount,
Pcl,
}
impl ArcRegister {
pub fn index(&self) -> u8 {
match self {
Self::R0 => 0,
Self::R1 => 1,
Self::R2 => 2,
Self::R3 => 3,
Self::R4 => 4,
Self::R5 => 5,
Self::R6 => 6,
Self::R7 => 7,
Self::R8 => 8,
Self::R9 => 9,
Self::R10 => 10,
Self::R11 => 11,
Self::R12 => 12,
Self::R13 => 13,
Self::R14 => 14,
Self::R15 => 15,
Self::R16 => 16,
Self::R17 => 17,
Self::R18 => 18,
Self::R19 => 19,
Self::R20 => 20,
Self::R21 => 21,
Self::R22 => 22,
Self::R23 => 23,
Self::R24 => 24,
Self::R25 => 25,
Self::R26 => 26,
Self::R27 => 27,
Self::R28 => 28,
Self::R29 => 29,
Self::R30 => 30,
Self::R31 => 31,
_ => 0xFF,
}
}
pub fn reg_id(&self) -> u32 {
let base: u32 = 13000;
match self {
Self::R0 => base,
Self::R1 => base + 1,
Self::R2 => base + 2,
Self::R3 => base + 3,
Self::R4 => base + 4,
Self::R5 => base + 5,
Self::R6 => base + 6,
Self::R7 => base + 7,
Self::R8 => base + 8,
Self::R9 => base + 9,
Self::R10 => base + 10,
Self::R11 => base + 11,
Self::R12 => base + 12,
Self::R13 => base + 13,
Self::R14 => base + 14,
Self::R15 => base + 15,
Self::R16 => base + 16,
Self::R17 => base + 17,
Self::R18 => base + 18,
Self::R19 => base + 19,
Self::R20 => base + 20,
Self::R21 => base + 21,
Self::R22 => base + 22,
Self::R23 => base + 23,
Self::R24 => base + 24,
Self::R25 => base + 25,
Self::R26 => base + 26,
Self::R27 => base + 27,
Self::R28 => base + 28,
Self::R29 => base + 29,
Self::R30 => base + 30,
Self::R31 => base + 31,
Self::Status32 => base + 32,
Self::Blink => base + 33,
Self::LpCount => base + 34,
Self::Pcl => base + 35,
}
}
pub fn name(&self) -> &'static str {
match self {
Self::R0 => "r0",
Self::R1 => "r1",
Self::R2 => "r2",
Self::R3 => "r3",
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",
Self::R16 => "r16",
Self::R17 => "r17",
Self::R18 => "r18",
Self::R19 => "r19",
Self::R20 => "r20",
Self::R21 => "r21",
Self::R22 => "r22",
Self::R23 => "r23",
Self::R24 => "r24",
Self::R25 => "r25",
Self::R26 => "r26",
Self::R27 => "r27",
Self::R28 => "r28",
Self::R29 => "r29",
Self::R30 => "r30",
Self::R31 => "r31",
Self::Status32 => "status32",
Self::Blink => "blink",
Self::LpCount => "lp_count",
Self::Pcl => "pcl",
}
}
pub fn is_gpr(&self) -> bool {
matches!(
self,
Self::R0
| Self::R1
| Self::R2
| Self::R3
| Self::R4
| Self::R5
| Self::R6
| Self::R7
| Self::R8
| Self::R9
| Self::R10
| Self::R11
| Self::R12
| Self::R13
| Self::R14
| Self::R15
| Self::R16
| Self::R17
| Self::R18
| Self::R19
| Self::R20
| Self::R21
| Self::R22
| Self::R23
| Self::R24
| Self::R25
| Self::R26
| Self::R27
| Self::R28
| Self::R29
| Self::R30
| Self::R31
)
}
pub fn is_special(&self) -> bool {
!self.is_gpr()
}
}
pub struct ArcCallingConvention {
pub arg_regs: Vec<ArcRegister>,
pub ret_regs: Vec<ArcRegister>,
pub callee_saved: Vec<ArcRegister>,
pub caller_saved: Vec<ArcRegister>,
pub sp: ArcRegister,
pub fp: ArcRegister,
pub lr: ArcRegister,
}
impl ArcCallingConvention {
pub fn new() -> Self {
ArcCallingConvention {
arg_regs: vec![
ArcRegister::R0,
ArcRegister::R1,
ArcRegister::R2,
ArcRegister::R3,
ArcRegister::R4,
ArcRegister::R5,
ArcRegister::R6,
ArcRegister::R7,
],
ret_regs: vec![ArcRegister::R0],
callee_saved: vec![
ArcRegister::R13,
ArcRegister::R14,
ArcRegister::R15,
ArcRegister::R16,
ArcRegister::R17,
ArcRegister::R18,
ArcRegister::R19,
ArcRegister::R20,
ArcRegister::R21,
ArcRegister::R22,
ArcRegister::R23,
ArcRegister::R24,
ArcRegister::R25,
],
caller_saved: vec![
ArcRegister::R0,
ArcRegister::R1,
ArcRegister::R2,
ArcRegister::R3,
ArcRegister::R4,
ArcRegister::R5,
ArcRegister::R6,
ArcRegister::R7,
ArcRegister::R8,
ArcRegister::R9,
ArcRegister::R10,
ArcRegister::R11,
ArcRegister::R12,
ArcRegister::R26,
ArcRegister::R27,
ArcRegister::R28,
ArcRegister::R29,
ArcRegister::R30,
ArcRegister::R31,
],
sp: ArcRegister::R28, fp: ArcRegister::R29, lr: ArcRegister::R31, }
}
}
pub struct ArcTargetMachine {
pub cpu: String,
pub use_short_instructions: bool,
pub has_barrel_shifter: bool,
pub has_multiplier: bool,
pub has_divider: bool,
pub has_norm: bool,
pub has_swap: bool,
pub calling_conv: ArcCallingConvention,
}
impl ArcTargetMachine {
pub fn new(cpu: &str) -> Self {
let (short, barrel, mul, div, norm, swap) = match cpu {
"arc600" => (true, false, false, false, false, false),
"arc700" => (true, true, true, true, true, true),
"archs" => (false, true, true, true, true, true),
"arcem" => (true, true, true, false, true, true),
_ => (true, true, true, true, true, true), };
ArcTargetMachine {
cpu: cpu.to_string(),
use_short_instructions: short,
has_barrel_shifter: barrel,
has_multiplier: mul,
has_divider: div,
has_norm: norm,
has_swap: swap,
calling_conv: ArcCallingConvention::new(),
}
}
pub fn default_target() -> Self {
Self::new("arc700")
}
pub fn get_target_triple(&self) -> String {
format!("{}-none-elf", self.cpu)
}
pub fn get_data_layout(&self) -> String {
"e-m:e-p:32:32-i1:8:32-i8:8:32-i16:16:32-i32:32:32-i64:32:32-f32:32:32-f64:32:32-a:0:32-n32"
.to_string()
}
pub fn get_pointer_size(&self) -> u32 {
32
}
pub fn get_register_width(&self) -> u32 {
32
}
pub fn get_cpu(&self) -> &str {
&self.cpu
}
pub fn get_stack_alignment(&self) -> u32 {
4
}
pub fn get_min_stack_size(&self) -> u32 {
256
}
pub fn has_short_instructions(&self) -> bool {
self.use_short_instructions
}
pub fn has_hardware_mul(&self) -> bool {
self.has_multiplier
}
pub fn has_hardware_div(&self) -> bool {
self.has_divider
}
pub fn get_num_gprs(&self) -> u32 {
32
}
}
impl Default for ArcTargetMachine {
fn default() -> Self {
Self::default_target()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_arc_register_index() {
assert_eq!(ArcRegister::R0.index(), 0);
assert_eq!(ArcRegister::R16.index(), 16);
assert_eq!(ArcRegister::R31.index(), 31);
}
#[test]
fn test_arc_register_ids() {
assert_eq!(ArcRegister::R0.reg_id(), 13000);
assert_eq!(ArcRegister::R31.reg_id(), 13031);
assert_eq!(ArcRegister::Status32.reg_id(), 13032);
assert_eq!(ArcRegister::Blink.reg_id(), 13033);
assert_eq!(ArcRegister::LpCount.reg_id(), 13034);
assert_eq!(ArcRegister::Pcl.reg_id(), 13035);
}
#[test]
fn test_arc_register_name() {
assert_eq!(ArcRegister::R0.name(), "r0");
assert_eq!(ArcRegister::R16.name(), "r16");
assert_eq!(ArcRegister::Status32.name(), "status32");
assert_eq!(ArcRegister::Blink.name(), "blink");
}
#[test]
fn test_arc_register_is_gpr() {
assert!(ArcRegister::R0.is_gpr());
assert!(ArcRegister::R31.is_gpr());
assert!(!ArcRegister::Status32.is_gpr());
assert!(!ArcRegister::Blink.is_gpr());
}
#[test]
fn test_calling_convention_arg_regs() {
let cc = ArcCallingConvention::new();
assert_eq!(cc.arg_regs.len(), 8);
assert_eq!(cc.arg_regs[0], ArcRegister::R0);
assert_eq!(cc.arg_regs[7], ArcRegister::R7);
}
#[test]
fn test_calling_convention_ret_regs() {
let cc = ArcCallingConvention::new();
assert_eq!(cc.ret_regs, vec![ArcRegister::R0]);
}
#[test]
fn test_calling_convention_callee_saved() {
let cc = ArcCallingConvention::new();
assert!(cc.callee_saved.contains(&ArcRegister::R13));
assert!(cc.callee_saved.contains(&ArcRegister::R25));
assert!(!cc.callee_saved.contains(&ArcRegister::R0));
}
#[test]
fn test_arc700_config() {
let tm = ArcTargetMachine::new("arc700");
assert_eq!(tm.cpu, "arc700");
assert!(tm.has_short_instructions());
assert!(tm.has_barrel_shifter);
assert!(tm.has_multiplier);
assert!(tm.has_divider);
}
#[test]
fn test_arc600_config() {
let tm = ArcTargetMachine::new("arc600");
assert!(tm.use_short_instructions);
assert!(!tm.has_barrel_shifter);
assert!(!tm.has_multiplier);
assert!(!tm.has_divider);
}
#[test]
fn test_arcem_config() {
let tm = ArcTargetMachine::new("arcem");
assert!(tm.has_multiplier);
assert!(!tm.has_divider);
}
#[test]
fn test_target_triple() {
let tm = ArcTargetMachine::default_target();
assert_eq!(tm.get_target_triple(), "arc700-none-elf");
}
#[test]
fn test_data_layout() {
let tm = ArcTargetMachine::default_target();
assert!(tm.get_data_layout().contains("p:32:32"));
assert!(tm.get_data_layout().contains("e-m:e"));
}
#[test]
fn test_pointer_size() {
let tm = ArcTargetMachine::default_target();
assert_eq!(tm.get_pointer_size(), 32);
}
#[test]
fn test_register_width() {
let tm = ArcTargetMachine::default_target();
assert_eq!(tm.get_register_width(), 32);
}
#[test]
fn test_stack_alignment() {
let tm = ArcTargetMachine::default_target();
assert_eq!(tm.get_stack_alignment(), 4);
}
#[test]
fn test_min_stack_size() {
let tm = ArcTargetMachine::default_target();
assert_eq!(tm.get_min_stack_size(), 256);
}
#[test]
fn test_num_gprs() {
let tm = ArcTargetMachine::default_target();
assert_eq!(tm.get_num_gprs(), 32);
}
#[test]
fn test_default_cpu_is_arc700() {
let tm = ArcTargetMachine::default_target();
assert_eq!(tm.cpu, "arc700");
}
}