//===- SPIRVDecorate.h - SPIR-V Decorations ----------------------*- C++ -*-===//
//
// The LLVM/SPIRV Translator
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
// Copyright (c) 2014 Advanced Micro Devices, Inc. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal with the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimers.
// Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimers in the documentation
// and/or other materials provided with the distribution.
// Neither the names of Advanced Micro Devices, Inc., nor the names of its
// contributors may be used to endorse or promote products derived from this
// Software without specific prior written permission.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH
// THE SOFTWARE.
//
//===----------------------------------------------------------------------===//
/// \file
///
/// This file defines SPIR-V decorations.
///
//===----------------------------------------------------------------------===//
#ifndef SPIRVDECORATE_HPP_
#define SPIRVDECORATE_HPP_
#include "SPIRVEntry.h"
#include "SPIRVUtil.h"
#include "SPIRVStream.h"
#include <string>
#include <vector>
#include <utility>
namespace SPIRV{
class SPIRVDecorationGroup;
class SPIRVDecorateGeneric:public SPIRVAnnotationGeneric{
public:
// Complete constructor for decorations without literals
SPIRVDecorateGeneric(Op OC, SPIRVWord WC, Decoration TheDec,
SPIRVEntry *TheTarget);
// Complete constructor for decorations with one word literal
SPIRVDecorateGeneric(Op OC, SPIRVWord WC, Decoration TheDec,
SPIRVEntry *TheTarget, SPIRVWord V);
// Incomplete constructor
SPIRVDecorateGeneric(Op OC);
SPIRVWord getLiteral(size_t) const;
Decoration getDecorateKind() const;
size_t getLiteralCount() const;
/// Compare for kind and literal only.
struct Comparator {
bool operator()(const SPIRVDecorateGeneric *A, const SPIRVDecorateGeneric *B);
};
/// Compare kind, literals and target.
friend bool operator==(const SPIRVDecorateGeneric &A,
const SPIRVDecorateGeneric &B);
SPIRVDecorationGroup* getOwner() const {
return Owner;
}
void setOwner(SPIRVDecorationGroup* owner) {
Owner = owner;
}
SPIRVCapVec getRequiredCapability() const {
return getCapability(Dec);
}
SPIRVWord getRequiredSPIRVVersion() const override {
switch (Dec) {
case DecorationSpecId:
if (getModule()->hasCapability(CapabilityKernel))
return SPIRV_1_1;
else
return SPIRV_1_0;
case DecorationMaxByteOffset:
return SPIRV_1_1;
default:
return SPIRV_1_0;
}
}
protected:
Decoration Dec;
std::vector<SPIRVWord> Literals;
SPIRVDecorationGroup *Owner; // Owning decorate group
};
class SPIRVDecorateSet: public std::multiset<const SPIRVDecorateGeneric *,
SPIRVDecorateGeneric::Comparator> {
public:
typedef std::multiset<const SPIRVDecorateGeneric *,
SPIRVDecorateGeneric::Comparator> BaseType;
iterator insert(const value_type& Dec) {
auto ER = BaseType::equal_range(Dec);
for (auto I = ER.first, E = ER.second; I != E; ++I) {
SPIRVDBG(spvdbgs() << "[compare decorate] " << *Dec
<< " vs " << **I << " : ");
if (**I == *Dec)
return I;
SPIRVDBG(spvdbgs() << " diff\n");
}
SPIRVDBG(spvdbgs() << "[add decorate] " << *Dec << '\n');
return BaseType::insert(Dec);
}
};
class SPIRVDecorate:public SPIRVDecorateGeneric{
public:
static const Op OC = OpDecorate;
static const SPIRVWord FixedWC = 3;
// Complete constructor for decorations without literals
SPIRVDecorate(Decoration TheDec, SPIRVEntry *TheTarget)
:SPIRVDecorateGeneric(OC, 3, TheDec, TheTarget){}
// Complete constructor for decorations with one word literal
SPIRVDecorate(Decoration TheDec, SPIRVEntry *TheTarget, SPIRVWord V)
:SPIRVDecorateGeneric(OC, 4, TheDec, TheTarget, V){}
// Incomplete constructor
SPIRVDecorate():SPIRVDecorateGeneric(OC){}
_SPIRV_DCL_ENCDEC
void setWordCount(SPIRVWord);
void validate()const {
SPIRVDecorateGeneric::validate();
assert(WordCount == Literals.size() + FixedWC);
}
};
class SPIRVDecorateLinkageAttr:public SPIRVDecorate{
public:
// Complete constructor for LinkageAttributes decorations
SPIRVDecorateLinkageAttr(SPIRVEntry *TheTarget,
const std::string &Name, SPIRVLinkageTypeKind Kind)
:SPIRVDecorate(DecorationLinkageAttributes, TheTarget) {
for (auto &I:getVec(Name))
Literals.push_back(I);
Literals.push_back(Kind);
WordCount += Literals.size();
}
// Incomplete constructor
SPIRVDecorateLinkageAttr():SPIRVDecorate(){}
std::string getLinkageName() const {
return getString(Literals.cbegin(), Literals.cend() - 1);
}
SPIRVLinkageTypeKind getLinkageType() const {
return (SPIRVLinkageTypeKind)Literals.back();
}
static void encodeLiterals(SPIRVEncoder& Encoder,
const std::vector<SPIRVWord>& Literals) {
#ifdef _SPIRV_SUPPORT_TEXT_FMT
if(SPIRVUseTextFormat) {
Encoder << getString(Literals.cbegin(), Literals.cend() - 1);
Encoder.OS << " ";
Encoder << (SPIRVLinkageTypeKind)Literals.back();
} else
#endif
Encoder << Literals;
}
static void decodeLiterals(SPIRVDecoder& Decoder, std::vector<SPIRVWord>& Literals) {
#ifdef _SPIRV_SUPPORT_TEXT_FMT
if(SPIRVUseTextFormat) {
std::string Name;
Decoder >> Name;
SPIRVLinkageTypeKind Kind;
Decoder >> Kind;
std::copy_n(getVec(Name).begin(), Literals.size()-1, Literals.begin());
Literals.back() = Kind;
} else
#endif
Decoder >> Literals;
}
};
class SPIRVMemberDecorate:public SPIRVDecorateGeneric{
public:
static const Op OC = OpMemberDecorate;
static const SPIRVWord FixedWC = 4;
// Complete constructor for decorations without literals
SPIRVMemberDecorate(Decoration TheDec, SPIRVWord Member,
SPIRVEntry *TheTarget)
:SPIRVDecorateGeneric(OC, 4, TheDec, TheTarget),
MemberNumber(Member){}
// Complete constructor for decorations with one word literal
SPIRVMemberDecorate(Decoration TheDec, SPIRVWord Member,
SPIRVEntry *TheTarget, SPIRVWord V)
:SPIRVDecorateGeneric(OC, 5, TheDec, TheTarget, V),
MemberNumber(Member){}
// Incomplete constructor
SPIRVMemberDecorate():SPIRVDecorateGeneric(OC), MemberNumber(SPIRVWORD_MAX){}
SPIRVWord getMemberNumber() const { return MemberNumber;}
std::pair<SPIRVWord, Decoration> getPair() const {
return std::make_pair(MemberNumber, Dec);
}
_SPIRV_DCL_ENCDEC
void setWordCount(SPIRVWord);
void validate()const {
SPIRVDecorateGeneric::validate();
assert(WordCount == Literals.size() + FixedWC);
}
protected:
SPIRVWord MemberNumber;
};
class SPIRVDecorationGroup:public SPIRVEntry{
public:
static const Op OC = OpDecorationGroup;
static const SPIRVWord WC = 2;
// Complete constructor. Does not populate Decorations.
SPIRVDecorationGroup(SPIRVModule *TheModule, SPIRVId TheId)
:SPIRVEntry(TheModule, WC, OC, TheId){
validate();
};
// Incomplete constructor
SPIRVDecorationGroup():SPIRVEntry(OC){}
void encodeAll(spv_ostream &O) const;
_SPIRV_DCL_ENCDEC
// Move the given decorates to the decoration group
void takeDecorates(SPIRVDecorateSet &Decs) {
Decorations = std::move(Decs);
for (auto &I:Decorations)
const_cast<SPIRVDecorateGeneric *>(I)->setOwner(this);
Decs.clear();
}
SPIRVDecorateSet& getDecorations() {
return Decorations;
}
protected:
SPIRVDecorateSet Decorations;
void validate()const {
assert(OpCode == OC);
assert(WordCount == WC);
}
};
class SPIRVGroupDecorateGeneric:public SPIRVEntryNoIdGeneric{
public:
static const SPIRVWord FixedWC = 2;
// Complete constructor
SPIRVGroupDecorateGeneric(Op OC, SPIRVDecorationGroup *TheGroup,
const std::vector<SPIRVId> &TheTargets)
:SPIRVEntryNoIdGeneric(TheGroup->getModule(), FixedWC + TheTargets.size(),
OC),
DecorationGroup(TheGroup), Targets(TheTargets){
}
// Incomplete constructor
SPIRVGroupDecorateGeneric(Op OC)
:SPIRVEntryNoIdGeneric(OC), DecorationGroup(nullptr){}
void setWordCount(SPIRVWord WC) {
SPIRVEntryNoIdGeneric::setWordCount(WC);
Targets.resize(WC - FixedWC);
}
virtual void decorateTargets() = 0;
_SPIRV_DCL_ENCDEC
protected:
SPIRVDecorationGroup *DecorationGroup;
std::vector<SPIRVId> Targets;
};
class SPIRVGroupDecorate:public SPIRVGroupDecorateGeneric{
public:
static const Op OC = OpGroupDecorate;
// Complete constructor
SPIRVGroupDecorate(SPIRVDecorationGroup *TheGroup,
const std::vector<SPIRVId> &TheTargets)
:SPIRVGroupDecorateGeneric(OC, TheGroup, TheTargets){}
// Incomplete constructor
SPIRVGroupDecorate()
:SPIRVGroupDecorateGeneric(OC){}
virtual void decorateTargets();
};
class SPIRVGroupMemberDecorate:public SPIRVGroupDecorateGeneric{
public:
static const Op OC = OpGroupMemberDecorate;
// Complete constructor
SPIRVGroupMemberDecorate(SPIRVDecorationGroup *TheGroup,
const std::vector<SPIRVId> &TheTargets)
:SPIRVGroupDecorateGeneric(OC, TheGroup, TheTargets){}
// Incomplete constructor
SPIRVGroupMemberDecorate()
:SPIRVGroupDecorateGeneric(OC){}
virtual void decorateTargets();
};
}
#endif /* SPIRVDECORATE_HPP_ */