mirror of
https://github.com/bkaradzic/bgfx.git
synced 2026-02-20 05:43:12 +01:00
Updated spirv-tools.
This commit is contained in:
25
3rdparty/spirv-tools/CHANGES
vendored
25
3rdparty/spirv-tools/CHANGES
vendored
@@ -1,20 +1,39 @@
|
||||
Revision history for SPIRV-Tools
|
||||
|
||||
v2018.7-dev 2018-12-10
|
||||
v2019.2-dev 2019-01-07
|
||||
- Start v2019.2-dev
|
||||
|
||||
v2019.1 2019-01-07
|
||||
- General:
|
||||
- Created a new tool called spirv-reduce.
|
||||
- Add cmake option to turn off SPIRV_TIMER_ENABLED (#2103)
|
||||
- New optimization pass to update the memory model from GLSL450 to VulkanKHR.
|
||||
- Recognize OpTypeAccelerationStructureNV as a type instruction and ray tracing storage classes.
|
||||
- Fix GCC8 build.
|
||||
- Add --target-env flag to spirv-opt.
|
||||
- Add --webgpu-mode flag to run optimizations for webgpu.
|
||||
- The output disassembled line number stead of byte offset in validation errors. (#2091)
|
||||
- Optimizer
|
||||
- Added the instrumentation passes for bindless validation.
|
||||
- Added passes to help preserve OpLine information (#2027)
|
||||
- Add basic support for EXT_fragment_invocation_density (#2100)
|
||||
- Fix invalid OpPhi generated by merge-return. (#2172)
|
||||
- Constant and type manager have been turned into analysies. (#2251)
|
||||
Fixes:
|
||||
- #2018: Don't inline functions with a return in a structured CFG contstruct.
|
||||
- #2047: Fix bug in folding when volatile stores are present.
|
||||
- #2053: Fix check for when folding floating pointer values is allowed.
|
||||
- #2130: Don't inline recursive functions.
|
||||
- #2202: Handle multiple edges between two basic blocks in SSA-rewriter.
|
||||
- #2205: Don't unswitch a latch condition during loop unswitch.
|
||||
- #2245: Don't fold branch in loop unswitch. Run dead branch elimination to fold them.
|
||||
- #2204: Fix eliminate common uniform to place OpPhi instructions correctly.
|
||||
- #2247: Fix type mismatches caused by scalar replacement.
|
||||
- #2248: Fix missing OpPhi after merge return.
|
||||
- #2211: After merge return, fix invalid continue target.
|
||||
- #2210: Fix loop invariant code motion to not place code between merge instruction and branch.
|
||||
- #2258: Handle CompositeInsert with no indices in VDCE.
|
||||
- #2261: Have replace load size handle extact with no index.
|
||||
- Validator
|
||||
- Changed the naming convention of outputing ids with names in diagnostic messages.
|
||||
- Added validation rules for UniformConstant variables in Vulkan.
|
||||
@@ -32,12 +51,14 @@ v2018.7-dev 2018-12-10
|
||||
- Allow Float16/Int8 for Vulkan 1.0 (#2153)
|
||||
- Check binding annotations in resource variables (#2151, #2167)
|
||||
- Validate OpForwardPointer (#2156)
|
||||
- Validate operation for OpSpecConstantOp (#2260)
|
||||
Fixes:
|
||||
- #2049: Allow InstanceId for NV ray tracing
|
||||
- Reduce
|
||||
- Initial commit wit a few passes to reduce test cases.
|
||||
- Validation is run after each reduction step.
|
||||
Fixes:
|
||||
|
||||
|
||||
|
||||
v2018.6 2018-11-07
|
||||
- General:
|
||||
|
||||
2
3rdparty/spirv-tools/DEPS
vendored
2
3rdparty/spirv-tools/DEPS
vendored
@@ -11,7 +11,7 @@ vars = {
|
||||
'googletest_revision': '98a0d007d7092b72eea0e501bb9ad17908a1a036',
|
||||
'testing_revision': '340252637e2e7c72c0901dcbeeacfff419e19b59',
|
||||
're2_revision': '6cf8ccd82dbaab2668e9b13596c68183c9ecd13f',
|
||||
'spirv_headers_revision': 'd5b2e1255f706ce1f88812217e9a554f299848af',
|
||||
'spirv_headers_revision': '79b6681aadcb53c27d1052e5f8a0e82a981dbf2f',
|
||||
}
|
||||
|
||||
deps = {
|
||||
|
||||
@@ -1 +1 @@
|
||||
"v2018.7-dev", "SPIRV-Tools v2018.7-dev bc65303576278bfb67295395327dc395a6adbf98"
|
||||
"v2019.2-dev", "SPIRV-Tools v2019.2-dev 3c8b3c81ef7f378717ef88916c06cb221eea890b"
|
||||
|
||||
@@ -75,8 +75,8 @@ static const int kInstCommonOutCnt = 4;
|
||||
// error.
|
||||
//
|
||||
// Vertex Shader Output Record Offsets
|
||||
static const int kInstVertOutVertexId = kInstCommonOutCnt;
|
||||
static const int kInstVertOutInstanceId = kInstCommonOutCnt + 1;
|
||||
static const int kInstVertOutVertexIndex = kInstCommonOutCnt;
|
||||
static const int kInstVertOutInstanceIndex = kInstCommonOutCnt + 1;
|
||||
|
||||
// Frag Shader Output Record Offsets
|
||||
static const int kInstFragOutFragCoordX = kInstCommonOutCnt;
|
||||
|
||||
@@ -58,33 +58,38 @@ if "%KOKORO_GITHUB_COMMIT%." == "." (
|
||||
set BUILD_SHA=%KOKORO_GITHUB_COMMIT%
|
||||
)
|
||||
|
||||
set CMAKE_FLAGS=-GNinja -DSPIRV_BUILD_COMPRESSION=ON -DCMAKE_BUILD_TYPE=%BUILD_TYPE% -DCMAKE_INSTALL_PREFIX=install -DRE2_BUILD_TESTING=OFF -DCMAKE_C_COMPILER=cl.exe -DCMAKE_CXX_COMPILER=cl.exe
|
||||
|
||||
:: Skip building tests for VS2013
|
||||
if %VS_VERSION% == 2013 (
|
||||
cmake -GNinja -DSPIRV_SKIP_TESTS=ON -DSPIRV_BUILD_COMPRESSION=ON -DCMAKE_BUILD_TYPE=%BUILD_TYPE% -DCMAKE_INSTALL_PREFIX=install -DRE2_BUILD_TESTING=OFF -DCMAKE_C_COMPILER=cl.exe -DCMAKE_CXX_COMPILER=cl.exe ..
|
||||
) else (
|
||||
cmake -GNinja -DSPIRV_BUILD_COMPRESSION=ON -DCMAKE_BUILD_TYPE=%BUILD_TYPE% -DCMAKE_INSTALL_PREFIX=install -DRE2_BUILD_TESTING=OFF -DCMAKE_C_COMPILER=cl.exe -DCMAKE_CXX_COMPILER=cl.exe ..
|
||||
set CMAKE_FLAGS=%CMAKE_FLAGS% -DSPIRV_SKIP_TESTS=ON
|
||||
)
|
||||
|
||||
if %ERRORLEVEL% GEQ 1 exit /b %ERRORLEVEL%
|
||||
cmake %CMAKE_FLAGS% ..
|
||||
|
||||
if %ERRORLEVEL% NEQ 0 exit /b %ERRORLEVEL%
|
||||
|
||||
echo "Build everything... %DATE% %TIME%"
|
||||
ninja
|
||||
if %ERRORLEVEL% GEQ 1 exit /b %ERRORLEVEL%
|
||||
if %ERRORLEVEL% NEQ 0 exit /b %ERRORLEVEL%
|
||||
echo "Build Completed %DATE% %TIME%"
|
||||
|
||||
:: This lets us use !ERRORLEVEL! inside an IF ... () and get the actual error at that point.
|
||||
setlocal ENABLEDELAYEDEXPANSION
|
||||
|
||||
:: ################################################
|
||||
:: Run the tests (We no longer run tests on VS2013)
|
||||
:: ################################################
|
||||
if NOT %VS_VERSION% == 2013 (
|
||||
echo "Running Tests... %DATE% %TIME%"
|
||||
echo "Running Tests... %DATE% %TIME%"
|
||||
if %VS_VERSION% NEQ 2013 (
|
||||
ctest -C %BUILD_TYPE% --output-on-failure --timeout 300
|
||||
if %ERRORLEVEL% GEQ 1 exit /b %ERRORLEVEL%
|
||||
echo "Tests Completed %DATE% %TIME%"
|
||||
if !ERRORLEVEL! NEQ 0 exit /b !ERRORLEVEL!
|
||||
)
|
||||
echo "Tests Completed %DATE% %TIME%"
|
||||
|
||||
:: Clean up some directories.
|
||||
rm -rf %SRC%\build
|
||||
rm -rf %SRC%\external
|
||||
|
||||
exit /b %ERRORLEVEL%
|
||||
exit /b 0
|
||||
|
||||
|
||||
3
3rdparty/spirv-tools/source/operand.cpp
vendored
3
3rdparty/spirv-tools/source/operand.cpp
vendored
@@ -481,6 +481,9 @@ std::function<bool(unsigned)> spvOperandCanBeForwardDeclaredFunction(
|
||||
case SpvOpTypeForwardPointer:
|
||||
out = [](unsigned index) { return index == 0; };
|
||||
break;
|
||||
case SpvOpTypeArray:
|
||||
out = [](unsigned index) { return index == 1; };
|
||||
break;
|
||||
default:
|
||||
out = [](unsigned) { return false; };
|
||||
break;
|
||||
|
||||
2
3rdparty/spirv-tools/source/opt/constants.h
vendored
2
3rdparty/spirv-tools/source/opt/constants.h
vendored
@@ -15,7 +15,7 @@
|
||||
#ifndef SOURCE_OPT_CONSTANTS_H_
|
||||
#define SOURCE_OPT_CONSTANTS_H_
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <cinttypes>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
|
||||
24
3rdparty/spirv-tools/source/opt/fold.cpp
vendored
24
3rdparty/spirv-tools/source/opt/fold.cpp
vendored
@@ -115,8 +115,10 @@ uint32_t InstructionFolder::BinaryOperate(SpvOp opcode, uint32_t a,
|
||||
|
||||
// Shifting
|
||||
case SpvOp::SpvOpShiftRightLogical:
|
||||
if (b > 32) {
|
||||
// This is undefined behaviour. Choose 0 for consistency.
|
||||
if (b >= 32) {
|
||||
// This is undefined behaviour when |b| > 32. Choose 0 for consistency.
|
||||
// When |b| == 32, doing the shift in C++ in undefined, but the result
|
||||
// will be 0, so just return that value.
|
||||
return 0;
|
||||
}
|
||||
return a >> b;
|
||||
@@ -125,10 +127,21 @@ uint32_t InstructionFolder::BinaryOperate(SpvOp opcode, uint32_t a,
|
||||
// This is undefined behaviour. Choose 0 for consistency.
|
||||
return 0;
|
||||
}
|
||||
if (b == 32) {
|
||||
// Doing the shift in C++ is undefined, but the result is defined in the
|
||||
// spir-v spec. Find that value another way.
|
||||
if (static_cast<int32_t>(a) >= 0) {
|
||||
return 0;
|
||||
} else {
|
||||
return static_cast<uint32_t>(-1);
|
||||
}
|
||||
}
|
||||
return (static_cast<int32_t>(a)) >> b;
|
||||
case SpvOp::SpvOpShiftLeftLogical:
|
||||
if (b > 32) {
|
||||
// This is undefined behaviour. Choose 0 for consistency.
|
||||
if (b >= 32) {
|
||||
// This is undefined behaviour when |b| > 32. Choose 0 for consistency.
|
||||
// When |b| == 32, doing the shift in C++ in undefined, but the result
|
||||
// will be 0, so just return that value.
|
||||
return 0;
|
||||
}
|
||||
return a << b;
|
||||
@@ -307,7 +320,8 @@ bool InstructionFolder::FoldBinaryIntegerOpToConstant(
|
||||
if (constants[1] != nullptr) {
|
||||
// When shifting by a value larger than the size of the result, the
|
||||
// result is undefined. We are setting the undefined behaviour to a
|
||||
// result of 0.
|
||||
// result of 0. If the shift amount is the same as the size of the
|
||||
// result, then the result is defined, and it 0.
|
||||
uint32_t shift_amount = constants[1]->GetU32BitValue();
|
||||
if (shift_amount >= 32) {
|
||||
*result = 0;
|
||||
|
||||
@@ -168,10 +168,10 @@ void InstrumentPass::GenStageStreamWriteCode(uint32_t stage_idx,
|
||||
switch (stage_idx) {
|
||||
case SpvExecutionModelVertex: {
|
||||
// Load and store VertexId and InstanceId
|
||||
GenBuiltinOutputCode(context()->GetBuiltinVarId(SpvBuiltInVertexId),
|
||||
kInstVertOutVertexId, base_offset_id, builder);
|
||||
GenBuiltinOutputCode(context()->GetBuiltinVarId(SpvBuiltInInstanceId),
|
||||
kInstVertOutInstanceId, base_offset_id, builder);
|
||||
GenBuiltinOutputCode(context()->GetBuiltinVarId(SpvBuiltInVertexIndex),
|
||||
kInstVertOutVertexIndex, base_offset_id, builder);
|
||||
GenBuiltinOutputCode(context()->GetBuiltinVarId(SpvBuiltInInstanceIndex),
|
||||
kInstVertOutInstanceIndex, base_offset_id, builder);
|
||||
} break;
|
||||
case SpvExecutionModelGLCompute: {
|
||||
// Load and store GlobalInvocationId. Second word is unused; store zero.
|
||||
@@ -309,6 +309,8 @@ uint32_t InstrumentPass::GetOutputBufferId() {
|
||||
analysis::RuntimeArray uint_rarr_ty(reg_uint_ty);
|
||||
analysis::Type* reg_uint_rarr_ty =
|
||||
type_mgr->GetRegisteredType(&uint_rarr_ty);
|
||||
uint32_t uint_arr_ty_id = type_mgr->GetTypeInstruction(reg_uint_rarr_ty);
|
||||
deco_mgr->AddDecorationVal(uint_arr_ty_id, SpvDecorationArrayStride, 4u);
|
||||
analysis::Struct obuf_ty({reg_uint_ty, reg_uint_rarr_ty});
|
||||
analysis::Type* reg_obuf_ty = type_mgr->GetRegisteredType(&obuf_ty);
|
||||
uint32_t obufTyId = type_mgr->GetTypeInstruction(reg_obuf_ty);
|
||||
|
||||
10
3rdparty/spirv-tools/source/opt/ir_builder.h
vendored
10
3rdparty/spirv-tools/source/opt/ir_builder.h
vendored
@@ -455,6 +455,16 @@ class InstructionBuilder {
|
||||
return AddInstruction(std::move(new_inst));
|
||||
}
|
||||
|
||||
Instruction* AddStore(uint32_t ptr_id, uint32_t obj_id) {
|
||||
std::vector<Operand> operands;
|
||||
operands.push_back({SPV_OPERAND_TYPE_ID, {ptr_id}});
|
||||
operands.push_back({SPV_OPERAND_TYPE_ID, {obj_id}});
|
||||
|
||||
std::unique_ptr<Instruction> new_inst(
|
||||
new Instruction(GetContext(), SpvOpStore, 0, 0, operands));
|
||||
return AddInstruction(std::move(new_inst));
|
||||
}
|
||||
|
||||
// Inserts the new instruction before the insertion point.
|
||||
Instruction* AddInstruction(std::unique_ptr<Instruction>&& insn) {
|
||||
Instruction* insn_ptr = &*insert_before_.InsertBefore(std::move(insn));
|
||||
|
||||
@@ -669,8 +669,8 @@ uint32_t IRContext::GetBuiltinVarId(uint32_t builtin) {
|
||||
reg_type = type_mgr->GetRegisteredType(&v4float_ty);
|
||||
break;
|
||||
}
|
||||
case SpvBuiltInVertexId:
|
||||
case SpvBuiltInInstanceId:
|
||||
case SpvBuiltInVertexIndex:
|
||||
case SpvBuiltInInstanceIndex:
|
||||
case SpvBuiltInPrimitiveId:
|
||||
case SpvBuiltInInvocationId:
|
||||
case SpvBuiltInGlobalInvocationId: {
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "source/opt/ir_builder.h"
|
||||
#include "source/opt/ir_context.h"
|
||||
#include "source/util/make_unique.h"
|
||||
|
||||
@@ -68,6 +69,22 @@ void UpgradeMemoryModel::UpgradeInstructions() {
|
||||
// instructions. Additionally, Workgroup storage class variables and function
|
||||
// parameters are implicitly coherent in GLSL450.
|
||||
|
||||
// Upgrade modf and frexp first since they generate new stores.
|
||||
for (auto& func : *get_module()) {
|
||||
func.ForEachInst([this](Instruction* inst) {
|
||||
if (inst->opcode() == SpvOpExtInst) {
|
||||
auto ext_inst = inst->GetSingleWordInOperand(1u);
|
||||
if (ext_inst == GLSLstd450Modf || ext_inst == GLSLstd450Frexp) {
|
||||
auto import =
|
||||
get_def_use_mgr()->GetDef(inst->GetSingleWordInOperand(0u));
|
||||
if (reinterpret_cast<char*>(import->GetInOperand(0u).words.data()) ==
|
||||
std::string("GLSL.std.450")) {
|
||||
UpgradeExtInst(inst);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
for (auto& func : *get_module()) {
|
||||
func.ForEachInst([this](Instruction* inst) {
|
||||
bool is_coherent = false;
|
||||
@@ -104,11 +121,11 @@ void UpgradeMemoryModel::UpgradeInstructions() {
|
||||
|
||||
switch (inst->opcode()) {
|
||||
case SpvOpLoad:
|
||||
UpgradeFlags(inst, 1u, is_coherent, is_volatile, kAvailability,
|
||||
UpgradeFlags(inst, 1u, is_coherent, is_volatile, kVisibility,
|
||||
kMemory);
|
||||
break;
|
||||
case SpvOpStore:
|
||||
UpgradeFlags(inst, 2u, is_coherent, is_volatile, kVisibility,
|
||||
UpgradeFlags(inst, 2u, is_coherent, is_volatile, kAvailability,
|
||||
kMemory);
|
||||
break;
|
||||
case SpvOpCopyMemory:
|
||||
@@ -125,11 +142,11 @@ void UpgradeMemoryModel::UpgradeInstructions() {
|
||||
break;
|
||||
case SpvOpImageRead:
|
||||
case SpvOpImageSparseRead:
|
||||
UpgradeFlags(inst, 2u, is_coherent, is_volatile, kAvailability,
|
||||
kImage);
|
||||
UpgradeFlags(inst, 2u, is_coherent, is_volatile, kVisibility, kImage);
|
||||
break;
|
||||
case SpvOpImageWrite:
|
||||
UpgradeFlags(inst, 3u, is_coherent, is_volatile, kVisibility, kImage);
|
||||
UpgradeFlags(inst, 3u, is_coherent, is_volatile, kAvailability,
|
||||
kImage);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -143,15 +160,15 @@ void UpgradeMemoryModel::UpgradeInstructions() {
|
||||
}
|
||||
// According to SPV_KHR_vulkan_memory_model, if both available and
|
||||
// visible flags are used the first scope operand is for availability
|
||||
// (reads) and the second is for visibiity (writes).
|
||||
if (src_coherent) {
|
||||
inst->AddOperand(
|
||||
{SPV_OPERAND_TYPE_SCOPE_ID, {GetScopeConstant(src_scope)}});
|
||||
}
|
||||
// (writes) and the second is for visibility (reads).
|
||||
if (dst_coherent) {
|
||||
inst->AddOperand(
|
||||
{SPV_OPERAND_TYPE_SCOPE_ID, {GetScopeConstant(dst_scope)}});
|
||||
}
|
||||
if (src_coherent) {
|
||||
inst->AddOperand(
|
||||
{SPV_OPERAND_TYPE_SCOPE_ID, {GetScopeConstant(src_scope)}});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -581,5 +598,43 @@ bool UpgradeMemoryModel::IsDeviceScope(uint32_t scope_id) {
|
||||
return false;
|
||||
}
|
||||
|
||||
void UpgradeMemoryModel::UpgradeExtInst(Instruction* ext_inst) {
|
||||
const bool is_modf = ext_inst->GetSingleWordInOperand(1u) == GLSLstd450Modf;
|
||||
auto ptr_id = ext_inst->GetSingleWordInOperand(3u);
|
||||
auto ptr_type_id = get_def_use_mgr()->GetDef(ptr_id)->type_id();
|
||||
auto pointee_type_id =
|
||||
get_def_use_mgr()->GetDef(ptr_type_id)->GetSingleWordInOperand(1u);
|
||||
auto element_type_id = ext_inst->type_id();
|
||||
std::vector<const analysis::Type*> element_types(2);
|
||||
element_types[0] = context()->get_type_mgr()->GetType(element_type_id);
|
||||
element_types[1] = context()->get_type_mgr()->GetType(pointee_type_id);
|
||||
analysis::Struct struct_type(element_types);
|
||||
uint32_t struct_id =
|
||||
context()->get_type_mgr()->GetTypeInstruction(&struct_type);
|
||||
// Change the operation
|
||||
GLSLstd450 new_op = is_modf ? GLSLstd450ModfStruct : GLSLstd450FrexpStruct;
|
||||
ext_inst->SetOperand(3u, {static_cast<uint32_t>(new_op)});
|
||||
// Remove the pointer argument
|
||||
ext_inst->RemoveOperand(5u);
|
||||
// Set the type id to the new struct.
|
||||
ext_inst->SetResultType(struct_id);
|
||||
|
||||
// The result is now a struct of the original result. The zero'th element is
|
||||
// old result and should replace the old result. The one'th element needs to
|
||||
// be stored via a new instruction.
|
||||
auto where = ext_inst->NextNode();
|
||||
InstructionBuilder builder(
|
||||
context(), where,
|
||||
IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping);
|
||||
auto extract_0 =
|
||||
builder.AddCompositeExtract(element_type_id, ext_inst->result_id(), {0});
|
||||
context()->ReplaceAllUsesWith(ext_inst->result_id(), extract_0->result_id());
|
||||
// The extract's input was just changed to itself, so fix that.
|
||||
extract_0->SetInOperand(0u, {ext_inst->result_id()});
|
||||
auto extract_1 =
|
||||
builder.AddCompositeExtract(pointee_type_id, ext_inst->result_id(), {1});
|
||||
builder.AddStore(ptr_id, extract_1->result_id());
|
||||
}
|
||||
|
||||
} // namespace opt
|
||||
} // namespace spvtools
|
||||
|
||||
@@ -118,6 +118,11 @@ class UpgradeMemoryModel : public Pass {
|
||||
// Returns true if |scope_id| is SpvScopeDevice.
|
||||
bool IsDeviceScope(uint32_t scope_id);
|
||||
|
||||
// Upgrades GLSL.std.450 modf and frexp. Both instructions are replaced with
|
||||
// their struct versions. New extracts and a store are added in order to
|
||||
// facilitate adding memory model flags.
|
||||
void UpgradeExtInst(Instruction* modf);
|
||||
|
||||
// Caches the result of TraceInstruction. For a given result id and set of
|
||||
// indices, stores whether that combination is coherent and/or volatile.
|
||||
std::unordered_map<std::pair<uint32_t, std::vector<uint32_t>>,
|
||||
|
||||
59
3rdparty/spirv-tools/source/val/validate.cpp
vendored
59
3rdparty/spirv-tools/source/val/validate.cpp
vendored
@@ -169,6 +169,57 @@ spv_result_t ValidateForwardDecls(ValidationState_t& _) {
|
||||
<< id_str.substr(0, id_str.size() - 1);
|
||||
}
|
||||
|
||||
std::vector<std::string> CalculateNamesForEntryPoint(ValidationState_t& _,
|
||||
const uint32_t id) {
|
||||
auto id_descriptions = _.entry_point_descriptions(id);
|
||||
auto id_names = std::vector<std::string>();
|
||||
id_names.reserve((id_descriptions.size()));
|
||||
|
||||
for (auto description : id_descriptions) id_names.push_back(description.name);
|
||||
|
||||
return id_names;
|
||||
}
|
||||
|
||||
spv_result_t ValidateEntryPointNameUnique(ValidationState_t& _,
|
||||
const uint32_t id) {
|
||||
auto id_names = CalculateNamesForEntryPoint(_, id);
|
||||
const auto names =
|
||||
std::unordered_set<std::string>(id_names.begin(), id_names.end());
|
||||
|
||||
if (id_names.size() != names.size()) {
|
||||
std::sort(id_names.begin(), id_names.end());
|
||||
for (size_t i = 0; i < id_names.size() - 1; i++) {
|
||||
if (id_names[i] == id_names[i + 1]) {
|
||||
return _.diag(SPV_ERROR_INVALID_BINARY, _.FindDef(id))
|
||||
<< "Entry point name \"" << id_names[i]
|
||||
<< "\" is not unique, which is not allow in WebGPU env.";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto other_id : _.entry_points()) {
|
||||
if (other_id == id) continue;
|
||||
const auto other_id_names = CalculateNamesForEntryPoint(_, other_id);
|
||||
for (const auto other_id_name : other_id_names) {
|
||||
if (names.find(other_id_name) != names.end()) {
|
||||
return _.diag(SPV_ERROR_INVALID_BINARY, _.FindDef(id))
|
||||
<< "Entry point name \"" << other_id_name
|
||||
<< "\" is not unique, which is not allow in WebGPU env.";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return SPV_SUCCESS;
|
||||
}
|
||||
|
||||
spv_result_t ValidateEntryPointNamesUnique(ValidationState_t& _) {
|
||||
for (const auto id : _.entry_points()) {
|
||||
auto result = ValidateEntryPointNameUnique(_, id);
|
||||
if (result != SPV_SUCCESS) return result;
|
||||
}
|
||||
return SPV_SUCCESS;
|
||||
}
|
||||
|
||||
// Entry point validation. Based on 2.16.1 (Universal Validation Rules) of the
|
||||
// SPIRV spec:
|
||||
// * There is at least one OpEntryPoint instruction, unless the Linkage
|
||||
@@ -177,7 +228,7 @@ spv_result_t ValidateForwardDecls(ValidationState_t& _) {
|
||||
// OpFunctionCall instruction.
|
||||
//
|
||||
// Additionally enforces that entry points for Vulkan and WebGPU should not have
|
||||
// recursion.
|
||||
// recursion. And that entry names should be unique for WebGPU.
|
||||
spv_result_t ValidateEntryPoints(ValidationState_t& _) {
|
||||
_.ComputeFunctionToEntryPointMapping();
|
||||
_.ComputeRecursiveEntryPoints();
|
||||
@@ -206,6 +257,12 @@ spv_result_t ValidateEntryPoints(ValidationState_t& _) {
|
||||
<< "Entry points may not have a call graph with cycles.";
|
||||
}
|
||||
}
|
||||
|
||||
// For WebGPU all entry point names must be unique.
|
||||
if (spvIsWebGPUEnv(_.context()->target_env)) {
|
||||
const auto result = ValidateEntryPointNamesUnique(_);
|
||||
if (result != SPV_SUCCESS) return result;
|
||||
}
|
||||
}
|
||||
|
||||
return SPV_SUCCESS;
|
||||
|
||||
@@ -127,6 +127,7 @@ spv_result_t AtomicsPass(ValidationState_t& _, const Instruction* inst) {
|
||||
case SpvStorageClassAtomicCounter:
|
||||
case SpvStorageClassImage:
|
||||
case SpvStorageClassStorageBuffer:
|
||||
case SpvStorageClassPhysicalStorageBufferEXT:
|
||||
break;
|
||||
default:
|
||||
if (spvIsOpenCLEnv(_.context()->target_env)) {
|
||||
|
||||
@@ -329,11 +329,19 @@ spv_result_t ValidateSpecConstantOp(ValidationState_t& _,
|
||||
}
|
||||
break;
|
||||
|
||||
case SpvOpUConvert:
|
||||
if (!_.features().uconvert_spec_constant_op &&
|
||||
!_.HasCapability(SpvCapabilityKernel)) {
|
||||
return _.diag(SPV_ERROR_INVALID_ID, inst)
|
||||
<< "UConvert requires Kernel capability or extension "
|
||||
"SPV_AMD_gpu_shader_int16";
|
||||
}
|
||||
break;
|
||||
|
||||
case SpvOpConvertFToS:
|
||||
case SpvOpConvertSToF:
|
||||
case SpvOpConvertFToU:
|
||||
case SpvOpConvertUToF:
|
||||
case SpvOpUConvert:
|
||||
case SpvOpConvertPtrToU:
|
||||
case SpvOpConvertUToPtr:
|
||||
case SpvOpGenericCastToPtr:
|
||||
|
||||
@@ -217,6 +217,23 @@ spv_result_t ConversionPass(ValidationState_t& _, const Instruction* inst) {
|
||||
if (!_.IsPointerType(input_type))
|
||||
return _.diag(SPV_ERROR_INVALID_DATA, inst)
|
||||
<< "Expected input to be a pointer: " << spvOpcodeString(opcode);
|
||||
|
||||
if (_.addressing_model() == SpvAddressingModelLogical)
|
||||
return _.diag(SPV_ERROR_INVALID_DATA, inst)
|
||||
<< "Logical addressing not supported: "
|
||||
<< spvOpcodeString(opcode);
|
||||
|
||||
if (_.addressing_model() ==
|
||||
SpvAddressingModelPhysicalStorageBuffer64EXT) {
|
||||
uint32_t input_storage_class = 0;
|
||||
uint32_t input_data_type = 0;
|
||||
_.GetPointerTypeInfo(input_type, &input_data_type,
|
||||
&input_storage_class);
|
||||
if (input_storage_class != SpvStorageClassPhysicalStorageBufferEXT)
|
||||
return _.diag(SPV_ERROR_INVALID_DATA, inst)
|
||||
<< "Pointer storage class must be PhysicalStorageBufferEXT: "
|
||||
<< spvOpcodeString(opcode);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -251,6 +268,23 @@ spv_result_t ConversionPass(ValidationState_t& _, const Instruction* inst) {
|
||||
if (!input_type || !_.IsIntScalarType(input_type))
|
||||
return _.diag(SPV_ERROR_INVALID_DATA, inst)
|
||||
<< "Expected int scalar as input: " << spvOpcodeString(opcode);
|
||||
|
||||
if (_.addressing_model() == SpvAddressingModelLogical)
|
||||
return _.diag(SPV_ERROR_INVALID_DATA, inst)
|
||||
<< "Logical addressing not supported: "
|
||||
<< spvOpcodeString(opcode);
|
||||
|
||||
if (_.addressing_model() ==
|
||||
SpvAddressingModelPhysicalStorageBuffer64EXT) {
|
||||
uint32_t result_storage_class = 0;
|
||||
uint32_t result_data_type = 0;
|
||||
_.GetPointerTypeInfo(result_type, &result_data_type,
|
||||
&result_storage_class);
|
||||
if (result_storage_class != SpvStorageClassPhysicalStorageBufferEXT)
|
||||
return _.diag(SPV_ERROR_INVALID_DATA, inst)
|
||||
<< "Pointer storage class must be PhysicalStorageBufferEXT: "
|
||||
<< spvOpcodeString(opcode);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -218,6 +218,9 @@ uint32_t getBaseAlignment(uint32_t member_id, bool roundUp,
|
||||
if (roundUp) baseAlignment = align(baseAlignment, 16u);
|
||||
break;
|
||||
}
|
||||
case SpvOpTypePointer:
|
||||
baseAlignment = vstate.pointer_size_and_alignment();
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
break;
|
||||
@@ -254,6 +257,8 @@ uint32_t getScalarAlignment(uint32_t type_id, ValidationState_t& vstate) {
|
||||
}
|
||||
return max_member_alignment;
|
||||
} break;
|
||||
case SpvOpTypePointer:
|
||||
return vstate.pointer_size_and_alignment();
|
||||
default:
|
||||
assert(0);
|
||||
break;
|
||||
@@ -331,6 +336,8 @@ uint32_t getSize(uint32_t member_id, const LayoutConstraints& inherited,
|
||||
const auto& constraint = constraints[std::make_pair(lastMember, lastIdx)];
|
||||
return offset + getSize(lastMember, constraint, constraints, vstate);
|
||||
}
|
||||
case SpvOpTypePointer:
|
||||
return vstate.pointer_size_and_alignment();
|
||||
default:
|
||||
assert(0);
|
||||
return 0;
|
||||
@@ -847,7 +854,9 @@ spv_result_t CheckDecorationsOfBuffers(ValidationState_t& vstate) {
|
||||
}
|
||||
}
|
||||
|
||||
if (uniform || push_constant || storage_buffer) {
|
||||
const bool phys_storage_buffer =
|
||||
storageClass == SpvStorageClassPhysicalStorageBufferEXT;
|
||||
if (uniform || push_constant || storage_buffer || phys_storage_buffer) {
|
||||
const auto ptrInst = vstate.FindDef(words[1]);
|
||||
assert(SpvOpTypePointer == ptrInst->opcode());
|
||||
const auto id = ptrInst->words()[3];
|
||||
@@ -899,9 +908,9 @@ spv_result_t CheckDecorationsOfBuffers(ValidationState_t& vstate) {
|
||||
const bool blockDeco = SpvDecorationBlock == dec.dec_type();
|
||||
const bool bufferDeco = SpvDecorationBufferBlock == dec.dec_type();
|
||||
const bool blockRules = uniform && blockDeco;
|
||||
const bool bufferRules = (uniform && bufferDeco) ||
|
||||
(push_constant && blockDeco) ||
|
||||
(storage_buffer && blockDeco);
|
||||
const bool bufferRules =
|
||||
(uniform && bufferDeco) || (push_constant && blockDeco) ||
|
||||
((storage_buffer || phys_storage_buffer) && blockDeco);
|
||||
if (blockRules || bufferRules) {
|
||||
const char* deco_str = blockDeco ? "Block" : "BufferBlock";
|
||||
spv_result_t recursive_status = SPV_SUCCESS;
|
||||
@@ -1127,12 +1136,13 @@ spv_result_t CheckFPRoundingModeForShaders(ValidationState_t& vstate,
|
||||
if (storage != SpvStorageClassStorageBuffer &&
|
||||
storage != SpvStorageClassUniform &&
|
||||
storage != SpvStorageClassPushConstant &&
|
||||
storage != SpvStorageClassInput && storage != SpvStorageClassOutput) {
|
||||
storage != SpvStorageClassInput && storage != SpvStorageClassOutput &&
|
||||
storage != SpvStorageClassPhysicalStorageBufferEXT) {
|
||||
return vstate.diag(SPV_ERROR_INVALID_ID, &inst)
|
||||
<< "FPRoundingMode decoration can be applied only to the "
|
||||
"Object operand of an OpStore in the StorageBuffer, "
|
||||
"Uniform, PushConstant, Input, or Output Storage "
|
||||
"Classes.";
|
||||
"PhysicalStorageBufferEXT, Uniform, PushConstant, Input, or "
|
||||
"Output Storage Classes.";
|
||||
}
|
||||
}
|
||||
return SPV_SUCCESS;
|
||||
@@ -1170,6 +1180,36 @@ spv_result_t CheckUniformDecoration(ValidationState_t& vstate,
|
||||
return SPV_SUCCESS;
|
||||
}
|
||||
|
||||
// Returns SPV_SUCCESS if validation rules are satisfied for NoSignedWrap or
|
||||
// NoUnsignedWrap decorations. Otherwise emits a diagnostic and returns
|
||||
// something other than SPV_SUCCESS. Assumes each decoration on a group has been
|
||||
// propagated down to the group members.
|
||||
spv_result_t CheckIntegerWrapDecoration(ValidationState_t& vstate,
|
||||
const Instruction& inst,
|
||||
const Decoration& decoration) {
|
||||
switch (inst.opcode()) {
|
||||
case SpvOpIAdd:
|
||||
case SpvOpISub:
|
||||
case SpvOpIMul:
|
||||
case SpvOpShiftLeftLogical:
|
||||
case SpvOpSNegate:
|
||||
return SPV_SUCCESS;
|
||||
case SpvOpExtInst:
|
||||
// TODO(dneto): Only certain extended instructions allow these
|
||||
// decorations. For now allow anything.
|
||||
return SPV_SUCCESS;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return vstate.diag(SPV_ERROR_INVALID_ID, &inst)
|
||||
<< (decoration.dec_type() == SpvDecorationNoSignedWrap
|
||||
? "NoSignedWrap"
|
||||
: "NoUnsignedWrap")
|
||||
<< " decoration may not be applied to "
|
||||
<< spvOpcodeString(inst.opcode());
|
||||
}
|
||||
|
||||
#define PASS_OR_BAIL_AT_LINE(X, LINE) \
|
||||
{ \
|
||||
spv_result_t e##LINE = (X); \
|
||||
@@ -1206,6 +1246,10 @@ spv_result_t CheckDecorationsFromDecoration(ValidationState_t& vstate) {
|
||||
case SpvDecorationUniform:
|
||||
PASS_OR_BAIL(CheckUniformDecoration(vstate, *inst, decoration));
|
||||
break;
|
||||
case SpvDecorationNoSignedWrap:
|
||||
case SpvDecorationNoUnsignedWrap:
|
||||
PASS_OR_BAIL(CheckIntegerWrapDecoration(vstate, *inst, decoration));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -111,6 +111,79 @@ spv_result_t ValidateFunctionParameter(ValidationState_t& _,
|
||||
<< "' does not match the OpTypeFunction parameter "
|
||||
"type of the same index.";
|
||||
}
|
||||
|
||||
// Validate that PhysicalStorageBufferEXT have one of Restrict, Aliased,
|
||||
// RestrictPointerEXT, or AliasedPointerEXT.
|
||||
auto param_nonarray_type_id = param_type->id();
|
||||
while (_.GetIdOpcode(param_nonarray_type_id) == SpvOpTypeArray) {
|
||||
param_nonarray_type_id =
|
||||
_.FindDef(param_nonarray_type_id)->GetOperandAs<uint32_t>(1u);
|
||||
}
|
||||
if (_.GetIdOpcode(param_nonarray_type_id) == SpvOpTypePointer) {
|
||||
auto param_nonarray_type = _.FindDef(param_nonarray_type_id);
|
||||
if (param_nonarray_type->GetOperandAs<uint32_t>(1u) ==
|
||||
SpvStorageClassPhysicalStorageBufferEXT) {
|
||||
// check for Aliased or Restrict
|
||||
const auto& decorations = _.id_decorations(inst->id());
|
||||
|
||||
bool foundAliased = std::any_of(
|
||||
decorations.begin(), decorations.end(), [](const Decoration& d) {
|
||||
return SpvDecorationAliased == d.dec_type();
|
||||
});
|
||||
|
||||
bool foundRestrict = std::any_of(
|
||||
decorations.begin(), decorations.end(), [](const Decoration& d) {
|
||||
return SpvDecorationRestrict == d.dec_type();
|
||||
});
|
||||
|
||||
if (!foundAliased && !foundRestrict) {
|
||||
return _.diag(SPV_ERROR_INVALID_ID, inst)
|
||||
<< "OpFunctionParameter " << inst->id()
|
||||
<< ": expected Aliased or Restrict for PhysicalStorageBufferEXT "
|
||||
"pointer.";
|
||||
}
|
||||
if (foundAliased && foundRestrict) {
|
||||
return _.diag(SPV_ERROR_INVALID_ID, inst)
|
||||
<< "OpFunctionParameter " << inst->id()
|
||||
<< ": can't specify both Aliased and Restrict for "
|
||||
"PhysicalStorageBufferEXT pointer.";
|
||||
}
|
||||
} else {
|
||||
const auto pointee_type_id =
|
||||
param_nonarray_type->GetOperandAs<uint32_t>(2);
|
||||
const auto pointee_type = _.FindDef(pointee_type_id);
|
||||
if (SpvOpTypePointer == pointee_type->opcode() &&
|
||||
pointee_type->GetOperandAs<uint32_t>(1u) ==
|
||||
SpvStorageClassPhysicalStorageBufferEXT) {
|
||||
// check for AliasedPointerEXT/RestrictPointerEXT
|
||||
const auto& decorations = _.id_decorations(inst->id());
|
||||
|
||||
bool foundAliased = std::any_of(
|
||||
decorations.begin(), decorations.end(), [](const Decoration& d) {
|
||||
return SpvDecorationAliasedPointerEXT == d.dec_type();
|
||||
});
|
||||
|
||||
bool foundRestrict = std::any_of(
|
||||
decorations.begin(), decorations.end(), [](const Decoration& d) {
|
||||
return SpvDecorationRestrictPointerEXT == d.dec_type();
|
||||
});
|
||||
|
||||
if (!foundAliased && !foundRestrict) {
|
||||
return _.diag(SPV_ERROR_INVALID_ID, inst)
|
||||
<< "OpFunctionParameter " << inst->id()
|
||||
<< ": expected AliasedPointerEXT or RestrictPointerEXT for "
|
||||
"PhysicalStorageBufferEXT pointer.";
|
||||
}
|
||||
if (foundAliased && foundRestrict) {
|
||||
return _.diag(SPV_ERROR_INVALID_ID, inst)
|
||||
<< "OpFunctionParameter " << inst->id()
|
||||
<< ": can't specify both AliasedPointerEXT and "
|
||||
"RestrictPointerEXT for PhysicalStorageBufferEXT pointer.";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return SPV_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
@@ -154,7 +154,8 @@ spv_result_t LogicalsPass(ValidationState_t& _, const Instruction* inst) {
|
||||
const SpvOp type_opcode = type_inst->opcode();
|
||||
switch (type_opcode) {
|
||||
case SpvOpTypePointer: {
|
||||
if (!_.features().variable_pointers &&
|
||||
if (_.addressing_model() == SpvAddressingModelLogical &&
|
||||
!_.features().variable_pointers &&
|
||||
!_.features().variable_pointers_storage_buffer)
|
||||
return _.diag(SPV_ERROR_INVALID_DATA, inst)
|
||||
<< "Using pointers with OpSelect requires capability "
|
||||
|
||||
177
3rdparty/spirv-tools/source/val/validate_memory.cpp
vendored
177
3rdparty/spirv-tools/source/val/validate_memory.cpp
vendored
@@ -277,7 +277,20 @@ uint32_t GetMakeVisibleScope(const Instruction* inst, uint32_t mask) {
|
||||
}
|
||||
|
||||
spv_result_t CheckMemoryAccess(ValidationState_t& _, const Instruction* inst,
|
||||
uint32_t mask) {
|
||||
uint32_t index) {
|
||||
SpvStorageClass dst_sc, src_sc;
|
||||
std::tie(dst_sc, src_sc) = GetStorageClass(_, inst);
|
||||
if (inst->operands().size() <= index) {
|
||||
if (src_sc == SpvStorageClassPhysicalStorageBufferEXT ||
|
||||
dst_sc == SpvStorageClassPhysicalStorageBufferEXT) {
|
||||
return _.diag(SPV_ERROR_INVALID_ID, inst) << "Memory accesses with "
|
||||
"PhysicalStorageBufferEXT "
|
||||
"must use Aligned.";
|
||||
}
|
||||
return SPV_SUCCESS;
|
||||
}
|
||||
|
||||
uint32_t mask = inst->GetOperandAs<uint32_t>(index);
|
||||
if (mask & SpvMemoryAccessMakePointerAvailableKHRMask) {
|
||||
if (inst->opcode() == SpvOpLoad) {
|
||||
return _.diag(SPV_ERROR_INVALID_ID, inst)
|
||||
@@ -314,13 +327,12 @@ spv_result_t CheckMemoryAccess(ValidationState_t& _, const Instruction* inst,
|
||||
}
|
||||
|
||||
if (mask & SpvMemoryAccessNonPrivatePointerKHRMask) {
|
||||
SpvStorageClass dst_sc, src_sc;
|
||||
std::tie(dst_sc, src_sc) = GetStorageClass(_, inst);
|
||||
if (dst_sc != SpvStorageClassUniform &&
|
||||
dst_sc != SpvStorageClassWorkgroup &&
|
||||
dst_sc != SpvStorageClassCrossWorkgroup &&
|
||||
dst_sc != SpvStorageClassGeneric && dst_sc != SpvStorageClassImage &&
|
||||
dst_sc != SpvStorageClassStorageBuffer) {
|
||||
dst_sc != SpvStorageClassStorageBuffer &&
|
||||
dst_sc != SpvStorageClassPhysicalStorageBufferEXT) {
|
||||
return _.diag(SPV_ERROR_INVALID_ID, inst)
|
||||
<< "NonPrivatePointerKHR requires a pointer in Uniform, "
|
||||
"Workgroup, CrossWorkgroup, Generic, Image or StorageBuffer "
|
||||
@@ -330,7 +342,8 @@ spv_result_t CheckMemoryAccess(ValidationState_t& _, const Instruction* inst,
|
||||
src_sc != SpvStorageClassWorkgroup &&
|
||||
src_sc != SpvStorageClassCrossWorkgroup &&
|
||||
src_sc != SpvStorageClassGeneric && src_sc != SpvStorageClassImage &&
|
||||
src_sc != SpvStorageClassStorageBuffer) {
|
||||
src_sc != SpvStorageClassStorageBuffer &&
|
||||
src_sc != SpvStorageClassPhysicalStorageBufferEXT) {
|
||||
return _.diag(SPV_ERROR_INVALID_ID, inst)
|
||||
<< "NonPrivatePointerKHR requires a pointer in Uniform, "
|
||||
"Workgroup, CrossWorkgroup, Generic, Image or StorageBuffer "
|
||||
@@ -338,6 +351,15 @@ spv_result_t CheckMemoryAccess(ValidationState_t& _, const Instruction* inst,
|
||||
}
|
||||
}
|
||||
|
||||
if (!(mask & SpvMemoryAccessAlignedMask)) {
|
||||
if (src_sc == SpvStorageClassPhysicalStorageBufferEXT ||
|
||||
dst_sc == SpvStorageClassPhysicalStorageBufferEXT) {
|
||||
return _.diag(SPV_ERROR_INVALID_ID, inst) << "Memory accesses with "
|
||||
"PhysicalStorageBufferEXT "
|
||||
"must use Aligned.";
|
||||
}
|
||||
}
|
||||
|
||||
return SPV_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -414,7 +436,7 @@ spv_result_t ValidateVariable(ValidationState_t& _, const Instruction* inst) {
|
||||
}
|
||||
|
||||
// Variable pointer related restrictions.
|
||||
auto pointee = _.FindDef(result_type->word(3));
|
||||
const auto pointee = _.FindDef(result_type->word(3));
|
||||
if (_.addressing_model() == SpvAddressingModelLogical &&
|
||||
!_.options()->relax_logical_pointer) {
|
||||
// VariablePointersStorageBuffer is implied by VariablePointers.
|
||||
@@ -507,6 +529,125 @@ spv_result_t ValidateVariable(ValidationState_t& _, const Instruction* inst) {
|
||||
}
|
||||
}
|
||||
|
||||
// WebGPU: All variables with storage class Output, Private, or Function MUST
|
||||
// have an initializer.
|
||||
if (spvIsWebGPUEnv(_.context()->target_env) && inst->operands().size() <= 3 &&
|
||||
(storage_class == SpvStorageClassOutput ||
|
||||
storage_class == SpvStorageClassPrivate ||
|
||||
storage_class == SpvStorageClassFunction)) {
|
||||
return _.diag(SPV_ERROR_INVALID_ID, inst)
|
||||
<< "OpVariable, <id> '" << _.getIdName(inst->id())
|
||||
<< "', must have an initializer.\n"
|
||||
<< "From WebGPU execution environment spec:\n"
|
||||
<< "All variables in the following storage classes must have an "
|
||||
<< "initializer: Output, Private, or Function";
|
||||
}
|
||||
|
||||
if (storage_class == SpvStorageClassPhysicalStorageBufferEXT) {
|
||||
return _.diag(SPV_ERROR_INVALID_ID, inst)
|
||||
<< "PhysicalStorageBufferEXT must not be used with OpVariable.";
|
||||
}
|
||||
|
||||
auto pointee_base = pointee;
|
||||
while (pointee_base->opcode() == SpvOpTypeArray) {
|
||||
pointee_base = _.FindDef(pointee_base->GetOperandAs<uint32_t>(1u));
|
||||
}
|
||||
if (pointee_base->opcode() == SpvOpTypePointer) {
|
||||
if (pointee_base->GetOperandAs<uint32_t>(1u) ==
|
||||
SpvStorageClassPhysicalStorageBufferEXT) {
|
||||
// check for AliasedPointerEXT/RestrictPointerEXT
|
||||
bool foundAliased =
|
||||
_.HasDecoration(inst->id(), SpvDecorationAliasedPointerEXT);
|
||||
bool foundRestrict =
|
||||
_.HasDecoration(inst->id(), SpvDecorationRestrictPointerEXT);
|
||||
if (!foundAliased && !foundRestrict) {
|
||||
return _.diag(SPV_ERROR_INVALID_ID, inst)
|
||||
<< "OpVariable " << inst->id()
|
||||
<< ": expected AliasedPointerEXT or RestrictPointerEXT for "
|
||||
"PhysicalStorageBufferEXT pointer.";
|
||||
}
|
||||
if (foundAliased && foundRestrict) {
|
||||
return _.diag(SPV_ERROR_INVALID_ID, inst)
|
||||
<< "OpVariable " << inst->id()
|
||||
<< ": can't specify both AliasedPointerEXT and "
|
||||
"RestrictPointerEXT for PhysicalStorageBufferEXT pointer.";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Vulkan specific validation rules for OpTypeRuntimeArray
|
||||
if (spvIsVulkanEnv(_.context()->target_env)) {
|
||||
const auto type_index = 2;
|
||||
const auto value_id = result_type->GetOperandAs<uint32_t>(type_index);
|
||||
auto value_type = _.FindDef(value_id);
|
||||
// OpTypeRuntimeArray should only ever be in a container like OpTypeStruct,
|
||||
// so should never appear as a bare variable.
|
||||
// Unless the module has the RuntimeDescriptorArrayEXT capability.
|
||||
if (value_type && value_type->opcode() == SpvOpTypeRuntimeArray) {
|
||||
if (!_.HasCapability(SpvCapabilityRuntimeDescriptorArrayEXT)) {
|
||||
return _.diag(SPV_ERROR_INVALID_ID, inst)
|
||||
<< "OpVariable, <id> '" << _.getIdName(inst->id())
|
||||
<< "', is attempting to create memory for an illegal type, "
|
||||
"OpTypeRuntimeArray.\nFor Vulkan OpTypeRuntimeArray can only "
|
||||
"appear as the final member of an OpTypeStruct, thus cannot "
|
||||
"be instantiated via OpVariable";
|
||||
} else {
|
||||
// A bare variable OpTypeRuntimeArray is allowed in this context, but
|
||||
// still need to check the storage class.
|
||||
if (storage_class != SpvStorageClassStorageBuffer &&
|
||||
storage_class != SpvStorageClassUniform &&
|
||||
storage_class != SpvStorageClassUniformConstant) {
|
||||
return _.diag(SPV_ERROR_INVALID_ID, inst)
|
||||
<< "For Vulkan with RuntimeDescriptorArrayEXT, a variable "
|
||||
"containing OpTypeRuntimeArray must have storage class of "
|
||||
"StorageBuffer, Uniform, or UniformConstant.";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If an OpStruct has an OpTypeRuntimeArray somewhere within it, then it
|
||||
// must either have the storage class StorageBuffer and be decorated
|
||||
// with Block, or it must be in the Uniform storage class and be decorated
|
||||
// as BufferBlock.
|
||||
if (value_type && value_type->opcode() == SpvOpTypeStruct) {
|
||||
bool contains_RTA = false;
|
||||
for (size_t member_type_index = 1;
|
||||
member_type_index < value_type->operands().size();
|
||||
++member_type_index) {
|
||||
const auto member_type_id =
|
||||
value_type->GetOperandAs<uint32_t>(member_type_index);
|
||||
const auto member_type = _.FindDef(member_type_id);
|
||||
if (member_type->opcode() == SpvOpTypeRuntimeArray) {
|
||||
contains_RTA = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (contains_RTA) {
|
||||
if (storage_class == SpvStorageClassStorageBuffer) {
|
||||
if (!_.HasDecoration(value_id, SpvDecorationBlock)) {
|
||||
return _.diag(SPV_ERROR_INVALID_ID, inst)
|
||||
<< "For Vulkan, an OpTypeStruct variable containing an "
|
||||
"OpTypeRuntimeArray must be decorated with Block if it "
|
||||
"has storage class StorageBuffer.";
|
||||
}
|
||||
} else if (storage_class == SpvStorageClassUniform) {
|
||||
if (!_.HasDecoration(value_id, SpvDecorationBufferBlock)) {
|
||||
return _.diag(SPV_ERROR_INVALID_ID, inst)
|
||||
<< "For Vulkan, an OpTypeStruct variable containing an "
|
||||
"OpTypeRuntimeArray must be decorated with BufferBlock "
|
||||
"if it has storage class Uniform.";
|
||||
}
|
||||
} else {
|
||||
return _.diag(SPV_ERROR_INVALID_ID, inst)
|
||||
<< "For Vulkan, OpTypeStruct variables containing "
|
||||
"OpTypeRuntimeArray must have storage class of "
|
||||
"StorageBuffer or Uniform.";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return SPV_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -550,11 +691,7 @@ spv_result_t ValidateLoad(ValidationState_t& _, const Instruction* inst) {
|
||||
<< "'s type.";
|
||||
}
|
||||
|
||||
if (inst->operands().size() > 3) {
|
||||
if (auto error =
|
||||
CheckMemoryAccess(_, inst, inst->GetOperandAs<uint32_t>(3)))
|
||||
return error;
|
||||
}
|
||||
if (auto error = CheckMemoryAccess(_, inst, 3)) return error;
|
||||
|
||||
return SPV_SUCCESS;
|
||||
}
|
||||
@@ -642,11 +779,7 @@ spv_result_t ValidateStore(ValidationState_t& _, const Instruction* inst) {
|
||||
}
|
||||
}
|
||||
|
||||
if (inst->operands().size() > 2) {
|
||||
if (auto error =
|
||||
CheckMemoryAccess(_, inst, inst->GetOperandAs<uint32_t>(2)))
|
||||
return error;
|
||||
}
|
||||
if (auto error = CheckMemoryAccess(_, inst, 2)) return error;
|
||||
|
||||
return SPV_SUCCESS;
|
||||
}
|
||||
@@ -710,11 +843,7 @@ spv_result_t ValidateCopyMemory(ValidationState_t& _, const Instruction* inst) {
|
||||
<< _.getIdName(source_type->id()) << "'s type.";
|
||||
}
|
||||
|
||||
if (inst->operands().size() > 2) {
|
||||
if (auto error =
|
||||
CheckMemoryAccess(_, inst, inst->GetOperandAs<uint32_t>(2)))
|
||||
return error;
|
||||
}
|
||||
if (auto error = CheckMemoryAccess(_, inst, 2)) return error;
|
||||
} else {
|
||||
const auto size_id = inst->GetOperandAs<uint32_t>(2);
|
||||
const auto size = _.FindDef(size_id);
|
||||
@@ -758,11 +887,7 @@ spv_result_t ValidateCopyMemory(ValidationState_t& _, const Instruction* inst) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (inst->operands().size() > 3) {
|
||||
if (auto error =
|
||||
CheckMemoryAccess(_, inst, inst->GetOperandAs<uint32_t>(3)))
|
||||
return error;
|
||||
}
|
||||
if (auto error = CheckMemoryAccess(_, inst, 3)) return error;
|
||||
}
|
||||
return SPV_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include "source/val/validate.h"
|
||||
|
||||
#include "source/opcode.h"
|
||||
#include "source/spirv_target_env.h"
|
||||
#include "source/val/instruction.h"
|
||||
#include "source/val/validation_state.h"
|
||||
|
||||
@@ -106,6 +107,13 @@ spv_result_t ValidateTypeArray(ValidationState_t& _, const Instruction* inst) {
|
||||
<< "' is a void type.";
|
||||
}
|
||||
|
||||
if (spvIsVulkanEnv(_.context()->target_env) &&
|
||||
element_type->opcode() == SpvOpTypeRuntimeArray) {
|
||||
return _.diag(SPV_ERROR_INVALID_ID, inst)
|
||||
<< "OpTypeArray Element Type <id> '" << _.getIdName(element_type_id)
|
||||
<< "' is not valid in Vulkan environment.";
|
||||
}
|
||||
|
||||
const auto length_index = 2;
|
||||
const auto length_id = inst->GetOperandAs<uint32_t>(length_index);
|
||||
const auto length = _.FindDef(length_id);
|
||||
@@ -161,6 +169,14 @@ spv_result_t ValidateTypeRuntimeArray(ValidationState_t& _,
|
||||
<< _.getIdName(element_id) << "' is a void type.";
|
||||
}
|
||||
|
||||
if (spvIsVulkanEnv(_.context()->target_env) &&
|
||||
element_type->opcode() == SpvOpTypeRuntimeArray) {
|
||||
return _.diag(SPV_ERROR_INVALID_ID, inst)
|
||||
<< "OpTypeRuntimeArray Element Type <id> '"
|
||||
<< _.getIdName(element_id)
|
||||
<< "' is not valid in Vulkan environment.";
|
||||
}
|
||||
|
||||
return SPV_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -206,7 +222,19 @@ spv_result_t ValidateTypeStruct(ValidationState_t& _, const Instruction* inst) {
|
||||
<< ".";
|
||||
}
|
||||
}
|
||||
|
||||
if (spvIsVulkanEnv(_.context()->target_env) &&
|
||||
member_type->opcode() == SpvOpTypeRuntimeArray) {
|
||||
const bool is_last_member =
|
||||
member_type_index == inst->operands().size() - 1;
|
||||
if (!is_last_member) {
|
||||
return _.diag(SPV_ERROR_INVALID_ID, inst)
|
||||
<< "In Vulkan, OpTypeRuntimeArray must only be used for the "
|
||||
"last member of an OpTypeStruct";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::unordered_set<uint32_t> built_in_members;
|
||||
for (auto decoration : _.id_decorations(struct_id)) {
|
||||
if (decoration.dec_type() == SpvDecorationBuiltIn &&
|
||||
|
||||
@@ -171,6 +171,7 @@ ValidationState_t::ValidationState_t(const spv_const_context ctx,
|
||||
grammar_(ctx),
|
||||
addressing_model_(SpvAddressingModelMax),
|
||||
memory_model_(SpvMemoryModelMax),
|
||||
pointer_size_and_alignment_(0),
|
||||
in_function_(false),
|
||||
num_of_warnings_(0),
|
||||
max_num_of_warnings_(max_warnings) {
|
||||
@@ -411,6 +412,11 @@ void ValidationState_t::RegisterExtension(Extension ext) {
|
||||
// https://github.com/KhronosGroup/SPIRV-Tools/issues/1375
|
||||
features_.declare_float16_type = true;
|
||||
break;
|
||||
case kSPV_AMD_gpu_shader_int16:
|
||||
// This is not yet in the extension, but it's recommended for it.
|
||||
// See https://github.com/KhronosGroup/glslang/issues/848
|
||||
features_.uconvert_spec_constant_op = true;
|
||||
break;
|
||||
case kSPV_AMD_shader_ballot:
|
||||
// The grammar doesn't encode the fact that SPV_AMD_shader_ballot
|
||||
// enables the use of group operations Reduce, InclusiveScan,
|
||||
@@ -435,6 +441,17 @@ bool ValidationState_t::HasAnyOfExtensions(
|
||||
|
||||
void ValidationState_t::set_addressing_model(SpvAddressingModel am) {
|
||||
addressing_model_ = am;
|
||||
switch (am) {
|
||||
case SpvAddressingModelPhysical32:
|
||||
pointer_size_and_alignment_ = 4;
|
||||
break;
|
||||
default:
|
||||
// fall through
|
||||
case SpvAddressingModelPhysical64:
|
||||
case SpvAddressingModelPhysicalStorageBuffer64EXT:
|
||||
pointer_size_and_alignment_ = 8;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
SpvAddressingModel ValidationState_t::addressing_model() const {
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#ifndef SOURCE_VAL_VALIDATION_STATE_H_
|
||||
#define SOURCE_VAL_VALIDATION_STATE_H_
|
||||
|
||||
#include <algorithm>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <string>
|
||||
@@ -104,6 +105,10 @@ class ValidationState_t {
|
||||
// - ArrayStride and MatrixStride are multiples of scalar alignment
|
||||
// Members need not be listed in offset order
|
||||
bool scalar_block_layout = false;
|
||||
|
||||
// Permit UConvert as an OpSpecConstantOp operation.
|
||||
// The Kernel capability already enables it, separately from this flag.
|
||||
bool uconvert_spec_constant_op = false;
|
||||
};
|
||||
|
||||
ValidationState_t(const spv_const_context context,
|
||||
@@ -339,6 +344,11 @@ class ValidationState_t {
|
||||
/// Returns the addressing model of this module, or Logical if uninitialized.
|
||||
SpvAddressingModel addressing_model() const;
|
||||
|
||||
/// Returns the addressing model of this module, or Logical if uninitialized.
|
||||
uint32_t pointer_size_and_alignment() const {
|
||||
return pointer_size_and_alignment_;
|
||||
}
|
||||
|
||||
/// Sets the memory model of this module.
|
||||
void set_memory_model(SpvMemoryModel mm);
|
||||
|
||||
@@ -387,17 +397,23 @@ class ValidationState_t {
|
||||
std::vector<Decoration>& id_decorations(uint32_t id) {
|
||||
return id_decorations_[id];
|
||||
}
|
||||
const std::vector<Decoration>& id_decorations(uint32_t id) const {
|
||||
// TODO: This would throw or generate SIGABRT if id has no
|
||||
// decorations. Remove/refactor this function.
|
||||
return id_decorations_.at(id);
|
||||
}
|
||||
|
||||
// Returns const pointer to the internal decoration container.
|
||||
const std::map<uint32_t, std::vector<Decoration>>& id_decorations() const {
|
||||
return id_decorations_;
|
||||
}
|
||||
|
||||
/// Returns true if the given id <id> has the given decoration <dec>,
|
||||
/// otherwise returns false.
|
||||
bool HasDecoration(uint32_t id, SpvDecoration dec) {
|
||||
const auto& decorations = id_decorations_.find(id);
|
||||
if (decorations == id_decorations_.end()) return false;
|
||||
|
||||
return std::any_of(
|
||||
decorations->second.begin(), decorations->second.end(),
|
||||
[dec](const Decoration& d) { return dec == d.dec_type(); });
|
||||
}
|
||||
|
||||
/// Finds id's def, if it exists. If found, returns the definition otherwise
|
||||
/// nullptr
|
||||
const Instruction* FindDef(uint32_t id) const;
|
||||
@@ -656,6 +672,9 @@ class ValidationState_t {
|
||||
|
||||
SpvAddressingModel addressing_model_;
|
||||
SpvMemoryModel memory_model_;
|
||||
// pointer size derived from addressing model. Assumes all storage classes
|
||||
// have the same pointer size (for physical pointer types).
|
||||
uint32_t pointer_size_and_alignment_;
|
||||
|
||||
/// NOTE: See correspoding getter functions
|
||||
bool in_function_;
|
||||
|
||||
@@ -197,6 +197,8 @@ ParsedInstruction MakeParsedInt32TypeInstruction(uint32_t result_id) {
|
||||
|
||||
class BinaryParseTest : public spvtest::TextToBinaryTestBase<::testing::Test> {
|
||||
protected:
|
||||
~BinaryParseTest() { spvDiagnosticDestroy(diagnostic_); }
|
||||
|
||||
void Parse(const SpirvVector& words, spv_result_t expected_result,
|
||||
bool flip_words = false) {
|
||||
SpirvVector flipped_words(words);
|
||||
|
||||
@@ -34,8 +34,12 @@ using ::testing::HasSubstr;
|
||||
|
||||
class BinaryToText : public ::testing::Test {
|
||||
public:
|
||||
BinaryToText() : context(spvContextCreate(SPV_ENV_UNIVERSAL_1_0)) {}
|
||||
~BinaryToText() { spvContextDestroy(context); }
|
||||
BinaryToText()
|
||||
: context(spvContextCreate(SPV_ENV_UNIVERSAL_1_0)), binary(nullptr) {}
|
||||
~BinaryToText() {
|
||||
spvBinaryDestroy(binary);
|
||||
spvContextDestroy(context);
|
||||
}
|
||||
|
||||
virtual void SetUp() {
|
||||
const char* textStr = R"(
|
||||
@@ -63,17 +67,20 @@ class BinaryToText : public ::testing::Test {
|
||||
spv_diagnostic diagnostic = nullptr;
|
||||
spv_result_t error =
|
||||
spvTextToBinary(context, text.str, text.length, &binary, &diagnostic);
|
||||
if (error) {
|
||||
spvDiagnosticPrint(diagnostic);
|
||||
spvDiagnosticDestroy(diagnostic);
|
||||
ASSERT_EQ(SPV_SUCCESS, error);
|
||||
}
|
||||
spvDiagnosticPrint(diagnostic);
|
||||
spvDiagnosticDestroy(diagnostic);
|
||||
ASSERT_EQ(SPV_SUCCESS, error);
|
||||
}
|
||||
|
||||
virtual void TearDown() { spvBinaryDestroy(binary); }
|
||||
virtual void TearDown() {
|
||||
spvBinaryDestroy(binary);
|
||||
binary = nullptr;
|
||||
}
|
||||
|
||||
// Compiles the given assembly text, and saves it into 'binary'.
|
||||
void CompileSuccessfully(std::string text) {
|
||||
spvBinaryDestroy(binary);
|
||||
binary = nullptr;
|
||||
spv_diagnostic diagnostic = nullptr;
|
||||
EXPECT_EQ(SPV_SUCCESS, spvTextToBinary(context, text.c_str(), text.size(),
|
||||
&binary, &diagnostic));
|
||||
|
||||
@@ -61,7 +61,7 @@ OpFunctionEnd
|
||||
; Generator: Khronos SPIR-V Tools Assembler; 0
|
||||
; Bound: 9
|
||||
; Schema: 0)";
|
||||
spv_binary binary;
|
||||
spv_binary binary = nullptr;
|
||||
spv_diagnostic diagnostic;
|
||||
spv_result_t error = spvTextToBinary(context, spirv.c_str(), spirv.size(),
|
||||
&binary, &diagnostic);
|
||||
@@ -102,6 +102,7 @@ OpFunctionEnd
|
||||
}
|
||||
EXPECT_EQ(spirv_header + spirv, output_text->str);
|
||||
spvTextDestroy(output_text);
|
||||
spvBinaryDestroy(binary);
|
||||
spvContextDestroy(context);
|
||||
}
|
||||
|
||||
|
||||
7
3rdparty/spirv-tools/test/opt/CMakeLists.txt
vendored
7
3rdparty/spirv-tools/test/opt/CMakeLists.txt
vendored
@@ -81,6 +81,7 @@ add_spvtools_unittest(TARGET opt
|
||||
type_manager_test.cpp
|
||||
types_test.cpp
|
||||
unify_const_test.cpp
|
||||
upgrade_memory_model_test.cpp
|
||||
utils_test.cpp pass_utils.cpp
|
||||
value_table_test.cpp
|
||||
vector_dce_test.cpp
|
||||
@@ -88,9 +89,3 @@ add_spvtools_unittest(TARGET opt
|
||||
LIBS SPIRV-Tools-opt
|
||||
PCH_FILE pch_test_opt
|
||||
)
|
||||
|
||||
add_spvtools_unittest(TARGET upgrade_memory_model
|
||||
SRCS upgrade_memory_model_test.cpp pass_utils.cpp
|
||||
LIBS SPIRV-Tools-opt
|
||||
PCH_FILE pch_test_opt
|
||||
)
|
||||
|
||||
37
3rdparty/spirv-tools/test/opt/fold_test.cpp
vendored
37
3rdparty/spirv-tools/test/opt/fold_test.cpp
vendored
@@ -168,6 +168,7 @@ OpName %main "main"
|
||||
%int_2 = OpConstant %int 2
|
||||
%int_3 = OpConstant %int 3
|
||||
%int_4 = OpConstant %int 4
|
||||
%int_n24 = OpConstant %int -24
|
||||
%int_min = OpConstant %int -2147483648
|
||||
%int_max = OpConstant %int 2147483647
|
||||
%long_0 = OpConstant %long 0
|
||||
@@ -486,7 +487,7 @@ INSTANTIATE_TEST_CASE_P(TestCase, IntegerInstructionFoldingTest,
|
||||
"OpReturn\n" +
|
||||
"OpFunctionEnd",
|
||||
2, 0),
|
||||
// Test case 21: fold signed n >> 42 (undefined, so set to zero).
|
||||
// Test case 23: fold signed n >> 42 (undefined, so set to zero).
|
||||
InstructionFoldingCase<uint32_t>(
|
||||
Header() + "%main = OpFunction %void None %void_func\n" +
|
||||
"%main_lab = OpLabel\n" +
|
||||
@@ -496,7 +497,7 @@ INSTANTIATE_TEST_CASE_P(TestCase, IntegerInstructionFoldingTest,
|
||||
"OpReturn\n" +
|
||||
"OpFunctionEnd",
|
||||
2, 0),
|
||||
// Test case 22: fold n << 42 (undefined, so set to zero).
|
||||
// Test case 24: fold n << 42 (undefined, so set to zero).
|
||||
InstructionFoldingCase<uint32_t>(
|
||||
Header() + "%main = OpFunction %void None %void_func\n" +
|
||||
"%main_lab = OpLabel\n" +
|
||||
@@ -505,6 +506,38 @@ INSTANTIATE_TEST_CASE_P(TestCase, IntegerInstructionFoldingTest,
|
||||
"%2 = OpShiftLeftLogical %int %load %uint_42\n" +
|
||||
"OpReturn\n" +
|
||||
"OpFunctionEnd",
|
||||
2, 0),
|
||||
// Test case 25: fold -24 >> 32 (defined as -1)
|
||||
InstructionFoldingCase<uint32_t>(
|
||||
Header() + "%main = OpFunction %void None %void_func\n" +
|
||||
"%main_lab = OpLabel\n" +
|
||||
"%2 = OpShiftRightArithmetic %int %int_n24 %uint_32\n" +
|
||||
"OpReturn\n" +
|
||||
"OpFunctionEnd",
|
||||
2, -1),
|
||||
// Test case 26: fold 2 >> 32 (signed)
|
||||
InstructionFoldingCase<uint32_t>(
|
||||
Header() + "%main = OpFunction %void None %void_func\n" +
|
||||
"%main_lab = OpLabel\n" +
|
||||
"%2 = OpShiftRightArithmetic %int %int_2 %uint_32\n" +
|
||||
"OpReturn\n" +
|
||||
"OpFunctionEnd",
|
||||
2, 0),
|
||||
// Test case 27: fold 2 >> 32 (unsigned)
|
||||
InstructionFoldingCase<uint32_t>(
|
||||
Header() + "%main = OpFunction %void None %void_func\n" +
|
||||
"%main_lab = OpLabel\n" +
|
||||
"%2 = OpShiftRightLogical %int %int_2 %uint_32\n" +
|
||||
"OpReturn\n" +
|
||||
"OpFunctionEnd",
|
||||
2, 0),
|
||||
// Test case 28: fold 2 << 32
|
||||
InstructionFoldingCase<uint32_t>(
|
||||
Header() + "%main = OpFunction %void None %void_func\n" +
|
||||
"%main_lab = OpLabel\n" +
|
||||
"%2 = OpShiftLeftLogical %int %int_2 %uint_32\n" +
|
||||
"OpReturn\n" +
|
||||
"OpFunctionEnd",
|
||||
2, 0)
|
||||
));
|
||||
// clang-format on
|
||||
|
||||
@@ -92,7 +92,8 @@ OpDecorate %_entryPointOutput_vColor Location 0
|
||||
)";
|
||||
|
||||
const std::string new_annots =
|
||||
R"(OpDecorate %_struct_55 Block
|
||||
R"(OpDecorate %_runtimearr_uint ArrayStride 4
|
||||
OpDecorate %_struct_55 Block
|
||||
OpMemberDecorate %_struct_55 0 Offset 0
|
||||
OpMemberDecorate %_struct_55 1 Offset 4
|
||||
OpDecorate %57 DescriptorSet 7
|
||||
@@ -441,6 +442,7 @@ OpDecorate %PerViewConstantBuffer_t Block
|
||||
OpDecorate %g_sAniso DescriptorSet 0
|
||||
OpDecorate %i_vTextureCoords Location 0
|
||||
OpDecorate %_entryPointOutput_vColor Location 0
|
||||
OpDecorate %_runtimearr_uint ArrayStride 4
|
||||
OpDecorate %_struct_63 Block
|
||||
OpMemberDecorate %_struct_63 0 Offset 0
|
||||
OpMemberDecorate %_struct_63 1 Offset 4
|
||||
@@ -735,6 +737,7 @@ OpDecorate %_entryPointOutput_vColor Location 0
|
||||
OpDecorate %10 DescriptorSet 7
|
||||
OpDecorate %10 Binding 0
|
||||
OpDecorate %gl_FragCoord BuiltIn FragCoord
|
||||
OpDecorate %_runtimearr_uint ArrayStride 4
|
||||
OpDecorate %_struct_34 Block
|
||||
OpMemberDecorate %_struct_34 0 Offset 0
|
||||
OpMemberDecorate %_struct_34 1 Offset 4
|
||||
@@ -968,6 +971,7 @@ OpMemberDecorate %PerViewConstantBuffer_t 0 Offset 0
|
||||
OpDecorate %PerViewConstantBuffer_t Block
|
||||
OpDecorate %i_vTextureCoords Location 0
|
||||
OpDecorate %_entryPointOutput_vColor Location 0
|
||||
OpDecorate %_runtimearr_uint ArrayStride 4
|
||||
OpDecorate %_struct_51 Block
|
||||
OpMemberDecorate %_struct_51 0 Offset 0
|
||||
OpMemberDecorate %_struct_51 1 Offset 4
|
||||
@@ -1193,6 +1197,7 @@ OpMemberDecorate %PerViewConstantBuffer_t 0 Offset 0
|
||||
OpDecorate %PerViewConstantBuffer_t Block
|
||||
OpDecorate %i_vTextureCoords Location 0
|
||||
OpDecorate %_entryPointOutput_vColor Location 0
|
||||
OpDecorate %_runtimearr_uint ArrayStride 4
|
||||
OpDecorate %_struct_49 Block
|
||||
OpMemberDecorate %_struct_49 0 Offset 0
|
||||
OpMemberDecorate %_struct_49 1 Offset 4
|
||||
@@ -1418,6 +1423,7 @@ OpMemberDecorate %PerViewConstantBuffer_t 0 Offset 0
|
||||
OpDecorate %PerViewConstantBuffer_t Block
|
||||
OpDecorate %i_vTextureCoords Location 0
|
||||
OpDecorate %_entryPointOutput_vColor Location 0
|
||||
OpDecorate %_runtimearr_uint ArrayStride 4
|
||||
OpDecorate %_struct_48 Block
|
||||
OpMemberDecorate %_struct_48 0 Offset 0
|
||||
OpMemberDecorate %_struct_48 1 Offset 4
|
||||
@@ -1644,7 +1650,7 @@ OpCapability Sampled1D
|
||||
OpExtension "SPV_KHR_storage_buffer_storage_class"
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Vertex %main "main" %_ %coords2D %gl_VertexID %gl_InstanceID
|
||||
OpEntryPoint Vertex %main "main" %_ %coords2D %gl_VertexIndex %gl_InstanceIndex
|
||||
OpSource GLSL 450
|
||||
OpName %main "main"
|
||||
OpName %lod "lod"
|
||||
@@ -1672,13 +1678,14 @@ OpDecorate %foo Block
|
||||
OpDecorate %__0 DescriptorSet 0
|
||||
OpDecorate %__0 Binding 5
|
||||
OpDecorate %coords2D Location 0
|
||||
OpDecorate %_runtimearr_uint ArrayStride 4
|
||||
OpDecorate %_struct_61 Block
|
||||
OpMemberDecorate %_struct_61 0 Offset 0
|
||||
OpMemberDecorate %_struct_61 1 Offset 4
|
||||
OpDecorate %63 DescriptorSet 7
|
||||
OpDecorate %63 Binding 0
|
||||
OpDecorate %gl_VertexID BuiltIn VertexId
|
||||
OpDecorate %gl_InstanceID BuiltIn InstanceId
|
||||
OpDecorate %gl_VertexIndex BuiltIn VertexIndex
|
||||
OpDecorate %gl_InstanceIndex BuiltIn InstanceIndex
|
||||
%void = OpTypeVoid
|
||||
%12 = OpTypeFunction %void
|
||||
%float = OpTypeFloat 32
|
||||
@@ -1723,8 +1730,8 @@ OpDecorate %gl_InstanceID BuiltIn InstanceId
|
||||
%uint_2 = OpConstant %uint 2
|
||||
%uint_3 = OpConstant %uint 3
|
||||
%_ptr_Input_uint = OpTypePointer Input %uint
|
||||
%gl_VertexID = OpVariable %_ptr_Input_uint Input
|
||||
%gl_InstanceID = OpVariable %_ptr_Input_uint Input
|
||||
%gl_VertexIndex = OpVariable %_ptr_Input_uint Input
|
||||
%gl_InstanceIndex = OpVariable %_ptr_Input_uint Input
|
||||
%uint_5 = OpConstant %uint 5
|
||||
%uint_6 = OpConstant %uint 6
|
||||
%uint_7 = OpConstant %uint 7
|
||||
@@ -1812,11 +1819,11 @@ OpStore %81 %55
|
||||
%83 = OpIAdd %uint %68 %uint_3
|
||||
%84 = OpAccessChain %_ptr_StorageBuffer_uint %63 %uint_1 %83
|
||||
OpStore %84 %uint_0
|
||||
%87 = OpLoad %uint %gl_VertexID
|
||||
%87 = OpLoad %uint %gl_VertexIndex
|
||||
%88 = OpIAdd %uint %68 %uint_4
|
||||
%89 = OpAccessChain %_ptr_StorageBuffer_uint %63 %uint_1 %88
|
||||
OpStore %89 %87
|
||||
%91 = OpLoad %uint %gl_InstanceID
|
||||
%91 = OpLoad %uint %gl_InstanceIndex
|
||||
%93 = OpIAdd %uint %68 %uint_5
|
||||
%94 = OpAccessChain %_ptr_StorageBuffer_uint %63 %uint_1 %93
|
||||
OpStore %94 %91
|
||||
|
||||
10
3rdparty/spirv-tools/test/opt/pass_fixture.h
vendored
10
3rdparty/spirv-tools/test/opt/pass_fixture.h
vendored
@@ -49,7 +49,7 @@ class PassTest : public TestT {
|
||||
[](spv_message_level_t, const char*, const spv_position_t&,
|
||||
const char* message) { std::cerr << message << std::endl; }),
|
||||
context_(nullptr),
|
||||
tools_(SPV_ENV_UNIVERSAL_1_1),
|
||||
tools_(SPV_ENV_UNIVERSAL_1_3),
|
||||
manager_(new PassManager()),
|
||||
assemble_options_(SpirvTools::kDefaultAssembleOption),
|
||||
disassemble_options_(SpirvTools::kDefaultDisassembleOption) {}
|
||||
@@ -59,7 +59,7 @@ class PassTest : public TestT {
|
||||
// from pass Process() function.
|
||||
std::tuple<std::vector<uint32_t>, Pass::Status> OptimizeToBinary(
|
||||
Pass* pass, const std::string& original, bool skip_nop) {
|
||||
context_ = std::move(BuildModule(SPV_ENV_UNIVERSAL_1_1, consumer_, original,
|
||||
context_ = std::move(BuildModule(SPV_ENV_UNIVERSAL_1_3, consumer_, original,
|
||||
assemble_options_));
|
||||
EXPECT_NE(nullptr, context()) << "Assembling failed for shader:\n"
|
||||
<< original << std::endl;
|
||||
@@ -97,7 +97,7 @@ class PassTest : public TestT {
|
||||
std::tie(optimized_bin, status) = SinglePassRunToBinary<PassT>(
|
||||
assembly, skip_nop, std::forward<Args>(args)...);
|
||||
if (do_validation) {
|
||||
spv_target_env target_env = SPV_ENV_UNIVERSAL_1_1;
|
||||
spv_target_env target_env = SPV_ENV_UNIVERSAL_1_3;
|
||||
spv_context spvContext = spvContextCreate(target_env);
|
||||
spv_diagnostic diagnostic = nullptr;
|
||||
spv_const_binary_t binary = {optimized_bin.data(), optimized_bin.size()};
|
||||
@@ -134,7 +134,7 @@ class PassTest : public TestT {
|
||||
EXPECT_EQ(original == expected,
|
||||
status == Pass::Status::SuccessWithoutChange);
|
||||
if (do_validation) {
|
||||
spv_target_env target_env = SPV_ENV_UNIVERSAL_1_1;
|
||||
spv_target_env target_env = SPV_ENV_UNIVERSAL_1_3;
|
||||
spv_context spvContext = spvContextCreate(target_env);
|
||||
spv_diagnostic diagnostic = nullptr;
|
||||
spv_const_binary_t binary = {optimized_bin.data(), optimized_bin.size()};
|
||||
@@ -202,7 +202,7 @@ class PassTest : public TestT {
|
||||
void RunAndCheck(const std::string& original, const std::string& expected) {
|
||||
assert(manager_->NumPasses());
|
||||
|
||||
context_ = std::move(BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, original,
|
||||
context_ = std::move(BuildModule(SPV_ENV_UNIVERSAL_1_3, nullptr, original,
|
||||
assemble_options_));
|
||||
ASSERT_NE(nullptr, context());
|
||||
|
||||
|
||||
@@ -23,7 +23,6 @@ using namespace spvtools;
|
||||
|
||||
using UpgradeMemoryModelTest = opt::PassTest<::testing::Test>;
|
||||
|
||||
#ifdef SPIRV_EFFCEE
|
||||
TEST_F(UpgradeMemoryModelTest, InvalidMemoryModelOpenCL) {
|
||||
const std::string text = R"(
|
||||
; CHECK: OpMemoryModel Logical OpenCL
|
||||
@@ -80,8 +79,8 @@ OpDecorate %var Coherent
|
||||
TEST_F(UpgradeMemoryModelTest, WorkgroupVariable) {
|
||||
const std::string text = R"(
|
||||
; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 2
|
||||
; CHECK: OpLoad {{%\w+}} {{%\w+}} MakePointerAvailableKHR|NonPrivatePointerKHR [[scope]]
|
||||
; CHECK: OpStore {{%\w+}} {{%\w+}} MakePointerVisibleKHR|NonPrivatePointerKHR [[scope]]
|
||||
; CHECK: OpLoad {{%\w+}} {{%\w+}} MakePointerVisibleKHR|NonPrivatePointerKHR [[scope]]
|
||||
; CHECK: OpStore {{%\w+}} {{%\w+}} MakePointerAvailableKHR|NonPrivatePointerKHR [[scope]]
|
||||
OpCapability Shader
|
||||
OpCapability Linkage
|
||||
OpMemoryModel Logical GLSL450
|
||||
@@ -104,8 +103,8 @@ OpFunctionEnd
|
||||
TEST_F(UpgradeMemoryModelTest, WorkgroupFunctionParameter) {
|
||||
const std::string text = R"(
|
||||
; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 2
|
||||
; CHECK: OpLoad {{%\w+}} {{%\w+}} MakePointerAvailableKHR|NonPrivatePointerKHR [[scope]]
|
||||
; CHECK: OpStore {{%\w+}} {{%\w+}} MakePointerVisibleKHR|NonPrivatePointerKHR [[scope]]
|
||||
; CHECK: OpLoad {{%\w+}} {{%\w+}} MakePointerVisibleKHR|NonPrivatePointerKHR [[scope]]
|
||||
; CHECK: OpStore {{%\w+}} {{%\w+}} MakePointerAvailableKHR|NonPrivatePointerKHR [[scope]]
|
||||
OpCapability Shader
|
||||
OpCapability Linkage
|
||||
OpMemoryModel Logical GLSL450
|
||||
@@ -129,8 +128,8 @@ TEST_F(UpgradeMemoryModelTest, SimpleUniformVariable) {
|
||||
const std::string text = R"(
|
||||
; CHECK-NOT: OpDecorate
|
||||
; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5
|
||||
; CHECK: OpLoad {{%\w+}} {{%\w+}} Volatile|MakePointerAvailableKHR|NonPrivatePointerKHR [[scope]]
|
||||
; CHECK: OpStore {{%\w+}} {{%\w+}} Volatile|MakePointerVisibleKHR|NonPrivatePointerKHR [[scope]]
|
||||
; CHECK: OpLoad {{%\w+}} {{%\w+}} Volatile|MakePointerVisibleKHR|NonPrivatePointerKHR [[scope]]
|
||||
; CHECK: OpStore {{%\w+}} {{%\w+}} Volatile|MakePointerAvailableKHR|NonPrivatePointerKHR [[scope]]
|
||||
OpCapability Shader
|
||||
OpCapability Linkage
|
||||
OpMemoryModel Logical GLSL450
|
||||
@@ -156,8 +155,8 @@ TEST_F(UpgradeMemoryModelTest, SimpleUniformFunctionParameter) {
|
||||
const std::string text = R"(
|
||||
; CHECK-NOT: OpDecorate
|
||||
; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5
|
||||
; CHECK: OpLoad {{%\w+}} {{%\w+}} Volatile|MakePointerAvailableKHR|NonPrivatePointerKHR [[scope]]
|
||||
; CHECK: OpStore {{%\w+}} {{%\w+}} Volatile|MakePointerVisibleKHR|NonPrivatePointerKHR [[scope]]
|
||||
; CHECK: OpLoad {{%\w+}} {{%\w+}} Volatile|MakePointerVisibleKHR|NonPrivatePointerKHR [[scope]]
|
||||
; CHECK: OpStore {{%\w+}} {{%\w+}} Volatile|MakePointerAvailableKHR|NonPrivatePointerKHR [[scope]]
|
||||
OpCapability Shader
|
||||
OpCapability Linkage
|
||||
OpMemoryModel Logical GLSL450
|
||||
@@ -209,8 +208,8 @@ TEST_F(UpgradeMemoryModelTest, SimpleUniformVariableCopied) {
|
||||
const std::string text = R"(
|
||||
; CHECK-NOT: OpDecorate
|
||||
; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5
|
||||
; CHECK: OpLoad {{%\w+}} {{%\w+}} Volatile|MakePointerAvailableKHR|NonPrivatePointerKHR [[scope]]
|
||||
; CHECK: OpStore {{%\w+}} {{%\w+}} Volatile|MakePointerVisibleKHR|NonPrivatePointerKHR [[scope]]
|
||||
; CHECK: OpLoad {{%\w+}} {{%\w+}} Volatile|MakePointerVisibleKHR|NonPrivatePointerKHR [[scope]]
|
||||
; CHECK: OpStore {{%\w+}} {{%\w+}} Volatile|MakePointerAvailableKHR|NonPrivatePointerKHR [[scope]]
|
||||
OpCapability Shader
|
||||
OpCapability Linkage
|
||||
OpMemoryModel Logical GLSL450
|
||||
@@ -237,8 +236,8 @@ TEST_F(UpgradeMemoryModelTest, SimpleUniformFunctionParameterCopied) {
|
||||
const std::string text = R"(
|
||||
; CHECK-NOT: OpDecorate
|
||||
; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5
|
||||
; CHECK: OpLoad {{%\w+}} {{%\w+}} Volatile|MakePointerAvailableKHR|NonPrivatePointerKHR [[scope]]
|
||||
; CHECK: OpStore {{%\w+}} {{%\w+}} Volatile|MakePointerVisibleKHR|NonPrivatePointerKHR [[scope]]
|
||||
; CHECK: OpLoad {{%\w+}} {{%\w+}} Volatile|MakePointerVisibleKHR|NonPrivatePointerKHR [[scope]]
|
||||
; CHECK: OpStore {{%\w+}} {{%\w+}} Volatile|MakePointerAvailableKHR|NonPrivatePointerKHR [[scope]]
|
||||
OpCapability Shader
|
||||
OpCapability Linkage
|
||||
OpMemoryModel Logical GLSL450
|
||||
@@ -266,8 +265,8 @@ TEST_F(UpgradeMemoryModelTest, SimpleUniformVariableAccessChain) {
|
||||
const std::string text = R"(
|
||||
; CHECK-NOT: OpDecorate
|
||||
; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5
|
||||
; CHECK: OpLoad {{%\w+}} {{%\w+}} Volatile|MakePointerAvailableKHR|NonPrivatePointerKHR [[scope]]
|
||||
; CHECK: OpStore {{%\w+}} {{%\w+}} Volatile|MakePointerVisibleKHR|NonPrivatePointerKHR [[scope]]
|
||||
; CHECK: OpLoad {{%\w+}} {{%\w+}} Volatile|MakePointerVisibleKHR|NonPrivatePointerKHR [[scope]]
|
||||
; CHECK: OpStore {{%\w+}} {{%\w+}} Volatile|MakePointerAvailableKHR|NonPrivatePointerKHR [[scope]]
|
||||
OpCapability Shader
|
||||
OpCapability Linkage
|
||||
OpMemoryModel Logical GLSL450
|
||||
@@ -298,8 +297,8 @@ TEST_F(UpgradeMemoryModelTest, SimpleUniformFunctionParameterAccessChain) {
|
||||
const std::string text = R"(
|
||||
; CHECK-NOT: OpDecorate
|
||||
; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5
|
||||
; CHECK: OpLoad {{%\w+}} {{%\w+}} Volatile|MakePointerAvailableKHR|NonPrivatePointerKHR [[scope]]
|
||||
; CHECK: OpStore {{%\w+}} {{%\w+}} Volatile|MakePointerVisibleKHR|NonPrivatePointerKHR [[scope]]
|
||||
; CHECK: OpLoad {{%\w+}} {{%\w+}} Volatile|MakePointerVisibleKHR|NonPrivatePointerKHR [[scope]]
|
||||
; CHECK: OpStore {{%\w+}} {{%\w+}} Volatile|MakePointerAvailableKHR|NonPrivatePointerKHR [[scope]]
|
||||
OpCapability Shader
|
||||
OpCapability Linkage
|
||||
OpMemoryModel Logical GLSL450
|
||||
@@ -331,8 +330,8 @@ TEST_F(UpgradeMemoryModelTest, VariablePointerSelect) {
|
||||
const std::string text = R"(
|
||||
; CHECK-NOT: OpDecorate
|
||||
; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5
|
||||
; CHECK: OpLoad {{%\w+}} {{%\w+}} Volatile|MakePointerAvailableKHR|NonPrivatePointerKHR [[scope]]
|
||||
; CHECK: OpStore {{%\w+}} {{%\w+}} Volatile|MakePointerVisibleKHR|NonPrivatePointerKHR [[scope]]
|
||||
; CHECK: OpLoad {{%\w+}} {{%\w+}} Volatile|MakePointerVisibleKHR|NonPrivatePointerKHR [[scope]]
|
||||
; CHECK: OpStore {{%\w+}} {{%\w+}} Volatile|MakePointerAvailableKHR|NonPrivatePointerKHR [[scope]]
|
||||
OpCapability Shader
|
||||
OpCapability Linkage
|
||||
OpCapability VariablePointers
|
||||
@@ -364,8 +363,8 @@ TEST_F(UpgradeMemoryModelTest, VariablePointerSelectConservative) {
|
||||
const std::string text = R"(
|
||||
; CHECK-NOT: OpDecorate
|
||||
; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5
|
||||
; CHECK: OpLoad {{%\w+}} {{%\w+}} Volatile|MakePointerAvailableKHR|NonPrivatePointerKHR [[scope]]
|
||||
; CHECK: OpStore {{%\w+}} {{%\w+}} Volatile|MakePointerVisibleKHR|NonPrivatePointerKHR [[scope]]
|
||||
; CHECK: OpLoad {{%\w+}} {{%\w+}} Volatile|MakePointerVisibleKHR|NonPrivatePointerKHR [[scope]]
|
||||
; CHECK: OpStore {{%\w+}} {{%\w+}} Volatile|MakePointerAvailableKHR|NonPrivatePointerKHR [[scope]]
|
||||
OpCapability Shader
|
||||
OpCapability Linkage
|
||||
OpCapability VariablePointers
|
||||
@@ -397,8 +396,8 @@ TEST_F(UpgradeMemoryModelTest, VariablePointerIncrement) {
|
||||
const std::string text = R"(
|
||||
; CHECK-NOT: OpDecorate {{%\w+}} Coherent
|
||||
; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5
|
||||
; CHECK: OpLoad {{%\w+}} {{%\w+}} MakePointerAvailableKHR|NonPrivatePointerKHR [[scope]]
|
||||
; CHECK: OpStore {{%\w+}} {{%\w+}} MakePointerVisibleKHR|NonPrivatePointerKHR [[scope]]
|
||||
; CHECK: OpLoad {{%\w+}} {{%\w+}} MakePointerVisibleKHR|NonPrivatePointerKHR [[scope]]
|
||||
; CHECK: OpStore {{%\w+}} {{%\w+}} MakePointerAvailableKHR|NonPrivatePointerKHR [[scope]]
|
||||
OpCapability Shader
|
||||
OpCapability Linkage
|
||||
OpCapability VariablePointers
|
||||
@@ -440,8 +439,8 @@ TEST_F(UpgradeMemoryModelTest, CoherentStructElement) {
|
||||
const std::string text = R"(
|
||||
; CHECK-NOT: OpMemberDecorate
|
||||
; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5
|
||||
; CHECK: OpLoad {{%\w+}} {{%\w+}} MakePointerAvailableKHR|NonPrivatePointerKHR [[scope]]
|
||||
; CHECK: OpStore {{%\w+}} {{%\w+}} MakePointerVisibleKHR|NonPrivatePointerKHR [[scope]]
|
||||
; CHECK: OpLoad {{%\w+}} {{%\w+}} MakePointerVisibleKHR|NonPrivatePointerKHR [[scope]]
|
||||
; CHECK: OpStore {{%\w+}} {{%\w+}} MakePointerAvailableKHR|NonPrivatePointerKHR [[scope]]
|
||||
OpCapability Shader
|
||||
OpCapability Linkage
|
||||
OpExtension "SPV_KHR_storage_buffer_storage_class"
|
||||
@@ -471,8 +470,8 @@ TEST_F(UpgradeMemoryModelTest, CoherentElementFullStructAccess) {
|
||||
const std::string text = R"(
|
||||
; CHECK-NOT: OpMemberDecorate
|
||||
; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5
|
||||
; CHECK: OpLoad {{%\w+}} {{%\w+}} MakePointerAvailableKHR|NonPrivatePointerKHR [[scope]]
|
||||
; CHECK: OpStore {{%\w+}} {{%\w+}} MakePointerVisibleKHR|NonPrivatePointerKHR [[scope]]
|
||||
; CHECK: OpLoad {{%\w+}} {{%\w+}} MakePointerVisibleKHR|NonPrivatePointerKHR [[scope]]
|
||||
; CHECK: OpStore {{%\w+}} {{%\w+}} MakePointerAvailableKHR|NonPrivatePointerKHR [[scope]]
|
||||
OpCapability Shader
|
||||
OpCapability Linkage
|
||||
OpExtension "SPV_KHR_storage_buffer_storage_class"
|
||||
@@ -530,8 +529,8 @@ TEST_F(UpgradeMemoryModelTest, MultiIndexAccessCoherent) {
|
||||
const std::string text = R"(
|
||||
; CHECK-NOT: OpMemberDecorate
|
||||
; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5
|
||||
; CHECK: OpLoad {{%\w+}} {{%\w+}} MakePointerAvailableKHR|NonPrivatePointerKHR [[scope]]
|
||||
; CHECK: OpStore {{%\w+}} {{%\w+}} MakePointerVisibleKHR|NonPrivatePointerKHR [[scope]]
|
||||
; CHECK: OpLoad {{%\w+}} {{%\w+}} MakePointerVisibleKHR|NonPrivatePointerKHR [[scope]]
|
||||
; CHECK: OpStore {{%\w+}} {{%\w+}} MakePointerAvailableKHR|NonPrivatePointerKHR [[scope]]
|
||||
OpCapability Shader
|
||||
OpCapability Linkage
|
||||
OpExtension "SPV_KHR_storage_buffer_storage_class"
|
||||
@@ -600,8 +599,8 @@ TEST_F(UpgradeMemoryModelTest, ConsecutiveAccessChainCoherent) {
|
||||
const std::string text = R"(
|
||||
; CHECK-NOT: OpMemberDecorate
|
||||
; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5
|
||||
; CHECK: OpLoad {{%\w+}} {{%\w+}} MakePointerAvailableKHR|NonPrivatePointerKHR [[scope]]
|
||||
; CHECK: OpStore {{%\w+}} {{%\w+}} MakePointerVisibleKHR|NonPrivatePointerKHR [[scope]]
|
||||
; CHECK: OpLoad {{%\w+}} {{%\w+}} MakePointerVisibleKHR|NonPrivatePointerKHR [[scope]]
|
||||
; CHECK: OpStore {{%\w+}} {{%\w+}} MakePointerAvailableKHR|NonPrivatePointerKHR [[scope]]
|
||||
OpCapability Shader
|
||||
OpCapability Linkage
|
||||
OpExtension "SPV_KHR_storage_buffer_storage_class"
|
||||
@@ -682,8 +681,8 @@ TEST_F(UpgradeMemoryModelTest, CoherentStructElementAccess) {
|
||||
const std::string text = R"(
|
||||
; CHECK-NOT: OpMemberDecorate
|
||||
; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5
|
||||
; CHECK: OpLoad {{%\w+}} {{%\w+}} MakePointerAvailableKHR|NonPrivatePointerKHR [[scope]]
|
||||
; CHECK: OpStore {{%\w+}} {{%\w+}} MakePointerVisibleKHR|NonPrivatePointerKHR [[scope]]
|
||||
; CHECK: OpLoad {{%\w+}} {{%\w+}} MakePointerVisibleKHR|NonPrivatePointerKHR [[scope]]
|
||||
; CHECK: OpStore {{%\w+}} {{%\w+}} MakePointerAvailableKHR|NonPrivatePointerKHR [[scope]]
|
||||
OpCapability Shader
|
||||
OpCapability Linkage
|
||||
OpExtension "SPV_KHR_storage_buffer_storage_class"
|
||||
@@ -723,8 +722,8 @@ TEST_F(UpgradeMemoryModelTest, NonCoherentLoadCoherentStore) {
|
||||
const std::string text = R"(
|
||||
; CHECK-NOT: OpMemberDecorate
|
||||
; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5
|
||||
; CHECK-NOT: MakePointerAvailableKHR
|
||||
; CHECK: OpStore {{%\w+}} {{%\w+}} MakePointerVisibleKHR|NonPrivatePointerKHR [[scope]]
|
||||
; CHECK-NOT: MakePointerVisibleKHR
|
||||
; CHECK: OpStore {{%\w+}} {{%\w+}} MakePointerAvailableKHR|NonPrivatePointerKHR [[scope]]
|
||||
OpCapability Shader
|
||||
OpCapability Linkage
|
||||
OpExtension "SPV_KHR_storage_buffer_storage_class"
|
||||
@@ -823,7 +822,7 @@ TEST_F(UpgradeMemoryModelTest, CopyMemoryTwoScopes) {
|
||||
; CHECK-NOT: OpDecorate
|
||||
; CHECK-DAG: [[queuefamily:%\w+]] = OpConstant {{%\w+}} 5
|
||||
; CHECK-DAG: [[workgroup:%\w+]] = OpConstant {{%\w+}} 2
|
||||
; CHECK: OpCopyMemory {{%\w+}} {{%\w+}} MakePointerAvailableKHR|MakePointerVisibleKHR|NonPrivatePointerKHR [[queuefamily]] [[workgroup]]
|
||||
; CHECK: OpCopyMemory {{%\w+}} {{%\w+}} MakePointerAvailableKHR|MakePointerVisibleKHR|NonPrivatePointerKHR [[workgroup]] [[queuefamily]]
|
||||
OpCapability Shader
|
||||
OpCapability Linkage
|
||||
OpExtension "SPV_KHR_storage_buffer_storage_class"
|
||||
@@ -883,8 +882,8 @@ TEST_F(UpgradeMemoryModelTest, CoherentImageRead) {
|
||||
const std::string text = R"(
|
||||
; CHECK-NOT: OpDecorate
|
||||
; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5
|
||||
; CHECK: OpLoad {{%\w+}} {{%\w+}} MakePointerAvailableKHR|NonPrivatePointerKHR [[scope]]
|
||||
; CHECK: OpImageRead {{%\w+}} {{%\w+}} {{%\w+}} MakeTexelAvailableKHR|NonPrivateTexelKHR [[scope]]
|
||||
; CHECK: OpLoad {{%\w+}} {{%\w+}} MakePointerVisibleKHR|NonPrivatePointerKHR [[scope]]
|
||||
; CHECK: OpImageRead {{%\w+}} {{%\w+}} {{%\w+}} MakeTexelVisibleKHR|NonPrivateTexelKHR [[scope]]
|
||||
OpCapability Shader
|
||||
OpCapability Linkage
|
||||
OpCapability StorageImageReadWithoutFormat
|
||||
@@ -917,9 +916,9 @@ TEST_F(UpgradeMemoryModelTest, CoherentImageReadExtractedFromSampledImage) {
|
||||
; CHECK-NOT: OpDecorate
|
||||
; CHECK: [[image:%\w+]] = OpTypeImage
|
||||
; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5
|
||||
; CHECK: OpLoad [[image]] {{%\w+}} MakePointerAvailableKHR|NonPrivatePointerKHR [[scope]]
|
||||
; CHECK: OpLoad [[image]] {{%\w+}} MakePointerVisibleKHR|NonPrivatePointerKHR [[scope]]
|
||||
; CHECK-NOT: NonPrivatePointerKHR
|
||||
; CHECK: OpImageRead {{%\w+}} {{%\w+}} {{%\w+}} MakeTexelAvailableKHR|NonPrivateTexelKHR [[scope]]
|
||||
; CHECK: OpImageRead {{%\w+}} {{%\w+}} {{%\w+}} MakeTexelVisibleKHR|NonPrivateTexelKHR [[scope]]
|
||||
OpCapability Shader
|
||||
OpCapability Linkage
|
||||
OpCapability StorageImageReadWithoutFormat
|
||||
@@ -990,8 +989,8 @@ TEST_F(UpgradeMemoryModelTest, CoherentImageWrite) {
|
||||
const std::string text = R"(
|
||||
; CHECK-NOT: OpDecorate
|
||||
; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5
|
||||
; CHECK: OpLoad {{%\w+}} {{%\w+}} MakePointerAvailableKHR|NonPrivatePointerKHR
|
||||
; CHECK: OpImageWrite {{%\w+}} {{%\w+}} {{%\w+}} MakeTexelVisibleKHR|NonPrivateTexelKHR [[scope]]
|
||||
; CHECK: OpLoad {{%\w+}} {{%\w+}} MakePointerVisibleKHR|NonPrivatePointerKHR
|
||||
; CHECK: OpImageWrite {{%\w+}} {{%\w+}} {{%\w+}} MakeTexelAvailableKHR|NonPrivateTexelKHR [[scope]]
|
||||
OpCapability Shader
|
||||
OpCapability Linkage
|
||||
OpCapability StorageImageWriteWithoutFormat
|
||||
@@ -1023,9 +1022,9 @@ TEST_F(UpgradeMemoryModelTest, CoherentImageWriteExtractFromSampledImage) {
|
||||
const std::string text = R"(
|
||||
; CHECK-NOT: OpDecorate
|
||||
; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5
|
||||
; CHECK: OpLoad {{%\w+}} {{%\w+}} MakePointerAvailableKHR|NonPrivatePointerKHR
|
||||
; CHECK: OpLoad {{%\w+}} {{%\w+}} MakePointerVisibleKHR|NonPrivatePointerKHR
|
||||
; CHECK-NOT: NonPrivatePointerKHR
|
||||
; CHECK: OpImageWrite {{%\w+}} {{%\w+}} {{%\w+}} MakeTexelVisibleKHR|NonPrivateTexelKHR [[scope]]
|
||||
; CHECK: OpImageWrite {{%\w+}} {{%\w+}} {{%\w+}} MakeTexelAvailableKHR|NonPrivateTexelKHR [[scope]]
|
||||
OpCapability Shader
|
||||
OpCapability Linkage
|
||||
OpCapability StorageImageWriteWithoutFormat
|
||||
@@ -1098,8 +1097,8 @@ TEST_F(UpgradeMemoryModelTest, CoherentImageSparseRead) {
|
||||
const std::string text = R"(
|
||||
; CHECK-NOT: OpDecorate
|
||||
; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5
|
||||
; CHECK: OpLoad {{%\w+}} {{%\w+}} MakePointerAvailableKHR|NonPrivatePointerKHR [[scope]]
|
||||
; CHECK: OpImageSparseRead {{%\w+}} {{%\w+}} {{%\w+}} MakeTexelAvailableKHR|NonPrivateTexelKHR [[scope]]
|
||||
; CHECK: OpLoad {{%\w+}} {{%\w+}} MakePointerVisibleKHR|NonPrivatePointerKHR [[scope]]
|
||||
; CHECK: OpImageSparseRead {{%\w+}} {{%\w+}} {{%\w+}} MakeTexelVisibleKHR|NonPrivateTexelKHR [[scope]]
|
||||
OpCapability Shader
|
||||
OpCapability Linkage
|
||||
OpCapability StorageImageReadWithoutFormat
|
||||
@@ -1135,9 +1134,9 @@ TEST_F(UpgradeMemoryModelTest,
|
||||
; CHECK-NOT: OpDecorate
|
||||
; CHECK: [[image:%\w+]] = OpTypeImage
|
||||
; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5
|
||||
; CHECK: OpLoad [[image]] {{%\w+}} MakePointerAvailableKHR|NonPrivatePointerKHR [[scope]]
|
||||
; CHECK: OpLoad [[image]] {{%\w+}} MakePointerVisibleKHR|NonPrivatePointerKHR [[scope]]
|
||||
; CHECK-NOT: NonPrivatePointerKHR
|
||||
; CHECK: OpImageSparseRead {{%\w+}} {{%\w+}} {{%\w+}} MakeTexelAvailableKHR|NonPrivateTexelKHR [[scope]]
|
||||
; CHECK: OpImageSparseRead {{%\w+}} {{%\w+}} {{%\w+}} MakeTexelVisibleKHR|NonPrivateTexelKHR [[scope]]
|
||||
OpCapability Shader
|
||||
OpCapability Linkage
|
||||
OpCapability StorageImageReadWithoutFormat
|
||||
@@ -1430,6 +1429,288 @@ OpFunctionEnd
|
||||
SinglePassRunAndMatch<opt::UpgradeMemoryModel>(text, true);
|
||||
}
|
||||
|
||||
#endif
|
||||
TEST_F(UpgradeMemoryModelTest, UpgradeModfNoFlags) {
|
||||
const std::string text = R"(
|
||||
; CHECK: [[float:%\w+]] = OpTypeFloat 32
|
||||
; CHECK: [[float_0:%\w+]] = OpConstant [[float]] 0
|
||||
; CHECK: [[ptr:%\w+]] = OpTypePointer StorageBuffer [[float]]
|
||||
; CHECK: [[var:%\w+]] = OpVariable [[ptr]] StorageBuffer
|
||||
; CHECK: [[struct:%\w+]] = OpTypeStruct [[float]] [[float]]
|
||||
; CHECK: [[modfstruct:%\w+]] = OpExtInst [[struct]] {{%\w+}} ModfStruct [[float_0]]
|
||||
; CHECK: [[ex0:%\w+]] = OpCompositeExtract [[float]] [[modfstruct]] 0
|
||||
; CHECK: [[ex1:%\w+]] = OpCompositeExtract [[float]] [[modfstruct]] 1
|
||||
; CHECK: OpStore [[var]] [[ex1]]
|
||||
; CHECK-NOT: NonPrivatePointerKHR
|
||||
; CHECK: OpFAdd [[float]] [[float_0]] [[ex0]]
|
||||
OpCapability Shader
|
||||
OpMemoryModel Logical GLSL450
|
||||
%import = OpExtInstImport "GLSL.std.450"
|
||||
OpEntryPoint GLCompute %func "func"
|
||||
%void = OpTypeVoid
|
||||
%float = OpTypeFloat 32
|
||||
%float_0 = OpConstant %float 0
|
||||
%ptr_ssbo_float = OpTypePointer StorageBuffer %float
|
||||
%ssbo_var = OpVariable %ptr_ssbo_float StorageBuffer
|
||||
%func_ty = OpTypeFunction %void
|
||||
%func = OpFunction %void None %func_ty
|
||||
%1 = OpLabel
|
||||
%2 = OpExtInst %float %import Modf %float_0 %ssbo_var
|
||||
%3 = OpFAdd %float %float_0 %2
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
SinglePassRunAndMatch<opt::UpgradeMemoryModel>(text, true);
|
||||
}
|
||||
|
||||
TEST_F(UpgradeMemoryModelTest, UpgradeModfWorkgroupCoherent) {
|
||||
const std::string text = R"(
|
||||
; CHECK: [[float:%\w+]] = OpTypeFloat 32
|
||||
; CHECK: [[float_0:%\w+]] = OpConstant [[float]] 0
|
||||
; CHECK: [[ptr:%\w+]] = OpTypePointer Workgroup [[float]]
|
||||
; CHECK: [[var:%\w+]] = OpVariable [[ptr]] Workgroup
|
||||
; CHECK: [[struct:%\w+]] = OpTypeStruct [[float]] [[float]]
|
||||
; CHECK: [[wg_scope:%\w+]] = OpConstant {{%\w+}} 2
|
||||
; CHECK: [[modfstruct:%\w+]] = OpExtInst [[struct]] {{%\w+}} ModfStruct [[float_0]]
|
||||
; CHECK: [[ex0:%\w+]] = OpCompositeExtract [[float]] [[modfstruct]] 0
|
||||
; CHECK: [[ex1:%\w+]] = OpCompositeExtract [[float]] [[modfstruct]] 1
|
||||
; CHECK: OpStore [[var]] [[ex1]] MakePointerAvailableKHR|NonPrivatePointerKHR [[wg_scope]]
|
||||
; CHECK: OpFAdd [[float]] [[float_0]] [[ex0]]
|
||||
OpCapability Shader
|
||||
OpMemoryModel Logical GLSL450
|
||||
%import = OpExtInstImport "GLSL.std.450"
|
||||
OpEntryPoint GLCompute %func "func"
|
||||
OpDecorate %wg_var Coherent
|
||||
%void = OpTypeVoid
|
||||
%float = OpTypeFloat 32
|
||||
%float_0 = OpConstant %float 0
|
||||
%ptr_wg_float = OpTypePointer Workgroup %float
|
||||
%wg_var = OpVariable %ptr_wg_float Workgroup
|
||||
%func_ty = OpTypeFunction %void
|
||||
%func = OpFunction %void None %func_ty
|
||||
%1 = OpLabel
|
||||
%2 = OpExtInst %float %import Modf %float_0 %wg_var
|
||||
%3 = OpFAdd %float %float_0 %2
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
SinglePassRunAndMatch<opt::UpgradeMemoryModel>(text, true);
|
||||
}
|
||||
|
||||
TEST_F(UpgradeMemoryModelTest, UpgradeModfSSBOCoherent) {
|
||||
const std::string text = R"(
|
||||
; CHECK: [[float:%\w+]] = OpTypeFloat 32
|
||||
; CHECK: [[float_0:%\w+]] = OpConstant [[float]] 0
|
||||
; CHECK: [[ptr:%\w+]] = OpTypePointer StorageBuffer [[float]]
|
||||
; CHECK: [[var:%\w+]] = OpVariable [[ptr]] StorageBuffer
|
||||
; CHECK: [[struct:%\w+]] = OpTypeStruct [[float]] [[float]]
|
||||
; CHECK: [[qf_scope:%\w+]] = OpConstant {{%\w+}} 5
|
||||
; CHECK: [[modfstruct:%\w+]] = OpExtInst [[struct]] {{%\w+}} ModfStruct [[float_0]]
|
||||
; CHECK: [[ex0:%\w+]] = OpCompositeExtract [[float]] [[modfstruct]] 0
|
||||
; CHECK: [[ex1:%\w+]] = OpCompositeExtract [[float]] [[modfstruct]] 1
|
||||
; CHECK: OpStore [[var]] [[ex1]] MakePointerAvailableKHR|NonPrivatePointerKHR [[qf_scope]]
|
||||
; CHECK: OpFAdd [[float]] [[float_0]] [[ex0]]
|
||||
OpCapability Shader
|
||||
OpMemoryModel Logical GLSL450
|
||||
%import = OpExtInstImport "GLSL.std.450"
|
||||
OpEntryPoint GLCompute %func "func"
|
||||
OpDecorate %ssbo_var Coherent
|
||||
%void = OpTypeVoid
|
||||
%float = OpTypeFloat 32
|
||||
%float_0 = OpConstant %float 0
|
||||
%ptr_ssbo_float = OpTypePointer StorageBuffer %float
|
||||
%ssbo_var = OpVariable %ptr_ssbo_float StorageBuffer
|
||||
%func_ty = OpTypeFunction %void
|
||||
%func = OpFunction %void None %func_ty
|
||||
%1 = OpLabel
|
||||
%2 = OpExtInst %float %import Modf %float_0 %ssbo_var
|
||||
%3 = OpFAdd %float %float_0 %2
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
SinglePassRunAndMatch<opt::UpgradeMemoryModel>(text, true);
|
||||
}
|
||||
|
||||
TEST_F(UpgradeMemoryModelTest, UpgradeModfSSBOVolatile) {
|
||||
const std::string text = R"(
|
||||
; CHECK: [[float:%\w+]] = OpTypeFloat 32
|
||||
; CHECK: [[float_0:%\w+]] = OpConstant [[float]] 0
|
||||
; CHECK: [[ptr:%\w+]] = OpTypePointer StorageBuffer [[float]]
|
||||
; CHECK: [[var:%\w+]] = OpVariable [[ptr]] StorageBuffer
|
||||
; CHECK: [[struct:%\w+]] = OpTypeStruct [[float]] [[float]]
|
||||
; CHECK: [[modfstruct:%\w+]] = OpExtInst [[struct]] {{%\w+}} ModfStruct [[float_0]]
|
||||
; CHECK: [[ex0:%\w+]] = OpCompositeExtract [[float]] [[modfstruct]] 0
|
||||
; CHECK: [[ex1:%\w+]] = OpCompositeExtract [[float]] [[modfstruct]] 1
|
||||
; CHECK: OpStore [[var]] [[ex1]] Volatile
|
||||
; CHECK: OpFAdd [[float]] [[float_0]] [[ex0]]
|
||||
OpCapability Shader
|
||||
OpMemoryModel Logical GLSL450
|
||||
%import = OpExtInstImport "GLSL.std.450"
|
||||
OpEntryPoint GLCompute %func "func"
|
||||
OpDecorate %wg_var Volatile
|
||||
%void = OpTypeVoid
|
||||
%float = OpTypeFloat 32
|
||||
%float_0 = OpConstant %float 0
|
||||
%ptr_ssbo_float = OpTypePointer StorageBuffer %float
|
||||
%wg_var = OpVariable %ptr_ssbo_float StorageBuffer
|
||||
%func_ty = OpTypeFunction %void
|
||||
%func = OpFunction %void None %func_ty
|
||||
%1 = OpLabel
|
||||
%2 = OpExtInst %float %import Modf %float_0 %wg_var
|
||||
%3 = OpFAdd %float %float_0 %2
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
SinglePassRunAndMatch<opt::UpgradeMemoryModel>(text, true);
|
||||
}
|
||||
|
||||
TEST_F(UpgradeMemoryModelTest, UpgradeFrexpNoFlags) {
|
||||
const std::string text = R"(
|
||||
; CHECK: [[float:%\w+]] = OpTypeFloat 32
|
||||
; CHECK: [[float_0:%\w+]] = OpConstant [[float]] 0
|
||||
; CHECK: [[int:%\w+]] = OpTypeInt 32 0
|
||||
; CHECK: [[ptr:%\w+]] = OpTypePointer StorageBuffer [[int]]
|
||||
; CHECK: [[var:%\w+]] = OpVariable [[ptr]] StorageBuffer
|
||||
; CHECK: [[struct:%\w+]] = OpTypeStruct [[float]] [[int]]
|
||||
; CHECK: [[modfstruct:%\w+]] = OpExtInst [[struct]] {{%\w+}} FrexpStruct [[float_0]]
|
||||
; CHECK: [[ex0:%\w+]] = OpCompositeExtract [[float]] [[modfstruct]] 0
|
||||
; CHECK: [[ex1:%\w+]] = OpCompositeExtract [[int]] [[modfstruct]] 1
|
||||
; CHECK: OpStore [[var]] [[ex1]]
|
||||
; CHECK-NOT: NonPrivatePointerKHR
|
||||
; CHECK: OpFAdd [[float]] [[float_0]] [[ex0]]
|
||||
OpCapability Shader
|
||||
OpMemoryModel Logical GLSL450
|
||||
%import = OpExtInstImport "GLSL.std.450"
|
||||
OpEntryPoint GLCompute %func "func"
|
||||
%void = OpTypeVoid
|
||||
%float = OpTypeFloat 32
|
||||
%float_0 = OpConstant %float 0
|
||||
%int = OpTypeInt 32 0
|
||||
%ptr_ssbo_int = OpTypePointer StorageBuffer %int
|
||||
%ssbo_var = OpVariable %ptr_ssbo_int StorageBuffer
|
||||
%func_ty = OpTypeFunction %void
|
||||
%func = OpFunction %void None %func_ty
|
||||
%1 = OpLabel
|
||||
%2 = OpExtInst %float %import Frexp %float_0 %ssbo_var
|
||||
%3 = OpFAdd %float %float_0 %2
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
SinglePassRunAndMatch<opt::UpgradeMemoryModel>(text, true);
|
||||
}
|
||||
|
||||
TEST_F(UpgradeMemoryModelTest, UpgradeFrexpWorkgroupCoherent) {
|
||||
const std::string text = R"(
|
||||
; CHECK: [[float:%\w+]] = OpTypeFloat 32
|
||||
; CHECK: [[float_0:%\w+]] = OpConstant [[float]] 0
|
||||
; CHECK: [[int:%\w+]] = OpTypeInt 32 0
|
||||
; CHECK: [[ptr:%\w+]] = OpTypePointer Workgroup [[int]]
|
||||
; CHECK: [[var:%\w+]] = OpVariable [[ptr]] Workgroup
|
||||
; CHECK: [[struct:%\w+]] = OpTypeStruct [[float]] [[int]]
|
||||
; CHECK: [[wg_scope:%\w+]] = OpConstant {{%\w+}} 2
|
||||
; CHECK: [[modfstruct:%\w+]] = OpExtInst [[struct]] {{%\w+}} FrexpStruct [[float_0]]
|
||||
; CHECK: [[ex0:%\w+]] = OpCompositeExtract [[float]] [[modfstruct]] 0
|
||||
; CHECK: [[ex1:%\w+]] = OpCompositeExtract [[int]] [[modfstruct]] 1
|
||||
; CHECK: OpStore [[var]] [[ex1]] MakePointerAvailableKHR|NonPrivatePointerKHR [[wg_scope]]
|
||||
; CHECK: OpFAdd [[float]] [[float_0]] [[ex0]]
|
||||
OpCapability Shader
|
||||
OpMemoryModel Logical GLSL450
|
||||
%import = OpExtInstImport "GLSL.std.450"
|
||||
OpEntryPoint GLCompute %func "func"
|
||||
OpDecorate %wg_var Coherent
|
||||
%void = OpTypeVoid
|
||||
%float = OpTypeFloat 32
|
||||
%float_0 = OpConstant %float 0
|
||||
%int = OpTypeInt 32 0
|
||||
%ptr_wg_int = OpTypePointer Workgroup %int
|
||||
%wg_var = OpVariable %ptr_wg_int Workgroup
|
||||
%func_ty = OpTypeFunction %void
|
||||
%func = OpFunction %void None %func_ty
|
||||
%1 = OpLabel
|
||||
%2 = OpExtInst %float %import Frexp %float_0 %wg_var
|
||||
%3 = OpFAdd %float %float_0 %2
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
SinglePassRunAndMatch<opt::UpgradeMemoryModel>(text, true);
|
||||
}
|
||||
|
||||
TEST_F(UpgradeMemoryModelTest, UpgradeFrexpSSBOCoherent) {
|
||||
const std::string text = R"(
|
||||
; CHECK: [[float:%\w+]] = OpTypeFloat 32
|
||||
; CHECK: [[float_0:%\w+]] = OpConstant [[float]] 0
|
||||
; CHECK: [[int:%\w+]] = OpTypeInt 32 0
|
||||
; CHECK: [[ptr:%\w+]] = OpTypePointer StorageBuffer [[int]]
|
||||
; CHECK: [[var:%\w+]] = OpVariable [[ptr]] StorageBuffer
|
||||
; CHECK: [[struct:%\w+]] = OpTypeStruct [[float]] [[int]]
|
||||
; CHECK: [[qf_scope:%\w+]] = OpConstant {{%\w+}} 5
|
||||
; CHECK: [[modfstruct:%\w+]] = OpExtInst [[struct]] {{%\w+}} FrexpStruct [[float_0]]
|
||||
; CHECK: [[ex0:%\w+]] = OpCompositeExtract [[float]] [[modfstruct]] 0
|
||||
; CHECK: [[ex1:%\w+]] = OpCompositeExtract [[int]] [[modfstruct]] 1
|
||||
; CHECK: OpStore [[var]] [[ex1]] MakePointerAvailableKHR|NonPrivatePointerKHR [[qf_scope]]
|
||||
; CHECK: OpFAdd [[float]] [[float_0]] [[ex0]]
|
||||
OpCapability Shader
|
||||
OpMemoryModel Logical GLSL450
|
||||
%import = OpExtInstImport "GLSL.std.450"
|
||||
OpEntryPoint GLCompute %func "func"
|
||||
OpDecorate %ssbo_var Coherent
|
||||
%void = OpTypeVoid
|
||||
%float = OpTypeFloat 32
|
||||
%float_0 = OpConstant %float 0
|
||||
%int = OpTypeInt 32 0
|
||||
%ptr_ssbo_int = OpTypePointer StorageBuffer %int
|
||||
%ssbo_var = OpVariable %ptr_ssbo_int StorageBuffer
|
||||
%func_ty = OpTypeFunction %void
|
||||
%func = OpFunction %void None %func_ty
|
||||
%1 = OpLabel
|
||||
%2 = OpExtInst %float %import Frexp %float_0 %ssbo_var
|
||||
%3 = OpFAdd %float %float_0 %2
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
SinglePassRunAndMatch<opt::UpgradeMemoryModel>(text, true);
|
||||
}
|
||||
|
||||
TEST_F(UpgradeMemoryModelTest, UpgradeFrexpSSBOVolatile) {
|
||||
const std::string text = R"(
|
||||
; CHECK: [[float:%\w+]] = OpTypeFloat 32
|
||||
; CHECK: [[float_0:%\w+]] = OpConstant [[float]] 0
|
||||
; CHECK: [[int:%\w+]] = OpTypeInt 32 0
|
||||
; CHECK: [[ptr:%\w+]] = OpTypePointer StorageBuffer [[int]]
|
||||
; CHECK: [[var:%\w+]] = OpVariable [[ptr]] StorageBuffer
|
||||
; CHECK: [[struct:%\w+]] = OpTypeStruct [[float]] [[int]]
|
||||
; CHECK: [[modfstruct:%\w+]] = OpExtInst [[struct]] {{%\w+}} FrexpStruct [[float_0]]
|
||||
; CHECK: [[ex0:%\w+]] = OpCompositeExtract [[float]] [[modfstruct]] 0
|
||||
; CHECK: [[ex1:%\w+]] = OpCompositeExtract [[int]] [[modfstruct]] 1
|
||||
; CHECK: OpStore [[var]] [[ex1]] Volatile
|
||||
; CHECK: OpFAdd [[float]] [[float_0]] [[ex0]]
|
||||
OpCapability Shader
|
||||
OpMemoryModel Logical GLSL450
|
||||
%import = OpExtInstImport "GLSL.std.450"
|
||||
OpEntryPoint GLCompute %func "func"
|
||||
OpDecorate %wg_var Volatile
|
||||
%void = OpTypeVoid
|
||||
%float = OpTypeFloat 32
|
||||
%float_0 = OpConstant %float 0
|
||||
%int = OpTypeInt 32 0
|
||||
%ptr_ssbo_int = OpTypePointer StorageBuffer %int
|
||||
%wg_var = OpVariable %ptr_ssbo_int StorageBuffer
|
||||
%func_ty = OpTypeFunction %void
|
||||
%func = OpFunction %void None %func_ty
|
||||
%1 = OpLabel
|
||||
%2 = OpExtInst %float %import Frexp %float_0 %wg_var
|
||||
%3 = OpFAdd %float %float_0 %2
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
SinglePassRunAndMatch<opt::UpgradeMemoryModel>(text, true);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
13
3rdparty/spirv-tools/test/test_fixture.h
vendored
13
3rdparty/spirv-tools/test/test_fixture.h
vendored
@@ -61,6 +61,8 @@ class TextToBinaryTestBase : public T {
|
||||
// compilation success. Returns the compiled code.
|
||||
SpirvVector CompileSuccessfully(const std::string& txt,
|
||||
spv_target_env env = SPV_ENV_UNIVERSAL_1_0) {
|
||||
DestroyBinary();
|
||||
DestroyDiagnostic();
|
||||
spv_result_t status =
|
||||
spvTextToBinary(ScopedContext(env).context, txt.c_str(), txt.size(),
|
||||
&binary, &diagnostic);
|
||||
@@ -79,6 +81,8 @@ class TextToBinaryTestBase : public T {
|
||||
// Returns the error message(s).
|
||||
std::string CompileFailure(const std::string& txt,
|
||||
spv_target_env env = SPV_ENV_UNIVERSAL_1_0) {
|
||||
DestroyBinary();
|
||||
DestroyDiagnostic();
|
||||
EXPECT_NE(SPV_SUCCESS,
|
||||
spvTextToBinary(ScopedContext(env).context, txt.c_str(),
|
||||
txt.size(), &binary, &diagnostic))
|
||||
@@ -94,6 +98,7 @@ class TextToBinaryTestBase : public T {
|
||||
uint32_t disassemble_options = SPV_BINARY_TO_TEXT_OPTION_NONE,
|
||||
spv_target_env env = SPV_ENV_UNIVERSAL_1_0) {
|
||||
DestroyBinary();
|
||||
DestroyDiagnostic();
|
||||
ScopedContext context(env);
|
||||
disassemble_options |= SPV_BINARY_TO_TEXT_OPTION_NO_HEADER;
|
||||
spv_result_t error = spvTextToBinary(context.context, txt.c_str(),
|
||||
@@ -126,6 +131,8 @@ class TextToBinaryTestBase : public T {
|
||||
// Returns the error message.
|
||||
std::string EncodeSuccessfullyDecodeFailed(
|
||||
const std::string& txt, const SpirvVector& words_to_append) {
|
||||
DestroyBinary();
|
||||
DestroyDiagnostic();
|
||||
SpirvVector code =
|
||||
spvtest::Concatenate({CompileSuccessfully(txt), words_to_append});
|
||||
|
||||
@@ -169,6 +176,12 @@ class TextToBinaryTestBase : public T {
|
||||
binary = nullptr;
|
||||
}
|
||||
|
||||
// Destroys the diagnostic, if it exists.
|
||||
void DestroyDiagnostic() {
|
||||
spvDiagnosticDestroy(diagnostic);
|
||||
diagnostic = nullptr;
|
||||
}
|
||||
|
||||
spv_diagnostic diagnostic;
|
||||
|
||||
std::string textString;
|
||||
|
||||
@@ -280,6 +280,20 @@ INSTANTIATE_TEST_CASE_P(
|
||||
"InBoundsPtrAccessChain"),
|
||||
}));
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
UConvertInAMD_gpu_shader_int16, ValidateConstantOp,
|
||||
ValuesIn(std::vector<ConstantOpCase>{
|
||||
// SPV_AMD_gpu_shader_int16 should enable UConvert for OpSpecConstantOp
|
||||
// https://github.com/KhronosGroup/glslang/issues/848
|
||||
{SPV_ENV_UNIVERSAL_1_0,
|
||||
"OpCapability Shader "
|
||||
"OpCapability Linkage ; So we don't need to define a function\n"
|
||||
"OpExtension \"SPV_AMD_gpu_shader_int16\" "
|
||||
"OpMemoryModel Logical Simple " kBasicTypes
|
||||
"%v = OpSpecConstantOp %uint UConvert %uint_0",
|
||||
true, ""},
|
||||
}));
|
||||
|
||||
} // namespace
|
||||
} // namespace val
|
||||
} // namespace spvtools
|
||||
|
||||
@@ -1302,6 +1302,118 @@ OpFunctionEnd
|
||||
"type"));
|
||||
}
|
||||
|
||||
TEST_F(ValidateConversion, ConvertUToPtrPSBSuccess) {
|
||||
const std::string body = R"(
|
||||
OpCapability PhysicalStorageBufferAddressesEXT
|
||||
OpCapability Int64
|
||||
OpCapability Shader
|
||||
OpExtension "SPV_EXT_physical_storage_buffer"
|
||||
OpMemoryModel PhysicalStorageBuffer64EXT GLSL450
|
||||
OpEntryPoint Fragment %main "main"
|
||||
OpExecutionMode %main OriginUpperLeft
|
||||
%uint64 = OpTypeInt 64 0
|
||||
%u64_1 = OpConstant %uint64 1
|
||||
%ptr = OpTypePointer PhysicalStorageBufferEXT %uint64
|
||||
%void = OpTypeVoid
|
||||
%voidfn = OpTypeFunction %void
|
||||
%main = OpFunction %void None %voidfn
|
||||
%entry = OpLabel
|
||||
%val1 = OpConvertUToPtr %ptr %u64_1
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
CompileSuccessfully(body.c_str());
|
||||
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
|
||||
}
|
||||
|
||||
TEST_F(ValidateConversion, ConvertUToPtrPSBStorageClass) {
|
||||
const std::string body = R"(
|
||||
OpCapability PhysicalStorageBufferAddressesEXT
|
||||
OpCapability Int64
|
||||
OpCapability Shader
|
||||
OpExtension "SPV_EXT_physical_storage_buffer"
|
||||
OpMemoryModel PhysicalStorageBuffer64EXT GLSL450
|
||||
OpEntryPoint Fragment %main "main"
|
||||
OpExecutionMode %main OriginUpperLeft
|
||||
%uint64 = OpTypeInt 64 0
|
||||
%u64_1 = OpConstant %uint64 1
|
||||
%ptr = OpTypePointer Function %uint64
|
||||
%void = OpTypeVoid
|
||||
%voidfn = OpTypeFunction %void
|
||||
%main = OpFunction %void None %voidfn
|
||||
%entry = OpLabel
|
||||
%val1 = OpConvertUToPtr %ptr %u64_1
|
||||
%val2 = OpConvertPtrToU %uint64 %val1
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
CompileSuccessfully(body.c_str());
|
||||
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
|
||||
EXPECT_THAT(getDiagnosticString(),
|
||||
HasSubstr("Pointer storage class must be "
|
||||
"PhysicalStorageBufferEXT: ConvertUToPtr"));
|
||||
}
|
||||
|
||||
TEST_F(ValidateConversion, ConvertPtrToUPSBSuccess) {
|
||||
const std::string body = R"(
|
||||
OpCapability PhysicalStorageBufferAddressesEXT
|
||||
OpCapability Int64
|
||||
OpCapability Shader
|
||||
OpExtension "SPV_EXT_physical_storage_buffer"
|
||||
OpMemoryModel PhysicalStorageBuffer64EXT GLSL450
|
||||
OpEntryPoint Fragment %main "main"
|
||||
OpExecutionMode %main OriginUpperLeft
|
||||
OpDecorate %val1 RestrictPointerEXT
|
||||
%uint64 = OpTypeInt 64 0
|
||||
%u64_1 = OpConstant %uint64 1
|
||||
%ptr = OpTypePointer PhysicalStorageBufferEXT %uint64
|
||||
%pptr_f = OpTypePointer Function %ptr
|
||||
%void = OpTypeVoid
|
||||
%voidfn = OpTypeFunction %void
|
||||
%main = OpFunction %void None %voidfn
|
||||
%entry = OpLabel
|
||||
%val1 = OpVariable %pptr_f Function
|
||||
%val2 = OpLoad %ptr %val1
|
||||
%val3 = OpConvertPtrToU %uint64 %val2
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
CompileSuccessfully(body.c_str());
|
||||
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
|
||||
}
|
||||
|
||||
TEST_F(ValidateConversion, ConvertPtrToUPSBStorageClass) {
|
||||
const std::string body = R"(
|
||||
OpCapability PhysicalStorageBufferAddressesEXT
|
||||
OpCapability Int64
|
||||
OpCapability Shader
|
||||
OpExtension "SPV_EXT_physical_storage_buffer"
|
||||
OpMemoryModel PhysicalStorageBuffer64EXT GLSL450
|
||||
OpEntryPoint Fragment %main "main"
|
||||
OpExecutionMode %main OriginUpperLeft
|
||||
%uint64 = OpTypeInt 64 0
|
||||
%u64_1 = OpConstant %uint64 1
|
||||
%ptr = OpTypePointer Function %uint64
|
||||
%void = OpTypeVoid
|
||||
%voidfn = OpTypeFunction %void
|
||||
%main = OpFunction %void None %voidfn
|
||||
%entry = OpLabel
|
||||
%val1 = OpVariable %ptr Function
|
||||
%val2 = OpConvertPtrToU %uint64 %val1
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
CompileSuccessfully(body.c_str());
|
||||
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
|
||||
EXPECT_THAT(getDiagnosticString(),
|
||||
HasSubstr("Pointer storage class must be "
|
||||
"PhysicalStorageBufferEXT: ConvertPtrToU"));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace val
|
||||
} // namespace spvtools
|
||||
|
||||
169
3rdparty/spirv-tools/test/val/val_data_test.cpp
vendored
169
3rdparty/spirv-tools/test/val/val_data_test.cpp
vendored
@@ -36,6 +36,24 @@ std::string HeaderWith(std::string cap) {
|
||||
cap + " OpMemoryModel Logical GLSL450 ";
|
||||
}
|
||||
|
||||
std::string WebGPUHeaderWith(std::string cap) {
|
||||
return R"(
|
||||
OpCapability Shader
|
||||
OpCapability )" +
|
||||
cap + R"(
|
||||
OpCapability VulkanMemoryModelKHR
|
||||
OpExtension "SPV_KHR_vulkan_memory_model"
|
||||
OpMemoryModel Logical VulkanKHR
|
||||
)";
|
||||
}
|
||||
|
||||
std::string webgpu_header = R"(
|
||||
OpCapability Shader
|
||||
OpCapability VulkanMemoryModelKHR
|
||||
OpExtension "SPV_KHR_vulkan_memory_model"
|
||||
OpMemoryModel Logical VulkanKHR
|
||||
)";
|
||||
|
||||
std::string header = R"(
|
||||
OpCapability Shader
|
||||
OpCapability Linkage
|
||||
@@ -249,6 +267,18 @@ TEST_F(ValidateData, int8_with_storage_push_constant_8_good) {
|
||||
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()) << getDiagnosticString();
|
||||
}
|
||||
|
||||
TEST_F(ValidateData, webgpu_int8_bad) {
|
||||
std::string str = WebGPUHeaderWith("Int8") + "%2 = OpTypeInt 8 0";
|
||||
CompileSuccessfully(str.c_str(), SPV_ENV_WEBGPU_0);
|
||||
ASSERT_EQ(SPV_ERROR_INVALID_CAPABILITY,
|
||||
ValidateInstructions(SPV_ENV_WEBGPU_0));
|
||||
EXPECT_THAT(
|
||||
getDiagnosticString(),
|
||||
HasSubstr("Capability Int8 is not allowed by WebGPU specification (or "
|
||||
"requires extension)\n"
|
||||
" OpCapability Int8\n"));
|
||||
}
|
||||
|
||||
TEST_F(ValidateData, int16_good) {
|
||||
std::string str = header_with_int16 + "%2 = OpTypeInt 16 1";
|
||||
CompileSuccessfully(str.c_str());
|
||||
@@ -308,6 +338,34 @@ TEST_F(ValidateData, int16_bad) {
|
||||
EXPECT_THAT(getDiagnosticString(), HasSubstr(missing_int16_cap_error));
|
||||
}
|
||||
|
||||
TEST_F(ValidateData, webgpu_int16_bad) {
|
||||
std::string str = WebGPUHeaderWith("Int16") + "%2 = OpTypeInt 16 1";
|
||||
CompileSuccessfully(str.c_str(), SPV_ENV_WEBGPU_0);
|
||||
ASSERT_EQ(SPV_ERROR_INVALID_CAPABILITY,
|
||||
ValidateInstructions(SPV_ENV_WEBGPU_0));
|
||||
EXPECT_THAT(
|
||||
getDiagnosticString(),
|
||||
HasSubstr("Capability Int16 is not allowed by WebGPU specification (or "
|
||||
"requires extension)\n"
|
||||
" OpCapability Int16\n"));
|
||||
}
|
||||
|
||||
TEST_F(ValidateData, webgpu_int32_good) {
|
||||
std::string str = webgpu_header + R"(
|
||||
OpEntryPoint Fragment %func "func"
|
||||
OpExecutionMode %func OriginUpperLeft
|
||||
%uint_t = OpTypeInt 32 0
|
||||
%void = OpTypeVoid
|
||||
%func_t = OpTypeFunction %void
|
||||
%func = OpFunction %void None %func_t
|
||||
%1 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
CompileSuccessfully(str.c_str(), SPV_ENV_WEBGPU_0);
|
||||
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_WEBGPU_0));
|
||||
}
|
||||
|
||||
TEST_F(ValidateData, int64_good) {
|
||||
std::string str = header_with_int64 + "%2 = OpTypeInt 64 1";
|
||||
CompileSuccessfully(str.c_str());
|
||||
@@ -321,6 +379,18 @@ TEST_F(ValidateData, int64_bad) {
|
||||
EXPECT_THAT(getDiagnosticString(), HasSubstr(missing_int64_cap_error));
|
||||
}
|
||||
|
||||
TEST_F(ValidateData, webgpu_int64_bad) {
|
||||
std::string str = WebGPUHeaderWith("Int64") + "%2 = OpTypeInt 64 1";
|
||||
CompileSuccessfully(str.c_str(), SPV_ENV_WEBGPU_0);
|
||||
ASSERT_EQ(SPV_ERROR_INVALID_CAPABILITY,
|
||||
ValidateInstructions(SPV_ENV_WEBGPU_0));
|
||||
EXPECT_THAT(
|
||||
getDiagnosticString(),
|
||||
HasSubstr("Capability Int64 is not allowed by WebGPU specification (or "
|
||||
"requires extension)\n"
|
||||
" OpCapability Int64\n"));
|
||||
}
|
||||
|
||||
// Number of bits in an integer may be only one of: {8,16,32,64}
|
||||
TEST_F(ValidateData, int_invalid_num_bits) {
|
||||
std::string str = header + "%2 = OpTypeInt 48 1";
|
||||
@@ -348,6 +418,34 @@ TEST_F(ValidateData, float16_bad) {
|
||||
EXPECT_THAT(getDiagnosticString(), HasSubstr(missing_float16_cap_error));
|
||||
}
|
||||
|
||||
TEST_F(ValidateData, webgpu_float16_bad) {
|
||||
std::string str = WebGPUHeaderWith("Float16") + "%2 = OpTypeFloat 16";
|
||||
CompileSuccessfully(str.c_str(), SPV_ENV_WEBGPU_0);
|
||||
ASSERT_EQ(SPV_ERROR_INVALID_CAPABILITY,
|
||||
ValidateInstructions(SPV_ENV_WEBGPU_0));
|
||||
EXPECT_THAT(
|
||||
getDiagnosticString(),
|
||||
HasSubstr("Capability Float16 is not allowed by WebGPU specification (or "
|
||||
"requires extension)\n"
|
||||
" OpCapability Float16\n"));
|
||||
}
|
||||
|
||||
TEST_F(ValidateData, webgpu_float32_good) {
|
||||
std::string str = webgpu_header + R"(
|
||||
OpEntryPoint Fragment %func "func"
|
||||
OpExecutionMode %func OriginUpperLeft
|
||||
%float_t = OpTypeFloat 32
|
||||
%void = OpTypeVoid
|
||||
%func_t = OpTypeFunction %void
|
||||
%func = OpFunction %void None %func_t
|
||||
%1 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
CompileSuccessfully(str.c_str(), SPV_ENV_WEBGPU_0);
|
||||
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_WEBGPU_0));
|
||||
}
|
||||
|
||||
TEST_F(ValidateData, float64_good) {
|
||||
std::string str = header_with_float64 + "%2 = OpTypeFloat 64";
|
||||
CompileSuccessfully(str.c_str());
|
||||
@@ -361,6 +459,18 @@ TEST_F(ValidateData, float64_bad) {
|
||||
EXPECT_THAT(getDiagnosticString(), HasSubstr(missing_float64_cap_error));
|
||||
}
|
||||
|
||||
TEST_F(ValidateData, webgpu_float64_bad) {
|
||||
std::string str = WebGPUHeaderWith("Float64") + "%2 = OpTypeFloat 64";
|
||||
CompileSuccessfully(str.c_str(), SPV_ENV_WEBGPU_0);
|
||||
ASSERT_EQ(SPV_ERROR_INVALID_CAPABILITY,
|
||||
ValidateInstructions(SPV_ENV_WEBGPU_0));
|
||||
EXPECT_THAT(
|
||||
getDiagnosticString(),
|
||||
HasSubstr("Capability Float64 is not allowed by WebGPU specification (or "
|
||||
"requires extension)\n"
|
||||
" OpCapability Float64\n"));
|
||||
}
|
||||
|
||||
// Number of bits in a float may be only one of: {16,32,64}
|
||||
TEST_F(ValidateData, float_invalid_num_bits) {
|
||||
std::string str = header + "%2 = OpTypeFloat 48";
|
||||
@@ -703,6 +813,65 @@ TEST_F(ValidateData, void_runtime_array) {
|
||||
HasSubstr(
|
||||
"OpTypeRuntimeArray Element Type <id> '1[%void]' is a void type."));
|
||||
}
|
||||
|
||||
TEST_F(ValidateData, vulkan_RTA_array_at_end_of_struct) {
|
||||
std::string str = R"(
|
||||
OpCapability Shader
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %func "func"
|
||||
OpExecutionMode %func OriginUpperLeft
|
||||
OpDecorate %array_t ArrayStride 4
|
||||
OpMemberDecorate %struct_t 0 Offset 0
|
||||
OpMemberDecorate %struct_t 1 Offset 4
|
||||
OpDecorate %struct_t Block
|
||||
%uint_t = OpTypeInt 32 0
|
||||
%array_t = OpTypeRuntimeArray %uint_t
|
||||
%struct_t = OpTypeStruct %uint_t %array_t
|
||||
%struct_ptr = OpTypePointer StorageBuffer %struct_t
|
||||
%2 = OpVariable %struct_ptr StorageBuffer
|
||||
%void = OpTypeVoid
|
||||
%func_t = OpTypeFunction %void
|
||||
%func = OpFunction %void None %func_t
|
||||
%1 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
CompileSuccessfully(str.c_str(), SPV_ENV_VULKAN_1_1);
|
||||
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_1));
|
||||
}
|
||||
|
||||
TEST_F(ValidateData, vulkan_RTA_not_at_end_of_struct) {
|
||||
std::string str = R"(
|
||||
OpCapability Shader
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %func "func"
|
||||
OpExecutionMode %func OriginUpperLeft
|
||||
OpDecorate %array_t ArrayStride 4
|
||||
OpMemberDecorate %struct_t 0 Offset 0
|
||||
OpMemberDecorate %struct_t 1 Offset 4
|
||||
OpDecorate %struct_t Block
|
||||
%uint_t = OpTypeInt 32 0
|
||||
%array_t = OpTypeRuntimeArray %uint_t
|
||||
%struct_t = OpTypeStruct %array_t %uint_t
|
||||
%struct_ptr = OpTypePointer StorageBuffer %struct_t
|
||||
%2 = OpVariable %struct_ptr StorageBuffer
|
||||
%void = OpTypeVoid
|
||||
%func_t = OpTypeFunction %void
|
||||
%func = OpFunction %void None %func_t
|
||||
%1 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
CompileSuccessfully(str.c_str(), SPV_ENV_VULKAN_1_1);
|
||||
ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1));
|
||||
EXPECT_THAT(getDiagnosticString(),
|
||||
HasSubstr("In Vulkan, OpTypeRuntimeArray must only be used for "
|
||||
"the last member of an OpTypeStruct\n %_struct_3 = "
|
||||
"OpTypeStruct %_runtimearr_uint %uint\n"));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace val
|
||||
} // namespace spvtools
|
||||
|
||||
@@ -4345,11 +4345,11 @@ OpFunctionEnd
|
||||
|
||||
CompileSuccessfully(spirv);
|
||||
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
|
||||
EXPECT_THAT(
|
||||
getDiagnosticString(),
|
||||
HasSubstr("FPRoundingMode decoration can be applied only to the "
|
||||
"Object operand of an OpStore in the StorageBuffer, Uniform, "
|
||||
"PushConstant, Input, or Output Storage Classes."));
|
||||
EXPECT_THAT(getDiagnosticString(),
|
||||
HasSubstr("FPRoundingMode decoration can be applied only to the "
|
||||
"Object operand of an OpStore in the StorageBuffer, "
|
||||
"PhysicalStorageBufferEXT, Uniform, "
|
||||
"PushConstant, Input, or Output Storage Classes."));
|
||||
}
|
||||
|
||||
TEST_F(ValidateDecorations, FPRoundingModeMultipleOpStoreGood) {
|
||||
@@ -4810,6 +4810,498 @@ TEST_F(ValidateDecorations, BlockAndBufferBlockDecorationsOnSameID) {
|
||||
"ID '2' decorated with both BufferBlock and Block is not allowed."));
|
||||
}
|
||||
|
||||
std::string MakeIntegerShader(
|
||||
const std::string& decoration, const std::string& inst,
|
||||
const std::string& extension =
|
||||
"OpExtension \"SPV_KHR_no_integer_wrap_decoration\"") {
|
||||
return R"(
|
||||
OpCapability Shader
|
||||
OpCapability Linkage
|
||||
)" + extension +
|
||||
R"(
|
||||
%glsl = OpExtInstImport "GLSL.std.450"
|
||||
%opencl = OpExtInstImport "OpenCL.std"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint GLCompute %main "main"
|
||||
OpName %entry "entry"
|
||||
)" + decoration +
|
||||
R"(
|
||||
%void = OpTypeVoid
|
||||
%voidfn = OpTypeFunction %void
|
||||
%int = OpTypeInt 32 1
|
||||
%zero = OpConstantNull %int
|
||||
%float = OpTypeFloat 32
|
||||
%float0 = OpConstantNull %float
|
||||
%main = OpFunction %void None %voidfn
|
||||
%entry = OpLabel
|
||||
)" + inst +
|
||||
R"(
|
||||
OpReturn
|
||||
OpFunctionEnd)";
|
||||
}
|
||||
|
||||
// NoSignedWrap
|
||||
|
||||
TEST_F(ValidateDecorations, NoSignedWrapOnTypeBad) {
|
||||
std::string spirv = MakeIntegerShader("OpDecorate %void NoSignedWrap", "");
|
||||
|
||||
CompileSuccessfully(spirv);
|
||||
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
|
||||
EXPECT_THAT(
|
||||
getDiagnosticString(),
|
||||
HasSubstr("NoSignedWrap decoration may not be applied to TypeVoid"));
|
||||
}
|
||||
|
||||
TEST_F(ValidateDecorations, NoSignedWrapOnLabelBad) {
|
||||
std::string spirv = MakeIntegerShader("OpDecorate %entry NoSignedWrap", "");
|
||||
|
||||
CompileSuccessfully(spirv);
|
||||
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
|
||||
EXPECT_THAT(getDiagnosticString(),
|
||||
HasSubstr("NoSignedWrap decoration may not be applied to Label"));
|
||||
}
|
||||
|
||||
TEST_F(ValidateDecorations, NoSignedWrapRequiresExtensionBad) {
|
||||
std::string spirv = MakeIntegerShader("OpDecorate %val NoSignedWrap",
|
||||
"%val = OpIAdd %int %zero %zero", "");
|
||||
|
||||
CompileSuccessfully(spirv);
|
||||
EXPECT_NE(SPV_SUCCESS, ValidateInstructions());
|
||||
EXPECT_THAT(getDiagnosticString(),
|
||||
HasSubstr("requires one of these extensions: "
|
||||
"SPV_KHR_no_integer_wrap_decoration"));
|
||||
}
|
||||
|
||||
TEST_F(ValidateDecorations, NoSignedWrapIAddGood) {
|
||||
std::string spirv = MakeIntegerShader("OpDecorate %val NoSignedWrap",
|
||||
"%val = OpIAdd %int %zero %zero");
|
||||
|
||||
CompileSuccessfully(spirv);
|
||||
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
|
||||
EXPECT_THAT(getDiagnosticString(), Eq(""));
|
||||
}
|
||||
|
||||
TEST_F(ValidateDecorations, NoSignedWrapISubGood) {
|
||||
std::string spirv = MakeIntegerShader("OpDecorate %val NoSignedWrap",
|
||||
"%val = OpISub %int %zero %zero");
|
||||
|
||||
CompileSuccessfully(spirv);
|
||||
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
|
||||
EXPECT_THAT(getDiagnosticString(), Eq(""));
|
||||
}
|
||||
|
||||
TEST_F(ValidateDecorations, NoSignedWrapIMulGood) {
|
||||
std::string spirv = MakeIntegerShader("OpDecorate %val NoSignedWrap",
|
||||
"%val = OpIMul %int %zero %zero");
|
||||
|
||||
CompileSuccessfully(spirv);
|
||||
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
|
||||
EXPECT_THAT(getDiagnosticString(), Eq(""));
|
||||
}
|
||||
|
||||
TEST_F(ValidateDecorations, NoSignedWrapShiftLeftLogicalGood) {
|
||||
std::string spirv =
|
||||
MakeIntegerShader("OpDecorate %val NoSignedWrap",
|
||||
"%val = OpShiftLeftLogical %int %zero %zero");
|
||||
|
||||
CompileSuccessfully(spirv);
|
||||
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
|
||||
EXPECT_THAT(getDiagnosticString(), Eq(""));
|
||||
}
|
||||
|
||||
TEST_F(ValidateDecorations, NoSignedWrapSNegateGood) {
|
||||
std::string spirv = MakeIntegerShader("OpDecorate %val NoSignedWrap",
|
||||
"%val = OpSNegate %int %zero");
|
||||
|
||||
CompileSuccessfully(spirv);
|
||||
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
|
||||
EXPECT_THAT(getDiagnosticString(), Eq(""));
|
||||
}
|
||||
|
||||
TEST_F(ValidateDecorations, NoSignedWrapSRemBad) {
|
||||
std::string spirv = MakeIntegerShader("OpDecorate %val NoSignedWrap",
|
||||
"%val = OpSRem %int %zero %zero");
|
||||
|
||||
CompileSuccessfully(spirv);
|
||||
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
|
||||
EXPECT_THAT(getDiagnosticString(),
|
||||
HasSubstr("NoSignedWrap decoration may not be applied to SRem"));
|
||||
}
|
||||
|
||||
TEST_F(ValidateDecorations, NoSignedWrapFAddBad) {
|
||||
std::string spirv = MakeIntegerShader("OpDecorate %val NoSignedWrap",
|
||||
"%val = OpFAdd %float %float0 %float0");
|
||||
|
||||
CompileSuccessfully(spirv);
|
||||
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
|
||||
EXPECT_THAT(getDiagnosticString(),
|
||||
HasSubstr("NoSignedWrap decoration may not be applied to FAdd"));
|
||||
}
|
||||
|
||||
TEST_F(ValidateDecorations, NoSignedWrapExtInstOpenCLGood) {
|
||||
std::string spirv =
|
||||
MakeIntegerShader("OpDecorate %val NoSignedWrap",
|
||||
"%val = OpExtInst %int %opencl s_abs %zero");
|
||||
|
||||
CompileSuccessfully(spirv);
|
||||
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
|
||||
EXPECT_THAT(getDiagnosticString(), Eq(""));
|
||||
}
|
||||
|
||||
TEST_F(ValidateDecorations, NoSignedWrapExtInstGLSLGood) {
|
||||
std::string spirv = MakeIntegerShader(
|
||||
"OpDecorate %val NoSignedWrap", "%val = OpExtInst %int %glsl SAbs %zero");
|
||||
|
||||
CompileSuccessfully(spirv);
|
||||
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
|
||||
EXPECT_THAT(getDiagnosticString(), Eq(""));
|
||||
}
|
||||
|
||||
// TODO(dneto): For NoSignedWrap and NoUnsignedWrap, permit
|
||||
// "OpExtInst for instruction numbers specified in the extended
|
||||
// instruction-set specifications as accepting this decoration."
|
||||
|
||||
// NoUnignedWrap
|
||||
|
||||
TEST_F(ValidateDecorations, NoUnsignedWrapOnTypeBad) {
|
||||
std::string spirv = MakeIntegerShader("OpDecorate %void NoUnsignedWrap", "");
|
||||
|
||||
CompileSuccessfully(spirv);
|
||||
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
|
||||
EXPECT_THAT(
|
||||
getDiagnosticString(),
|
||||
HasSubstr("NoUnsignedWrap decoration may not be applied to TypeVoid"));
|
||||
}
|
||||
|
||||
TEST_F(ValidateDecorations, NoUnsignedWrapOnLabelBad) {
|
||||
std::string spirv = MakeIntegerShader("OpDecorate %entry NoUnsignedWrap", "");
|
||||
|
||||
CompileSuccessfully(spirv);
|
||||
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
|
||||
EXPECT_THAT(
|
||||
getDiagnosticString(),
|
||||
HasSubstr("NoUnsignedWrap decoration may not be applied to Label"));
|
||||
}
|
||||
|
||||
TEST_F(ValidateDecorations, NoUnsignedWrapRequiresExtensionBad) {
|
||||
std::string spirv = MakeIntegerShader("OpDecorate %val NoUnsignedWrap",
|
||||
"%val = OpIAdd %int %zero %zero", "");
|
||||
|
||||
CompileSuccessfully(spirv);
|
||||
EXPECT_NE(SPV_SUCCESS, ValidateInstructions());
|
||||
EXPECT_THAT(getDiagnosticString(),
|
||||
HasSubstr("requires one of these extensions: "
|
||||
"SPV_KHR_no_integer_wrap_decoration"));
|
||||
}
|
||||
|
||||
TEST_F(ValidateDecorations, NoUnsignedWrapIAddGood) {
|
||||
std::string spirv = MakeIntegerShader("OpDecorate %val NoUnsignedWrap",
|
||||
"%val = OpIAdd %int %zero %zero");
|
||||
|
||||
CompileSuccessfully(spirv);
|
||||
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
|
||||
EXPECT_THAT(getDiagnosticString(), Eq(""));
|
||||
}
|
||||
|
||||
TEST_F(ValidateDecorations, NoUnsignedWrapISubGood) {
|
||||
std::string spirv = MakeIntegerShader("OpDecorate %val NoUnsignedWrap",
|
||||
"%val = OpISub %int %zero %zero");
|
||||
|
||||
CompileSuccessfully(spirv);
|
||||
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
|
||||
EXPECT_THAT(getDiagnosticString(), Eq(""));
|
||||
}
|
||||
|
||||
TEST_F(ValidateDecorations, NoUnsignedWrapIMulGood) {
|
||||
std::string spirv = MakeIntegerShader("OpDecorate %val NoUnsignedWrap",
|
||||
"%val = OpIMul %int %zero %zero");
|
||||
|
||||
CompileSuccessfully(spirv);
|
||||
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
|
||||
EXPECT_THAT(getDiagnosticString(), Eq(""));
|
||||
}
|
||||
|
||||
TEST_F(ValidateDecorations, NoUnsignedWrapShiftLeftLogicalGood) {
|
||||
std::string spirv =
|
||||
MakeIntegerShader("OpDecorate %val NoUnsignedWrap",
|
||||
"%val = OpShiftLeftLogical %int %zero %zero");
|
||||
|
||||
CompileSuccessfully(spirv);
|
||||
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
|
||||
EXPECT_THAT(getDiagnosticString(), Eq(""));
|
||||
}
|
||||
|
||||
TEST_F(ValidateDecorations, NoUnsignedWrapSNegateGood) {
|
||||
std::string spirv = MakeIntegerShader("OpDecorate %val NoUnsignedWrap",
|
||||
"%val = OpSNegate %int %zero");
|
||||
|
||||
CompileSuccessfully(spirv);
|
||||
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
|
||||
EXPECT_THAT(getDiagnosticString(), Eq(""));
|
||||
}
|
||||
|
||||
TEST_F(ValidateDecorations, NoUnsignedWrapSRemBad) {
|
||||
std::string spirv = MakeIntegerShader("OpDecorate %val NoUnsignedWrap",
|
||||
"%val = OpSRem %int %zero %zero");
|
||||
|
||||
CompileSuccessfully(spirv);
|
||||
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
|
||||
EXPECT_THAT(
|
||||
getDiagnosticString(),
|
||||
HasSubstr("NoUnsignedWrap decoration may not be applied to SRem"));
|
||||
}
|
||||
|
||||
TEST_F(ValidateDecorations, NoUnsignedWrapFAddBad) {
|
||||
std::string spirv = MakeIntegerShader("OpDecorate %val NoUnsignedWrap",
|
||||
"%val = OpFAdd %float %float0 %float0");
|
||||
|
||||
CompileSuccessfully(spirv);
|
||||
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
|
||||
EXPECT_THAT(
|
||||
getDiagnosticString(),
|
||||
HasSubstr("NoUnsignedWrap decoration may not be applied to FAdd"));
|
||||
}
|
||||
|
||||
TEST_F(ValidateDecorations, NoUnsignedWrapExtInstOpenCLGood) {
|
||||
std::string spirv =
|
||||
MakeIntegerShader("OpDecorate %val NoUnsignedWrap",
|
||||
"%val = OpExtInst %int %opencl s_abs %zero");
|
||||
|
||||
CompileSuccessfully(spirv);
|
||||
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
|
||||
EXPECT_THAT(getDiagnosticString(), Eq(""));
|
||||
}
|
||||
|
||||
TEST_F(ValidateDecorations, NoUnsignedWrapExtInstGLSLGood) {
|
||||
std::string spirv =
|
||||
MakeIntegerShader("OpDecorate %val NoUnsignedWrap",
|
||||
"%val = OpExtInst %int %glsl SAbs %zero");
|
||||
|
||||
CompileSuccessfully(spirv);
|
||||
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
|
||||
EXPECT_THAT(getDiagnosticString(), Eq(""));
|
||||
}
|
||||
|
||||
// TODO(dneto): For NoUnsignedWrap and NoUnsignedWrap, permit
|
||||
// "OpExtInst for instruction numbers specified in the extended
|
||||
// instruction-set specifications as accepting this decoration."
|
||||
|
||||
TEST_F(ValidateDecorations, PSBAliasedRestrictPointerSuccess) {
|
||||
const std::string body = R"(
|
||||
OpCapability PhysicalStorageBufferAddressesEXT
|
||||
OpCapability Int64
|
||||
OpCapability Shader
|
||||
OpExtension "SPV_EXT_physical_storage_buffer"
|
||||
OpMemoryModel PhysicalStorageBuffer64EXT GLSL450
|
||||
OpEntryPoint Fragment %main "main"
|
||||
OpExecutionMode %main OriginUpperLeft
|
||||
OpDecorate %val1 RestrictPointerEXT
|
||||
%uint64 = OpTypeInt 64 0
|
||||
%ptr = OpTypePointer PhysicalStorageBufferEXT %uint64
|
||||
%pptr_f = OpTypePointer Function %ptr
|
||||
%void = OpTypeVoid
|
||||
%voidfn = OpTypeFunction %void
|
||||
%main = OpFunction %void None %voidfn
|
||||
%entry = OpLabel
|
||||
%val1 = OpVariable %pptr_f Function
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
CompileSuccessfully(body.c_str());
|
||||
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
|
||||
}
|
||||
|
||||
TEST_F(ValidateDecorations, PSBAliasedRestrictPointerMissing) {
|
||||
const std::string body = R"(
|
||||
OpCapability PhysicalStorageBufferAddressesEXT
|
||||
OpCapability Int64
|
||||
OpCapability Shader
|
||||
OpExtension "SPV_EXT_physical_storage_buffer"
|
||||
OpMemoryModel PhysicalStorageBuffer64EXT GLSL450
|
||||
OpEntryPoint Fragment %main "main"
|
||||
OpExecutionMode %main OriginUpperLeft
|
||||
%uint64 = OpTypeInt 64 0
|
||||
%ptr = OpTypePointer PhysicalStorageBufferEXT %uint64
|
||||
%pptr_f = OpTypePointer Function %ptr
|
||||
%void = OpTypeVoid
|
||||
%voidfn = OpTypeFunction %void
|
||||
%main = OpFunction %void None %voidfn
|
||||
%entry = OpLabel
|
||||
%val1 = OpVariable %pptr_f Function
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
CompileSuccessfully(body.c_str());
|
||||
ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
|
||||
EXPECT_THAT(getDiagnosticString(),
|
||||
HasSubstr("expected AliasedPointerEXT or RestrictPointerEXT for "
|
||||
"PhysicalStorageBufferEXT pointer"));
|
||||
}
|
||||
|
||||
TEST_F(ValidateDecorations, PSBAliasedRestrictPointerBoth) {
|
||||
const std::string body = R"(
|
||||
OpCapability PhysicalStorageBufferAddressesEXT
|
||||
OpCapability Int64
|
||||
OpCapability Shader
|
||||
OpExtension "SPV_EXT_physical_storage_buffer"
|
||||
OpMemoryModel PhysicalStorageBuffer64EXT GLSL450
|
||||
OpEntryPoint Fragment %main "main"
|
||||
OpExecutionMode %main OriginUpperLeft
|
||||
OpDecorate %val1 RestrictPointerEXT
|
||||
OpDecorate %val1 AliasedPointerEXT
|
||||
%uint64 = OpTypeInt 64 0
|
||||
%ptr = OpTypePointer PhysicalStorageBufferEXT %uint64
|
||||
%pptr_f = OpTypePointer Function %ptr
|
||||
%void = OpTypeVoid
|
||||
%voidfn = OpTypeFunction %void
|
||||
%main = OpFunction %void None %voidfn
|
||||
%entry = OpLabel
|
||||
%val1 = OpVariable %pptr_f Function
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
CompileSuccessfully(body.c_str());
|
||||
ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
|
||||
EXPECT_THAT(
|
||||
getDiagnosticString(),
|
||||
HasSubstr("can't specify both AliasedPointerEXT and RestrictPointerEXT "
|
||||
"for PhysicalStorageBufferEXT pointer"));
|
||||
}
|
||||
|
||||
TEST_F(ValidateDecorations, PSBAliasedRestrictFunctionParamSuccess) {
|
||||
const std::string body = R"(
|
||||
OpCapability PhysicalStorageBufferAddressesEXT
|
||||
OpCapability Int64
|
||||
OpCapability Shader
|
||||
OpExtension "SPV_EXT_physical_storage_buffer"
|
||||
OpMemoryModel PhysicalStorageBuffer64EXT GLSL450
|
||||
OpEntryPoint Fragment %main "main"
|
||||
OpExecutionMode %main OriginUpperLeft
|
||||
OpDecorate %fparam Restrict
|
||||
%uint64 = OpTypeInt 64 0
|
||||
%ptr = OpTypePointer PhysicalStorageBufferEXT %uint64
|
||||
%void = OpTypeVoid
|
||||
%voidfn = OpTypeFunction %void
|
||||
%fnptr = OpTypeFunction %void %ptr
|
||||
%main = OpFunction %void None %voidfn
|
||||
%entry = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
%fn = OpFunction %void None %fnptr
|
||||
%fparam = OpFunctionParameter %ptr
|
||||
%lab = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
CompileSuccessfully(body.c_str());
|
||||
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
|
||||
}
|
||||
|
||||
TEST_F(ValidateDecorations, PSBAliasedRestrictFunctionParamMissing) {
|
||||
const std::string body = R"(
|
||||
OpCapability PhysicalStorageBufferAddressesEXT
|
||||
OpCapability Int64
|
||||
OpCapability Shader
|
||||
OpExtension "SPV_EXT_physical_storage_buffer"
|
||||
OpMemoryModel PhysicalStorageBuffer64EXT GLSL450
|
||||
OpEntryPoint Fragment %main "main"
|
||||
OpExecutionMode %main OriginUpperLeft
|
||||
%uint64 = OpTypeInt 64 0
|
||||
%ptr = OpTypePointer PhysicalStorageBufferEXT %uint64
|
||||
%void = OpTypeVoid
|
||||
%voidfn = OpTypeFunction %void
|
||||
%fnptr = OpTypeFunction %void %ptr
|
||||
%main = OpFunction %void None %voidfn
|
||||
%entry = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
%fn = OpFunction %void None %fnptr
|
||||
%fparam = OpFunctionParameter %ptr
|
||||
%lab = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
CompileSuccessfully(body.c_str());
|
||||
ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
|
||||
EXPECT_THAT(getDiagnosticString(),
|
||||
HasSubstr("expected Aliased or Restrict for "
|
||||
"PhysicalStorageBufferEXT pointer"));
|
||||
}
|
||||
|
||||
TEST_F(ValidateDecorations, PSBAliasedRestrictFunctionParamBoth) {
|
||||
const std::string body = R"(
|
||||
OpCapability PhysicalStorageBufferAddressesEXT
|
||||
OpCapability Int64
|
||||
OpCapability Shader
|
||||
OpExtension "SPV_EXT_physical_storage_buffer"
|
||||
OpMemoryModel PhysicalStorageBuffer64EXT GLSL450
|
||||
OpEntryPoint Fragment %main "main"
|
||||
OpExecutionMode %main OriginUpperLeft
|
||||
OpDecorate %fparam Restrict
|
||||
OpDecorate %fparam Aliased
|
||||
%uint64 = OpTypeInt 64 0
|
||||
%ptr = OpTypePointer PhysicalStorageBufferEXT %uint64
|
||||
%void = OpTypeVoid
|
||||
%voidfn = OpTypeFunction %void
|
||||
%fnptr = OpTypeFunction %void %ptr
|
||||
%main = OpFunction %void None %voidfn
|
||||
%entry = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
%fn = OpFunction %void None %fnptr
|
||||
%fparam = OpFunctionParameter %ptr
|
||||
%lab = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
CompileSuccessfully(body.c_str());
|
||||
ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
|
||||
EXPECT_THAT(getDiagnosticString(),
|
||||
HasSubstr("can't specify both Aliased and Restrict for "
|
||||
"PhysicalStorageBufferEXT pointer"));
|
||||
}
|
||||
|
||||
TEST_F(ValidateDecorations, PSBFPRoundingModeSuccess) {
|
||||
std::string spirv = R"(
|
||||
OpCapability PhysicalStorageBufferAddressesEXT
|
||||
OpCapability Shader
|
||||
OpCapability Linkage
|
||||
OpCapability StorageBuffer16BitAccess
|
||||
OpExtension "SPV_EXT_physical_storage_buffer"
|
||||
OpExtension "SPV_KHR_storage_buffer_storage_class"
|
||||
OpExtension "SPV_KHR_variable_pointers"
|
||||
OpExtension "SPV_KHR_16bit_storage"
|
||||
OpMemoryModel PhysicalStorageBuffer64EXT GLSL450
|
||||
OpEntryPoint GLCompute %main "main"
|
||||
OpDecorate %_ FPRoundingMode RTE
|
||||
OpDecorate %half_ptr_var AliasedPointerEXT
|
||||
%half = OpTypeFloat 16
|
||||
%float = OpTypeFloat 32
|
||||
%float_1_25 = OpConstant %float 1.25
|
||||
%half_ptr = OpTypePointer PhysicalStorageBufferEXT %half
|
||||
%half_pptr_f = OpTypePointer Function %half_ptr
|
||||
%void = OpTypeVoid
|
||||
%func = OpTypeFunction %void
|
||||
%main = OpFunction %void None %func
|
||||
%main_entry = OpLabel
|
||||
%half_ptr_var = OpVariable %half_pptr_f Function
|
||||
%val1 = OpLoad %half_ptr %half_ptr_var
|
||||
%_ = OpFConvert %half %float_1_25
|
||||
OpStore %val1 %_ Aligned 2
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
CompileSuccessfully(spirv);
|
||||
EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState());
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace val
|
||||
} // namespace spvtools
|
||||
|
||||
22
3rdparty/spirv-tools/test/val/val_fixtures.h
vendored
22
3rdparty/spirv-tools/test/val/val_fixtures.h
vendored
@@ -56,6 +56,18 @@ class ValidateBase : public ::testing::Test,
|
||||
spv_result_t ValidateAndRetrieveValidationState(
|
||||
spv_target_env env = SPV_ENV_UNIVERSAL_1_0);
|
||||
|
||||
// Destroys the stored binary.
|
||||
void DestroyBinary() {
|
||||
spvBinaryDestroy(binary_);
|
||||
binary_ = nullptr;
|
||||
}
|
||||
|
||||
// Destroys the stored diagnostic.
|
||||
void DestroyDiagnostic() {
|
||||
spvDiagnosticDestroy(diagnostic_);
|
||||
diagnostic_ = nullptr;
|
||||
}
|
||||
|
||||
std::string getDiagnosticString();
|
||||
spv_position_t getErrorPosition();
|
||||
spv_validator_options getValidatorOptions();
|
||||
@@ -67,7 +79,7 @@ class ValidateBase : public ::testing::Test,
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
ValidateBase<T>::ValidateBase() : binary_(), diagnostic_() {
|
||||
ValidateBase<T>::ValidateBase() : binary_(nullptr), diagnostic_(nullptr) {
|
||||
// Initialize to default command line options. Different tests can then
|
||||
// specialize specific options as necessary.
|
||||
options_ = spvValidatorOptionsCreate();
|
||||
@@ -83,14 +95,15 @@ void ValidateBase<T>::TearDown() {
|
||||
if (diagnostic_) {
|
||||
spvDiagnosticPrint(diagnostic_);
|
||||
}
|
||||
spvDiagnosticDestroy(diagnostic_);
|
||||
spvBinaryDestroy(binary_);
|
||||
DestroyBinary();
|
||||
DestroyDiagnostic();
|
||||
spvValidatorOptionsDestroy(options_);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void ValidateBase<T>::CompileSuccessfully(std::string code,
|
||||
spv_target_env env) {
|
||||
DestroyBinary();
|
||||
spv_diagnostic diagnostic = nullptr;
|
||||
ASSERT_EQ(SPV_SUCCESS,
|
||||
spvTextToBinary(ScopedContext(env).context, code.c_str(),
|
||||
@@ -98,6 +111,7 @@ void ValidateBase<T>::CompileSuccessfully(std::string code,
|
||||
<< "ERROR: " << diagnostic->error
|
||||
<< "\nSPIR-V could not be compiled into binary:\n"
|
||||
<< code;
|
||||
spvDiagnosticDestroy(diagnostic);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
@@ -110,6 +124,7 @@ void ValidateBase<T>::OverwriteAssembledBinary(uint32_t index, uint32_t word) {
|
||||
|
||||
template <typename T>
|
||||
spv_result_t ValidateBase<T>::ValidateInstructions(spv_target_env env) {
|
||||
DestroyDiagnostic();
|
||||
return spvValidateWithOptions(ScopedContext(env).context, options_,
|
||||
get_const_binary(), &diagnostic_);
|
||||
}
|
||||
@@ -117,6 +132,7 @@ spv_result_t ValidateBase<T>::ValidateInstructions(spv_target_env env) {
|
||||
template <typename T>
|
||||
spv_result_t ValidateBase<T>::ValidateAndRetrieveValidationState(
|
||||
spv_target_env env) {
|
||||
DestroyDiagnostic();
|
||||
return spvtools::val::ValidateBinaryAndKeepValidationState(
|
||||
ScopedContext(env).context, options_, get_const_binary()->code,
|
||||
get_const_binary()->wordCount, &diagnostic_, &vstate_);
|
||||
|
||||
@@ -780,6 +780,8 @@ class OpTypeArrayLengthTest
|
||||
// Runs spvValidate() on v, printing any errors via spvDiagnosticPrint().
|
||||
spv_result_t Val(const SpirvVector& v, const std::string& expected_err = "") {
|
||||
spv_const_binary_t cbinary{v.data(), v.size()};
|
||||
spvDiagnosticDestroy(diagnostic_);
|
||||
diagnostic_ = nullptr;
|
||||
const auto status =
|
||||
spvValidate(ScopedContext().context, &cbinary, &diagnostic_);
|
||||
if (status != SPV_SUCCESS) {
|
||||
|
||||
@@ -919,6 +919,36 @@ TEST_F(ValidateLogicals, OpSGreaterThanDifferentBitWidth) {
|
||||
"width: SGreaterThan"));
|
||||
}
|
||||
|
||||
TEST_F(ValidateLogicals, PSBSelectSuccess) {
|
||||
const std::string body = R"(
|
||||
OpCapability PhysicalStorageBufferAddressesEXT
|
||||
OpCapability Int64
|
||||
OpCapability Shader
|
||||
OpExtension "SPV_EXT_physical_storage_buffer"
|
||||
OpMemoryModel PhysicalStorageBuffer64EXT GLSL450
|
||||
OpEntryPoint Fragment %main "main"
|
||||
OpExecutionMode %main OriginUpperLeft
|
||||
OpDecorate %val1 AliasedPointerEXT
|
||||
%uint64 = OpTypeInt 64 0
|
||||
%bool = OpTypeBool
|
||||
%true = OpConstantTrue %bool
|
||||
%ptr = OpTypePointer PhysicalStorageBufferEXT %uint64
|
||||
%pptr_f = OpTypePointer Function %ptr
|
||||
%void = OpTypeVoid
|
||||
%voidfn = OpTypeFunction %void
|
||||
%main = OpFunction %void None %voidfn
|
||||
%entry = OpLabel
|
||||
%val1 = OpVariable %pptr_f Function
|
||||
%val2 = OpLoad %ptr %val1
|
||||
%val3 = OpSelect %ptr %true %val2 %val2
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
CompileSuccessfully(body.c_str());
|
||||
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace val
|
||||
} // namespace spvtools
|
||||
|
||||
815
3rdparty/spirv-tools/test/val/val_memory_test.cpp
vendored
815
3rdparty/spirv-tools/test/val/val_memory_test.cpp
vendored
@@ -138,7 +138,9 @@ OpFunctionEnd
|
||||
|
||||
TEST_F(ValidateMemory, VulkanUniformConstantOnOpaqueResourceRuntimeArrayGood) {
|
||||
std::string spirv = R"(
|
||||
OpCapability RuntimeDescriptorArrayEXT
|
||||
OpCapability Shader
|
||||
OpExtension "SPV_EXT_descriptor_indexing"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %func "func"
|
||||
OpExecutionMode %func OriginUpperLeft
|
||||
@@ -455,6 +457,93 @@ OpFunctionEnd
|
||||
" %5 = OpVariable %_ptr_Uniform_float Uniform %float_1\n"));
|
||||
}
|
||||
|
||||
TEST_F(ValidateMemory, WebGPUOutputStorageClassWithoutInitializerBad) {
|
||||
std::string spirv = R"(
|
||||
OpCapability Shader
|
||||
OpCapability VulkanMemoryModelKHR
|
||||
OpExtension "SPV_KHR_vulkan_memory_model"
|
||||
OpMemoryModel Logical VulkanKHR
|
||||
OpEntryPoint Fragment %func "func"
|
||||
OpExecutionMode %func OriginUpperLeft
|
||||
%float = OpTypeFloat 32
|
||||
%float_ptr = OpTypePointer Output %float
|
||||
%1 = OpVariable %float_ptr Output
|
||||
%void = OpTypeVoid
|
||||
%functy = OpTypeFunction %void
|
||||
%func = OpFunction %void None %functy
|
||||
%2 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
CompileSuccessfully(spirv.c_str(), SPV_ENV_WEBGPU_0);
|
||||
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_WEBGPU_0));
|
||||
EXPECT_THAT(
|
||||
getDiagnosticString(),
|
||||
HasSubstr("OpVariable, <id> '4[%4]', must have an initializer.\n"
|
||||
"From WebGPU execution environment spec:\n"
|
||||
"All variables in the following storage classes must have an "
|
||||
"initializer: Output, Private, or Function\n"
|
||||
" %4 = OpVariable %_ptr_Output_float Output\n"));
|
||||
}
|
||||
|
||||
TEST_F(ValidateMemory, WebGPUFunctionStorageClassWithoutInitializerBad) {
|
||||
std::string spirv = R"(
|
||||
OpCapability Shader
|
||||
OpCapability VulkanMemoryModelKHR
|
||||
OpExtension "SPV_KHR_vulkan_memory_model"
|
||||
OpMemoryModel Logical VulkanKHR
|
||||
OpEntryPoint Fragment %func "func"
|
||||
OpExecutionMode %func OriginUpperLeft
|
||||
%float = OpTypeFloat 32
|
||||
%float_ptr = OpTypePointer Function %float
|
||||
%void = OpTypeVoid
|
||||
%functy = OpTypeFunction %void
|
||||
%func = OpFunction %void None %functy
|
||||
%1 = OpLabel
|
||||
%2 = OpVariable %float_ptr Function
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
CompileSuccessfully(spirv.c_str(), SPV_ENV_WEBGPU_0);
|
||||
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_WEBGPU_0));
|
||||
EXPECT_THAT(
|
||||
getDiagnosticString(),
|
||||
HasSubstr("OpVariable, <id> '7[%7]', must have an initializer.\n"
|
||||
"From WebGPU execution environment spec:\n"
|
||||
"All variables in the following storage classes must have an "
|
||||
"initializer: Output, Private, or Function\n"
|
||||
" %7 = OpVariable %_ptr_Function_float Function\n"));
|
||||
}
|
||||
|
||||
TEST_F(ValidateMemory, WebGPUPrivateStorageClassWithoutInitializerBad) {
|
||||
std::string spirv = R"(
|
||||
OpCapability Shader
|
||||
OpCapability VulkanMemoryModelKHR
|
||||
OpExtension "SPV_KHR_vulkan_memory_model"
|
||||
OpMemoryModel Logical VulkanKHR
|
||||
OpEntryPoint Fragment %func "func"
|
||||
OpExecutionMode %func OriginUpperLeft
|
||||
%float = OpTypeFloat 32
|
||||
%float_ptr = OpTypePointer Private %float
|
||||
%1 = OpVariable %float_ptr Private
|
||||
%void = OpTypeVoid
|
||||
%functy = OpTypeFunction %void
|
||||
%func = OpFunction %void None %functy
|
||||
%2 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
CompileSuccessfully(spirv.c_str(), SPV_ENV_WEBGPU_0);
|
||||
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_WEBGPU_0));
|
||||
EXPECT_THAT(
|
||||
getDiagnosticString(),
|
||||
HasSubstr("OpVariable, <id> '4[%4]', must have an initializer.\n"
|
||||
"From WebGPU execution environment spec:\n"
|
||||
"All variables in the following storage classes must have an "
|
||||
"initializer: Output, Private, or Function\n"
|
||||
" %4 = OpVariable %_ptr_Private_float Private\n"));
|
||||
}
|
||||
|
||||
TEST_F(ValidateMemory, VulkanInitializerWithOutputStorageClassesGood) {
|
||||
std::string spirv = R"(
|
||||
OpCapability Shader
|
||||
@@ -1537,6 +1626,732 @@ OpFunctionEnd
|
||||
HasSubstr("Operand 1[%incorrect] requires a type"));
|
||||
}
|
||||
|
||||
TEST_F(ValidateMemory, PSBLoadAlignedSuccess) {
|
||||
const std::string body = R"(
|
||||
OpCapability PhysicalStorageBufferAddressesEXT
|
||||
OpCapability Int64
|
||||
OpCapability Shader
|
||||
OpExtension "SPV_EXT_physical_storage_buffer"
|
||||
OpMemoryModel PhysicalStorageBuffer64EXT GLSL450
|
||||
OpEntryPoint Fragment %main "main"
|
||||
OpExecutionMode %main OriginUpperLeft
|
||||
OpDecorate %val1 AliasedPointerEXT
|
||||
%uint64 = OpTypeInt 64 0
|
||||
%ptr = OpTypePointer PhysicalStorageBufferEXT %uint64
|
||||
%pptr_f = OpTypePointer Function %ptr
|
||||
%void = OpTypeVoid
|
||||
%voidfn = OpTypeFunction %void
|
||||
%main = OpFunction %void None %voidfn
|
||||
%entry = OpLabel
|
||||
%val1 = OpVariable %pptr_f Function
|
||||
%val2 = OpLoad %ptr %val1
|
||||
%val3 = OpLoad %uint64 %val2 Aligned 8
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
CompileSuccessfully(body.c_str());
|
||||
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
|
||||
}
|
||||
|
||||
TEST_F(ValidateMemory, PSBLoadAlignedMissing) {
|
||||
const std::string body = R"(
|
||||
OpCapability PhysicalStorageBufferAddressesEXT
|
||||
OpCapability Int64
|
||||
OpCapability Shader
|
||||
OpExtension "SPV_EXT_physical_storage_buffer"
|
||||
OpMemoryModel PhysicalStorageBuffer64EXT GLSL450
|
||||
OpEntryPoint Fragment %main "main"
|
||||
OpExecutionMode %main OriginUpperLeft
|
||||
OpDecorate %val1 AliasedPointerEXT
|
||||
%uint64 = OpTypeInt 64 0
|
||||
%ptr = OpTypePointer PhysicalStorageBufferEXT %uint64
|
||||
%pptr_f = OpTypePointer Function %ptr
|
||||
%void = OpTypeVoid
|
||||
%voidfn = OpTypeFunction %void
|
||||
%main = OpFunction %void None %voidfn
|
||||
%entry = OpLabel
|
||||
%val1 = OpVariable %pptr_f Function
|
||||
%val2 = OpLoad %ptr %val1
|
||||
%val3 = OpLoad %uint64 %val2
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
CompileSuccessfully(body.c_str());
|
||||
ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
|
||||
EXPECT_THAT(
|
||||
getDiagnosticString(),
|
||||
HasSubstr(
|
||||
"Memory accesses with PhysicalStorageBufferEXT must use Aligned"));
|
||||
}
|
||||
|
||||
TEST_F(ValidateMemory, PSBStoreAlignedSuccess) {
|
||||
const std::string body = R"(
|
||||
OpCapability PhysicalStorageBufferAddressesEXT
|
||||
OpCapability Int64
|
||||
OpCapability Shader
|
||||
OpExtension "SPV_EXT_physical_storage_buffer"
|
||||
OpMemoryModel PhysicalStorageBuffer64EXT GLSL450
|
||||
OpEntryPoint Fragment %main "main"
|
||||
OpExecutionMode %main OriginUpperLeft
|
||||
OpDecorate %val1 AliasedPointerEXT
|
||||
%uint64 = OpTypeInt 64 0
|
||||
%u64_1 = OpConstant %uint64 1
|
||||
%ptr = OpTypePointer PhysicalStorageBufferEXT %uint64
|
||||
%pptr_f = OpTypePointer Function %ptr
|
||||
%void = OpTypeVoid
|
||||
%voidfn = OpTypeFunction %void
|
||||
%main = OpFunction %void None %voidfn
|
||||
%entry = OpLabel
|
||||
%val1 = OpVariable %pptr_f Function
|
||||
%val2 = OpLoad %ptr %val1
|
||||
OpStore %val2 %u64_1 Aligned 8
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
CompileSuccessfully(body.c_str());
|
||||
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
|
||||
}
|
||||
|
||||
TEST_F(ValidateMemory, PSBStoreAlignedMissing) {
|
||||
const std::string body = R"(
|
||||
OpCapability PhysicalStorageBufferAddressesEXT
|
||||
OpCapability Int64
|
||||
OpCapability Shader
|
||||
OpExtension "SPV_EXT_physical_storage_buffer"
|
||||
OpMemoryModel PhysicalStorageBuffer64EXT GLSL450
|
||||
OpEntryPoint Fragment %main "main"
|
||||
OpExecutionMode %main OriginUpperLeft
|
||||
OpDecorate %val1 AliasedPointerEXT
|
||||
%uint64 = OpTypeInt 64 0
|
||||
%u64_1 = OpConstant %uint64 1
|
||||
%ptr = OpTypePointer PhysicalStorageBufferEXT %uint64
|
||||
%pptr_f = OpTypePointer Function %ptr
|
||||
%void = OpTypeVoid
|
||||
%voidfn = OpTypeFunction %void
|
||||
%main = OpFunction %void None %voidfn
|
||||
%entry = OpLabel
|
||||
%val1 = OpVariable %pptr_f Function
|
||||
%val2 = OpLoad %ptr %val1
|
||||
OpStore %val2 %u64_1 None
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
CompileSuccessfully(body.c_str());
|
||||
ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
|
||||
EXPECT_THAT(
|
||||
getDiagnosticString(),
|
||||
HasSubstr(
|
||||
"Memory accesses with PhysicalStorageBufferEXT must use Aligned"));
|
||||
}
|
||||
|
||||
TEST_F(ValidateMemory, PSBVariable) {
|
||||
const std::string body = R"(
|
||||
OpCapability PhysicalStorageBufferAddressesEXT
|
||||
OpCapability Int64
|
||||
OpCapability Shader
|
||||
OpExtension "SPV_EXT_physical_storage_buffer"
|
||||
OpMemoryModel PhysicalStorageBuffer64EXT GLSL450
|
||||
OpEntryPoint Fragment %main "main"
|
||||
OpExecutionMode %main OriginUpperLeft
|
||||
OpDecorate %val1 AliasedPointerEXT
|
||||
%uint64 = OpTypeInt 64 0
|
||||
%ptr = OpTypePointer PhysicalStorageBufferEXT %uint64
|
||||
%val1 = OpVariable %ptr PhysicalStorageBufferEXT
|
||||
%void = OpTypeVoid
|
||||
%voidfn = OpTypeFunction %void
|
||||
%main = OpFunction %void None %voidfn
|
||||
%entry = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
CompileSuccessfully(body.c_str());
|
||||
ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
|
||||
EXPECT_THAT(
|
||||
getDiagnosticString(),
|
||||
HasSubstr("PhysicalStorageBufferEXT must not be used with OpVariable"));
|
||||
}
|
||||
|
||||
TEST_F(ValidateMemory, VulkanRTAOutsideOfStructBad) {
|
||||
std::string spirv = R"(
|
||||
OpCapability Shader
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %func "func"
|
||||
OpExecutionMode %func OriginUpperLeft
|
||||
%sampler_t = OpTypeSampler
|
||||
%array_t = OpTypeRuntimeArray %sampler_t
|
||||
%array_ptr = OpTypePointer UniformConstant %array_t
|
||||
%2 = OpVariable %array_ptr UniformConstant
|
||||
%void = OpTypeVoid
|
||||
%func_t = OpTypeFunction %void
|
||||
%func = OpFunction %void None %func_t
|
||||
%1 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1);
|
||||
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1));
|
||||
EXPECT_THAT(
|
||||
getDiagnosticString(),
|
||||
HasSubstr(
|
||||
"OpVariable, <id> '5[%5]', is attempting to create memory for an "
|
||||
"illegal type, OpTypeRuntimeArray.\nFor Vulkan OpTypeRuntimeArray "
|
||||
"can only appear as the final member of an OpTypeStruct, thus cannot "
|
||||
"be instantiated via OpVariable\n %5 = OpVariable "
|
||||
"%_ptr_UniformConstant__runtimearr_2 UniformConstant\n"));
|
||||
}
|
||||
|
||||
TEST_F(ValidateMemory, VulkanRTAOutsideOfStructWithRuntimeDescriptorArrayGood) {
|
||||
std::string spirv = R"(
|
||||
OpCapability Shader
|
||||
OpCapability RuntimeDescriptorArrayEXT
|
||||
OpExtension "SPV_EXT_descriptor_indexing"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %func "func"
|
||||
OpExecutionMode %func OriginUpperLeft
|
||||
%sampler_t = OpTypeSampler
|
||||
%array_t = OpTypeRuntimeArray %sampler_t
|
||||
%array_sb_ptr = OpTypePointer StorageBuffer %array_t
|
||||
%2 = OpVariable %array_sb_ptr StorageBuffer
|
||||
%array_uc_ptr = OpTypePointer UniformConstant %array_t
|
||||
%3 = OpVariable %array_uc_ptr UniformConstant
|
||||
%void = OpTypeVoid
|
||||
%func_t = OpTypeFunction %void
|
||||
%func = OpFunction %void None %func_t
|
||||
%1 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1);
|
||||
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_1));
|
||||
}
|
||||
|
||||
TEST_F(
|
||||
ValidateMemory,
|
||||
VulkanRTAOutsideOfStructWithRuntimeDescriptorArrayAndWrongStorageClassBad) {
|
||||
std::string spirv = R"(
|
||||
OpCapability Shader
|
||||
OpCapability RuntimeDescriptorArrayEXT
|
||||
OpExtension "SPV_EXT_descriptor_indexing"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %func "func"
|
||||
OpExecutionMode %func OriginUpperLeft
|
||||
%uint_t = OpTypeInt 32 0
|
||||
%array_t = OpTypeRuntimeArray %uint_t
|
||||
%array_ptr = OpTypePointer Workgroup %array_t
|
||||
%2 = OpVariable %array_ptr Workgroup
|
||||
%void = OpTypeVoid
|
||||
%func_t = OpTypeFunction %void
|
||||
%func = OpFunction %void None %func_t
|
||||
%1 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1);
|
||||
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1));
|
||||
EXPECT_THAT(
|
||||
getDiagnosticString(),
|
||||
HasSubstr("For Vulkan with RuntimeDescriptorArrayEXT, a variable "
|
||||
"containing OpTypeRuntimeArray must have storage class of "
|
||||
"StorageBuffer, Uniform, or UniformConstant.\n %5 = "
|
||||
"OpVariable %_ptr_Workgroup__runtimearr_uint Workgroup\n"));
|
||||
}
|
||||
|
||||
TEST_F(ValidateMemory, VulkanRTAInsideStorageBufferStructGood) {
|
||||
std::string spirv = R"(
|
||||
OpCapability Shader
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %func "func"
|
||||
OpExecutionMode %func OriginUpperLeft
|
||||
OpDecorate %array_t ArrayStride 4
|
||||
OpMemberDecorate %struct_t 0 Offset 0
|
||||
OpDecorate %struct_t Block
|
||||
%uint_t = OpTypeInt 32 0
|
||||
%array_t = OpTypeRuntimeArray %uint_t
|
||||
%struct_t = OpTypeStruct %array_t
|
||||
%struct_ptr = OpTypePointer StorageBuffer %struct_t
|
||||
%2 = OpVariable %struct_ptr StorageBuffer
|
||||
%void = OpTypeVoid
|
||||
%func_t = OpTypeFunction %void
|
||||
%func = OpFunction %void None %func_t
|
||||
%1 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1);
|
||||
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_1));
|
||||
}
|
||||
|
||||
TEST_F(ValidateMemory, VulkanRTAInsideWrongStorageClassStructBad) {
|
||||
std::string spirv = R"(
|
||||
OpCapability Shader
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %func "func"
|
||||
OpExecutionMode %func OriginUpperLeft
|
||||
%uint_t = OpTypeInt 32 0
|
||||
%array_t = OpTypeRuntimeArray %uint_t
|
||||
%struct_t = OpTypeStruct %array_t
|
||||
%struct_ptr = OpTypePointer Workgroup %struct_t
|
||||
%2 = OpVariable %struct_ptr Workgroup
|
||||
%void = OpTypeVoid
|
||||
%func_t = OpTypeFunction %void
|
||||
%func = OpFunction %void None %func_t
|
||||
%1 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1);
|
||||
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1));
|
||||
EXPECT_THAT(
|
||||
getDiagnosticString(),
|
||||
HasSubstr(
|
||||
"For Vulkan, OpTypeStruct variables containing OpTypeRuntimeArray "
|
||||
"must have storage class of StorageBuffer or Uniform.\n %6 = "
|
||||
"OpVariable %_ptr_Workgroup__struct_4 Workgroup\n"));
|
||||
}
|
||||
|
||||
TEST_F(ValidateMemory, VulkanRTAInsideStorageBufferStructWithoutBlockBad) {
|
||||
std::string spirv = R"(
|
||||
OpCapability Shader
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %func "func"
|
||||
OpExecutionMode %func OriginUpperLeft
|
||||
%uint_t = OpTypeInt 32 0
|
||||
%array_t = OpTypeRuntimeArray %uint_t
|
||||
%struct_t = OpTypeStruct %array_t
|
||||
%struct_ptr = OpTypePointer StorageBuffer %struct_t
|
||||
%2 = OpVariable %struct_ptr StorageBuffer
|
||||
%void = OpTypeVoid
|
||||
%func_t = OpTypeFunction %void
|
||||
%func = OpFunction %void None %func_t
|
||||
%1 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1);
|
||||
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1));
|
||||
EXPECT_THAT(getDiagnosticString(),
|
||||
HasSubstr("For Vulkan, an OpTypeStruct variable containing an "
|
||||
"OpTypeRuntimeArray must be decorated with Block if it "
|
||||
"has storage class StorageBuffer.\n %6 = OpVariable "
|
||||
"%_ptr_StorageBuffer__struct_4 StorageBuffer\n"));
|
||||
}
|
||||
|
||||
TEST_F(ValidateMemory, VulkanRTAInsideUniformStructGood) {
|
||||
std::string spirv = R"(
|
||||
OpCapability Shader
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %func "func"
|
||||
OpExecutionMode %func OriginUpperLeft
|
||||
OpDecorate %array_t ArrayStride 4
|
||||
OpMemberDecorate %struct_t 0 Offset 0
|
||||
OpDecorate %struct_t BufferBlock
|
||||
%uint_t = OpTypeInt 32 0
|
||||
%array_t = OpTypeRuntimeArray %uint_t
|
||||
%struct_t = OpTypeStruct %array_t
|
||||
%struct_ptr = OpTypePointer Uniform %struct_t
|
||||
%2 = OpVariable %struct_ptr Uniform
|
||||
%void = OpTypeVoid
|
||||
%func_t = OpTypeFunction %void
|
||||
%func = OpFunction %void None %func_t
|
||||
%1 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1);
|
||||
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_1));
|
||||
}
|
||||
|
||||
TEST_F(ValidateMemory, VulkanRTAInsideUniformStructWithoutBufferBlockBad) {
|
||||
std::string spirv = R"(
|
||||
OpCapability Shader
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %func "func"
|
||||
OpExecutionMode %func OriginUpperLeft
|
||||
%uint_t = OpTypeInt 32 0
|
||||
%array_t = OpTypeRuntimeArray %uint_t
|
||||
%struct_t = OpTypeStruct %array_t
|
||||
%struct_ptr = OpTypePointer Uniform %struct_t
|
||||
%2 = OpVariable %struct_ptr Uniform
|
||||
%void = OpTypeVoid
|
||||
%func_t = OpTypeFunction %void
|
||||
%func = OpFunction %void None %func_t
|
||||
%1 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1);
|
||||
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1));
|
||||
EXPECT_THAT(getDiagnosticString(),
|
||||
HasSubstr("For Vulkan, an OpTypeStruct variable containing an "
|
||||
"OpTypeRuntimeArray must be decorated with BufferBlock "
|
||||
"if it has storage class Uniform.\n %6 = OpVariable "
|
||||
"%_ptr_Uniform__struct_4 Uniform\n"));
|
||||
}
|
||||
|
||||
TEST_F(ValidateMemory, VulkanRTAInsideRTABad) {
|
||||
std::string spirv = R"(
|
||||
OpCapability Shader
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %func "func"
|
||||
OpExecutionMode %func OriginUpperLeft
|
||||
%sampler_t = OpTypeSampler
|
||||
%inner_array_t = OpTypeRuntimeArray %sampler_t
|
||||
%array_t = OpTypeRuntimeArray %inner_array_t
|
||||
%array_ptr = OpTypePointer UniformConstant %array_t
|
||||
%2 = OpVariable %array_ptr UniformConstant
|
||||
%void = OpTypeVoid
|
||||
%func_t = OpTypeFunction %void
|
||||
%func = OpFunction %void None %func_t
|
||||
%1 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1);
|
||||
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1));
|
||||
EXPECT_THAT(
|
||||
getDiagnosticString(),
|
||||
HasSubstr(
|
||||
"OpTypeRuntimeArray Element Type <id> '3[%_runtimearr_2]' is not "
|
||||
"valid in Vulkan environment.\n %_runtimearr__runtimearr_2 = "
|
||||
"OpTypeRuntimeArray %_runtimearr_2\n"));
|
||||
}
|
||||
|
||||
TEST_F(ValidateMemory, VulkanRTAInsideRTAWithRuntimeDescriptorArrayBad) {
|
||||
std::string spirv = R"(
|
||||
OpCapability RuntimeDescriptorArrayEXT
|
||||
OpCapability Shader
|
||||
OpExtension "SPV_EXT_descriptor_indexing"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %func "func"
|
||||
OpExecutionMode %func OriginUpperLeft
|
||||
OpDecorate %array_t Block
|
||||
%uint_t = OpTypeInt 32 0
|
||||
%inner_array_t = OpTypeRuntimeArray %uint_t
|
||||
%array_t = OpTypeRuntimeArray %inner_array_t
|
||||
%array_ptr = OpTypePointer StorageBuffer %array_t
|
||||
%2 = OpVariable %array_ptr StorageBuffer
|
||||
%void = OpTypeVoid
|
||||
%func_t = OpTypeFunction %void
|
||||
%func = OpFunction %void None %func_t
|
||||
%1 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1);
|
||||
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1));
|
||||
EXPECT_THAT(
|
||||
getDiagnosticString(),
|
||||
HasSubstr(
|
||||
"OpTypeRuntimeArray Element Type <id> '4[%_runtimearr_uint]' is not "
|
||||
"valid in Vulkan environment.\n %_runtimearr__runtimearr_uint = "
|
||||
"OpTypeRuntimeArray %_runtimearr_uint\n"));
|
||||
}
|
||||
|
||||
TEST_F(ValidateMemory,
|
||||
VulkanUniformStructInsideRTAWithRuntimeDescriptorArrayGood) {
|
||||
std::string spirv = R"(
|
||||
OpCapability RuntimeDescriptorArrayEXT
|
||||
OpCapability Shader
|
||||
OpExtension "SPV_EXT_descriptor_indexing"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %func "func"
|
||||
OpExecutionMode %func OriginUpperLeft
|
||||
OpDecorate %array_t ArrayStride 4
|
||||
OpMemberDecorate %struct_t 0 Offset 0
|
||||
OpDecorate %struct_t Block
|
||||
%uint_t = OpTypeInt 32 0
|
||||
%struct_t = OpTypeStruct %uint_t
|
||||
%array_t = OpTypeRuntimeArray %struct_t
|
||||
%array_ptr = OpTypePointer Uniform %array_t
|
||||
%2 = OpVariable %array_ptr Uniform
|
||||
%void = OpTypeVoid
|
||||
%func_t = OpTypeFunction %void
|
||||
%func = OpFunction %void None %func_t
|
||||
%1 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1);
|
||||
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_1));
|
||||
}
|
||||
|
||||
TEST_F(ValidateMemory, VulkanRTAInsideRTAInsideStructBad) {
|
||||
std::string spirv = R"(
|
||||
OpCapability Shader
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %func "func"
|
||||
OpExecutionMode %func OriginUpperLeft
|
||||
OpDecorate %array_t ArrayStride 4
|
||||
OpMemberDecorate %struct_t 0 Offset 0
|
||||
OpDecorate %struct_t Block
|
||||
%uint_t = OpTypeInt 32 0
|
||||
%inner_array_t = OpTypeRuntimeArray %uint_t
|
||||
%array_t = OpTypeRuntimeArray %inner_array_t
|
||||
%struct_t = OpTypeStruct %array_t
|
||||
%struct_ptr = OpTypePointer StorageBuffer %struct_t
|
||||
%2 = OpVariable %struct_ptr StorageBuffer
|
||||
%void = OpTypeVoid
|
||||
%func_t = OpTypeFunction %void
|
||||
%func = OpFunction %void None %func_t
|
||||
%1 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1);
|
||||
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1));
|
||||
EXPECT_THAT(
|
||||
getDiagnosticString(),
|
||||
HasSubstr(
|
||||
"OpTypeRuntimeArray Element Type <id> '5[%_runtimearr_uint]' is not "
|
||||
"valid in Vulkan environment.\n %_runtimearr__runtimearr_uint = "
|
||||
"OpTypeRuntimeArray %_runtimearr_uint\n"));
|
||||
}
|
||||
|
||||
TEST_F(ValidateMemory,
|
||||
VulkanRTAInsideRTAInsideStructWithRuntimeDescriptorArrayBad) {
|
||||
std::string spirv = R"(
|
||||
OpCapability RuntimeDescriptorArrayEXT
|
||||
OpCapability Shader
|
||||
OpExtension "SPV_EXT_descriptor_indexing"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %func "func"
|
||||
OpExecutionMode %func OriginUpperLeft
|
||||
OpDecorate %array_t ArrayStride 4
|
||||
OpMemberDecorate %struct_t 0 Offset 0
|
||||
OpDecorate %struct_t Block
|
||||
%uint_t = OpTypeInt 32 0
|
||||
%inner_array_t = OpTypeRuntimeArray %uint_t
|
||||
%array_t = OpTypeRuntimeArray %inner_array_t
|
||||
%struct_t = OpTypeStruct %array_t
|
||||
%struct_ptr = OpTypePointer StorageBuffer %struct_t
|
||||
%2 = OpVariable %struct_ptr StorageBuffer
|
||||
%void = OpTypeVoid
|
||||
%func_t = OpTypeFunction %void
|
||||
%func = OpFunction %void None %func_t
|
||||
%1 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1);
|
||||
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1));
|
||||
EXPECT_THAT(
|
||||
getDiagnosticString(),
|
||||
HasSubstr(
|
||||
"OpTypeRuntimeArray Element Type <id> '5[%_runtimearr_uint]' is not "
|
||||
"valid in Vulkan environment.\n %_runtimearr__runtimearr_uint = "
|
||||
"OpTypeRuntimeArray %_runtimearr_uint\n"));
|
||||
}
|
||||
|
||||
TEST_F(ValidateMemory, VulkanRTAInsideArrayBad) {
|
||||
std::string spirv = R"(
|
||||
OpCapability Shader
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %func "func"
|
||||
OpExecutionMode %func OriginUpperLeft
|
||||
%uint_t = OpTypeInt 32 0
|
||||
%dim = OpConstant %uint_t 1
|
||||
%sampler_t = OpTypeSampler
|
||||
%inner_array_t = OpTypeRuntimeArray %sampler_t
|
||||
%array_t = OpTypeArray %inner_array_t %dim
|
||||
%array_ptr = OpTypePointer UniformConstant %array_t
|
||||
%2 = OpVariable %array_ptr UniformConstant
|
||||
%void = OpTypeVoid
|
||||
%func_t = OpTypeFunction %void
|
||||
%func = OpFunction %void None %func_t
|
||||
%1 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1);
|
||||
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1));
|
||||
EXPECT_THAT(
|
||||
getDiagnosticString(),
|
||||
HasSubstr("OpTypeArray Element Type <id> '5[%_runtimearr_4]' is not "
|
||||
"valid in Vulkan environment.\n %_arr__runtimearr_4_uint_1 = "
|
||||
"OpTypeArray %_runtimearr_4 %uint_1\n"));
|
||||
}
|
||||
|
||||
TEST_F(ValidateMemory, VulkanRTAInsideArrayWithRuntimeDescriptorArrayBad) {
|
||||
std::string spirv = R"(
|
||||
OpCapability RuntimeDescriptorArrayEXT
|
||||
OpCapability Shader
|
||||
OpExtension "SPV_EXT_descriptor_indexing"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %func "func"
|
||||
OpExecutionMode %func OriginUpperLeft
|
||||
OpDecorate %array_t Block
|
||||
%uint_t = OpTypeInt 32 0
|
||||
%dim = OpConstant %uint_t 1
|
||||
%sampler_t = OpTypeSampler
|
||||
%inner_array_t = OpTypeRuntimeArray %uint_t
|
||||
%array_t = OpTypeRuntimeArray %inner_array_t
|
||||
%array_ptr = OpTypePointer StorageBuffer %array_t
|
||||
%2 = OpVariable %array_ptr StorageBuffer
|
||||
%void = OpTypeVoid
|
||||
%func_t = OpTypeFunction %void
|
||||
%func = OpFunction %void None %func_t
|
||||
%1 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1);
|
||||
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1));
|
||||
EXPECT_THAT(
|
||||
getDiagnosticString(),
|
||||
HasSubstr(
|
||||
"OpTypeRuntimeArray Element Type <id> '6[%_runtimearr_uint]' is not "
|
||||
"valid in Vulkan environment.\n %_runtimearr__runtimearr_uint = "
|
||||
"OpTypeRuntimeArray %_runtimearr_uint\n"));
|
||||
}
|
||||
|
||||
TEST_F(ValidateMemory, VulkanRTAInsideArrayInsideStructBad) {
|
||||
std::string spirv = R"(
|
||||
OpCapability Shader
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %func "func"
|
||||
OpExecutionMode %func OriginUpperLeft
|
||||
OpDecorate %array_t ArrayStride 4
|
||||
OpMemberDecorate %struct_t 0 Offset 0
|
||||
OpDecorate %struct_t Block
|
||||
%uint_t = OpTypeInt 32 0
|
||||
%dim = OpConstant %uint_t 1
|
||||
%inner_array_t = OpTypeRuntimeArray %uint_t
|
||||
%array_t = OpTypeArray %inner_array_t %dim
|
||||
%struct_t = OpTypeStruct %array_t
|
||||
%struct_ptr = OpTypePointer StorageBuffer %struct_t
|
||||
%2 = OpVariable %struct_ptr StorageBuffer
|
||||
%void = OpTypeVoid
|
||||
%func_t = OpTypeFunction %void
|
||||
%func = OpFunction %void None %func_t
|
||||
%1 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1);
|
||||
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1));
|
||||
EXPECT_THAT(
|
||||
getDiagnosticString(),
|
||||
HasSubstr("OpTypeArray Element Type <id> '6[%_runtimearr_uint]' is not "
|
||||
"valid in Vulkan environment.\n %_arr__runtimearr_uint_uint_1 "
|
||||
"= OpTypeArray %_runtimearr_uint %uint_1\n"));
|
||||
}
|
||||
|
||||
TEST_F(ValidateMemory,
|
||||
VulkanRTAInsideArrayInsideStructWithRuntimeDescriptorArrayBad) {
|
||||
std::string spirv = R"(
|
||||
OpCapability RuntimeDescriptorArrayEXT
|
||||
OpCapability Shader
|
||||
OpExtension "SPV_EXT_descriptor_indexing"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %func "func"
|
||||
OpExecutionMode %func OriginUpperLeft
|
||||
OpDecorate %array_t ArrayStride 4
|
||||
OpMemberDecorate %struct_t 0 Offset 0
|
||||
OpDecorate %struct_t Block
|
||||
%uint_t = OpTypeInt 32 0
|
||||
%dim = OpConstant %uint_t 1
|
||||
%inner_array_t = OpTypeRuntimeArray %uint_t
|
||||
%array_t = OpTypeArray %inner_array_t %dim
|
||||
%struct_t = OpTypeStruct %array_t
|
||||
%struct_ptr = OpTypePointer StorageBuffer %struct_t
|
||||
%2 = OpVariable %struct_ptr StorageBuffer
|
||||
%void = OpTypeVoid
|
||||
%func_t = OpTypeFunction %void
|
||||
%func = OpFunction %void None %func_t
|
||||
%1 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1);
|
||||
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1));
|
||||
EXPECT_THAT(
|
||||
getDiagnosticString(),
|
||||
HasSubstr("OpTypeArray Element Type <id> '6[%_runtimearr_uint]' is not "
|
||||
"valid in Vulkan environment.\n %_arr__runtimearr_uint_uint_1 "
|
||||
"= OpTypeArray %_runtimearr_uint %uint_1\n"));
|
||||
}
|
||||
|
||||
TEST_F(ValidateMemory, VulkanRTAStructInsideRTAWithRuntimeDescriptorArrayGood) {
|
||||
std::string spirv = R"(
|
||||
OpCapability RuntimeDescriptorArrayEXT
|
||||
OpCapability Shader
|
||||
OpExtension "SPV_EXT_descriptor_indexing"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %func "func"
|
||||
OpExecutionMode %func OriginUpperLeft
|
||||
OpDecorate %array_t ArrayStride 4
|
||||
OpMemberDecorate %struct_t 0 Offset 0
|
||||
OpDecorate %struct_t Block
|
||||
%uint_t = OpTypeInt 32 0
|
||||
%inner_array_t = OpTypeRuntimeArray %uint_t
|
||||
%struct_t = OpTypeStruct %inner_array_t
|
||||
%array_t = OpTypeRuntimeArray %struct_t
|
||||
%array_ptr = OpTypePointer StorageBuffer %array_t
|
||||
%2 = OpVariable %array_ptr StorageBuffer
|
||||
%void = OpTypeVoid
|
||||
%func_t = OpTypeFunction %void
|
||||
%func = OpFunction %void None %func_t
|
||||
%1 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1);
|
||||
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_1));
|
||||
}
|
||||
|
||||
TEST_F(ValidateMemory, VulkanRTAStructInsideArrayGood) {
|
||||
std::string spirv = R"(
|
||||
OpCapability RuntimeDescriptorArrayEXT
|
||||
OpCapability Shader
|
||||
OpExtension "SPV_EXT_descriptor_indexing"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %func "func"
|
||||
OpExecutionMode %func OriginUpperLeft
|
||||
OpDecorate %array_t ArrayStride 4
|
||||
OpMemberDecorate %struct_t 0 Offset 0
|
||||
OpDecorate %struct_t Block
|
||||
%uint_t = OpTypeInt 32 0
|
||||
%inner_array_t = OpTypeRuntimeArray %uint_t
|
||||
%struct_t = OpTypeStruct %inner_array_t
|
||||
%array_size = OpConstant %uint_t 5
|
||||
%array_t = OpTypeArray %struct_t %array_size
|
||||
%array_ptr = OpTypePointer StorageBuffer %array_t
|
||||
%2 = OpVariable %array_ptr StorageBuffer
|
||||
%void = OpTypeVoid
|
||||
%func_t = OpTypeFunction %void
|
||||
%func = OpFunction %void None %func_t
|
||||
%1 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1);
|
||||
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_1));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace val
|
||||
} // namespace spvtools
|
||||
|
||||
@@ -306,6 +306,54 @@ TEST_F(ValidationStateTest, CheckWebGPUIndirectlyRecursiveBodyBad) {
|
||||
"called.\n %9 = OpFunctionCall %_struct_5 %10\n"));
|
||||
}
|
||||
|
||||
TEST_F(ValidationStateTest,
|
||||
CheckWebGPUDuplicateEntryNamesDifferentFunctionsBad) {
|
||||
std::string spirv = std::string(kVulkanMemoryHeader) + R"(
|
||||
OpEntryPoint Fragment %func_1 "main"
|
||||
OpEntryPoint Vertex %func_2 "main"
|
||||
OpExecutionMode %func_1 OriginUpperLeft
|
||||
%void = OpTypeVoid
|
||||
%void_f = OpTypeFunction %void
|
||||
%func_1 = OpFunction %void None %void_f
|
||||
%label_1 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
%func_2 = OpFunction %void None %void_f
|
||||
%label_2 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
CompileSuccessfully(spirv, SPV_ENV_WEBGPU_0);
|
||||
EXPECT_EQ(SPV_ERROR_INVALID_BINARY,
|
||||
ValidateAndRetrieveValidationState(SPV_ENV_WEBGPU_0));
|
||||
EXPECT_THAT(
|
||||
getDiagnosticString(),
|
||||
HasSubstr("Entry point name \"main\" is not unique, which is not allow "
|
||||
"in WebGPU env.\n %1 = OpFunction %void None %4\n"));
|
||||
}
|
||||
|
||||
TEST_F(ValidationStateTest, CheckWebGPUDuplicateEntryNamesSameFunctionBad) {
|
||||
std::string spirv = std::string(kVulkanMemoryHeader) + R"(
|
||||
OpEntryPoint GLCompute %func_1 "main"
|
||||
OpEntryPoint Vertex %func_1 "main"
|
||||
%void = OpTypeVoid
|
||||
%void_f = OpTypeFunction %void
|
||||
%func_1 = OpFunction %void None %void_f
|
||||
%label_1 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
CompileSuccessfully(spirv, SPV_ENV_WEBGPU_0);
|
||||
EXPECT_EQ(SPV_ERROR_INVALID_BINARY,
|
||||
ValidateAndRetrieveValidationState(SPV_ENV_WEBGPU_0));
|
||||
EXPECT_THAT(
|
||||
getDiagnosticString(),
|
||||
HasSubstr("Entry point name \"main\" is not unique, which is not allow "
|
||||
"in WebGPU env.\n %1 = OpFunction %void None %3\n"));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace val
|
||||
} // namespace spvtools
|
||||
|
||||
Reference in New Issue
Block a user