diff --git a/cranelift/filetests/isa/intel/prologue-epilogue.cton b/cranelift/filetests/isa/intel/prologue-epilogue.cton
index cd774fe6bd..416f90df63 100644
--- a/cranelift/filetests/isa/intel/prologue-epilogue.cton
+++ b/cranelift/filetests/isa/intel/prologue-epilogue.cton
@@ -3,30 +3,206 @@ set is_64bit
set is_compressed
isa intel haswell
-function %foo() {
+; An empty function.
+
+function %empty() {
+ebb0:
+ return
+}
+
+; check: function %empty(i64 fp [%rbp]) -> i64 fp [%rbp] system_v {
+; nextln: ss0 = incoming_arg 16, offset -16
+; nextln:
+; nextln: ebb0(v0: i64 [%rbp]):
+; nextln: x86_push v0
+; nextln: copy_special %rsp -> %rbp
+; nextln: v1 = x86_pop.i64
+; nextln: return v1
+; nextln: }
+
+; A function with a single stack slot.
+
+function %one_stack_slot() {
ss0 = explicit_slot 168
ebb0:
return
}
-; check: function %foo(i64 fp [%rbp], i64 csr [%rbx], i64 csr [%r12], i64 csr [%r13], i64 csr [%r14], i64 csr [%r15]) -> i64 fp [%rbp], i64 csr [%rbx], i64 csr [%r12], i64 csr [%r13], i64 csr [%r14], i64 csr [%r15] system_v {
-; nextln: ss0 = explicit_slot 168, offset -224
-; nextln: ss1 = incoming_arg 56, offset -56
-; check: ebb0(v0: i64 [%rbp], v1: i64 [%rbx], v2: i64 [%r12], v3: i64 [%r13], v4: i64 [%r14], v5: i64 [%r15]):
+; check: function %one_stack_slot(i64 fp [%rbp]) -> i64 fp [%rbp] system_v {
+; nextln: ss0 = explicit_slot 168, offset -184
+; nextln: ss1 = incoming_arg 16, offset -16
+; nextln:
+; nextln: ebb0(v0: i64 [%rbp]):
; nextln: x86_push v0
; nextln: copy_special %rsp -> %rbp
-; nextln: x86_push v1
-; nextln: x86_push v2
-; nextln: x86_push v3
-; nextln: x86_push v4
-; nextln: x86_push v5
-; nextln: adjust_sp_imm -168
-; nextln: adjust_sp_imm 168
-; nextln: v11 = x86_pop.i64
-; nextln: v10 = x86_pop.i64
-; nextln: v9 = x86_pop.i64
-; nextln: v8 = x86_pop.i64
-; nextln: v7 = x86_pop.i64
-; nextln: v6 = x86_pop.i64
-; nextln: return v6, v7, v8, v9, v10, v11
+; nextln: adjust_sp_imm -176
+; nextln: adjust_sp_imm 176
+; nextln: v1 = x86_pop.i64
+; nextln: return v1
+; nextln: }
+
+; A function performing a call.
+
+function %call() {
+ fn0 = function %foo()
+
+ebb0:
+ call fn0()
+ return
+}
+
+; check: function %call(i64 fp [%rbp]) -> i64 fp [%rbp] system_v {
+; nextln: ss0 = incoming_arg 16, offset -16
+; nextln: sig0 = () system_v
+; nextln: fn0 = sig0 %foo
+; nextln:
+; nextln: ebb0(v0: i64 [%rbp]):
+; nextln: x86_push v0
+; nextln: copy_special %rsp -> %rbp
+; nextln: call fn0()
+; nextln: v1 = x86_pop.i64
+; nextln: return v1
+; nextln: }
+
+; A function that uses a lot of registers but doesn't quite need to spill.
+
+function %no_spill(i64, i64) {
+ebb0(v0: i64, v1: i64):
+ v2 = load.i32 v0+0
+ v3 = load.i32 v0+8
+ v4 = load.i32 v0+16
+ v5 = load.i32 v0+24
+ v6 = load.i32 v0+32
+ v7 = load.i32 v0+40
+ v8 = load.i32 v0+48
+ v9 = load.i32 v0+56
+ v10 = load.i32 v0+64
+ v11 = load.i32 v0+72
+ v12 = load.i32 v0+80
+ v13 = load.i32 v0+88
+ v14 = load.i32 v0+96
+ store.i32 v2, v1+0
+ store.i32 v3, v1+8
+ store.i32 v4, v1+16
+ store.i32 v5, v1+24
+ store.i32 v6, v1+32
+ store.i32 v7, v1+40
+ store.i32 v8, v1+48
+ store.i32 v9, v1+56
+ store.i32 v10, v1+64
+ store.i32 v11, v1+72
+ store.i32 v12, v1+80
+ store.i32 v13, v1+88
+ store.i32 v14, v1+96
+ return
+}
+
+; check: function %no_spill(i64 [%rdi], i64 [%rsi], i64 fp [%rbp], i64 csr [%rbx], i64 csr [%r12], i64 csr [%r13], i64 csr [%r14], i64 csr [%r15]) -> i64 fp [%rbp], i64 csr [%rbx], i64 csr [%r12], i64 csr [%r13], i64 csr [%r14], i64 csr [%r15] system_v {
+; nextln: ss0 = incoming_arg 56, offset -56
+; nextln:
+; nextln: ebb0(v0: i64 [%rdi], v1: i64 [%rsi], v15: i64 [%rbp], v16: i64 [%rbx], v17: i64 [%r12], v18: i64 [%r13], v19: i64 [%r14], v20: i64 [%r15]):
+; nextln: x86_push v15
+; nextln: copy_special %rsp -> %rbp
+; nextln: x86_push v16
+; nextln: x86_push v17
+; nextln: x86_push v18
+; nextln: x86_push v19
+; nextln: x86_push v20
+; nextln: adjust_sp_imm -8
+; nextln: v2 = load.i32 v0
+; nextln: v3 = load.i32 v0+8
+; nextln: v4 = load.i32 v0+16
+; nextln: v5 = load.i32 v0+24
+; nextln: v6 = load.i32 v0+32
+; nextln: v7 = load.i32 v0+40
+; nextln: v8 = load.i32 v0+48
+; nextln: v9 = load.i32 v0+56
+; nextln: v10 = load.i32 v0+64
+; nextln: v11 = load.i32 v0+72
+; nextln: v12 = load.i32 v0+80
+; nextln: v13 = load.i32 v0+88
+; nextln: v14 = load.i32 v0+96
+; nextln: store v2, v1
+; nextln: store v3, v1+8
+; nextln: store v4, v1+16
+; nextln: store v5, v1+24
+; nextln: store v6, v1+32
+; nextln: store v7, v1+40
+; nextln: store v8, v1+48
+; nextln: store v9, v1+56
+; nextln: store v10, v1+64
+; nextln: store v11, v1+72
+; nextln: store v12, v1+80
+; nextln: store v13, v1+88
+; nextln: store v14, v1+96
+; nextln: adjust_sp_imm 8
+; nextln: v26 = x86_pop.i64
+; nextln: v25 = x86_pop.i64
+; nextln: v24 = x86_pop.i64
+; nextln: v23 = x86_pop.i64
+; nextln: v22 = x86_pop.i64
+; nextln: v21 = x86_pop.i64
+; nextln: return v21, v22, v23, v24, v25, v26
+; nextln: }
+
+; This function requires too many registers and must spill.
+
+function %yes_spill(i64, i64) {
+ebb0(v0: i64, v1: i64):
+ v2 = load.i32 v0+0
+ v3 = load.i32 v0+8
+ v4 = load.i32 v0+16
+ v5 = load.i32 v0+24
+ v6 = load.i32 v0+32
+ v7 = load.i32 v0+40
+ v8 = load.i32 v0+48
+ v9 = load.i32 v0+56
+ v10 = load.i32 v0+64
+ v11 = load.i32 v0+72
+ v12 = load.i32 v0+80
+ v13 = load.i32 v0+88
+ v14 = load.i32 v0+96
+ v15 = load.i32 v0+104
+ store.i32 v2, v1+0
+ store.i32 v3, v1+8
+ store.i32 v4, v1+16
+ store.i32 v5, v1+24
+ store.i32 v6, v1+32
+ store.i32 v7, v1+40
+ store.i32 v8, v1+48
+ store.i32 v9, v1+56
+ store.i32 v10, v1+64
+ store.i32 v11, v1+72
+ store.i32 v12, v1+80
+ store.i32 v13, v1+88
+ store.i32 v14, v1+96
+ store.i32 v15, v1+104
+ return
+}
+
+; check: function %yes_spill(i64 [%rdi], i64 [%rsi], i64 fp [%rbp], i64 csr [%rbx], i64 csr [%r12], i64 csr [%r13], i64 csr [%r14], i64 csr [%r15]) -> i64 fp [%rbp], i64 csr [%rbx], i64 csr [%r12], i64 csr [%r13], i64 csr [%r14], i64 csr [%r15] system_v {
+; check: ss0 = spill_slot
+
+; check: ebb0(v16: i64 [%rdi], v17: i64 [%rsi], v48: i64 [%rbp], v49: i64 [%rbx], v50: i64 [%r12], v51: i64 [%r13], v52: i64 [%r14], v53: i64 [%r15]):
+; nextln: x86_push v48
+; nextln: copy_special %rsp -> %rbp
+; nextln: x86_push v49
+; nextln: x86_push v50
+; nextln: x86_push v51
+; nextln: x86_push v52
+; nextln: x86_push v53
+; nextln: adjust_sp_imm
+
+; check: spill
+
+; check: fill
+
+; check: adjust_sp_imm
+; nextln: v59 = x86_pop.i64
+; nextln: v58 = x86_pop.i64
+; nextln: v57 = x86_pop.i64
+; nextln: v56 = x86_pop.i64
+; nextln: v55 = x86_pop.i64
+; nextln: v54 = x86_pop.i64
+; nextln: return v54, v55, v56, v57, v58, v59
; nextln: }
diff --git a/lib/cretonne/src/isa/arm32/abi.rs b/lib/cretonne/src/isa/arm32/abi.rs
index 528a396570..1305685825 100644
--- a/lib/cretonne/src/isa/arm32/abi.rs
+++ b/lib/cretonne/src/isa/arm32/abi.rs
@@ -3,7 +3,7 @@
use super::registers::{D, GPR, Q, S};
use ir;
use isa::RegClass;
-use regalloc::AllocatableSet;
+use regalloc::RegisterSet;
use settings as shared_settings;
/// Legalize `sig`.
@@ -30,6 +30,6 @@ 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 {
+pub fn allocatable_registers(_func: &ir::Function) -> RegisterSet {
unimplemented!()
}
diff --git a/lib/cretonne/src/isa/arm32/mod.rs b/lib/cretonne/src/isa/arm32/mod.rs
index 350764a436..dbef9aaf8a 100644
--- a/lib/cretonne/src/isa/arm32/mod.rs
+++ b/lib/cretonne/src/isa/arm32/mod.rs
@@ -92,7 +92,7 @@ impl TargetIsa for Isa {
abi::regclass_for_abi_type(ty)
}
- fn allocatable_registers(&self, func: &ir::Function) -> regalloc::AllocatableSet {
+ fn allocatable_registers(&self, func: &ir::Function) -> regalloc::RegisterSet {
abi::allocatable_registers(func)
}
diff --git a/lib/cretonne/src/isa/arm64/abi.rs b/lib/cretonne/src/isa/arm64/abi.rs
index 0540746afa..4bd9aad7be 100644
--- a/lib/cretonne/src/isa/arm64/abi.rs
+++ b/lib/cretonne/src/isa/arm64/abi.rs
@@ -3,7 +3,7 @@
use super::registers::{FPR, GPR};
use ir;
use isa::RegClass;
-use regalloc::AllocatableSet;
+use regalloc::RegisterSet;
use settings as shared_settings;
/// Legalize `sig`.
@@ -21,6 +21,6 @@ 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 {
+pub fn allocatable_registers(_func: &ir::Function) -> RegisterSet {
unimplemented!()
}
diff --git a/lib/cretonne/src/isa/arm64/mod.rs b/lib/cretonne/src/isa/arm64/mod.rs
index 3b63d56d54..eeddec74fd 100644
--- a/lib/cretonne/src/isa/arm64/mod.rs
+++ b/lib/cretonne/src/isa/arm64/mod.rs
@@ -85,7 +85,7 @@ impl TargetIsa for Isa {
abi::regclass_for_abi_type(ty)
}
- fn allocatable_registers(&self, func: &ir::Function) -> regalloc::AllocatableSet {
+ fn allocatable_registers(&self, func: &ir::Function) -> regalloc::RegisterSet {
abi::allocatable_registers(func)
}
diff --git a/lib/cretonne/src/isa/intel/abi.rs b/lib/cretonne/src/isa/intel/abi.rs
index e9019291ef..f1abd1cb42 100644
--- a/lib/cretonne/src/isa/intel/abi.rs
+++ b/lib/cretonne/src/isa/intel/abi.rs
@@ -6,9 +6,10 @@ use cursor::{Cursor, CursorPosition, EncCursor};
use ir;
use ir::immediates::Imm64;
use ir::stackslot::{StackOffset, StackSize};
-use ir::{AbiParam, ArgumentExtension, ArgumentLoc, ArgumentPurpose, CallConv, InstBuilder};
+use ir::{AbiParam, ArgumentExtension, ArgumentLoc, ArgumentPurpose, CallConv, InstBuilder,
+ ValueLoc};
use isa::{RegClass, RegUnit, TargetIsa};
-use regalloc::AllocatableSet;
+use regalloc::RegisterSet;
use result;
use settings as shared_settings;
use stack_layout::layout_stack;
@@ -140,11 +141,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,
- flags: &shared_settings::Flags,
-) -> AllocatableSet {
- let mut regs = AllocatableSet::new();
+pub fn allocatable_registers(_func: &ir::Function, flags: &shared_settings::Flags) -> RegisterSet {
+ let mut regs = RegisterSet::new();
regs.take(GPR, RU::rsp as RegUnit);
regs.take(GPR, RU::rbp as RegUnit);
@@ -160,7 +158,7 @@ pub fn allocatable_registers(
}
/// Get the set of callee-saved registers.
-pub fn callee_saved_registers(flags: &shared_settings::Flags) -> &'static [RU] {
+fn callee_saved_gprs(flags: &shared_settings::Flags) -> &'static [RU] {
if flags.is_64bit() {
&[RU::rbx, RU::r12, RU::r13, RU::r14, RU::r15]
} else {
@@ -168,6 +166,28 @@ pub fn callee_saved_registers(flags: &shared_settings::Flags) -> &'static [RU] {
}
}
+fn callee_saved_gprs_used(flags: &shared_settings::Flags, func: &ir::Function) -> RegisterSet {
+ let mut all_callee_saved = RegisterSet::empty();
+ for reg in callee_saved_gprs(flags) {
+ all_callee_saved.free(GPR, *reg as RegUnit);
+ }
+
+ let mut used = RegisterSet::empty();
+ for value_loc in func.locations.values() {
+ // Note that `value_loc` here contains only a single unit of a potentially multi-unit
+ // register. We don't use registers that overlap each other in the x86 ISA, but in others
+ // we do. So this should not be blindly reused.
+ if let ValueLoc::Reg(ru) = *value_loc {
+ if !used.is_avail(GPR, ru) {
+ used.free(GPR, ru);
+ }
+ }
+ }
+
+ used.intersect(&all_callee_saved);
+ return used;
+}
+
pub fn prologue_epilogue(func: &mut ir::Function, isa: &TargetIsa) -> result::CtonResult {
match func.signature.call_conv {
ir::CallConv::SystemV => system_v_prologue_epilogue(func, isa),
@@ -203,7 +223,8 @@ pub fn system_v_prologue_epilogue(func: &mut ir::Function, isa: &TargetIsa) -> r
} else {
ir::types::I32
};
- let csrs = callee_saved_registers(isa.flags());
+
+ let csrs = callee_saved_gprs_used(isa.flags(), func);
// The reserved stack area is composed of:
// return address + frame pointer + all callee-saved registers
@@ -212,7 +233,7 @@ pub fn system_v_prologue_epilogue(func: &mut ir::Function, isa: &TargetIsa) -> r
// instruction. Each of the others we will then push explicitly. Then we
// will adjust the stack pointer to make room for the rest of the required
// space for this frame.
- let csr_stack_size = ((csrs.len() + 2) * word_size as usize) as i32;
+ let csr_stack_size = ((csrs.iter(GPR).len() + 2) * word_size as usize) as i32;
func.create_stack_slot(ir::StackSlotData {
kind: ir::StackSlotKind::IncomingArg,
size: csr_stack_size as u32,
@@ -231,9 +252,8 @@ pub fn system_v_prologue_epilogue(func: &mut ir::Function, isa: &TargetIsa) -> r
func.signature.params.push(fp_arg);
func.signature.returns.push(fp_arg);
- for csr in csrs.iter() {
- let csr_arg =
- ir::AbiParam::special_reg(csr_type, ir::ArgumentPurpose::CalleeSaved, *csr as RegUnit);
+ for csr in csrs.iter(GPR) {
+ let csr_arg = ir::AbiParam::special_reg(csr_type, ir::ArgumentPurpose::CalleeSaved, csr);
func.signature.params.push(csr_arg);
func.signature.returns.push(csr_arg);
}
@@ -241,11 +261,11 @@ pub fn system_v_prologue_epilogue(func: &mut ir::Function, isa: &TargetIsa) -> r
// Set up the cursor and insert the prologue
let entry_ebb = func.layout.entry_block().expect("missing entry block");
let mut pos = EncCursor::new(func, isa).at_first_insertion_point(entry_ebb);
- insert_system_v_prologue(&mut pos, local_stack_size, csr_type, csrs);
+ insert_system_v_prologue(&mut pos, local_stack_size, csr_type, &csrs);
// Reset the cursor and insert the epilogue
let mut pos = pos.at_position(CursorPosition::Nowhere);
- insert_system_v_epilogues(&mut pos, local_stack_size, csr_type, csrs);
+ insert_system_v_epilogues(&mut pos, local_stack_size, csr_type, &csrs);
Ok(())
}
@@ -255,7 +275,7 @@ fn insert_system_v_prologue(
pos: &mut EncCursor,
stack_size: i64,
csr_type: ir::types::Type,
- csrs: &'static [RU],
+ csrs: &RegisterSet,
) {
// Append param to entry EBB
let ebb = pos.current_ebb().expect("missing ebb under cursor");
@@ -268,12 +288,12 @@ fn insert_system_v_prologue(
RU::rbp as RegUnit,
);
- for reg in csrs.iter() {
+ for reg in csrs.iter(GPR) {
// Append param to entry EBB
let csr_arg = pos.func.dfg.append_ebb_param(ebb, csr_type);
// Assign it a location
- pos.func.locations[csr_arg] = ir::ValueLoc::Reg(*reg as RegUnit);
+ pos.func.locations[csr_arg] = ir::ValueLoc::Reg(reg);
// Remember it so we can push it momentarily
pos.ins().x86_push(csr_arg);
@@ -289,7 +309,7 @@ fn insert_system_v_epilogues(
pos: &mut EncCursor,
stack_size: i64,
csr_type: ir::types::Type,
- csrs: &'static [RU],
+ csrs: &RegisterSet,
) {
while let Some(ebb) = pos.next_ebb() {
pos.goto_last_inst(ebb);
@@ -307,7 +327,7 @@ fn insert_system_v_epilogue(
stack_size: i64,
pos: &mut EncCursor,
csr_type: ir::types::Type,
- csrs: &'static [RU],
+ csrs: &RegisterSet,
) {
if stack_size > 0 {
pos.ins().adjust_sp_imm(Imm64::new(stack_size));
@@ -321,11 +341,11 @@ fn insert_system_v_epilogue(
pos.func.locations[fp_ret] = ir::ValueLoc::Reg(RU::rbp as RegUnit);
pos.func.dfg.append_inst_arg(inst, fp_ret);
- for reg in csrs.iter() {
+ for reg in csrs.iter(GPR) {
let csr_ret = pos.ins().x86_pop(csr_type);
pos.prev_inst();
- pos.func.locations[csr_ret] = ir::ValueLoc::Reg(*reg as RegUnit);
+ pos.func.locations[csr_ret] = ir::ValueLoc::Reg(reg);
pos.func.dfg.append_inst_arg(inst, csr_ret);
}
}
diff --git a/lib/cretonne/src/isa/intel/mod.rs b/lib/cretonne/src/isa/intel/mod.rs
index 91d8325a6b..02cccc4f54 100644
--- a/lib/cretonne/src/isa/intel/mod.rs
+++ b/lib/cretonne/src/isa/intel/mod.rs
@@ -98,7 +98,7 @@ impl TargetIsa for Isa {
abi::regclass_for_abi_type(ty)
}
- fn allocatable_registers(&self, func: &ir::Function) -> regalloc::AllocatableSet {
+ fn allocatable_registers(&self, func: &ir::Function) -> regalloc::RegisterSet {
abi::allocatable_registers(func, &self.shared_flags)
}
diff --git a/lib/cretonne/src/isa/mod.rs b/lib/cretonne/src/isa/mod.rs
index 39d7d4eb60..71537a0487 100644
--- a/lib/cretonne/src/isa/mod.rs
+++ b/lib/cretonne/src/isa/mod.rs
@@ -238,7 +238,7 @@ pub trait TargetIsa: fmt::Display {
///
/// This set excludes reserved registers like the stack pointer and other special-purpose
/// registers.
- fn allocatable_registers(&self, func: &ir::Function) -> regalloc::AllocatableSet;
+ fn allocatable_registers(&self, func: &ir::Function) -> regalloc::RegisterSet;
/// Compute the stack layout and insert prologue and epilogue code into `func`.
///
diff --git a/lib/cretonne/src/isa/riscv/abi.rs b/lib/cretonne/src/isa/riscv/abi.rs
index 0782fa5e53..96e532e827 100644
--- a/lib/cretonne/src/isa/riscv/abi.rs
+++ b/lib/cretonne/src/isa/riscv/abi.rs
@@ -10,7 +10,7 @@ use super::settings;
use abi::{legalize_args, ArgAction, ArgAssigner, ValueConversion};
use ir::{self, AbiParam, ArgumentExtension, ArgumentLoc, ArgumentPurpose, Type};
use isa::RegClass;
-use regalloc::AllocatableSet;
+use regalloc::RegisterSet;
use settings as shared_settings;
use std::i32;
@@ -120,8 +120,8 @@ 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();
+pub fn allocatable_registers(_func: &ir::Function, isa_flags: &settings::Flags) -> RegisterSet {
+ let mut regs = RegisterSet::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.
diff --git a/lib/cretonne/src/isa/riscv/mod.rs b/lib/cretonne/src/isa/riscv/mod.rs
index 9c3a498d5e..c81d3baceb 100644
--- a/lib/cretonne/src/isa/riscv/mod.rs
+++ b/lib/cretonne/src/isa/riscv/mod.rs
@@ -92,7 +92,7 @@ impl TargetIsa for Isa {
abi::regclass_for_abi_type(ty)
}
- fn allocatable_registers(&self, func: &ir::Function) -> regalloc::AllocatableSet {
+ fn allocatable_registers(&self, func: &ir::Function) -> regalloc::RegisterSet {
abi::allocatable_registers(func, &self.isa_flags)
}
diff --git a/lib/cretonne/src/regalloc/coloring.rs b/lib/cretonne/src/regalloc/coloring.rs
index b9b1512220..4ddda53e16 100644
--- a/lib/cretonne/src/regalloc/coloring.rs
+++ b/lib/cretonne/src/regalloc/coloring.rs
@@ -51,7 +51,7 @@ use isa::{regs_overlap, RegClass, RegInfo, RegUnit};
use packed_option::PackedOption;
use regalloc::RegDiversions;
use regalloc::affinity::Affinity;
-use regalloc::allocatable_set::AllocatableSet;
+use regalloc::register_set::RegisterSet;
use regalloc::live_value_tracker::{LiveValue, LiveValueTracker};
use regalloc::liveness::Liveness;
use regalloc::liverange::{LiveRange, LiveRangeContext};
@@ -96,7 +96,7 @@ struct Context<'a> {
// Pristine set of registers that the allocator can use.
// This set remains immutable, we make clones.
- usable_regs: AllocatableSet,
+ usable_regs: RegisterSet,
}
impl Coloring {
@@ -699,7 +699,7 @@ impl<'a> Context<'a> {
defs: &[LiveValue],
throughs: &[LiveValue],
replace_global_defines: &mut bool,
- global_regs: &AllocatableSet,
+ global_regs: &RegisterSet,
) {
for (op, lv) in constraints.iter().zip(defs) {
match op.kind {
@@ -732,7 +732,7 @@ impl<'a> Context<'a> {
defs: &[LiveValue],
throughs: &[LiveValue],
replace_global_defines: &mut bool,
- global_regs: &AllocatableSet,
+ global_regs: &RegisterSet,
) {
// It's technically possible for a call instruction to have fixed results before the
// variable list of results, but we have no known instances of that.
@@ -797,7 +797,7 @@ impl<'a> Context<'a> {
constraints: &[OperandConstraint],
defs: &[LiveValue],
replace_global_defines: &mut bool,
- global_regs: &AllocatableSet,
+ global_regs: &RegisterSet,
) {
for (op, lv) in constraints.iter().zip(defs) {
match op.kind {
@@ -843,9 +843,9 @@ impl<'a> Context<'a> {
fn iterate_solution(
&mut self,
throughs: &[LiveValue],
- global_regs: &AllocatableSet,
+ global_regs: &RegisterSet,
replace_global_defines: &mut bool,
- ) -> AllocatableSet {
+ ) -> RegisterSet {
// Make sure `try_add_var()` below doesn't create a variable with too loose constraints.
self.program_complete_input_constraints();
@@ -923,7 +923,7 @@ impl<'a> Context<'a> {
/// inserted before.
///
/// The solver needs to be reminded of the available registers before any moves are inserted.
- fn shuffle_inputs(&mut self, regs: &mut AllocatableSet) {
+ fn shuffle_inputs(&mut self, regs: &mut RegisterSet) {
use regalloc::solver::Move::*;
let spills = self.solver.schedule_moves(regs);
@@ -1114,19 +1114,19 @@ fn program_input_abi(
struct AvailableRegs {
/// The exact set of registers available on the input side of the current instruction. This
/// takes into account register diversions, and it includes both local and global live ranges.
- input: AllocatableSet,
+ input: RegisterSet,
/// Registers available for allocating globally live values. This set ignores any local values,
/// and it does not account for register diversions.
///
/// Global values must be allocated out of this set because conflicts with other global values
/// can't be resolved with local diversions.
- global: AllocatableSet,
+ global: RegisterSet,
}
impl AvailableRegs {
/// Initialize both the input and global sets from `regs`.
- pub fn new(regs: &AllocatableSet) -> AvailableRegs {
+ pub fn new(regs: &RegisterSet) -> AvailableRegs {
AvailableRegs {
input: regs.clone(),
global: regs.clone(),
diff --git a/lib/cretonne/src/regalloc/mod.rs b/lib/cretonne/src/regalloc/mod.rs
index 6868c0a235..1444874b83 100644
--- a/lib/cretonne/src/regalloc/mod.rs
+++ b/lib/cretonne/src/regalloc/mod.rs
@@ -2,7 +2,7 @@
//!
//! This module contains data structures and algorithms used for register allocation.
-pub mod allocatable_set;
+pub mod register_set;
pub mod coloring;
pub mod live_value_tracker;
pub mod liveness;
@@ -18,6 +18,6 @@ mod reload;
mod solver;
mod spilling;
-pub use self::allocatable_set::AllocatableSet;
+pub use self::register_set::RegisterSet;
pub use self::context::Context;
pub use self::diversion::RegDiversions;
diff --git a/lib/cretonne/src/regalloc/pressure.rs b/lib/cretonne/src/regalloc/pressure.rs
index 14978f48b8..9f7d64365d 100644
--- a/lib/cretonne/src/regalloc/pressure.rs
+++ b/lib/cretonne/src/regalloc/pressure.rs
@@ -37,7 +37,7 @@
#![allow(dead_code)]
use isa::registers::{RegClass, RegClassMask, RegInfo, MAX_TRACKED_TOPRCS};
-use regalloc::AllocatableSet;
+use regalloc::RegisterSet;
use std::cmp::min;
use std::fmt;
use std::iter::ExactSizeIterator;
@@ -81,7 +81,7 @@ pub struct Pressure {
impl Pressure {
/// Create a new register pressure tracker.
- pub fn new(reginfo: &RegInfo, usable: &AllocatableSet) -> Pressure {
+ pub fn new(reginfo: &RegInfo, usable: &RegisterSet) -> Pressure {
let mut p = Pressure {
aliased: 0,
toprc: Default::default(),
@@ -271,7 +271,7 @@ impl fmt::Display for Pressure {
mod tests {
use super::Pressure;
use isa::{RegClass, TargetIsa};
- use regalloc::AllocatableSet;
+ use regalloc::RegisterSet;
use std::borrow::Borrow;
use std::boxed::Box;
@@ -302,7 +302,7 @@ mod tests {
let gpr = rc_by_name(isa, "GPR");
let s = rc_by_name(isa, "S");
let reginfo = isa.register_info();
- let regs = AllocatableSet::new();
+ let regs = RegisterSet::new();
let mut pressure = Pressure::new(®info, ®s);
let mut count = 0;
@@ -331,7 +331,7 @@ mod tests {
let d = rc_by_name(isa, "D");
let q = rc_by_name(isa, "Q");
let reginfo = isa.register_info();
- let regs = AllocatableSet::new();
+ let regs = RegisterSet::new();
let mut pressure = Pressure::new(®info, ®s);
assert_eq!(pressure.check_avail(s), 0);
diff --git a/lib/cretonne/src/regalloc/allocatable_set.rs b/lib/cretonne/src/regalloc/register_set.rs
similarity index 90%
rename from lib/cretonne/src/regalloc/allocatable_set.rs
rename to lib/cretonne/src/regalloc/register_set.rs
index 63b7a297d7..f2f109ecd9 100644
--- a/lib/cretonne/src/regalloc/allocatable_set.rs
+++ b/lib/cretonne/src/regalloc/register_set.rs
@@ -13,7 +13,7 @@ use std::mem::size_of_val;
/// Set of registers available for allocation.
#[derive(Clone)]
-pub struct AllocatableSet {
+pub struct RegisterSet {
avail: RegUnitMask,
}
@@ -32,7 +32,7 @@ fn bitmask(rc: RegClass, reg: RegUnit) -> (usize, u32) {
(word_index, reg_bits)
}
-impl AllocatableSet {
+impl RegisterSet {
/// Create a new register set with all registers available.
///
/// Note that this includes *all* registers. Query the `TargetIsa` object to get a set of
@@ -41,6 +41,11 @@ impl AllocatableSet {
Self { avail: [!0; 3] }
}
+ /// Create a new register set with no registers available.
+ pub fn empty() -> Self {
+ Self { avail: [0; 3] }
+ }
+
/// Returns `true` if the specified register is available.
pub fn is_avail(&self, rc: RegClass, reg: RegUnit) -> bool {
let (idx, bits) = bitmask(rc, reg);
@@ -62,7 +67,7 @@ impl AllocatableSet {
self.avail[idx] &= !bits;
}
- /// Make `reg` available for allocation again.
+ /// Return `reg` and all of its register units to the set of available registers.
pub fn free(&mut self, rc: RegClass, reg: RegUnit) {
let (idx, bits) = bitmask(rc, reg);
debug_assert!(
@@ -98,15 +103,15 @@ impl AllocatableSet {
/// of `other`.
///
/// This assumes that unused bits are 1.
- pub fn interferes_with(&self, other: &AllocatableSet) -> bool {
+ pub fn interferes_with(&self, other: &RegisterSet) -> bool {
self.avail.iter().zip(&other.avail).any(
|(&x, &y)| (x | y) != !0,
)
}
- /// Intersect this set of allocatable registers with `other`. This has the effect of removing
- /// any register units from this set that are not in `other`.
- pub fn intersect(&mut self, other: &AllocatableSet) {
+ /// Intersect this set of registers with `other`. This has the effect of removing any register
+ /// units from this set that are not in `other`.
+ pub fn intersect(&mut self, other: &RegisterSet) {
for (x, &y) in self.avail.iter_mut().zip(&other.avail) {
*x &= y;
}
@@ -114,8 +119,8 @@ impl AllocatableSet {
/// Return an object that can display this register set, using the register info from the
/// target ISA.
- pub fn display<'a, R: Into