Skip to content

Commit b552a64

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

File tree

11 files changed

+567
-512
lines changed

11 files changed

+567
-512
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;
@@ -3853,7 +3853,7 @@ impl Print for FuncAt<'_, Node> {
38533853
])
38543854
}
38553855
NodeKind::ExitInvocation {
3856-
kind: cfg::ExitInvocationKind::SpvInst(spv::Inst { opcode, imms }),
3856+
kind: cf::ExitInvocationKind::SpvInst(spv::Inst { opcode, imms }),
38573857
inputs,
38583858
} => printer.pretty_spv_inst(
38593859
kw_style,
@@ -4269,7 +4269,7 @@ impl Print for FuncAt<'_, DataInst> {
42694269
}
42704270
}
42714271

4272-
impl Print for cfg::ControlInst {
4272+
impl Print for cf::unstructured::ControlInst {
42734273
type Output = pretty::Fragment;
42744274
fn print(&self, printer: &Printer<'_>) -> pretty::Fragment {
42754275
let Self { attrs, kind, inputs, targets, target_inputs } = self;
@@ -4295,12 +4295,12 @@ impl Print for cfg::ControlInst {
42954295
});
42964296

42974297
let def = match kind {
4298-
cfg::ControlInstKind::Unreachable => {
4298+
cf::unstructured::ControlInstKind::Unreachable => {
42994299
// FIXME(eddyb) use `targets.is_empty()` when that is stabilized.
43004300
assert!(targets.len() == 0 && inputs.is_empty());
43014301
kw("unreachable")
43024302
}
4303-
cfg::ControlInstKind::Return => {
4303+
cf::unstructured::ControlInstKind::Return => {
43044304
// FIXME(eddyb) use `targets.is_empty()` when that is stabilized.
43054305
assert!(targets.len() == 0);
43064306
match inputs[..] {
@@ -4309,10 +4309,9 @@ impl Print for cfg::ControlInst {
43094309
_ => unreachable!(),
43104310
}
43114311
}
4312-
cfg::ControlInstKind::ExitInvocation(cfg::ExitInvocationKind::SpvInst(spv::Inst {
4313-
opcode,
4314-
imms,
4315-
})) => {
4312+
cf::unstructured::ControlInstKind::ExitInvocation(cf::ExitInvocationKind::SpvInst(
4313+
spv::Inst { opcode, imms },
4314+
)) => {
43164315
// FIXME(eddyb) use `targets.is_empty()` when that is stabilized.
43174316
assert!(targets.len() == 0);
43184317
printer.pretty_spv_inst(
@@ -4323,12 +4322,12 @@ impl Print for cfg::ControlInst {
43234322
)
43244323
}
43254324

4326-
cfg::ControlInstKind::Branch => {
4325+
cf::unstructured::ControlInstKind::Branch => {
43274326
assert_eq!((targets.len(), inputs.len()), (1, 0));
43284327
targets.next().unwrap()
43294328
}
43304329

4331-
cfg::ControlInstKind::SelectBranch(kind) => {
4330+
cf::unstructured::ControlInstKind::SelectBranch(kind) => {
43324331
assert_eq!(inputs.len(), 1);
43334332
kind.print_with_scrutinee_and_cases(printer, kw_style, inputs[0], targets)
43344333
}

src/spv/lift.rs

Lines changed: 39 additions & 27 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(),
@@ -877,7 +889,7 @@ impl<'a> FuncLifting<'a> {
877889
original_terminator;
878890

879891
*attrs == AttrSet::default()
880-
&& matches!(**kind, cfg::ControlInstKind::Branch)
892+
&& matches!(**kind, cf::unstructured::ControlInstKind::Branch)
881893
&& inputs.is_empty()
882894
&& targets.len() == 1
883895
&& target_phi_values.is_empty()
@@ -903,7 +915,7 @@ impl<'a> FuncLifting<'a> {
903915
new_terminator,
904916
Terminator {
905917
attrs: Default::default(),
906-
kind: Cow::Owned(cfg::ControlInstKind::Unreachable),
918+
kind: Cow::Owned(cf::unstructured::ControlInstKind::Unreachable),
907919
inputs: Default::default(),
908920
targets: Default::default(),
909921
target_phi_values: Default::default(),
@@ -1282,26 +1294,26 @@ impl LazyInst<'_, '_> {
12821294
},
12831295
Self::Terminator { parent_func, terminator } => {
12841296
let inst = match &*terminator.kind {
1285-
cfg::ControlInstKind::Unreachable => wk.OpUnreachable.into(),
1286-
cfg::ControlInstKind::Return => {
1297+
cf::unstructured::ControlInstKind::Unreachable => wk.OpUnreachable.into(),
1298+
cf::unstructured::ControlInstKind::Return => {
12871299
if terminator.inputs.is_empty() {
12881300
wk.OpReturn.into()
12891301
} else {
12901302
wk.OpReturnValue.into()
12911303
}
12921304
}
1293-
cfg::ControlInstKind::ExitInvocation(cfg::ExitInvocationKind::SpvInst(
1305+
cf::unstructured::ControlInstKind::ExitInvocation(
1306+
cf::ExitInvocationKind::SpvInst(inst),
1307+
)
1308+
| cf::unstructured::ControlInstKind::SelectBranch(SelectionKind::SpvInst(
12941309
inst,
12951310
)) => inst.clone(),
12961311

1297-
cfg::ControlInstKind::Branch => wk.OpBranch.into(),
1312+
cf::unstructured::ControlInstKind::Branch => wk.OpBranch.into(),
12981313

1299-
cfg::ControlInstKind::SelectBranch(SelectionKind::BoolCond) => {
1314+
cf::unstructured::ControlInstKind::SelectBranch(SelectionKind::BoolCond) => {
13001315
wk.OpBranchConditional.into()
13011316
}
1302-
cfg::ControlInstKind::SelectBranch(SelectionKind::SpvInst(inst)) => {
1303-
inst.clone()
1304-
}
13051317
};
13061318
spv::InstWithIds {
13071319
without_ids: inst,

0 commit comments

Comments
 (0)