use crate::OperandConstraint::{self, *};
use crate::OperandKind::{self, *};
use crate::{
run, Algorithm, Allocation, Block, Function, Inst, InstRange, MachineEnv, Operand, OperandPos,
PReg, PRegSet, ProgPoint, RegClass, RegallocOptions, VReg,
};
use alloc::vec;
use alloc::vec::Vec;
#[test]
fn test_debug_locations1() {
let mach_env = mach_env(10);
let mut options = RegallocOptions::default();
options.validate_ssa = true;
options.algorithm = Algorithm::Fastalloc;
let mut f = RealFunction::new(vec![BlockBuildInfo {
insts: vec![
vec![op(Def, 0, FixedReg(p(0)))],
vec![
op(Def, 1, FixedReg(p(0))),
op(Use, 0, FixedReg(p(0))),
op(Use, 0, Reg),
],
vec![
op(Def, 2, FixedReg(p(8))),
op(Use, 0, FixedReg(p(2))),
op(Use, 1, FixedReg(p(0))),
],
vec![op(Def, 3, FixedReg(p(9))), op(Use, 0, FixedReg(p(9)))],
],
}]);
f.debug_value_labels = vec![
(v(0), i(0), i(4), 32),
(v(2), i(2), i(4), 70),
(v(2), i(2), i(4), 71),
(v(3), i(3), i(4), 34),
];
let result = run(&f, &mach_env, &options).unwrap();
assert_eq!(
result.debug_locations,
vec![
(
32,
ProgPoint::after(i(0)),
ProgPoint::after(i(3)),
alloc(p(9))
),
(
34,
ProgPoint::after(i(3)),
ProgPoint::before(i(4)),
alloc(p(9))
),
(
70,
ProgPoint::after(i(2)),
ProgPoint::before(i(3)),
alloc(p(8))
),
(
71,
ProgPoint::after(i(2)),
ProgPoint::before(i(3)),
alloc(p(8))
),
]
);
}
#[test]
fn test_debug_locations2() {
let mach_env = mach_env(2);
let mut options = RegallocOptions::default();
options.validate_ssa = true;
options.algorithm = Algorithm::Fastalloc;
let mut f = RealFunction::new(vec![BlockBuildInfo {
insts: vec![
vec![op(Def, 2, FixedReg(p(0)))],
vec![op(Def, 0, FixedReg(p(0)))],
vec![op(Def, 1, FixedReg(p(1)))],
vec![op(Use, 0, FixedReg(p(0))), op(Use, 0, FixedReg(p(1)))],
vec![op(Use, 1, FixedReg(p(1)))],
],
}]);
f.debug_value_labels = vec![
(v(0), i(1), i(4), 10),
(v(1), i(0), i(1), 11),
(v(1), i(2), i(3), 23),
];
let result = run(&f, &mach_env, &options).unwrap();
assert_eq!(result.debug_locations.len(), 2);
assert_eq!(
result.debug_locations[0],
(
10,
ProgPoint::after(i(1)),
ProgPoint::after(i(3)),
alloc(p(0))
)
);
assert_eq!(result.debug_locations[1].0, 23);
assert_eq!(result.debug_locations[1].1, ProgPoint::after(i(2)));
assert_eq!(result.debug_locations[1].2, ProgPoint::after(i(4)));
assert!(matches!(result.debug_locations[1].3.as_stack(), Some(_)));
}
impl RealFunction {
fn new(blocks: Vec<BlockBuildInfo>) -> Self {
assert!(blocks.len() <= 2, "Just for testing purposes");
let mut f = Self::default();
let mut max_vreg_num_seen = 0;
for block in blocks.iter() {
f.blocks.push(RealBlock {
params: vec![],
preds: vec![],
succs: vec![],
});
let start_inst_idx = f.insts.len();
for inst in block.insts.iter() {
f.insts.push(RealInst {
inst: Inst::new(f.insts.len()),
kind: RealInstKind::Normal,
});
let start_op_idx = f.operands.len();
for op in inst.iter() {
max_vreg_num_seen = max_vreg_num_seen.max(op.vreg().vreg());
f.operands.push(*op);
}
f.operand_ranges.push((start_op_idx, f.operands.len()));
}
if !block.insts.is_empty() {
f.insts.last_mut().unwrap().kind = RealInstKind::Ret;
}
f.inst_ranges.push((start_inst_idx, f.insts.len()));
}
f.num_vregs = max_vreg_num_seen + 1;
f
}
}
fn mach_env(no_of_regs: usize) -> MachineEnv {
MachineEnv {
preferred_regs_by_class: [
(0..no_of_regs)
.map(|no| PReg::new(no, RegClass::Int))
.collect(),
PRegSet::empty(),
PRegSet::empty(),
],
non_preferred_regs_by_class: [PRegSet::empty(); 3],
scratch_by_class: [None, None, None],
fixed_stack_slots: vec![],
}
}
fn op(kind: OperandKind, vreg_num: usize, constraint: OperandConstraint) -> Operand {
Operand::new(
VReg::new(vreg_num, RegClass::Int),
constraint,
kind,
match kind {
Use => OperandPos::Early,
Def => OperandPos::Late,
},
)
}
fn alloc(preg: PReg) -> Allocation {
Allocation::reg(preg)
}
fn v(vreg_num: usize) -> VReg {
VReg::new(vreg_num, RegClass::Int)
}
fn i(inst: usize) -> Inst {
Inst::new(inst)
}
fn p(hw_enc: usize) -> PReg {
PReg::new(hw_enc, RegClass::Int)
}
struct BlockBuildInfo {
insts: Vec<Vec<Operand>>,
}
#[derive(Default)]
struct RealFunction {
blocks: Vec<RealBlock>,
insts: Vec<RealInst>,
operands: Vec<Operand>,
operand_ranges: Vec<(usize, usize)>,
inst_ranges: Vec<(usize, usize)>,
num_vregs: usize,
debug_value_labels: Vec<(VReg, Inst, Inst, u32)>,
}
struct RealBlock {
params: Vec<VReg>,
preds: Vec<Block>,
succs: Vec<Block>,
}
struct RealInst {
inst: Inst,
kind: RealInstKind,
}
impl RealInst {
fn is_branch(&self) -> bool {
match self.kind {
RealInstKind::Branch(_, _) => true,
_ => false,
}
}
fn is_ret(&self) -> bool {
match self.kind {
RealInstKind::Ret => true,
_ => false,
}
}
}
enum RealInstKind {
Normal,
Branch(Block, Vec<VReg>),
Ret,
}
impl Function for RealFunction {
fn num_insts(&self) -> usize {
self.insts.len()
}
fn num_blocks(&self) -> usize {
self.blocks.len()
}
fn block_insns(&self, block: crate::Block) -> crate::InstRange {
let (start, end) = self.inst_ranges[block.index()];
if start != end {
InstRange::new(
self.insts[start].inst,
Inst::new(self.insts[end - 1].inst.index() + 1),
)
} else {
InstRange::new(Inst::new(0), Inst::new(0))
}
}
fn allow_multiple_vreg_defs(&self) -> bool {
false
}
fn block_params(&self, block: crate::Block) -> &[VReg] {
&self.blocks[block.index()].params
}
fn block_preds(&self, block: crate::Block) -> &[crate::Block] {
&self.blocks[block.index()].preds
}
fn block_succs(&self, block: Block) -> &[Block] {
&self.blocks[block.index()].succs
}
fn debug_value_labels(&self) -> &[(VReg, Inst, Inst, u32)] {
&self.debug_value_labels
}
fn entry_block(&self) -> Block {
Block::new(0)
}
fn inst_clobbers(&self, _insn: Inst) -> crate::PRegSet {
PRegSet::empty()
}
fn inst_operands(&self, insn: Inst) -> &[Operand] {
let (start, end) = self.operand_ranges[insn.index()];
&self.operands[start..end]
}
fn is_branch(&self, insn: Inst) -> bool {
self.insts[insn.index()].is_branch()
}
fn is_ret(&self, insn: Inst) -> bool {
self.insts[insn.index()].is_ret()
}
fn multi_spillslot_named_by_last_slot(&self) -> bool {
false
}
fn num_vregs(&self) -> usize {
self.num_vregs
}
fn spillslot_size(&self, regclass: crate::RegClass) -> usize {
match regclass {
RegClass::Int => 2,
RegClass::Float => 4,
RegClass::Vector => 8,
}
}
fn branch_blockparams(&self, _block: Block, _insn: Inst, _succ_idx: usize) -> &[VReg] {
&[]
}
}