hlsl: Implement compound assignment

Use the ExpandCompoundAssignment transform to convert compound
assignments to regular assignments.

Bug: tint:1325
Change-Id: Ic843964ec24d8a2f00f801823f8f8bbf1c6fab5c
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/85284
Reviewed-by: Ben Clayton <bclayton@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
This commit is contained in:
James Price 2022-03-31 22:30:10 +00:00
parent 60107e7435
commit 508a9660a5
33 changed files with 299 additions and 347 deletions

View File

@ -52,6 +52,7 @@
#include "src/tint/transform/calculate_array_length.h" #include "src/tint/transform/calculate_array_length.h"
#include "src/tint/transform/canonicalize_entry_point_io.h" #include "src/tint/transform/canonicalize_entry_point_io.h"
#include "src/tint/transform/decompose_memory_access.h" #include "src/tint/transform/decompose_memory_access.h"
#include "src/tint/transform/expand_compound_assignment.h"
#include "src/tint/transform/fold_trivial_single_use_lets.h" #include "src/tint/transform/fold_trivial_single_use_lets.h"
#include "src/tint/transform/localize_struct_array_assignment.h" #include "src/tint/transform/localize_struct_array_assignment.h"
#include "src/tint/transform/loop_to_for_loop.h" #include "src/tint/transform/loop_to_for_loop.h"
@ -188,6 +189,7 @@ SanitizedResult Sanitize(
// assumes that num_workgroups builtins only appear as struct members and are // assumes that num_workgroups builtins only appear as struct members and are
// only accessed directly via member accessors. // only accessed directly via member accessors.
manager.Add<transform::NumWorkgroupsFromUniform>(); manager.Add<transform::NumWorkgroupsFromUniform>();
manager.Add<transform::ExpandCompoundAssignment>();
manager.Add<transform::PromoteSideEffectsToDecl>(); manager.Add<transform::PromoteSideEffectsToDecl>();
manager.Add<transform::UnwindDiscardFunctions>(); manager.Add<transform::UnwindDiscardFunctions>();
manager.Add<transform::SimplifyPointers>(); manager.Add<transform::SimplifyPointers>();

View File

@ -1,26 +1,32 @@
SKIP: FAILED void set_int4(inout int4 vec, int idx, int val) {
vec = (idx.xxxx == int4(0, 1, 2, 3)) ? val.xxxx : vec;
}
[numthreads(1, 1, 1)]
void unused_entry_point() {
return;
}
struct S { struct S {
a : array<vec4<i32>, 4>, int4 a[4];
} };
var<private> counter : i32; static int counter = 0;
fn foo() -> i32 { int foo() {
counter += 1; counter = (counter + 1);
return counter; return counter;
} }
fn bar() -> i32 { int bar() {
counter += 2; counter = (counter + 2);
return counter; return counter;
} }
fn main() { void main() {
var x = S(); S x = (S)0;
let p = &(x); const int tint_symbol_2 = foo();
(*(p)).a[foo()][bar()] += 5; const int tint_symbol_save = tint_symbol_2;
const int tint_symbol_1 = bar();
set_int4(x.a[tint_symbol_save], tint_symbol_1, (x.a[tint_symbol_save][tint_symbol_1] + 5));
} }
Failed to generate: error: unknown statement type: tint::ast::CompoundAssignmentStatement

View File

@ -1,19 +1,18 @@
SKIP: FAILED [numthreads(1, 1, 1)]
void unused_entry_point() {
return;
var<private> a : i32;
var<private> b : f32;
fn foo(maybe_zero : i32) {
a /= 0;
a %= 0;
a /= maybe_zero;
a %= maybe_zero;
b /= 0.0;
b %= 0.0;
b /= f32(maybe_zero);
b %= f32(maybe_zero);
} }
Failed to generate: error: unknown statement type: tint::ast::CompoundAssignmentStatement static int a = 0;
static float b = 0.0f;
void foo(int maybe_zero) {
a = (a / 1);
a = (a % 1);
a = (a / (maybe_zero == 0 ? 1 : maybe_zero));
a = (a % (maybe_zero == 0 ? 1 : maybe_zero));
b = (b / 0.0f);
b = (b % 0.0f);
b = (b / float(maybe_zero));
b = (b % float(maybe_zero));
}

View File

@ -1,35 +1,44 @@
SKIP: FAILED [numthreads(1, 1, 1)]
void unused_entry_point() {
return;
struct S {
a : i32,
b : vec4<f32>,
c : mat2x2<f32>,
} }
@group(0) @binding(0) var<storage, read_write> v : S; RWByteAddressBuffer v : register(u0, space0);
static uint i = 0u;
var<private> i : u32; int idx1() {
i = (i + 1u);
fn idx1() -> i32 {
i += 1u;
return 1; return 1;
} }
fn idx2() -> i32 { int idx2() {
i += 2u; i = (i + 2u);
return 1; return 1;
} }
fn idx3() -> i32 { int idx3() {
i += 3u; i = (i + 3u);
return 1; return 1;
} }
fn foo() { void foo() {
var a = array<f32, 4>(); float a[4] = (float[4])0;
for(a[idx1()] *= 2.0; (a[idx2()] < 10.0); a[idx3()] += 1.0) { const int tint_symbol_2 = idx1();
const int tint_symbol_save = tint_symbol_2;
{
a[tint_symbol_save] = (a[tint_symbol_save] * 2.0f);
[loop] while (true) {
const int tint_symbol_3 = idx2();
if (!((a[tint_symbol_3] < 10.0f))) {
break;
}
{
}
{
const int tint_symbol_4 = idx3();
const int tint_symbol_1_save = tint_symbol_4;
a[tint_symbol_1_save] = (a[tint_symbol_1_save] + 1.0f);
}
}
} }
} }
Failed to generate: error: unknown statement type: tint::ast::CompoundAssignmentStatement

View File

@ -1,13 +1,13 @@
SKIP: FAILED [numthreads(1, 1, 1)]
void unused_entry_point() {
return;
fn foo() {
var<function> a : i32;
var<function> b : vec4<f32>;
var<function> c : mat2x2<f32>;
a /= 2;
b *= mat4x4<f32>();
c *= 2.0;
} }
Failed to generate: error: unknown statement type: tint::ast::CompoundAssignmentStatement void foo() {
int a = 0;
float4 b = float4(0.0f, 0.0f, 0.0f, 0.0f);
float2x2 c = float2x2(0.0f, 0.0f, 0.0f, 0.0f);
a = (a / 2);
b = mul(float4x4(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), b);
c = (c * 2.0f);
}

View File

@ -1,14 +1,21 @@
SKIP: FAILED [numthreads(1, 1, 1)]
void unused_entry_point() {
return;
struct S {
a : mat4x4<f32>,
} }
@group(0) @binding(0) var<storage, read_write> v : S; RWByteAddressBuffer v : register(u0, space0);
fn foo() { void tint_symbol(RWByteAddressBuffer buffer, uint offset, float4x4 value) {
v.a -= mat4x4<f32>(); buffer.Store4((offset + 0u), asuint(value[0u]));
buffer.Store4((offset + 16u), asuint(value[1u]));
buffer.Store4((offset + 32u), asuint(value[2u]));
buffer.Store4((offset + 48u), asuint(value[3u]));
} }
Failed to generate: error: cannot assign to value of type 'mat4x4<f32>' float4x4 tint_symbol_2(RWByteAddressBuffer buffer, uint offset) {
return float4x4(asfloat(buffer.Load4((offset + 0u))), asfloat(buffer.Load4((offset + 16u))), asfloat(buffer.Load4((offset + 32u))), asfloat(buffer.Load4((offset + 48u))));
}
void foo() {
tint_symbol(v, 0u, (tint_symbol_2(v, 0u) - float4x4(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)));
}

View File

@ -1,14 +1,21 @@
SKIP: FAILED [numthreads(1, 1, 1)]
void unused_entry_point() {
return;
struct S {
a : mat4x4<f32>,
} }
@group(0) @binding(0) var<storage, read_write> v : S; RWByteAddressBuffer v : register(u0, space0);
fn foo() { void tint_symbol(RWByteAddressBuffer buffer, uint offset, float4x4 value) {
v.a += mat4x4<f32>(); buffer.Store4((offset + 0u), asuint(value[0u]));
buffer.Store4((offset + 16u), asuint(value[1u]));
buffer.Store4((offset + 32u), asuint(value[2u]));
buffer.Store4((offset + 48u), asuint(value[3u]));
} }
Failed to generate: error: cannot assign to value of type 'mat4x4<f32>' float4x4 tint_symbol_2(RWByteAddressBuffer buffer, uint offset) {
return float4x4(asfloat(buffer.Load4((offset + 0u))), asfloat(buffer.Load4((offset + 16u))), asfloat(buffer.Load4((offset + 32u))), asfloat(buffer.Load4((offset + 48u))));
}
void foo() {
tint_symbol(v, 0u, (tint_symbol_2(v, 0u) + float4x4(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)));
}

View File

@ -1,14 +1,21 @@
SKIP: FAILED [numthreads(1, 1, 1)]
void unused_entry_point() {
return;
struct S {
a : mat4x4<f32>,
} }
@group(0) @binding(0) var<storage, read_write> v : S; RWByteAddressBuffer v : register(u0, space0);
fn foo() { void tint_symbol(RWByteAddressBuffer buffer, uint offset, float4x4 value) {
v.a *= 2.0; buffer.Store4((offset + 0u), asuint(value[0u]));
buffer.Store4((offset + 16u), asuint(value[1u]));
buffer.Store4((offset + 32u), asuint(value[2u]));
buffer.Store4((offset + 48u), asuint(value[3u]));
} }
Failed to generate: error: cannot assign to value of type 'mat4x4<f32>' float4x4 tint_symbol_2(RWByteAddressBuffer buffer, uint offset) {
return float4x4(asfloat(buffer.Load4((offset + 0u))), asfloat(buffer.Load4((offset + 16u))), asfloat(buffer.Load4((offset + 32u))), asfloat(buffer.Load4((offset + 48u))));
}
void foo() {
tint_symbol(v, 0u, (tint_symbol_2(v, 0u) * 2.0f));
}

View File

@ -1,14 +1,21 @@
SKIP: FAILED [numthreads(1, 1, 1)]
void unused_entry_point() {
return;
struct S {
a : mat4x4<f32>,
} }
@group(0) @binding(0) var<storage, read_write> v : S; RWByteAddressBuffer v : register(u0, space0);
fn foo() { void tint_symbol(RWByteAddressBuffer buffer, uint offset, float4x4 value) {
v.a *= mat4x4<f32>(); buffer.Store4((offset + 0u), asuint(value[0u]));
buffer.Store4((offset + 16u), asuint(value[1u]));
buffer.Store4((offset + 32u), asuint(value[2u]));
buffer.Store4((offset + 48u), asuint(value[3u]));
} }
Failed to generate: error: cannot assign to value of type 'mat4x4<f32>' float4x4 tint_symbol_2(RWByteAddressBuffer buffer, uint offset) {
return float4x4(asfloat(buffer.Load4((offset + 0u))), asfloat(buffer.Load4((offset + 16u))), asfloat(buffer.Load4((offset + 32u))), asfloat(buffer.Load4((offset + 48u))));
}
void foo() {
tint_symbol(v, 0u, mul(float4x4(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), tint_symbol_2(v, 0u)));
}

View File

@ -1,16 +1,14 @@
SKIP: FAILED [numthreads(1, 1, 1)]
void unused_entry_point() {
return;
var<private> a : i32;
var<private> b : vec4<f32>;
var<private> c : mat2x2<f32>;
fn foo() {
a /= 2;
b *= mat4x4<f32>();
c *= 2.0;
} }
Failed to generate: error: unknown statement type: tint::ast::CompoundAssignmentStatement static int a = 0;
static float4 b = float4(0.0f, 0.0f, 0.0f, 0.0f);
static float2x2 c = float2x2(0.0f, 0.0f, 0.0f, 0.0f);
void foo() {
a = (a / 2);
b = mul(float4x4(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), b);
c = (c * 2.0f);
}

View File

@ -1,14 +1,10 @@
SKIP: FAILED [numthreads(1, 1, 1)]
void unused_entry_point() {
return;
struct S {
a : i32,
} }
@group(0) @binding(0) var<storage, read_write> v : S; RWByteAddressBuffer v : register(u0, space0);
fn foo() { void foo() {
v.a &= 2; v.Store(0u, asuint((asint(v.Load(0u)) & 2)));
} }
Failed to generate: error: cannot assign to value of type 'i32'

View File

@ -1,14 +1,10 @@
SKIP: FAILED [numthreads(1, 1, 1)]
void unused_entry_point() {
return;
struct S {
a : i32,
} }
@group(0) @binding(0) var<storage, read_write> v : S; RWByteAddressBuffer v : register(u0, space0);
fn foo() { void foo() {
v.a /= 2; v.Store(0u, asuint((asint(v.Load(0u)) / 2)));
} }
Failed to generate: error: cannot assign to value of type 'i32'

View File

@ -1,14 +1,10 @@
SKIP: FAILED [numthreads(1, 1, 1)]
void unused_entry_point() {
return;
struct S {
a : i32,
} }
@group(0) @binding(0) var<storage, read_write> v : S; RWByteAddressBuffer v : register(u0, space0);
fn foo() { void foo() {
v.a -= 2; v.Store(0u, asuint((asint(v.Load(0u)) - 2)));
} }
Failed to generate: error: cannot assign to value of type 'i32'

View File

@ -1,14 +1,10 @@
SKIP: FAILED [numthreads(1, 1, 1)]
void unused_entry_point() {
return;
struct S {
a : i32,
} }
@group(0) @binding(0) var<storage, read_write> v : S; RWByteAddressBuffer v : register(u0, space0);
fn foo() { void foo() {
v.a %= 2; v.Store(0u, asuint((asint(v.Load(0u)) % 2)));
} }
Failed to generate: error: cannot assign to value of type 'i32'

View File

@ -1,14 +1,10 @@
SKIP: FAILED [numthreads(1, 1, 1)]
void unused_entry_point() {
return;
struct S {
a : i32,
} }
@group(0) @binding(0) var<storage, read_write> v : S; RWByteAddressBuffer v : register(u0, space0);
fn foo() { void foo() {
v.a |= 2; v.Store(0u, asuint((asint(v.Load(0u)) | 2)));
} }
Failed to generate: error: cannot assign to value of type 'i32'

View File

@ -1,14 +1,10 @@
SKIP: FAILED [numthreads(1, 1, 1)]
void unused_entry_point() {
return;
struct S {
a : i32,
} }
@group(0) @binding(0) var<storage, read_write> v : S; RWByteAddressBuffer v : register(u0, space0);
fn foo() { void foo() {
v.a += 2; v.Store(0u, asuint((asint(v.Load(0u)) + 2)));
} }
Failed to generate: error: cannot assign to value of type 'i32'

View File

@ -1,14 +1,10 @@
SKIP: FAILED [numthreads(1, 1, 1)]
void unused_entry_point() {
return;
struct S {
a : i32,
} }
@group(0) @binding(0) var<storage, read_write> v : S; RWByteAddressBuffer v : register(u0, space0);
fn foo() { void foo() {
v.a *= 2; v.Store(0u, asuint((asint(v.Load(0u)) * 2)));
} }
Failed to generate: error: cannot assign to value of type 'i32'

View File

@ -1,14 +1,10 @@
SKIP: FAILED [numthreads(1, 1, 1)]
void unused_entry_point() {
return;
struct S {
a : i32,
} }
@group(0) @binding(0) var<storage, read_write> v : S; RWByteAddressBuffer v : register(u0, space0);
fn foo() { void foo() {
v.a ^= 2; v.Store(0u, asuint((asint(v.Load(0u)) ^ 2)));
} }
Failed to generate: error: cannot assign to value of type 'i32'

View File

@ -1,14 +1,10 @@
SKIP: FAILED [numthreads(1, 1, 1)]
void unused_entry_point() {
return;
struct S {
a : vec4<i32>,
} }
@group(0) @binding(0) var<storage, read_write> v : S; RWByteAddressBuffer v : register(u0, space0);
fn foo() { void foo() {
v.a &= vec4<i32>(2); v.Store4(0u, asuint((asint(v.Load4(0u)) & int4((2).xxxx))));
} }
Failed to generate: error: cannot assign to value of type 'vec4<i32>'

View File

@ -1,14 +1,10 @@
SKIP: FAILED [numthreads(1, 1, 1)]
void unused_entry_point() {
return;
struct S {
a : vec4<f32>,
} }
@group(0) @binding(0) var<storage, read_write> v : S; RWByteAddressBuffer v : register(u0, space0);
fn foo() { void foo() {
v.a /= 2.0; v.Store4(0u, asuint((asfloat(v.Load4(0u)) / 2.0f)));
} }
Failed to generate: error: cannot assign to value of type 'vec4<f32>'

View File

@ -1,14 +1,10 @@
SKIP: FAILED [numthreads(1, 1, 1)]
void unused_entry_point() {
return;
struct S {
a : vec4<i32>,
} }
@group(0) @binding(0) var<storage, read_write> v : S; RWByteAddressBuffer v : register(u0, space0);
fn foo() { void foo() {
v.a /= vec4<i32>(2); v.Store4(0u, asuint((asint(v.Load4(0u)) / int4((2).xxxx))));
} }
Failed to generate: error: cannot assign to value of type 'vec4<i32>'

View File

@ -1,14 +1,10 @@
SKIP: FAILED [numthreads(1, 1, 1)]
void unused_entry_point() {
return;
struct S {
a : vec4<f32>,
} }
@group(0) @binding(0) var<storage, read_write> v : S; RWByteAddressBuffer v : register(u0, space0);
fn foo() { void foo() {
v.a -= 2.0; v.Store4(0u, asuint((asfloat(v.Load4(0u)) - 2.0f)));
} }
Failed to generate: error: cannot assign to value of type 'vec4<f32>'

View File

@ -1,14 +1,10 @@
SKIP: FAILED [numthreads(1, 1, 1)]
void unused_entry_point() {
return;
struct S {
a : vec4<i32>,
} }
@group(0) @binding(0) var<storage, read_write> v : S; RWByteAddressBuffer v : register(u0, space0);
fn foo() { void foo() {
v.a -= vec4<i32>(2); v.Store4(0u, asuint((asint(v.Load4(0u)) - int4((2).xxxx))));
} }
Failed to generate: error: cannot assign to value of type 'vec4<i32>'

View File

@ -1,14 +1,10 @@
SKIP: FAILED [numthreads(1, 1, 1)]
void unused_entry_point() {
return;
struct S {
a : vec4<i32>,
} }
@group(0) @binding(0) var<storage, read_write> v : S; RWByteAddressBuffer v : register(u0, space0);
fn foo() { void foo() {
v.a %= 2; v.Store4(0u, asuint((asint(v.Load4(0u)) % 2)));
} }
Failed to generate: error: cannot assign to value of type 'vec4<i32>'

View File

@ -1,14 +1,10 @@
SKIP: FAILED [numthreads(1, 1, 1)]
void unused_entry_point() {
return;
struct S {
a : vec4<i32>,
} }
@group(0) @binding(0) var<storage, read_write> v : S; RWByteAddressBuffer v : register(u0, space0);
fn foo() { void foo() {
v.a %= vec4<i32>(2); v.Store4(0u, asuint((asint(v.Load4(0u)) % int4((2).xxxx))));
} }
Failed to generate: error: cannot assign to value of type 'vec4<i32>'

View File

@ -1,14 +1,10 @@
SKIP: FAILED [numthreads(1, 1, 1)]
void unused_entry_point() {
return;
struct S {
a : vec4<i32>,
} }
@group(0) @binding(0) var<storage, read_write> v : S; RWByteAddressBuffer v : register(u0, space0);
fn foo() { void foo() {
v.a |= vec4<i32>(2); v.Store4(0u, asuint((asint(v.Load4(0u)) | int4((2).xxxx))));
} }
Failed to generate: error: cannot assign to value of type 'vec4<i32>'

View File

@ -1,14 +1,10 @@
SKIP: FAILED [numthreads(1, 1, 1)]
void unused_entry_point() {
return;
struct S {
a : vec4<f32>,
} }
@group(0) @binding(0) var<storage, read_write> v : S; RWByteAddressBuffer v : register(u0, space0);
fn foo() { void foo() {
v.a += 2.0; v.Store4(0u, asuint((asfloat(v.Load4(0u)) + 2.0f)));
} }
Failed to generate: error: cannot assign to value of type 'vec4<f32>'

View File

@ -1,14 +1,10 @@
SKIP: FAILED [numthreads(1, 1, 1)]
void unused_entry_point() {
return;
struct S {
a : vec4<i32>,
} }
@group(0) @binding(0) var<storage, read_write> v : S; RWByteAddressBuffer v : register(u0, space0);
fn foo() { void foo() {
v.a += vec4<i32>(2); v.Store4(0u, asuint((asint(v.Load4(0u)) + int4((2).xxxx))));
} }
Failed to generate: error: cannot assign to value of type 'vec4<i32>'

View File

@ -1,14 +1,10 @@
SKIP: FAILED [numthreads(1, 1, 1)]
void unused_entry_point() {
return;
struct S {
a : vec4<f32>,
} }
@group(0) @binding(0) var<storage, read_write> v : S; RWByteAddressBuffer v : register(u0, space0);
fn foo() { void foo() {
v.a *= mat4x4<f32>(); v.Store4(0u, asuint(mul(float4x4(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), asfloat(v.Load4(0u)))));
} }
Failed to generate: error: cannot assign to value of type 'vec4<f32>'

View File

@ -1,14 +1,10 @@
SKIP: FAILED [numthreads(1, 1, 1)]
void unused_entry_point() {
return;
struct S {
a : vec4<f32>,
} }
@group(0) @binding(0) var<storage, read_write> v : S; RWByteAddressBuffer v : register(u0, space0);
fn foo() { void foo() {
v.a *= 2.0; v.Store4(0u, asuint((asfloat(v.Load4(0u)) * 2.0f)));
} }
Failed to generate: error: cannot assign to value of type 'vec4<f32>'

View File

@ -1,14 +1,10 @@
SKIP: FAILED [numthreads(1, 1, 1)]
void unused_entry_point() {
return;
struct S {
a : vec4<i32>,
} }
@group(0) @binding(0) var<storage, read_write> v : S; RWByteAddressBuffer v : register(u0, space0);
fn foo() { void foo() {
v.a *= vec4<i32>(2); v.Store4(0u, asuint((asint(v.Load4(0u)) * int4((2).xxxx))));
} }
Failed to generate: error: cannot assign to value of type 'vec4<i32>'

View File

@ -1,14 +1,10 @@
SKIP: FAILED [numthreads(1, 1, 1)]
void unused_entry_point() {
return;
struct S {
a : vec4<i32>,
} }
@group(0) @binding(0) var<storage, read_write> v : S; RWByteAddressBuffer v : register(u0, space0);
fn foo() { void foo() {
v.a ^= vec4<i32>(2); v.Store4(0u, asuint((asint(v.Load4(0u)) ^ int4((2).xxxx))));
} }
Failed to generate: error: cannot assign to value of type 'vec4<i32>'

View File

@ -1,16 +1,14 @@
SKIP: FAILED [numthreads(1, 1, 1)]
void unused_entry_point() {
return;
var<workgroup> a : i32;
var<workgroup> b : vec4<f32>;
var<workgroup> c : mat2x2<f32>;
fn foo() {
a /= 2;
b *= mat4x4<f32>();
c *= 2.0;
} }
Failed to generate: error: unknown statement type: tint::ast::CompoundAssignmentStatement groupshared int a;
groupshared float4 b;
groupshared float2x2 c;
void foo() {
a = (a / 2);
b = mul(float4x4(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), b);
c = (c * 2.0f);
}