Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .gitmodules
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
[submodule "khronos-spec/SPIRV-Headers"]
path = khronos-spec/SPIRV-Headers
url = https://github.com/KhronosGroup/SPIRV-Headers
branch = vulkan-sdk-1.3.290
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ fn main() -> @location(0) i32 {
```cxx
#[spv.Decoration.Flat]
#[spv.Decoration.Location(Location: 0)]
global_var GV0 in spv.StorageClass.Output: s32
global_var GV0(spv.StorageClass.Output): s32

func F0() -> spv.OpTypeVoid {
loop(v0: s32 <- 1s32, v1: s32 <- 1s32) {
Expand Down
12 changes: 7 additions & 5 deletions examples/spv-lower-link-qptr-lift.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,10 +80,10 @@ fn main() -> std::io::Result<()> {
after_pass("", &module)?;

// HACK(eddyb) this is roughly what Rust-GPU would need.
let layout_config = &spirt::qptr::LayoutConfig {
let layout_config = &spirt::mem::LayoutConfig {
abstract_bool_size_align: (1, 1),
logical_ptr_size_align: (4, 4),
..spirt::qptr::LayoutConfig::VULKAN_SCALAR_LAYOUT
..spirt::mem::LayoutConfig::VULKAN_SCALAR_LAYOUT
};

eprint_duration(|| {
Expand All @@ -92,9 +92,11 @@ fn main() -> std::io::Result<()> {
eprintln!("qptr::lower_from_spv_ptrs");
after_pass("qptr::lower_from_spv_ptrs", &module)?;

eprint_duration(|| spirt::passes::qptr::analyze_uses(&mut module, layout_config));
eprintln!("qptr::analyze_uses");
after_pass("qptr::analyze_uses", &module)?;
eprint_duration(|| {
spirt::passes::qptr::analyze_mem_accesses(&mut module, layout_config)
});
eprintln!("mem::analyze_accesses");
after_pass("mem::analyze_accesses", &module)?;

eprint_duration(|| spirt::passes::qptr::lift_to_spv_ptrs(&mut module, layout_config));
eprintln!("qptr::lift_to_spv_ptrs");
Expand Down
2 changes: 1 addition & 1 deletion khronos-spec/SPIRV-Headers
Submodule SPIRV-Headers updated 116 files
66 changes: 31 additions & 35 deletions src/cfg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1022,41 +1022,37 @@ impl<'a> Structurizer<'a> {
});

let (loop_header_to_exit_targets, incoming_edge_counts_including_loop_exits) =
func_def_body
.unstructured_cfg
.as_ref()
.map(|cfg| {
let loop_header_to_exit_targets = {
let mut loop_finder = LoopFinder::new(cfg);
loop_finder.find_earliest_scc_root_of(func_def_body.body);
loop_finder.loop_header_to_exit_targets
};
func_def_body.unstructured_cfg.as_ref().map_or_default(|cfg| {
let loop_header_to_exit_targets = {
let mut loop_finder = LoopFinder::new(cfg);
loop_finder.find_earliest_scc_root_of(func_def_body.body);
loop_finder.loop_header_to_exit_targets
};

let mut state = TraversalState {
incoming_edge_counts: EntityOrientedDenseMap::new(),
let mut state = TraversalState {
incoming_edge_counts: EntityOrientedDenseMap::new(),

pre_order_visit: |_| {},
post_order_visit: |_| {},
reverse_targets: false,
};
cfg.traverse_whole_func(func_def_body, &mut state);

// HACK(eddyb) treat loop exits as "false edges", that their
// respective loop header "owns", such that structurization
// naturally stops at those loop exits, instead of continuing
// greedily into the loop exterior (producing "maximal loops").
for loop_exit_targets in loop_header_to_exit_targets.values() {
for &exit_target in loop_exit_targets {
*state
.incoming_edge_counts
.entry(exit_target)
.get_or_insert(Default::default()) += IncomingEdgeCount::ONE;
}
pre_order_visit: |_| {},
post_order_visit: |_| {},
reverse_targets: false,
};
cfg.traverse_whole_func(func_def_body, &mut state);

// HACK(eddyb) treat loop exits as "false edges", that their
// respective loop header "owns", such that structurization
// naturally stops at those loop exits, instead of continuing
// greedily into the loop exterior (producing "maximal loops").
for loop_exit_targets in loop_header_to_exit_targets.values() {
for &exit_target in loop_exit_targets {
*state
.incoming_edge_counts
.entry(exit_target)
.get_or_insert(Default::default()) += IncomingEdgeCount::ONE;
}
}

(loop_header_to_exit_targets, state.incoming_edge_counts)
})
.unwrap_or_default();
(loop_header_to_exit_targets, state.incoming_edge_counts)
});

Self {
cx,
Expand Down Expand Up @@ -1548,8 +1544,7 @@ impl<'a> Structurizer<'a> {
// Cache the edge count for backedges (which later get turned into loops).
let accumulated_backedge_count = deferred_edges
.get_edge_bundle_by_target(DeferredTarget::Region(region))
.map(|backedge| backedge.accumulated_count)
.unwrap_or_default();
.map_or_default(|backedge| backedge.accumulated_count);

let old_state = self.structurize_region_state.insert(
region,
Expand Down Expand Up @@ -2035,8 +2030,9 @@ impl<'a> Structurizer<'a> {
}
};

let condition = Some(condition)
.filter(|_| else_target_and_inputs.is_some())
let condition = else_target_and_inputs
.is_some()
.then_some(condition)
.map(|cond| self.materialize_lazy_cond(&cond));
let branch_control_inst = ControlInst {
attrs: AttrSet::default(),
Expand Down
9 changes: 2 additions & 7 deletions src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -348,19 +348,14 @@ pub struct EntityOrientedDenseMap<K: EntityOrientedMapKey<V>, V> {
// since the ideal state is one chunk per map, the slow case might never be hit,
// unless one `EntityOrientedDenseMap` is used with more than one `EntityDefs`,
// which could still maybe be implemented more efficiently than `FxHashMap`.
#[derive(Clone)]
#[derive(Clone, Default)]
enum SmallFxHashMap<K, V> {
#[default]
Empty,
One(K, V),
More(FxHashMap<K, V>),
}

impl<K, V> Default for SmallFxHashMap<K, V> {
fn default() -> Self {
Self::Empty
}
}

impl<K: Copy + Eq + Hash, V: Default> SmallFxHashMap<K, V> {
fn get_mut_or_insert_default(&mut self, k: K) -> &mut V {
// HACK(eddyb) to avoid borrowing issues, this is done in two stages:
Expand Down
46 changes: 39 additions & 7 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,6 @@
clippy::dbg_macro,
clippy::debug_assert_with_mut_call,
clippy::doc_markdown,
clippy::empty_enum,
clippy::enum_glob_use,
clippy::exit,
clippy::expl_impl_clone_on_copy,
Expand All @@ -82,7 +81,6 @@
clippy::flat_map_option,
clippy::float_cmp_const,
clippy::fn_params_excessive_bools,
clippy::from_iter_instead_of_collect,
clippy::if_let_mutex,
clippy::implicit_clone,
clippy::imprecise_flops,
Expand Down Expand Up @@ -121,7 +119,6 @@
clippy::string_add_assign,
clippy::string_add,
clippy::string_lit_as_bytes,
clippy::string_to_string,
clippy::todo,
clippy::trait_duplication_in_bounds,
clippy::unimplemented,
Expand Down Expand Up @@ -169,6 +166,7 @@ pub mod passes {
pub mod link;
pub mod qptr;
}
pub mod mem;
pub mod qptr;
pub mod spv;

Expand Down Expand Up @@ -397,11 +395,28 @@ pub enum Attr {
// of `AttrSetDef::{dbg_src_loc,set_dbg_src_loc}`.
DbgSrcLoc(OrdAssertEq<DbgSrcLoc>),

/// Memory-specific attributes (see [`mem::MemAttr`]).
#[from]
Mem(mem::MemAttr),

/// `QPtr`-specific attributes (see [`qptr::QPtrAttr`]).
#[from]
QPtr(qptr::QPtrAttr),

SpvAnnotation(spv::Inst),
SpvAnnotation {
spv_inst: spv::Inst,

/// If present, each "instance" represents a different use of `spv_inst`,
/// grouped together only because the non-ID operands (enumerand/literals)
/// inside `spv::Inst` are not enough to uniquely identify an annotation
/// (i.e. at least some of the `Const` IDs are semantically part of the
/// "key" side `Attr`, which should normally be outside the `OrdAssertEq`).
//
// HACK(eddyb) this is enough of a complication to furthger call into
// question the use of ordered sets for `AttrSet`s, in the first place.
#[allow(clippy::type_complexity)]
per_instance_const_inputs: Option<OrdAssertEq<Rc<Vec<SmallVec<[Const; 2]>>>>>,
},

/// Some SPIR-V instructions, like `OpFunction`, take a bitflags operand
/// that is effectively an optimization over using `OpDecorate`.
Expand Down Expand Up @@ -489,7 +504,7 @@ pub enum DiagMsgPart {
Attrs(AttrSet),
Type(Type),
Const(Const),
QPtrUsage(qptr::QPtrUsage),
MemAccesses(mem::MemAccesses),
}

/// Wrapper to limit `Ord` for interned index types (e.g. [`InternedStr`])
Expand Down Expand Up @@ -555,6 +570,10 @@ pub enum TypeKind {
type_and_const_inputs: SmallVec<[TypeOrConst; 2]>,
},

/// The type of a [`ConstKind::SpvTypeOperand`] constant, i.e. a [`Type`]
/// embedded in a [`Value`] to be passed as a SPIR-V operand.
SpvTypeOperand,

/// The type of a [`ConstKind::SpvStringLiteralForExtInst`] constant, i.e.
/// a SPIR-V `OpString` with no actual type in SPIR-V.
SpvStringLiteralForExtInst,
Expand Down Expand Up @@ -590,14 +609,23 @@ pub struct ConstDef {

#[derive(Clone, PartialEq, Eq, Hash)]
pub enum ConstKind {
// FIXME(eddyb) maybe merge these? however, their connection is somewhat
// tenuous (being one of the LLVM-isms SPIR-V inherited, among other things),
// there's still the need to rename "global variable" post-`Var`-refactor,
// and last but not least, `PtrToFunc` needs `SPV_INTEL_function_pointers`,
// an OpenCL-only extension Intel came up with for their own SPIR-V tooling.
PtrToGlobalVar(GlobalVar),
PtrToFunc(Func),

// HACK(eddyb) this is a fallback case that should become increasingly rare
// (especially wrt recursive consts), `Rc` means it can't bloat `ConstDef`.
SpvInst {
spv_inst_and_const_inputs: Rc<(spv::Inst, SmallVec<[Const; 4]>)>,
},

/// Type used as an operand to a SPIR-V instruction (other than result type).
SpvTypeOperand(Type),

/// SPIR-V `OpString`, but only when used as an operand for an `OpExtInst`,
/// which can't have literals itself - for non-string literals `OpConstant*`
/// are readily usable, but only `OpString` is supported for string literals.
Expand Down Expand Up @@ -638,7 +666,7 @@ pub struct GlobalVarDecl {

/// When `type_of_ptr_to` is `QPtr`, `shape` must be used to describe the
/// global variable (see `GlobalVarShape`'s documentation for more details).
pub shape: Option<qptr::shapes::GlobalVarShape>,
pub shape: Option<mem::shapes::GlobalVarShape>,

/// The address space the global variable will be allocated into.
pub addr_space: AddrSpace,
Expand Down Expand Up @@ -679,7 +707,7 @@ pub struct FuncDecl {
pub def: DeclDef<FuncDefBody>,
}

#[derive(Copy, Clone)]
#[derive(Copy, Clone, PartialEq, Eq)]
pub struct FuncParam {
pub attrs: AttrSet,

Expand Down Expand Up @@ -947,6 +975,10 @@ pub enum DataInstKind {
// to avoid needing special handling for recursion where it's impossible.
FuncCall(Func),

/// Memory-specific operations (see [`mem::MemOp`]).
#[from]
Mem(mem::MemOp),

/// `QPtr`-specific operations (see [`qptr::QPtrOp`]).
#[from]
QPtr(qptr::QPtrOp),
Expand Down
Loading
Loading