Skip to content
Merged
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
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
cargo-features = ["profile-rustflags"]

[package]
name = "drop_glue"
version = "0.1.0"
Expand All @@ -11,3 +13,18 @@ license = "Apache-2.0"
cuda-core = { path = "../../../../../cuda-core" }
cuda-device = { path = "../../../cuda-device" }
cuda-host = { path = "../../../cuda-host" }

# The compile-only probes need each destructor's own MIR to reach the importer:
# a CFG cycle in `LoopingDrop::drop`, the recursive call in `RecursiveDrop::drop`
# and the two-way branch in `DiamondDrop::drop`. At default release settings
# rustc's MIR inliner folds the empty callees into the destructors and the
# destructors into their glue first. `#[inline(never)]` is not the answer:
# it is carried to LLVM as `noinline`, so the destructors would stay real PTX
# functions and the optimized kernels would call them instead of showing the
# store-then-self-loop that verify-code-shape.sh checks. Switching MIR inlining
# off for this one crate keeps the calls for LLVM to inline. Scoping the flag
# to this package keeps the shared dependency tree identical to every other
# example; a global RUSTFLAGS entry would re-key every dependency unit and
# force a full second dependency-tree build in CI.
[profile.release.package.drop_glue]
rustflags = ["-Zinline-mir=no"]
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,10 @@ checks the optimized PTX. For the diverging probes the pre-drop store
remains and is immediately followed by an unconditional self-loop, while
the unreachable post-drop store is absent. For the reconverging probe both
stores remain. The PTX adjacency holds because `opt -O2` inlines the
retained glue; `#[inline(never)]` is not propagated as `noinline`.
retained glue and the destructors. They carry no inline attribute, since
`#[inline(never)]` reaches LLVM as `noinline` and would keep them real PTX
functions; MIR inlining is off for this crate instead (`Cargo.toml`), so the
importer still sees each destructor's own MIR.

These kernels are compiled but **never launched by `main`**. Do not launch
the diverging probes manually: their destructors intentionally never
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,20 +42,20 @@ impl Drop for DropMarker {
}

// Compile-only regression probes. These destructors intentionally never return;
// their kernels are generated but never launched by `main`.
// their kernels are generated but never launched by `main`. MIR inlining is
// off for this crate (see Cargo.toml) so each destructor reaches the importer
// with its own MIR.
#[allow(dead_code)]
struct LoopingDrop(u8);

impl Drop for LoopingDrop {
#[inline(never)]
#[allow(clippy::empty_loop)]
fn drop(&mut self) {
loop {}
}
}

#[allow(unconditional_recursion)]
#[inline(never)]
fn recursive_noop() {
recursive_noop();
}
Expand All @@ -64,7 +64,6 @@ fn recursive_noop() {
struct RecursiveDrop(u8);

impl Drop for RecursiveDrop {
#[inline(never)]
fn drop(&mut self) {
recursive_noop();
}
Expand All @@ -73,18 +72,17 @@ impl Drop for RecursiveDrop {
// Precision control for the proof. An effect-free destructor whose two
// branches join back together returns on every path, so the proof must keep
// accepting it and lower the drop to a plain branch. The callees have visible
// empty bodies; `#[inline(never)]` keeps the diamond in the destructor's MIR.
#[inline(never)]
// empty bodies. MIR inlining is off for this crate (see Cargo.toml), which
// keeps the diamond in the destructor's MIR; `#[inline(never)]` would reach
// LLVM as `noinline` and keep these helpers real PTX functions.
fn left_noop() {}

#[inline(never)]
fn right_noop() {}

#[allow(dead_code)]
struct DiamondDrop(u8);

impl Drop for DiamondDrop {
#[inline(never)]
fn drop(&mut self) {
if self.0 == 0 {
left_noop()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,10 +100,12 @@ def require_store(body, value, name, label="pre-drop"):
return store.end()

# The PTX adjacency below holds because `opt -O2` inlines the retained glue
# and the destructor into the kernel: `#[inline(never)]` is not propagated as
# `noinline`, as the cluster example's shape check also notes. The
# drop_glue.ll assertion is the one that tracks the importer's own decision;
# this check confirms what LLVM made of the call it kept.
# and the destructor into the kernel. The destructors carry no inline
# attribute: `#[inline(never)]` reaches LLVM as `noinline` and would keep them
# real PTX functions, so the kernel would call them instead. MIR inlining is
# off for this crate (Cargo.toml) so the importer still sees each destructor's
# own MIR. The drop_glue.ll assertion is the one that tracks the importer's
# own decision; this check confirms what LLVM made of the call it kept.
def require_nonreturning_loop(body, after_store, name):
# Both optimized probes lower to a store followed by an unconditional
# self-loop. Tie the loop to that store's continuation: an unrelated
Expand Down
Loading