From 50f8a678091c632c740320f089f01582ca7d4438 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 30 Sep 2025 13:59:42 +1000 Subject: [PATCH 1/5] Update to `nightly-2025-07-07`. - We now get warnings about unnecessary parentheses around `dyn` types. - Spelling of `sf.name.prefer_remapped_unconditionaly` was fixed (now ends in `lly`). - `Pointer::into_parts` has been replaced with `Pointer::prov_and_relative_offset`. --- crates/rustc_codegen_spirv/build.rs | 4 ++-- crates/rustc_codegen_spirv/src/builder_spirv.rs | 2 +- crates/rustc_codegen_spirv/src/codegen_cx/constant.rs | 4 ++-- crates/rustc_codegen_spirv/src/lib.rs | 3 +-- rust-toolchain.toml | 4 ++-- 5 files changed, 8 insertions(+), 9 deletions(-) diff --git a/crates/rustc_codegen_spirv/build.rs b/crates/rustc_codegen_spirv/build.rs index 4577f73793..a47920daaa 100644 --- a/crates/rustc_codegen_spirv/build.rs +++ b/crates/rustc_codegen_spirv/build.rs @@ -19,9 +19,9 @@ use std::{env, fs, mem}; /// `cargo publish`. We need to figure out a way to do this properly, but let's hardcode it for now :/ //const REQUIRED_RUST_TOOLCHAIN: &str = include_str!("../../rust-toolchain.toml"); const REQUIRED_RUST_TOOLCHAIN: &str = r#"[toolchain] -channel = "nightly-2025-06-30" +channel = "nightly-2025-07-07" components = ["rust-src", "rustc-dev", "llvm-tools"] -# commit_hash = 35f6036521777bdc0dcea1f980be4c192962a168"#; +# commit_hash = a84ab0ce6c4557a2f01a3a6c3fdb0f92098db78d"#; fn rustc_output(arg: &str) -> Result> { let rustc = env::var("RUSTC").unwrap_or_else(|_| "rustc".into()); diff --git a/crates/rustc_codegen_spirv/src/builder_spirv.rs b/crates/rustc_codegen_spirv/src/builder_spirv.rs index e05b433057..ba8e01fd44 100644 --- a/crates/rustc_codegen_spirv/src/builder_spirv.rs +++ b/crates/rustc_codegen_spirv/src/builder_spirv.rs @@ -887,7 +887,7 @@ impl<'tcx> BuilderSpirv<'tcx> { FileName::Real(name) => { name.to_string_lossy(FileNameDisplayPreference::Remapped) } - _ => sf.name.prefer_remapped_unconditionaly().to_string().into(), + _ => sf.name.prefer_remapped_unconditionally().to_string().into(), }; let file_name = { // FIXME(eddyb) it should be possible to arena-allocate a diff --git a/crates/rustc_codegen_spirv/src/codegen_cx/constant.rs b/crates/rustc_codegen_spirv/src/codegen_cx/constant.rs index acd9b42172..a9ec6ad0f8 100644 --- a/crates/rustc_codegen_spirv/src/codegen_cx/constant.rs +++ b/crates/rustc_codegen_spirv/src/codegen_cx/constant.rs @@ -246,7 +246,7 @@ impl ConstCodegenMethods for CodegenCx<'_> { } } Scalar::Ptr(ptr, _) => { - let (prov, offset) = ptr.into_parts(); + let (prov, offset) = ptr.prov_and_relative_offset(); let alloc_id = prov.alloc_id(); let (base_addr, _base_addr_space) = match self.tcx.global_alloc(alloc_id) { GlobalAlloc::Memory(alloc) => { @@ -449,7 +449,7 @@ impl<'tcx> CodegenCx<'tcx> { .inner() .read_scalar(self, range, /* read_provenance */ true) { - let (prov, _offset) = ptr.into_parts(); + let (prov, _offset) = ptr.prov_and_relative_offset(); primitive = Primitive::Pointer( self.tcx.global_alloc(prov.alloc_id()).address_space(self), ); diff --git a/crates/rustc_codegen_spirv/src/lib.rs b/crates/rustc_codegen_spirv/src/lib.rs index 3e57d8648d..c88d4fcf39 100644 --- a/crates/rustc_codegen_spirv/src/lib.rs +++ b/crates/rustc_codegen_spirv/src/lib.rs @@ -547,8 +547,7 @@ impl ExtraBackendMethods for SpirvCodegenBackend { _sess: &Session, _opt_level: config::OptLevel, _target_features: &[String], - ) -> Arc<(dyn Fn(TargetMachineFactoryConfig) -> Result<(), String> + Send + Sync + 'static)> - { + ) -> Arc Result<(), String> + Send + Sync + 'static> { Arc::new(|_| Ok(())) } } diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 06deb6d52d..0e0847c587 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,7 +1,7 @@ [toolchain] -channel = "nightly-2025-06-30" +channel = "nightly-2025-07-07" components = ["rust-src", "rustc-dev", "llvm-tools"] -# commit_hash = 35f6036521777bdc0dcea1f980be4c192962a168 +# commit_hash = a84ab0ce6c4557a2f01a3a6c3fdb0f92098db78d # Whenever changing the nightly channel, update the commit hash above, and # change `REQUIRED_RUST_TOOLCHAIN` in `crates/rustc_codegen_spirv/build.rs` too. From f2f668ffda4870487ab09b2b125adc8db09a4377 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 30 Sep 2025 16:04:10 +1000 Subject: [PATCH 2/5] Update to `nightly-2025-07-14`. - `BuilderMethods::dynamic_alloca` was removed. - `TargetDataLayout::pointer_{size,align}` were changed from fields to methods. - `AddressSpace::DATA` was renamed `AddressSpace::ZERO`. --- crates/rustc_codegen_spirv/build.rs | 4 ++-- crates/rustc_codegen_spirv/src/abi.rs | 4 ++-- .../src/builder/builder_methods.rs | 4 ---- .../src/codegen_cx/constant.rs | 22 ++++++++++++++----- .../src/codegen_cx/type_.rs | 4 ++-- crates/rustc_codegen_spirv/src/spirv_type.rs | 4 ++-- rust-toolchain.toml | 4 ++-- 7 files changed, 27 insertions(+), 19 deletions(-) diff --git a/crates/rustc_codegen_spirv/build.rs b/crates/rustc_codegen_spirv/build.rs index a47920daaa..286d142ed7 100644 --- a/crates/rustc_codegen_spirv/build.rs +++ b/crates/rustc_codegen_spirv/build.rs @@ -19,9 +19,9 @@ use std::{env, fs, mem}; /// `cargo publish`. We need to figure out a way to do this properly, but let's hardcode it for now :/ //const REQUIRED_RUST_TOOLCHAIN: &str = include_str!("../../rust-toolchain.toml"); const REQUIRED_RUST_TOOLCHAIN: &str = r#"[toolchain] -channel = "nightly-2025-07-07" +channel = "nightly-2025-07-14" components = ["rust-src", "rustc-dev", "llvm-tools"] -# commit_hash = a84ab0ce6c4557a2f01a3a6c3fdb0f92098db78d"#; +# commit_hash = e9182f195b8505c87c4bd055b9f6e114ccda0981"#; fn rustc_output(arg: &str) -> Result> { let rustc = env::var("RUSTC").unwrap_or_else(|_| "rustc".into()); diff --git a/crates/rustc_codegen_spirv/src/abi.rs b/crates/rustc_codegen_spirv/src/abi.rs index 0c5cf69f4d..c42d64a518 100644 --- a/crates/rustc_codegen_spirv/src/abi.rs +++ b/crates/rustc_codegen_spirv/src/abi.rs @@ -791,7 +791,7 @@ fn trans_intrinsic_type<'tcx>( 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) + SpirvType::Integer(cx.tcx.data_layout.pointer_size().bits() as u32, true) .def(span, cx) } IntTy::I8 => SpirvType::Integer(8, true).def(span, cx), @@ -802,7 +802,7 @@ fn trans_intrinsic_type<'tcx>( }, TyKind::Uint(uint) => match uint { UintTy::Usize => { - SpirvType::Integer(cx.tcx.data_layout.pointer_size.bits() as u32, false) + SpirvType::Integer(cx.tcx.data_layout.pointer_size().bits() as u32, false) .def(span, cx) } UintTy::U8 => SpirvType::Integer(8, false).def(span, cx), diff --git a/crates/rustc_codegen_spirv/src/builder/builder_methods.rs b/crates/rustc_codegen_spirv/src/builder/builder_methods.rs index 840a206174..375e11ff35 100644 --- a/crates/rustc_codegen_spirv/src/builder/builder_methods.rs +++ b/crates/rustc_codegen_spirv/src/builder/builder_methods.rs @@ -1825,10 +1825,6 @@ impl<'a, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'tcx> { self.declare_func_local_var(self.type_array(self.type_i8(), size.bytes()), align) } - fn dynamic_alloca(&mut self, _len: Self::Value, _align: Align) -> Self::Value { - self.fatal("dynamic alloca not supported yet") - } - fn load(&mut self, ty: Self::Type, ptr: Self::Value, _align: Align) -> Self::Value { let (ptr, access_ty) = self.adjust_pointer_for_typed_access(ptr, ty); let loaded_val = ptr.const_fold_load(self).unwrap_or_else(|| { diff --git a/crates/rustc_codegen_spirv/src/codegen_cx/constant.rs b/crates/rustc_codegen_spirv/src/codegen_cx/constant.rs index a9ec6ad0f8..3e3f97a48e 100644 --- a/crates/rustc_codegen_spirv/src/codegen_cx/constant.rs +++ b/crates/rustc_codegen_spirv/src/codegen_cx/constant.rs @@ -152,7 +152,7 @@ impl ConstCodegenMethods for CodegenCx<'_> { 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 ptr_size = self.tcx.data_layout.pointer_size().bits() as u32; let t = SpirvType::Integer(ptr_size, false).def(DUMMY_SP, self); self.constant_int(t, i.into()) } @@ -263,7 +263,7 @@ impl ConstCodegenMethods for CodegenCx<'_> { .try_read_from_const_alloc(alloc, pointee) .unwrap_or_else(|| self.const_data_from_alloc(alloc)); let value = self.static_addr_of(init, alloc.inner().align, None); - (value, AddressSpace::DATA) + (value, AddressSpace::ZERO) } GlobalAlloc::Function { instance } => ( self.get_fn_addr(instance), @@ -292,12 +292,24 @@ impl ConstCodegenMethods for CodegenCx<'_> { .try_read_from_const_alloc(alloc, pointee) .unwrap_or_else(|| self.const_data_from_alloc(alloc)); let value = self.static_addr_of(init, alloc.inner().align, None); - (value, AddressSpace::DATA) + (value, AddressSpace::ZERO) } GlobalAlloc::Static(def_id) => { assert!(self.tcx.is_static(def_id)); assert!(!self.tcx.is_thread_local_static(def_id)); - (self.get_static(def_id), AddressSpace::DATA) + (self.get_static(def_id), AddressSpace::ZERO) + } + GlobalAlloc::TypeId { .. } => { + return if offset.bytes() == 0 { + self.constant_null(ty) + } else { + let result = self.undef(ty); + self.zombie_no_span( + result.def_cx(self), + "pointer has non-null integer address", + ); + result + }; } }; self.const_bitcast(self.const_ptr_byte_offset(base_addr, offset), ty) @@ -430,7 +442,7 @@ impl<'tcx> CodegenCx<'tcx> { .fatal(format!("invalid size for float: {other}")); } }), - SpirvType::Pointer { .. } => Primitive::Pointer(AddressSpace::DATA), + SpirvType::Pointer { .. } => Primitive::Pointer(AddressSpace::ZERO), _ => unreachable!(), }; diff --git a/crates/rustc_codegen_spirv/src/codegen_cx/type_.rs b/crates/rustc_codegen_spirv/src/codegen_cx/type_.rs index 6ed23ead89..be570c7015 100644 --- a/crates/rustc_codegen_spirv/src/codegen_cx/type_.rs +++ b/crates/rustc_codegen_spirv/src/codegen_cx/type_.rs @@ -124,7 +124,7 @@ impl<'tcx> LayoutTypeCodegenMethods<'tcx> for CodegenCx<'tcx> { impl<'tcx> CodegenCx<'tcx> { pub fn type_usize(&self) -> Word { - let ptr_size = self.tcx.data_layout.pointer_size.bits() as u32; + let ptr_size = self.tcx.data_layout.pointer_size().bits() as u32; SpirvType::Integer(ptr_size, false).def(DUMMY_SP, self) } } @@ -146,7 +146,7 @@ impl BaseTypeCodegenMethods for CodegenCx<'_> { SpirvType::Integer(128, false).def(DUMMY_SP, self) } fn type_isize(&self) -> Self::Type { - let ptr_size = self.tcx.data_layout.pointer_size.bits() as u32; + let ptr_size = self.tcx.data_layout.pointer_size().bits() as u32; SpirvType::Integer(ptr_size, false).def(DUMMY_SP, self) } diff --git a/crates/rustc_codegen_spirv/src/spirv_type.rs b/crates/rustc_codegen_spirv/src/spirv_type.rs index 3213b13129..cc4f62ad0b 100644 --- a/crates/rustc_codegen_spirv/src/spirv_type.rs +++ b/crates/rustc_codegen_spirv/src/spirv_type.rs @@ -335,7 +335,7 @@ impl SpirvType<'_> { .expect("SpirvType::Array.count to be a u32 constant"); element.checked_mul(count, cx).expect("overflow") } - Self::Pointer { .. } => cx.tcx.data_layout.pointer_size, + Self::Pointer { .. } => cx.tcx.data_layout.pointer_size(), Self::Image { .. } | Self::AccelerationStructureKhr | Self::RayQueryKhr @@ -357,7 +357,7 @@ impl SpirvType<'_> { Self::Array { element, .. } | Self::RuntimeArray { element } | Self::Matrix { element, .. } => cx.lookup_type(element).alignof(cx), - Self::Pointer { .. } => cx.tcx.data_layout.pointer_align.abi, + Self::Pointer { .. } => cx.tcx.data_layout.pointer_align().abi, Self::Image { .. } | Self::AccelerationStructureKhr | Self::RayQueryKhr diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 0e0847c587..833f167631 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,7 +1,7 @@ [toolchain] -channel = "nightly-2025-07-07" +channel = "nightly-2025-07-14" components = ["rust-src", "rustc-dev", "llvm-tools"] -# commit_hash = a84ab0ce6c4557a2f01a3a6c3fdb0f92098db78d +# commit_hash = e9182f195b8505c87c4bd055b9f6e114ccda0981 # Whenever changing the nightly channel, update the commit hash above, and # change `REQUIRED_RUST_TOOLCHAIN` in `crates/rustc_codegen_spirv/build.rs` too. From 9c61be21b2bd813e690f95a2ffd5210c6f16a447 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 2 Oct 2025 09:28:23 +1000 Subject: [PATCH 3/5] Update to `nightly-2025-07-28`. - `run_fat_lto`, `optimize_fat`, and `autodiff` were merged into `run_and_optimize_fat_lto`, and the parameters were changed. - `run_thin_lto` parameters were changed. - `codegen` parameters were changed. - `LtoModuleCodegen` was removed. - Minor error message changes: - Some line number changes in rustc. - Some error message wording tweaks. The LTO changes occurred in rust-lang/rust PR 143388 and PR 144062. --- crates/rustc_codegen_spirv/build.rs | 4 +- crates/rustc_codegen_spirv/src/lib.rs | 38 ++++++---------- crates/rustc_codegen_spirv/src/link.rs | 8 ++-- rust-toolchain.toml | 4 +- .../ui/dis/ptr_copy.normal.stderr | 8 ++-- tests/compiletests/ui/dis/ptr_read.stderr | 2 +- .../ui/dis/ptr_read_method.stderr | 2 +- tests/compiletests/ui/dis/ptr_write.stderr | 2 +- .../ui/dis/ptr_write_method.stderr | 2 +- .../ui/spirv-attr/invalid-target.stderr | 44 +++++++++---------- 10 files changed, 51 insertions(+), 63 deletions(-) diff --git a/crates/rustc_codegen_spirv/build.rs b/crates/rustc_codegen_spirv/build.rs index 286d142ed7..9b9beab933 100644 --- a/crates/rustc_codegen_spirv/build.rs +++ b/crates/rustc_codegen_spirv/build.rs @@ -19,9 +19,9 @@ use std::{env, fs, mem}; /// `cargo publish`. We need to figure out a way to do this properly, but let's hardcode it for now :/ //const REQUIRED_RUST_TOOLCHAIN: &str = include_str!("../../rust-toolchain.toml"); const REQUIRED_RUST_TOOLCHAIN: &str = r#"[toolchain] -channel = "nightly-2025-07-14" +channel = "nightly-2025-07-28" components = ["rust-src", "rustc-dev", "llvm-tools"] -# commit_hash = e9182f195b8505c87c4bd055b9f6e114ccda0981"#; +# commit_hash = f8e355c230c6eb7b78ffce6a92fd81f78c890524"#; fn rustc_output(arg: &str) -> Result> { let rustc = env::var("RUSTC").unwrap_or_else(|_| "rustc".into()); diff --git a/crates/rustc_codegen_spirv/src/lib.rs b/crates/rustc_codegen_spirv/src/lib.rs index c88d4fcf39..9f28a26a22 100644 --- a/crates/rustc_codegen_spirv/src/lib.rs +++ b/crates/rustc_codegen_spirv/src/lib.rs @@ -141,7 +141,7 @@ mod target_feature; use builder::Builder; use codegen_cx::CodegenCx; -use maybe_pqp_cg_ssa::back::lto::{LtoModuleCodegen, SerializedModule, ThinModule}; +use maybe_pqp_cg_ssa::back::lto::{SerializedModule, ThinModule}; use maybe_pqp_cg_ssa::back::write::{ CodegenContext, FatLtoInput, ModuleConfig, OngoingCodegen, TargetMachineFactoryConfig, }; @@ -170,7 +170,7 @@ use std::any::Any; use std::fs; use std::io::Cursor; use std::io::Write; -use std::path::Path; +use std::path::{Path, PathBuf}; use std::sync::Arc; use tracing::{error, warn}; @@ -333,7 +333,7 @@ impl WriteBackendMethods for SpirvCodegenBackend { type ThinBuffer = SpirvModuleBuffer; // FIXME(eddyb) reuse the "merge" stage of `crate::linker` for this, or even - // delegate to `run_fat_lto` (although `-Zcombine-cgu` is much more niche). + // delegate to `run_and_optimize_fat_lto` (although `-Zcombine-cgu` is much more niche). fn run_link( cgcx: &CodegenContext, diag_handler: DiagCtxtHandle<'_>, @@ -351,14 +351,16 @@ impl WriteBackendMethods for SpirvCodegenBackend { // consider setting `requires_lto = true` in the target specs and moving the // entirety of `crate::linker` into this stage (lacking diagnostics may be // an issue - it's surprising `CodegenBackend::link` has `Session` at all). - fn run_fat_lto( + fn run_and_optimize_fat_lto( cgcx: &CodegenContext, + _exported_symbols_for_lto: &[String], + _each_linked_rlib_for_lto: &[PathBuf], _modules: Vec>, - _cached_modules: Vec<(SerializedModule, WorkProduct)>, - ) -> Result, FatalError> { + _diff_fncs: Vec, + ) -> Result, FatalError> { assert!( cgcx.lto == rustc_session::config::Lto::Fat, - "`run_fat_lto` (for `WorkItemResult::NeedsFatLto`) should \ + "`run_and_optimize_fat_lto` (for `WorkItemResult::NeedsFatLto`) should \ only be invoked due to `-Clto` (or equivalent)" ); unreachable!("Rust-GPU does not support fat LTO") @@ -366,9 +368,12 @@ impl WriteBackendMethods for SpirvCodegenBackend { fn run_thin_lto( cgcx: &CodegenContext, + // FIXME(bjorn3): Limit LTO exports to these symbols + _exported_symbols_for_lto: &[String], + _each_linked_rlib_for_lto: &[PathBuf], // njn: ? modules: Vec<(String, Self::ThinBuffer)>, cached_modules: Vec<(SerializedModule, WorkProduct)>, - ) -> Result<(Vec>, Vec), FatalError> { + ) -> Result<(Vec>, Vec), FatalError> { link::run_thin(cgcx, modules, cached_modules) } @@ -409,16 +414,8 @@ impl WriteBackendMethods for SpirvCodegenBackend { Ok(module) } - fn optimize_fat( - cgcx: &CodegenContext, - module: &mut ModuleCodegen, - ) -> Result<(), FatalError> { - Self::optimize_common(cgcx, module) - } - fn codegen( cgcx: &CodegenContext, - _diag_handler: DiagCtxtHandle<'_>, module: ModuleCodegen, _config: &ModuleConfig, ) -> Result { @@ -457,15 +454,6 @@ impl WriteBackendMethods for SpirvCodegenBackend { SpirvModuleBuffer(module.module_llvm.assemble()), ) } - - fn autodiff( - _cgcx: &CodegenContext, - _module: &ModuleCodegen, - _diff_fncs: Vec, - _config: &ModuleConfig, - ) -> Result<(), FatalError> { - unreachable!("Rust-GPU does not support autodiff") - } } impl ExtraBackendMethods for SpirvCodegenBackend { diff --git a/crates/rustc_codegen_spirv/src/link.rs b/crates/rustc_codegen_spirv/src/link.rs index 038d307930..6e129c491c 100644 --- a/crates/rustc_codegen_spirv/src/link.rs +++ b/crates/rustc_codegen_spirv/src/link.rs @@ -8,7 +8,7 @@ use rspirv::binary::Assemble; use rspirv::dr::Module; use rustc_ast::CRATE_NODE_ID; use rustc_codegen_spirv_types::{CompileResult, ModuleResult}; -use rustc_codegen_ssa::back::lto::{LtoModuleCodegen, SerializedModule, ThinModule, ThinShared}; +use rustc_codegen_ssa::back::lto::{SerializedModule, ThinModule, ThinShared}; use rustc_codegen_ssa::back::write::CodegenContext; use rustc_codegen_ssa::{CodegenResults, NativeLib}; use rustc_data_structures::fx::FxHashSet; @@ -634,7 +634,7 @@ pub(crate) fn run_thin( cgcx: &CodegenContext, modules: Vec<(String, SpirvModuleBuffer)>, cached_modules: Vec<(SerializedModule, WorkProduct)>, -) -> Result<(Vec>, Vec), FatalError> { +) -> Result<(Vec>, Vec), FatalError> { if cgcx.opts.cg.linker_plugin_lto.enabled() { unreachable!("We should never reach this case if the LTO step is deferred to the linker"); } @@ -668,10 +668,10 @@ pub(crate) fn run_thin( let mut opt_jobs = vec![]; for (module_index, _) in shared.module_names.iter().enumerate() { - opt_jobs.push(LtoModuleCodegen::Thin(ThinModule { + opt_jobs.push(ThinModule { shared: shared.clone(), idx: module_index, - })); + }); } Ok((opt_jobs, vec![])) diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 833f167631..54f82d0844 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,7 +1,7 @@ [toolchain] -channel = "nightly-2025-07-14" +channel = "nightly-2025-07-28" components = ["rust-src", "rustc-dev", "llvm-tools"] -# commit_hash = e9182f195b8505c87c4bd055b9f6e114ccda0981 +# commit_hash = f8e355c230c6eb7b78ffce6a92fd81f78c890524 # Whenever changing the nightly channel, update the commit hash above, and # change `REQUIRED_RUST_TOOLCHAIN` in `crates/rustc_codegen_spirv/build.rs` too. diff --git a/tests/compiletests/ui/dis/ptr_copy.normal.stderr b/tests/compiletests/ui/dis/ptr_copy.normal.stderr index dd442fbb40..fd9b231031 100644 --- a/tests/compiletests/ui/dis/ptr_copy.normal.stderr +++ b/tests/compiletests/ui/dis/ptr_copy.normal.stderr @@ -1,11 +1,11 @@ error: cannot memcpy dynamically sized data - --> $CORE_SRC/ptr/mod.rs:633:9 + --> $CORE_SRC/ptr/mod.rs:638:9 | LL | crate::intrinsics::copy(src, dst, count) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: used from within `core::ptr::copy::` - --> $CORE_SRC/ptr/mod.rs:618:21 + --> $CORE_SRC/ptr/mod.rs:623:21 | LL | pub const unsafe fn copy(src: *const T, dst: *mut T, count: usize) { | ^^^^ @@ -28,7 +28,7 @@ LL | pub fn main(i: f32, o: &mut f32) { error: cannot cast between pointer types from `*f32` to `*struct () { }` - --> $CORE_SRC/ptr/mod.rs:621:9 + --> $CORE_SRC/ptr/mod.rs:626:9 | LL | / ub_checks::assert_unsafe_precondition!( LL | | check_language_ub, @@ -39,7 +39,7 @@ LL | | ); | |_________^ | note: used from within `core::ptr::copy::` - --> $CORE_SRC/ptr/mod.rs:621:9 + --> $CORE_SRC/ptr/mod.rs:626:9 | LL | / ub_checks::assert_unsafe_precondition!( LL | | check_language_ub, diff --git a/tests/compiletests/ui/dis/ptr_read.stderr b/tests/compiletests/ui/dis/ptr_read.stderr index 87764b0941..93d0921375 100644 --- a/tests/compiletests/ui/dis/ptr_read.stderr +++ b/tests/compiletests/ui/dis/ptr_read.stderr @@ -2,7 +2,7 @@ %4 = OpFunctionParameter %5 %6 = OpFunctionParameter %5 %7 = OpLabel -OpLine %8 1732 8 +OpLine %8 1737 8 %9 = OpLoad %10 %4 OpLine %11 7 13 OpStore %6 %9 diff --git a/tests/compiletests/ui/dis/ptr_read_method.stderr b/tests/compiletests/ui/dis/ptr_read_method.stderr index 87764b0941..93d0921375 100644 --- a/tests/compiletests/ui/dis/ptr_read_method.stderr +++ b/tests/compiletests/ui/dis/ptr_read_method.stderr @@ -2,7 +2,7 @@ %4 = OpFunctionParameter %5 %6 = OpFunctionParameter %5 %7 = OpLabel -OpLine %8 1732 8 +OpLine %8 1737 8 %9 = OpLoad %10 %4 OpLine %11 7 13 OpStore %6 %9 diff --git a/tests/compiletests/ui/dis/ptr_write.stderr b/tests/compiletests/ui/dis/ptr_write.stderr index 26d592becb..e2075881c2 100644 --- a/tests/compiletests/ui/dis/ptr_write.stderr +++ b/tests/compiletests/ui/dis/ptr_write.stderr @@ -4,7 +4,7 @@ %7 = OpLabel OpLine %8 7 35 %9 = OpLoad %10 %4 -OpLine %11 1932 8 +OpLine %11 1937 8 OpStore %6 %9 OpNoLine OpReturn diff --git a/tests/compiletests/ui/dis/ptr_write_method.stderr b/tests/compiletests/ui/dis/ptr_write_method.stderr index 7b94da100b..3d539802b8 100644 --- a/tests/compiletests/ui/dis/ptr_write_method.stderr +++ b/tests/compiletests/ui/dis/ptr_write_method.stderr @@ -4,7 +4,7 @@ %7 = OpLabel OpLine %8 7 37 %9 = OpLoad %10 %4 -OpLine %11 1932 8 +OpLine %11 1937 8 OpStore %6 %9 OpNoLine OpReturn diff --git a/tests/compiletests/ui/spirv-attr/invalid-target.stderr b/tests/compiletests/ui/spirv-attr/invalid-target.stderr index 5cb3a5e890..e796b01656 100644 --- a/tests/compiletests/ui/spirv-attr/invalid-target.stderr +++ b/tests/compiletests/ui/spirv-attr/invalid-target.stderr @@ -1030,67 +1030,67 @@ error: attribute is only valid on a function parameter, not on a struct field LL | uniform, position, descriptor_set = 0, binding = 0, flat, invariant, // param-only | ^^^^^^^^^ -error: attribute is only valid on a struct, not on a implementation block +error: attribute is only valid on a struct, not on a inherent implementation block --> $DIR/invalid-target.rs:176:5 | LL | sampler, block, sampled_image, generic_image_type, // struct-only | ^^^^^^^ -error: attribute is only valid on a struct, not on a implementation block +error: attribute is only valid on a struct, not on a inherent implementation block --> $DIR/invalid-target.rs:176:14 | LL | sampler, block, sampled_image, generic_image_type, // struct-only | ^^^^^ -error: attribute is only valid on a struct, not on a implementation block +error: attribute is only valid on a struct, not on a inherent implementation block --> $DIR/invalid-target.rs:176:21 | LL | sampler, block, sampled_image, generic_image_type, // struct-only | ^^^^^^^^^^^^^ -error: attribute is only valid on a struct, not on a implementation block +error: attribute is only valid on a struct, not on a inherent implementation block --> $DIR/invalid-target.rs:176:36 | LL | sampler, block, sampled_image, generic_image_type, // struct-only | ^^^^^^^^^^^^^^^^^^ -error: attribute is only valid on a function, not on a implementation block +error: attribute is only valid on a function, not on a inherent implementation block --> $DIR/invalid-target.rs:177:5 | LL | vertex, // fn-only | ^^^^^^ -error: attribute is only valid on a function parameter, not on a implementation block +error: attribute is only valid on a function parameter, not on a inherent implementation block --> $DIR/invalid-target.rs:178:5 | LL | uniform, position, descriptor_set = 0, binding = 0, flat, invariant, // param-only | ^^^^^^^ -error: attribute is only valid on a function parameter, not on a implementation block +error: attribute is only valid on a function parameter, not on a inherent implementation block --> $DIR/invalid-target.rs:178:14 | LL | uniform, position, descriptor_set = 0, binding = 0, flat, invariant, // param-only | ^^^^^^^^ -error: attribute is only valid on a function parameter, not on a implementation block +error: attribute is only valid on a function parameter, not on a inherent implementation block --> $DIR/invalid-target.rs:178:24 | LL | uniform, position, descriptor_set = 0, binding = 0, flat, invariant, // param-only | ^^^^^^^^^^^^^^^^^^ -error: attribute is only valid on a function parameter, not on a implementation block +error: attribute is only valid on a function parameter, not on a inherent implementation block --> $DIR/invalid-target.rs:178:44 | LL | uniform, position, descriptor_set = 0, binding = 0, flat, invariant, // param-only | ^^^^^^^^^^^ -error: attribute is only valid on a function parameter, not on a implementation block +error: attribute is only valid on a function parameter, not on a inherent implementation block --> $DIR/invalid-target.rs:178:57 | LL | uniform, position, descriptor_set = 0, binding = 0, flat, invariant, // param-only | ^^^^ -error: attribute is only valid on a function parameter, not on a implementation block +error: attribute is only valid on a function parameter, not on a inherent implementation block --> $DIR/invalid-target.rs:178:63 | LL | uniform, position, descriptor_set = 0, binding = 0, flat, invariant, // param-only @@ -1228,67 +1228,67 @@ error: attribute is only valid on a function parameter, not on a trait LL | uniform, position, descriptor_set = 0, binding = 0, flat, invariant, // param-only | ^^^^^^^^^ -error: attribute is only valid on a struct, not on a implementation block +error: attribute is only valid on a struct, not on a trait implementation block --> $DIR/invalid-target.rs:237:5 | LL | sampler, block, sampled_image, generic_image_type, // struct-only | ^^^^^^^ -error: attribute is only valid on a struct, not on a implementation block +error: attribute is only valid on a struct, not on a trait implementation block --> $DIR/invalid-target.rs:237:14 | LL | sampler, block, sampled_image, generic_image_type, // struct-only | ^^^^^ -error: attribute is only valid on a struct, not on a implementation block +error: attribute is only valid on a struct, not on a trait implementation block --> $DIR/invalid-target.rs:237:21 | LL | sampler, block, sampled_image, generic_image_type, // struct-only | ^^^^^^^^^^^^^ -error: attribute is only valid on a struct, not on a implementation block +error: attribute is only valid on a struct, not on a trait implementation block --> $DIR/invalid-target.rs:237:36 | LL | sampler, block, sampled_image, generic_image_type, // struct-only | ^^^^^^^^^^^^^^^^^^ -error: attribute is only valid on a function, not on a implementation block +error: attribute is only valid on a function, not on a trait implementation block --> $DIR/invalid-target.rs:238:5 | LL | vertex, // fn-only | ^^^^^^ -error: attribute is only valid on a function parameter, not on a implementation block +error: attribute is only valid on a function parameter, not on a trait implementation block --> $DIR/invalid-target.rs:239:5 | LL | uniform, position, descriptor_set = 0, binding = 0, flat, invariant, // param-only | ^^^^^^^ -error: attribute is only valid on a function parameter, not on a implementation block +error: attribute is only valid on a function parameter, not on a trait implementation block --> $DIR/invalid-target.rs:239:14 | LL | uniform, position, descriptor_set = 0, binding = 0, flat, invariant, // param-only | ^^^^^^^^ -error: attribute is only valid on a function parameter, not on a implementation block +error: attribute is only valid on a function parameter, not on a trait implementation block --> $DIR/invalid-target.rs:239:24 | LL | uniform, position, descriptor_set = 0, binding = 0, flat, invariant, // param-only | ^^^^^^^^^^^^^^^^^^ -error: attribute is only valid on a function parameter, not on a implementation block +error: attribute is only valid on a function parameter, not on a trait implementation block --> $DIR/invalid-target.rs:239:44 | LL | uniform, position, descriptor_set = 0, binding = 0, flat, invariant, // param-only | ^^^^^^^^^^^ -error: attribute is only valid on a function parameter, not on a implementation block +error: attribute is only valid on a function parameter, not on a trait implementation block --> $DIR/invalid-target.rs:239:57 | LL | uniform, position, descriptor_set = 0, binding = 0, flat, invariant, // param-only | ^^^^ -error: attribute is only valid on a function parameter, not on a implementation block +error: attribute is only valid on a function parameter, not on a trait implementation block --> $DIR/invalid-target.rs:239:63 | LL | uniform, position, descriptor_set = 0, binding = 0, flat, invariant, // param-only From 5796ebceb2901c796bdd827b07d93f65b7470afc Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 2 Oct 2025 11:41:33 +1000 Subject: [PATCH 4/5] Update to `nightly-2025-08-04`. - `tcx.get_attrs_unchecked(...)` was replaced with `tcx.get_all_attrs(...)`. - `run_link` has been removed. - `BuilderMethods::tail_call` was added. It's currently `todo!()`. - Adjust expected test outputs for very minor error message formatting changes. - And update to glam 0.30.8. --- crates/rustc_codegen_spirv/build.rs | 4 ++-- crates/rustc_codegen_spirv/src/abi.rs | 2 +- .../src/builder/builder_methods.rs | 13 +++++++++++++ .../rustc_codegen_spirv/src/codegen_cx/declare.rs | 6 +++--- crates/rustc_codegen_spirv/src/lib.rs | 15 --------------- rust-toolchain.toml | 4 ++-- tests/compiletests/ui/dis/ptr_read.stderr | 2 +- tests/compiletests/ui/dis/ptr_read_method.stderr | 2 +- tests/compiletests/ui/dis/ptr_write.stderr | 2 +- tests/compiletests/ui/dis/ptr_write_method.stderr | 2 +- 10 files changed, 25 insertions(+), 27 deletions(-) diff --git a/crates/rustc_codegen_spirv/build.rs b/crates/rustc_codegen_spirv/build.rs index 9b9beab933..363f0f36a7 100644 --- a/crates/rustc_codegen_spirv/build.rs +++ b/crates/rustc_codegen_spirv/build.rs @@ -19,9 +19,9 @@ use std::{env, fs, mem}; /// `cargo publish`. We need to figure out a way to do this properly, but let's hardcode it for now :/ //const REQUIRED_RUST_TOOLCHAIN: &str = include_str!("../../rust-toolchain.toml"); const REQUIRED_RUST_TOOLCHAIN: &str = r#"[toolchain] -channel = "nightly-2025-07-28" +channel = "nightly-2025-08-04" components = ["rust-src", "rustc-dev", "llvm-tools"] -# commit_hash = f8e355c230c6eb7b78ffce6a92fd81f78c890524"#; +# commit_hash = f34ba774c78ea32b7c40598b8ad23e75cdac42a6"#; fn rustc_output(arg: &str) -> Result> { let rustc = env::var("RUSTC").unwrap_or_else(|_| "rustc".into()); diff --git a/crates/rustc_codegen_spirv/src/abi.rs b/crates/rustc_codegen_spirv/src/abi.rs index c42d64a518..bcfa0d86af 100644 --- a/crates/rustc_codegen_spirv/src/abi.rs +++ b/crates/rustc_codegen_spirv/src/abi.rs @@ -286,7 +286,7 @@ impl<'tcx> ConvSpirvType<'tcx> for TyAndLayout<'tcx> { span = cx.tcx.def_span(adt.did()); } - let attrs = AggregatedSpirvAttributes::parse(cx, cx.tcx.get_attrs_unchecked(adt.did())); + let attrs = AggregatedSpirvAttributes::parse(cx, cx.tcx.get_all_attrs(adt.did())); if let Some(intrinsic_type_attr) = attrs.intrinsic_type.map(|attr| attr.value) && let Ok(spirv_type) = diff --git a/crates/rustc_codegen_spirv/src/builder/builder_methods.rs b/crates/rustc_codegen_spirv/src/builder/builder_methods.rs index 375e11ff35..8973b753e9 100644 --- a/crates/rustc_codegen_spirv/src/builder/builder_methods.rs +++ b/crates/rustc_codegen_spirv/src/builder/builder_methods.rs @@ -3391,6 +3391,19 @@ impl<'a, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'tcx> { .with_type(result_type) } + fn tail_call( + &mut self, + _llty: Self::Type, + _fn_attrs: Option<&CodegenFnAttrs>, + _fn_abi: &FnAbi<'tcx, Ty<'tcx>>, + _llfn: Self::Value, + _args: &[Self::Value], + _funclet: Option<&Self::Funclet>, + _instance: Option>, + ) { + todo!() + } + fn zext(&mut self, val: Self::Value, dest_ty: Self::Type) -> Self::Value { self.intcast(val, dest_ty, false) } diff --git a/crates/rustc_codegen_spirv/src/codegen_cx/declare.rs b/crates/rustc_codegen_spirv/src/codegen_cx/declare.rs index af14f8b037..d6bf4b60be 100644 --- a/crates/rustc_codegen_spirv/src/codegen_cx/declare.rs +++ b/crates/rustc_codegen_spirv/src/codegen_cx/declare.rs @@ -10,8 +10,8 @@ use crate::spirv_type::SpirvType; use itertools::Itertools; use rspirv::spirv::{FunctionControl, LinkageType, StorageClass, Word}; use rustc_abi::Align; -use rustc_attr_data_structures::InlineAttr; use rustc_codegen_ssa::traits::{PreDefineCodegenMethods, StaticCodegenMethods}; +use rustc_hir::attrs::InlineAttr; use rustc_middle::bug; use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs}; use rustc_middle::mir::mono::{Linkage, MonoItem, Visibility}; @@ -133,7 +133,7 @@ impl<'tcx> CodegenCx<'tcx> { self.set_linkage(fn_id, symbol_name.to_owned(), linkage); } - let attrs = AggregatedSpirvAttributes::parse(self, self.tcx.get_attrs_unchecked(def_id)); + let attrs = AggregatedSpirvAttributes::parse(self, self.tcx.get_all_attrs(def_id)); if let Some(entry) = attrs.entry.map(|attr| attr.value) { // HACK(eddyb) early insert to let `shader_entry_stub` call this // very function via `get_fn_addr`. @@ -167,7 +167,7 @@ impl<'tcx> CodegenCx<'tcx> { } // Check if this is a From trait implementation - if let Some(impl_def_id) = self.tcx.impl_of_method(def_id) + if let Some(impl_def_id) = self.tcx.impl_of_assoc(def_id) && let Some(trait_ref) = self.tcx.impl_trait_ref(impl_def_id) { let trait_def_id = trait_ref.skip_binder().def_id; diff --git a/crates/rustc_codegen_spirv/src/lib.rs b/crates/rustc_codegen_spirv/src/lib.rs index 9f28a26a22..61a2b3d3c2 100644 --- a/crates/rustc_codegen_spirv/src/lib.rs +++ b/crates/rustc_codegen_spirv/src/lib.rs @@ -332,21 +332,6 @@ impl WriteBackendMethods for SpirvCodegenBackend { type ThinData = (); type ThinBuffer = SpirvModuleBuffer; - // FIXME(eddyb) reuse the "merge" stage of `crate::linker` for this, or even - // delegate to `run_and_optimize_fat_lto` (although `-Zcombine-cgu` is much more niche). - fn run_link( - cgcx: &CodegenContext, - diag_handler: DiagCtxtHandle<'_>, - _modules: Vec>, - ) -> Result, FatalError> { - assert!( - cgcx.opts.unstable_opts.combine_cgu, - "`run_link` (for `WorkItemResult::NeedsLink`) should \ - only be invoked due to `-Zcombine-cgu`" - ); - diag_handler.fatal("Rust-GPU does not support `-Zcombine-cgu`") - } - // FIXME(eddyb) reuse the "merge" stage of `crate::linker` for this, or even // consider setting `requires_lto = true` in the target specs and moving the // entirety of `crate::linker` into this stage (lacking diagnostics may be diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 54f82d0844..2dad704aad 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,7 +1,7 @@ [toolchain] -channel = "nightly-2025-07-28" +channel = "nightly-2025-08-04" components = ["rust-src", "rustc-dev", "llvm-tools"] -# commit_hash = f8e355c230c6eb7b78ffce6a92fd81f78c890524 +# commit_hash = f34ba774c78ea32b7c40598b8ad23e75cdac42a6 # Whenever changing the nightly channel, update the commit hash above, and # change `REQUIRED_RUST_TOOLCHAIN` in `crates/rustc_codegen_spirv/build.rs` too. diff --git a/tests/compiletests/ui/dis/ptr_read.stderr b/tests/compiletests/ui/dis/ptr_read.stderr index 93d0921375..356ab80393 100644 --- a/tests/compiletests/ui/dis/ptr_read.stderr +++ b/tests/compiletests/ui/dis/ptr_read.stderr @@ -2,7 +2,7 @@ %4 = OpFunctionParameter %5 %6 = OpFunctionParameter %5 %7 = OpLabel -OpLine %8 1737 8 +OpLine %8 1739 8 %9 = OpLoad %10 %4 OpLine %11 7 13 OpStore %6 %9 diff --git a/tests/compiletests/ui/dis/ptr_read_method.stderr b/tests/compiletests/ui/dis/ptr_read_method.stderr index 93d0921375..356ab80393 100644 --- a/tests/compiletests/ui/dis/ptr_read_method.stderr +++ b/tests/compiletests/ui/dis/ptr_read_method.stderr @@ -2,7 +2,7 @@ %4 = OpFunctionParameter %5 %6 = OpFunctionParameter %5 %7 = OpLabel -OpLine %8 1737 8 +OpLine %8 1739 8 %9 = OpLoad %10 %4 OpLine %11 7 13 OpStore %6 %9 diff --git a/tests/compiletests/ui/dis/ptr_write.stderr b/tests/compiletests/ui/dis/ptr_write.stderr index e2075881c2..6a82111894 100644 --- a/tests/compiletests/ui/dis/ptr_write.stderr +++ b/tests/compiletests/ui/dis/ptr_write.stderr @@ -4,7 +4,7 @@ %7 = OpLabel OpLine %8 7 35 %9 = OpLoad %10 %4 -OpLine %11 1937 8 +OpLine %11 1939 8 OpStore %6 %9 OpNoLine OpReturn diff --git a/tests/compiletests/ui/dis/ptr_write_method.stderr b/tests/compiletests/ui/dis/ptr_write_method.stderr index 3d539802b8..b882dca670 100644 --- a/tests/compiletests/ui/dis/ptr_write_method.stderr +++ b/tests/compiletests/ui/dis/ptr_write_method.stderr @@ -4,7 +4,7 @@ %7 = OpLabel OpLine %8 7 37 %9 = OpLoad %10 %4 -OpLine %11 1937 8 +OpLine %11 1939 8 OpStore %6 %9 OpNoLine OpReturn From 5a8cdc60c8f216ff602fb6f6afc28472b134d033 Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Thu, 8 Jan 2026 16:10:43 -0500 Subject: [PATCH 5/5] Add workaround for `MaybeUninit::uninit` and bless tests --- .../src/builder/builder_methods.rs | 9 ++++++ .../subgroup_composite_enum_err.stderr | 2 +- .../ui/lang/core/unwrap_or.stderr | 31 +++++++++---------- 3 files changed, 24 insertions(+), 18 deletions(-) diff --git a/crates/rustc_codegen_spirv/src/builder/builder_methods.rs b/crates/rustc_codegen_spirv/src/builder/builder_methods.rs index 8973b753e9..155047b3c5 100644 --- a/crates/rustc_codegen_spirv/src/builder/builder_methods.rs +++ b/crates/rustc_codegen_spirv/src/builder/builder_methods.rs @@ -3383,6 +3383,15 @@ impl<'a, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'tcx> { } } + // HACK(fee1-dead): `MaybeUninit` uses a union which we don't have very good support yet. Replacing all calls to it + // with an `Undef` serves the same purpose and fixes compiler errors + if instance_def_id.is_some_and(|did| { + self.tcx + .is_diagnostic_item(rustc_span::sym::maybe_uninit_uninit, did) + }) { + return self.undef(result_type); + } + // Default: emit a regular function call let args = args.iter().map(|arg| arg.def(self)).collect::>(); self.emit() diff --git a/tests/compiletests/ui/arch/subgroup/subgroup_composite_enum_err.stderr b/tests/compiletests/ui/arch/subgroup/subgroup_composite_enum_err.stderr index 4d0c7ce481..c30f70f2da 100644 --- a/tests/compiletests/ui/arch/subgroup/subgroup_composite_enum_err.stderr +++ b/tests/compiletests/ui/arch/subgroup/subgroup_composite_enum_err.stderr @@ -43,7 +43,7 @@ LL + #[repr(crate::NoFrom)] LL - #[repr(C)] LL + #[repr(crate::NoRepr)] | - and 2 other candidates + = and 2 other candidates help: a type parameter with a similar name exists | LL - #[repr(C)] diff --git a/tests/compiletests/ui/lang/core/unwrap_or.stderr b/tests/compiletests/ui/lang/core/unwrap_or.stderr index e950047a28..56ecc9fb21 100644 --- a/tests/compiletests/ui/lang/core/unwrap_or.stderr +++ b/tests/compiletests/ui/lang/core/unwrap_or.stderr @@ -1,23 +1,20 @@ %1 = OpFunction %2 None %3 %4 = OpLabel -OpLine %5 13 11 -%6 = OpCompositeInsert %7 %8 %9 0 -%10 = OpCompositeExtract %11 %6 1 -OpLine %12 1026 14 -%13 = OpBitcast %14 %8 -OpLine %12 1026 8 -%15 = OpINotEqual %16 %13 %17 +OpLine %5 1035 14 +%6 = OpBitcast %7 %8 +OpLine %5 1035 8 +%9 = OpINotEqual %10 %6 %11 OpNoLine -OpSelectionMerge %18 None -OpBranchConditional %15 %19 %20 -%19 = OpLabel -OpBranch %18 -%20 = OpLabel -OpBranch %18 -%18 = OpLabel -%21 = OpPhi %11 %10 %19 %22 %20 -OpLine %5 13 4 -OpStore %23 %21 +OpSelectionMerge %12 None +OpBranchConditional %9 %13 %14 +%13 = OpLabel +OpBranch %12 +%14 = OpLabel +OpBranch %12 +%12 = OpLabel +%15 = OpPhi %16 %17 %13 %18 %14 +OpLine %19 13 4 +OpStore %20 %15 OpNoLine OpReturn OpFunctionEnd