Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 5 additions & 10 deletions crates/rustc_codegen_spirv/src/builder/builder_methods.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use crate::custom_insts::CustomInst;
use crate::spirv_type::SpirvType;
use itertools::Itertools;
use rspirv::dr::{InsertPoint, Instruction, Operand};
use rspirv::spirv::{Capability, MemoryModel, MemorySemantics, Op, Scope, StorageClass, Word};
use rspirv::spirv::{MemoryModel, MemorySemantics, Op, Scope, StorageClass, Word};
use rustc_abi::{Align, BackendRepr, Scalar, Size, WrappingRange};
use rustc_apfloat::{Float, Round, Status, ieee};
use rustc_codegen_ssa::MemFlags;
Expand Down Expand Up @@ -591,13 +591,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
}

#[instrument(level = "trace", skip(self))]
fn zombie_ptr_equal(&self, def: Word, inst: &str) {
if !self.builder.has_capability(Capability::VariablePointers) {
self.zombie(
def,
&format!("{inst} without OpCapability VariablePointers"),
);
}
fn zombie_ptr_equal(&self, def: Word) {
self.zombie(def, "cannot check pointers for equality");
}

/// Convenience wrapper for `adjust_pointer_for_sized_access`, falling back
Expand Down Expand Up @@ -2596,7 +2591,7 @@ impl<'a, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'tcx> {
self.emit()
.ptr_equal(b, None, lhs.def(self), rhs.def(self))
.inspect(|&result| {
self.zombie_ptr_equal(result, "OpPtrEqual");
self.zombie_ptr_equal(result);
})
} else {
let int_ty = self.type_usize();
Expand All @@ -2618,7 +2613,7 @@ impl<'a, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'tcx> {
self.emit()
.ptr_not_equal(b, None, lhs.def(self), rhs.def(self))
.inspect(|&result| {
self.zombie_ptr_equal(result, "OpPtrNotEqual");
self.zombie_ptr_equal(result);
})
} else {
let int_ty = self.type_usize();
Expand Down
25 changes: 10 additions & 15 deletions crates/rustc_codegen_spirv/src/builder/byte_addressable_buffer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ use crate::builder_spirv::{SpirvValue, SpirvValueExt, SpirvValueKind};
use crate::spirv_type::SpirvType;
use rspirv::spirv::{Decoration, Word};
use rustc_abi::{Align, Size};
use rustc_codegen_spirv_types::Capability;
use rustc_codegen_ssa::traits::BuilderMethods;
use rustc_errors::ErrorGuaranteed;
use rustc_middle::ty::Ty;
Expand Down Expand Up @@ -50,13 +49,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
.in_bounds_access_chain(u32_ptr, None, array, [actual_index])
.unwrap()
.with_type(u32_ptr);
if self.builder.has_capability(Capability::ShaderNonUniform) {
// apply NonUniform to the operation and the index
self.emit()
.decorate(ptr.def(self), Decoration::NonUniform, []);
self.emit()
.decorate(actual_index, Decoration::NonUniform, []);
}
// apply NonUniform to the operation and the index
self.emit()
.decorate(ptr.def(self), Decoration::NonUniform, []);
self.emit()
.decorate(actual_index, Decoration::NonUniform, []);
Comment on lines -53 to +56

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add a test using this feature, but not enabling ShaderNonUniform?

It should trigger a validation error from the new SPIR-T-based validation pass, if I'm not mistaken.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done, works without any issues. I seem to have added tests for everything except ByteAddressableBuffer.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To be clear, I am talking about a test that lacks the ShaderNonUniform capability, and therefore results in an error. If it compiles successfully and contains NonUniform decorations, without the necessary capability, that's a bug IMO.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you look at the tests this PR adds, there's a ByteAddressableBuffer variant with NonUniform capability, and a ByteAddressableBufferUniform variant without, all disassembled so you can diff that and see the the uniform variant missing the OpDecoration %x NonUniform

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But you removed the condition that gates NonUniform on ShaderNonUniform, and the decoration should always be emitted now... is something else removing the NonUniform decorations?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yea, here a linker pass that removes all NonUniform decorations, which has been added in #177 1.5 years ago. I wanted it so I could write just one image access asm! block with all the needed NonUniform decorations, since you can't conditionally exclude an asm line.

self.load(u32_ty, ptr, Align::ONE)
}

Expand Down Expand Up @@ -252,13 +249,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
.in_bounds_access_chain(u32_ptr, None, array, [actual_index])
.unwrap()
.with_type(u32_ptr);
if self.builder.has_capability(Capability::ShaderNonUniform) {
// apply NonUniform to the operation and the index
self.emit()
.decorate(ptr.def(self), Decoration::NonUniform, []);
self.emit()
.decorate(actual_index, Decoration::NonUniform, []);
}
// apply NonUniform to the operation and the index
self.emit()
.decorate(ptr.def(self), Decoration::NonUniform, []);
self.emit()
.decorate(actual_index, Decoration::NonUniform, []);
self.store(value, ptr, Align::ONE);
Ok(())
}
Expand Down
46 changes: 7 additions & 39 deletions crates/rustc_codegen_spirv/src/builder_spirv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,11 @@ use rspirv::{binary::Assemble, binary::Disassemble};
use rustc_abi::Size;
use rustc_arena::DroplessArena;
use rustc_codegen_ssa::traits::ConstCodegenMethods as _;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::fx::FxHashMap;
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;
use rustc_span::{DUMMY_SP, SourceFile, Span};
use std::assert_matches;
use std::cell::{RefCell, RefMut};
Expand Down Expand Up @@ -442,8 +441,6 @@ pub struct BuilderSpirv<'tcx> {
id_to_const: RefCell<FxHashMap<Word, WithConstLegality<SpirvConst<'tcx, 'tcx>>>>,

debug_file_cache: RefCell<FxHashMap<DebugFileKey, DebugFileSpirv<'tcx>>>,

enabled_capabilities: FxHashSet<Capability>,
}

impl<'tcx> BuilderSpirv<'tcx> {
Expand All @@ -460,50 +457,26 @@ impl<'tcx> BuilderSpirv<'tcx> {
builder.set_version(version.0, version.1);
builder.module_mut().header.as_mut().unwrap().generator = 0x001B_0000;

let mut enabled_capabilities = FxHashSet::default();

fn add_cap(
builder: &mut Builder,
enabled_capabilities: &mut FxHashSet<Capability>,
cap: Capability,
) {
// This should be the only callsite of Builder::capability (aside from tests), to make
// sure the hashset stays in sync.
builder.capability(cap);
enabled_capabilities.insert(cap);
}
fn add_ext(builder: &mut Builder, ext: Symbol) {
// This should be the only callsite of Builder::extension (aside from tests), to make
// sure the hashset stays in sync.
builder.extension(ext.as_str());
}

for feature in features {
match *feature {
TargetFeature::Capability(cap) => {
add_cap(&mut builder, &mut enabled_capabilities, cap);
builder.capability(cap);
}
TargetFeature::Extension(ext) => {
add_ext(&mut builder, ext);
builder.extension(ext.as_str());
}
}
}

add_cap(&mut builder, &mut enabled_capabilities, Capability::Shader);
builder.capability(Capability::Shader);
if memory_model == MemoryModel::Vulkan {
if version < SpirvVersion::V1_5 {
add_ext(&mut builder, sym.spv_khr_vulkan_memory_model);
builder.extension(sym.spv_khr_vulkan_memory_model.as_str());
}
add_cap(
&mut builder,
&mut enabled_capabilities,
Capability::VulkanMemoryModel,
);
builder.capability(Capability::VulkanMemoryModel);
}

// The linker will always be ran on this module
add_cap(&mut builder, &mut enabled_capabilities, Capability::Linkage);

builder.capability(Capability::Linkage);
builder.memory_model(AddressingModel::Logical, memory_model);

Self {
Expand All @@ -513,7 +486,6 @@ impl<'tcx> BuilderSpirv<'tcx> {
const_to_id: Default::default(),
id_to_const: Default::default(),
debug_file_cache: Default::default(),
enabled_capabilities,
}
}

Expand All @@ -534,10 +506,6 @@ impl<'tcx> BuilderSpirv<'tcx> {
.unwrap();
}

pub fn has_capability(&self, capability: Capability) -> bool {
self.enabled_capabilities.contains(&capability)
}

/// See comment on `BuilderCursor`
fn builder(&self, cursor: BuilderCursor) -> RefMut<'_, Builder> {
let mut builder = self.builder.borrow_mut();
Expand Down
8 changes: 2 additions & 6 deletions crates/rustc_codegen_spirv/src/codegen_cx/entry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use crate::builder_spirv::{SpirvFunctionCursor, SpirvValue, SpirvValueExt};
use crate::spirv_type::SpirvType;
use rspirv::dr::Operand;
use rspirv::spirv::{
BuiltIn, Capability, Decoration, Dim, ExecutionModel, FunctionControl, StorageClass, Word,
BuiltIn, Decoration, Dim, ExecutionModel, FunctionControl, StorageClass, Word,
};
use rustc_abi::FieldsShape;
use rustc_codegen_ssa::traits::{BaseTypeCodegenMethods, BuilderMethods, MiscCodegenMethods as _};
Expand Down Expand Up @@ -931,16 +931,12 @@ impl<'tcx> CodegenCx<'tcx> {
_ => false,
};
if let Some(attachment_index) = attrs.input_attachment_index {
if is_subpass_input && self.builder.has_capability(Capability::InputAttachment) {
if is_subpass_input {
self.emit_global().decorate(
var_id.unwrap(),
Decoration::InputAttachmentIndex,
std::iter::once(Operand::LiteralBit32(attachment_index.value)),
);
} else if is_subpass_input {
self.tcx
.dcx()
.span_err(hir_param.ty_span, "Missing capability InputAttachment");
} else {
self.tcx.dcx().span_err(
attachment_index.span,
Expand Down
34 changes: 34 additions & 0 deletions tests/compiletests/ui/arch/non_uniform/buffer.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// build-pass
// compile-flags: -C llvm-args=--disassemble
// compile-flags: -C target-feature=+RuntimeDescriptorArray,+StorageBufferArrayDynamicIndexing
// compile-flags: -C target-feature=+ShaderNonUniform,+StorageBufferArrayNonUniformIndexing
// 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-spv1.4
// ignore-vulkan1.0
// ignore-vulkan1.1

use spirv_std::glam::*;
use spirv_std::image::*;
use spirv_std::*;

#[spirv(vertex)]
pub fn main(
index: u32,
#[spirv(descriptor_set = 0, binding = 0, storage_buffer)] buffers: &RuntimeArray<
TypedBuffer<Vec4>,
>,
out: &mut Vec4,
) {
unsafe {
*out = **buffers.index(index as usize);
}
}
44 changes: 44 additions & 0 deletions tests/compiletests/ui/arch/non_uniform/buffer.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
OpCapability Shader
OpCapability StorageBufferArrayDynamicIndexing
OpCapability ShaderNonUniform
OpCapability RuntimeDescriptorArray
OpCapability StorageBufferArrayNonUniformIndexing
OpMemoryModel Logical Simple
OpEntryPoint Vertex %1 "main" %2 %3 %4
OpName %2 "index"
OpName %3 "buffers"
OpName %4 "out"
OpDecorate %8 Block
OpMemberDecorate %8 0 Offset 0
OpDecorate %2 Location 0
OpDecorate %3 NonWritable
OpDecorate %3 Binding 0
OpDecorate %3 DescriptorSet 0
OpDecorate %4 Location 0
OpDecorate %9 NonUniform
%10 = OpTypeInt 32 0
%11 = OpTypePointer Input %10
%12 = OpTypeFloat 32
%13 = OpTypeVector %12 4
%8 = OpTypeStruct %13
%14 = OpTypeRuntimeArray %8
%15 = OpTypePointer StorageBuffer %14
%16 = OpTypePointer Output %13
%17 = OpTypeVoid
%18 = OpTypeFunction %17
%2 = OpVariable %11 Input
%19 = OpTypePointer StorageBuffer %8
%3 = OpVariable %15 StorageBuffer
%20 = OpTypePointer StorageBuffer %13
%21 = OpConstant %10 0
%4 = OpVariable %16 Output
%1 = OpFunction %17 None %18
%22 = OpLabel
%23 = OpLoad %10 %2
%9 = OpAccessChain %19 %3 %23
%24 = OpAccessChain %20 %9 %21
%25 = OpLoad %13 %24
OpStore %4 %25
OpNoLine
OpReturn
OpFunctionEnd
33 changes: 33 additions & 0 deletions tests/compiletests/ui/arch/non_uniform/buffer_uniform.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// build-pass
// compile-flags: -C llvm-args=--disassemble
// compile-flags: -C target-feature=+RuntimeDescriptorArray,+StorageBufferArrayDynamicIndexing
// 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-spv1.4
// ignore-vulkan1.0
// ignore-vulkan1.1

use spirv_std::glam::*;
use spirv_std::image::*;
use spirv_std::*;

#[spirv(vertex)]
pub fn main(
index: u32,
#[spirv(descriptor_set = 0, binding = 0, storage_buffer)] buffers: &RuntimeArray<
TypedBuffer<Vec4>,
>,
out: &mut Vec4,
) {
unsafe {
*out = **buffers.index(index as usize);
}
}
41 changes: 41 additions & 0 deletions tests/compiletests/ui/arch/non_uniform/buffer_uniform.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
OpCapability Shader
OpCapability StorageBufferArrayDynamicIndexing
OpCapability RuntimeDescriptorArray
OpMemoryModel Logical Simple
OpEntryPoint Vertex %1 "main" %2 %3 %4
OpName %2 "index"
OpName %3 "buffers"
OpName %4 "out"
OpDecorate %8 Block
OpMemberDecorate %8 0 Offset 0
OpDecorate %2 Location 0
OpDecorate %3 NonWritable
OpDecorate %3 Binding 0
OpDecorate %3 DescriptorSet 0
OpDecorate %4 Location 0
%9 = OpTypeInt 32 0
%10 = OpTypePointer Input %9
%11 = OpTypeFloat 32
%12 = OpTypeVector %11 4
%8 = OpTypeStruct %12
%13 = OpTypeRuntimeArray %8
%14 = OpTypePointer StorageBuffer %13
%15 = OpTypePointer Output %12
%16 = OpTypeVoid
%17 = OpTypeFunction %16
%2 = OpVariable %10 Input
%18 = OpTypePointer StorageBuffer %8
%3 = OpVariable %14 StorageBuffer
%19 = OpTypePointer StorageBuffer %12
%20 = OpConstant %9 0
%4 = OpVariable %15 Output
%1 = OpFunction %16 None %17
%21 = OpLabel
%22 = OpLoad %9 %2
%23 = OpAccessChain %18 %3 %22
%24 = OpAccessChain %19 %23 %20
%25 = OpLoad %12 %24
OpStore %4 %25
OpNoLine
OpReturn
OpFunctionEnd
Loading