From fca717db741f0096e4d0459bede26bc43f26ee69 Mon Sep 17 00:00:00 2001 From: Christian Legnitto Date: Wed, 30 Aug 2023 16:09:46 -0400 Subject: [PATCH 1/8] Update to nightly-2023-08-29 --- Cargo.lock | 5 +- crates/rustc_codegen_spirv/Cargo.toml | 7 ++ crates/rustc_codegen_spirv/build.rs | 6 +- crates/rustc_codegen_spirv/src/abi.rs | 46 ++++++----- crates/rustc_codegen_spirv/src/attr.rs | 10 +-- .../src/builder/byte_addressable_buffer.rs | 2 +- .../src/builder/intrinsics.rs | 6 +- .../src/builder/spirv_asm.rs | 12 +-- .../src/codegen_cx/constant.rs | 14 +--- .../src/codegen_cx/declare.rs | 8 +- .../rustc_codegen_spirv/src/codegen_cx/mod.rs | 10 ++- .../src/codegen_cx/type_.rs | 10 +-- crates/rustc_codegen_spirv/src/lib.rs | 24 ++++-- crates/rustc_codegen_spirv/src/link.rs | 4 +- crates/rustc_codegen_spirv/src/linker/test.rs | 80 +++++++++++-------- rust-toolchain.toml | 6 +- 16 files changed, 138 insertions(+), 112 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d58f05163e..8354e79cb7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2041,6 +2041,7 @@ dependencies = [ "spirv-tools", "syn", "tempfile", + "termcolor", ] [[package]] @@ -2473,9 +2474,9 @@ dependencies = [ [[package]] name = "termcolor" -version = "1.1.2" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4" +checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" dependencies = [ "winapi-util", ] diff --git a/crates/rustc_codegen_spirv/Cargo.toml b/crates/rustc_codegen_spirv/Cargo.toml index 4b94d02edf..6188b59c03 100644 --- a/crates/rustc_codegen_spirv/Cargo.toml +++ b/crates/rustc_codegen_spirv/Cargo.toml @@ -62,6 +62,13 @@ spirt = "0.3.0" lazy_static = "1.4.0" itertools = "0.10.5" +# `termcolor` is needed because we cannot construct an Emitter after it was added in +# https://github.com/rust-lang/rust/pull/114104. This can be removed when +# https://github.com/rust-lang/rust/pull/115393 lands. +# We need to construct an emitter as yet another workaround, +# see https://github.com/rust-lang/rust/pull/102992. +termcolor = "1.2" + [dev-dependencies] pipe = "0.4" pretty_assertions = "1.0" diff --git a/crates/rustc_codegen_spirv/build.rs b/crates/rustc_codegen_spirv/build.rs index 86605ea183..e69bcd95f1 100644 --- a/crates/rustc_codegen_spirv/build.rs +++ b/crates/rustc_codegen_spirv/build.rs @@ -10,9 +10,9 @@ use std::process::{Command, ExitCode}; /// `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-2023-07-08" -components = ["rust-src", "rustc-dev", "llvm-tools-preview"] -# commit_hash = cb80ff132a0e9aa71529b701427e4e6c243b58df"#; +channel = "nightly-2023-08-29" +components = ["rust-src", "rustc-dev", "llvm-tools"] +# commit_hash = 4e78abb437a0478d1f42115198ee45888e5330fd"#; fn get_rustc_commit_hash() -> Result> { let rustc = std::env::var("RUSTC").unwrap_or_else(|_| String::from("rustc")); diff --git a/crates/rustc_codegen_spirv/src/abi.rs b/crates/rustc_codegen_spirv/src/abi.rs index f2260dfc80..bea2231fce 100644 --- a/crates/rustc_codegen_spirv/src/abi.rs +++ b/crates/rustc_codegen_spirv/src/abi.rs @@ -10,9 +10,9 @@ use rustc_errors::ErrorGuaranteed; use rustc_index::Idx; use rustc_middle::query::{ExternProviders, Providers}; use rustc_middle::ty::layout::{FnAbiOf, LayoutOf, TyAndLayout}; -use rustc_middle::ty::subst::SubstsRef; +use rustc_middle::ty::GenericArgsRef; use rustc_middle::ty::{ - self, Const, FloatTy, GeneratorSubsts, IntTy, ParamEnv, PolyFnSig, Ty, TyCtxt, TyKind, + self, Const, FloatTy, GeneratorArgs, IntTy, ParamEnv, PolyFnSig, Ty, TyCtxt, TyKind, TypeAndMut, UintTy, }; use rustc_middle::{bug, span_bug}; @@ -104,6 +104,8 @@ pub(crate) fn provide(providers: &mut Providers) { largest_niche, align, size, + max_repr_align, + unadjusted_abi_align, } = *layout; LayoutS { fields: match *fields { @@ -147,6 +149,8 @@ pub(crate) fn provide(providers: &mut Providers) { largest_niche, align, size, + max_repr_align, + unadjusted_abi_align, } } providers.layout_of = |tcx, key| { @@ -343,7 +347,7 @@ impl<'tcx> ConvSpirvType<'tcx> for FnAbi<'tcx, Ty<'tcx>> { impl<'tcx> ConvSpirvType<'tcx> for TyAndLayout<'tcx> { fn spirv_type(&self, mut span: Span, cx: &CodegenCx<'tcx>) -> Word { - if let TyKind::Adt(adt, substs) = *self.ty.kind() { + if let TyKind::Adt(adt, args) = *self.ty.kind() { if span == DUMMY_SP { span = cx.tcx.def_span(adt.did()); } @@ -352,7 +356,7 @@ impl<'tcx> ConvSpirvType<'tcx> for TyAndLayout<'tcx> { if let Some(intrinsic_type_attr) = attrs.intrinsic_type.map(|attr| attr.value) { if let Ok(spirv_type) = - trans_intrinsic_type(cx, span, *self, substs, intrinsic_type_attr) + trans_intrinsic_type(cx, span, *self, args, intrinsic_type_attr) { return spirv_type; } @@ -782,7 +786,7 @@ impl fmt::Display for TyLayoutNameKey<'_> { } } if let (TyKind::Generator(_, _, _), Some(index)) = (self.ty.kind(), self.variant) { - write!(f, "::{}", GeneratorSubsts::variant_name(index))?; + write!(f, "::{}", GeneratorArgs::variant_name(index))?; } Ok(()) } @@ -792,7 +796,7 @@ fn trans_intrinsic_type<'tcx>( cx: &CodegenCx<'tcx>, span: Span, ty: TyAndLayout<'tcx>, - substs: SubstsRef<'tcx>, + args: GenericArgsRef<'tcx>, intrinsic_type_attr: IntrinsicType, ) -> Result { match intrinsic_type_attr { @@ -817,7 +821,7 @@ fn trans_intrinsic_type<'tcx>( // <_>::from_u64(value).unwrap() // } - let sampled_type = match substs.type_at(0).kind() { + let sampled_type = match args.type_at(0).kind() { TyKind::Int(int) => match int { IntTy::Isize => { SpirvType::Integer(cx.tcx.data_layout.pointer_size.bits() as u32, true) @@ -850,13 +854,13 @@ fn trans_intrinsic_type<'tcx>( } }; - // let dim: spirv::Dim = type_from_variant_discriminant(cx, substs.const_at(1)); - // let depth: u32 = type_from_variant_discriminant(cx, substs.const_at(2)); - // let arrayed: u32 = type_from_variant_discriminant(cx, substs.const_at(3)); - // let multisampled: u32 = type_from_variant_discriminant(cx, substs.const_at(4)); - // let sampled: u32 = type_from_variant_discriminant(cx, substs.const_at(5)); + // let dim: spirv::Dim = type_from_variant_discriminant(cx, args.const_at(1)); + // let depth: u32 = type_from_variant_discriminant(cx, args.const_at(2)); + // let arrayed: u32 = type_from_variant_discriminant(cx, args.const_at(3)); + // let multisampled: u32 = type_from_variant_discriminant(cx, args.const_at(4)); + // let sampled: u32 = type_from_variant_discriminant(cx, args.const_at(5)); // let image_format: spirv::ImageFormat = - // type_from_variant_discriminant(cx, substs.const_at(6)); + // type_from_variant_discriminant(cx, args.const_at(6)); fn const_int_value<'tcx, P: FromPrimitive>( cx: &CodegenCx<'tcx>, @@ -873,12 +877,12 @@ fn trans_intrinsic_type<'tcx>( } } - let dim = const_int_value(cx, substs.const_at(1))?; - let depth = const_int_value(cx, substs.const_at(2))?; - let arrayed = const_int_value(cx, substs.const_at(3))?; - let multisampled = const_int_value(cx, substs.const_at(4))?; - let sampled = const_int_value(cx, substs.const_at(5))?; - let image_format = const_int_value(cx, substs.const_at(6))?; + let dim = const_int_value(cx, args.const_at(1))?; + let depth = const_int_value(cx, args.const_at(2))?; + let arrayed = const_int_value(cx, args.const_at(3))?; + let multisampled = const_int_value(cx, args.const_at(4))?; + let sampled = const_int_value(cx, args.const_at(5))?; + let image_format = const_int_value(cx, args.const_at(6))?; let ty = SpirvType::Image { sampled_type, @@ -913,7 +917,7 @@ fn trans_intrinsic_type<'tcx>( // We use a generic to indicate the underlying image type of the sampled image. // The spirv type of it will be generated by querying the type of the first generic. - if let Some(image_ty) = substs.types().next() { + if let Some(image_ty) = args.types().next() { // TODO: enforce that the generic param is an image type? let image_type = cx.layout_of(image_ty).spirv_type(span, cx); Ok(SpirvType::SampledImage { image_type }.def(span, cx)) @@ -934,7 +938,7 @@ fn trans_intrinsic_type<'tcx>( // We use a generic to indicate the underlying element type. // The spirv type of it will be generated by querying the type of the first generic. - if let Some(elem_ty) = substs.types().next() { + if let Some(elem_ty) = args.types().next() { let element = cx.layout_of(elem_ty).spirv_type(span, cx); Ok(SpirvType::RuntimeArray { element }.def(span, cx)) } else { diff --git a/crates/rustc_codegen_spirv/src/attr.rs b/crates/rustc_codegen_spirv/src/attr.rs index 37915a2b09..b796e86db6 100644 --- a/crates/rustc_codegen_spirv/src/attr.rs +++ b/crates/rustc_codegen_spirv/src/attr.rs @@ -7,7 +7,7 @@ use crate::symbols::Symbols; use rspirv::spirv::{BuiltIn, ExecutionMode, ExecutionModel, StorageClass}; use rustc_ast::Attribute; use rustc_hir as hir; -use rustc_hir::def_id::LocalDefId; +use rustc_hir::def_id::LocalModDefId; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{HirId, MethodKind, Target, CRATE_HIR_ID}; use rustc_middle::hir::nested_filter; @@ -484,7 +484,7 @@ impl<'tcx> Visitor<'tcx> for CheckSpirvAttrVisitor<'tcx> { } // FIXME(eddyb) DRY this somehow and make it reusable from somewhere in `rustc`. -fn check_mod_attrs(tcx: TyCtxt<'_>, module_def_id: LocalDefId) { +fn check_mod_attrs(tcx: TyCtxt<'_>, module_def_id: LocalModDefId) { let check_spirv_attr_visitor = &mut CheckSpirvAttrVisitor { tcx, sym: Symbols::get(), @@ -498,10 +498,10 @@ fn check_mod_attrs(tcx: TyCtxt<'_>, module_def_id: LocalDefId) { pub(crate) fn provide(providers: &mut Providers) { *providers = Providers { - check_mod_attrs: |tcx, def_id| { + 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, def_id); - check_mod_attrs(tcx, def_id); + (rustc_interface::DEFAULT_QUERY_PROVIDERS.check_mod_attrs)(tcx, module_def_id); + check_mod_attrs(tcx, module_def_id); }, ..*providers }; diff --git a/crates/rustc_codegen_spirv/src/builder/byte_addressable_buffer.rs b/crates/rustc_codegen_spirv/src/builder/byte_addressable_buffer.rs index 088b86e364..902ed8a756 100644 --- a/crates/rustc_codegen_spirv/src/builder/byte_addressable_buffer.rs +++ b/crates/rustc_codegen_spirv/src/builder/byte_addressable_buffer.rs @@ -2,7 +2,7 @@ use super::Builder; use crate::builder_spirv::{SpirvValue, SpirvValueExt, SpirvValueKind}; use crate::spirv_type::SpirvType; use rspirv::spirv::Word; -use rustc_codegen_ssa::traits::{BaseTypeMethods, BuilderMethods}; +use rustc_codegen_ssa::traits::BuilderMethods; use rustc_errors::ErrorGuaranteed; use rustc_span::DUMMY_SP; use rustc_target::abi::call::PassMode; diff --git a/crates/rustc_codegen_spirv/src/builder/intrinsics.rs b/crates/rustc_codegen_spirv/src/builder/intrinsics.rs index 229238d2fb..a06f7bf270 100644 --- a/crates/rustc_codegen_spirv/src/builder/intrinsics.rs +++ b/crates/rustc_codegen_spirv/src/builder/intrinsics.rs @@ -74,8 +74,8 @@ impl<'a, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'tcx> { ) { let callee_ty = instance.ty(self.tcx, ParamEnv::reveal_all()); - let (def_id, substs) = match *callee_ty.kind() { - FnDef(def_id, substs) => (def_id, substs), + let (def_id, fn_args) = match *callee_ty.kind() { + FnDef(def_id, fn_args) => (def_id, fn_args), _ => bug!("expected fn item type, found {}", callee_ty), }; @@ -103,7 +103,7 @@ impl<'a, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'tcx> { sym::volatile_load | sym::unaligned_volatile_load => { let ptr = args[0].immediate(); - let layout = self.layout_of(substs.type_at(0)); + let layout = self.layout_of(fn_args.type_at(0)); let load = self.volatile_load(layout.spirv_type(self.span(), self), ptr); self.to_immediate(load, layout) } diff --git a/crates/rustc_codegen_spirv/src/builder/spirv_asm.rs b/crates/rustc_codegen_spirv/src/builder/spirv_asm.rs index 97c4d9cfa1..a7354cb843 100644 --- a/crates/rustc_codegen_spirv/src/builder/spirv_asm.rs +++ b/crates/rustc_codegen_spirv/src/builder/spirv_asm.rs @@ -660,7 +660,7 @@ impl<'cx, 'tcx> Builder<'cx, 'tcx> { /// `leftover_operands` is used for `IndexComposite` patterns, if any exist. /// If the pattern isn't constraining enough to determine an unique type, /// `Err(Ambiguous)` is returned instead. - fn subst_ty_pat( + fn arg_ty_pat( cx: &CodegenCx<'_>, pat: &TyPat<'_>, ty_vars: &[Option], @@ -673,23 +673,23 @@ impl<'cx, 'tcx> Builder<'cx, 'tcx> { }, TyPat::Pointer(_, pat) => SpirvType::Pointer { - pointee: subst_ty_pat(cx, pat, ty_vars, leftover_operands)?, + pointee: arg_ty_pat(cx, pat, ty_vars, leftover_operands)?, } .def(DUMMY_SP, cx), TyPat::Vector4(pat) => SpirvType::Vector { - element: subst_ty_pat(cx, pat, ty_vars, leftover_operands)?, + element: arg_ty_pat(cx, pat, ty_vars, leftover_operands)?, count: 4, } .def(DUMMY_SP, cx), TyPat::SampledImage(pat) => SpirvType::SampledImage { - image_type: subst_ty_pat(cx, pat, ty_vars, leftover_operands)?, + image_type: arg_ty_pat(cx, pat, ty_vars, leftover_operands)?, } .def(DUMMY_SP, cx), TyPat::IndexComposite(pat) => { - let mut ty = subst_ty_pat(cx, pat, ty_vars, leftover_operands)?; + let mut ty =arg_ty_pat(cx, pat, ty_vars, leftover_operands)?; for index in leftover_operands { let index_to_usize = || match *index { // FIXME(eddyb) support more than just literals, @@ -780,7 +780,7 @@ impl<'cx, 'tcx> Builder<'cx, 'tcx> { _ => return None, } - match subst_ty_pat( + match arg_ty_pat( self, sig.output_type.unwrap(), &combined_ty_vars, diff --git a/crates/rustc_codegen_spirv/src/codegen_cx/constant.rs b/crates/rustc_codegen_spirv/src/codegen_cx/constant.rs index d49be57993..52462e44c0 100644 --- a/crates/rustc_codegen_spirv/src/codegen_cx/constant.rs +++ b/crates/rustc_codegen_spirv/src/codegen_cx/constant.rs @@ -3,7 +3,7 @@ use crate::abi::ConvSpirvType; use crate::builder_spirv::{SpirvConst, SpirvValue, SpirvValueExt, SpirvValueKind}; use crate::spirv_type::SpirvType; use rspirv::spirv::Word; -use rustc_codegen_ssa::traits::{BaseTypeMethods, ConstMethods, MiscMethods, StaticMethods}; +use rustc_codegen_ssa::traits::{ConstMethods, MiscMethods, StaticMethods}; use rustc_middle::bug; use rustc_middle::mir::interpret::{alloc_range, ConstAllocation, GlobalAlloc, Scalar}; use rustc_middle::ty::layout::LayoutOf; @@ -361,18 +361,6 @@ impl<'tcx> ConstMethods<'tcx> for CodegenCx<'tcx> { self.def_constant(void_type, SpirvConst::ConstDataFromAlloc(alloc)) } - // FIXME(eddyb) is this just redundant with `const_bitcast`?! - fn const_ptrcast(&self, val: Self::Value, ty: Self::Type) -> Self::Value { - if val.ty == ty { - val - } else { - // FIXME(eddyb) implement via `OpSpecConstantOp`. - // FIXME(eddyb) this zombies the original value without creating a new one. - let result = val.def_cx(self).with_type(ty); - self.zombie_no_span(result.def_cx(self), "const_ptrcast"); - result - } - } fn const_bitcast(&self, val: Self::Value, ty: Self::Type) -> Self::Value { // HACK(eddyb) special-case `const_data_from_alloc` + `static_addr_of` // as the old `from_const_alloc` (now `OperandRef::from_const_alloc`). diff --git a/crates/rustc_codegen_spirv/src/codegen_cx/declare.rs b/crates/rustc_codegen_spirv/src/codegen_cx/declare.rs index 0065c6a095..0786c22835 100644 --- a/crates/rustc_codegen_spirv/src/codegen_cx/declare.rs +++ b/crates/rustc_codegen_spirv/src/codegen_cx/declare.rs @@ -7,7 +7,7 @@ use crate::spirv_type::SpirvType; use itertools::Itertools; use rspirv::spirv::{FunctionControl, LinkageType, StorageClass, Word}; use rustc_attr::InlineAttr; -use rustc_codegen_ssa::traits::{BaseTypeMethods, PreDefineMethods, StaticMethods}; +use rustc_codegen_ssa::traits::{PreDefineMethods, StaticMethods}; use rustc_hir::def::DefKind; use rustc_middle::bug; use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs}; @@ -37,8 +37,8 @@ fn attrs_to_spirv(attrs: &CodegenFnAttrs) -> FunctionControl { impl<'tcx> CodegenCx<'tcx> { /// Returns a function if it already exists, or declares a header if it doesn't. pub fn get_fn_ext(&self, instance: Instance<'tcx>) -> SpirvValue { - assert!(!instance.substs.has_infer()); - assert!(!instance.substs.has_escaping_bound_vars()); + assert!(!instance.args.has_infer()); + assert!(!instance.args.has_escaping_bound_vars()); if let Some(&func) = self.instances.borrow().get(&instance) { return func; @@ -214,7 +214,7 @@ impl<'tcx> CodegenCx<'tcx> { }) }); if let Some(spec) = spec { - if let Some((ty,)) = instance.substs.types().collect_tuple() { + if let Some((ty,)) = instance.args.types().collect_tuple() { self.fmt_rt_arg_new_fn_ids_to_ty_and_spec .borrow_mut() .insert(fn_id, (ty, spec)); diff --git a/crates/rustc_codegen_spirv/src/codegen_cx/mod.rs b/crates/rustc_codegen_spirv/src/codegen_cx/mod.rs index 621471fd62..2f9d0d9dec 100644 --- a/crates/rustc_codegen_spirv/src/codegen_cx/mod.rs +++ b/crates/rustc_codegen_spirv/src/codegen_cx/mod.rs @@ -26,7 +26,7 @@ use rustc_session::Session; use rustc_span::symbol::Symbol; use rustc_span::{SourceFile, Span, DUMMY_SP}; use rustc_target::abi::call::{FnAbi, PassMode}; -use rustc_target::abi::{HasDataLayout, TargetDataLayout}; +use rustc_target::abi::{AddressSpace, HasDataLayout, TargetDataLayout}; use rustc_target::spec::{HasTargetSpec, Target}; use std::cell::RefCell; use std::collections::BTreeSet; @@ -162,6 +162,14 @@ impl<'tcx> CodegenCx<'tcx> { self.lookup_type(ty).debug(ty, self) } + pub fn type_ptr_to(&self, ty: Word) -> Word { + SpirvType::Pointer { pointee: ty }.def(DUMMY_SP, self) + } + + pub fn type_ptr_to_ext(&self, ty: Word, _address_space: AddressSpace) -> Word { + SpirvType::Pointer { pointee: ty }.def(DUMMY_SP, self) + } + /// Zombie system: /// /// If something unrepresentable is encountered, we don't want to fail diff --git a/crates/rustc_codegen_spirv/src/codegen_cx/type_.rs b/crates/rustc_codegen_spirv/src/codegen_cx/type_.rs index 3d60dd37fa..adcc332153 100644 --- a/crates/rustc_codegen_spirv/src/codegen_cx/type_.rs +++ b/crates/rustc_codegen_spirv/src/codegen_cx/type_.rs @@ -194,7 +194,7 @@ impl<'tcx> BaseTypeMethods<'tcx> for CodegenCx<'tcx> { align, size, field_types: els, - field_offsets: &field_offsets, + field_offsets: &field_offsets.as_slice(), field_names: None, } .def(DUMMY_SP, self) @@ -230,11 +230,11 @@ impl<'tcx> BaseTypeMethods<'tcx> for CodegenCx<'tcx> { => TypeKind::Token, } } - fn type_ptr_to(&self, ty: Self::Type) -> Self::Type { - SpirvType::Pointer { pointee: ty }.def(DUMMY_SP, self) + fn type_ptr(&self) -> Self::Type { + self.type_ptr_to(SpirvType::Void.def(DUMMY_SP, self)) } - fn type_ptr_to_ext(&self, ty: Self::Type, _address_space: AddressSpace) -> Self::Type { - SpirvType::Pointer { pointee: ty }.def(DUMMY_SP, self) + fn type_ptr_ext(&self, address_space: AddressSpace) -> Self::Type { + self.type_ptr_to_ext(SpirvType::Void.def(DUMMY_SP, self), address_space) } fn element_type(&self, ty: Self::Type) -> Self::Type { match self.lookup_type(ty) { diff --git a/crates/rustc_codegen_spirv/src/lib.rs b/crates/rustc_codegen_spirv/src/lib.rs index e0d33d693c..e0be7b4f34 100644 --- a/crates/rustc_codegen_spirv/src/lib.rs +++ b/crates/rustc_codegen_spirv/src/lib.rs @@ -88,7 +88,7 @@ use rspirv::binary::Assemble; use rustc_ast::expand::allocator::AllocatorKind; use rustc_codegen_ssa::back::lto::{LtoModuleCodegen, SerializedModule, ThinModule}; use rustc_codegen_ssa::back::write::{ - CodegenContext, FatLTOInput, ModuleConfig, OngoingCodegen, TargetMachineFactoryConfig, + CodegenContext, FatLtoInput, ModuleConfig, OngoingCodegen, TargetMachineFactoryConfig, }; use rustc_codegen_ssa::base::maybe_create_entry_wrapper; use rustc_codegen_ssa::mono_item::MonoItemExt; @@ -101,7 +101,7 @@ use rustc_data_structures::fx::FxIndexMap; use rustc_errors::{ErrorGuaranteed, FatalError, Handler}; use rustc_metadata::EncodedMetadata; use rustc_middle::dep_graph::{WorkProduct, WorkProductId}; -use rustc_middle::mir::mono::{Linkage, MonoItem, Visibility}; +use rustc_middle::mir::mono::{MonoItem, MonoItemData}; use rustc_middle::mir::pretty::write_mir_pretty; use rustc_middle::query; use rustc_middle::ty::print::with_no_trimmed_paths; @@ -117,10 +117,10 @@ use std::io::Write; use std::path::Path; use std::sync::Arc; -fn dump_mir(tcx: TyCtxt<'_>, mono_items: &[(MonoItem<'_>, (Linkage, Visibility))], path: &Path) { +fn dump_mir(tcx: TyCtxt<'_>, mono_items: &[(MonoItem<'_>, MonoItemData)], path: &Path) { create_dir_all(path.parent().unwrap()).unwrap(); let mut file = File::create(path).unwrap(); - for &(mono_item, (_, _)) in mono_items { + for &(mono_item, _) in mono_items { if let MonoItem::Fn(instance) = mono_item { if matches!(instance.def, InstanceDef::Item(_)) { let mut mir = Cursor::new(Vec::new()); @@ -306,7 +306,7 @@ impl WriteBackendMethods for SpirvCodegenBackend { fn run_fat_lto( _: &CodegenContext, - _: Vec>, + _: Vec>, _: Vec<(SerializedModule, WorkProduct)>, ) -> Result, FatalError> { todo!() @@ -324,6 +324,10 @@ impl WriteBackendMethods for SpirvCodegenBackend { println!("TODO: Implement print_pass_timings"); } + fn print_statistics(&self) { + println!("TODO: Implement print_statistics") + } + unsafe fn optimize( _: &CodegenContext, _: &Handler, @@ -416,16 +420,20 @@ impl ExtraBackendMethods for SpirvCodegenBackend { let mono_items = cx.codegen_unit.items_in_deterministic_order(cx.tcx); if let Some(dir) = &cx.codegen_args.dump_mir { - dump_mir(tcx, &mono_items, &dir.join(cgu_name.to_string())); + dump_mir(tcx, mono_items.as_slice(), &dir.join(cgu_name.to_string())); } - for &(mono_item, (linkage, visibility)) in mono_items.iter() { + for &(mono_item, mono_item_data) in mono_items.iter() { if let MonoItem::Fn(instance) = mono_item { if is_blocklisted_fn(cx.tcx, &cx.sym, instance) { continue; } } - mono_item.predefine::>(&cx, linkage, visibility); + mono_item.predefine::>( + &cx, + mono_item_data.linkage, + mono_item_data.visibility, + ); } // ... and now that we have everything pre-defined, fill out those definitions. diff --git a/crates/rustc_codegen_spirv/src/link.rs b/crates/rustc_codegen_spirv/src/link.rs index 1211ea68a6..d1b8710320 100644 --- a/crates/rustc_codegen_spirv/src/link.rs +++ b/crates/rustc_codegen_spirv/src/link.rs @@ -36,7 +36,7 @@ pub fn link( crate_name: &str, ) { let output_metadata = sess.opts.output_types.contains_key(&OutputType::Metadata); - for &crate_type in sess.crate_types().iter() { + for &crate_type in sess.opts.crate_types.iter() { if (sess.opts.unstable_opts.no_codegen || !sess.opts.output_types.should_codegen()) && !output_metadata && crate_type == CrateType::Executable @@ -601,7 +601,7 @@ fn do_link( Ok(v) => v, Err(rustc_errors::ErrorGuaranteed { .. }) => { sess.abort_if_errors(); - bug!("Linker errored, but no error reported") + bug!("Linker errored, but no error reported"); } } } diff --git a/crates/rustc_codegen_spirv/src/linker/test.rs b/crates/rustc_codegen_spirv/src/linker/test.rs index 8694492add..59bfb13337 100644 --- a/crates/rustc_codegen_spirv/src/linker/test.rs +++ b/crates/rustc_codegen_spirv/src/linker/test.rs @@ -1,11 +1,12 @@ use super::{link, LinkResult}; -use pipe::pipe; use rspirv::dr::{Loader, Module}; -use rustc_errors::{registry::Registry, TerminalUrl}; +use rustc_errors::registry::Registry; use rustc_session::config::{Input, OutputFilenames, OutputTypes}; use rustc_session::CompilerIO; use rustc_span::FileName; -use std::io::Read; +use std::io::Write; +use std::sync::{Arc, Mutex}; +use termcolor::{ColorSpec, WriteColor}; // https://github.com/colin-kiegel/rust-pretty-assertions/issues/24 #[derive(PartialEq, Eq)] @@ -75,20 +76,40 @@ fn link_with_linker_opts( ) -> Result { let modules = binaries.iter().cloned().map(load).collect::>(); - // FIXME(eddyb) this seems ridiculous, we should be able to write to - // some kind of `Arc>>` without a separate thread. - // - // need pipe here because the writer must be 'static. - let (mut read_diags, write_diags) = pipe(); - let read_diags_thread = std::thread::spawn(move || { - // must spawn thread because pipe crate is synchronous - let mut diags = String::new(); - read_diags.read_to_string(&mut diags).unwrap(); - if let Some(diags_without_trailing_newlines) = diags.strip_suffix("\n\n") { - diags.truncate(diags_without_trailing_newlines.len()); + // A threadsafe buffer for writing. + #[derive(Default, Clone)] + struct BufWriter(Arc>>); + + impl BufWriter { + fn to_string(self) -> String { + let x = self.0.into_inner().expect("diagnostics unlocked"); + String::from_utf8(x).expect("conversion to string") + } + } + + impl Write for BufWriter { + fn write(&mut self, buf: &[u8]) -> std::io::Result { + self.0.lock().unwrap().write(buf) + } + fn flush(&mut self) -> std::io::Result<()> { + self.0.lock().unwrap().flush() + } + } + impl WriteColor for BufWriter { + fn supports_color(&self) -> bool { + false + } + + fn set_color(&mut self, _spec: &ColorSpec) -> std::io::Result<()> { + Ok(()) + } + + fn reset(&mut self) -> std::io::Result<()> { + Ok(()) } - diags - }); + } + let buf = BufWriter::default(); + let output = buf.clone(); // NOTE(eddyb) without `catch_fatal_errors`, you'd get the really strange // effect of test failures with no output (because the `FatalError` "panic" @@ -126,6 +147,7 @@ fn link_with_linker_opts( None, None, rustc_interface::util::rustc_version_str().unwrap_or("unknown"), + None, ); // HACK(eddyb) inject `write_diags` into `sess`, to work around @@ -138,24 +160,12 @@ fn link_with_linker_opts( sess.opts.unstable_opts.translate_directionality_markers, ) }; - let emitter = rustc_errors::emitter::EmitterWriter::new( - Box::new(write_diags), - Some(sess.parse_sess.clone_source_map()), - None, - fallback_bundle, - false, - false, - false, - None, - false, - false, - TerminalUrl::No, - ); - - rustc_errors::Handler::with_emitter_and_flags( - Box::new(emitter), - sess.opts.unstable_opts.diagnostic_handler_flags(true), - ) + let emitter = + rustc_errors::emitter::EmitterWriter::new(Box::new(buf), fallback_bundle) + .sm(Some(sess.parse_sess.clone_source_map())); + + rustc_errors::Handler::with_emitter(Box::new(emitter)) + .with_flags(sess.opts.unstable_opts.diagnostic_handler_flags(true)) }; let res = link( @@ -180,7 +190,7 @@ fn link_with_linker_opts( }) }) .flatten() - .map_err(|_e| read_diags_thread.join().unwrap()) + .map_err(|_e| buf.to_string()) .map_err(PrettyString) } diff --git a/rust-toolchain.toml b/rust-toolchain.toml index abd2d7b0ca..7bba50d68b 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,7 +1,7 @@ [toolchain] -channel = "nightly-2023-07-08" -components = ["rust-src", "rustc-dev", "llvm-tools-preview"] -# commit_hash = cb80ff132a0e9aa71529b701427e4e6c243b58df +channel = "nightly-2023-08-29" +components = ["rust-src", "rustc-dev", "llvm-tools"] +# commit_hash = 4e78abb437a0478d1f42115198ee45888e5330fd # Whenever changing the nightly channel, update the commit hash above, and make # sure to change `REQUIRED_TOOLCHAIN` in `crates/rustc_codegen_spirv/build.rs` also. From 9536c3e50293e33e9757fadc68f5ec89b4d8c3fc Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Tue, 21 Nov 2023 10:36:39 +0200 Subject: [PATCH 2/8] Undo accidental subst->arg renames in `builder/spirv_asm`. --- crates/rustc_codegen_spirv/src/builder/spirv_asm.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/crates/rustc_codegen_spirv/src/builder/spirv_asm.rs b/crates/rustc_codegen_spirv/src/builder/spirv_asm.rs index a7354cb843..97c4d9cfa1 100644 --- a/crates/rustc_codegen_spirv/src/builder/spirv_asm.rs +++ b/crates/rustc_codegen_spirv/src/builder/spirv_asm.rs @@ -660,7 +660,7 @@ impl<'cx, 'tcx> Builder<'cx, 'tcx> { /// `leftover_operands` is used for `IndexComposite` patterns, if any exist. /// If the pattern isn't constraining enough to determine an unique type, /// `Err(Ambiguous)` is returned instead. - fn arg_ty_pat( + fn subst_ty_pat( cx: &CodegenCx<'_>, pat: &TyPat<'_>, ty_vars: &[Option], @@ -673,23 +673,23 @@ impl<'cx, 'tcx> Builder<'cx, 'tcx> { }, TyPat::Pointer(_, pat) => SpirvType::Pointer { - pointee: arg_ty_pat(cx, pat, ty_vars, leftover_operands)?, + pointee: subst_ty_pat(cx, pat, ty_vars, leftover_operands)?, } .def(DUMMY_SP, cx), TyPat::Vector4(pat) => SpirvType::Vector { - element: arg_ty_pat(cx, pat, ty_vars, leftover_operands)?, + element: subst_ty_pat(cx, pat, ty_vars, leftover_operands)?, count: 4, } .def(DUMMY_SP, cx), TyPat::SampledImage(pat) => SpirvType::SampledImage { - image_type: arg_ty_pat(cx, pat, ty_vars, leftover_operands)?, + image_type: subst_ty_pat(cx, pat, ty_vars, leftover_operands)?, } .def(DUMMY_SP, cx), TyPat::IndexComposite(pat) => { - let mut ty =arg_ty_pat(cx, pat, ty_vars, leftover_operands)?; + let mut ty = subst_ty_pat(cx, pat, ty_vars, leftover_operands)?; for index in leftover_operands { let index_to_usize = || match *index { // FIXME(eddyb) support more than just literals, @@ -780,7 +780,7 @@ impl<'cx, 'tcx> Builder<'cx, 'tcx> { _ => return None, } - match arg_ty_pat( + match subst_ty_pat( self, sig.output_type.unwrap(), &combined_ty_vars, From bc5c5109835563e8b9394de4aaf2503dc6b4dbbc Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Tue, 21 Nov 2023 17:20:43 +0200 Subject: [PATCH 3/8] Address new rustc/clippy lints. --- crates/rustc_codegen_spirv/src/builder/mod.rs | 2 +- crates/rustc_codegen_spirv/src/lib.rs | 2 +- crates/spirv-std/src/lib.rs | 1 + tests/ui/dis/ptr_copy.rs | 2 +- 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/crates/rustc_codegen_spirv/src/builder/mod.rs b/crates/rustc_codegen_spirv/src/builder/mod.rs index b64ddd184c..34b63f1034 100644 --- a/crates/rustc_codegen_spirv/src/builder/mod.rs +++ b/crates/rustc_codegen_spirv/src/builder/mod.rs @@ -298,7 +298,7 @@ impl<'a, 'tcx> ArgAbiMethods<'tcx> for Builder<'a, 'tcx> { idx: &mut usize, dst: PlaceRef<'tcx, Self::Value>, ) { - fn next(bx: &mut Builder<'_, '_>, idx: &mut usize) -> SpirvValue { + fn next(bx: &Builder<'_, '_>, idx: &mut usize) -> SpirvValue { let val = bx.function_parameter_values.borrow()[&bx.current_fn.def(bx)][*idx]; *idx += 1; val diff --git a/crates/rustc_codegen_spirv/src/lib.rs b/crates/rustc_codegen_spirv/src/lib.rs index e0be7b4f34..27d6d11357 100644 --- a/crates/rustc_codegen_spirv/src/lib.rs +++ b/crates/rustc_codegen_spirv/src/lib.rs @@ -325,7 +325,7 @@ impl WriteBackendMethods for SpirvCodegenBackend { } fn print_statistics(&self) { - println!("TODO: Implement print_statistics") + println!("TODO: Implement print_statistics"); } unsafe fn optimize( diff --git a/crates/spirv-std/src/lib.rs b/crates/spirv-std/src/lib.rs index b9f993565f..3f4920c3e2 100644 --- a/crates/spirv-std/src/lib.rs +++ b/crates/spirv-std/src/lib.rs @@ -1,6 +1,7 @@ #![no_std] #![cfg_attr( target_arch = "spirv", + allow(internal_features), feature( asm_const, asm_experimental_arch, diff --git a/tests/ui/dis/ptr_copy.rs b/tests/ui/dis/ptr_copy.rs index ca376e25c1..89f1a83d84 100644 --- a/tests/ui/dis/ptr_copy.rs +++ b/tests/ui/dis/ptr_copy.rs @@ -4,7 +4,7 @@ //[via_intrinsic] build-pass // compile-flags: -C llvm-args=--disassemble-fn=ptr_copy::copy_via_raw_ptr -#![cfg_attr(via_intrinsic, feature(intrinsics))] +#![cfg_attr(via_intrinsic, allow(internal_features), feature(intrinsics))] use spirv_std::spirv; From c2a494a6d246590bae872792c69bc6f912b80704 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Tue, 21 Nov 2023 17:27:52 +0200 Subject: [PATCH 4/8] intrinsics: stub out `compare_bytes` (as zombie instead of fatal error). --- crates/rustc_codegen_spirv/src/builder/intrinsics.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/crates/rustc_codegen_spirv/src/builder/intrinsics.rs b/crates/rustc_codegen_spirv/src/builder/intrinsics.rs index a06f7bf270..9d8b886ea8 100644 --- a/crates/rustc_codegen_spirv/src/builder/intrinsics.rs +++ b/crates/rustc_codegen_spirv/src/builder/intrinsics.rs @@ -327,6 +327,12 @@ impl<'a, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'tcx> { } } + sym::compare_bytes => { + let undef = self.undef(ret_ty); + self.zombie(undef.def(self), "memcmp not implemented"); + undef + } + _ => self.fatal(format!("TODO: Unknown intrinsic '{name}'")), }; From ff9dd738bcafa5cc377bdabf0a4da001555c65e7 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Sat, 18 Nov 2023 00:48:18 +0200 Subject: [PATCH 5/8] builder: aggressively `pointercast`/`bitcast` to paper over opaque pointers. --- .../src/builder/builder_methods.rs | 547 +++++++++++------- crates/rustc_codegen_spirv/src/builder/mod.rs | 24 +- .../rustc_codegen_spirv/src/builder_spirv.rs | 22 +- .../src/codegen_cx/constant.rs | 17 +- .../src/codegen_cx/type_.rs | 2 +- crates/rustc_codegen_spirv/src/lib.rs | 1 + crates/spirv-std/macros/src/lib.rs | 8 +- .../ui/arch/debug_printf_type_checking.stderr | 36 +- tests/ui/dis/ptr_copy.normal.stderr | 8 +- tests/ui/dis/ptr_read.stderr | 2 +- tests/ui/dis/ptr_read_method.stderr | 2 +- tests/ui/dis/ptr_write.stderr | 2 +- tests/ui/dis/ptr_write_method.stderr | 2 +- 13 files changed, 405 insertions(+), 268 deletions(-) diff --git a/crates/rustc_codegen_spirv/src/builder/builder_methods.rs b/crates/rustc_codegen_spirv/src/builder/builder_methods.rs index 60c525758b..86766ff75f 100644 --- a/crates/rustc_codegen_spirv/src/builder/builder_methods.rs +++ b/crates/rustc_codegen_spirv/src/builder/builder_methods.rs @@ -373,31 +373,108 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } - /// If possible, return the appropriate `OpAccessChain` indices for going from - /// a pointer to `ty`, to a pointer to `leaf_ty`, with an added `offset`. + /// Convenience wrapper for `adjust_pointer_for_sized_access`, falling back + /// on choosing `ty` as the leaf's type (and casting `ptr` to a pointer to it). + // + // HACK(eddyb) temporary workaround for untyped pointers upstream. + // FIXME(eddyb) replace with untyped memory SPIR-V + `qptr` or similar. + fn adjust_pointer_for_typed_access( + &mut self, + ptr: SpirvValue, + ty: ::Type, + ) -> (SpirvValue, ::Type) { + self.lookup_type(ty) + .sizeof(self) + .and_then(|size| self.adjust_pointer_for_sized_access(ptr, size)) + .unwrap_or_else(|| (self.pointercast(ptr, self.type_ptr_to(ty)), ty)) + } + + /// If `ptr`'s pointee type contains any prefix field/element of size `size`, + /// i.e. some leaf which can be used for all accesses of size `size`, return + /// `ptr` adjusted to point to the innermost such leaf, and the leaf's type. + // + // FIXME(eddyb) technically this duplicates `pointercast`, but the main use + // of `pointercast` is being replaced by this, and this can be more efficient. + // + // HACK(eddyb) temporary workaround for untyped pointers upstream. + // FIXME(eddyb) replace with untyped memory SPIR-V + `qptr` or similar. + fn adjust_pointer_for_sized_access( + &mut self, + ptr: SpirvValue, + size: Size, + ) -> Option<(SpirvValue, ::Type)> { + let ptr = ptr.strip_ptrcasts(); + let mut leaf_ty = match self.lookup_type(ptr.ty) { + SpirvType::Pointer { pointee } => pointee, + other => self.fatal(format!("non-pointer type: {other:?}")), + }; + + // FIXME(eddyb) this isn't efficient, `recover_access_chain_from_offset` + // could instead be doing all the extra digging itself. + let mut indices = SmallVec::<[_; 8]>::new(); + while let Some((inner_indices, inner_ty)) = + self.recover_access_chain_from_offset(leaf_ty, Size::ZERO, Some(size), None) + { + indices.extend(inner_indices); + leaf_ty = inner_ty; + } + + let leaf_ptr_ty = (self.lookup_type(leaf_ty).sizeof(self) == Some(size)) + .then(|| self.type_ptr_to(leaf_ty))?; + + let leaf_ptr = if indices.is_empty() { + assert_ty_eq!(self, ptr.ty, leaf_ptr_ty); + ptr + } else { + let indices = indices + .into_iter() + .map(|idx| self.constant_u32(self.span(), idx).def(self)) + .collect::>(); + self.emit() + .access_chain(leaf_ptr_ty, None, ptr.def(self), indices) + .unwrap() + .with_type(leaf_ptr_ty) + }; + Some((leaf_ptr, leaf_ty)) + } + + /// If possible, return the appropriate `OpAccessChain` indices for going + /// from a pointer to `ty`, to a pointer to some leaf field/element of size + /// `leaf_size` (and optionally type `leaf_ty`), while adding `offset` bytes. /// /// That is, try to turn `((_: *T) as *u8).add(offset) as *Leaf` into a series /// of struct field and array/vector element accesses. fn recover_access_chain_from_offset( &self, - mut ty: Word, - leaf_ty: Word, + mut ty: ::Type, mut offset: Size, - ) -> Option> { - assert_ne!(ty, leaf_ty); + // FIXME(eddyb) using `None` for "unsized" is a pretty bad design. + leaf_size_or_unsized: Option, + leaf_ty: Option<::Type>, + ) -> Option<(SmallVec<[u32; 8]>, ::Type)> { + assert_ne!(Some(ty), leaf_ty); + + // HACK(eddyb) this has the correct ordering (`Sized(_) < Unsized`). + #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] + enum MaybeSized { + Sized(Size), + Unsized, + } + let leaf_size = leaf_size_or_unsized.map_or(MaybeSized::Unsized, MaybeSized::Sized); - // NOTE(eddyb) `ty` and `ty_kind` should be kept in sync. + // NOTE(eddyb) `ty` and `ty_kind`/`ty_size` should be kept in sync. let mut ty_kind = self.lookup_type(ty); - let mut indices = Vec::new(); + let mut indices = SmallVec::new(); loop { + let ty_size; match ty_kind { SpirvType::Adt { field_types, field_offsets, .. } => { - let (i, field_ty, field_ty_kind, offset_in_field) = field_offsets + let (i, field_ty, field_ty_kind, field_ty_size, offset_in_field) = field_offsets .iter() .enumerate() .find_map(|(i, &field_offset)| { @@ -409,16 +486,16 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // the leaf is somewhere inside the field. let field_ty = field_types[i]; let field_ty_kind = self.lookup_type(field_ty); + let field_ty_size = field_ty_kind + .sizeof(self).map_or(MaybeSized::Unsized, MaybeSized::Sized); let offset_in_field = offset - field_offset; - if field_ty_kind - .sizeof(self) - .map_or(true, |size| offset_in_field < size) - // If the field is a zero sized type, check the type to - // get the correct entry - || offset_in_field == Size::ZERO && leaf_ty == field_ty + if MaybeSized::Sized(offset_in_field) < field_ty_size + // If the field is a zero sized type, check the + // expected size and type to get the correct entry + || offset_in_field == Size::ZERO && leaf_size == MaybeSized::Sized(Size::ZERO) && leaf_ty == Some(field_ty) { - Some((i, field_ty, field_ty_kind, offset_in_field)) + Some((i, field_ty, field_ty_kind, field_ty_size, offset_in_field)) } else { None } @@ -426,6 +503,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ty = field_ty; ty_kind = field_ty_kind; + ty_size = field_ty_size; indices.push(i as u32); offset = offset_in_field; @@ -438,14 +516,24 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ty_kind = self.lookup_type(ty); let stride = ty_kind.sizeof(self)?; + ty_size = MaybeSized::Sized(stride); + indices.push((offset.bytes() / stride.bytes()).try_into().ok()?); offset = Size::from_bytes(offset.bytes() % stride.bytes()); } _ => return None, } - if offset == Size::ZERO && ty == leaf_ty { - return Some(indices); + // Avoid digging beyond the point the leaf could actually fit. + if ty_size < leaf_size { + return None; + } + + if offset == Size::ZERO + && ty_size == leaf_size + && leaf_ty.map_or(true, |leaf_ty| leaf_ty == ty) + { + return Some((indices, ty)); } } } @@ -765,6 +853,16 @@ impl<'a, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'tcx> { } fn ret(&mut self, value: Self::Value) { + let func_ret_ty = { + let builder = self.emit(); + let func = &builder.module_ref().functions[builder.selected_function().unwrap()]; + func.def.as_ref().unwrap().result_type.unwrap() + }; + + // HACK(eddyb) temporary workaround for untyped pointers upstream. + // FIXME(eddyb) replace with untyped memory SPIR-V + `qptr` or similar. + let value = self.bitcast(value, func_ret_ty); + self.emit().ret_value(value.def(self)).unwrap(); } @@ -1055,7 +1153,7 @@ impl<'a, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'tcx> { } fn alloca(&mut self, ty: Self::Type, _align: Align) -> Self::Value { - let ptr_ty = SpirvType::Pointer { pointee: ty }.def(self.span(), self); + let ptr_ty = self.type_ptr_to(ty); // "All OpVariable instructions in a function must be the first instructions in the first block." let mut builder = self.emit(); builder.select_block(Some(0)).unwrap(); @@ -1092,22 +1190,14 @@ impl<'a, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'tcx> { } fn load(&mut self, ty: Self::Type, ptr: Self::Value, _align: Align) -> Self::Value { - if let Some(value) = ptr.const_fold_load(self) { - return value; - } - let ty = match self.lookup_type(ptr.ty) { - SpirvType::Pointer { pointee } => { - assert_ty_eq!(self, ty, pointee); - pointee - } - ty => self.fatal(format!( - "load called on variable that wasn't a pointer: {ty:?}" - )), - }; - self.emit() - .load(ty, None, ptr.def(self), None, empty()) - .unwrap() - .with_type(ty) + let (ptr, access_ty) = self.adjust_pointer_for_typed_access(ptr, ty); + let loaded_val = ptr.const_fold_load(self).unwrap_or_else(|| { + self.emit() + .load(access_ty, None, ptr.def(self), None, empty()) + .unwrap() + .with_type(access_ty) + }); + self.bitcast(loaded_val, ty) } fn volatile_load(&mut self, ty: Self::Type, ptr: Self::Value) -> Self::Value { @@ -1124,31 +1214,24 @@ impl<'a, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'tcx> { order: AtomicOrdering, _size: Size, ) -> Self::Value { - let ty = match self.lookup_type(ptr.ty) { - SpirvType::Pointer { pointee } => { - assert_ty_eq!(self, ty, pointee); - pointee - } - ty => self.fatal(format!( - "atomic_load called on variable that wasn't a pointer: {ty:?}" - )), - }; + let (ptr, access_ty) = self.adjust_pointer_for_typed_access(ptr, ty); + // TODO: Default to device scope let memory = self.constant_u32(self.span(), Scope::Device as u32); let semantics = self.ordering_to_semantics_def(order); let result = self .emit() .atomic_load( - ty, + access_ty, None, ptr.def(self), memory.def(self), semantics.def(self), ) .unwrap() - .with_type(ty); - self.validate_atomic(ty, result.def(self)); - result + .with_type(access_ty); + self.validate_atomic(access_ty, result.def(self)); + self.bitcast(result, ty) } fn load_operand( @@ -1230,29 +1313,13 @@ impl<'a, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'tcx> { } fn store(&mut self, val: Self::Value, ptr: Self::Value, _align: Align) -> Self::Value { - let ptr_elem_ty = match self.lookup_type(ptr.ty) { - SpirvType::Pointer { pointee } => pointee, - ty => self.fatal(format!( - "store called on variable that wasn't a pointer: {ty:?}" - )), - }; + let (ptr, access_ty) = self.adjust_pointer_for_typed_access(ptr, val.ty); + let val = self.bitcast(val, access_ty); - // HACK(eddyb) https://github.com/rust-lang/rust/pull/101483 accidentally - // abused the fact that an `i1` LLVM value will be automatically `zext`'d - // to `i8` by `from_immediate`, and so you can pretend that, from the - // Rust perspective, a `bool` value has the type `u8`, as long as it will - // be stored to memory (which intrinsics all do, for historical reasons) - // - but we don't do that in `from_immediate`, so it's emulated here. - let val = match (self.lookup_type(val.ty), self.lookup_type(ptr_elem_ty)) { - (SpirvType::Bool, SpirvType::Integer(8, false)) => self.zext(val, ptr_elem_ty), - - _ => val, - }; - - assert_ty_eq!(self, ptr_elem_ty, val.ty); self.emit() .store(ptr.def(self), val.def(self), None, empty()) .unwrap(); + // FIXME(eddyb) this is meant to be a handle the store instruction itself. val } @@ -1276,13 +1343,9 @@ impl<'a, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'tcx> { order: AtomicOrdering, _size: Size, ) { - let ptr_elem_ty = match self.lookup_type(ptr.ty) { - SpirvType::Pointer { pointee } => pointee, - ty => self.fatal(format!( - "atomic_store called on variable that wasn't a pointer: {ty:?}" - )), - }; - assert_ty_eq!(self, ptr_elem_ty, val.ty); + let (ptr, access_ty) = self.adjust_pointer_for_typed_access(ptr, val.ty); + let val = self.bitcast(val, access_ty); + // TODO: Default to device scope let memory = self.constant_u32(self.span(), Scope::Device as u32); let semantics = self.ordering_to_semantics_def(order); @@ -1311,70 +1374,60 @@ impl<'a, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'tcx> { } fn struct_gep(&mut self, ty: Self::Type, ptr: Self::Value, idx: u64) -> Self::Value { - let pointee = match self.lookup_type(ptr.ty) { - SpirvType::Pointer { pointee } => { - assert_ty_eq!(self, ty, pointee); - pointee - } - other => self.fatal(format!( - "struct_gep not on pointer type: {other:?}, index {idx}" - )), - }; - let pointee_kind = self.lookup_type(pointee); - let result_pointee_type = match pointee_kind { - SpirvType::Adt { field_types, .. } => field_types[idx as usize], + let (offset, result_pointee_type) = match self.lookup_type(ty) { + SpirvType::Adt { + field_offsets, + field_types, + .. + } => (field_offsets[idx as usize], field_types[idx as usize]), SpirvType::Array { element, .. } | SpirvType::RuntimeArray { element, .. } | SpirvType::Vector { element, .. } - | SpirvType::Matrix { element, .. } => element, + | SpirvType::Matrix { element, .. } => ( + self.lookup_type(element).sizeof(self).unwrap() * idx, + element, + ), SpirvType::InterfaceBlock { inner_type } => { assert_eq!(idx, 0); - inner_type + (Size::ZERO, inner_type) } other => self.fatal(format!( "struct_gep not on struct, array, or vector type: {other:?}, index {idx}" )), }; - let result_type = SpirvType::Pointer { - pointee: result_pointee_type, - } - .def(self.span(), self); + let result_type = self.type_ptr_to(result_pointee_type); // Special-case field accesses through a `pointercast`, to accesss the // right field in the original type, for the `Logical` addressing model. - if let SpirvValueKind::LogicalPtrCast { - original_ptr, + let ptr = ptr.strip_ptrcasts(); + let original_pointee_ty = match self.lookup_type(ptr.ty) { + SpirvType::Pointer { pointee } => pointee, + other => self.fatal(format!("struct_gep called on non-pointer type: {other:?}")), + }; + if let Some((indices, _)) = self.recover_access_chain_from_offset( original_pointee_ty, - bitcast_result_id: _, - } = ptr.kind - { - let offset = match pointee_kind { - SpirvType::Adt { field_offsets, .. } => field_offsets[idx as usize], - SpirvType::Array { element, .. } - | SpirvType::RuntimeArray { element, .. } - | SpirvType::Vector { element, .. } - | SpirvType::Matrix { element, .. } => { - self.lookup_type(element).sizeof(self).unwrap() * idx - } - _ => unreachable!(), - }; - if let Some(indices) = self.recover_access_chain_from_offset( - original_pointee_ty, - result_pointee_type, - offset, - ) { - let indices = indices - .into_iter() - .map(|idx| self.constant_u32(self.span(), idx).def(self)) - .collect::>(); - return self - .emit() - .access_chain(result_type, None, original_ptr, indices) - .unwrap() - .with_type(result_type); - } + offset, + self.lookup_type(result_pointee_type).sizeof(self), + Some(result_pointee_type), + ) { + let original_ptr = ptr.def(self); + let indices = indices + .into_iter() + .map(|idx| self.constant_u32(self.span(), idx).def(self)) + .collect::>(); + return self + .emit() + .access_chain(result_type, None, original_ptr, indices) + .unwrap() + .with_type(result_type); } + // FIXME(eddyb) can we even get to this point, with valid SPIR-V? + + // HACK(eddyb) temporary workaround for untyped pointers upstream. + // FIXME(eddyb) replace with untyped memory SPIR-V + `qptr` or similar. + let ptr = self.pointercast(ptr, self.type_ptr_to(ty)); + // Important! LLVM, and therefore intel-compute-runtime, require the `getelementptr` instruction (and therefore // OpAccessChain) on structs to be a constant i32. Not i64! i32. if idx > u32::MAX as u64 { @@ -1517,8 +1570,59 @@ impl<'a, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'tcx> { if val.ty == dest_ty { val } else { - let val_is_ptr = matches!(self.lookup_type(val.ty), SpirvType::Pointer { .. }); - let dest_is_ptr = matches!(self.lookup_type(dest_ty), SpirvType::Pointer { .. }); + let val_ty_kind = self.lookup_type(val.ty); + let dest_ty_kind = self.lookup_type(dest_ty); + + // HACK(eddyb) account for bitcasts from/to aggregates not being legal + // in SPIR-V, but still being used to paper over untyped pointers, + // by unpacking/repacking newtype-shaped aggregates as-needed. + let unpack_newtype = |ty, kind| { + if !matches!(kind, SpirvType::Adt { .. } | SpirvType::Array { .. }) { + return None; + } + let size = kind.sizeof(self)?; + let mut leaf_ty = ty; + + // FIXME(eddyb) this isn't efficient, `recover_access_chain_from_offset` + // could instead be doing all the extra digging itself. + let mut indices = SmallVec::<[_; 8]>::new(); + while let Some((inner_indices, inner_ty)) = + self.recover_access_chain_from_offset(leaf_ty, Size::ZERO, Some(size), None) + { + indices.extend(inner_indices); + leaf_ty = inner_ty; + } + + (!indices.is_empty()).then_some((indices, leaf_ty)) + }; + // Unpack input newtypes, and bitcast the leaf inside, instead. + if let Some((indices, in_leaf_ty)) = unpack_newtype(val.ty, val_ty_kind) { + let in_leaf = self + .emit() + .composite_extract(in_leaf_ty, None, val.def(self), indices) + .unwrap() + .with_type(in_leaf_ty); + return self.bitcast(in_leaf, dest_ty); + } + // Repack output newtypes, after bitcasting the leaf inside, instead. + if let Some((indices, out_leaf_ty)) = unpack_newtype(dest_ty, dest_ty_kind) { + let out_leaf = self.bitcast(val, out_leaf_ty); + let out_agg_undef = self.undef(dest_ty); + return self + .emit() + .composite_insert( + dest_ty, + None, + out_leaf.def(self), + out_agg_undef.def(self), + indices, + ) + .unwrap() + .with_type(dest_ty); + } + + let val_is_ptr = matches!(val_ty_kind, SpirvType::Pointer { .. }); + let dest_is_ptr = matches!(dest_ty_kind, SpirvType::Pointer { .. }); // Reuse the pointer-specific logic in `pointercast` for `*T -> *U`. if val_is_ptr && dest_is_ptr { @@ -1605,29 +1709,21 @@ impl<'a, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'tcx> { } } - fn pointercast(&mut self, val: Self::Value, dest_ty: Self::Type) -> Self::Value { - let (val, val_pointee) = match val.kind { - // Strip a previous `pointercast`, to reveal the original pointer type. - SpirvValueKind::LogicalPtrCast { - original_ptr, - original_pointee_ty, - bitcast_result_id: _, - } => ( - original_ptr.with_type( - SpirvType::Pointer { - pointee: original_pointee_ty, - } - .def(self.span(), self), - ), - original_pointee_ty, - ), + fn pointercast(&mut self, ptr: Self::Value, dest_ty: Self::Type) -> Self::Value { + // HACK(eddyb) reuse the special-casing in `const_bitcast`, which relies + // on adding a pointer type to an untyped pointer (to some const data). + if let SpirvValueKind::IllegalConst(_) = ptr.kind { + return self.const_bitcast(ptr, dest_ty); + } - _ => match self.lookup_type(val.ty) { - SpirvType::Pointer { pointee } => (val, pointee), - other => self.fatal(format!( - "pointercast called on non-pointer source type: {other:?}" - )), - }, + // Strip a previous `pointercast`, to reveal the original pointer type. + let ptr = ptr.strip_ptrcasts(); + + let ptr_pointee = match self.lookup_type(ptr.ty) { + SpirvType::Pointer { pointee } => pointee, + other => self.fatal(format!( + "pointercast called on non-pointer source type: {other:?}" + )), }; let dest_pointee = match self.lookup_type(dest_ty) { SpirvType::Pointer { pointee } => pointee, @@ -1635,26 +1731,29 @@ impl<'a, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'tcx> { "pointercast called on non-pointer dest type: {other:?}" )), }; - if val.ty == dest_ty { - val - } else if let Some(indices) = - self.recover_access_chain_from_offset(val_pointee, dest_pointee, Size::ZERO) - { + if ptr.ty == dest_ty { + ptr + } else if let Some((indices, _)) = self.recover_access_chain_from_offset( + ptr_pointee, + Size::ZERO, + self.lookup_type(dest_pointee).sizeof(self), + Some(dest_pointee), + ) { let indices = indices .into_iter() .map(|idx| self.constant_u32(self.span(), idx).def(self)) .collect::>(); self.emit() - .access_chain(dest_ty, None, val.def(self), indices) + .access_chain(dest_ty, None, ptr.def(self), indices) .unwrap() .with_type(dest_ty) } else { // Defer the cast so that it has a chance to be avoided. - let original_ptr = val.def(self); + let original_ptr = ptr.def(self); SpirvValue { kind: SpirvValueKind::LogicalPtrCast { original_ptr, - original_pointee_ty: val_pointee, + original_ptr_ty: ptr.ty, bitcast_result_id: self.emit().bitcast(dest_ty, None, original_ptr).unwrap(), }, ty: dest_ty, @@ -1930,17 +2029,33 @@ impl<'a, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'tcx> { "memcpy with mem flags is not supported yet: {flags:?}" )); } - let const_size = self.builder.lookup_const_u64(size); - if const_size == Some(0) { + let const_size = self.builder.lookup_const_u64(size).map(Size::from_bytes); + if const_size == Some(Size::ZERO) { // Nothing to do! return; } - let src_pointee = match self.lookup_type(src.ty) { - SpirvType::Pointer { pointee } => Some(pointee), - _ => None, - }; - let src_element_size = src_pointee.and_then(|p| self.lookup_type(p).sizeof(self)); - if src_element_size.is_some() && src_element_size == const_size.map(Size::from_bytes) { + + let typed_copy_dst_src = const_size.and_then(|const_size| { + let dst_adj = self.adjust_pointer_for_sized_access(dst, const_size); + let src_adj = self.adjust_pointer_for_sized_access(src, const_size); + match (dst_adj, src_adj) { + // HACK(eddyb) fill in missing `dst`/`src` with the other side. + (Some((dst, access_ty)), None) => { + Some((dst, self.pointercast(src, self.type_ptr_to(access_ty)))) + } + (None, Some((src, access_ty))) => { + Some((self.pointercast(dst, self.type_ptr_to(access_ty)), src)) + } + (Some((dst, dst_access_ty)), Some((src, src_access_ty))) + if dst_access_ty == src_access_ty => + { + Some((dst, src)) + } + (None, None) | (Some(_), Some(_)) => None, + } + }); + + if let Some((dst, src)) = typed_copy_dst_src { if let Some(const_value) = src.const_fold_load(self) { self.store(const_value, dst, Align::from_bytes(0).unwrap()); } else { @@ -2095,12 +2210,15 @@ impl<'a, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'tcx> { } fn insert_value(&mut self, agg_val: Self::Value, elt: Self::Value, idx: u64) -> Self::Value { - match self.lookup_type(agg_val.ty) { - SpirvType::Adt { field_types, .. } => { - assert_ty_eq!(self, field_types[idx as usize], elt.ty); - } + let field_type = match self.lookup_type(agg_val.ty) { + SpirvType::Adt { field_types, .. } => field_types[idx as usize], other => self.fatal(format!("insert_value not implemented on type {other:?}")), }; + + // HACK(eddyb) temporary workaround for untyped pointers upstream. + // FIXME(eddyb) replace with untyped memory SPIR-V + `qptr` or similar. + let elt = self.bitcast(elt, field_type); + self.emit() .composite_insert( agg_val.ty, @@ -2165,23 +2283,23 @@ impl<'a, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'tcx> { failure_order: AtomicOrdering, _weak: bool, ) -> Self::Value { - let dst_pointee_ty = match self.lookup_type(dst.ty) { - SpirvType::Pointer { pointee } => pointee, - ty => self.fatal(format!( - "atomic_cmpxchg called on variable that wasn't a pointer: {ty:?}" - )), - }; - assert_ty_eq!(self, dst_pointee_ty, cmp.ty); - assert_ty_eq!(self, dst_pointee_ty, src.ty); - self.validate_atomic(dst_pointee_ty, dst.def(self)); + assert_ty_eq!(self, cmp.ty, src.ty); + let ty = src.ty; + + let (dst, access_ty) = self.adjust_pointer_for_typed_access(dst, ty); + let cmp = self.bitcast(cmp, access_ty); + let src = self.bitcast(src, access_ty); + + self.validate_atomic(access_ty, dst.def(self)); // TODO: Default to device scope let memory = self.constant_u32(self.span(), Scope::Device as u32); let semantics_equal = self.ordering_to_semantics_def(order); let semantics_unequal = self.ordering_to_semantics_def(failure_order); // Note: OpAtomicCompareExchangeWeak is deprecated, and has the same semantics - self.emit() + let result = self + .emit() .atomic_compare_exchange( - src.ty, + access_ty, None, dst.def(self), memory.def(self), @@ -2191,7 +2309,8 @@ impl<'a, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'tcx> { cmp.def(self), ) .unwrap() - .with_type(src.ty) + .with_type(access_ty); + self.bitcast(result, ty) } fn atomic_rmw( @@ -2201,48 +2320,45 @@ impl<'a, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'tcx> { src: Self::Value, order: AtomicOrdering, ) -> Self::Value { - let dst_pointee_ty = match self.lookup_type(dst.ty) { - SpirvType::Pointer { pointee } => pointee, - ty => self.fatal(format!( - "atomic_rmw called on variable that wasn't a pointer: {ty:?}" - )), - }; - assert_ty_eq!(self, dst_pointee_ty, src.ty); - self.validate_atomic(dst_pointee_ty, dst.def(self)); + let ty = src.ty; + + let (dst, access_ty) = self.adjust_pointer_for_typed_access(dst, ty); + let src = self.bitcast(src, access_ty); + + self.validate_atomic(access_ty, dst.def(self)); // TODO: Default to device scope let memory = self .constant_u32(self.span(), Scope::Device as u32) .def(self); let semantics = self.ordering_to_semantics_def(order).def(self); - let mut emit = self.emit(); use AtomicRmwBinOp::*; - match op { - AtomicXchg => emit.atomic_exchange( - src.ty, + let result = match op { + AtomicXchg => self.emit().atomic_exchange( + access_ty, None, dst.def(self), memory, semantics, src.def(self), ), - AtomicAdd => emit.atomic_i_add( - src.ty, + AtomicAdd => self.emit().atomic_i_add( + access_ty, None, dst.def(self), memory, semantics, src.def(self), ), - AtomicSub => emit.atomic_i_sub( - src.ty, + AtomicSub => self.emit().atomic_i_sub( + access_ty, None, dst.def(self), memory, semantics, src.def(self), ), - AtomicAnd => emit.atomic_and( - src.ty, + AtomicAnd => self.emit().atomic_and( + access_ty, None, dst.def(self), memory, @@ -2250,48 +2366,48 @@ impl<'a, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'tcx> { src.def(self), ), AtomicNand => self.fatal("atomic nand is not supported"), - AtomicOr => emit.atomic_or( - src.ty, + AtomicOr => self.emit().atomic_or( + access_ty, None, dst.def(self), memory, semantics, src.def(self), ), - AtomicXor => emit.atomic_xor( - src.ty, + AtomicXor => self.emit().atomic_xor( + access_ty, None, dst.def(self), memory, semantics, src.def(self), ), - AtomicMax => emit.atomic_s_max( - src.ty, + AtomicMax => self.emit().atomic_s_max( + access_ty, None, dst.def(self), memory, semantics, src.def(self), ), - AtomicMin => emit.atomic_s_min( - src.ty, + AtomicMin => self.emit().atomic_s_min( + access_ty, None, dst.def(self), memory, semantics, src.def(self), ), - AtomicUMax => emit.atomic_u_max( - src.ty, + AtomicUMax => self.emit().atomic_u_max( + access_ty, None, dst.def(self), memory, semantics, src.def(self), ), - AtomicUMin => emit.atomic_u_min( - src.ty, + AtomicUMin => self.emit().atomic_u_min( + access_ty, None, dst.def(self), memory, @@ -2300,7 +2416,8 @@ impl<'a, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'tcx> { ), } .unwrap() - .with_type(src.ty) + .with_type(access_ty); + self.bitcast(result, ty) } fn atomic_fence(&mut self, order: AtomicOrdering, _scope: SynchronizationScope) { @@ -2394,9 +2511,15 @@ impl<'a, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'tcx> { ), }; - for (argument, &argument_type) in args.iter().zip(argument_types) { - assert_ty_eq!(self, argument.ty, argument_type); - } + // HACK(eddyb) temporary workaround for untyped pointers upstream. + // FIXME(eddyb) replace with untyped memory SPIR-V + `qptr` or similar. + let args: SmallVec<[_; 8]> = args + .iter() + .zip_eq(argument_types) + .map(|(&arg, &expected_type)| self.bitcast(arg, expected_type)) + .collect(); + let args = &args[..]; + let libm_intrinsic = self.libm_intrinsics.borrow().get(&callee_val).copied(); let buffer_load_intrinsic = self .buffer_load_intrinsic_fn_id diff --git a/crates/rustc_codegen_spirv/src/builder/mod.rs b/crates/rustc_codegen_spirv/src/builder/mod.rs index 34b63f1034..d15585960a 100644 --- a/crates/rustc_codegen_spirv/src/builder/mod.rs +++ b/crates/rustc_codegen_spirv/src/builder/mod.rs @@ -102,6 +102,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { self.current_span.unwrap_or(DUMMY_SP) } + // HACK(eddyb) like the `CodegenCx` method but with `self.span()` awareness. + pub fn type_ptr_to(&self, ty: Word) -> Word { + SpirvType::Pointer { pointee: ty }.def(self.span(), self) + } + // Given an ID, check if it's defined by an OpAccessChain, and if it is, return its ptr/indices fn find_access_chain(&self, id: spirv::Word) -> Option<(spirv::Word, Vec)> { let emit = self.emit(); @@ -130,20 +135,16 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { indices: &[SpirvValue], is_inbounds: bool, ) -> SpirvValue { + // HACK(eddyb) temporary workaround for untyped pointers upstream. + // FIXME(eddyb) replace with untyped memory SPIR-V + `qptr` or similar. + let ptr = self.pointercast(ptr, self.type_ptr_to(ty)); + // The first index is an offset to the pointer, the rest are actual members. // https://llvm.org/docs/GetElementPtr.html // "An OpAccessChain instruction is the equivalent of an LLVM getelementptr instruction where the first index element is zero." // https://github.com/gpuweb/gpuweb/issues/33 let mut result_indices = Vec::with_capacity(indices.len() - 1); - let mut result_pointee_type = match self.lookup_type(ptr.ty) { - SpirvType::Pointer { pointee } => { - assert_ty_eq!(self, ty, pointee); - pointee - } - other_type => self.fatal(format!( - "GEP first deref not implemented for type {other_type:?}" - )), - }; + let mut result_pointee_type = ty; for index in indices.iter().cloned().skip(1) { result_indices.push(index.def(self)); result_pointee_type = match self.lookup_type(result_pointee_type) { @@ -154,10 +155,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { )), }; } - let result_type = SpirvType::Pointer { - pointee: result_pointee_type, - } - .def(self.span(), self); + let result_type = self.type_ptr_to(result_pointee_type); let ptr_id = ptr.def(self); if let Some((original_ptr, mut original_indices)) = self.find_access_chain(ptr_id) { diff --git a/crates/rustc_codegen_spirv/src/builder_spirv.rs b/crates/rustc_codegen_spirv/src/builder_spirv.rs index 0a85d8aab3..56993f4245 100644 --- a/crates/rustc_codegen_spirv/src/builder_spirv.rs +++ b/crates/rustc_codegen_spirv/src/builder_spirv.rs @@ -58,8 +58,8 @@ pub enum SpirvValueKind { /// Pointer value being cast. original_ptr: Word, - /// Pointee type of `original_ptr`. - original_pointee_ty: Word, + /// Pointer type of `original_ptr`. + original_ptr_ty: Word, /// Result ID for the `OpBitcast` instruction representing the cast, /// to attach zombies to. @@ -77,6 +77,18 @@ pub struct SpirvValue { } impl SpirvValue { + pub fn strip_ptrcasts(self) -> Self { + match self.kind { + SpirvValueKind::LogicalPtrCast { + original_ptr, + original_ptr_ty, + bitcast_result_id: _, + } => original_ptr.with_type(original_ptr_ty), + + _ => self, + } + } + pub fn const_fold_load(self, cx: &CodegenCx<'_>) -> Option { match self.kind { SpirvValueKind::Def(id) | SpirvValueKind::IllegalConst(id) => { @@ -173,7 +185,7 @@ impl SpirvValue { SpirvValueKind::LogicalPtrCast { original_ptr: _, - original_pointee_ty, + original_ptr_ty, bitcast_result_id, } => { cx.zombie_with_span( @@ -181,9 +193,9 @@ impl SpirvValue { span, &format!( "cannot cast between pointer types\ - \nfrom `*{}`\ + \nfrom `{}`\ \n to `{}`", - cx.debug_type(original_pointee_ty), + cx.debug_type(original_ptr_ty), cx.debug_type(self.ty) ), ); diff --git a/crates/rustc_codegen_spirv/src/codegen_cx/constant.rs b/crates/rustc_codegen_spirv/src/codegen_cx/constant.rs index 52462e44c0..83b60b4fdd 100644 --- a/crates/rustc_codegen_spirv/src/codegen_cx/constant.rs +++ b/crates/rustc_codegen_spirv/src/codegen_cx/constant.rs @@ -370,7 +370,8 @@ impl<'tcx> ConstMethods<'tcx> for CodegenCx<'tcx> { self.builder.lookup_const_by_id(pointee) { if let SpirvType::Pointer { pointee } = self.lookup_type(ty) { - let init = self.create_const_alloc(alloc, pointee); + let mut offset = Size::ZERO; + let init = self.read_from_const_alloc(alloc, &mut offset, pointee); return self.static_addr_of(init, alloc.inner().align, None); } } @@ -422,7 +423,7 @@ impl<'tcx> CodegenCx<'tcx> { // alloc.len() // ); let mut offset = Size::ZERO; - let result = self.create_const_alloc2(alloc, &mut offset, ty); + let result = self.read_from_const_alloc(alloc, &mut offset, ty); assert_eq!( offset.bytes_usize(), alloc.inner().len(), @@ -432,7 +433,7 @@ impl<'tcx> CodegenCx<'tcx> { result } - fn create_const_alloc2( + fn read_from_const_alloc( &self, alloc: ConstAllocation<'tcx>, offset: &mut Size, @@ -515,7 +516,7 @@ impl<'tcx> CodegenCx<'tcx> { let total_offset_start = base + field_offset; let mut total_offset_end = total_offset_start; values.push( - self.create_const_alloc2(alloc, &mut total_offset_end, ty) + self.read_from_const_alloc(alloc, &mut total_offset_end, ty) .def_cx(self), ); occupied_spaces.push(total_offset_start..total_offset_end); @@ -534,7 +535,7 @@ impl<'tcx> CodegenCx<'tcx> { SpirvType::Array { element, count } => { let count = self.builder.lookup_const_u64(count).unwrap() as usize; let values = (0..count).map(|_| { - self.create_const_alloc2(alloc, offset, element) + self.read_from_const_alloc(alloc, offset, element) .def_cx(self) }); self.constant_composite(ty, values) @@ -545,7 +546,7 @@ impl<'tcx> CodegenCx<'tcx> { .expect("create_const_alloc: Vectors must be sized"); let final_offset = *offset + total_size; let values = (0..count).map(|_| { - self.create_const_alloc2(alloc, offset, element) + self.read_from_const_alloc(alloc, offset, element) .def_cx(self) }); let result = self.constant_composite(ty, values); @@ -560,7 +561,7 @@ impl<'tcx> CodegenCx<'tcx> { .expect("create_const_alloc: Matrices must be sized"); let final_offset = *offset + total_size; let values = (0..count).map(|_| { - self.create_const_alloc2(alloc, offset, element) + self.read_from_const_alloc(alloc, offset, element) .def_cx(self) }); let result = self.constant_composite(ty, values); @@ -573,7 +574,7 @@ impl<'tcx> CodegenCx<'tcx> { let mut values = Vec::new(); while offset.bytes_usize() != alloc.inner().len() { values.push( - self.create_const_alloc2(alloc, offset, element) + self.read_from_const_alloc(alloc, offset, element) .def_cx(self), ); } diff --git a/crates/rustc_codegen_spirv/src/codegen_cx/type_.rs b/crates/rustc_codegen_spirv/src/codegen_cx/type_.rs index adcc332153..6effea59b9 100644 --- a/crates/rustc_codegen_spirv/src/codegen_cx/type_.rs +++ b/crates/rustc_codegen_spirv/src/codegen_cx/type_.rs @@ -194,7 +194,7 @@ impl<'tcx> BaseTypeMethods<'tcx> for CodegenCx<'tcx> { align, size, field_types: els, - field_offsets: &field_offsets.as_slice(), + field_offsets: &field_offsets, field_names: None, } .def(DUMMY_SP, self) diff --git a/crates/rustc_codegen_spirv/src/lib.rs b/crates/rustc_codegen_spirv/src/lib.rs index 27d6d11357..99cb405790 100644 --- a/crates/rustc_codegen_spirv/src/lib.rs +++ b/crates/rustc_codegen_spirv/src/lib.rs @@ -16,6 +16,7 @@ //! [`spirv-tools`]: https://embarkstudios.github.io/rust-gpu/api/spirv_tools //! [`spirv-tools-sys`]: https://embarkstudios.github.io/rust-gpu/api/spirv_tools_sys #![feature(rustc_private)] +#![feature(array_methods)] #![feature(assert_matches)] #![feature(result_flattening)] #![feature(lint_reasons)] diff --git a/crates/spirv-std/macros/src/lib.rs b/crates/spirv-std/macros/src/lib.rs index fe492e2e18..9ecc7aef8b 100644 --- a/crates/spirv-std/macros/src/lib.rs +++ b/crates/spirv-std/macros/src/lib.rs @@ -740,10 +740,14 @@ impl SampleImplRewriter { fn add_regs(&self, t: &mut Vec) { for i in 0..SAMPLE_PARAM_COUNT { if self.0 & (1 << i) != 0 { + // HACK(eddyb) the extra `{...}` force the pointers to be to + // fresh variables holding value copies, instead of the originals, + // allowing `OpLoad _` inference to pick the appropriate type. let s = if is_grad(i) { - String::from("grad_x=in(reg) ¶ms.grad.0.0,grad_y=in(reg) ¶ms.grad.0.1,") + "grad_x=in(reg) &{params.grad.0.0},grad_y=in(reg) &{params.grad.0.1}," + .to_string() } else { - format!("{0} = in(reg) ¶ms.{0}.0,", SAMPLE_PARAM_NAMES[i]) + format!("{0} = in(reg) &{{params.{0}.0}},", SAMPLE_PARAM_NAMES[i]) }; let ts: proc_macro2::TokenStream = s.parse().unwrap(); t.extend(ts); diff --git a/tests/ui/arch/debug_printf_type_checking.stderr b/tests/ui/arch/debug_printf_type_checking.stderr index 194c322f59..0bd4cb7494 100644 --- a/tests/ui/arch/debug_printf_type_checking.stderr +++ b/tests/ui/arch/debug_printf_type_checking.stderr @@ -75,9 +75,9 @@ help: the return type of this call is `u32` due to the type of the argument pass | | | this argument influences the return type of `spirv_std` note: function defined here - --> $SPIRV_STD_SRC/lib.rs:135:8 + --> $SPIRV_STD_SRC/lib.rs:136:8 | -135 | pub fn debug_printf_assert_is_type(ty: T) -> T { +136 | pub fn debug_printf_assert_is_type(ty: T) -> T { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: this error originates in the macro `debug_printf` (in Nightly builds, run with -Z macro-backtrace for more info) help: change the type of the numeric literal from `u32` to `f32` @@ -102,9 +102,9 @@ help: the return type of this call is `f32` due to the type of the argument pass | | | this argument influences the return type of `spirv_std` note: function defined here - --> $SPIRV_STD_SRC/lib.rs:135:8 + --> $SPIRV_STD_SRC/lib.rs:136:8 | -135 | pub fn debug_printf_assert_is_type(ty: T) -> T { +136 | pub fn debug_printf_assert_is_type(ty: T) -> T { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: this error originates in the macro `debug_printf` (in Nightly builds, run with -Z macro-backtrace for more info) help: change the type of the numeric literal from `f32` to `u32` @@ -113,32 +113,30 @@ help: change the type of the numeric literal from `f32` to `u32` | ~~~ error[E0277]: the trait bound `{float}: Vector` is not satisfied - --> $DIR/debug_printf_type_checking.rs:23:31 + --> $DIR/debug_printf_type_checking.rs:23:9 | 23 | debug_printf!("%v2f", 11.0); - | ----------------------^^^^- - | | | - | | the trait `Vector` is not implemented for `{float}` - | required by a bound introduced by this call + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Vector` is not implemented for `{float}` | = help: the following other types implement trait `Vector`: + > + > + > + > > > > > - > - > - > - > and 5 others note: required by a bound in `debug_printf_assert_is_vector` - --> $SPIRV_STD_SRC/lib.rs:142:8 + --> $SPIRV_STD_SRC/lib.rs:143:8 | -140 | pub fn debug_printf_assert_is_vector< +141 | pub fn debug_printf_assert_is_vector< | ----------------------------- required by a bound in this function -141 | TY: crate::scalar::Scalar, -142 | V: crate::vector::Vector, +142 | TY: crate::scalar::Scalar, +143 | V: crate::vector::Vector, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `debug_printf_assert_is_vector` + = note: this error originates in the macro `debug_printf` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0308]: mismatched types --> $DIR/debug_printf_type_checking.rs:24:29 @@ -157,9 +155,9 @@ help: the return type of this call is `Vec2` due to the type of the argument pas | | | this argument influences the return type of `spirv_std` note: function defined here - --> $SPIRV_STD_SRC/lib.rs:135:8 + --> $SPIRV_STD_SRC/lib.rs:136:8 | -135 | pub fn debug_printf_assert_is_type(ty: T) -> T { +136 | pub fn debug_printf_assert_is_type(ty: T) -> T { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: this error originates in the macro `debug_printf` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/dis/ptr_copy.normal.stderr b/tests/ui/dis/ptr_copy.normal.stderr index 8118ae08b7..196c73353e 100644 --- a/tests/ui/dis/ptr_copy.normal.stderr +++ b/tests/ui/dis/ptr_copy.normal.stderr @@ -1,13 +1,13 @@ error: cannot memcpy dynamically sized data - --> $CORE_SRC/intrinsics.rs:2767:9 + --> $CORE_SRC/intrinsics.rs:2771:9 | -2767 | copy(src, dst, count) +2771 | copy(src, dst, count) | ^^^^^^^^^^^^^^^^^^^^^ | note: used from within `core::intrinsics::copy::` - --> $CORE_SRC/intrinsics.rs:2753:21 + --> $CORE_SRC/intrinsics.rs:2757:21 | -2753 | pub const unsafe fn copy(src: *const T, dst: *mut T, count: usize) { +2757 | pub const unsafe fn copy(src: *const T, dst: *mut T, count: usize) { | ^^^^ note: called by `ptr_copy::copy_via_raw_ptr` --> $DIR/ptr_copy.rs:28:18 diff --git a/tests/ui/dis/ptr_read.stderr b/tests/ui/dis/ptr_read.stderr index 0bf7992457..7ec82f82f5 100644 --- a/tests/ui/dis/ptr_read.stderr +++ b/tests/ui/dis/ptr_read.stderr @@ -2,7 +2,7 @@ %4 = OpFunctionParameter %5 %6 = OpFunctionParameter %5 %7 = OpLabel -OpLine %8 1179 8 +OpLine %8 1180 8 %9 = OpLoad %10 %4 OpLine %11 7 13 OpStore %6 %9 diff --git a/tests/ui/dis/ptr_read_method.stderr b/tests/ui/dis/ptr_read_method.stderr index 0bf7992457..7ec82f82f5 100644 --- a/tests/ui/dis/ptr_read_method.stderr +++ b/tests/ui/dis/ptr_read_method.stderr @@ -2,7 +2,7 @@ %4 = OpFunctionParameter %5 %6 = OpFunctionParameter %5 %7 = OpLabel -OpLine %8 1179 8 +OpLine %8 1180 8 %9 = OpLoad %10 %4 OpLine %11 7 13 OpStore %6 %9 diff --git a/tests/ui/dis/ptr_write.stderr b/tests/ui/dis/ptr_write.stderr index a101a05269..5d3995f906 100644 --- a/tests/ui/dis/ptr_write.stderr +++ b/tests/ui/dis/ptr_write.stderr @@ -4,7 +4,7 @@ %7 = OpLabel OpLine %8 7 35 %9 = OpLoad %10 %4 -OpLine %11 1377 8 +OpLine %11 1379 8 OpStore %6 %9 OpNoLine OpReturn diff --git a/tests/ui/dis/ptr_write_method.stderr b/tests/ui/dis/ptr_write_method.stderr index 2c6ae1dc37..2ee93c4b9c 100644 --- a/tests/ui/dis/ptr_write_method.stderr +++ b/tests/ui/dis/ptr_write_method.stderr @@ -4,7 +4,7 @@ %7 = OpLabel OpLine %8 7 37 %9 = OpLoad %10 %4 -OpLine %11 1377 8 +OpLine %11 1379 8 OpStore %6 %9 OpNoLine OpReturn From 82cf0f0b2b383c02e024be221b1c73f267eac34a Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Tue, 21 Nov 2023 17:30:11 +0200 Subject: [PATCH 6/8] rustc_codegen_spirv/test: unbreak after termcolor-related changes. --- Cargo.lock | 1 - crates/rustc_codegen_spirv/Cargo.toml | 7 ------- crates/rustc_codegen_spirv/src/linker/test.rs | 20 +++++++++++++++---- 3 files changed, 16 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8354e79cb7..ea02c934de 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2041,7 +2041,6 @@ dependencies = [ "spirv-tools", "syn", "tempfile", - "termcolor", ] [[package]] diff --git a/crates/rustc_codegen_spirv/Cargo.toml b/crates/rustc_codegen_spirv/Cargo.toml index 6188b59c03..4b94d02edf 100644 --- a/crates/rustc_codegen_spirv/Cargo.toml +++ b/crates/rustc_codegen_spirv/Cargo.toml @@ -62,13 +62,6 @@ spirt = "0.3.0" lazy_static = "1.4.0" itertools = "0.10.5" -# `termcolor` is needed because we cannot construct an Emitter after it was added in -# https://github.com/rust-lang/rust/pull/114104. This can be removed when -# https://github.com/rust-lang/rust/pull/115393 lands. -# We need to construct an emitter as yet another workaround, -# see https://github.com/rust-lang/rust/pull/102992. -termcolor = "1.2" - [dev-dependencies] pipe = "0.4" pretty_assertions = "1.0" diff --git a/crates/rustc_codegen_spirv/src/linker/test.rs b/crates/rustc_codegen_spirv/src/linker/test.rs index 59bfb13337..63916cc209 100644 --- a/crates/rustc_codegen_spirv/src/linker/test.rs +++ b/crates/rustc_codegen_spirv/src/linker/test.rs @@ -6,6 +6,13 @@ use rustc_session::CompilerIO; use rustc_span::FileName; use std::io::Write; use std::sync::{Arc, Mutex}; + +// `termcolor` is needed because we cannot construct an Emitter after it was added in +// https://github.com/rust-lang/rust/pull/114104. This can be removed when +// https://github.com/rust-lang/rust/pull/115393 lands. +// We need to construct an emitter as yet another workaround, +// see https://github.com/rust-lang/rust/pull/102992. +extern crate termcolor; use termcolor::{ColorSpec, WriteColor}; // https://github.com/colin-kiegel/rust-pretty-assertions/issues/24 @@ -81,9 +88,8 @@ fn link_with_linker_opts( struct BufWriter(Arc>>); impl BufWriter { - fn to_string(self) -> String { - let x = self.0.into_inner().expect("diagnostics unlocked"); - String::from_utf8(x).expect("conversion to string") + fn unwrap_to_string(self) -> String { + String::from_utf8(Arc::try_unwrap(self.0).ok().unwrap().into_inner().unwrap()).unwrap() } } @@ -190,7 +196,13 @@ fn link_with_linker_opts( }) }) .flatten() - .map_err(|_e| buf.to_string()) + .map_err(|_e| { + let mut diags = output.unwrap_to_string(); + if let Some(diags_without_trailing_newlines) = diags.strip_suffix("\n\n") { + diags.truncate(diags_without_trailing_newlines.len()); + } + diags + }) .map_err(PrettyString) } From 38cc3bfa45ae52e143e0653caa1438b989448534 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Tue, 21 Nov 2023 17:44:07 +0200 Subject: [PATCH 7/8] Appease `cargo deny`. --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ea02c934de..dd3223f113 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -35,9 +35,9 @@ checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" [[package]] name = "ahash" -version = "0.7.6" +version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" +checksum = "5a824f2aa7e75a0c98c5a504fceb80649e9c35265d44525b5f94de4771a395cd" dependencies = [ "getrandom", "once_cell", From 185545864faeb58bb38a3993be5ece1b730b78f3 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Tue, 21 Nov 2023 18:18:31 +0200 Subject: [PATCH 8/8] Updated CHANGELOG. --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4f294e28d8..f71d4d5c0b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,6 +30,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] ### Changed 🛠 +- [PR#1091](https://github.com/EmbarkStudios/rust-gpu/pull/1091) updated toolchain to `nightly-2023-08-29` - [PR#1085](https://github.com/EmbarkStudios/rust-gpu/pull/1085) updated toolchain to `nightly-2023-07-08` ## [0.9.0]