Propagate OpLine to all applied instructions in spirv-opt (#3951)

Based on the OpLine spec, an OpLine instruction must be applied to
the instructions physically following it up to the first occurrence
of the next end of block, the next OpLine instruction, or the next
OpNoLine instruction.

```
OpLine %file 0 0
OpNoLine
OpLine %file 1 1
OpStore %foo %int_1
%value = OpLoad %int %foo
OpLine %file 2 2
```

For the above code, the current spirv-opt keeps three line
instructions `OpLine %file 0 0`, `OpNoLine`, and `OpLine %file 1 1`
in `std::vector<Instruction> dbg_line_insts_` of Instruction class
for `OpStore %foo %int_1`. It does not put any line instruction to
`std::vector<Instruction> dbg_line_insts_` of
`%value = OpLoad %int %foo` even though `OpLine %file 1 1` must be
applied to `%value = OpLoad %int %foo` based on the spec.

This results in the missing line information for
`%value = OpLoad %int %foo` while each spirv-opt pass optimizes the
code. We have to put `OpLine %file 1 1` to
`std::vector<Instruction> dbg_line_insts_` of
both `%value = OpLoad %int %foo` and `OpStore %foo %int_1`.

This commit conducts the line instruction propagation and skips
emitting the eliminated line instructions at the end, which are the same
with PropagateLineInfoPass and RedundantLineInfoElimPass. This
commit removes PropagateLineInfoPass and RedundantLineInfoElimPass.

KhronosGroup/glslang#2440 is a related PR that stop using
PropagateLineInfoPass and RedundantLineInfoElimPass from glslang.
When the code in this PR applied, the glslang tests will pass.
This commit is contained in:
Jaebaek Seo 2020-10-29 13:06:30 -04:00 committed by GitHub
parent 7403dfafd8
commit 56d0f50357
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 180 additions and 998 deletions

View File

@ -149,7 +149,6 @@ SPVTOOLS_OPT_SRC_FILES := \
source/opt/pass.cpp \
source/opt/pass_manager.cpp \
source/opt/private_to_local_pass.cpp \
source/opt/process_lines_pass.cpp \
source/opt/propagator.cpp \
source/opt/reduce_load_size.cpp \
source/opt/redundancy_elimination.cpp \

View File

@ -654,8 +654,6 @@ static_library("spvtools_opt") {
"source/opt/passes.h",
"source/opt/private_to_local_pass.cpp",
"source/opt/private_to_local_pass.h",
"source/opt/process_lines_pass.cpp",
"source/opt/process_lines_pass.h",
"source/opt/propagator.cpp",
"source/opt/propagator.h",
"source/opt/reduce_load_size.cpp",

View File

@ -536,30 +536,6 @@ Optimizer::PassToken CreateDeadInsertElimPass();
// eliminated with standard dead code elimination.
Optimizer::PassToken CreateAggressiveDCEPass();
// Create line propagation pass
// This pass propagates line information based on the rules for OpLine and
// OpNoline and clones an appropriate line instruction into every instruction
// which does not already have debug line instructions.
//
// This pass is intended to maximize preservation of source line information
// through passes which delete, move and clone instructions. Ideally it should
// be run before any such pass. It is a bookend pass with EliminateDeadLines
// which can be used to remove redundant line instructions at the end of a
// run of such passes and reduce final output file size.
Optimizer::PassToken CreatePropagateLineInfoPass();
// Create dead line elimination pass
// This pass eliminates redundant line instructions based on the rules for
// OpLine and OpNoline. Its main purpose is to reduce the size of the file
// need to store the SPIR-V without losing line information.
//
// This is a bookend pass with PropagateLines which attaches line instructions
// to every instruction to preserve line information during passes which
// delete, move and clone instructions. DeadLineElim should be run after
// PropagateLines and all such subsequent passes. Normally it would be one
// of the last passes to be run.
Optimizer::PassToken CreateRedundantLineInfoElimPass();
// Creates a compact ids pass.
// The pass remaps result ids to a compact and gapless range starting from %1.
Optimizer::PassToken CreateCompactIdsPass();

View File

@ -89,7 +89,6 @@ set(SPIRV_TOOLS_OPT_SOURCES
pass.h
pass_manager.h
private_to_local_pass.h
process_lines_pass.h
propagator.h
reduce_load_size.h
redundancy_elimination.h
@ -196,7 +195,6 @@ set(SPIRV_TOOLS_OPT_SOURCES
pass.cpp
pass_manager.cpp
private_to_local_pass.cpp
process_lines_pass.cpp
propagator.cpp
reduce_load_size.cpp
redundancy_elimination.cpp

View File

@ -41,6 +41,7 @@ bool IrLoader::AddInstruction(const spv_parsed_instruction_t* inst) {
++inst_index_;
const auto opcode = static_cast<SpvOp>(inst->opcode);
if (IsDebugLineInst(opcode)) {
last_line_inst_.reset();
dbg_line_info_.push_back(
Instruction(module()->context(), *inst, last_dbg_scope_));
return true;
@ -90,7 +91,16 @@ bool IrLoader::AddInstruction(const spv_parsed_instruction_t* inst) {
std::unique_ptr<Instruction> spv_inst(
new Instruction(module()->context(), *inst, std::move(dbg_line_info_)));
dbg_line_info_.clear();
if (!spv_inst->dbg_line_insts().empty()) {
if (spv_inst->dbg_line_insts().back().opcode() != SpvOpNoLine) {
last_line_inst_ = std::unique_ptr<Instruction>(
spv_inst->dbg_line_insts().back().Clone(module()->context()));
}
dbg_line_info_.clear();
} else if (last_line_inst_ != nullptr) {
last_line_inst_->SetDebugScope(last_dbg_scope_);
spv_inst->dbg_line_insts().push_back(*last_line_inst_);
}
const char* src = source_.c_str();
spv_position_t loc = {inst_index_, 0, 0};
@ -141,6 +151,8 @@ bool IrLoader::AddInstruction(const spv_parsed_instruction_t* inst) {
function_->AddBasicBlock(std::move(block_));
block_ = nullptr;
last_dbg_scope_ = DebugScope(kNoDebugScope, kNoInlinedAt);
last_line_inst_.reset();
dbg_line_info_.clear();
} else {
if (function_ == nullptr) { // Outside function definition
SPIRV_ASSERT(consumer_, block_ == nullptr);

View File

@ -78,6 +78,8 @@ class IrLoader {
std::unique_ptr<BasicBlock> block_;
// Line related debug instructions accumulated thus far.
std::vector<Instruction> dbg_line_info_;
// Line instruction that should be applied to the next instruction.
std::unique_ptr<Instruction> last_line_inst_;
// The last DebugScope information that IrLoader::AddInstruction() handled.
DebugScope last_dbg_scope_;

View File

@ -143,8 +143,38 @@ void Module::ToBinary(std::vector<uint32_t>* binary, bool skip_nop) const {
size_t bound_idx = binary->size() - 2;
DebugScope last_scope(kNoDebugScope, kNoInlinedAt);
auto write_inst = [binary, skip_nop, &last_scope,
this](const Instruction* i) {
const Instruction* last_line_inst = nullptr;
bool between_merge_and_branch = false;
auto write_inst = [binary, skip_nop, &last_scope, &last_line_inst,
&between_merge_and_branch, this](const Instruction* i) {
// Skip emitting line instructions between merge and branch instructions.
auto opcode = i->opcode();
if (between_merge_and_branch &&
(opcode == SpvOpLine || opcode == SpvOpNoLine)) {
return;
}
between_merge_and_branch = false;
if (last_line_inst != nullptr) {
// If the current instruction is OpLine and it is the same with
// the last line instruction that is still effective (can be applied
// to the next instruction), we skip writing the current instruction.
if (opcode == SpvOpLine) {
uint32_t operand_index = 0;
if (last_line_inst->WhileEachInOperand(
[&operand_index, i](const uint32_t* word) {
assert(i->NumInOperandWords() > operand_index);
return *word == i->GetSingleWordInOperand(operand_index++);
})) {
return;
}
} else if (opcode != SpvOpNoLine && i->dbg_line_insts().empty()) {
// If the current instruction does not have the line information,
// the last line information is not effective any more. Emit OpNoLine
// to specify it.
binary->push_back((1 << 16) | static_cast<uint16_t>(SpvOpNoLine));
last_line_inst = nullptr;
}
}
if (!(skip_nop && i->IsNop())) {
const auto& scope = i->GetDebugScope();
if (scope != last_scope) {
@ -157,6 +187,15 @@ void Module::ToBinary(std::vector<uint32_t>* binary, bool skip_nop) const {
i->ToBinaryWithoutAttachedDebugInsts(binary);
}
// Update the last line instruction.
if (IsTerminatorInst(opcode) || opcode == SpvOpNoLine) {
last_line_inst = nullptr;
} else if (opcode == SpvOpLoopMerge || opcode == SpvOpSelectionMerge) {
between_merge_and_branch = true;
last_line_inst = nullptr;
} else if (opcode == SpvOpLine) {
last_line_inst = i;
}
};
ForEachInst(write_inst, true);

View File

@ -246,6 +246,12 @@ class Module {
// If |skip_nop| is true and this is a OpNop, do nothing.
void ToBinary(std::vector<uint32_t>* binary, bool skip_nop) const;
// Pushes the binary segments for this instruction into the back of *|binary|
// including all OpLine and OpNoLine even if we can skip emitting some line
// instructions. If |skip_nop| is true and this is a OpNop, do nothing.
void ToBinaryWithAllOpLines(std::vector<uint32_t>* binary,
bool skip_nop) const;
// Returns 1 more than the maximum Id value mentioned in the module.
uint32_t ComputeIdBound() const;

View File

@ -339,10 +339,6 @@ bool Optimizer::RegisterPassFromFlag(const std::string& flag) {
RegisterPass(CreateDescriptorScalarReplacementPass());
} else if (pass_name == "eliminate-dead-code-aggressive") {
RegisterPass(CreateAggressiveDCEPass());
} else if (pass_name == "propagate-line-info") {
RegisterPass(CreatePropagateLineInfoPass());
} else if (pass_name == "eliminate-redundant-line-info") {
RegisterPass(CreateRedundantLineInfoElimPass());
} else if (pass_name == "eliminate-insert-extract") {
RegisterPass(CreateInsertExtractElimPass());
} else if (pass_name == "eliminate-local-single-block") {
@ -757,16 +753,6 @@ Optimizer::PassToken CreateAggressiveDCEPass() {
MakeUnique<opt::AggressiveDCEPass>());
}
Optimizer::PassToken CreatePropagateLineInfoPass() {
return MakeUnique<Optimizer::PassToken::Impl>(
MakeUnique<opt::ProcessLinesPass>(opt::kLinesPropagateLines));
}
Optimizer::PassToken CreateRedundantLineInfoElimPass() {
return MakeUnique<Optimizer::PassToken::Impl>(
MakeUnique<opt::ProcessLinesPass>(opt::kLinesEliminateDeadLines));
}
Optimizer::PassToken CreateCompactIdsPass() {
return MakeUnique<Optimizer::PassToken::Impl>(
MakeUnique<opt::CompactIdsPass>());

View File

@ -61,7 +61,6 @@
#include "source/opt/merge_return_pass.h"
#include "source/opt/null_pass.h"
#include "source/opt/private_to_local_pass.h"
#include "source/opt/process_lines_pass.h"
#include "source/opt/reduce_load_size.h"
#include "source/opt/redundancy_elimination.h"
#include "source/opt/relax_float_ops_pass.h"

View File

@ -1,157 +0,0 @@
// Copyright (c) 2018 The Khronos Group Inc.
// Copyright (c) 2018 Valve Corporation
// Copyright (c) 2018 LunarG 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 "source/opt/process_lines_pass.h"
#include <set>
#include <unordered_set>
#include <vector>
namespace {
// Input Operand Indices
static const int kSpvLineFileInIdx = 0;
static const int kSpvLineLineInIdx = 1;
static const int kSpvLineColInIdx = 2;
} // anonymous namespace
namespace spvtools {
namespace opt {
Pass::Status ProcessLinesPass::Process() {
bool modified = ProcessLines();
return (modified ? Status::SuccessWithChange : Status::SuccessWithoutChange);
}
bool ProcessLinesPass::ProcessLines() {
bool modified = false;
uint32_t file_id = 0;
uint32_t line = 0;
uint32_t col = 0;
// Process types, globals, constants
for (Instruction& inst : get_module()->types_values())
modified |= line_process_func_(&inst, &file_id, &line, &col);
// Process functions
for (Function& function : *get_module()) {
modified |= line_process_func_(&function.DefInst(), &file_id, &line, &col);
function.ForEachParam(
[this, &modified, &file_id, &line, &col](Instruction* param) {
modified |= line_process_func_(param, &file_id, &line, &col);
});
for (BasicBlock& block : function) {
modified |=
line_process_func_(block.GetLabelInst(), &file_id, &line, &col);
for (Instruction& inst : block) {
modified |= line_process_func_(&inst, &file_id, &line, &col);
// Don't process terminal instruction if preceeded by merge
if (inst.opcode() == SpvOpSelectionMerge ||
inst.opcode() == SpvOpLoopMerge)
break;
}
// Nullify line info after each block.
file_id = 0;
}
modified |= line_process_func_(function.EndInst(), &file_id, &line, &col);
}
return modified;
}
bool ProcessLinesPass::PropagateLine(Instruction* inst, uint32_t* file_id,
uint32_t* line, uint32_t* col) {
bool modified = false;
// only the last debug instruction needs to be considered
auto line_itr = inst->dbg_line_insts().rbegin();
// if no line instructions, propagate previous info
if (line_itr == inst->dbg_line_insts().rend()) {
// if no current line info, add OpNoLine, else OpLine
if (*file_id == 0)
inst->dbg_line_insts().push_back(Instruction(context(), SpvOpNoLine));
else
inst->dbg_line_insts().push_back(Instruction(
context(), SpvOpLine, 0, 0,
{{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {*file_id}},
{spv_operand_type_t::SPV_OPERAND_TYPE_LITERAL_INTEGER, {*line}},
{spv_operand_type_t::SPV_OPERAND_TYPE_LITERAL_INTEGER, {*col}}}));
modified = true;
} else {
// else pre-existing line instruction, so update source line info
if (line_itr->opcode() == SpvOpNoLine) {
*file_id = 0;
} else {
assert(line_itr->opcode() == SpvOpLine && "unexpected debug inst");
*file_id = line_itr->GetSingleWordInOperand(kSpvLineFileInIdx);
*line = line_itr->GetSingleWordInOperand(kSpvLineLineInIdx);
*col = line_itr->GetSingleWordInOperand(kSpvLineColInIdx);
}
}
return modified;
}
bool ProcessLinesPass::EliminateDeadLines(Instruction* inst, uint32_t* file_id,
uint32_t* line, uint32_t* col) {
// If no debug line instructions, return without modifying lines
if (inst->dbg_line_insts().empty()) return false;
// Only the last debug instruction needs to be considered; delete all others
bool modified = inst->dbg_line_insts().size() > 1;
Instruction last_inst = inst->dbg_line_insts().back();
inst->dbg_line_insts().clear();
// If last line is OpNoLine
if (last_inst.opcode() == SpvOpNoLine) {
// If no propagated line info, throw away redundant OpNoLine
if (*file_id == 0) {
modified = true;
// Else replace OpNoLine and propagate no line info
} else {
inst->dbg_line_insts().push_back(last_inst);
*file_id = 0;
}
} else {
// Else last line is OpLine
assert(last_inst.opcode() == SpvOpLine && "unexpected debug inst");
// If propagated info matches last line, throw away last line
if (*file_id == last_inst.GetSingleWordInOperand(kSpvLineFileInIdx) &&
*line == last_inst.GetSingleWordInOperand(kSpvLineLineInIdx) &&
*col == last_inst.GetSingleWordInOperand(kSpvLineColInIdx)) {
modified = true;
} else {
// Else replace last line and propagate line info
*file_id = last_inst.GetSingleWordInOperand(kSpvLineFileInIdx);
*line = last_inst.GetSingleWordInOperand(kSpvLineLineInIdx);
*col = last_inst.GetSingleWordInOperand(kSpvLineColInIdx);
inst->dbg_line_insts().push_back(last_inst);
}
}
return modified;
}
ProcessLinesPass::ProcessLinesPass(uint32_t func_id) {
if (func_id == kLinesPropagateLines) {
line_process_func_ = [this](Instruction* inst, uint32_t* file_id,
uint32_t* line, uint32_t* col) {
return PropagateLine(inst, file_id, line, col);
};
} else {
assert(func_id == kLinesEliminateDeadLines && "unknown Lines param");
line_process_func_ = [this](Instruction* inst, uint32_t* file_id,
uint32_t* line, uint32_t* col) {
return EliminateDeadLines(inst, file_id, line, col);
};
}
}
} // namespace opt
} // namespace spvtools

View File

@ -1,87 +0,0 @@
// Copyright (c) 2018 The Khronos Group Inc.
// Copyright (c) 2018 Valve Corporation
// Copyright (c) 2018 LunarG 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.
#ifndef SOURCE_OPT_PROPAGATE_LINES_PASS_H_
#define SOURCE_OPT_PROPAGATE_LINES_PASS_H_
#include "source/opt/function.h"
#include "source/opt/ir_context.h"
#include "source/opt/pass.h"
namespace spvtools {
namespace opt {
namespace {
// Constructor Parameters
static const int kLinesPropagateLines = 0;
static const int kLinesEliminateDeadLines = 1;
} // anonymous namespace
// See optimizer.hpp for documentation.
class ProcessLinesPass : public Pass {
using LineProcessFunction =
std::function<bool(Instruction*, uint32_t*, uint32_t*, uint32_t*)>;
public:
ProcessLinesPass(uint32_t func_id);
~ProcessLinesPass() override = default;
const char* name() const override { return "propagate-lines"; }
// See optimizer.hpp for this pass' user documentation.
Status Process() override;
IRContext::Analysis GetPreservedAnalyses() override {
return IRContext::kAnalysisDefUse |
IRContext::kAnalysisInstrToBlockMapping |
IRContext::kAnalysisDecorations | IRContext::kAnalysisCombinators |
IRContext::kAnalysisCFG | IRContext::kAnalysisDominatorAnalysis |
IRContext::kAnalysisNameMap | IRContext::kAnalysisConstants |
IRContext::kAnalysisTypes;
}
private:
// If |inst| has no debug line instruction, create one with
// |file_id, line, col|. If |inst| has debug line instructions, set
// |file_id, line, col| from the last. |file_id| equals 0 indicates no line
// info is available. Return true if |inst| modified.
bool PropagateLine(Instruction* inst, uint32_t* file_id, uint32_t* line,
uint32_t* col);
// If last debug line instruction of |inst| matches |file_id, line, col|,
// delete all debug line instructions of |inst|. If they do not match,
// replace all debug line instructions of |inst| with new line instruction
// set from |file_id, line, col|. If |inst| has no debug line instructions,
// do not modify |inst|. |file_id| equals 0 indicates no line info is
// available. Return true if |inst| modified.
bool EliminateDeadLines(Instruction* inst, uint32_t* file_id, uint32_t* line,
uint32_t* col);
// Apply lpfn() to all type, constant, global variable and function
// instructions in their physical order.
bool ProcessLines();
// A function that calls either PropagateLine or EliminateDeadLines.
// Initialized by the class constructor.
LineProcessFunction line_process_func_;
};
} // namespace opt
} // namespace spvtools
#endif // SOURCE_OPT_PROPAGATE_LINES_PASS_H_

View File

@ -78,7 +78,6 @@ add_spvtools_unittest(TARGET opt
pass_remove_duplicates_test.cpp
pass_utils.cpp
private_to_local_test.cpp
process_lines_test.cpp
propagator_test.cpp
reduce_load_size_test.cpp
redundancy_elimination_test.cpp

View File

@ -3377,7 +3377,7 @@ OpBranch %18
%18 = OpLabel
; CHECK: DebugScope [[bb3]]
; CHECK-NOT: OpLine {{%\w+}} 3 0
; CHECK: OpLine {{%\w+}} 3 0
; CHECK: DebugValue [[dbg_foo]] [[value]]
; CHECK: OpLine {{%\w+}} 4 0
; CHECK: OpStore %gl_FragColor [[value]]

View File

@ -2103,7 +2103,7 @@ OpDecorate %gl_FragCoord BuiltIn FragCoord
%uint_7 = OpConstant %uint 7
%uint_8 = OpConstant %uint 8
%uint_9 = OpConstant %uint 9
%uint_93 = OpConstant %uint 93
%uint_109 = OpConstant %uint 109
%125 = OpConstantNull %v4float
)";
@ -2180,19 +2180,23 @@ OpLine %5 24 0
%54 = OpSampledImage %37 %52 %53
%55 = OpAccessChain %_ptr_Function_v2float %i %int_0
%56 = OpLoad %v2float %55
OpNoLine
%62 = OpULessThan %bool %50 %uint_128
OpSelectionMerge %63 None
OpBranchConditional %62 %64 %65
%64 = OpLabel
%66 = OpLoad %27 %51
%67 = OpSampledImage %37 %66 %53
OpLine %5 24 0
%68 = OpImageSampleImplicitLod %v4float %67 %56
OpNoLine
OpBranch %63
%65 = OpLabel
%124 = OpFunctionCall %void %69 %uint_93 %uint_0 %50 %uint_128
%124 = OpFunctionCall %void %69 %uint_109 %uint_0 %50 %uint_128
OpBranch %63
%63 = OpLabel
%126 = OpPhi %v4float %68 %64 %125 %65
OpLine %5 24 0
%58 = OpAccessChain %_ptr_Function_v4float %ps_output %int_0
OpStore %58 %126
OpLine %5 25 0

View File

@ -21,6 +21,7 @@
#include "gtest/gtest.h"
#include "source/opt/build_module.h"
#include "source/opt/def_use_manager.h"
#include "source/opt/ir_context.h"
#include "spirv-tools/libspirv.hpp"
@ -28,6 +29,8 @@ namespace spvtools {
namespace opt {
namespace {
constexpr uint32_t kOpLineOperandLineIndex = 1;
void DoRoundTripCheck(const std::string& text) {
SpirvTools t(SPV_ENV_UNIVERSAL_1_1);
std::unique_ptr<IRContext> context =
@ -129,6 +132,110 @@ TEST(IrBuilder, KeepLineDebugInfo) {
// clang-format on
}
TEST(IrBuilder, DistributeLineDebugInfo) {
const std::string text =
// clang-format off
"OpCapability Shader\n"
"%1 = OpExtInstImport \"GLSL.std.450\"\n"
"OpMemoryModel Logical GLSL450\n"
"OpEntryPoint Vertex %main \"main\"\n"
"OpSource ESSL 310\n"
"%file = OpString \"test\"\n"
"OpName %main \"main\"\n"
"OpName %f_ \"f(\"\n"
"OpName %gv1 \"gv1\"\n"
"OpName %gv2 \"gv2\"\n"
"OpName %lv1 \"lv1\"\n"
"OpName %lv2 \"lv2\"\n"
"OpName %lv1_0 \"lv1\"\n"
"%void = OpTypeVoid\n"
"%10 = OpTypeFunction %void\n"
"OpLine %file 10 0\n"
"%float = OpTypeFloat 32\n"
"%12 = OpTypeFunction %float\n"
"%_ptr_Private_float = OpTypePointer Private %float\n"
"%gv1 = OpVariable %_ptr_Private_float Private\n"
"%float_10 = OpConstant %float 10\n"
"%gv2 = OpVariable %_ptr_Private_float Private\n"
"%float_100 = OpConstant %float 100\n"
"%_ptr_Function_float = OpTypePointer Function %float\n"
"%main = OpFunction %void None %10\n"
"%17 = OpLabel\n"
"%lv1_0 = OpVariable %_ptr_Function_float Function\n"
"OpStore %gv1 %float_10\n"
"OpStore %gv2 %float_100\n"
"OpLine %file 1 0\n"
"OpNoLine\n"
"OpLine %file 2 0\n"
"%18 = OpLoad %float %gv1\n"
"%19 = OpLoad %float %gv2\n"
"%20 = OpFSub %float %18 %19\n"
"OpStore %lv1_0 %20\n"
"OpReturn\n"
"OpFunctionEnd\n"
"%f_ = OpFunction %float None %12\n"
"%21 = OpLabel\n"
"%lv1 = OpVariable %_ptr_Function_float Function\n"
"%lv2 = OpVariable %_ptr_Function_float Function\n"
"OpLine %file 3 0\n"
"OpLine %file 4 0\n"
"%22 = OpLoad %float %gv1\n"
"%23 = OpLoad %float %gv2\n"
"%24 = OpFAdd %float %22 %23\n"
"OpStore %lv1 %24\n"
"OpLine %file 5 0\n"
"OpLine %file 6 0\n"
"OpNoLine\n"
"%25 = OpLoad %float %gv1\n"
"%26 = OpLoad %float %gv2\n"
"%27 = OpFMul %float %25 %26\n"
"OpBranch %28\n"
"%28 = OpLabel\n"
"OpStore %lv2 %27\n"
"%29 = OpLoad %float %lv1\n"
"OpLine %file 7 0\n"
"%30 = OpLoad %float %lv2\n"
"%31 = OpFDiv %float %28 %29\n"
"OpReturnValue %30\n"
"OpFunctionEnd\n";
// clang-format on
std::unique_ptr<IRContext> context =
BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
ASSERT_NE(nullptr, context);
struct LineInstrCheck {
uint32_t id;
std::vector<uint32_t> line_numbers;
};
const uint32_t kNoLine = 0;
const LineInstrCheck line_checks[] = {
{12, {10}}, {18, {1, kNoLine, 2}},
{19, {2}}, {20, {2}},
{22, {3, 4}}, {23, {4}},
{24, {4}}, {25, {5, 6, kNoLine}},
{26, {}}, {27, {}},
{28, {}}, {29, {}},
{30, {7}}, {31, {7}},
};
spvtools::opt::analysis::DefUseManager* def_use_mgr =
context->get_def_use_mgr();
for (const LineInstrCheck& check : line_checks) {
auto& lines = def_use_mgr->GetDef(check.id)->dbg_line_insts();
for (uint32_t i = 0; i < check.line_numbers.size(); ++i) {
if (check.line_numbers[i] == kNoLine) {
EXPECT_EQ(lines[i].opcode(), SpvOpNoLine);
continue;
}
EXPECT_EQ(lines[i].opcode(), SpvOpLine);
EXPECT_EQ(lines[i].GetSingleWordOperand(kOpLineOperandLineIndex),
check.line_numbers[i]);
}
}
}
TEST(IrBuilder, ConsumeDebugInfoInst) {
// /* HLSL */
//

View File

@ -160,13 +160,10 @@ OpName %gl_FragColor "gl_FragColor"
; CHECK: [[st_id:%\w+]] = OpLoad %v4float %BaseColor
; CHECK: OpLine {{%\w+}} 1 0
; CHECK: [[ld1:%\w+]] = OpLoad %S_t %s0
; CHECK: OpLine {{%\w+}} 1 0
; CHECK: [[ex1:%\w+]] = OpCompositeInsert %S_t [[st_id]] [[ld1]] 1
; CHECK: OpLine {{%\w+}} 1 0
; CHECK: OpStore %s0 [[ex1]]
; CHECK: OpLine {{%\w+}} 3 0
; CHECK: [[ld2:%\w+]] = OpLoad %S_t %s0
; CHECK: OpLine {{%\w+}} 3 0
; CHECK: [[ex2:%\w+]] = OpCompositeExtract %v4float [[ld2]] 1
; CHECK: OpLine {{%\w+}} 4 0
; CHECK: OpStore %gl_FragColor [[ex2]]
@ -263,15 +260,12 @@ OpName %gl_FragColor "gl_FragColor"
; CHECK: DebugValue [[dbg_s0:%\w+]] [[s0_1_ptr]]
; CHECK: OpLine {{%\w+}} 1 0
; CHECK: [[s0:%\w+]] = OpLoad %S_t %s0
; CHECK: OpLine {{%\w+}} 1 0
; CHECK: [[comp:%\w+]] = OpCompositeInsert %S_t [[st_id]] [[s0]] 1
; CHECK: OpLine {{%\w+}} 1 0
; CHECK: OpStore %s0 [[comp]]
; CHECK: OpLine {{%\w+}} 2 0
; CHECK: [[s0_2_ptr:%\w+]] = OpAccessChain %_ptr_Function_v4float %s0 %int_1
; CHECK: OpLine {{%\w+}} 3 0
; CHECK: [[s0:%\w+]] = OpLoad %S_t %s0
; CHECK: OpLine {{%\w+}} 3 0
; CHECK: [[s0_2_val:%\w+]] = OpCompositeExtract %v4float [[s0]] 1
; CHECK: DebugValue [[dbg_s0]] [[s0_2_val]]
; CHECK: OpLine {{%\w+}} 4 0

View File

@ -1,695 +0,0 @@
// Copyright (c) 2017 Valve Corporation
// Copyright (c) 2017 LunarG 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 <memory>
#include <string>
#include <vector>
#include "test/opt/pass_fixture.h"
#include "test/opt/pass_utils.h"
namespace spvtools {
namespace opt {
namespace {
using ProcessLinesTest = PassTest<::testing::Test>;
TEST_F(ProcessLinesTest, SimplePropagation) {
// Texture2D g_tColor[128];
//
// layout(push_constant) cbuffer PerViewConstantBuffer_t
// {
// uint g_nDataIdx;
// uint g_nDataIdx2;
// bool g_B;
// };
//
// SamplerState g_sAniso;
//
// struct PS_INPUT
// {
// float2 vTextureCoords : TEXCOORD2;
// };
//
// struct PS_OUTPUT
// {
// float4 vColor : SV_Target0;
// };
//
// PS_OUTPUT MainPs(PS_INPUT i)
// {
// PS_OUTPUT ps_output;
//
// uint u;
// if (g_B)
// u = g_nDataIdx;
// else
// u = g_nDataIdx2;
// ps_output.vColor = g_tColor[u].Sample(g_sAniso, i.vTextureCoords.xy);
// return ps_output;
// }
const std::string predefs =
R"(OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %MainPs "MainPs" %i_vTextureCoords %_entryPointOutput_vColor
OpExecutionMode %MainPs OriginUpperLeft
%5 = OpString "foo.frag"
OpSource HLSL 500
OpName %MainPs "MainPs"
OpName %PS_INPUT "PS_INPUT"
OpMemberName %PS_INPUT 0 "vTextureCoords"
OpName %PS_OUTPUT "PS_OUTPUT"
OpMemberName %PS_OUTPUT 0 "vColor"
OpName %_MainPs_struct_PS_INPUT_vf21_ "@MainPs(struct-PS_INPUT-vf21;"
OpName %i "i"
OpName %PerViewConstantBuffer_t "PerViewConstantBuffer_t"
OpMemberName %PerViewConstantBuffer_t 0 "g_nDataIdx"
OpMemberName %PerViewConstantBuffer_t 1 "g_nDataIdx2"
OpMemberName %PerViewConstantBuffer_t 2 "g_B"
OpName %_ ""
OpName %u "u"
OpName %ps_output "ps_output"
OpName %g_tColor "g_tColor"
OpName %g_sAniso "g_sAniso"
OpName %i_0 "i"
OpName %i_vTextureCoords "i.vTextureCoords"
OpName %_entryPointOutput_vColor "@entryPointOutput.vColor"
OpName %param "param"
OpMemberDecorate %PerViewConstantBuffer_t 0 Offset 0
OpMemberDecorate %PerViewConstantBuffer_t 1 Offset 4
OpMemberDecorate %PerViewConstantBuffer_t 2 Offset 8
OpDecorate %PerViewConstantBuffer_t Block
OpDecorate %g_tColor DescriptorSet 0
OpDecorate %g_sAniso DescriptorSet 0
OpDecorate %i_vTextureCoords Location 0
OpDecorate %_entryPointOutput_vColor Location 0
)";
const std::string before =
R"(%void = OpTypeVoid
%19 = OpTypeFunction %void
%float = OpTypeFloat 32
%v2float = OpTypeVector %float 2
%PS_INPUT = OpTypeStruct %v2float
%_ptr_Function_PS_INPUT = OpTypePointer Function %PS_INPUT
%v4float = OpTypeVector %float 4
%PS_OUTPUT = OpTypeStruct %v4float
%24 = OpTypeFunction %PS_OUTPUT %_ptr_Function_PS_INPUT
%uint = OpTypeInt 32 0
%PerViewConstantBuffer_t = OpTypeStruct %uint %uint %uint
%_ptr_PushConstant_PerViewConstantBuffer_t = OpTypePointer PushConstant %PerViewConstantBuffer_t
%_ = OpVariable %_ptr_PushConstant_PerViewConstantBuffer_t PushConstant
%int = OpTypeInt 32 1
%int_2 = OpConstant %int 2
%_ptr_PushConstant_uint = OpTypePointer PushConstant %uint
%bool = OpTypeBool
%uint_0 = OpConstant %uint 0
%_ptr_Function_uint = OpTypePointer Function %uint
%int_0 = OpConstant %int 0
%int_1 = OpConstant %int 1
%_ptr_Function_PS_OUTPUT = OpTypePointer Function %PS_OUTPUT
%36 = OpTypeImage %float 2D 0 0 0 1 Unknown
%uint_128 = OpConstant %uint 128
%_arr_36_uint_128 = OpTypeArray %36 %uint_128
%_ptr_UniformConstant__arr_36_uint_128 = OpTypePointer UniformConstant %_arr_36_uint_128
%g_tColor = OpVariable %_ptr_UniformConstant__arr_36_uint_128 UniformConstant
%_ptr_UniformConstant_36 = OpTypePointer UniformConstant %36
%41 = OpTypeSampler
%_ptr_UniformConstant_41 = OpTypePointer UniformConstant %41
%g_sAniso = OpVariable %_ptr_UniformConstant_41 UniformConstant
%43 = OpTypeSampledImage %36
%_ptr_Function_v2float = OpTypePointer Function %v2float
%_ptr_Function_v4float = OpTypePointer Function %v4float
%_ptr_Input_v2float = OpTypePointer Input %v2float
%i_vTextureCoords = OpVariable %_ptr_Input_v2float Input
%_ptr_Output_v4float = OpTypePointer Output %v4float
%_entryPointOutput_vColor = OpVariable %_ptr_Output_v4float Output
%MainPs = OpFunction %void None %19
%48 = OpLabel
%i_0 = OpVariable %_ptr_Function_PS_INPUT Function
%param = OpVariable %_ptr_Function_PS_INPUT Function
OpLine %5 23 0
%49 = OpLoad %v2float %i_vTextureCoords
%50 = OpAccessChain %_ptr_Function_v2float %i_0 %int_0
OpStore %50 %49
%51 = OpLoad %PS_INPUT %i_0
OpStore %param %51
%52 = OpFunctionCall %PS_OUTPUT %_MainPs_struct_PS_INPUT_vf21_ %param
%53 = OpCompositeExtract %v4float %52 0
OpStore %_entryPointOutput_vColor %53
OpReturn
OpFunctionEnd
%_MainPs_struct_PS_INPUT_vf21_ = OpFunction %PS_OUTPUT None %24
%i = OpFunctionParameter %_ptr_Function_PS_INPUT
%54 = OpLabel
%u = OpVariable %_ptr_Function_uint Function
%ps_output = OpVariable %_ptr_Function_PS_OUTPUT Function
OpLine %5 27 0
%55 = OpAccessChain %_ptr_PushConstant_uint %_ %int_2
%56 = OpLoad %uint %55
%57 = OpINotEqual %bool %56 %uint_0
OpSelectionMerge %58 None
OpBranchConditional %57 %59 %60
%59 = OpLabel
OpLine %5 28 0
%61 = OpAccessChain %_ptr_PushConstant_uint %_ %int_0
%62 = OpLoad %uint %61
OpStore %u %62
OpBranch %58
%60 = OpLabel
OpLine %5 30 0
%63 = OpAccessChain %_ptr_PushConstant_uint %_ %int_1
%64 = OpLoad %uint %63
OpStore %u %64
OpBranch %58
%58 = OpLabel
OpLine %5 31 0
%65 = OpLoad %uint %u
%66 = OpAccessChain %_ptr_UniformConstant_36 %g_tColor %65
%67 = OpLoad %36 %66
%68 = OpLoad %41 %g_sAniso
%69 = OpSampledImage %43 %67 %68
%70 = OpAccessChain %_ptr_Function_v2float %i %int_0
%71 = OpLoad %v2float %70
%72 = OpImageSampleImplicitLod %v4float %69 %71
%73 = OpAccessChain %_ptr_Function_v4float %ps_output %int_0
OpStore %73 %72
OpLine %5 32 0
%74 = OpLoad %PS_OUTPUT %ps_output
OpReturnValue %74
OpFunctionEnd
)";
const std::string after =
R"(OpNoLine
%void = OpTypeVoid
OpNoLine
%19 = OpTypeFunction %void
OpNoLine
%float = OpTypeFloat 32
OpNoLine
%v2float = OpTypeVector %float 2
OpNoLine
%PS_INPUT = OpTypeStruct %v2float
OpNoLine
%_ptr_Function_PS_INPUT = OpTypePointer Function %PS_INPUT
OpNoLine
%v4float = OpTypeVector %float 4
OpNoLine
%PS_OUTPUT = OpTypeStruct %v4float
OpNoLine
%24 = OpTypeFunction %PS_OUTPUT %_ptr_Function_PS_INPUT
OpNoLine
%uint = OpTypeInt 32 0
OpNoLine
%PerViewConstantBuffer_t = OpTypeStruct %uint %uint %uint
OpNoLine
%_ptr_PushConstant_PerViewConstantBuffer_t = OpTypePointer PushConstant %PerViewConstantBuffer_t
OpNoLine
%_ = OpVariable %_ptr_PushConstant_PerViewConstantBuffer_t PushConstant
OpNoLine
%int = OpTypeInt 32 1
OpNoLine
%int_2 = OpConstant %int 2
OpNoLine
%_ptr_PushConstant_uint = OpTypePointer PushConstant %uint
OpNoLine
%bool = OpTypeBool
OpNoLine
%uint_0 = OpConstant %uint 0
OpNoLine
%_ptr_Function_uint = OpTypePointer Function %uint
OpNoLine
%int_0 = OpConstant %int 0
OpNoLine
%int_1 = OpConstant %int 1
OpNoLine
%_ptr_Function_PS_OUTPUT = OpTypePointer Function %PS_OUTPUT
OpNoLine
%36 = OpTypeImage %float 2D 0 0 0 1 Unknown
OpNoLine
%uint_128 = OpConstant %uint 128
OpNoLine
%_arr_36_uint_128 = OpTypeArray %36 %uint_128
OpNoLine
%_ptr_UniformConstant__arr_36_uint_128 = OpTypePointer UniformConstant %_arr_36_uint_128
OpNoLine
%g_tColor = OpVariable %_ptr_UniformConstant__arr_36_uint_128 UniformConstant
OpNoLine
%_ptr_UniformConstant_36 = OpTypePointer UniformConstant %36
OpNoLine
%41 = OpTypeSampler
OpNoLine
%_ptr_UniformConstant_41 = OpTypePointer UniformConstant %41
OpNoLine
%g_sAniso = OpVariable %_ptr_UniformConstant_41 UniformConstant
OpNoLine
%43 = OpTypeSampledImage %36
OpNoLine
%_ptr_Function_v2float = OpTypePointer Function %v2float
OpNoLine
%_ptr_Function_v4float = OpTypePointer Function %v4float
OpNoLine
%_ptr_Input_v2float = OpTypePointer Input %v2float
OpNoLine
%i_vTextureCoords = OpVariable %_ptr_Input_v2float Input
OpNoLine
%_ptr_Output_v4float = OpTypePointer Output %v4float
OpNoLine
%_entryPointOutput_vColor = OpVariable %_ptr_Output_v4float Output
OpNoLine
%MainPs = OpFunction %void None %19
OpNoLine
%48 = OpLabel
OpNoLine
%i_0 = OpVariable %_ptr_Function_PS_INPUT Function
OpNoLine
%param = OpVariable %_ptr_Function_PS_INPUT Function
OpLine %5 23 0
%49 = OpLoad %v2float %i_vTextureCoords
OpLine %5 23 0
%50 = OpAccessChain %_ptr_Function_v2float %i_0 %int_0
OpLine %5 23 0
OpStore %50 %49
OpLine %5 23 0
%51 = OpLoad %PS_INPUT %i_0
OpLine %5 23 0
OpStore %param %51
OpLine %5 23 0
%52 = OpFunctionCall %PS_OUTPUT %_MainPs_struct_PS_INPUT_vf21_ %param
OpLine %5 23 0
%53 = OpCompositeExtract %v4float %52 0
OpLine %5 23 0
OpStore %_entryPointOutput_vColor %53
OpLine %5 23 0
OpReturn
OpNoLine
OpFunctionEnd
OpNoLine
%_MainPs_struct_PS_INPUT_vf21_ = OpFunction %PS_OUTPUT None %24
OpNoLine
%i = OpFunctionParameter %_ptr_Function_PS_INPUT
OpNoLine
%54 = OpLabel
OpNoLine
%u = OpVariable %_ptr_Function_uint Function
OpNoLine
%ps_output = OpVariable %_ptr_Function_PS_OUTPUT Function
OpLine %5 27 0
%55 = OpAccessChain %_ptr_PushConstant_uint %_ %int_2
OpLine %5 27 0
%56 = OpLoad %uint %55
OpLine %5 27 0
%57 = OpINotEqual %bool %56 %uint_0
OpLine %5 27 0
OpSelectionMerge %58 None
OpBranchConditional %57 %59 %60
OpNoLine
%59 = OpLabel
OpLine %5 28 0
%61 = OpAccessChain %_ptr_PushConstant_uint %_ %int_0
OpLine %5 28 0
%62 = OpLoad %uint %61
OpLine %5 28 0
OpStore %u %62
OpLine %5 28 0
OpBranch %58
OpNoLine
%60 = OpLabel
OpLine %5 30 0
%63 = OpAccessChain %_ptr_PushConstant_uint %_ %int_1
OpLine %5 30 0
%64 = OpLoad %uint %63
OpLine %5 30 0
OpStore %u %64
OpLine %5 30 0
OpBranch %58
OpNoLine
%58 = OpLabel
OpLine %5 31 0
%65 = OpLoad %uint %u
OpLine %5 31 0
%66 = OpAccessChain %_ptr_UniformConstant_36 %g_tColor %65
OpLine %5 31 0
%67 = OpLoad %36 %66
OpLine %5 31 0
%68 = OpLoad %41 %g_sAniso
OpLine %5 31 0
%69 = OpSampledImage %43 %67 %68
OpLine %5 31 0
%70 = OpAccessChain %_ptr_Function_v2float %i %int_0
OpLine %5 31 0
%71 = OpLoad %v2float %70
OpLine %5 31 0
%72 = OpImageSampleImplicitLod %v4float %69 %71
OpLine %5 31 0
%73 = OpAccessChain %_ptr_Function_v4float %ps_output %int_0
OpLine %5 31 0
OpStore %73 %72
OpLine %5 32 0
%74 = OpLoad %PS_OUTPUT %ps_output
OpLine %5 32 0
OpReturnValue %74
OpNoLine
OpFunctionEnd
)";
SinglePassRunAndCheck<ProcessLinesPass>(predefs + before, predefs + after,
false, true, kLinesPropagateLines);
}
TEST_F(ProcessLinesTest, SimpleElimination) {
// Previous test with before and after reversed
const std::string predefs =
R"(OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %MainPs "MainPs" %i_vTextureCoords %_entryPointOutput_vColor
OpExecutionMode %MainPs OriginUpperLeft
%5 = OpString "foo.frag"
OpSource HLSL 500
OpName %MainPs "MainPs"
OpName %PS_INPUT "PS_INPUT"
OpMemberName %PS_INPUT 0 "vTextureCoords"
OpName %PS_OUTPUT "PS_OUTPUT"
OpMemberName %PS_OUTPUT 0 "vColor"
OpName %_MainPs_struct_PS_INPUT_vf21_ "@MainPs(struct-PS_INPUT-vf21;"
OpName %i "i"
OpName %PerViewConstantBuffer_t "PerViewConstantBuffer_t"
OpMemberName %PerViewConstantBuffer_t 0 "g_nDataIdx"
OpMemberName %PerViewConstantBuffer_t 1 "g_nDataIdx2"
OpMemberName %PerViewConstantBuffer_t 2 "g_B"
OpName %_ ""
OpName %u "u"
OpName %ps_output "ps_output"
OpName %g_tColor "g_tColor"
OpName %g_sAniso "g_sAniso"
OpName %i_0 "i"
OpName %i_vTextureCoords "i.vTextureCoords"
OpName %_entryPointOutput_vColor "@entryPointOutput.vColor"
OpName %param "param"
OpMemberDecorate %PerViewConstantBuffer_t 0 Offset 0
OpMemberDecorate %PerViewConstantBuffer_t 1 Offset 4
OpMemberDecorate %PerViewConstantBuffer_t 2 Offset 8
OpDecorate %PerViewConstantBuffer_t Block
OpDecorate %g_tColor DescriptorSet 0
OpDecorate %g_sAniso DescriptorSet 0
OpDecorate %i_vTextureCoords Location 0
OpDecorate %_entryPointOutput_vColor Location 0
)";
const std::string before =
R"(OpNoLine
%void = OpTypeVoid
OpNoLine
%19 = OpTypeFunction %void
OpNoLine
%float = OpTypeFloat 32
OpNoLine
%v2float = OpTypeVector %float 2
OpNoLine
%PS_INPUT = OpTypeStruct %v2float
OpNoLine
%_ptr_Function_PS_INPUT = OpTypePointer Function %PS_INPUT
OpNoLine
%v4float = OpTypeVector %float 4
OpNoLine
%PS_OUTPUT = OpTypeStruct %v4float
OpNoLine
%24 = OpTypeFunction %PS_OUTPUT %_ptr_Function_PS_INPUT
OpNoLine
%uint = OpTypeInt 32 0
OpNoLine
%PerViewConstantBuffer_t = OpTypeStruct %uint %uint %uint
OpNoLine
%_ptr_PushConstant_PerViewConstantBuffer_t = OpTypePointer PushConstant %PerViewConstantBuffer_t
OpNoLine
%_ = OpVariable %_ptr_PushConstant_PerViewConstantBuffer_t PushConstant
OpNoLine
%int = OpTypeInt 32 1
OpNoLine
%int_2 = OpConstant %int 2
OpNoLine
%_ptr_PushConstant_uint = OpTypePointer PushConstant %uint
OpNoLine
%bool = OpTypeBool
OpNoLine
%uint_0 = OpConstant %uint 0
OpNoLine
%_ptr_Function_uint = OpTypePointer Function %uint
OpNoLine
%int_0 = OpConstant %int 0
OpNoLine
%int_1 = OpConstant %int 1
OpNoLine
%_ptr_Function_PS_OUTPUT = OpTypePointer Function %PS_OUTPUT
OpNoLine
%36 = OpTypeImage %float 2D 0 0 0 1 Unknown
OpNoLine
%uint_128 = OpConstant %uint 128
OpNoLine
%_arr_36_uint_128 = OpTypeArray %36 %uint_128
OpNoLine
%_ptr_UniformConstant__arr_36_uint_128 = OpTypePointer UniformConstant %_arr_36_uint_128
OpNoLine
%g_tColor = OpVariable %_ptr_UniformConstant__arr_36_uint_128 UniformConstant
OpNoLine
%_ptr_UniformConstant_36 = OpTypePointer UniformConstant %36
OpNoLine
%41 = OpTypeSampler
OpNoLine
%_ptr_UniformConstant_41 = OpTypePointer UniformConstant %41
OpNoLine
%g_sAniso = OpVariable %_ptr_UniformConstant_41 UniformConstant
OpNoLine
%43 = OpTypeSampledImage %36
OpNoLine
%_ptr_Function_v2float = OpTypePointer Function %v2float
OpNoLine
%_ptr_Function_v4float = OpTypePointer Function %v4float
OpNoLine
%_ptr_Input_v2float = OpTypePointer Input %v2float
OpNoLine
%i_vTextureCoords = OpVariable %_ptr_Input_v2float Input
OpNoLine
%_ptr_Output_v4float = OpTypePointer Output %v4float
OpNoLine
%_entryPointOutput_vColor = OpVariable %_ptr_Output_v4float Output
OpNoLine
%MainPs = OpFunction %void None %19
OpNoLine
%48 = OpLabel
OpNoLine
%i_0 = OpVariable %_ptr_Function_PS_INPUT Function
OpNoLine
%param = OpVariable %_ptr_Function_PS_INPUT Function
OpLine %5 23 0
%49 = OpLoad %v2float %i_vTextureCoords
OpLine %5 23 0
%50 = OpAccessChain %_ptr_Function_v2float %i_0 %int_0
OpLine %5 23 0
OpStore %50 %49
OpLine %5 23 0
%51 = OpLoad %PS_INPUT %i_0
OpLine %5 23 0
OpStore %param %51
OpLine %5 23 0
%52 = OpFunctionCall %PS_OUTPUT %_MainPs_struct_PS_INPUT_vf21_ %param
OpLine %5 23 0
%53 = OpCompositeExtract %v4float %52 0
OpLine %5 23 0
OpStore %_entryPointOutput_vColor %53
OpLine %5 23 0
OpReturn
OpNoLine
OpFunctionEnd
OpNoLine
%_MainPs_struct_PS_INPUT_vf21_ = OpFunction %PS_OUTPUT None %24
OpNoLine
%i = OpFunctionParameter %_ptr_Function_PS_INPUT
OpNoLine
%54 = OpLabel
OpNoLine
%u = OpVariable %_ptr_Function_uint Function
OpNoLine
%ps_output = OpVariable %_ptr_Function_PS_OUTPUT Function
OpLine %5 27 0
%55 = OpAccessChain %_ptr_PushConstant_uint %_ %int_2
OpLine %5 27 0
%56 = OpLoad %uint %55
OpLine %5 27 0
%57 = OpINotEqual %bool %56 %uint_0
OpLine %5 27 0
OpSelectionMerge %58 None
OpBranchConditional %57 %59 %60
OpNoLine
%59 = OpLabel
OpLine %5 28 0
%61 = OpAccessChain %_ptr_PushConstant_uint %_ %int_0
OpLine %5 28 0
%62 = OpLoad %uint %61
OpLine %5 28 0
OpStore %u %62
OpLine %5 28 0
OpBranch %58
OpNoLine
%60 = OpLabel
OpLine %5 30 0
%63 = OpAccessChain %_ptr_PushConstant_uint %_ %int_1
OpLine %5 30 0
%64 = OpLoad %uint %63
OpLine %5 30 0
OpStore %u %64
OpLine %5 30 0
OpBranch %58
OpNoLine
%58 = OpLabel
OpLine %5 31 0
%65 = OpLoad %uint %u
OpLine %5 31 0
%66 = OpAccessChain %_ptr_UniformConstant_36 %g_tColor %65
OpLine %5 31 0
%67 = OpLoad %36 %66
OpLine %5 31 0
%68 = OpLoad %41 %g_sAniso
OpLine %5 31 0
%69 = OpSampledImage %43 %67 %68
OpLine %5 31 0
%70 = OpAccessChain %_ptr_Function_v2float %i %int_0
OpLine %5 31 0
%71 = OpLoad %v2float %70
OpLine %5 31 0
%72 = OpImageSampleImplicitLod %v4float %69 %71
OpLine %5 31 0
%73 = OpAccessChain %_ptr_Function_v4float %ps_output %int_0
OpLine %5 31 0
OpStore %73 %72
OpLine %5 32 0
%74 = OpLoad %PS_OUTPUT %ps_output
OpLine %5 32 0
OpReturnValue %74
OpNoLine
OpFunctionEnd
)";
const std::string after =
R"(%void = OpTypeVoid
%19 = OpTypeFunction %void
%float = OpTypeFloat 32
%v2float = OpTypeVector %float 2
%PS_INPUT = OpTypeStruct %v2float
%_ptr_Function_PS_INPUT = OpTypePointer Function %PS_INPUT
%v4float = OpTypeVector %float 4
%PS_OUTPUT = OpTypeStruct %v4float
%24 = OpTypeFunction %PS_OUTPUT %_ptr_Function_PS_INPUT
%uint = OpTypeInt 32 0
%PerViewConstantBuffer_t = OpTypeStruct %uint %uint %uint
%_ptr_PushConstant_PerViewConstantBuffer_t = OpTypePointer PushConstant %PerViewConstantBuffer_t
%_ = OpVariable %_ptr_PushConstant_PerViewConstantBuffer_t PushConstant
%int = OpTypeInt 32 1
%int_2 = OpConstant %int 2
%_ptr_PushConstant_uint = OpTypePointer PushConstant %uint
%bool = OpTypeBool
%uint_0 = OpConstant %uint 0
%_ptr_Function_uint = OpTypePointer Function %uint
%int_0 = OpConstant %int 0
%int_1 = OpConstant %int 1
%_ptr_Function_PS_OUTPUT = OpTypePointer Function %PS_OUTPUT
%36 = OpTypeImage %float 2D 0 0 0 1 Unknown
%uint_128 = OpConstant %uint 128
%_arr_36_uint_128 = OpTypeArray %36 %uint_128
%_ptr_UniformConstant__arr_36_uint_128 = OpTypePointer UniformConstant %_arr_36_uint_128
%g_tColor = OpVariable %_ptr_UniformConstant__arr_36_uint_128 UniformConstant
%_ptr_UniformConstant_36 = OpTypePointer UniformConstant %36
%41 = OpTypeSampler
%_ptr_UniformConstant_41 = OpTypePointer UniformConstant %41
%g_sAniso = OpVariable %_ptr_UniformConstant_41 UniformConstant
%43 = OpTypeSampledImage %36
%_ptr_Function_v2float = OpTypePointer Function %v2float
%_ptr_Function_v4float = OpTypePointer Function %v4float
%_ptr_Input_v2float = OpTypePointer Input %v2float
%i_vTextureCoords = OpVariable %_ptr_Input_v2float Input
%_ptr_Output_v4float = OpTypePointer Output %v4float
%_entryPointOutput_vColor = OpVariable %_ptr_Output_v4float Output
%MainPs = OpFunction %void None %19
%48 = OpLabel
%i_0 = OpVariable %_ptr_Function_PS_INPUT Function
%param = OpVariable %_ptr_Function_PS_INPUT Function
OpLine %5 23 0
%49 = OpLoad %v2float %i_vTextureCoords
%50 = OpAccessChain %_ptr_Function_v2float %i_0 %int_0
OpStore %50 %49
%51 = OpLoad %PS_INPUT %i_0
OpStore %param %51
%52 = OpFunctionCall %PS_OUTPUT %_MainPs_struct_PS_INPUT_vf21_ %param
%53 = OpCompositeExtract %v4float %52 0
OpStore %_entryPointOutput_vColor %53
OpReturn
OpFunctionEnd
%_MainPs_struct_PS_INPUT_vf21_ = OpFunction %PS_OUTPUT None %24
%i = OpFunctionParameter %_ptr_Function_PS_INPUT
%54 = OpLabel
%u = OpVariable %_ptr_Function_uint Function
%ps_output = OpVariable %_ptr_Function_PS_OUTPUT Function
OpLine %5 27 0
%55 = OpAccessChain %_ptr_PushConstant_uint %_ %int_2
%56 = OpLoad %uint %55
%57 = OpINotEqual %bool %56 %uint_0
OpSelectionMerge %58 None
OpBranchConditional %57 %59 %60
%59 = OpLabel
OpLine %5 28 0
%61 = OpAccessChain %_ptr_PushConstant_uint %_ %int_0
%62 = OpLoad %uint %61
OpStore %u %62
OpBranch %58
%60 = OpLabel
OpLine %5 30 0
%63 = OpAccessChain %_ptr_PushConstant_uint %_ %int_1
%64 = OpLoad %uint %63
OpStore %u %64
OpBranch %58
%58 = OpLabel
OpLine %5 31 0
%65 = OpLoad %uint %u
%66 = OpAccessChain %_ptr_UniformConstant_36 %g_tColor %65
%67 = OpLoad %36 %66
%68 = OpLoad %41 %g_sAniso
%69 = OpSampledImage %43 %67 %68
%70 = OpAccessChain %_ptr_Function_v2float %i %int_0
%71 = OpLoad %v2float %70
%72 = OpImageSampleImplicitLod %v4float %69 %71
%73 = OpAccessChain %_ptr_Function_v4float %ps_output %int_0
OpStore %73 %72
OpLine %5 32 0
%74 = OpLoad %PS_OUTPUT %ps_output
OpReturnValue %74
OpFunctionEnd
)";
SinglePassRunAndCheck<ProcessLinesPass>(
predefs + before, predefs + after, false, true, kLinesEliminateDeadLines);
}
// TODO(greg-lunarg): Add tests to verify handling of these cases:
//
// TODO(greg-lunarg): Think about other tests :)
} // namespace
} // namespace opt
} // namespace spvtools

View File

@ -315,8 +315,10 @@ TEST_F(RedundancyEliminationTest, OpenCLDebugInfo100) {
; After removing one `OpFAdd %float %26 %26`, two DebugValues are the same.
; One must be removed.
;
; CHECK: [[add:%\w+]] = OpFAdd %float [[value:%\w+]]
; CHECK: OpLine {{%\w+}} 0 0
; CHECK-NEXT: [[add:%\w+]] = OpFAdd %float [[value:%\w+]]
; CHECK-NEXT: DebugValue [[dbg_local_var]] [[add]]
; CHECK-NEXT: OpLine {{%\w+}} 1 0
; CHECK-NEXT: OpFAdd %float [[add]] [[value]]
; CHECK-NEXT: OpReturn
%27 = OpFAdd %float %26 %26

View File

@ -903,7 +903,7 @@ TEST_F(WrapOpKillTest, DebugInfoSimple) {
; CHECK-NEXT: {{%\d+}} = OpExtInst %void [[ext:%\d+]] DebugScope
; CHECK-NEXT: OpLine [[file:%\d+]] 100 200
; CHECK-NEXT: OpFunctionCall %void [[new_kill:%\w+]]
; CHECK-NEXT: {{%\d+}} = OpExtInst %void [[ext]] DebugNoScope
; CHECK: {{%\d+}} = OpExtInst %void [[ext]] DebugNoScope
; CHECK-NEXT: OpReturn
; CHECK: [[new_kill]] = OpFunction
; CHECK-NEXT: OpLabel