John Kessenich | f04c51b | 2018-08-03 15:56:12 -0600 | [diff] [blame] | 1 | // |
| 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" |
| 50 | namespace 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 | |
| 62 | namespace spv { |
| 63 | |
| 64 | // Called for each instruction in a block. |
| 65 | void Builder::postProcess(Instruction& inst) |
| 66 | { |
| 67 | // Add capabilities based simply on the opcode. |
| 68 | switch (inst.getOpCode()) { |
| 69 | case OpExtInst: |
| 70 | switch (inst.getIdOperand(1)) { |
| 71 | 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. |
| 110 | void 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 |
| 116 | void 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 |