Updated spirv-tools.

This commit is contained in:
Бранимир Караџић
2019-04-27 14:13:23 -07:00
parent 2189a81a94
commit 17382cac5d
12 changed files with 419 additions and 89 deletions

View File

@@ -47,7 +47,7 @@ version. An API call reports the software version as a C-style string.
* Support for SPIR-V 1.0, 1.1, 1.2, and 1.3
* Based on SPIR-V syntax described by JSON grammar files in the
[SPIRV-Headers](spirv-headers) repository.
[SPIRV-Headers](https://github.com/KhronosGroup/SPIRV-Headers) repository.
* Support for extended instruction sets:
* GLSL std450 version 1.0 Rev 3
* OpenCL version 1.0 Rev 2

View File

@@ -28,6 +28,7 @@
int main() {
const std::string source =
" OpCapability Linkage "
" OpCapability Shader "
" OpMemoryModel Logical GLSL450 "
" OpSource GLSL 450 "
@@ -36,8 +37,8 @@ int main() {
" %spec = OpSpecConstant %int 0 "
"%const = OpConstant %int 42";
spvtools::SpirvTools core(SPV_ENV_VULKAN_1_0);
spvtools::Optimizer opt(SPV_ENV_VULKAN_1_0);
spvtools::SpirvTools core(SPV_ENV_UNIVERSAL_1_3);
spvtools::Optimizer opt(SPV_ENV_UNIVERSAL_1_3);
auto print_msg_to_stderr = [](spv_message_level_t, const char*,
const spv_position_t&, const char* m) {

View File

@@ -1 +1 @@
"v2019.3-dev", "SPIRV-Tools v2019.3-dev v2019.1-147-g7aad9653"
"v2019.3-dev", "SPIRV-Tools v2019.3-dev v2019.1-154-g64faf6d9"

View File

@@ -34,43 +34,78 @@ bool HasInitializer(Instruction* inst) {
Pass::Status DecomposeInitializedVariablesPass::Process() {
auto* module = context()->module();
bool changed = false;
std::unordered_set<Instruction*> changed;
// TODO(zoddicus): Handle 'Output' variables
// TODO(zoddicus): Handle 'Private' variables
std::vector<std::tuple<uint32_t, uint32_t>> global_stores;
for (auto iter = module->types_values_begin();
iter != module->types_values_end(); ++iter) {
Instruction* inst = &(*iter);
if (!HasInitializer(inst)) continue;
auto var_id = inst->result_id();
auto val_id = inst->GetOperand(3).words[0];
global_stores.push_back(std::make_tuple(var_id, val_id));
iter->RemoveOperand(3);
changed.insert(&*iter);
}
std::unordered_set<uint32_t> entry_ids;
for (auto entry = module->entry_points().begin();
entry != module->entry_points().end(); ++entry) {
entry_ids.insert(entry->GetSingleWordInOperand(1));
}
// Handle 'Function' variables
for (auto func = module->begin(); func != module->end(); ++func) {
auto block = func->entry().get();
std::vector<Instruction*> new_stores;
auto last_var = block->begin();
for (auto iter = block->begin();
iter != block->end() && iter->opcode() == SpvOpVariable; ++iter) {
last_var = iter;
std::vector<Instruction*> function_stores;
auto first_block = func->entry().get();
inst_iterator insert_point = first_block->begin();
for (auto iter = first_block->begin();
iter != first_block->end() && iter->opcode() == SpvOpVariable;
++iter) {
// For valid SPIRV-V, there is guaranteed to be at least one instruction
// after the OpVariable instructions.
insert_point = (*iter).NextNode();
Instruction* inst = &(*iter);
if (!HasInitializer(inst)) continue;
changed = true;
auto var_id = inst->result_id();
auto val_id = inst->GetOperand(3).words[0];
Instruction* store_inst = new Instruction(
context(), SpvOpStore, 0, 0,
{{SPV_OPERAND_TYPE_ID, {var_id}}, {SPV_OPERAND_TYPE_ID, {val_id}}});
new_stores.push_back(store_inst);
function_stores.push_back(store_inst);
iter->RemoveOperand(3);
get_def_use_mgr()->UpdateDefUse(&*iter);
changed.insert(&*iter);
}
for (auto store = new_stores.begin(); store != new_stores.end(); ++store) {
context()->AnalyzeDefUse(*store);
context()->set_instr_block(*store, block);
(*store)->InsertAfter(&*last_var);
last_var = *store;
if (entry_ids.find(func->result_id()) != entry_ids.end()) {
for (auto store_ids : global_stores) {
uint32_t var_id;
uint32_t val_id;
std::tie(var_id, val_id) = store_ids;
auto* store_inst = new Instruction(
context(), SpvOpStore, 0, 0,
{{SPV_OPERAND_TYPE_ID, {var_id}}, {SPV_OPERAND_TYPE_ID, {val_id}}});
context()->set_instr_block(store_inst, &*first_block);
first_block->AddInstruction(std::unique_ptr<Instruction>(store_inst));
store_inst->InsertBefore(&*insert_point);
changed.insert(store_inst);
}
}
for (auto store = function_stores.begin(); store != function_stores.end();
++store) {
context()->set_instr_block(*store, first_block);
(*store)->InsertBefore(&*insert_point);
changed.insert(*store);
}
}
return changed ? Status::SuccessWithChange : Status::SuccessWithoutChange;
auto* def_use_mgr = get_def_use_mgr();
for (auto* inst : changed) def_use_mgr->UpdateDefUse(inst);
return !changed.empty() ? Pass::Status::SuccessWithChange
: Pass::Status::SuccessWithoutChange;
}
} // namespace opt

View File

@@ -225,12 +225,12 @@ bool ScalarReplacementPass::ReplaceAccessChain(
// indexes) or a direct use of the replacement variable.
uint32_t indexId = chain->GetSingleWordInOperand(1u);
const Instruction* index = get_def_use_mgr()->GetDef(indexId);
size_t indexValue = GetConstantInteger(index);
uint64_t indexValue = GetConstantInteger(index);
if (indexValue > replacements.size()) {
// Out of bounds access, this is illegal IR.
return false;
} else {
const Instruction* var = replacements[indexValue];
const Instruction* var = replacements[static_cast<size_t>(indexValue)];
if (chain->NumInOperands() > 2) {
// Replace input access chain with another access chain.
BasicBlock::iterator chainIter(chain);
@@ -457,16 +457,16 @@ void ScalarReplacementPass::GetOrCreateInitialValue(Instruction* source,
}
}
size_t ScalarReplacementPass::GetIntegerLiteral(const Operand& op) const {
uint64_t ScalarReplacementPass::GetIntegerLiteral(const Operand& op) const {
assert(op.words.size() <= 2);
size_t len = 0;
uint64_t len = 0;
for (uint32_t i = 0; i != op.words.size(); ++i) {
len |= (op.words[i] << (32 * i));
}
return len;
}
size_t ScalarReplacementPass::GetConstantInteger(
uint64_t ScalarReplacementPass::GetConstantInteger(
const Instruction* constant) const {
assert(get_def_use_mgr()->GetDef(constant->type_id())->opcode() ==
SpvOpTypeInt);
@@ -480,7 +480,7 @@ size_t ScalarReplacementPass::GetConstantInteger(
return GetIntegerLiteral(op);
}
size_t ScalarReplacementPass::GetArrayLength(
uint64_t ScalarReplacementPass::GetArrayLength(
const Instruction* arrayType) const {
assert(arrayType->opcode() == SpvOpTypeArray);
const Instruction* length =
@@ -488,14 +488,14 @@ size_t ScalarReplacementPass::GetArrayLength(
return GetConstantInteger(length);
}
size_t ScalarReplacementPass::GetNumElements(const Instruction* type) const {
uint64_t ScalarReplacementPass::GetNumElements(const Instruction* type) const {
assert(type->opcode() == SpvOpTypeVector ||
type->opcode() == SpvOpTypeMatrix);
const Operand& op = type->GetInOperand(1u);
assert(op.words.size() <= 2);
size_t len = 0;
for (uint32_t i = 0; i != op.words.size(); ++i) {
len |= (op.words[i] << (32 * i));
uint64_t len = 0;
for (size_t i = 0; i != op.words.size(); ++i) {
len |= (static_cast<uint64_t>(op.words[i]) << (32ull * i));
}
return len;
}
@@ -717,7 +717,7 @@ bool ScalarReplacementPass::CheckStore(const Instruction* inst,
return false;
return true;
}
bool ScalarReplacementPass::IsLargerThanSizeLimit(size_t length) const {
bool ScalarReplacementPass::IsLargerThanSizeLimit(uint64_t length) const {
if (max_num_elements_ == 0) {
return false;
}

View File

@@ -157,18 +157,18 @@ class ScalarReplacementPass : public Pass {
// Returns the value of an OpConstant of integer type.
//
// |constant| must use two or fewer words to generate the value.
size_t GetConstantInteger(const Instruction* constant) const;
uint64_t GetConstantInteger(const Instruction* constant) const;
// Returns the integer literal for |op|.
size_t GetIntegerLiteral(const Operand& op) const;
uint64_t GetIntegerLiteral(const Operand& op) const;
// Returns the array length for |arrayInst|.
size_t GetArrayLength(const Instruction* arrayInst) const;
uint64_t GetArrayLength(const Instruction* arrayInst) const;
// Returns the number of elements in |type|.
//
// |type| must be a vector or matrix type.
size_t GetNumElements(const Instruction* type) const;
uint64_t GetNumElements(const Instruction* type) const;
// Returns true if |id| is a specialization constant.
//
@@ -228,7 +228,7 @@ class ScalarReplacementPass : public Pass {
// Limit on the number of members in an object that will be replaced.
// 0 means there is no limit.
uint32_t max_num_elements_;
bool IsLargerThanSizeLimit(size_t length) const;
bool IsLargerThanSizeLimit(uint64_t length) const;
char name_[55];
};

View File

@@ -548,6 +548,9 @@ spv_result_t checkLayout(uint32_t struct_id, const char* storage_class_str,
typeId, storage_class_str, decoration_str,
blockRules, next_offset, constraints, vstate)))
return recursive_status;
// If offsets accumulate up to a 16-byte multiple stop checking since
// it will just repeat.
if (i > 0 && (next_offset % 16 == 0)) break;
}
// Proceed to the element in case it is an array.

View File

@@ -55,9 +55,7 @@ spv_result_t ValidateMemorySemantics(ValidationState_t& _,
SpvMemorySemanticsMakeAvailableKHRMask |
SpvMemorySemanticsMakeVisibleKHRMask;
if (!spvOpcodeIsAtomicOp(inst->opcode())) {
valid_bits |= SpvMemorySemanticsAcquireMask |
SpvMemorySemanticsReleaseMask |
SpvMemorySemanticsAcquireReleaseMask;
valid_bits |= SpvMemorySemanticsAcquireReleaseMask;
}
if (value & ~valid_bits) {
@@ -69,11 +67,18 @@ spv_result_t ValidateMemorySemantics(ValidationState_t& _,
} else {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
<< "WebGPU spec disallows any bit masks in Memory Semantics "
"that are not Acquire, Release, AcquireRelease, "
"UniformMemory, WorkgroupMemory, ImageMemory, "
"OutputMemoryKHR, MakeAvailableKHR, or MakeVisibleKHR";
"that are not AcquireRelease, UniformMemory, "
"WorkgroupMemory, ImageMemory, OutputMemoryKHR, "
"MakeAvailableKHR, or MakeVisibleKHR";
}
}
if (!spvOpcodeIsAtomicOp(inst->opcode()) &&
!(value & SpvMemorySemanticsAcquireReleaseMask)) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
<< "WebGPU spec requires AcquireRelease to set in Memory "
"Semantics.";
}
}
const size_t num_memory_order_set_bits = spvtools::utils::CountSetBits(

View File

@@ -23,63 +23,230 @@ namespace {
using DecomposeInitializedVariablesTest = PassTest<::testing::Test>;
void operator+=(std::vector<const char*>& lhs,
const std::vector<const char*> rhs) {
for (auto elem : rhs) lhs.push_back(elem);
}
std::string single_entry_header = R"(OpCapability Shader
OpCapability VulkanMemoryModelKHR
OpExtension "SPV_KHR_vulkan_memory_model"
OpMemoryModel Logical VulkanKHR
OpEntryPoint Vertex %1 "shader"
%uint = OpTypeInt 32 0
%uint_1 = OpConstant %uint 1
%4 = OpConstantNull %uint
%void = OpTypeVoid
%6 = OpTypeFunction %void
)";
std::vector<const char*> header = {
"OpCapability Shader",
"OpCapability VulkanMemoryModelKHR",
"OpExtension \"SPV_KHR_vulkan_memory_model\"",
"OpMemoryModel Logical VulkanKHR",
"OpEntryPoint Vertex %1 \"shader\"",
"%uint = OpTypeInt 32 0",
"%uint_1 = OpConstant %uint 1",
"%4 = OpConstantNull %uint",
"%void = OpTypeVoid",
"%6 = OpTypeFunction %void"};
std::string GetFunctionTest(std::vector<const char*> body) {
auto result = header;
result += {"%_ptr_Function_uint = OpTypePointer Function %uint",
"%1 = OpFunction %void None %6", "%8 = OpLabel"};
result += body;
result += {"OpReturn", "OpFunctionEnd"};
return JoinAllInsts(result);
std::string GetFunctionTest(std::string body) {
auto result = single_entry_header;
result += "%_ptr_Function_uint = OpTypePointer Function %uint\n";
result += "%1 = OpFunction %void None %6\n";
result += "%8 = OpLabel\n";
result += body + "\n";
result += "OpReturn\n";
result += "OpFunctionEnd\n";
return result;
}
TEST_F(DecomposeInitializedVariablesTest, FunctionChanged) {
std::string input =
GetFunctionTest({"%9 = OpVariable %_ptr_Function_uint Function %uint_1"});
std::string expected = GetFunctionTest(
{"%9 = OpVariable %_ptr_Function_uint Function", "OpStore %9 %uint_1"});
std::string input = "%9 = OpVariable %_ptr_Function_uint Function %uint_1";
std::string expected = R"(%9 = OpVariable %_ptr_Function_uint Function
OpStore %9 %uint_1)";
SinglePassRunAndCheck<DecomposeInitializedVariablesPass>(
GetFunctionTest(input), GetFunctionTest(expected),
/* skip_nop = */ false);
}
TEST_F(DecomposeInitializedVariablesTest, FunctionUnchanged) {
std::string input = "%9 = OpVariable %_ptr_Function_uint Function";
SinglePassRunAndCheck<DecomposeInitializedVariablesPass>(
GetFunctionTest(input), GetFunctionTest(input), /* skip_nop = */ false);
}
TEST_F(DecomposeInitializedVariablesTest, FunctionMultipleVariables) {
std::string input = R"(%9 = OpVariable %_ptr_Function_uint Function %uint_1
%10 = OpVariable %_ptr_Function_uint Function %4)";
std::string expected = R"(%9 = OpVariable %_ptr_Function_uint Function
%10 = OpVariable %_ptr_Function_uint Function
OpStore %9 %uint_1
OpStore %10 %4)";
SinglePassRunAndCheck<DecomposeInitializedVariablesPass>(
GetFunctionTest(input), GetFunctionTest(expected),
/* skip_nop = */ false);
}
std::string GetGlobalTest(std::string storage_class, bool initialized,
bool decomposed) {
auto result = single_entry_header;
result += "%_ptr_" + storage_class + "_uint = OpTypePointer " +
storage_class + " %uint\n";
if (initialized) {
result += "%8 = OpVariable %_ptr_" + storage_class + "_uint " +
storage_class + " %4\n";
} else {
result += "%8 = OpVariable %_ptr_" + storage_class + "_uint " +
storage_class + "\n";
}
result += R"(%1 = OpFunction %void None %9
%9 = OpLabel
)";
if (decomposed) result += "OpStore %8 %4\n";
result += R"(OpReturn
OpFunctionEnd
)";
return result;
}
TEST_F(DecomposeInitializedVariablesTest, PrivateChanged) {
std::string input = GetGlobalTest("Private", true, false);
std::string expected = GetGlobalTest("Private", false, true);
SinglePassRunAndCheck<DecomposeInitializedVariablesPass>(
input, expected, /* skip_nop = */ false);
}
TEST_F(DecomposeInitializedVariablesTest, FunctionUnchanged) {
std::string input =
GetFunctionTest({"%9 = OpVariable %_ptr_Function_uint Function"});
TEST_F(DecomposeInitializedVariablesTest, PrivateUnchanged) {
std::string input = GetGlobalTest("Private", false, false);
SinglePassRunAndCheck<DecomposeInitializedVariablesPass>(
input, input, /* skip_nop = */ false);
}
TEST_F(DecomposeInitializedVariablesTest, FunctionMultipleVariables) {
std::string input =
GetFunctionTest({"%9 = OpVariable %_ptr_Function_uint Function %uint_1",
"%10 = OpVariable %_ptr_Function_uint Function %4"});
std::string expected =
GetFunctionTest({"%9 = OpVariable %_ptr_Function_uint Function",
"%10 = OpVariable %_ptr_Function_uint Function",
"OpStore %9 %uint_1", "OpStore %10 %4"});
TEST_F(DecomposeInitializedVariablesTest, OutputChanged) {
std::string input = GetGlobalTest("Output", true, false);
std::string expected = GetGlobalTest("Output", false, true);
SinglePassRunAndCheck<DecomposeInitializedVariablesPass>(
input, expected, /* skip_nop = */ false);
}
TEST_F(DecomposeInitializedVariablesTest, OutputUnchanged) {
std::string input = GetGlobalTest("Output", false, false);
SinglePassRunAndCheck<DecomposeInitializedVariablesPass>(
input, input, /* skip_nop = */ false);
}
std::string multiple_entry_header = R"(OpCapability Shader
OpCapability VulkanMemoryModelKHR
OpExtension "SPV_KHR_vulkan_memory_model"
OpMemoryModel Logical VulkanKHR
OpEntryPoint Vertex %1 "vertex"
OpEntryPoint Fragment %2 "fragment"
%uint = OpTypeInt 32 0
%4 = OpConstantNull %uint
%void = OpTypeVoid
%6 = OpTypeFunction %void
)";
std::string GetGlobalMultipleEntryTest(std::string storage_class,
bool initialized, bool decomposed) {
auto result = multiple_entry_header;
result += "%_ptr_" + storage_class + "_uint = OpTypePointer " +
storage_class + " %uint\n";
if (initialized) {
result += "%8 = OpVariable %_ptr_" + storage_class + "_uint " +
storage_class + " %4\n";
} else {
result += "%8 = OpVariable %_ptr_" + storage_class + "_uint " +
storage_class + "\n";
}
result += R"(%1 = OpFunction %void None %9
%9 = OpLabel
)";
if (decomposed) result += "OpStore %8 %4\n";
result += R"(OpReturn
OpFunctionEnd
%2 = OpFunction %void None %10
%10 = OpLabel
)";
if (decomposed) result += "OpStore %8 %4\n";
result += R"(OpReturn
OpFunctionEnd
)";
return result;
}
TEST_F(DecomposeInitializedVariablesTest, PrivateMultipleEntryChanged) {
std::string input = GetGlobalMultipleEntryTest("Private", true, false);
std::string expected = GetGlobalMultipleEntryTest("Private", false, true);
SinglePassRunAndCheck<DecomposeInitializedVariablesPass>(
input, expected, /* skip_nop = */ false);
}
TEST_F(DecomposeInitializedVariablesTest, PrivateMultipleEntryUnchanged) {
std::string input = GetGlobalMultipleEntryTest("Private", false, false);
SinglePassRunAndCheck<DecomposeInitializedVariablesPass>(
input, input, /* skip_nop = */ false);
}
TEST_F(DecomposeInitializedVariablesTest, OutputMultipleEntryChanged) {
std::string input = GetGlobalMultipleEntryTest("Output", true, false);
std::string expected = GetGlobalMultipleEntryTest("Output", false, true);
SinglePassRunAndCheck<DecomposeInitializedVariablesPass>(
input, expected, /* skip_nop = */ false);
}
TEST_F(DecomposeInitializedVariablesTest, OutputMultipleEntryUnchanged) {
std::string input = GetGlobalMultipleEntryTest("Output", false, false);
SinglePassRunAndCheck<DecomposeInitializedVariablesPass>(
input, input, /* skip_nop = */ false);
}
std::string GetGlobalWithNonEntryPointTest(std::string storage_class,
bool initialized, bool decomposed) {
auto result = single_entry_header;
result += "%_ptr_" + storage_class + "_uint = OpTypePointer " +
storage_class + " %uint\n";
if (initialized) {
result += "%8 = OpVariable %_ptr_" + storage_class + "_uint " +
storage_class + " %4\n";
} else {
result += "%8 = OpVariable %_ptr_" + storage_class + "_uint " +
storage_class + "\n";
}
result += R"(%1 = OpFunction %void None %9
%9 = OpLabel
)";
if (decomposed) result += "OpStore %8 %4\n";
result += R"(OpReturn
OpFunctionEnd
%10 = OpFunction %void None %11
%11 = OpLabel
OpReturn
OpFunctionEnd
)";
return result;
}
TEST_F(DecomposeInitializedVariablesTest, PrivateWithNonEntryPointChanged) {
std::string input = GetGlobalWithNonEntryPointTest("Private", true, false);
std::string expected = GetGlobalWithNonEntryPointTest("Private", false, true);
SinglePassRunAndCheck<DecomposeInitializedVariablesPass>(
input, expected, /* skip_nop = */ false);
}
TEST_F(DecomposeInitializedVariablesTest, PrivateWithNonEntryPointUnchanged) {
std::string input = GetGlobalWithNonEntryPointTest("Private", false, false);
// SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
SinglePassRunAndCheck<DecomposeInitializedVariablesPass>(
input, input, /* skip_nop = */ false);
}
TEST_F(DecomposeInitializedVariablesTest, OutputWithNonEntryPointChanged) {
std::string input = GetGlobalWithNonEntryPointTest("Output", true, false);
std::string expected = GetGlobalWithNonEntryPointTest("Output", false, true);
SinglePassRunAndCheck<DecomposeInitializedVariablesPass>(
input, expected, /* skip_nop = */ false);
}
TEST_F(DecomposeInitializedVariablesTest, OutputWithNonEntryPointUnchanged) {
std::string input = GetGlobalWithNonEntryPointTest("Output", false, false);
// SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
SinglePassRunAndCheck<DecomposeInitializedVariablesPass>(
input, input, /* skip_nop = */ false);
}
} // namespace
} // namespace opt
} // namespace spvtools

View File

@@ -78,9 +78,13 @@ OpCapability Shader
%acquire_and_release = OpConstant %u32 6
%sequentially_consistent = OpConstant %u32 16
%acquire_release_uniform_workgroup = OpConstant %u32 328
%acquire_uniform_workgroup = OpConstant %u32 322
%release_uniform_workgroup = OpConstant %u32 324
%acquire_and_release_uniform = OpConstant %u32 70
%acquire_release_subgroup = OpConstant %u32 136
%uniform = OpConstant %u32 64
%uniform_workgroup = OpConstant %u32 320
%main = OpFunction %void None %func
%main_entry = OpLabel
@@ -245,9 +249,8 @@ OpControlBarrier %workgroup %workgroup %acquire_release_uniform_workgroup
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_0));
}
TEST_F(ValidateBarriers, OpControlBarrierWebGPUSuccess) {
TEST_F(ValidateBarriers, OpControlBarrierWebGPUAcquireReleaseSuccess) {
const std::string body = R"(
OpControlBarrier %workgroup %queuefamily %none
OpControlBarrier %workgroup %workgroup %acquire_release_uniform_workgroup
)";
@@ -255,6 +258,41 @@ OpControlBarrier %workgroup %workgroup %acquire_release_uniform_workgroup
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_WEBGPU_0));
}
TEST_F(ValidateBarriers, OpControlBarrierWebGPURelaxedFailure) {
const std::string body = R"(
OpControlBarrier %workgroup %workgroup %uniform_workgroup
)";
CompileSuccessfully(GenerateWebGPUShaderCode(body), SPV_ENV_WEBGPU_0);
EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_WEBGPU_0));
EXPECT_THAT(getDiagnosticString(),
HasSubstr("WebGPU spec requires AcquireRelease to set"));
}
TEST_F(ValidateBarriers, OpControlBarrierWebGPUAcquireFailure) {
const std::string body = R"(
OpControlBarrier %workgroup %workgroup %acquire_uniform_workgroup
)";
CompileSuccessfully(GenerateWebGPUShaderCode(body), SPV_ENV_WEBGPU_0);
EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_WEBGPU_0));
EXPECT_THAT(
getDiagnosticString(),
HasSubstr("WebGPU spec disallows any bit masks in Memory Semantics"));
}
TEST_F(ValidateBarriers, OpControlBarrierWebGPUReleaseFailure) {
const std::string body = R"(
OpControlBarrier %workgroup %workgroup %release_uniform_workgroup
)";
CompileSuccessfully(GenerateWebGPUShaderCode(body), SPV_ENV_WEBGPU_0);
EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_WEBGPU_0));
EXPECT_THAT(
getDiagnosticString(),
HasSubstr("WebGPU spec disallows any bit masks in Memory Semantics"));
}
TEST_F(ValidateBarriers, OpControlBarrierExecutionModelFragmentSpirv12) {
const std::string body = R"(
OpControlBarrier %device %device %none
@@ -630,6 +668,50 @@ OpMemoryBarrier %workgroup %acquire_release_uniform_workgroup
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_0));
}
TEST_F(ValidateBarriers, OpMemoryBarrierWebGPUAcquireReleaseSuccess) {
const std::string body = R"(
OpMemoryBarrier %workgroup %acquire_release_uniform_workgroup
)";
CompileSuccessfully(GenerateWebGPUShaderCode(body), SPV_ENV_WEBGPU_0);
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_WEBGPU_0));
}
TEST_F(ValidateBarriers, OpMemoryBarrierWebGPURelaxedFailure) {
const std::string body = R"(
OpMemoryBarrier %workgroup %uniform_workgroup
)";
CompileSuccessfully(GenerateWebGPUShaderCode(body), SPV_ENV_WEBGPU_0);
EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_WEBGPU_0));
EXPECT_THAT(getDiagnosticString(),
HasSubstr("WebGPU spec requires AcquireRelease to set"));
}
TEST_F(ValidateBarriers, OpMemoryBarrierWebGPUAcquireFailure) {
const std::string body = R"(
OpMemoryBarrier %workgroup %acquire_uniform_workgroup
)";
CompileSuccessfully(GenerateWebGPUShaderCode(body), SPV_ENV_WEBGPU_0);
EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_WEBGPU_0));
EXPECT_THAT(
getDiagnosticString(),
HasSubstr("WebGPU spec disallows any bit masks in Memory Semantics"));
}
TEST_F(ValidateBarriers, OpMemoryBarrierWebGPUReleaseFailure) {
const std::string body = R"(
OpMemoryBarrier %workgroup %release_uniform_workgroup
)";
CompileSuccessfully(GenerateWebGPUShaderCode(body), SPV_ENV_WEBGPU_0);
EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_WEBGPU_0));
EXPECT_THAT(
getDiagnosticString(),
HasSubstr("WebGPU spec disallows any bit masks in Memory Semantics"));
}
TEST_F(ValidateBarriers, OpMemoryBarrierFloatMemoryScope) {
const std::string body = R"(
OpMemoryBarrier %f32_1 %acquire_release_uniform_workgroup

View File

@@ -5719,6 +5719,41 @@ OpFunctionEnd
"improperly straddling vector at offset 28"));
}
TEST_F(ValidateDecorations, LargeArray) {
const std::string spirv = R"(
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint GLCompute %main "main"
OpExecutionMode %main LocalSize 1 1 1
OpDecorate %struct Block
OpMemberDecorate %struct 0 Offset 0
OpDecorate %array ArrayStride 24
OpMemberDecorate %inner 0 Offset 0
OpMemberDecorate %inner 1 Offset 8
OpMemberDecorate %inner 2 Offset 16
OpMemberDecorate %inner 3 Offset 20
OpDecorate %var DescriptorSet 0
OpDecorate %var Binding 0
%void = OpTypeVoid
%int = OpTypeInt 32 0
%int_2000000 = OpConstant %int 2000000
%int2 = OpTypeVector %int 2
%inner = OpTypeStruct %int %int2 %int %int
%array = OpTypeArray %inner %int_2000000
%struct = OpTypeStruct %array
%ptr_struct = OpTypePointer StorageBuffer %struct
%var = OpVariable %ptr_struct StorageBuffer
%void_fn = OpTypeFunction %void
%main = OpFunction %void None %void_fn
%entry = OpLabel
OpReturn
OpFunctionEnd
)";
CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1);
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_1));
}
// NonWritable
// Returns a SPIR-V shader module with variables in various storage classes,

View File

@@ -12,7 +12,9 @@
# See the License for the specific language governing permissions and
# limitations under the License.
add_subdirectory(lesspipe)
if (NOT ${SPIRV_SKIP_EXECUTABLES})
add_subdirectory(lesspipe)
endif()
add_subdirectory(emacs)
# Add a SPIR-V Tools command line tool. Signature: