Implement SSA CCP (SSA Conditional Constant Propagation)#1102
Implement SSA CCP (SSA Conditional Constant Propagation)#1102dnovillo merged 1 commit intoKhronosGroup:masterfrom
Conversation
source/opt/ccp_pass.cpp
Outdated
| uint32_t id = it.first; | ||
| uint32_t cst_id = it.second; | ||
| if (id != cst_id) { | ||
| context()->get_def_use_mgr()->ForEachUser( |
There was a problem hiding this comment.
Why isn't this just IRContext::ReplaceAllUsesWith? Separately DefUseManager::ForEachUse will go through all the operands so you don't have to write the nested loop
There was a problem hiding this comment.
Thanks. I don't know what I was thinking. Fixed.
source/opt/ccp_pass.cpp
Outdated
| // assignment (i.e., each constant is its own value). | ||
| for (const auto& inst : c->module()->GetConstants()) { | ||
| values_[inst->result_id()] = inst->result_id(); | ||
| const_mgr_->MapConstantToInst(const_mgr_->GetConstantFromInst(inst), inst); |
There was a problem hiding this comment.
Add ConstantManager::MapInst and merge these functions together?
There was a problem hiding this comment.
I suggest merging "const_mgr_->MapConstantToInst(const_mgr_->GetConstantFromInst(inst), inst)" together into a single new function maybe called MapInst. Since the input since to rely on other constant manager information it might be convenient to provide the single function too.
source/opt/constants.cpp
Outdated
| std::unique_ptr<analysis::Constant> new_const; | ||
| const Constant* ConstantManager::CreateConstant( | ||
| const Type* type, const std::vector<uint32_t>& literal_words_or_ids) const { | ||
| std::unique_ptr<Constant> new_const; |
There was a problem hiding this comment.
Fixed. Odd that the compiler didn't get it.
test/opt/ccp_test.cpp
Outdated
| %25 = OpLabel | ||
|
|
||
| ; %int_4 should have propagated to both OpPhi operands. | ||
| ; CHECK: OpPhi %int %int_4 [[id:%\d+]] %int_4 [[id:%\d+]] |
There was a problem hiding this comment.
If you want to capture the math, you can use {{}} for plain regexes.
| SinglePassRunAndMatch<opt::CCPPass>(spv_asm, true); | ||
| } | ||
|
|
||
| TEST_F(CCPTest, SimplifySwitches) { |
There was a problem hiding this comment.
You should have another test for taking the default value of the switch.
alan-baker
left a comment
There was a problem hiding this comment.
Refactoring and more tests.
s-perron
left a comment
There was a problem hiding this comment.
Few things that might be correct, but are not clear to me. Please have a look.
| // | ||
| // Constant values in expressions and conditional jumps are folded and | ||
| // simplified. This may reduce code size by removing never executed jump targets | ||
| // and computations with constant operands. |
There was a problem hiding this comment.
Does this pass remove the jumps or is that left for cfg cleanup?
There was a problem hiding this comment.
It does not. It leaves this to CFGCleanup, which needs to be extended (#1124).
| basic_block.cpp | ||
| block_merge_pass.cpp | ||
| build_module.cpp | ||
| ccp_pass.cpp |
There was a problem hiding this comment.
Need to add this to the android.mk file as well. I don't see that.
source/opt/ccp_pass.cpp
Outdated
| // do not bother folding it. Indicate that this instruction does not produce | ||
| // an interesting value for now. TODO(dnovillo): Some instructions will never | ||
| // produce an interesting constant value (e.g., most function calls). Return | ||
| // kVarying for those. |
There was a problem hiding this comment.
Instructions that are not "Combinators" should be kVarying. See IsCombinatorInstruction in the IRContext.
There was a problem hiding this comment.
I've added a filter for the opcodes that the folder supports.
| std::vector<uint32_t> cst_val_ids; | ||
| for (uint32_t i = 0; i < instr->NumInOperands(); i++) { | ||
| uint32_t op_id = instr->GetSingleWordInOperand(i); | ||
| auto it = values_.find(op_id); |
There was a problem hiding this comment.
Not all operands are ids. Some are literals that represent other things.
There was a problem hiding this comment.
Still seems borken to me. I recommend using Instruction::ForEachInId
| if (it != values_.end()) { | ||
| cst_val_ids.push_back(it->second); | ||
| } else { | ||
| break; |
There was a problem hiding this comment.
How do you tell if you exited early? Does it matter? My guess is that this is an id that is not constant, so you do care.
There was a problem hiding this comment.
No, we do not. If we do not find a foldable instruction, we just mark it not interesting. The propagator will continue simulating and come back to visit this instruction if any SSA edge changed (i.e., some operand became constant).
I've protected this code with a predicate that filters all non-foldable instructions.
There was a problem hiding this comment.
I agree with @s-perron here. If you find an id that is non-constant, then you should bail early here rather than relying on FoldScalars later on to try to fail.
I could see an instruction being foldable even with a non-constant Id. (e.g. %mul = OpIMul %uint %x %uint_0) however, in that case how does FoldScalars line up the constant-values with the operands. The Id that is non-constant is missing from the vector and the folding call is nonsensical.
|
|
||
| // Otherwise, fold the instruction with all the operands to produce a new | ||
| // constant. | ||
| uint32_t result_val = FoldScalars(instr->opcode(), constants); |
There was a problem hiding this comment.
Are you sure you can successfully fold all instructions? What happens if you cannot? Shouldn't it become kVarying?
There was a problem hiding this comment.
Good point. We'd die because the folder asserts when we send it a unsupported opcode. I've added code to mark as varying any instruction whose opcode is not one of the supported ones by the folder. This will be conservatively safe. We can expand the set as we augment the folder capabilities.
There was a problem hiding this comment.
Also worth saying you only handle scalars with bit patterns of 32-bits.
| assert(instr->IsBranch() && "Expected a branch instruction."); | ||
| uint32_t dest_label = 0; | ||
|
|
||
| if (instr->opcode() == SpvOpBranch) { |
There was a problem hiding this comment.
It is only three cases, but would this be cleaner as a switch? Also, we could code this more defensively with a default case that assert for unknown branch instructions. If a new branch is added with IsBranch changing, it will let people know they have to add a case.
There was a problem hiding this comment.
Well, there's not much to switch on. The branches are protected against unknown branches in VisitBranch and the third case is not about specific opcodes.
| return VisitInstruction(instr, dest_bb); | ||
| }; | ||
|
|
||
| InsertPhiInstructions(fp); |
There was a problem hiding this comment.
Do we really want this to be part of CCP, and not its own pass? If another pass already did this, do we really want to do it again?
There was a problem hiding this comment.
Phi insertion is called by whatever pass needs Phi instructions. It's a pass helper, not a pass itself. Doing it again is a nop. Phis are not inserted if they're not needed.
source/opt/ccp_pass.h
Outdated
| bool PropagateConstants(ir::Function* fp); | ||
|
|
||
| // Visits a single instruction |instr|. If the instruction is a conditional | ||
| // branch with that always jumps to the same basic block, it sets the |
There was a problem hiding this comment.
Should be "branch that always jumps"
| // Visits a branch instruction |instr|. If the branch is conditional | ||
| // (OpBranchConditional or OpSwitch), and the value of its selector is known, | ||
| // |dest_bb| will be set to the corresponding destination block. | ||
| SSAPropagator::PropStatus VisitBranch(ir::Instruction* instr, |
There was a problem hiding this comment.
|dest_bb| is also set if the branch in an unconditional branch.
3030282 to
1b5e14b
Compare
dnovillo
left a comment
There was a problem hiding this comment.
Addressed review feedback. Thanks. PTAL.
| // | ||
| // Constant values in expressions and conditional jumps are folded and | ||
| // simplified. This may reduce code size by removing never executed jump targets | ||
| // and computations with constant operands. |
There was a problem hiding this comment.
It does not. It leaves this to CFGCleanup, which needs to be extended (#1124).
| basic_block.cpp | ||
| block_merge_pass.cpp | ||
| build_module.cpp | ||
| ccp_pass.cpp |
| std::vector<uint32_t> cst_val_ids; | ||
| for (uint32_t i = 0; i < instr->NumInOperands(); i++) { | ||
| uint32_t op_id = instr->GetSingleWordInOperand(i); | ||
| auto it = values_.find(op_id); |
| if (it != values_.end()) { | ||
| cst_val_ids.push_back(it->second); | ||
| } else { | ||
| break; |
There was a problem hiding this comment.
No, we do not. If we do not find a foldable instruction, we just mark it not interesting. The propagator will continue simulating and come back to visit this instruction if any SSA edge changed (i.e., some operand became constant).
I've protected this code with a predicate that filters all non-foldable instructions.
source/opt/ccp_pass.cpp
Outdated
| // do not bother folding it. Indicate that this instruction does not produce | ||
| // an interesting value for now. TODO(dnovillo): Some instructions will never | ||
| // produce an interesting constant value (e.g., most function calls). Return | ||
| // kVarying for those. |
There was a problem hiding this comment.
I've added a filter for the opcodes that the folder supports.
| return VisitInstruction(instr, dest_bb); | ||
| }; | ||
|
|
||
| InsertPhiInstructions(fp); |
There was a problem hiding this comment.
Phi insertion is called by whatever pass needs Phi instructions. It's a pass helper, not a pass itself. Doing it again is a nop. Phis are not inserted if they're not needed.
source/opt/ccp_pass.cpp
Outdated
| // assignment (i.e., each constant is its own value). | ||
| for (const auto& inst : c->module()->GetConstants()) { | ||
| values_[inst->result_id()] = inst->result_id(); | ||
| const_mgr_->MapConstantToInst(const_mgr_->GetConstantFromInst(inst), inst); |
| assert(instr->IsBranch() && "Expected a branch instruction."); | ||
| uint32_t dest_label = 0; | ||
|
|
||
| if (instr->opcode() == SpvOpBranch) { |
There was a problem hiding this comment.
Well, there's not much to switch on. The branches are protected against unknown branches in VisitBranch and the third case is not about specific opcodes.
source/opt/ccp_pass.h
Outdated
| bool PropagateConstants(ir::Function* fp); | ||
|
|
||
| // Visits a single instruction |instr|. If the instruction is a conditional | ||
| // branch with that always jumps to the same basic block, it sets the |
| // Visits a branch instruction |instr|. If the branch is conditional | ||
| // (OpBranchConditional or OpSwitch), and the value of its selector is known, | ||
| // |dest_bb| will be set to the corresponding destination block. | ||
| SSAPropagator::PropStatus VisitBranch(ir::Instruction* instr, |
d6ff75b to
f97177d
Compare
This implements the conditional constant propagation pass proposed in Constant propagation with conditional branches, Wegman and Zadeck, ACM TOPLAS 13(2):181-210. The main logic resides in CCPPass::VisitInstruction. Instruction that may produce a constant value are evaluated with the constant folder. If they produce a new constant, the instruction is considered interesting. Otherwise, it's considered varying (for unfoldable instructions) or just not interesting (when not enough operands have a constant value). The other main piece of logic is in CCPPass::VisitBranch. This evaluates the selector of the branch. When it's found to be a known value, it computes the destination basic block and sets it. This tells the propagator which branches to follow. The patch required extensions to the constant manager as well. Instead of hashing the Constant pointers, this patch changes the constant pool to hash the contents of the Constant. This allows the lookups to be done using the actual values of the Constant, preventing duplicate definitions.
| bool Run(ir::Function* fn); | ||
|
|
||
| // Returns true if the |i|th argument for |phi| comes through a CFG edge that | ||
| // has been marked executable. |
There was a problem hiding this comment.
MIght be worth saying the numbering for |i| is 0-based and includes result id and type id ??
Or just say you're going to use it with GetSingleWordOperand
| std::vector<uint32_t> cst_val_ids; | ||
| for (uint32_t i = 0; i < instr->NumInOperands(); i++) { | ||
| uint32_t op_id = instr->GetSingleWordInOperand(i); | ||
| auto it = values_.find(op_id); |
There was a problem hiding this comment.
Still seems borken to me. I recommend using Instruction::ForEachInId
|
|
||
| uint32_t FoldScalars(SpvOp opcode, | ||
| const std::vector<analysis::Constant*>& operands); | ||
| const std::vector<const analysis::Constant*>& operands); |
There was a problem hiding this comment.
This needs a method comment out here in the header. I don't want to have to read the code to know what's going on.
| const std::vector<analysis::Constant*>& operands); | ||
| const std::vector<const analysis::Constant*>& operands); | ||
|
|
||
| bool IsFoldableOpcode(SpvOp opcode); |
| if (it != values_.end()) { | ||
| cst_val_ids.push_back(it->second); | ||
| } else { | ||
| break; |
There was a problem hiding this comment.
I agree with @s-perron here. If you find an id that is non-constant, then you should bail early here rather than relying on FoldScalars later on to try to fail.
I could see an instruction being foldable even with a non-constant Id. (e.g. %mul = OpIMul %uint %x %uint_0) however, in that case how does FoldScalars line up the constant-values with the operands. The Id that is non-constant is missing from the vector and the folding call is nonsensical.
|
|
||
| // Otherwise, fold the instruction with all the operands to produce a new | ||
| // constant. | ||
| uint32_t result_val = FoldScalars(instr->opcode(), constants); |
There was a problem hiding this comment.
Also worth saying you only handle scalars with bit patterns of 32-bits.
| ir::BasicBlock** dest_bb) const { | ||
| assert(instr->IsBranch() && "Expected a branch instruction."); | ||
| uint32_t dest_label = 0; | ||
|
|
There was a problem hiding this comment.
Optional: *dest_bb =nullptr right at the start. It's defensive.
| // Start assuming that the selector will take the default value; | ||
| dest_label = instr->GetSingleWordOperand(1); | ||
| for (uint32_t i = 2; i < instr->NumOperands(); i += 2) { | ||
| if (val->words()[0] == instr->GetSingleWordOperand(i)) { |
There was a problem hiding this comment.
This doesn't work with OpSwitch over 64 bit values. You must handle or bail on that case.
| const Type* type, const std::vector<uint32_t>& literal_words_or_ids); | ||
|
|
||
| // Gets or creates a Constant instance to hold the constant value of the given | ||
| // instruction. It returns a pointer to the Constant's defining instruction or |
There was a problem hiding this comment.
Return value is described incorrectly. It returns a Constant*
|
I filed #1130 for things I'd like fixed. |
|
On Thu, Dec 21, 2017 at 2:41 PM, David Neto ***@***.***> wrote:
***@***.**** requested changes on this pull request.
I'm still reviewing....
------------------------------
In source/opt/propagator.h
<#1102 (comment)>
:
> // the function. Otherwise, it returns false.
bool Run(ir::Function* fn);
+ // Returns true if the |i|th argument for |phi| comes through a CFG edge that
+ // has been marked executable.
MIght be worth saying the numbering for |i| is 0-based and includes result
id and type id ??
Or just say you're going to use it with GetSingleWordOperand
Done.
------------------------------
In source/opt/ccp_pass.cpp
<#1102 (comment)>
:
> + // value to the LHS.
+ if (instr->opcode() == SpvOpCopyObject) {
+ uint32_t rhs_id = instr->GetSingleWordInOperand(0);
+ auto it = values_.find(rhs_id);
+ if (it != values_.end()) {
+ values_[instr->result_id()] = it->second;
+ return SSAPropagator::kInteresting;
+ }
+ return SSAPropagator::kNotInteresting;
+ }
+
+ // Otherwise, see if the RHS of the assignment folds into a constant value.
+ std::vector<uint32_t> cst_val_ids;
+ for (uint32_t i = 0; i < instr->NumInOperands(); i++) {
+ uint32_t op_id = instr->GetSingleWordInOperand(i);
+ auto it = values_.find(op_id);
Still seems borken to me. I recommend using Instruction::ForEachInId
Done.
------------------------------
In source/opt/fold.h
<#1102 (comment)>
:
> @@ -25,11 +25,13 @@ namespace spvtools {
namespace opt {
uint32_t FoldScalars(SpvOp opcode,
- const std::vector<analysis::Constant*>& operands);
+ const std::vector<const analysis::Constant*>& operands);
This needs a method comment out here in the header. I don't want to have
to read the code to know what's going on.
Done.
------------------------------
In source/opt/fold.h
<#1102 (comment)>
:
>
std::vector<uint32_t> FoldVectors(
SpvOp opcode, uint32_t num_dims,
- const std::vector<analysis::Constant*>& operands);
+ const std::vector<const analysis::Constant*>& operands);
+
+bool IsFoldableOpcode(SpvOp opcode);
Needs a method comment.
Done.
------------------------------
In source/opt/ccp_pass.cpp
<#1102 (comment)>
:
> + if (it != values_.end()) {
+ values_[instr->result_id()] = it->second;
+ return SSAPropagator::kInteresting;
+ }
+ return SSAPropagator::kNotInteresting;
+ }
+
+ // Otherwise, see if the RHS of the assignment folds into a constant value.
+ std::vector<uint32_t> cst_val_ids;
+ for (uint32_t i = 0; i < instr->NumInOperands(); i++) {
+ uint32_t op_id = instr->GetSingleWordInOperand(i);
+ auto it = values_.find(op_id);
+ if (it != values_.end()) {
+ cst_val_ids.push_back(it->second);
+ } else {
+ break;
I agree with @s-perron <https://github.com/s-perron> here. If you find an
id that is non-constant, then you should bail early here rather than
relying on FoldScalars later on to try to fail.
I *could* see an instruction being foldable even with a non-constant Id.
(e.g. %mul = OpIMul %uint %x %uint_0) however, in that case how does
FoldScalars line up the constant-values with the operands. The Id that is
non-constant is missing from the vector and the folding call is nonsensical.
We do bail early. If we cannot obtain a Constant instance out of ALL the
operands in the instruction, the |constants| vector down below will be
empty. I've now added an IsFoldableConstant() method in the folder. This
way, we can return varying if any constants are unsupported.
------------------------------
In source/opt/ccp_pass.cpp
<#1102 (comment)>
:
> + }
+ }
+
+ // If we did not find a constant value for every operand in the instruction,
+ // do not bother folding it. Indicate that this instruction does not produce
+ // an interesting value for now. TODO(dnovillo): Some instructions will never
+ // produce an interesting constant value (e.g., most function calls). Return
+ // kVarying for those.
+ auto constants = const_mgr_->GetConstantsFromIds(cst_val_ids);
+ if (constants.size() == 0) {
+ return SSAPropagator::kNotInteresting;
+ }
+
+ // Otherwise, fold the instruction with all the operands to produce a new
+ // constant.
+ uint32_t result_val = FoldScalars(instr->opcode(), constants);
Also worth saying you only handle scalars with bit patterns of 32-bits.
Done. New IsFoldableConstant() helper in fold.cpp
------------------------------
In source/opt/ccp_pass.cpp
<#1102 (comment)>
:
> + // Otherwise, fold the instruction with all the operands to produce a new
+ // constant.
+ uint32_t result_val = FoldScalars(instr->opcode(), constants);
+ const analysis::Constant* result_const =
+ const_mgr_->GetConstant(const_mgr_->GetType(instr), {result_val});
+ ir::Instruction* const_decl =
+ const_mgr_->GetDefiningInstruction(result_const);
+ values_[instr->result_id()] = const_decl->result_id();
+ return SSAPropagator::kInteresting;
+}
+
+SSAPropagator::PropStatus CCPPass::VisitBranch(ir::Instruction* instr,
+ ir::BasicBlock** dest_bb) const {
+ assert(instr->IsBranch() && "Expected a branch instruction.");
+ uint32_t dest_label = 0;
+
Optional: *dest_bb =nullptr right at the start. It's defensive.
It's set in every path, and the caller, but I floated it above for clarity.
------------------------------
In source/opt/ccp_pass.cpp
<#1102 (comment)>
:
> + *dest_bb = nullptr;
+ return SSAPropagator::kVarying;
+ }
+
+ // Get the constant value for the selector from the value table. Use it to
+ // decide which branch will be taken.
+ uint32_t select_val_id = it->second;
+ const analysis::Constant* c =
+ const_mgr_->FindDeclaredConstant(select_val_id);
+ assert(c && "Expected to find a constant declaration for a known value.");
+ const analysis::IntConstant* val = c->AsIntConstant();
+
+ // Start assuming that the selector will take the default value;
+ dest_label = instr->GetSingleWordOperand(1);
+ for (uint32_t i = 2; i < instr->NumOperands(); i += 2) {
+ if (val->words()[0] == instr->GetSingleWordOperand(i)) {
This doesn't work with OpSwitch over 64 bit values. You must handle or
bail on that case.
Done.
|
Roll third_party/effcee/ 5af957bbf..2ec8f8738 (3 commits) google/effcee@5af957b...2ec8f87 $ git log 5af957bbf..2ec8f8738 --date=short --no-merges --format='%ad %ae %s' 2020-06-16 dneto Start v2020.0-dev 2020-06-16 dneto Finalize v2019.1 2020-06-15 dneto Update CHANGES Created with: roll-dep third_party/effcee Roll third_party/glslang/ e8c9fd6..b481744 (19 commits) KhronosGroup/glslang@e8c9fd6...b481744 $ git log e8c9fd6..b481744 --date=short --no-merges --format='%ad %ae %s' 2020-07-14 bclayton Give build_info.py the executable bit 2020-07-14 cepheus Fix recently found non-determinism with gl_WorldToObject3x4EXT. 2020-07-14 cepheus Non-determinism: Remove test file that seems to trigger non-determinism. 2020-07-13 bclayton Add bison license to LICENSE.txt 2020-07-13 bclayton CMake: Move project() to top of CMakeLists.txt 2020-07-13 bclayton Kokoro: Print test output to stdout 2020-07-13 cepheus Fix comma in licence checker. 2020-07-13 cepheus Revert "Merge pull request KhronosGroup#2330 from ShabbyX/optimize_for_angle" 2020-07-13 cepheus Fix a couple lines that were too long, to retrigger bots. 2020-07-13 cepheus Fix KhronosGroup#2329: don't use invalid initializers. 2020-07-12 bclayton Add missing comma from license-checker.cfg 2020-07-12 ccom Common: include standard headers before doing any defines 2020-07-10 bclayton Fix CMake rules when nesting CMake projects 2020-07-10 bclayton Attempt to fix chromium builds 2020-06-17 bclayton Generate build information from CHANGES.md 2020-07-03 ShabbyX Customize glslang.y to GLSLANG_ANGLE 2020-07-03 ShabbyX Use GLSLANG_ANGLE to strip features to what ANGLE requires 2020-07-07 rharrison Make sure glslang_angle has a definition in BUILD.gn 2020-07-07 bclayton Use CMake's builtin functionality for PCHs Created with: roll-dep third_party/glslang Roll third_party/googletest/ 356f2d264..70b90929b (7 commits) google/googletest@356f2d2...70b9092 $ git log 356f2d264..70b90929b --date=short --no-merges --format='%ad %ae %s' 2020-07-09 absl-team Googletest export 2020-07-07 ofats Googletest export 2020-07-07 absl-team Googletest export 2020-07-07 absl-team Googletest export 2020-04-11 olivier.ldff use target_compile_features to use c++11 if cmake > 3.8 2020-05-30 eli fix compilation on OpenBSD 6.7 2020-01-22 mjvk Fixes extensions missing for QNX Created with: roll-dep third_party/googletest Roll third_party/spirv-cross/ 559b21c6c..6575e451f (2 commits) KhronosGroup/SPIRV-Cross@559b21c...6575e45 $ git log 559b21c6c..6575e451f --date=short --no-merges --format='%ad %ae %s' 2020-07-11 post MSVC 2013: Fix silently broken builds. 2020-07-07 troughton MSL: Ensure OpStore source operands are marked for inclusion in function arguments Created with: roll-dep third_party/spirv-cross Roll third_party/spirv-tools/ 6a4da9d..c9b254d (17 commits) KhronosGroup/SPIRV-Tools@6a4da9d...c9b254d $ git log 6a4da9d..c9b254d --date=short --no-merges --format='%ad %ae %s' 2020-07-14 andreperezmaselco.developer spirv-fuzz: Support adding dead break from back-edge block (KhronosGroup#3519) 2020-07-14 andreperezmaselco.developer Support OpPhi when replacing boolean constant operand (KhronosGroup#3518) 2020-07-12 vasniktel spirv-fuzz: TransformationAddSynonyms (KhronosGroup#3447) 2020-07-11 vasniktel spirv-fuzz: Remove unused functions (KhronosGroup#3510) 2020-07-11 vasniktel spirv-fuzz: Minor refactoring (KhronosGroup#3507) 2020-07-10 greg Preserve OpenCL.DebugInfo.100 through elim-local-single-store (KhronosGroup#3498) 2020-07-10 jaebaek Preserve debug info in vector DCE pass (KhronosGroup#3497) 2020-07-10 stefano.milizia00 Implement transformation to record synonymous constants. (KhronosGroup#3494) 2020-07-09 jaebaek Fix build failure (KhronosGroup#3508) 2020-07-09 greg Upgrade elim-local-single-block for OpenCL.DebugInfo.100 (KhronosGroup#3451) 2020-07-09 vasniktel spirv-fuzz: TransformationReplaceParameterWithGlobal (KhronosGroup#3434) 2020-07-09 andreperezmaselco.developer Implement the OpMatrixTimesVector linear algebra case (KhronosGroup#3500) 2020-07-08 jaebaek Preserve OpenCL.100.DebugInfo in reduce-load-size pass (KhronosGroup#3492) 2020-07-08 andreperezmaselco.developer spirv-fuzz: Add image sample unused components transformation (KhronosGroup#3439) 2020-07-07 andreperezmaselco.developer spirv-fuzz: Add variables with workgroup storage class (KhronosGroup#3485) 2020-07-07 andreperezmaselco.developer spirv-fuzz: Implement the OpVectorTimesMatrix linear algebra case (KhronosGroup#3489) 2020-07-07 vasniktel spirv-fuzz: fuzzerutil::MaybeGetConstant* KhronosGroup#3487 Created with: roll-dep third_party/spirv-tools
This implements the conditional constant propagation pass proposed in
The implementation uses the SSA propagation engine added in #985 and is the final fix needed for #889.
The implementation required several changes in the constant manager. I believe I should separate those changes into a separate PR. I'll see about doing this early next week.
The test cases cover all the possible CFG situations the propagator can find itself in. CCP has the potential of leaving unreachable regions in the CFG (when it simplifies conditionals) and dead code (when it propagates an assignment).
I've scheduled CCP in -O and -Os so that DCE and CFGCleanup run after it. We'll need to adjust this as we test with real code.