Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
aa9ef5e
Update pinned toolchain to nightly-2026-03-06
LegNeato Mar 6, 2026
2de9db3
Port backend trait surface to rustc 1.96 APIs
LegNeato Mar 6, 2026
285545f
Port backend internals and ABI plumbing to latest nightly
LegNeato Mar 6, 2026
be7148b
Handle newer panic format_args lowering patterns
LegNeato Mar 6, 2026
771aa99
Handle nightly panic format_args lowering and unsized const reification
LegNeato Mar 6, 2026
0453c80
Fix new nightly clippy suggestions in type trie and linker
LegNeato Mar 6, 2026
543eb26
Port linker test harness to current rustc session APIs
LegNeato Mar 6, 2026
a303ad3
Resolve new collapsible-match clippy lints in example runners
LegNeato Mar 6, 2026
c70cdc3
Guard runtime-array const reification against truncation and ZST tails
LegNeato Mar 6, 2026
a8b858a
Replace fmt::Arguments sentinel metadata with typed constructor tags
LegNeato Mar 6, 2026
2af3b54
Gate bounds/precondition panic-entry detection to non-local core symbols
LegNeato Mar 6, 2026
1c64a85
Fix panic-entry matching and disable-pqp unused-features lint
LegNeato Mar 7, 2026
6c9a7b4
Bless compiletest stderr for updated nightly diagnostics
LegNeato Mar 7, 2026
e0ef82c
Rustfmt codegen_cx panic-entry matcher formatting
LegNeato Mar 7, 2026
d5b1aef
spirv-builder: pass -Zjson-target-spec for JSON targets
LegNeato Mar 7, 2026
65058a9
compiletests: bless sampled image query_size_lod stderr
LegNeato Mar 7, 2026
5795f08
codegen: adapt panic format_args decompiler for new nightly shapes
LegNeato Mar 7, 2026
3ae3af3
codegen: stop treating core precondition_check as panic entry point
LegNeato Mar 7, 2026
7669aa1
codegen: harden panic format_args fallback for split/pass-through shapes
LegNeato Mar 7, 2026
899a7b0
codegen: preserve raw fn ABI query invariants
LegNeato Mar 7, 2026
156887d
codegen: harden panic message decoding for nightly call shapes
LegNeato Mar 7, 2026
facad7d
codegen: preserve panic_const messages in panic fast path
LegNeato Mar 7, 2026
b4a6a4c
codegen: decode panic_bounds_check debug-printf args
LegNeato Mar 7, 2026
e900eb2
compiletests: normalize relative spirv-std paths in stderr
LegNeato Mar 7, 2026
c3cedf9
fix lint and spv1.3 stderr for panic/message updates
LegNeato Mar 7, 2026
12cc6a9
codegen: use size-based alloca for panic arg spill
LegNeato Mar 7, 2026
12c5bb4
codegen: emit typed local panic spills without typed_alloca
LegNeato Mar 7, 2026
f9d718f
codegen: align funclet stubs and likely handling notes
LegNeato Mar 11, 2026
203c750
codegen: fix panic entry-point classification and arg decoding
LegNeato Mar 11, 2026
2f54cdf
codegen: match likely/unlikely via intrinsic symbols
LegNeato Mar 11, 2026
ee49a27
compiletests: update ptr_copy stderr for extra pointer-cast diagnostic
LegNeato Mar 11, 2026
db063f6
style: run cargo fmt --all
LegNeato Mar 11, 2026
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
2 changes: 1 addition & 1 deletion crates/rustc_codegen_spirv-types/src/compile_result.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ impl<'a> Trie<'a> {

fn emit(&self, builder: &mut String, full_name: String, indent: usize) {
let mut children = self.children.iter().collect::<Vec<_>>();
children.sort_unstable_by(|(k1, _), (k2, _)| k1.cmp(k2));
children.sort_unstable_by_key(|(k1, _)| *k1);
for (child_name, child) in children {
let full_child_name = if full_name.is_empty() {
(*child_name).to_string()
Expand Down
8 changes: 3 additions & 5 deletions crates/rustc_codegen_spirv/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@ use std::{env, fs, mem};
/// `cargo publish`. We need to figure out a way to do this properly, but let's hardcode it for now :/
//const REQUIRED_RUST_TOOLCHAIN: &str = include_str!("../../rust-toolchain.toml");
const REQUIRED_RUST_TOOLCHAIN: &str = r#"[toolchain]
channel = "nightly-2025-11-13"
channel = "nightly-2026-03-06"
components = ["rust-src", "rustc-dev", "llvm-tools"]
# commit_hash = 01867557cd7dbe256a031a7b8e28d05daecd75ab"#;
# commit_hash = 69370dc4a8862b8401615a2a7b950704ba66c495"#;

fn rustc_output(arg: &str) -> Result<String, Box<dyn Error>> {
let rustc = env::var("RUSTC").unwrap_or_else(|_| "rustc".into());
Expand Down Expand Up @@ -322,16 +322,14 @@ pub(super) fn elf_e_flags(architecture: Architecture, sess: &Session) -> u32 {",
let pqp_cg_ssa_top_level = all_extern_crates
+ r#"

// HACK(eddyb) reexporting macro output for further macro use (can't patch macro).
use maybe_pqp_cg_ssa::fluent_generated;

#[allow(unused, clippy::all, clippy::pedantic, clippy::restriction)]
#[path = "pqp_cg_ssa/src/lib.rs"]
mod maybe_pqp_cg_ssa;
"#;
fs::write(out_dir.join("pqp_cg_ssa.rs"), pqp_cg_ssa_top_level)?;

println!("cargo::rustc-check-cfg=cfg(rustc_codegen_spirv_disable_pqp_cg_ssa)");
println!("cargo::rustc-check-cfg=cfg(bootstrap)");

// HACK(eddyb) `if cfg!(llvm_enzyme)` added upstream for autodiff support.
println!("cargo::rustc-check-cfg=cfg(llvm_enzyme)");
Expand Down
98 changes: 66 additions & 32 deletions crates/rustc_codegen_spirv/src/abi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,15 @@ use rustc_abi::{
use rustc_data_structures::fx::FxHashMap;
use rustc_errors::ErrorGuaranteed;
use rustc_index::Idx;
use rustc_middle::query::Providers;
use rustc_middle::ty::layout::{FnAbiOf, LayoutOf, TyAndLayout};
use rustc_middle::ty::{
self, Const, CoroutineArgs, CoroutineArgsExt as _, FloatTy, IntTy, PolyFnSig, Ty, TyCtxt,
TyKind, UintTy,
TyKind, UintTy, ValTreeKindExt,
};
use rustc_middle::ty::{GenericArgsRef, ScalarInt};
use rustc_middle::util::Providers;
use rustc_middle::{bug, span_bug};
use rustc_session::config::OptLevel;
use rustc_span::DUMMY_SP;
use rustc_span::def_id::DefId;
use rustc_span::{Span, Symbol};
Expand All @@ -29,6 +30,19 @@ use std::cell::RefCell;
use std::collections::hash_map::Entry;
use std::fmt;

fn rewrite_c_abi_to_rust<'tcx>(
fn_sig: ty::EarlyBinder<'tcx, ty::PolyFnSig<'tcx>>,
) -> ty::EarlyBinder<'tcx, ty::PolyFnSig<'tcx>> {
fn_sig.map_bound(|outer| {
outer.map_bound(|mut inner| {
if let Abi::C { .. } = inner.abi {
inner.abi = Abi::Rust;
}
inner
})
})
}

pub(crate) fn provide(providers: &mut Providers) {
// This is a lil weird: so, we obviously don't support C ABIs at all. However, libcore does declare some extern
// C functions:
Expand All @@ -44,18 +58,19 @@ pub(crate) fn provide(providers: &mut Providers) {
// NOTE: this used to rewrite to `extern "unadjusted"`, but rustc now
// validates `#[rustc_pass_indirectly_in_non_rustic_abis]` for non-Rust ABIs,
// and `Unadjusted` does not satisfy that requirement.
providers.fn_sig = |tcx, def_id| {
providers.queries.fn_sig = |tcx, def_id| {
// We can't capture the old fn_sig and just call that, because fn_sig is a `fn`, not a `Fn`, i.e. it can't
// capture variables. Fortunately, the defaults are exposed (thanks rustdoc), so use that instead.
let result = (rustc_interface::DEFAULT_QUERY_PROVIDERS.fn_sig)(tcx, def_id);
result.map_bound(|outer| {
outer.map_bound(|mut inner| {
if let Abi::C { .. } = inner.abi {
inner.abi = Abi::Rust;
}
inner
})
})
let result = (rustc_interface::DEFAULT_QUERY_PROVIDERS.queries.fn_sig)(tcx, def_id);
rewrite_c_abi_to_rust(result)
};
providers.extern_queries.fn_sig = |tcx, def_id| {
// We can't capture the old fn_sig and just call that, because fn_sig is a `fn`, not a `Fn`, i.e. it can't
// capture variables. Fortunately, the defaults are exposed (thanks rustdoc), so use that instead.
let result = (rustc_interface::DEFAULT_QUERY_PROVIDERS
.extern_queries
.fn_sig)(tcx, def_id);
rewrite_c_abi_to_rust(result)
};

// For the Rust ABI, `FnAbi` adjustments are backend-agnostic, but they will
Expand All @@ -67,7 +82,7 @@ pub(crate) fn provide(providers: &mut Providers) {
fn_abi: &'tcx FnAbi<'tcx, Ty<'tcx>>,
) -> &'tcx FnAbi<'tcx, Ty<'tcx>> {
let readjust_arg_abi = |arg: &ArgAbi<'tcx, Ty<'tcx>>| {
let mut arg = ArgAbi::new(&tcx, arg.layout, |_, _, _| ArgAttributes::new());
let mut arg = ArgAbi::new(&tcx, arg.layout, |_, _| ArgAttributes::new());
// FIXME: this is bad! https://github.com/rust-lang/rust/issues/115666
// <https://github.com/rust-lang/rust/commit/eaaa03faf77b157907894a4207d8378ecaec7b45>
arg.make_direct_deprecated();
Expand All @@ -86,6 +101,12 @@ pub(crate) fn provide(providers: &mut Providers) {
arg.mode = PassMode::Ignore;
}

// SPIR-V backend lowers arguments by-value and cannot handle
// backend-specific indirection/casts at this layer.
if matches!(arg.mode, PassMode::Cast { .. } | PassMode::Indirect { .. }) {
arg.mode = PassMode::Direct(ArgAttributes::new());
}

arg
};
tcx.arena.alloc(FnAbi {
Expand All @@ -101,12 +122,30 @@ pub(crate) fn provide(providers: &mut Providers) {
can_unwind: fn_abi.can_unwind,
})
}
providers.fn_abi_of_fn_ptr = |tcx, key| {
let result = (rustc_interface::DEFAULT_QUERY_PROVIDERS.fn_abi_of_fn_ptr)(tcx, key);
providers.queries.fn_abi_of_fn_ptr = |tcx, key| {
let result = (rustc_interface::DEFAULT_QUERY_PROVIDERS
.queries
.fn_abi_of_fn_ptr)(tcx, key);
Ok(readjust_fn_abi(tcx, result?))
};
providers.fn_abi_of_instance = |tcx, key| {
let result = (rustc_interface::DEFAULT_QUERY_PROVIDERS.fn_abi_of_instance)(tcx, key);
providers.queries.fn_abi_of_instance_no_deduced_attrs = |tcx, key| {
let result = (rustc_interface::DEFAULT_QUERY_PROVIDERS
.queries
.fn_abi_of_instance_no_deduced_attrs)(tcx, key);
// Keep this query in its original shape while `fn_abi_of_instance_raw`
// is being computed: rustc validates strict invariants there.
// Otherwise, if `fn_abi_of_instance` would route through this query
// directly (e.g. incremental or opt-level=0), apply SPIR-V readjustment.
if tcx.sess.opts.optimize != OptLevel::No && tcx.sess.opts.incremental.is_none() {
result
} else {
Ok(readjust_fn_abi(tcx, result?))
}
};
providers.queries.fn_abi_of_instance_raw = |tcx, key| {
let result = (rustc_interface::DEFAULT_QUERY_PROVIDERS
.queries
.fn_abi_of_instance_raw)(tcx, key);
Ok(readjust_fn_abi(tcx, result?))
};

Expand All @@ -116,7 +155,7 @@ pub(crate) fn provide(providers: &mut Providers) {
//
// FIXME(eddyb) same as the FIXME comment on `check_well_formed`:
// need to migrate away from `#[repr(simd)]` ASAP.
providers.check_mono_item = |_, _| {};
providers.queries.check_mono_item = |_, _| {};
}

/// If a struct contains a pointer to itself, even indirectly, then doing a naiive recursive walk
Expand Down Expand Up @@ -291,6 +330,7 @@ impl<'tcx> ConvSpirvType<'tcx> for TyAndLayout<'tcx> {
span = cx.tcx.def_span(adt.did());
}

#[allow(deprecated)]
let attrs = AggregatedSpirvAttributes::parse(cx, cx.tcx.get_all_attrs(adt.did()));

if let Some(intrinsic_type_attr) = attrs.intrinsic_type.map(|attr| attr.value)
Expand Down Expand Up @@ -395,6 +435,10 @@ impl<'tcx> ConvSpirvType<'tcx> for TyAndLayout<'tcx> {
}
.def(span, cx)
}
BackendRepr::ScalableVector { .. } => cx
.tcx
.dcx()
.fatal("scalable vectors are not supported in SPIR-V backend"),
BackendRepr::Memory { sized: _ } => trans_aggregate(cx, span, *self),
}
}
Expand Down Expand Up @@ -614,22 +658,11 @@ fn trans_aggregate<'tcx>(cx: &CodegenCx<'tcx>, span: Span, ty: TyAndLayout<'tcx>
.def(span, cx)
}
}
FieldsShape::Arbitrary {
offsets: _,
memory_index: _,
} => trans_struct_or_union(cx, span, ty, None),
FieldsShape::Arbitrary { .. } => trans_struct_or_union(cx, span, ty, None),
}
}

#[cfg_attr(
not(rustc_codegen_spirv_disable_pqp_cg_ssa),
expect(
unused,
reason = "actually used from \
`<rustc_codegen_ssa::traits::ConstCodegenMethods for CodegenCx<'_>>::const_struct`, \
but `rustc_codegen_ssa` being `pqp_cg_ssa` makes that trait unexported"
)
)]
#[cfg_attr(not(rustc_codegen_spirv_disable_pqp_cg_ssa), allow(unused))]
// returns (field_offsets, size, align)
pub fn auto_struct_layout(
cx: &CodegenCx<'_>,
Expand Down Expand Up @@ -866,7 +899,8 @@ fn trans_intrinsic_type<'tcx>(
} = const_.to_value();
assert!(const_ty.is_integral());
const_val
.try_to_scalar_int()
.try_to_scalar()
.and_then(|scalar| scalar.try_to_scalar_int().ok())
.and_then(P::from_scalar_int)
.ok_or_else(|| {
cx.tcx
Expand Down
12 changes: 7 additions & 5 deletions crates/rustc_codegen_spirv/src/attr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -514,7 +514,9 @@ pub(crate) fn provide(providers: &mut Providers) {
*providers = Providers {
check_mod_attrs: |tcx, module_def_id| {
// Run both the default checks, and our `#[spirv(...)]` ones.
(rustc_interface::DEFAULT_QUERY_PROVIDERS.check_mod_attrs)(tcx, module_def_id);
(rustc_interface::DEFAULT_QUERY_PROVIDERS
.queries
.check_mod_attrs)(tcx, module_def_id);
check_mod_attrs(tcx, module_def_id);
},
..*providers
Expand All @@ -537,10 +539,10 @@ fn parse_attrs_for_checking<'a>(
Attribute::Unparsed(item) => {
// #[...]
let s = &item.path.segments;
if let Some(rust_gpu) = s.get(0) && rust_gpu.name == sym.rust_gpu {
if let Some(rust_gpu) = s.get(0) && *rust_gpu == sym.rust_gpu {
// #[rust_gpu ...]
match s.get(1) {
Some(command) if command.name == sym.spirv_attr_with_version => {
Some(command) if *command == sym.spirv_attr_with_version => {
// #[rust_gpu::spirv ...]
if let Some(args) = attr.meta_item_list() {
// #[rust_gpu::spirv(...)]
Expand All @@ -554,11 +556,11 @@ fn parse_attrs_for_checking<'a>(
))
}
}
Some(command) if command.name == sym.vector => {
Some(command) if *command == sym.vector => {
// #[rust_gpu::vector ...]
match s.get(2) {
// #[rust_gpu::vector::v1]
Some(version) if version.name == sym.v1 => {
Some(version) if *version == sym.v1 => {
Ok(SmallVec::from_iter([
Ok((attr.span(), SpirvAttribute::IntrinsicType(IntrinsicType::Vector)))
]))
Expand Down
24 changes: 18 additions & 6 deletions crates/rustc_codegen_spirv/src/builder/builder_methods.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1825,6 +1825,10 @@ impl<'a, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'tcx> {
self.declare_func_local_var(self.type_array(self.type_i8(), size.bytes()), align)
}

fn scalable_alloca(&mut self, _elt: u64, _align: Align, _element_ty: Ty<'_>) -> Self::Value {
bug!("scalable alloca is not supported in SPIR-V backend")
}

fn load(&mut self, ty: Self::Type, ptr: Self::Value, _align: Align) -> Self::Value {
let (ptr, access_ty) = self.adjust_pointer_for_typed_access(ptr, ty);
let loaded_val = ptr.const_fold_load(self).unwrap_or_else(|| {
Expand Down Expand Up @@ -3057,15 +3061,15 @@ impl<'a, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'tcx> {
_parent: Option<Self::Value>,
_args: &[Self::Value],
) -> Self::Funclet {
todo!()
bug!("Funclets are not supported")
}

fn cleanup_ret(&mut self, _funclet: &Self::Funclet, _unwind: Option<Self::BasicBlock>) {
todo!()
bug!("Funclets are not supported")
}

fn catch_pad(&mut self, _parent: Self::Value, _args: &[Self::Value]) -> Self::Funclet {
todo!()
bug!("Funclets are not supported")
}

fn catch_switch(
Expand All @@ -3074,7 +3078,11 @@ impl<'a, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'tcx> {
_unwind: Option<Self::BasicBlock>,
_handlers: &[Self::BasicBlock],
) -> Self::Value {
todo!()
bug!("Funclets are not supported")
}

fn get_funclet_cleanuppad(&self, _funclet: &Self::Funclet) -> Self::Value {
bug!("Funclets are not supported")
}

fn atomic_cmpxchg(
Expand Down Expand Up @@ -3372,8 +3380,12 @@ impl<'a, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'tcx> {
}

if is_panic_entry_point {
return DecodedFormatArgs::try_decode_and_remove_format_args(self, args)
.codegen_panic(self, result_type);
return DecodedFormatArgs::try_decode_and_remove_format_args(
self,
args,
instance_def_id,
)
.codegen_panic(self, result_type);
}
if buffer_load_intrinsic {
return self.codegen_buffer_load_intrinsic(fn_abi, result_type, args);
Expand Down
Loading
Loading