Handle id overflow in the ssa rewriter. (#2845)

* Handle id overflow in the ssa rewriter.

Remove LocalSSAElim pass at the same time.  It does the same thing as the SSARewrite pass. Then even share almost all of the same code.

Fixes crbug.com/997246
This commit is contained in:
Steven Perron 2019-09-10 09:38:23 -04:00 committed by GitHub
parent 7f7236f1eb
commit 35c9518c4e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 140 additions and 255 deletions

View File

@ -131,7 +131,6 @@ SPVTOOLS_OPT_SRC_FILES := \
source/opt/local_redundancy_elimination.cpp \
source/opt/local_single_block_elim_pass.cpp \
source/opt/local_single_store_elim_pass.cpp \
source/opt/local_ssa_elim_pass.cpp \
source/opt/loop_dependence.cpp \
source/opt/loop_dependence_helpers.cpp \
source/opt/loop_descriptor.cpp \

View File

@ -565,8 +565,6 @@ static_library("spvtools_opt") {
"source/opt/local_single_block_elim_pass.h",
"source/opt/local_single_store_elim_pass.cpp",
"source/opt/local_single_store_elim_pass.h",
"source/opt/local_ssa_elim_pass.cpp",
"source/opt/local_ssa_elim_pass.h",
"source/opt/log.h",
"source/opt/loop_dependence.cpp",
"source/opt/loop_dependence.h",

View File

@ -69,7 +69,6 @@ set(SPIRV_TOOLS_OPT_SOURCES
local_redundancy_elimination.h
local_single_block_elim_pass.h
local_single_store_elim_pass.h
local_ssa_elim_pass.h
log.h
loop_dependence.h
loop_descriptor.h
@ -176,7 +175,6 @@ set(SPIRV_TOOLS_OPT_SOURCES
local_redundancy_elimination.cpp
local_single_block_elim_pass.cpp
local_single_store_elim_pass.cpp
local_ssa_elim_pass.cpp
loop_dependence.cpp
loop_dependence_helpers.cpp
loop_descriptor.cpp

View File

@ -110,15 +110,26 @@ void CFG::ForEachBlockInPostOrder(BasicBlock* bb,
void CFG::ForEachBlockInReversePostOrder(
BasicBlock* bb, const std::function<void(BasicBlock*)>& f) {
WhileEachBlockInReversePostOrder(bb, [f](BasicBlock* b) {
f(b);
return true;
});
}
bool CFG::WhileEachBlockInReversePostOrder(
BasicBlock* bb, const std::function<bool(BasicBlock*)>& f) {
std::vector<BasicBlock*> po;
std::unordered_set<BasicBlock*> seen;
ComputePostOrderTraversal(bb, &po, &seen);
for (auto current_bb = po.rbegin(); current_bb != po.rend(); ++current_bb) {
if (!IsPseudoExitBlock(*current_bb) && !IsPseudoEntryBlock(*current_bb)) {
f(*current_bb);
if (!f(*current_bb)) {
return false;
}
}
}
return true;
}
void CFG::ComputeStructuredSuccessors(Function* func) {

View File

@ -65,18 +65,21 @@ class CFG {
void ComputeStructuredOrder(Function* func, BasicBlock* root,
std::list<BasicBlock*>* order);
// Applies |f| to the basic block in post order starting with |bb|.
// Note that basic blocks that cannot be reached from |bb| node will not be
// processed.
// Applies |f| to all blocks that can be reach from |bb| in post order.
void ForEachBlockInPostOrder(BasicBlock* bb,
const std::function<void(BasicBlock*)>& f);
// Applies |f| to the basic block in reverse post order starting with |bb|.
// Note that basic blocks that cannot be reached from |bb| node will not be
// processed.
// Applies |f| to all blocks that can be reach from |bb| in reverse post
// order.
void ForEachBlockInReversePostOrder(
BasicBlock* bb, const std::function<void(BasicBlock*)>& f);
// Applies |f| to all blocks that can be reach from |bb| in reverse post
// order. Return false if |f| return false on any basic block, and stops
// processing.
bool WhileEachBlockInReversePostOrder(
BasicBlock* bb, const std::function<bool(BasicBlock*)>& f);
// Registers |blk| as a basic block in the cfg, this also updates the
// predecessor lists of each successor of |blk|. |blk| must have a terminator
// instruction at the end of the block.

View File

@ -1,113 +0,0 @@
// Copyright (c) 2017 The Khronos Group Inc.
// 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 "source/opt/local_ssa_elim_pass.h"
#include "source/cfa.h"
#include "source/opt/iterator.h"
#include "source/opt/ssa_rewrite_pass.h"
namespace spvtools {
namespace opt {
bool LocalMultiStoreElimPass::AllExtensionsSupported() const {
// If any extension not in whitelist, return false
for (auto& ei : get_module()->extensions()) {
const char* extName =
reinterpret_cast<const char*>(&ei.GetInOperand(0).words[0]);
if (extensions_whitelist_.find(extName) == extensions_whitelist_.end())
return false;
}
return true;
}
Pass::Status LocalMultiStoreElimPass::ProcessImpl() {
// Assumes relaxed logical addressing only (see instruction.h)
// TODO(greg-lunarg): Add support for physical addressing
if (context()->get_feature_mgr()->HasCapability(SpvCapabilityAddresses))
return Status::SuccessWithoutChange;
// Do not process if module contains OpGroupDecorate. Additional
// support required in KillNamesAndDecorates().
// TODO(greg-lunarg): Add support for OpGroupDecorate
for (auto& ai : get_module()->annotations())
if (ai.opcode() == SpvOpGroupDecorate) return Status::SuccessWithoutChange;
// Do not process if any disallowed extensions are enabled
if (!AllExtensionsSupported()) return Status::SuccessWithoutChange;
// Process functions
ProcessFunction pfn = [this](Function* fp) {
return SSARewriter(this).RewriteFunctionIntoSSA(fp);
};
bool modified = context()->ProcessEntryPointCallTree(pfn);
return modified ? Status::SuccessWithChange : Status::SuccessWithoutChange;
}
LocalMultiStoreElimPass::LocalMultiStoreElimPass() = default;
Pass::Status LocalMultiStoreElimPass::Process() {
// Initialize extension whitelist
InitExtensions();
return ProcessImpl();
}
void LocalMultiStoreElimPass::InitExtensions() {
extensions_whitelist_.clear();
extensions_whitelist_.insert({
"SPV_AMD_shader_explicit_vertex_parameter",
"SPV_AMD_shader_trinary_minmax",
"SPV_AMD_gcn_shader",
"SPV_KHR_shader_ballot",
"SPV_AMD_shader_ballot",
"SPV_AMD_gpu_shader_half_float",
"SPV_KHR_shader_draw_parameters",
"SPV_KHR_subgroup_vote",
"SPV_KHR_16bit_storage",
"SPV_KHR_device_group",
"SPV_KHR_multiview",
"SPV_NVX_multiview_per_view_attributes",
"SPV_NV_viewport_array2",
"SPV_NV_stereo_view_rendering",
"SPV_NV_sample_mask_override_coverage",
"SPV_NV_geometry_shader_passthrough",
"SPV_AMD_texture_gather_bias_lod",
"SPV_KHR_storage_buffer_storage_class",
"SPV_KHR_variable_pointers",
"SPV_AMD_gpu_shader_int16",
"SPV_KHR_post_depth_coverage",
"SPV_KHR_shader_atomic_counter_ops",
"SPV_EXT_shader_stencil_export",
"SPV_EXT_shader_viewport_index_layer",
"SPV_AMD_shader_image_load_store_lod",
"SPV_AMD_shader_fragment_mask",
"SPV_EXT_fragment_fully_covered",
"SPV_AMD_gpu_shader_half_float_fetch",
"SPV_GOOGLE_decorate_string",
"SPV_GOOGLE_hlsl_functionality1",
"SPV_GOOGLE_user_type",
"SPV_NV_shader_subgroup_partitioned",
"SPV_EXT_descriptor_indexing",
"SPV_NV_fragment_shader_barycentric",
"SPV_NV_compute_shader_derivatives",
"SPV_NV_shader_image_footprint",
"SPV_NV_shading_rate",
"SPV_NV_mesh_shader",
"SPV_NV_ray_tracing",
"SPV_EXT_fragment_invocation_density",
"SPV_EXT_physical_storage_buffer",
});
}
} // namespace opt
} // namespace spvtools

View File

@ -1,72 +0,0 @@
// Copyright (c) 2017 The Khronos Group Inc.
// 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.
#ifndef SOURCE_OPT_LOCAL_SSA_ELIM_PASS_H_
#define SOURCE_OPT_LOCAL_SSA_ELIM_PASS_H_
#include <algorithm>
#include <map>
#include <queue>
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#include <vector>
#include "source/opt/basic_block.h"
#include "source/opt/def_use_manager.h"
#include "source/opt/mem_pass.h"
#include "source/opt/module.h"
namespace spvtools {
namespace opt {
// See optimizer.hpp for documentation.
class LocalMultiStoreElimPass : public MemPass {
using cbb_ptr = const BasicBlock*;
public:
using GetBlocksFunction =
std::function<std::vector<BasicBlock*>*(const BasicBlock*)>;
LocalMultiStoreElimPass();
const char* name() const override { return "eliminate-local-multi-store"; }
Status Process() override;
IRContext::Analysis GetPreservedAnalyses() override {
return IRContext::kAnalysisDefUse |
IRContext::kAnalysisInstrToBlockMapping |
IRContext::kAnalysisConstants | IRContext::kAnalysisTypes;
}
private:
// Initialize extensions whitelist
void InitExtensions();
// Return true if all extensions in this module are allowed by this pass.
bool AllExtensionsSupported() const;
Pass::Status ProcessImpl();
// Extensions supported by this pass.
std::unordered_set<std::string> extensions_whitelist_;
};
} // namespace opt
} // namespace spvtools
#endif // SOURCE_OPT_LOCAL_SSA_ELIM_PASS_H_

View File

@ -233,6 +233,10 @@ uint32_t MemPass::Type2Undef(uint32_t type_id) {
const auto uitr = type2undefs_.find(type_id);
if (uitr != type2undefs_.end()) return uitr->second;
const uint32_t undefId = TakeNextId();
if (undefId == 0) {
return 0;
}
std::unique_ptr<Instruction> undef_inst(
new Instruction(context(), SpvOpUndef, type_id, undefId, {}));
get_def_use_mgr()->AnalyzeInstDefUse(&*undef_inst);

View File

@ -121,9 +121,10 @@ class MemPass : public Pass {
return (op == SpvOpDecorate || op == SpvOpDecorateId);
}
// Return undef in function for type. Create and insert an undef after the
// first non-variable in the function if it doesn't already exist. Add
// undef to function undef map.
// Return the id of an undef value with type |type_id|. Create and insert an
// undef after the first non-variable in the function if it doesn't already
// exist. Add undef to function undef map. Returns 0 of the value does not
// exist, and cannot be created.
uint32_t Type2Undef(uint32_t type_id);
// Cache of verified target vars

View File

@ -715,7 +715,7 @@ Optimizer::PassToken CreateDeadBranchElimPass() {
Optimizer::PassToken CreateLocalMultiStoreElimPass() {
return MakeUnique<Optimizer::PassToken::Impl>(
MakeUnique<opt::LocalMultiStoreElimPass>());
MakeUnique<opt::SSARewritePass>());
}
Optimizer::PassToken CreateAggressiveDCEPass() {

View File

@ -52,7 +52,6 @@
#include "source/opt/local_redundancy_elimination.h"
#include "source/opt/local_single_block_elim_pass.h"
#include "source/opt/local_single_store_elim_pass.h"
#include "source/opt/local_ssa_elim_pass.h"
#include "source/opt/loop_fission.h"
#include "source/opt/loop_fusion_pass.h"
#include "source/opt/loop_peeling.h"

View File

@ -274,6 +274,9 @@ uint32_t SSARewriter::GetReachingDef(uint32_t var_id, BasicBlock* bb) {
// of the CFG, the variable is not defined, so we use undef.
if (val_id == 0) {
val_id = pass_->GetUndefVal(var_id);
if (val_id == 0) {
return 0;
}
}
WriteVariable(var_id, bb, val_id);
@ -313,12 +316,15 @@ void SSARewriter::ProcessStore(Instruction* inst, BasicBlock* bb) {
}
}
void SSARewriter::ProcessLoad(Instruction* inst, BasicBlock* bb) {
bool SSARewriter::ProcessLoad(Instruction* inst, BasicBlock* bb) {
uint32_t var_id = 0;
(void)pass_->GetPtr(inst, &var_id);
if (pass_->IsTargetVar(var_id)) {
// Get the immediate reaching definition for |var_id|.
uint32_t val_id = GetReachingDef(var_id, bb);
if (val_id == 0) {
return false;
}
// Schedule a replacement for the result of this load instruction with
// |val_id|. After all the rewriting decisions are made, every use of
@ -337,6 +343,7 @@ void SSARewriter::ProcessLoad(Instruction* inst, BasicBlock* bb) {
<< " (replacement for %" << load_id << " is %" << val_id << ")\n";
#endif
}
return true;
}
void SSARewriter::PrintPhiCandidates() const {
@ -356,7 +363,7 @@ void SSARewriter::PrintReplacementTable() const {
std::cerr << "\n";
}
void SSARewriter::GenerateSSAReplacements(BasicBlock* bb) {
bool SSARewriter::GenerateSSAReplacements(BasicBlock* bb) {
#if SSA_REWRITE_DEBUGGING_LEVEL > 1
std::cerr << "Generating SSA replacements for block: " << bb->id() << "\n";
std::cerr << bb->PrettyPrint(SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES)
@ -368,7 +375,9 @@ void SSARewriter::GenerateSSAReplacements(BasicBlock* bb) {
if (opcode == SpvOpStore || opcode == SpvOpVariable) {
ProcessStore(&inst, bb);
} else if (inst.opcode() == SpvOpLoad) {
ProcessLoad(&inst, bb);
if (!ProcessLoad(&inst, bb)) {
return false;
}
}
}
@ -381,6 +390,7 @@ void SSARewriter::GenerateSSAReplacements(BasicBlock* bb) {
PrintReplacementTable();
std::cerr << "\n\n";
#endif
return true;
}
uint32_t SSARewriter::GetReplacement(std::pair<uint32_t, uint32_t> repl) {
@ -560,7 +570,7 @@ void SSARewriter::FinalizePhiCandidates() {
}
}
bool SSARewriter::RewriteFunctionIntoSSA(Function* fp) {
Pass::Status SSARewriter::RewriteFunctionIntoSSA(Function* fp) {
#if SSA_REWRITE_DEBUGGING_LEVEL > 0
std::cerr << "Function before SSA rewrite:\n"
<< fp->PrettyPrint(0) << "\n\n\n";
@ -571,9 +581,17 @@ bool SSARewriter::RewriteFunctionIntoSSA(Function* fp) {
// Generate all the SSA replacements and Phi candidates. This will
// generate incomplete and trivial Phis.
pass_->cfg()->ForEachBlockInReversePostOrder(
fp->entry().get(),
[this](BasicBlock* bb) { GenerateSSAReplacements(bb); });
bool succeeded = pass_->cfg()->WhileEachBlockInReversePostOrder(
fp->entry().get(), [this](BasicBlock* bb) {
if (!GenerateSSAReplacements(bb)) {
return false;
}
return true;
});
if (!succeeded) {
return Pass::Status::Failure;
}
// Remove trivial Phis and add arguments to incomplete Phis.
FinalizePhiCandidates();
@ -586,17 +604,21 @@ bool SSARewriter::RewriteFunctionIntoSSA(Function* fp) {
<< fp->PrettyPrint(0) << "\n";
#endif
return modified;
}
Pass::Status SSARewritePass::Process() {
bool modified = false;
for (auto& fn : *get_module()) {
modified |= SSARewriter(this).RewriteFunctionIntoSSA(&fn);
}
return modified ? Pass::Status::SuccessWithChange
: Pass::Status::SuccessWithoutChange;
}
Pass::Status SSARewritePass::Process() {
Status status = Status::SuccessWithoutChange;
for (auto& fn : *get_module()) {
status =
CombineStatus(status, SSARewriter(this).RewriteFunctionIntoSSA(&fn));
if (status == Status::Failure) {
break;
}
}
return status;
}
} // namespace opt
} // namespace spvtools

View File

@ -46,9 +46,9 @@ class SSARewriter {
// entry point for the SSA rewrite algorithm. SSA-target variables are
// locally defined variables that meet the criteria set by IsSSATargetVar.
//
// It returns true if function |fp| was modified. Otherwise, it returns
// false.
bool RewriteFunctionIntoSSA(Function* fp);
// Returns whether the function was modified or not, and whether or not the
// rewrite was successful.
Pass::Status RewriteFunctionIntoSSA(Function* fp);
private:
class PhiCandidate {
@ -128,8 +128,8 @@ class SSARewriter {
// Generates all the SSA rewriting decisions for basic block |bb|. This
// populates the Phi candidate table (|phi_candidate_|) and the load
// replacement table (|load_replacement_).
void GenerateSSAReplacements(BasicBlock* bb);
// replacement table (|load_replacement_). Returns true if successful.
bool GenerateSSAReplacements(BasicBlock* bb);
// Seals block |bb|. Sealing a basic block means |bb| and all its
// predecessors of |bb| have been scanned for loads/stores.
@ -202,8 +202,8 @@ class SSARewriter {
// Processes the load operation |inst| in basic block |bb|. This extracts
// the variable ID being stored into, determines whether the variable is an
// SSA-target variable, and, if it is, it reads its reaching definition by
// calling |GetReachingDef|.
void ProcessLoad(Instruction* inst, BasicBlock* bb);
// calling |GetReachingDef|. Returns true if successful.
bool ProcessLoad(Instruction* inst, BasicBlock* bb);
// Reads the current definition for variable |var_id| in basic block |bb|.
// If |var_id| is not defined in block |bb| it walks up the predecessors of

View File

@ -138,8 +138,8 @@ OpReturn
OpFunctionEnd
)";
SinglePassRunAndCheck<LocalMultiStoreElimPass>(predefs + before,
predefs + after, true, true);
SinglePassRunAndCheck<SSARewritePass>(predefs + before, predefs + after, true,
true);
}
TEST_F(LocalSSAElimTest, NestedForLoop) {
@ -280,8 +280,8 @@ OpReturn
OpFunctionEnd
)";
SinglePassRunAndCheck<LocalMultiStoreElimPass>(predefs + before,
predefs + after, true, true);
SinglePassRunAndCheck<SSARewritePass>(predefs + before, predefs + after, true,
true);
}
TEST_F(LocalSSAElimTest, ForLoopWithContinue) {
@ -426,9 +426,9 @@ OpReturn
OpFunctionEnd
)";
SinglePassRunAndCheck<LocalMultiStoreElimPass>(
predefs + names + predefs2 + before, predefs + names + predefs2 + after,
true, true);
SinglePassRunAndCheck<SSARewritePass>(predefs + names + predefs2 + before,
predefs + names + predefs2 + after,
true, true);
}
TEST_F(LocalSSAElimTest, ForLoopWithBreak) {
@ -567,8 +567,8 @@ OpReturn
OpFunctionEnd
)";
SinglePassRunAndCheck<LocalMultiStoreElimPass>(predefs + before,
predefs + after, true, true);
SinglePassRunAndCheck<SSARewritePass>(predefs + before, predefs + after, true,
true);
}
TEST_F(LocalSSAElimTest, SwapProblem) {
@ -704,8 +704,8 @@ OpReturn
OpFunctionEnd
)";
SinglePassRunAndCheck<LocalMultiStoreElimPass>(predefs + before,
predefs + after, true, true);
SinglePassRunAndCheck<SSARewritePass>(predefs + before, predefs + after, true,
true);
}
TEST_F(LocalSSAElimTest, LostCopyProblem) {
@ -848,8 +848,8 @@ OpReturn
OpFunctionEnd
)";
SinglePassRunAndCheck<LocalMultiStoreElimPass>(predefs + before,
predefs + after, true, true);
SinglePassRunAndCheck<SSARewritePass>(predefs + before, predefs + after, true,
true);
}
TEST_F(LocalSSAElimTest, IfThenElse) {
@ -948,8 +948,8 @@ OpReturn
OpFunctionEnd
)";
SinglePassRunAndCheck<LocalMultiStoreElimPass>(predefs + before,
predefs + after, true, true);
SinglePassRunAndCheck<SSARewritePass>(predefs + before, predefs + after, true,
true);
}
TEST_F(LocalSSAElimTest, IfThen) {
@ -1037,8 +1037,8 @@ OpReturn
OpFunctionEnd
)";
SinglePassRunAndCheck<LocalMultiStoreElimPass>(predefs + before,
predefs + after, true, true);
SinglePassRunAndCheck<SSARewritePass>(predefs + before, predefs + after, true,
true);
}
TEST_F(LocalSSAElimTest, Switch) {
@ -1168,8 +1168,8 @@ OpReturn
OpFunctionEnd
)";
SinglePassRunAndCheck<LocalMultiStoreElimPass>(predefs + before,
predefs + after, true, true);
SinglePassRunAndCheck<SSARewritePass>(predefs + before, predefs + after, true,
true);
}
TEST_F(LocalSSAElimTest, SwitchWithFallThrough) {
@ -1300,8 +1300,8 @@ OpReturn
OpFunctionEnd
)";
SinglePassRunAndCheck<LocalMultiStoreElimPass>(predefs + before,
predefs + after, true, true);
SinglePassRunAndCheck<SSARewritePass>(predefs + before, predefs + after, true,
true);
}
TEST_F(LocalSSAElimTest, DontPatchPhiInLoopHeaderThatIsNotAVar) {
@ -1331,7 +1331,7 @@ OpReturn
OpFunctionEnd
)";
SinglePassRunAndCheck<LocalMultiStoreElimPass>(before, before, true, true);
SinglePassRunAndCheck<SSARewritePass>(before, before, true, true);
}
TEST_F(LocalSSAElimTest, OptInitializedVariableLikeStore) {
@ -1428,8 +1428,8 @@ OpReturn
OpFunctionEnd
)";
SinglePassRunAndCheck<LocalMultiStoreElimPass>(
predefs + func_before, predefs + func_after, true, true);
SinglePassRunAndCheck<SSARewritePass>(predefs + func_before,
predefs + func_after, true, true);
}
TEST_F(LocalSSAElimTest, PointerVariable) {
@ -1531,7 +1531,7 @@ OpFunctionEnd
// Relax logical pointers to allow pointer allocations.
SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
ValidatorOptions()->relax_logical_pointer = true;
SinglePassRunAndCheck<LocalMultiStoreElimPass>(before, after, true, true);
SinglePassRunAndCheck<SSARewritePass>(before, after, true, true);
}
TEST_F(LocalSSAElimTest, VerifyInstToBlockMap) {
@ -1620,7 +1620,7 @@ OpFunctionEnd
// Force the instruction to block mapping to get built.
context->get_instr_block(27u);
auto pass = MakeUnique<LocalMultiStoreElimPass>();
auto pass = MakeUnique<SSARewritePass>();
pass->SetMessageConsumer(nullptr);
const auto status = pass->Run(context.get());
EXPECT_TRUE(status == Pass::Status::SuccessWithChange);
@ -1927,7 +1927,7 @@ TEST_F(LocalSSAElimTest, VariablePointerTest2) {
OpReturn
OpFunctionEnd
)";
SinglePassRunAndMatch<LocalMultiStoreElimPass>(text, false);
SinglePassRunAndMatch<SSARewritePass>(text, false);
}
TEST_F(LocalSSAElimTest, ChainedTrivialPhis) {
@ -1987,6 +1987,41 @@ TEST_F(LocalSSAElimTest, ChainedTrivialPhis) {
SinglePassRunAndMatch<SSARewritePass>(text, false);
}
TEST_F(LocalSSAElimTest, Overflowtest1) {
// Check that the copy object get the undef value implicitly assigned in the
// entry block.
const std::string text = R"(
OpCapability Geometry
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %4 "P2Mai" %12 %17
OpExecutionMode %4 OriginUpperLeft
%2 = OpTypeVoid
%3 = OpTypeFunction %2
%6 = OpTypeFloat 32
%7 = OpTypeVector %6 4
%11 = OpTypePointer Input %7
%16 = OpTypePointer Output %7
%23 = OpTypePointer Function %7
%12 = OpVariable %11 Input
%17 = OpVariable %16 Output
%4 = OpFunction %2 None %3
%2177 = OpLabel
%4194302 = OpVariable %23 Function
%4194301 = OpLoad %7 %4194302
OpStore %17 %4194301
OpReturn
OpFunctionEnd
)";
SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
std::vector<Message> messages = {
{SPV_MSG_ERROR, "", 0, 0, "ID overflow. Try running compact-ids."}};
SetMessageConsumer(GetTestMessageConsumer(messages));
auto result = SinglePassRunToBinary<SSARewritePass>(text, true);
EXPECT_EQ(Pass::Status::Failure, std::get<1>(result));
}
// TODO(greg-lunarg): Add tests to verify handling of these cases:
//
// No optimization in the presence of

View File

@ -91,7 +91,7 @@ class TestValidPassFlags(expect.ValidObjectFile1_4,
'eliminate-dead-variables',
# --eliminate-insert-extract runs the simplify-instructions pass.
'simplify-instructions',
'eliminate-local-multi-store',
'ssa-rewrite',
'eliminate-local-single-block',
'eliminate-local-single-store',
'flatten-decorations',
@ -149,7 +149,7 @@ class TestPerformanceOptimizationPasses(expect.ValidObjectFile1_4,
'eliminate-local-single-block',
'eliminate-local-single-store',
'eliminate-dead-code-aggressive',
'eliminate-local-multi-store',
'ssa-rewrite',
'eliminate-dead-code-aggressive',
'ccp',
'eliminate-dead-code-aggressive',
@ -196,7 +196,7 @@ class TestSizeOptimizationPasses(expect.ValidObjectFile1_4,
'eliminate-dead-code-aggressive',
'simplify-instructions',
'eliminate-dead-inserts',
'eliminate-local-multi-store',
'ssa-rewrite',
'eliminate-dead-code-aggressive',
'ccp',
'eliminate-dead-code-aggressive',
@ -238,7 +238,7 @@ class TestLegalizationPasses(expect.ValidObjectFile1_4,
'eliminate-local-single-block',
'eliminate-local-single-store',
'eliminate-dead-code-aggressive',
'eliminate-local-multi-store',
'ssa-rewrite',
'eliminate-dead-code-aggressive',
'ccp',
'loop-unroll',