Commit 10973789 by John Kessenich

Merge branch 'dead-code' of https://github.com/dneto0/glslang into dneto0-dead-code

parents 7f77b2e8 8c3d5b4b
......@@ -1630,11 +1630,11 @@ void TGlslangToSpvTraverser::finishSpv()
for (auto it = iOSet.cbegin(); it != iOSet.cend(); ++it)
entryPoint->addIdOperand(*it);
#ifndef GLSLANG_WEB
// Add capabilities, extensions, remove unneeded decorations, etc.,
// Add capabilities, extensions, remove unneeded decorations, etc.,
// based on the resulting SPIR-V.
// Note: WebGPU code generation must have the opportunity to aggressively
// prune unreachable merge blocks and continue targets.
builder.postProcess();
#endif
}
// Write the SPV into 'out'.
......
......@@ -61,17 +61,22 @@ namespace {
// Use by calling visit() on the root block.
class ReadableOrderTraverser {
public:
explicit ReadableOrderTraverser(std::function<void(Block*)> callback) : callback_(callback) {}
ReadableOrderTraverser(std::function<void(Block*, spv::ReachReason, Block*)> callback)
: callback_(callback) {}
// Visits the block if it hasn't been visited already and isn't currently
// being delayed. Invokes callback(block), then descends into its
// being delayed. Invokes callback(block, why, header), then descends into its
// successors. Delays merge-block and continue-block processing until all
// the branches have been completed.
void visit(Block* block)
// the branches have been completed. If |block| is an unreachable merge block or
// an unreachable continue target, then |header| is the corresponding header block.
void visit(Block* block, spv::ReachReason why, Block* header)
{
assert(block);
if (why == spv::ReachViaControlFlow) {
reachableViaControlFlow_.insert(block);
}
if (visited_.count(block) || delayed_.count(block))
return;
callback_(block);
callback_(block, why, header);
visited_.insert(block);
Block* mergeBlock = nullptr;
Block* continueBlock = nullptr;
......@@ -87,27 +92,40 @@ public:
delayed_.insert(continueBlock);
}
}
const auto successors = block->getSuccessors();
for (auto it = successors.cbegin(); it != successors.cend(); ++it)
visit(*it);
if (why == spv::ReachViaControlFlow) {
const auto& successors = block->getSuccessors();
for (auto it = successors.cbegin(); it != successors.cend(); ++it)
visit(*it, why, nullptr);
}
if (continueBlock) {
const spv::ReachReason continueWhy =
(reachableViaControlFlow_.count(continueBlock) > 0)
? spv::ReachViaControlFlow
: spv::ReachDeadContinue;
delayed_.erase(continueBlock);
visit(continueBlock);
visit(continueBlock, continueWhy, block);
}
if (mergeBlock) {
const spv::ReachReason mergeWhy =
(reachableViaControlFlow_.count(mergeBlock) > 0)
? spv::ReachViaControlFlow
: spv::ReachDeadMerge;
delayed_.erase(mergeBlock);
visit(mergeBlock);
visit(mergeBlock, mergeWhy, block);
}
}
private:
std::function<void(Block*)> callback_;
std::function<void(Block*, spv::ReachReason, Block*)> callback_;
// Whether a block has already been visited or is being delayed.
std::unordered_set<Block *> visited_, delayed_;
// The set of blocks that actually are reached via control flow.
std::unordered_set<Block *> reachableViaControlFlow_;
};
}
void spv::inReadableOrder(Block* root, std::function<void(Block*)> callback)
void spv::inReadableOrder(Block* root, std::function<void(Block*, spv::ReachReason, Block*)> callback)
{
ReadableOrderTraverser(callback).visit(root);
ReadableOrderTraverser(callback).visit(root, spv::ReachViaControlFlow, nullptr);
}
......@@ -683,14 +683,12 @@ public:
// based on the type of the base and the chain of dereferences.
Id accessChainGetInferredType();
// Add capabilities, extensions, remove unneeded decorations, etc.,
// Add capabilities, extensions, remove unneeded decorations, etc.,
// based on the resulting SPIR-V.
void postProcess();
// Hook to visit each instruction in a block in a function
void postProcess(Instruction&);
// Hook to visit each instruction in a reachable block in a function.
void postProcessReachable(const Instruction&);
// Hook to visit each non-32-bit sized float/int operation in a block.
void postProcessType(const Instruction&, spv::Id typeId);
......
......@@ -39,6 +39,7 @@
#include <cassert>
#include <cstdlib>
#include <unordered_map>
#include <unordered_set>
#include <algorithm>
......@@ -319,16 +320,14 @@ void Builder::postProcess(Instruction& inst)
}
}
// Called for each instruction in a reachable block.
void Builder::postProcessReachable(const Instruction&)
{
// did have code here, but questionable to do so without deleting the instructions
}
// comment in header
void Builder::postProcess()
{
// reachableBlocks is the set of blockss reached via control flow, or which are
// unreachable continue targert or unreachable merge.
std::unordered_set<const Block*> reachableBlocks;
std::unordered_map<Block*, Block*> headerForUnreachableContinue;
std::unordered_set<Block*> unreachableMerges;
std::unordered_set<Id> unreachableDefinitions;
// Collect IDs defined in unreachable blocks. For each function, label the
// reachable blocks first. Then for each unreachable block, collect the
......@@ -336,16 +335,41 @@ void Builder::postProcess()
for (auto fi = module.getFunctions().cbegin(); fi != module.getFunctions().cend(); fi++) {
Function* f = *fi;
Block* entry = f->getEntryBlock();
inReadableOrder(entry, [&reachableBlocks](const Block* b) { reachableBlocks.insert(b); });
inReadableOrder(entry,
[&reachableBlocks, &unreachableMerges, &headerForUnreachableContinue]
(Block* b, ReachReason why, Block* header) {
reachableBlocks.insert(b);
if (why == ReachDeadContinue) headerForUnreachableContinue[b] = header;
if (why == ReachDeadMerge) unreachableMerges.insert(b);
});
for (auto bi = f->getBlocks().cbegin(); bi != f->getBlocks().cend(); bi++) {
Block* b = *bi;
if (reachableBlocks.count(b) == 0) {
for (auto ii = b->getInstructions().cbegin(); ii != b->getInstructions().cend(); ii++)
if (unreachableMerges.count(b) != 0 || headerForUnreachableContinue.count(b) != 0) {
auto ii = b->getInstructions().cbegin();
++ii; // Keep potential decorations on the label.
for (; ii != b->getInstructions().cend(); ++ii)
unreachableDefinitions.insert(ii->get()->getResultId());
} else if (reachableBlocks.count(b) == 0) {
// The normal case for unreachable code. All definitions are considered dead.
for (auto ii = b->getInstructions().cbegin(); ii != b->getInstructions().cend(); ++ii)
unreachableDefinitions.insert(ii->get()->getResultId());
}
}
}
// Modify unreachable merge blocks and unreachable continue targets.
// Delete their contents.
for (auto mergeIter = unreachableMerges.begin(); mergeIter != unreachableMerges.end(); ++mergeIter) {
(*mergeIter)->rewriteAsCanonicalUnreachableMerge();
}
for (auto continueIter = headerForUnreachableContinue.begin();
continueIter != headerForUnreachableContinue.end();
++continueIter) {
Block* continue_target = continueIter->first;
Block* header = continueIter->second;
continue_target->rewriteAsCanonicalUnreachableContinue(header);
}
// Remove unneeded decorations, for unreachable instructions
decorations.erase(std::remove_if(decorations.begin(), decorations.end(),
[&unreachableDefinitions](std::unique_ptr<Instruction>& I) -> bool {
......@@ -374,13 +398,6 @@ void Builder::postProcess()
}
}
// process all reachable instructions...
for (auto bi = reachableBlocks.cbegin(); bi != reachableBlocks.cend(); ++bi) {
const Block* block = *bi;
const auto function = [this](const std::unique_ptr<Instruction>& inst) { postProcessReachable(*inst.get()); };
std::for_each(block->getInstructions().begin(), block->getInstructions().end(), function);
}
// process all block-contained instructions
for (auto fi = module.getFunctions().cbegin(); fi != module.getFunctions().cend(); fi++) {
Function* f = *fi;
......
......@@ -226,6 +226,36 @@ public:
return nullptr;
}
// Change this block into a canonical dead merge block. Delete instructions
// as necessary. A canonical dead merge block has only an OpLabel and an
// OpUnreachable.
void rewriteAsCanonicalUnreachableMerge() {
assert(localVariables.empty());
// Delete all instructions except for the label.
assert(instructions.size() > 0);
instructions.resize(1);
successors.clear();
Instruction* unreachable = new Instruction(OpUnreachable);
addInstruction(std::unique_ptr<Instruction>(unreachable));
}
// Change this block into a canonical dead continue target branching to the
// given header ID. Delete instructions as necessary. A canonical dead continue
// target has only an OpLabel and an unconditional branch back to the corresponding
// header.
void rewriteAsCanonicalUnreachableContinue(Block* header) {
assert(localVariables.empty());
// Delete all instructions except for the label.
assert(instructions.size() > 0);
instructions.resize(1);
successors.clear();
// Add OpBranch back to the header.
assert(header != nullptr);
Instruction* branch = new Instruction(OpBranch);
branch->addIdOperand(header->getId());
addInstruction(std::move(std::unique_ptr<Instruction>(branch)));
successors.push_back(header);
}
bool isTerminated() const
{
switch (instructions.back()->getOpCode()) {
......@@ -235,6 +265,7 @@ public:
case OpKill:
case OpReturn:
case OpReturnValue:
case OpUnreachable:
return true;
default:
return false;
......@@ -268,10 +299,24 @@ protected:
bool unreachable;
};
// The different reasons for reaching a block in the inReadableOrder traversal.
typedef enum ReachReason {
// Reachable from the entry block via transfers of control, i.e. branches.
ReachViaControlFlow = 0,
// A continue target that is not reachable via control flow.
ReachDeadContinue,
// A merge block that is not reachable via control flow.
ReachDeadMerge
};
// Traverses the control-flow graph rooted at root in an order suited for
// readable code generation. Invokes callback at every node in the traversal
// order.
void inReadableOrder(Block* root, std::function<void(Block*)> callback);
// order. The callback arguments are:
// - the block,
// - the reason we reached the block,
// - if the reason was that block is an unreachable continue or unreachable merge block
// then the last parameter is the corresponding header block.
void inReadableOrder(Block* root, std::function<void(Block*, ReachReason, Block* header)> callback);
//
// SPIR-V IR Function.
......@@ -321,7 +366,7 @@ public:
parameterInstructions[p]->dump(out);
// Blocks
inReadableOrder(blocks[0], [&out](const Block* b) { b->dump(out); });
inReadableOrder(blocks[0], [&out](const Block* b, ReachReason, Block*) { b->dump(out); });
Instruction end(0, 0, OpFunctionEnd);
end.dump(out);
}
......
......@@ -988,7 +988,7 @@ void CompileAndLinkShaderUnits(std::vector<ShaderCompUnit> compUnits)
// Set base bindings
shader->setShiftBinding(res, baseBinding[res][compUnit.stage]);
// Set bindings for particular resource sets
// TODO: use a range based for loop here, when available in all environments.
for (auto i = baseBindingForSet[res][compUnit.stage].begin();
......
......@@ -240,6 +240,5 @@ Validation failed
60: 7(fvec4) CompositeConstruct 59 59 59 59
ReturnValue 60
30: Label
62: 7(fvec4) Undef
ReturnValue 62
Unreachable
FunctionEnd
......@@ -305,6 +305,5 @@ gl_FragCoord origin is upper left
66: 9(fvec4) CompositeConstruct 65 65 65 65
ReturnValue 66
45: Label
68: 9(fvec4) Undef
ReturnValue 68
Unreachable
FunctionEnd
......@@ -344,6 +344,5 @@ gl_FragCoord origin is upper left
84: 9(fvec4) CompositeConstruct 83 83 83 83
ReturnValue 84
53: Label
86: 9(fvec4) Undef
ReturnValue 86
Unreachable
FunctionEnd
......@@ -303,6 +303,5 @@ gl_FragCoord origin is upper left
66: 9(fvec4) CompositeConstruct 65 65 65 65
ReturnValue 66
45: Label
68: 9(fvec4) Undef
ReturnValue 68
Unreachable
FunctionEnd
......@@ -118,6 +118,5 @@ gl_FragCoord origin is upper left
23: Label
ReturnValue 24
16: Label
26: 7(fvec4) Undef
ReturnValue 26
Unreachable
FunctionEnd
......@@ -88,7 +88,7 @@ remap.similar_1a.everything.frag
22102: 649(ptr) Variable Function
24151: 12(int) Load 4408
13868: 9(bool) SGreaterThan 24151 2577
SelectionMerge 22309 None
SelectionMerge 14966 None
BranchConditional 13868 9492 17416
9492: Label
15624: 12(int) Load 4408
......@@ -109,7 +109,6 @@ remap.similar_1a.everything.frag
10505: 12(int) IAdd 11462 21176
14626: 13(float) ConvertSToF 10505
ReturnValue 14626
22309: Label
6429: 13(float) Undef
ReturnValue 6429
14966: Label
Unreachable
FunctionEnd
......@@ -124,6 +124,5 @@ remap.similar_1a.none.frag
68: 8(float) ConvertSToF 67
ReturnValue 68
43: Label
70: 8(float) Undef
ReturnValue 70
Unreachable
FunctionEnd
......@@ -93,7 +93,7 @@ remap.similar_1b.everything.frag
22102: 649(ptr) Variable Function
24151: 12(int) Load 4408
13868: 9(bool) SGreaterThan 24151 2577
SelectionMerge 22309 None
SelectionMerge 14966 None
BranchConditional 13868 10822 17416
10822: Label
22680: 12(int) Load 4408
......@@ -115,7 +115,6 @@ remap.similar_1b.everything.frag
10505: 12(int) IAdd 11462 21176
14626: 13(float) ConvertSToF 10505
ReturnValue 14626
22309: Label
6429: 13(float) Undef
ReturnValue 6429
14966: Label
Unreachable
FunctionEnd
......@@ -130,6 +130,5 @@ remap.similar_1b.none.frag
73: 8(float) ConvertSToF 72
ReturnValue 73
46: Label
75: 8(float) Undef
ReturnValue 75
Unreachable
FunctionEnd
spv.dead-after-continue.vert
// Module Version 10000
// Generated by (magic number): 80007
// Id's are bound by 29
Capability Shader
1: ExtInstImport "GLSL.std.450"
MemoryModel Logical GLSL450
EntryPoint Vertex 4 "main" 20 28
Source GLSL 450
Name 4 "main"
Name 8 "i"
Name 20 "o"
Name 28 "c"
Decorate 20(o) Location 0
Decorate 28(c) Location 0
2: TypeVoid
3: TypeFunction 2
6: TypeInt 32 1
7: TypePointer Function 6(int)
9: 6(int) Constant 0
16: 6(int) Constant 5
17: TypeBool
19: TypePointer Output 6(int)
20(o): 19(ptr) Variable Output
21: 6(int) Constant 1
23: 6(int) Constant 2
26: 6(int) Constant 3
27: TypePointer Input 6(int)
28(c): 27(ptr) Variable Input
4(main): 2 Function None 3
5: Label
8(i): 7(ptr) Variable Function
Store 8(i) 9
Branch 10
10: Label
LoopMerge 12 13 None
Branch 14
14: Label
15: 6(int) Load 8(i)
18: 17(bool) SLessThan 15 16
BranchConditional 18 11 12
11: Label
Store 20(o) 21
Branch 13
13: Label
24: 6(int) Load 8(i)
25: 6(int) IAdd 24 21
Store 8(i) 25
Branch 10
12: Label
Store 20(o) 26
Return
FunctionEnd
spv.dead-after-discard.frag
// Module Version 10000
// Generated by (magic number): 80007
// Id's are bound by 15
Capability Shader
1: ExtInstImport "GLSL.std.450"
MemoryModel Logical GLSL450
EntryPoint Fragment 4 "main" 8 14
ExecutionMode 4 OriginUpperLeft
Source GLSL 450
Name 4 "main"
Name 8 "o"
Name 14 "c"
Decorate 8(o) Location 0
Decorate 14(c) Location 0
2: TypeVoid
3: TypeFunction 2
6: TypeInt 32 1
7: TypePointer Output 6(int)
8(o): 7(ptr) Variable Output
9: 6(int) Constant 1
11: 6(int) Constant 3
12: TypeFloat 32
13: TypePointer Input 12(float)
14(c): 13(ptr) Variable Input
4(main): 2 Function None 3
5: Label
Store 8(o) 9
Kill
FunctionEnd
spv.dead-after-loop-break.vert
// Module Version 10000
// Generated by (magic number): 80007
// Id's are bound by 36
Capability Shader
1: ExtInstImport "GLSL.std.450"
MemoryModel Logical GLSL450
EntryPoint Vertex 4 "main" 8 25
Source GLSL 450
Name 4 "main"
Name 8 "o"
Name 11 "i"
Name 25 "c"
Decorate 8(o) Location 0
Decorate 25(c) Location 0
2: TypeVoid
3: TypeFunction 2
6: TypeInt 32 1
7: TypePointer Output 6(int)
8(o): 7(ptr) Variable Output
9: 6(int) Constant 1
10: TypePointer Function 6(int)
12: 6(int) Constant 0
19: 6(int) Constant 5
20: TypeBool
22: 6(int) Constant 2
24: TypePointer Input 6(int)
25(c): 24(ptr) Variable Input
30: 6(int) Constant 3
32: 6(int) Constant 4
35: 6(int) Constant 6
4(main): 2 Function None 3
5: Label
11(i): 10(ptr) Variable Function
Store 8(o) 9
Store 11(i) 12
Branch 13
13: Label
LoopMerge 15 16 None
Branch 17
17: Label
18: 6(int) Load 11(i)
21: 20(bool) SLessThan 18 19
BranchConditional 21 14 15
14: Label
Store 8(o) 22
23: 6(int) Load 11(i)
26: 6(int) Load 25(c)
27: 20(bool) IEqual 23 26
SelectionMerge 29 None
BranchConditional 27 28 29
28: Label
Store 8(o) 30
Branch 15
29: Label
Store 8(o) 19
Branch 16
16: Label
33: 6(int) Load 11(i)
34: 6(int) IAdd 33 9
Store 11(i) 34
Branch 13
15: Label
Store 8(o) 35
Return
FunctionEnd
spv.dead-after-return.vert
// Module Version 10000
// Generated by (magic number): 80007
// Id's are bound by 14
Capability Shader
1: ExtInstImport "GLSL.std.450"
MemoryModel Logical GLSL450
EntryPoint Vertex 4 "main" 8 13
Source GLSL 450
Name 4 "main"
Name 8 "o"
Name 13 "c"
Decorate 8(o) Location 0
Decorate 13(c) Location 0
2: TypeVoid
3: TypeFunction 2
6: TypeInt 32 1
7: TypePointer Output 6(int)
8(o): 7(ptr) Variable Output
9: 6(int) Constant 1
11: 6(int) Constant 3
12: TypePointer Input 6(int)
13(c): 12(ptr) Variable Input
4(main): 2 Function None 3
5: Label
Store 8(o) 9
Return
FunctionEnd
spv.dead-after-switch-break.vert
// Module Version 10000
// Generated by (magic number): 80007
// Id's are bound by 21
Capability Shader
1: ExtInstImport "GLSL.std.450"
MemoryModel Logical GLSL450
EntryPoint Vertex 4 "main" 8 14
Source GLSL 450
Name 4 "main"
Name 8 "c"
Name 14 "o"
Decorate 8(c) Location 0
Decorate 14(o) Location 0
2: TypeVoid
3: TypeFunction 2
6: TypeInt 32 1
7: TypePointer Input 6(int)
8(c): 7(ptr) Variable Input
13: TypePointer Output 6(int)
14(o): 13(ptr) Variable Output
15: 6(int) Constant 1
17: 6(int) Constant 2
20: 6(int) Constant 3
4(main): 2 Function None 3
5: Label
9: 6(int) Load 8(c)
SelectionMerge 12 None
Switch 9 11
case 0: 10
11: Label
Branch 12
10: Label
Store 14(o) 15
Branch 12
12: Label
Store 14(o) 20
Return
FunctionEnd
spv.dead-complex-continue-after-return.vert
// Module Version 10000
// Generated by (magic number): 80007
// Id's are bound by 31
Capability Shader
1: ExtInstImport "GLSL.std.450"
MemoryModel Logical GLSL450
EntryPoint Vertex 4 "main" 11 30
Source GLSL 450
Name 4 "main"
Name 8 "i"
Name 11 "o"
Name 30 "c"
Decorate 11(o) Location 0
Decorate 30(c) Location 0
2: TypeVoid
3: TypeFunction 2
6: TypeInt 32 1
7: TypePointer Function 6(int)
9: 6(int) Constant 0
10: TypePointer Output 6(int)
11(o): 10(ptr) Variable Output
12: 6(int) Constant 1
19: 6(int) Constant 5
20: TypeBool
22: 6(int) Constant 2
24: 6(int) Constant 3
27: 6(int) Constant 99
28: 6(int) Constant 4
29: TypePointer Input 6(int)
30(c): 29(ptr) Variable Input
4(main): 2 Function None 3
5: Label
8(i): 7(ptr) Variable Function
Store 8(i) 9
Store 11(o) 12
Store 8(i) 9
Branch 13
13: Label
LoopMerge 15 16 None
Branch 17
17: Label
18: 6(int) Load 8(i)
21: 20(bool) SLessThan 18 19
BranchConditional 21 14 15
14: Label
Store 11(o) 22
Return
16: Label
Branch 13
15: Label
Store 11(o) 28
Return
FunctionEnd
spv.dead-complex-merge-after-return.vert
// Module Version 10000
// Generated by (magic number): 80007
// Id's are bound by 36
Capability Shader
1: ExtInstImport "GLSL.std.450"
MemoryModel Logical GLSL450
EntryPoint Vertex 4 "main" 11 27
Source GLSL 450
Name 4 "main"
Name 8 "i"
Name 11 "o"
Name 27 "c"
Decorate 11(o) Location 0
Decorate 27(c) Location 0
2: TypeVoid
3: TypeFunction 2
6: TypeInt 32 1
7: TypePointer Function 6(int)
9: 6(int) Constant 0
10: TypePointer Output 6(int)
11(o): 10(ptr) Variable Output
12: 6(int) Constant 1
17: 6(int) Constant 2
19: 6(int) Constant 3
22: 6(int) Constant 5
23: TypeBool
25: 6(int) Constant 4
26: TypePointer Input 6(int)
27(c): 26(ptr) Variable Input
32: 6(int) Constant 100
34: 6(int) Constant 200
35: 6(int) Constant 300
4(main): 2 Function None 3
5: Label
8(i): 7(ptr) Variable Function
Store 8(i) 9
Store 11(o) 12
Branch 13
13: Label
LoopMerge 15 16 None
Branch 14
14: Label
Store 11(o) 17
Return
16: Label
Branch 13
15: Label
Unreachable
FunctionEnd
......@@ -160,7 +160,7 @@ spv.earlyReturnDiscard.frag
102: Label
Return
100: Label
Branch 67
Unreachable
67: Label
106: 7(fvec4) Load 9(color)
107: 7(fvec4) Load 13(color2)
......
......@@ -38,5 +38,5 @@ spv.for-notest.vert
Store 8(i) 19
Branch 10
12: Label
Return
Unreachable
FunctionEnd
......@@ -99,8 +99,7 @@ spv.forwardFun.frag
45: Label
ReturnValue 46
42: Label
48: 8(float) Undef
ReturnValue 48
Unreachable
FunctionEnd
16(foo(vf4;): 8(float) Function None 14
15(bar): 13(ptr) FunctionParameter
......
......@@ -105,8 +105,7 @@ WARNING: 0:5: varying deprecated in version 130; may be removed in future releas
44: Label
ReturnValue 45
41: Label
47: 6(float) Undef
ReturnValue 47
Unreachable
FunctionEnd
18(missingReturn(): 6(float) Function None 15
19: Label
......
......@@ -37,5 +37,5 @@ spv.merge-unreachable.frag
23: Label
Return
21: Label
Return
Unreachable
FunctionEnd
float4 PixelShaderFunction(float input) : COLOR0
{
void f0() {
[unroll] do {} while (false);
}
void f1() {
[unroll] do {;} while (false);
}
float f2(float input) {
do { return (float4)input; } while (input > 2.0);
}
void f3(float input) {
do ++input; while (input < 10.0);
}
void f4(float input) {
do while (++input < 10.0); while (++input < 10.0); // nest while inside do-while
}
float4 PixelShaderFunction(float input) : COLOR0
{
f0();
f1();
f2(input);
f3(input);
f4(input);
return (float4)input;
}
float4 PixelShaderFunction(float4 input) : COLOR0
{
void f0() {
for (;;) ;
}
void f1(float4 input) {
for (++input; ; ) ;
}
void f2(float4 input) {
[unroll] for (; any(input != input); ) {}
}
float f3(float4 input) {
for (; any(input != input); ) { return -input; }
}
float f4(float4 input) {
for (--input; any(input != input); input += 2) { return -input; }
}
void f5(float4 input) {
for (;;) if (input.x > 2.0) break;
}
void f6(float4 input) {
for (;;) if (input.x > 2.0) continue;
}
void f99() {
for (int first = 0, second = 1; ;) first + second;
}
void f100(float ii) {
for (--ii, --ii, --ii;;) ii;
}
float4 PixelShaderFunction(float4 input) : COLOR0
{
f0();
f1(input);
f2(input);
f3(input);
f4(input);
f5(input);
f6(input);
float ii;
for (int ii = -1; ii < 3; ++ii) if (ii == 2) continue;
--ii;
for (int first = 0, second = 1; ;) first + second;
f99();
for ( int i = 0, count = int(ii); i < count; i++ );
for (float first = 0, second[2], third; first < second[0]; ++second[1]) first + second[1] + third;
for (--ii, --ii, --ii;;) ii;
f100(ii);
return input;
}
float4 PixelShaderFunction(float4 input) : COLOR0
{
float4 f0(float4 input) {
if (all(input == input))
return input;
else
return -input;
}
if (all(input == input))
float4 f1(float4 input) {
if (all(input == input)) {
return input;
else
} else {
return -input;
}
}
float4 PixelShaderFunction(float4 input) : COLOR0
{
if (all(input == input))
return input;
f0(input);
if (all(input == input))
;
......@@ -20,11 +32,7 @@ float4 PixelShaderFunction(float4 input) : COLOR0
return input;
}
if (all(input == input)) {
return input;
} else {
return -input;
}
f1(input);
int ii;
if (float ii = input.z)
......
......@@ -4,11 +4,18 @@
bool cond;
void f0() {
[[loop]] for (;;) { }
}
void f1() {
[[dont_unroll]] while(true) { }
}
void main()
{
[[unroll]] for (int i = 0; i < 8; ++i) { }
[[loop]] for (;;) { }
[[dont_unroll]] while(true) { }
f0();
[[dependency_infinite]] do { } while(true);
[[dependency_length(1+3)]] for (int i = 0; i < 8; ++i) { }
[[flatten]] if (cond) { } else { }
......
#version 450
layout(location =0 ) in int c;
layout(location =0 ) out int o;
void main() {
int i;
for (i=0; i < 5; i++) {
o = 1;
continue;
o = 2;
}
o = 3;
}
#version 450
layout(location =0 ) in float c;
layout(location =0 ) out int o;
void main() {
o = 1;
discard;
o = 3;
}
#version 450
layout(location =0 ) in int c;
layout(location =0 ) out int o;
void main() {
int i;
o = 1;
for (i=0; i < 5; i++) {
o = 2;
if (i==c) {
o = 3;
break;
o = 4;
}
o = 5;
}
o = 6;
}
#version 450
layout(location =0 ) in int c;
layout(location =0 ) out int o;
void main() {
o = 1;
return;
o = 3;
}
#version 450
layout(location =0 ) in int c;
layout(location =0 ) out int o;
void main() {
int i;
switch(c) {
case 0: o=1;
break;
o=2;
default: break;
}
o = 3;
}
#version 450
layout(location =0 ) in int c;
layout(location =0 ) out int o;
void main() {
int i = 0;
o = 1;
// This has non-trivial continue target.
for (i=0; i < 5; ++i, o=99) {
o = 2;
return;
o = 3;
}
// This is considered reachable since Glslang codegen will
// create a conditional branch in the header, and one arm
// of that branch reaches this merge block.
o = 4;
}
#version 450
layout(location =0 ) in int c;
layout(location =0 ) out int o;
void main() {
int i = 0;
o = 1;
do {
o = 2;
return;
o = 3;
} while(i++ < 5);
// All this is a dead merge block.
o = 4;
if (c==4) {
o = 100;
} else {
o = 200;
}
o = 300;
}
......@@ -63,6 +63,7 @@ std::string FileNameAsCustomTestSuffixIoMap(
}
using CompileVulkanToSpirvTest = GlslangTest<::testing::TestWithParam<std::string>>;
using CompileVulkanToSpirvDeadCodeElimTest = GlslangTest<::testing::TestWithParam<std::string>>;
using CompileVulkanToDebugSpirvTest = GlslangTest<::testing::TestWithParam<std::string>>;
using CompileVulkan1_1ToSpirvTest = GlslangTest<::testing::TestWithParam<std::string>>;
using CompileToSpirv14Test = GlslangTest<::testing::TestWithParam<std::string>>;
......@@ -85,6 +86,13 @@ TEST_P(CompileVulkanToSpirvTest, FromFile)
Target::Spv);
}
TEST_P(CompileVulkanToSpirvDeadCodeElimTest, FromFile)
{
loadFileCompileAndCheck(GlobalTestSettings.testRoot, GetParam(),
Source::GLSL, Semantics::Vulkan, glslang::EShTargetVulkan_1_0, glslang::EShTargetSpv_1_0,
Target::Spv);
}
// Compiling GLSL to SPIR-V with debug info under Vulkan semantics. Expected
// to successfully generate SPIR-V.
TEST_P(CompileVulkanToDebugSpirvTest, FromFile)
......@@ -417,6 +425,23 @@ INSTANTIATE_TEST_CASE_P(
FileNameAsCustomTestSuffix
);
// Cases with deliberately unreachable code.
// By default the compiler will aggressively eliminate
// unreachable merges and continues.
INSTANTIATE_TEST_CASE_P(
GlslWithDeadCode, CompileVulkanToSpirvDeadCodeElimTest,
::testing::ValuesIn(std::vector<std::string>({
"spv.dead-after-continue.vert",
"spv.dead-after-discard.frag",
"spv.dead-after-return.vert",
"spv.dead-after-loop-break.vert",
"spv.dead-after-switch-break.vert",
"spv.dead-complex-continue-after-return.vert",
"spv.dead-complex-merge-after-return.vert",
})),
FileNameAsCustomTestSuffix
);
// clang-format off
INSTANTIATE_TEST_CASE_P(
Glsl, CompileVulkanToDebugSpirvTest,
......
......@@ -113,7 +113,7 @@ public:
forceVersionProfile(false),
isForwardCompatible(false) {
// Perform validation by default.
validatorOptions.validate = true;
spirvOptions.validate = true;
}
// Tries to load the contents from the file at the given |path|. On success,
......@@ -693,14 +693,14 @@ public:
expectedOutputFname, result.spirvWarningsErrors);
}
glslang::SpvOptions& options() { return validatorOptions; }
glslang::SpvOptions& options() { return spirvOptions; }
private:
const int defaultVersion;
const EProfile defaultProfile;
const bool forceVersionProfile;
const bool isForwardCompatible;
glslang::SpvOptions validatorOptions;
glslang::SpvOptions spirvOptions;
};
} // namespace glslangtest
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment