diff --git a/crates/rustc_codegen_spirv/src/attr.rs b/crates/rustc_codegen_spirv/src/attr.rs index e56f96c2a5..3a877241d2 100644 --- a/crates/rustc_codegen_spirv/src/attr.rs +++ b/crates/rustc_codegen_spirv/src/attr.rs @@ -94,6 +94,7 @@ pub enum SpirvAttribute { Builtin(BuiltIn), DescriptorSet(u32), Binding(u32), + Location(u32), Flat, PerPrimitiveExt, Invariant, @@ -130,6 +131,7 @@ pub struct AggregatedSpirvAttributes { pub builtin: Option>, pub descriptor_set: Option>, pub binding: Option>, + pub location: Option>, pub flat: Option>, pub invariant: Option>, pub per_primitive_ext: Option>, @@ -216,6 +218,7 @@ impl AggregatedSpirvAttributes { "#[spirv(descriptor_set)]", ), Binding(value) => try_insert(&mut self.binding, value, span, "#[spirv(binding)]"), + Location(value) => try_insert(&mut self.location, value, span, "#[spirv(location)]"), Flat => try_insert(&mut self.flat, (), span, "#[spirv(flat)]"), Invariant => try_insert(&mut self.invariant, (), span, "#[spirv(invariant)]"), PerPrimitiveExt => try_insert( @@ -323,6 +326,7 @@ impl CheckSpirvAttrVisitor<'_> { | SpirvAttribute::Builtin(_) | SpirvAttribute::DescriptorSet(_) | SpirvAttribute::Binding(_) + | SpirvAttribute::Location(_) | SpirvAttribute::Flat | SpirvAttribute::Invariant | SpirvAttribute::PerPrimitiveExt @@ -602,6 +606,8 @@ fn parse_spirv_attr<'a>( SpirvAttribute::DescriptorSet(parse_attr_int_value(arg)?) } else if arg.has_name(sym.binding) { SpirvAttribute::Binding(parse_attr_int_value(arg)?) + } else if arg.has_name(sym.location) { + SpirvAttribute::Location(parse_attr_int_value(arg)?) } else if arg.has_name(sym.input_attachment_index) { SpirvAttribute::InputAttachmentIndex(parse_attr_int_value(arg)?) } else if arg.has_name(sym.spec_constant) { diff --git a/crates/rustc_codegen_spirv/src/codegen_cx/entry.rs b/crates/rustc_codegen_spirv/src/codegen_cx/entry.rs index 0c16adfd6c..2f36fdcab9 100644 --- a/crates/rustc_codegen_spirv/src/codegen_cx/entry.rs +++ b/crates/rustc_codegen_spirv/src/codegen_cx/entry.rs @@ -710,6 +710,41 @@ impl<'tcx> CodegenCx<'tcx> { .name(var_id.or(spec_const_id).unwrap(), ident.to_string()); } + // location assignment + // Note(@firestar99): UniformConstant are things like `SampledImage`, `StorageImage`, `Sampler` and + // `Acceleration structure`. Almost always they are assigned a `descriptor_set` and binding, thus never end up + // here being assigned locations. I think this is one of those occasions where spirv allows us to assign + // locations, but the "client API" Vulkan doesn't describe any use-case for them, or at least none I'm aware of. + // A quick scour through the spec revealed that `VK_KHR_dynamic_rendering_local_read` may need this, and while + // we don't support it yet (I assume), I'll just keep it here in case it becomes useful in the future. + let has_location = matches!( + storage_class, + Ok(StorageClass::Input | StorageClass::Output | StorageClass::UniformConstant) + ); + let mut assign_location = |var_id: Result, explicit: Option| { + let location = decoration_locations + .entry(storage_class.unwrap()) + .or_insert_with(|| 0); + if let Some(explicit) = explicit { + *location = explicit; + } + self.emit_global().decorate( + var_id.unwrap(), + Decoration::Location, + std::iter::once(Operand::LiteralBit32(*location)), + ); + let spirv_type = self.lookup_type(value_spirv_type); + if let Some(location_size) = spirv_type.location_size(self) { + *location += location_size; + } else { + *location += 1; + self.tcx.dcx().span_err( + hir_param.ty_span, + "Type not supported in Input or Output declarations", + ); + } + }; + // Emit `OpDecorate`s based on attributes. let mut decoration_supersedes_location = false; if let Some(builtin) = attrs.builtin { @@ -757,6 +792,35 @@ impl<'tcx> CodegenCx<'tcx> { ); decoration_supersedes_location = true; } + if let Some(location) = attrs.location { + if let Err(SpecConstant { .. }) = storage_class { + self.tcx.dcx().span_fatal( + location.span, + "`#[spirv(location = ...)]` cannot apply to `#[spirv(spec_constant)]`", + ); + } + if attrs.descriptor_set.is_some() { + self.tcx.dcx().span_fatal( + location.span, + "`#[spirv(location = ...)]` cannot be combined with `#[spirv(descriptor_set = ...)]`", + ); + } + if attrs.binding.is_some() { + self.tcx.dcx().span_fatal( + location.span, + "`#[spirv(location = ...)]` cannot be combined with `#[spirv(binding = ...)]`", + ); + } + if !has_location { + self.tcx.dcx().span_fatal( + location.span, + "`#[spirv(location = ...)]` can only be used on Inputs (declared as plain values, eg. `Vec4`)\ + or Outputs (declared as mut ref, eg. `&mut Vec4`)", + ); + } + assign_location(var_id, Some(location.value)); + decoration_supersedes_location = true; + } if let Some(flat) = attrs.flat { if let Err(SpecConstant { .. }) = storage_class { self.tcx.dcx().span_fatal( @@ -867,21 +931,8 @@ impl<'tcx> CodegenCx<'tcx> { // individually. // TODO: Is this right for UniformConstant? Do they share locations with // input/outpus? - let has_location = !decoration_supersedes_location - && matches!( - storage_class, - Ok(StorageClass::Input | StorageClass::Output | StorageClass::UniformConstant) - ); - if has_location { - let location = decoration_locations - .entry(storage_class.unwrap()) - .or_insert_with(|| 0); - self.emit_global().decorate( - var_id.unwrap(), - Decoration::Location, - std::iter::once(Operand::LiteralBit32(*location)), - ); - *location += 1; + if !decoration_supersedes_location && has_location { + assign_location(var_id, None); } match storage_class { diff --git a/crates/rustc_codegen_spirv/src/spirv_type.rs b/crates/rustc_codegen_spirv/src/spirv_type.rs index c2d85dcbac..d1e50d7ce5 100644 --- a/crates/rustc_codegen_spirv/src/spirv_type.rs +++ b/crates/rustc_codegen_spirv/src/spirv_type.rs @@ -276,6 +276,34 @@ impl SpirvType<'_> { id } + /// Returns how many Input / Output `location`s this type occupies, or None if this type is not allowed to be sent. + /// + /// See [Vulkan Spec 16.1.4. Location and Component Assignment](https://registry.khronos.org/vulkan/specs/latest/html/vkspec.html#interfaces-iointerfaces-locations) + #[allow(clippy::match_same_arms)] + pub fn location_size(&self, cx: &CodegenCx<'_>) -> Option { + let result = match *self { + // bools cannot be in an Input / Output interface + Self::Bool => return None, + Self::Integer(_, _) | Self::Float(_) => 1, + Self::Vector { .. } => 1, + Self::Adt { field_types, .. } => { + let mut locations = 0; + for f in field_types { + locations += cx.lookup_type(*f).location_size(cx)?; + } + locations + } + Self::Matrix { element, count } => cx.lookup_type(element).location_size(cx)? * count, + Self::Array { element, count } => { + let count = cx.builder.lookup_const_scalar(count).unwrap(); + let count: u32 = count.try_into().unwrap(); + cx.lookup_type(element).location_size(cx)? * count + } + _ => return None, + }; + Some(result) + } + pub fn sizeof(&self, cx: &CodegenCx<'_>) -> Option { let result = match *self { // Types that have a dynamic size, or no concept of size at all. @@ -287,12 +315,9 @@ impl SpirvType<'_> { Self::Vector { size, .. } => size, Self::Matrix { element, count } => cx.lookup_type(element).sizeof(cx)? * count as u64, Self::Array { element, count } => { - cx.lookup_type(element).sizeof(cx)? - * cx.builder - .lookup_const_scalar(count) - .unwrap() - .try_into() - .unwrap() + let count = cx.builder.lookup_const_scalar(count).unwrap(); + let count = count.try_into().unwrap(); + cx.lookup_type(element).sizeof(cx)? * count } Self::Pointer { .. } => cx.tcx.data_layout.pointer_size, Self::Image { .. } diff --git a/crates/rustc_codegen_spirv/src/symbols.rs b/crates/rustc_codegen_spirv/src/symbols.rs index e81f1bb7ad..7660f37b5a 100644 --- a/crates/rustc_codegen_spirv/src/symbols.rs +++ b/crates/rustc_codegen_spirv/src/symbols.rs @@ -23,6 +23,7 @@ pub struct Symbols { pub descriptor_set: Symbol, pub binding: Symbol, + pub location: Symbol, pub input_attachment_index: Symbol, pub spec_constant: Symbol, @@ -420,6 +421,7 @@ impl Symbols { descriptor_set: Symbol::intern("descriptor_set"), binding: Symbol::intern("binding"), + location: Symbol::intern("location"), input_attachment_index: Symbol::intern("input_attachment_index"), spec_constant: Symbol::intern("spec_constant"), diff --git a/tests/compiletests/ui/lang/core/ptr/allocate_const_scalar.stderr b/tests/compiletests/ui/lang/core/ptr/allocate_const_scalar.stderr index aac0775325..c3b0b1a8b8 100644 --- a/tests/compiletests/ui/lang/core/ptr/allocate_const_scalar.stderr +++ b/tests/compiletests/ui/lang/core/ptr/allocate_const_scalar.stderr @@ -7,18 +7,11 @@ LL | #![feature(ptr_internals)] = note: using it is strongly discouraged = note: `#[warn(internal_features)]` on by default -error: pointer has non-null integer address - | -note: used from within `allocate_const_scalar::main` - --> $DIR/allocate_const_scalar.rs:16:5 - | -LL | *output = POINTER; - | ^^^^^^^^^^^^^^^^^ -note: called by `main` - --> $DIR/allocate_const_scalar.rs:15:8 +error: Type not supported in Input or Output declarations + --> $DIR/allocate_const_scalar.rs:15:21 | LL | pub fn main(output: &mut Unique<()>) { - | ^^^^ + | ^^^^^^^^^^^^^^^ error: aborting due to 1 previous error; 1 warning emitted diff --git a/tests/compiletests/ui/spirv-attr/bad-deduce-storage-class.rs b/tests/compiletests/ui/spirv-attr/bad-deduce-storage-class.rs index ef1a523ecf..ec6ce8cd5c 100644 --- a/tests/compiletests/ui/spirv-attr/bad-deduce-storage-class.rs +++ b/tests/compiletests/ui/spirv-attr/bad-deduce-storage-class.rs @@ -5,11 +5,11 @@ use spirv_std::{Image, spirv}; #[spirv(vertex)] pub fn main( - #[spirv(uniform)] error: &Image!(2D, type=f32), - #[spirv(uniform_constant)] warning: &Image!(2D, type=f32), + #[spirv(descriptor_set = 0, binding = 0, uniform)] error: &Image!(2D, type=f32), + #[spirv(descriptor_set = 0, binding = 1, uniform_constant)] warning: &Image!(2D, type=f32), ) { } // https://github.com/EmbarkStudios/rust-gpu/issues/585 #[spirv(vertex)] -pub fn issue_585(invalid: Image!(2D, type=f32)) {} +pub fn issue_585(#[spirv(descriptor_set = 0, binding = 0)] invalid: Image!(2D, type=f32)) {} diff --git a/tests/compiletests/ui/spirv-attr/bad-deduce-storage-class.stderr b/tests/compiletests/ui/spirv-attr/bad-deduce-storage-class.stderr index b98d2e98a8..68bff7bf19 100644 --- a/tests/compiletests/ui/spirv-attr/bad-deduce-storage-class.stderr +++ b/tests/compiletests/ui/spirv-attr/bad-deduce-storage-class.stderr @@ -1,25 +1,25 @@ error: storage class mismatch --> $DIR/bad-deduce-storage-class.rs:8:5 | -LL | #[spirv(uniform)] error: &Image!(2D, type=f32), - | ^^^^^^^^-------^^^^^^^^^^--------------------- - | | | - | | `UniformConstant` deduced from type - | `Uniform` specified in attribute +LL | #[spirv(descriptor_set = 0, binding = 0, uniform)] error: &Image!(2D, type=f32), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-------^^^^^^^^^^--------------------- + | | | + | | `UniformConstant` deduced from type + | `Uniform` specified in attribute | = help: remove storage class attribute to use `UniformConstant` as storage class warning: redundant storage class attribute, storage class is deduced from type - --> $DIR/bad-deduce-storage-class.rs:9:13 + --> $DIR/bad-deduce-storage-class.rs:9:46 | -LL | #[spirv(uniform_constant)] warning: &Image!(2D, type=f32), - | ^^^^^^^^^^^^^^^^ +LL | #[spirv(descriptor_set = 0, binding = 1, uniform_constant)] warning: &Image!(2D, type=f32), + | ^^^^^^^^^^^^^^^^ error: entry parameter type must be by-reference: `&spirv_std::image::Image` - --> $DIR/bad-deduce-storage-class.rs:15:27 + --> $DIR/bad-deduce-storage-class.rs:15:69 | -LL | pub fn issue_585(invalid: Image!(2D, type=f32)) {} - | ^^^^^^^^^^^^^^^^^^^^ +LL | pub fn issue_585(#[spirv(descriptor_set = 0, binding = 0)] invalid: Image!(2D, type=f32)) {} + | ^^^^^^^^^^^^^^^^^^^^ | = note: this error originates in the macro `Image` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/compiletests/ui/spirv-attr/bool-inputs-err.stderr b/tests/compiletests/ui/spirv-attr/bool-inputs-err.stderr index 8a08baf3eb..b65854c934 100644 --- a/tests/compiletests/ui/spirv-attr/bool-inputs-err.stderr +++ b/tests/compiletests/ui/spirv-attr/bool-inputs-err.stderr @@ -4,12 +4,24 @@ error: entry-point parameter cannot contain `bool`s LL | input: bool, | ^^^^ +error: Type not supported in Input or Output declarations + --> $DIR/bool-inputs-err.rs:13:12 + | +LL | input: bool, + | ^^^^ + error: entry-point parameter cannot contain `bool`s --> $DIR/bool-inputs-err.rs:14:13 | LL | output: &mut bool, | ^^^^^^^^^ +error: Type not supported in Input or Output declarations + --> $DIR/bool-inputs-err.rs:14:13 + | +LL | output: &mut bool, + | ^^^^^^^^^ + error: entry-point parameter cannot contain `bool`s --> $DIR/bool-inputs-err.rs:15:35 | @@ -22,5 +34,5 @@ error: entry-point parameter cannot contain `bool`s LL | #[spirv(uniform)] uniform: &Boolthing, | ^^^^^^^^^^ -error: aborting due to 4 previous errors +error: aborting due to 6 previous errors diff --git a/tests/compiletests/ui/spirv-attr/location_assignment.rs b/tests/compiletests/ui/spirv-attr/location_assignment.rs new file mode 100644 index 0000000000..d11bb8f810 --- /dev/null +++ b/tests/compiletests/ui/spirv-attr/location_assignment.rs @@ -0,0 +1,31 @@ +// build-pass +// compile-flags: -C llvm-args=--disassemble +// normalize-stderr-test "OpSource .*\n" -> "" +// normalize-stderr-test "OpLine .*\n" -> "" +// normalize-stderr-test "%\d+ = OpString .*\n" -> "" +// normalize-stderr-test "; .*\n" -> "" +// normalize-stderr-test "OpCapability VulkanMemoryModel\n" -> "" +// normalize-stderr-test "OpMemoryModel Logical Vulkan" -> "OpMemoryModel Logical Simple" +// ignore-spv1.0 +// ignore-spv1.1 +// ignore-spv1.2 +// ignore-spv1.3 +// ignore-vulkan1.0 +// ignore-vulkan1.1 + +use spirv_std::glam::*; +use spirv_std::{Image, spirv}; + +#[derive(Copy, Clone, Default)] +pub struct LargerThanVec4 { + a: Vec4, + b: Vec2, +} + +#[spirv(vertex)] +pub fn main(out1: &mut LargerThanVec4, out2: &mut Vec2, out3: &mut Mat4, out4: &mut f32) { + *out1 = Default::default(); + *out2 = Default::default(); + *out3 = Default::default(); + *out4 = Default::default(); +} diff --git a/tests/compiletests/ui/spirv-attr/location_assignment.stderr b/tests/compiletests/ui/spirv-attr/location_assignment.stderr new file mode 100644 index 0000000000..8753619811 --- /dev/null +++ b/tests/compiletests/ui/spirv-attr/location_assignment.stderr @@ -0,0 +1,70 @@ +OpCapability Shader +OpMemoryModel Logical Simple +OpEntryPoint Vertex %1 "main" %2 %3 %4 %5 +OpName %7 "LargerThanVec4" +OpMemberName %7 0 "a" +OpMemberName %7 1 "b" +OpName %8 "spirv_std::glam::Mat4" +OpMemberName %8 0 "x_axis" +OpMemberName %8 1 "y_axis" +OpMemberName %8 2 "z_axis" +OpMemberName %8 3 "w_axis" +OpName %9 "LargerThanVec4" +OpMemberName %9 0 "a" +OpMemberName %9 1 "b" +OpName %2 "out1" +OpName %3 "out2" +OpName %4 "out3" +OpName %5 "out4" +OpMemberDecorate %9 0 Offset 0 +OpMemberDecorate %9 1 Offset 16 +OpDecorate %2 Location 0 +OpDecorate %3 Location 2 +OpDecorate %4 Location 3 +OpDecorate %5 Location 7 +%10 = OpTypeFloat 32 +%11 = OpTypeVector %10 4 +%12 = OpTypeVector %10 2 +%7 = OpTypeStruct %11 %12 +%13 = OpTypePointer Output %7 +%14 = OpTypePointer Output %12 +%8 = OpTypeStruct %11 %11 %11 %11 +%15 = OpTypePointer Output %8 +%16 = OpTypePointer Output %10 +%17 = OpTypeVoid +%18 = OpTypeFunction %17 +%9 = OpTypeStruct %11 %12 +%19 = OpConstant %10 0 +%20 = OpConstantComposite %11 %19 %19 %19 %19 +%21 = OpUndef %9 +%2 = OpVariable %13 Output +%3 = OpVariable %14 Output +%22 = OpTypeInt 32 0 +%23 = OpConstant %22 0 +%24 = OpConstant %22 1 +%4 = OpVariable %15 Output +%25 = OpConstant %10 1 +%26 = OpConstantComposite %11 %25 %19 %19 %19 +%27 = OpConstantComposite %11 %19 %25 %19 %19 +%28 = OpConstantComposite %11 %19 %19 %25 %19 +%29 = OpConstantComposite %11 %19 %19 %19 %25 +%30 = OpConstantComposite %8 %26 %27 %28 %29 +%5 = OpVariable %16 Output +%1 = OpFunction %17 None %18 +%31 = OpLabel +%32 = OpCompositeInsert %9 %20 %21 0 +%33 = OpCompositeInsert %9 %19 %32 1 0 +%34 = OpCompositeInsert %9 %19 %33 1 1 +%35 = OpCompositeExtract %11 %34 0 +%36 = OpCompositeExtract %12 %34 1 +%37 = OpCompositeConstruct %7 %35 %36 +OpStore %2 %37 +%38 = OpInBoundsAccessChain %16 %3 %23 +OpStore %38 %19 +%39 = OpInBoundsAccessChain %16 %3 %24 +OpStore %39 %19 +OpStore %4 %30 +OpStore %5 %19 +OpNoLine +OpReturn +OpFunctionEnd diff --git a/tests/compiletests/ui/spirv-attr/location_assignment_array_f32.rs b/tests/compiletests/ui/spirv-attr/location_assignment_array_f32.rs new file mode 100644 index 0000000000..c643a45e4b --- /dev/null +++ b/tests/compiletests/ui/spirv-attr/location_assignment_array_f32.rs @@ -0,0 +1,23 @@ +// build-pass +// compile-flags: -C llvm-args=--disassemble +// normalize-stderr-test "OpSource .*\n" -> "" +// normalize-stderr-test "OpLine .*\n" -> "" +// normalize-stderr-test "%\d+ = OpString .*\n" -> "" +// normalize-stderr-test "; .*\n" -> "" +// normalize-stderr-test "OpCapability VulkanMemoryModel\n" -> "" +// normalize-stderr-test "OpMemoryModel Logical Vulkan" -> "OpMemoryModel Logical Simple" +// ignore-spv1.0 +// ignore-spv1.1 +// ignore-spv1.2 +// ignore-spv1.3 +// ignore-vulkan1.0 +// ignore-vulkan1.1 + +use spirv_std::glam::*; +use spirv_std::{Image, spirv}; + +#[spirv(vertex)] +pub fn main(out1: &mut [f32; 3], out2: &mut f32) { + *out1 = Default::default(); + *out2 = Default::default(); +} diff --git a/tests/compiletests/ui/spirv-attr/location_assignment_array_f32.stderr b/tests/compiletests/ui/spirv-attr/location_assignment_array_f32.stderr new file mode 100644 index 0000000000..c73ab9c004 --- /dev/null +++ b/tests/compiletests/ui/spirv-attr/location_assignment_array_f32.stderr @@ -0,0 +1,39 @@ +OpCapability Shader +OpMemoryModel Logical Simple +OpEntryPoint Vertex %1 "main" %2 %3 +OpName %2 "out1" +OpName %3 "out2" +OpName %6 "<[f32OpDecorate %7 ArrayStride 4 +OpDecorate %2 Location 0 +OpDecorate %3 Location 3 +%8 = OpTypeFloat 32 +%9 = OpTypeInt 32 0 +%10 = OpConstant %9 3 +%11 = OpTypeArray %8 %10 +%12 = OpTypePointer Output %11 +%13 = OpTypePointer Output %8 +%14 = OpTypeVoid +%15 = OpTypeFunction %14 +%7 = OpTypeArray %8 %10 +%16 = OpTypeFunction %7 +%17 = OpConstant %8 0 +%2 = OpVariable %12 Output +%3 = OpVariable %13 Output +%1 = OpFunction %14 None %15 +%18 = OpLabel +%19 = OpFunctionCall %7 %6 +%20 = OpCompositeExtract %8 %19 0 +%21 = OpCompositeExtract %8 %19 1 +%22 = OpCompositeExtract %8 %19 2 +%23 = OpCompositeConstruct %11 %20 %21 %22 +OpStore %2 %23 +OpStore %3 %17 +OpNoLine +OpReturn +OpFunctionEnd +%6 = OpFunction %7 None %16 +%24 = OpLabel +%25 = OpCompositeConstruct %7 %17 %17 %17 +OpNoLine +OpReturnValue %25 +OpFunctionEnd diff --git a/tests/compiletests/ui/spirv-attr/location_assignment_explicit.rs b/tests/compiletests/ui/spirv-attr/location_assignment_explicit.rs new file mode 100644 index 0000000000..4f25e131ee --- /dev/null +++ b/tests/compiletests/ui/spirv-attr/location_assignment_explicit.rs @@ -0,0 +1,37 @@ +// build-pass +// compile-flags: -C llvm-args=--disassemble +// normalize-stderr-test "OpSource .*\n" -> "" +// normalize-stderr-test "OpLine .*\n" -> "" +// normalize-stderr-test "%\d+ = OpString .*\n" -> "" +// normalize-stderr-test "; .*\n" -> "" +// normalize-stderr-test "OpCapability VulkanMemoryModel\n" -> "" +// normalize-stderr-test "OpMemoryModel Logical Vulkan" -> "OpMemoryModel Logical Simple" +// ignore-spv1.0 +// ignore-spv1.1 +// ignore-spv1.2 +// ignore-spv1.3 +// ignore-vulkan1.0 +// ignore-vulkan1.1 + +use spirv_std::glam::*; +use spirv_std::{Image, spirv}; + +#[derive(Copy, Clone, Default)] +pub struct LargerThanVec4 { + a: Vec4, + b: Vec2, +} + +#[spirv(vertex)] +pub fn main( + #[spirv(location = 4)] out1: &mut LargerThanVec4, + out2: &mut Vec2, // should be 6 + #[spirv(location = 0)] out3: &mut Mat4, + // 8 to 11 are unused, that's fine + #[spirv(location = 12)] out4: &mut f32, +) { + *out1 = Default::default(); + *out2 = Default::default(); + *out3 = Default::default(); + *out4 = Default::default(); +} diff --git a/tests/compiletests/ui/spirv-attr/location_assignment_explicit.stderr b/tests/compiletests/ui/spirv-attr/location_assignment_explicit.stderr new file mode 100644 index 0000000000..b6c1ac8302 --- /dev/null +++ b/tests/compiletests/ui/spirv-attr/location_assignment_explicit.stderr @@ -0,0 +1,70 @@ +OpCapability Shader +OpMemoryModel Logical Simple +OpEntryPoint Vertex %1 "main" %2 %3 %4 %5 +OpName %7 "LargerThanVec4" +OpMemberName %7 0 "a" +OpMemberName %7 1 "b" +OpName %8 "spirv_std::glam::Mat4" +OpMemberName %8 0 "x_axis" +OpMemberName %8 1 "y_axis" +OpMemberName %8 2 "z_axis" +OpMemberName %8 3 "w_axis" +OpName %9 "LargerThanVec4" +OpMemberName %9 0 "a" +OpMemberName %9 1 "b" +OpName %2 "out1" +OpName %3 "out2" +OpName %4 "out3" +OpName %5 "out4" +OpMemberDecorate %9 0 Offset 0 +OpMemberDecorate %9 1 Offset 16 +OpDecorate %2 Location 4 +OpDecorate %3 Location 6 +OpDecorate %4 Location 0 +OpDecorate %5 Location 12 +%10 = OpTypeFloat 32 +%11 = OpTypeVector %10 4 +%12 = OpTypeVector %10 2 +%7 = OpTypeStruct %11 %12 +%13 = OpTypePointer Output %7 +%14 = OpTypePointer Output %12 +%8 = OpTypeStruct %11 %11 %11 %11 +%15 = OpTypePointer Output %8 +%16 = OpTypePointer Output %10 +%17 = OpTypeVoid +%18 = OpTypeFunction %17 +%9 = OpTypeStruct %11 %12 +%19 = OpConstant %10 0 +%20 = OpConstantComposite %11 %19 %19 %19 %19 +%21 = OpUndef %9 +%2 = OpVariable %13 Output +%3 = OpVariable %14 Output +%22 = OpTypeInt 32 0 +%23 = OpConstant %22 0 +%24 = OpConstant %22 1 +%4 = OpVariable %15 Output +%25 = OpConstant %10 1 +%26 = OpConstantComposite %11 %25 %19 %19 %19 +%27 = OpConstantComposite %11 %19 %25 %19 %19 +%28 = OpConstantComposite %11 %19 %19 %25 %19 +%29 = OpConstantComposite %11 %19 %19 %19 %25 +%30 = OpConstantComposite %8 %26 %27 %28 %29 +%5 = OpVariable %16 Output +%1 = OpFunction %17 None %18 +%31 = OpLabel +%32 = OpCompositeInsert %9 %20 %21 0 +%33 = OpCompositeInsert %9 %19 %32 1 0 +%34 = OpCompositeInsert %9 %19 %33 1 1 +%35 = OpCompositeExtract %11 %34 0 +%36 = OpCompositeExtract %12 %34 1 +%37 = OpCompositeConstruct %7 %35 %36 +OpStore %2 %37 +%38 = OpInBoundsAccessChain %16 %3 %23 +OpStore %38 %19 +%39 = OpInBoundsAccessChain %16 %3 %24 +OpStore %39 %19 +OpStore %4 %30 +OpStore %5 %19 +OpNoLine +OpReturn +OpFunctionEnd diff --git a/tests/compiletests/ui/spirv-attr/location_assignment_explicit_overlap.rs b/tests/compiletests/ui/spirv-attr/location_assignment_explicit_overlap.rs new file mode 100644 index 0000000000..2181f3c5ad --- /dev/null +++ b/tests/compiletests/ui/spirv-attr/location_assignment_explicit_overlap.rs @@ -0,0 +1,27 @@ +// build-fail +// compile-flags: -C llvm-args=--disassemble +// normalize-stderr-test "OpSource .*\n" -> "" +// normalize-stderr-test "OpLine .*\n" -> "" +// normalize-stderr-test "%\d+ = OpString .*\n" -> "" +// normalize-stderr-test "; .*\n" -> "" +// normalize-stderr-test "OpCapability VulkanMemoryModel\n" -> "" +// normalize-stderr-test "OpMemoryModel Logical Vulkan" -> "OpMemoryModel Logical Simple" +// normalize-stderr-test "= note: module `.*`" -> "= note: module ``" +// ignore-spv1.0 +// ignore-spv1.1 +// ignore-spv1.2 +// ignore-spv1.3 +// ignore-spv1.4 +// ignore-spv1.5 +// ignore-spv1.6 +// ignore-vulkan1.0 +// ignore-vulkan1.1 + +use spirv_std::glam::*; +use spirv_std::{Image, spirv}; + +#[spirv(vertex)] +pub fn main(#[spirv(location = 0)] out1: &mut Mat4, #[spirv(location = 1)] out2: &mut Vec2) { + *out1 = Default::default(); + *out2 = Default::default(); +} diff --git a/tests/compiletests/ui/spirv-attr/location_assignment_explicit_overlap.stderr b/tests/compiletests/ui/spirv-attr/location_assignment_explicit_overlap.stderr new file mode 100644 index 0000000000..dbde616b1c --- /dev/null +++ b/tests/compiletests/ui/spirv-attr/location_assignment_explicit_overlap.stderr @@ -0,0 +1,51 @@ +OpCapability Shader +OpMemoryModel Logical Simple +OpEntryPoint Vertex %1 "main" %2 %3 +OpName %5 "spirv_std::glam::Mat4" +OpMemberName %5 0 "x_axis" +OpMemberName %5 1 "y_axis" +OpMemberName %5 2 "z_axis" +OpMemberName %5 3 "w_axis" +OpName %2 "out1" +OpName %3 "out2" +OpDecorate %2 Location 0 +OpDecorate %3 Location 1 +%6 = OpTypeFloat 32 +%7 = OpTypeVector %6 4 +%5 = OpTypeStruct %7 %7 %7 %7 +%8 = OpTypePointer Output %5 +%9 = OpTypeVector %6 2 +%10 = OpTypePointer Output %9 +%11 = OpTypeVoid +%12 = OpTypeFunction %11 +%2 = OpVariable %8 Output +%13 = OpConstant %6 1 +%14 = OpConstant %6 0 +%15 = OpConstantComposite %7 %13 %14 %14 %14 +%16 = OpConstantComposite %7 %14 %13 %14 %14 +%17 = OpConstantComposite %7 %14 %14 %13 %14 +%18 = OpConstantComposite %7 %14 %14 %14 %13 +%19 = OpConstantComposite %5 %15 %16 %17 %18 +%20 = OpTypePointer Output %6 +%3 = OpVariable %10 Output +%21 = OpTypeInt 32 0 +%22 = OpConstant %21 0 +%23 = OpConstant %21 1 +%1 = OpFunction %11 None %12 +%24 = OpLabel +OpStore %2 %19 +%25 = OpInBoundsAccessChain %20 %3 %22 +OpStore %25 %14 +%26 = OpInBoundsAccessChain %20 %3 %23 +OpStore %26 %14 +OpNoLine +OpReturn +OpFunctionEnd +error: error:0:0 - [VUID-StandaloneSpirv-OpEntryPoint-08722] Entry-point has conflicting output location assignment at location 1, component 0 + OpEntryPoint Vertex %1 "main" %out1 %out2 + | + = note: spirv-val failed + = note: module `` + +error: aborting due to 1 previous error + diff --git a/tests/compiletests/ui/spirv-attr/location_assignment_many_f32_struct.rs b/tests/compiletests/ui/spirv-attr/location_assignment_many_f32_struct.rs new file mode 100644 index 0000000000..ffc4ea4fac --- /dev/null +++ b/tests/compiletests/ui/spirv-attr/location_assignment_many_f32_struct.rs @@ -0,0 +1,34 @@ +// build-pass +// compile-flags: -C llvm-args=--scalar-block-layout -C llvm-args=--disassemble +// normalize-stderr-test "OpSource .*\n" -> "" +// normalize-stderr-test "OpLine .*\n" -> "" +// normalize-stderr-test "%\d+ = OpString .*\n" -> "" +// normalize-stderr-test "; .*\n" -> "" +// normalize-stderr-test "OpCapability VulkanMemoryModel\n" -> "" +// normalize-stderr-test "OpMemoryModel Logical Vulkan" -> "OpMemoryModel Logical Simple" +// ignore-spv1.0 +// ignore-spv1.1 +// ignore-spv1.2 +// ignore-spv1.3 +// ignore-vulkan1.0 +// ignore-vulkan1.1 + +use spirv_std::glam::*; +use spirv_std::{Image, spirv}; + +#[repr(C)] +#[derive(Copy, Clone, Default)] +pub struct ManyFloats { + a: f32, + b: f32, + c: f32, +} + +#[spirv(vertex)] +pub fn main(out1: &mut ManyFloats, out2: &mut f32) { + const { + assert!(size_of::() == 12); + } + *out1 = Default::default(); + *out2 = Default::default(); +} diff --git a/tests/compiletests/ui/spirv-attr/location_assignment_many_f32_struct.stderr b/tests/compiletests/ui/spirv-attr/location_assignment_many_f32_struct.stderr new file mode 100644 index 0000000000..77faad8497 --- /dev/null +++ b/tests/compiletests/ui/spirv-attr/location_assignment_many_f32_struct.stderr @@ -0,0 +1,40 @@ +OpCapability Shader +OpMemoryModel Logical Simple +OpEntryPoint Vertex %1 "main" %2 %3 +OpName %5 "ManyFloats" +OpMemberName %5 0 "a" +OpMemberName %5 1 "b" +OpMemberName %5 2 "c" +OpName %6 "ManyFloats" +OpMemberName %6 0 "a" +OpMemberName %6 1 "b" +OpMemberName %6 2 "c" +OpName %2 "out1" +OpName %3 "out2" +OpMemberDecorate %6 0 Offset 0 +OpMemberDecorate %6 1 Offset 4 +OpMemberDecorate %6 2 Offset 8 +OpDecorate %2 Location 0 +OpDecorate %3 Location 3 +%7 = OpTypeFloat 32 +%5 = OpTypeStruct %7 %7 %7 +%8 = OpTypePointer Output %5 +%9 = OpTypePointer Output %7 +%10 = OpTypeVoid +%11 = OpTypeFunction %10 +%6 = OpTypeStruct %7 %7 %7 +%12 = OpConstant %7 0 +%2 = OpVariable %8 Output +%3 = OpVariable %9 Output +%1 = OpFunction %10 None %11 +%13 = OpLabel +%14 = OpCompositeConstruct %6 %12 %12 %12 +%15 = OpCompositeExtract %7 %14 0 +%16 = OpCompositeExtract %7 %14 1 +%17 = OpCompositeExtract %7 %14 2 +%18 = OpCompositeConstruct %5 %15 %16 %17 +OpStore %2 %18 +OpStore %3 %12 +OpNoLine +OpReturn +OpFunctionEnd diff --git a/tests/compiletests/ui/spirv-attr/location_assignment_vec3_f32.rs b/tests/compiletests/ui/spirv-attr/location_assignment_vec3_f32.rs new file mode 100644 index 0000000000..0a7d754e26 --- /dev/null +++ b/tests/compiletests/ui/spirv-attr/location_assignment_vec3_f32.rs @@ -0,0 +1,33 @@ +// build-pass +// compile-flags: -C llvm-args=--disassemble +// normalize-stderr-test "OpSource .*\n" -> "" +// normalize-stderr-test "OpLine .*\n" -> "" +// normalize-stderr-test "%\d+ = OpString .*\n" -> "" +// normalize-stderr-test "; .*\n" -> "" +// normalize-stderr-test "OpCapability VulkanMemoryModel\n" -> "" +// normalize-stderr-test "OpMemoryModel Logical Vulkan" -> "OpMemoryModel Logical Simple" +// ignore-spv1.0 +// ignore-spv1.1 +// ignore-spv1.2 +// ignore-spv1.3 +// ignore-vulkan1.0 +// ignore-vulkan1.1 + +use spirv_std::glam::*; +use spirv_std::{Image, spirv}; + +#[repr(C)] +#[derive(Copy, Clone, Default)] +pub struct Vec3AndFloat { + a: Vec3, + b: f32, +} + +#[spirv(vertex)] +pub fn main(out1: &mut Vec3AndFloat, out2: &mut f32) { + const { + assert!(size_of::() == 16); + } + *out1 = Default::default(); + *out2 = Default::default(); +} diff --git a/tests/compiletests/ui/spirv-attr/location_assignment_vec3_f32.stderr b/tests/compiletests/ui/spirv-attr/location_assignment_vec3_f32.stderr new file mode 100644 index 0000000000..3ff48a28c3 --- /dev/null +++ b/tests/compiletests/ui/spirv-attr/location_assignment_vec3_f32.stderr @@ -0,0 +1,38 @@ +OpCapability Shader +OpMemoryModel Logical Simple +OpEntryPoint Vertex %1 "main" %2 %3 +OpName %5 "Vec3AndFloat" +OpMemberName %5 0 "a" +OpMemberName %5 1 "b" +OpName %6 "Vec3AndFloat" +OpMemberName %6 0 "a" +OpMemberName %6 1 "b" +OpName %2 "out1" +OpName %3 "out2" +OpMemberDecorate %6 0 Offset 0 +OpMemberDecorate %6 1 Offset 12 +OpDecorate %2 Location 0 +OpDecorate %3 Location 2 +%7 = OpTypeFloat 32 +%8 = OpTypeVector %7 3 +%5 = OpTypeStruct %8 %7 +%9 = OpTypePointer Output %5 +%10 = OpTypePointer Output %7 +%11 = OpTypeVoid +%12 = OpTypeFunction %11 +%6 = OpTypeStruct %8 %7 +%13 = OpConstant %7 0 +%14 = OpConstantComposite %8 %13 %13 %13 +%2 = OpVariable %9 Output +%3 = OpVariable %10 Output +%1 = OpFunction %11 None %12 +%15 = OpLabel +%16 = OpCompositeConstruct %6 %14 %13 +%17 = OpCompositeExtract %8 %16 0 +%18 = OpCompositeExtract %7 %16 1 +%19 = OpCompositeConstruct %5 %17 %18 +OpStore %2 %19 +OpStore %3 %13 +OpNoLine +OpReturn +OpFunctionEnd diff --git a/tests/compiletests/ui/spirv-attr/uniform-constant-storage-class.rs b/tests/compiletests/ui/spirv-attr/uniform-constant-storage-class.rs new file mode 100644 index 0000000000..9ed459fee2 --- /dev/null +++ b/tests/compiletests/ui/spirv-attr/uniform-constant-storage-class.rs @@ -0,0 +1,11 @@ +// build-pass + +use spirv_std::image::Image2d; +use spirv_std::spirv; + +#[spirv(vertex)] +pub fn main( + #[spirv(descriptor_set = 0, binding = 0)] implicit: &Image2d, + #[spirv(descriptor_set = 0, binding = 1, uniform_constant)] explicit: &Image2d, +) { +} diff --git a/tests/compiletests/ui/spirv-attr/uniform-constant-storage-class.stderr b/tests/compiletests/ui/spirv-attr/uniform-constant-storage-class.stderr new file mode 100644 index 0000000000..589df04f32 --- /dev/null +++ b/tests/compiletests/ui/spirv-attr/uniform-constant-storage-class.stderr @@ -0,0 +1,8 @@ +warning: redundant storage class attribute, storage class is deduced from type + --> $DIR/uniform-constant-storage-class.rs:9:46 + | +LL | #[spirv(descriptor_set = 0, binding = 1, uniform_constant)] explicit: &Image2d, + | ^^^^^^^^^^^^^^^^ + +warning: 1 warning emitted +