An OpVariable initializer can be a module-scope variable

Fixes https://github.com/KhronosGroup/SPIRV-Tools/issues/482
This commit is contained in:
David Neto 2016-12-07 10:33:27 -05:00
parent aadf696fce
commit d5b0cd34c9
2 changed files with 66 additions and 8 deletions

View File

@ -988,7 +988,7 @@ bool idUsage::isValid<SpvOpSpecConstantOp>(const spv_instruction_t *inst) {}
template <> template <>
bool idUsage::isValid<SpvOpVariable>(const spv_instruction_t* inst, bool idUsage::isValid<SpvOpVariable>(const spv_instruction_t* inst,
const spv_opcode_desc opcodeEntry) { const spv_opcode_desc) {
auto resultTypeIndex = 1; auto resultTypeIndex = 1;
auto resultType = module_.FindDef(inst->words[resultTypeIndex]); auto resultType = module_.FindDef(inst->words[resultTypeIndex]);
if (!resultType || SpvOpTypePointer != resultType->opcode()) { if (!resultType || SpvOpTypePointer != resultType->opcode()) {
@ -997,13 +997,19 @@ bool idUsage::isValid<SpvOpVariable>(const spv_instruction_t* inst,
<< "' is not a pointer type."; << "' is not a pointer type.";
return false; return false;
} }
if (opcodeEntry->numTypes < inst->words.size()) { const auto initialiserIndex = 4;
auto initialiserIndex = 4; if (initialiserIndex < inst->words.size()) {
auto initialiser = module_.FindDef(inst->words[initialiserIndex]); const auto initialiser = module_.FindDef(inst->words[initialiserIndex]);
if (!initialiser || !spvOpcodeIsConstant(initialiser->opcode())) { const auto storageClassIndex = 3;
const auto is_module_scope_var =
initialiser && (initialiser->opcode() == SpvOpVariable) &&
(initialiser->word(storageClassIndex) != SpvStorageClassFunction);
const auto is_constant =
initialiser && spvOpcodeIsConstant(initialiser->opcode());
if (!initialiser || !(is_constant || is_module_scope_var)) {
DIAG(initialiserIndex) << "OpVariable Initializer <id> '" DIAG(initialiserIndex) << "OpVariable Initializer <id> '"
<< inst->words[initialiserIndex] << inst->words[initialiserIndex]
<< "' is not a constant."; << "' is not a constant or module-scope variable.";
return false; return false;
} }
} }

View File

@ -1461,7 +1461,7 @@ TEST_F(ValidateIdWithMessage, OpVariableGood) {
CompileSuccessfully(spirv.c_str()); CompileSuccessfully(spirv.c_str());
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
} }
TEST_F(ValidateIdWithMessage, OpVariableInitializerGood) { TEST_F(ValidateIdWithMessage, OpVariableInitializerConstantGood) {
string spirv = kGLSL450MemoryModel + R"( string spirv = kGLSL450MemoryModel + R"(
%1 = OpTypeInt 32 1 %1 = OpTypeInt 32 1
%2 = OpTypePointer Input %1 %2 = OpTypePointer Input %1
@ -1470,6 +1470,16 @@ TEST_F(ValidateIdWithMessage, OpVariableInitializerGood) {
CompileSuccessfully(spirv.c_str()); CompileSuccessfully(spirv.c_str());
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
} }
TEST_F(ValidateIdWithMessage, OpVariableInitializerGlobalVariableGood) {
string spirv = kGLSL450MemoryModel + R"(
%1 = OpTypeInt 32 1
%2 = OpTypePointer Uniform %1
%3 = OpVariable %2 Uniform
%4 = OpTypePointer Uniform %2 ; pointer to pointer
%5 = OpVariable %4 Uniform %3)";
CompileSuccessfully(spirv.c_str());
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
}
// TODO: Positive test OpVariable with OpConstantNull of OpTypePointer // TODO: Positive test OpVariable with OpConstantNull of OpTypePointer
TEST_F(ValidateIdWithMessage, OpVariableResultTypeBad) { TEST_F(ValidateIdWithMessage, OpVariableResultTypeBad) {
string spirv = kGLSL450MemoryModel + R"( string spirv = kGLSL450MemoryModel + R"(
@ -1478,13 +1488,55 @@ TEST_F(ValidateIdWithMessage, OpVariableResultTypeBad) {
CompileSuccessfully(spirv.c_str()); CompileSuccessfully(spirv.c_str());
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
} }
TEST_F(ValidateIdWithMessage, OpVariableInitializerBad) { TEST_F(ValidateIdWithMessage, OpVariableInitializerIsTypeBad) {
string spirv = kGLSL450MemoryModel + R"( string spirv = kGLSL450MemoryModel + R"(
%1 = OpTypeInt 32 1 %1 = OpTypeInt 32 1
%2 = OpTypePointer Input %1 %2 = OpTypePointer Input %1
%3 = OpVariable %2 Input %2)"; %3 = OpVariable %2 Input %2)";
CompileSuccessfully(spirv.c_str()); CompileSuccessfully(spirv.c_str());
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(),
HasSubstr("OpVariable Initializer <id> '2' is not a constant or "
"module-scope variable"));
}
TEST_F(ValidateIdWithMessage, OpVariableInitializerIsFunctionVarBad) {
string spirv = kGLSL450MemoryModel + R"(
%int = OpTypeInt 32 1
%ptrint = OpTypePointer Function %int
%ptrptrint = OpTypePointer Function %ptrint
%void = OpTypeVoid
%fnty = OpTypeFunction %void
%main = OpFunction %void None %fnty
%entry = OpLabel
%var = OpVariable %ptrint Function
%varinit = OpVariable %ptrptrint Function %var ; Can't initialize function variable.
OpReturn
OpFunctionEnd
)";
CompileSuccessfully(spirv.c_str());
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(),
HasSubstr("OpVariable Initializer <id> '8' is not a constant or "
"module-scope variable"));
}
TEST_F(ValidateIdWithMessage, OpVariableInitializerIsModuleVarGood) {
string spirv = kGLSL450MemoryModel + R"(
%int = OpTypeInt 32 1
%ptrint = OpTypePointer Uniform %int
%mvar = OpVariable %ptrint Uniform
%ptrptrint = OpTypePointer Function %ptrint
%void = OpTypeVoid
%fnty = OpTypeFunction %void
%main = OpFunction %void None %fnty
%entry = OpLabel
%goodvar = OpVariable %ptrptrint Function %mvar ; This is ok
OpReturn
OpFunctionEnd
)";
CompileSuccessfully(spirv.c_str());
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
} }
TEST_F(ValidateIdWithMessage, OpLoadGood) { TEST_F(ValidateIdWithMessage, OpLoadGood) {