mirror of
https://github.com/KhronosGroup/SPIRV-Tools
synced 2025-01-13 09:50:06 +00:00
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:
parent
7f7236f1eb
commit
35c9518c4e
@ -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 \
|
||||
|
2
BUILD.gn
2
BUILD.gn
@ -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",
|
||||
|
@ -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
|
||||
|
@ -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) {
|
||||
|
@ -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.
|
||||
|
@ -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
|
@ -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_
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -715,7 +715,7 @@ Optimizer::PassToken CreateDeadBranchElimPass() {
|
||||
|
||||
Optimizer::PassToken CreateLocalMultiStoreElimPass() {
|
||||
return MakeUnique<Optimizer::PassToken::Impl>(
|
||||
MakeUnique<opt::LocalMultiStoreElimPass>());
|
||||
MakeUnique<opt::SSARewritePass>());
|
||||
}
|
||||
|
||||
Optimizer::PassToken CreateAggressiveDCEPass() {
|
||||
|
@ -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"
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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',
|
||||
|
Loading…
Reference in New Issue
Block a user