Implement OpTypeMatrix (#738)

* Implement OpTypeMatrix

* clippy

* Use cached Symbol

* Implement #[spirv(matrix(ty, m, n))] instead of Matrix trait

* Update #[spirv(matrix(..))]

- #[spirv(matrix(ty, m, n))]
  Specify all of type, rows, columns.
- #[spirv(matrix(ty, m))]
  Specify all of type, rows. Infer columns.
- #[spirv(matrix(ty))]
  Specify all of type. Infer others.
- #[spirv(matrix)]
  Infer all.

* Drop #[spirv(matrix(..))] (with arguments)

* Fix IntrinsicType::Matrix type construction

* Update matrix-type.rs

* Update tests/ui/spirv-attr/multiple.rs to test Matrix

* Fix tests/ui/spirv-attr/matrix-type.rs

* Add failing tests for #[spirv(matrix)

* Update error messages for #[spirv(matrix)]
This commit is contained in:
hatoo 2021-08-30 22:45:29 +09:00 committed by GitHub
parent 1e3881bfcb
commit b0676cba61
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 322 additions and 74 deletions

View File

@ -843,5 +843,45 @@ fn trans_intrinsic_type<'tcx>(
Err(ErrorReported)
}
}
IntrinsicType::Matrix => {
let span = def_id_for_spirv_type_adt(ty)
.map(|did| cx.tcx.def_span(did))
.expect("#[spirv(matrix)] must be added to a type which has DefId");
let field_types = (0..ty.fields.count())
.map(|i| trans_type_impl(cx, span, ty.field(cx, i), false))
.collect::<Vec<_>>();
if field_types.len() < 2 {
cx.tcx
.sess
.span_err(span, "#[spirv(matrix)] type must have at least two fields");
return Err(ErrorReported);
}
let elem_type = field_types[0];
if !field_types.iter().all(|&ty| ty == elem_type) {
cx.tcx.sess.span_err(
span,
"#[spirv(matrix)] type fields must all be the same type",
);
return Err(ErrorReported);
}
match cx.lookup_type(elem_type) {
SpirvType::Vector { .. } => (),
ty => {
cx.tcx
.sess
.struct_span_err(span, "#[spirv(matrix)] type fields must all be vectors")
.note(&format!("field type is {}", ty.debug(elem_type, cx)))
.emit();
return Err(ErrorReported);
}
}
Ok(SpirvType::Matrix {
element: elem_type,
count: field_types.len() as u32,
}
.def(span, cx))
}
}
}

View File

@ -65,6 +65,7 @@ pub enum IntrinsicType {
SampledImage,
RayQueryKhr,
RuntimeArray,
Matrix,
}
// NOTE(eddyb) when adding new `#[spirv(...)]` attributes, the tests found inside

View File

@ -210,7 +210,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
)),
},
SpirvType::Adt { .. } => self.fatal("memset on structs not implemented yet"),
SpirvType::Vector { element, count } => {
SpirvType::Vector { element, count } | SpirvType::Matrix { element, count } => {
let elem_pat = self.memset_const_pattern(&self.lookup_type(element), fill_byte);
self.constant_composite(
ty.clone().def(self.span(), self),
@ -277,7 +277,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
)
.unwrap()
}
SpirvType::Vector { element, count } => {
SpirvType::Vector { element, count } | SpirvType::Matrix { element, count } => {
let elem_pat = self.memset_dynamic_pattern(&self.lookup_type(element), fill_var);
self.emit()
.composite_construct(
@ -426,7 +426,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
}
SpirvType::Vector { element, .. }
| SpirvType::Array { element, .. }
| SpirvType::RuntimeArray { element } => {
| SpirvType::RuntimeArray { element }
| SpirvType::Matrix { element, .. } => {
ty = element;
ty_kind = self.lookup_type(ty);
@ -1080,7 +1081,8 @@ impl<'a, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'tcx> {
} => field_types[idx as usize],
SpirvType::Array { element, .. }
| SpirvType::RuntimeArray { element, .. }
| SpirvType::Vector { element, .. } => element,
| SpirvType::Vector { element, .. }
| SpirvType::Matrix { element, .. } => element,
SpirvType::InterfaceBlock { inner_type } => {
assert_eq!(idx, 0);
inner_type
@ -1107,7 +1109,8 @@ impl<'a, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'tcx> {
SpirvType::Adt { field_offsets, .. } => field_offsets[idx as usize],
SpirvType::Array { element, .. }
| SpirvType::RuntimeArray { element, .. }
| SpirvType::Vector { element, .. } => {
| SpirvType::Vector { element, .. }
| SpirvType::Matrix { element, .. } => {
self.lookup_type(element).sizeof(self).unwrap() * idx
}
_ => unreachable!(),
@ -1843,7 +1846,9 @@ impl<'a, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'tcx> {
fn extract_value(&mut self, agg_val: Self::Value, idx: u64) -> Self::Value {
let result_type = match self.lookup_type(agg_val.ty) {
SpirvType::Adt { field_types, .. } => field_types[idx as usize],
SpirvType::Array { element, .. } | SpirvType::Vector { element, .. } => element,
SpirvType::Array { element, .. }
| SpirvType::Vector { element, .. }
| SpirvType::Matrix { element, .. } => element,
other => self.fatal(&format!(
"extract_value not implemented on type {:?}",
other

View File

@ -303,6 +303,11 @@ impl<'cx, 'tcx> Builder<'cx, 'tcx> {
count: inst.operands[1].unwrap_literal_int32(),
}
.def(self.span(), self),
Op::TypeMatrix => SpirvType::Matrix {
element: inst.operands[0].unwrap_id_ref(),
count: inst.operands[1].unwrap_literal_int32(),
}
.def(self.span(), self),
Op::TypeArray => {
self.err("OpTypeArray in asm! is not supported yet");
return;

View File

@ -482,6 +482,21 @@ impl<'tcx> CodegenCx<'tcx> {
*offset = final_offset;
result
}
SpirvType::Matrix { element, count } => {
let total_size = ty_concrete
.sizeof(self)
.expect("create_const_alloc: Matrices must be sized");
let final_offset = *offset + total_size;
let values = (0..count).map(|_| {
self.create_const_alloc2(alloc, offset, element)
.def_cx(self)
});
let result = self.constant_composite(ty, values);
assert!(*offset <= final_offset);
// Matrices sometimes have padding at the end (e.g. Mat4x3), skip over it.
*offset = final_offset;
result
}
SpirvType::RuntimeArray { element } => {
let mut values = Vec::new();
while offset.bytes_usize() != alloc.len() {

View File

@ -174,7 +174,7 @@ impl<'tcx> BaseTypeMethods<'tcx> for CodegenCx<'tcx> {
TypeKind::Struct
}
SpirvType::Vector { .. } => TypeKind::Vector,
SpirvType::Array { .. } | SpirvType::RuntimeArray { .. } => TypeKind::Array,
SpirvType::Array { .. } | SpirvType::RuntimeArray { .. } | SpirvType::Matrix { .. } => TypeKind::Array,
SpirvType::Pointer { .. } => TypeKind::Pointer,
SpirvType::Function { .. } => TypeKind::Function,
// HACK(eddyb) this is probably the closest `TypeKind` (which is still

View File

@ -47,6 +47,11 @@ pub enum SpirvType {
/// Note: vector count is literal.
count: u32,
},
Matrix {
element: Word,
/// Note: matrix count is literal.
count: u32,
},
Array {
element: Word,
/// Note: array count is ref to constant.
@ -174,6 +179,7 @@ impl SpirvType {
result
}
Self::Vector { element, count } => cx.emit_global().type_vector_id(id, element, count),
Self::Matrix { element, count } => cx.emit_global().type_matrix_id(id, element, count),
Self::Array { element, count } => {
// ArrayStride decoration wants in *bytes*
let element_size = cx
@ -347,6 +353,7 @@ impl SpirvType {
Self::Vector { element, count } => {
cx.lookup_type(element).sizeof(cx)? * count.next_power_of_two() as u64
}
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_u64(count).unwrap()
}
@ -377,9 +384,9 @@ impl SpirvType {
.bytes(),
)
.expect("alignof: Vectors must have power-of-2 size"),
Self::Array { element, .. } | Self::RuntimeArray { element } => {
cx.lookup_type(element).alignof(cx)
}
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::Image { .. }
| Self::AccelerationStructureKhr
@ -455,6 +462,12 @@ impl fmt::Debug for SpirvTypePrinter<'_, '_> {
.field("element", &self.cx.debug_type(element))
.field("count", &count)
.finish(),
SpirvType::Matrix { element, count } => f
.debug_struct("Matrix")
.field("id", &self.id)
.field("element", &self.cx.debug_type(element))
.field("count", &count)
.finish(),
SpirvType::Array { element, count } => f
.debug_struct("Array")
.field("id", &self.id)
@ -612,7 +625,7 @@ impl SpirvTypePrinter<'_, '_> {
}
f.write_str(" }")
}
SpirvType::Vector { element, count } => {
SpirvType::Vector { element, count } | SpirvType::Matrix { element, count } => {
ty(self.cx, stack, f, element)?;
write!(f, "x{}", count)
}

View File

@ -334,6 +334,10 @@ impl Symbols {
"runtime_array",
SpirvAttribute::IntrinsicType(IntrinsicType::RuntimeArray),
),
(
"matrix",
SpirvAttribute::IntrinsicType(IntrinsicType::Matrix),
),
("unroll_loops", SpirvAttribute::UnrollLoops),
]
.iter()

View File

@ -0,0 +1,12 @@
// Tests that matrix type inference fails correctly, for empty struct
// build-fail
use spirv_std as _;
#[spirv(matrix)]
pub struct _EmptyStruct {}
#[spirv(fragment)]
pub fn _entry() {
let _empty_struct = _EmptyStruct {};
}

View File

@ -0,0 +1,8 @@
error: #[spirv(matrix)] type must have at least two fields
--> $DIR/invalid-matrix-type-empty.rs:7:1
|
7 | pub struct _EmptyStruct {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to previous error

View File

@ -0,0 +1,25 @@
// Tests that matrix type inference fails correctly
// build-fail
use spirv_std as _;
#[spirv(matrix)]
pub struct _FewerFields {
_v: glam::Vec3,
}
#[spirv(matrix)]
pub struct _NotVectorField {
_x: f32,
_y: f32,
_z: f32,
}
#[spirv(matrix)]
pub struct _DifferentType {
_x: glam::Vec3,
_y: glam::Vec2,
}
#[spirv(fragment)]
pub fn _entry(_arg1: _FewerFields, _arg2: _NotVectorField, _arg3: _DifferentType) {}

View File

@ -0,0 +1,31 @@
error: #[spirv(matrix)] type must have at least two fields
--> $DIR/invalid-matrix-type.rs:7:1
|
7 | / pub struct _FewerFields {
8 | | _v: glam::Vec3,
9 | | }
| |_^
error: #[spirv(matrix)] type fields must all be vectors
--> $DIR/invalid-matrix-type.rs:12:1
|
12 | / pub struct _NotVectorField {
13 | | _x: f32,
14 | | _y: f32,
15 | | _z: f32,
16 | | }
| |_^
|
= note: field type is f32
error: #[spirv(matrix)] type fields must all be the same type
--> $DIR/invalid-matrix-type.rs:19:1
|
19 | / pub struct _DifferentType {
20 | | _x: glam::Vec3,
21 | | _y: glam::Vec2,
22 | | }
| |_^
error: aborting due to 3 previous errors

View File

@ -0,0 +1,53 @@
// build-pass
// compile-flags: -Ctarget-feature=+RayTracingKHR,+ext:SPV_KHR_ray_tracing
use spirv_std as _;
#[derive(Clone, Copy)]
#[spirv(matrix)]
pub struct Affine3 {
pub x: glam::Vec3,
pub y: glam::Vec3,
pub z: glam::Vec3,
pub w: glam::Vec3,
}
impl Affine3 {
pub const ZERO: Self = Self {
x: glam::Vec3::ZERO,
y: glam::Vec3::ZERO,
z: glam::Vec3::ZERO,
w: glam::Vec3::ZERO,
};
pub const IDENTITY: Self = Self {
x: glam::Vec3::X,
y: glam::Vec3::Y,
z: glam::Vec3::Z,
w: glam::Vec3::ZERO,
};
}
impl Default for Affine3 {
#[inline]
fn default() -> Self {
Self::IDENTITY
}
}
#[spirv(closest_hit)]
pub fn main_attrs(
#[spirv(object_to_world)] _object_to_world: Affine3,
#[spirv(world_to_object)] _world_to_object: Affine3,
) {
}
#[spirv(fragment)]
pub fn main_default(out: &mut Affine3) {
*out = Affine3::default();
}
#[spirv(fragment)]
pub fn main_add(affine3: Affine3, out: &mut glam::Vec3) {
*out = affine3.x + affine3.y + affine3.z + affine3.w;
}

View File

@ -8,9 +8,21 @@ use spirv_std as _;
#[spirv(sampler, sampler)]
struct _SameIntrinsicType {}
#[spirv(matrix, matrix)]
struct _SameIntrinsicMatrixType {
x: glam::Vec3,
y: glam::Vec3,
}
#[spirv(sampler, generic_image_type)]
struct _DiffIntrinsicType {}
#[spirv(sampler, matrix)]
struct _SamplerAndMatrix {
x: glam::Vec3,
y: glam::Vec3,
}
#[spirv(block, block)]
struct _Block {}

View File

@ -11,190 +11,214 @@ note: previous intrinsic type attribute
| ^^^^^^^
error: only one intrinsic type attribute is allowed on a struct
--> $DIR/multiple.rs:11:18
--> $DIR/multiple.rs:11:17
|
11 | #[spirv(sampler, generic_image_type)]
| ^^^^^^^^^^^^^^^^^^
11 | #[spirv(matrix, matrix)]
| ^^^^^^
|
note: previous intrinsic type attribute
--> $DIR/multiple.rs:11:9
|
11 | #[spirv(sampler, generic_image_type)]
11 | #[spirv(matrix, matrix)]
| ^^^^^^
error: only one intrinsic type attribute is allowed on a struct
--> $DIR/multiple.rs:17:18
|
17 | #[spirv(sampler, generic_image_type)]
| ^^^^^^^^^^^^^^^^^^
|
note: previous intrinsic type attribute
--> $DIR/multiple.rs:17:9
|
17 | #[spirv(sampler, generic_image_type)]
| ^^^^^^^
error: only one intrinsic type attribute is allowed on a struct
--> $DIR/multiple.rs:20:18
|
20 | #[spirv(sampler, matrix)]
| ^^^^^^
|
note: previous intrinsic type attribute
--> $DIR/multiple.rs:20:9
|
20 | #[spirv(sampler, matrix)]
| ^^^^^^^
error: only one #[spirv(block)] attribute is allowed on a struct
--> $DIR/multiple.rs:14:16
--> $DIR/multiple.rs:26:16
|
14 | #[spirv(block, block)]
26 | #[spirv(block, block)]
| ^^^^^
|
note: previous #[spirv(block)] attribute
--> $DIR/multiple.rs:14:9
--> $DIR/multiple.rs:26:9
|
14 | #[spirv(block, block)]
26 | #[spirv(block, block)]
| ^^^^^
warning: #[spirv(block)] is no longer needed and should be removed
--> $DIR/multiple.rs:14:9
--> $DIR/multiple.rs:26:9
|
14 | #[spirv(block, block)]
26 | #[spirv(block, block)]
| ^^^^^
error: only one entry-point attribute is allowed on a function
--> $DIR/multiple.rs:17:17
--> $DIR/multiple.rs:29:17
|
17 | #[spirv(vertex, vertex)]
29 | #[spirv(vertex, vertex)]
| ^^^^^^
|
note: previous entry-point attribute
--> $DIR/multiple.rs:17:9
--> $DIR/multiple.rs:29:9
|
17 | #[spirv(vertex, vertex)]
29 | #[spirv(vertex, vertex)]
| ^^^^^^
error: only one entry-point attribute is allowed on a function
--> $DIR/multiple.rs:20:17
--> $DIR/multiple.rs:32:17
|
20 | #[spirv(vertex, fragment)]
32 | #[spirv(vertex, fragment)]
| ^^^^^^^^
|
note: previous entry-point attribute
--> $DIR/multiple.rs:20:9
--> $DIR/multiple.rs:32:9
|
20 | #[spirv(vertex, fragment)]
32 | #[spirv(vertex, fragment)]
| ^^^^^^
error: only one storage class attribute is allowed on a function param
--> $DIR/multiple.rs:25:22
--> $DIR/multiple.rs:37:22
|
25 | #[spirv(uniform, uniform)] _same_storage_class: (),
37 | #[spirv(uniform, uniform)] _same_storage_class: (),
| ^^^^^^^
|
note: previous storage class attribute
--> $DIR/multiple.rs:25:13
--> $DIR/multiple.rs:37:13
|
25 | #[spirv(uniform, uniform)] _same_storage_class: (),
37 | #[spirv(uniform, uniform)] _same_storage_class: (),
| ^^^^^^^
error: only one storage class attribute is allowed on a function param
--> $DIR/multiple.rs:26:22
--> $DIR/multiple.rs:38:22
|
26 | #[spirv(uniform, push_constant)] _diff_storage_class: (),
38 | #[spirv(uniform, push_constant)] _diff_storage_class: (),
| ^^^^^^^^^^^^^
|
note: previous storage class attribute
--> $DIR/multiple.rs:26:13
--> $DIR/multiple.rs:38:13
|
26 | #[spirv(uniform, push_constant)] _diff_storage_class: (),
38 | #[spirv(uniform, push_constant)] _diff_storage_class: (),
| ^^^^^^^
error: only one builtin attribute is allowed on a function param
--> $DIR/multiple.rs:28:23
--> $DIR/multiple.rs:40:23
|
28 | #[spirv(position, position)] _same_builtin: (),
40 | #[spirv(position, position)] _same_builtin: (),
| ^^^^^^^^
|
note: previous builtin attribute
--> $DIR/multiple.rs:28:13
--> $DIR/multiple.rs:40:13
|
28 | #[spirv(position, position)] _same_builtin: (),
40 | #[spirv(position, position)] _same_builtin: (),
| ^^^^^^^^
error: only one builtin attribute is allowed on a function param
--> $DIR/multiple.rs:29:23
--> $DIR/multiple.rs:41:23
|
29 | #[spirv(position, vertex_index)] _diff_builtin: (),
41 | #[spirv(position, vertex_index)] _diff_builtin: (),
| ^^^^^^^^^^^^
|
note: previous builtin attribute
--> $DIR/multiple.rs:29:13
--> $DIR/multiple.rs:41:13
|
29 | #[spirv(position, vertex_index)] _diff_builtin: (),
41 | #[spirv(position, vertex_index)] _diff_builtin: (),
| ^^^^^^^^
error: only one #[spirv(descriptor_set)] attribute is allowed on a function param
--> $DIR/multiple.rs:31:33
--> $DIR/multiple.rs:43:33
|
31 | #[spirv(descriptor_set = 0, descriptor_set = 0)] _same_descriptor_set: (),
43 | #[spirv(descriptor_set = 0, descriptor_set = 0)] _same_descriptor_set: (),
| ^^^^^^^^^^^^^^^^^^
|
note: previous #[spirv(descriptor_set)] attribute
--> $DIR/multiple.rs:31:13
--> $DIR/multiple.rs:43:13
|
31 | #[spirv(descriptor_set = 0, descriptor_set = 0)] _same_descriptor_set: (),
43 | #[spirv(descriptor_set = 0, descriptor_set = 0)] _same_descriptor_set: (),
| ^^^^^^^^^^^^^^^^^^
error: only one #[spirv(descriptor_set)] attribute is allowed on a function param
--> $DIR/multiple.rs:32:33
--> $DIR/multiple.rs:44:33
|
32 | #[spirv(descriptor_set = 0, descriptor_set = 1)] _diff_descriptor_set: (),
44 | #[spirv(descriptor_set = 0, descriptor_set = 1)] _diff_descriptor_set: (),
| ^^^^^^^^^^^^^^^^^^
|
note: previous #[spirv(descriptor_set)] attribute
--> $DIR/multiple.rs:32:13
--> $DIR/multiple.rs:44:13
|
32 | #[spirv(descriptor_set = 0, descriptor_set = 1)] _diff_descriptor_set: (),
44 | #[spirv(descriptor_set = 0, descriptor_set = 1)] _diff_descriptor_set: (),
| ^^^^^^^^^^^^^^^^^^
error: only one #[spirv(binding)] attribute is allowed on a function param
--> $DIR/multiple.rs:34:26
--> $DIR/multiple.rs:46:26
|
34 | #[spirv(binding = 0, binding = 0)] _same_binding: (),
46 | #[spirv(binding = 0, binding = 0)] _same_binding: (),
| ^^^^^^^^^^^
|
note: previous #[spirv(binding)] attribute
--> $DIR/multiple.rs:34:13
--> $DIR/multiple.rs:46:13
|
34 | #[spirv(binding = 0, binding = 0)] _same_binding: (),
46 | #[spirv(binding = 0, binding = 0)] _same_binding: (),
| ^^^^^^^^^^^
error: only one #[spirv(binding)] attribute is allowed on a function param
--> $DIR/multiple.rs:35:26
--> $DIR/multiple.rs:47:26
|
35 | #[spirv(binding = 0, binding = 1)] _diff_binding: (),
47 | #[spirv(binding = 0, binding = 1)] _diff_binding: (),
| ^^^^^^^^^^^
|
note: previous #[spirv(binding)] attribute
--> $DIR/multiple.rs:35:13
--> $DIR/multiple.rs:47:13
|
35 | #[spirv(binding = 0, binding = 1)] _diff_binding: (),
47 | #[spirv(binding = 0, binding = 1)] _diff_binding: (),
| ^^^^^^^^^^^
error: only one #[spirv(flat)] attribute is allowed on a function param
--> $DIR/multiple.rs:37:19
--> $DIR/multiple.rs:49:19
|
37 | #[spirv(flat, flat)] _flat: (),
49 | #[spirv(flat, flat)] _flat: (),
| ^^^^
|
note: previous #[spirv(flat)] attribute
--> $DIR/multiple.rs:37:13
--> $DIR/multiple.rs:49:13
|
37 | #[spirv(flat, flat)] _flat: (),
49 | #[spirv(flat, flat)] _flat: (),
| ^^^^
error: only one #[spirv(invariant)] attribute is allowed on a function param
--> $DIR/multiple.rs:39:24
--> $DIR/multiple.rs:51:24
|
39 | #[spirv(invariant, invariant)] _invariant: (),
51 | #[spirv(invariant, invariant)] _invariant: (),
| ^^^^^^^^^
|
note: previous #[spirv(invariant)] attribute
--> $DIR/multiple.rs:39:13
--> $DIR/multiple.rs:51:13
|
39 | #[spirv(invariant, invariant)] _invariant: (),
51 | #[spirv(invariant, invariant)] _invariant: (),
| ^^^^^^^^^
error: only one #[spirv(unroll_loops)] attribute is allowed on a function
--> $DIR/multiple.rs:43:23
--> $DIR/multiple.rs:55:23
|
43 | #[spirv(unroll_loops, unroll_loops)]
55 | #[spirv(unroll_loops, unroll_loops)]
| ^^^^^^^^^^^^
|
note: previous #[spirv(unroll_loops)] attribute
--> $DIR/multiple.rs:43:9
--> $DIR/multiple.rs:55:9
|
43 | #[spirv(unroll_loops, unroll_loops)]
55 | #[spirv(unroll_loops, unroll_loops)]
| ^^^^^^^^^^^^
error: aborting due to 16 previous errors; 1 warning emitted
error: aborting due to 18 previous errors; 1 warning emitted