Skip to content

Implement SSA CCP (SSA Conditional Constant Propagation)#1102

Merged
dnovillo merged 1 commit intoKhronosGroup:masterfrom
dnovillo:const-prop
Dec 21, 2017
Merged

Implement SSA CCP (SSA Conditional Constant Propagation)#1102
dnovillo merged 1 commit intoKhronosGroup:masterfrom
dnovillo:const-prop

Conversation

@dnovillo
Copy link
Copy Markdown
Contributor

This implements the conditional constant propagation pass proposed in

Constant propagation with conditional branches,
Wegman and Zadeck, ACM TOPLAS 13(2):181-210.

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.

uint32_t id = it.first;
uint32_t cst_id = it.second;
if (id != cst_id) {
context()->get_def_use_mgr()->ForEachUser(
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks. I don't know what I was thinking. Fixed.

// 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);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add ConstantManager::MapInst and merge these functions together?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MapInst?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

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;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unused variable

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed. Odd that the compiler didn't get it.

%25 = OpLabel

; %int_4 should have propagated to both OpPhi operands.
; CHECK: OpPhi %int %int_4 [[id:%\d+]] %int_4 [[id:%\d+]]
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you want to capture the math, you can use {{}} for plain regexes.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

SinglePassRunAndMatch<opt::CCPPass>(spv_asm, true);
}

TEST_F(CCPTest, SimplifySwitches) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should have another test for taking the default value of the switch.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

Copy link
Copy Markdown
Contributor

@alan-baker alan-baker left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Refactoring and more tests.

Copy link
Copy Markdown
Collaborator

@s-perron s-perron left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this pass remove the jumps or is that left for cfg cleanup?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need to add this to the android.mk file as well. I don't see that.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

// 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.
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instructions that are not "Combinators" should be kVarying. See IsCombinatorInstruction in the IRContext.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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);
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not all operands are ids. Some are literals that represent other things.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, yes. Fixed.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Still seems borken to me. I recommend using Instruction::ForEachInId

if (it != values_.end()) {
cst_val_ids.push_back(it->second);
} else {
break;
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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);
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you sure you can successfully fold all instructions? What happens if you cannot? Shouldn't it become kVarying?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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) {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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);
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

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
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be "branch that always jumps"

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.

// 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,
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

|dest_bb| is also set if the branch in an unconditional branch.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.

Copy link
Copy Markdown
Contributor Author

@dnovillo dnovillo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

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);
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, yes. Fixed.

if (it != values_.end()) {
cst_val_ids.push_back(it->second);
} else {
break;
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

// 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.
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've added a filter for the opcodes that the folder supports.

return VisitInstruction(instr, dest_bb);
};

InsertPhiInstructions(fp);
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

// 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);
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

assert(instr->IsBranch() && "Expected a branch instruction.");
uint32_t dest_label = 0;

if (instr->opcode() == SpvOpBranch) {
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

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
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.

// 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,
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.

@dnovillo dnovillo force-pushed the const-prop branch 3 times, most recently from d6ff75b to f97177d Compare December 21, 2017 16:52
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.
Copy link
Copy Markdown
Collaborator

@dneto0 dneto0 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm still reviewing....

bool Run(ir::Function* fn);

// Returns true if the |i|th argument for |phi| comes through a CFG edge that
// has been marked executable.
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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);
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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);
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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);
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Needs a method comment.

if (it != values_.end()) {
cst_val_ids.push_back(it->second);
} else {
break;
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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);
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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)) {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't work with OpSwitch over 64 bit values. You must handle or bail on that case.

@dnovillo dnovillo merged commit 4ba9dcc into KhronosGroup:master Dec 21, 2017
@dnovillo
Copy link
Copy Markdown
Contributor Author

Gah. Sorry @dneto0. I pushed too early. 4ba9dcc. I'll address David's comments and fix in a new PR.

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
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Return value is described incorrectly. It returns a Constant*

@dneto0
Copy link
Copy Markdown
Collaborator

dneto0 commented Dec 21, 2017

I filed #1130 for things I'd like fixed.

@dnovillo
Copy link
Copy Markdown
Contributor Author

dnovillo commented Dec 22, 2017 via email

dneto0 pushed a commit to dneto0/SPIRV-Tools that referenced this pull request Sep 14, 2024
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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants