Skip to content

Commit 219f924

Browse files
committed
Add cf ("control-flow") module and split cfg into cf::unstructured vs cf::structurize.
1 parent d3ae59f commit 219f924

File tree

11 files changed

+572
-515
lines changed

11 files changed

+572
-515
lines changed
File renamed without changes.

src/cf/mod.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
//! Control-flow abstractions and passes.
2+
//
3+
// FIXME(eddyb) consider moving more definitions into this module.
4+
5+
use crate::spv;
6+
7+
// NOTE(eddyb) all the modules are declared here, but they're documented "inside"
8+
// (i.e. using inner doc comments).
9+
pub mod cfgssa;
10+
pub mod structurize;
11+
pub mod unstructured;
12+
13+
#[derive(Clone)]
14+
pub enum SelectionKind {
15+
/// Two-case selection based on boolean condition, i.e. `if`-`else`, with
16+
/// the two cases being "then" and "else" (in that order).
17+
BoolCond,
18+
19+
SpvInst(spv::Inst),
20+
}
21+
22+
#[derive(Clone)]
23+
pub enum ExitInvocationKind {
24+
SpvInst(spv::Inst),
25+
}

src/cfg.rs renamed to src/cf/structurize.rs

Lines changed: 11 additions & 423 deletions
Large diffs are not rendered by default.

src/cf/unstructured.rs

Lines changed: 429 additions & 0 deletions
Large diffs are not rendered by default.

src/lib.rs

Lines changed: 6 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -153,8 +153,7 @@
153153

154154
// NOTE(eddyb) all the modules are declared here, but they're documented "inside"
155155
// (i.e. using inner doc comments).
156-
pub mod cfg;
157-
pub mod cfgssa;
156+
pub mod cf;
158157
mod context;
159158
pub mod func_at;
160159
pub mod print;
@@ -717,7 +716,9 @@ pub struct FuncDefBody {
717716
/// When present, it starts at `body` (more specifically, its exit),
718717
/// effectively replacing the structured return `body` otherwise implies,
719718
/// with `body` (or rather, its `children`) always being fully structured.
720-
pub unstructured_cfg: Option<cfg::ControlFlowGraph>,
719+
//
720+
// FIXME(eddyb) replace this with a new `NodeKind` variant.
721+
pub unstructured_cfg: Option<cf::unstructured::ControlFlowGraph>,
721722
}
722723

723724
/// Entity handle for a [`RegionDef`](crate::RegionDef)
@@ -881,7 +882,7 @@ pub enum NodeKind {
881882
///
882883
/// This corresponds to "gamma" (`γ`) nodes in (R)VSDG, though those are
883884
/// sometimes limited only to a two-way selection on a boolean condition.
884-
Select { kind: SelectionKind, scrutinee: Value, cases: SmallVec<[Region; 2]> },
885+
Select { kind: cf::SelectionKind, scrutinee: Value, cases: SmallVec<[Region; 2]> },
885886

886887
/// Execute `body` repeatedly, until `repeat_condition` evaluates to `false`.
887888
///
@@ -910,23 +911,14 @@ pub enum NodeKind {
910911
//
911912
// FIXME(eddyb) make this less shader-controlflow-centric.
912913
ExitInvocation {
913-
kind: cfg::ExitInvocationKind,
914+
kind: cf::ExitInvocationKind,
914915

915916
// FIXME(eddyb) centralize `Value` inputs across `Node`s,
916917
// and only use stricter types for building/traversing the IR.
917918
inputs: SmallVec<[Value; 2]>,
918919
},
919920
}
920921

921-
#[derive(Clone)]
922-
pub enum SelectionKind {
923-
/// Two-case selection based on boolean condition, i.e. `if`-`else`, with
924-
/// the two cases being "then" and "else" (in that order).
925-
BoolCond,
926-
927-
SpvInst(spv::Inst),
928-
}
929-
930922
/// Entity handle for a [`DataInstDef`](crate::DataInstDef) (a leaf instruction).
931923
pub use context::DataInst;
932924

src/passes/legalize.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use crate::visit::{InnerVisit, Visitor};
2-
use crate::{AttrSet, Const, Context, DeclDef, Func, FxIndexSet, GlobalVar, Module, Type, cfg};
2+
use crate::{AttrSet, Const, Context, DeclDef, Func, FxIndexSet, GlobalVar, Module, Type, cf};
33

44
/// Apply the [`cfg::Structurizer`] algorithm to all function definitions in `module`.
55
pub fn structurize_func_cfgs(module: &mut Module) {
@@ -22,7 +22,7 @@ pub fn structurize_func_cfgs(module: &mut Module) {
2222

2323
for &func in &collector.seen_funcs {
2424
if let DeclDef::Present(func_def_body) = &mut module.funcs[func].def {
25-
cfg::Structurizer::new(cx, func_def_body).structurize_func();
25+
cf::structurize::Structurizer::new(cx, func_def_body).structurize_func();
2626
}
2727
}
2828
}

src/print/mod.rs

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#![allow(unstable_name_collisions)]
2020
use itertools::Itertools as _;
2121

22+
use crate::cf::{self, SelectionKind};
2223
use crate::func_at::FuncAt;
2324
use crate::mem::{DataHapp, DataHappKind, MemAccesses, MemAttr, MemOp};
2425
use crate::print::multiversion::Versions;
@@ -30,8 +31,7 @@ use crate::{
3031
EntityOrientedDenseMap, ExportKey, Exportee, Func, FuncDecl, FuncDefBody, FuncParam,
3132
FxIndexMap, FxIndexSet, GlobalVar, GlobalVarDecl, GlobalVarDefBody, Import, InternedStr,
3233
Module, ModuleDebugInfo, ModuleDialect, Node, NodeDef, NodeKind, NodeOutputDecl, OrdAssertEq,
33-
Region, RegionDef, RegionInputDecl, SelectionKind, Type, TypeDef, TypeKind, TypeOrConst, Value,
34-
cfg, spv,
34+
Region, RegionDef, RegionInputDecl, Type, TypeDef, TypeKind, TypeOrConst, Value, spv,
3535
};
3636
use arrayvec::ArrayVec;
3737
use itertools::Either;
@@ -3858,7 +3858,7 @@ impl Print for FuncAt<'_, Node> {
38583858
])
38593859
}
38603860
NodeKind::ExitInvocation {
3861-
kind: cfg::ExitInvocationKind::SpvInst(spv::Inst { opcode, imms }),
3861+
kind: cf::ExitInvocationKind::SpvInst(spv::Inst { opcode, imms }),
38623862
inputs,
38633863
} => printer.pretty_spv_inst(
38643864
kw_style,
@@ -4274,7 +4274,7 @@ impl Print for FuncAt<'_, DataInst> {
42744274
}
42754275
}
42764276

4277-
impl Print for cfg::ControlInst {
4277+
impl Print for cf::unstructured::ControlInst {
42784278
type Output = pretty::Fragment;
42794279
fn print(&self, printer: &Printer<'_>) -> pretty::Fragment {
42804280
let Self { attrs, kind, inputs, targets, target_inputs } = self;
@@ -4300,12 +4300,12 @@ impl Print for cfg::ControlInst {
43004300
});
43014301

43024302
let def = match kind {
4303-
cfg::ControlInstKind::Unreachable => {
4303+
cf::unstructured::ControlInstKind::Unreachable => {
43044304
// FIXME(eddyb) use `targets.is_empty()` when that is stabilized.
43054305
assert!(targets.len() == 0 && inputs.is_empty());
43064306
kw("unreachable")
43074307
}
4308-
cfg::ControlInstKind::Return => {
4308+
cf::unstructured::ControlInstKind::Return => {
43094309
// FIXME(eddyb) use `targets.is_empty()` when that is stabilized.
43104310
assert!(targets.len() == 0);
43114311
match inputs[..] {
@@ -4314,10 +4314,9 @@ impl Print for cfg::ControlInst {
43144314
_ => unreachable!(),
43154315
}
43164316
}
4317-
cfg::ControlInstKind::ExitInvocation(cfg::ExitInvocationKind::SpvInst(spv::Inst {
4318-
opcode,
4319-
imms,
4320-
})) => {
4317+
cf::unstructured::ControlInstKind::ExitInvocation(cf::ExitInvocationKind::SpvInst(
4318+
spv::Inst { opcode, imms },
4319+
)) => {
43214320
// FIXME(eddyb) use `targets.is_empty()` when that is stabilized.
43224321
assert!(targets.len() == 0);
43234322
printer.pretty_spv_inst(
@@ -4328,12 +4327,12 @@ impl Print for cfg::ControlInst {
43284327
)
43294328
}
43304329

4331-
cfg::ControlInstKind::Branch => {
4330+
cf::unstructured::ControlInstKind::Branch => {
43324331
assert_eq!((targets.len(), inputs.len()), (1, 0));
43334332
targets.next().unwrap()
43344333
}
43354334

4336-
cfg::ControlInstKind::SelectBranch(kind) => {
4335+
cf::unstructured::ControlInstKind::SelectBranch(kind) => {
43374336
assert_eq!(inputs.len(), 1);
43384337
kind.print_with_scrutinee_and_cases(printer, kw_style, inputs[0], targets)
43394338
}

src/spv/lift.rs

Lines changed: 44 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
//! SPIR-T to SPIR-V lifting.
22
3+
use crate::cf::{self, SelectionKind};
34
use crate::func_at::FuncAt;
45
use crate::spv::{self, spec};
56
use crate::visit::{InnerVisit, Visitor};
67
use crate::{
78
AddrSpace, Attr, AttrSet, Const, ConstDef, ConstKind, Context, DataInst, DataInstDef,
89
DataInstKind, DbgSrcLoc, DeclDef, EntityList, ExportKey, Exportee, Func, FuncDecl, FuncParam,
910
FxIndexMap, FxIndexSet, GlobalVar, GlobalVarDefBody, Import, Module, ModuleDebugInfo,
10-
ModuleDialect, Node, NodeKind, NodeOutputDecl, OrdAssertEq, Region, RegionInputDecl,
11-
SelectionKind, Type, TypeDef, TypeKind, TypeOrConst, Value, cfg,
11+
ModuleDialect, Node, NodeKind, NodeOutputDecl, OrdAssertEq, Region, RegionInputDecl, Type,
12+
TypeDef, TypeKind, TypeOrConst, Value,
1213
};
1314
use rustc_hash::FxHashMap;
1415
use smallvec::SmallVec;
@@ -262,7 +263,7 @@ struct FuncLifting<'a> {
262263
/// What determines the values for [`Value::RegionInput`]s, for a specific
263264
/// region (effectively the subset of "region parents" that support inputs).
264265
///
265-
/// Note that this is not used when a [`cfg::ControlInst`] has `target_inputs`,
266+
/// Note that this is not used when a [`cf::unstructured::ControlInst`] has `target_inputs`,
266267
/// and the target [`Region`] itself has phis for its `inputs`.
267268
enum RegionInputsSource {
268269
FuncParams,
@@ -299,7 +300,7 @@ struct Phi {
299300
default_value: Option<Value>,
300301
}
301302

302-
/// Similar to [`cfg::ControlInst`], except:
303+
/// Similar to [`cf::unstructured::ControlInst`], except:
303304
/// * `targets` use [`CfgPoint`]s instead of [`Region`]s, to be able to
304305
/// reach any of the SPIR-V blocks being created during lifting
305306
/// * φ ("phi") values can be provided for targets regardless of "which side" of
@@ -310,7 +311,7 @@ struct Phi {
310311
struct Terminator<'a> {
311312
attrs: AttrSet,
312313

313-
kind: Cow<'a, cfg::ControlInstKind>,
314+
kind: Cow<'a, cf::unstructured::ControlInstKind>,
314315

315316
// FIXME(eddyb) use `Cow` or something, but ideally the "owned" case always
316317
// has at most one input, so allocating a whole `Vec` for that seems unwise.
@@ -640,8 +641,13 @@ impl<'a> FuncLifting<'a> {
640641
.as_ref()
641642
.and_then(|cfg| cfg.control_inst_on_exit_from.get(region));
642643
if let Some(terminator) = unstructured_terminator {
643-
let cfg::ControlInst { attrs, kind, inputs, targets, target_inputs } =
644-
terminator;
644+
let cf::unstructured::ControlInst {
645+
attrs,
646+
kind,
647+
inputs,
648+
targets,
649+
target_inputs,
650+
} = terminator;
645651
Terminator {
646652
attrs: *attrs,
647653
kind: Cow::Borrowed(kind),
@@ -664,7 +670,7 @@ impl<'a> FuncLifting<'a> {
664670
assert!(region == func_def_body.body);
665671
Terminator {
666672
attrs: AttrSet::default(),
667-
kind: Cow::Owned(cfg::ControlInstKind::Return),
673+
kind: Cow::Owned(cf::unstructured::ControlInstKind::Return),
668674
inputs: func_def_body.at_body().def().outputs.clone(),
669675
targets: [].into_iter().collect(),
670676
target_phi_values: FxIndexMap::default(),
@@ -683,7 +689,9 @@ impl<'a> FuncLifting<'a> {
683689

684690
NodeKind::Select { kind, scrutinee, cases } => Terminator {
685691
attrs: AttrSet::default(),
686-
kind: Cow::Owned(cfg::ControlInstKind::SelectBranch(kind.clone())),
692+
kind: Cow::Owned(cf::unstructured::ControlInstKind::SelectBranch(
693+
kind.clone(),
694+
)),
687695
inputs: [*scrutinee].into_iter().collect(),
688696
targets: cases
689697
.iter()
@@ -696,7 +704,7 @@ impl<'a> FuncLifting<'a> {
696704
NodeKind::Loop { initial_inputs: _, body, repeat_condition: _ } => {
697705
Terminator {
698706
attrs: AttrSet::default(),
699-
kind: Cow::Owned(cfg::ControlInstKind::Branch),
707+
kind: Cow::Owned(cf::unstructured::ControlInstKind::Branch),
700708
inputs: [].into_iter().collect(),
701709
targets: [CfgPoint::RegionEntry(*body)].into_iter().collect(),
702710
target_phi_values: FxIndexMap::default(),
@@ -716,7 +724,9 @@ impl<'a> FuncLifting<'a> {
716724

717725
NodeKind::ExitInvocation { kind, inputs } => Terminator {
718726
attrs: AttrSet::default(),
719-
kind: Cow::Owned(cfg::ControlInstKind::ExitInvocation(kind.clone())),
727+
kind: Cow::Owned(cf::unstructured::ControlInstKind::ExitInvocation(
728+
kind.clone(),
729+
)),
720730
inputs: inputs.clone(),
721731
targets: [].into_iter().collect(),
722732
target_phi_values: FxIndexMap::default(),
@@ -743,7 +753,7 @@ impl<'a> FuncLifting<'a> {
743753

744754
NodeKind::Select { .. } => Terminator {
745755
attrs: AttrSet::default(),
746-
kind: Cow::Owned(cfg::ControlInstKind::Branch),
756+
kind: Cow::Owned(cf::unstructured::ControlInstKind::Branch),
747757
inputs: [].into_iter().collect(),
748758
targets: [parent_exit].into_iter().collect(),
749759
target_phi_values: region_outputs
@@ -775,7 +785,7 @@ impl<'a> FuncLifting<'a> {
775785
if is_infinite_loop {
776786
Terminator {
777787
attrs: AttrSet::default(),
778-
kind: Cow::Owned(cfg::ControlInstKind::Branch),
788+
kind: Cow::Owned(cf::unstructured::ControlInstKind::Branch),
779789
inputs: [].into_iter().collect(),
780790
targets: [backedge].into_iter().collect(),
781791
target_phi_values,
@@ -784,9 +794,11 @@ impl<'a> FuncLifting<'a> {
784794
} else {
785795
Terminator {
786796
attrs: AttrSet::default(),
787-
kind: Cow::Owned(cfg::ControlInstKind::SelectBranch(
788-
SelectionKind::BoolCond,
789-
)),
797+
kind: Cow::Owned(
798+
cf::unstructured::ControlInstKind::SelectBranch(
799+
SelectionKind::BoolCond,
800+
),
801+
),
790802
inputs: [repeat_condition].into_iter().collect(),
791803
targets: [backedge, parent_exit].into_iter().collect(),
792804
target_phi_values,
@@ -801,7 +813,7 @@ impl<'a> FuncLifting<'a> {
801813
// implied edge from a `Block`'s `Entry` to its `Exit`).
802814
(_, Some(succ_cursor)) => Terminator {
803815
attrs: AttrSet::default(),
804-
kind: Cow::Owned(cfg::ControlInstKind::Branch),
816+
kind: Cow::Owned(cf::unstructured::ControlInstKind::Branch),
805817
inputs: [].into_iter().collect(),
806818
targets: [succ_cursor.point].into_iter().collect(),
807819
target_phi_values: FxIndexMap::default(),
@@ -874,8 +886,10 @@ impl<'a> FuncLifting<'a> {
874886
// SPIR-V allows their targets to just be the whole merge block
875887
// (the same one that `OpSelectionMerge` describes).
876888
let block = &blocks[block_idx];
877-
if let (cfg::ControlInstKind::SelectBranch(_), Some(Merge::Selection(merge_point))) =
878-
(&*block.terminator.kind, block.terminator.merge)
889+
if let (
890+
cf::unstructured::ControlInstKind::SelectBranch(_),
891+
Some(Merge::Selection(merge_point)),
892+
) = (&*block.terminator.kind, block.terminator.merge)
879893
{
880894
for target_idx in 0..block.terminator.targets.len() {
881895
let block = &blocks[block_idx];
@@ -902,7 +916,7 @@ impl<'a> FuncLifting<'a> {
902916
(phis.is_empty()
903917
&& insts.iter().all(|insts| insts.is_empty())
904918
&& *attrs == AttrSet::default()
905-
&& matches!(**kind, cfg::ControlInstKind::Branch)
919+
&& matches!(**kind, cf::unstructured::ControlInstKind::Branch)
906920
&& inputs.is_empty()
907921
&& targets.len() == 1
908922
&& target_phi_values.is_empty()
@@ -927,7 +941,7 @@ impl<'a> FuncLifting<'a> {
927941
&block.terminator;
928942

929943
(*attrs == AttrSet::default()
930-
&& matches!(**kind, cfg::ControlInstKind::Branch)
944+
&& matches!(**kind, cf::unstructured::ControlInstKind::Branch)
931945
&& inputs.is_empty()
932946
&& targets.len() == 1
933947
&& target_phi_values.is_empty()
@@ -953,7 +967,7 @@ impl<'a> FuncLifting<'a> {
953967
new_terminator,
954968
Terminator {
955969
attrs: Default::default(),
956-
kind: Cow::Owned(cfg::ControlInstKind::Unreachable),
970+
kind: Cow::Owned(cf::unstructured::ControlInstKind::Unreachable),
957971
inputs: Default::default(),
958972
targets: Default::default(),
959973
target_phi_values: Default::default(),
@@ -1332,26 +1346,26 @@ impl LazyInst<'_, '_> {
13321346
},
13331347
Self::Terminator { parent_func, terminator } => {
13341348
let inst = match &*terminator.kind {
1335-
cfg::ControlInstKind::Unreachable => wk.OpUnreachable.into(),
1336-
cfg::ControlInstKind::Return => {
1349+
cf::unstructured::ControlInstKind::Unreachable => wk.OpUnreachable.into(),
1350+
cf::unstructured::ControlInstKind::Return => {
13371351
if terminator.inputs.is_empty() {
13381352
wk.OpReturn.into()
13391353
} else {
13401354
wk.OpReturnValue.into()
13411355
}
13421356
}
1343-
cfg::ControlInstKind::ExitInvocation(cfg::ExitInvocationKind::SpvInst(
1357+
cf::unstructured::ControlInstKind::ExitInvocation(
1358+
cf::ExitInvocationKind::SpvInst(inst),
1359+
)
1360+
| cf::unstructured::ControlInstKind::SelectBranch(SelectionKind::SpvInst(
13441361
inst,
13451362
)) => inst.clone(),
13461363

1347-
cfg::ControlInstKind::Branch => wk.OpBranch.into(),
1364+
cf::unstructured::ControlInstKind::Branch => wk.OpBranch.into(),
13481365

1349-
cfg::ControlInstKind::SelectBranch(SelectionKind::BoolCond) => {
1366+
cf::unstructured::ControlInstKind::SelectBranch(SelectionKind::BoolCond) => {
13501367
wk.OpBranchConditional.into()
13511368
}
1352-
cfg::ControlInstKind::SelectBranch(SelectionKind::SpvInst(inst)) => {
1353-
inst.clone()
1354-
}
13551369
};
13561370
spv::InstWithIds {
13571371
without_ids: inst,

0 commit comments

Comments
 (0)