1 //! Generate the ISA-specific registers.
2 use crate::cdsl::isa::TargetIsa;
3 use crate::cdsl::regs::{RegBank, RegClass};
4 use crate::error;
5 use crate::srcgen::Formatter;
6 use cranelift_entity::EntityRef;
7 
gen_regbank(fmt: &mut Formatter, reg_bank: &RegBank)8 fn gen_regbank(fmt: &mut Formatter, reg_bank: &RegBank) {
9     let names = if !reg_bank.names.is_empty() {
10         format!(r#""{}""#, reg_bank.names.join(r#"", ""#))
11     } else {
12         "".to_string()
13     };
14     fmtln!(fmt, "RegBank {");
15     fmt.indent(|fmt| {
16         fmtln!(fmt, r#"name: "{}","#, reg_bank.name);
17         fmtln!(fmt, "first_unit: {},", reg_bank.first_unit);
18         fmtln!(fmt, "units: {},", reg_bank.units);
19         fmtln!(fmt, "names: &[{}],", names);
20         fmtln!(fmt, r#"prefix: "{}","#, reg_bank.prefix);
21         fmtln!(fmt, "first_toprc: {},", reg_bank.toprcs[0].index());
22         fmtln!(fmt, "num_toprcs: {},", reg_bank.toprcs.len());
23         fmtln!(
24             fmt,
25             "pressure_tracking: {},",
26             if reg_bank.pressure_tracking {
27                 "true"
28             } else {
29                 "false"
30             }
31         );
32     });
33     fmtln!(fmt, "},");
34 }
35 
gen_regclass(isa: &TargetIsa, reg_class: &RegClass, fmt: &mut Formatter)36 fn gen_regclass(isa: &TargetIsa, reg_class: &RegClass, fmt: &mut Formatter) {
37     let reg_bank = isa.regs.banks.get(reg_class.bank).unwrap();
38 
39     let mask: Vec<String> = reg_class
40         .mask(reg_bank.first_unit)
41         .iter()
42         .map(|x| format!("0x{:08x}", x))
43         .collect();
44     let mask = mask.join(", ");
45 
46     fmtln!(
47         fmt,
48         "pub static {}_DATA: RegClassData = RegClassData {{",
49         reg_class.name
50     );
51     fmt.indent(|fmt| {
52         fmtln!(fmt, r#"name: "{}","#, reg_class.name);
53         fmtln!(fmt, "index: {},", reg_class.index.index());
54         fmtln!(fmt, "width: {},", reg_class.width);
55         fmtln!(fmt, "bank: {},", reg_class.bank.index());
56         fmtln!(fmt, "toprc: {},", reg_class.toprc.index());
57         fmtln!(fmt, "first: {},", reg_bank.first_unit + reg_class.start);
58         fmtln!(fmt, "subclasses: {:#x},", reg_class.subclass_mask());
59         fmtln!(fmt, "mask: [{}],", mask);
60         fmtln!(
61             fmt,
62             "pinned_reg: {:?},",
63             reg_bank
64                 .pinned_reg
65                 .map(|index| index + reg_bank.first_unit as u16 + reg_class.start as u16)
66         );
67         fmtln!(fmt, "info: &INFO,");
68     });
69     fmtln!(fmt, "};");
70 
71     fmtln!(fmt, "#[allow(dead_code)]");
72     fmtln!(
73         fmt,
74         "pub static {}: RegClass = &{}_DATA;",
75         reg_class.name,
76         reg_class.name
77     );
78 }
79 
gen_regbank_units(reg_bank: &RegBank, fmt: &mut Formatter)80 fn gen_regbank_units(reg_bank: &RegBank, fmt: &mut Formatter) {
81     for unit in 0..reg_bank.units {
82         let v = unit + reg_bank.first_unit;
83         if (unit as usize) < reg_bank.names.len() {
84             fmtln!(fmt, "{} = {},", reg_bank.names[unit as usize], v);
85             continue;
86         }
87         fmtln!(fmt, "{}{} = {},", reg_bank.prefix, unit, v);
88     }
89 }
90 
gen_isa(isa: &TargetIsa, fmt: &mut Formatter)91 fn gen_isa(isa: &TargetIsa, fmt: &mut Formatter) {
92     // Emit RegInfo.
93     fmtln!(fmt, "pub static INFO: RegInfo = RegInfo {");
94 
95     fmt.indent(|fmt| {
96         fmtln!(fmt, "banks: &[");
97         // Bank descriptors.
98         fmt.indent(|fmt| {
99             for reg_bank in isa.regs.banks.values() {
100                 gen_regbank(fmt, &reg_bank);
101             }
102         });
103         fmtln!(fmt, "],");
104         // References to register classes.
105         fmtln!(fmt, "classes: &[");
106         fmt.indent(|fmt| {
107             for reg_class in isa.regs.classes.values() {
108                 fmtln!(fmt, "&{}_DATA,", reg_class.name);
109             }
110         });
111         fmtln!(fmt, "],");
112     });
113     fmtln!(fmt, "};");
114 
115     // Register class descriptors.
116     for rc in isa.regs.classes.values() {
117         gen_regclass(&isa, rc, fmt);
118     }
119 
120     // Emit constants for all the register units.
121     fmtln!(fmt, "#[allow(dead_code, non_camel_case_types)]");
122     fmtln!(fmt, "#[derive(Clone, Copy)]");
123     fmtln!(fmt, "pub enum RU {");
124     fmt.indent(|fmt| {
125         for reg_bank in isa.regs.banks.values() {
126             gen_regbank_units(reg_bank, fmt);
127         }
128     });
129     fmtln!(fmt, "}");
130 
131     // Emit Into conversion for the RU class.
132     fmtln!(fmt, "impl Into<RegUnit> for RU {");
133     fmt.indent(|fmt| {
134         fmtln!(fmt, "fn into(self) -> RegUnit {");
135         fmt.indent(|fmt| {
136             fmtln!(fmt, "self as RegUnit");
137         });
138         fmtln!(fmt, "}");
139     });
140     fmtln!(fmt, "}");
141 }
142 
generate(isa: &TargetIsa, filename: &str, out_dir: &str) -> Result<(), error::Error>143 pub(crate) fn generate(isa: &TargetIsa, filename: &str, out_dir: &str) -> Result<(), error::Error> {
144     let mut fmt = Formatter::new();
145     gen_isa(&isa, &mut fmt);
146     fmt.update_file(filename, out_dir)?;
147     Ok(())
148 }
149