Add arrayLength() intrinsic that accepts a pointer argument
The old non-pointer argument overload remains, but is now deprecated. Bug: tint:806 Change-Id: Ic917ccec0f162414ce1b03df49e332ad84d8060f Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/54061 Kokoro: Kokoro <noreply+kokoro@google.com> Commit-Queue: Ben Clayton <bclayton@google.com> Reviewed-by: David Neto <dneto@google.com>
This commit is contained in:
parent
0aa7edbbd5
commit
aba42ed362
File diff suppressed because it is too large
Load Diff
|
@ -259,7 +259,8 @@ fn acos(f32) -> f32
|
||||||
fn acos<N: num>(vec<N, f32>) -> vec<N, f32>
|
fn acos<N: num>(vec<N, f32>) -> vec<N, f32>
|
||||||
fn all<N: num>(vec<N, bool>) -> bool
|
fn all<N: num>(vec<N, bool>) -> bool
|
||||||
fn any<N: num>(vec<N, bool>) -> bool
|
fn any<N: num>(vec<N, bool>) -> bool
|
||||||
fn arrayLength<T>(array<T>) -> u32
|
[[deprecated]] fn arrayLength<T>(array<T>) -> u32
|
||||||
|
fn arrayLength<T, A: access>(ptr<storage, array<T>, A>) -> u32
|
||||||
fn asin(f32) -> f32
|
fn asin(f32) -> f32
|
||||||
fn asin<N: num>(vec<N, f32>) -> vec<N, f32>
|
fn asin<N: num>(vec<N, f32>) -> vec<N, f32>
|
||||||
fn atan(f32) -> f32
|
fn atan(f32) -> f32
|
||||||
|
|
|
@ -792,8 +792,9 @@ TEST_F(ResolverIntrinsicDataTest, ArrayLength_Error_ArraySized) {
|
||||||
|
|
||||||
EXPECT_EQ(r()->error(),
|
EXPECT_EQ(r()->error(),
|
||||||
"error: no matching call to arrayLength(array<i32, 4>)\n\n"
|
"error: no matching call to arrayLength(array<i32, 4>)\n\n"
|
||||||
"1 candidate function:\n"
|
"2 candidate functions:\n"
|
||||||
" arrayLength(array<T>) -> u32\n");
|
" arrayLength(array<T>) -> u32\n"
|
||||||
|
" arrayLength(ptr<array<T>>) -> u32\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverIntrinsicDataTest, Normalize_Vector) {
|
TEST_F(ResolverIntrinsicDataTest, Normalize_Vector) {
|
||||||
|
|
|
@ -119,20 +119,29 @@ Output CalculateArrayLength::Run(const Program* in, const DataMap&) {
|
||||||
if (intrinsic->Type() == sem::IntrinsicType::kArrayLength) {
|
if (intrinsic->Type() == sem::IntrinsicType::kArrayLength) {
|
||||||
// We're dealing with an arrayLength() call
|
// We're dealing with an arrayLength() call
|
||||||
|
|
||||||
// https://gpuweb.github.io/gpuweb/wgsl.html#array-types states:
|
// https://gpuweb.github.io/gpuweb/wgsl/#array-types states:
|
||||||
//
|
//
|
||||||
// * The last member of the structure type defining the store type for
|
// * The last member of the structure type defining the store type for
|
||||||
// a variable in the storage storage class may be a runtime-sized
|
// a variable in the storage storage class may be a runtime-sized
|
||||||
// array.
|
// array.
|
||||||
// * A runtime-sized array must not be used as the store type or
|
// * A runtime-sized array must not be used as the store type or
|
||||||
// contained within a store type in any other cases.
|
// contained within a store type in any other cases.
|
||||||
// * The type of an expression must not be a runtime-sized array type.
|
// * An expression must not evaluate to a runtime-sized array type.
|
||||||
// arrayLength()
|
|
||||||
//
|
//
|
||||||
// We can assume that the arrayLength() call has a single argument of
|
// We can assume that the arrayLength() call has a single argument of
|
||||||
// the form: arrayLength(X.Y) where X is an expression that resolves
|
// the form: arrayLength(&X.Y) or the now deprecated form
|
||||||
// to the storage buffer structure, and Y is the runtime sized array.
|
// arrayLength(X.Y) where X is an expression that resolves to the
|
||||||
|
// storage buffer structure, and Y is the runtime sized array.
|
||||||
auto* array_expr = call_expr->params()[0];
|
auto* array_expr = call_expr->params()[0];
|
||||||
|
|
||||||
|
// TODO(crbug.com/tint/806): Once the deprecated arrayLength()
|
||||||
|
// overload is removed, this can safely assume a pointer arg.
|
||||||
|
if (auto* address_of = array_expr->As<ast::UnaryOpExpression>()) {
|
||||||
|
if (address_of->op() == ast::UnaryOp::kAddressOf) {
|
||||||
|
array_expr = address_of->expr();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
auto* accessor = array_expr->As<ast::MemberAccessorExpression>();
|
auto* accessor = array_expr->As<ast::MemberAccessorExpression>();
|
||||||
if (!accessor) {
|
if (!accessor) {
|
||||||
TINT_ICE(ctx.dst->Diagnostics())
|
TINT_ICE(ctx.dst->Diagnostics())
|
||||||
|
|
|
@ -22,7 +22,8 @@ namespace {
|
||||||
|
|
||||||
using CalculateArrayLengthTest = TransformTest;
|
using CalculateArrayLengthTest = TransformTest;
|
||||||
|
|
||||||
TEST_F(CalculateArrayLengthTest, Basic) {
|
// TODO(crbug.com/tint/806): Remove
|
||||||
|
TEST_F(CalculateArrayLengthTest, Basic_DEPRECATED) {
|
||||||
auto* src = R"(
|
auto* src = R"(
|
||||||
[[block]]
|
[[block]]
|
||||||
struct SB {
|
struct SB {
|
||||||
|
@ -64,7 +65,8 @@ fn main() {
|
||||||
EXPECT_EQ(expect, str(got));
|
EXPECT_EQ(expect, str(got));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(CalculateArrayLengthTest, InSameBlock) {
|
// TODO(crbug.com/tint/806): Remove
|
||||||
|
TEST_F(CalculateArrayLengthTest, InSameBlock_DEPRECATED) {
|
||||||
auto* src = R"(
|
auto* src = R"(
|
||||||
[[block]]
|
[[block]]
|
||||||
struct SB {
|
struct SB {
|
||||||
|
@ -110,7 +112,8 @@ fn main() {
|
||||||
EXPECT_EQ(expect, str(got));
|
EXPECT_EQ(expect, str(got));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(CalculateArrayLengthTest, WithStride) {
|
// TODO(crbug.com/tint/806): Remove
|
||||||
|
TEST_F(CalculateArrayLengthTest, WithStride_DEPRECATED) {
|
||||||
auto* src = R"(
|
auto* src = R"(
|
||||||
[[block]]
|
[[block]]
|
||||||
struct SB {
|
struct SB {
|
||||||
|
@ -154,7 +157,8 @@ fn main() {
|
||||||
EXPECT_EQ(expect, str(got));
|
EXPECT_EQ(expect, str(got));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(CalculateArrayLengthTest, Nested) {
|
// TODO(crbug.com/tint/806): Remove
|
||||||
|
TEST_F(CalculateArrayLengthTest, Nested_DEPRECATED) {
|
||||||
auto* src = R"(
|
auto* src = R"(
|
||||||
[[block]]
|
[[block]]
|
||||||
struct SB {
|
struct SB {
|
||||||
|
@ -211,7 +215,8 @@ fn main() {
|
||||||
EXPECT_EQ(expect, str(got));
|
EXPECT_EQ(expect, str(got));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(CalculateArrayLengthTest, MultipleStorageBuffers) {
|
// TODO(crbug.com/tint/806): Remove
|
||||||
|
TEST_F(CalculateArrayLengthTest, MultipleStorageBuffers_DEPRECATED) {
|
||||||
auto* src = R"(
|
auto* src = R"(
|
||||||
[[block]]
|
[[block]]
|
||||||
struct SB1 {
|
struct SB1 {
|
||||||
|
@ -279,6 +284,263 @@ fn main() {
|
||||||
EXPECT_EQ(expect, str(got));
|
EXPECT_EQ(expect, str(got));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(CalculateArrayLengthTest, Basic) {
|
||||||
|
auto* src = R"(
|
||||||
|
[[block]]
|
||||||
|
struct SB {
|
||||||
|
x : i32;
|
||||||
|
arr : array<i32>;
|
||||||
|
};
|
||||||
|
|
||||||
|
[[group(0), binding(0)]] var<storage, read> sb : SB;
|
||||||
|
|
||||||
|
[[stage(compute)]]
|
||||||
|
fn main() {
|
||||||
|
var len : u32 = arrayLength(&sb.arr);
|
||||||
|
}
|
||||||
|
)";
|
||||||
|
|
||||||
|
auto* expect = R"(
|
||||||
|
[[block]]
|
||||||
|
struct SB {
|
||||||
|
x : i32;
|
||||||
|
arr : array<i32>;
|
||||||
|
};
|
||||||
|
|
||||||
|
[[internal(intrinsic_buffer_size)]]
|
||||||
|
fn tint_symbol(buffer : SB, result : ptr<function, u32>)
|
||||||
|
|
||||||
|
[[group(0), binding(0)]] var<storage, read> sb : SB;
|
||||||
|
|
||||||
|
[[stage(compute)]]
|
||||||
|
fn main() {
|
||||||
|
var tint_symbol_1 : u32 = 0u;
|
||||||
|
tint_symbol(sb, &(tint_symbol_1));
|
||||||
|
let tint_symbol_2 : u32 = ((tint_symbol_1 - 4u) / 4u);
|
||||||
|
var len : u32 = tint_symbol_2;
|
||||||
|
}
|
||||||
|
)";
|
||||||
|
|
||||||
|
auto got = Run<CalculateArrayLength>(src);
|
||||||
|
|
||||||
|
EXPECT_EQ(expect, str(got));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(CalculateArrayLengthTest, InSameBlock) {
|
||||||
|
auto* src = R"(
|
||||||
|
[[block]]
|
||||||
|
struct SB {
|
||||||
|
x : i32;
|
||||||
|
arr : array<i32>;
|
||||||
|
};
|
||||||
|
|
||||||
|
[[group(0), binding(0)]] var<storage, read> sb : SB;
|
||||||
|
|
||||||
|
[[stage(compute)]]
|
||||||
|
fn main() {
|
||||||
|
var a : u32 = arrayLength(&sb.arr);
|
||||||
|
var b : u32 = arrayLength(&sb.arr);
|
||||||
|
var c : u32 = arrayLength(&sb.arr);
|
||||||
|
}
|
||||||
|
)";
|
||||||
|
|
||||||
|
auto* expect = R"(
|
||||||
|
[[block]]
|
||||||
|
struct SB {
|
||||||
|
x : i32;
|
||||||
|
arr : array<i32>;
|
||||||
|
};
|
||||||
|
|
||||||
|
[[internal(intrinsic_buffer_size)]]
|
||||||
|
fn tint_symbol(buffer : SB, result : ptr<function, u32>)
|
||||||
|
|
||||||
|
[[group(0), binding(0)]] var<storage, read> sb : SB;
|
||||||
|
|
||||||
|
[[stage(compute)]]
|
||||||
|
fn main() {
|
||||||
|
var tint_symbol_1 : u32 = 0u;
|
||||||
|
tint_symbol(sb, &(tint_symbol_1));
|
||||||
|
let tint_symbol_2 : u32 = ((tint_symbol_1 - 4u) / 4u);
|
||||||
|
var a : u32 = tint_symbol_2;
|
||||||
|
var b : u32 = tint_symbol_2;
|
||||||
|
var c : u32 = tint_symbol_2;
|
||||||
|
}
|
||||||
|
)";
|
||||||
|
|
||||||
|
auto got = Run<CalculateArrayLength>(src);
|
||||||
|
|
||||||
|
EXPECT_EQ(expect, str(got));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(CalculateArrayLengthTest, WithStride) {
|
||||||
|
auto* src = R"(
|
||||||
|
[[block]]
|
||||||
|
struct SB {
|
||||||
|
x : i32;
|
||||||
|
y : f32;
|
||||||
|
arr : [[stride(64)]] array<i32>;
|
||||||
|
};
|
||||||
|
|
||||||
|
[[group(0), binding(0)]] var<storage, read> sb : SB;
|
||||||
|
|
||||||
|
[[stage(compute)]]
|
||||||
|
fn main() {
|
||||||
|
var len : u32 = arrayLength(&sb.arr);
|
||||||
|
}
|
||||||
|
)";
|
||||||
|
|
||||||
|
auto* expect = R"(
|
||||||
|
[[block]]
|
||||||
|
struct SB {
|
||||||
|
x : i32;
|
||||||
|
y : f32;
|
||||||
|
arr : [[stride(64)]] array<i32>;
|
||||||
|
};
|
||||||
|
|
||||||
|
[[internal(intrinsic_buffer_size)]]
|
||||||
|
fn tint_symbol(buffer : SB, result : ptr<function, u32>)
|
||||||
|
|
||||||
|
[[group(0), binding(0)]] var<storage, read> sb : SB;
|
||||||
|
|
||||||
|
[[stage(compute)]]
|
||||||
|
fn main() {
|
||||||
|
var tint_symbol_1 : u32 = 0u;
|
||||||
|
tint_symbol(sb, &(tint_symbol_1));
|
||||||
|
let tint_symbol_2 : u32 = ((tint_symbol_1 - 8u) / 64u);
|
||||||
|
var len : u32 = tint_symbol_2;
|
||||||
|
}
|
||||||
|
)";
|
||||||
|
|
||||||
|
auto got = Run<CalculateArrayLength>(src);
|
||||||
|
|
||||||
|
EXPECT_EQ(expect, str(got));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(CalculateArrayLengthTest, Nested) {
|
||||||
|
auto* src = R"(
|
||||||
|
[[block]]
|
||||||
|
struct SB {
|
||||||
|
x : i32;
|
||||||
|
arr : array<i32>;
|
||||||
|
};
|
||||||
|
|
||||||
|
[[group(0), binding(0)]] var<storage, read> sb : SB;
|
||||||
|
|
||||||
|
[[stage(compute)]]
|
||||||
|
fn main() {
|
||||||
|
if (true) {
|
||||||
|
var len : u32 = arrayLength(&sb.arr);
|
||||||
|
} else {
|
||||||
|
if (true) {
|
||||||
|
var len : u32 = arrayLength(&sb.arr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)";
|
||||||
|
|
||||||
|
auto* expect = R"(
|
||||||
|
[[block]]
|
||||||
|
struct SB {
|
||||||
|
x : i32;
|
||||||
|
arr : array<i32>;
|
||||||
|
};
|
||||||
|
|
||||||
|
[[internal(intrinsic_buffer_size)]]
|
||||||
|
fn tint_symbol(buffer : SB, result : ptr<function, u32>)
|
||||||
|
|
||||||
|
[[group(0), binding(0)]] var<storage, read> sb : SB;
|
||||||
|
|
||||||
|
[[stage(compute)]]
|
||||||
|
fn main() {
|
||||||
|
if (true) {
|
||||||
|
var tint_symbol_1 : u32 = 0u;
|
||||||
|
tint_symbol(sb, &(tint_symbol_1));
|
||||||
|
let tint_symbol_2 : u32 = ((tint_symbol_1 - 4u) / 4u);
|
||||||
|
var len : u32 = tint_symbol_2;
|
||||||
|
} else {
|
||||||
|
if (true) {
|
||||||
|
var tint_symbol_3 : u32 = 0u;
|
||||||
|
tint_symbol(sb, &(tint_symbol_3));
|
||||||
|
let tint_symbol_4 : u32 = ((tint_symbol_3 - 4u) / 4u);
|
||||||
|
var len : u32 = tint_symbol_4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)";
|
||||||
|
|
||||||
|
auto got = Run<CalculateArrayLength>(src);
|
||||||
|
|
||||||
|
EXPECT_EQ(expect, str(got));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(CalculateArrayLengthTest, MultipleStorageBuffers) {
|
||||||
|
auto* src = R"(
|
||||||
|
[[block]]
|
||||||
|
struct SB1 {
|
||||||
|
x : i32;
|
||||||
|
arr1 : array<i32>;
|
||||||
|
};
|
||||||
|
|
||||||
|
[[block]]
|
||||||
|
struct SB2 {
|
||||||
|
x : i32;
|
||||||
|
arr2 : array<vec4<f32>>;
|
||||||
|
};
|
||||||
|
|
||||||
|
[[group(0), binding(0)]] var<storage, read> sb1 : SB1;
|
||||||
|
|
||||||
|
[[group(0), binding(1)]] var<storage, read> sb2 : SB2;
|
||||||
|
|
||||||
|
[[stage(compute)]]
|
||||||
|
fn main() {
|
||||||
|
var len1 : u32 = arrayLength(&(sb1.arr1));
|
||||||
|
var len2 : u32 = arrayLength(&(sb2.arr2));
|
||||||
|
var x : u32 = (len1 + len2);
|
||||||
|
}
|
||||||
|
)";
|
||||||
|
|
||||||
|
auto* expect = R"(
|
||||||
|
[[block]]
|
||||||
|
struct SB1 {
|
||||||
|
x : i32;
|
||||||
|
arr1 : array<i32>;
|
||||||
|
};
|
||||||
|
|
||||||
|
[[internal(intrinsic_buffer_size)]]
|
||||||
|
fn tint_symbol(buffer : SB1, result : ptr<function, u32>)
|
||||||
|
|
||||||
|
[[block]]
|
||||||
|
struct SB2 {
|
||||||
|
x : i32;
|
||||||
|
arr2 : array<vec4<f32>>;
|
||||||
|
};
|
||||||
|
|
||||||
|
[[internal(intrinsic_buffer_size)]]
|
||||||
|
fn tint_symbol_3(buffer : SB2, result : ptr<function, u32>)
|
||||||
|
|
||||||
|
[[group(0), binding(0)]] var<storage, read> sb1 : SB1;
|
||||||
|
|
||||||
|
[[group(0), binding(1)]] var<storage, read> sb2 : SB2;
|
||||||
|
|
||||||
|
[[stage(compute)]]
|
||||||
|
fn main() {
|
||||||
|
var tint_symbol_1 : u32 = 0u;
|
||||||
|
tint_symbol(sb1, &(tint_symbol_1));
|
||||||
|
let tint_symbol_2 : u32 = ((tint_symbol_1 - 4u) / 4u);
|
||||||
|
var tint_symbol_4 : u32 = 0u;
|
||||||
|
tint_symbol_3(sb2, &(tint_symbol_4));
|
||||||
|
let tint_symbol_5 : u32 = ((tint_symbol_4 - 16u) / 16u);
|
||||||
|
var len1 : u32 = tint_symbol_2;
|
||||||
|
var len2 : u32 = tint_symbol_5;
|
||||||
|
var x : u32 = (len1 + len2);
|
||||||
|
}
|
||||||
|
)";
|
||||||
|
|
||||||
|
auto got = Run<CalculateArrayLength>(src);
|
||||||
|
|
||||||
|
EXPECT_EQ(expect, str(got));
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
} // namespace transform
|
} // namespace transform
|
||||||
} // namespace tint
|
} // namespace tint
|
||||||
|
|
|
@ -30,6 +30,7 @@
|
||||||
#include "src/sem/call.h"
|
#include "src/sem/call.h"
|
||||||
#include "src/sem/member_accessor_expression.h"
|
#include "src/sem/member_accessor_expression.h"
|
||||||
#include "src/sem/reference_type.h"
|
#include "src/sem/reference_type.h"
|
||||||
|
#include "src/sem/statement.h"
|
||||||
#include "src/sem/struct.h"
|
#include "src/sem/struct.h"
|
||||||
#include "src/sem/variable.h"
|
#include "src/sem/variable.h"
|
||||||
#include "src/utils/get_or_create.h"
|
#include "src/utils/get_or_create.h"
|
||||||
|
@ -742,7 +743,14 @@ Output DecomposeStorageAccess::Run(const Program* in, const DataMap&) {
|
||||||
// arrayLength(X)
|
// arrayLength(X)
|
||||||
// Don't convert X into a load, this actually requires the real
|
// Don't convert X into a load, this actually requires the real
|
||||||
// reference.
|
// reference.
|
||||||
state.TakeAccess(call_expr->params()[0]);
|
auto* arg = call_expr->params()[0];
|
||||||
|
|
||||||
|
// TODO(crbug.com/tint/806): Once the deprecated arrayLength()
|
||||||
|
// overload is removed, this can safely assume a pointer arg.
|
||||||
|
if (auto* address_of = arg->As<ast::UnaryOpExpression>()) {
|
||||||
|
arg = address_of->expr();
|
||||||
|
}
|
||||||
|
state.TakeAccess(arg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,6 +44,9 @@ Output Hlsl::Run(const Program* in, const DataMap&) {
|
||||||
// after Simplify, as we need to fold away the address-of and defers of
|
// after Simplify, as we need to fold away the address-of and defers of
|
||||||
// `*(&(intrinsic_load()))` expressions.
|
// `*(&(intrinsic_load()))` expressions.
|
||||||
manager.Add<DecomposeStorageAccess>();
|
manager.Add<DecomposeStorageAccess>();
|
||||||
|
// CalculateArrayLength must come after DecomposeStorageAccess, as
|
||||||
|
// DecomposeStorageAccess special-cases the arrayLength() intrinsic, which
|
||||||
|
// will be transformed by CalculateArrayLength
|
||||||
manager.Add<CalculateArrayLength>();
|
manager.Add<CalculateArrayLength>();
|
||||||
manager.Add<ExternalTextureTransform>();
|
manager.Add<ExternalTextureTransform>();
|
||||||
manager.Add<PromoteInitializersToConstVar>();
|
manager.Add<PromoteInitializersToConstVar>();
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include "src/ast/call_statement.h"
|
||||||
#include "src/ast/stage_decoration.h"
|
#include "src/ast/stage_decoration.h"
|
||||||
#include "src/ast/struct_block_decoration.h"
|
#include "src/ast/struct_block_decoration.h"
|
||||||
#include "src/ast/variable_decl_statement.h"
|
#include "src/ast/variable_decl_statement.h"
|
||||||
|
@ -24,7 +25,8 @@ namespace {
|
||||||
|
|
||||||
using HlslSanitizerTest = TestHelper;
|
using HlslSanitizerTest = TestHelper;
|
||||||
|
|
||||||
TEST_F(HlslSanitizerTest, ArrayLength) {
|
// TODO(crbug.com/tint/806): Remove
|
||||||
|
TEST_F(HlslSanitizerTest, ArrayLength_DEPRECATED) {
|
||||||
auto* sb_ty = Structure("SB",
|
auto* sb_ty = Structure("SB",
|
||||||
{
|
{
|
||||||
Member("x", ty.f32()),
|
Member("x", ty.f32()),
|
||||||
|
@ -69,6 +71,131 @@ void main() {
|
||||||
EXPECT_EQ(expect, got);
|
EXPECT_EQ(expect, got);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(HlslSanitizerTest, Call_ArrayLength) {
|
||||||
|
auto* s = Structure("my_struct", {Member(0, "a", ty.array<f32>(4))},
|
||||||
|
{create<ast::StructBlockDecoration>()});
|
||||||
|
Global("b", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
|
||||||
|
ast::DecorationList{
|
||||||
|
create<ast::BindingDecoration>(1),
|
||||||
|
create<ast::GroupDecoration>(2),
|
||||||
|
});
|
||||||
|
|
||||||
|
Func("a_func", ast::VariableList{}, ty.void_(),
|
||||||
|
ast::StatementList{
|
||||||
|
Decl(Var("len", ty.u32(), ast::StorageClass::kNone,
|
||||||
|
Call("arrayLength", AddressOf(MemberAccessor("b", "a"))))),
|
||||||
|
},
|
||||||
|
ast::DecorationList{
|
||||||
|
Stage(ast::PipelineStage::kFragment),
|
||||||
|
});
|
||||||
|
|
||||||
|
GeneratorImpl& gen = SanitizeAndBuild();
|
||||||
|
|
||||||
|
ASSERT_TRUE(gen.Generate(out)) << gen.error();
|
||||||
|
|
||||||
|
auto got = result();
|
||||||
|
auto* expect = R"(
|
||||||
|
ByteAddressBuffer b : register(t1, space2);
|
||||||
|
|
||||||
|
void a_func() {
|
||||||
|
uint tint_symbol_1 = 0u;
|
||||||
|
b.GetDimensions(tint_symbol_1);
|
||||||
|
const uint tint_symbol_2 = ((tint_symbol_1 - 0u) / 4u);
|
||||||
|
uint len = tint_symbol_2;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
)";
|
||||||
|
EXPECT_EQ(expect, got);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(HlslSanitizerTest, Call_ArrayLength_OtherMembersInStruct) {
|
||||||
|
auto* s = Structure("my_struct",
|
||||||
|
{
|
||||||
|
Member(0, "z", ty.f32()),
|
||||||
|
Member(4, "a", ty.array<f32>(4)),
|
||||||
|
},
|
||||||
|
{create<ast::StructBlockDecoration>()});
|
||||||
|
Global("b", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
|
||||||
|
ast::DecorationList{
|
||||||
|
create<ast::BindingDecoration>(1),
|
||||||
|
create<ast::GroupDecoration>(2),
|
||||||
|
});
|
||||||
|
|
||||||
|
Func("a_func", ast::VariableList{}, ty.void_(),
|
||||||
|
ast::StatementList{
|
||||||
|
Decl(Var("len", ty.u32(), ast::StorageClass::kNone,
|
||||||
|
Call("arrayLength", AddressOf(MemberAccessor("b", "a"))))),
|
||||||
|
},
|
||||||
|
ast::DecorationList{
|
||||||
|
Stage(ast::PipelineStage::kFragment),
|
||||||
|
});
|
||||||
|
|
||||||
|
GeneratorImpl& gen = SanitizeAndBuild();
|
||||||
|
|
||||||
|
ASSERT_TRUE(gen.Generate(out)) << gen.error();
|
||||||
|
|
||||||
|
auto got = result();
|
||||||
|
auto* expect = R"(
|
||||||
|
ByteAddressBuffer b : register(t1, space2);
|
||||||
|
|
||||||
|
void a_func() {
|
||||||
|
uint tint_symbol_1 = 0u;
|
||||||
|
b.GetDimensions(tint_symbol_1);
|
||||||
|
const uint tint_symbol_2 = ((tint_symbol_1 - 4u) / 4u);
|
||||||
|
uint len = tint_symbol_2;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
)";
|
||||||
|
|
||||||
|
EXPECT_EQ(expect, got);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(HlslSanitizerTest, Call_ArrayLength_ViaLets) {
|
||||||
|
auto* s = Structure("my_struct", {Member(0, "a", ty.array<f32>(4))},
|
||||||
|
{create<ast::StructBlockDecoration>()});
|
||||||
|
Global("b", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
|
||||||
|
ast::DecorationList{
|
||||||
|
create<ast::BindingDecoration>(1),
|
||||||
|
create<ast::GroupDecoration>(2),
|
||||||
|
});
|
||||||
|
|
||||||
|
auto* p = Const("p", nullptr, AddressOf("b"));
|
||||||
|
auto* p2 = Const("p2", nullptr, AddressOf(MemberAccessor(Deref(p), "a")));
|
||||||
|
|
||||||
|
Func("a_func", ast::VariableList{}, ty.void_(),
|
||||||
|
ast::StatementList{
|
||||||
|
Decl(p),
|
||||||
|
Decl(p2),
|
||||||
|
Decl(Var("len", ty.u32(), ast::StorageClass::kNone,
|
||||||
|
Call("arrayLength", p2))),
|
||||||
|
},
|
||||||
|
ast::DecorationList{
|
||||||
|
Stage(ast::PipelineStage::kFragment),
|
||||||
|
});
|
||||||
|
|
||||||
|
GeneratorImpl& gen = SanitizeAndBuild();
|
||||||
|
|
||||||
|
ASSERT_TRUE(gen.Generate(out)) << gen.error();
|
||||||
|
|
||||||
|
auto got = result();
|
||||||
|
auto* expect = R"(
|
||||||
|
ByteAddressBuffer b : register(t1, space2);
|
||||||
|
|
||||||
|
void a_func() {
|
||||||
|
uint tint_symbol_1 = 0u;
|
||||||
|
b.GetDimensions(tint_symbol_1);
|
||||||
|
const uint tint_symbol_2 = ((tint_symbol_1 - 0u) / 4u);
|
||||||
|
uint len = tint_symbol_2;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
)";
|
||||||
|
|
||||||
|
EXPECT_EQ(expect, got);
|
||||||
|
}
|
||||||
|
|
||||||
TEST_F(HlslSanitizerTest, PromoteArrayInitializerToConstVar) {
|
TEST_F(HlslSanitizerTest, PromoteArrayInitializerToConstVar) {
|
||||||
auto* array_init = array<i32, 4>(1, 2, 3, 4);
|
auto* array_init = array<i32, 4>(1, 2, 3, 4);
|
||||||
auto* array_index = IndexAccessor(array_init, 3);
|
auto* array_index = IndexAccessor(array_init, 3);
|
||||||
|
|
|
@ -2187,9 +2187,17 @@ uint32_t Builder::GenerateIntrinsic(ast::CallExpression* call,
|
||||||
}
|
}
|
||||||
auto* arg = call->params()[0];
|
auto* arg = call->params()[0];
|
||||||
|
|
||||||
|
// TODO(crbug.com/tint/806): Once the deprecated arrayLength()
|
||||||
|
// overload is removed, this can safely assume a pointer arg.
|
||||||
|
if (auto* address_of = arg->As<ast::UnaryOpExpression>()) {
|
||||||
|
arg = address_of->expr();
|
||||||
|
}
|
||||||
|
|
||||||
auto* accessor = arg->As<ast::MemberAccessorExpression>();
|
auto* accessor = arg->As<ast::MemberAccessorExpression>();
|
||||||
if (accessor == nullptr) {
|
if (accessor == nullptr) {
|
||||||
error_ = "invalid expression for array length";
|
// The InlinePtrLets and Simplify transforms should have sanitized any
|
||||||
|
// lets, or &*&*& noise.
|
||||||
|
error_ = "expected argument to arrayLength() to be a member accessor";
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1571,7 +1571,8 @@ OpFunctionEnd
|
||||||
)");
|
)");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(IntrinsicBuilderTest, Call_ArrayLength) {
|
// TODO(crbug.com/tint/806): Remove
|
||||||
|
TEST_F(IntrinsicBuilderTest, Call_ArrayLength_DEPRECATED) {
|
||||||
auto* s = Structure("my_struct", {Member(0, "a", ty.array<f32>(4))},
|
auto* s = Structure("my_struct", {Member(0, "a", ty.array<f32>(4))},
|
||||||
{create<ast::StructBlockDecoration>()});
|
{create<ast::StructBlockDecoration>()});
|
||||||
Global("b", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
|
Global("b", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
|
||||||
|
@ -1616,6 +1617,101 @@ TEST_F(IntrinsicBuilderTest, Call_ArrayLength) {
|
||||||
Validate(b);
|
Validate(b);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO(crbug.com/tint/806): Remove
|
||||||
|
TEST_F(IntrinsicBuilderTest, Call_ArrayLength_OtherMembersInStruct_DEPRECATED) {
|
||||||
|
auto* s = Structure("my_struct",
|
||||||
|
{
|
||||||
|
Member(0, "z", ty.f32()),
|
||||||
|
Member(4, "a", ty.array<f32>(4)),
|
||||||
|
},
|
||||||
|
{create<ast::StructBlockDecoration>()});
|
||||||
|
Global("b", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
|
||||||
|
ast::DecorationList{
|
||||||
|
create<ast::BindingDecoration>(1),
|
||||||
|
create<ast::GroupDecoration>(2),
|
||||||
|
});
|
||||||
|
|
||||||
|
auto* expr = Call("arrayLength", MemberAccessor("b", "a"));
|
||||||
|
|
||||||
|
Func("a_func", ast::VariableList{}, ty.void_(),
|
||||||
|
ast::StatementList{
|
||||||
|
create<ast::CallStatement>(expr),
|
||||||
|
},
|
||||||
|
ast::DecorationList{
|
||||||
|
Stage(ast::PipelineStage::kFragment),
|
||||||
|
});
|
||||||
|
|
||||||
|
spirv::Builder& b = Build();
|
||||||
|
|
||||||
|
ASSERT_TRUE(b.Build()) << b.error();
|
||||||
|
|
||||||
|
ASSERT_EQ(b.functions().size(), 1u);
|
||||||
|
|
||||||
|
auto* expected_types = R"(%4 = OpTypeFloat 32
|
||||||
|
%5 = OpTypeRuntimeArray %4
|
||||||
|
%3 = OpTypeStruct %4 %5
|
||||||
|
%2 = OpTypePointer StorageBuffer %3
|
||||||
|
%1 = OpVariable %2 StorageBuffer
|
||||||
|
%7 = OpTypeVoid
|
||||||
|
%6 = OpTypeFunction %7
|
||||||
|
%11 = OpTypeInt 32 0
|
||||||
|
)";
|
||||||
|
auto got_types = DumpInstructions(b.types());
|
||||||
|
EXPECT_EQ(expected_types, got_types);
|
||||||
|
|
||||||
|
auto* expected_instructions = R"(%10 = OpArrayLength %11 %1 1
|
||||||
|
)";
|
||||||
|
auto got_instructions = DumpInstructions(b.functions()[0].instructions());
|
||||||
|
EXPECT_EQ(expected_instructions, got_instructions);
|
||||||
|
|
||||||
|
Validate(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(IntrinsicBuilderTest, Call_ArrayLength) {
|
||||||
|
auto* s = Structure("my_struct", {Member(0, "a", ty.array<f32>(4))},
|
||||||
|
{create<ast::StructBlockDecoration>()});
|
||||||
|
Global("b", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
|
||||||
|
ast::DecorationList{
|
||||||
|
create<ast::BindingDecoration>(1),
|
||||||
|
create<ast::GroupDecoration>(2),
|
||||||
|
});
|
||||||
|
|
||||||
|
auto* expr = Call("arrayLength", AddressOf(MemberAccessor("b", "a")));
|
||||||
|
|
||||||
|
Func("a_func", ast::VariableList{}, ty.void_(),
|
||||||
|
ast::StatementList{
|
||||||
|
create<ast::CallStatement>(expr),
|
||||||
|
},
|
||||||
|
ast::DecorationList{
|
||||||
|
Stage(ast::PipelineStage::kFragment),
|
||||||
|
});
|
||||||
|
|
||||||
|
spirv::Builder& b = Build();
|
||||||
|
|
||||||
|
ASSERT_TRUE(b.Build()) << b.error();
|
||||||
|
|
||||||
|
ASSERT_EQ(b.functions().size(), 1u);
|
||||||
|
|
||||||
|
auto* expected_types = R"(%5 = OpTypeFloat 32
|
||||||
|
%4 = OpTypeRuntimeArray %5
|
||||||
|
%3 = OpTypeStruct %4
|
||||||
|
%2 = OpTypePointer StorageBuffer %3
|
||||||
|
%1 = OpVariable %2 StorageBuffer
|
||||||
|
%7 = OpTypeVoid
|
||||||
|
%6 = OpTypeFunction %7
|
||||||
|
%11 = OpTypeInt 32 0
|
||||||
|
)";
|
||||||
|
auto got_types = DumpInstructions(b.types());
|
||||||
|
EXPECT_EQ(expected_types, got_types);
|
||||||
|
|
||||||
|
auto* expected_instructions = R"(%10 = OpArrayLength %11 %1 0
|
||||||
|
)";
|
||||||
|
auto got_instructions = DumpInstructions(b.functions()[0].instructions());
|
||||||
|
EXPECT_EQ(expected_instructions, got_instructions);
|
||||||
|
|
||||||
|
Validate(b);
|
||||||
|
}
|
||||||
|
|
||||||
TEST_F(IntrinsicBuilderTest, Call_ArrayLength_OtherMembersInStruct) {
|
TEST_F(IntrinsicBuilderTest, Call_ArrayLength_OtherMembersInStruct) {
|
||||||
auto* s = Structure("my_struct",
|
auto* s = Structure("my_struct",
|
||||||
{
|
{
|
||||||
|
@ -1629,7 +1725,7 @@ TEST_F(IntrinsicBuilderTest, Call_ArrayLength_OtherMembersInStruct) {
|
||||||
create<ast::GroupDecoration>(2),
|
create<ast::GroupDecoration>(2),
|
||||||
});
|
});
|
||||||
|
|
||||||
auto* expr = Call("arrayLength", MemberAccessor("b", "a"));
|
auto* expr = Call("arrayLength", AddressOf(MemberAccessor("b", "a")));
|
||||||
|
|
||||||
Func("a_func", ast::VariableList{}, ty.void_(),
|
Func("a_func", ast::VariableList{}, ty.void_(),
|
||||||
ast::StatementList{
|
ast::StatementList{
|
||||||
|
@ -1665,6 +1761,116 @@ TEST_F(IntrinsicBuilderTest, Call_ArrayLength_OtherMembersInStruct) {
|
||||||
Validate(b);
|
Validate(b);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(IntrinsicBuilderTest, Call_ArrayLength_ViaLets) {
|
||||||
|
auto* s = Structure("my_struct", {Member(0, "a", ty.array<f32>(4))},
|
||||||
|
{create<ast::StructBlockDecoration>()});
|
||||||
|
Global("b", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
|
||||||
|
ast::DecorationList{
|
||||||
|
create<ast::BindingDecoration>(1),
|
||||||
|
create<ast::GroupDecoration>(2),
|
||||||
|
});
|
||||||
|
|
||||||
|
auto* p = Const("p", nullptr, AddressOf("b"));
|
||||||
|
auto* p2 = Const("p2", nullptr, AddressOf(MemberAccessor(Deref(p), "a")));
|
||||||
|
auto* expr = Call("arrayLength", p2);
|
||||||
|
|
||||||
|
Func("a_func", ast::VariableList{}, ty.void_(),
|
||||||
|
ast::StatementList{
|
||||||
|
Decl(p),
|
||||||
|
Decl(p2),
|
||||||
|
create<ast::CallStatement>(expr),
|
||||||
|
},
|
||||||
|
ast::DecorationList{
|
||||||
|
Stage(ast::PipelineStage::kFragment),
|
||||||
|
});
|
||||||
|
|
||||||
|
spirv::Builder& b = SanitizeAndBuild();
|
||||||
|
|
||||||
|
ASSERT_TRUE(b.Build()) << b.error();
|
||||||
|
|
||||||
|
ASSERT_EQ(b.functions().size(), 1u);
|
||||||
|
|
||||||
|
auto* expected_types = R"(%5 = OpTypeFloat 32
|
||||||
|
%4 = OpTypeRuntimeArray %5
|
||||||
|
%3 = OpTypeStruct %4
|
||||||
|
%2 = OpTypePointer StorageBuffer %3
|
||||||
|
%1 = OpVariable %2 StorageBuffer
|
||||||
|
%7 = OpTypeVoid
|
||||||
|
%6 = OpTypeFunction %7
|
||||||
|
%11 = OpTypeInt 32 0
|
||||||
|
)";
|
||||||
|
auto got_types = DumpInstructions(b.types());
|
||||||
|
EXPECT_EQ(expected_types, got_types);
|
||||||
|
|
||||||
|
auto* expected_instructions = R"(%10 = OpArrayLength %11 %1 0
|
||||||
|
)";
|
||||||
|
auto got_instructions = DumpInstructions(b.functions()[0].instructions());
|
||||||
|
EXPECT_EQ(expected_instructions, got_instructions);
|
||||||
|
|
||||||
|
Validate(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(IntrinsicBuilderTest, Call_ArrayLength_ViaLets_WithPtrNoise) {
|
||||||
|
// struct my_struct {
|
||||||
|
// a : [[stride(4)]] array<f32>;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// fn a_func() {
|
||||||
|
// let p = &*&b;
|
||||||
|
// let p2 = &*p;
|
||||||
|
// let p3 = &((*p).a);
|
||||||
|
// arrayLength(&*p3);
|
||||||
|
// }
|
||||||
|
auto* s = Structure("my_struct", {Member(0, "a", ty.array<f32>(4))},
|
||||||
|
{create<ast::StructBlockDecoration>()});
|
||||||
|
Global("b", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
|
||||||
|
ast::DecorationList{
|
||||||
|
create<ast::BindingDecoration>(1),
|
||||||
|
create<ast::GroupDecoration>(2),
|
||||||
|
});
|
||||||
|
|
||||||
|
auto* p = Const("p", nullptr, AddressOf(Deref(AddressOf("b"))));
|
||||||
|
auto* p2 = Const("p2", nullptr, AddressOf(Deref(p)));
|
||||||
|
auto* p3 = Const("p3", nullptr, AddressOf(MemberAccessor(Deref(p2), "a")));
|
||||||
|
auto* expr = Call("arrayLength", AddressOf(Deref(p3)));
|
||||||
|
|
||||||
|
Func("a_func", ast::VariableList{}, ty.void_(),
|
||||||
|
ast::StatementList{
|
||||||
|
Decl(p),
|
||||||
|
Decl(p2),
|
||||||
|
Decl(p3),
|
||||||
|
create<ast::CallStatement>(expr),
|
||||||
|
},
|
||||||
|
ast::DecorationList{
|
||||||
|
Stage(ast::PipelineStage::kFragment),
|
||||||
|
});
|
||||||
|
|
||||||
|
spirv::Builder& b = SanitizeAndBuild();
|
||||||
|
|
||||||
|
ASSERT_TRUE(b.Build()) << b.error();
|
||||||
|
|
||||||
|
ASSERT_EQ(b.functions().size(), 1u);
|
||||||
|
|
||||||
|
auto* expected_types = R"(%5 = OpTypeFloat 32
|
||||||
|
%4 = OpTypeRuntimeArray %5
|
||||||
|
%3 = OpTypeStruct %4
|
||||||
|
%2 = OpTypePointer StorageBuffer %3
|
||||||
|
%1 = OpVariable %2 StorageBuffer
|
||||||
|
%7 = OpTypeVoid
|
||||||
|
%6 = OpTypeFunction %7
|
||||||
|
%11 = OpTypeInt 32 0
|
||||||
|
)";
|
||||||
|
auto got_types = DumpInstructions(b.types());
|
||||||
|
EXPECT_EQ(expected_types, got_types);
|
||||||
|
|
||||||
|
auto* expected_instructions = R"(%10 = OpArrayLength %11 %1 0
|
||||||
|
)";
|
||||||
|
auto got_instructions = DumpInstructions(b.functions()[0].instructions());
|
||||||
|
EXPECT_EQ(expected_instructions, got_instructions);
|
||||||
|
|
||||||
|
Validate(b);
|
||||||
|
}
|
||||||
|
|
||||||
using Intrinsic_Builtin_DataPacking_Test =
|
using Intrinsic_Builtin_DataPacking_Test =
|
||||||
IntrinsicBuilderTestWithParam<IntrinsicData>;
|
IntrinsicBuilderTestWithParam<IntrinsicData>;
|
||||||
TEST_P(Intrinsic_Builtin_DataPacking_Test, Binary) {
|
TEST_P(Intrinsic_Builtin_DataPacking_Test, Binary) {
|
||||||
|
|
|
@ -1,6 +0,0 @@
|
||||||
|
|
||||||
[numthreads(1, 1, 1)]
|
|
||||||
void main() {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,11 +0,0 @@
|
||||||
#include <metal_stdlib>
|
|
||||||
|
|
||||||
using namespace metal;
|
|
||||||
struct S {
|
|
||||||
/* 0x0000 */ int a[1];
|
|
||||||
};
|
|
||||||
|
|
||||||
kernel void tint_symbol() {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
|
@ -7,6 +7,7 @@ struct S {
|
||||||
|
|
||||||
[[stage(compute)]]
|
[[stage(compute)]]
|
||||||
fn main() {
|
fn main() {
|
||||||
// TODO(crbug.com/tint/806): arrayLength signature is currently wrong
|
let p = &G;
|
||||||
// let l : i32 = arrayLength(&G.a);
|
let p2 = &((*p).a);
|
||||||
|
let l1 : u32 = arrayLength(p2);
|
||||||
}
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
|
||||||
|
ByteAddressBuffer G : register(t0, space0);
|
||||||
|
|
||||||
|
[numthreads(1, 1, 1)]
|
||||||
|
void main() {
|
||||||
|
uint tint_symbol_1 = 0u;
|
||||||
|
G.GetDimensions(tint_symbol_1);
|
||||||
|
const uint tint_symbol_2 = ((tint_symbol_1 - 0u) / 4u);
|
||||||
|
const uint l1 = tint_symbol_2;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
SKIP: FAILED
|
||||||
|
|
||||||
|
|
||||||
|
[[block]]
|
||||||
|
struct S {
|
||||||
|
a : array<i32>;
|
||||||
|
};
|
||||||
|
|
||||||
|
[[group(0), binding(0)]] var<storage, read> G : S;
|
||||||
|
|
||||||
|
[[stage(compute)]]
|
||||||
|
fn tint_symbol() {
|
||||||
|
let p = &(G);
|
||||||
|
let p2 = &((*(p)).a);
|
||||||
|
let l1 : u32 = arrayLength(p2);
|
||||||
|
}
|
||||||
|
|
||||||
|
Failed to generate: error: Unknown import method: arrayLength
|
|
@ -1,7 +1,7 @@
|
||||||
; SPIR-V
|
; SPIR-V
|
||||||
; Version: 1.3
|
; Version: 1.3
|
||||||
; Generator: Google Tint Compiler; 0
|
; Generator: Google Tint Compiler; 0
|
||||||
; Bound: 10
|
; Bound: 12
|
||||||
; Schema: 0
|
; Schema: 0
|
||||||
OpCapability Shader
|
OpCapability Shader
|
||||||
OpMemoryModel Logical GLSL450
|
OpMemoryModel Logical GLSL450
|
||||||
|
@ -24,7 +24,9 @@
|
||||||
%G = OpVariable %_ptr_StorageBuffer_S StorageBuffer
|
%G = OpVariable %_ptr_StorageBuffer_S StorageBuffer
|
||||||
%void = OpTypeVoid
|
%void = OpTypeVoid
|
||||||
%6 = OpTypeFunction %void
|
%6 = OpTypeFunction %void
|
||||||
|
%uint = OpTypeInt 32 0
|
||||||
%main = OpFunction %void None %6
|
%main = OpFunction %void None %6
|
||||||
%9 = OpLabel
|
%9 = OpLabel
|
||||||
|
%10 = OpArrayLength %uint %G 0
|
||||||
OpReturn
|
OpReturn
|
||||||
OpFunctionEnd
|
OpFunctionEnd
|
|
@ -0,0 +1,13 @@
|
||||||
|
[[block]]
|
||||||
|
struct S {
|
||||||
|
a : array<i32>;
|
||||||
|
};
|
||||||
|
|
||||||
|
[[group(0), binding(0)]] var<storage, read> G : S;
|
||||||
|
|
||||||
|
[[stage(compute)]]
|
||||||
|
fn main() {
|
||||||
|
let p = &(G);
|
||||||
|
let p2 = &((*(p)).a);
|
||||||
|
let l1 : u32 = arrayLength(p2);
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
[[block]]
|
||||||
|
struct S {
|
||||||
|
a : array<i32>;
|
||||||
|
};
|
||||||
|
|
||||||
|
[[group(0), binding(0)]] var<storage, read> G : S;
|
||||||
|
|
||||||
|
[[stage(compute)]]
|
||||||
|
fn main() {
|
||||||
|
let l1 : u32 = arrayLength(&G.a);
|
||||||
|
|
||||||
|
let p = &G.a;
|
||||||
|
let l2 : u32 = arrayLength(p);
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
|
||||||
|
ByteAddressBuffer G : register(t0, space0);
|
||||||
|
|
||||||
|
[numthreads(1, 1, 1)]
|
||||||
|
void main() {
|
||||||
|
uint tint_symbol_1 = 0u;
|
||||||
|
G.GetDimensions(tint_symbol_1);
|
||||||
|
const uint tint_symbol_2 = ((tint_symbol_1 - 0u) / 4u);
|
||||||
|
const uint l1 = tint_symbol_2;
|
||||||
|
const uint l2 = tint_symbol_2;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
SKIP: FAILED
|
||||||
|
|
||||||
|
|
||||||
|
[[block]]
|
||||||
|
struct S {
|
||||||
|
a : array<i32>;
|
||||||
|
};
|
||||||
|
|
||||||
|
[[group(0), binding(0)]] var<storage, read> G : S;
|
||||||
|
|
||||||
|
[[stage(compute)]]
|
||||||
|
fn tint_symbol() {
|
||||||
|
let l1 : u32 = arrayLength(&(G.a));
|
||||||
|
let p = &(G.a);
|
||||||
|
let l2 : u32 = arrayLength(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
Failed to generate: error: Unknown import method: arrayLength
|
|
@ -0,0 +1,33 @@
|
||||||
|
; SPIR-V
|
||||||
|
; Version: 1.3
|
||||||
|
; Generator: Google Tint Compiler; 0
|
||||||
|
; Bound: 13
|
||||||
|
; Schema: 0
|
||||||
|
OpCapability Shader
|
||||||
|
OpMemoryModel Logical GLSL450
|
||||||
|
OpEntryPoint GLCompute %main "main"
|
||||||
|
OpExecutionMode %main LocalSize 1 1 1
|
||||||
|
OpName %S "S"
|
||||||
|
OpMemberName %S 0 "a"
|
||||||
|
OpName %G "G"
|
||||||
|
OpName %main "main"
|
||||||
|
OpDecorate %S Block
|
||||||
|
OpMemberDecorate %S 0 Offset 0
|
||||||
|
OpDecorate %_runtimearr_int ArrayStride 4
|
||||||
|
OpDecorate %G NonWritable
|
||||||
|
OpDecorate %G DescriptorSet 0
|
||||||
|
OpDecorate %G Binding 0
|
||||||
|
%int = OpTypeInt 32 1
|
||||||
|
%_runtimearr_int = OpTypeRuntimeArray %int
|
||||||
|
%S = OpTypeStruct %_runtimearr_int
|
||||||
|
%_ptr_StorageBuffer_S = OpTypePointer StorageBuffer %S
|
||||||
|
%G = OpVariable %_ptr_StorageBuffer_S StorageBuffer
|
||||||
|
%void = OpTypeVoid
|
||||||
|
%6 = OpTypeFunction %void
|
||||||
|
%uint = OpTypeInt 32 0
|
||||||
|
%main = OpFunction %void None %6
|
||||||
|
%9 = OpLabel
|
||||||
|
%10 = OpArrayLength %uint %G 0
|
||||||
|
%12 = OpArrayLength %uint %G 0
|
||||||
|
OpReturn
|
||||||
|
OpFunctionEnd
|
|
@ -0,0 +1,13 @@
|
||||||
|
[[block]]
|
||||||
|
struct S {
|
||||||
|
a : array<i32>;
|
||||||
|
};
|
||||||
|
|
||||||
|
[[group(0), binding(0)]] var<storage, read> G : S;
|
||||||
|
|
||||||
|
[[stage(compute)]]
|
||||||
|
fn main() {
|
||||||
|
let l1 : u32 = arrayLength(&(G.a));
|
||||||
|
let p = &(G.a);
|
||||||
|
let l2 : u32 = arrayLength(p);
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
[[block]]
|
||||||
|
struct S {
|
||||||
|
a : array<i32>;
|
||||||
|
};
|
||||||
|
|
||||||
|
[[group(0), binding(0)]] var<storage, read> G : S;
|
||||||
|
|
||||||
|
[[stage(compute)]]
|
||||||
|
fn main() {
|
||||||
|
let l1 : u32 = arrayLength(&G.a);
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
|
||||||
|
ByteAddressBuffer G : register(t0, space0);
|
||||||
|
|
||||||
|
[numthreads(1, 1, 1)]
|
||||||
|
void main() {
|
||||||
|
uint tint_symbol_1 = 0u;
|
||||||
|
G.GetDimensions(tint_symbol_1);
|
||||||
|
const uint tint_symbol_2 = ((tint_symbol_1 - 0u) / 4u);
|
||||||
|
const uint l1 = tint_symbol_2;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
SKIP: FAILED
|
||||||
|
|
||||||
|
|
||||||
|
[[block]]
|
||||||
|
struct S {
|
||||||
|
a : array<i32>;
|
||||||
|
};
|
||||||
|
|
||||||
|
[[group(0), binding(0)]] var<storage, read> G : S;
|
||||||
|
|
||||||
|
[[stage(compute)]]
|
||||||
|
fn tint_symbol() {
|
||||||
|
let l1 : u32 = arrayLength(&(G.a));
|
||||||
|
}
|
||||||
|
|
||||||
|
Failed to generate: error: Unknown import method: arrayLength
|
|
@ -0,0 +1,32 @@
|
||||||
|
; SPIR-V
|
||||||
|
; Version: 1.3
|
||||||
|
; Generator: Google Tint Compiler; 0
|
||||||
|
; Bound: 12
|
||||||
|
; Schema: 0
|
||||||
|
OpCapability Shader
|
||||||
|
OpMemoryModel Logical GLSL450
|
||||||
|
OpEntryPoint GLCompute %main "main"
|
||||||
|
OpExecutionMode %main LocalSize 1 1 1
|
||||||
|
OpName %S "S"
|
||||||
|
OpMemberName %S 0 "a"
|
||||||
|
OpName %G "G"
|
||||||
|
OpName %main "main"
|
||||||
|
OpDecorate %S Block
|
||||||
|
OpMemberDecorate %S 0 Offset 0
|
||||||
|
OpDecorate %_runtimearr_int ArrayStride 4
|
||||||
|
OpDecorate %G NonWritable
|
||||||
|
OpDecorate %G DescriptorSet 0
|
||||||
|
OpDecorate %G Binding 0
|
||||||
|
%int = OpTypeInt 32 1
|
||||||
|
%_runtimearr_int = OpTypeRuntimeArray %int
|
||||||
|
%S = OpTypeStruct %_runtimearr_int
|
||||||
|
%_ptr_StorageBuffer_S = OpTypePointer StorageBuffer %S
|
||||||
|
%G = OpVariable %_ptr_StorageBuffer_S StorageBuffer
|
||||||
|
%void = OpTypeVoid
|
||||||
|
%6 = OpTypeFunction %void
|
||||||
|
%uint = OpTypeInt 32 0
|
||||||
|
%main = OpFunction %void None %6
|
||||||
|
%9 = OpLabel
|
||||||
|
%10 = OpArrayLength %uint %G 0
|
||||||
|
OpReturn
|
||||||
|
OpFunctionEnd
|
|
@ -7,4 +7,5 @@ struct S {
|
||||||
|
|
||||||
[[stage(compute)]]
|
[[stage(compute)]]
|
||||||
fn main() {
|
fn main() {
|
||||||
|
let l1 : u32 = arrayLength(&(G.a));
|
||||||
}
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
[[block]]
|
||||||
|
struct S {
|
||||||
|
a : array<i32>;
|
||||||
|
};
|
||||||
|
|
||||||
|
[[group(0), binding(0)]] var<storage, read> G : S;
|
||||||
|
|
||||||
|
[[stage(compute)]]
|
||||||
|
fn main() {
|
||||||
|
let p = &G.a;
|
||||||
|
let p2 = p;
|
||||||
|
let l1 : u32 = arrayLength(p2);
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
|
||||||
|
ByteAddressBuffer G : register(t0, space0);
|
||||||
|
|
||||||
|
[numthreads(1, 1, 1)]
|
||||||
|
void main() {
|
||||||
|
uint tint_symbol_1 = 0u;
|
||||||
|
G.GetDimensions(tint_symbol_1);
|
||||||
|
const uint tint_symbol_2 = ((tint_symbol_1 - 0u) / 4u);
|
||||||
|
const uint l1 = tint_symbol_2;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
SKIP: FAILED
|
||||||
|
|
||||||
|
|
||||||
|
[[block]]
|
||||||
|
struct S {
|
||||||
|
a : array<i32>;
|
||||||
|
};
|
||||||
|
|
||||||
|
[[group(0), binding(0)]] var<storage, read> G : S;
|
||||||
|
|
||||||
|
[[stage(compute)]]
|
||||||
|
fn tint_symbol() {
|
||||||
|
let p = &(G.a);
|
||||||
|
let p2 = p;
|
||||||
|
let l1 : u32 = arrayLength(p2);
|
||||||
|
}
|
||||||
|
|
||||||
|
Failed to generate: error: Unknown import method: arrayLength
|
|
@ -0,0 +1,32 @@
|
||||||
|
; SPIR-V
|
||||||
|
; Version: 1.3
|
||||||
|
; Generator: Google Tint Compiler; 0
|
||||||
|
; Bound: 12
|
||||||
|
; Schema: 0
|
||||||
|
OpCapability Shader
|
||||||
|
OpMemoryModel Logical GLSL450
|
||||||
|
OpEntryPoint GLCompute %main "main"
|
||||||
|
OpExecutionMode %main LocalSize 1 1 1
|
||||||
|
OpName %S "S"
|
||||||
|
OpMemberName %S 0 "a"
|
||||||
|
OpName %G "G"
|
||||||
|
OpName %main "main"
|
||||||
|
OpDecorate %S Block
|
||||||
|
OpMemberDecorate %S 0 Offset 0
|
||||||
|
OpDecorate %_runtimearr_int ArrayStride 4
|
||||||
|
OpDecorate %G NonWritable
|
||||||
|
OpDecorate %G DescriptorSet 0
|
||||||
|
OpDecorate %G Binding 0
|
||||||
|
%int = OpTypeInt 32 1
|
||||||
|
%_runtimearr_int = OpTypeRuntimeArray %int
|
||||||
|
%S = OpTypeStruct %_runtimearr_int
|
||||||
|
%_ptr_StorageBuffer_S = OpTypePointer StorageBuffer %S
|
||||||
|
%G = OpVariable %_ptr_StorageBuffer_S StorageBuffer
|
||||||
|
%void = OpTypeVoid
|
||||||
|
%6 = OpTypeFunction %void
|
||||||
|
%uint = OpTypeInt 32 0
|
||||||
|
%main = OpFunction %void None %6
|
||||||
|
%9 = OpLabel
|
||||||
|
%10 = OpArrayLength %uint %G 0
|
||||||
|
OpReturn
|
||||||
|
OpFunctionEnd
|
|
@ -0,0 +1,13 @@
|
||||||
|
[[block]]
|
||||||
|
struct S {
|
||||||
|
a : array<i32>;
|
||||||
|
};
|
||||||
|
|
||||||
|
[[group(0), binding(0)]] var<storage, read> G : S;
|
||||||
|
|
||||||
|
[[stage(compute)]]
|
||||||
|
fn main() {
|
||||||
|
let p = &(G.a);
|
||||||
|
let p2 = p;
|
||||||
|
let l1 : u32 = arrayLength(p2);
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
[[block]]
|
||||||
|
struct S {
|
||||||
|
a : array<i32>;
|
||||||
|
};
|
||||||
|
|
||||||
|
[[group(0), binding(0)]] var<storage, read> G : S;
|
||||||
|
|
||||||
|
[[stage(compute)]]
|
||||||
|
fn main() {
|
||||||
|
let p = &*&G;
|
||||||
|
let p2 = &*p;
|
||||||
|
let p3 = &((*p).a);
|
||||||
|
let l1 : u32 = arrayLength(&*p3);
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
|
||||||
|
ByteAddressBuffer G : register(t0, space0);
|
||||||
|
|
||||||
|
[numthreads(1, 1, 1)]
|
||||||
|
void main() {
|
||||||
|
uint tint_symbol_1 = 0u;
|
||||||
|
G.GetDimensions(tint_symbol_1);
|
||||||
|
const uint tint_symbol_2 = ((tint_symbol_1 - 0u) / 4u);
|
||||||
|
const uint l1 = tint_symbol_2;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
SKIP: FAILED
|
||||||
|
|
||||||
|
|
||||||
|
[[block]]
|
||||||
|
struct S {
|
||||||
|
a : array<i32>;
|
||||||
|
};
|
||||||
|
|
||||||
|
[[group(0), binding(0)]] var<storage, read> G : S;
|
||||||
|
|
||||||
|
[[stage(compute)]]
|
||||||
|
fn tint_symbol() {
|
||||||
|
let p = &(*(&(G)));
|
||||||
|
let p2 = &(*(p));
|
||||||
|
let p3 = &((*(p)).a);
|
||||||
|
let l1 : u32 = arrayLength(&(*(p3)));
|
||||||
|
}
|
||||||
|
|
||||||
|
Failed to generate: error: Unknown import method: arrayLength
|
|
@ -0,0 +1,32 @@
|
||||||
|
; SPIR-V
|
||||||
|
; Version: 1.3
|
||||||
|
; Generator: Google Tint Compiler; 0
|
||||||
|
; Bound: 12
|
||||||
|
; Schema: 0
|
||||||
|
OpCapability Shader
|
||||||
|
OpMemoryModel Logical GLSL450
|
||||||
|
OpEntryPoint GLCompute %main "main"
|
||||||
|
OpExecutionMode %main LocalSize 1 1 1
|
||||||
|
OpName %S "S"
|
||||||
|
OpMemberName %S 0 "a"
|
||||||
|
OpName %G "G"
|
||||||
|
OpName %main "main"
|
||||||
|
OpDecorate %S Block
|
||||||
|
OpMemberDecorate %S 0 Offset 0
|
||||||
|
OpDecorate %_runtimearr_int ArrayStride 4
|
||||||
|
OpDecorate %G NonWritable
|
||||||
|
OpDecorate %G DescriptorSet 0
|
||||||
|
OpDecorate %G Binding 0
|
||||||
|
%int = OpTypeInt 32 1
|
||||||
|
%_runtimearr_int = OpTypeRuntimeArray %int
|
||||||
|
%S = OpTypeStruct %_runtimearr_int
|
||||||
|
%_ptr_StorageBuffer_S = OpTypePointer StorageBuffer %S
|
||||||
|
%G = OpVariable %_ptr_StorageBuffer_S StorageBuffer
|
||||||
|
%void = OpTypeVoid
|
||||||
|
%6 = OpTypeFunction %void
|
||||||
|
%uint = OpTypeInt 32 0
|
||||||
|
%main = OpFunction %void None %6
|
||||||
|
%9 = OpLabel
|
||||||
|
%10 = OpArrayLength %uint %G 0
|
||||||
|
OpReturn
|
||||||
|
OpFunctionEnd
|
|
@ -0,0 +1,14 @@
|
||||||
|
[[block]]
|
||||||
|
struct S {
|
||||||
|
a : array<i32>;
|
||||||
|
};
|
||||||
|
|
||||||
|
[[group(0), binding(0)]] var<storage, read> G : S;
|
||||||
|
|
||||||
|
[[stage(compute)]]
|
||||||
|
fn main() {
|
||||||
|
let p = &(*(&(G)));
|
||||||
|
let p2 = &(*(p));
|
||||||
|
let p3 = &((*(p)).a);
|
||||||
|
let l1 : u32 = arrayLength(&(*(p3)));
|
||||||
|
}
|
|
@ -1,3 +1,7 @@
|
||||||
|
intrinsics/gen/arrayLength/647a40.wgsl:31:18 warning: use of deprecated intrinsic
|
||||||
|
var res: u32 = arrayLength(sb.arg_0);
|
||||||
|
^^^^^^^^^^^
|
||||||
|
|
||||||
struct tint_symbol {
|
struct tint_symbol {
|
||||||
float4 value : SV_Position;
|
float4 value : SV_Position;
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,3 +1,7 @@
|
||||||
|
intrinsics/gen/arrayLength/647a40.wgsl:31:18 warning: use of deprecated intrinsic
|
||||||
|
var res: u32 = arrayLength(sb.arg_0);
|
||||||
|
^^^^^^^^^^^
|
||||||
|
|
||||||
; SPIR-V
|
; SPIR-V
|
||||||
; Version: 1.3
|
; Version: 1.3
|
||||||
; Generator: Google Tint Compiler; 0
|
; Generator: Google Tint Compiler; 0
|
||||||
|
|
|
@ -1,3 +1,7 @@
|
||||||
|
intrinsics/gen/arrayLength/647a40.wgsl:31:18 warning: use of deprecated intrinsic
|
||||||
|
var res: u32 = arrayLength(sb.arg_0);
|
||||||
|
^^^^^^^^^^^
|
||||||
|
|
||||||
[[block]]
|
[[block]]
|
||||||
struct SB {
|
struct SB {
|
||||||
arg_0 : array<u32>;
|
arg_0 : array<u32>;
|
||||||
|
|
|
@ -1,3 +1,7 @@
|
||||||
|
intrinsics/gen/arrayLength/721c9d.wgsl:31:18 warning: use of deprecated intrinsic
|
||||||
|
var res: u32 = arrayLength(sb.arg_0);
|
||||||
|
^^^^^^^^^^^
|
||||||
|
|
||||||
struct tint_symbol {
|
struct tint_symbol {
|
||||||
float4 value : SV_Position;
|
float4 value : SV_Position;
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,3 +1,7 @@
|
||||||
|
intrinsics/gen/arrayLength/721c9d.wgsl:31:18 warning: use of deprecated intrinsic
|
||||||
|
var res: u32 = arrayLength(sb.arg_0);
|
||||||
|
^^^^^^^^^^^
|
||||||
|
|
||||||
; SPIR-V
|
; SPIR-V
|
||||||
; Version: 1.3
|
; Version: 1.3
|
||||||
; Generator: Google Tint Compiler; 0
|
; Generator: Google Tint Compiler; 0
|
||||||
|
|
|
@ -1,3 +1,7 @@
|
||||||
|
intrinsics/gen/arrayLength/721c9d.wgsl:31:18 warning: use of deprecated intrinsic
|
||||||
|
var res: u32 = arrayLength(sb.arg_0);
|
||||||
|
^^^^^^^^^^^
|
||||||
|
|
||||||
[[block]]
|
[[block]]
|
||||||
struct SB {
|
struct SB {
|
||||||
arg_0 : array<i32>;
|
arg_0 : array<i32>;
|
||||||
|
|
|
@ -1,3 +1,7 @@
|
||||||
|
intrinsics/gen/arrayLength/b083be.wgsl:31:18 warning: use of deprecated intrinsic
|
||||||
|
var res: u32 = arrayLength(sb.arg_0);
|
||||||
|
^^^^^^^^^^^
|
||||||
|
|
||||||
struct tint_symbol {
|
struct tint_symbol {
|
||||||
float4 value : SV_Position;
|
float4 value : SV_Position;
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,3 +1,7 @@
|
||||||
|
intrinsics/gen/arrayLength/b083be.wgsl:31:18 warning: use of deprecated intrinsic
|
||||||
|
var res: u32 = arrayLength(sb.arg_0);
|
||||||
|
^^^^^^^^^^^
|
||||||
|
|
||||||
; SPIR-V
|
; SPIR-V
|
||||||
; Version: 1.3
|
; Version: 1.3
|
||||||
; Generator: Google Tint Compiler; 0
|
; Generator: Google Tint Compiler; 0
|
||||||
|
|
|
@ -1,3 +1,7 @@
|
||||||
|
intrinsics/gen/arrayLength/b083be.wgsl:31:18 warning: use of deprecated intrinsic
|
||||||
|
var res: u32 = arrayLength(sb.arg_0);
|
||||||
|
^^^^^^^^^^^
|
||||||
|
|
||||||
[[block]]
|
[[block]]
|
||||||
struct SB {
|
struct SB {
|
||||||
arg_0 : array<f32>;
|
arg_0 : array<f32>;
|
||||||
|
|
Loading…
Reference in New Issue