godot/thirdparty/glslang/SPIRV/SPVRemapper.cpp

//
// Copyright (C) 2015 LunarG, Inc.
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
//    Redistributions of source code must retain the above copyright
//    notice, this list of conditions and the following disclaimer.
//
//    Redistributions in binary form must reproduce the above
//    copyright notice, this list of conditions and the following
//    disclaimer in the documentation and/or other materials provided
//    with the distribution.
//
//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
//    contributors may be used to endorse or promote products derived
//    from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//

#include "SPVRemapper.h"
#include "doc.h"

#include <algorithm>
#include <cassert>
#include "../glslang/Include/Common.h"

namespace spv {

    // By default, just abort on error.  Can be overridden via RegisterErrorHandler
    spirvbin_t::errorfn_t spirvbin_t::errorHandler =;
    // By default, eat log messages.  Can be overridden via RegisterLogHandler
    spirvbin_t::logfn_t   spirvbin_t::logHandler   =;

    // This can be overridden to provide other message behavior if needed
    void spirvbin_t::msg(int minVerbosity, int indent, const std::string& txt) const
    {}

    // hash opcode, with special handling for OpExtInst
    std::uint32_t spirvbin_t::asOpCodeHash(unsigned word)
    {}

    spirvbin_t::range_t spirvbin_t::literalRange(spv::Op opCode) const
    {}

    spirvbin_t::range_t spirvbin_t::typeRange(spv::Op opCode) const
    {}

    spirvbin_t::range_t spirvbin_t::constRange(spv::Op opCode) const
    {}

    // Return the size of a type in 32-bit words.  This currently only
    // handles ints and floats, and is only invoked by queries which must be
    // integer types.  If ever needed, it can be generalized.
    unsigned spirvbin_t::typeSizeInWords(spv::Id id) const
    {}

    // Looks up the type of a given const or variable ID, and
    // returns its size in 32-bit words.
    unsigned spirvbin_t::idTypeSizeInWords(spv::Id id) const
    {}

    // Is this an opcode we should remove when using --strip?
    bool spirvbin_t::isStripOp(spv::Op opCode, unsigned start) const
    {}

    // Return true if this opcode is flow control
    bool spirvbin_t::isFlowCtrl(spv::Op opCode) const
    {}

    // Return true if this opcode defines a type
    bool spirvbin_t::isTypeOp(spv::Op opCode) const
    {}

    // Return true if this opcode defines a constant
    bool spirvbin_t::isConstOp(spv::Op opCode) const
    {}

    const auto inst_fn_nop =;
    const auto op_fn_nop   =;

    // g++ doesn't like these defined in the class proper in an anonymous namespace.
    // Dunno why.  Also MSVC doesn't like the constexpr keyword.  Also dunno why.
    // Defining them externally seems to please both compilers, so, here they are.
    const spv::Id spirvbin_t::unmapped    =;
    const spv::Id spirvbin_t::unused      =;
    const int     spirvbin_t::header_size =;

    spv::Id spirvbin_t::nextUnusedId(spv::Id id)
    {}

    spv::Id spirvbin_t::localId(spv::Id id, spv::Id newId)
    {}

    // Parse a literal string from the SPIR binary and return it as an std::string
    // Due to C++11 RValue references, this doesn't copy the result string.
    std::string spirvbin_t::literalString(unsigned word) const
    {}

    void spirvbin_t::applyMap()
    {}

    // Find free IDs for anything we haven't mapped
    void spirvbin_t::mapRemainder()
    {}

    // Mark debug instructions for stripping
    void spirvbin_t::stripDebug()
    {}

    // Mark instructions that refer to now-removed IDs for stripping
    void spirvbin_t::stripDeadRefs()
    {}

    // Update local maps of ID, type, etc positions
    void spirvbin_t::buildLocalMaps()
    {}

    // Validate the SPIR header
    void spirvbin_t::validate() const
    {}

    int spirvbin_t::processInstruction(unsigned word, instfn_t instFn, idfn_t idFn)
    {}

    // Make a pass over all the instructions and process them given appropriate functions
    spirvbin_t& spirvbin_t::process(instfn_t instFn, idfn_t idFn, unsigned begin, unsigned end)
    {}

    // Apply global name mapping to a single module
    void spirvbin_t::mapNames()
    {}

    // Map fn contents to IDs of similar functions in other modules
    void spirvbin_t::mapFnBodies()
    {}

    // EXPERIMENTAL: forward IO and uniform load/stores into operands
    // This produces invalid Schema-0 SPIRV
    void spirvbin_t::forwardLoadStores()
    {}

    // optimize loads and stores
    void spirvbin_t::optLoadStore()
    {}

    // remove bodies of uncalled functions
    void spirvbin_t::dceFuncs()
    {}

    // remove unused function variables + decorations
    void spirvbin_t::dceVars()
    {}

    // remove unused types
    void spirvbin_t::dceTypes()
    {}

#ifdef NOTDEF
    bool spirvbin_t::matchType(const spirvbin_t::globaltypes_t& globalTypes, spv::Id lt, spv::Id gt) const
    {
        // Find the local type id "lt" and global type id "gt"
        const auto lt_it = typeConstPosR.find(lt);
        if (lt_it == typeConstPosR.end())
            return false;

        const auto typeStart = lt_it->second;

        // Search for entry in global table
        const auto gtype = globalTypes.find(gt);
        if (gtype == globalTypes.end())
            return false;

        const auto& gdata = gtype->second;

        // local wordcount and opcode
        const int     wordCount   = asWordCount(typeStart);
        const spv::Op opCode      = asOpCode(typeStart);

        // no type match if opcodes don't match, or operand count doesn't match
        if (opCode != opOpCode(gdata[0]) || wordCount != opWordCount(gdata[0]))
            return false;

        const unsigned numOperands = wordCount - 2; // all types have a result

        const auto cmpIdRange = [&](range_t range) {
            for (int x=range.first; x<std::min(range.second, wordCount); ++x)
                if (!matchType(globalTypes, asId(typeStart+x), gdata[x]))
                    return false;
            return true;
        };

        const auto cmpConst   = [&]() { return cmpIdRange(constRange(opCode)); };
        const auto cmpSubType = [&]() { return cmpIdRange(typeRange(opCode));  };

        // Compare literals in range [start,end)
        const auto cmpLiteral = [&]() {
            const auto range = literalRange(opCode);
            return std::equal(spir.begin() + typeStart + range.first,
                spir.begin() + typeStart + std::min(range.second, wordCount),
                gdata.begin() + range.first);
        };

        assert(isTypeOp(opCode) || isConstOp(opCode));

        switch (opCode) {
        case spv::OpTypeOpaque:       // TODO: disable until we compare the literal strings.
        case spv::OpTypeQueue:        return false;
        case spv::OpTypeEvent:        // fall through...
        case spv::OpTypeDeviceEvent:  // ...
        case spv::OpTypeReserveId:    return false;
            // for samplers, we don't handle the optional parameters yet
        case spv::OpTypeSampler:      return cmpLiteral() && cmpConst() && cmpSubType() && wordCount == 8;
        default:                      return cmpLiteral() && cmpConst() && cmpSubType();
        }
    }

    // Look for an equivalent type in the globalTypes map
    spv::Id spirvbin_t::findType(const spirvbin_t::globaltypes_t& globalTypes, spv::Id lt) const
    {
        // Try a recursive type match on each in turn, and return a match if we find one
        for (const auto& gt : globalTypes)
            if (matchType(globalTypes, lt, gt.first))
                return gt.first;

        return spv::NoType;
    }
#endif // NOTDEF

    // Return start position in SPV of given Id.  error if not found.
    unsigned spirvbin_t::idPos(spv::Id id) const
    {}

    // Hash types to canonical values.  This can return ID collisions (it's a bit
    // inevitable): it's up to the caller to handle that gracefully.
    std::uint32_t spirvbin_t::hashType(unsigned typeStart) const
    {}

    void spirvbin_t::mapTypeConst()
    {}

    // Strip a single binary by removing ranges given in stripRange
    void spirvbin_t::strip()
    {}

    // Strip a single binary by removing ranges given in stripRange
    void spirvbin_t::remap(std::uint32_t opts)
    {}

    // remap from a memory image
    void spirvbin_t::remap(std::vector<std::uint32_t>& in_spv, const std::vector<std::string>& whiteListStrings,
                           std::uint32_t opts)
    {}

    // remap from a memory image - legacy interface without white list
    void spirvbin_t::remap(std::vector<std::uint32_t>& in_spv, std::uint32_t opts)
    {}

} // namespace SPV