mirror of
https://github.com/KhronosGroup/SPIRV-Tools
synced 2024-11-22 11:40:05 +00:00
Add pass to reaplce invalid opcodes
Creates a pass that will remove instructions that are invalid for the current shader stage. For the instruction to be considered for replacement 1) The opcode must be valid for a shader modules. 2) The opcode must be invalid for the current shader stage. 3) All entry points to the module must be for the same shader stage. 4) The function containing the instruction must be reachable from an entry point. Fixes #1247.
This commit is contained in:
parent
d37869c842
commit
61d8c0384b
@ -106,6 +106,7 @@ SPVTOOLS_OPT_SRC_FILES := \
|
||||
source/opt/propagator.cpp \
|
||||
source/opt/redundancy_elimination.cpp \
|
||||
source/opt/remove_duplicates_pass.cpp \
|
||||
source/opt/replace_invalid_opc.cpp \
|
||||
source/opt/scalar_replacement_pass.cpp \
|
||||
source/opt/set_spec_constant_default_value_pass.cpp \
|
||||
source/opt/strength_reduction_pass.cpp \
|
||||
|
@ -500,6 +500,10 @@ Optimizer::PassToken CreateWorkaround1209Pass();
|
||||
// Creates a pass that converts if-then-else like assignments into OpSelect.
|
||||
Optimizer::PassToken CreateIfConversionPass();
|
||||
|
||||
// Creates a pass that will replace instructions that are not valid for the
|
||||
// current shader stage by constants. Has no effect on non-shader modules.
|
||||
Optimizer::PassToken CreateReplaceInvalidOpcodePass();
|
||||
|
||||
} // namespace spvtools
|
||||
|
||||
#endif // SPIRV_TOOLS_OPTIMIZER_HPP_
|
||||
|
@ -65,6 +65,7 @@ add_library(SPIRV-Tools-opt
|
||||
redundancy_elimination.h
|
||||
reflect.h
|
||||
remove_duplicates_pass.h
|
||||
replace_invalid_opc.h
|
||||
scalar_replacement_pass.h
|
||||
set_spec_constant_default_value_pass.h
|
||||
strength_reduction_pass.h
|
||||
@ -127,6 +128,7 @@ add_library(SPIRV-Tools-opt
|
||||
propagator.cpp
|
||||
redundancy_elimination.cpp
|
||||
remove_duplicates_pass.cpp
|
||||
replace_invalid_opc.cpp
|
||||
scalar_replacement_pass.cpp
|
||||
set_spec_constant_default_value_pass.cpp
|
||||
strength_reduction_pass.cpp
|
||||
|
@ -375,4 +375,8 @@ Optimizer::PassToken CreateIfConversionPass() {
|
||||
MakeUnique<opt::IfConversion>());
|
||||
}
|
||||
|
||||
Optimizer::PassToken CreateReplaceInvalidOpcodePass() {
|
||||
return MakeUnique<Optimizer::PassToken::Impl>(
|
||||
MakeUnique<opt::ReplaceInvalidOpcodePass>());
|
||||
}
|
||||
} // namespace spvtools
|
||||
|
@ -45,6 +45,7 @@
|
||||
#include "private_to_local_pass.h"
|
||||
#include "redundancy_elimination.h"
|
||||
#include "remove_duplicates_pass.h"
|
||||
#include "replace_invalid_opc.h"
|
||||
#include "scalar_replacement_pass.h"
|
||||
#include "set_spec_constant_default_value_pass.h"
|
||||
#include "strength_reduction_pass.h"
|
||||
|
207
source/opt/replace_invalid_opc.cpp
Normal file
207
source/opt/replace_invalid_opc.cpp
Normal file
@ -0,0 +1,207 @@
|
||||
// Copyright (c) 2018 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "replace_invalid_opc.h"
|
||||
|
||||
#include <bitset>
|
||||
|
||||
namespace spvtools {
|
||||
namespace opt {
|
||||
|
||||
Pass::Status ReplaceInvalidOpcodePass::Process(ir::IRContext* c) {
|
||||
InitializeProcessing(c);
|
||||
bool modified = false;
|
||||
|
||||
if (context()->get_feature_mgr()->HasCapability(SpvCapabilityLinkage)) {
|
||||
return Status::SuccessWithoutChange;
|
||||
}
|
||||
|
||||
SpvExecutionModel execution_model = GetExecutionModel();
|
||||
if (execution_model == SpvExecutionModelKernel) {
|
||||
// We do not handle kernels.
|
||||
return Status::SuccessWithoutChange;
|
||||
}
|
||||
if (execution_model == SpvExecutionModelMax) {
|
||||
// Mixed execution models for the entry points. This case is not currently
|
||||
// handled.
|
||||
return Status::SuccessWithoutChange;
|
||||
}
|
||||
|
||||
for (ir::Function& func : *get_module()) {
|
||||
modified |= RewriteFunction(&func, execution_model);
|
||||
}
|
||||
return (modified ? Status::SuccessWithChange : Status::SuccessWithoutChange);
|
||||
}
|
||||
|
||||
SpvExecutionModel ReplaceInvalidOpcodePass::GetExecutionModel() {
|
||||
SpvExecutionModel result = SpvExecutionModelMax;
|
||||
bool first = true;
|
||||
for (ir::Instruction& entry_point : get_module()->entry_points()) {
|
||||
if (first) {
|
||||
result =
|
||||
static_cast<SpvExecutionModel>(entry_point.GetSingleWordInOperand(0));
|
||||
first = false;
|
||||
} else {
|
||||
SpvExecutionModel current_model =
|
||||
static_cast<SpvExecutionModel>(entry_point.GetSingleWordInOperand(0));
|
||||
if (current_model != result) {
|
||||
result = SpvExecutionModelMax;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool ReplaceInvalidOpcodePass::RewriteFunction(ir::Function* function,
|
||||
SpvExecutionModel model) {
|
||||
bool modified = false;
|
||||
ir::Instruction* last_line_dbg_inst = nullptr;
|
||||
function->ForEachInst(
|
||||
[model, &modified, &last_line_dbg_inst, this](ir::Instruction* inst) {
|
||||
// Track the debug information so we can have a meaningful message.
|
||||
if (inst->opcode() == SpvOpLabel || inst->opcode() == SpvOpNoLine) {
|
||||
last_line_dbg_inst = nullptr;
|
||||
return;
|
||||
} else if (inst->opcode() == SpvOpLine) {
|
||||
last_line_dbg_inst = inst;
|
||||
return;
|
||||
}
|
||||
|
||||
bool replace = false;
|
||||
if (model != SpvExecutionModelFragment &&
|
||||
IsFragmentShaderOnlyInstruction(inst)) {
|
||||
replace = true;
|
||||
}
|
||||
|
||||
if (model != SpvExecutionModelTessellationControl &&
|
||||
model != SpvExecutionModelGLCompute) {
|
||||
if (inst->opcode() == SpvOpControlBarrier) {
|
||||
assert(model != SpvExecutionModelKernel &&
|
||||
"Expecting to be working on a shader module.");
|
||||
replace = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (replace) {
|
||||
modified = true;
|
||||
if (last_line_dbg_inst == nullptr) {
|
||||
ReplaceInstruction(inst, nullptr, 0, 0);
|
||||
} else {
|
||||
// Get the name of the source file.
|
||||
ir::Instruction* file_name = context()->get_def_use_mgr()->GetDef(
|
||||
last_line_dbg_inst->GetSingleWordInOperand(0));
|
||||
const char* source = reinterpret_cast<const char*>(
|
||||
&file_name->GetInOperand(0).words[0]);
|
||||
|
||||
// Get the line number and column number.
|
||||
uint32_t line_number =
|
||||
last_line_dbg_inst->GetSingleWordInOperand(1);
|
||||
uint32_t col_number = last_line_dbg_inst->GetSingleWordInOperand(2);
|
||||
|
||||
// Replace the instruction.
|
||||
ReplaceInstruction(inst, source, line_number, col_number);
|
||||
}
|
||||
}
|
||||
},
|
||||
/* run_on_debug_line_insts = */ true);
|
||||
return modified;
|
||||
}
|
||||
|
||||
bool ReplaceInvalidOpcodePass::IsFragmentShaderOnlyInstruction(
|
||||
ir::Instruction* inst) {
|
||||
switch (inst->opcode()) {
|
||||
case SpvOpDPdx:
|
||||
case SpvOpDPdy:
|
||||
case SpvOpFwidth:
|
||||
case SpvOpDPdxFine:
|
||||
case SpvOpDPdyFine:
|
||||
case SpvOpFwidthFine:
|
||||
case SpvOpDPdxCoarse:
|
||||
case SpvOpDPdyCoarse:
|
||||
case SpvOpFwidthCoarse:
|
||||
case SpvOpImageSampleImplicitLod:
|
||||
case SpvOpImageSampleDrefImplicitLod:
|
||||
case SpvOpImageSampleProjImplicitLod:
|
||||
case SpvOpImageSampleProjDrefImplicitLod:
|
||||
case SpvOpImageSparseSampleImplicitLod:
|
||||
case SpvOpImageSparseSampleDrefImplicitLod:
|
||||
case SpvOpImageQueryLod:
|
||||
// TODO: Teach |ReplaceInstruction| to handle block terminators. Then
|
||||
// uncomment the OpKill case.
|
||||
// case SpvOpKill:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void ReplaceInvalidOpcodePass::ReplaceInstruction(ir::Instruction* inst,
|
||||
const char* source,
|
||||
uint32_t line_number,
|
||||
uint32_t column_number) {
|
||||
if (inst->result_id() != 0) {
|
||||
uint32_t const_id = GetSpecialConstant(inst->type_id());
|
||||
context()->KillNamesAndDecorates(inst);
|
||||
context()->ReplaceAllUsesWith(inst->result_id(), const_id);
|
||||
}
|
||||
assert(!inst->IsBlockTerminator() &&
|
||||
"We cannot simply delete a block terminator. It must be replaced "
|
||||
"with something.");
|
||||
if (consumer()) {
|
||||
std::string message = BuildWarningMessage(inst->opcode());
|
||||
consumer()(SPV_MSG_WARNING, source, {line_number, column_number, 0},
|
||||
message.c_str());
|
||||
}
|
||||
context()->KillInst(inst);
|
||||
}
|
||||
|
||||
uint32_t ReplaceInvalidOpcodePass::GetSpecialConstant(uint32_t type_id) {
|
||||
const analysis::Constant* special_const = nullptr;
|
||||
analysis::ConstantManager* const_mgr = context()->get_constant_mgr();
|
||||
analysis::TypeManager* type_mgr = context()->get_type_mgr();
|
||||
|
||||
ir::Instruction* type = context()->get_def_use_mgr()->GetDef(type_id);
|
||||
if (type->opcode() == SpvOpTypeVector) {
|
||||
uint32_t component_const =
|
||||
GetSpecialConstant(type->GetSingleWordInOperand(0));
|
||||
std::vector<uint32_t> ids;
|
||||
for (uint32_t i = 0; i < type->GetSingleWordInOperand(1); ++i) {
|
||||
ids.push_back(component_const);
|
||||
}
|
||||
special_const = const_mgr->GetConstant(type_mgr->GetType(type_id), ids);
|
||||
} else {
|
||||
assert(type->opcode() == SpvOpTypeInt || type->opcode() == SpvOpTypeFloat);
|
||||
std::vector<uint32_t> literal_words;
|
||||
for (uint32_t i = 0; i < type->GetSingleWordInOperand(0); i += 32) {
|
||||
literal_words.push_back(0xDEADBEEF);
|
||||
}
|
||||
special_const =
|
||||
const_mgr->GetConstant(type_mgr->GetType(type_id), literal_words);
|
||||
}
|
||||
assert(special_const != nullptr);
|
||||
return const_mgr->GetDefiningInstruction(special_const)->result_id();
|
||||
}
|
||||
|
||||
std::string ReplaceInvalidOpcodePass::BuildWarningMessage(SpvOp opcode) {
|
||||
spv_opcode_desc opcode_info;
|
||||
context()->grammar().lookupOpcode(opcode, &opcode_info);
|
||||
std::string message = "Removing ";
|
||||
message += opcode_info->name;
|
||||
message += " instruction because of incompatible execution model.";
|
||||
return message;
|
||||
}
|
||||
|
||||
} // namespace opt
|
||||
} // namespace spvtools
|
65
source/opt/replace_invalid_opc.h
Normal file
65
source/opt/replace_invalid_opc.h
Normal file
@ -0,0 +1,65 @@
|
||||
// Copyright (c) 2018 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef LIBSPIRV_OPT_REPLACE_INVALID_OPC_H_
|
||||
#define LIBSPIRV_OPT_REPLACE_INVALID_OPC_H_
|
||||
|
||||
#include "pass.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace opt {
|
||||
|
||||
// This pass will runs on shader modules only. It will replace the result of
|
||||
// instructions that are valid for shader modules, but not the current shader
|
||||
// stage, with a constant value. If the instruction does not have a return
|
||||
// value, the instruction will simply be deleted.
|
||||
class ReplaceInvalidOpcodePass : public Pass {
|
||||
public:
|
||||
const char* name() const override { return "replace-invalid-opcodes"; }
|
||||
Status Process(ir::IRContext*) override;
|
||||
|
||||
private:
|
||||
// Returns the execution model that is used by every entry point in the
|
||||
// module. If more than one execution model is used in the module, then the
|
||||
// return value is SpvExecutionModelMax.
|
||||
SpvExecutionModel GetExecutionModel();
|
||||
|
||||
// Replaces all instructions in |function| that are invalid with execution
|
||||
// model |mode|, but valid for another shader model, with a special constant
|
||||
// value. See |GetSpecialConstant|.
|
||||
bool RewriteFunction(ir::Function* function, SpvExecutionModel mode);
|
||||
|
||||
// Returns true if |inst| is valid for fragment shaders only.
|
||||
bool IsFragmentShaderOnlyInstruction(ir::Instruction* inst);
|
||||
|
||||
// Replaces all uses of the result of |inst|, if there is one, with the id of
|
||||
// a special constant. Then |inst| is killed. |inst| cannot be a block
|
||||
// terminator because the basic block will then become invalid. |inst| is no
|
||||
// longer valid after calling this function.
|
||||
void ReplaceInstruction(ir::Instruction* inst, const char* source,
|
||||
uint32_t line_number, uint32_t column_number);
|
||||
|
||||
// Returns the id of a constant with type |type_id|. The type must be an
|
||||
// integer, float, or vector. For scalar types, the hex representation of the
|
||||
// constant will be the concatenation of 0xDEADBEEF with itself until the
|
||||
// width of the type has been reached. For a vector, each element of the
|
||||
// constant will be constructed the same way.
|
||||
uint32_t GetSpecialConstant(uint32_t type_id);
|
||||
std::string BuildWarningMessage(SpvOp opcode);
|
||||
};
|
||||
|
||||
} // namespace opt
|
||||
} // namespace spvtools
|
||||
|
||||
#endif // LIBSPIRV_OPT_REPLACE_INVALID_OPC_H_
|
@ -286,3 +286,8 @@ add_spvtools_unittest(TARGET instruction_folding
|
||||
SRCS fold_test.cpp pass_utils.cpp
|
||||
LIBS SPIRV-Tools-opt
|
||||
)
|
||||
|
||||
add_spvtools_unittest(TARGET replace_invalid_opc
|
||||
SRCS replace_invalid_opc_test.cpp pass_utils.cpp
|
||||
LIBS SPIRV-Tools-opt
|
||||
)
|
||||
|
@ -226,6 +226,10 @@ class PassTest : public TestT {
|
||||
MessageConsumer consumer() { return consumer_; }
|
||||
ir::IRContext* context() { return context_.get(); }
|
||||
|
||||
void SetMessageConsumer(MessageConsumer msg_consumer) {
|
||||
consumer_ = msg_consumer;
|
||||
}
|
||||
|
||||
private:
|
||||
MessageConsumer consumer_; // Message consumer.
|
||||
std::unique_ptr<ir::IRContext> context_; // IR context
|
||||
|
590
test/opt/replace_invalid_opc_test.cpp
Normal file
590
test/opt/replace_invalid_opc_test.cpp
Normal file
@ -0,0 +1,590 @@
|
||||
// Copyright (c) 2017 Google Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "assembly_builder.h"
|
||||
#include "gmock/gmock.h"
|
||||
#include "pass_fixture.h"
|
||||
|
||||
#include <cstdarg>
|
||||
|
||||
namespace {
|
||||
|
||||
using namespace spvtools;
|
||||
|
||||
using ReplaceInvalidOpcodeTest = PassTest<::testing::Test>;
|
||||
|
||||
#ifdef SPIRV_EFFCEE
|
||||
TEST_F(ReplaceInvalidOpcodeTest, ReplaceInstruction) {
|
||||
const std::string text = R"(
|
||||
; CHECK: [[special_const:%\w+]] = OpConstant %float -6.25985e+18
|
||||
; CHECK: [[constant:%\w+]] = OpConstantComposite %v4float [[special_const]] [[special_const]] [[special_const]] [[special_const]]
|
||||
; CHECK-NOT: OpImageSampleImplicitLod
|
||||
; CHECK: OpStore [[:%\w+]] [[constant]]
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Vertex %main "main" %3 %gl_VertexIndex %5
|
||||
OpSource GLSL 400
|
||||
OpSourceExtension "GL_ARB_separate_shader_objects"
|
||||
OpSourceExtension "GL_ARB_shading_language_420pack"
|
||||
OpName %main "main"
|
||||
OpDecorate %3 Location 0
|
||||
OpDecorate %gl_VertexIndex BuiltIn VertexIndex
|
||||
OpMemberDecorate %_struct_6 0 BuiltIn Position
|
||||
OpDecorate %_struct_6 Block
|
||||
%void = OpTypeVoid
|
||||
%8 = OpTypeFunction %void
|
||||
%float = OpTypeFloat 32
|
||||
%10 = OpTypeImage %float 2D 0 0 0 1 Unknown
|
||||
%_ptr_UniformConstant_10 = OpTypePointer UniformConstant %10
|
||||
%12 = OpTypeSampler
|
||||
%_ptr_UniformConstant_12 = OpTypePointer UniformConstant %12
|
||||
%14 = OpTypeSampledImage %10
|
||||
%v4float = OpTypeVector %float 4
|
||||
%v2float = OpTypeVector %float 2
|
||||
%_ptr_Output_v4float = OpTypePointer Output %v4float
|
||||
%3 = OpVariable %_ptr_Output_v4float Output
|
||||
%int = OpTypeInt 32 1
|
||||
%_ptr_Input_int = OpTypePointer Input %int
|
||||
%gl_VertexIndex = OpVariable %_ptr_Input_int Input
|
||||
%_struct_6 = OpTypeStruct %v4float
|
||||
%_ptr_Output__struct_6 = OpTypePointer Output %_struct_6
|
||||
%5 = OpVariable %_ptr_Output__struct_6 Output
|
||||
%int_0 = OpConstant %int 0
|
||||
%float_0 = OpConstant %float 0
|
||||
%23 = OpConstantComposite %v2float %float_0 %float_0
|
||||
%24 = OpVariable %_ptr_UniformConstant_10 UniformConstant
|
||||
%25 = OpVariable %_ptr_UniformConstant_12 UniformConstant
|
||||
%main = OpFunction %void None %8
|
||||
%26 = OpLabel
|
||||
%27 = OpLoad %12 %25
|
||||
%28 = OpLoad %10 %24
|
||||
%29 = OpSampledImage %14 %28 %27
|
||||
%30 = OpImageSampleImplicitLod %v4float %29 %23
|
||||
%31 = OpAccessChain %_ptr_Output_v4float %5 %int_0
|
||||
OpStore %31 %30
|
||||
OpReturn
|
||||
OpFunctionEnd)";
|
||||
|
||||
SinglePassRunAndMatch<opt::ReplaceInvalidOpcodePass>(text, false);
|
||||
}
|
||||
|
||||
TEST_F(ReplaceInvalidOpcodeTest, ReplaceInstructionInNonEntryPoint) {
|
||||
const std::string text = R"(
|
||||
; CHECK: [[special_const:%\w+]] = OpConstant %float -6.25985e+18
|
||||
; CHECK: [[constant:%\w+]] = OpConstantComposite %v4float [[special_const]] [[special_const]] [[special_const]] [[special_const]]
|
||||
; CHECK-NOT: OpImageSampleImplicitLod
|
||||
; CHECK: OpStore [[:%\w+]] [[constant]]
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Vertex %main "main" %3 %gl_VertexIndex %5
|
||||
OpSource GLSL 400
|
||||
OpSourceExtension "GL_ARB_separate_shader_objects"
|
||||
OpSourceExtension "GL_ARB_shading_language_420pack"
|
||||
OpName %main "main"
|
||||
OpDecorate %3 Location 0
|
||||
OpDecorate %gl_VertexIndex BuiltIn VertexIndex
|
||||
OpMemberDecorate %_struct_6 0 BuiltIn Position
|
||||
OpDecorate %_struct_6 Block
|
||||
%void = OpTypeVoid
|
||||
%8 = OpTypeFunction %void
|
||||
%float = OpTypeFloat 32
|
||||
%10 = OpTypeImage %float 2D 0 0 0 1 Unknown
|
||||
%_ptr_UniformConstant_10 = OpTypePointer UniformConstant %10
|
||||
%12 = OpTypeSampler
|
||||
%_ptr_UniformConstant_12 = OpTypePointer UniformConstant %12
|
||||
%14 = OpTypeSampledImage %10
|
||||
%v4float = OpTypeVector %float 4
|
||||
%v2float = OpTypeVector %float 2
|
||||
%_ptr_Output_v4float = OpTypePointer Output %v4float
|
||||
%3 = OpVariable %_ptr_Output_v4float Output
|
||||
%int = OpTypeInt 32 1
|
||||
%_ptr_Input_int = OpTypePointer Input %int
|
||||
%gl_VertexIndex = OpVariable %_ptr_Input_int Input
|
||||
%_struct_6 = OpTypeStruct %v4float
|
||||
%_ptr_Output__struct_6 = OpTypePointer Output %_struct_6
|
||||
%5 = OpVariable %_ptr_Output__struct_6 Output
|
||||
%int_0 = OpConstant %int 0
|
||||
%float_0 = OpConstant %float 0
|
||||
%23 = OpConstantComposite %v2float %float_0 %float_0
|
||||
%24 = OpVariable %_ptr_UniformConstant_10 UniformConstant
|
||||
%25 = OpVariable %_ptr_UniformConstant_12 UniformConstant
|
||||
%main = OpFunction %void None %8
|
||||
%26 = OpLabel
|
||||
%27 = OpFunctionCall %void %28
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
%28 = OpFunction %void None %8
|
||||
%29 = OpLabel
|
||||
%30 = OpLoad %12 %25
|
||||
%31 = OpLoad %10 %24
|
||||
%32 = OpSampledImage %14 %31 %30
|
||||
%33 = OpImageSampleImplicitLod %v4float %32 %23
|
||||
%34 = OpAccessChain %_ptr_Output_v4float %5 %int_0
|
||||
OpStore %34 %33
|
||||
OpReturn
|
||||
OpFunctionEnd)";
|
||||
|
||||
SinglePassRunAndMatch<opt::ReplaceInvalidOpcodePass>(text, false);
|
||||
}
|
||||
|
||||
TEST_F(ReplaceInvalidOpcodeTest, ReplaceInstructionMultipleEntryPoints) {
|
||||
const std::string text = R"(
|
||||
; CHECK: [[special_const:%\w+]] = OpConstant %float -6.25985e+18
|
||||
; CHECK: [[constant:%\w+]] = OpConstantComposite %v4float [[special_const]] [[special_const]] [[special_const]] [[special_const]]
|
||||
; CHECK-NOT: OpImageSampleImplicitLod
|
||||
; CHECK: OpStore [[:%\w+]] [[constant]]
|
||||
; CHECK-NOT: OpImageSampleImplicitLod
|
||||
; CHECK: OpStore [[:%\w+]] [[constant]]
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Vertex %main "main" %3 %gl_VertexIndex %5
|
||||
OpEntryPoint Vertex %main2 "main2" %3 %gl_VertexIndex %5
|
||||
OpSource GLSL 400
|
||||
OpSourceExtension "GL_ARB_separate_shader_objects"
|
||||
OpSourceExtension "GL_ARB_shading_language_420pack"
|
||||
OpName %main "main"
|
||||
OpName %main2 "main2"
|
||||
OpDecorate %3 Location 0
|
||||
OpDecorate %gl_VertexIndex BuiltIn VertexIndex
|
||||
OpMemberDecorate %_struct_6 0 BuiltIn Position
|
||||
OpDecorate %_struct_6 Block
|
||||
%void = OpTypeVoid
|
||||
%8 = OpTypeFunction %void
|
||||
%float = OpTypeFloat 32
|
||||
%10 = OpTypeImage %float 2D 0 0 0 1 Unknown
|
||||
%_ptr_UniformConstant_10 = OpTypePointer UniformConstant %10
|
||||
%12 = OpTypeSampler
|
||||
%_ptr_UniformConstant_12 = OpTypePointer UniformConstant %12
|
||||
%14 = OpTypeSampledImage %10
|
||||
%v4float = OpTypeVector %float 4
|
||||
%v2float = OpTypeVector %float 2
|
||||
%_ptr_Output_v4float = OpTypePointer Output %v4float
|
||||
%3 = OpVariable %_ptr_Output_v4float Output
|
||||
%int = OpTypeInt 32 1
|
||||
%_ptr_Input_int = OpTypePointer Input %int
|
||||
%gl_VertexIndex = OpVariable %_ptr_Input_int Input
|
||||
%_struct_6 = OpTypeStruct %v4float
|
||||
%_ptr_Output__struct_6 = OpTypePointer Output %_struct_6
|
||||
%5 = OpVariable %_ptr_Output__struct_6 Output
|
||||
%int_0 = OpConstant %int 0
|
||||
%float_0 = OpConstant %float 0
|
||||
%23 = OpConstantComposite %v2float %float_0 %float_0
|
||||
%24 = OpVariable %_ptr_UniformConstant_10 UniformConstant
|
||||
%25 = OpVariable %_ptr_UniformConstant_12 UniformConstant
|
||||
%main = OpFunction %void None %8
|
||||
%26 = OpLabel
|
||||
%27 = OpLoad %12 %25
|
||||
%28 = OpLoad %10 %24
|
||||
%29 = OpSampledImage %14 %28 %27
|
||||
%30 = OpImageSampleImplicitLod %v4float %29 %23
|
||||
%31 = OpAccessChain %_ptr_Output_v4float %5 %int_0
|
||||
OpStore %31 %30
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
%main2 = OpFunction %void None %8
|
||||
%46 = OpLabel
|
||||
%47 = OpLoad %12 %25
|
||||
%48 = OpLoad %10 %24
|
||||
%49 = OpSampledImage %14 %48 %47
|
||||
%50 = OpImageSampleImplicitLod %v4float %49 %23
|
||||
%51 = OpAccessChain %_ptr_Output_v4float %5 %int_0
|
||||
OpStore %51 %50
|
||||
OpReturn
|
||||
OpFunctionEnd)";
|
||||
|
||||
SinglePassRunAndMatch<opt::ReplaceInvalidOpcodePass>(text, false);
|
||||
}
|
||||
TEST_F(ReplaceInvalidOpcodeTest, DontReplaceInstruction) {
|
||||
const std::string text = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %main "main" %3 %gl_VertexIndex %5
|
||||
OpSource GLSL 400
|
||||
OpSourceExtension "GL_ARB_separate_shader_objects"
|
||||
OpSourceExtension "GL_ARB_shading_language_420pack"
|
||||
OpName %main "main"
|
||||
OpDecorate %3 Location 0
|
||||
OpDecorate %gl_VertexIndex BuiltIn VertexIndex
|
||||
OpMemberDecorate %_struct_6 0 BuiltIn Position
|
||||
OpDecorate %_struct_6 Block
|
||||
%void = OpTypeVoid
|
||||
%8 = OpTypeFunction %void
|
||||
%float = OpTypeFloat 32
|
||||
%10 = OpTypeImage %float 2D 0 0 0 1 Unknown
|
||||
%_ptr_UniformConstant_10 = OpTypePointer UniformConstant %10
|
||||
%12 = OpTypeSampler
|
||||
%_ptr_UniformConstant_12 = OpTypePointer UniformConstant %12
|
||||
%14 = OpTypeSampledImage %10
|
||||
%v4float = OpTypeVector %float 4
|
||||
%v2float = OpTypeVector %float 2
|
||||
%_ptr_Output_v4float = OpTypePointer Output %v4float
|
||||
%3 = OpVariable %_ptr_Output_v4float Output
|
||||
%int = OpTypeInt 32 1
|
||||
%_ptr_Input_int = OpTypePointer Input %int
|
||||
%gl_VertexIndex = OpVariable %_ptr_Input_int Input
|
||||
%_struct_6 = OpTypeStruct %v4float
|
||||
%_ptr_Output__struct_6 = OpTypePointer Output %_struct_6
|
||||
%5 = OpVariable %_ptr_Output__struct_6 Output
|
||||
%int_0 = OpConstant %int 0
|
||||
%float_0 = OpConstant %float 0
|
||||
%23 = OpConstantComposite %v2float %float_0 %float_0
|
||||
%24 = OpVariable %_ptr_UniformConstant_10 UniformConstant
|
||||
%25 = OpVariable %_ptr_UniformConstant_12 UniformConstant
|
||||
%main = OpFunction %void None %8
|
||||
%26 = OpLabel
|
||||
%27 = OpLoad %12 %25
|
||||
%28 = OpLoad %10 %24
|
||||
%29 = OpSampledImage %14 %28 %27
|
||||
%30 = OpImageSampleImplicitLod %v4float %29 %23
|
||||
%31 = OpAccessChain %_ptr_Output_v4float %5 %int_0
|
||||
OpStore %31 %30
|
||||
OpReturn
|
||||
OpFunctionEnd)";
|
||||
|
||||
auto result = SinglePassRunAndDisassemble<opt::ReplaceInvalidOpcodePass>(
|
||||
text, /* skip_nop = */ true, /* do_validation = */ false);
|
||||
EXPECT_EQ(opt::Pass::Status::SuccessWithoutChange, std::get<1>(result));
|
||||
}
|
||||
|
||||
TEST_F(ReplaceInvalidOpcodeTest, MultipleEntryPointsDifferentStage) {
|
||||
const std::string text = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Vertex %main "main" %3 %gl_VertexIndex %5
|
||||
OpEntryPoint Fragment %main2 "main2" %3 %gl_VertexIndex %5
|
||||
OpSource GLSL 400
|
||||
OpSourceExtension "GL_ARB_separate_shader_objects"
|
||||
OpSourceExtension "GL_ARB_shading_language_420pack"
|
||||
OpName %main "main"
|
||||
OpName %main2 "main2"
|
||||
OpDecorate %3 Location 0
|
||||
OpDecorate %gl_VertexIndex BuiltIn VertexIndex
|
||||
OpMemberDecorate %_struct_6 0 BuiltIn Position
|
||||
OpDecorate %_struct_6 Block
|
||||
%void = OpTypeVoid
|
||||
%8 = OpTypeFunction %void
|
||||
%float = OpTypeFloat 32
|
||||
%10 = OpTypeImage %float 2D 0 0 0 1 Unknown
|
||||
%_ptr_UniformConstant_10 = OpTypePointer UniformConstant %10
|
||||
%12 = OpTypeSampler
|
||||
%_ptr_UniformConstant_12 = OpTypePointer UniformConstant %12
|
||||
%14 = OpTypeSampledImage %10
|
||||
%v4float = OpTypeVector %float 4
|
||||
%v2float = OpTypeVector %float 2
|
||||
%_ptr_Output_v4float = OpTypePointer Output %v4float
|
||||
%3 = OpVariable %_ptr_Output_v4float Output
|
||||
%int = OpTypeInt 32 1
|
||||
%_ptr_Input_int = OpTypePointer Input %int
|
||||
%gl_VertexIndex = OpVariable %_ptr_Input_int Input
|
||||
%_struct_6 = OpTypeStruct %v4float
|
||||
%_ptr_Output__struct_6 = OpTypePointer Output %_struct_6
|
||||
%5 = OpVariable %_ptr_Output__struct_6 Output
|
||||
%int_0 = OpConstant %int 0
|
||||
%float_0 = OpConstant %float 0
|
||||
%23 = OpConstantComposite %v2float %float_0 %float_0
|
||||
%24 = OpVariable %_ptr_UniformConstant_10 UniformConstant
|
||||
%25 = OpVariable %_ptr_UniformConstant_12 UniformConstant
|
||||
%main = OpFunction %void None %8
|
||||
%26 = OpLabel
|
||||
%27 = OpLoad %12 %25
|
||||
%28 = OpLoad %10 %24
|
||||
%29 = OpSampledImage %14 %28 %27
|
||||
%30 = OpImageSampleImplicitLod %v4float %29 %23
|
||||
%31 = OpAccessChain %_ptr_Output_v4float %5 %int_0
|
||||
OpStore %31 %30
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
%main2 = OpFunction %void None %8
|
||||
%46 = OpLabel
|
||||
%47 = OpLoad %12 %25
|
||||
%48 = OpLoad %10 %24
|
||||
%49 = OpSampledImage %14 %48 %47
|
||||
%50 = OpImageSampleImplicitLod %v4float %49 %23
|
||||
%51 = OpAccessChain %_ptr_Output_v4float %5 %int_0
|
||||
OpStore %51 %50
|
||||
OpReturn
|
||||
OpFunctionEnd)";
|
||||
|
||||
auto result = SinglePassRunAndDisassemble<opt::ReplaceInvalidOpcodePass>(
|
||||
text, /* skip_nop = */ true, /* do_validation = */ false);
|
||||
EXPECT_EQ(opt::Pass::Status::SuccessWithoutChange, std::get<1>(result));
|
||||
}
|
||||
|
||||
TEST_F(ReplaceInvalidOpcodeTest, DontReplaceLinkage) {
|
||||
const std::string text = R"(
|
||||
OpCapability Shader
|
||||
OpCapability Linkage
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Vertex %main "main" %3 %gl_VertexIndex %5
|
||||
OpSource GLSL 400
|
||||
OpSourceExtension "GL_ARB_separate_shader_objects"
|
||||
OpSourceExtension "GL_ARB_shading_language_420pack"
|
||||
OpName %main "main"
|
||||
OpDecorate %3 Location 0
|
||||
OpDecorate %gl_VertexIndex BuiltIn VertexIndex
|
||||
OpMemberDecorate %_struct_6 0 BuiltIn Position
|
||||
OpDecorate %_struct_6 Block
|
||||
%void = OpTypeVoid
|
||||
%8 = OpTypeFunction %void
|
||||
%float = OpTypeFloat 32
|
||||
%10 = OpTypeImage %float 2D 0 0 0 1 Unknown
|
||||
%_ptr_UniformConstant_10 = OpTypePointer UniformConstant %10
|
||||
%12 = OpTypeSampler
|
||||
%_ptr_UniformConstant_12 = OpTypePointer UniformConstant %12
|
||||
%14 = OpTypeSampledImage %10
|
||||
%v4float = OpTypeVector %float 4
|
||||
%v2float = OpTypeVector %float 2
|
||||
%_ptr_Output_v4float = OpTypePointer Output %v4float
|
||||
%3 = OpVariable %_ptr_Output_v4float Output
|
||||
%int = OpTypeInt 32 1
|
||||
%_ptr_Input_int = OpTypePointer Input %int
|
||||
%gl_VertexIndex = OpVariable %_ptr_Input_int Input
|
||||
%_struct_6 = OpTypeStruct %v4float
|
||||
%_ptr_Output__struct_6 = OpTypePointer Output %_struct_6
|
||||
%5 = OpVariable %_ptr_Output__struct_6 Output
|
||||
%int_0 = OpConstant %int 0
|
||||
%float_0 = OpConstant %float 0
|
||||
%23 = OpConstantComposite %v2float %float_0 %float_0
|
||||
%24 = OpVariable %_ptr_UniformConstant_10 UniformConstant
|
||||
%25 = OpVariable %_ptr_UniformConstant_12 UniformConstant
|
||||
%main = OpFunction %void None %8
|
||||
%26 = OpLabel
|
||||
%27 = OpLoad %12 %25
|
||||
%28 = OpLoad %10 %24
|
||||
%29 = OpSampledImage %14 %28 %27
|
||||
%30 = OpImageSampleImplicitLod %v4float %29 %23
|
||||
%31 = OpAccessChain %_ptr_Output_v4float %5 %int_0
|
||||
OpStore %31 %30
|
||||
OpReturn
|
||||
OpFunctionEnd)";
|
||||
|
||||
auto result = SinglePassRunAndDisassemble<opt::ReplaceInvalidOpcodePass>(
|
||||
text, /* skip_nop = */ true, /* do_validation = */ false);
|
||||
EXPECT_EQ(opt::Pass::Status::SuccessWithoutChange, std::get<1>(result));
|
||||
}
|
||||
|
||||
TEST_F(ReplaceInvalidOpcodeTest, BarrierDontReplace) {
|
||||
const std::string text = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint GLCompute %main "main"
|
||||
OpExecutionMode %main LocalSize 1 1 1
|
||||
OpSource GLSL 450
|
||||
OpSourceExtension "GL_GOOGLE_cpp_style_line_directive"
|
||||
OpSourceExtension "GL_GOOGLE_include_directive"
|
||||
OpName %main "main"
|
||||
%void = OpTypeVoid
|
||||
%3 = OpTypeFunction %void
|
||||
%uint = OpTypeInt 32 0
|
||||
%uint_2 = OpConstant %uint 2
|
||||
%uint_264 = OpConstant %uint 264
|
||||
%main = OpFunction %void None %3
|
||||
%5 = OpLabel
|
||||
OpControlBarrier %uint_2 %uint_2 %uint_264
|
||||
OpReturn
|
||||
OpFunctionEnd)";
|
||||
|
||||
auto result = SinglePassRunAndDisassemble<opt::ReplaceInvalidOpcodePass>(
|
||||
text, /* skip_nop = */ true, /* do_validation = */ false);
|
||||
EXPECT_EQ(opt::Pass::Status::SuccessWithoutChange, std::get<1>(result));
|
||||
}
|
||||
|
||||
TEST_F(ReplaceInvalidOpcodeTest, BarrierReplace) {
|
||||
const std::string text = R"(
|
||||
; CHECK-NOT: OpControlBarrier
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Vertex %main "main"
|
||||
OpExecutionMode %main LocalSize 1 1 1
|
||||
OpSource GLSL 450
|
||||
OpSourceExtension "GL_GOOGLE_cpp_style_line_directive"
|
||||
OpSourceExtension "GL_GOOGLE_include_directive"
|
||||
OpName %main "main"
|
||||
%void = OpTypeVoid
|
||||
%3 = OpTypeFunction %void
|
||||
%uint = OpTypeInt 32 0
|
||||
%uint_2 = OpConstant %uint 2
|
||||
%uint_264 = OpConstant %uint 264
|
||||
%main = OpFunction %void None %3
|
||||
%5 = OpLabel
|
||||
OpControlBarrier %uint_2 %uint_2 %uint_264
|
||||
OpReturn
|
||||
OpFunctionEnd)";
|
||||
|
||||
SinglePassRunAndMatch<opt::ReplaceInvalidOpcodePass>(text, false);
|
||||
}
|
||||
|
||||
struct Message {
|
||||
spv_message_level_t level;
|
||||
const char* source_file;
|
||||
uint32_t line_number;
|
||||
uint32_t column_number;
|
||||
const char* message;
|
||||
};
|
||||
|
||||
MessageConsumer GetTestMessageConsumer(
|
||||
std::vector<Message>& expected_messages) {
|
||||
return [&expected_messages](spv_message_level_t level, const char* source,
|
||||
const spv_position_t& position,
|
||||
const char* message) {
|
||||
EXPECT_TRUE(!expected_messages.empty());
|
||||
if (expected_messages.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
EXPECT_EQ(expected_messages[0].level, level);
|
||||
EXPECT_EQ(expected_messages[0].line_number, position.line);
|
||||
EXPECT_EQ(expected_messages[0].column_number, position.column);
|
||||
EXPECT_STREQ(expected_messages[0].source_file, source);
|
||||
EXPECT_STREQ(expected_messages[0].message, message);
|
||||
|
||||
expected_messages.erase(expected_messages.begin());
|
||||
};
|
||||
}
|
||||
|
||||
TEST_F(ReplaceInvalidOpcodeTest, MessageTest) {
|
||||
const std::string text = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Vertex %main "main" %3 %gl_VertexIndex %5
|
||||
OpSource GLSL 400
|
||||
%6 = OpString "test.hlsl"
|
||||
OpSourceExtension "GL_ARB_separate_shader_objects"
|
||||
OpSourceExtension "GL_ARB_shading_language_420pack"
|
||||
OpName %main "main"
|
||||
OpDecorate %3 Location 0
|
||||
OpDecorate %gl_VertexIndex BuiltIn VertexIndex
|
||||
OpMemberDecorate %_struct_7 0 BuiltIn Position
|
||||
OpDecorate %_struct_7 Block
|
||||
%void = OpTypeVoid
|
||||
%9 = OpTypeFunction %void
|
||||
%float = OpTypeFloat 32
|
||||
%11 = OpTypeImage %float 2D 0 0 0 1 Unknown
|
||||
%_ptr_UniformConstant_11 = OpTypePointer UniformConstant %11
|
||||
%13 = OpTypeSampler
|
||||
%_ptr_UniformConstant_13 = OpTypePointer UniformConstant %13
|
||||
%15 = OpTypeSampledImage %11
|
||||
%v4float = OpTypeVector %float 4
|
||||
%v2float = OpTypeVector %float 2
|
||||
%_ptr_Output_v4float = OpTypePointer Output %v4float
|
||||
%3 = OpVariable %_ptr_Output_v4float Output
|
||||
%int = OpTypeInt 32 1
|
||||
%_ptr_Input_int = OpTypePointer Input %int
|
||||
%gl_VertexIndex = OpVariable %_ptr_Input_int Input
|
||||
%_struct_7 = OpTypeStruct %v4float
|
||||
%_ptr_Output__struct_7 = OpTypePointer Output %_struct_7
|
||||
%5 = OpVariable %_ptr_Output__struct_7 Output
|
||||
%int_0 = OpConstant %int 0
|
||||
%float_0 = OpConstant %float 0
|
||||
%24 = OpConstantComposite %v2float %float_0 %float_0
|
||||
%25 = OpVariable %_ptr_UniformConstant_11 UniformConstant
|
||||
%26 = OpVariable %_ptr_UniformConstant_13 UniformConstant
|
||||
%main = OpFunction %void None %9
|
||||
%27 = OpLabel
|
||||
OpLine %6 2 4
|
||||
%28 = OpLoad %13 %26
|
||||
%29 = OpLoad %11 %25
|
||||
%30 = OpSampledImage %15 %29 %28
|
||||
%31 = OpImageSampleImplicitLod %v4float %30 %24
|
||||
%32 = OpAccessChain %_ptr_Output_v4float %5 %int_0
|
||||
OpStore %32 %31
|
||||
OpReturn
|
||||
OpFunctionEnd)";
|
||||
|
||||
std::vector<Message> messages = {
|
||||
{SPV_MSG_WARNING, "test.hlsl", 2, 4,
|
||||
"Removing ImageSampleImplicitLod instruction because of incompatible "
|
||||
"execution model."}};
|
||||
SetMessageConsumer(GetTestMessageConsumer(messages));
|
||||
auto result = SinglePassRunAndDisassemble<opt::ReplaceInvalidOpcodePass>(
|
||||
text, /* skip_nop = */ true, /* do_validation = */ false);
|
||||
EXPECT_EQ(opt::Pass::Status::SuccessWithChange, std::get<1>(result));
|
||||
}
|
||||
|
||||
TEST_F(ReplaceInvalidOpcodeTest, MultipleMessageTest) {
|
||||
const std::string text = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Vertex %main "main" %3 %gl_VertexIndex %5
|
||||
OpSource GLSL 400
|
||||
%6 = OpString "test.hlsl"
|
||||
OpSourceExtension "GL_ARB_separate_shader_objects"
|
||||
OpSourceExtension "GL_ARB_shading_language_420pack"
|
||||
OpName %main "main"
|
||||
OpDecorate %3 Location 0
|
||||
OpDecorate %gl_VertexIndex BuiltIn VertexIndex
|
||||
OpMemberDecorate %_struct_7 0 BuiltIn Position
|
||||
OpDecorate %_struct_7 Block
|
||||
%void = OpTypeVoid
|
||||
%9 = OpTypeFunction %void
|
||||
%float = OpTypeFloat 32
|
||||
%11 = OpTypeImage %float 2D 0 0 0 1 Unknown
|
||||
%_ptr_UniformConstant_11 = OpTypePointer UniformConstant %11
|
||||
%13 = OpTypeSampler
|
||||
%_ptr_UniformConstant_13 = OpTypePointer UniformConstant %13
|
||||
%15 = OpTypeSampledImage %11
|
||||
%v4float = OpTypeVector %float 4
|
||||
%v2float = OpTypeVector %float 2
|
||||
%_ptr_Output_v4float = OpTypePointer Output %v4float
|
||||
%3 = OpVariable %_ptr_Output_v4float Output
|
||||
%int = OpTypeInt 32 1
|
||||
%_ptr_Input_int = OpTypePointer Input %int
|
||||
%gl_VertexIndex = OpVariable %_ptr_Input_int Input
|
||||
%_struct_7 = OpTypeStruct %v4float
|
||||
%_ptr_Output__struct_7 = OpTypePointer Output %_struct_7
|
||||
%5 = OpVariable %_ptr_Output__struct_7 Output
|
||||
%int_0 = OpConstant %int 0
|
||||
%float_0 = OpConstant %float 0
|
||||
%24 = OpConstantComposite %v2float %float_0 %float_0
|
||||
%25 = OpVariable %_ptr_UniformConstant_11 UniformConstant
|
||||
%26 = OpVariable %_ptr_UniformConstant_13 UniformConstant
|
||||
%main = OpFunction %void None %9
|
||||
%27 = OpLabel
|
||||
OpLine %6 2 4
|
||||
%28 = OpLoad %13 %26
|
||||
%29 = OpLoad %11 %25
|
||||
%30 = OpSampledImage %15 %29 %28
|
||||
%31 = OpImageSampleImplicitLod %v4float %30 %24
|
||||
OpLine %6 12 4
|
||||
%41 = OpImageSampleProjImplicitLod %v4float %30 %24
|
||||
%32 = OpAccessChain %_ptr_Output_v4float %5 %int_0
|
||||
OpStore %32 %31
|
||||
OpReturn
|
||||
OpFunctionEnd)";
|
||||
|
||||
std::vector<Message> messages = {
|
||||
{SPV_MSG_WARNING, "test.hlsl", 2, 4,
|
||||
"Removing ImageSampleImplicitLod instruction because of incompatible "
|
||||
"execution model."},
|
||||
{SPV_MSG_WARNING, "test.hlsl", 12, 4,
|
||||
"Removing ImageSampleProjImplicitLod instruction because of "
|
||||
"incompatible "
|
||||
"execution model."}};
|
||||
SetMessageConsumer(GetTestMessageConsumer(messages));
|
||||
auto result = SinglePassRunAndDisassemble<opt::ReplaceInvalidOpcodePass>(
|
||||
text, /* skip_nop = */ true, /* do_validation = */ false);
|
||||
EXPECT_EQ(opt::Pass::Status::SuccessWithChange, std::get<1>(result));
|
||||
}
|
||||
#endif
|
||||
} // anonymous namespace
|
@ -240,6 +240,10 @@ Options (in lexicographical order):
|
||||
Allow store from one struct type to a different type with
|
||||
compatible layout and members. This option is forwarded to the
|
||||
validator.
|
||||
--replace-invalid-opcode
|
||||
Replaces instructions whose opcode is valid for shader modules,
|
||||
but not for the current shader stage. To have an effect, all
|
||||
entry points must have the same execution model.
|
||||
--scalar-replacement
|
||||
Replace aggregate function scope variables that are only accessed
|
||||
via their elements with new function variables representing each
|
||||
@ -459,6 +463,8 @@ OptStatus ParseFlags(int argc, const char** argv, Optimizer* optimizer,
|
||||
optimizer->RegisterPass(CreateWorkaround1209Pass());
|
||||
} else if (0 == strcmp(cur_arg, "--relax-struct-store")) {
|
||||
options->relax_struct_store = true;
|
||||
} else if (0 == strcmp(cur_arg, "--replace-invalid-opcode")) {
|
||||
optimizer->RegisterPass(CreateReplaceInvalidOpcodePass());
|
||||
} else if (0 == strcmp(cur_arg, "--skip-validation")) {
|
||||
*skip_validator = true;
|
||||
} else if (0 == strcmp(cur_arg, "-O")) {
|
||||
|
Loading…
Reference in New Issue
Block a user