[codegen] Add a pinned register that's entirely under the control of the user;

This commit is contained in:
Benjamin Bouvier
2019-08-28 17:33:45 +02:00
parent d1d2e790b9
commit 660b8b28b8
15 changed files with 229 additions and 30 deletions

View File

@@ -11,6 +11,7 @@ pub struct RegBank {
pub names: Vec<&'static str>,
pub prefix: &'static str,
pub pressure_tracking: bool,
pub pinned_reg: Option<u16>,
pub toprcs: Vec<RegClassIndex>,
pub classes: Vec<RegClassIndex>,
}
@@ -23,6 +24,7 @@ impl RegBank {
names: Vec<&'static str>,
prefix: &'static str,
pressure_tracking: bool,
pinned_reg: Option<u16>,
) -> Self {
RegBank {
name,
@@ -31,6 +33,7 @@ impl RegBank {
names,
prefix,
pressure_tracking,
pinned_reg,
toprcs: Vec::new(),
classes: Vec::new(),
}
@@ -183,6 +186,7 @@ pub struct RegBankBuilder {
pub names: Vec<&'static str>,
pub prefix: &'static str,
pub pressure_tracking: Option<bool>,
pub pinned_reg: Option<u16>,
}
impl RegBankBuilder {
@@ -193,6 +197,7 @@ impl RegBankBuilder {
names: vec![],
prefix,
pressure_tracking: None,
pinned_reg: None,
}
}
pub fn units(mut self, units: u8) -> Self {
@@ -207,6 +212,11 @@ impl RegBankBuilder {
self.pressure_tracking = Some(track);
self
}
pub fn pinned_reg(mut self, unit: u16) -> Self {
assert!(unit < (self.units as u16));
self.pinned_reg = Some(unit);
self
}
}
pub struct IsaRegsBuilder {
@@ -246,6 +256,7 @@ impl IsaRegsBuilder {
builder
.pressure_tracking
.expect("Pressure tracking must be explicitly set"),
builder.pinned_reg,
))
}

View File

@@ -56,6 +56,7 @@ fn gen_regclass(isa: &TargetIsa, reg_class: &RegClass, fmt: &mut Formatter) {
fmtln!(fmt, "first: {},", reg_bank.first_unit + reg_class.start);
fmtln!(fmt, "subclasses: {:#x},", reg_class.subclass_mask());
fmtln!(fmt, "mask: [{}],", mask);
fmtln!(fmt, "pinned_reg: {:?},", reg_bank.pinned_reg);
fmtln!(fmt, "info: &INFO,");
});
fmtln!(fmt, "};");

View File

@@ -372,6 +372,7 @@ pub(crate) fn define(
let fpromote = shared.by_name("fpromote");
let fsub = shared.by_name("fsub");
let func_addr = shared.by_name("func_addr");
let get_pinned_reg = shared.by_name("get_pinned_reg");
let iadd = shared.by_name("iadd");
let iadd_cout = shared.by_name("iadd_cout");
let iadd_cin = shared.by_name("iadd_cin");
@@ -421,6 +422,7 @@ pub(crate) fn define(
let scalar_to_vector = shared.by_name("scalar_to_vector");
let selectif = shared.by_name("selectif");
let sextend = shared.by_name("sextend");
let set_pinned_reg = shared.by_name("set_pinned_reg");
let sload16 = shared.by_name("sload16");
let sload16_complex = shared.by_name("sload16_complex");
let sload32 = shared.by_name("sload32");
@@ -516,6 +518,7 @@ pub(crate) fn define(
let rec_furm = r.template("furm");
let rec_furm_reg_to_ssa = r.template("furm_reg_to_ssa");
let rec_furmi_rnd = r.template("furmi_rnd");
let rec_get_pinned_reg = r.recipe("get_pinned_reg");
let rec_got_fnaddr8 = r.template("got_fnaddr8");
let rec_got_gvaddr8 = r.template("got_gvaddr8");
let rec_gvaddr4 = r.template("gvaddr4");
@@ -569,6 +572,7 @@ pub(crate) fn define(
let rec_safepoint = r.recipe("safepoint");
let rec_setf_abcd = r.template("setf_abcd");
let rec_seti_abcd = r.template("seti_abcd");
let rec_set_pinned_reg = r.template("set_pinned_reg");
let rec_spaddr4_id = r.template("spaddr4_id");
let rec_spaddr8_id = r.template("spaddr8_id");
let rec_spillSib32 = r.template("spillSib32");
@@ -619,6 +623,13 @@ pub(crate) fn define(
// Definitions.
let mut e = PerCpuModeEncodings::new();
// The pinned reg is fixed to a certain value entirely user-controlled, so it generates nothing!
e.enc64_rec(get_pinned_reg.bind(I64), rec_get_pinned_reg, 0);
e.enc_x86_64(
set_pinned_reg.bind(I64),
rec_set_pinned_reg.opcodes(vec![0x89]).rex().w(),
);
e.enc_i32_i64(iadd, rec_rr.opcodes(vec![0x01]));
e.enc_i32_i64(iadd_cout, rec_rr.opcodes(vec![0x01]));
e.enc_i32_i64(iadd_cin, rec_rin.opcodes(vec![0x11]));

View File

@@ -351,6 +351,7 @@ pub(crate) fn define<'shared>(
let reg_rax = Register::new(gpr, regs.regunit_by_name(gpr, "rax"));
let reg_rcx = Register::new(gpr, regs.regunit_by_name(gpr, "rcx"));
let reg_rdx = Register::new(gpr, regs.regunit_by_name(gpr, "rdx"));
let reg_r15 = Register::new(gpr, regs.regunit_by_name(gpr, "r15"));
// Stack operand with a 32-bit signed displacement from either RBP or RSP.
let stack_gpr32 = Stack::new(gpr);
@@ -428,6 +429,25 @@ pub(crate) fn define<'shared>(
.emit(""),
);
recipes.add_recipe(
EncodingRecipeBuilder::new("get_pinned_reg", f_nullary, 0)
.operands_out(vec![reg_r15])
.emit(""),
);
// umr with a fixed register output that's r15.
recipes.add_template_recipe(
EncodingRecipeBuilder::new("set_pinned_reg", f_unary, 1)
.operands_in(vec![gpr])
.clobbers_flags(false)
.emit(
r#"
let r15 = RU::r15.into();
{{PUT_OP}}(bits, rex2(r15, in_reg0), sink);
modrm_rr(r15, in_reg0, sink);
"#,
),
);
// No-op fills, created by late-stage redundant-fill removal.
recipes.add_recipe(
EncodingRecipeBuilder::new("fillnull", f_unary, 0)

View File

@@ -6,7 +6,8 @@ pub fn define() -> IsaRegs {
let builder = RegBankBuilder::new("IntRegs", "r")
.units(16)
.names(vec!["rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi"])
.track_pressure(true);
.track_pressure(true)
.pinned_reg(15);
let int_regs = regs.add_bank(builder);
let builder = RegBankBuilder::new("FloatRegs", "xmm")

View File

@@ -964,6 +964,34 @@ pub(crate) fn define(
.operands_out(vec![addr]),
);
// Note this instruction is marked as having other side-effects, so GVN won't try to hoist it,
// which would result in it being subject to spilling. While not hoisting would generally hurt
// performance, since a computed value used many times may need to be regenerated before each
// use, it is not the case here: this instruction doesn't generate any code. That's because,
// by definition the pinned register is never used by the register allocator, but is written to
// and read explicitly and exclusively by set_pinned_reg and get_pinned_reg.
ig.push(
Inst::new(
"get_pinned_reg",
r#"
Gets the content of the pinned register, when it's enabled.
"#,
)
.operands_out(vec![addr])
.other_side_effects(true),
);
ig.push(
Inst::new(
"set_pinned_reg",
r#"
Sets the content of the pinned register, when it's enabled.
"#,
)
.operands_in(vec![addr])
.other_side_effects(true),
);
let TableOffset = &TypeVar::new(
"TableOffset",
"An unsigned table offset",

View File

@@ -84,6 +84,17 @@ pub fn define() -> SettingGroup {
false,
);
settings.add_bool(
"enable_pinned_reg",
r#"Enable the use of the pinned register.
This register is excluded from register allocation, and is completely under the control of
the end-user. It is possible to read it via the get_pinned_reg instruction, and to set it
with the set_pinned_reg instruction.
"#,
false,
);
settings.add_bool("enable_simd", "Enable the use of SIMD instructions.", false);
settings.add_bool(