blob: df6ba81729fbef7f46efa8b3909943f6783aa974 [file] [log] [blame]
John Kessenichf04c51b2018-08-03 15:56:12 -06001//
2// Copyright (C) 2016-2018 Google, Inc.
3//
4// All rights reserved.
5//
6// Redistribution and use in source and binary forms, with or without
7// modification, are permitted provided that the following conditions
8// are met:
9//
10// Redistributions of source code must retain the above copyright
11// notice, this list of conditions and the following disclaimer.
12//
13// Redistributions in binary form must reproduce the above
14// copyright notice, this list of conditions and the following
15// disclaimer in the documentation and/or other materials provided
16// with the distribution.
17//
18// Neither the name of 3Dlabs Inc. Ltd. nor the names of its
19// contributors may be used to endorse or promote products derived
20// from this software without specific prior written permission.
21//
22// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
26// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
27// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
28// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
30// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
32// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33// POSSIBILITY OF SUCH DAMAGE.
34
35//
36// Post-processing for SPIR-V IR, in internal form, not standard binary form.
37//
38
39#include <cassert>
40#include <cstdlib>
41
42#include <unordered_set>
43#include <algorithm>
44
45#include "SpvBuilder.h"
46
47#include "spirv.hpp"
48#include "GlslangToSpv.h"
49#include "SpvBuilder.h"
50namespace spv {
51 #include "GLSL.std.450.h"
52 #include "GLSL.ext.KHR.h"
53 #include "GLSL.ext.EXT.h"
54#ifdef AMD_EXTENSIONS
55 #include "GLSL.ext.AMD.h"
56#endif
57#ifdef NV_EXTENSIONS
58 #include "GLSL.ext.NV.h"
59#endif
60}
61
62namespace spv {
63
John Kessenich228e9642018-08-13 21:37:59 -060064// Called for each instruction that resides in a block.
John Kessenichf04c51b2018-08-03 15:56:12 -060065void Builder::postProcess(Instruction& inst)
66{
67 // Add capabilities based simply on the opcode.
68 switch (inst.getOpCode()) {
69 case OpExtInst:
John Kessenich228e9642018-08-13 21:37:59 -060070 switch (inst.getImmediateOperand(1)) {
John Kessenichf04c51b2018-08-03 15:56:12 -060071 case GLSLstd450InterpolateAtCentroid:
72 case GLSLstd450InterpolateAtSample:
73 case GLSLstd450InterpolateAtOffset:
74 addCapability(CapabilityInterpolationFunction);
75 break;
76 default:
77 break;
78 }
79 break;
80 case OpDPdxFine:
81 case OpDPdyFine:
82 case OpFwidthFine:
83 case OpDPdxCoarse:
84 case OpDPdyCoarse:
85 case OpFwidthCoarse:
86 addCapability(CapabilityDerivativeControl);
87 break;
88
89 case OpImageQueryLod:
90 case OpImageQuerySize:
91 case OpImageQuerySizeLod:
92 case OpImageQuerySamples:
93 case OpImageQueryLevels:
94 addCapability(CapabilityImageQuery);
95 break;
96
97#ifdef NV_EXTENSIONS
98 case OpGroupNonUniformPartitionNV:
99 addExtension(E_SPV_NV_shader_subgroup_partitioned);
100 addCapability(CapabilityGroupNonUniformPartitionedNV);
101 break;
102#endif
103
104 default:
105 break;
106 }
107}
108
109// Called for each instruction in a reachable block.
110void Builder::postProcessReachable(Instruction& inst)
111{
112 // did have code here, but questionable to do so without deleting the instructions
113}
114
115// comment in header
116void Builder::postProcess()
117{
118 std::unordered_set<const Block*> reachableBlocks;
119 std::unordered_set<Id> unreachableDefinitions;
120 // Collect IDs defined in unreachable blocks. For each function, label the
121 // reachable blocks first. Then for each unreachable block, collect the
122 // result IDs of the instructions in it.
123 for (auto fi = module.getFunctions().cbegin(); fi != module.getFunctions().cend(); fi++) {
124 Function* f = *fi;
125 Block* entry = f->getEntryBlock();
126 inReadableOrder(entry, [&reachableBlocks](const Block* b) { reachableBlocks.insert(b); });
127 for (auto bi = f->getBlocks().cbegin(); bi != f->getBlocks().cend(); bi++) {
128 Block* b = *bi;
129 if (reachableBlocks.count(b) == 0) {
130 for (auto ii = b->getInstructions().cbegin(); ii != b->getInstructions().cend(); ii++)
131 unreachableDefinitions.insert(ii->get()->getResultId());
132 }
133 }
134 }
135
136 // Remove unneeded decorations, for unreachable instructions
137 decorations.erase(std::remove_if(decorations.begin(), decorations.end(),
138 [&unreachableDefinitions](std::unique_ptr<Instruction>& I) -> bool {
139 Id decoration_id = I.get()->getIdOperand(0);
140 return unreachableDefinitions.count(decoration_id) != 0;
141 }),
142 decorations.end());
143
144 // Add per-instruction capabilities, extensions, etc.,
145
146 // process all reachable instructions...
147 for (auto bi = reachableBlocks.cbegin(); bi != reachableBlocks.cend(); ++bi) {
148 const Block* block = *bi;
149 const auto function = [this](const std::unique_ptr<Instruction>& inst) { postProcessReachable(*inst.get()); };
150 std::for_each(block->getInstructions().begin(), block->getInstructions().end(), function);
151 }
152
153 // process all block-contained instructions
154 for (auto fi = module.getFunctions().cbegin(); fi != module.getFunctions().cend(); fi++) {
155 Function* f = *fi;
156 for (auto bi = f->getBlocks().cbegin(); bi != f->getBlocks().cend(); bi++) {
157 Block* b = *bi;
158 for (auto ii = b->getInstructions().cbegin(); ii != b->getInstructions().cend(); ii++)
159 postProcess(*ii->get());
160 }
161 }
162}
163
164}; // end spv namespace