From 6197bfff7249b6dcca9a4a670cd915559a2cec6f Mon Sep 17 00:00:00 2001 From: Jakob Stoklund Olesen Date: Wed, 26 Apr 2017 13:54:40 -0700 Subject: [PATCH] Add a TargetIsa::allocatable_registers() method. This gives the target ISA a chance to reserve registers like the stack pointer or hard-wired 0 registers like %x0 on RISC-V. --- cranelift/filetests/regalloc/basic.cton | 3 ++- lib/cretonne/src/isa/arm32/abi.rs | 6 ++++++ lib/cretonne/src/isa/arm32/mod.rs | 5 +++++ lib/cretonne/src/isa/arm64/abi.rs | 6 ++++++ lib/cretonne/src/isa/arm64/mod.rs | 5 +++++ lib/cretonne/src/isa/intel/abi.rs | 6 ++++++ lib/cretonne/src/isa/intel/mod.rs | 5 +++++ lib/cretonne/src/isa/mod.rs | 21 ++++++++++++++------- lib/cretonne/src/isa/riscv/abi.rs | 24 ++++++++++++++++++++++-- lib/cretonne/src/isa/riscv/mod.rs | 19 ++++++++++++------- lib/cretonne/src/regalloc/coloring.rs | 3 +-- lib/cretonne/src/regalloc/mod.rs | 1 + 12 files changed, 85 insertions(+), 19 deletions(-) diff --git a/cranelift/filetests/regalloc/basic.cton b/cranelift/filetests/regalloc/basic.cton index cbff589431..3fc58dabd9 100644 --- a/cranelift/filetests/regalloc/basic.cton +++ b/cranelift/filetests/regalloc/basic.cton @@ -6,7 +6,8 @@ isa riscv function add(i32, i32) { ebb0(v1: i32, v2: i32): v3 = iadd v1, v2 -; check: [R#0c,%x0] +; TODO: This shouldn't clobber the link register. +; check: [R#0c,%x1] ; sameln: iadd return } diff --git a/lib/cretonne/src/isa/arm32/abi.rs b/lib/cretonne/src/isa/arm32/abi.rs index c4e0ffc2ee..93ae0e7e61 100644 --- a/lib/cretonne/src/isa/arm32/abi.rs +++ b/lib/cretonne/src/isa/arm32/abi.rs @@ -2,6 +2,7 @@ use ir; use isa::RegClass; +use regalloc::AllocatableSet; use settings as shared_settings; use super::registers::{S, D, Q, GPR}; @@ -25,3 +26,8 @@ pub fn regclass_for_abi_type(ty: ir::Type) -> RegClass { } } } + +/// Get the set of allocatable registers for `func`. +pub fn allocatable_registers(_func: &ir::Function) -> AllocatableSet { + unimplemented!() +} diff --git a/lib/cretonne/src/isa/arm32/mod.rs b/lib/cretonne/src/isa/arm32/mod.rs index 735fcd4b2c..ec9de51917 100644 --- a/lib/cretonne/src/isa/arm32/mod.rs +++ b/lib/cretonne/src/isa/arm32/mod.rs @@ -12,6 +12,7 @@ use isa::enc_tables::{self as shared_enc_tables, lookup_enclist, general_encodin use isa::Builder as IsaBuilder; use isa::{TargetIsa, RegInfo, RegClass, EncInfo, Encoding, Legalize}; use ir; +use regalloc; #[allow(dead_code)] struct Isa { @@ -86,6 +87,10 @@ impl TargetIsa for Isa { abi::regclass_for_abi_type(ty) } + fn allocatable_registers(&self, func: &ir::Function) -> regalloc::AllocatableSet { + abi::allocatable_registers(func) + } + fn emit_inst(&self, func: &ir::Function, inst: ir::Inst, sink: &mut CodeSink) { binemit::emit_inst(func, inst, sink) } diff --git a/lib/cretonne/src/isa/arm64/abi.rs b/lib/cretonne/src/isa/arm64/abi.rs index 8c2e9ed7d6..f5a2dc91c7 100644 --- a/lib/cretonne/src/isa/arm64/abi.rs +++ b/lib/cretonne/src/isa/arm64/abi.rs @@ -2,6 +2,7 @@ use ir; use isa::RegClass; +use regalloc::AllocatableSet; use settings as shared_settings; use super::registers::{GPR, FPR}; @@ -16,3 +17,8 @@ pub fn legalize_signature(_sig: &mut ir::Signature, pub fn regclass_for_abi_type(ty: ir::Type) -> RegClass { if ty.is_int() { GPR } else { FPR } } + +/// Get the set of allocatable registers for `func`. +pub fn allocatable_registers(_func: &ir::Function) -> AllocatableSet { + unimplemented!() +} diff --git a/lib/cretonne/src/isa/arm64/mod.rs b/lib/cretonne/src/isa/arm64/mod.rs index 91a8a50f4e..4067142f57 100644 --- a/lib/cretonne/src/isa/arm64/mod.rs +++ b/lib/cretonne/src/isa/arm64/mod.rs @@ -12,6 +12,7 @@ use isa::enc_tables::{lookup_enclist, general_encoding}; use isa::Builder as IsaBuilder; use isa::{TargetIsa, RegInfo, RegClass, EncInfo, Encoding, Legalize}; use ir; +use regalloc; #[allow(dead_code)] struct Isa { @@ -79,6 +80,10 @@ impl TargetIsa for Isa { abi::regclass_for_abi_type(ty) } + fn allocatable_registers(&self, func: &ir::Function) -> regalloc::AllocatableSet { + abi::allocatable_registers(func) + } + fn emit_inst(&self, func: &ir::Function, inst: ir::Inst, sink: &mut CodeSink) { binemit::emit_inst(func, inst, sink) } diff --git a/lib/cretonne/src/isa/intel/abi.rs b/lib/cretonne/src/isa/intel/abi.rs index 437925cd40..e6c5edd5bf 100644 --- a/lib/cretonne/src/isa/intel/abi.rs +++ b/lib/cretonne/src/isa/intel/abi.rs @@ -2,6 +2,7 @@ use ir; use isa::RegClass; +use regalloc::AllocatableSet; use settings as shared_settings; use super::registers::{GPR, FPR}; @@ -16,3 +17,8 @@ pub fn legalize_signature(_sig: &mut ir::Signature, pub fn regclass_for_abi_type(ty: ir::Type) -> RegClass { if ty.is_int() { GPR } else { FPR } } + +/// Get the set of allocatable registers for `func`. +pub fn allocatable_registers(_func: &ir::Function) -> AllocatableSet { + unimplemented!() +} diff --git a/lib/cretonne/src/isa/intel/mod.rs b/lib/cretonne/src/isa/intel/mod.rs index 768150eb50..1812a41354 100644 --- a/lib/cretonne/src/isa/intel/mod.rs +++ b/lib/cretonne/src/isa/intel/mod.rs @@ -12,6 +12,7 @@ use isa::enc_tables::{self as shared_enc_tables, lookup_enclist, general_encodin use isa::Builder as IsaBuilder; use isa::{TargetIsa, RegInfo, RegClass, EncInfo, Encoding, Legalize}; use ir; +use regalloc; #[allow(dead_code)] struct Isa { @@ -86,6 +87,10 @@ impl TargetIsa for Isa { abi::regclass_for_abi_type(ty) } + fn allocatable_registers(&self, func: &ir::Function) -> regalloc::AllocatableSet { + abi::allocatable_registers(func) + } + fn emit_inst(&self, func: &ir::Function, inst: ir::Inst, sink: &mut CodeSink) { binemit::emit_inst(func, inst, sink) } diff --git a/lib/cretonne/src/isa/mod.rs b/lib/cretonne/src/isa/mod.rs index bd9e0caf9a..4b618e0798 100644 --- a/lib/cretonne/src/isa/mod.rs +++ b/lib/cretonne/src/isa/mod.rs @@ -46,7 +46,8 @@ pub use isa::registers::{RegInfo, RegUnit, RegClass, RegClassIndex}; use binemit::CodeSink; use settings; -use ir::{Function, Inst, InstructionData, DataFlowGraph, Signature, Type}; +use ir; +use regalloc; pub mod riscv; pub mod intel; @@ -142,9 +143,9 @@ pub trait TargetIsa { /// /// This is also the main entry point for determining if an instruction is legal. fn encode(&self, - dfg: &DataFlowGraph, - inst: &InstructionData, - ctrl_typevar: Type) + dfg: &ir::DataFlowGraph, + inst: &ir::InstructionData, + ctrl_typevar: ir::Type) -> Result; /// Get a data structure describing the instruction encodings in this ISA. @@ -183,7 +184,7 @@ pub trait TargetIsa { /// Arguments and return values for the caller's frame pointer and other callee-saved registers /// should not be added by this function. These arguments are not added until after register /// allocation. - fn legalize_signature(&self, sig: &mut Signature, current: bool); + fn legalize_signature(&self, sig: &mut ir::Signature, current: bool); /// Get the register class that should be used to represent an ABI argument or return value of /// type `ty`. This should be the top-level register class that contains the argument @@ -191,13 +192,19 @@ pub trait TargetIsa { /// /// This function can assume that it will only be asked to provide register classes for types /// that `legalize_signature()` produces in `ArgumentLoc::Reg` entries. - fn regclass_for_abi_type(&self, ty: Type) -> RegClass; + fn regclass_for_abi_type(&self, ty: ir::Type) -> RegClass; + + /// Get the set of allocatable registers that can be used when compiling `func`. + /// + /// This set excludes reserved registers like the stack pointer and other special-purpose + /// registers. + fn allocatable_registers(&self, func: &ir::Function) -> regalloc::AllocatableSet; /// Emit binary machine code for a single instruction into the `sink` trait object. /// /// Note that this will call `put*` methods on the trait object via its vtable which is not the /// fastest way of emitting code. - fn emit_inst(&self, func: &Function, inst: Inst, sink: &mut CodeSink); + fn emit_inst(&self, func: &ir::Function, inst: ir::Inst, sink: &mut CodeSink); /// Get a static array of names associated with relocations in this ISA. /// diff --git a/lib/cretonne/src/isa/riscv/abi.rs b/lib/cretonne/src/isa/riscv/abi.rs index 0df3806529..ab9e485ed5 100644 --- a/lib/cretonne/src/isa/riscv/abi.rs +++ b/lib/cretonne/src/isa/riscv/abi.rs @@ -6,8 +6,9 @@ //! This doesn't support the soft-float ABI at the moment. use abi::{ArgAction, ValueConversion, ArgAssigner, legalize_args}; -use ir::{Signature, Type, ArgumentType, ArgumentLoc, ArgumentExtension, ArgumentPurpose}; +use ir::{self, Type, ArgumentType, ArgumentLoc, ArgumentExtension, ArgumentPurpose}; use isa::RegClass; +use regalloc::AllocatableSet; use settings as shared_settings; use super::registers::{GPR, FPR}; use super::settings; @@ -84,7 +85,7 @@ impl ArgAssigner for Args { } /// Legalize `sig` for RISC-V. -pub fn legalize_signature(sig: &mut Signature, +pub fn legalize_signature(sig: &mut ir::Signature, flags: &shared_settings::Flags, isa_flags: &settings::Flags, current: bool) { @@ -114,3 +115,22 @@ pub fn legalize_signature(sig: &mut Signature, pub fn regclass_for_abi_type(ty: Type) -> RegClass { if ty.is_float() { FPR } else { GPR } } + +pub fn allocatable_registers(_func: &ir::Function, isa_flags: &settings::Flags) -> AllocatableSet { + let mut regs = AllocatableSet::new(); + regs.take(GPR, GPR.unit(0)); // Hard-wired 0. + // %x1 is the link register which is available for allocation. + regs.take(GPR, GPR.unit(2)); // Stack pointer. + regs.take(GPR, GPR.unit(3)); // Global pointer. + regs.take(GPR, GPR.unit(4)); // Thread pointer. + // TODO: %x8 is the frame pointer. Reserve it? + + // Remove %x16 and up for RV32E. + if isa_flags.enable_e() { + for u in 16..32 { + regs.take(GPR, GPR.unit(u)); + } + } + + regs +} diff --git a/lib/cretonne/src/isa/riscv/mod.rs b/lib/cretonne/src/isa/riscv/mod.rs index fe267ae870..cf5aafc7db 100644 --- a/lib/cretonne/src/isa/riscv/mod.rs +++ b/lib/cretonne/src/isa/riscv/mod.rs @@ -11,7 +11,8 @@ use binemit::CodeSink; use isa::enc_tables::{self as shared_enc_tables, lookup_enclist, general_encoding}; use isa::Builder as IsaBuilder; use isa::{TargetIsa, RegInfo, RegClass, EncInfo, Encoding, Legalize}; -use ir::{Function, Inst, InstructionData, DataFlowGraph, Signature, Type}; +use ir; +use regalloc; #[allow(dead_code)] struct Isa { @@ -61,9 +62,9 @@ impl TargetIsa for Isa { } fn encode(&self, - _dfg: &DataFlowGraph, - inst: &InstructionData, - ctrl_typevar: Type) + _dfg: &ir::DataFlowGraph, + inst: &ir::InstructionData, + ctrl_typevar: ir::Type) -> Result { lookup_enclist(ctrl_typevar, inst.opcode(), @@ -78,15 +79,19 @@ impl TargetIsa for Isa { }) } - fn legalize_signature(&self, sig: &mut Signature, current: bool) { + fn legalize_signature(&self, sig: &mut ir::Signature, current: bool) { abi::legalize_signature(sig, &self.shared_flags, &self.isa_flags, current) } - fn regclass_for_abi_type(&self, ty: Type) -> RegClass { + fn regclass_for_abi_type(&self, ty: ir::Type) -> RegClass { abi::regclass_for_abi_type(ty) } - fn emit_inst(&self, func: &Function, inst: Inst, sink: &mut CodeSink) { + fn allocatable_registers(&self, func: &ir::Function) -> regalloc::AllocatableSet { + abi::allocatable_registers(func, &self.isa_flags) + } + + fn emit_inst(&self, func: &ir::Function, inst: ir::Inst, sink: &mut CodeSink) { binemit::emit_inst(func, inst, sink) } diff --git a/lib/cretonne/src/regalloc/coloring.rs b/lib/cretonne/src/regalloc/coloring.rs index 84e81660d7..f1fc2348ad 100644 --- a/lib/cretonne/src/regalloc/coloring.rs +++ b/lib/cretonne/src/regalloc/coloring.rs @@ -101,8 +101,7 @@ impl Coloring { encinfo: isa.encoding_info(), domtree: domtree, liveness: liveness, - // TODO: Ask the target ISA about reserved registers etc. - usable_regs: AllocatableSet::new(), + usable_regs: isa.allocatable_registers(func), }; ctx.run(self, func, tracker) } diff --git a/lib/cretonne/src/regalloc/mod.rs b/lib/cretonne/src/regalloc/mod.rs index fb19286670..0682be2fd6 100644 --- a/lib/cretonne/src/regalloc/mod.rs +++ b/lib/cretonne/src/regalloc/mod.rs @@ -11,4 +11,5 @@ pub mod coloring; mod affinity; mod context; +pub use self::allocatable_set::AllocatableSet; pub use self::context::Context;