diff --git a/CHANGELOG.md b/CHANGELOG.md index 6ef4fd99b2..4f294e28d8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,6 +29,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Changed 🛠 +- [PR#1085](https://github.com/EmbarkStudios/rust-gpu/pull/1085) updated toolchain to `nightly-2023-07-08` + ## [0.9.0] ### Added ⭐ diff --git a/Cargo.lock b/Cargo.lock index cfd1bc3707..d58f05163e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1837,9 +1837,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.47" +version = "1.0.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ea3d908b0e36316caf9e9e2c4625cdde190a7e6f440d794667ed17a1855e725" +checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" dependencies = [ "unicode-ident", ] diff --git a/crates/rustc_codegen_spirv/build.rs b/crates/rustc_codegen_spirv/build.rs index c3de9b5924..86605ea183 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-05-27" +channel = "nightly-2023-07-08" components = ["rust-src", "rustc-dev", "llvm-tools-preview"] -# commit_hash = 1a5f8bce74ee432f7cc3aa131bc3d6920e06de10"#; +# commit_hash = cb80ff132a0e9aa71529b701427e4e6c243b58df"#; 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/builder/builder_methods.rs b/crates/rustc_codegen_spirv/src/builder/builder_methods.rs index a828d39d55..60c525758b 100644 --- a/crates/rustc_codegen_spirv/src/builder/builder_methods.rs +++ b/crates/rustc_codegen_spirv/src/builder/builder_methods.rs @@ -201,7 +201,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { 64 => self .constant_u64(self.span(), memset_fill_u64(fill_byte)) .def(self), - _ => self.fatal(&format!( + _ => self.fatal(format!( "memset on integer width {width} not implemented yet" )), }, @@ -212,9 +212,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { 64 => self .constant_f64(self.span(), f64::from_bits(memset_fill_u64(fill_byte))) .def(self), - _ => self.fatal(&format!( - "memset on float width {width} not implemented yet" - )), + _ => self.fatal(format!("memset on float width {width} not implemented yet")), }, SpirvType::Adt { .. } => self.fatal("memset on structs not implemented yet"), SpirvType::Vector { element, count } | SpirvType::Matrix { element, count } => { @@ -259,16 +257,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { 16 => memset_dynamic_scalar(self, fill_var, 2, false), 32 => memset_dynamic_scalar(self, fill_var, 4, false), 64 => memset_dynamic_scalar(self, fill_var, 8, false), - _ => self.fatal(&format!( + _ => self.fatal(format!( "memset on integer width {width} not implemented yet" )), }, SpirvType::Float(width) => match width { 32 => memset_dynamic_scalar(self, fill_var, 4, true), 64 => memset_dynamic_scalar(self, fill_var, 8, true), - _ => self.fatal(&format!( - "memset on float width {width} not implemented yet" - )), + _ => self.fatal(format!("memset on float width {width} not implemented yet")), }, SpirvType::Adt { .. } => self.fatal("memset on structs not implemented yet"), SpirvType::Array { element, count } => { @@ -805,7 +801,7 @@ impl<'a, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'tcx> { ) { fn construct_8(self_: &Builder<'_, '_>, signed: bool, v: u128) -> Operand { if v > u8::MAX as u128 { - self_.fatal(&format!( + self_.fatal(format!( "Switches to values above u8::MAX not supported: {v:?}" )) } else if signed { @@ -817,7 +813,7 @@ impl<'a, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'tcx> { } fn construct_16(self_: &Builder<'_, '_>, signed: bool, v: u128) -> Operand { if v > u16::MAX as u128 { - self_.fatal(&format!( + self_.fatal(format!( "Switches to values above u16::MAX not supported: {v:?}" )) } else if signed { @@ -828,7 +824,7 @@ impl<'a, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'tcx> { } fn construct_32(self_: &Builder<'_, '_>, _signed: bool, v: u128) -> Operand { if v > u32::MAX as u128 { - self_.fatal(&format!( + self_.fatal(format!( "Switches to values above u32::MAX not supported: {v:?}" )) } else { @@ -837,7 +833,7 @@ impl<'a, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'tcx> { } fn construct_64(self_: &Builder<'_, '_>, _signed: bool, v: u128) -> Operand { if v > u64::MAX as u128 { - self_.fatal(&format!( + self_.fatal(format!( "Switches to values above u64::MAX not supported: {v:?}" )) } else { @@ -852,13 +848,13 @@ impl<'a, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'tcx> { 16 => construct_16, 32 => construct_32, 64 => construct_64, - other => self.fatal(&format!( + other => self.fatal(format!( "switch selector cannot have width {other} (only 8, 16, 32, and 64 bits allowed)" )), }; (signed, construct_case) } - other => self.fatal(&format!( + other => self.fatal(format!( "switch selector cannot have non-integer type {}", other.debug(v.ty, self) )), @@ -947,7 +943,7 @@ impl<'a, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'tcx> { SpirvType::Bool => self .emit() .logical_and(ty, None, lhs.def(self), rhs.def(self)), - o => self.fatal(&format!( + o => self.fatal(format!( "and() not implemented for type {}", o.debug(ty, self) )), @@ -966,7 +962,7 @@ impl<'a, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'tcx> { SpirvType::Bool => self .emit() .logical_or(ty, None, lhs.def(self), rhs.def(self)), - o => self.fatal(&format!( + o => self.fatal(format!( "or() not implemented for type {}", o.debug(ty, self) )), @@ -986,7 +982,7 @@ impl<'a, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'tcx> { self.emit() .logical_not_equal(ty, None, lhs.def(self), rhs.def(self)) } - o => self.fatal(&format!( + o => self.fatal(format!( "xor() not implemented for type {}", o.debug(ty, self) )), @@ -1003,7 +999,7 @@ impl<'a, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'tcx> { self.emit() .logical_not_equal(val.ty, None, val.def(self), true_.def(self)) } - o => self.fatal(&format!( + o => self.fatal(format!( "not() not implemented for type {}", o.debug(val.ty, self) )), @@ -1104,7 +1100,7 @@ impl<'a, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'tcx> { assert_ty_eq!(self, ty, pointee); pointee } - ty => self.fatal(&format!( + ty => self.fatal(format!( "load called on variable that wasn't a pointer: {ty:?}" )), }; @@ -1133,7 +1129,7 @@ impl<'a, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'tcx> { assert_ty_eq!(self, ty, pointee); pointee } - ty => self.fatal(&format!( + ty => self.fatal(format!( "atomic_load called on variable that wasn't a pointer: {ty:?}" )), }; @@ -1160,7 +1156,7 @@ impl<'a, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'tcx> { place: PlaceRef<'tcx, Self::Value>, ) -> OperandRef<'tcx, Self::Value> { if place.layout.is_zst() { - return OperandRef::new_zst(self, place.layout); + return OperandRef::zero_sized(place.layout); } let val = if let Some(llextra) = place.llextra { @@ -1236,7 +1232,7 @@ 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!( + ty => self.fatal(format!( "store called on variable that wasn't a pointer: {ty:?}" )), }; @@ -1268,7 +1264,7 @@ impl<'a, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'tcx> { flags: MemFlags, ) -> Self::Value { if flags != MemFlags::empty() { - self.err(&format!("store_with_flags is not supported yet: {flags:?}")); + self.err(format!("store_with_flags is not supported yet: {flags:?}")); } self.store(val, ptr, align) } @@ -1282,7 +1278,7 @@ impl<'a, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'tcx> { ) { let ptr_elem_ty = match self.lookup_type(ptr.ty) { SpirvType::Pointer { pointee } => pointee, - ty => self.fatal(&format!( + ty => self.fatal(format!( "atomic_store called on variable that wasn't a pointer: {ty:?}" )), }; @@ -1320,7 +1316,7 @@ impl<'a, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'tcx> { assert_ty_eq!(self, ty, pointee); pointee } - other => self.fatal(&format!( + other => self.fatal(format!( "struct_gep not on pointer type: {other:?}, index {idx}" )), }; @@ -1335,7 +1331,7 @@ impl<'a, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'tcx> { assert_eq!(idx, 0); inner_type } - other => self.fatal(&format!( + other => self.fatal(format!( "struct_gep not on struct, array, or vector type: {other:?}, index {idx}" )), }; @@ -1480,7 +1476,7 @@ impl<'a, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'tcx> { fn ptrtoint(&mut self, val: Self::Value, dest_ty: Self::Type) -> Self::Value { match self.lookup_type(val.ty) { SpirvType::Pointer { .. } => (), - other => self.fatal(&format!( + other => self.fatal(format!( "ptrtoint called on non-pointer source type: {other:?}" )), } @@ -1500,7 +1496,7 @@ impl<'a, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'tcx> { fn inttoptr(&mut self, val: Self::Value, dest_ty: Self::Type) -> Self::Value { match self.lookup_type(dest_ty) { SpirvType::Pointer { .. } => (), - other => self.fatal(&format!( + other => self.fatal(format!( "inttoptr called on non-pointer dest type: {other:?}" )), } @@ -1603,7 +1599,7 @@ impl<'a, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'tcx> { .unwrap() .with_type(dest_ty) } - (val_ty, dest_ty_spv) => self.fatal(&format!( + (val_ty, dest_ty_spv) => self.fatal(format!( "TODO: intcast not implemented yet: val={val:?} val.ty={val_ty:?} dest_ty={dest_ty_spv:?} is_signed={is_signed}" )), } @@ -1628,14 +1624,14 @@ impl<'a, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'tcx> { _ => match self.lookup_type(val.ty) { SpirvType::Pointer { pointee } => (val, pointee), - other => self.fatal(&format!( + 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, - other => self.fatal(&format!( + other => self.fatal(format!( "pointercast called on non-pointer dest type: {other:?}" )), }; @@ -1860,7 +1856,7 @@ impl<'a, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'tcx> { IntSLT => self.fatal("TODO: boolean operator IntSLT not implemented yet"), IntSLE => self.fatal("TODO: boolean operator IntSLE not implemented yet"), }, - other => self.fatal(&format!( + other => self.fatal(format!( "Int comparison not implemented on {}", other.debug(lhs.ty, self) )), @@ -1930,7 +1926,7 @@ impl<'a, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'tcx> { flags: MemFlags, ) { if flags != MemFlags::empty() { - self.err(&format!( + self.err(format!( "memcpy with mem flags is not supported yet: {flags:?}" )); } @@ -1988,13 +1984,13 @@ impl<'a, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'tcx> { flags: MemFlags, ) { if flags != MemFlags::empty() { - self.err(&format!( + self.err(format!( "memset with mem flags is not supported yet: {flags:?}" )); } let elem_ty = match self.lookup_type(ptr.ty) { SpirvType::Pointer { pointee } => pointee, - _ => self.fatal(&format!( + _ => self.fatal(format!( "memset called on non-pointer type: {}", self.debug_type(ptr.ty) )), @@ -2038,9 +2034,7 @@ impl<'a, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'tcx> { fn extract_element(&mut self, vec: Self::Value, idx: Self::Value) -> Self::Value { let result_type = match self.lookup_type(vec.ty) { SpirvType::Vector { element, .. } => element, - other => self.fatal(&format!( - "extract_element not implemented on type {other:?}" - )), + other => self.fatal(format!("extract_element not implemented on type {other:?}")), }; match self.builder.lookup_const_u64(idx) { Some(const_index) => self.emit().composite_extract( @@ -2084,7 +2078,7 @@ impl<'a, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'tcx> { SpirvType::Array { element, .. } | SpirvType::Vector { element, .. } | SpirvType::Matrix { element, .. } => element, - other => self.fatal(&format!( + other => self.fatal(format!( "extract_value not implemented on type {}", other.debug(agg_val.ty, self) )), @@ -2105,7 +2099,7 @@ impl<'a, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'tcx> { SpirvType::Adt { field_types, .. } => { assert_ty_eq!(self, field_types[idx as usize], elt.ty); } - other => self.fatal(&format!("insert_value not implemented on type {other:?}")), + other => self.fatal(format!("insert_value not implemented on type {other:?}")), }; self.emit() .composite_insert( @@ -2173,7 +2167,7 @@ impl<'a, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'tcx> { ) -> Self::Value { let dst_pointee_ty = match self.lookup_type(dst.ty) { SpirvType::Pointer { pointee } => pointee, - ty => self.fatal(&format!( + ty => self.fatal(format!( "atomic_cmpxchg called on variable that wasn't a pointer: {ty:?}" )), }; @@ -2209,7 +2203,7 @@ impl<'a, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'tcx> { ) -> Self::Value { let dst_pointee_ty = match self.lookup_type(dst.ty) { SpirvType::Pointer { pointee } => pointee, - ty => self.fatal(&format!( + ty => self.fatal(format!( "atomic_rmw called on variable that wasn't a pointer: {ty:?}" )), }; @@ -2562,8 +2556,8 @@ impl<'a, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'tcx> { enum Inst<'tcx, ID> { Bitcast(ID, ID), CompositeExtract(ID, ID, u32), - AccessChain(ID, ID, SpirvConst<'tcx>), - InBoundsAccessChain(ID, ID, SpirvConst<'tcx>), + AccessChain(ID, ID, SpirvConst<'tcx, 'tcx>), + InBoundsAccessChain(ID, ID, SpirvConst<'tcx, 'tcx>), Store(ID, ID), Load(ID, ID), Call(ID, ID, SmallVec<[ID; 4]>), 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 e918a82f6a..088b86e364 100644 --- a/crates/rustc_codegen_spirv/src/builder/byte_addressable_buffer.rs +++ b/crates/rustc_codegen_spirv/src/builder/byte_addressable_buffer.rs @@ -10,7 +10,7 @@ use rustc_target::abi::{Align, Size}; impl<'a, 'tcx> Builder<'a, 'tcx> { fn load_err(&mut self, original_type: Word, invalid_type: Word) -> SpirvValue { - let mut err = self.struct_err(&format!( + let mut err = self.struct_err(format!( "cannot load type {} in an untyped buffer load", self.debug_type(original_type) )); @@ -191,7 +191,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // Signature: fn load(array: &[u32], index: u32) -> T; if args.len() != 3 { - self.fatal(&format!( + self.fatal(format!( "buffer_load_intrinsic should have 3 args, it has {}", args.len() )); @@ -205,7 +205,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } fn store_err(&mut self, original_type: Word, value: SpirvValue) -> Result<(), ErrorGuaranteed> { - let mut err = self.struct_err(&format!( + let mut err = self.struct_err(format!( "cannot store type {} in an untyped buffer store", self.debug_type(original_type) )); @@ -358,7 +358,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { }; let expected_args = if is_pair { 5 } else { 4 }; if args.len() != expected_args { - self.fatal(&format!( + self.fatal(format!( "buffer_store_intrinsic should have {} args, it has {}", expected_args, args.len() diff --git a/crates/rustc_codegen_spirv/src/builder/intrinsics.rs b/crates/rustc_codegen_spirv/src/builder/intrinsics.rs index 8089bd09b3..229238d2fb 100644 --- a/crates/rustc_codegen_spirv/src/builder/intrinsics.rs +++ b/crates/rustc_codegen_spirv/src/builder/intrinsics.rs @@ -124,7 +124,7 @@ impl<'a, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'tcx> { self.add(args[0].immediate(), args[1].immediate()) } TyKind::Float(_) => self.fadd(args[0].immediate(), args[1].immediate()), - other => self.fatal(&format!( + other => self.fatal(format!( "Unimplemented saturating_add intrinsic type: {other:#?}" )), }; @@ -139,7 +139,7 @@ impl<'a, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'tcx> { self.sub(args[0].immediate(), args[1].immediate()) } TyKind::Float(_) => self.fsub(args[0].immediate(), args[1].immediate()), - other => self.fatal(&format!( + other => self.fatal(format!( "Unimplemented saturating_sub intrinsic type: {other:#?}" )), }; @@ -327,7 +327,7 @@ impl<'a, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'tcx> { } } - _ => self.fatal(&format!("TODO: Unknown intrinsic '{name}'")), + _ => self.fatal(format!("TODO: Unknown intrinsic '{name}'")), }; if !fn_abi.ret.is_ignore() { diff --git a/crates/rustc_codegen_spirv/src/builder/mod.rs b/crates/rustc_codegen_spirv/src/builder/mod.rs index 7ac0f4a2f5..b64ddd184c 100644 --- a/crates/rustc_codegen_spirv/src/builder/mod.rs +++ b/crates/rustc_codegen_spirv/src/builder/mod.rs @@ -20,10 +20,8 @@ use rustc_codegen_ssa::traits::{ AbiBuilderMethods, ArgAbiMethods, BackendTypes, BuilderMethods, CoverageInfoBuilderMethods, DebugInfoBuilderMethods, HasCodegen, StaticBuilderMethods, TypeMembershipMethods, }; -use rustc_errors::{DiagnosticBuilder, ErrorGuaranteed}; -use rustc_middle::mir::coverage::{ - CodeRegion, CounterValueReference, ExpressionOperandId, InjectedExpressionId, Op, -}; +use rustc_errors::{DiagnosticBuilder, DiagnosticMessage, ErrorGuaranteed}; +use rustc_middle::mir::Coverage; use rustc_middle::span_bug; use rustc_middle::ty::layout::{ FnAbiError, FnAbiOfHelpers, FnAbiRequest, HasParamEnv, HasTyCtxt, LayoutError, LayoutOfHelpers, @@ -70,7 +68,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } - pub fn struct_err(&self, msg: &str) -> DiagnosticBuilder<'_, ErrorGuaranteed> { + #[track_caller] + pub fn struct_err( + &self, + msg: impl Into, + ) -> DiagnosticBuilder<'_, ErrorGuaranteed> { if let Some(current_span) = self.current_span { self.tcx.sess.struct_span_err(current_span, msg) } else { @@ -78,7 +80,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } - pub fn err(&self, msg: &str) { + #[track_caller] + pub fn err(&self, msg: impl Into) { if let Some(current_span) = self.current_span { self.tcx.sess.span_err(current_span, msg); } else { @@ -86,7 +89,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } - pub fn fatal(&self, msg: &str) -> ! { + #[track_caller] + pub fn fatal(&self, msg: impl Into) -> ! { if let Some(current_span) = self.current_span { self.tcx.sess.span_fatal(current_span, msg) } else { @@ -136,7 +140,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { assert_ty_eq!(self, ty, pointee); pointee } - other_type => self.fatal(&format!( + other_type => self.fatal(format!( "GEP first deref not implemented for type {other_type:?}" )), }; @@ -144,7 +148,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { result_indices.push(index.def(self)); result_pointee_type = match self.lookup_type(result_pointee_type) { SpirvType::Array { element, .. } | SpirvType::RuntimeArray { element } => element, - _ => self.fatal(&format!( + _ => self.fatal(format!( "GEP not implemented for type {}", self.debug_type(result_pointee_type) )), @@ -218,7 +222,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { fn rotate(&mut self, value: SpirvValue, shift: SpirvValue, is_left: bool) -> SpirvValue { let width = match self.lookup_type(shift.ty) { SpirvType::Integer(width, _) => width, - other => self.fatal(&format!( + other => self.fatal(format!( "cannot rotate non-integer type: {}", other.debug(shift.ty, self) )), @@ -257,31 +261,7 @@ impl<'a, 'tcx> Deref for Builder<'a, 'tcx> { } impl<'a, 'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'a, 'tcx> { - fn set_function_source_hash(&mut self, _: rustc_middle::ty::Instance<'tcx>, _: u64) -> bool { - todo!() - } - fn add_coverage_counter( - &mut self, - _: Instance<'tcx>, - _: CounterValueReference, - _: CodeRegion, - ) -> bool { - todo!() - } - fn add_coverage_counter_expression( - &mut self, - _: Instance<'tcx>, - _: InjectedExpressionId, - _: ExpressionOperandId, - _: Op, - _: ExpressionOperandId, - _: Option, - ) -> bool { - todo!() - } - fn add_coverage_unreachable(&mut self, _: Instance<'tcx>, _: CodeRegion) -> bool { - todo!() - } + fn add_coverage(&mut self, _instance: Instance<'tcx>, _coverage: &Coverage) {} } impl<'a, 'tcx> DebugInfoBuilderMethods for Builder<'a, 'tcx> { diff --git a/crates/rustc_codegen_spirv/src/builder/spirv_asm.rs b/crates/rustc_codegen_spirv/src/builder/spirv_asm.rs index fe02bf9c8e..97c4d9cfa1 100644 --- a/crates/rustc_codegen_spirv/src/builder/spirv_asm.rs +++ b/crates/rustc_codegen_spirv/src/builder/spirv_asm.rs @@ -64,7 +64,7 @@ impl<'a, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'tcx> { const SUPPORTED_OPTIONS: InlineAsmOptions = InlineAsmOptions::NORETURN; let unsupported_options = options & !SUPPORTED_OPTIONS; if !unsupported_options.is_empty() { - self.err(&format!("asm flags not supported: {unsupported_options:?}")); + self.err(format!("asm flags not supported: {unsupported_options:?}")); } // vec of lines, and each line is vec of tokens let mut tokens = vec![vec![]]; @@ -162,14 +162,14 @@ impl<'a, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'tcx> { } (false, AsmBlock::Open) => (), (false, AsmBlock::End(terminator)) => { - self.err(&format!( + self.err(format!( "trailing terminator `Op{terminator:?}` requires `options(noreturn)`" )); } } for (id, num) in id_map { if !defined_ids.contains(&num) { - self.err(&format!("%{id} is used but not defined")); + self.err(format!("%{id} is used but not defined")); } } } @@ -232,7 +232,7 @@ impl<'cx, 'tcx> Builder<'cx, 'tcx> { Some('\'') => '\'', Some('"') => '"', Some(escape) => { - self.err(&format!("invalid escape '\\{escape}'")); + self.err(format!("invalid escape '\\{escape}'")); return None; } }; @@ -359,7 +359,7 @@ impl<'cx, 'tcx> Builder<'cx, 'tcx> { // NOTE(eddyb) allowing the instruction to be added below avoids // spurious "`noreturn` requires a terminator at the end" errors. if let Op::Return | Op::ReturnValue = op { - self.struct_err(&format!( + self.struct_err(format!( "using `Op{op:?}` to return from within `asm!` is disallowed" )) .note( @@ -383,7 +383,7 @@ impl<'cx, 'tcx> Builder<'cx, 'tcx> { } AsmBlock::End(terminator) => { if op != Op::Label { - self.err(&format!( + self.err(format!( "expected `OpLabel` after terminator `Op{terminator:?}`" )); } @@ -466,7 +466,7 @@ impl<'cx, 'tcx> Builder<'cx, 'tcx> { let inst_class = if let Some(inst) = inst_class { inst } else { - self.err(&format!("unknown spirv instruction {inst_name}")); + self.err(format!("unknown spirv instruction {inst_name}")); return; }; let result_id = match out_register { @@ -521,7 +521,7 @@ impl<'cx, 'tcx> Builder<'cx, 'tcx> { if kind == OperandKind::IdResult { assert_eq!(quantifier, OperandQuantifier::One); if instruction.result_id.is_none() { - self.err(&format!( + self.err(format!( "instruction {} expects a result id", instruction.class.opname )); @@ -539,7 +539,7 @@ impl<'cx, 'tcx> Builder<'cx, 'tcx> { instruction.result_type = Some(id); } } else { - self.err(&format!( + self.err(format!( "instruction {} expects a result type", instruction.class.opname )); @@ -552,7 +552,7 @@ impl<'cx, 'tcx> Builder<'cx, 'tcx> { match quantifier { OperandQuantifier::One => { if !self.parse_one_operand(id_map, instruction, kind, &mut tokens) { - self.err(&format!( + self.err(format!( "expected operand after instruction: {}", instruction.class.opname )); @@ -576,7 +576,7 @@ impl<'cx, 'tcx> Builder<'cx, 'tcx> { } if !saw_id_result && instruction.result_id.is_some() { - self.err(&format!( + self.err(format!( "instruction {} does not expect a result id", instruction.class.opname )); @@ -593,7 +593,7 @@ impl<'cx, 'tcx> Builder<'cx, 'tcx> { match self.infer_result_type(id_to_type_map, instruction) { Some(result_type) => instruction.result_type = Some(result_type), - None => self.err(&format!( + None => self.err(format!( "instruction {} cannot have its result type inferred", instruction.class.opname )), @@ -816,7 +816,7 @@ impl<'cx, 'tcx> Builder<'cx, 'tcx> { Some(OutRegister::Regular({ let num = *id_map.entry(id).or_insert_with(|| self.emit().id()); if !defined_ids.insert(num) { - self.err(&format!("%{id} is defined more than once")); + self.err(format!("%{id} is defined more than once")); } num })) @@ -1078,7 +1078,7 @@ impl<'cx, 'tcx> Builder<'cx, 'tcx> { (OperandKind::LiteralInteger, Some(word)) => match word.parse() { Ok(v) => inst.operands.push(dr::Operand::LiteralInt32(v)), - Err(e) => self.err(&format!("invalid integer: {e}")), + Err(e) => self.err(format!("invalid integer: {e}")), }, (OperandKind::LiteralString, _) => { if let Token::String(value) = token { @@ -1128,12 +1128,12 @@ impl<'cx, 'tcx> Builder<'cx, 'tcx> { } match parse(self.lookup_type(ty), word) { Ok(op) => inst.operands.push(op), - Err(err) => self.err(&err), + Err(err) => self.err(err), } } (OperandKind::LiteralExtInstInteger, Some(word)) => match word.parse() { Ok(v) => inst.operands.push(dr::Operand::LiteralExtInstInteger(v)), - Err(e) => self.err(&format!("invalid integer: {e}")), + Err(e) => self.err(format!("invalid integer: {e}")), }, (OperandKind::LiteralSpecConstantOpInteger, Some(word)) => { match self.instruction_table.table.get(word) { @@ -1154,11 +1154,11 @@ impl<'cx, 'tcx> Builder<'cx, 'tcx> { Some(Token::Word(word)) => match word.parse() { Ok(v) => inst.operands.push(dr::Operand::LiteralInt32(v)), Err(e) => { - self.err(&format!("invalid integer: {e}")); + self.err(format!("invalid integer: {e}")); } }, Some(Token::String(_)) => { - self.err(&format!("expected a literal, not a string for a {kind:?}")); + self.err(format!("expected a literal, not a string for a {kind:?}")); } Some(Token::Placeholder(_, span)) => { self.tcx.sess.span_err( @@ -1195,172 +1195,172 @@ impl<'cx, 'tcx> Builder<'cx, 'tcx> { (OperandKind::ImageOperands, Some(word)) => { match parse_bitflags_operand(IMAGE_OPERANDS, word) { Some(x) => inst.operands.push(dr::Operand::ImageOperands(x)), - None => self.err(&format!("Unknown ImageOperands {word}")), + None => self.err(format!("Unknown ImageOperands {word}")), } } (OperandKind::FPFastMathMode, Some(word)) => { match parse_bitflags_operand(FP_FAST_MATH_MODE, word) { Some(x) => inst.operands.push(dr::Operand::FPFastMathMode(x)), - None => self.err(&format!("Unknown FPFastMathMode {word}")), + None => self.err(format!("Unknown FPFastMathMode {word}")), } } (OperandKind::SelectionControl, Some(word)) => { match parse_bitflags_operand(SELECTION_CONTROL, word) { Some(x) => inst.operands.push(dr::Operand::SelectionControl(x)), - None => self.err(&format!("Unknown SelectionControl {word}")), + None => self.err(format!("Unknown SelectionControl {word}")), } } (OperandKind::LoopControl, Some(word)) => { match parse_bitflags_operand(LOOP_CONTROL, word) { Some(x) => inst.operands.push(dr::Operand::LoopControl(x)), - None => self.err(&format!("Unknown LoopControl {word}")), + None => self.err(format!("Unknown LoopControl {word}")), } } (OperandKind::FunctionControl, Some(word)) => { match parse_bitflags_operand(FUNCTION_CONTROL, word) { Some(x) => inst.operands.push(dr::Operand::FunctionControl(x)), - None => self.err(&format!("Unknown FunctionControl {word}")), + None => self.err(format!("Unknown FunctionControl {word}")), } } (OperandKind::MemorySemantics, Some(word)) => { match parse_bitflags_operand(MEMORY_SEMANTICS, word) { Some(x) => inst.operands.push(dr::Operand::MemorySemantics(x)), - None => self.err(&format!("Unknown MemorySemantics {word}")), + None => self.err(format!("Unknown MemorySemantics {word}")), } } (OperandKind::MemoryAccess, Some(word)) => { match parse_bitflags_operand(MEMORY_ACCESS, word) { Some(x) => inst.operands.push(dr::Operand::MemoryAccess(x)), - None => self.err(&format!("Unknown MemoryAccess {word}")), + None => self.err(format!("Unknown MemoryAccess {word}")), } } (OperandKind::KernelProfilingInfo, Some(word)) => { match parse_bitflags_operand(KERNEL_PROFILING_INFO, word) { Some(x) => inst.operands.push(dr::Operand::KernelProfilingInfo(x)), - None => self.err(&format!("Unknown KernelProfilingInfo {word}")), + None => self.err(format!("Unknown KernelProfilingInfo {word}")), } } (OperandKind::RayFlags, Some(word)) => match parse_bitflags_operand(RAY_FLAGS, word) { Some(x) => inst.operands.push(dr::Operand::RayFlags(x)), - None => self.err(&format!("Unknown RayFlags {word}")), + None => self.err(format!("Unknown RayFlags {word}")), }, (OperandKind::FragmentShadingRate, Some(word)) => { match parse_bitflags_operand(FRAGMENT_SHADING_RATE, word) { Some(x) => inst.operands.push(dr::Operand::FragmentShadingRate(x)), - None => self.err(&format!("Unknown FragmentShadingRate {word}")), + None => self.err(format!("Unknown FragmentShadingRate {word}")), } } (OperandKind::SourceLanguage, Some(word)) => match word.parse() { Ok(x) => inst.operands.push(dr::Operand::SourceLanguage(x)), - Err(()) => self.err(&format!("Unknown SourceLanguage {word}")), + Err(()) => self.err(format!("Unknown SourceLanguage {word}")), }, (OperandKind::ExecutionModel, Some(word)) => match word.parse() { Ok(x) => inst.operands.push(dr::Operand::ExecutionModel(x)), - Err(()) => self.err(&format!("unknown ExecutionModel {word}")), + Err(()) => self.err(format!("unknown ExecutionModel {word}")), }, (OperandKind::AddressingModel, Some(word)) => match word.parse() { Ok(x) => inst.operands.push(dr::Operand::AddressingModel(x)), - Err(()) => self.err(&format!("unknown AddressingModel {word}")), + Err(()) => self.err(format!("unknown AddressingModel {word}")), }, (OperandKind::MemoryModel, Some(word)) => match word.parse() { Ok(x) => inst.operands.push(dr::Operand::MemoryModel(x)), - Err(()) => self.err(&format!("unknown MemoryModel {word}")), + Err(()) => self.err(format!("unknown MemoryModel {word}")), }, (OperandKind::ExecutionMode, Some(word)) => match word.parse() { Ok(x) => inst.operands.push(dr::Operand::ExecutionMode(x)), - Err(()) => self.err(&format!("unknown ExecutionMode {word}")), + Err(()) => self.err(format!("unknown ExecutionMode {word}")), }, (OperandKind::StorageClass, Some(word)) => match word.parse() { Ok(x) => inst.operands.push(dr::Operand::StorageClass(x)), - Err(()) => self.err(&format!("unknown StorageClass {word}")), + Err(()) => self.err(format!("unknown StorageClass {word}")), }, (OperandKind::Dim, Some(word)) => match word.parse() { Ok(x) => inst.operands.push(dr::Operand::Dim(x)), - Err(()) => self.err(&format!("unknown Dim {word}")), + Err(()) => self.err(format!("unknown Dim {word}")), }, (OperandKind::SamplerAddressingMode, Some(word)) => match word.parse() { Ok(x) => inst.operands.push(dr::Operand::SamplerAddressingMode(x)), - Err(()) => self.err(&format!("unknown SamplerAddressingMode {word}")), + Err(()) => self.err(format!("unknown SamplerAddressingMode {word}")), }, (OperandKind::SamplerFilterMode, Some(word)) => match word.parse() { Ok(x) => inst.operands.push(dr::Operand::SamplerFilterMode(x)), - Err(()) => self.err(&format!("unknown SamplerFilterMode {word}")), + Err(()) => self.err(format!("unknown SamplerFilterMode {word}")), }, (OperandKind::ImageFormat, Some(word)) => match word.parse() { Ok(x) => inst.operands.push(dr::Operand::ImageFormat(x)), - Err(()) => self.err(&format!("unknown ImageFormat {word}")), + Err(()) => self.err(format!("unknown ImageFormat {word}")), }, (OperandKind::ImageChannelOrder, Some(word)) => match word.parse() { Ok(x) => inst.operands.push(dr::Operand::ImageChannelOrder(x)), - Err(()) => self.err(&format!("unknown ImageChannelOrder {word}")), + Err(()) => self.err(format!("unknown ImageChannelOrder {word}")), }, (OperandKind::ImageChannelDataType, Some(word)) => match word.parse() { Ok(x) => inst.operands.push(dr::Operand::ImageChannelDataType(x)), - Err(()) => self.err(&format!("unknown ImageChannelDataType {word}")), + Err(()) => self.err(format!("unknown ImageChannelDataType {word}")), }, (OperandKind::FPRoundingMode, Some(word)) => match word.parse() { Ok(x) => inst.operands.push(dr::Operand::FPRoundingMode(x)), - Err(()) => self.err(&format!("unknown FPRoundingMode {word}")), + Err(()) => self.err(format!("unknown FPRoundingMode {word}")), }, (OperandKind::LinkageType, Some(word)) => match word.parse() { Ok(x) => inst.operands.push(dr::Operand::LinkageType(x)), - Err(()) => self.err(&format!("unknown LinkageType {word}")), + Err(()) => self.err(format!("unknown LinkageType {word}")), }, (OperandKind::AccessQualifier, Some(word)) => match word.parse() { Ok(x) => inst.operands.push(dr::Operand::AccessQualifier(x)), - Err(()) => self.err(&format!("unknown AccessQualifier {word}")), + Err(()) => self.err(format!("unknown AccessQualifier {word}")), }, (OperandKind::FunctionParameterAttribute, Some(word)) => match word.parse() { Ok(x) => inst .operands .push(dr::Operand::FunctionParameterAttribute(x)), - Err(()) => self.err(&format!("unknown FunctionParameterAttribute {word}")), + Err(()) => self.err(format!("unknown FunctionParameterAttribute {word}")), }, (OperandKind::Decoration, Some(word)) => match word.parse() { Ok(x) => inst.operands.push(dr::Operand::Decoration(x)), - Err(()) => self.err(&format!("unknown Decoration {word}")), + Err(()) => self.err(format!("unknown Decoration {word}")), }, (OperandKind::BuiltIn, Some(word)) => match word.parse() { Ok(x) => inst.operands.push(dr::Operand::BuiltIn(x)), - Err(()) => self.err(&format!("unknown BuiltIn {word}")), + Err(()) => self.err(format!("unknown BuiltIn {word}")), }, (OperandKind::Scope, Some(word)) => match word.parse() { Ok(x) => inst.operands.push(dr::Operand::Scope(x)), - Err(()) => self.err(&format!("unknown Scope {word}")), + Err(()) => self.err(format!("unknown Scope {word}")), }, (OperandKind::GroupOperation, Some(word)) => match word.parse() { Ok(x) => inst.operands.push(dr::Operand::GroupOperation(x)), - Err(()) => self.err(&format!("unknown GroupOperation {word}")), + Err(()) => self.err(format!("unknown GroupOperation {word}")), }, (OperandKind::KernelEnqueueFlags, Some(word)) => match word.parse() { Ok(x) => inst.operands.push(dr::Operand::KernelEnqueueFlags(x)), - Err(()) => self.err(&format!("unknown KernelEnqueueFlags {word}")), + Err(()) => self.err(format!("unknown KernelEnqueueFlags {word}")), }, (OperandKind::Capability, Some(word)) => match word.parse() { Ok(x) => inst.operands.push(dr::Operand::Capability(x)), - Err(()) => self.err(&format!("unknown Capability {word}")), + Err(()) => self.err(format!("unknown Capability {word}")), }, (OperandKind::RayQueryIntersection, Some(word)) => match word.parse() { Ok(x) => inst.operands.push(dr::Operand::RayQueryIntersection(x)), - Err(()) => self.err(&format!("unknown RayQueryIntersection {word}")), + Err(()) => self.err(format!("unknown RayQueryIntersection {word}")), }, (OperandKind::RayQueryCommittedIntersectionType, Some(word)) => match word.parse() { Ok(x) => inst .operands .push(dr::Operand::RayQueryCommittedIntersectionType(x)), - Err(()) => self.err(&format!("unknown RayQueryCommittedIntersectionType {word}")), + Err(()) => self.err(format!("unknown RayQueryCommittedIntersectionType {word}")), }, (OperandKind::RayQueryCandidateIntersectionType, Some(word)) => match word.parse() { Ok(x) => inst .operands .push(dr::Operand::RayQueryCandidateIntersectionType(x)), - Err(()) => self.err(&format!("unknown RayQueryCandidateIntersectionType {word}")), + Err(()) => self.err(format!("unknown RayQueryCandidateIntersectionType {word}")), }, (kind, None) => match token { Token::Word(_) => bug!(), Token::String(_) => { - self.err(&format!("expected a literal, not a string for a {kind:?}")); + self.err(format!("expected a literal, not a string for a {kind:?}")); } Token::Placeholder(_, span) => { self.tcx.sess.span_err( diff --git a/crates/rustc_codegen_spirv/src/builder_spirv.rs b/crates/rustc_codegen_spirv/src/builder_spirv.rs index a2b64a8b69..0a85d8aab3 100644 --- a/crates/rustc_codegen_spirv/src/builder_spirv.rs +++ b/crates/rustc_codegen_spirv/src/builder_spirv.rs @@ -13,6 +13,7 @@ use rustc_arena::DroplessArena; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::sync::Lrc; use rustc_middle::bug; +use rustc_middle::mir::interpret::ConstAllocation; use rustc_middle::ty::TyCtxt; use rustc_span::source_map::SourceMap; use rustc_span::symbol::Symbol; @@ -206,8 +207,8 @@ impl SpirvValueExt for Word { } } -#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)] -pub enum SpirvConst<'tcx> { +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +pub enum SpirvConst<'a, 'tcx> { U32(u32), U64(u64), /// f32 isn't hash, so store bits @@ -225,16 +226,23 @@ pub enum SpirvConst<'tcx> { // different functions, but of the same type, don't overlap their zombies. ZombieUndefForFnAddr, - Composite(&'tcx [Word]), + Composite(&'a [Word]), /// Pointer to constant data, i.e. `&pointee`, represented as an `OpVariable` /// in the `Private` storage class, and with `pointee` as its initializer. PtrTo { pointee: Word, }, + + /// Symbolic result for the `const_data_from_alloc` method, to allow deferring + /// the actual value generation until after a pointer to this value is cast + /// to its final type (e.g. that will be loaded as). + // + // FIXME(eddyb) replace this with `qptr` handling of constant data. + ConstDataFromAlloc(ConstAllocation<'tcx>), } -impl SpirvConst<'_> { +impl<'tcx> SpirvConst<'_, 'tcx> { /// Replace `&[T]` fields with `&'tcx [T]` ones produced by calling /// `tcx.arena.dropless.alloc_slice(...)` - this is done late for two reasons: /// 1. it avoids allocating in the arena when the cache would be hit anyway, @@ -242,7 +250,7 @@ impl SpirvConst<'_> { /// (ideally these would also be interned, but that's even more refactors) /// 2. an empty slice is disallowed (as it's usually handled as a special /// case elsewhere, e.g. `rustc`'s `ty::List` - sadly we can't use that) - fn tcx_arena_alloc_slices<'tcx>(self, cx: &CodegenCx<'tcx>) -> SpirvConst<'tcx> { + fn tcx_arena_alloc_slices(self, cx: &CodegenCx<'tcx>) -> SpirvConst<'tcx, 'tcx> { fn arena_alloc_slice<'tcx, T: Copy>(cx: &CodegenCx<'tcx>, xs: &[T]) -> &'tcx [T] { if xs.is_empty() { &[] @@ -264,6 +272,8 @@ impl SpirvConst<'_> { SpirvConst::PtrTo { pointee } => SpirvConst::PtrTo { pointee }, SpirvConst::Composite(fields) => SpirvConst::Composite(arena_alloc_slice(cx, fields)), + + SpirvConst::ConstDataFromAlloc(alloc) => SpirvConst::ConstDataFromAlloc(alloc), } } } @@ -282,6 +292,12 @@ enum LeafIllegalConst { /// as its operands, and `OpVariable`s are never considered constant. // FIXME(eddyb) figure out if this is an accidental omission in SPIR-V. CompositeContainsPtrTo, + + /// `ConstDataFromAlloc` constant, which cannot currently be materialized + /// to SPIR-V (and requires to be wrapped in `PtrTo` and bitcast, first). + // + // FIXME(eddyb) replace this with `qptr` handling of constant data. + UntypedConstDataFromAlloc, } impl LeafIllegalConst { @@ -290,6 +306,10 @@ impl LeafIllegalConst { Self::CompositeContainsPtrTo => { "constant arrays/structs cannot contain pointers to other constants" } + Self::UntypedConstDataFromAlloc => { + "`const_data_from_alloc` result wasn't passed through `static_addr_of`, \ + then `const_bitcast` (which would've given it a type)" + } } } } @@ -391,8 +411,8 @@ pub struct BuilderSpirv<'tcx> { // (e.g. `OpConstant...`) instruction. // NOTE(eddyb) both maps have `WithConstLegality` around their keys, which // allows getting that legality information without additional lookups. - const_to_id: RefCell>, WithConstLegality>>, - id_to_const: RefCell>>>, + const_to_id: RefCell>, WithConstLegality>>, + id_to_const: RefCell>>>, debug_file_cache: RefCell>>, @@ -535,7 +555,7 @@ impl<'tcx> BuilderSpirv<'tcx> { pub(crate) fn def_constant_cx( &self, ty: Word, - val: SpirvConst<'_>, + val: SpirvConst<'_, 'tcx>, cx: &CodegenCx<'tcx>, ) -> SpirvValue { let val_with_type = WithType { ty, val }; @@ -564,7 +584,9 @@ impl<'tcx> BuilderSpirv<'tcx> { } SpirvConst::Null => builder.constant_null(ty), - SpirvConst::Undef | SpirvConst::ZombieUndefForFnAddr => builder.undef(ty, None), + SpirvConst::Undef + | SpirvConst::ZombieUndefForFnAddr + | SpirvConst::ConstDataFromAlloc(_) => builder.undef(ty, None), SpirvConst::Composite(v) => builder.constant_composite(ty, v.iter().copied()), @@ -597,35 +619,40 @@ impl<'tcx> BuilderSpirv<'tcx> { Ok(()) } - SpirvConst::Composite(v) => v.iter().fold(Ok(()), |composite_legal, field| { - let field_entry = &self.id_to_const.borrow()[field]; - let field_legal_in_composite = field_entry.legal.and( - // `field` is itself some legal `SpirvConst`, but can we have - // it as part of an `OpConstantComposite`? - match field_entry.val { - SpirvConst::PtrTo { .. } => Err(IllegalConst::Shallow( - LeafIllegalConst::CompositeContainsPtrTo, - )), - _ => Ok(()), - }, - ); - - match (composite_legal, field_legal_in_composite) { - (Ok(()), Ok(())) => Ok(()), - (Err(illegal), Ok(())) | (Ok(()), Err(illegal)) => Err(illegal), - - // Combining two causes of an illegal `SpirvConst` has to - // take into account which is "worse", i.e. which imposes - // more restrictions on how the resulting value can be used. - // `Indirect` is worse than `Shallow` because it cannot be - // materialized at runtime in the same way `Shallow` can be. - (Err(illegal @ IllegalConst::Indirect(_)), Err(_)) - | (Err(_), Err(illegal @ IllegalConst::Indirect(_))) - | (Err(illegal @ IllegalConst::Shallow(_)), Err(IllegalConst::Shallow(_))) => { - Err(illegal) + SpirvConst::Composite(v) => v + .iter() + .map(|field| { + let field_entry = &self.id_to_const.borrow()[field]; + field_entry.legal.and( + // `field` is itself some legal `SpirvConst`, but can we have + // it as part of an `OpConstantComposite`? + match field_entry.val { + SpirvConst::PtrTo { .. } => Err(IllegalConst::Shallow( + LeafIllegalConst::CompositeContainsPtrTo, + )), + _ => Ok(()), + }, + ) + }) + .reduce(|a, b| { + match (a, b) { + (Ok(()), Ok(())) => Ok(()), + (Err(illegal), Ok(())) | (Ok(()), Err(illegal)) => Err(illegal), + + // Combining two causes of an illegal `SpirvConst` has to + // take into account which is "worse", i.e. which imposes + // more restrictions on how the resulting value can be used. + // `Indirect` is worse than `Shallow` because it cannot be + // materialized at runtime in the same way `Shallow` can be. + (Err(illegal @ IllegalConst::Indirect(_)), Err(_)) + | (Err(_), Err(illegal @ IllegalConst::Indirect(_))) + | ( + Err(illegal @ IllegalConst::Shallow(_)), + Err(IllegalConst::Shallow(_)), + ) => Err(illegal), } - } - }), + }) + .unwrap_or(Ok(())), SpirvConst::PtrTo { pointee } => match self.id_to_const.borrow()[&pointee].legal { Ok(()) => Ok(()), @@ -635,6 +662,10 @@ impl<'tcx> BuilderSpirv<'tcx> { Err(IllegalConst::Indirect(cause)) } }, + + SpirvConst::ConstDataFromAlloc(_) => Err(IllegalConst::Shallow( + LeafIllegalConst::UntypedConstDataFromAlloc, + )), }; let val = val.tcx_arena_alloc_slices(cx); assert_matches!( @@ -658,11 +689,11 @@ impl<'tcx> BuilderSpirv<'tcx> { SpirvValue { kind, ty } } - pub fn lookup_const_by_id(&self, id: Word) -> Option> { + pub fn lookup_const_by_id(&self, id: Word) -> Option> { Some(self.id_to_const.borrow().get(&id)?.val) } - pub fn lookup_const(&self, def: SpirvValue) -> Option> { + pub fn lookup_const(&self, def: SpirvValue) -> Option> { match def.kind { SpirvValueKind::Def(id) | SpirvValueKind::IllegalConst(id) => { self.lookup_const_by_id(id) diff --git a/crates/rustc_codegen_spirv/src/codegen_cx/constant.rs b/crates/rustc_codegen_spirv/src/codegen_cx/constant.rs index 65fe219e00..d49be57993 100644 --- a/crates/rustc_codegen_spirv/src/codegen_cx/constant.rs +++ b/crates/rustc_codegen_spirv/src/codegen_cx/constant.rs @@ -1,18 +1,17 @@ use super::CodegenCx; use crate::abi::ConvSpirvType; -use crate::builder_spirv::{SpirvConst, SpirvValue, SpirvValueExt}; +use crate::builder_spirv::{SpirvConst, SpirvValue, SpirvValueExt, SpirvValueKind}; use crate::spirv_type::SpirvType; use rspirv::spirv::Word; -use rustc_codegen_ssa::mir::place::PlaceRef; use rustc_codegen_ssa::traits::{BaseTypeMethods, ConstMethods, MiscMethods, StaticMethods}; use rustc_middle::bug; use rustc_middle::mir::interpret::{alloc_range, ConstAllocation, GlobalAlloc, Scalar}; -use rustc_middle::ty::layout::{LayoutOf, TyAndLayout}; +use rustc_middle::ty::layout::LayoutOf; use rustc_span::{Span, DUMMY_SP}; use rustc_target::abi::{self, AddressSpace, HasDataLayout, Integer, Primitive, Size}; impl<'tcx> CodegenCx<'tcx> { - pub fn def_constant(&self, ty: Word, val: SpirvConst<'_>) -> SpirvValue { + pub fn def_constant(&self, ty: Word, val: SpirvConst<'_, 'tcx>) -> SpirvValue { self.builder.def_constant_cx(ty, val, self) } @@ -137,8 +136,22 @@ impl<'tcx> ConstMethods<'tcx> for CodegenCx<'tcx> { fn const_uint(&self, t: Self::Type, i: u64) -> Self::Value { self.constant_int(t, i) } - fn const_uint_big(&self, t: Self::Type, u: u128) -> Self::Value { - self.constant_int(t, u as u64) + // FIXME(eddyb) support `u128`. + fn const_uint_big(&self, t: Self::Type, i: u128) -> Self::Value { + let i_as_u64 = i as u64; + let c = self.constant_int(t, i_as_u64); + match self.lookup_type(t) { + SpirvType::Integer(width, _) if width > 64 => { + if u128::from(i_as_u64) != i { + self.zombie_no_span( + c.def_cx(self), + "const_uint_big truncated a 128-bit constant to 64 bits", + ); + } + } + _ => {} + } + c } fn const_bool(&self, val: bool) -> Self::Value { self.constant_bool(DUMMY_SP, val) @@ -155,6 +168,10 @@ impl<'tcx> ConstMethods<'tcx> for CodegenCx<'tcx> { fn const_u64(&self, i: u64) -> Self::Value { self.constant_u64(DUMMY_SP, i) } + fn const_u128(&self, i: u128) -> Self::Value { + let ty = SpirvType::Integer(128, false).def(DUMMY_SP, self); + self.const_uint_big(ty, i) + } fn const_usize(&self, i: u64) -> Self::Value { let ptr_size = self.tcx.data_layout.pointer_size.bits() as u32; let t = SpirvType::Integer(ptr_size, false).def(DUMMY_SP, self); @@ -335,36 +352,64 @@ impl<'tcx> ConstMethods<'tcx> for CodegenCx<'tcx> { } } - // FIXME(eddyb) this shouldn't exist, and is only used by vtable creation, - // see https://github.com/rust-lang/rust/pull/86475#discussion_r680792727. - fn const_data_from_alloc(&self, _alloc: ConstAllocation<'tcx>) -> Self::Value { - let undef = self.undef(SpirvType::Void.def(DUMMY_SP, self)); - self.zombie_no_span(undef.def_cx(self), "const_data_from_alloc"); - undef - } - fn from_const_alloc( - &self, - layout: TyAndLayout<'tcx>, - alloc: ConstAllocation<'tcx>, - offset: Size, - ) -> PlaceRef<'tcx, Self::Value> { - assert_eq!(offset, Size::ZERO); - let ty = layout.spirv_type(DUMMY_SP, self); - let init = self.create_const_alloc(alloc, ty); - let result = self.static_addr_of(init, alloc.inner().align, None); - PlaceRef::new_sized(result, layout) + // HACK(eddyb) this uses a symbolic `ConstDataFromAlloc`, to allow deferring + // the actual value generation until after a pointer to this value is cast + // to its final type (e.g. that will be loaded as). + // FIXME(eddyb) replace this with `qptr` handling of constant data. + fn const_data_from_alloc(&self, alloc: ConstAllocation<'tcx>) -> Self::Value { + let void_type = SpirvType::Void.def(DUMMY_SP, self); + 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 { - // constant ptrcast is not supported in spir-v + // 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`). + if let SpirvValueKind::IllegalConst(_) = val.kind { + if let Some(SpirvConst::PtrTo { pointee }) = self.builder.lookup_const(val) { + if let Some(SpirvConst::ConstDataFromAlloc(alloc)) = + self.builder.lookup_const_by_id(pointee) + { + if let SpirvType::Pointer { pointee } = self.lookup_type(ty) { + let init = self.create_const_alloc(alloc, pointee); + return self.static_addr_of(init, alloc.inner().align, None); + } + } + } + } + + 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_bitcast"); + result + } + } + fn const_ptr_byte_offset(&self, val: Self::Value, offset: Size) -> Self::Value { + if offset == Size::ZERO { + val + } else { + // FIXME(eddyb) implement via `OpSpecConstantOp`. + // FIXME(eddyb) this zombies the original value without creating a new one. + let result = val; + self.zombie_no_span(result.def_cx(self), "const_ptr_byte_offset"); + result + } + } } impl<'tcx> CodegenCx<'tcx> { diff --git a/crates/rustc_codegen_spirv/src/codegen_cx/mod.rs b/crates/rustc_codegen_spirv/src/codegen_cx/mod.rs index 362f89b209..621471fd62 100644 --- a/crates/rustc_codegen_spirv/src/codegen_cx/mod.rs +++ b/crates/rustc_codegen_spirv/src/codegen_cx/mod.rs @@ -15,8 +15,7 @@ use rspirv::spirv::{Decoration, LinkageType, Op, Word}; use rustc_ast::ast::{InlineAsmOptions, InlineAsmTemplatePiece}; use rustc_codegen_ssa::mir::debuginfo::{FunctionDebugContext, VariableKind}; use rustc_codegen_ssa::traits::{ - AsmMethods, BackendTypes, CoverageInfoMethods, DebugInfoMethods, GlobalAsmOperandRef, - MiscMethods, + AsmMethods, BackendTypes, DebugInfoMethods, GlobalAsmOperandRef, MiscMethods, }; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_middle::mir::mono::CodegenUnit; @@ -24,7 +23,6 @@ use rustc_middle::mir::Body; use rustc_middle::ty::layout::{HasParamEnv, HasTyCtxt}; use rustc_middle::ty::{Instance, ParamEnv, PolyExistentialTraitRef, Ty, TyCtxt}; use rustc_session::Session; -use rustc_span::def_id::DefId; use rustc_span::symbol::Symbol; use rustc_span::{SourceFile, Span, DUMMY_SP}; use rustc_target::abi::call::{FnAbi, PassMode}; @@ -885,18 +883,6 @@ impl<'tcx> DebugInfoMethods<'tcx> for CodegenCx<'tcx> { } } -impl<'tcx> CoverageInfoMethods<'tcx> for CodegenCx<'tcx> { - fn coverageinfo_finalize(&self) { - todo!() - } - fn get_pgo_func_name_var(&self, _: Instance<'tcx>) -> SpirvValue { - todo!() - } - fn define_unused_fn(&self, _: DefId) { - todo!() - } -} - impl<'tcx> AsmMethods<'tcx> for CodegenCx<'tcx> { fn codegen_global_asm( &self, diff --git a/crates/rustc_codegen_spirv/src/codegen_cx/type_.rs b/crates/rustc_codegen_spirv/src/codegen_cx/type_.rs index 5f8e9be8fe..3d60dd37fa 100644 --- a/crates/rustc_codegen_spirv/src/codegen_cx/type_.rs +++ b/crates/rustc_codegen_spirv/src/codegen_cx/type_.rs @@ -9,7 +9,7 @@ use rustc_middle::ty::layout::{ }; use rustc_middle::ty::Ty; use rustc_middle::{bug, span_bug}; -use rustc_span::source_map::{Span, DUMMY_SP}; +use rustc_span::source_map::{Span, Spanned, DUMMY_SP}; use rustc_target::abi::call::{CastTarget, FnAbi, Reg}; use rustc_target::abi::{Abi, AddressSpace, FieldsShape}; @@ -37,16 +37,13 @@ impl<'tcx> FnAbiOfHelpers<'tcx> for CodegenCx<'tcx> { fn_abi_request: FnAbiRequest<'tcx>, ) -> ! { if let FnAbiError::Layout(LayoutError::SizeOverflow(_)) = err { - self.tcx.sess.span_fatal(span, err.to_string()) + self.tcx.sess.emit_fatal(Spanned { span, node: err }) } else { match fn_abi_request { FnAbiRequest::OfFnPtr { sig, extra_args } => { span_bug!( span, - "`fn_abi_of_fn_ptr({}, {:?})` failed: {}", - sig, - extra_args, - err + "`fn_abi_of_fn_ptr({sig}, {extra_args:?})` failed: {err:?}", ); } FnAbiRequest::OfInstance { @@ -55,10 +52,7 @@ impl<'tcx> FnAbiOfHelpers<'tcx> for CodegenCx<'tcx> { } => { span_bug!( span, - "`fn_abi_of_instance({}, {:?})` failed: {}", - instance, - extra_args, - err + "`fn_abi_of_instance({instance}, {extra_args:?})` failed: {err:?}", ); } } diff --git a/crates/rustc_codegen_spirv/src/lib.rs b/crates/rustc_codegen_spirv/src/lib.rs index 72bd14c2a1..e0d33d693c 100644 --- a/crates/rustc_codegen_spirv/src/lib.rs +++ b/crates/rustc_codegen_spirv/src/lib.rs @@ -97,7 +97,7 @@ use rustc_codegen_ssa::traits::{ WriteBackendMethods, }; use rustc_codegen_ssa::{CodegenResults, CompiledModule, ModuleCodegen, ModuleKind}; -use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::fx::FxIndexMap; use rustc_errors::{ErrorGuaranteed, FatalError, Handler}; use rustc_metadata::EncodedMetadata; use rustc_middle::dep_graph::{WorkProduct, WorkProductId}; @@ -257,7 +257,7 @@ impl CodegenBackend for SpirvCodegenBackend { ongoing_codegen: Box, sess: &Session, _outputs: &OutputFilenames, - ) -> Result<(CodegenResults, FxHashMap), ErrorGuaranteed> { + ) -> Result<(CodegenResults, FxIndexMap), ErrorGuaranteed> { let (codegen_results, work_products) = ongoing_codegen .downcast::>() .expect("Expected OngoingCodegen, found Box") diff --git a/crates/rustc_codegen_spirv/src/link.rs b/crates/rustc_codegen_spirv/src/link.rs index aba8f3c366..1211ea68a6 100644 --- a/crates/rustc_codegen_spirv/src/link.rs +++ b/crates/rustc_codegen_spirv/src/link.rs @@ -14,7 +14,9 @@ use rustc_metadata::fs::METADATA_FILENAME; use rustc_middle::bug; use rustc_middle::dep_graph::WorkProduct; use rustc_middle::middle::dependency_format::Linkage; -use rustc_session::config::{CrateType, DebugInfo, Lto, OptLevel, OutputFilenames, OutputType}; +use rustc_session::config::{ + CrateType, DebugInfo, Lto, OptLevel, OutFileName, OutputFilenames, OutputType, +}; use rustc_session::output::{check_file_is_writeable, invalid_output_for_target, out_filename}; use rustc_session::utils::NativeLibKind; use rustc_session::Session; @@ -60,9 +62,11 @@ pub fn link( if outputs.outputs.should_codegen() { let out_filename = out_filename(sess, crate_type, outputs, Symbol::intern(crate_name)); + let out_filename_file_for_writing = + out_filename.file_for_writing(outputs, OutputType::Exe, None); match crate_type { CrateType::Rlib => { - link_rlib(sess, codegen_results, &out_filename); + link_rlib(sess, codegen_results, &out_filename_file_for_writing); } CrateType::Executable | CrateType::Cdylib | CrateType::Dylib => { // HACK(eddyb) there's no way way to access `outputs.filestem`, @@ -76,7 +80,7 @@ pub fn link( link_exe( sess, crate_type, - &out_filename, + &out_filename_file_for_writing, codegen_results, outputs, &disambiguated_crate_name_for_dumps, @@ -86,6 +90,21 @@ pub fn link( sess.err(format!("CrateType {other:?} not supported yet")); } } + match out_filename { + OutFileName::Real(_) => { + // Already written to, above. + } + OutFileName::Stdout => { + // HACK(eddyb) wrote a file above, time to read it back out. + std::io::copy( + &mut std::io::BufReader::new( + std::fs::File::open(out_filename_file_for_writing).unwrap(), + ), + &mut std::io::stdout(), + ) + .unwrap(); + } + } } } } diff --git a/crates/rustc_codegen_spirv/src/linker/test.rs b/crates/rustc_codegen_spirv/src/linker/test.rs index 849951db31..8694492add 100644 --- a/crates/rustc_codegen_spirv/src/linker/test.rs +++ b/crates/rustc_codegen_spirv/src/linker/test.rs @@ -95,11 +95,20 @@ fn link_with_linker_opts( // is really a silent unwinding device, that should be treated the same as // `Err(ErrorGuaranteed)` returns from `link`). rustc_driver::catch_fatal_errors(|| { - let matches = rustc_driver::handle_options(&["".to_string(), "x.rs".to_string()]).unwrap(); - let sopts = rustc_session::config::build_session_options(&matches); + let mut early_error_handler = rustc_session::EarlyErrorHandler::new( + rustc_session::config::ErrorOutputType::default(), + ); + let matches = rustc_driver::handle_options( + &early_error_handler, + &["".to_string(), "x.rs".to_string()], + ) + .unwrap(); + let sopts = + rustc_session::config::build_session_options(&mut early_error_handler, &matches); rustc_span::create_session_globals_then(sopts.edition, || { let mut sess = rustc_session::build_session( + &early_error_handler, sopts, CompilerIO { input: Input::Str { diff --git a/crates/spirv-builder/src/watch.rs b/crates/spirv-builder/src/watch.rs index d38d2410a5..44b92d7317 100644 --- a/crates/spirv-builder/src/watch.rs +++ b/crates/spirv-builder/src/watch.rs @@ -105,7 +105,7 @@ impl SpirvBuilder { } } }); - std::mem::forget(thread); + std::mem::drop(thread); Ok(first_result) } } diff --git a/crates/spirv-std/src/memory.rs b/crates/spirv-std/src/memory.rs index 512f01e508..b8eccfaab3 100644 --- a/crates/spirv-std/src/memory.rs +++ b/crates/spirv-std/src/memory.rs @@ -1,5 +1,8 @@ //! Types for handling memory ordering constraints for concurrent memory access. +// NOTE(eddyb) "&-masking with zero", likely due to `NONE = 0` in `bitflags!`. +#![allow(clippy::bad_bit_mask)] + /// Specification for how large of a scope some instructions should operate on - used when calling /// functions that take a configurable scope. #[derive(Debug, PartialEq, Eq)] diff --git a/crates/spirv-std/src/ray_tracing.rs b/crates/spirv-std/src/ray_tracing.rs index 78cfe0878e..39803599b8 100644 --- a/crates/spirv-std/src/ray_tracing.rs +++ b/crates/spirv-std/src/ray_tracing.rs @@ -1,4 +1,8 @@ //! Ray-tracing data types + +// NOTE(eddyb) "&-masking with zero", likely due to `NONE = 0` in `bitflags!`. +#![allow(clippy::bad_bit_mask)] + use crate::vector::Vector; #[cfg(target_arch = "spirv")] use core::arch::asm; diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 639bbf34b6..abd2d7b0ca 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,7 +1,7 @@ [toolchain] -channel = "nightly-2023-05-27" +channel = "nightly-2023-07-08" components = ["rust-src", "rustc-dev", "llvm-tools-preview"] -# commit_hash = 1a5f8bce74ee432f7cc3aa131bc3d6920e06de10 +# commit_hash = cb80ff132a0e9aa71529b701427e4e6c243b58df # 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. diff --git a/tests/ui/dis/generic-fn-op-name.rs b/tests/ui/dis/generic-fn-op-name.rs index 07db02a6e1..1f07f69b5a 100644 --- a/tests/ui/dis/generic-fn-op-name.rs +++ b/tests/ui/dis/generic-fn-op-name.rs @@ -11,9 +11,17 @@ #![feature(adt_const_params)] #![allow(incomplete_features)] -use spirv_std::image::Dimensionality; use spirv_std::spirv; +// HACK(eddyb) not using `spirv_std::image::Dimensionality` as that `enum` doesn't +// actually implement `ConstParamTy` (nor do we need *that* `enum`, just any). +#[derive(PartialEq, Eq, PartialOrd, Ord, core::marker::ConstParamTy)] +enum Dimensionality { + OneD, + TwoD, + ThreeD, +} + fn generic() {} #[spirv(fragment)] diff --git a/tests/ui/dis/generic-fn-op-name.stderr b/tests/ui/dis/generic-fn-op-name.stderr index ea408d66ce..09d24a139e 100644 --- a/tests/ui/dis/generic-fn-op-name.stderr +++ b/tests/ui/dis/generic-fn-op-name.stderr @@ -10,6 +10,6 @@ OpEntryPoint Fragment %1 "main" OpExecutionMode %1 OriginUpperLeft %2 = OpString "$OPSTRING_FILENAME/generic-fn-op-name.rs" OpName %3 "generic_fn_op_name::main" -OpName %4 "generic_fn_op_name::generic::" +OpName %4 "generic_fn_op_name::generic::" %5 = OpTypeVoid %6 = OpTypeFunction %5 diff --git a/tests/ui/dis/ptr_copy.normal.stderr b/tests/ui/dis/ptr_copy.normal.stderr index 15e50f796a..8118ae08b7 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:2760:9 + --> $CORE_SRC/intrinsics.rs:2767:9 | -2760 | copy(src, dst, count) +2767 | copy(src, dst, count) | ^^^^^^^^^^^^^^^^^^^^^ | note: used from within `core::intrinsics::copy::` - --> $CORE_SRC/intrinsics.rs:2746:21 + --> $CORE_SRC/intrinsics.rs:2753:21 | -2746 | pub const unsafe fn copy(src: *const T, dst: *mut T, count: usize) { +2753 | 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 f00fdb22d8..0bf7992457 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 1178 8 +OpLine %8 1179 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 f00fdb22d8..0bf7992457 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 1178 8 +OpLine %8 1179 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 0cf10a1b02..a101a05269 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 1376 8 +OpLine %11 1377 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 b6b4a900db..2c6ae1dc37 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 1376 8 +OpLine %11 1377 8 OpStore %6 %9 OpNoLine OpReturn