Skip to content

Commit 822f2bc

Browse files
authored
Merge pull request #18 from Amanieu/blockparam
Rework the API for outgoing blockparams
2 parents fdd9913 + 6621a57 commit 822f2bc

File tree

5 files changed

+88
-70
lines changed

5 files changed

+88
-70
lines changed

src/cfg.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ impl CFGInfo {
101101
}
102102
if require_no_branch_args {
103103
let last = f.block_insns(block).last();
104-
if f.branch_blockparam_arg_offset(block, last) > 0 {
104+
if !f.inst_operands(last).is_empty() {
105105
return Err(RegAllocError::DisallowedBranchArg(last));
106106
}
107107
}

src/fuzzing/func.rs

+44-24
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ use arbitrary::{Arbitrary, Unstructured};
1313

1414
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
1515
pub enum InstOpcode {
16-
Phi,
1716
Op,
1817
Ret,
1918
Branch,
@@ -40,14 +39,10 @@ impl InstData {
4039
is_safepoint: false,
4140
}
4241
}
43-
pub fn branch(uses: &[usize]) -> InstData {
44-
let mut operands = vec![];
45-
for &u in uses {
46-
operands.push(Operand::reg_use(VReg::new(u, RegClass::Int)));
47-
}
42+
pub fn branch() -> InstData {
4843
InstData {
4944
op: InstOpcode::Branch,
50-
operands,
45+
operands: vec![],
5146
clobbers: vec![],
5247
is_safepoint: false,
5348
}
@@ -68,7 +63,8 @@ pub struct Func {
6863
blocks: Vec<InstRange>,
6964
block_preds: Vec<Vec<Block>>,
7065
block_succs: Vec<Vec<Block>>,
71-
block_params: Vec<Vec<VReg>>,
66+
block_params_in: Vec<Vec<VReg>>,
67+
block_params_out: Vec<Vec<Vec<VReg>>>,
7268
num_vregs: usize,
7369
reftype_vregs: Vec<VReg>,
7470
}
@@ -100,7 +96,7 @@ impl Function for Func {
10096
}
10197

10298
fn block_params(&self, block: Block) -> &[VReg] {
103-
&self.block_params[block.index()][..]
99+
&self.block_params_in[block.index()][..]
104100
}
105101

106102
fn is_ret(&self, insn: Inst) -> bool {
@@ -111,10 +107,8 @@ impl Function for Func {
111107
self.insts[insn.index()].op == InstOpcode::Branch
112108
}
113109

114-
fn branch_blockparam_arg_offset(&self, _: Block, _: Inst) -> usize {
115-
// Branch blockparam args always start at zero for this
116-
// Function implementation.
117-
0
110+
fn branch_blockparams(&self, block: Block, _: Inst, succ: usize) -> &[VReg] {
111+
&self.block_params_out[block.index()][succ][..]
118112
}
119113

120114
fn requires_refs_on_stack(&self, insn: Inst) -> bool {
@@ -164,7 +158,8 @@ impl FuncBuilder {
164158
f: Func {
165159
block_preds: vec![],
166160
block_succs: vec![],
167-
block_params: vec![],
161+
block_params_in: vec![],
162+
block_params_out: vec![],
168163
insts: vec![],
169164
blocks: vec![],
170165
num_vregs: 0,
@@ -181,7 +176,8 @@ impl FuncBuilder {
181176
.push(InstRange::forward(Inst::new(0), Inst::new(0)));
182177
self.f.block_preds.push(vec![]);
183178
self.f.block_succs.push(vec![]);
184-
self.f.block_params.push(vec![]);
179+
self.f.block_params_in.push(vec![]);
180+
self.f.block_params_out.push(vec![]);
185181
self.insts_per_block.push(vec![]);
186182
b
187183
}
@@ -195,8 +191,12 @@ impl FuncBuilder {
195191
self.f.block_preds[to.index()].push(from);
196192
}
197193

198-
pub fn set_block_params(&mut self, block: Block, params: &[VReg]) {
199-
self.f.block_params[block.index()] = params.iter().cloned().collect();
194+
pub fn set_block_params_in(&mut self, block: Block, params: &[VReg]) {
195+
self.f.block_params_in[block.index()] = params.iter().cloned().collect();
196+
}
197+
198+
pub fn set_block_params_out(&mut self, block: Block, params: Vec<Vec<VReg>>) {
199+
self.f.block_params_out[block.index()] = params;
200200
}
201201

202202
fn compute_doms(&mut self) {
@@ -388,7 +388,7 @@ impl Func {
388388
}
389389
}
390390
vregs_by_block_to_be_defined.last_mut().unwrap().reverse();
391-
builder.set_block_params(Block::new(block), &block_params[block][..]);
391+
builder.set_block_params_in(Block::new(block), &block_params[block][..]);
392392
}
393393

394394
for block in 0..num_blocks {
@@ -510,9 +510,10 @@ impl Func {
510510
// Define the branch with blockparam args that must end
511511
// the block.
512512
if builder.f.block_succs[block].len() > 0 {
513-
let mut args = vec![];
513+
let mut params = vec![];
514514
for &succ in &builder.f.block_succs[block] {
515-
for _ in 0..builder.f.block_params[succ.index()].len() {
515+
let mut args = vec![];
516+
for _ in 0..builder.f.block_params_in[succ.index()].len() {
516517
let dom_block = choose_dominating_block(
517518
&builder.idom[..],
518519
Block::new(block),
@@ -524,10 +525,12 @@ impl Func {
524525
} else {
525526
u.choose(&avail[..])?
526527
};
527-
args.push(vreg.vreg());
528+
args.push(*vreg);
528529
}
530+
params.push(args);
529531
}
530-
builder.add_inst(Block::new(block), InstData::branch(&args[..]));
532+
builder.set_block_params_out(Block::new(block), params);
533+
builder.add_inst(Block::new(block), InstData::branch());
531534
} else {
532535
builder.add_inst(Block::new(block), InstData::ret());
533536
}
@@ -552,15 +555,29 @@ impl std::fmt::Debug for Func {
552555
.iter()
553556
.map(|b| b.index())
554557
.collect::<Vec<_>>();
555-
let params = self.block_params[i]
558+
let params_in = self.block_params_in[i]
556559
.iter()
557560
.map(|v| format!("v{}", v.vreg()))
558561
.collect::<Vec<_>>()
559562
.join(", ");
563+
let params_out = self.block_params_out[i]
564+
.iter()
565+
.enumerate()
566+
.map(|(succ_idx, vec)| {
567+
let succ = self.block_succs[i][succ_idx];
568+
let params = vec
569+
.iter()
570+
.map(|v| format!("v{}", v.vreg()))
571+
.collect::<Vec<_>>()
572+
.join(", ");
573+
format!("block{}({})", succ.index(), params)
574+
})
575+
.collect::<Vec<_>>()
576+
.join(", ");
560577
write!(
561578
f,
562579
" block{}({}): # succs:{:?} preds:{:?}\n",
563-
i, params, succs, preds
580+
i, params_in, succs, preds
564581
)?;
565582
for inst in blockrange.iter() {
566583
if self.requires_refs_on_stack(inst) {
@@ -574,6 +591,9 @@ impl std::fmt::Debug for Func {
574591
self.insts[inst.index()].operands,
575592
self.insts[inst.index()].clobbers
576593
)?;
594+
if let InstOpcode::Branch = self.insts[inst.index()].op {
595+
write!(f, " params: {}\n", params_out)?;
596+
}
577597
}
578598
}
579599
write!(f, "}}\n")?;

src/ion/liveranges.rs

+32-26
Original file line numberDiff line numberDiff line change
@@ -315,6 +315,7 @@ impl<'a, F: Function> Env<'a, F> {
315315
while !workqueue.is_empty() {
316316
let block = workqueue.pop_front().unwrap();
317317
workqueue_set.remove(&block);
318+
let insns = self.func.block_insns(block);
318319

319320
log::trace!("computing liveins for block{}", block.index());
320321

@@ -323,7 +324,16 @@ impl<'a, F: Function> Env<'a, F> {
323324
let mut live = self.liveouts[block.index()].clone();
324325
log::trace!(" -> initial liveout set: {:?}", live);
325326

326-
for inst in self.func.block_insns(block).rev().iter() {
327+
// Include outgoing blockparams in the initial live set.
328+
if self.func.is_branch(insns.last()) {
329+
for i in 0..self.func.block_succs(block).len() {
330+
for param in self.func.branch_blockparams(block, insns.last(), i) {
331+
live.set(param.vreg(), true);
332+
}
333+
}
334+
}
335+
336+
for inst in insns.rev().iter() {
327337
if let Some((src, dst)) = self.func.is_move(inst) {
328338
live.set(dst.vreg().vreg(), false);
329339
live.set(src.vreg().vreg(), true);
@@ -399,12 +409,33 @@ impl<'a, F: Function> Env<'a, F> {
399409

400410
for i in (0..self.func.num_blocks()).rev() {
401411
let block = Block::new(i);
412+
let insns = self.func.block_insns(block);
402413

403414
self.stats.livein_blocks += 1;
404415

405416
// Init our local live-in set.
406417
let mut live = self.liveouts[block.index()].clone();
407418

419+
// If the last instruction is a branch (rather than
420+
// return), create blockparam_out entries.
421+
if self.func.is_branch(insns.last()) {
422+
for (i, &succ) in self.func.block_succs(block).iter().enumerate() {
423+
let blockparams_in = self.func.block_params(succ);
424+
let blockparams_out = self.func.branch_blockparams(block, insns.last(), i);
425+
for (&blockparam_in, &blockparam_out) in
426+
blockparams_in.iter().zip(blockparams_out)
427+
{
428+
let blockparam_out = VRegIndex::new(blockparam_out.vreg());
429+
let blockparam_in = VRegIndex::new(blockparam_in.vreg());
430+
self.blockparam_outs
431+
.push((blockparam_out, block, succ, blockparam_in));
432+
433+
// Include outgoing blockparams in the initial live set.
434+
live.set(blockparam_out.index(), true);
435+
}
436+
}
437+
}
438+
408439
// Initially, registers are assumed live for the whole block.
409440
for vreg in live.iter() {
410441
let range = CodeRange {
@@ -426,24 +457,6 @@ impl<'a, F: Function> Env<'a, F> {
426457
self.vregs[param.vreg()].blockparam = block;
427458
}
428459

429-
let insns = self.func.block_insns(block);
430-
431-
// If the last instruction is a branch (rather than
432-
// return), create blockparam_out entries.
433-
if self.func.is_branch(insns.last()) {
434-
let operands = self.func.inst_operands(insns.last());
435-
let mut i = self.func.branch_blockparam_arg_offset(block, insns.last());
436-
for &succ in self.func.block_succs(block) {
437-
for &blockparam in self.func.block_params(succ) {
438-
let from_vreg = VRegIndex::new(operands[i].vreg().vreg());
439-
let blockparam_vreg = VRegIndex::new(blockparam.vreg());
440-
self.blockparam_outs
441-
.push((from_vreg, block, succ, blockparam_vreg));
442-
i += 1;
443-
}
444-
}
445-
}
446-
447460
// For each instruction, in reverse order, process
448461
// operands and clobbers.
449462
for inst in insns.rev().iter() {
@@ -892,13 +905,6 @@ impl<'a, F: Function> Env<'a, F> {
892905
(OperandKind::Def, OperandPos::Early) => ProgPoint::before(inst),
893906
(OperandKind::Def, OperandPos::Late) => ProgPoint::after(inst),
894907
(OperandKind::Use, OperandPos::Late) => ProgPoint::after(inst),
895-
// If this is a branch, extend `pos` to
896-
// the end of the block. (Branch uses are
897-
// blockparams and need to be live at the
898-
// end of the block.)
899-
(OperandKind::Use, _) if self.func.is_branch(inst) => {
900-
self.cfginfo.block_exit[block.index()]
901-
}
902908
// If there are any reused inputs in this
903909
// instruction, and this is *not* the
904910
// reused input, force `pos` to

src/lib.rs

+5-12
Original file line numberDiff line numberDiff line change
@@ -860,21 +860,14 @@ pub trait Function {
860860
fn is_ret(&self, insn: Inst) -> bool;
861861

862862
/// Determine whether an instruction is the end-of-block
863-
/// branch. If so, its operands at the indices given by
864-
/// `branch_blockparam_arg_offset()` below *must* be the block
865-
/// parameters for each of its block's `block_succs` successor
866-
/// blocks, in order.
863+
/// branch.
867864
fn is_branch(&self, insn: Inst) -> bool;
868865

869866
/// If `insn` is a branch at the end of `block`, returns the
870-
/// operand index at which outgoing blockparam arguments are
871-
/// found. Starting at this index, blockparam arguments for each
872-
/// successor block's blockparams, in order, must be found.
873-
///
874-
/// It is an error if `self.inst_operands(insn).len() -
875-
/// self.branch_blockparam_arg_offset(insn)` is not exactly equal
876-
/// to the sum of blockparam counts for all successor blocks.
877-
fn branch_blockparam_arg_offset(&self, block: Block, insn: Inst) -> usize;
867+
/// outgoing blockparam arguments for the given successor. The
868+
/// number of arguments must match the number incoming blockparams
869+
/// for each respective successor block.
870+
fn branch_blockparams(&self, block: Block, insn: Inst, succ_idx: usize) -> &[VReg];
878871

879872
/// Determine whether an instruction requires all reference-typed
880873
/// values to be placed onto the stack. For these instructions,

src/ssa.rs

+6-7
Original file line numberDiff line numberDiff line change
@@ -71,13 +71,12 @@ pub fn validate_ssa<F: Function>(f: &F, cfginfo: &CFGInfo) -> Result<(), RegAllo
7171
return Err(RegAllocError::BB(block));
7272
}
7373
if f.is_branch(insn) {
74-
let expected = f
75-
.block_succs(block)
76-
.iter()
77-
.map(|&succ| f.block_params(succ).len())
78-
.sum();
79-
if f.inst_operands(insn).len() != expected {
80-
return Err(RegAllocError::Branch(insn));
74+
for (i, &succ) in f.block_succs(block).iter().enumerate() {
75+
let blockparams_in = f.block_params(succ);
76+
let blockparams_out = f.branch_blockparams(block, insn, i);
77+
if blockparams_in.len() != blockparams_out.len() {
78+
return Err(RegAllocError::Branch(insn));
79+
}
8180
}
8281
}
8382
} else {

0 commit comments

Comments
 (0)